orizu 0.3.7 → 0.4.0
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 +109 -10
- package/dist/index.js +736 -44
- package/dist/setup-prompt.js +22 -0
- package/dist/skill-installer.js +243 -17
- 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 +109 -10
- package/src/index.ts +815 -46
- package/src/setup-prompt.ts +27 -0
- package/src/skill-installer.ts +343 -17
- 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 +8 -3
- package/vendor/skills/orizu-cli/references/cli-reference.md +25 -4
- 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/index.ts
CHANGED
|
@@ -35,15 +35,32 @@ import {
|
|
|
35
35
|
setGlobalFlags,
|
|
36
36
|
} from './http.js'
|
|
37
37
|
import {
|
|
38
|
+
computeSkillContentHash,
|
|
38
39
|
getSkillInstallPath,
|
|
40
|
+
getSkillTargetStatus,
|
|
41
|
+
getTargetForAgent,
|
|
39
42
|
installSkillTarget,
|
|
43
|
+
isSkillInstallAgent,
|
|
40
44
|
isSkillInstallTarget,
|
|
45
|
+
resolveSkillSource,
|
|
46
|
+
SKILL_INSTALL_AGENTS,
|
|
41
47
|
SKILL_INSTALL_TARGETS,
|
|
48
|
+
SkillInstallMode,
|
|
49
|
+
SkillInstallScope,
|
|
42
50
|
SkillInstallTarget,
|
|
51
|
+
SkillTargetStatus,
|
|
43
52
|
targetNeedsOverwrite,
|
|
44
53
|
} from './skill-installer.js'
|
|
54
|
+
import { renderBanner } from './banner.js'
|
|
45
55
|
import { formatTaskCreateError } from './task-create-error.js'
|
|
56
|
+
import { renderAgentSetupPrompt } from './setup-prompt.js'
|
|
46
57
|
import { LoginResponse } from './types.js'
|
|
58
|
+
import {
|
|
59
|
+
getWorkspaceRoot,
|
|
60
|
+
initOrizuWorkspace,
|
|
61
|
+
WORKSPACE_DIR_NAME,
|
|
62
|
+
workspaceExists,
|
|
63
|
+
} from './workspace.js'
|
|
47
64
|
|
|
48
65
|
interface Team {
|
|
49
66
|
id: string
|
|
@@ -107,6 +124,8 @@ interface PromptSummary {
|
|
|
107
124
|
id: string
|
|
108
125
|
name: string
|
|
109
126
|
role: string
|
|
127
|
+
status?: string
|
|
128
|
+
archivedAt?: string | null
|
|
110
129
|
description?: string | null
|
|
111
130
|
}
|
|
112
131
|
|
|
@@ -279,7 +298,16 @@ function printVersion() {
|
|
|
279
298
|
printLine(`orizu ${getCliVersion()}`)
|
|
280
299
|
}
|
|
281
300
|
|
|
301
|
+
function printBannerIfInteractive() {
|
|
302
|
+
if (!process.stdout.isTTY) {
|
|
303
|
+
return
|
|
304
|
+
}
|
|
305
|
+
printLine(renderBanner())
|
|
306
|
+
printLine('')
|
|
307
|
+
}
|
|
308
|
+
|
|
282
309
|
function printUsage() {
|
|
310
|
+
printBannerIfInteractive()
|
|
283
311
|
printLine(renderRootHelp())
|
|
284
312
|
}
|
|
285
313
|
|
|
@@ -288,7 +316,7 @@ function printPreviewUsage() {
|
|
|
288
316
|
}
|
|
289
317
|
|
|
290
318
|
function printOptimizationUsage() {
|
|
291
|
-
printLine(`\nOptimization lifecycle commands:\n\n orizu optimizations start --project <team/project> --optimizer-version <id> --prompt-version <id[,id]> --selection-scorer <id> [--reflection-scorer <id>] [--pareto-scorer <id>] [--best-scorer <id>] --dataset-version <id> --split-set <id> [--train-split <name>] [--validation-split <name>] [--metadata <json|@file>] [--json]\n 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] [--no-skip-perfect-parent-reflection]\n orizu optimizations export <run-id> [--out <path>] [--json]\n orizu optimizations pause <run-id> [--reason <text>] [--json]\n orizu optimizations resume <run-id> [--json]\n orizu optimizations finish <run-id> [--best-score <n>] [--best-candidate <id>] [--result-prompt-version <id>] [--report <markdown|@file> | --report-file <path>] [--metadata <json|@file>] [--json]\n orizu optimizations fail <run-id> [--reason <text>] [--report <markdown|@file> | --report-file <path>] [--metadata <json|@file>] [--json]\n orizu optimizations cancel <run-id> [--reason <text>] [--report <markdown|@file> | --report-file <path>] [--json]`)
|
|
319
|
+
printLine(`\nOptimization lifecycle commands:\n\n orizu optimizations start --project <team/project> --optimizer-version <id> --prompt-version <id[,id]> --selection-scorer <id> [--reflection-scorer <id>] [--pareto-scorer <id>] [--best-scorer <id>] --dataset-version <id> --split-set <id> [--train-split <name>] [--validation-split <name>] [--metadata <json|@file>] [--json]\n 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] [--no-skip-perfect-parent-reflection]\n orizu optimizations export <run-id> [--out <path>] [--json]\n orizu optimizations pause <run-id> [--reason <text>] [--json]\n orizu optimizations resume <run-id> [--json]\n orizu optimizations finish <run-id> [--best-score <n>] [--best-candidate <id>] [--result-prompt-version <id>] [--report <markdown|@file> | --report-file <path>] [--metadata <json|@file>] [--json]\n orizu optimizations fail <run-id> [--reason <text>] [--report <markdown|@file> | --report-file <path>] [--metadata <json|@file>] [--json]\n orizu optimizations cancel <run-id> [--reason <text>] [--report <markdown|@file> | --report-file <path>] [--json]`)
|
|
292
320
|
}
|
|
293
321
|
|
|
294
322
|
let cliArgs = process.argv.slice(2)
|
|
@@ -492,15 +520,17 @@ function printPromptSummaries(items: PromptSummary[], emptyMessage: string) {
|
|
|
492
520
|
id: sanitizeTerminalText(item.id),
|
|
493
521
|
name: sanitizeTerminalText(item.name),
|
|
494
522
|
role: sanitizeTerminalText(item.role),
|
|
523
|
+
status: sanitizeTerminalText(item.status || 'active'),
|
|
495
524
|
}))
|
|
496
525
|
const idWidth = Math.max('ID'.length, ...rows.map(row => row.id.length))
|
|
497
526
|
const nameWidth = Math.max('NAME'.length, ...rows.map(row => row.name.length))
|
|
498
527
|
const roleWidth = Math.max('ROLE'.length, ...rows.map(row => row.role.length))
|
|
528
|
+
const statusWidth = Math.max('STATUS'.length, ...rows.map(row => row.status.length))
|
|
499
529
|
|
|
500
|
-
printLine(`${'ID'.padEnd(idWidth)} ${'NAME'.padEnd(nameWidth)} ${'ROLE'.padEnd(roleWidth)}`)
|
|
501
|
-
printLine(`${'-'.repeat(idWidth)} ${'-'.repeat(nameWidth)} ${'-'.repeat(roleWidth)}`)
|
|
530
|
+
printLine(`${'ID'.padEnd(idWidth)} ${'NAME'.padEnd(nameWidth)} ${'ROLE'.padEnd(roleWidth)} ${'STATUS'.padEnd(statusWidth)}`)
|
|
531
|
+
printLine(`${'-'.repeat(idWidth)} ${'-'.repeat(nameWidth)} ${'-'.repeat(roleWidth)} ${'-'.repeat(statusWidth)}`)
|
|
502
532
|
rows.forEach(row => {
|
|
503
|
-
printLine(`${row.id.padEnd(idWidth)} ${row.name.padEnd(nameWidth)} ${row.role.padEnd(roleWidth)}`)
|
|
533
|
+
printLine(`${row.id.padEnd(idWidth)} ${row.name.padEnd(nameWidth)} ${row.role.padEnd(roleWidth)} ${row.status.padEnd(statusWidth)}`)
|
|
504
534
|
})
|
|
505
535
|
}
|
|
506
536
|
|
|
@@ -1168,6 +1198,10 @@ async function login() {
|
|
|
1168
1198
|
assertSecureTokenTransport(baseUrl)
|
|
1169
1199
|
|
|
1170
1200
|
if (hasArg('--no-prompt-if-logged-in') && getServerCredentials(baseUrl)) {
|
|
1201
|
+
if (hasJsonFlag()) {
|
|
1202
|
+
printJson({ status: 'already-logged-in', server: baseUrl })
|
|
1203
|
+
return
|
|
1204
|
+
}
|
|
1171
1205
|
printLine(`Already logged in to ${sanitizeTerminalText(baseUrl)}.`)
|
|
1172
1206
|
return
|
|
1173
1207
|
}
|
|
@@ -1262,6 +1296,14 @@ async function login() {
|
|
|
1262
1296
|
apiKey: loginData.apiKey,
|
|
1263
1297
|
})
|
|
1264
1298
|
|
|
1299
|
+
if (hasJsonFlag()) {
|
|
1300
|
+
printJson({
|
|
1301
|
+
status: 'logged-in',
|
|
1302
|
+
server: baseUrl,
|
|
1303
|
+
user: { id: loginData.user.id, email: loginData.user.email ?? null },
|
|
1304
|
+
})
|
|
1305
|
+
return
|
|
1306
|
+
}
|
|
1265
1307
|
printLine(`Logged in as ${sanitizeTerminalText(loginData.user.email ?? loginData.user.id)}`)
|
|
1266
1308
|
}
|
|
1267
1309
|
|
|
@@ -1272,6 +1314,10 @@ async function whoami() {
|
|
|
1272
1314
|
}
|
|
1273
1315
|
|
|
1274
1316
|
const data = await response.json() as { user: { id: string; email: string | null } }
|
|
1317
|
+
if (hasJsonFlag()) {
|
|
1318
|
+
printJson({ user: data.user, server: getBaseUrl() })
|
|
1319
|
+
return
|
|
1320
|
+
}
|
|
1275
1321
|
printLine(sanitizeTerminalText(data.user.email ?? data.user.id))
|
|
1276
1322
|
}
|
|
1277
1323
|
|
|
@@ -1279,6 +1325,10 @@ async function logout() {
|
|
|
1279
1325
|
const baseUrl = getBaseUrl()
|
|
1280
1326
|
const credentials = getServerCredentials(baseUrl)
|
|
1281
1327
|
if (!credentials) {
|
|
1328
|
+
if (hasJsonFlag()) {
|
|
1329
|
+
printJson({ status: 'already-logged-out', server: baseUrl })
|
|
1330
|
+
return
|
|
1331
|
+
}
|
|
1282
1332
|
printLine(`Already logged out for ${sanitizeTerminalText(baseUrl)}.`)
|
|
1283
1333
|
return
|
|
1284
1334
|
}
|
|
@@ -1306,6 +1356,10 @@ async function logout() {
|
|
|
1306
1356
|
}
|
|
1307
1357
|
|
|
1308
1358
|
clearServerCredentials(baseUrl)
|
|
1359
|
+
if (hasJsonFlag()) {
|
|
1360
|
+
printJson({ status: 'logged-out', server: baseUrl, remoteLogoutError })
|
|
1361
|
+
return
|
|
1362
|
+
}
|
|
1309
1363
|
if (remoteLogoutError) {
|
|
1310
1364
|
console.warn(`Warning: remote logout failed: ${remoteLogoutError}`)
|
|
1311
1365
|
}
|
|
@@ -1320,6 +1374,15 @@ async function printEnv() {
|
|
|
1320
1374
|
const projectId = project?.id || getArg('--project-id') || process.env.ORIZU_PROJECT_ID || ''
|
|
1321
1375
|
const projectSlug = project ? `${project.teamSlug}/${project.slug}` : process.env.ORIZU_PROJECT || ''
|
|
1322
1376
|
|
|
1377
|
+
if (hasJsonFlag()) {
|
|
1378
|
+
printJson({
|
|
1379
|
+
ORIZU_API_URL: baseUrl,
|
|
1380
|
+
ORIZU_TOKEN: token,
|
|
1381
|
+
ORIZU_PROJECT_ID: projectId,
|
|
1382
|
+
...(projectSlug ? { ORIZU_PROJECT: projectSlug } : {}),
|
|
1383
|
+
})
|
|
1384
|
+
return
|
|
1385
|
+
}
|
|
1323
1386
|
printLine(`export ORIZU_API_URL=${shellQuote(baseUrl)}`)
|
|
1324
1387
|
printLine(`export ORIZU_TOKEN=${shellQuote(token)}`)
|
|
1325
1388
|
printLine(`export ORIZU_PROJECT_ID=${shellQuote(projectId)}`)
|
|
@@ -1361,28 +1424,52 @@ async function logOptimizationEvent() {
|
|
|
1361
1424
|
}
|
|
1362
1425
|
|
|
1363
1426
|
const data = await parseJsonResponse<{ eventId: string }>(response, 'Optimization event log')
|
|
1427
|
+
if (hasJsonFlag()) {
|
|
1428
|
+
printJson({ eventId: data.eventId })
|
|
1429
|
+
return
|
|
1430
|
+
}
|
|
1364
1431
|
printLine(`Logged event ${sanitizeTerminalText(data.eventId)}`)
|
|
1365
1432
|
}
|
|
1366
1433
|
|
|
1367
1434
|
async function listPrompts() {
|
|
1368
1435
|
const project = getArg('--project') || await resolveProjectSlug(null)
|
|
1369
|
-
const
|
|
1436
|
+
const status = getArg('--status') || 'active'
|
|
1437
|
+
if (!['active', 'archived', 'all'].includes(status)) {
|
|
1438
|
+
throw new Error('Usage: orizu prompts list --project <team/project> [--status active|archived|all]')
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
const params = new URLSearchParams({ project, status })
|
|
1442
|
+
const response = await authedFetch(`/api/cli/prompts?${params.toString()}`)
|
|
1370
1443
|
if (!response.ok) {
|
|
1371
1444
|
throw new Error(`Failed to fetch prompts: ${await response.text()}`)
|
|
1372
1445
|
}
|
|
1373
1446
|
|
|
1374
1447
|
const data = await parseJsonResponse<{ prompts: PromptSummary[] }>(response, 'Prompts list')
|
|
1448
|
+
if (hasJsonFlag()) {
|
|
1449
|
+
printJson(data as unknown as Record<string, unknown>)
|
|
1450
|
+
return
|
|
1451
|
+
}
|
|
1375
1452
|
printPromptSummaries(data.prompts, 'No prompts found.')
|
|
1376
1453
|
}
|
|
1377
1454
|
|
|
1378
1455
|
async function listJudges() {
|
|
1379
1456
|
const project = getArg('--project') || await resolveProjectSlug(null)
|
|
1380
|
-
const
|
|
1457
|
+
const status = getArg('--status') || 'active'
|
|
1458
|
+
if (!['active', 'archived', 'all'].includes(status)) {
|
|
1459
|
+
throw new Error('Usage: orizu judges list --project <team/project> [--status active|archived|all]')
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
const params = new URLSearchParams({ project, status })
|
|
1463
|
+
const response = await authedFetch(`/api/cli/judges?${params.toString()}`)
|
|
1381
1464
|
if (!response.ok) {
|
|
1382
1465
|
throw new Error(`Failed to fetch judges: ${await response.text()}`)
|
|
1383
1466
|
}
|
|
1384
1467
|
|
|
1385
1468
|
const data = await parseJsonResponse<{ judges: PromptSummary[] }>(response, 'Judges list')
|
|
1469
|
+
if (hasJsonFlag()) {
|
|
1470
|
+
printJson(data as unknown as Record<string, unknown>)
|
|
1471
|
+
return
|
|
1472
|
+
}
|
|
1386
1473
|
printPromptSummaries(data.judges, 'No judges found.')
|
|
1387
1474
|
}
|
|
1388
1475
|
|
|
@@ -1425,6 +1512,10 @@ async function listScorers() {
|
|
|
1425
1512
|
}
|
|
1426
1513
|
|
|
1427
1514
|
const data = await parseJsonResponse<{ scorers: ScorerSummary[] }>(response, 'Scorers list')
|
|
1515
|
+
if (hasJsonFlag()) {
|
|
1516
|
+
printJson(data as unknown as Record<string, unknown>)
|
|
1517
|
+
return
|
|
1518
|
+
}
|
|
1428
1519
|
printScorerSummaries(data.scorers)
|
|
1429
1520
|
}
|
|
1430
1521
|
|
|
@@ -1775,6 +1866,40 @@ async function setPromptLabel() {
|
|
|
1775
1866
|
printLine(`Moved ${sanitizeTerminalText(label)} to ${sanitizeTerminalText(promptVersionId)}`)
|
|
1776
1867
|
}
|
|
1777
1868
|
|
|
1869
|
+
async function setPromptArchivedState(archived: boolean) {
|
|
1870
|
+
const promptRef = getPositionalArg(2)
|
|
1871
|
+
const project = getArg('--project') || await resolveProjectSlug(null)
|
|
1872
|
+
const command = archived ? 'archive' : 'restore'
|
|
1873
|
+
|
|
1874
|
+
if (!promptRef) {
|
|
1875
|
+
throw new Error(`Usage: orizu prompts ${command} <prompt-id-or-name> --project <team/project> [--json]`)
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1878
|
+
const response = await authedFetch(`/api/cli/prompts/${encodeURIComponent(promptRef)}?project=${encodeURIComponent(project)}`, {
|
|
1879
|
+
method: 'PATCH',
|
|
1880
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1881
|
+
body: JSON.stringify({ archived }),
|
|
1882
|
+
})
|
|
1883
|
+
|
|
1884
|
+
if (!response.ok) {
|
|
1885
|
+
throw new Error(`Failed to ${command} prompt: ${await response.text()}`)
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1888
|
+
const data = await parseJsonResponse<{
|
|
1889
|
+
prompt: {
|
|
1890
|
+
id: string
|
|
1891
|
+
name: string
|
|
1892
|
+
status: string
|
|
1893
|
+
}
|
|
1894
|
+
}>(response, `Prompt ${command}`)
|
|
1895
|
+
if (hasJsonFlag()) {
|
|
1896
|
+
printJson(data)
|
|
1897
|
+
return
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
printLine(`${archived ? 'Archived' : 'Restored'} prompt ${sanitizeTerminalText(data.prompt.name)} (${sanitizeTerminalText(data.prompt.id)})`)
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1778
1903
|
async function bindPromptScorer(role: 'headline' | 'tracked') {
|
|
1779
1904
|
const promptId = getPositionalArg(3)
|
|
1780
1905
|
const project = getArg('--project') || await resolveProjectSlug(null)
|
|
@@ -2032,6 +2157,10 @@ async function submitRunResults() {
|
|
|
2032
2157
|
perRowResultsStoragePath: string
|
|
2033
2158
|
}
|
|
2034
2159
|
}>(response, 'Run submit')
|
|
2160
|
+
if (hasJsonFlag()) {
|
|
2161
|
+
printJson({ run: data.run })
|
|
2162
|
+
return
|
|
2163
|
+
}
|
|
2035
2164
|
printLine(
|
|
2036
2165
|
`Submitted run ${sanitizeTerminalText(data.run.id)} ` +
|
|
2037
2166
|
`(${formatPercent(data.run.aggregateScore)}) -> ` +
|
|
@@ -2595,10 +2724,19 @@ async function runGepaOptimization() {
|
|
|
2595
2724
|
if (result.status !== 0) {
|
|
2596
2725
|
throw new Error(`orizu-gepa failed with exit code ${result.status}`)
|
|
2597
2726
|
}
|
|
2727
|
+
|
|
2728
|
+
if (hasJsonFlag()) {
|
|
2729
|
+
printJson({ status: 'completed', exitCode: 0 })
|
|
2730
|
+
}
|
|
2598
2731
|
}
|
|
2599
2732
|
|
|
2600
2733
|
async function listTeams() {
|
|
2601
|
-
|
|
2734
|
+
const teams = await fetchTeams()
|
|
2735
|
+
if (hasJsonFlag()) {
|
|
2736
|
+
printJson({ teams })
|
|
2737
|
+
return
|
|
2738
|
+
}
|
|
2739
|
+
printTeams(teams)
|
|
2602
2740
|
}
|
|
2603
2741
|
|
|
2604
2742
|
async function resolveTeamSlug(teamSlugArg: string | null): Promise<string> {
|
|
@@ -2643,13 +2781,22 @@ async function createTeam() {
|
|
|
2643
2781
|
}
|
|
2644
2782
|
|
|
2645
2783
|
const data = await parseJsonResponse<{ team: Team }>(response, 'Team create')
|
|
2784
|
+
if (hasJsonFlag()) {
|
|
2785
|
+
printJson({ team: data.team })
|
|
2786
|
+
return
|
|
2787
|
+
}
|
|
2646
2788
|
printLine(`Created team: ${sanitizeTerminalText(data.team.name)} (${sanitizeTerminalText(data.team.slug)})`)
|
|
2647
2789
|
}
|
|
2648
2790
|
|
|
2649
2791
|
async function listProjects() {
|
|
2650
2792
|
const teamSlugArg = getArg('--team')
|
|
2651
2793
|
const teamSlug = teamSlugArg ? normalizeSlugInput(teamSlugArg) : null
|
|
2652
|
-
|
|
2794
|
+
const projects = await fetchProjects(teamSlug || undefined)
|
|
2795
|
+
if (hasJsonFlag()) {
|
|
2796
|
+
printJson({ projects })
|
|
2797
|
+
return
|
|
2798
|
+
}
|
|
2799
|
+
printProjects(projects)
|
|
2653
2800
|
}
|
|
2654
2801
|
|
|
2655
2802
|
async function createProject() {
|
|
@@ -2684,17 +2831,31 @@ async function createProject() {
|
|
|
2684
2831
|
const data = await parseJsonResponse<{
|
|
2685
2832
|
project: { id: string; name: string; slug: string; teamSlug: string }
|
|
2686
2833
|
}>(response, 'Project create')
|
|
2834
|
+
if (hasJsonFlag()) {
|
|
2835
|
+
printJson({ project: data.project })
|
|
2836
|
+
return
|
|
2837
|
+
}
|
|
2687
2838
|
printLine(`Created project ${sanitizeTerminalText(`${data.project.teamSlug}/${data.project.slug}`)}`)
|
|
2688
2839
|
}
|
|
2689
2840
|
|
|
2690
2841
|
async function listTasks() {
|
|
2691
2842
|
const project = getArg('--project')
|
|
2692
|
-
|
|
2843
|
+
const tasks = await fetchTasks(project || undefined)
|
|
2844
|
+
if (hasJsonFlag()) {
|
|
2845
|
+
printJson({ tasks })
|
|
2846
|
+
return
|
|
2847
|
+
}
|
|
2848
|
+
printTasks(tasks)
|
|
2693
2849
|
}
|
|
2694
2850
|
|
|
2695
2851
|
async function listApps() {
|
|
2696
2852
|
const project = getArg('--project') || await resolveProjectSlug(null)
|
|
2697
|
-
|
|
2853
|
+
const apps = await fetchApps(project)
|
|
2854
|
+
if (hasJsonFlag()) {
|
|
2855
|
+
printJson({ apps })
|
|
2856
|
+
return
|
|
2857
|
+
}
|
|
2858
|
+
printApps(apps)
|
|
2698
2859
|
}
|
|
2699
2860
|
|
|
2700
2861
|
function readSourceFile(pathArg: string): string {
|
|
@@ -2759,29 +2920,97 @@ async function askYesNo(question: string, defaultYes: boolean): Promise<boolean>
|
|
|
2759
2920
|
}
|
|
2760
2921
|
}
|
|
2761
2922
|
|
|
2762
|
-
|
|
2923
|
+
const SKILL_INSTALL_USAGE =
|
|
2924
|
+
`Usage: orizu install-skill [--agent <${SKILL_INSTALL_AGENTS.join('|')}>]... [--scope global|project] [--mode auto|link|copy] [--target <${SKILL_INSTALL_TARGETS.join('|')}>]... [--yes] [--dry-run]`
|
|
2925
|
+
|
|
2926
|
+
interface SkillInstallChoice {
|
|
2927
|
+
label: string
|
|
2928
|
+
target: SkillInstallTarget
|
|
2929
|
+
defaultYes: boolean
|
|
2930
|
+
}
|
|
2931
|
+
|
|
2932
|
+
function describeSkillTarget(target: SkillInstallTarget): string {
|
|
2933
|
+
if (target === 'claude-user') return 'Claude Code, for you across all projects'
|
|
2934
|
+
if (target === 'claude-project') return 'Claude Code, only for this project'
|
|
2935
|
+
if (target === 'agent-user') return 'Codex / Open Agent Skills, for you across all projects'
|
|
2936
|
+
if (target === 'agents-project') return 'Codex / Open Agent Skills, only for this project'
|
|
2937
|
+
if (target === 'codex-project') return 'Codex legacy project folder (.codex/skills)'
|
|
2938
|
+
return 'Project instructions, managed Orizu section in AGENTS.md'
|
|
2939
|
+
}
|
|
2940
|
+
|
|
2941
|
+
async function promptSkillInstallTargets(scope: SkillInstallScope): Promise<SkillInstallTarget[]> {
|
|
2763
2942
|
if (!isInteractiveTerminal()) {
|
|
2764
|
-
throw new Error(
|
|
2765
|
-
`Usage: orizu install-skill --target <${SKILL_INSTALL_TARGETS.join('|')}> [--yes] [--dry-run]`
|
|
2766
|
-
)
|
|
2943
|
+
throw new Error(SKILL_INSTALL_USAGE)
|
|
2767
2944
|
}
|
|
2768
2945
|
|
|
2769
|
-
|
|
2946
|
+
const choices: SkillInstallChoice[] = [
|
|
2947
|
+
{ label: describeSkillTarget(getTargetForAgent('claude', scope)), target: getTargetForAgent('claude', scope), defaultYes: true },
|
|
2948
|
+
{ label: describeSkillTarget(getTargetForAgent('codex', scope)), target: getTargetForAgent('codex', scope), defaultYes: true },
|
|
2949
|
+
{ label: describeSkillTarget('agents-md'), target: 'agents-md', defaultYes: false },
|
|
2950
|
+
]
|
|
2951
|
+
|
|
2952
|
+
printLine('Where should Orizu be available?')
|
|
2770
2953
|
const targets: SkillInstallTarget[] = []
|
|
2771
|
-
for (const
|
|
2772
|
-
const
|
|
2773
|
-
if (await askYesNo(`
|
|
2774
|
-
targets.push(target)
|
|
2954
|
+
for (const choice of choices) {
|
|
2955
|
+
const installPath = getSkillInstallPath(choice.target)
|
|
2956
|
+
if (await askYesNo(` ${choice.label}\n ${installPath}?`, choice.defaultYes)) {
|
|
2957
|
+
targets.push(choice.target)
|
|
2958
|
+
}
|
|
2959
|
+
}
|
|
2960
|
+
|
|
2961
|
+
if (await askYesNo(' Show advanced targets?', false)) {
|
|
2962
|
+
for (const target of SKILL_INSTALL_TARGETS) {
|
|
2963
|
+
if (targets.includes(target)) {
|
|
2964
|
+
continue
|
|
2965
|
+
}
|
|
2966
|
+
const installPath = getSkillInstallPath(target)
|
|
2967
|
+
if (await askYesNo(` ${describeSkillTarget(target)} [${target}]\n ${installPath}?`, false)) {
|
|
2968
|
+
targets.push(target)
|
|
2969
|
+
}
|
|
2775
2970
|
}
|
|
2776
2971
|
}
|
|
2777
2972
|
|
|
2778
2973
|
return targets
|
|
2779
2974
|
}
|
|
2780
2975
|
|
|
2781
|
-
function
|
|
2782
|
-
const
|
|
2976
|
+
function parseSkillInstallScope(): SkillInstallScope {
|
|
2977
|
+
const raw = getArg('--scope')
|
|
2978
|
+
if (raw === null || raw === 'global') {
|
|
2979
|
+
return 'global'
|
|
2980
|
+
}
|
|
2981
|
+
if (raw === 'project') {
|
|
2982
|
+
return 'local'
|
|
2983
|
+
}
|
|
2984
|
+
throw new Error(`Unknown --scope '${raw}'. Choices: global, project.`)
|
|
2985
|
+
}
|
|
2986
|
+
|
|
2987
|
+
function parseSkillInstallMode(): SkillInstallMode {
|
|
2988
|
+
const raw = getArg('--mode')
|
|
2989
|
+
if (raw === null) {
|
|
2990
|
+
return 'auto'
|
|
2991
|
+
}
|
|
2992
|
+
if (raw !== 'auto' && raw !== 'link' && raw !== 'copy') {
|
|
2993
|
+
throw new Error(`Unknown --mode '${raw}'. Choices: auto, link, copy.`)
|
|
2994
|
+
}
|
|
2995
|
+
return raw
|
|
2996
|
+
}
|
|
2997
|
+
|
|
2998
|
+
function parseSkillInstallTargets(scope: SkillInstallScope): SkillInstallTarget[] {
|
|
2783
2999
|
const targets: SkillInstallTarget[] = []
|
|
2784
|
-
|
|
3000
|
+
|
|
3001
|
+
for (const agent of getArgs('--agent')) {
|
|
3002
|
+
if (!isSkillInstallAgent(agent)) {
|
|
3003
|
+
throw new Error(
|
|
3004
|
+
`Unknown agent '${agent}'. Available agents: ${SKILL_INSTALL_AGENTS.join(', ')}`
|
|
3005
|
+
)
|
|
3006
|
+
}
|
|
3007
|
+
const target = getTargetForAgent(agent, scope)
|
|
3008
|
+
if (!targets.includes(target)) {
|
|
3009
|
+
targets.push(target)
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
3012
|
+
|
|
3013
|
+
for (const target of getArgs('--target')) {
|
|
2785
3014
|
if (!isSkillInstallTarget(target)) {
|
|
2786
3015
|
throw new Error(
|
|
2787
3016
|
`Unknown skill install target '${target}'. Available targets: ${SKILL_INSTALL_TARGETS.join(', ')}`
|
|
@@ -2791,6 +3020,7 @@ function parseSkillInstallTargets(): SkillInstallTarget[] {
|
|
|
2791
3020
|
targets.push(target)
|
|
2792
3021
|
}
|
|
2793
3022
|
}
|
|
3023
|
+
|
|
2794
3024
|
return targets
|
|
2795
3025
|
}
|
|
2796
3026
|
|
|
@@ -2801,39 +3031,444 @@ function formatSkillInstallAction(action: string): string {
|
|
|
2801
3031
|
return 'Would update'
|
|
2802
3032
|
}
|
|
2803
3033
|
|
|
2804
|
-
|
|
2805
|
-
const
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
if (targets.length === 0) {
|
|
2809
|
-
targets = await promptSkillInstallTargets()
|
|
3034
|
+
function describePlannedWrite(target: SkillInstallTarget, action: string, mode: string, path: string): string {
|
|
3035
|
+
const verb = action.includes('create') || action === 'created' ? 'create' : 'replace'
|
|
3036
|
+
if (target === 'agents-md') {
|
|
3037
|
+
return ` ${path} (${verb} managed Orizu section)`
|
|
2810
3038
|
}
|
|
3039
|
+
if (mode === 'link') {
|
|
3040
|
+
return ` ${path} (${verb}, symlink to the CLI-managed skill)`
|
|
3041
|
+
}
|
|
3042
|
+
return ` ${path} (${verb}, full copy with sync metadata)`
|
|
3043
|
+
}
|
|
2811
3044
|
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
3045
|
+
interface SkillInstallOutcome {
|
|
3046
|
+
target: SkillInstallTarget
|
|
3047
|
+
path: string
|
|
3048
|
+
action: 'created' | 'updated' | 'skipped' | 'failed'
|
|
3049
|
+
mode: 'link' | 'copy' | 'section' | null
|
|
3050
|
+
error?: string
|
|
3051
|
+
}
|
|
3052
|
+
|
|
3053
|
+
async function applySkillInstallTargets(
|
|
3054
|
+
targets: SkillInstallTarget[],
|
|
3055
|
+
options: { mode: SkillInstallMode, skipConfirm: boolean, dryRun: boolean }
|
|
3056
|
+
): Promise<SkillInstallOutcome[]> {
|
|
3057
|
+
const cliVersion = getCliVersion()
|
|
3058
|
+
const jsonMode = hasJsonFlag()
|
|
3059
|
+
const planned = targets.map(target =>
|
|
3060
|
+
installSkillTarget(target, { dryRun: true, mode: options.mode, cliVersion })
|
|
3061
|
+
)
|
|
3062
|
+
|
|
3063
|
+
if (!jsonMode) {
|
|
3064
|
+
printLine('Planned writes:')
|
|
3065
|
+
for (const plan of planned) {
|
|
3066
|
+
printLine(describePlannedWrite(plan.target, plan.action, plan.mode, plan.path))
|
|
3067
|
+
}
|
|
3068
|
+
printLine('')
|
|
3069
|
+
}
|
|
3070
|
+
|
|
3071
|
+
if (options.dryRun) {
|
|
3072
|
+
if (!jsonMode) {
|
|
3073
|
+
printLine('Dry run: no files were changed.')
|
|
3074
|
+
}
|
|
3075
|
+
return planned.map(plan => ({
|
|
3076
|
+
target: plan.target,
|
|
3077
|
+
path: plan.path,
|
|
3078
|
+
action: 'skipped',
|
|
3079
|
+
mode: plan.mode,
|
|
3080
|
+
}))
|
|
2815
3081
|
}
|
|
2816
3082
|
|
|
3083
|
+
const outcomes: SkillInstallOutcome[] = []
|
|
2817
3084
|
for (const target of targets) {
|
|
2818
|
-
let overwrite = skipConfirm
|
|
3085
|
+
let overwrite = options.skipConfirm
|
|
2819
3086
|
const installPath = getSkillInstallPath(target)
|
|
2820
|
-
if (!
|
|
3087
|
+
if (!overwrite && targetNeedsOverwrite(target)) {
|
|
2821
3088
|
if (!isInteractiveTerminal()) {
|
|
2822
3089
|
throw new Error(`${installPath} already exists. Pass --yes to replace it.`)
|
|
2823
3090
|
}
|
|
2824
3091
|
overwrite = await askYesNo(`Replace ${installPath}?`, true)
|
|
2825
3092
|
if (!overwrite) {
|
|
2826
|
-
|
|
3093
|
+
if (!jsonMode) {
|
|
3094
|
+
printLine(`Skipped ${installPath}`)
|
|
3095
|
+
}
|
|
3096
|
+
outcomes.push({ target, path: installPath, action: 'skipped', mode: null })
|
|
2827
3097
|
continue
|
|
2828
3098
|
}
|
|
2829
3099
|
}
|
|
2830
3100
|
|
|
3101
|
+
try {
|
|
3102
|
+
const result = installSkillTarget(target, {
|
|
3103
|
+
overwrite,
|
|
3104
|
+
mode: options.mode,
|
|
3105
|
+
cliVersion,
|
|
3106
|
+
})
|
|
3107
|
+
if (!jsonMode) {
|
|
3108
|
+
const suffix = result.mode === 'link' ? ' (symlink)' : ''
|
|
3109
|
+
printLine(`${formatSkillInstallAction(result.action)} ${result.path}${suffix}`)
|
|
3110
|
+
}
|
|
3111
|
+
outcomes.push({
|
|
3112
|
+
target,
|
|
3113
|
+
path: result.path,
|
|
3114
|
+
action: result.action as 'created' | 'updated',
|
|
3115
|
+
mode: result.mode,
|
|
3116
|
+
})
|
|
3117
|
+
} catch (error: any) {
|
|
3118
|
+
const message = error?.message || String(error)
|
|
3119
|
+
if (!jsonMode) {
|
|
3120
|
+
printLine(`Failed ${installPath}: ${message}`)
|
|
3121
|
+
}
|
|
3122
|
+
outcomes.push({ target, path: installPath, action: 'failed', mode: null, error: message })
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
|
|
3126
|
+
return outcomes
|
|
3127
|
+
}
|
|
3128
|
+
|
|
3129
|
+
async function installSkillCommand() {
|
|
3130
|
+
const skipConfirm = hasArg('--yes')
|
|
3131
|
+
const dryRun = hasArg('--dry-run')
|
|
3132
|
+
const scope = parseSkillInstallScope()
|
|
3133
|
+
const mode = parseSkillInstallMode()
|
|
3134
|
+
let targets = parseSkillInstallTargets(scope)
|
|
3135
|
+
if (targets.length === 0) {
|
|
3136
|
+
targets = await promptSkillInstallTargets(scope)
|
|
3137
|
+
}
|
|
3138
|
+
|
|
3139
|
+
if (targets.length === 0) {
|
|
3140
|
+
if (hasJsonFlag()) {
|
|
3141
|
+
printJson({ installs: [] })
|
|
3142
|
+
return
|
|
3143
|
+
}
|
|
3144
|
+
printLine('No targets selected; nothing to do.')
|
|
3145
|
+
return
|
|
3146
|
+
}
|
|
3147
|
+
|
|
3148
|
+
const outcomes = await applySkillInstallTargets(targets, { mode, skipConfirm, dryRun })
|
|
3149
|
+
if (hasJsonFlag()) {
|
|
3150
|
+
printJson({ dryRun, installs: outcomes })
|
|
3151
|
+
}
|
|
3152
|
+
}
|
|
3153
|
+
|
|
3154
|
+
function describeSkillTargetState(status: SkillTargetStatus): string {
|
|
3155
|
+
if (status.state === 'current') return 'current'
|
|
3156
|
+
if (status.state === 'stale') return 'stale (run `orizu skills update`)'
|
|
3157
|
+
if (status.state === 'broken-link') return 'broken symlink (run `orizu skills update`)'
|
|
3158
|
+
if (status.state === 'unmanaged') return 'exists without a managed Orizu section'
|
|
3159
|
+
return 'not installed'
|
|
3160
|
+
}
|
|
3161
|
+
|
|
3162
|
+
function skillsStatusCommand() {
|
|
3163
|
+
const source = resolveSkillSource()
|
|
3164
|
+
const statuses = SKILL_INSTALL_TARGETS.map(target => getSkillTargetStatus(target))
|
|
3165
|
+
|
|
3166
|
+
if (hasJsonFlag()) {
|
|
3167
|
+
printJson({
|
|
3168
|
+
name: source.name,
|
|
3169
|
+
root: source.root,
|
|
3170
|
+
source: source.source,
|
|
3171
|
+
cliVersion: getCliVersion(),
|
|
3172
|
+
sourceHash: computeSkillContentHash(source.root),
|
|
3173
|
+
targets: statuses.map(status => ({
|
|
3174
|
+
target: status.target,
|
|
3175
|
+
path: status.path,
|
|
3176
|
+
state: status.state,
|
|
3177
|
+
mode: status.mode,
|
|
3178
|
+
linkTarget: status.linkTarget,
|
|
3179
|
+
installedHash: status.installedHash,
|
|
3180
|
+
meta: status.meta,
|
|
3181
|
+
})),
|
|
3182
|
+
})
|
|
3183
|
+
return
|
|
3184
|
+
}
|
|
3185
|
+
|
|
3186
|
+
printLine(`Skill source: ${source.root} (${source.source})`)
|
|
3187
|
+
printLine('')
|
|
3188
|
+
for (const status of statuses) {
|
|
3189
|
+
const mode = status.mode ? `, ${status.mode}` : ''
|
|
3190
|
+
printLine(` ${status.target.padEnd(16)} ${describeSkillTargetState(status)}${mode}`)
|
|
3191
|
+
printLine(` ${''.padEnd(16)} ${status.path}`)
|
|
3192
|
+
}
|
|
3193
|
+
}
|
|
3194
|
+
|
|
3195
|
+
async function skillsUpdateCommand() {
|
|
3196
|
+
const dryRun = hasArg('--dry-run')
|
|
3197
|
+
const cliVersion = getCliVersion()
|
|
3198
|
+
const updates: Array<{ target: SkillInstallTarget, path: string, action: string }> = []
|
|
3199
|
+
|
|
3200
|
+
for (const target of SKILL_INSTALL_TARGETS) {
|
|
3201
|
+
const status = getSkillTargetStatus(target)
|
|
3202
|
+
if (status.state === 'missing' || status.state === 'unmanaged') {
|
|
3203
|
+
continue
|
|
3204
|
+
}
|
|
3205
|
+
|
|
3206
|
+
if (status.state === 'current') {
|
|
3207
|
+
updates.push({ target, path: status.path, action: 'already-current' })
|
|
3208
|
+
continue
|
|
3209
|
+
}
|
|
3210
|
+
|
|
3211
|
+
if (dryRun) {
|
|
3212
|
+
updates.push({ target, path: status.path, action: 'would-update' })
|
|
3213
|
+
continue
|
|
3214
|
+
}
|
|
3215
|
+
|
|
3216
|
+
const refreshMode: SkillInstallMode = status.mode === 'link' ? 'auto' : 'copy'
|
|
2831
3217
|
const result = installSkillTarget(target, {
|
|
2832
|
-
overwrite,
|
|
2833
|
-
|
|
3218
|
+
overwrite: true,
|
|
3219
|
+
mode: refreshMode,
|
|
3220
|
+
cliVersion,
|
|
3221
|
+
})
|
|
3222
|
+
updates.push({
|
|
3223
|
+
target,
|
|
3224
|
+
path: status.path,
|
|
3225
|
+
action: status.state === 'broken-link' ? 'relinked' : result.action,
|
|
3226
|
+
})
|
|
3227
|
+
}
|
|
3228
|
+
|
|
3229
|
+
if (hasJsonFlag()) {
|
|
3230
|
+
printJson({ updates })
|
|
3231
|
+
return
|
|
3232
|
+
}
|
|
3233
|
+
|
|
3234
|
+
if (updates.length === 0) {
|
|
3235
|
+
printLine('No Orizu skill installs found. Run `orizu install-skill` first.')
|
|
3236
|
+
return
|
|
3237
|
+
}
|
|
3238
|
+
|
|
3239
|
+
for (const update of updates) {
|
|
3240
|
+
if (update.action === 'already-current') {
|
|
3241
|
+
printLine(`Current ${update.path}`)
|
|
3242
|
+
} else if (update.action === 'would-update') {
|
|
3243
|
+
printLine(`Would update ${update.path}`)
|
|
3244
|
+
} else if (update.action === 'relinked') {
|
|
3245
|
+
printLine(`Relinked ${update.path}`)
|
|
3246
|
+
} else {
|
|
3247
|
+
printLine(`Updated ${update.path}`)
|
|
3248
|
+
}
|
|
3249
|
+
}
|
|
3250
|
+
}
|
|
3251
|
+
|
|
3252
|
+
function skillsPathCommand() {
|
|
3253
|
+
const source = resolveSkillSource()
|
|
3254
|
+
|
|
3255
|
+
if (hasJsonFlag()) {
|
|
3256
|
+
printJson({
|
|
3257
|
+
name: source.name,
|
|
3258
|
+
root: source.root,
|
|
3259
|
+
skillMd: source.skillMd,
|
|
3260
|
+
source: source.source,
|
|
3261
|
+
cliVersion: getCliVersion(),
|
|
3262
|
+
skillHash: computeSkillContentHash(source.root),
|
|
2834
3263
|
})
|
|
2835
|
-
|
|
3264
|
+
return
|
|
3265
|
+
}
|
|
3266
|
+
|
|
3267
|
+
printLine(hasArg('--skill-md') ? source.skillMd : source.root)
|
|
3268
|
+
}
|
|
3269
|
+
|
|
3270
|
+
const LAUNCHABLE_AGENTS: Record<string, string> = {
|
|
3271
|
+
claude: 'claude',
|
|
3272
|
+
codex: 'codex',
|
|
3273
|
+
}
|
|
3274
|
+
|
|
3275
|
+
function findExecutable(name: string): string | null {
|
|
3276
|
+
const pathValue = process.env.PATH || ''
|
|
3277
|
+
for (const dir of pathValue.split(delimiter)) {
|
|
3278
|
+
if (!dir) {
|
|
3279
|
+
continue
|
|
3280
|
+
}
|
|
3281
|
+
const candidate = join(dir, name)
|
|
3282
|
+
if (existsSync(candidate)) {
|
|
3283
|
+
return candidate
|
|
3284
|
+
}
|
|
3285
|
+
}
|
|
3286
|
+
return null
|
|
3287
|
+
}
|
|
3288
|
+
|
|
3289
|
+
function describeSetupAuthState(): { state: 'signed-in' | 'signed-out', baseUrl: string } {
|
|
3290
|
+
const baseUrl = getBaseUrl()
|
|
3291
|
+
return {
|
|
3292
|
+
state: getServerCredentials(baseUrl) ? 'signed-in' : 'signed-out',
|
|
3293
|
+
baseUrl,
|
|
3294
|
+
}
|
|
3295
|
+
}
|
|
3296
|
+
|
|
3297
|
+
async function setupCommand() {
|
|
3298
|
+
const dryRun = hasArg('--dry-run')
|
|
3299
|
+
const skipConfirm = hasArg('--yes')
|
|
3300
|
+
const noInput = hasArg('--no-input') || !isInteractiveTerminal()
|
|
3301
|
+
|
|
3302
|
+
printBannerIfInteractive()
|
|
3303
|
+
printLine('Orizu setup')
|
|
3304
|
+
printLine('')
|
|
3305
|
+
|
|
3306
|
+
// Phase 1: login
|
|
3307
|
+
printLine('1. Authentication')
|
|
3308
|
+
let auth = describeSetupAuthState()
|
|
3309
|
+
if (hasArg('--skip-login')) {
|
|
3310
|
+
printLine(' Skipped (--skip-login).')
|
|
3311
|
+
} else if (auth.state === 'signed-in') {
|
|
3312
|
+
printLine(` Already authenticated with ${sanitizeTerminalText(auth.baseUrl)}.`)
|
|
3313
|
+
} else if (noInput || dryRun) {
|
|
3314
|
+
printLine(' Not signed in. Run `orizu login` to authenticate.')
|
|
3315
|
+
} else if (await askYesNo(' Sign in to Orizu now?', true)) {
|
|
3316
|
+
await login()
|
|
3317
|
+
auth = describeSetupAuthState()
|
|
3318
|
+
} else {
|
|
3319
|
+
printLine(' Skipped. Run `orizu login` when ready.')
|
|
3320
|
+
}
|
|
3321
|
+
printLine('')
|
|
3322
|
+
|
|
3323
|
+
// Phase 2: agent integration
|
|
3324
|
+
printLine('2. Agent integration')
|
|
3325
|
+
const scope = parseSkillInstallScope()
|
|
3326
|
+
const mode = parseSkillInstallMode()
|
|
3327
|
+
let targets = hasArg('--no-install') ? [] : parseSkillInstallTargets(scope)
|
|
3328
|
+
if (targets.length === 0 && !hasArg('--no-install')) {
|
|
3329
|
+
if (noInput) {
|
|
3330
|
+
printLine(' No agents selected. Pass --agent claude and/or --agent codex, or rerun interactively.')
|
|
3331
|
+
} else {
|
|
3332
|
+
targets = await promptSkillInstallTargets(scope)
|
|
3333
|
+
}
|
|
3334
|
+
}
|
|
3335
|
+
|
|
3336
|
+
let installOutcomes: SkillInstallOutcome[] = []
|
|
3337
|
+
if (targets.length > 0) {
|
|
3338
|
+
installOutcomes = await applySkillInstallTargets(targets, { mode, skipConfirm, dryRun })
|
|
3339
|
+
} else if (hasArg('--no-install')) {
|
|
3340
|
+
printLine(' Skipped (--no-install).')
|
|
3341
|
+
}
|
|
3342
|
+
printLine('')
|
|
3343
|
+
|
|
3344
|
+
// Phase 3: local workspace
|
|
3345
|
+
printLine('3. Local workspace')
|
|
3346
|
+
let workspaceState: 'created' | 'exists' | 'skipped' | 'would-create' = 'skipped'
|
|
3347
|
+
if (hasArg('--no-workspace')) {
|
|
3348
|
+
printLine(' Skipped (--no-workspace).')
|
|
3349
|
+
} else if (workspaceExists()) {
|
|
3350
|
+
workspaceState = 'exists'
|
|
3351
|
+
printLine(` ${WORKSPACE_DIR_NAME}/ already initialized.`)
|
|
3352
|
+
} else {
|
|
3353
|
+
const wantsWorkspace = hasArg('--workspace') ||
|
|
3354
|
+
(!noInput && await askYesNo(` Create a gitignored ${WORKSPACE_DIR_NAME}/ workspace for local Orizu artifacts?`, true))
|
|
3355
|
+
if (wantsWorkspace) {
|
|
3356
|
+
const result = initOrizuWorkspace({
|
|
3357
|
+
baseUrl: auth.baseUrl,
|
|
3358
|
+
cliVersion: getCliVersion(),
|
|
3359
|
+
dryRun,
|
|
3360
|
+
})
|
|
3361
|
+
workspaceState = result.state === 'would-create' ? 'would-create' : result.state
|
|
3362
|
+
for (const action of result.actions) {
|
|
3363
|
+
printLine(` ${dryRun ? 'Would ' : 'Did '}${action}`)
|
|
3364
|
+
}
|
|
3365
|
+
} else {
|
|
3366
|
+
printLine(` Skipped. Rerun with --workspace to create ${WORKSPACE_DIR_NAME}/.`)
|
|
3367
|
+
}
|
|
3368
|
+
}
|
|
3369
|
+
printLine('')
|
|
3370
|
+
|
|
3371
|
+
// Phase 4: coding-agent handoff
|
|
3372
|
+
const handoffPrompt = renderAgentSetupPrompt({
|
|
3373
|
+
workspacePath: workspaceState === 'created' || workspaceState === 'exists'
|
|
3374
|
+
? getWorkspaceRoot()
|
|
3375
|
+
: null,
|
|
3376
|
+
})
|
|
3377
|
+
if (!hasArg('--no-handoff')) {
|
|
3378
|
+
printLine('4. Coding-agent handoff')
|
|
3379
|
+
printLine(' Give your coding agent this prompt to plan repo-specific Orizu adoption:')
|
|
3380
|
+
printLine('')
|
|
3381
|
+
printLine('--- prompt start ---')
|
|
3382
|
+
printLine(handoffPrompt)
|
|
3383
|
+
printLine('--- prompt end ---')
|
|
3384
|
+
printLine('')
|
|
3385
|
+
|
|
3386
|
+
const detected = Object.keys(LAUNCHABLE_AGENTS).filter(agent => findExecutable(LAUNCHABLE_AGENTS[agent]))
|
|
3387
|
+
if (detected.length > 0) {
|
|
3388
|
+
printLine(` Detected agents: ${detected.join(', ')}. Launch one with the prompt, e.g.:`)
|
|
3389
|
+
for (const agent of detected) {
|
|
3390
|
+
printLine(` ${LAUNCHABLE_AGENTS[agent]} "$(orizu setup prompt)"`)
|
|
3391
|
+
}
|
|
3392
|
+
}
|
|
3393
|
+
|
|
3394
|
+
const launchAgent = getArg('--launch')
|
|
3395
|
+
if (launchAgent) {
|
|
3396
|
+
if (!(launchAgent in LAUNCHABLE_AGENTS)) {
|
|
3397
|
+
throw new Error(`Unknown --launch agent '${launchAgent}'. Choices: ${Object.keys(LAUNCHABLE_AGENTS).join(', ')}.`)
|
|
3398
|
+
}
|
|
3399
|
+
const binary = findExecutable(LAUNCHABLE_AGENTS[launchAgent])
|
|
3400
|
+
if (!isInteractiveTerminal()) {
|
|
3401
|
+
printLine(' Not launching: --launch requires an interactive terminal.')
|
|
3402
|
+
} else if (!binary) {
|
|
3403
|
+
printLine(` Not launching: '${LAUNCHABLE_AGENTS[launchAgent]}' was not found on PATH.`)
|
|
3404
|
+
} else if (dryRun) {
|
|
3405
|
+
printLine(` Would launch ${binary} with the setup prompt.`)
|
|
3406
|
+
} else if (skipConfirm || await askYesNo(` Launch ${LAUNCHABLE_AGENTS[launchAgent]} with the setup prompt now?`, true)) {
|
|
3407
|
+
printLine(` Launching ${binary}…`)
|
|
3408
|
+
spawnSync(binary, [handoffPrompt], { stdio: 'inherit' })
|
|
3409
|
+
}
|
|
3410
|
+
}
|
|
3411
|
+
printLine('')
|
|
3412
|
+
}
|
|
3413
|
+
|
|
3414
|
+
// Setup summary (success criteria checklist)
|
|
3415
|
+
const summaryTargets = installOutcomes.length > 0
|
|
3416
|
+
? installOutcomes
|
|
3417
|
+
.filter(outcome => outcome.action !== 'failed')
|
|
3418
|
+
.map(outcome => ({ outcome, status: getSkillTargetStatus(outcome.target) }))
|
|
3419
|
+
: []
|
|
3420
|
+
const source = resolveSkillSource()
|
|
3421
|
+
|
|
3422
|
+
if (hasJsonFlag()) {
|
|
3423
|
+
printJson({
|
|
3424
|
+
auth: { state: auth.state, server: auth.baseUrl },
|
|
3425
|
+
integrations: installOutcomes.map(outcome => ({
|
|
3426
|
+
target: outcome.target,
|
|
3427
|
+
path: outcome.path,
|
|
3428
|
+
action: outcome.action,
|
|
3429
|
+
mode: outcome.mode,
|
|
3430
|
+
error: outcome.error,
|
|
3431
|
+
})),
|
|
3432
|
+
skill: {
|
|
3433
|
+
root: source.root,
|
|
3434
|
+
source: source.source,
|
|
3435
|
+
cliVersion: getCliVersion(),
|
|
3436
|
+
skillHash: computeSkillContentHash(source.root),
|
|
3437
|
+
},
|
|
3438
|
+
workspace: { state: workspaceState, path: getWorkspaceRoot() },
|
|
3439
|
+
})
|
|
3440
|
+
return
|
|
3441
|
+
}
|
|
3442
|
+
|
|
3443
|
+
printLine('Setup summary')
|
|
3444
|
+
printLine(` Auth: ${auth.state === 'signed-in' ? `signed in (${sanitizeTerminalText(auth.baseUrl)})` : 'not signed in — run `orizu login`'}`)
|
|
3445
|
+
if (summaryTargets.length > 0) {
|
|
3446
|
+
printLine(' Integrations:')
|
|
3447
|
+
for (const { outcome, status } of summaryTargets) {
|
|
3448
|
+
const modeLabel = status.mode ? `, ${status.mode}` : ''
|
|
3449
|
+
printLine(` ${outcome.target.padEnd(16)} ${status.state}${modeLabel} ${outcome.path}`)
|
|
3450
|
+
}
|
|
3451
|
+
} else {
|
|
3452
|
+
printLine(' Integrations: none installed this run — `orizu install-skill` sets them up.')
|
|
3453
|
+
}
|
|
3454
|
+
const failed = installOutcomes.filter(outcome => outcome.action === 'failed')
|
|
3455
|
+
for (const failure of failed) {
|
|
3456
|
+
printLine(` ${failure.target.padEnd(16)} failed: ${failure.error}`)
|
|
3457
|
+
}
|
|
3458
|
+
printLine(` Skill source: ${source.root} (${source.source})`)
|
|
3459
|
+
printLine(` Workspace: ${workspaceState === 'skipped' ? 'skipped' : `${getWorkspaceRoot()} (${workspaceState})`}`)
|
|
3460
|
+
printLine(' Next: hand the prompt above to your coding agent to plan repo-specific Orizu adoption.')
|
|
3461
|
+
}
|
|
3462
|
+
|
|
3463
|
+
function setupPromptCommand() {
|
|
3464
|
+
const prompt = renderAgentSetupPrompt({
|
|
3465
|
+
workspacePath: workspaceExists() ? getWorkspaceRoot() : null,
|
|
3466
|
+
})
|
|
3467
|
+
if (hasJsonFlag()) {
|
|
3468
|
+
printJson({ prompt })
|
|
3469
|
+
return
|
|
2836
3470
|
}
|
|
3471
|
+
printLine(prompt)
|
|
2837
3472
|
}
|
|
2838
3473
|
|
|
2839
3474
|
function readJsonFile(pathArg: string): Record<string, unknown> {
|
|
@@ -3100,6 +3735,10 @@ async function createAppFromFile() {
|
|
|
3100
3735
|
app: { id: string; name: string; versionNum: number; componentName?: string; url?: string }
|
|
3101
3736
|
warnings?: string[]
|
|
3102
3737
|
}>(response, 'App create')
|
|
3738
|
+
if (hasJsonFlag()) {
|
|
3739
|
+
printJson({ app: data.app, warnings: data.warnings || [] })
|
|
3740
|
+
return
|
|
3741
|
+
}
|
|
3103
3742
|
printLine(`Created app ${sanitizeTerminalText(data.app.name)} (${sanitizeTerminalText(data.app.id)}) v${data.app.versionNum}`)
|
|
3104
3743
|
if (data.app.url) {
|
|
3105
3744
|
printLine(`View app: ${formatTerminalLink(data.app.url)}`)
|
|
@@ -3140,6 +3779,14 @@ async function previewAppFromFile() {
|
|
|
3140
3779
|
keepOpen,
|
|
3141
3780
|
})
|
|
3142
3781
|
|
|
3782
|
+
if (hasJsonFlag()) {
|
|
3783
|
+
printJson({
|
|
3784
|
+
url: result.url,
|
|
3785
|
+
screenshotPath: result.screenshotPath || null,
|
|
3786
|
+
warnings: result.warnings,
|
|
3787
|
+
})
|
|
3788
|
+
return
|
|
3789
|
+
}
|
|
3143
3790
|
printLine(`Preview rendered: ${formatTerminalLink(result.url)}`)
|
|
3144
3791
|
if (result.screenshotPath) {
|
|
3145
3792
|
printLine(`Screenshot: ${sanitizeTerminalText(result.screenshotPath)}`)
|
|
@@ -3191,6 +3838,10 @@ async function updateAppFromFile() {
|
|
|
3191
3838
|
app: { id: string; name: string; versionNum: number; componentName?: string }
|
|
3192
3839
|
warnings?: string[]
|
|
3193
3840
|
}>(response, 'App update')
|
|
3841
|
+
if (hasJsonFlag()) {
|
|
3842
|
+
printJson({ app: data.app, warnings: data.warnings || [] })
|
|
3843
|
+
return
|
|
3844
|
+
}
|
|
3194
3845
|
printLine(`Updated app ${sanitizeTerminalText(data.app.name)} (${sanitizeTerminalText(data.app.id)}) to v${data.app.versionNum}`)
|
|
3195
3846
|
if (data.warnings?.length) {
|
|
3196
3847
|
printLine(`Warnings: ${sanitizeTerminalText(data.warnings.join('; '))}`)
|
|
@@ -3238,6 +3889,10 @@ async function linkAppDataset() {
|
|
|
3238
3889
|
versionNum: number
|
|
3239
3890
|
}>(response, 'App link dataset')
|
|
3240
3891
|
|
|
3892
|
+
if (hasJsonFlag()) {
|
|
3893
|
+
printJson({ app: data.app, linkedDataset: data.linkedDataset, versionNum: data.versionNum })
|
|
3894
|
+
return
|
|
3895
|
+
}
|
|
3241
3896
|
printLine(
|
|
3242
3897
|
`Linked dataset ${sanitizeTerminalText(data.linkedDataset.name)} (${sanitizeTerminalText(data.linkedDataset.id)}) to app ${sanitizeTerminalText(data.app.name)} (${sanitizeTerminalText(data.app.id)}) version ${data.versionNum}`
|
|
3243
3898
|
)
|
|
@@ -3294,7 +3949,7 @@ async function createTask() {
|
|
|
3294
3949
|
|
|
3295
3950
|
if (!response.ok) {
|
|
3296
3951
|
const cliError = await formatTaskCreateError(response)
|
|
3297
|
-
if (
|
|
3952
|
+
if (hasJsonFlag()) {
|
|
3298
3953
|
const payload = cliError.structuredPayload ?? { error: cliError.message }
|
|
3299
3954
|
printLine(JSON.stringify({
|
|
3300
3955
|
...payload,
|
|
@@ -3318,7 +3973,7 @@ async function createTask() {
|
|
|
3318
3973
|
warning?: string
|
|
3319
3974
|
}>(response, 'Task create')
|
|
3320
3975
|
|
|
3321
|
-
if (
|
|
3976
|
+
if (hasJsonFlag()) {
|
|
3322
3977
|
printLine(JSON.stringify({
|
|
3323
3978
|
taskId: data.task.id,
|
|
3324
3979
|
datasetId,
|
|
@@ -3390,7 +4045,7 @@ async function publishTask() {
|
|
|
3390
4045
|
'Task publish'
|
|
3391
4046
|
)
|
|
3392
4047
|
|
|
3393
|
-
if (
|
|
4048
|
+
if (hasJsonFlag()) {
|
|
3394
4049
|
printLine(JSON.stringify({
|
|
3395
4050
|
taskId: data.task.id,
|
|
3396
4051
|
status: data.task.status,
|
|
@@ -3436,6 +4091,10 @@ async function assignTask() {
|
|
|
3436
4091
|
}
|
|
3437
4092
|
|
|
3438
4093
|
const data = await parseJsonResponse<{ assignmentsCreated: number }>(response, 'Task assign')
|
|
4094
|
+
if (hasJsonFlag()) {
|
|
4095
|
+
printJson({ assignmentsCreated: data.assignmentsCreated })
|
|
4096
|
+
return
|
|
4097
|
+
}
|
|
3439
4098
|
printLine(`Created ${data.assignmentsCreated} assignments.`)
|
|
3440
4099
|
}
|
|
3441
4100
|
|
|
@@ -3448,7 +4107,7 @@ async function taskStatus() {
|
|
|
3448
4107
|
const response = await authedFetch(`/api/cli/tasks/${encodeURIComponent(taskId)}/status`)
|
|
3449
4108
|
if (!response.ok) {
|
|
3450
4109
|
const rawBody = await response.text()
|
|
3451
|
-
if (
|
|
4110
|
+
if (hasJsonFlag()) {
|
|
3452
4111
|
let errorPayload: Record<string, unknown> = { error: rawBody }
|
|
3453
4112
|
try {
|
|
3454
4113
|
const parsed = JSON.parse(rawBody)
|
|
@@ -3475,7 +4134,7 @@ async function taskStatus() {
|
|
|
3475
4134
|
}
|
|
3476
4135
|
|
|
3477
4136
|
const data = await parseJsonResponse<TaskStatusPayload>(response, 'Task status')
|
|
3478
|
-
if (
|
|
4137
|
+
if (hasJsonFlag()) {
|
|
3479
4138
|
printLine(JSON.stringify(data, null, 2))
|
|
3480
4139
|
return
|
|
3481
4140
|
}
|
|
@@ -3502,6 +4161,10 @@ async function updateTaskStatus(targetStatus: 'paused' | 'active') {
|
|
|
3502
4161
|
}
|
|
3503
4162
|
|
|
3504
4163
|
const data = await parseJsonResponse<{ task: { id: string; status: string } }>(response, 'Task status update')
|
|
4164
|
+
if (hasJsonFlag()) {
|
|
4165
|
+
printJson({ task: data.task })
|
|
4166
|
+
return
|
|
4167
|
+
}
|
|
3505
4168
|
const action = targetStatus === 'paused' ? 'Paused' : 'Unpaused'
|
|
3506
4169
|
printLine(`${action} task ${sanitizeTerminalText(data.task.id)} [${sanitizeTerminalText(data.task.status)}]`)
|
|
3507
4170
|
}
|
|
@@ -3626,7 +4289,7 @@ async function appDetail() {
|
|
|
3626
4289
|
throw new Error(`App '${appId}' not found in project '${projectSlug}'`)
|
|
3627
4290
|
}
|
|
3628
4291
|
|
|
3629
|
-
if (
|
|
4292
|
+
if (hasJsonFlag()) {
|
|
3630
4293
|
printLine(JSON.stringify(detail, null, 2))
|
|
3631
4294
|
return
|
|
3632
4295
|
}
|
|
@@ -3687,6 +4350,14 @@ async function exportAppSource() {
|
|
|
3687
4350
|
: defaultAppExportFilename(data.app.name, data.version.versionNum)
|
|
3688
4351
|
|
|
3689
4352
|
writeTextFileEnsuringDir(filename, data.version.code)
|
|
4353
|
+
if (hasJsonFlag()) {
|
|
4354
|
+
printJson({
|
|
4355
|
+
app: { id: data.app.id, name: data.app.name },
|
|
4356
|
+
versionNum: data.version.versionNum,
|
|
4357
|
+
savedTo: filename,
|
|
4358
|
+
})
|
|
4359
|
+
return
|
|
4360
|
+
}
|
|
3690
4361
|
printLine(
|
|
3691
4362
|
`Saved app ${sanitizeTerminalText(data.app.name)} v${data.version.versionNum} source to ${sanitizeTerminalText(filename)}`
|
|
3692
4363
|
)
|
|
@@ -3694,8 +4365,12 @@ async function exportAppSource() {
|
|
|
3694
4365
|
|
|
3695
4366
|
async function listTeamMembers() {
|
|
3696
4367
|
const teamSlug = await resolveTeamSlug(getArg('--team'))
|
|
3697
|
-
|
|
3698
|
-
|
|
4368
|
+
const members = await fetchTeamMembers(teamSlug)
|
|
4369
|
+
if (hasJsonFlag()) {
|
|
4370
|
+
printJson({ team: teamSlug, members })
|
|
4371
|
+
return
|
|
4372
|
+
}
|
|
4373
|
+
printTeamMembers(members)
|
|
3699
4374
|
}
|
|
3700
4375
|
|
|
3701
4376
|
async function addTeamMember() {
|
|
@@ -3714,6 +4389,10 @@ async function addTeamMember() {
|
|
|
3714
4389
|
throw new Error(`Failed to add team member: ${await response.text()}`)
|
|
3715
4390
|
}
|
|
3716
4391
|
const data = await parseJsonResponse<{ member: TeamMember }>(response, 'Team member add')
|
|
4392
|
+
if (hasJsonFlag()) {
|
|
4393
|
+
printJson({ member: data.member })
|
|
4394
|
+
return
|
|
4395
|
+
}
|
|
3717
4396
|
printLine(`Added team member ${sanitizeTerminalText(data.member.email)} (${sanitizeTerminalText(data.member.id)})`)
|
|
3718
4397
|
}
|
|
3719
4398
|
|
|
@@ -3737,6 +4416,10 @@ async function removeTeamMember() {
|
|
|
3737
4416
|
if (!response.ok) {
|
|
3738
4417
|
throw new Error(`Failed to remove team member: ${await response.text()}`)
|
|
3739
4418
|
}
|
|
4419
|
+
if (hasJsonFlag()) {
|
|
4420
|
+
printJson({ removed: { id: member.id, email: member.email } })
|
|
4421
|
+
return
|
|
4422
|
+
}
|
|
3740
4423
|
printLine(`Removed team member ${sanitizeTerminalText(member.email)}`)
|
|
3741
4424
|
}
|
|
3742
4425
|
|
|
@@ -3771,6 +4454,10 @@ async function changeTeamMemberRole() {
|
|
|
3771
4454
|
throw new Error(`Failed to update member role: ${await response.text()}`)
|
|
3772
4455
|
}
|
|
3773
4456
|
|
|
4457
|
+
if (hasJsonFlag()) {
|
|
4458
|
+
printJson({ member: { id: member.id, email: member.email, role } })
|
|
4459
|
+
return
|
|
4460
|
+
}
|
|
3774
4461
|
printLine(`Updated ${sanitizeTerminalText(member.email)} role to ${sanitizeTerminalText(role)}`)
|
|
3775
4462
|
}
|
|
3776
4463
|
|
|
@@ -3873,6 +4560,10 @@ async function uploadJsonlDatasetInChunks(
|
|
|
3873
4560
|
throw new Error('Dataset file contains no rows')
|
|
3874
4561
|
}
|
|
3875
4562
|
|
|
4563
|
+
if (hasJsonFlag()) {
|
|
4564
|
+
printJson({ dataset })
|
|
4565
|
+
return
|
|
4566
|
+
}
|
|
3876
4567
|
printLine(`Uploaded dataset ${sanitizeTerminalText(dataset.name)} (${sanitizeTerminalText(dataset.id)}) with ${dataset.rowCount} rows.`)
|
|
3877
4568
|
if (dataset.url) {
|
|
3878
4569
|
printLine(`View dataset: ${formatTerminalLink(dataset.url)}`)
|
|
@@ -3902,6 +4593,10 @@ async function uploadDataset() {
|
|
|
3902
4593
|
const { rows, sourceType } = parseDatasetFile(file)
|
|
3903
4594
|
const data = await createDatasetFromRows(project, datasetName, sourceType, rows, readmeMarkdown)
|
|
3904
4595
|
|
|
4596
|
+
if (hasJsonFlag()) {
|
|
4597
|
+
printJson({ dataset: data.dataset })
|
|
4598
|
+
return
|
|
4599
|
+
}
|
|
3905
4600
|
printLine(`Uploaded dataset ${sanitizeTerminalText(data.dataset.name)} (${sanitizeTerminalText(data.dataset.id)}) with ${data.dataset.rowCount} rows.`)
|
|
3906
4601
|
if (data.dataset.url) {
|
|
3907
4602
|
printLine(`View dataset: ${formatTerminalLink(data.dataset.url)}`)
|
|
@@ -4039,6 +4734,10 @@ async function downloadDataset() {
|
|
|
4039
4734
|
const bytes = new Uint8Array(await response.arrayBuffer())
|
|
4040
4735
|
writeFileSync(filename, bytes)
|
|
4041
4736
|
|
|
4737
|
+
if (hasJsonFlag()) {
|
|
4738
|
+
printJson({ datasetId, format, savedTo: filename })
|
|
4739
|
+
return
|
|
4740
|
+
}
|
|
4042
4741
|
printLine(`Saved dataset ${sanitizeTerminalText(datasetId)} (${format.toUpperCase()}) to ${sanitizeTerminalText(filename)}`)
|
|
4043
4742
|
}
|
|
4044
4743
|
|
|
@@ -4204,6 +4903,10 @@ async function appendDatasetRows() {
|
|
|
4204
4903
|
}
|
|
4205
4904
|
|
|
4206
4905
|
if (lastResult) {
|
|
4906
|
+
if (hasJsonFlag()) {
|
|
4907
|
+
printJson({ dataset: lastResult.dataset, appendedCount: totalAppended })
|
|
4908
|
+
return
|
|
4909
|
+
}
|
|
4207
4910
|
printLine(
|
|
4208
4911
|
`Appended ${totalAppended} rows to dataset ${sanitizeTerminalText(lastResult.dataset.name)} (${sanitizeTerminalText(lastResult.dataset.id)}). New row count: ${lastResult.dataset.rowCount}`
|
|
4209
4912
|
)
|
|
@@ -4265,6 +4968,10 @@ async function editDatasetRows() {
|
|
|
4265
4968
|
updatedCount: number
|
|
4266
4969
|
}>(response, 'Dataset edit rows')
|
|
4267
4970
|
|
|
4971
|
+
if (hasJsonFlag()) {
|
|
4972
|
+
printJson({ dataset: data.dataset, updatedCount: data.updatedCount })
|
|
4973
|
+
return
|
|
4974
|
+
}
|
|
4268
4975
|
printLine(
|
|
4269
4976
|
`Updated ${data.updatedCount} rows in dataset ${sanitizeTerminalText(data.dataset.name)} (${sanitizeTerminalText(data.dataset.id)}). Current row count: ${data.dataset.rowCount}`
|
|
4270
4977
|
)
|
|
@@ -4304,6 +5011,10 @@ async function deleteDatasetRows() {
|
|
|
4304
5011
|
deletedCount: number
|
|
4305
5012
|
}>(response, 'Dataset delete rows')
|
|
4306
5013
|
|
|
5014
|
+
if (hasJsonFlag()) {
|
|
5015
|
+
printJson({ dataset: data.dataset, deletedCount: data.deletedCount })
|
|
5016
|
+
return
|
|
5017
|
+
}
|
|
4307
5018
|
printLine(
|
|
4308
5019
|
`Deleted ${data.deletedCount} rows from dataset ${sanitizeTerminalText(data.dataset.name)} (${sanitizeTerminalText(data.dataset.id)}). New row count: ${data.dataset.rowCount}`
|
|
4309
5020
|
)
|
|
@@ -4358,6 +5069,10 @@ async function deleteDataset() {
|
|
|
4358
5069
|
dataset: { id: string }
|
|
4359
5070
|
}>(response, 'Dataset delete')
|
|
4360
5071
|
|
|
5072
|
+
if (hasJsonFlag()) {
|
|
5073
|
+
printJson({ dataset: data.dataset, deleted: true })
|
|
5074
|
+
return
|
|
5075
|
+
}
|
|
4361
5076
|
printLine(`Deleted dataset ${sanitizeTerminalText(data.dataset.id)}.`)
|
|
4362
5077
|
}
|
|
4363
5078
|
|
|
@@ -4394,6 +5109,10 @@ async function lockDataset() {
|
|
|
4394
5109
|
}
|
|
4395
5110
|
}>(response, 'Dataset lock')
|
|
4396
5111
|
|
|
5112
|
+
if (hasJsonFlag()) {
|
|
5113
|
+
printJson({ dataset: data.dataset })
|
|
5114
|
+
return
|
|
5115
|
+
}
|
|
4397
5116
|
printLine(
|
|
4398
5117
|
`Locked dataset ${sanitizeTerminalText(data.dataset.name)} (${sanitizeTerminalText(data.dataset.id)}) at ${sanitizeTerminalText(data.dataset.lockedAt)}. Row count: ${data.dataset.rowCount}`
|
|
4399
5118
|
)
|
|
@@ -4431,6 +5150,10 @@ async function cloneDataset() {
|
|
|
4431
5150
|
}
|
|
4432
5151
|
}>(response, 'Dataset clone')
|
|
4433
5152
|
|
|
5153
|
+
if (hasJsonFlag()) {
|
|
5154
|
+
printJson({ dataset: data.dataset })
|
|
5155
|
+
return
|
|
5156
|
+
}
|
|
4434
5157
|
printLine(
|
|
4435
5158
|
`Cloned dataset ${sanitizeTerminalText(data.dataset.parentDatasetId)} -> ${sanitizeTerminalText(data.dataset.name)} (${sanitizeTerminalText(data.dataset.id)}). Row count: ${data.dataset.rowCount}`
|
|
4436
5159
|
)
|
|
@@ -4462,6 +5185,10 @@ async function downloadAnnotations() {
|
|
|
4462
5185
|
const bytes = new Uint8Array(await response.arrayBuffer())
|
|
4463
5186
|
writeFileSync(filename, bytes)
|
|
4464
5187
|
|
|
5188
|
+
if (hasJsonFlag()) {
|
|
5189
|
+
printJson({ taskId, format, savedTo: filename })
|
|
5190
|
+
return
|
|
5191
|
+
}
|
|
4465
5192
|
printLine(`Saved ${format.toUpperCase()} export to ${sanitizeTerminalText(filename)}`)
|
|
4466
5193
|
}
|
|
4467
5194
|
|
|
@@ -4706,7 +5433,11 @@ async function runnersExec() {
|
|
|
4706
5433
|
} else {
|
|
4707
5434
|
writeFileSync(outPath, resultJsonl)
|
|
4708
5435
|
}
|
|
4709
|
-
|
|
5436
|
+
if (hasJsonFlag()) {
|
|
5437
|
+
printJson({ rowCount: context.rows.length, out: outPath })
|
|
5438
|
+
} else {
|
|
5439
|
+
printLine(`Wrote ${context.rows.length} runner results to ${sanitizeTerminalText(outPath)}`)
|
|
5440
|
+
}
|
|
4710
5441
|
} finally {
|
|
4711
5442
|
materializedRunner.cleanup()
|
|
4712
5443
|
}
|
|
@@ -4747,6 +5478,9 @@ export async function main(rawArgs = process.argv.slice(2)) {
|
|
|
4747
5478
|
|
|
4748
5479
|
const helpTarget = extractHelpTarget(cliArgs)
|
|
4749
5480
|
if (helpTarget !== null) {
|
|
5481
|
+
if (helpTarget.length === 0) {
|
|
5482
|
+
printBannerIfInteractive()
|
|
5483
|
+
}
|
|
4750
5484
|
printLine(renderHelpForArgs(helpTarget))
|
|
4751
5485
|
return
|
|
4752
5486
|
}
|
|
@@ -4769,6 +5503,16 @@ export async function main(rawArgs = process.argv.slice(2)) {
|
|
|
4769
5503
|
return
|
|
4770
5504
|
}
|
|
4771
5505
|
|
|
5506
|
+
if (command === 'setup' && subcommand === 'prompt') {
|
|
5507
|
+
setupPromptCommand()
|
|
5508
|
+
return
|
|
5509
|
+
}
|
|
5510
|
+
|
|
5511
|
+
if (command === 'setup') {
|
|
5512
|
+
await setupCommand()
|
|
5513
|
+
return
|
|
5514
|
+
}
|
|
5515
|
+
|
|
4772
5516
|
if (command === 'install-skill') {
|
|
4773
5517
|
await installSkillCommand()
|
|
4774
5518
|
return
|
|
@@ -4779,6 +5523,21 @@ export async function main(rawArgs = process.argv.slice(2)) {
|
|
|
4779
5523
|
return
|
|
4780
5524
|
}
|
|
4781
5525
|
|
|
5526
|
+
if (command === 'skills' && subcommand === 'path') {
|
|
5527
|
+
skillsPathCommand()
|
|
5528
|
+
return
|
|
5529
|
+
}
|
|
5530
|
+
|
|
5531
|
+
if (command === 'skills' && subcommand === 'status') {
|
|
5532
|
+
skillsStatusCommand()
|
|
5533
|
+
return
|
|
5534
|
+
}
|
|
5535
|
+
|
|
5536
|
+
if (command === 'skills' && subcommand === 'update') {
|
|
5537
|
+
await skillsUpdateCommand()
|
|
5538
|
+
return
|
|
5539
|
+
}
|
|
5540
|
+
|
|
4782
5541
|
if (command === 'login') {
|
|
4783
5542
|
await login()
|
|
4784
5543
|
return
|
|
@@ -4862,6 +5621,16 @@ export async function main(rawArgs = process.argv.slice(2)) {
|
|
|
4862
5621
|
return
|
|
4863
5622
|
}
|
|
4864
5623
|
|
|
5624
|
+
if (command === 'prompts' && subcommand === 'archive') {
|
|
5625
|
+
await setPromptArchivedState(true)
|
|
5626
|
+
return
|
|
5627
|
+
}
|
|
5628
|
+
|
|
5629
|
+
if (command === 'prompts' && subcommand === 'restore') {
|
|
5630
|
+
await setPromptArchivedState(false)
|
|
5631
|
+
return
|
|
5632
|
+
}
|
|
5633
|
+
|
|
4865
5634
|
if (command === 'prompts' && subcommand === 'labels' && cliArgs[2] === 'set') {
|
|
4866
5635
|
await setPromptLabel()
|
|
4867
5636
|
return
|