orizu 0.3.7 → 0.4.1
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 +55 -6
- package/dist/banner.js +20 -0
- package/dist/csv.js +117 -9
- package/dist/help.js +114 -15
- package/dist/index.js +828 -67
- package/dist/setup-prompt.js +22 -0
- package/dist/skill-installer.js +243 -17
- package/dist/task-assignment-manifest.js +59 -0
- package/dist/workspace.js +76 -0
- package/package.json +5 -1
- package/src/banner.ts +21 -0
- package/src/csv.ts +140 -10
- package/src/help.ts +114 -15
- package/src/index.ts +933 -70
- package/src/setup-prompt.ts +27 -0
- package/src/skill-installer.ts +343 -17
- package/src/task-assignment-manifest.ts +96 -0
- package/src/workspace.ts +112 -0
- package/vendor/orizu-gepa-python/src/orizu_gepa/__init__.py +2 -0
- package/vendor/orizu-gepa-python/src/orizu_gepa/cli.py +57 -3
- package/vendor/orizu-gepa-python/src/orizu_gepa/client.py +37 -1
- package/vendor/orizu-gepa-python/src/orizu_gepa/optimizer.py +233 -17
- package/vendor/orizu-gepa-python/src/orizu_gepa/reflection.py +98 -17
- package/vendor/skills/orizu-cli/SKILL.md +13 -6
- package/vendor/skills/orizu-cli/references/cli-reference.md +34 -5
- package/vendor/skills/orizu-cli/references/optimization-reports.md +2 -2
- package/vendor/skills/orizu-cli/references/optimization-with-gepa.md +1 -0
- package/vendor/skills/orizu-cli/references/prompt-control-plane.md +17 -5
package/src/csv.ts
CHANGED
|
@@ -1,4 +1,124 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* CSV parsing utilities with RFC 4180 compliance.
|
|
3
|
+
*
|
|
4
|
+
* This is the single canonical implementation shared by the web app and the
|
|
5
|
+
* published CLI: lib/csv-utils.ts re-exports from here. It lives inside
|
|
6
|
+
* packages/cli because the CLI is published standalone to npm and cannot
|
|
7
|
+
* import files outside its package root, while the app can import anything.
|
|
8
|
+
*
|
|
9
|
+
* Resource limits are enforced while parsing so a hostile CSV cannot exhaust
|
|
10
|
+
* memory. The numeric defaults are inlined here (this package cannot import
|
|
11
|
+
* @/lib/resource-limits) and mirror RESOURCE_LIMITS.CSV_* in that module —
|
|
12
|
+
* keep the two in sync.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export class CSVResourceLimitError extends Error {
|
|
16
|
+
constructor(message: string) {
|
|
17
|
+
super(message)
|
|
18
|
+
this.name = 'CSVResourceLimitError'
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface CSVParseOptions {
|
|
23
|
+
maxBytes?: number
|
|
24
|
+
maxRows?: number
|
|
25
|
+
maxFields?: number
|
|
26
|
+
maxFieldBytes?: number
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Mirrors RESOURCE_LIMITS.CSV_* in lib/resource-limits.ts.
|
|
30
|
+
const DEFAULT_CSV_MAX_BYTES = 10 * 1024 * 1024
|
|
31
|
+
const DEFAULT_CSV_MAX_ROWS = 5_000
|
|
32
|
+
const DEFAULT_CSV_MAX_FIELDS = 200
|
|
33
|
+
const DEFAULT_CSV_MAX_FIELD_BYTES = 128 * 1024
|
|
34
|
+
|
|
35
|
+
function getUtf8ByteLength(value: string): number {
|
|
36
|
+
let bytes = 0
|
|
37
|
+
|
|
38
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
39
|
+
const codePoint = value.charCodeAt(index)
|
|
40
|
+
|
|
41
|
+
if (codePoint <= 0x7f) {
|
|
42
|
+
bytes += 1
|
|
43
|
+
} else if (codePoint <= 0x7ff) {
|
|
44
|
+
bytes += 2
|
|
45
|
+
} else if (
|
|
46
|
+
codePoint >= 0xd800 &&
|
|
47
|
+
codePoint <= 0xdbff &&
|
|
48
|
+
index + 1 < value.length
|
|
49
|
+
) {
|
|
50
|
+
const next = value.charCodeAt(index + 1)
|
|
51
|
+
if (next >= 0xdc00 && next <= 0xdfff) {
|
|
52
|
+
bytes += 4
|
|
53
|
+
index += 1
|
|
54
|
+
} else {
|
|
55
|
+
bytes += 3
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
bytes += 3
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return bytes
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function enforceCsvTextLimit(csvText: string, options: CSVParseOptions): void {
|
|
66
|
+
const maxBytes = options.maxBytes ?? DEFAULT_CSV_MAX_BYTES
|
|
67
|
+
if (getUtf8ByteLength(csvText) > maxBytes) {
|
|
68
|
+
throw new CSVResourceLimitError(`CSV data is too large (max ${maxBytes} bytes)`)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function enforceRowLimit(rowCount: number, options: CSVParseOptions): void {
|
|
73
|
+
const maxRows = options.maxRows ?? DEFAULT_CSV_MAX_ROWS
|
|
74
|
+
if (rowCount > maxRows) {
|
|
75
|
+
throw new CSVResourceLimitError(`CSV has too many rows (max ${maxRows})`)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function enforceFieldLimits(row: string[], options: CSVParseOptions): void {
|
|
80
|
+
const maxFields = options.maxFields ?? DEFAULT_CSV_MAX_FIELDS
|
|
81
|
+
if (row.length > maxFields) {
|
|
82
|
+
throw new CSVResourceLimitError(`CSV row has too many fields (max ${maxFields})`)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const maxFieldBytes = options.maxFieldBytes ?? DEFAULT_CSV_MAX_FIELD_BYTES
|
|
86
|
+
for (const field of row) {
|
|
87
|
+
if (getUtf8ByteLength(field) > maxFieldBytes) {
|
|
88
|
+
throw new CSVResourceLimitError(`CSV field is too large (max ${maxFieldBytes} bytes)`)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function addCsvRow(result: string[][], row: string[], options: CSVParseOptions): void {
|
|
94
|
+
// Only keep rows with at least one non-whitespace field
|
|
95
|
+
if (!row.some(field => field.trim())) {
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
enforceFieldLimits(row, options)
|
|
100
|
+
result.push(row)
|
|
101
|
+
enforceRowLimit(result.length, options)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Parses CSV text into a 2D array of strings, handling quoted fields, escaped
|
|
106
|
+
* quotes, multiline fields, and different line endings (CRLF, LF, CR).
|
|
107
|
+
* Completely empty rows are skipped.
|
|
108
|
+
*
|
|
109
|
+
* Resource limits (size, rows, fields, field size) are enforced during
|
|
110
|
+
* parsing; pass `options` to override the defaults. A violation throws
|
|
111
|
+
* {@link CSVResourceLimitError}.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```typescript
|
|
115
|
+
* const csv = 'name,age,city\nJohn,25,"New York"'
|
|
116
|
+
* parseCSV(csv) // [['name', 'age', 'city'], ['John', '25', 'New York']]
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
export function parseCSV(csvText: string, options: CSVParseOptions = {}): string[][] {
|
|
120
|
+
enforceCsvTextLimit(csvText, options)
|
|
121
|
+
|
|
2
122
|
const result: string[][] = []
|
|
3
123
|
let currentRow: string[] = []
|
|
4
124
|
let currentField = ''
|
|
@@ -11,6 +131,7 @@ export function parseCSV(csvText: string): string[][] {
|
|
|
11
131
|
|
|
12
132
|
if (char === '"') {
|
|
13
133
|
if (inQuotes && nextChar === '"') {
|
|
134
|
+
// Escaped quote - convert "" to "
|
|
14
135
|
currentField += '"'
|
|
15
136
|
i += 2
|
|
16
137
|
continue
|
|
@@ -32,9 +153,7 @@ export function parseCSV(csvText: string): string[][] {
|
|
|
32
153
|
if (char === '\n' || char === '\r') {
|
|
33
154
|
if (currentField || currentRow.length > 0) {
|
|
34
155
|
currentRow.push(currentField)
|
|
35
|
-
|
|
36
|
-
result.push(currentRow)
|
|
37
|
-
}
|
|
156
|
+
addCsvRow(result, currentRow, options)
|
|
38
157
|
currentRow = []
|
|
39
158
|
currentField = ''
|
|
40
159
|
}
|
|
@@ -53,18 +172,29 @@ export function parseCSV(csvText: string): string[][] {
|
|
|
53
172
|
i++
|
|
54
173
|
}
|
|
55
174
|
|
|
175
|
+
// CSV might not end with a newline
|
|
56
176
|
if (currentField || currentRow.length > 0) {
|
|
57
177
|
currentRow.push(currentField)
|
|
58
|
-
|
|
59
|
-
result.push(currentRow)
|
|
60
|
-
}
|
|
178
|
+
addCsvRow(result, currentRow, options)
|
|
61
179
|
}
|
|
62
180
|
|
|
63
181
|
return result
|
|
64
182
|
}
|
|
65
183
|
|
|
66
|
-
|
|
67
|
-
|
|
184
|
+
/**
|
|
185
|
+
* Parses CSV data into an array of objects using the first row as headers.
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```typescript
|
|
189
|
+
* const csv = 'name,age\nJohn,25'
|
|
190
|
+
* parseCSVToObjects(csv) // [{ name: 'John', age: '25' }]
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
export function parseCSVToObjects(
|
|
194
|
+
csvText: string,
|
|
195
|
+
options: CSVParseOptions = {}
|
|
196
|
+
): Record<string, string>[] {
|
|
197
|
+
const rows = parseCSV(csvText, options)
|
|
68
198
|
|
|
69
199
|
if (rows.length < 2) {
|
|
70
200
|
return []
|
|
@@ -74,7 +204,7 @@ export function parseCSVToObjects(csvText: string): Record<string, unknown>[] {
|
|
|
74
204
|
const dataRows = rows.slice(1)
|
|
75
205
|
|
|
76
206
|
return dataRows.map(row => {
|
|
77
|
-
const obj: Record<string,
|
|
207
|
+
const obj: Record<string, string> = {}
|
|
78
208
|
headers.forEach((header, index) => {
|
|
79
209
|
obj[header] = row[index]?.trim() || ''
|
|
80
210
|
})
|
package/src/help.ts
CHANGED
|
@@ -22,6 +22,7 @@ interface CliGroupDoc {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
const GLOBAL_OPTIONS = [
|
|
25
|
+
['--json', 'Emit machine-readable JSON instead of human text. Available on every command, as a prefix (orizu --json <command>) or trailing flag.'],
|
|
25
26
|
['--local', 'Use http://localhost:3000.'],
|
|
26
27
|
['--server <url>', 'Use a specific server origin, for example https://preview.example.com.'],
|
|
27
28
|
['--version, -v', 'Print the orizu CLI version.'],
|
|
@@ -76,26 +77,111 @@ export const COMMAND_DOCS: CliCommandDoc[] = [
|
|
|
76
77
|
summary: 'Submit an optimization event payload.',
|
|
77
78
|
group: 'Optimizations',
|
|
78
79
|
},
|
|
80
|
+
{
|
|
81
|
+
path: ['setup'],
|
|
82
|
+
usage: 'orizu setup [--agent <claude|codex>]... [--scope global|project] [--mode auto|link|copy] [--workspace|--no-workspace] [--no-install] [--no-handoff] [--launch <claude|codex>] [--skip-login] [--yes] [--dry-run] [--no-input] [--json]',
|
|
83
|
+
summary: 'Guided onboarding: sign in, set up your coding agents, create a local workspace, and hand off to your agent.',
|
|
84
|
+
group: 'Agent setup',
|
|
85
|
+
options: [
|
|
86
|
+
{ name: '--agent <agent>', help: 'Coding agent to set up. Repeat for multiple agents.', repeatable: true, choices: ['claude', 'codex'] },
|
|
87
|
+
{ name: '--scope <scope>', help: 'global (default) installs for you across all projects; project installs into the current repo.', choices: ['global', 'project'] },
|
|
88
|
+
{ name: '--mode <mode>', help: 'Skill install sync mode (auto, link, copy).', choices: ['auto', 'link', 'copy'] },
|
|
89
|
+
{ name: '--workspace', help: 'Create the gitignored .orizu/ workspace without prompting.' },
|
|
90
|
+
{ name: '--no-workspace', help: 'Skip workspace creation.' },
|
|
91
|
+
{ name: '--no-install', help: 'Skip the agent integration phase.' },
|
|
92
|
+
{ name: '--no-handoff', help: 'Skip printing the coding-agent setup prompt.' },
|
|
93
|
+
{ name: '--launch <agent>', help: 'Launch a detected coding agent with the setup prompt (interactive terminals only).', choices: ['claude', 'codex'] },
|
|
94
|
+
{ name: '--skip-login', help: 'Skip the authentication phase.' },
|
|
95
|
+
{ name: '--yes', help: 'Apply changes without per-step confirmation prompts.' },
|
|
96
|
+
{ name: '--dry-run', help: 'Preview every planned change without writing.' },
|
|
97
|
+
{ name: '--no-input', help: 'Never prompt; behave as in a non-interactive terminal.' },
|
|
98
|
+
{ name: '--json', help: 'Emit the setup summary as JSON.' },
|
|
99
|
+
],
|
|
100
|
+
examples: [
|
|
101
|
+
'orizu setup',
|
|
102
|
+
'orizu setup --agent claude --agent codex --yes',
|
|
103
|
+
'orizu setup --skip-login --no-workspace --dry-run',
|
|
104
|
+
],
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
path: ['setup', 'prompt'],
|
|
108
|
+
usage: 'orizu setup prompt',
|
|
109
|
+
summary: 'Print the coding-agent setup prompt for repo-specific Orizu adoption.',
|
|
110
|
+
group: 'Agent setup',
|
|
111
|
+
examples: ['orizu setup prompt', 'claude "$(orizu setup prompt)"'],
|
|
112
|
+
},
|
|
79
113
|
{
|
|
80
114
|
path: ['install-skill'],
|
|
81
|
-
usage: 'orizu install-skill [--target <target>]... [--yes] [--dry-run]',
|
|
82
|
-
summary: '
|
|
115
|
+
usage: 'orizu install-skill [--agent <claude|codex>]... [--scope global|project] [--mode auto|link|copy] [--target <target>]... [--yes] [--dry-run]',
|
|
116
|
+
summary: 'Set up the Orizu skill for your coding agents (Claude Code, Codex/Open Agent Skills, or project instructions).',
|
|
83
117
|
group: 'Agent setup',
|
|
84
118
|
aliases: [['skills', 'install']],
|
|
85
119
|
options: [
|
|
120
|
+
{
|
|
121
|
+
name: '--agent <agent>',
|
|
122
|
+
help: 'Coding agent to set up. Repeat for multiple agents.',
|
|
123
|
+
repeatable: true,
|
|
124
|
+
choices: ['claude', 'codex'],
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: '--scope <scope>',
|
|
128
|
+
help: 'Where the install lives: global installs for you across all projects (default); project installs into the current repo.',
|
|
129
|
+
choices: ['global', 'project'],
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
name: '--mode <mode>',
|
|
133
|
+
help: 'How installs stay in sync with the CLI: auto (default) symlinks when the CLI install path is stable and copies otherwise; link forces a symlink; copy forces a full copy with sync metadata. Project-scope installs always copy.',
|
|
134
|
+
choices: ['auto', 'link', 'copy'],
|
|
135
|
+
},
|
|
86
136
|
{
|
|
87
137
|
name: '--target <target>',
|
|
88
|
-
help: '
|
|
138
|
+
help: 'Advanced: explicit install destination ID. Repeat for multiple targets.',
|
|
89
139
|
repeatable: true,
|
|
90
|
-
choices: ['agent-user', 'codex-project', 'claude-user', 'claude-project', 'agents-md'],
|
|
140
|
+
choices: ['agent-user', 'agents-project', 'codex-project', 'claude-user', 'claude-project', 'agents-md'],
|
|
91
141
|
},
|
|
92
142
|
{ name: '--yes', help: 'Replace an existing managed skill or AGENTS.md section without prompting.' },
|
|
93
143
|
{ name: '--dry-run', help: 'Show planned writes without changing files.' },
|
|
94
144
|
],
|
|
95
145
|
examples: [
|
|
96
|
-
'orizu install-skill --
|
|
97
|
-
'orizu install-skill --
|
|
98
|
-
'orizu
|
|
146
|
+
'orizu install-skill --agent claude --agent codex --yes',
|
|
147
|
+
'orizu install-skill --agent claude --scope project --yes',
|
|
148
|
+
'orizu install-skill --target agents-md --dry-run',
|
|
149
|
+
],
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
path: ['skills', 'status'],
|
|
153
|
+
usage: 'orizu skills status [--json]',
|
|
154
|
+
summary: 'Report installed Orizu skill targets and whether each is in sync with the CLI.',
|
|
155
|
+
group: 'Agent setup',
|
|
156
|
+
options: [
|
|
157
|
+
{ name: '--json', help: 'Emit machine-readable status for every known install target.' },
|
|
158
|
+
],
|
|
159
|
+
examples: ['orizu skills status', 'orizu skills status --json'],
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
path: ['skills', 'update'],
|
|
163
|
+
usage: 'orizu skills update [--dry-run] [--json]',
|
|
164
|
+
summary: 'Refresh stale copied skill installs and repair broken symlinks.',
|
|
165
|
+
group: 'Agent setup',
|
|
166
|
+
options: [
|
|
167
|
+
{ name: '--dry-run', help: 'Show which installs would be refreshed without changing files.' },
|
|
168
|
+
{ name: '--json', help: 'Emit machine-readable update results.' },
|
|
169
|
+
],
|
|
170
|
+
examples: ['orizu skills update', 'orizu skills update --dry-run'],
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
path: ['skills', 'path'],
|
|
174
|
+
usage: 'orizu skills path [--skill-md] [--json]',
|
|
175
|
+
summary: 'Print where the bundled Orizu skill lives so agents can read it without installing.',
|
|
176
|
+
group: 'Agent setup',
|
|
177
|
+
options: [
|
|
178
|
+
{ name: '--skill-md', help: 'Print the full path to SKILL.md instead of the skill root directory.' },
|
|
179
|
+
{ name: '--json', help: 'Emit machine-readable metadata: name, root, skillMd, source, cliVersion, skillHash.' },
|
|
180
|
+
],
|
|
181
|
+
examples: [
|
|
182
|
+
'orizu skills path',
|
|
183
|
+
'orizu skills path --skill-md',
|
|
184
|
+
'orizu skills path --json',
|
|
99
185
|
],
|
|
100
186
|
},
|
|
101
187
|
{
|
|
@@ -158,10 +244,22 @@ export const COMMAND_DOCS: CliCommandDoc[] = [
|
|
|
158
244
|
},
|
|
159
245
|
{
|
|
160
246
|
path: ['prompts', 'list'],
|
|
161
|
-
usage: 'orizu prompts list --project <team/project>',
|
|
247
|
+
usage: 'orizu prompts list --project <team/project> [--status active|archived|all]',
|
|
162
248
|
summary: 'List prompt artifacts in a project.',
|
|
163
249
|
group: 'Prompts and judges',
|
|
164
250
|
},
|
|
251
|
+
{
|
|
252
|
+
path: ['prompts', 'archive'],
|
|
253
|
+
usage: 'orizu prompts archive <prompt-id-or-name> --project <team/project> [--json]',
|
|
254
|
+
summary: 'Mark a prompt artifact as archived.',
|
|
255
|
+
group: 'Prompts and judges',
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
path: ['prompts', 'restore'],
|
|
259
|
+
usage: 'orizu prompts restore <prompt-id-or-name> --project <team/project> [--json]',
|
|
260
|
+
summary: 'Restore an archived prompt artifact to active status.',
|
|
261
|
+
group: 'Prompts and judges',
|
|
262
|
+
},
|
|
165
263
|
{
|
|
166
264
|
path: ['prompts', 'comments'],
|
|
167
265
|
usage: 'orizu prompts comments <prompt-id-or-name> --project <team/project> [--label <label> | --version <id>] [--json]',
|
|
@@ -200,7 +298,7 @@ export const COMMAND_DOCS: CliCommandDoc[] = [
|
|
|
200
298
|
},
|
|
201
299
|
{
|
|
202
300
|
path: ['judges', 'list'],
|
|
203
|
-
usage: 'orizu judges list --project <team/project>',
|
|
301
|
+
usage: 'orizu judges list --project <team/project> [--status active|archived|all]',
|
|
204
302
|
summary: 'List judge prompt artifacts in a project.',
|
|
205
303
|
group: 'Prompts and judges',
|
|
206
304
|
},
|
|
@@ -284,7 +382,7 @@ export const COMMAND_DOCS: CliCommandDoc[] = [
|
|
|
284
382
|
},
|
|
285
383
|
{
|
|
286
384
|
path: ['optimizations', 'run-gepa'],
|
|
287
|
-
usage: 'orizu optimizations run-gepa --project <team/project> --optimizer-version-id <id> --candidate-version-id <id> --runner-version-id <id> --candidate-runner-dir <dir> --scorer-version-id <id> --scorer-runner-version-id <id> --scorer-runner-dir <dir> --dataset-version-id <id> --split-set-id <id> [--train-split train] [--val-split validation] [--num-threads auto|N] [--log-dir logs]',
|
|
385
|
+
usage: 'orizu optimizations run-gepa --project <team/project> --optimizer-version-id <id> --candidate-version-id <id> --runner-version-id <id> --candidate-runner-dir <dir> --scorer-version-id <id> --scorer-runner-version-id <id> --scorer-runner-dir <dir> --dataset-version-id <id> --split-set-id <id> [--train-split train] [--val-split validation] [--budget auto|light|medium|heavy | --max-metric-calls <n> | --max-full-evals <n> | --max-iterations <n>] [--num-threads auto|N] [--reflection-retry-attempts N] [--reflection-http-timeout-seconds N] [--log-dir logs]',
|
|
288
386
|
summary: 'Run the bundled GEPA-style optimizer locally and stream events.',
|
|
289
387
|
group: 'Optimizations',
|
|
290
388
|
},
|
|
@@ -377,20 +475,20 @@ export const COMMAND_DOCS: CliCommandDoc[] = [
|
|
|
377
475
|
},
|
|
378
476
|
{
|
|
379
477
|
path: ['tasks', 'create'],
|
|
380
|
-
usage: 'orizu tasks create --project <team/project> --dataset <datasetId> --app <appId> --title <title> [--assignees <userIdOrEmail1,userIdOrEmail2>] [--publish] [--version <n>] [--instructions <text>] [--labels-per-item <n>] [--json]',
|
|
381
|
-
summary: 'Create a draft review task by default, or
|
|
478
|
+
usage: 'orizu tasks create --project <team/project> --dataset <datasetId> --app <appId> --title <title> [--assignees <userIdOrEmail1,userIdOrEmail2> | --assignment-file <path>] [--publish] [--version <n>] [--instructions <text>] [--labels-per-item <n>] [--json]',
|
|
479
|
+
summary: 'Create a draft review task by default, with auto distribution or an explicit row-assignment JSONL file.',
|
|
382
480
|
group: 'Tasks',
|
|
383
481
|
},
|
|
384
482
|
{
|
|
385
483
|
path: ['tasks', 'publish'],
|
|
386
|
-
usage: 'orizu tasks publish --task <taskId> --assignees <userId1,userId2> [--json]',
|
|
484
|
+
usage: 'orizu tasks publish --task <taskId> (--assignees <userId1,userId2> | --assignment-file <path>) [--json]',
|
|
387
485
|
summary: 'Publish an approved draft task and assign reviewers.',
|
|
388
486
|
group: 'Tasks',
|
|
389
487
|
},
|
|
390
488
|
{
|
|
391
489
|
path: ['tasks', 'assign'],
|
|
392
|
-
usage: 'orizu tasks assign --task <taskId> --assignees <userId1,userId2>',
|
|
393
|
-
summary: 'Assign a task
|
|
490
|
+
usage: 'orizu tasks assign --task <taskId> (--assignees <userId1,userId2> | --assignment-file <path>) [--replace-existing] [--json]',
|
|
491
|
+
summary: 'Assign a task with auto distribution or an explicit row-assignment JSONL file.',
|
|
394
492
|
group: 'Tasks',
|
|
395
493
|
},
|
|
396
494
|
{
|
|
@@ -658,6 +756,7 @@ export function getCapabilities(version: string) {
|
|
|
658
756
|
return {
|
|
659
757
|
name: 'orizu',
|
|
660
758
|
version,
|
|
759
|
+
globalOptions: GLOBAL_OPTIONS.map(([name, help]) => ({ name, help })),
|
|
661
760
|
commands: COMMAND_DOCS.map(doc => ({
|
|
662
761
|
name: commandKey(doc.path),
|
|
663
762
|
usage: doc.usage,
|