@reximo/cli 0.1.0-alpha.2 → 0.1.0-alpha.4

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 CHANGED
@@ -20,8 +20,15 @@ For a project-local install, use `npx reximo`, `npm exec reximo`, or `./node_mod
20
20
  ## Local usage
21
21
 
22
22
  ```bash
23
- pnpm reximo:cli:dev -- hello
24
23
  pnpm reximo:cli:dev -- info --json
24
+ pnpm reximo:cli:dev -- login --email user@example.com --password 'secret' --organization-id 123
25
+ pnpm reximo:cli:dev -- issues search --search restore --page-size 10
26
+ pnpm reximo:cli:dev -- issues create --title "Restore CLI issue workflow" --project-id 34
27
+ pnpm reximo:cli:dev -- issues update 77 --priority high --clear-due-at
28
+ pnpm reximo:cli:dev -- issues delete 77
29
+ pnpm reximo:cli:dev -- projects list --visibility public
30
+ pnpm reximo:cli:dev -- me
31
+ pnpm reximo:cli:dev -- logout
25
32
  pnpm reximo:cli:build
26
33
  pnpm reximo:cli:pack
27
34
  ```
@@ -32,9 +39,19 @@ pnpm reximo:cli:pack
32
39
 
33
40
  ## Commands
34
41
 
35
- - `reximo hello`
36
- - `reximo hello --name <name>`
37
42
  - `reximo info`
43
+ - `reximo login`
44
+ - `reximo login --email <email> --password <password>`
45
+ - `reximo login --organization-id <organizationId>`
46
+ - `reximo me`
47
+ - `reximo profile`
48
+ - `reximo logout`
49
+ - `reximo issues search`
50
+ - `reximo issues list`
51
+ - `reximo issues create --title <title>`
52
+ - `reximo issues update <issueId>`
53
+ - `reximo issues delete <issueId>`
54
+ - `reximo projects list`
38
55
  - `reximo config show`
39
56
  - `reximo --help`
40
57
 
@@ -50,6 +67,8 @@ Supported environment variables:
50
67
 
51
68
  - `REXIMO_API_BASE_URL`
52
69
  - `REXIMO_TOKEN`
70
+ - `REXIMO_REFRESH_TOKEN`
71
+ - `REXIMO_ORGANIZATION_ID`
53
72
  - `REXIMO_PROFILE`
54
73
  - `REXIMO_CONFIG`
55
74
 
@@ -66,13 +85,113 @@ Example config file:
66
85
  "profile": "default",
67
86
  "profiles": {
68
87
  "default": {
69
- "apiBaseUrl": "https://api.reximo.example",
70
- "token": "redacted"
88
+ "apiBaseUrl": "https://api.reximo.app",
89
+ "accessToken": "redacted-access-token",
90
+ "refreshToken": "redacted-refresh-token",
91
+ "organizationId": "123"
71
92
  }
72
93
  }
73
94
  }
74
95
  ```
75
96
 
