@revos/cli 0.1.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 +171 -0
- package/bin/revos.js +7 -0
- package/dist/adapters/oclif/commands/auth/login.d.mts +15 -0
- package/dist/adapters/oclif/commands/auth/login.mjs +69 -0
- package/dist/adapters/oclif/commands/auth/logout.d.mts +11 -0
- package/dist/adapters/oclif/commands/auth/logout.mjs +17 -0
- package/dist/adapters/oclif/commands/auth/status.d.mts +11 -0
- package/dist/adapters/oclif/commands/auth/status.mjs +58 -0
- package/dist/adapters/oclif/commands/init.d.mts +13 -0
- package/dist/adapters/oclif/commands/init.mjs +41 -0
- package/dist/adapters/oclif/commands/org/current.d.mts +15 -0
- package/dist/adapters/oclif/commands/org/current.mjs +45 -0
- package/dist/adapters/oclif/commands/org/list.d.mts +14 -0
- package/dist/adapters/oclif/commands/org/list.mjs +34 -0
- package/dist/adapters/oclif/commands/org/switch.d.mts +13 -0
- package/dist/adapters/oclif/commands/org/switch.mjs +33 -0
- package/dist/adapters/oclif/commands/overlays/diff.d.mts +19 -0
- package/dist/adapters/oclif/commands/overlays/diff.mjs +80 -0
- package/dist/adapters/oclif/commands/overlays/pull.d.mts +15 -0
- package/dist/adapters/oclif/commands/overlays/pull.mjs +44 -0
- package/dist/adapters/oclif/commands/overlays/push.d.mts +18 -0
- package/dist/adapters/oclif/commands/overlays/push.mjs +59 -0
- package/dist/adapters/oclif/commands/overlays/status.d.mts +18 -0
- package/dist/adapters/oclif/commands/overlays/status.mjs +53 -0
- package/dist/base.command-BGM225ik.mjs +62 -0
- package/dist/base.command-BjFWMIzL.d.mts +24 -0
- package/dist/core-Bif-kxlo.mjs +1060 -0
- package/dist/index-C0e8MXGP.d.mts +187 -0
- package/dist/index.d.mts +4 -0
- package/dist/index.mjs +2 -0
- package/dist/templates/AGENTS.md +23 -0
- package/dist/templates/CLAUDE.md +17 -0
- package/dist/templates/index.d.mts +4 -0
- package/dist/templates/index.mjs +6 -0
- package/dist/types-DZssnweO.d.mts +65 -0
- package/dist/types-DsQtGF-c.d.mts +56 -0
- package/package.json +73 -0
package/README.md
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# RevOS CLI
|
|
2
|
+
|
|
3
|
+
Command-line interface for managing RevOS resources.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @revos/cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
revos [command] [options]
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Global Options
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
-o, --org <id> Override organization ID for this command
|
|
21
|
+
--json Format output as JSON
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Commands
|
|
25
|
+
|
|
26
|
+
### Project Initialization
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
revos init [project-name]
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Scaffolds a new RevOS data engineering project. If `project-name` is omitted, uses the current directory name.
|
|
33
|
+
|
|
34
|
+
**What it does:**
|
|
35
|
+
|
|
36
|
+
1. Fetches your organizations and prompts you to select one (auto-selects if only one).
|
|
37
|
+
2. Provisions a GCP service account for your org (idempotent) and writes the key to `~/.revos/{project-name}-gsa-creds.json`.
|
|
38
|
+
3. Creates the project directory structure (medallion layout: bronze/silver/gold).
|
|
39
|
+
4. Generates `.devcontainer/devcontainer.json` with Python 3.11, Node.js, Google Cloud SDK (`bq`), and dbt pre-installed. The Dev Container mounts `~/.revos/{project-name}-gsa-creds.json` automatically.
|
|
40
|
+
5. Generates `dbt/profiles.yml` pre-configured for BigQuery.
|
|
41
|
+
6. Generates `.gitignore` and `README.md`.
|
|
42
|
+
7. Scaffolds AI companion files: `CLAUDE.md`, `AGENTS.md`, and `.claude/skills/`.
|
|
43
|
+
|
|
44
|
+
**Requires:** `revos auth login` first.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
### Authentication
|
|
49
|
+
|
|
50
|
+
#### Login
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
revos auth login
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
#### Logout
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
revos auth logout
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
#### Show auth status
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
revos auth status [--json]
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
### Organization Management
|
|
71
|
+
|
|
72
|
+
#### List organizations
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
revos org list [--columns name,id] [--json]
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
#### Show current organization
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
revos org current [--json]
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
#### Switch organization
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Interactive mode
|
|
88
|
+
revos org switch
|
|
89
|
+
|
|
90
|
+
# Direct by ID
|
|
91
|
+
revos org switch <org-id>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
### Overlays Management
|
|
97
|
+
|
|
98
|
+
Overlay files contain only Cube definition data (dimensions, measures, joins, etc.). The overlay name is derived from the filename (without `.json`). A `description` field in the file is synced with the overlay's description on push.
|
|
99
|
+
|
|
100
|
+
Example `my-overlay.json`:
|
|
101
|
+
|
|
102
|
+
```json
|
|
103
|
+
{
|
|
104
|
+
"description": "My custom overlay",
|
|
105
|
+
"sql_table": "my_table",
|
|
106
|
+
"dimensions": {
|
|
107
|
+
"id": { "sql": "id", "type": "number", "primary_key": true }
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
#### Push overlays to API
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
revos overlays push [files...] [-d <dir>] [-f] [--json]
|
|
116
|
+
|
|
117
|
+
Options:
|
|
118
|
+
-d, --dir <path> Directory containing overlay files (default: "./overlays")
|
|
119
|
+
-f, --force Force push even if remote is newer
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### Pull overlays from API
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
revos overlays pull [-d <dir>] [-n <name>...] [--json]
|
|
126
|
+
|
|
127
|
+
Options:
|
|
128
|
+
-d, --dir <path> Directory to save overlay files (default: "./overlays")
|
|
129
|
+
-n, --name <name> Specific overlay names to pull (repeatable)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
#### Show diff between local and remote
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
revos overlays diff [files...] [-d <dir>] [--json]
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
#### Check overlay status
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
revos overlays status [files...] [-d <dir>] [--columns name,status] [--json]
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Output Formats
|
|
147
|
+
|
|
148
|
+
Every command supports `--json` for machine-readable output:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
revos org list --json
|
|
152
|
+
revos auth status --json
|
|
153
|
+
revos overlays status --json
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
List commands support `--columns` to limit displayed columns:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
revos org list --columns name
|
|
160
|
+
revos overlays status --columns name,status
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Configuration
|
|
166
|
+
|
|
167
|
+
| Variable | Description |
|
|
168
|
+
| --------------- | -------------------------------------------------------- |
|
|
169
|
+
| `REVOS_TOKEN` | Authentication token (alternative to `revos auth login`) |
|
|
170
|
+
| `REVOS_API_URL` | API endpoint (default: `https://api.revos.ai`) |
|
|
171
|
+
| `REVOS_ORG_ID` | Organization ID override |
|
package/bin/revos.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { t as AuthResult } from "../../../../types-DsQtGF-c.mjs";
|
|
2
|
+
import { t as BaseCommand } from "../../../../base.command-BjFWMIzL.mjs";
|
|
3
|
+
import * as _$_oclif_core_interfaces0 from "@oclif/core/interfaces";
|
|
4
|
+
|
|
5
|
+
//#region src/adapters/oclif/commands/auth/login.d.ts
|
|
6
|
+
declare class AuthLogin extends BaseCommand<typeof AuthLogin> {
|
|
7
|
+
static description: string;
|
|
8
|
+
static flags: {
|
|
9
|
+
"clerk-domain": _$_oclif_core_interfaces0.OptionFlag<string | undefined, _$_oclif_core_interfaces0.CustomOptions>;
|
|
10
|
+
"clerk-client-id": _$_oclif_core_interfaces0.OptionFlag<string | undefined, _$_oclif_core_interfaces0.CustomOptions>;
|
|
11
|
+
};
|
|
12
|
+
run(): Promise<AuthResult>;
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { AuthLogin as default };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { A as getCredentialsPath, C as getUserInfo, D as tokenResponseToCredentials, N as saveCredentials, O as startOAuthServer, S as generatePKCEChallenge, T as setClerkConfig, b as buildAuthorizationUrl, m as unwrap, n as selectOrganization, p as createApiClient, x as exchangeCodeForTokens } from "../../../../core-Bif-kxlo.mjs";
|
|
2
|
+
import { t as BaseCommand } from "../../../../base.command-BGM225ik.mjs";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { Flags } from "@oclif/core";
|
|
5
|
+
import open from "open";
|
|
6
|
+
//#region src/adapters/oclif/commands/auth/login.ts
|
|
7
|
+
var AuthLogin = class extends BaseCommand {
|
|
8
|
+
static description = "Authenticate with RevOS via browser";
|
|
9
|
+
static flags = {
|
|
10
|
+
"clerk-domain": Flags.string({ description: "Custom Clerk domain URL" }),
|
|
11
|
+
"clerk-client-id": Flags.string({ description: "Custom Clerk OAuth client ID" })
|
|
12
|
+
};
|
|
13
|
+
async run() {
|
|
14
|
+
const { flags } = this;
|
|
15
|
+
if (flags["clerk-domain"] || flags["clerk-client-id"]) setClerkConfig({
|
|
16
|
+
clerkDomain: flags["clerk-domain"],
|
|
17
|
+
clerkClientId: flags["clerk-client-id"]
|
|
18
|
+
});
|
|
19
|
+
if (!this.jsonEnabled()) this.log("Starting authentication...\n");
|
|
20
|
+
const server = await startOAuthServer();
|
|
21
|
+
const redirectUri = `http://localhost:${server.port}/callback`;
|
|
22
|
+
const pkce = generatePKCEChallenge();
|
|
23
|
+
const authUrl = buildAuthorizationUrl(redirectUri, pkce);
|
|
24
|
+
if (!this.jsonEnabled()) {
|
|
25
|
+
this.log("Opening browser for authentication...");
|
|
26
|
+
this.log("If the browser doesn't open, visit this URL:\n");
|
|
27
|
+
this.log(` ${authUrl}\n`);
|
|
28
|
+
this.log("Waiting for authentication... (Press Ctrl+C to cancel)\n");
|
|
29
|
+
}
|
|
30
|
+
await open(authUrl);
|
|
31
|
+
const callbackResult = await server.waitForCallback();
|
|
32
|
+
if (callbackResult.state !== pkce.state) throw new Error("Invalid state parameter. Authentication may have been tampered with.");
|
|
33
|
+
if (!this.jsonEnabled()) this.log("Received authorization code, exchanging for tokens...\n");
|
|
34
|
+
const tokenResponse = await exchangeCodeForTokens(callbackResult.code, redirectUri, pkce.codeVerifier);
|
|
35
|
+
const userInfo = await getUserInfo(tokenResponse.access_token);
|
|
36
|
+
const credentials = tokenResponseToCredentials(tokenResponse, userInfo);
|
|
37
|
+
saveCredentials(credentials);
|
|
38
|
+
if (!this.jsonEnabled()) {
|
|
39
|
+
this.log(chalk.green(`\nAuthenticated as ${userInfo.email || userInfo.sub}`));
|
|
40
|
+
this.log(`\nCredentials saved to ${getCredentialsPath()}`);
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
const orgs = unwrap(await createApiClient({
|
|
44
|
+
apiUrl: process.env.REVOS_API_URL || "https://api.revos.ai",
|
|
45
|
+
token: tokenResponse.access_token
|
|
46
|
+
}).organizations.list());
|
|
47
|
+
if (orgs.length === 1) {
|
|
48
|
+
credentials.organizationId = orgs[0].id;
|
|
49
|
+
saveCredentials(credentials);
|
|
50
|
+
if (!this.jsonEnabled()) this.log(chalk.green(`\nAutomatically selected organization: ${orgs[0].name}`));
|
|
51
|
+
} else if (orgs.length > 1 && !this.jsonEnabled()) {
|
|
52
|
+
this.log(`\nYou belong to ${orgs.length} organizations.`);
|
|
53
|
+
const selected = await selectOrganization(orgs);
|
|
54
|
+
credentials.organizationId = selected.id;
|
|
55
|
+
saveCredentials(credentials);
|
|
56
|
+
this.log(chalk.green(`\nSelected organization: ${selected.name}`));
|
|
57
|
+
}
|
|
58
|
+
} catch {
|
|
59
|
+
if (!this.jsonEnabled()) this.log("\nRun 'revos org list' to see your organizations.");
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
success: true,
|
|
63
|
+
email: userInfo.email,
|
|
64
|
+
userId: userInfo.sub
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
//#endregion
|
|
69
|
+
export { AuthLogin as default };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { t as BaseCommand } from "../../../../base.command-BjFWMIzL.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/adapters/oclif/commands/auth/logout.d.ts
|
|
4
|
+
declare class AuthLogout extends BaseCommand<typeof AuthLogout> {
|
|
5
|
+
static description: string;
|
|
6
|
+
run(): Promise<{
|
|
7
|
+
deleted: boolean;
|
|
8
|
+
}>;
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
export { AuthLogout as default };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { k as deleteCredentials } from "../../../../core-Bif-kxlo.mjs";
|
|
2
|
+
import { t as BaseCommand } from "../../../../base.command-BGM225ik.mjs";
|
|
3
|
+
//#region src/adapters/oclif/commands/auth/logout.ts
|
|
4
|
+
var AuthLogout = class extends BaseCommand {
|
|
5
|
+
static description = "Remove stored authentication credentials";
|
|
6
|
+
async run() {
|
|
7
|
+
const deleted = deleteCredentials();
|
|
8
|
+
if (!this.jsonEnabled()) {
|
|
9
|
+
if (deleted) this.log("Logged out successfully. Credentials removed.");
|
|
10
|
+
else this.log("No stored credentials found.");
|
|
11
|
+
if (process.env.REVOS_TOKEN) this.warn("REVOS_TOKEN environment variable is still set. Unset it to fully log out:\n\n unset REVOS_TOKEN");
|
|
12
|
+
}
|
|
13
|
+
return { deleted };
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
//#endregion
|
|
17
|
+
export { AuthLogout as default };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { n as AuthStatusInfo } from "../../../../types-DsQtGF-c.mjs";
|
|
2
|
+
import { t as BaseCommand } from "../../../../base.command-BjFWMIzL.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/adapters/oclif/commands/auth/status.d.ts
|
|
5
|
+
declare class AuthStatus extends BaseCommand<typeof AuthStatus> {
|
|
6
|
+
static description: string;
|
|
7
|
+
run(): Promise<AuthStatusInfo>;
|
|
8
|
+
private renderStatus;
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
export { AuthStatus as default };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { A as getCredentialsPath, M as loadCredentials, j as isTokenExpired } from "../../../../core-Bif-kxlo.mjs";
|
|
2
|
+
import { t as BaseCommand } from "../../../../base.command-BGM225ik.mjs";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
//#region src/adapters/oclif/commands/auth/status.ts
|
|
5
|
+
var AuthStatus = class extends BaseCommand {
|
|
6
|
+
static description = "Show current authentication status";
|
|
7
|
+
async run() {
|
|
8
|
+
const envToken = process.env.REVOS_TOKEN;
|
|
9
|
+
const storedCredentials = loadCredentials();
|
|
10
|
+
let status;
|
|
11
|
+
if (envToken) status = {
|
|
12
|
+
authenticated: true,
|
|
13
|
+
source: "env"
|
|
14
|
+
};
|
|
15
|
+
else if (storedCredentials) {
|
|
16
|
+
const expired = isTokenExpired(storedCredentials);
|
|
17
|
+
status = {
|
|
18
|
+
authenticated: !expired,
|
|
19
|
+
source: "stored",
|
|
20
|
+
email: storedCredentials.email,
|
|
21
|
+
userId: storedCredentials.userId,
|
|
22
|
+
expiresAt: storedCredentials.expiresAt ? new Date(storedCredentials.expiresAt) : void 0,
|
|
23
|
+
credentialsPath: getCredentialsPath(),
|
|
24
|
+
organizationId: storedCredentials.organizationId
|
|
25
|
+
};
|
|
26
|
+
if (!this.jsonEnabled() && expired) this.warn("Token has expired. Please run 'revos auth login' to re-authenticate.");
|
|
27
|
+
} else status = { authenticated: false };
|
|
28
|
+
if (!this.jsonEnabled()) this.renderStatus(status);
|
|
29
|
+
return status;
|
|
30
|
+
}
|
|
31
|
+
renderStatus(status) {
|
|
32
|
+
if (!status.authenticated) {
|
|
33
|
+
this.log(chalk.yellow("Not authenticated"));
|
|
34
|
+
this.log(chalk.gray("\nRun 'revos auth login' to authenticate."));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
this.log(chalk.bold("Authentication Status:\n"));
|
|
38
|
+
this.log(chalk.green(" Status: Authenticated"));
|
|
39
|
+
if (status.source === "env") this.log(chalk.gray(" Source: REVOS_TOKEN environment variable"));
|
|
40
|
+
else this.log(chalk.gray(" Source: Stored credentials"));
|
|
41
|
+
if (status.email) this.log(` User: ${status.email}`);
|
|
42
|
+
if (status.expiresAt) {
|
|
43
|
+
const diffMs = status.expiresAt.getTime() - Date.now();
|
|
44
|
+
if (diffMs > 0) {
|
|
45
|
+
const hours = Math.floor(diffMs / 36e5);
|
|
46
|
+
const minutes = Math.floor(diffMs % 36e5 / 6e4);
|
|
47
|
+
this.log(` Expires: in ${hours > 0 ? `${hours}h ` : ""}${minutes}m`);
|
|
48
|
+
} else this.log(chalk.yellow(" Expires: Token expired"));
|
|
49
|
+
}
|
|
50
|
+
if (status.organizationId) {
|
|
51
|
+
const orgDisplay = status.organizationName ? `${status.organizationName} (${status.organizationId})` : status.organizationId;
|
|
52
|
+
this.log(` Organization: ${orgDisplay}`);
|
|
53
|
+
}
|
|
54
|
+
if (status.credentialsPath) this.log(chalk.gray(`\n Credentials: ${status.credentialsPath}`));
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
//#endregion
|
|
58
|
+
export { AuthStatus as default };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { t as BaseCommand } from "../../../base.command-BjFWMIzL.mjs";
|
|
2
|
+
import * as _$_oclif_core_interfaces0 from "@oclif/core/interfaces";
|
|
3
|
+
|
|
4
|
+
//#region src/adapters/oclif/commands/init.d.ts
|
|
5
|
+
declare class Init extends BaseCommand<typeof Init> {
|
|
6
|
+
static description: string;
|
|
7
|
+
static args: {
|
|
8
|
+
name: _$_oclif_core_interfaces0.Arg<string | undefined, Record<string, unknown>>;
|
|
9
|
+
};
|
|
10
|
+
run(): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
export { Init as default };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { P as ApiError, t as InitService, y as getConfig } from "../../../core-Bif-kxlo.mjs";
|
|
2
|
+
import { TEMPLATES_DIR } from "../../../templates/index.mjs";
|
|
3
|
+
import { t as BaseCommand } from "../../../base.command-BGM225ik.mjs";
|
|
4
|
+
import * as path from "path";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import { Args } from "@oclif/core";
|
|
7
|
+
//#region src/adapters/oclif/commands/init.ts
|
|
8
|
+
var Init = class extends BaseCommand {
|
|
9
|
+
static description = "Scaffold a new RevOS data engineering project";
|
|
10
|
+
static args = { name: Args.string({
|
|
11
|
+
description: "Project name (used as directory name)",
|
|
12
|
+
required: false
|
|
13
|
+
}) };
|
|
14
|
+
async run() {
|
|
15
|
+
const { apiUrl, token } = getConfig();
|
|
16
|
+
const projectName = this.args.name ?? path.basename(process.cwd());
|
|
17
|
+
if (!projectName || projectName.includes("/") || projectName.includes("\\") || projectName === "..") this.error(`Invalid project name: "${projectName}"`, { exit: 1 });
|
|
18
|
+
this.log(`\nInitializing project ${chalk.bold(projectName)}...\n`);
|
|
19
|
+
const result = await new InitService(TEMPLATES_DIR).run({
|
|
20
|
+
projectName,
|
|
21
|
+
targetDir: process.cwd(),
|
|
22
|
+
apiUrl,
|
|
23
|
+
token
|
|
24
|
+
}).catch((err) => {
|
|
25
|
+
if (err instanceof ApiError) {
|
|
26
|
+
this.log(chalk.red(`\nAPI error: ${err.status} ${err.statusText}`));
|
|
27
|
+
this.log(chalk.red(`URL: ${err.url}`));
|
|
28
|
+
this.log(chalk.red(`Body: ${JSON.stringify(err.body, null, 2)}`));
|
|
29
|
+
}
|
|
30
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
31
|
+
this.error(message, { exit: 1 });
|
|
32
|
+
});
|
|
33
|
+
this.log(chalk.green(`\nOrganization: ${result.organization.name}`));
|
|
34
|
+
this.log(chalk.green(`\nProject created at ${result.projectDir}`));
|
|
35
|
+
this.log("\nGenerated files:");
|
|
36
|
+
for (const f of result.createdFiles) this.log(` ${f}`);
|
|
37
|
+
this.log(`\nNext step: open ${chalk.bold(result.projectDir)} in VS Code and click ${chalk.bold("Reopen in Container")}.\n`);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
//#endregion
|
|
41
|
+
export { Init as default };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { s as OrganizationInfo } from "../../../../types-DsQtGF-c.mjs";
|
|
2
|
+
import { t as BaseCommand } from "../../../../base.command-BjFWMIzL.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/adapters/oclif/commands/org/current.d.ts
|
|
5
|
+
interface CurrentOrgResult {
|
|
6
|
+
organizationId: string | null;
|
|
7
|
+
organization: OrganizationInfo | null;
|
|
8
|
+
source: "env" | "credentials" | null;
|
|
9
|
+
}
|
|
10
|
+
declare class OrgCurrent extends BaseCommand<typeof OrgCurrent> {
|
|
11
|
+
static description: string;
|
|
12
|
+
run(): Promise<CurrentOrgResult>;
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { OrgCurrent as default };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { M as loadCredentials, m as unwrap, p as createApiClient, y as getConfig } from "../../../../core-Bif-kxlo.mjs";
|
|
2
|
+
import { t as BaseCommand } from "../../../../base.command-BGM225ik.mjs";
|
|
3
|
+
//#region src/adapters/oclif/commands/org/current.ts
|
|
4
|
+
var OrgCurrent = class extends BaseCommand {
|
|
5
|
+
static description = "Show currently selected organization";
|
|
6
|
+
async run() {
|
|
7
|
+
const credentials = loadCredentials();
|
|
8
|
+
const envOrgId = process.env.REVOS_ORG_ID;
|
|
9
|
+
if (envOrgId) {
|
|
10
|
+
if (!this.jsonEnabled()) this.log(`Current organization (from REVOS_ORG_ID): ${envOrgId}`);
|
|
11
|
+
return {
|
|
12
|
+
organizationId: envOrgId,
|
|
13
|
+
organization: null,
|
|
14
|
+
source: "env"
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
if (!credentials?.organizationId) {
|
|
18
|
+
if (!this.jsonEnabled()) this.warn("No organization selected. Run 'revos org switch' to select one.");
|
|
19
|
+
return {
|
|
20
|
+
organizationId: null,
|
|
21
|
+
organization: null,
|
|
22
|
+
source: null
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const current = unwrap(await createApiClient(getConfig()).organizations.list()).find((o) => o.id === credentials.organizationId) ?? null;
|
|
27
|
+
if (!this.jsonEnabled()) if (current) this.log(`Current organization: ${current.name} (${current.id})`);
|
|
28
|
+
else this.log(`Current organization ID: ${credentials.organizationId}`);
|
|
29
|
+
return {
|
|
30
|
+
organizationId: credentials.organizationId,
|
|
31
|
+
organization: current,
|
|
32
|
+
source: "credentials"
|
|
33
|
+
};
|
|
34
|
+
} catch {
|
|
35
|
+
if (!this.jsonEnabled()) this.log(`Current organization ID: ${credentials.organizationId}`);
|
|
36
|
+
return {
|
|
37
|
+
organizationId: credentials.organizationId,
|
|
38
|
+
organization: null,
|
|
39
|
+
source: "credentials"
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
//#endregion
|
|
45
|
+
export { OrgCurrent as default };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { a as OrgListResult } from "../../../../types-DsQtGF-c.mjs";
|
|
2
|
+
import { t as BaseCommand } from "../../../../base.command-BjFWMIzL.mjs";
|
|
3
|
+
import * as _$_oclif_core_interfaces0 from "@oclif/core/interfaces";
|
|
4
|
+
|
|
5
|
+
//#region src/adapters/oclif/commands/org/list.d.ts
|
|
6
|
+
declare class OrgList extends BaseCommand<typeof OrgList> {
|
|
7
|
+
static description: string;
|
|
8
|
+
static flags: {
|
|
9
|
+
columns: _$_oclif_core_interfaces0.OptionFlag<string | undefined, _$_oclif_core_interfaces0.CustomOptions>;
|
|
10
|
+
};
|
|
11
|
+
run(): Promise<OrgListResult>;
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { OrgList as default };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { m as unwrap, p as createApiClient, y as getConfig } from "../../../../core-Bif-kxlo.mjs";
|
|
2
|
+
import { t as BaseCommand } from "../../../../base.command-BGM225ik.mjs";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { Flags } from "@oclif/core";
|
|
5
|
+
//#region src/adapters/oclif/commands/org/list.ts
|
|
6
|
+
const ALL_COLUMNS = ["name", "id"];
|
|
7
|
+
var OrgList = class extends BaseCommand {
|
|
8
|
+
static description = "List organizations you belong to";
|
|
9
|
+
static flags = { columns: Flags.string({
|
|
10
|
+
description: `Columns to display (comma-separated). Available: ${ALL_COLUMNS.join(", ")}`,
|
|
11
|
+
helpValue: "name,id"
|
|
12
|
+
}) };
|
|
13
|
+
async run() {
|
|
14
|
+
const { flags } = this;
|
|
15
|
+
const config = getConfig();
|
|
16
|
+
const organizations = unwrap(await createApiClient(config).organizations.list());
|
|
17
|
+
const result = {
|
|
18
|
+
organizations,
|
|
19
|
+
currentOrgId: config.organizationId
|
|
20
|
+
};
|
|
21
|
+
if (!this.jsonEnabled()) if (organizations.length === 0) this.warn("You don't belong to any organizations.");
|
|
22
|
+
else {
|
|
23
|
+
const cols = flags.columns?.split(",").map((c) => c.trim()).filter((c) => ALL_COLUMNS.includes(c)) ?? [...ALL_COLUMNS];
|
|
24
|
+
const rows = organizations.map((org) => ({
|
|
25
|
+
name: org.id === config.organizationId ? `${org.name} ${chalk.green("✓")}` : org.name,
|
|
26
|
+
id: org.id
|
|
27
|
+
}));
|
|
28
|
+
this.table(rows, { columns: cols.map((c) => ({ key: c })) });
|
|
29
|
+
}
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
//#endregion
|
|
34
|
+
export { OrgList as default };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { t as BaseCommand } from "../../../../base.command-BjFWMIzL.mjs";
|
|
2
|
+
import * as _$_oclif_core_interfaces0 from "@oclif/core/interfaces";
|
|
3
|
+
|
|
4
|
+
//#region src/adapters/oclif/commands/org/switch.d.ts
|
|
5
|
+
declare class OrgSwitch extends BaseCommand<typeof OrgSwitch> {
|
|
6
|
+
static description: string;
|
|
7
|
+
static args: {
|
|
8
|
+
id: _$_oclif_core_interfaces0.Arg<string | undefined, Record<string, unknown>>;
|
|
9
|
+
};
|
|
10
|
+
run(): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
export { OrgSwitch as default };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { M as loadCredentials, N as saveCredentials, m as unwrap, n as selectOrganization, p as createApiClient, y as getConfig } from "../../../../core-Bif-kxlo.mjs";
|
|
2
|
+
import { t as BaseCommand } from "../../../../base.command-BGM225ik.mjs";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { Args } from "@oclif/core";
|
|
5
|
+
//#region src/adapters/oclif/commands/org/switch.ts
|
|
6
|
+
var OrgSwitch = class extends BaseCommand {
|
|
7
|
+
static description = "Switch to a different organization";
|
|
8
|
+
static args = { id: Args.string({
|
|
9
|
+
description: "Organization ID",
|
|
10
|
+
required: false
|
|
11
|
+
}) };
|
|
12
|
+
async run() {
|
|
13
|
+
const { args } = this;
|
|
14
|
+
const organizations = unwrap(await createApiClient(getConfig()).organizations.list());
|
|
15
|
+
if (organizations.length === 0) this.error("You don't belong to any organizations.", { exit: 1 });
|
|
16
|
+
let selected;
|
|
17
|
+
if (args.id) {
|
|
18
|
+
selected = organizations.find((o) => o.id === args.id);
|
|
19
|
+
if (!selected) {
|
|
20
|
+
const available = organizations.map((o) => ` ${o.name} (${o.id})`).join("\n");
|
|
21
|
+
this.error(`Organization "${args.id}" not found.\n\nAvailable organizations:\n${available}`, { exit: 1 });
|
|
22
|
+
}
|
|
23
|
+
} else selected = await selectOrganization(organizations);
|
|
24
|
+
const credentials = loadCredentials();
|
|
25
|
+
if (credentials) saveCredentials({
|
|
26
|
+
...credentials,
|
|
27
|
+
organizationId: selected.id
|
|
28
|
+
});
|
|
29
|
+
this.log(chalk.green(`Switched to organization: ${selected.name}`));
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
//#endregion
|
|
33
|
+
export { OrgSwitch as default };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { o as DiffResult } from "../../../../types-DZssnweO.mjs";
|
|
2
|
+
import { t as BaseCommand } from "../../../../base.command-BjFWMIzL.mjs";
|
|
3
|
+
import * as _$_oclif_core_interfaces0 from "@oclif/core/interfaces";
|
|
4
|
+
|
|
5
|
+
//#region src/adapters/oclif/commands/overlays/diff.d.ts
|
|
6
|
+
declare class OverlaysDiff extends BaseCommand<typeof OverlaysDiff> {
|
|
7
|
+
static description: string;
|
|
8
|
+
static flags: {
|
|
9
|
+
dir: _$_oclif_core_interfaces0.OptionFlag<string, _$_oclif_core_interfaces0.CustomOptions>;
|
|
10
|
+
};
|
|
11
|
+
static args: {
|
|
12
|
+
files: _$_oclif_core_interfaces0.Arg<string[] | undefined, Record<string, unknown>>;
|
|
13
|
+
};
|
|
14
|
+
run(): Promise<DiffResult>;
|
|
15
|
+
private renderEntry;
|
|
16
|
+
private renderDataDiff;
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { OverlaysDiff as default };
|