@uagents/syncenv-cli 0.1.5 → 0.1.6
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 +207 -49
- package/dist/{chunk-JBMZAAVP.js → chunk-LWTV6MO2.js} +1 -1
- package/dist/{chunk-OVEYHV4C.js → chunk-YXE467TO.js} +51 -11
- package/dist/{cookie-store-Z6DNTUGS.js → cookie-store-UGGEBXBV.js} +1 -1
- package/dist/index.js +1272 -239
- package/dist/{secure-storage-UEK3LD5L.js → secure-storage-AR7HZFTA.js} +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -30,85 +30,129 @@ curl -sL https://syncenv-files.uagents.app/cli/install.sh | INSTALL_DIR=~/.local
|
|
|
30
30
|
|
|
31
31
|
## Quick Start
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
### One-Command Setup (Recommended)
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
2. **Create an account or login:**
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
syncenv auth signup
|
|
43
|
-
# or
|
|
44
|
-
syncenv auth login
|
|
45
|
-
```
|
|
35
|
+
```bash
|
|
36
|
+
syncenv setup
|
|
37
|
+
```
|
|
46
38
|
|
|
47
|
-
|
|
39
|
+
The `setup` wizard will:
|
|
40
|
+
1. Check if you're authenticated (prompt for login/signup if not)
|
|
41
|
+
2. Guide you through account creation if needed
|
|
42
|
+
3. Automatically generate your encryption keys
|
|
43
|
+
4. Save keys to server and cache locally
|
|
48
44
|
|
|
49
|
-
|
|
50
|
-
syncenv project create
|
|
51
|
-
```
|
|
45
|
+
### Then Initialize Your Project
|
|
52
46
|
|
|
53
|
-
|
|
47
|
+
```bash
|
|
48
|
+
cd ~/my-project
|
|
49
|
+
syncenv init
|
|
50
|
+
syncenv env push
|
|
51
|
+
```
|
|
54
52
|
|
|
55
|
-
|
|
56
|
-
syncenv env push
|
|
57
|
-
```
|
|
53
|
+
## Commands
|
|
58
54
|
|
|
59
|
-
|
|
60
|
-
```bash
|
|
61
|
-
syncenv env pull
|
|
62
|
-
```
|
|
55
|
+
### Setup
|
|
63
56
|
|
|
64
|
-
|
|
57
|
+
- `syncenv setup` - First-time setup wizard (login + encryption keys)
|
|
58
|
+
- `--debug` - Enable debug mode with verbose logging
|
|
65
59
|
|
|
66
60
|
### Authentication
|
|
67
61
|
|
|
68
|
-
- `syncenv auth signup` - Create a new account
|
|
69
62
|
- `syncenv auth login` - Login to your account
|
|
63
|
+
- `--debug` - Enable debug mode
|
|
70
64
|
- `syncenv auth logout` - Logout and clear session
|
|
71
65
|
- `syncenv auth status` - Check authentication status
|
|
66
|
+
- `syncenv auth signup` - Open browser to create account
|
|
72
67
|
|
|
73
68
|
### Project Management
|
|
74
69
|
|
|
75
|
-
- `syncenv init` - Initialize project configuration
|
|
70
|
+
- `syncenv init` - Initialize project configuration (creates `.syncenvrc` and optionally creates project on server)
|
|
71
|
+
- `-y, --yes` - Skip prompts and use defaults
|
|
72
|
+
- `--debug` - Enable debug mode
|
|
73
|
+
|
|
74
|
+
**Note:** Environments are created automatically on first push. Run `syncenv env push -e <env>` to create and upload to an environment.
|
|
76
75
|
- `syncenv project list` - List all projects
|
|
76
|
+
- `-s, --search <query>` - Search projects by name
|
|
77
|
+
- `-l, --limit <number>` - Number of projects to show (default: 20)
|
|
78
|
+
- `--cursor <cursor>` - Cursor for pagination
|
|
79
|
+
- `--debug` - Enable debug mode
|
|
77
80
|
- `syncenv project create [name]` - Create a new project
|
|
78
|
-
-
|
|
79
|
-
- `
|
|
80
|
-
- `syncenv project
|
|
81
|
+
- `-d, --description <description>` - Project description
|
|
82
|
+
- `--debug` - Enable debug mode
|
|
83
|
+
- `syncenv project get <identifier>` - Get project details. Identifier can be project ID (`proj_xxx`) or project name
|
|
84
|
+
- `--debug` - Enable debug mode
|
|
85
|
+
- `syncenv project delete <identifier>` - Delete a project. Identifier can be project ID (`proj_xxx`) or project name
|
|
86
|
+
- `-f, --force` - Skip confirmation
|
|
87
|
+
- `--debug` - Enable debug mode
|
|
88
|
+
- `syncenv project use <identifier>` - Set default project for current directory (updates `.syncenvrc`). Identifier can be project ID (`proj_xxx`) or project name
|
|
89
|
+
- `--debug` - Enable debug mode
|
|
90
|
+
|
|
91
|
+
### Configuration Management
|
|
92
|
+
|
|
93
|
+
- `syncenv config list` - List all configuration values
|
|
94
|
+
- `--debug` - Enable debug mode
|
|
95
|
+
- `syncenv config get <key>` - Get a configuration value
|
|
96
|
+
- `--debug` - Enable debug mode
|
|
97
|
+
- `syncenv config set <key> [value]` - Set a configuration value
|
|
98
|
+
- `--debug` - Enable debug mode
|
|
99
|
+
- `syncenv config delete <key>` - Delete a configuration value (reset to default)
|
|
100
|
+
- `--debug` - Enable debug mode
|
|
101
|
+
- `syncenv config reset` - Reset all configuration to defaults
|
|
102
|
+
- `-f, --force` - Skip confirmation
|
|
103
|
+
- `--debug` - Enable debug mode
|
|
104
|
+
- `syncenv config path` - Show configuration file path
|
|
81
105
|
|
|
82
106
|
### Environment Variables
|
|
83
107
|
|
|
84
108
|
- `syncenv env push` - Push .env file to server
|
|
85
|
-
- `-p, --project <id>` - Project ID
|
|
86
|
-
- `-e, --env <name>` - Environment name
|
|
109
|
+
- `-p, --project <id>` - Project ID (or use `.syncenvrc` project.id)
|
|
110
|
+
- `-e, --env <name>` - Environment name (default: dev)
|
|
87
111
|
- `-f, --file <path>` - File path
|
|
88
112
|
- `-m, --message <message>` - Change description
|
|
89
|
-
|
|
113
|
+
- `--force` - Force push without conflict check
|
|
114
|
+
- `--strategy <strategy>` - Merge strategy on conflict
|
|
115
|
+
- `--debug` - Enable debug mode
|
|
90
116
|
- `syncenv env pull` - Pull .env file from server
|
|
91
117
|
- `-p, --project <id>` - Project ID
|
|
92
118
|
- `-e, --env <name>` - Environment name
|
|
93
119
|
- `-f, --file <path>` - Output file path
|
|
94
120
|
- `-v, --version <number>` - Specific version to pull
|
|
95
121
|
- `-m, --merge` - Merge with existing file
|
|
96
|
-
|
|
122
|
+
- `--debug` - Enable debug mode
|
|
123
|
+
- `syncenv env sync` - Smart sync (pull + merge + push)
|
|
124
|
+
- `--strategy <strategy>` - Conflict resolution: `interactive`, `local-wins`, `remote-wins`, `fail-on-conflict`
|
|
125
|
+
- `--dry-run` - Preview changes without applying
|
|
126
|
+
- `-y, --yes` - Skip confirmation prompts
|
|
127
|
+
- `--debug` - Enable debug mode
|
|
97
128
|
- `syncenv env history` - Show version history
|
|
98
129
|
- `-l, --limit <number>` - Number of versions to show
|
|
99
|
-
|
|
130
|
+
- `--debug` - Enable debug mode
|
|
100
131
|
- `syncenv env diff <v1> <v2>` - Compare two versions
|
|
101
|
-
|
|
132
|
+
- `--debug` - Enable debug mode
|
|
102
133
|
- `syncenv env rollback <version>` - Rollback to a specific version
|
|
103
|
-
|
|
104
|
-
- `
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
134
|
+
- `-f, --force` - Skip confirmation
|
|
135
|
+
- `--debug` - Enable debug mode
|
|
136
|
+
|
|
137
|
+
### User Keys (Encryption Management)
|
|
138
|
+
|
|
139
|
+
- `syncenv user-keys setup` - Initialize encryption keys (first time)
|
|
140
|
+
- `--debug` - Enable debug mode
|
|
141
|
+
- `syncenv user-keys unlock` - Unlock encryption keys for session
|
|
142
|
+
- `--no-remember` - Do not store in keychain
|
|
143
|
+
- `--debug` - Enable debug mode
|
|
144
|
+
- `syncenv user-keys lock` - Lock keys from memory
|
|
145
|
+
- `--forget` - Also remove from keychain
|
|
146
|
+
- `--debug` - Enable debug mode
|
|
147
|
+
- `syncenv user-keys status` - Check encryption key status
|
|
148
|
+
- `--debug` - Enable debug mode
|
|
149
|
+
- `syncenv user-keys rotate` - Re-encrypt keys with new password
|
|
150
|
+
- `--debug` - Enable debug mode
|
|
108
151
|
|
|
109
152
|
### Device Management
|
|
110
153
|
|
|
111
154
|
- `syncenv device list` - List all devices
|
|
155
|
+
- `--debug` - Enable debug mode
|
|
112
156
|
- `syncenv device authorize <id>` - Authorize a pending device
|
|
113
157
|
- `syncenv device revoke <id>` - Revoke a device
|
|
114
158
|
- `syncenv device remove <id>` - Remove a device
|
|
@@ -117,6 +161,7 @@ curl -sL https://syncenv-files.uagents.app/cli/install.sh | INSTALL_DIR=~/.local
|
|
|
117
161
|
### Diagnostics
|
|
118
162
|
|
|
119
163
|
- `syncenv doctor` - Diagnose configuration and connectivity issues
|
|
164
|
+
- `--debug` - Enable debug mode
|
|
120
165
|
|
|
121
166
|
## Smart Merge
|
|
122
167
|
|
|
@@ -151,14 +196,18 @@ syncenv env push --strategy=fail-on-conflict
|
|
|
151
196
|
|
|
152
197
|
### CLI Config
|
|
153
198
|
|
|
154
|
-
Stored in OS-specific config directory
|
|
199
|
+
Stored in OS-specific config directory:
|
|
200
|
+
- **macOS:** `~/Library/Application Support/syncenv/`
|
|
201
|
+
- **Linux:** `~/.config/syncenv/`
|
|
202
|
+
- **Windows:** `%APPDATA%/syncenv/`
|
|
155
203
|
|
|
156
|
-
|
|
157
|
-
- `
|
|
204
|
+
Contains:
|
|
205
|
+
- `apiUrl` - API base URL (default: https://syncenv-api.uagents.app)
|
|
206
|
+
- `autoLockMinutes` - Auto-lock timeout in minutes (0 to disable, default: 30)
|
|
158
207
|
- `userId` - User ID
|
|
159
|
-
- `
|
|
208
|
+
- `userEmail` - User email
|
|
160
209
|
|
|
161
|
-
### Project Config (`.
|
|
210
|
+
### Project Config (`.syncenvrc`)
|
|
162
211
|
|
|
163
212
|
Example:
|
|
164
213
|
|
|
@@ -188,16 +237,125 @@ environments:
|
|
|
188
237
|
|
|
189
238
|
## Environment Variables
|
|
190
239
|
|
|
191
|
-
- `SYNCENV_API_URL` - API base URL (default:
|
|
240
|
+
- `SYNCENV_API_URL` - API base URL (default: https://syncenv-api.uagents.app)
|
|
241
|
+
- `SYNCENV_DEBUG` - Enable debug mode (set to `true`)
|
|
192
242
|
- `SYNCENV_VERBOSE` - Enable verbose logging
|
|
193
243
|
|
|
244
|
+
## Common Workflows
|
|
245
|
+
|
|
246
|
+
### First-Time Setup
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
# Install CLI
|
|
250
|
+
curl -sL https://syncenv-files.uagents.app/cli/install.sh | bash
|
|
251
|
+
|
|
252
|
+
# Run setup wizard
|
|
253
|
+
syncenv setup
|
|
254
|
+
|
|
255
|
+
# Initialize your project
|
|
256
|
+
cd ~/my-project
|
|
257
|
+
syncenv init
|
|
258
|
+
|
|
259
|
+
# Push your first environment
|
|
260
|
+
syncenv env push -m "Initial setup"
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Daily Development
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
# Unlock keys (cached in keychain by default)
|
|
267
|
+
syncenv user-keys unlock
|
|
268
|
+
|
|
269
|
+
# Sync environment (pull + merge + push)
|
|
270
|
+
syncenv env sync
|
|
271
|
+
|
|
272
|
+
# Make changes to .env...
|
|
273
|
+
|
|
274
|
+
# Push with message
|
|
275
|
+
syncenv env push -m "Added Stripe API keys"
|
|
276
|
+
|
|
277
|
+
# Lock when done (optional on personal machine)
|
|
278
|
+
syncenv user-keys lock
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Working with Multiple Environments
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
# Push to specific environment
|
|
285
|
+
syncenv env push -e production -m "Database migration config"
|
|
286
|
+
|
|
287
|
+
# Pull from staging
|
|
288
|
+
syncenv env pull -e staging
|
|
289
|
+
|
|
290
|
+
# Sync with specific strategy
|
|
291
|
+
syncenv env sync -e production --strategy=interactive
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### CI/CD Pipeline
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
# Non-interactive pull
|
|
298
|
+
syncenv env pull -e production -y
|
|
299
|
+
|
|
300
|
+
# Or with specific strategy
|
|
301
|
+
syncenv env sync -e production --strategy=local-wins -y
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## Troubleshooting
|
|
305
|
+
|
|
306
|
+
### Debug Mode
|
|
307
|
+
|
|
308
|
+
Most commands support `--debug` flag:
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
syncenv setup --debug
|
|
312
|
+
syncenv auth login --debug
|
|
313
|
+
syncenv env push --debug
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Common Issues
|
|
317
|
+
|
|
318
|
+
**"Not authenticated" error:**
|
|
319
|
+
```bash
|
|
320
|
+
syncenv auth login
|
|
321
|
+
# or
|
|
322
|
+
syncenv setup
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
**"Encryption keys are locked" error:**
|
|
326
|
+
```bash
|
|
327
|
+
syncenv user-keys unlock
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
**"No project specified" error:**
|
|
331
|
+
```bash
|
|
332
|
+
# Option 1: Set project in .syncenvrc (supports ID or name)
|
|
333
|
+
syncenv project use my-project-name
|
|
334
|
+
# or
|
|
335
|
+
syncenv project use proj_xxx
|
|
336
|
+
|
|
337
|
+
# Option 2: Use --project flag
|
|
338
|
+
syncenv env push --project proj_xxx
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**Merge conflicts:**
|
|
342
|
+
```bash
|
|
343
|
+
# Interactive resolution
|
|
344
|
+
syncenv env sync --strategy=interactive
|
|
345
|
+
|
|
346
|
+
# Or force local changes
|
|
347
|
+
syncenv env push --force
|
|
348
|
+
```
|
|
349
|
+
|
|
194
350
|
## Security
|
|
195
351
|
|
|
196
352
|
- All encryption/decryption happens locally on your device
|
|
197
|
-
-
|
|
353
|
+
- Your login password never leaves your device
|
|
198
354
|
- Data Encryption Keys (DEK) are encrypted with your Key Encryption Key (KEK)
|
|
199
|
-
- KEK is derived from your
|
|
355
|
+
- KEK is derived from your login password using PBKDF2
|
|
200
356
|
- Server only stores encrypted data and cannot decrypt your environment variables
|
|
357
|
+
- Keys are cached in system keychain by default (use `--no-remember` to disable)
|
|
358
|
+
- Always run `syncenv user-keys lock` when done on shared machines
|
|
201
359
|
|
|
202
360
|
## License
|
|
203
361
|
|
|
@@ -6,6 +6,7 @@ import chalk from "chalk";
|
|
|
6
6
|
import Conf from "conf";
|
|
7
7
|
import yaml from "js-yaml";
|
|
8
8
|
import { z } from "zod";
|
|
9
|
+
import inquirer from "inquirer";
|
|
9
10
|
var ProjectConfigSchema = z.object({
|
|
10
11
|
project: z.object({
|
|
11
12
|
name: z.string(),
|
|
@@ -28,7 +29,7 @@ var ProjectConfigSchema = z.object({
|
|
|
28
29
|
)
|
|
29
30
|
});
|
|
30
31
|
var defaultConfig = {
|
|
31
|
-
apiUrl: process.env.SYNCENV_API_URL || "https://syncenv.uagents.app"
|
|
32
|
+
apiUrl: process.env.SYNCENV_API_URL || "https://syncenv-api.uagents.app"
|
|
32
33
|
};
|
|
33
34
|
var conf;
|
|
34
35
|
try {
|
|
@@ -57,6 +58,9 @@ function setConfig(key, value) {
|
|
|
57
58
|
function deleteConfig(key) {
|
|
58
59
|
conf.delete(key);
|
|
59
60
|
}
|
|
61
|
+
function clearConfig() {
|
|
62
|
+
conf.clear();
|
|
63
|
+
}
|
|
60
64
|
function getConfigPath() {
|
|
61
65
|
return conf.path;
|
|
62
66
|
}
|
|
@@ -65,7 +69,7 @@ function isAuthenticated() {
|
|
|
65
69
|
return !!cookieHeader && cookieHeader.includes("better-auth");
|
|
66
70
|
}
|
|
67
71
|
async function loadProjectConfig(cwd = process.cwd()) {
|
|
68
|
-
const configPath = path.join(cwd, ".
|
|
72
|
+
const configPath = path.join(cwd, ".syncenvrc");
|
|
69
73
|
try {
|
|
70
74
|
const content = await fs.readFile(configPath, "utf-8");
|
|
71
75
|
const parsed = yaml.load(content);
|
|
@@ -74,17 +78,17 @@ async function loadProjectConfig(cwd = process.cwd()) {
|
|
|
74
78
|
if (error.code === "ENOENT") {
|
|
75
79
|
return null;
|
|
76
80
|
}
|
|
77
|
-
throw new Error(`Failed to parse .
|
|
81
|
+
throw new Error(`Failed to parse .syncenvrc: ${error.message}`);
|
|
78
82
|
}
|
|
79
83
|
}
|
|
80
84
|
async function saveProjectConfig(config, cwd = process.cwd()) {
|
|
81
|
-
const configPath = path.join(cwd, ".
|
|
85
|
+
const configPath = path.join(cwd, ".syncenvrc");
|
|
82
86
|
const content = yaml.dump(config, { indent: 2 });
|
|
83
87
|
await fs.writeFile(configPath, content, "utf-8");
|
|
84
88
|
}
|
|
85
89
|
async function hasProjectConfig(cwd = process.cwd()) {
|
|
86
90
|
try {
|
|
87
|
-
await fs.access(path.join(cwd, ".
|
|
91
|
+
await fs.access(path.join(cwd, ".syncenvrc"));
|
|
88
92
|
return true;
|
|
89
93
|
} catch {
|
|
90
94
|
return false;
|
|
@@ -99,10 +103,15 @@ async function loadConfig() {
|
|
|
99
103
|
};
|
|
100
104
|
}
|
|
101
105
|
async function fetchWithCookies(input, init) {
|
|
106
|
+
const apiUrl = conf.get("apiUrl") || defaultConfig.apiUrl;
|
|
107
|
+
const webOrigin = apiUrl.replace("-api", "");
|
|
108
|
+
const origin = apiUrl.startsWith("http://localhost") ? apiUrl : webOrigin;
|
|
102
109
|
if (input instanceof Request) {
|
|
103
110
|
const url2 = input.url;
|
|
104
111
|
const cookieHeader2 = getCookieHeader();
|
|
105
|
-
const headers2 = {
|
|
112
|
+
const headers2 = {
|
|
113
|
+
Origin: origin
|
|
114
|
+
};
|
|
106
115
|
input.headers.forEach((value, key) => {
|
|
107
116
|
headers2[key] = value;
|
|
108
117
|
});
|
|
@@ -123,7 +132,8 @@ async function fetchWithCookies(input, init) {
|
|
|
123
132
|
const url = input.toString();
|
|
124
133
|
const cookieHeader = getCookieHeader();
|
|
125
134
|
const headers = {
|
|
126
|
-
...init?.headers
|
|
135
|
+
...init?.headers,
|
|
136
|
+
Origin: origin
|
|
127
137
|
};
|
|
128
138
|
if (cookieHeader) {
|
|
129
139
|
headers["Cookie"] = cookieHeader;
|
|
@@ -149,7 +159,7 @@ function createClient() {
|
|
|
149
159
|
}
|
|
150
160
|
var client = createClient();
|
|
151
161
|
async function clearAuthState() {
|
|
152
|
-
const { clearCachedKEK, deleteKEKPassword, deleteEncryptedKEK } = await import("./secure-storage-
|
|
162
|
+
const { clearCachedKEK, deleteKEKPassword, deleteEncryptedKEK } = await import("./secure-storage-AR7HZFTA.js");
|
|
153
163
|
clearCachedKEK();
|
|
154
164
|
await deleteKEKPassword();
|
|
155
165
|
deleteEncryptedKEK();
|
|
@@ -181,7 +191,7 @@ function handleAuthError(_error) {
|
|
|
181
191
|
process.exit(1);
|
|
182
192
|
}
|
|
183
193
|
async function getOrUnlockUserKEK() {
|
|
184
|
-
const { getCachedKEK, cacheKEKInMemory, getKEKPassword, saveEncryptedKEK } = await import("./secure-storage-
|
|
194
|
+
const { getCachedKEK, cacheKEKInMemory, getKEKPassword, saveEncryptedKEK } = await import("./secure-storage-AR7HZFTA.js");
|
|
185
195
|
const cached = getCachedKEK();
|
|
186
196
|
if (cached) return cached;
|
|
187
197
|
const password = await getKEKPassword();
|
|
@@ -196,7 +206,7 @@ async function getOrUnlockUserKEK() {
|
|
|
196
206
|
userKeys.kekSalt
|
|
197
207
|
);
|
|
198
208
|
if (!kek) {
|
|
199
|
-
const { deleteKEKPassword } = await import("./secure-storage-
|
|
209
|
+
const { deleteKEKPassword } = await import("./secure-storage-AR7HZFTA.js");
|
|
200
210
|
await deleteKEKPassword();
|
|
201
211
|
return null;
|
|
202
212
|
}
|
|
@@ -225,6 +235,34 @@ async function withAuthGuard(apiCall) {
|
|
|
225
235
|
throw error;
|
|
226
236
|
}
|
|
227
237
|
}
|
|
238
|
+
async function resolveProjectIdentifier(identifier) {
|
|
239
|
+
if (identifier.startsWith("proj_")) {
|
|
240
|
+
try {
|
|
241
|
+
return await withAuthGuard(() => client.projects.get(identifier));
|
|
242
|
+
} catch (err) {
|
|
243
|
+
if (err instanceof ApiError && err.statusCode === 404) {
|
|
244
|
+
throw new Error(`Project not found: ${identifier}`);
|
|
245
|
+
}
|
|
246
|
+
throw err;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
const result = await withAuthGuard(() => client.projects.getByName(identifier));
|
|
250
|
+
if ("error" in result && "projects" in result) {
|
|
251
|
+
const { selectedId } = await inquirer.prompt([
|
|
252
|
+
{
|
|
253
|
+
type: "list",
|
|
254
|
+
name: "selectedId",
|
|
255
|
+
message: `Multiple projects match "${identifier}". Select one:`,
|
|
256
|
+
choices: result.projects.map((p) => ({
|
|
257
|
+
name: `${p.name} (ID: ${p.id}, Updated: ${new Date(p.updatedAt).toLocaleDateString()})`,
|
|
258
|
+
value: p.id
|
|
259
|
+
}))
|
|
260
|
+
}
|
|
261
|
+
]);
|
|
262
|
+
return result.projects.find((p) => p.id === selectedId);
|
|
263
|
+
}
|
|
264
|
+
return result;
|
|
265
|
+
}
|
|
228
266
|
|
|
229
267
|
// src/cookie-store.ts
|
|
230
268
|
function parseSetCookie(setCookieValue) {
|
|
@@ -320,6 +358,7 @@ export {
|
|
|
320
358
|
getConfig,
|
|
321
359
|
setConfig,
|
|
322
360
|
deleteConfig,
|
|
361
|
+
clearConfig,
|
|
323
362
|
getConfigPath,
|
|
324
363
|
isAuthenticated,
|
|
325
364
|
loadProjectConfig,
|
|
@@ -329,5 +368,6 @@ export {
|
|
|
329
368
|
client,
|
|
330
369
|
clearAuthState,
|
|
331
370
|
getOrUnlockUserKEK,
|
|
332
|
-
withAuthGuard
|
|
371
|
+
withAuthGuard,
|
|
372
|
+
resolveProjectIdentifier
|
|
333
373
|
};
|