97
+ The CLI stores persisted auth state in `~/.reximo/config.json` by default. Environment variables still override the file at runtime.
98
+
99
+ `REXIMO_TOKEN` remains the access-token override for compatibility.
100
+
101
+ ## Login
102
+
103
+ `reximo login` supports both flag-driven and interactive use.
104
+
105
+ Flag-driven:
106
+
107
+ ```bash
108
+ reximo login --email user@example.com --password 'secret' --organization-id 123
109
+ ```
110
+
111
+ Interactive:
112
+
113
+ ```bash
114
+ reximo login
115
+ ```
116
+
117
+ Behavior:
118
+
119
+ - the CLI authenticates against `https://api.reximo.app/api/v1/auth/login` by default
120
+ - it persists the access token, refresh token, and selected organization ID to the active profile
121
+ - if multiple active organizations are available, it prompts for selection in an interactive terminal
122
+ - in non-interactive use, pass `--organization-id` when multiple organizations are possible
123
+
124
+ ## Issues
125
+
126
+ Authenticated issue commands require both an access token and an organization id in the active CLI profile or environment.
127
+
128
+ Search issues:
129
+
130
+ ```bash
131
+ reximo issues search --search restore --project-id 34 --status in_progress --page-size 25
132
+ reximo issues list --json
133
+ ```
134
+
135
+ Create an issue:
136
+
137
+ ```bash
138
+ reximo issues create \
139
+ --title "Restore CLI issue workflow" \
140
+ --description-markdown "Bring issue management to the CLI." \
141
+ --project-id 34 \
142
+ --status backlog \
143
+ --priority high
144
+ ```
145
+
146
+ Update an issue by numeric id:
147
+
148
+ ```bash
149
+ reximo issues update 77 --title "Restore CLI issue workflow" --priority low
150
+ reximo issues update 77 --clear-estimate --clear-due-at
151
+ ```
152
+
153
+ Delete an issue by numeric id:
154
+
155
+ ```bash
156
+ reximo issues delete 77
157
+ ```
158
+
159
+ Notes:
160
+
161
+ - `issues search` and `issues list` are the same command surface
162
+ - by default, `issues search` and `issues list` exclude issues with status `done`
163
+ - pass `--status done` or `--statuses ...` to override the default status filter
164
+ - `issues update` requires at least one update flag
165
+ - `issues create` requires `--title`
166
+ - `--json` is supported for scripting on all commands
167
+
168
+ ## Projects
169
+
170
+ `reximo projects list` returns projects visible to the current user in the configured organization.
171
+
172
+ Visibility behavior:
173
+
174
+ - public projects are listed for the organization
175
+ - private projects are listed only when the current user is a member
176
+
177
+ Examples:
178
+
179
+ ```bash
180
+ reximo projects list
181
+ reximo projects list --visibility private --page-size 50
182
+ reximo projects list --json
183
+ ```
184
+
185
+ ## Generated Client
186
+
187
+ The CLI API client is generated from the API OpenAPI spec emitted at `.agentic/docs/reference/api/openapi-v1.json`.
188
+
189
+ Regenerate it with:
190
+
191
+ ```bash
192
+ pnpm --dir packages/reximo-cli generate:client
193
+ ```
194
+
76
195
  ## Release checks
77
196
 
78
197
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reximo/cli",
3
- "version": "0.1.0-alpha.2",
3
+ "version": "0.1.0-alpha.4",
4
4
  "description": "Command-line interface for Reximo.",
5
5
  "type": "commonjs",
6
6
  "license": "ISC",
@@ -46,9 +46,10 @@
46
46
  "scripts": {
47
47
  "build": "pnpm -C ../.. exec nx build reximo-cli",
48
48
  "dev": "pnpm exec tsx src/cli.ts",
49
+ "generate:client": "pnpm -C ../.. docs:openapi && pnpm exec tsx scripts/generate-client.ts",
49
50
  "lint": "ESLINT_USE_FLAT_CONFIG=false pnpm exec eslint src --ext .ts",
50
51
  "pack:dry-run": "pnpm run build && cd ../../dist/packages/reximo-cli && npm pack --dry-run",
51
- "test": "pnpm exec tsx --test src/**/*.test.ts",
52
+ "test": "pnpm exec tsx --test src/run-cli.test.ts src/lib/config.test.ts",
52
53
  "typecheck": "tsc --noEmit",
53
54
  "verify": "pnpm run lint && pnpm run typecheck && pnpm run test"
54
55
  },
