oblien 2.0.5 → 2.0.7
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/dist/cli/auth.d.ts +3 -3
- package/dist/cli/auth.d.ts.map +1 -1
- package/dist/cli/auth.js +27 -17
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli/commands/auth.d.ts +1 -2
- package/dist/cli/commands/auth.d.ts.map +1 -1
- package/dist/cli/commands/auth.js +48 -30
- package/dist/cli/commands/auth.js.map +1 -1
- package/dist/cli/commands/config.js +13 -8
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/scp.d.ts +3 -0
- package/dist/cli/commands/scp.d.ts.map +1 -0
- package/dist/cli/commands/scp.js +126 -0
- package/dist/cli/commands/scp.js.map +1 -0
- package/dist/cli/commands/ssh-util.d.ts +6 -0
- package/dist/cli/commands/ssh-util.d.ts.map +1 -0
- package/dist/cli/commands/ssh-util.js +24 -0
- package/dist/cli/commands/ssh-util.js.map +1 -0
- package/dist/cli/commands/ssh.d.ts.map +1 -1
- package/dist/cli/commands/ssh.js +62 -13
- package/dist/cli/commands/ssh.js.map +1 -1
- package/dist/cli/commands/types.d.ts +1 -0
- package/dist/cli/commands/types.d.ts.map +1 -1
- package/dist/cli/commands/workspaces.d.ts.map +1 -1
- package/dist/cli/commands/workspaces.js +12 -12
- package/dist/cli/commands/workspaces.js.map +1 -1
- package/dist/cli/config-store.d.ts +5 -2
- package/dist/cli/config-store.d.ts.map +1 -1
- package/dist/cli/config-store.js.map +1 -1
- package/dist/cli/index.js +8 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/output.d.ts +1 -0
- package/dist/cli/output.d.ts.map +1 -1
- package/dist/cli/output.js +5 -0
- package/dist/cli/output.js.map +1 -1
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +15 -6
- package/dist/http.js.map +1 -1
- package/dist/runtime-http.d.ts.map +1 -1
- package/dist/runtime-http.js +10 -2
- package/dist/runtime-http.js.map +1 -1
- package/dist/types/client.d.ts +7 -1
- package/dist/types/client.d.ts.map +1 -1
- package/dist/types/resources.d.ts +5 -3
- package/dist/types/resources.d.ts.map +1 -1
- package/dist/types/workspace-resources.d.ts +9 -1
- package/dist/types/workspace-resources.d.ts.map +1 -1
- package/dist/types/workspace.d.ts +43 -9
- package/dist/types/workspace.d.ts.map +1 -1
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +12 -1
- package/dist/workspace.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/auth.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Oblien } from '../client.js';
|
|
2
2
|
/**
|
|
3
3
|
* Build an Oblien client from (in priority order):
|
|
4
|
-
* 1. Explicit flags (--client-id
|
|
5
|
-
* 2. Environment variables (OBLIEN_CLIENT_ID,
|
|
6
|
-
* 3. Config file (~/.oblien/credentials.json)
|
|
4
|
+
* 1. Explicit flags (--client-id + --client-secret)
|
|
5
|
+
* 2. Environment variables (OBLIEN_CLIENT_ID + OBLIEN_CLIENT_SECRET, or OBLIEN_TOKEN)
|
|
6
|
+
* 3. Config file (~/.oblien/credentials.json) — token or API keys
|
|
7
7
|
*/
|
|
8
8
|
export declare function buildClient(flags?: {
|
|
9
9
|
clientId?: string;
|
package/dist/cli/auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/cli/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAItC;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,CAAC,EAAE;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/cli/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAItC;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,CAAC,EAAE;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,MAAM,CAuCT"}
|
package/dist/cli/auth.js
CHANGED
|
@@ -2,30 +2,40 @@ import { Oblien } from '../client.js';
|
|
|
2
2
|
import { loadConfig } from './config-store.js';
|
|
3
3
|
/**
|
|
4
4
|
* Build an Oblien client from (in priority order):
|
|
5
|
-
* 1. Explicit flags (--client-id
|
|
6
|
-
* 2. Environment variables (OBLIEN_CLIENT_ID,
|
|
7
|
-
* 3. Config file (~/.oblien/credentials.json)
|
|
5
|
+
* 1. Explicit flags (--client-id + --client-secret)
|
|
6
|
+
* 2. Environment variables (OBLIEN_CLIENT_ID + OBLIEN_CLIENT_SECRET, or OBLIEN_TOKEN)
|
|
7
|
+
* 3. Config file (~/.oblien/credentials.json) — token or API keys
|
|
8
8
|
*/
|
|
9
9
|
export function buildClient(flags) {
|
|
10
|
+
const config = loadConfig();
|
|
11
|
+
// 1. API key auth (flags → env → config)
|
|
10
12
|
const clientId = flags?.clientId ??
|
|
11
13
|
process.env.OBLIEN_CLIENT_ID ??
|
|
12
|
-
|
|
14
|
+
config?.clientId;
|
|
13
15
|
const clientSecret = flags?.clientSecret ??
|
|
14
16
|
process.env.OBLIEN_CLIENT_SECRET ??
|
|
15
|
-
|
|
16
|
-
if (
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
' 4. Flags: --client-id <id> --client-secret <secret>\n');
|
|
23
|
-
process.exit(1);
|
|
17
|
+
config?.clientSecret;
|
|
18
|
+
if (clientId && clientSecret) {
|
|
19
|
+
const opts = { clientId, clientSecret };
|
|
20
|
+
const base = flags?.baseUrl ?? process.env.OBLIEN_BASE_URL ?? config?.baseUrl;
|
|
21
|
+
if (base)
|
|
22
|
+
opts.baseUrl = base;
|
|
23
|
+
return new Oblien(opts);
|
|
24
24
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
// 2. Token auth (env → config)
|
|
26
|
+
const token = process.env.OBLIEN_TOKEN ?? config?.token;
|
|
27
|
+
if (token) {
|
|
28
|
+
const opts = { token };
|
|
29
|
+
const base = flags?.baseUrl ?? process.env.OBLIEN_BASE_URL ?? config?.baseUrl;
|
|
30
|
+
if (base)
|
|
31
|
+
opts.baseUrl = base;
|
|
32
|
+
return new Oblien(opts);
|
|
28
33
|
}
|
|
29
|
-
|
|
34
|
+
console.error('Error: Missing credentials.\n\n' +
|
|
35
|
+
'Provide credentials via:\n' +
|
|
36
|
+
' 1. oblien login\n' +
|
|
37
|
+
' 2. Environment: OBLIEN_TOKEN or OBLIEN_CLIENT_ID + OBLIEN_CLIENT_SECRET\n' +
|
|
38
|
+
' 3. Flags: --client-id <id> --client-secret <secret>\n');
|
|
39
|
+
process.exit(1);
|
|
30
40
|
}
|
|
31
41
|
//# sourceMappingURL=auth.js.map
|
package/dist/cli/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/cli/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,KAI3B;IACC,MAAM,QAAQ,GACZ,KAAK,EAAE,QAAQ;QACf,OAAO,CAAC,GAAG,CAAC,gBAAgB;QAC5B,
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/cli/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,KAI3B;IACC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAE5B,yCAAyC;IACzC,MAAM,QAAQ,GACZ,KAAK,EAAE,QAAQ;QACf,OAAO,CAAC,GAAG,CAAC,gBAAgB;QAC5B,MAAM,EAAE,QAAQ,CAAC;IAEnB,MAAM,YAAY,GAChB,KAAK,EAAE,YAAY;QACnB,OAAO,CAAC,GAAG,CAAC,oBAAoB;QAChC,MAAM,EAAE,YAAY,CAAC;IAEvB,IAAI,QAAQ,IAAI,YAAY,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAkB,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;QACvD,MAAM,IAAI,GAAG,KAAK,EAAE,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,MAAM,EAAE,OAAO,CAAC;QAC9E,IAAI,IAAI;YAAG,IAAY,CAAC,OAAO,GAAG,IAAI,CAAC;QACvC,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,+BAA+B;IAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,MAAM,EAAE,KAAK,CAAC;IAExD,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,IAAI,GAAkB,EAAE,KAAK,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,KAAK,EAAE,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,MAAM,EAAE,OAAO,CAAC;QAC9E,IAAI,IAAI;YAAG,IAAY,CAAC,OAAO,GAAG,IAAI,CAAC;QACvC,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,OAAO,CAAC,KAAK,CACX,iCAAiC;QACjC,4BAA4B;QAC5B,qBAAqB;QACrB,6EAA6E;QAC7E,yDAAyD,CAC1D,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
|
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
* 2. Creates an auth session via /auth/session → https://auth.oblien.com/{id}
|
|
6
6
|
* 3. Opens the URL in the user's browser (or prints it)
|
|
7
7
|
* 4. Polls /auth/verify until the user finishes login
|
|
8
|
-
* 5.
|
|
9
|
-
* 6. Stores clientId + clientSecret in ~/.oblien/credentials.json
|
|
8
|
+
* 5. Stores the JWT token in ~/.oblien/credentials.json
|
|
10
9
|
*/
|
|
11
10
|
import type { CliFlags } from './types.js';
|
|
12
11
|
export declare function authCmd(args: string[], flags: CliFlags): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/auth.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAoM3C,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA2B5E"}
|
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
* 2. Creates an auth session via /auth/session → https://auth.oblien.com/{id}
|
|
6
6
|
* 3. Opens the URL in the user's browser (or prints it)
|
|
7
7
|
* 4. Polls /auth/verify until the user finishes login
|
|
8
|
-
* 5.
|
|
9
|
-
* 6. Stores clientId + clientSecret in ~/.oblien/credentials.json
|
|
8
|
+
* 5. Stores the JWT token in ~/.oblien/credentials.json
|
|
10
9
|
*/
|
|
11
10
|
import { createInterface } from 'node:readline';
|
|
12
11
|
import { exec } from 'node:child_process';
|
|
@@ -51,7 +50,7 @@ async function authLogin(flags) {
|
|
|
51
50
|
const base = flags.baseUrl ?? DEFAULT_BASE;
|
|
52
51
|
// Check if already logged in
|
|
53
52
|
const existing = loadConfig();
|
|
54
|
-
if (existing?.clientId && existing?.clientSecret) {
|
|
53
|
+
if (existing?.token || (existing?.clientId && existing?.clientSecret)) {
|
|
55
54
|
const answer = await prompt('You are already logged in. Re-authenticate? [y/N] ');
|
|
56
55
|
if (answer.toLowerCase() !== 'y') {
|
|
57
56
|
console.log('Cancelled.');
|
|
@@ -69,7 +68,7 @@ async function authLogin(flags) {
|
|
|
69
68
|
// Step 2: Create auth session
|
|
70
69
|
const sessionRes = await api(base, '/auth/session', {
|
|
71
70
|
token: jwt,
|
|
72
|
-
body: { app: 'oblien', redirect_url:
|
|
71
|
+
body: { app: 'oblien', redirect_url: 'https://oblien.com/cli?login=success' },
|
|
73
72
|
});
|
|
74
73
|
if (!sessionRes.success || !sessionRes.url) {
|
|
75
74
|
printError('Failed to create auth session.');
|
|
@@ -115,26 +114,13 @@ async function authLogin(flags) {
|
|
|
115
114
|
process.exit(1);
|
|
116
115
|
}
|
|
117
116
|
console.log(' ✓ Authenticated!\n');
|
|
118
|
-
// Step 5:
|
|
119
|
-
console.log(' Creating API credentials...');
|
|
120
|
-
const credRes = await api(base, '/developer/credentials', {
|
|
121
|
-
token: loggedInToken,
|
|
122
|
-
body: { name: 'Oblien CLI', scope: 'admin' },
|
|
123
|
-
});
|
|
124
|
-
if (!credRes.success || !credRes.credential) {
|
|
125
|
-
printError('Login succeeded but failed to create API credentials.');
|
|
126
|
-
printError('Create them manually at https://oblien.com/dashboard/developer');
|
|
127
|
-
process.exit(1);
|
|
128
|
-
}
|
|
129
|
-
const { client_id, client_secret } = credRes.credential;
|
|
130
|
-
// Step 6: Save to config
|
|
117
|
+
// Step 5: Save token
|
|
131
118
|
saveConfig({
|
|
132
|
-
|
|
133
|
-
clientSecret: client_secret,
|
|
119
|
+
token: loggedInToken,
|
|
134
120
|
...(base !== DEFAULT_BASE ? { baseUrl: base } : {}),
|
|
135
121
|
});
|
|
136
122
|
printSuccess('Logged in!');
|
|
137
|
-
console.log(`
|
|
123
|
+
console.log(` Token saved to ${configPath()}\n`);
|
|
138
124
|
console.log(' You can now use the CLI and MCP server.\n');
|
|
139
125
|
}
|
|
140
126
|
// ── Logout ──────────────────────────────────────────────────────────
|
|
@@ -143,15 +129,44 @@ function authLogout() {
|
|
|
143
129
|
printSuccess('Logged out. Credentials removed.');
|
|
144
130
|
}
|
|
145
131
|
// ── Status ──────────────────────────────────────────────────────────
|
|
146
|
-
function authStatus() {
|
|
132
|
+
async function authStatus(flags) {
|
|
147
133
|
const config = loadConfig();
|
|
148
|
-
if (!config?.clientId) {
|
|
149
|
-
console.log('Not logged in.\n\nRun: oblien
|
|
134
|
+
if (!config?.token && !config?.clientId) {
|
|
135
|
+
console.log('Not logged in.\n\nRun: oblien login');
|
|
150
136
|
return;
|
|
151
137
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
138
|
+
const base = config.baseUrl ?? flags.baseUrl ?? DEFAULT_BASE;
|
|
139
|
+
// Verify credentials are still valid
|
|
140
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
141
|
+
if (config.token) {
|
|
142
|
+
headers['Authorization'] = `Bearer ${config.token}`;
|
|
143
|
+
}
|
|
144
|
+
else if (config.clientId && config.clientSecret) {
|
|
145
|
+
headers['X-Client-ID'] = config.clientId;
|
|
146
|
+
headers['X-Client-Secret'] = config.clientSecret;
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
const res = await fetch(`${base}/settings/profile`, { headers });
|
|
150
|
+
const data = await res.json();
|
|
151
|
+
if (data.error || !data.success) {
|
|
152
|
+
printError('Session expired. Run: oblien login');
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const user = data.user;
|
|
156
|
+
console.log(` Logged in as ${user?.name ?? user?.email ?? 'unknown'}`);
|
|
157
|
+
if (user?.email)
|
|
158
|
+
console.log(` Email: ${user.email}`);
|
|
159
|
+
console.log(` Auth: ${config.token ? 'Token' : 'API Key'}`);
|
|
160
|
+
if (config.clientId)
|
|
161
|
+
console.log(` Client ID: ${config.clientId.slice(0, 16)}…`);
|
|
162
|
+
console.log(` Config: ${configPath()}`);
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
// Network error — show cached info
|
|
166
|
+
console.log(` Logged in (offline — could not verify)`);
|
|
167
|
+
console.log(` Auth: ${config.token ? 'Token' : 'API Key'}`);
|
|
168
|
+
console.log(` Config: ${configPath()}`);
|
|
169
|
+
}
|
|
155
170
|
}
|
|
156
171
|
// ── Router ──────────────────────────────────────────────────────────
|
|
157
172
|
export async function authCmd(args, flags) {
|
|
@@ -162,19 +177,22 @@ export async function authCmd(args, flags) {
|
|
|
162
177
|
case 'logout':
|
|
163
178
|
return authLogout();
|
|
164
179
|
case 'status':
|
|
165
|
-
return authStatus();
|
|
180
|
+
return authStatus(flags);
|
|
166
181
|
default:
|
|
167
182
|
console.log(`
|
|
168
183
|
oblien auth - Authenticate with Oblien
|
|
169
184
|
|
|
170
185
|
Usage:
|
|
171
|
-
oblien auth login Log in via browser
|
|
186
|
+
oblien auth login Log in via browser
|
|
172
187
|
oblien auth logout Remove stored credentials
|
|
173
188
|
oblien auth status Show current auth status
|
|
174
189
|
|
|
175
190
|
This opens a browser window where you log in with your Oblien account.
|
|
176
|
-
On success,
|
|
177
|
-
|
|
191
|
+
On success, your session token is saved to ${configPath()}.
|
|
192
|
+
|
|
193
|
+
For CI/scripts, you can also use API keys:
|
|
194
|
+
oblien config set --client-id <id> --client-secret <secret>
|
|
195
|
+
OBLIEN_CLIENT_ID + OBLIEN_CLIENT_SECRET environment variables
|
|
178
196
|
`);
|
|
179
197
|
}
|
|
180
198
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/cli/commands/auth.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/cli/commands/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAGxD,MAAM,YAAY,GAAG,wBAAwB,CAAC;AAE9C,uEAAuE;AAEvE,KAAK,UAAU,GAAG,CAAC,IAAY,EAAE,IAAY,EAAE,OAI3C,EAAE;IACJ,MAAM,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC;IAC7B,MAAM,OAAO,GAA2B,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC;IAC/E,IAAI,IAAI,CAAC,KAAK;QAAE,OAAO,CAAC,eAAe,CAAC,GAAG,UAAU,IAAI,CAAC,KAAK,EAAE,CAAC;IAElE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAC3B,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,MAAM;QAC7B,OAAO;QACP,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;KACxD,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACpB,CAAC;AAED,SAAS,WAAW,CAAC,GAAW;IAC9B,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,KAAK,QAAQ;QACvC,CAAC,CAAC,SAAS,GAAG,GAAG;QACjB,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO;YAC5B,CAAC,CAAC,aAAa,GAAG,GAAG;YACrB,CAAC,CAAC,aAAa,GAAG,GAAG,CAAC;IAE1B,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAiD,CAAC,CAAC,CAAC;AACrE,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,MAAM,CAAC,QAAgB;IAC9B,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7E,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE;QAC3B,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE;YAC7B,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,uEAAuE;AAEvE,KAAK,UAAU,SAAS,CAAC,KAAe;IACtC,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,IAAI,YAAY,CAAC;IAE3C,6BAA6B;IAC7B,MAAM,QAAQ,GAAG,UAAU,EAAE,CAAC;IAC9B,IAAI,QAAQ,EAAE,KAAK,IAAI,CAAC,QAAQ,EAAE,QAAQ,IAAI,QAAQ,EAAE,YAAY,CAAC,EAAE,CAAC;QACtE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,oDAAoD,CAAC,CAAC;QAClF,IAAI,MAAM,CAAC,WAAW,EAAE,KAAK,GAAG,EAAE,CAAC;YACjC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;YAC1B,OAAO;QACT,CAAC;IACH,CAAC;IAED,8BAA8B;IAC9B,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;IAChD,IAAI,CAAC,QAAQ,CAAC,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACzC,UAAU,CAAC,4CAA4C,CAAC,CAAC;QACzD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC;IAE3B,8BAA8B;IAC9B,MAAM,UAAU,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,eAAe,EAAE;QAClD,KAAK,EAAE,GAAG;QACV,IAAI,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,YAAY,EAAE,sCAAsC,EAAE;KAC9E,CAAC,CAAC;IAEH,IAAI,CAAC,UAAU,CAAC,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC;QAC3C,UAAU,CAAC,gCAAgC,CAAC,CAAC;QAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC;IAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAG,CAAC;IAEzC,kCAAkC;IAClC,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;IAC5D,OAAO,CAAC,GAAG,CAAC,YAAY,OAAO,WAAW,CAAC,CAAC;IAE5C,WAAW,CAAC,OAAO,CAAC,CAAC;IACrB,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IAEjD,oCAAoC;IACpC,MAAM,aAAa,GAAG,KAAK,CAAC;IAC5B,MAAM,YAAY,GAAG,OAAO,CAAC,CAAC,YAAY;IAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,IAAI,aAAa,GAAkB,IAAI,CAAC;IAExC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,YAAY,EAAE,CAAC;QACzC,MAAM,KAAK,CAAC,aAAa,CAAC,CAAC;QAE3B,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,cAAc,EAAE;YAChD,IAAI,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE;SAC5B,CAAC,CAAC;QAEH,IAAI,SAAS,CAAC,OAAO,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC;YACzC,aAAa,GAAG,SAAS,CAAC,KAAK,CAAC;YAChC,MAAM;QACR,CAAC;QAED,kEAAkE;QAClE,4DAA4D;QAC5D,IAAI,SAAS,CAAC,MAAM,KAAK,mBAAmB,IAAI,SAAS,CAAC,YAAY,EAAE,CAAC;YACvE,iEAAiE;YACjE,+CAA+C;YAC/C,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,cAAc,EAAE;gBAC9C,IAAI,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE;aAC5B,CAAC,CAAC;YACH,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;gBAClB,aAAa,GAAG,OAAO,CAAC,KAAK,CAAC;gBAC9B,MAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,UAAU,CAAC,oCAAoC,CAAC,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IAEpC,qBAAqB;IACrB,UAAU,CAAC;QACT,KAAK,EAAE,aAAa;QACpB,GAAG,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACpD,CAAC,CAAC;IAEH,YAAY,CAAC,YAAY,CAAC,CAAC;IAC3B,OAAO,CAAC,GAAG,CAAC,oBAAoB,UAAU,EAAE,IAAI,CAAC,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;AAC7D,CAAC;AAED,uEAAuE;AAEvE,SAAS,UAAU;IACjB,WAAW,EAAE,CAAC;IACd,YAAY,CAAC,kCAAkC,CAAC,CAAC;AACnD,CAAC;AAED,uEAAuE;AAEvE,KAAK,UAAU,UAAU,CAAC,KAAe;IACvC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;QACnD,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,IAAI,YAAY,CAAC;IAE7D,qCAAqC;IACrC,MAAM,OAAO,GAA2B,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC;IAC/E,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,OAAO,CAAC,eAAe,CAAC,GAAG,UAAU,MAAM,CAAC,KAAK,EAAE,CAAC;IACtD,CAAC;SAAM,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QAClD,OAAO,CAAC,aAAa,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC;QACzC,OAAO,CAAC,iBAAiB,CAAC,GAAG,MAAM,CAAC,YAAY,CAAC;IACnD,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,mBAAmB,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QACjE,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAA6B,CAAC;QAEzD,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAChC,UAAU,CAAC,oCAAoC,CAAC,CAAC;YACjD,OAAO;QACT,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,IAA0C,CAAC;QAC7D,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,EAAE,IAAI,IAAI,IAAI,EAAE,KAAK,IAAI,SAAS,EAAE,CAAC,CAAC;QACxE,IAAI,IAAI,EAAE,KAAK;YAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAC5D,OAAO,CAAC,GAAG,CAAC,iBAAiB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;QACnE,IAAI,MAAM,CAAC,QAAQ;YAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;QACnF,OAAO,CAAC,GAAG,CAAC,iBAAiB,UAAU,EAAE,EAAE,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,mCAAmC;QACnC,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;QACxD,OAAO,CAAC,GAAG,CAAC,iBAAiB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;QACnE,OAAO,CAAC,GAAG,CAAC,iBAAiB,UAAU,EAAE,EAAE,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC;AAED,uEAAuE;AAEvE,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAc,EAAE,KAAe;IAC3D,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAEpB,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,OAAO;YACV,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC;QAC1B,KAAK,QAAQ;YACX,OAAO,UAAU,EAAE,CAAC;QACtB,KAAK,QAAQ;YACX,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC;QAC3B;YACE,OAAO,CAAC,GAAG,CAAC;;;;;;;;;+CAS6B,UAAU,EAAE;;;;;CAK1D,CAAC,CAAC;IACD,CAAC;AACH,CAAC"}
|
|
@@ -49,15 +49,20 @@ function configSet(args) {
|
|
|
49
49
|
}
|
|
50
50
|
function configShow() {
|
|
51
51
|
const config = loadConfig();
|
|
52
|
-
if (!config || !config.clientId) {
|
|
53
|
-
console.log('No credentials configured.\n\nRun: oblien
|
|
52
|
+
if (!config || (!config.clientId && !config.token)) {
|
|
53
|
+
console.log('No credentials configured.\n\nRun: oblien login');
|
|
54
54
|
return;
|
|
55
55
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
56
|
+
const info = {};
|
|
57
|
+
if (config.token) {
|
|
58
|
+
info.auth = 'Token';
|
|
59
|
+
}
|
|
60
|
+
if (config.clientId) {
|
|
61
|
+
info.clientId = config.clientId;
|
|
62
|
+
info.clientSecret = (config.clientSecret ?? '').slice(0, 8) + '…';
|
|
63
|
+
}
|
|
64
|
+
info.baseUrl = config.baseUrl ?? 'https://api.oblien.com (default)';
|
|
65
|
+
info.path = configPath();
|
|
66
|
+
printKeyValue(info);
|
|
62
67
|
}
|
|
63
68
|
//# sourceMappingURL=config.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/cli/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAG3D,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAc,EAAE,MAAgB;IAC9D,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAEpB,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,KAAK;YACR,OAAO,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAClC,KAAK,MAAM;YACT,OAAO,UAAU,EAAE,CAAC;QACtB,KAAK,MAAM;YACT,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;YAC1B,OAAO;QACT,KAAK,OAAO;YACV,WAAW,EAAE,CAAC;YACd,YAAY,CAAC,sBAAsB,CAAC,CAAC;YACrC,OAAO;QACT;YACE,OAAO,CAAC,GAAG,CAAC;;;;;;;;;8BASY,UAAU,EAAE;CACzC,CAAC,CAAC;IACD,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,IAAc;IAC/B,IAAI,QAA4B,CAAC;IACjC,IAAI,YAAgC,CAAC;IACrC,IAAI,OAA2B,CAAC;IAEhC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,aAAa,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM;YAAE,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aACtE,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,iBAAiB,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM;YAAE,YAAY,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aACnF,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,YAAY,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM;YAAE,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAChF,CAAC;IAED,IAAI,CAAC,QAAQ,IAAI,CAAC,YAAY,EAAE,CAAC;QAC/B,OAAO,CAAC,KAAK,CAAC,uFAAuF,CAAC,CAAC;QACvG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,UAAU,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,CAAC;IAChD,YAAY,CAAC,wBAAwB,UAAU,EAAE,EAAE,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,UAAU;IACjB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/cli/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAG3D,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAc,EAAE,MAAgB;IAC9D,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAEpB,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,KAAK;YACR,OAAO,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAClC,KAAK,MAAM;YACT,OAAO,UAAU,EAAE,CAAC;QACtB,KAAK,MAAM;YACT,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;YAC1B,OAAO;QACT,KAAK,OAAO;YACV,WAAW,EAAE,CAAC;YACd,YAAY,CAAC,sBAAsB,CAAC,CAAC;YACrC,OAAO;QACT;YACE,OAAO,CAAC,GAAG,CAAC;;;;;;;;;8BASY,UAAU,EAAE;CACzC,CAAC,CAAC;IACD,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,IAAc;IAC/B,IAAI,QAA4B,CAAC;IACjC,IAAI,YAAgC,CAAC;IACrC,IAAI,OAA2B,CAAC;IAEhC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,aAAa,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM;YAAE,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aACtE,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,iBAAiB,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM;YAAE,YAAY,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aACnF,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,YAAY,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM;YAAE,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAChF,CAAC;IAED,IAAI,CAAC,QAAQ,IAAI,CAAC,YAAY,EAAE,CAAC;QAC/B,OAAO,CAAC,KAAK,CAAC,uFAAuF,CAAC,CAAC;QACvG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,UAAU,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,CAAC;IAChD,YAAY,CAAC,wBAAwB,UAAU,EAAE,EAAE,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,UAAU;IACjB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;QAC/D,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAA2B,EAAE,CAAC;IACxC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC;IACtB,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACpB,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QAChC,IAAI,CAAC,YAAY,GAAG,CAAC,MAAM,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC;IACpE,CAAC;IACD,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,kCAAkC,CAAC;IACpE,IAAI,CAAC,IAAI,GAAG,UAAU,EAAE,CAAC;IAEzB,aAAa,CAAC,IAAI,CAAC,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scp.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/scp.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAM3C,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAqC3E"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { buildClient } from '../auth.js';
|
|
2
|
+
import { requireId } from './helpers.js';
|
|
3
|
+
import { spawn } from 'child_process';
|
|
4
|
+
export async function scpCmd(args, flags) {
|
|
5
|
+
const sub = args[0];
|
|
6
|
+
switch (sub) {
|
|
7
|
+
case 'push':
|
|
8
|
+
case 'upload': return scpPush(args[1], args.slice(2), flags);
|
|
9
|
+
case 'pull':
|
|
10
|
+
case 'download': return scpPull(args[1], args.slice(2), flags);
|
|
11
|
+
default:
|
|
12
|
+
console.log(`
|
|
13
|
+
oblien scp - Transfer files via SCP (SSH-based)
|
|
14
|
+
|
|
15
|
+
Works over the SSH bastion — no runtime API needed.
|
|
16
|
+
SSH must be enabled on the workspace. Use "oblien ssh enable <ws>" first,
|
|
17
|
+
or these commands will auto-enable it for you.
|
|
18
|
+
|
|
19
|
+
Usage:
|
|
20
|
+
oblien scp push <ws> <local-paths...> [--dest <remote-dir>]
|
|
21
|
+
oblien scp pull <ws> <remote-paths...> [--dest <local-dir>]
|
|
22
|
+
|
|
23
|
+
Aliases:
|
|
24
|
+
push = upload
|
|
25
|
+
pull = download
|
|
26
|
+
|
|
27
|
+
Examples:
|
|
28
|
+
oblien scp push my-app ./src ./package.json --dest /app
|
|
29
|
+
oblien scp push my-app ./deploy.sh
|
|
30
|
+
oblien scp pull my-app /app/dist --dest ./build
|
|
31
|
+
oblien scp pull my-app /var/log/app.log
|
|
32
|
+
|
|
33
|
+
Notes:
|
|
34
|
+
- Uses SCP over the SSH bastion (ProxyJump).
|
|
35
|
+
- For bulk transfers, "oblien files push/pull" uses the runtime API
|
|
36
|
+
and may be faster for large directory trees.
|
|
37
|
+
- Set your SSH key with "oblien ssh set-key" for passwordless transfers.
|
|
38
|
+
`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** Ensure SSH is enabled and return connection info. */
|
|
42
|
+
async function ensureSshConnection(wsId, flags) {
|
|
43
|
+
const client = buildClient(flags);
|
|
44
|
+
let status = await client.workspaces.ssh.status(wsId);
|
|
45
|
+
if (!status.ssh_enabled) {
|
|
46
|
+
console.error('SSH is not enabled. Enabling...');
|
|
47
|
+
const res = await client.workspaces.ssh.enable(wsId);
|
|
48
|
+
const password = res.ssh_password;
|
|
49
|
+
if (password) {
|
|
50
|
+
console.error(`SSH password: ${password}`);
|
|
51
|
+
}
|
|
52
|
+
status = await client.workspaces.ssh.status(wsId);
|
|
53
|
+
}
|
|
54
|
+
if (!status.connection) {
|
|
55
|
+
console.error('SSH is enabled but no connection info available.');
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
return status.connection;
|
|
59
|
+
}
|
|
60
|
+
// ── Push: local → workspace ──────────────────────────────────────────
|
|
61
|
+
async function scpPush(wsId, args, flags) {
|
|
62
|
+
const id = requireId(wsId, 'scp push <workspace> <local-paths...>');
|
|
63
|
+
let dest = '/root/';
|
|
64
|
+
const localPaths = [];
|
|
65
|
+
for (let i = 0; i < args.length; i++) {
|
|
66
|
+
if (args[i] === '--dest' && i + 1 < args.length) {
|
|
67
|
+
dest = args[++i];
|
|
68
|
+
}
|
|
69
|
+
else if (!args[i].startsWith('-')) {
|
|
70
|
+
localPaths.push(args[i]);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (localPaths.length === 0) {
|
|
74
|
+
console.error('Usage: oblien scp push <ws> <local-paths...> [--dest <remote-dir>]');
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
const conn = await ensureSshConnection(id, flags);
|
|
78
|
+
// Build: scp -o 'ProxyJump root@bastion' -r <paths...> root@host:<dest>
|
|
79
|
+
const scpArgs = [
|
|
80
|
+
'-o', `ProxyJump ${conn.user}@${conn.bastion}`,
|
|
81
|
+
'-r',
|
|
82
|
+
...localPaths,
|
|
83
|
+
`${conn.user}@${conn.host}:${dest}`,
|
|
84
|
+
];
|
|
85
|
+
console.error(`Uploading ${localPaths.length} path(s) to ${dest}...`);
|
|
86
|
+
runScp(scpArgs);
|
|
87
|
+
}
|
|
88
|
+
// ── Pull: workspace → local ─────────────────────────────────────────
|
|
89
|
+
async function scpPull(wsId, args, flags) {
|
|
90
|
+
const id = requireId(wsId, 'scp pull <workspace> <remote-paths...>');
|
|
91
|
+
let localDest = '.';
|
|
92
|
+
const remotePaths = [];
|
|
93
|
+
for (let i = 0; i < args.length; i++) {
|
|
94
|
+
if (args[i] === '--dest' && i + 1 < args.length) {
|
|
95
|
+
localDest = args[++i];
|
|
96
|
+
}
|
|
97
|
+
else if (!args[i].startsWith('-')) {
|
|
98
|
+
remotePaths.push(args[i]);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (remotePaths.length === 0) {
|
|
102
|
+
console.error('Usage: oblien scp pull <ws> <remote-paths...> [--dest <local-dir>]');
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
const conn = await ensureSshConnection(id, flags);
|
|
106
|
+
// Build: scp -o 'ProxyJump root@bastion' -r root@host:<path1> root@host:<path2> <local>
|
|
107
|
+
const remoteArgs = remotePaths.map(p => `${conn.user}@${conn.host}:${p}`);
|
|
108
|
+
const scpArgs = [
|
|
109
|
+
'-o', `ProxyJump ${conn.user}@${conn.bastion}`,
|
|
110
|
+
'-r',
|
|
111
|
+
...remoteArgs,
|
|
112
|
+
localDest,
|
|
113
|
+
];
|
|
114
|
+
console.error(`Downloading ${remotePaths.length} path(s) to ${localDest}...`);
|
|
115
|
+
runScp(scpArgs);
|
|
116
|
+
}
|
|
117
|
+
// ── Helpers ──────────────────────────────────────────────────────────
|
|
118
|
+
function runScp(scpArgs) {
|
|
119
|
+
const child = spawn('scp', scpArgs, { stdio: 'inherit' });
|
|
120
|
+
child.on('close', (code) => process.exit(code ?? 0));
|
|
121
|
+
child.on('error', (err) => {
|
|
122
|
+
console.error(`Failed to start scp: ${err.message}`);
|
|
123
|
+
process.exit(1);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=scp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scp.js","sourceRoot":"","sources":["../../../src/cli/commands/scp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remove all known_hosts entries that reference the given host.
|
|
3
|
+
* Matches plain `host`, bracketed `[host]:port`, and comma-separated lists containing the host.
|
|
4
|
+
*/
|
|
5
|
+
export declare function removeKnownHost(host: string): void;
|
|
6
|
+
//# sourceMappingURL=ssh-util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh-util.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/ssh-util.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAgBlD"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
/**
|
|
5
|
+
* Remove all known_hosts entries that reference the given host.
|
|
6
|
+
* Matches plain `host`, bracketed `[host]:port`, and comma-separated lists containing the host.
|
|
7
|
+
*/
|
|
8
|
+
export function removeKnownHost(host) {
|
|
9
|
+
const knownHostsPath = join(homedir(), '.ssh', 'known_hosts');
|
|
10
|
+
if (!existsSync(knownHostsPath))
|
|
11
|
+
return;
|
|
12
|
+
const lines = readFileSync(knownHostsPath, 'utf-8').split('\n');
|
|
13
|
+
const filtered = lines.filter((line) => {
|
|
14
|
+
const hostField = line.split(/\s/)[0] ?? '';
|
|
15
|
+
// Check each comma-separated host pattern in the first field
|
|
16
|
+
const hosts = hostField.split(',');
|
|
17
|
+
return !hosts.some((h) => h === host || h === `[${host}]` || h.startsWith(`[${host}]:`));
|
|
18
|
+
});
|
|
19
|
+
if (filtered.length !== lines.length) {
|
|
20
|
+
writeFileSync(knownHostsPath, filtered.join('\n'), { mode: 0o600 });
|
|
21
|
+
console.log(`Removed stale SSH fingerprint for ${host} from known_hosts`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=ssh-util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh-util.js","sourceRoot":"","sources":["../../../src/cli/commands/ssh-util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;IAC9D,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC;QAAE,OAAO;IAExC,MAAM,KAAK,GAAG,YAAY,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAChE,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QACrC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5C,6DAA6D;QAC7D,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACnC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,GAAG,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC;IAC3F,CAAC,CAAC,CAAC;IAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC;QACrC,aAAa,CAAC,cAAc,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACpE,OAAO,CAAC,GAAG,CAAC,qCAAqC,IAAI,mBAAmB,CAAC,CAAC;IAC5E,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssh.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/ssh.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"ssh.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/ssh.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAmB3C,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAqC3E"}
|
package/dist/cli/commands/ssh.js
CHANGED
|
@@ -2,6 +2,18 @@ import { buildClient } from '../auth.js';
|
|
|
2
2
|
import { printResult, printSuccess } from '../output.js';
|
|
3
3
|
import { parseFlag, requireId } from './helpers.js';
|
|
4
4
|
import { spawn } from 'child_process';
|
|
5
|
+
import { removeKnownHost } from './ssh-util.js';
|
|
6
|
+
import { createInterface } from 'node:readline';
|
|
7
|
+
/** Prompt the user for a line of input (promise-based). */
|
|
8
|
+
function prompt(message) {
|
|
9
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
10
|
+
return new Promise((resolve) => {
|
|
11
|
+
rl.question(message, (answer) => {
|
|
12
|
+
rl.close();
|
|
13
|
+
resolve(answer);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
}
|
|
5
17
|
export async function sshCmd(args, flags) {
|
|
6
18
|
const sub = args[0];
|
|
7
19
|
switch (sub) {
|
|
@@ -16,7 +28,7 @@ export async function sshCmd(args, flags) {
|
|
|
16
28
|
oblien ssh - Manage SSH access
|
|
17
29
|
|
|
18
30
|
Usage:
|
|
19
|
-
oblien ssh connect <ws>
|
|
31
|
+
oblien ssh connect <ws> [--passwordless] Connect via SSH
|
|
20
32
|
oblien ssh status <ws> Check SSH status
|
|
21
33
|
oblien ssh enable <ws> Enable SSH
|
|
22
34
|
oblien ssh disable <ws> Disable SSH
|
|
@@ -25,8 +37,13 @@ export async function sshCmd(args, flags) {
|
|
|
25
37
|
|
|
26
38
|
<ws> can be a workspace ID or slug.
|
|
27
39
|
|
|
40
|
+
Flags:
|
|
41
|
+
--passwordless Auto-enable SSH and set a public key if needed, then
|
|
42
|
+
connect without a password prompt.
|
|
43
|
+
|
|
28
44
|
Examples:
|
|
29
45
|
oblien ssh connect my-dev-env
|
|
46
|
+
oblien ssh connect my-dev-env --passwordless
|
|
30
47
|
oblien ssh status ws_abc123
|
|
31
48
|
oblien ssh enable my-api
|
|
32
49
|
oblien ssh set-password ws_abc123 --password mysecret
|
|
@@ -37,32 +54,64 @@ export async function sshCmd(args, flags) {
|
|
|
37
54
|
async function sshConnect(id, flags) {
|
|
38
55
|
const wsId = requireId(id, 'ssh connect <workspace>');
|
|
39
56
|
const client = buildClient(flags);
|
|
40
|
-
|
|
57
|
+
let status = await client.workspaces.ssh.status(wsId);
|
|
58
|
+
// ── Passwordless flow ──────────────────────────────────────────────
|
|
59
|
+
if (flags.passwordless) {
|
|
60
|
+
// Ensure SSH is enabled
|
|
61
|
+
if (!status.ssh_enabled) {
|
|
62
|
+
await client.workspaces.ssh.enable(wsId);
|
|
63
|
+
status = await client.workspaces.ssh.status(wsId);
|
|
64
|
+
}
|
|
65
|
+
// Ensure a public key is authorized
|
|
66
|
+
if (!status.ssh_key_set) {
|
|
67
|
+
console.log('No SSH key set for this workspace.');
|
|
68
|
+
const pubkey = await prompt('Paste your SSH public key: ');
|
|
69
|
+
if (!pubkey.trim()) {
|
|
70
|
+
console.error('No key provided. Aborting.');
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
await client.workspaces.ssh.setKey(wsId, { public_key: pubkey.trim() });
|
|
74
|
+
console.log('SSH key set. Connecting...');
|
|
75
|
+
status = await client.workspaces.ssh.status(wsId);
|
|
76
|
+
}
|
|
77
|
+
const conn = status.connection;
|
|
78
|
+
if (!conn) {
|
|
79
|
+
console.error('SSH is enabled but no connection info available.');
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
startSsh(conn);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
// ── Normal flow ────────────────────────────────────────────────────
|
|
86
|
+
// Clean stale known_hosts entry when the VM was rebuilt
|
|
87
|
+
if (status.connection?.host) {
|
|
88
|
+
removeKnownHost(status.connection.host);
|
|
89
|
+
}
|
|
41
90
|
if (!status.ssh_enabled) {
|
|
42
91
|
console.log('SSH is not enabled on this workspace. Enabling...');
|
|
43
92
|
const enableRes = await client.workspaces.ssh.enable(wsId);
|
|
44
93
|
const password = enableRes.ssh_password;
|
|
45
94
|
if (password) {
|
|
46
95
|
console.log(`SSH password: ${password}`);
|
|
96
|
+
console.log('Tip: Use "oblien ssh connect <ws> --passwordless" or set your public key for key-based access.');
|
|
47
97
|
}
|
|
48
|
-
|
|
49
|
-
const updated = await client.workspaces.ssh.status(wsId);
|
|
50
|
-
if (!updated.connection) {
|
|
51
|
-
console.error('Failed to get SSH connection info after enabling.');
|
|
52
|
-
process.exit(1);
|
|
53
|
-
}
|
|
54
|
-
startSsh(updated.connection);
|
|
55
|
-
return;
|
|
98
|
+
status = await client.workspaces.ssh.status(wsId);
|
|
56
99
|
}
|
|
57
|
-
|
|
100
|
+
const conn = status.connection;
|
|
101
|
+
if (!conn) {
|
|
58
102
|
console.error('SSH is enabled but no connection info available.');
|
|
59
103
|
process.exit(1);
|
|
60
104
|
}
|
|
61
|
-
startSsh(
|
|
105
|
+
startSsh(conn);
|
|
62
106
|
}
|
|
63
107
|
function startSsh(connection) {
|
|
64
|
-
const parts = connection.command.split(/\s+/);
|
|
108
|
+
const parts = connection.command.split(/\s+/).filter(Boolean);
|
|
65
109
|
const bin = parts[0];
|
|
110
|
+
// Only allow the ssh binary — never execute arbitrary commands from the API
|
|
111
|
+
if (bin !== 'ssh') {
|
|
112
|
+
console.error(`Unexpected SSH command: ${connection.command}`);
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
66
115
|
const sshArgs = parts.slice(1);
|
|
67
116
|
const child = spawn(bin, sshArgs, { stdio: 'inherit' });
|
|
68
117
|
child.on('close', (code) => process.exit(code ?? 0));
|