orizu 0.5.29 → 0.5.31
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 +8 -2
- package/dist/account-directory.d.ts +132 -0
- package/dist/account-directory.d.ts.map +1 -0
- package/dist/account-directory.js +434 -0
- package/dist/app-commands.d.ts +29 -0
- package/dist/app-commands.d.ts.map +1 -0
- package/dist/app-commands.js +375 -0
- package/dist/auth-commands.d.ts +11 -0
- package/dist/auth-commands.d.ts.map +1 -0
- package/dist/auth-commands.js +321 -0
- package/dist/cli-console-output.d.ts +12 -0
- package/dist/cli-console-output.d.ts.map +1 -0
- package/dist/cli-console-output.js +57 -0
- package/dist/cli-project-slug.d.ts +3 -0
- package/dist/cli-project-slug.d.ts.map +1 -1
- package/dist/cli-project-slug.js +12 -0
- package/dist/command-line-arguments.d.ts +15 -0
- package/dist/command-line-arguments.d.ts.map +1 -0
- package/dist/command-line-arguments.js +77 -0
- package/dist/credentials.d.ts +2 -0
- package/dist/credentials.d.ts.map +1 -1
- package/dist/credentials.js +43 -0
- package/dist/dataset-commands.d.ts +16 -0
- package/dist/dataset-commands.d.ts.map +1 -0
- package/dist/dataset-commands.js +634 -0
- package/dist/dataset-download.d.ts.map +1 -1
- package/dist/dataset-download.js +4 -3
- package/dist/egress-policy.d.ts +8 -5
- package/dist/egress-policy.d.ts.map +1 -1
- package/dist/egress-policy.js +18 -7
- package/dist/feedback-cli.d.ts.map +1 -1
- package/dist/feedback-cli.js +22 -8
- package/dist/feedback-contract.d.ts +2 -0
- package/dist/feedback-contract.d.ts.map +1 -1
- package/dist/feedback-contract.js +17 -3
- package/dist/feedback-scrub.d.ts.map +1 -1
- package/dist/feedback-scrub.js +308 -22
- package/dist/gepa-engine-dispatch.d.ts.map +1 -1
- package/dist/gepa-engine-dispatch.js +28 -3
- package/dist/global-flags.d.ts +1 -0
- package/dist/global-flags.d.ts.map +1 -1
- package/dist/global-flags.js +7 -0
- package/dist/help.d.ts.map +1 -1
- package/dist/help.js +69 -2
- package/dist/hosted-environment.d.ts +10 -0
- package/dist/hosted-environment.d.ts.map +1 -1
- package/dist/hosted-environment.js +81 -0
- package/dist/hosted-gepa-cli.d.ts.map +1 -1
- package/dist/hosted-gepa-cli.js +44 -6
- package/dist/hosted-harness-claude.d.ts +1 -2
- package/dist/hosted-harness-claude.d.ts.map +1 -1
- package/dist/hosted-harness-claude.js +12 -5
- package/dist/hosted-harness-opencode.d.ts +16 -10
- package/dist/hosted-harness-opencode.d.ts.map +1 -1
- package/dist/hosted-harness-opencode.js +50 -21
- package/dist/hosted-harness.d.ts +30 -1
- package/dist/hosted-harness.d.ts.map +1 -1
- package/dist/hosted-harness.js +5 -0
- package/dist/hosted-optimization-refusals.d.ts +6 -1
- package/dist/hosted-optimization-refusals.d.ts.map +1 -1
- package/dist/hosted-optimization-refusals.js +8 -2
- package/dist/hosted-optimization.d.ts.map +1 -1
- package/dist/hosted-optimization.js +40 -10
- package/dist/hosted-provider-credentials.d.ts +16 -0
- package/dist/hosted-provider-credentials.d.ts.map +1 -0
- package/dist/hosted-provider-credentials.js +36 -0
- package/dist/hosted-provider-settings.d.ts +7 -4
- package/dist/hosted-provider-settings.d.ts.map +1 -1
- package/dist/hosted-provider-settings.js +16 -13
- package/dist/hosted-tool-hints.d.ts +56 -0
- package/dist/hosted-tool-hints.d.ts.map +1 -0
- package/dist/hosted-tool-hints.js +105 -0
- package/dist/http.d.ts +11 -0
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +23 -10
- package/dist/index.d.ts +2 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +336 -3679
- package/dist/instruction-set-gepa-launch.d.ts +21 -2
- package/dist/instruction-set-gepa-launch.d.ts.map +1 -1
- package/dist/instruction-set-gepa-launch.js +123 -3
- package/dist/last-error-caps.d.ts +1 -0
- package/dist/last-error-caps.d.ts.map +1 -1
- package/dist/last-error-caps.js +1 -0
- package/dist/last-error-record.d.ts +3 -0
- package/dist/last-error-record.d.ts.map +1 -1
- package/dist/last-error-record.js +33 -6
- package/dist/model-config-fields.d.ts +2 -4
- package/dist/model-config-fields.d.ts.map +1 -1
- package/dist/model-config-fields.js +26 -9
- package/dist/model-config-price.d.ts +17 -0
- package/dist/model-config-price.d.ts.map +1 -0
- package/dist/model-config-price.js +42 -0
- package/dist/model-configs-cli.d.ts +2 -0
- package/dist/model-configs-cli.d.ts.map +1 -1
- package/dist/model-configs-cli.js +47 -4
- package/dist/optimization-export-cli.d.ts.map +1 -1
- package/dist/optimization-export-cli.js +19 -0
- package/dist/optimizations-promote-cli.d.ts.map +1 -1
- package/dist/optimizations-promote-cli.js +19 -0
- package/dist/preview-runtime.d.ts.map +1 -1
- package/dist/preview-runtime.js +11 -4
- package/dist/prompt-length-wire.d.ts +1 -1
- package/dist/prompt-length-wire.d.ts.map +1 -1
- package/dist/prompt-length-wire.js +1 -0
- package/dist/provider-lookup.d.ts +24 -0
- package/dist/provider-lookup.d.ts.map +1 -0
- package/dist/provider-lookup.js +43 -0
- package/dist/provider-probe.d.ts +24 -0
- package/dist/provider-probe.d.ts.map +1 -0
- package/dist/provider-probe.js +88 -0
- package/dist/provider-refusals.d.ts +83 -0
- package/dist/provider-refusals.d.ts.map +1 -0
- package/dist/provider-refusals.js +48 -0
- package/dist/provider-registry.d.ts +146 -0
- package/dist/provider-registry.d.ts.map +1 -0
- package/dist/provider-registry.js +155 -0
- package/dist/providers-cli.d.ts +3 -0
- package/dist/providers-cli.d.ts.map +1 -0
- package/dist/providers-cli.js +178 -0
- package/dist/runner-env-allowlist.d.ts +4 -0
- package/dist/runner-env-allowlist.d.ts.map +1 -0
- package/dist/runner-env-allowlist.js +36 -0
- package/dist/runner-env.d.ts +6 -2
- package/dist/runner-env.d.ts.map +1 -1
- package/dist/runner-env.js +44 -21
- package/dist/seed-against-production.d.ts +11 -0
- package/dist/seed-against-production.d.ts.map +1 -0
- package/dist/seed-against-production.js +1 -0
- package/dist/setup-and-skills-commands.d.ts +11 -0
- package/dist/setup-and-skills-commands.d.ts.map +1 -0
- package/dist/setup-and-skills-commands.js +1055 -0
- package/dist/task-commands.d.ts +13 -0
- package/dist/task-commands.d.ts.map +1 -0
- package/dist/task-commands.js +512 -0
- package/dist/workspace.d.ts +1 -0
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +11 -0
- package/package.json +1 -1
- package/src/account-directory.ts +751 -0
- package/src/app-commands.ts +520 -0
- package/src/auth-commands.ts +388 -0
- package/src/cli-console-output.ts +83 -0
- package/src/cli-project-slug.ts +15 -0
- package/src/command-line-arguments.ts +111 -0
- package/src/credentials.ts +41 -0
- package/src/dataset-commands.ts +863 -0
- package/src/dataset-download.ts +4 -3
- package/src/egress-policy.ts +19 -8
- package/src/feedback-cli.ts +22 -7
- package/src/feedback-contract.ts +21 -2
- package/src/feedback-scrub.ts +376 -43
- package/src/gepa-engine-dispatch.ts +34 -3
- package/src/global-flags.ts +8 -0
- package/src/help.ts +69 -2
- package/src/hosted-environment.ts +70 -0
- package/src/hosted-gepa-cli.ts +42 -6
- package/src/hosted-harness-claude.ts +13 -5
- package/src/hosted-harness-opencode.ts +52 -21
- package/src/hosted-harness.ts +32 -1
- package/src/hosted-optimization-refusals.ts +11 -3
- package/src/hosted-optimization.ts +42 -12
- package/src/hosted-provider-credentials.js +2 -0
- package/src/hosted-provider-credentials.ts +42 -0
- package/src/hosted-provider-settings.ts +21 -13
- package/src/hosted-tool-hints.ts +153 -0
- package/src/http.ts +35 -9
- package/src/index.ts +1077 -5332
- package/src/instruction-set-gepa-launch.ts +161 -3
- package/src/last-error-caps.ts +1 -0
- package/src/last-error-record.ts +40 -7
- package/src/model-config-fields.ts +29 -10
- package/src/model-config-price.js +2 -0
- package/src/model-config-price.ts +55 -0
- package/src/model-configs-cli.ts +41 -4
- package/src/optimization-export-cli.ts +23 -0
- package/src/optimizations-promote-cli.ts +20 -2
- package/src/preview-runtime.ts +11 -4
- package/src/prompt-length-wire.ts +1 -0
- package/src/provider-lookup.js +2 -0
- package/src/provider-lookup.ts +73 -0
- package/src/provider-probe.ts +101 -0
- package/src/provider-refusals.ts +53 -0
- package/src/provider-registry.js +4 -0
- package/src/provider-registry.ts +186 -0
- package/src/providers-cli.ts +153 -0
- package/src/runner-env-allowlist.js +4 -0
- package/src/runner-env-allowlist.ts +38 -0
- package/src/runner-env.js +4 -0
- package/src/runner-env.ts +49 -22
- package/src/seed-against-production.ts +10 -0
- package/src/setup-and-skills-commands.ts +1242 -0
- package/src/task-commands.ts +703 -0
- package/src/workspace.ts +11 -0
- package/vendor/orizu-gepa/pyproject.toml +7 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/callbacks.py +77 -39
- package/vendor/orizu-gepa/src/orizu_gepa_connector/providers.generated.json +32 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/reflection.py +5 -3
- package/vendor/orizu-gepa/src/orizu_gepa_connector/runtime.py +16 -2
- package/vendor/orizu-gepa/src/orizu_gepa_connector/skilled_proposer_bridge.py +14 -1
- package/vendor/orizu-gepa/src/orizu_gepa_connector/translator.py +91 -24
- package/vendor/orizu-gepa-python/pyproject.toml +7 -0
- package/vendor/orizu-gepa-python/src/orizu_gepa/local_log.py +3 -0
- package/vendor/orizu-gepa-python/src/orizu_gepa/providers.generated.json +32 -0
- package/vendor/orizu-gepa-python/src/orizu_gepa/providers.py +321 -0
- package/vendor/orizu-gepa-python/src/orizu_gepa/reflection.py +269 -89
- package/vendor/orizu-gepa-python/src/orizu_gepa/runner.py +40 -6
- package/vendor/skills/orizu/SKILL.md +22 -22
- package/vendor/skills/orizu/flows/promote.md +3 -3
- package/vendor/skills/orizu/flows/triage.md +5 -5
- package/vendor/skills/orizu/references/assess-and-plan.md +16 -16
- package/vendor/skills/orizu/references/building-apps.md +92 -92
- package/vendor/skills/orizu/references/building-judges.md +6 -6
- package/vendor/skills/orizu/references/cli-reference.md +19 -15
- package/vendor/skills/orizu/references/dataset-design.md +3 -3
- package/vendor/skills/orizu/references/eval-strategy.md +8 -8
- package/vendor/skills/orizu/references/feedback.md +21 -9
- package/vendor/skills/orizu/references/instructions-after-prompts.md +5 -5
- package/vendor/skills/orizu/references/migrate-existing-gepa-setup.md +16 -17
- package/vendor/skills/orizu/references/migrate-hand-rolled-instruction-layout.md +4 -4
- package/vendor/skills/orizu/references/optimization-reports.md +6 -6
- package/vendor/skills/orizu/references/optimization-with-gepa.md +42 -36
- package/vendor/skills/orizu/references/orizu-in-your-codebase.md +8 -8
- package/vendor/skills/orizu/references/primer.md +42 -42
- package/vendor/skills/orizu/references/prompt-control-plane.md +35 -30
- package/vendor/skills/orizu/references/vocabulary.md +18 -18
package/README.md
CHANGED
|
@@ -23,7 +23,13 @@ Note: the one task we do _not_ let you perform from your CLI is any reviews assi
|
|
|
23
23
|
- Access to an Orizu web app/API
|
|
24
24
|
- A valid Orizu account
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
The CLI talks to https://app.orizu.ai. If you previously signed in against orizu.ai, the CLI moves that sign-in over automatically the next time it runs. This also applies to www.orizu.ai and commands that explicitly select either old address. If a different sign-in is already saved for app.orizu.ai, the CLI stops without changing either one. Run `orizu --server https://app.orizu.ai logout` to remove the app sign-in, or `orizu --server https://app.orizu.ai login` to sign in again. Plain `orizu logout` removes the selected old sign-in instead.
|
|
27
|
+
|
|
28
|
+
### App-host login
|
|
29
|
+
|
|
30
|
+
Login accepts browser handoffs between `orizu.ai` and its subdomains over standard HTTPS. Custom and local servers still require an exact origin match. `--server`, `--local` and `ORIZU_BASE_URL` keep their priority. Custom, preview and local servers stay unchanged; `--no-prompt-if-logged-in` uses the migrated server.
|
|
31
|
+
|
|
32
|
+
If default app-host login fails, the CLI advises checking connectivity to app.orizu.ai and retrying login. It never tries the old address instead.
|
|
27
33
|
|
|
28
34
|
## Updating bundled GEPA
|
|
29
35
|
|
|
@@ -200,7 +206,7 @@ In a hosted session, a human curator using the local CLI must run create/push, a
|
|
|
200
206
|
orizu login
|
|
201
207
|
```
|
|
202
208
|
|
|
203
|
-
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.
|
|
209
|
+
This will open a browser tab for you to login with. You must either have an account on the [Orizu platform](https://app.orizu.ai) or it will help you create one.
|
|
204
210
|
Approving the login creates a personal access token for the CLI and stores it in your local Orizu credentials file. You can revoke CLI tokens from the Personal Tokens page in Orizu.
|
|
205
211
|
|
|
206
212
|
In an SSH or display-less Linux session, the CLI automatically prints an approval URL and polls for completion instead of opening a local browser. Force this mode when needed with:
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { type AuthenticatedRequestContext } from './http.js';
|
|
2
|
+
interface Team {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
slug: string;
|
|
6
|
+
role: string;
|
|
7
|
+
}
|
|
8
|
+
interface Project {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
slug: string;
|
|
12
|
+
teamId: string;
|
|
13
|
+
teamName: string;
|
|
14
|
+
teamSlug: string;
|
|
15
|
+
role: string;
|
|
16
|
+
}
|
|
17
|
+
interface Task {
|
|
18
|
+
id: string;
|
|
19
|
+
title: string;
|
|
20
|
+
status: string;
|
|
21
|
+
archiveStatus?: string;
|
|
22
|
+
archivedAt?: string | null;
|
|
23
|
+
createdAt: string;
|
|
24
|
+
projectName?: string;
|
|
25
|
+
projectSlug?: string;
|
|
26
|
+
teamName?: string;
|
|
27
|
+
teamSlug?: string;
|
|
28
|
+
}
|
|
29
|
+
interface AppSummary {
|
|
30
|
+
id: string;
|
|
31
|
+
name: string;
|
|
32
|
+
currentVersionNum: number;
|
|
33
|
+
createdAt: string;
|
|
34
|
+
teamSlug: string;
|
|
35
|
+
teamName: string;
|
|
36
|
+
projectSlug: string;
|
|
37
|
+
projectName: string;
|
|
38
|
+
status?: string;
|
|
39
|
+
archivedAt?: string | null;
|
|
40
|
+
}
|
|
41
|
+
interface DatasetSummary {
|
|
42
|
+
id: string;
|
|
43
|
+
name: string;
|
|
44
|
+
rowCount: number;
|
|
45
|
+
sourceType: string;
|
|
46
|
+
createdAt: string;
|
|
47
|
+
projectId: string;
|
|
48
|
+
projectName: string;
|
|
49
|
+
projectSlug: string;
|
|
50
|
+
teamName: string;
|
|
51
|
+
teamSlug: string;
|
|
52
|
+
status?: string;
|
|
53
|
+
archivedAt?: string | null;
|
|
54
|
+
}
|
|
55
|
+
interface DatasetSelection {
|
|
56
|
+
datasetId: string;
|
|
57
|
+
project?: string;
|
|
58
|
+
name?: string;
|
|
59
|
+
}
|
|
60
|
+
interface TaskStatusPayload {
|
|
61
|
+
task: {
|
|
62
|
+
id: string;
|
|
63
|
+
title: string;
|
|
64
|
+
status: string;
|
|
65
|
+
createdAt: string;
|
|
66
|
+
teamSlug: string;
|
|
67
|
+
teamName: string;
|
|
68
|
+
projectSlug: string;
|
|
69
|
+
projectName: string;
|
|
70
|
+
datasetRowCount: number;
|
|
71
|
+
requiredAssignmentsPerRow: number;
|
|
72
|
+
totalRequiredAssignments: number;
|
|
73
|
+
counts: {
|
|
74
|
+
completed: number;
|
|
75
|
+
inProgress: number;
|
|
76
|
+
pending: number;
|
|
77
|
+
skipped: number;
|
|
78
|
+
};
|
|
79
|
+
progressPercentage: number;
|
|
80
|
+
assignees: Array<{
|
|
81
|
+
assigneeId: string;
|
|
82
|
+
email: string;
|
|
83
|
+
completed: number;
|
|
84
|
+
inProgress: number;
|
|
85
|
+
pending: number;
|
|
86
|
+
skipped: number;
|
|
87
|
+
total: number;
|
|
88
|
+
}>;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
declare const TASK_STATUS_ACTION_LABELS: {
|
|
92
|
+
readonly paused: {
|
|
93
|
+
readonly verb: "pause";
|
|
94
|
+
readonly pastTense: "Paused";
|
|
95
|
+
};
|
|
96
|
+
readonly active: {
|
|
97
|
+
readonly verb: "unpause";
|
|
98
|
+
readonly pastTense: "Unpaused";
|
|
99
|
+
};
|
|
100
|
+
readonly completed: {
|
|
101
|
+
readonly verb: "complete";
|
|
102
|
+
readonly pastTense: "Completed";
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
type AuthenticatedRequest = AuthenticatedRequestContext['fetch'];
|
|
106
|
+
declare function fetchTeams(request?: AuthenticatedRequest): Promise<Team[]>;
|
|
107
|
+
declare function fetchProjects(teamSlug?: string, request?: AuthenticatedRequest): Promise<Project[]>;
|
|
108
|
+
declare function fetchTasks(project?: string, status?: string): Promise<Task[]>;
|
|
109
|
+
declare function fetchApps(project: string, status?: string): Promise<AppSummary[]>;
|
|
110
|
+
declare function fetchDatasets(project: string, status?: string): Promise<DatasetSummary[]>;
|
|
111
|
+
declare function createTeamOnServer(name: string, request?: AuthenticatedRequest): Promise<Team>;
|
|
112
|
+
declare function createProjectOnServer(teamSlug: string, name: string, request?: AuthenticatedRequest): Promise<Project>;
|
|
113
|
+
declare function resolveProjectSelection(projectArg: string | null): Promise<Project>;
|
|
114
|
+
declare function resolveProjectSlug(projectArg: string | null): Promise<string>;
|
|
115
|
+
declare function selectTaskIdInteractively(): Promise<string>;
|
|
116
|
+
declare function selectAppIdInteractively(projectArg: string | null): Promise<{
|
|
117
|
+
appId: string;
|
|
118
|
+
project: string;
|
|
119
|
+
}>;
|
|
120
|
+
declare function selectDatasetInteractively(projectArg: string | null): Promise<DatasetSelection>;
|
|
121
|
+
declare function printTaskStatusSummary(data: TaskStatusPayload): void;
|
|
122
|
+
declare function listTeams(): Promise<void>;
|
|
123
|
+
declare function createTeam(): Promise<void>;
|
|
124
|
+
declare function listProjects(): Promise<void>;
|
|
125
|
+
declare function createProject(): Promise<void>;
|
|
126
|
+
declare function listTeamMembers(): Promise<void>;
|
|
127
|
+
declare function addTeamMember(): Promise<void>;
|
|
128
|
+
declare function removeTeamMember(): Promise<void>;
|
|
129
|
+
declare function changeTeamMemberRole(): Promise<void>;
|
|
130
|
+
export { resolveProjectSlug, fetchDatasets, fetchTasks, fetchApps, createTeamOnServer, fetchTeams, fetchProjects, createProjectOnServer, selectAppIdInteractively, printTaskStatusSummary, TASK_STATUS_ACTION_LABELS, selectDatasetInteractively, selectTaskIdInteractively, listTeams, createTeam, listTeamMembers, addTeamMember, removeTeamMember, changeTeamMemberRole, listProjects, createProject, resolveProjectSelection, };
|
|
131
|
+
export type { Team, AuthenticatedRequest, Project, TaskStatusPayload, DatasetSelection };
|
|
132
|
+
//# sourceMappingURL=account-directory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-directory.d.ts","sourceRoot":"","sources":["../src/account-directory.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,2BAA2B,EAAe,MAAM,WAAW,CAAA;AAEzE,UAAU,IAAI;IACZ,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb;AAED,UAAU,OAAO;IACf,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;CACb;AAED,UAAU,IAAI;IACZ,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,UAAU,UAAU;IAClB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,iBAAiB,EAAE,MAAM,CAAA;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC3B;AAED,UAAU,cAAc;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC3B;AAED,UAAU,gBAAgB;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAUD,UAAU,iBAAiB;IACzB,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM,CAAA;QACV,KAAK,EAAE,MAAM,CAAA;QACb,MAAM,EAAE,MAAM,CAAA;QACd,SAAS,EAAE,MAAM,CAAA;QACjB,QAAQ,EAAE,MAAM,CAAA;QAChB,QAAQ,EAAE,MAAM,CAAA;QAChB,WAAW,EAAE,MAAM,CAAA;QACnB,WAAW,EAAE,MAAM,CAAA;QACnB,eAAe,EAAE,MAAM,CAAA;QACvB,yBAAyB,EAAE,MAAM,CAAA;QACjC,wBAAwB,EAAE,MAAM,CAAA;QAChC,MAAM,EAAE;YACN,SAAS,EAAE,MAAM,CAAA;YACjB,UAAU,EAAE,MAAM,CAAA;YAClB,OAAO,EAAE,MAAM,CAAA;YACf,OAAO,EAAE,MAAM,CAAA;SAChB,CAAA;QACD,kBAAkB,EAAE,MAAM,CAAA;QAC1B,SAAS,EAAE,KAAK,CAAC;YACf,UAAU,EAAE,MAAM,CAAA;YAClB,KAAK,EAAE,MAAM,CAAA;YACb,SAAS,EAAE,MAAM,CAAA;YACjB,UAAU,EAAE,MAAM,CAAA;YAClB,OAAO,EAAE,MAAM,CAAA;YACf,OAAO,EAAE,MAAM,CAAA;YACf,KAAK,EAAE,MAAM,CAAA;SACd,CAAC,CAAA;KACH,CAAA;CACF;AAED,QAAA,MAAM,yBAAyB;;;;;;;;;;;;;CAarB,CAAA;AA2CV,KAAK,oBAAoB,GAAG,2BAA2B,CAAC,OAAO,CAAC,CAAA;AAChE,iBAAe,UAAU,CAAC,OAAO,GAAE,oBAAkC,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAOtF;AAED,iBAAe,aAAa,CAC1B,QAAQ,CAAC,EAAE,MAAM,EACjB,OAAO,GAAE,oBAAkC,GAC1C,OAAO,CAAC,OAAO,EAAE,CAAC,CASpB;AAED,iBAAe,UAAU,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,SAAW,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAY9E;AAED,iBAAe,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAW,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAUlF;AAED,iBAAe,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAW,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAU1F;AAYD,iBAAe,kBAAkB,CAC/B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,oBAAkC,GAC1C,OAAO,CAAC,IAAI,CAAC,CAWf;AAED,iBAAe,qBAAqB,CAClC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,oBAAkC,GAC1C,OAAO,CAAC,OAAO,CAAC,CA6BlB;AAED,iBAAe,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAmElF;AAED,iBAAe,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAG5E;AAED,iBAAe,yBAAyB,IAAI,OAAO,CAAC,MAAM,CAAC,CAwB1D;AAED,iBAAe,wBAAwB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAkB9G;AAED,iBAAe,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAmB9F;AA2FD,iBAAS,sBAAsB,CAAC,IAAI,EAAE,iBAAiB,QAiBtD;AAED,iBAAe,SAAS,kBAOvB;AAiBD,iBAAe,UAAU,kBAsBxB;AAED,iBAAe,YAAY,kBAS1B;AAED,iBAAe,aAAa,kBAyB3B;AAED,iBAAe,eAAe,kBAQ7B;AAED,iBAAe,aAAa,kBAqB3B;AAED,iBAAe,gBAAgB,kBAyB9B;AAED,iBAAe,oBAAoB,kBAoClC;AAED,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,UAAU,EACV,SAAS,EACT,kBAAkB,EAClB,UAAU,EACV,aAAa,EACb,qBAAqB,EACrB,wBAAwB,EACxB,sBAAsB,EACtB,yBAAyB,EACzB,0BAA0B,EAC1B,yBAAyB,EACzB,SAAS,EACT,UAAU,EACV,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,YAAY,EACZ,aAAa,EACb,uBAAuB,GACxB,CAAA;AAED,YAAY,EAAE,IAAI,EAAE,oBAAoB,EAAE,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,CAAA"}
|
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
// ORI-2044: moved from index.ts to keep account directory together.
|
|
2
|
+
import { stdin as input, stdout as output } from 'process';
|
|
3
|
+
import { createInterface } from 'readline/promises';
|
|
4
|
+
import { isInteractiveTerminal, normalizeSlugInput, hasJsonFlag, getArg } from './command-line-arguments.js';
|
|
5
|
+
import { printLine, printError, printJson } from './cli-console-output.js';
|
|
6
|
+
import { sanitizeTerminalText, parseJsonResponse } from './json-response.js';
|
|
7
|
+
import { authedFetch } from './http.js';
|
|
8
|
+
const TASK_STATUS_ACTION_LABELS = {
|
|
9
|
+
paused: {
|
|
10
|
+
verb: 'pause',
|
|
11
|
+
pastTense: 'Paused',
|
|
12
|
+
},
|
|
13
|
+
active: {
|
|
14
|
+
verb: 'unpause',
|
|
15
|
+
pastTense: 'Unpaused',
|
|
16
|
+
},
|
|
17
|
+
completed: {
|
|
18
|
+
verb: 'complete',
|
|
19
|
+
pastTense: 'Completed',
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
async function promptSelect(title, items, label, options) {
|
|
23
|
+
if (items.length === 0) {
|
|
24
|
+
throw new Error(`No options available for ${title.toLowerCase()}`);
|
|
25
|
+
}
|
|
26
|
+
if (!isInteractiveTerminal()) {
|
|
27
|
+
throw new Error(`${title} selection requires interactive terminal. Provide flags explicitly instead.`);
|
|
28
|
+
}
|
|
29
|
+
if (items.length === 1 && !options?.forcePrompt) {
|
|
30
|
+
return items[0];
|
|
31
|
+
}
|
|
32
|
+
printLine(`\n${sanitizeTerminalText(title)}`);
|
|
33
|
+
items.forEach((item, index) => {
|
|
34
|
+
printLine(` ${index + 1}. ${sanitizeTerminalText(label(item, index))}`);
|
|
35
|
+
});
|
|
36
|
+
const rl = createInterface({ input, output });
|
|
37
|
+
try {
|
|
38
|
+
while (true) {
|
|
39
|
+
const answer = (await rl.question('Choose a number: ')).trim();
|
|
40
|
+
const chosenIndex = Number(answer);
|
|
41
|
+
if (Number.isInteger(chosenIndex) && chosenIndex >= 1 && chosenIndex <= items.length) {
|
|
42
|
+
return items[chosenIndex - 1];
|
|
43
|
+
}
|
|
44
|
+
printLine('Invalid selection. Enter a valid number from the list.');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
rl.close();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async function fetchTeams(request = authedFetch) {
|
|
52
|
+
const response = await request('/api/cli/teams');
|
|
53
|
+
if (!response.ok) {
|
|
54
|
+
throw new Error(`Failed to fetch teams: ${await response.text()}`);
|
|
55
|
+
}
|
|
56
|
+
const data = await parseJsonResponse(response, 'Teams list');
|
|
57
|
+
return data.teams;
|
|
58
|
+
}
|
|
59
|
+
async function fetchProjects(teamSlug, request = authedFetch) {
|
|
60
|
+
const normalizedTeamSlug = teamSlug ? normalizeSlugInput(teamSlug) : undefined;
|
|
61
|
+
const query = normalizedTeamSlug ? `?teamSlug=${encodeURIComponent(normalizedTeamSlug)}` : '';
|
|
62
|
+
const response = await request(`/api/cli/projects${query}`);
|
|
63
|
+
if (!response.ok) {
|
|
64
|
+
throw new Error(`Failed to fetch projects: ${await response.text()}`);
|
|
65
|
+
}
|
|
66
|
+
const data = await parseJsonResponse(response, 'Projects list');
|
|
67
|
+
return data.projects;
|
|
68
|
+
}
|
|
69
|
+
async function fetchTasks(project, status = 'active') {
|
|
70
|
+
const params = new URLSearchParams();
|
|
71
|
+
if (project)
|
|
72
|
+
params.set('project', project);
|
|
73
|
+
if (status !== 'active')
|
|
74
|
+
params.set('status', status);
|
|
75
|
+
const query = params.size > 0 ? `?${params.toString()}` : '';
|
|
76
|
+
const response = await authedFetch(`/api/cli/tasks${query}`);
|
|
77
|
+
if (!response.ok) {
|
|
78
|
+
throw new Error(`Failed to fetch tasks: ${await response.text()}`);
|
|
79
|
+
}
|
|
80
|
+
const data = await parseJsonResponse(response, 'Tasks list');
|
|
81
|
+
return data.tasks;
|
|
82
|
+
}
|
|
83
|
+
async function fetchApps(project, status = 'active') {
|
|
84
|
+
const params = new URLSearchParams({ project });
|
|
85
|
+
if (status !== 'active')
|
|
86
|
+
params.set('status', status);
|
|
87
|
+
const response = await authedFetch(`/api/cli/apps?${params.toString()}`);
|
|
88
|
+
if (!response.ok) {
|
|
89
|
+
throw new Error(`Failed to fetch apps: ${await response.text()}`);
|
|
90
|
+
}
|
|
91
|
+
const data = await parseJsonResponse(response, 'Apps list');
|
|
92
|
+
return data.apps;
|
|
93
|
+
}
|
|
94
|
+
async function fetchDatasets(project, status = 'active') {
|
|
95
|
+
const params = new URLSearchParams({ project });
|
|
96
|
+
if (status !== 'active')
|
|
97
|
+
params.set('status', status);
|
|
98
|
+
const response = await authedFetch(`/api/cli/datasets?${params.toString()}`);
|
|
99
|
+
if (!response.ok) {
|
|
100
|
+
throw new Error(`Failed to fetch datasets: ${await response.text()}`);
|
|
101
|
+
}
|
|
102
|
+
const data = await parseJsonResponse(response, 'Datasets list');
|
|
103
|
+
return data.datasets;
|
|
104
|
+
}
|
|
105
|
+
async function fetchTeamMembers(teamSlug) {
|
|
106
|
+
const response = await authedFetch(`/api/cli/teams/${encodeURIComponent(teamSlug)}/members`);
|
|
107
|
+
if (!response.ok) {
|
|
108
|
+
throw new Error(`Failed to fetch team members: ${await response.text()}`);
|
|
109
|
+
}
|
|
110
|
+
const data = await parseJsonResponse(response, 'Team members list');
|
|
111
|
+
return data.members;
|
|
112
|
+
}
|
|
113
|
+
async function createTeamOnServer(name, request = authedFetch) {
|
|
114
|
+
const response = await request('/api/cli/teams', {
|
|
115
|
+
method: 'POST',
|
|
116
|
+
headers: { 'Content-Type': 'application/json' },
|
|
117
|
+
body: JSON.stringify({ name }),
|
|
118
|
+
});
|
|
119
|
+
if (!response.ok) {
|
|
120
|
+
throw new Error(`Failed to create team: ${await response.text()}`);
|
|
121
|
+
}
|
|
122
|
+
const data = await parseJsonResponse(response, 'Team create');
|
|
123
|
+
return data.team;
|
|
124
|
+
}
|
|
125
|
+
async function createProjectOnServer(teamSlug, name, request = authedFetch) {
|
|
126
|
+
const response = await request('/api/cli/projects', {
|
|
127
|
+
method: 'POST',
|
|
128
|
+
headers: { 'Content-Type': 'application/json' },
|
|
129
|
+
body: JSON.stringify({ teamSlug, name }),
|
|
130
|
+
});
|
|
131
|
+
if (!response.ok) {
|
|
132
|
+
throw new Error(`Failed to create project: ${await response.text()}`);
|
|
133
|
+
}
|
|
134
|
+
const data = await parseJsonResponse(response, 'Project create');
|
|
135
|
+
return {
|
|
136
|
+
id: data.project.id,
|
|
137
|
+
name: data.project.name,
|
|
138
|
+
slug: data.project.slug,
|
|
139
|
+
teamId: data.project.teamId || '',
|
|
140
|
+
teamName: data.project.teamName || data.project.teamSlug,
|
|
141
|
+
teamSlug: data.project.teamSlug,
|
|
142
|
+
role: data.project.role || 'admin',
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
async function resolveProjectSelection(projectArg) {
|
|
146
|
+
projectArg = projectArg || process.env.ORIZU_PROJECT || null;
|
|
147
|
+
const teams = await fetchTeams();
|
|
148
|
+
if (teams.length === 0) {
|
|
149
|
+
throw new Error('No accessible teams found for this user.');
|
|
150
|
+
}
|
|
151
|
+
if (!projectArg) {
|
|
152
|
+
const team = await promptSelect('Select a team', teams, teamOption => `${teamOption.name} (${teamOption.slug})`, { forcePrompt: true });
|
|
153
|
+
const projects = await fetchProjects(team.slug);
|
|
154
|
+
const project = await promptSelect(`Select a project in ${team.slug}`, projects, projectOption => `${projectOption.name} (${projectOption.teamSlug}/${projectOption.slug})`, { forcePrompt: true });
|
|
155
|
+
return project;
|
|
156
|
+
}
|
|
157
|
+
const segments = projectArg.split('/');
|
|
158
|
+
if (segments.length !== 2 || !segments[0] || !segments[1]) {
|
|
159
|
+
throw new Error('Project must be in format teamSlug/projectSlug');
|
|
160
|
+
}
|
|
161
|
+
const [teamSlug, projectSlug] = segments.map(normalizeSlugInput);
|
|
162
|
+
const matchedTeam = teams.find(team => team.slug === teamSlug);
|
|
163
|
+
if (!matchedTeam) {
|
|
164
|
+
printError(`Team '${teamSlug}' not found in your accessible teams.`);
|
|
165
|
+
const selectedTeam = await promptSelect('Select a team', teams, team => `${team.name} (${team.slug})`);
|
|
166
|
+
const projects = await fetchProjects(selectedTeam.slug);
|
|
167
|
+
const selectedProject = await promptSelect(`Select a project in ${selectedTeam.slug}`, projects, project => `${project.name} (${project.teamSlug}/${project.slug})`);
|
|
168
|
+
return selectedProject;
|
|
169
|
+
}
|
|
170
|
+
const projects = await fetchProjects(matchedTeam.slug);
|
|
171
|
+
const matchedProject = projects.find(project => project.slug === projectSlug);
|
|
172
|
+
if (!matchedProject) {
|
|
173
|
+
printError(`Project '${projectSlug}' not found in team '${matchedTeam.slug}'.`);
|
|
174
|
+
const selectedProject = await promptSelect(`Select a project in ${matchedTeam.slug}`, projects, project => `${project.name} (${project.teamSlug}/${project.slug})`);
|
|
175
|
+
return selectedProject;
|
|
176
|
+
}
|
|
177
|
+
return matchedProject;
|
|
178
|
+
}
|
|
179
|
+
async function resolveProjectSlug(projectArg) {
|
|
180
|
+
const project = await resolveProjectSelection(projectArg);
|
|
181
|
+
return `${project.teamSlug}/${project.slug}`;
|
|
182
|
+
}
|
|
183
|
+
async function selectTaskIdInteractively() {
|
|
184
|
+
const team = await promptSelect('Select a team', await fetchTeams(), item => `${item.name} (${item.slug})`, { forcePrompt: true });
|
|
185
|
+
const project = await promptSelect(`Select a project in ${team.slug}`, await fetchProjects(team.slug), item => `${item.name} (${item.teamSlug}/${item.slug})`, { forcePrompt: true });
|
|
186
|
+
const tasks = await fetchTasks(`${project.teamSlug}/${project.slug}`);
|
|
187
|
+
const task = await promptSelect(`Select a task in ${project.teamSlug}/${project.slug}`, tasks, item => `${item.title} [${item.status}] (${item.id})`, { forcePrompt: true });
|
|
188
|
+
return task.id;
|
|
189
|
+
}
|
|
190
|
+
async function selectAppIdInteractively(projectArg) {
|
|
191
|
+
let project = projectArg;
|
|
192
|
+
if (!project) {
|
|
193
|
+
project = await resolveProjectSlug(null);
|
|
194
|
+
}
|
|
195
|
+
const apps = await fetchApps(project);
|
|
196
|
+
const app = await promptSelect(`Select an app in ${project}`, apps, item => `${item.name} (id=${item.id}, v${item.currentVersionNum})`, { forcePrompt: true });
|
|
197
|
+
return {
|
|
198
|
+
appId: app.id,
|
|
199
|
+
project,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
async function selectDatasetInteractively(projectArg) {
|
|
203
|
+
let project = projectArg;
|
|
204
|
+
if (!project) {
|
|
205
|
+
project = await resolveProjectSlug(null);
|
|
206
|
+
}
|
|
207
|
+
const datasets = await fetchDatasets(project);
|
|
208
|
+
const dataset = await promptSelect(`Select a dataset in ${project}`, datasets, item => `${item.name} (id=${item.id}, rows=${item.rowCount})`, { forcePrompt: true });
|
|
209
|
+
return {
|
|
210
|
+
datasetId: dataset.id,
|
|
211
|
+
project,
|
|
212
|
+
name: dataset.name,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
function printTeams(teams) {
|
|
216
|
+
if (teams.length === 0) {
|
|
217
|
+
printLine('No teams found.');
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
const rows = teams.map(team => ({
|
|
221
|
+
slug: sanitizeTerminalText(team.slug),
|
|
222
|
+
name: sanitizeTerminalText(team.name || '-'),
|
|
223
|
+
role: sanitizeTerminalText(team.role || '-'),
|
|
224
|
+
}));
|
|
225
|
+
const slugWidth = Math.max('TEAM SLUG'.length, ...rows.map(row => row.slug.length));
|
|
226
|
+
const nameWidth = Math.max('TEAM NAME'.length, ...rows.map(row => row.name.length));
|
|
227
|
+
const roleWidth = Math.max('ROLE'.length, ...rows.map(row => row.role.length));
|
|
228
|
+
printLine(`${'TEAM SLUG'.padEnd(slugWidth)} ${'TEAM NAME'.padEnd(nameWidth)} ${'ROLE'.padEnd(roleWidth)}`);
|
|
229
|
+
printLine(`${'-'.repeat(slugWidth)} ${'-'.repeat(nameWidth)} ${'-'.repeat(roleWidth)}`);
|
|
230
|
+
rows.forEach(row => {
|
|
231
|
+
printLine(`${row.slug.padEnd(slugWidth)} ${row.name.padEnd(nameWidth)} ${row.role.padEnd(roleWidth)}`);
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
function printProjects(projects) {
|
|
235
|
+
if (projects.length === 0) {
|
|
236
|
+
printLine('No projects found.');
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
const rows = projects.map(project => ({
|
|
240
|
+
project: sanitizeTerminalText(`${project.teamSlug}/${project.slug}`),
|
|
241
|
+
name: sanitizeTerminalText(project.name || '-'),
|
|
242
|
+
role: sanitizeTerminalText(project.role || '-'),
|
|
243
|
+
}));
|
|
244
|
+
const projectWidth = Math.max('TEAM/PROJECT'.length, ...rows.map(row => row.project.length));
|
|
245
|
+
const nameWidth = Math.max('PROJECT NAME'.length, ...rows.map(row => row.name.length));
|
|
246
|
+
const roleWidth = Math.max('ROLE'.length, ...rows.map(row => row.role.length));
|
|
247
|
+
printLine(`${'TEAM/PROJECT'.padEnd(projectWidth)} ${'PROJECT NAME'.padEnd(nameWidth)} ${'ROLE'.padEnd(roleWidth)}`);
|
|
248
|
+
printLine(`${'-'.repeat(projectWidth)} ${'-'.repeat(nameWidth)} ${'-'.repeat(roleWidth)}`);
|
|
249
|
+
rows.forEach(row => {
|
|
250
|
+
printLine(`${row.project.padEnd(projectWidth)} ${row.name.padEnd(nameWidth)} ${row.role.padEnd(roleWidth)}`);
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
function printTeamMembers(members) {
|
|
254
|
+
if (members.length === 0) {
|
|
255
|
+
printLine('No team members found.');
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
const rows = members.map(member => ({
|
|
259
|
+
id: sanitizeTerminalText(member.id),
|
|
260
|
+
userId: sanitizeTerminalText(member.user_id || '-'),
|
|
261
|
+
email: sanitizeTerminalText(member.email || '-'),
|
|
262
|
+
role: sanitizeTerminalText(member.role || '-'),
|
|
263
|
+
}));
|
|
264
|
+
const idWidth = Math.max('MEMBER ID'.length, ...rows.map(row => row.id.length));
|
|
265
|
+
const userIdWidth = Math.max('USER ID'.length, ...rows.map(row => row.userId.length));
|
|
266
|
+
const emailWidth = Math.max('EMAIL'.length, ...rows.map(row => row.email.length));
|
|
267
|
+
const roleWidth = Math.max('ROLE'.length, ...rows.map(row => row.role.length));
|
|
268
|
+
printLine(`${'MEMBER ID'.padEnd(idWidth)} ${'USER ID'.padEnd(userIdWidth)} ${'EMAIL'.padEnd(emailWidth)} ${'ROLE'.padEnd(roleWidth)}`);
|
|
269
|
+
printLine(`${'-'.repeat(idWidth)} ${'-'.repeat(userIdWidth)} ${'-'.repeat(emailWidth)} ${'-'.repeat(roleWidth)}`);
|
|
270
|
+
rows.forEach(row => {
|
|
271
|
+
printLine(`${row.id.padEnd(idWidth)} ${row.userId.padEnd(userIdWidth)} ${row.email.padEnd(emailWidth)} ${row.role.padEnd(roleWidth)}`);
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
function printTaskStatusSummary(data) {
|
|
275
|
+
const task = data.task;
|
|
276
|
+
printLine(`Task: ${sanitizeTerminalText(task.title)} (${sanitizeTerminalText(task.id)})`);
|
|
277
|
+
printLine(`Status: ${sanitizeTerminalText(task.status)}`);
|
|
278
|
+
printLine(`Project: ${sanitizeTerminalText(`${task.teamSlug}/${task.projectSlug}`)}`);
|
|
279
|
+
printLine(`Progress: ${task.progressPercentage}%`);
|
|
280
|
+
printLine(`Counts: completed=${task.counts.completed}, in_progress=${task.counts.inProgress}, pending=${task.counts.pending}, skipped=${task.counts.skipped}`);
|
|
281
|
+
printLine(`Required assignments: ${task.totalRequiredAssignments} (${task.datasetRowCount} rows x ${task.requiredAssignmentsPerRow})`);
|
|
282
|
+
if (task.assignees.length > 0) {
|
|
283
|
+
printLine('\nAssignees');
|
|
284
|
+
task.assignees.forEach(assignee => {
|
|
285
|
+
printLine(` ${sanitizeTerminalText(assignee.email)}: total=${assignee.total}, completed=${assignee.completed}, in_progress=${assignee.inProgress}, pending=${assignee.pending}, skipped=${assignee.skipped}`);
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
async function listTeams() {
|
|
290
|
+
const teams = await fetchTeams();
|
|
291
|
+
if (hasJsonFlag()) {
|
|
292
|
+
printJson({ teams });
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
printTeams(teams);
|
|
296
|
+
}
|
|
297
|
+
async function resolveTeamSlug(teamSlugArg) {
|
|
298
|
+
if (teamSlugArg) {
|
|
299
|
+
return normalizeSlugInput(teamSlugArg);
|
|
300
|
+
}
|
|
301
|
+
const team = await promptSelect('Select a team', await fetchTeams(), item => `${item.name} (${item.slug})`, { forcePrompt: true });
|
|
302
|
+
return team.slug;
|
|
303
|
+
}
|
|
304
|
+
async function createTeam() {
|
|
305
|
+
let name = getArg('--name');
|
|
306
|
+
if (!name && isInteractiveTerminal()) {
|
|
307
|
+
const rl = createInterface({ input, output });
|
|
308
|
+
try {
|
|
309
|
+
name = (await rl.question('Team name: ')).trim();
|
|
310
|
+
}
|
|
311
|
+
finally {
|
|
312
|
+
rl.close();
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
if (!name) {
|
|
316
|
+
throw new Error('Usage: orizu teams create --name <name>');
|
|
317
|
+
}
|
|
318
|
+
const team = await createTeamOnServer(name);
|
|
319
|
+
if (hasJsonFlag()) {
|
|
320
|
+
printJson({ team });
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
printLine(`Created team: ${sanitizeTerminalText(team.name)} (${sanitizeTerminalText(team.slug)})`);
|
|
324
|
+
}
|
|
325
|
+
async function listProjects() {
|
|
326
|
+
const teamSlugArg = getArg('--team');
|
|
327
|
+
const teamSlug = teamSlugArg ? normalizeSlugInput(teamSlugArg) : null;
|
|
328
|
+
const projects = await fetchProjects(teamSlug || undefined);
|
|
329
|
+
if (hasJsonFlag()) {
|
|
330
|
+
printJson({ projects });
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
printProjects(projects);
|
|
334
|
+
}
|
|
335
|
+
async function createProject() {
|
|
336
|
+
const name = getArg('--name');
|
|
337
|
+
const teamSlugArg = getArg('--team');
|
|
338
|
+
let teamSlug = teamSlugArg ? normalizeSlugInput(teamSlugArg) : null;
|
|
339
|
+
if (!name) {
|
|
340
|
+
throw new Error('Usage: orizu projects create --name <name> [--team <teamSlug>]');
|
|
341
|
+
}
|
|
342
|
+
if (!teamSlug) {
|
|
343
|
+
const team = await promptSelect('Select a team', await fetchTeams(), item => `${item.name} (${item.slug})`, { forcePrompt: true });
|
|
344
|
+
teamSlug = team.slug;
|
|
345
|
+
}
|
|
346
|
+
const project = await createProjectOnServer(teamSlug, name);
|
|
347
|
+
if (hasJsonFlag()) {
|
|
348
|
+
printJson({ project });
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
printLine(`Created project ${sanitizeTerminalText(`${project.teamSlug}/${project.slug}`)}`);
|
|
352
|
+
}
|
|
353
|
+
async function listTeamMembers() {
|
|
354
|
+
const teamSlug = await resolveTeamSlug(getArg('--team'));
|
|
355
|
+
const members = await fetchTeamMembers(teamSlug);
|
|
356
|
+
if (hasJsonFlag()) {
|
|
357
|
+
printJson({ team: teamSlug, members });
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
printTeamMembers(members);
|
|
361
|
+
}
|
|
362
|
+
async function addTeamMember() {
|
|
363
|
+
const teamSlug = await resolveTeamSlug(getArg('--team'));
|
|
364
|
+
const email = getArg('--email');
|
|
365
|
+
if (!email) {
|
|
366
|
+
throw new Error('Usage: orizu teams members add --email <email> [--team <teamSlug>]');
|
|
367
|
+
}
|
|
368
|
+
const response = await authedFetch(`/api/cli/teams/${encodeURIComponent(teamSlug)}/members`, {
|
|
369
|
+
method: 'POST',
|
|
370
|
+
headers: { 'Content-Type': 'application/json' },
|
|
371
|
+
body: JSON.stringify({ email }),
|
|
372
|
+
});
|
|
373
|
+
if (!response.ok) {
|
|
374
|
+
throw new Error(`Failed to add team member: ${await response.text()}`);
|
|
375
|
+
}
|
|
376
|
+
const data = await parseJsonResponse(response, 'Team member add');
|
|
377
|
+
if (hasJsonFlag()) {
|
|
378
|
+
printJson({ member: data.member });
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
printLine(`Added team member ${sanitizeTerminalText(data.member.email)} (${sanitizeTerminalText(data.member.id)})`);
|
|
382
|
+
}
|
|
383
|
+
async function removeTeamMember() {
|
|
384
|
+
const teamSlug = await resolveTeamSlug(getArg('--team'));
|
|
385
|
+
const email = getArg('--email');
|
|
386
|
+
if (!email) {
|
|
387
|
+
throw new Error('Usage: orizu teams members remove --email <email> [--team <teamSlug>]');
|
|
388
|
+
}
|
|
389
|
+
const members = await fetchTeamMembers(teamSlug);
|
|
390
|
+
const member = members.find(item => item.email.toLowerCase() === email.toLowerCase());
|
|
391
|
+
if (!member) {
|
|
392
|
+
throw new Error(`No member found with email '${email}' in team '${teamSlug}'`);
|
|
393
|
+
}
|
|
394
|
+
const response = await authedFetch(`/api/cli/teams/${encodeURIComponent(teamSlug)}/members/${encodeURIComponent(member.id)}`, { method: 'DELETE' });
|
|
395
|
+
if (!response.ok) {
|
|
396
|
+
throw new Error(`Failed to remove team member: ${await response.text()}`);
|
|
397
|
+
}
|
|
398
|
+
if (hasJsonFlag()) {
|
|
399
|
+
printJson({ removed: { id: member.id, email: member.email } });
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
printLine(`Removed team member ${sanitizeTerminalText(member.email)}`);
|
|
403
|
+
}
|
|
404
|
+
async function changeTeamMemberRole() {
|
|
405
|
+
const teamSlugArg = getArg('--team');
|
|
406
|
+
const teamSlug = teamSlugArg ? normalizeSlugInput(teamSlugArg) : null;
|
|
407
|
+
const email = getArg('--email');
|
|
408
|
+
const role = getArg('--role');
|
|
409
|
+
if (!teamSlug || !email || !role) {
|
|
410
|
+
throw new Error('Usage: orizu teams members role --team <teamSlug> --email <email> --role <admin|curator|judge>');
|
|
411
|
+
}
|
|
412
|
+
if (!['admin', 'curator', 'judge'].includes(role)) {
|
|
413
|
+
throw new Error('role must be one of: admin, curator, judge');
|
|
414
|
+
}
|
|
415
|
+
const members = await fetchTeamMembers(teamSlug);
|
|
416
|
+
const member = members.find(item => item.email.toLowerCase() === email.toLowerCase());
|
|
417
|
+
if (!member) {
|
|
418
|
+
throw new Error(`No member found with email '${email}' in team '${teamSlug}'`);
|
|
419
|
+
}
|
|
420
|
+
const response = await authedFetch(`/api/cli/teams/${encodeURIComponent(teamSlug)}/members/${encodeURIComponent(member.id)}`, {
|
|
421
|
+
method: 'PATCH',
|
|
422
|
+
headers: { 'Content-Type': 'application/json' },
|
|
423
|
+
body: JSON.stringify({ role }),
|
|
424
|
+
});
|
|
425
|
+
if (!response.ok) {
|
|
426
|
+
throw new Error(`Failed to update member role: ${await response.text()}`);
|
|
427
|
+
}
|
|
428
|
+
if (hasJsonFlag()) {
|
|
429
|
+
printJson({ member: { id: member.id, email: member.email, role } });
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
printLine(`Updated ${sanitizeTerminalText(member.email)} role to ${sanitizeTerminalText(role)}`);
|
|
433
|
+
}
|
|
434
|
+
export { resolveProjectSlug, fetchDatasets, fetchTasks, fetchApps, createTeamOnServer, fetchTeams, fetchProjects, createProjectOnServer, selectAppIdInteractively, printTaskStatusSummary, TASK_STATUS_ACTION_LABELS, selectDatasetInteractively, selectTaskIdInteractively, listTeams, createTeam, listTeamMembers, addTeamMember, removeTeamMember, changeTeamMemberRole, listProjects, createProject, resolveProjectSelection, };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
declare function listApps(): Promise<void>;
|
|
2
|
+
declare function readSourceFile(pathArg: string): string;
|
|
3
|
+
declare function readSourceBytes(pathArg: string): Buffer;
|
|
4
|
+
declare function readJsonFile(pathArg: string): Record<string, unknown>;
|
|
5
|
+
declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
6
|
+
declare function stringFromRecord(record: Record<string, unknown>, key: string): string | undefined;
|
|
7
|
+
declare function safeRelativePath(value: string, fallback: string): string;
|
|
8
|
+
declare function sha256Hex(value: string | Buffer): string;
|
|
9
|
+
declare function readPromptPrimaryText(manifest: Record<string, unknown>, promptDir: string): {
|
|
10
|
+
body: string;
|
|
11
|
+
bodyKind: string;
|
|
12
|
+
path: string;
|
|
13
|
+
};
|
|
14
|
+
declare function readPromptSidecars(manifest: Record<string, unknown>, promptDir: string): {
|
|
15
|
+
type: string;
|
|
16
|
+
path: string;
|
|
17
|
+
content: string;
|
|
18
|
+
contentSha256: string;
|
|
19
|
+
}[];
|
|
20
|
+
declare function writeTextFileEnsuringDir(pathArg: string, content: string): void;
|
|
21
|
+
declare function readManifestFile(dirArg: string): Record<string, unknown>;
|
|
22
|
+
declare function createAppFromFile(): Promise<void>;
|
|
23
|
+
declare function previewAppFromFile(): Promise<void>;
|
|
24
|
+
declare function updateAppFromFile(): Promise<void>;
|
|
25
|
+
declare function linkAppDataset(): Promise<void>;
|
|
26
|
+
declare function appDetail(): Promise<void>;
|
|
27
|
+
declare function exportAppSource(): Promise<void>;
|
|
28
|
+
export { readSourceFile, readJsonFile, readManifestFile, readPromptPrimaryText, readPromptSidecars, stringFromRecord, isRecord, safeRelativePath, writeTextFileEnsuringDir, sha256Hex, readSourceBytes, listApps, createAppFromFile, previewAppFromFile, updateAppFromFile, linkAppDataset, appDetail, exportAppSource, };
|
|
29
|
+
//# sourceMappingURL=app-commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-commands.d.ts","sourceRoot":"","sources":["../src/app-commands.ts"],"names":[],"mappings":"AAgCA,iBAAe,QAAQ,kBAQtB;AAED,iBAAS,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAU/C;AAED,iBAAS,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAUhD;AAED,iBAAS,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAY9D;AAED,iBAAS,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAElE;AAED,iBAAS,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG1F;AAED,iBAAS,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUjE;AAED,iBAAS,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAEjD;AAED,iBAAS,qBAAqB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG;IACpF,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;CACb,CAeA;AAED,iBAAS,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,MAAM;;;;;IAoB/E;AAED,iBAAS,wBAAwB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,QAGjE;AAED,iBAAS,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEjE;AAED,iBAAe,iBAAiB,kBAiD/B;AAED,iBAAe,kBAAkB,kBAiDhC;AAED,iBAAe,iBAAiB,kBA+C/B;AAED,iBAAe,cAAc,kBAgD5B;AA+CD,iBAAe,SAAS,kBA2CvB;AAED,iBAAe,eAAe,kBAkD7B;AAED,OAAO,EACL,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,EAChB,QAAQ,EACR,gBAAgB,EAChB,wBAAwB,EACxB,SAAS,EACT,eAAe,EACf,QAAQ,EACR,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,SAAS,EACT,eAAe,GAChB,CAAA"}
|