@@ -0,0 +1 @@
1
+ export { ReximoApiClient, ReximoApiError, type AuthenticatedRequestOptions, type BaseResponseDto, type CreateIssueRequest, type CreateIssueResponse, type DeleteIssueResponse, type GetMeOptions, type GetMeResponse, type GetMyOrganizationsResponse, type GetIssueResponse, type IssueDetailDto, type IssueListItemDto, type LoginOptions, type LoginRequest, type LoginResponse, type ListIssuesOptions, type ListIssuesResponse, type ListProjectsOptions, type ListProjectsResponse, type LogoutOptions, type LogoutResponse, type GetMyOrganizationsOptions, type RefreshTokenOptions, type RefreshTokenRequest, type RefreshTokenResponse, type ReximoApiClientOptions, type UpdateIssueRequest, type UpdateIssueResponse, type UserOrganizationDto } from './reximo-api-client.generated';
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ReximoApiError = exports.ReximoApiClient = void 0;
4
+ var reximo_api_client_generated_1 = require("./reximo-api-client.generated");
5
+ Object.defineProperty(exports, "ReximoApiClient", { enumerable: true, get: function () { return reximo_api_client_generated_1.ReximoApiClient; } });
6
+ Object.defineProperty(exports, "ReximoApiError", { enumerable: true, get: function () { return reximo_api_client_generated_1.ReximoApiError; } });
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/reximo-cli/src/client/generated/index.ts"],"names":[],"mappings":";;;AAAA,6EA+BuC;AA9BrC,8HAAA,eAAe,OAAA;AACf,6HAAA,cAAc,OAAA"}
@@ -0,0 +1,306 @@
1
+ /**
2
+ * Generated from .agentic/docs/reference/api/openapi-v1.json.
3
+ * Do not edit manually. Regenerate with:
4
+ * pnpm --dir packages/reximo-cli generate:client
5
+ */
6
+ export interface BaseResponseDto<T> {
7
+ data: T;
8
+ metadata?: {
9
+ timestamp?: string;
10
+ version?: string;
11
+ requestId?: string;
12
+ error?: Record<string, unknown>;
13
+ };
14
+ }
15
+ export interface LoginDto {
16
+ email: string;
17
+ password: string;
18
+ }
19
+ export interface RefreshTokenDto {
20
+ refreshToken: string;
21
+ }
22
+ export interface AuthResponseDto {
23
+ accessToken: string;
24
+ refreshToken: string;
25
+ idToken: string;
26
+ expiresIn: number;
27
+ refreshExpiresIn: number;
28
+ user: {
29
+ "userId"?: string;
30
+ "username"?: string;
31
+ "email"?: string;
32
+ "emailVerified"?: boolean;
33
+ "roles"?: Array<string>;
34
+ "permissions"?: Array<string>;
35
+ "tenantId"?: string;
36
+ };
37
+ isNewUser: boolean;
38
+ }
39
+ export interface UserOrganizationDto {
40
+ organizationId: string;
41
+ tenantId: string;
42
+ name: string;
43
+ displayName?: string;
44
+ slug: string;
45
+ role: string;
46
+ isDefault: boolean;
47
+ isActive: boolean;
48
+ }
49
+ export interface CreateIssueDto {
50
+ title: string;
51
+ descriptionMarkdown?: string;
52
+ status?: "backlog" | "in_progress" | "blocked" | "done";
53
+ statusDefinitionId?: number | null;
54
+ priority?: "urgent" | "high" | "medium" | "low";
55
+ projectId?: number;
56
+ parentIssueId?: number;
57
+ position?: number;
58
+ estimate?: number;
59
+ dueAt?: string;
60
+ }
61
+ export interface UpdateIssueDto {
62
+ title?: string;
63
+ descriptionMarkdown?: string;
64
+ status?: "backlog" | "in_progress" | "blocked" | "done";
65
+ statusDefinitionId?: number | null;
66
+ priority?: "urgent" | "high" | "medium" | "low";
67
+ parentIssueId?: number;
68
+ position?: number;
69
+ estimate?: number | null;
70
+ dueAt?: string | null;
71
+ baseRevision?: string;
72
+ }
73
+ export interface IssueListItemDto {
74
+ id: number;
75
+ organizationId: number;
76
+ projectId?: number | null;
77
+ project?: IssueProjectDto;
78
+ parentIssueId?: number | null;
79
+ parentIssue?: IssueParentSummaryDto;
80
+ issueNumber: number;
81
+ title: string;
82
+ descriptionMarkdown: string;
83
+ status: string;
84
+ statusDefinition: IssueStatusDefinitionDto;
85
+ priority: string;
86
+ position: number;
87
+ estimate?: number | null;
88
+ dueAt?: string | null;
89
+ resolvedAt?: Record<string, unknown> | null;
90
+ createdBy: number;
91
+ updatedBy: number;
92
+ createdAt: string;
93
+ updatedAt: string;
94
+ assignees: Array<IssueParticipantDto>;
95
+ labels: Array<IssueLabelDto>;
96
+ commentsCount: number;
97
+ attachmentsCount: number;
98
+ watchersCount: number;
99
+ subtaskCount: number;
100
+ completedSubtaskCount: number;
101
+ activity?: Array<IssueActivityDto>;
102
+ }
103
+ export interface IssueProjectDto {
104
+ id: number;
105
+ key: string;
106
+ name: string;
107
+ visibility: string;
108
+ }
109
+ export interface IssueParentSummaryDto {
110
+ id: number;
111
+ identifier: string;
112
+ title: string;
113
+ }
114
+ export interface IssueStatusDefinitionDto {
115
+ id?: number | null;
116
+ key: string;
117
+ name: string;
118
+ color?: string | null;
119
+ description?: string | null;
120
+ baseStatus: string;
121
+ projectId?: number | null;
122
+ position?: number | null;
123
+ }
124
+ export interface IssueParticipantDto {
125
+ userId: number;
126
+ displayName?: string | null;
127
+ photoUrl?: string | null;
128
+ }
129
+ export interface IssueLabelDto {
130
+ id: number;
131
+ name: string;
132
+ color?: string | null;
133
+ description?: string | null;
134
+ projectId?: number | null;
135
+ }
136
+ export interface IssueActivityDto {
137
+ id: number;
138
+ activityType: string;
139
+ actorUserId?: number | null;
140
+ actorDisplayName?: string | null;
141
+ actorPhotoUrl?: string | null;
142
+ metadata: Record<string, unknown>;
143
+ createdAt: string;
144
+ }
145
+ export interface IssueDetailDto {
146
+ id: number;
147
+ organizationId: number;
148
+ projectId?: number | null;
149
+ project?: IssueProjectDto;
150
+ parentIssueId?: number | null;
151
+ parentIssue?: IssueParentSummaryDto;
152
+ issueNumber: number;
153
+ title: string;
154
+ descriptionMarkdown: string;
155
+ status: string;
156
+ statusDefinition: IssueStatusDefinitionDto;
157
+ priority: string;
158
+ position: number;
159
+ estimate?: number | null;
160
+ dueAt?: string | null;
161
+ resolvedAt?: Record<string, unknown> | null;
162
+ createdBy: number;
163
+ updatedBy: number;
164
+ createdAt: string;
165
+ updatedAt: string;
166
+ assignees: Array<IssueParticipantDto>;
167
+ labels: Array<IssueLabelDto>;
168
+ commentsCount: number;
169
+ attachmentsCount: number;
170
+ watchersCount: number;
171
+ subtaskCount: number;
172
+ completedSubtaskCount: number;
173
+ activity?: Array<IssueActivityDto>;
174
+ watchers: Array<IssueParticipantDto>;
175
+ comments: Array<IssueCommentDto>;
176
+ relations: Array<IssueRelationDto>;
177
+ subtasks: Array<IssueListItemDto>;
178
+ }
179
+ export interface IssueCommentDto {
180
+ id: number;
181
+ authorUserId: number;
182
+ authorDisplayName?: string | null;
183
+ authorPhotoUrl?: string | null;
184
+ bodyMarkdown: string;
185
+ createdAt: string;
186
+ updatedAt: string;
187
+ }
188
+ export interface IssueRelationDto {
189
+ id: number;
190
+ relationType: string;
191
+ relatedIssueId: number;
192
+ relatedIssueTitle: string;
193
+ relatedIssueNumber: number;
194
+ }
195
+ export type LoginRequest = LoginDto;
196
+ export type LoginResponse = AuthResponseDto;
197
+ export type RefreshTokenRequest = RefreshTokenDto;
198
+ export type RefreshTokenResponse = AuthResponseDto;
199
+ export type GetMyOrganizationsResponse = BaseResponseDto<Array<UserOrganizationDto>>;
200
+ export type GetMeResponse = {
201
+ "data"?: {
202
+ "userId"?: string;
203
+ "tenantId"?: string;
204
+ "actorId"?: string;
205
+ "email"?: string;
206
+ "name"?: string;
207
+ "displayName"?: string;
208
+ "photoUrl"?: string;
209
+ "isActive"?: boolean;
210
+ "isVerified"?: boolean;
211
+ "emailVerified"?: boolean;
212
+ "roles"?: Array<string>;
213
+ "permissions"?: Array<string>;
214
+ };
215
+ "metadata"?: {
216
+ "timestamp"?: string;
217
+ "version"?: string;
218
+ };
219
+ };
220
+ export type LogoutResponse = {
221
+ "message": string;
222
+ };
223
+ export type ListIssuesResponse = Array<IssueListItemDto>;
224
+ export type CreateIssueRequest = CreateIssueDto;
225
+ export type CreateIssueResponse = IssueDetailDto;
226
+ export type GetIssueResponse = IssueDetailDto;
227
+ export type UpdateIssueRequest = UpdateIssueDto;
228
+ export type UpdateIssueResponse = IssueDetailDto;
229
+ export type DeleteIssueResponse = void;
230
+ export type ListProjectsResponse = unknown;
231
+ export declare class ReximoApiError extends Error {
232
+ readonly status: number;
233
+ readonly body: unknown;
234
+ constructor(status: number, body: unknown, message: string);
235
+ }
236
+ export type ReximoApiClientOptions = {
237
+ baseUrl: string;
238
+ fetchFn?: typeof fetch;
239
+ };
240
+ export type LoginOptions = {
241
+ signal?: AbortSignal;
242
+ tenantId?: string | null;
243
+ };
244
+ export type GetMyOrganizationsOptions = {
245
+ signal?: AbortSignal;
246
+ accessToken: string;
247
+ tenantId?: string | null;
248
+ };
249
+ export type GetMeOptions = {
250
+ signal?: AbortSignal;
251
+ accessToken: string;
252
+ tenantId?: string | null;
253
+ };
254
+ export type RefreshTokenOptions = {
255
+ signal?: AbortSignal;
256
+ tenantId?: string | null;
257
+ };
258
+ export type LogoutOptions = {
259
+ signal?: AbortSignal;
260
+ accessToken: string;
261
+ tenantId: string;
262
+ };
263
+ export type AuthenticatedRequestOptions = {
264
+ signal?: AbortSignal;
265
+ accessToken: string;
266
+ tenantId?: string | null;
267
+ };
268
+ export type ListIssuesOptions = AuthenticatedRequestOptions & {
269
+ page?: number;
270
+ pageSize?: number;
271
+ projectId?: number;
272
+ labelId?: number;
273
+ assigneeUserId?: number;
274
+ watcherUserId?: number;
275
+ activityActorUserId?: number;
276
+ search?: string;
277
+ status?: 'backlog' | 'in_progress' | 'blocked' | 'done';
278
+ statuses?: Array<'backlog' | 'in_progress' | 'blocked' | 'done'>;
279
+ priority?: 'urgent' | 'high' | 'medium' | 'low';
280
+ sortBy?: 'updatedAt' | 'createdAt' | 'priority' | 'dueAt' | 'position';
281
+ sortOrder?: 'asc' | 'desc';
282
+ };
283
+ export type ListProjectsOptions = AuthenticatedRequestOptions & {
284
+ page?: number;
285
+ pageSize?: number;
286
+ search?: string;
287
+ visibility?: 'public' | 'private';
288
+ sortBy?: 'name' | 'createdAt' | 'updatedAt' | 'visibility';
289
+ sortOrder?: 'asc' | 'desc';
290
+ };
291
+ export declare class ReximoApiClient {
292
+ private readonly baseUrl;
293
+ private readonly fetchFn;
294
+ constructor(options: ReximoApiClientOptions);
295
+ login(body: LoginRequest, options?: LoginOptions): Promise<LoginResponse>;
296
+ getMyOrganizations(options: GetMyOrganizationsOptions): Promise<GetMyOrganizationsResponse>;
297
+ getMe(options: GetMeOptions): Promise<GetMeResponse>;
298
+ refreshToken(body: RefreshTokenRequest, options?: RefreshTokenOptions): Promise<RefreshTokenResponse>;
299
+ logout(body: RefreshTokenRequest, options: LogoutOptions): Promise<LogoutResponse>;
300
+ listIssues(options: ListIssuesOptions): Promise<ListIssuesResponse>;
301
+ createIssue(body: CreateIssueRequest, options: AuthenticatedRequestOptions): Promise<CreateIssueResponse>;
302
+ getIssue(issueId: string, options: AuthenticatedRequestOptions): Promise<GetIssueResponse>;
303
+ updateIssue(issueId: string, body: UpdateIssueRequest, options: AuthenticatedRequestOptions): Promise<UpdateIssueResponse>;
304
+ deleteIssue(issueId: string, options: AuthenticatedRequestOptions): Promise<void>;
305
+ listProjects(options: ListProjectsOptions): Promise<ListProjectsResponse>;
306
+ }