orizu 0.1.3 → 0.1.5

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/README.md ADDED
@@ -0,0 +1,220 @@
1
+ # Orizu CLI
2
+
3
+ ## What is Orizu
4
+
5
+ Orizu is a platform that helps you build continually learning agents and other LLM applications. It does so in a scientific, measurable manner by first helping you build evals and then helping you hill climb on them.
6
+
7
+ ## How Orizu works
8
+
9
+ There are 3 key pillars to Orizu:
10
+ 1. **Human evaluation:** We consider human evaluation to be the gold standard, particularly when the humans involved are people with deep context and understanding of the output being evaluated. This is often the cross-functional team behind a product (product managers, engineers, designers, content writers, researchers, etc) or external experts (lawyers, engineers, writers, etc). Any good evaluation system relies on the presence of such high quality judgment to compare to. We provide tools that simplify the process of collecting the feedback from this audience.
11
+ 2. **Auto evaluation:** Ultimately, human experts can only review so much. As your data scales, you need to encode their knowledge, their opinions, their taste and judgment into auto-evaluations. We automate this for you using the data we help you collect above.
12
+ 3. **Optimization:** We turn your evals into an asset for you by building an automated hill-climbing workflow. We've started with prompt optimization because multiple studies and our own experience with our customers has shown strong measurable lifts with even relatively small datasets. Over time, we'll introduce additional capabilities, including optimizing your skills and other contextual information, and even model weights if your model provider allows finetuning.
13
+
14
+ ## CLI and Agent Skills
15
+
16
+ We've created a CLI for you to use so that you can perform any task that you can on our platform – from admin stuff like creating teams and projects to uploading datasets and assigning reviews – from your terminal. The obvious reason we did this is so that you can have your coding agents do this for you.
17
+
18
+ Note: the one task we do _not_ let you perform from your CLI is any reviews assigned to you. We want to ensure that the data being collected is from the intended human expert.
19
+
20
+ ## Requirements
21
+
22
+ - [Node.js 20+](https://nodejs.org/en/download)
23
+ - Access to an Orizu web app/API
24
+ - A valid Orizu account
25
+
26
+ By default, the CLI talks to `https://orizu.ai`.
27
+
28
+ ## Install
29
+
30
+ Install the CLI globally with your package manager:
31
+
32
+ | Package manager | Command |
33
+ | --- | --- |
34
+ | npm | `npm i -g orizu` |
35
+ | pnpm | `pnpm add -g orizu` |
36
+ | Bun | `bun add -g orizu` |
37
+
38
+ Install the companion coding agent skill using [Skills.sh](https://skills.sh).
39
+
40
+ ```bash
41
+ npx skills add raveeshbhalla/orizu-cli --skill orizu-cli
42
+ ```
43
+
44
+ ## Authentication
45
+
46
+ **Sign in**
47
+
48
+ ```bash
49
+ orizu login
50
+ ```
51
+
52
+ This will open a browser tab for you to login with. You must either have an account on the [Orizu platform](https://orizu.ai) or it will help you create one.
53
+
54
+ **Check the signed-in user**
55
+
56
+ ```bash
57
+ orizu whoami
58
+ ```
59
+
60
+ **Sign out**
61
+
62
+ ```bash
63
+ orizu logout
64
+ ```
65
+
66
+ ## Common Commands
67
+
68
+ <table>
69
+ <tr>
70
+ <th>Task</th>
71
+ <th>Command</th>
72
+ </tr>
73
+ <tr>
74
+ <td colspan="2"><strong>Teams</strong></td>
75
+ </tr>
76
+ <tr>
77
+ <td>List teams</td>
78
+ <td><code>orizu teams list</code></td>
79
+ </tr>
80
+ <tr>
81
+ <td>Create a team</td>
82
+ <td><code>orizu teams create --name "Ops Eval"</code></td>
83
+ </tr>
84
+ <tr>
85
+ <td>List team members</td>
86
+ <td><code>orizu teams members list --team ops-eval</code></td>
87
+ </tr>
88
+ <tr>
89
+ <td>Add a team member</td>
90
+ <td><code>orizu teams members add --email person@example.com --team ops-eval</code></td>
91
+ </tr>
92
+ <tr>
93
+ <td colspan="2"><strong>Projects</strong></td>
94
+ </tr>
95
+ <tr>
96
+ <td>List projects</td>
97
+ <td><code>orizu projects list --team ops-eval</code></td>
98
+ </tr>
99
+ <tr>
100
+ <td>Create a project</td>
101
+ <td><code>orizu projects create --name "Support QA" --team ops-eval</code></td>
102
+ </tr>
103
+ <tr>
104
+ <td colspan="2"><strong>Datasets</strong></td>
105
+ </tr>
106
+ <tr>
107
+ <td>Upload a dataset</td>
108
+ <td>
109
+ <pre><code>orizu datasets upload \
110
+ --project ops-eval/support-qa \
111
+ --file ./datasets/support.jsonl \
112
+ --name "Support Batch 1"</code></pre>
113
+ </td>
114
+ </tr>
115
+ <tr>
116
+ <td>Download a dataset</td>
117
+ <td><code>orizu datasets download --dataset &lt;datasetId&gt; --format jsonl --out ./dataset.jsonl</code></td>
118
+ </tr>
119
+ <tr>
120
+ <td>Append dataset rows</td>
121
+ <td><code>orizu datasets append --dataset &lt;datasetId&gt; --file ./datasets/support-extra.jsonl</code></td>
122
+ </tr>
123
+ <tr>
124
+ <td>Lock a dataset</td>
125
+ <td><code>orizu datasets lock --dataset &lt;datasetId&gt; --reason "Finalize for labeling"</code></td>
126
+ </tr>
127
+ <tr>
128
+ <td colspan="2"><strong>Apps</strong></td>
129
+ </tr>
130
+ <tr>
131
+ <td>List apps</td>
132
+ <td><code>orizu apps list --project ops-eval/support-qa</code></td>
133
+ </tr>
134
+ <tr>
135
+ <td>Create an app</td>
136
+ <td>
137
+ <pre><code>orizu apps create \
138
+ --project ops-eval/support-qa \
139
+ --name "Support Labeler" \
140
+ --dataset &lt;datasetId&gt; \
141
+ --file ./apps/SupportLabeler.tsx \
142
+ --input-schema ./schemas/support-input.json \
143
+ --output-schema ./schemas/support-output.json</code></pre>
144
+ </td>
145
+ </tr>
146
+ <tr>
147
+ <td>Update an app</td>
148
+ <td>
149
+ <pre><code>orizu apps update \
150
+ --app &lt;appId&gt; \
151
+ --file ./apps/SupportLabeler.tsx \
152
+ --input-schema ./schemas/support-input.json \
153
+ --output-schema ./schemas/support-output.json</code></pre>
154
+ </td>
155
+ </tr>
156
+ <tr>
157
+ <td>Link a dataset to an app</td>
158
+ <td><code>orizu apps link-dataset --app &lt;appId&gt; --dataset &lt;datasetId&gt;</code></td>
159
+ </tr>
160
+ <tr>
161
+ <td colspan="2"><strong>Tasks</strong></td>
162
+ </tr>
163
+ <tr>
164
+ <td>Create a task</td>
165
+ <td>
166
+ <pre><code>orizu tasks create \
167
+ --project ops-eval/support-qa \
168
+ --dataset &lt;datasetId&gt; \
169
+ --app &lt;appId&gt; \
170
+ --title "Support QA Round 1" \
171
+ --assignees &lt;userIdOrEmail1,userIdOrEmail2&gt; \
172
+ --labels-per-item 2</code></pre>
173
+ </td>
174
+ </tr>
175
+ <tr>
176
+ <td>Check task status</td>
177
+ <td><code>orizu tasks status --task &lt;taskId&gt;</code></td>
178
+ </tr>
179
+ <tr>
180
+ <td>Pause a task</td>
181
+ <td><code>orizu tasks pause --task &lt;taskId&gt;</code></td>
182
+ </tr>
183
+ <tr>
184
+ <td>Resume a task</td>
185
+ <td><code>orizu tasks unpause --task &lt;taskId&gt;</code></td>
186
+ </tr>
187
+ <tr>
188
+ <td>Export task results</td>
189
+ <td><code>orizu tasks export --task &lt;taskId&gt; --format csv --out ./support-round1.csv</code></td>
190
+ </tr>
191
+ </table>
192
+
193
+ ## Supported Data Formats
194
+
195
+ Dataset upload, append, and edit-rows commands support:
196
+
197
+ - `.csv`
198
+ - `.json` files containing an array of objects
199
+ - `.jsonl` files containing one object per line
200
+
201
+ Task and dataset export support:
202
+
203
+ - `csv`
204
+ - `json`
205
+ - `jsonl`
206
+
207
+ ## Interactive And Automated Usage
208
+
209
+ Many commands can prompt for missing team, project, app, dataset, or task selections in an interactive terminal. In scripts and CI, pass explicit flags instead:
210
+
211
+ ```bash
212
+ orizu tasks export --task <taskId> --format jsonl --out ./labels.jsonl
213
+ ```
214
+
215
+ Use `--json` on supported task and app commands when automation needs structured output.
216
+
217
+ ## More Documentation
218
+
219
+ - [docs/cli.md](docs/cli.md): complete CLI guide and command reference
220
+ - [skills/orizu-cli/references/cli-reference.md](skills/orizu-cli/references/cli-reference.md): compact command matrix and end-to-end flows
package/dist/index.js CHANGED
@@ -360,6 +360,113 @@ function resolveAuthCallbackPort() {
360
360
  }
361
361
  return parsed;
362
362
  }
363
+ function renderCliAuthBrowserPage(status) {
364
+ const isSuccess = status === 'success';
365
+ const eyebrow = isSuccess ? '// cli login complete' : '// cli login';
366
+ const title = isSuccess ? 'Browser authorization complete' : 'Missing authorization code';
367
+ const detail = isSuccess
368
+ ? 'Your terminal will finish connecting the Orizu CLI. You can close this tab.'
369
+ : 'Close this tab and run orizu login again to start a fresh browser request.';
370
+ const accent = isSuccess ? '#E8923C' : '#C8442A';
371
+ return `<!doctype html>
372
+ <html lang="en">
373
+ <head>
374
+ <meta charset="utf-8">
375
+ <meta name="viewport" content="width=device-width, initial-scale=1">
376
+ <title>Orizu CLI Login</title>
377
+ <style>
378
+ @import url('https://fonts.googleapis.com/css2?family=Geist+Mono:wght@400;500;700&display=swap');
379
+ :root {
380
+ color-scheme: light;
381
+ --paper: #F4EFE3;
382
+ --border: #E6DFCE;
383
+ --ink: #353535;
384
+ --muted: #6B6358;
385
+ }
386
+ * { box-sizing: border-box; }
387
+ body {
388
+ margin: 0;
389
+ min-height: 100vh;
390
+ background: #FFFFFF;
391
+ color: #4B4B4B;
392
+ font-family: 'Geist Mono', Menlo, Monaco, Consolas, monospace;
393
+ letter-spacing: -0.025em;
394
+ }
395
+ main {
396
+ min-height: 100vh;
397
+ display: flex;
398
+ align-items: center;
399
+ justify-content: center;
400
+ padding: 48px 24px;
401
+ }
402
+ section {
403
+ width: min(100%, 520px);
404
+ text-align: center;
405
+ }
406
+ .brand {
407
+ display: flex;
408
+ flex-direction: column;
409
+ align-items: center;
410
+ gap: 12px;
411
+ margin-bottom: 28px;
412
+ }
413
+ .brand svg {
414
+ width: 42px;
415
+ height: 42px;
416
+ color: #202124;
417
+ }
418
+ .brand span {
419
+ color: #000000;
420
+ font-size: 16px;
421
+ font-weight: 700;
422
+ }
423
+ .eyebrow {
424
+ margin: 0 0 12px;
425
+ color: ${accent};
426
+ font-size: 12px;
427
+ text-transform: lowercase;
428
+ }
429
+ h1 {
430
+ margin: 0 0 8px;
431
+ color: var(--ink);
432
+ font-size: 24px;
433
+ line-height: 1.15;
434
+ letter-spacing: -0.05em;
435
+ }
436
+ .detail {
437
+ margin: 0;
438
+ color: var(--muted);
439
+ font-size: 13px;
440
+ line-height: 1.6;
441
+ }
442
+ </style>
443
+ </head>
444
+ <body>
445
+ <main>
446
+ <section>
447
+ <div class="brand" aria-hidden="true">
448
+ <svg viewBox="0 0 2048 2048" xmlns="http://www.w3.org/2000/svg">
449
+ <g fill="currentColor">
450
+ <polygon points="1545,879 787,1195 1189,1577"></polygon>
451
+ <polygon points="992,624 444,1104 688,1338"></polygon>
452
+ <polygon points="602,1593 1180,1594 768,1202"></polygon>
453
+ <polygon points="1650,1195 1398,1203 1204,1594 1229,1593"></polygon>
454
+ <polygon points="807,413 751,509 823,744 980,608"></polygon>
455
+ <polygon points="441,1127 592,1572 681,1356"></polygon>
456
+ <polygon points="793,399 611,457 604,471 658,602"></polygon>
457
+ <polygon points="593,493 498,667 636,600"></polygon>
458
+ </g>
459
+ </svg>
460
+ <span>orizu</span>
461
+ </div>
462
+ <p class="eyebrow">${eyebrow}</p>
463
+ <h1>${title}</h1>
464
+ <p class="detail">${detail}</p>
465
+ </section>
466
+ </main>
467
+ </body>
468
+ </html>`;
469
+ }
363
470
  async function login() {
364
471
  const baseUrl = resolveLoginBaseUrl();
365
472
  const codeVerifier = createCodeVerifier();
@@ -372,12 +479,13 @@ async function login() {
372
479
  const code = url.searchParams.get('code');
373
480
  if (!code) {
374
481
  response.statusCode = 400;
375
- response.end('Missing code');
482
+ response.setHeader('content-type', 'text/html; charset=utf-8');
483
+ response.end(renderCliAuthBrowserPage('error'));
376
484
  return;
377
485
  }
378
486
  response.statusCode = 200;
379
- response.setHeader('content-type', 'text/html');
380
- response.end('<html><body><h3>CLI login complete. You can close this tab.</h3></body></html>');
487
+ response.setHeader('content-type', 'text/html; charset=utf-8');
488
+ response.end(renderCliAuthBrowserPage('success'));
381
489
  server.close();
382
490
  resolve(code);
383
491
  }
@@ -453,8 +561,10 @@ async function logout() {
453
561
  await fetch(`${baseUrl}/api/cli/auth/logout`, {
454
562
  method: 'POST',
455
563
  headers: {
564
+ 'Content-Type': 'application/json',
456
565
  Authorization: `Bearer ${credentials.accessToken}`,
457
566
  },
567
+ body: JSON.stringify({ refreshToken: credentials.refreshToken }),
458
568
  }).catch(() => undefined);
459
569
  clearServerCredentials(baseUrl);
460
570
  console.log(`Logged out from ${baseUrl}.`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orizu",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {
package/src/index.ts CHANGED
@@ -637,6 +637,115 @@ function resolveAuthCallbackPort(): number {
637
637
  return parsed
638
638
  }
639
639
 
640
+ function renderCliAuthBrowserPage(status: 'success' | 'error'): string {
641
+ const isSuccess = status === 'success'
642
+ const eyebrow = isSuccess ? '// cli login complete' : '// cli login'
643
+ const title = isSuccess ? 'Browser authorization complete' : 'Missing authorization code'
644
+ const detail = isSuccess
645
+ ? 'Your terminal will finish connecting the Orizu CLI. You can close this tab.'
646
+ : 'Close this tab and run orizu login again to start a fresh browser request.'
647
+ const accent = isSuccess ? '#E8923C' : '#C8442A'
648
+
649
+ return `<!doctype html>
650
+ <html lang="en">
651
+ <head>
652
+ <meta charset="utf-8">
653
+ <meta name="viewport" content="width=device-width, initial-scale=1">
654
+ <title>Orizu CLI Login</title>
655
+ <style>
656
+ @import url('https://fonts.googleapis.com/css2?family=Geist+Mono:wght@400;500;700&display=swap');
657
+ :root {
658
+ color-scheme: light;
659
+ --paper: #F4EFE3;
660
+ --border: #E6DFCE;
661
+ --ink: #353535;
662
+ --muted: #6B6358;
663
+ }
664
+ * { box-sizing: border-box; }
665
+ body {
666
+ margin: 0;
667
+ min-height: 100vh;
668
+ background: #FFFFFF;
669
+ color: #4B4B4B;
670
+ font-family: 'Geist Mono', Menlo, Monaco, Consolas, monospace;
671
+ letter-spacing: -0.025em;
672
+ }
673
+ main {
674
+ min-height: 100vh;
675
+ display: flex;
676
+ align-items: center;
677
+ justify-content: center;
678
+ padding: 48px 24px;
679
+ }
680
+ section {
681
+ width: min(100%, 520px);
682
+ text-align: center;
683
+ }
684
+ .brand {
685
+ display: flex;
686
+ flex-direction: column;
687
+ align-items: center;
688
+ gap: 12px;
689
+ margin-bottom: 28px;
690
+ }
691
+ .brand svg {
692
+ width: 42px;
693
+ height: 42px;
694
+ color: #202124;
695
+ }
696
+ .brand span {
697
+ color: #000000;
698
+ font-size: 16px;
699
+ font-weight: 700;
700
+ }
701
+ .eyebrow {
702
+ margin: 0 0 12px;
703
+ color: ${accent};
704
+ font-size: 12px;
705
+ text-transform: lowercase;
706
+ }
707
+ h1 {
708
+ margin: 0 0 8px;
709
+ color: var(--ink);
710
+ font-size: 24px;
711
+ line-height: 1.15;
712
+ letter-spacing: -0.05em;
713
+ }
714
+ .detail {
715
+ margin: 0;
716
+ color: var(--muted);
717
+ font-size: 13px;
718
+ line-height: 1.6;
719
+ }
720
+ </style>
721
+ </head>
722
+ <body>
723
+ <main>
724
+ <section>
725
+ <div class="brand" aria-hidden="true">
726
+ <svg viewBox="0 0 2048 2048" xmlns="http://www.w3.org/2000/svg">
727
+ <g fill="currentColor">
728
+ <polygon points="1545,879 787,1195 1189,1577"></polygon>
729
+ <polygon points="992,624 444,1104 688,1338"></polygon>
730
+ <polygon points="602,1593 1180,1594 768,1202"></polygon>
731
+ <polygon points="1650,1195 1398,1203 1204,1594 1229,1593"></polygon>
732
+ <polygon points="807,413 751,509 823,744 980,608"></polygon>
733
+ <polygon points="441,1127 592,1572 681,1356"></polygon>
734
+ <polygon points="793,399 611,457 604,471 658,602"></polygon>
735
+ <polygon points="593,493 498,667 636,600"></polygon>
736
+ </g>
737
+ </svg>
738
+ <span>orizu</span>
739
+ </div>
740
+ <p class="eyebrow">${eyebrow}</p>
741
+ <h1>${title}</h1>
742
+ <p class="detail">${detail}</p>
743
+ </section>
744
+ </main>
745
+ </body>
746
+ </html>`
747
+ }
748
+
640
749
  async function login() {
641
750
  const baseUrl = resolveLoginBaseUrl()
642
751
  const codeVerifier = createCodeVerifier()
@@ -651,13 +760,14 @@ async function login() {
651
760
 
652
761
  if (!code) {
653
762
  response.statusCode = 400
654
- response.end('Missing code')
763
+ response.setHeader('content-type', 'text/html; charset=utf-8')
764
+ response.end(renderCliAuthBrowserPage('error'))
655
765
  return
656
766
  }
657
767
 
658
768
  response.statusCode = 200
659
- response.setHeader('content-type', 'text/html')
660
- response.end('<html><body><h3>CLI login complete. You can close this tab.</h3></body></html>')
769
+ response.setHeader('content-type', 'text/html; charset=utf-8')
770
+ response.end(renderCliAuthBrowserPage('success'))
661
771
 
662
772
  server.close()
663
773
  resolve(code)
@@ -748,8 +858,10 @@ async function logout() {
748
858
  await fetch(`${baseUrl}/api/cli/auth/logout`, {
749
859
  method: 'POST',
750
860
  headers: {
861
+ 'Content-Type': 'application/json',
751
862
  Authorization: `Bearer ${credentials.accessToken}`,
752
863
  },
864
+ body: JSON.stringify({ refreshToken: credentials.refreshToken }),
753
865
  }).catch(() => undefined)
754
866
 
755
867
  clearServerCredentials(baseUrl)