@sylphx/cli 0.3.0 → 0.3.1

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.
Files changed (2) hide show
  1. package/dist/index.js +570 -717
  2. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -24,13 +24,13 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  ));
25
25
 
26
26
  // src/index.ts
27
- var import_chalk24 = __toESM(require("chalk"));
28
- var import_commander23 = require("commander");
27
+ var import_chalk25 = __toESM(require("chalk"));
28
+ var import_commander24 = require("commander");
29
29
 
30
30
  // package.json
31
31
  var package_default = {
32
32
  name: "@sylphx/cli",
33
- version: "0.3.0",
33
+ version: "0.3.1",
34
34
  description: "Sylphx Platform CLI \u2014 deploy, manage logs, env vars, and more",
35
35
  type: "commonjs",
36
36
  bin: {
@@ -55,6 +55,7 @@ var package_default = {
55
55
  registry: "https://registry.npmjs.org/"
56
56
  },
57
57
  dependencies: {
58
+ "@sylphx/management": "workspace:*",
58
59
  chalk: "^5.3.0",
59
60
  commander: "^12.1.0",
60
61
  conf: "^13.0.0",
@@ -153,491 +154,213 @@ var config = {
153
154
  };
154
155
 
155
156
  // src/api.ts
157
+ var import_management = require("@sylphx/management");
156
158
  var { version } = package_default;
157
- var BASE_URL = process.env.SYLPHX_API_URL ?? "https://api.sylphx.com";
158
- var API_BASE = `${BASE_URL}/v1`;
159
- var AUTH_BASE_URL = "https://sylphx.com";
160
- var ApiError = class extends Error {
161
- constructor(status, message, body) {
162
- super(message);
163
- this.status = status;
164
- this.body = body;
165
- this.name = "ApiError";
166
- }
167
- };
168
- async function request(method, path5, options) {
169
- const token = options?.token ?? config.getToken();
159
+ function getMgmt() {
160
+ const token = config.getToken();
170
161
  if (!token) {
171
- throw new ApiError(401, "Not authenticated. Run `sylphx login` first.");
172
- }
173
- let url = `${API_BASE}${path5}`;
174
- if (options?.query) {
175
- const params = new URLSearchParams(options.query);
176
- url += `?${params.toString()}`;
162
+ throw new import_management.ApiError(401, "Not authenticated. Run `sylphx login` first.");
177
163
  }
178
- const headers = {
179
- Authorization: `Bearer ${token}`,
180
- "Content-Type": "application/json",
181
- "User-Agent": `sylphx-cli/${version}`
182
- };
183
- const res = await fetch(url, {
184
- method,
185
- headers,
186
- body: options?.body ? JSON.stringify(options.body) : void 0
164
+ return new import_management.SylphxManagement({
165
+ token,
166
+ userAgent: `sylphx-cli/${version}`
187
167
  });
188
- if (!res.ok) {
189
- let body;
190
- const text = await res.text();
191
- try {
192
- body = JSON.parse(text);
193
- } catch {
194
- body = text;
195
- }
196
- const message = typeof body === "object" && body !== null && "message" in body ? String(body.message) : `HTTP ${res.status}`;
197
- throw new ApiError(res.status, message, body);
198
- }
199
- if (res.status === 204) {
200
- return void 0;
201
- }
202
- return res.json();
203
168
  }
204
169
  var api = {
205
- /** Get deployment status for a project */
170
+ // Deployments
206
171
  async getDeploymentStatus(projectId) {
207
- return request("GET", `/projects/${projectId}/status`);
172
+ return getMgmt().deployments.status(projectId);
208
173
  },
209
- /** Trigger a deploy for a project environment */
210
174
  async triggerDeploy(projectId, envType) {
211
- return request("POST", `/projects/${projectId}/deploy`, {
212
- body: { envType }
213
- });
175
+ return getMgmt().deployments.trigger(projectId, envType);
214
176
  },
215
- /** Get deployment history for a project environment */
216
177
  async getDeploymentHistory(projectId, envType) {
217
- return request("GET", `/projects/${projectId}/deployments`, {
218
- query: { envType }
219
- });
178
+ return getMgmt().deployments.history(projectId, envType);
220
179
  },
221
- /** Rollback to previous deployment.
222
- * Accepts envId (rollback env to previous deploy), deploymentRecordId, or buildRecordId.
223
- * One of these is required.
224
- */
225
180
  async rollback(projectId, body) {
226
- return request("POST", `/projects/${projectId}/rollback`, { body });
181
+ return getMgmt().deployments.rollback(projectId, body);
227
182
  },
228
- /** List env vars for a project environment */
183
+ // Env Vars
229
184
  async listEnvVars(projectId, envType) {
230
- const res = await request(
231
- "GET",
232
- `/projects/${projectId}/env-vars`,
233
- {
234
- query: { envType }
235
- }
236
- );
237
- return Array.isArray(res) ? res : res.data ?? [];
185
+ return getMgmt().envVars.list(projectId, envType);
238
186
  },
239
- /** Set an env var (or batch of vars) for a project environment */
240
187
  async setEnvVar(projectId, key, value, envType, secret) {
241
- return request("POST", `/projects/${projectId}/env-vars`, {
242
- body: {
243
- envType,
244
- vars: [{ key, value, secret: secret ?? false }]
245
- }
246
- });
188
+ return getMgmt().envVars.set(projectId, key, value, envType, secret);
247
189
  },
248
- /** Delete an env var for a project environment */
249
190
  async deleteEnvVar(projectId, key, envType) {
250
- return request("DELETE", `/projects/${projectId}/env-vars/${encodeURIComponent(key)}`, {
251
- query: { envType }
252
- });
191
+ return getMgmt().envVars.delete(projectId, key, envType);
192
+ },
193
+ async setEnvVars(projectId, vars, envType) {
194
+ return getMgmt().envVars.setMany(projectId, vars, envType);
253
195
  },
254
- // ── Domain Management (Unified System) ──────────────────────────────────
255
- /** List all apex domains for a project environment */
196
+ // Domains
256
197
  async listDomains(projectId, envType = "production") {
257
- return request("GET", `/projects/${projectId}/domains`, {
258
- query: { envType }
259
- });
198
+ return getMgmt().domains.list(projectId, envType);
260
199
  },
261
- /** Register an apex domain for a project (full domain object with DNS records) */
262
200
  async createDomain(projectId, apexDomain, envType = "production") {
263
- return request("POST", `/projects/${projectId}/domains`, {
264
- body: { apexDomain, envType }
265
- });
201
+ return getMgmt().domains.create(projectId, apexDomain, envType);
266
202
  },
267
- /** Add a hostname binding to an existing domain */
268
203
  async addHostname(projectId, domainId, hostname, opts) {
269
- const { envType = "production", ...bodyOpts } = opts ?? {};
270
- return request("POST", `/projects/${projectId}/domains/${domainId}/hostnames`, {
271
- query: { envType },
272
- body: { hostname, ...bodyOpts }
273
- });
204
+ return getMgmt().domains.addHostname(projectId, domainId, hostname, opts);
274
205
  },
275
- /** Remove a hostname binding */
276
206
  async removeHostname(projectId, domainId, hostnameId) {
277
- return request(
278
- "DELETE",
279
- `/projects/${projectId}/domains/${domainId}/hostnames/${hostnameId}`
280
- );
207
+ return getMgmt().domains.removeHostname(projectId, domainId, hostnameId);
281
208
  },
282
- /** Trigger DNS check for a hostname */
283
209
  async checkHostname(projectId, domainId, hostnameId) {
284
- return request(
285
- "POST",
286
- `/projects/${projectId}/domains/${domainId}/hostnames/${hostnameId}/check`
287
- );
210
+ return getMgmt().domains.checkHostname(projectId, domainId, hostnameId);
288
211
  },
289
- /** Enable email sending for a domain (generates DKIM keypair) */
290
212
  async enableEmail(projectId, domainId, opts) {
291
- return request("POST", `/projects/${projectId}/domains/${domainId}/email`, {
292
- body: opts ?? {}
293
- });
213
+ return getMgmt().domains.enableEmail(projectId, domainId, opts);
294
214
  },
295
- /** Check DKIM DNS propagation and load into Stalwart */
296
215
  async checkEmail(projectId, domainId) {
297
- return request(
298
- "POST",
299
- `/projects/${projectId}/domains/${domainId}/email/check`
300
- );
216
+ return getMgmt().domains.checkEmail(projectId, domainId);
301
217
  },
302
- /** Disable email sending for a domain */
303
218
  async disableEmail(projectId, domainId) {
304
- return request("DELETE", `/projects/${projectId}/domains/${domainId}/email`);
219
+ return getMgmt().domains.disableEmail(projectId, domainId);
305
220
  },
306
- /** Get current user and orgs */
221
+ // User
307
222
  async whoami() {
308
- return request("GET", "/user/me");
223
+ return getMgmt().user.whoami();
309
224
  },
310
- /** List projects (org is scoped to token) */
225
+ // Projects
311
226
  async listProjects() {
312
- const res = await request("GET", "/projects");
313
- return Array.isArray(res) ? res : res.data ?? [];
227
+ return getMgmt().projects.list();
314
228
  },
315
- /** Create a new project */
316
229
  async createProject(data) {
317
- return request("POST", "/projects", { body: data });
230
+ return getMgmt().projects.create(data);
318
231
  },
319
- /** Delete a project */
320
232
  async deleteProject(id) {
321
- return request("DELETE", `/projects/${encodeURIComponent(id)}`);
233
+ return getMgmt().projects.delete(id);
322
234
  },
323
- /** @deprecated Use listProjects() — org is from token scope */
235
+ // Organization
236
+ async getCurrentOrg() {
237
+ return getMgmt().org.current();
238
+ },
239
+ async listOrgMembers(orgId) {
240
+ return getMgmt().org.listMembers(orgId);
241
+ },
242
+ async inviteOrgMember(orgId, email, role) {
243
+ return getMgmt().org.inviteMember(orgId, email, role);
244
+ },
245
+ async removeOrgMember(orgId, userId) {
246
+ return getMgmt().org.removeMember(orgId, userId);
247
+ },
248
+ /** @deprecated Use listProjects() */
324
249
  async listApps(_orgId) {
325
250
  return this.listProjects();
326
251
  },
327
- /** List all databases (via unified Resources API) */
252
+ // Databases
328
253
  async listDatabases() {
329
- const res = await request(
330
- "GET",
331
- "/resources",
332
- {
333
- query: { kind: "database" }
334
- }
335
- );
336
- return Array.isArray(res) ? res : res.data ?? [];
254
+ return getMgmt().databases.list();
337
255
  },
338
- /** Provision a new database (via unified Resources API) */
339
256
  async createDatabase(data) {
340
- return request("POST", "/resources", { body: { ...data, kind: "database" } });
257
+ return getMgmt().databases.create(data);
341
258
  },
342
- /** Get database details (via unified Resources API) */
343
259
  async getDatabase(id) {
344
- return request("GET", `/resources/${encodeURIComponent(id)}`);
260
+ return getMgmt().databases.get(id);
345
261
  },
346
- /** Delete a database (via unified Resources API) */
347
262
  async deleteDatabase(id) {
348
- return request("DELETE", `/resources/${encodeURIComponent(id)}`);
263
+ return getMgmt().databases.delete(id);
349
264
  },
350
- /** Branch a database for staging/preview (via unified Resources API) */
351
265
  async branchDatabase(id, data) {
352
- return request("POST", `/resources/${encodeURIComponent(id)}/branch`, { body: data });
353
- },
354
- /** Batch-set env vars for a project environment */
355
- async setEnvVars(projectId, vars, envType) {
356
- return request("POST", `/projects/${projectId}/env-vars`, {
357
- body: { envType, vars }
358
- });
266
+ return getMgmt().databases.branch(id, data);
359
267
  },
360
- /** CLI auth: poll for token (uses main sylphx.com domain) */
361
- async pollCliAuth(code) {
362
- const res = await fetch(`${AUTH_BASE_URL}/api/auth/cli/poll?code=${encodeURIComponent(code)}`, {
363
- headers: { "User-Agent": `sylphx-cli/${version}` }
364
- });
365
- if (!res.ok) {
366
- throw new ApiError(res.status, "Failed to poll auth status");
367
- }
368
- return res.json();
369
- },
370
- // ── Services ─────────────────────────────────────────────────────────────
371
- /** List services for a project */
268
+ // Services
372
269
  async listServices(projectId) {
373
- const res = await request(
374
- "GET",
375
- `/projects/${encodeURIComponent(projectId)}/services`
376
- );
377
- return Array.isArray(res) ? res : res.data ?? [];
270
+ return getMgmt().services.list(projectId);
378
271
  },
379
- /** Get a service by name */
380
272
  async getService(projectId, name) {
381
- return request(
382
- "GET",
383
- `/projects/${encodeURIComponent(projectId)}/services/${encodeURIComponent(name)}`
384
- );
273
+ return getMgmt().services.get(projectId, name);
385
274
  },
386
- /**
387
- * Deploy a specific service.
388
- * Backend expects { environmentId?, force?, image? } — NOT envType.
389
- * Resolves envType → environmentId automatically.
390
- */
391
275
  async deployService(projectId, name, envType) {
392
- const environmentId = await this.resolveEnvId(projectId, envType);
393
- return request(
394
- "POST",
395
- `/projects/${encodeURIComponent(projectId)}/services/${encodeURIComponent(name)}/deploy`,
396
- { body: environmentId ? { environmentId } : {} }
397
- );
276
+ return getMgmt().services.deploy(projectId, name, envType);
398
277
  },
399
- /** Delete a service */
400
278
  async deleteService(projectId, name) {
401
- return request(
402
- "DELETE",
403
- `/projects/${encodeURIComponent(projectId)}/services/${encodeURIComponent(name)}`
404
- );
279
+ return getMgmt().services.delete(projectId, name);
405
280
  },
406
- // ── Volumes ───────────────────────────────────────────────────────────────
407
- /** List volumes for a project */
281
+ // Volumes
408
282
  async listVolumes(projectId) {
409
- const res = await request(
410
- "GET",
411
- `/projects/${encodeURIComponent(projectId)}/volumes`
412
- );
413
- return Array.isArray(res) ? res : res.volumes ?? [];
283
+ return getMgmt().volumes.list(projectId);
414
284
  },
415
- /** Create a volume */
416
285
  async createVolume(projectId, data) {
417
- return request(
418
- "POST",
419
- `/projects/${encodeURIComponent(projectId)}/volumes`,
420
- { body: data }
421
- );
286
+ return getMgmt().volumes.create(projectId, data);
422
287
  },
423
- /** Delete a volume */
424
288
  async deleteVolume(projectId, volId) {
425
- return request(
426
- "DELETE",
427
- `/projects/${encodeURIComponent(projectId)}/volumes/${encodeURIComponent(volId)}`
428
- );
289
+ return getMgmt().volumes.delete(projectId, volId);
429
290
  },
430
- // ── Storage (Blob) ────────────────────────────────────────────────────────
431
- /** List storage resources for a project.
432
- * Backend returns a plain array of binding objects (not wrapped in { data: [...] }).
433
- * Optionally filter by envType client-side.
434
- */
291
+ // Storage
435
292
  async listStorage(projectId, envType) {
436
- const res = await request(
437
- "GET",
438
- `/projects/${encodeURIComponent(projectId)}/storage`
439
- );
440
- const list = Array.isArray(res) ? res : [];
441
- return envType ? list.filter((r) => !r.envType || r.envType === envType) : list;
293
+ return getMgmt().storage.list(projectId, envType);
442
294
  },
443
- /** Provision blob storage for a project environment */
444
295
  async createStorage(projectId, data) {
445
- return request("POST", `/projects/${encodeURIComponent(projectId)}/storage`, {
446
- body: data
447
- });
296
+ return getMgmt().storage.create(projectId, data);
448
297
  },
449
- /** Delete a storage resource */
450
298
  async deleteStorage(projectId, storageId) {
451
- return request(
452
- "DELETE",
453
- `/projects/${encodeURIComponent(projectId)}/storage/${encodeURIComponent(storageId)}`
454
- );
299
+ return getMgmt().storage.delete(projectId, storageId);
455
300
  },
456
- // ── Config (remote key-value) ─────────────────────────────────────────────
457
- /**
458
- * List all config keys for a project.
459
- * Backend uses ?env=<envId> (not ?envType). Resolves envType → envId automatically.
460
- */
301
+ // Config
461
302
  async listConfig(projectId, envType) {
462
- const query = {};
463
- if (envType) {
464
- const envId = await this.resolveEnvId(projectId, envType);
465
- if (envId) query.env = envId;
466
- }
467
- const res = await request(
468
- "GET",
469
- `/projects/${encodeURIComponent(projectId)}/config`,
470
- { query }
471
- );
472
- return Array.isArray(res) ? res : res.data ?? [];
303
+ return getMgmt().config.list(projectId, envType);
473
304
  },
474
- /**
475
- * Get a single config key.
476
- * Backend uses ?env=<envId> (not ?envType). Resolves envType → envId automatically.
477
- */
478
305
  async getConfig(projectId, key, envType) {
479
- const query = {};
480
- if (envType) {
481
- const envId = await this.resolveEnvId(projectId, envType);
482
- if (envId) query.env = envId;
483
- }
484
- return request(
485
- "GET",
486
- `/projects/${encodeURIComponent(projectId)}/config/${encodeURIComponent(key)}`,
487
- { query }
488
- );
306
+ return getMgmt().config.get(projectId, key, envType);
489
307
  },
490
- /**
491
- * Set a config key.
492
- * Backend expects { key, value, environmentId } (not envType).
493
- * Resolves envType → environmentId automatically when envType is provided.
494
- */
495
308
  async setConfig(projectId, key, value, envType) {
496
- let environmentId = null;
497
- if (envType) {
498
- environmentId = await this.resolveEnvId(projectId, envType);
499
- }
500
- return request("POST", `/projects/${encodeURIComponent(projectId)}/config`, {
501
- body: { key, value, environmentId }
502
- });
309
+ return getMgmt().config.set(projectId, key, value, envType);
503
310
  },
504
- /**
505
- * Delete a config key.
506
- * Backend uses ?env=<envId> (not ?envType). Resolves envType → envId automatically.
507
- */
508
311
  async deleteConfig(projectId, key, envType) {
509
- const query = {};
510
- if (envType) {
511
- const envId = await this.resolveEnvId(projectId, envType);
512
- if (envId) query.env = envId;
513
- }
514
- return request(
515
- "DELETE",
516
- `/projects/${encodeURIComponent(projectId)}/config/${encodeURIComponent(key)}`,
517
- { query }
518
- );
312
+ return getMgmt().config.delete(projectId, key, envType);
519
313
  },
520
- // ── Environments ──────────────────────────────────────────────────────────
521
- /** List environments for a project */
314
+ // Environments
522
315
  async listEnvironments(projectId) {
523
- const res = await request(
524
- "GET",
525
- `/projects/${encodeURIComponent(projectId)}/environments`
526
- );
527
- return Array.isArray(res) ? res : res.data ?? [];
316
+ return getMgmt().environments.list(projectId);
528
317
  },
529
- /**
530
- * Resolve an environment type string (e.g. "production") → its envId for the given project.
531
- * Returns null if not found. Used internally by config commands.
532
- */
533
318
  async resolveEnvId(projectId, envType) {
534
- const envs = await this.listEnvironments(projectId);
535
- const match = envs.find((e) => (e.envType ?? "").toLowerCase() === envType.toLowerCase());
536
- return match?.id ?? null;
319
+ return getMgmt().environments.resolveId(projectId, envType);
537
320
  },
538
- /** Promote an environment (e.g. staging → production).
539
- * Backend returns { promoted: number, services: [...], sourceEnvironment, targetEnvironment }
540
- */
541
321
  async promoteEnvironment(projectId, targetEnvId, sourceEnvId) {
542
- return request(
543
- "POST",
544
- `/projects/${encodeURIComponent(projectId)}/environments/${encodeURIComponent(targetEnvId)}/promote`,
545
- { body: { sourceEnvId } }
546
- );
322
+ return getMgmt().environments.promote(projectId, targetEnvId, sourceEnvId);
547
323
  },
548
- // ── Resource Bindings ─────────────────────────────────────────────────────
549
- /** List bindings for a resource (which envs it's linked to).
550
- * Backend returns { bindings: [...] }.
551
- */
324
+ // Resource Bindings
552
325
  async listResourceBindings(resourceId) {
553
- const res = await request(
554
- "GET",
555
- `/resources/${encodeURIComponent(resourceId)}/bindings`
556
- );
557
- return res.bindings ?? [];
326
+ return getMgmt().resources.listBindings(resourceId);
558
327
  },
559
- /**
560
- * Bind a resource to a project environment.
561
- * Backend expects { appEnvironmentId, role? }.
562
- * Accepts projectId + envType and resolves to appEnvironmentId automatically.
563
- */
564
328
  async bindResource(resourceId, data) {
565
- const appEnvironmentId = await this.resolveEnvId(data.projectId, data.envType);
566
- if (!appEnvironmentId) {
567
- throw new Error(`Environment '${data.envType}' not found for project '${data.projectId}'`);
568
- }
569
- return request(
570
- "POST",
571
- `/resources/${encodeURIComponent(resourceId)}/bindings`,
572
- { body: { appEnvironmentId, role: data.role ?? "primary" } }
573
- );
329
+ return getMgmt().resources.bind(resourceId, data);
574
330
  },
575
- /** Unbind a resource from a project environment */
576
331
  async unbindResource(resourceId, bindingId) {
577
- return request(
578
- "DELETE",
579
- `/resources/${encodeURIComponent(resourceId)}/bindings/${encodeURIComponent(bindingId)}`
580
- );
332
+ return getMgmt().resources.unbind(resourceId, bindingId);
581
333
  },
582
- // ── Tasks ─────────────────────────────────────────────────────────────────
583
- /**
584
- * List task definitions for a project environment.
585
- * Uses ?envId=<envId> (resolved from envType automatically).
586
- */
334
+ // Tasks
587
335
  async listTasks(projectId, envType) {
588
- const query = {};
589
- if (envType) {
590
- const envId = await this.resolveEnvId(projectId, envType);
591
- if (envId) query.envId = envId;
592
- }
593
- const res = await request(
594
- "GET",
595
- `/projects/${encodeURIComponent(projectId)}/tasks`,
596
- { query }
597
- );
598
- return res.tasks ?? [];
336
+ return getMgmt().tasks.list(projectId, envType);
599
337
  },
600
- /**
601
- * Create or update a task definition (upserts on taskName + environmentId).
602
- * Backend requires envId — resolves from envType automatically.
603
- */
604
338
  async createTask(projectId, data) {
605
- const envId = await this.resolveEnvId(projectId, data.envType);
606
- if (!envId)
607
- throw new Error(`Environment '${data.envType}' not found for project '${projectId}'`);
608
- const { envType: _drop, ...rest } = data;
609
- const res = await request(
610
- "POST",
611
- `/projects/${encodeURIComponent(projectId)}/tasks`,
612
- { body: { ...rest, envId } }
613
- );
614
- return res.task;
339
+ return getMgmt().tasks.create(projectId, data);
615
340
  },
616
- /** Get a single task definition */
617
341
  async getTask(projectId, taskId) {
618
- const res = await request(
619
- "GET",
620
- `/projects/${encodeURIComponent(projectId)}/tasks/${encodeURIComponent(taskId)}`
621
- );
622
- return res.task;
342
+ return getMgmt().tasks.get(projectId, taskId);
623
343
  },
624
- /** Update a task definition */
625
344
  async updateTask(projectId, taskId, data) {
626
- const res = await request(
627
- "PATCH",
628
- `/projects/${encodeURIComponent(projectId)}/tasks/${encodeURIComponent(taskId)}`,
629
- { body: data }
630
- );
631
- return res.task;
345
+ return getMgmt().tasks.update(projectId, taskId, data);
632
346
  },
633
- /** Delete a task definition */
634
347
  async deleteTask(projectId, taskId) {
635
- await request(
636
- "DELETE",
637
- `/projects/${encodeURIComponent(projectId)}/tasks/${encodeURIComponent(taskId)}`
638
- );
348
+ return getMgmt().tasks.delete(projectId, taskId);
349
+ },
350
+ // CLI-specific: auth poll (uses main sylphx.com domain, not api.sylphx.com)
351
+ async pollCliAuth(code) {
352
+ const AUTH_BASE_URL = "https://sylphx.com";
353
+ const res = await fetch(`${AUTH_BASE_URL}/api/auth/cli/poll?code=${encodeURIComponent(code)}`, {
354
+ headers: { "User-Agent": `sylphx-cli/${version}` }
355
+ });
356
+ if (!res.ok) {
357
+ throw new import_management.ApiError(res.status, "Failed to poll auth status");
358
+ }
359
+ return res.json();
639
360
  }
640
361
  };
362
+ var BASE_URL = process.env.SYLPHX_API_URL ?? "https://api.sylphx.com";
363
+ var API_BASE = `${BASE_URL}/v1`;
641
364
  function createLogStream(projectId, envType) {
642
365
  const params = new URLSearchParams({ envType, stream: "true", limit: "200" });
643
366
  return {
@@ -1875,7 +1598,6 @@ var loginCommand = new import_commander8.Command("login").description("Authentic
1875
1598
  try {
1876
1599
  config.setToken(opts.token);
1877
1600
  const me = await api.whoami();
1878
- config.setToken(opts.token);
1879
1601
  spinner2.succeed(import_chalk9.default.green(`Authenticated as ${import_chalk9.default.bold(me.user.email)}`));
1880
1602
  } catch (err) {
1881
1603
  config.clearToken();
@@ -2038,15 +1760,146 @@ var openCommand = new import_commander11.Command("open").description("Open the a
2038
1760
  }
2039
1761
  });
2040
1762
 
2041
- // src/commands/projects.ts
2042
- var import_node_readline4 = __toESM(require("readline"));
1763
+ // src/commands/orgs.ts
2043
1764
  var import_chalk13 = __toESM(require("chalk"));
2044
1765
  var import_commander12 = require("commander");
2045
1766
  var import_ora10 = __toESM(require("ora"));
2046
1767
  function requireAuth2() {
2047
1768
  const token = config.getToken();
2048
1769
  if (!token) {
2049
- console.log(import_chalk13.default.red("Not authenticated. Run `sylphx login` first."));
1770
+ console.error(import_chalk13.default.red("Not authenticated. Run `sylphx login` first."));
1771
+ process.exit(1);
1772
+ }
1773
+ return token;
1774
+ }
1775
+ function roleBadge(role) {
1776
+ switch (role.toLowerCase()) {
1777
+ case "owner":
1778
+ return import_chalk13.default.yellow("owner ");
1779
+ case "admin":
1780
+ return import_chalk13.default.cyan("admin ");
1781
+ default:
1782
+ return import_chalk13.default.dim("member");
1783
+ }
1784
+ }
1785
+ async function showCurrentOrg() {
1786
+ requireAuth2();
1787
+ const spinner = (0, import_ora10.default)("Fetching org info...").start();
1788
+ try {
1789
+ const [org, whoami] = await Promise.all([api.getCurrentOrg(), api.whoami()]);
1790
+ spinner.stop();
1791
+ console.log("");
1792
+ console.log(import_chalk13.default.bold(" Organization"));
1793
+ console.log(import_chalk13.default.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
1794
+ console.log(` ${import_chalk13.default.bold("Name")} ${org.name}`);
1795
+ console.log(` ${import_chalk13.default.bold("Slug")} ${import_chalk13.default.cyan(org.slug)}`);
1796
+ console.log(` ${import_chalk13.default.bold("ID")} ${import_chalk13.default.dim(org.id)}`);
1797
+ if (org.email) console.log(` ${import_chalk13.default.bold("Email")} ${org.email}`);
1798
+ console.log("");
1799
+ const allOrgs = whoami.orgs;
1800
+ if (allOrgs.length > 1) {
1801
+ console.log(import_chalk13.default.dim(` You are a member of ${allOrgs.length} organizations:`));
1802
+ for (const o of allOrgs) {
1803
+ const isCurrent = o.id === org.id;
1804
+ console.log(
1805
+ ` ${isCurrent ? import_chalk13.default.green("\u2192") : " "} ${import_chalk13.default.bold(o.name)} ${import_chalk13.default.dim(`(${o.slug})`)}`
1806
+ );
1807
+ }
1808
+ console.log("");
1809
+ }
1810
+ } catch (err) {
1811
+ spinner.fail("Failed to fetch org info");
1812
+ const message = err instanceof Error ? err.message : String(err);
1813
+ console.error(import_chalk13.default.red(message));
1814
+ process.exit(1);
1815
+ }
1816
+ }
1817
+ var membersListCommand = new import_commander12.Command("list").alias("ls").description("List organization members").action(async () => {
1818
+ requireAuth2();
1819
+ const spinner = (0, import_ora10.default)("Fetching members...").start();
1820
+ try {
1821
+ const org = await api.getCurrentOrg();
1822
+ const members = await api.listOrgMembers(org.id);
1823
+ spinner.stop();
1824
+ if (members.length === 0) {
1825
+ console.log(import_chalk13.default.dim("\n No members found.\n"));
1826
+ return;
1827
+ }
1828
+ const colEmail = Math.max(5, ...members.map((m) => m.email.length));
1829
+ const colName = Math.max(4, ...members.map((m) => (m.name ?? "\u2014").length));
1830
+ console.log("");
1831
+ console.log(import_chalk13.default.bold(` Members of ${org.name}`));
1832
+ console.log(import_chalk13.default.dim(` ${"\u2500".repeat(colEmail + colName + 20)}`));
1833
+ console.log(
1834
+ import_chalk13.default.dim(` ${"ROLE ".padEnd(7)} ${"EMAIL".padEnd(colEmail)} ${"NAME".padEnd(colName)}`)
1835
+ );
1836
+ console.log(import_chalk13.default.dim(` ${"\u2500".repeat(colEmail + colName + 20)}`));
1837
+ for (const m of members) {
1838
+ const joined = m.joinedAt ? new Date(m.joinedAt).toLocaleDateString() : "";
1839
+ console.log(
1840
+ ` ${roleBadge(m.role)} ${m.email.padEnd(colEmail)} ${(m.name ?? import_chalk13.default.dim("\u2014")).padEnd(colName)} ${import_chalk13.default.dim(joined)}`
1841
+ );
1842
+ }
1843
+ console.log("");
1844
+ console.log(import_chalk13.default.dim(` ${members.length} member${members.length !== 1 ? "s" : ""}`));
1845
+ console.log("");
1846
+ } catch (err) {
1847
+ spinner.fail("Failed to fetch members");
1848
+ const message = err instanceof Error ? err.message : String(err);
1849
+ console.error(import_chalk13.default.red(message));
1850
+ process.exit(1);
1851
+ }
1852
+ });
1853
+ var membersInviteCommand = new import_commander12.Command("invite").description("Invite a member to the organization by email").argument("<email>", "Email address to invite").option("--role <role>", "Role to assign (admin | member)", "member").action(async (email, options) => {
1854
+ requireAuth2();
1855
+ const role = options.role;
1856
+ if (role !== "admin" && role !== "member") {
1857
+ console.error(import_chalk13.default.red(`Invalid role "${role}". Must be "admin" or "member".`));
1858
+ process.exit(1);
1859
+ }
1860
+ const spinner = (0, import_ora10.default)(`Inviting ${email}...`).start();
1861
+ try {
1862
+ const org = await api.getCurrentOrg();
1863
+ await api.inviteOrgMember(org.id, email, role);
1864
+ spinner.succeed(
1865
+ `Invited ${import_chalk13.default.bold(email)} as ${import_chalk13.default.cyan(role)} to ${import_chalk13.default.bold(org.name)}`
1866
+ );
1867
+ console.log(import_chalk13.default.dim(" They will receive an invitation email shortly."));
1868
+ } catch (err) {
1869
+ spinner.fail("Failed to send invitation");
1870
+ const message = err instanceof Error ? err.message : String(err);
1871
+ console.error(import_chalk13.default.red(message));
1872
+ process.exit(1);
1873
+ }
1874
+ });
1875
+ var membersRemoveCommand = new import_commander12.Command("remove").description("Remove a member from the organization").argument("<userId>", "User ID to remove (use `sylphx orgs members` to list)").action(async (userId) => {
1876
+ requireAuth2();
1877
+ const spinner = (0, import_ora10.default)(`Removing member ${userId}...`).start();
1878
+ try {
1879
+ const org = await api.getCurrentOrg();
1880
+ await api.removeOrgMember(org.id, userId);
1881
+ spinner.succeed(`Removed member ${import_chalk13.default.bold(userId)} from ${import_chalk13.default.bold(org.name)}`);
1882
+ } catch (err) {
1883
+ spinner.fail("Failed to remove member");
1884
+ const message = err instanceof Error ? err.message : String(err);
1885
+ console.error(import_chalk13.default.red(message));
1886
+ process.exit(1);
1887
+ }
1888
+ });
1889
+ var membersCommand = new import_commander12.Command("members").description("Manage organization members").action(async () => {
1890
+ await membersListCommand.parseAsync([], { from: "user" });
1891
+ }).addCommand(membersListCommand).addCommand(membersInviteCommand).addCommand(membersRemoveCommand);
1892
+ var orgsCommand = new import_commander12.Command("orgs").description("Manage organizations").action(showCurrentOrg).addCommand(membersCommand);
1893
+
1894
+ // src/commands/projects.ts
1895
+ var import_node_readline4 = __toESM(require("readline"));
1896
+ var import_chalk14 = __toESM(require("chalk"));
1897
+ var import_commander13 = require("commander");
1898
+ var import_ora11 = __toESM(require("ora"));
1899
+ function requireAuth3() {
1900
+ const token = config.getToken();
1901
+ if (!token) {
1902
+ console.log(import_chalk14.default.red("Not authenticated. Run `sylphx login` first."));
2050
1903
  process.exit(1);
2051
1904
  }
2052
1905
  return token;
@@ -2063,41 +1916,41 @@ function prompt4(question) {
2063
1916
  });
2064
1917
  });
2065
1918
  }
2066
- var projectsListCommand = new import_commander12.Command("list").description("List all projects").action(async () => {
2067
- requireAuth2();
2068
- const spinner = (0, import_ora10.default)("Fetching projects...").start();
1919
+ var projectsListCommand = new import_commander13.Command("list").description("List all projects").action(async () => {
1920
+ requireAuth3();
1921
+ const spinner = (0, import_ora11.default)("Fetching projects...").start();
2069
1922
  try {
2070
1923
  const projects = await api.listProjects();
2071
1924
  spinner.stop();
2072
1925
  if (projects.length === 0) {
2073
- console.log(import_chalk13.default.dim("\n No projects found.\n"));
1926
+ console.log(import_chalk14.default.dim("\n No projects found.\n"));
2074
1927
  return;
2075
1928
  }
2076
1929
  const colSlug = Math.max(4, ...projects.map((p) => p.slug.length));
2077
1930
  const colName = Math.max(4, ...projects.map((p) => p.name.length));
2078
1931
  console.log("");
2079
- console.log(import_chalk13.default.bold(" Projects"));
2080
- console.log(import_chalk13.default.dim(` ${"\u2500".repeat(colSlug + colName + 30)}`));
1932
+ console.log(import_chalk14.default.bold(" Projects"));
1933
+ console.log(import_chalk14.default.dim(` ${"\u2500".repeat(colSlug + colName + 30)}`));
2081
1934
  console.log(
2082
- import_chalk13.default.dim(` ${"SLUG".padEnd(colSlug)} ${"NAME".padEnd(colName)} ${"ENVIRONMENTS"}`)
1935
+ import_chalk14.default.dim(` ${"SLUG".padEnd(colSlug)} ${"NAME".padEnd(colName)} ${"ENVIRONMENTS"}`)
2083
1936
  );
2084
- console.log(import_chalk13.default.dim(` ${"\u2500".repeat(colSlug + colName + 30)}`));
1937
+ console.log(import_chalk14.default.dim(` ${"\u2500".repeat(colSlug + colName + 30)}`));
2085
1938
  for (const p of projects) {
2086
- const envNames = p.environments && p.environments.length > 0 ? p.environments.map((e) => e.name || e.envType || e.id).join(", ") : import_chalk13.default.dim("\u2014");
1939
+ const envNames = p.environments && p.environments.length > 0 ? p.environments.map((e) => e.name || e.envType || e.id).join(", ") : import_chalk14.default.dim("\u2014");
2087
1940
  console.log(
2088
- ` ${import_chalk13.default.cyan(p.slug.padEnd(colSlug))} ${p.name.padEnd(colName)} ${envNames}`
1941
+ ` ${import_chalk14.default.cyan(p.slug.padEnd(colSlug))} ${p.name.padEnd(colName)} ${envNames}`
2089
1942
  );
2090
1943
  }
2091
1944
  console.log("");
2092
1945
  } catch (err) {
2093
- spinner.fail(import_chalk13.default.red(`Failed: ${err instanceof Error ? err.message : String(err)}`));
1946
+ spinner.fail(import_chalk14.default.red(`Failed: ${err instanceof Error ? err.message : String(err)}`));
2094
1947
  process.exit(1);
2095
1948
  }
2096
1949
  });
2097
- var projectsCreateCommand = new import_commander12.Command("create").description("Create a new project (without linking the current directory)").argument("<name>", "Project name").option("--git <repo>", "Git repository (e.g. owner/repo)").option("--port <port>", "Application port").action(async (name, opts) => {
2098
- requireAuth2();
1950
+ var projectsCreateCommand = new import_commander13.Command("create").description("Create a new project (without linking the current directory)").argument("<name>", "Project name").option("--git <repo>", "Git repository (e.g. owner/repo)").option("--port <port>", "Application port").action(async (name, opts) => {
1951
+ requireAuth3();
2099
1952
  const slug = slugify2(name);
2100
- const spinner = (0, import_ora10.default)(`Creating project ${import_chalk13.default.bold(name)}...`).start();
1953
+ const spinner = (0, import_ora11.default)(`Creating project ${import_chalk14.default.bold(name)}...`).start();
2101
1954
  try {
2102
1955
  const project = await api.createProject({
2103
1956
  name,
@@ -2105,63 +1958,63 @@ var projectsCreateCommand = new import_commander12.Command("create").description
2105
1958
  ...opts.git ? { gitRepository: opts.git } : {},
2106
1959
  ...opts.port ? { port: Number.parseInt(opts.port, 10) } : {}
2107
1960
  });
2108
- spinner.succeed(import_chalk13.default.green(`\u2713 Created project ${import_chalk13.default.bold(project.name)}`));
1961
+ spinner.succeed(import_chalk14.default.green(`\u2713 Created project ${import_chalk14.default.bold(project.name)}`));
2109
1962
  console.log("");
2110
- console.log(import_chalk13.default.dim(` ID : ${project.id}`));
2111
- console.log(import_chalk13.default.dim(` Slug : ${project.slug}`));
1963
+ console.log(import_chalk14.default.dim(` ID : ${project.id}`));
1964
+ console.log(import_chalk14.default.dim(` Slug : ${project.slug}`));
2112
1965
  console.log("");
2113
1966
  console.log(
2114
- import_chalk13.default.dim(` Run ${import_chalk13.default.cyan("sylphx link")} to link this project to a directory.`)
1967
+ import_chalk14.default.dim(` Run ${import_chalk14.default.cyan("sylphx link")} to link this project to a directory.`)
2115
1968
  );
2116
1969
  console.log("");
2117
1970
  } catch (err) {
2118
- spinner.fail(import_chalk13.default.red(`Failed: ${err instanceof Error ? err.message : String(err)}`));
1971
+ spinner.fail(import_chalk14.default.red(`Failed: ${err instanceof Error ? err.message : String(err)}`));
2119
1972
  process.exit(1);
2120
1973
  }
2121
1974
  });
2122
- var projectsDeleteCommand = new import_commander12.Command("delete").description("Delete a project").argument("<id>", "Project ID or slug").option("--force", "Skip confirmation prompt").action(async (id, opts) => {
2123
- requireAuth2();
1975
+ var projectsDeleteCommand = new import_commander13.Command("delete").description("Delete a project").argument("<id>", "Project ID or slug").option("--force", "Skip confirmation prompt").action(async (id, opts) => {
1976
+ requireAuth3();
2124
1977
  if (!opts.force) {
2125
1978
  console.log("");
2126
1979
  console.log(
2127
- import_chalk13.default.yellow(` \u26A0 You are about to permanently delete project ${import_chalk13.default.bold(id)}.`)
1980
+ import_chalk14.default.yellow(` \u26A0 You are about to permanently delete project ${import_chalk14.default.bold(id)}.`)
2128
1981
  );
2129
- console.log(import_chalk13.default.yellow(" This action cannot be undone."));
1982
+ console.log(import_chalk14.default.yellow(" This action cannot be undone."));
2130
1983
  console.log("");
2131
1984
  const answer = await prompt4(" Type the project ID/slug to confirm");
2132
1985
  if (answer !== id) {
2133
- console.log(import_chalk13.default.red("Confirmation did not match. Aborted."));
1986
+ console.log(import_chalk14.default.red("Confirmation did not match. Aborted."));
2134
1987
  process.exit(1);
2135
1988
  }
2136
1989
  }
2137
- const spinner = (0, import_ora10.default)(`Deleting project ${import_chalk13.default.bold(id)}...`).start();
1990
+ const spinner = (0, import_ora11.default)(`Deleting project ${import_chalk14.default.bold(id)}...`).start();
2138
1991
  try {
2139
1992
  await api.deleteProject(id);
2140
- spinner.succeed(import_chalk13.default.green(`\u2713 Deleted project ${import_chalk13.default.bold(id)}`));
1993
+ spinner.succeed(import_chalk14.default.green(`\u2713 Deleted project ${import_chalk14.default.bold(id)}`));
2141
1994
  } catch (err) {
2142
- spinner.fail(import_chalk13.default.red(`Failed: ${err instanceof Error ? err.message : String(err)}`));
1995
+ spinner.fail(import_chalk14.default.red(`Failed: ${err instanceof Error ? err.message : String(err)}`));
2143
1996
  process.exit(1);
2144
1997
  }
2145
1998
  });
2146
- var projectsCommand = new import_commander12.Command("projects").description("Manage Sylphx projects").addCommand(projectsListCommand).addCommand(projectsCreateCommand).addCommand(projectsDeleteCommand);
1999
+ var projectsCommand = new import_commander13.Command("projects").description("Manage Sylphx projects").addCommand(projectsListCommand).addCommand(projectsCreateCommand).addCommand(projectsDeleteCommand);
2147
2000
 
2148
2001
  // src/commands/promote.ts
2149
- var import_chalk14 = __toESM(require("chalk"));
2150
- var import_commander13 = require("commander");
2151
- var import_ora11 = __toESM(require("ora"));
2152
- var promoteCommand = new import_commander13.Command("promote").description("Promote an environment (e.g. staging \u2192 production)").option("--from <env>", "Source environment (default: staging)", "staging").option("--to <env>", "Target environment (default: production)", "production").option("--force", "Skip confirmation prompt").action(async (opts) => {
2002
+ var import_chalk15 = __toESM(require("chalk"));
2003
+ var import_commander14 = require("commander");
2004
+ var import_ora12 = __toESM(require("ora"));
2005
+ var promoteCommand = new import_commander14.Command("promote").description("Promote an environment (e.g. staging \u2192 production)").option("--from <env>", "Source environment (default: staging)", "staging").option("--to <env>", "Target environment (default: production)", "production").option("--force", "Skip confirmation prompt").action(async (opts) => {
2153
2006
  const token = config.getToken();
2154
2007
  if (!token) {
2155
- console.log(import_chalk14.default.red("Not authenticated. Run `sylphx login` first."));
2008
+ console.log(import_chalk15.default.red("Not authenticated. Run `sylphx login` first."));
2156
2009
  process.exit(1);
2157
2010
  }
2158
2011
  const linked = config.getLinkedApp();
2159
2012
  if (!linked) {
2160
- console.log(import_chalk14.default.red("No app linked. Run `sylphx link` first."));
2013
+ console.log(import_chalk15.default.red("No app linked. Run `sylphx link` first."));
2161
2014
  process.exit(1);
2162
2015
  }
2163
2016
  if (opts.from === opts.to) {
2164
- console.log(import_chalk14.default.red("Source and target environments must be different."));
2017
+ console.log(import_chalk15.default.red("Source and target environments must be different."));
2165
2018
  process.exit(1);
2166
2019
  }
2167
2020
  if (!opts.force) {
@@ -2169,13 +2022,13 @@ var promoteCommand = new import_commander13.Command("promote").description("Prom
2169
2022
  const rl = readline9.createInterface({ input: process.stdin, output: process.stdout });
2170
2023
  await new Promise((resolve) => {
2171
2024
  rl.question(
2172
- import_chalk14.default.yellow(
2173
- ` Promote ${import_chalk14.default.bold(linked.appId)}: ${import_chalk14.default.cyan(opts.from)} \u2192 ${import_chalk14.default.green(opts.to)}? (y/N) `
2025
+ import_chalk15.default.yellow(
2026
+ ` Promote ${import_chalk15.default.bold(linked.appId)}: ${import_chalk15.default.cyan(opts.from)} \u2192 ${import_chalk15.default.green(opts.to)}? (y/N) `
2174
2027
  ),
2175
2028
  (answer) => {
2176
2029
  rl.close();
2177
2030
  if (answer.toLowerCase() !== "y") {
2178
- console.log(import_chalk14.default.dim(" Cancelled."));
2031
+ console.log(import_chalk15.default.dim(" Cancelled."));
2179
2032
  process.exit(0);
2180
2033
  }
2181
2034
  resolve();
@@ -2183,7 +2036,7 @@ var promoteCommand = new import_commander13.Command("promote").description("Prom
2183
2036
  );
2184
2037
  });
2185
2038
  }
2186
- const spinner = (0, import_ora11.default)(`Resolving environments...`).start();
2039
+ const spinner = (0, import_ora12.default)(`Resolving environments...`).start();
2187
2040
  try {
2188
2041
  const envs = await api.listEnvironments(linked.appId);
2189
2042
  const sourceEnv = envs.find(
@@ -2193,48 +2046,48 @@ var promoteCommand = new import_commander13.Command("promote").description("Prom
2193
2046
  (e) => (e.envType ?? e.name ?? "").toLowerCase() === opts.to.toLowerCase()
2194
2047
  );
2195
2048
  if (!sourceEnv) {
2196
- spinner.fail(import_chalk14.default.red(`Source environment '${opts.from}' not found.`));
2197
- console.log(import_chalk14.default.dim(` Available: ${envs.map((e) => e.envType ?? e.name).join(", ")}`));
2049
+ spinner.fail(import_chalk15.default.red(`Source environment '${opts.from}' not found.`));
2050
+ console.log(import_chalk15.default.dim(` Available: ${envs.map((e) => e.envType ?? e.name).join(", ")}`));
2198
2051
  process.exit(1);
2199
2052
  }
2200
2053
  if (!targetEnv) {
2201
- spinner.fail(import_chalk14.default.red(`Target environment '${opts.to}' not found.`));
2202
- console.log(import_chalk14.default.dim(` Available: ${envs.map((e) => e.envType ?? e.name).join(", ")}`));
2054
+ spinner.fail(import_chalk15.default.red(`Target environment '${opts.to}' not found.`));
2055
+ console.log(import_chalk15.default.dim(` Available: ${envs.map((e) => e.envType ?? e.name).join(", ")}`));
2203
2056
  process.exit(1);
2204
2057
  }
2205
2058
  spinner.text = `Promoting ${opts.from} \u2192 ${opts.to}...`;
2206
2059
  const result = await api.promoteEnvironment(linked.appId, targetEnv.id, sourceEnv.id);
2207
2060
  if (result.promoted === 0) {
2208
2061
  spinner.warn(
2209
- import_chalk14.default.yellow(
2210
- `No services promoted from ${import_chalk14.default.bold(opts.from)} \u2014 nothing to push (source may have no deployed image yet)`
2062
+ import_chalk15.default.yellow(
2063
+ `No services promoted from ${import_chalk15.default.bold(opts.from)} \u2014 nothing to push (source may have no deployed image yet)`
2211
2064
  )
2212
2065
  );
2213
2066
  } else {
2214
2067
  spinner.succeed(
2215
- import_chalk14.default.green(
2216
- `\u2713 Promoted ${import_chalk14.default.bold(opts.from)} \u2192 ${import_chalk14.default.bold(opts.to)} (${result.promoted} service${result.promoted !== 1 ? "s" : ""})`
2068
+ import_chalk15.default.green(
2069
+ `\u2713 Promoted ${import_chalk15.default.bold(opts.from)} \u2192 ${import_chalk15.default.bold(opts.to)} (${result.promoted} service${result.promoted !== 1 ? "s" : ""})`
2217
2070
  )
2218
2071
  );
2219
2072
  console.log(
2220
- import_chalk14.default.dim(`
2221
- Deployments queued. Run ${import_chalk14.default.cyan("sylphx status")} to monitor.`)
2073
+ import_chalk15.default.dim(`
2074
+ Deployments queued. Run ${import_chalk15.default.cyan("sylphx status")} to monitor.`)
2222
2075
  );
2223
2076
  }
2224
2077
  } catch (err) {
2225
- spinner.fail(import_chalk14.default.red(`Promote failed: ${err instanceof Error ? err.message : String(err)}`));
2078
+ spinner.fail(import_chalk15.default.red(`Promote failed: ${err instanceof Error ? err.message : String(err)}`));
2226
2079
  process.exit(1);
2227
2080
  }
2228
2081
  });
2229
2082
 
2230
2083
  // src/commands/resources.ts
2231
- var import_chalk15 = __toESM(require("chalk"));
2232
- var import_commander14 = require("commander");
2233
- var import_ora12 = __toESM(require("ora"));
2084
+ var import_chalk16 = __toESM(require("chalk"));
2085
+ var import_commander15 = require("commander");
2086
+ var import_ora13 = __toESM(require("ora"));
2234
2087
  function requireLinkedApp4() {
2235
2088
  const linked = config.getLinkedApp();
2236
2089
  if (!linked) {
2237
- console.log(import_chalk15.default.red("No app linked. Run `sylphx link` first."));
2090
+ console.log(import_chalk16.default.red("No app linked. Run `sylphx link` first."));
2238
2091
  process.exit(1);
2239
2092
  }
2240
2093
  return linked;
@@ -2242,145 +2095,145 @@ function requireLinkedApp4() {
2242
2095
  function requireToken2() {
2243
2096
  const token = config.getToken();
2244
2097
  if (!token) {
2245
- console.log(import_chalk15.default.red("Not authenticated. Run `sylphx login` first."));
2098
+ console.log(import_chalk16.default.red("Not authenticated. Run `sylphx login` first."));
2246
2099
  process.exit(1);
2247
2100
  }
2248
2101
  return token;
2249
2102
  }
2250
- var listCmd2 = new import_commander14.Command("list").description("List managed resources (databases, volumes, storage)").option("--kind <kind>", "Filter by kind: database, volume, storage").action(async (opts) => {
2103
+ var listCmd2 = new import_commander15.Command("list").description("List managed resources (databases, volumes, storage)").option("--kind <kind>", "Filter by kind: database, volume, storage").action(async (opts) => {
2251
2104
  requireToken2();
2252
- const spinner = (0, import_ora12.default)("Fetching resources...").start();
2105
+ const spinner = (0, import_ora13.default)("Fetching resources...").start();
2253
2106
  try {
2254
2107
  const resources = await api.listDatabases();
2255
2108
  spinner.stop();
2256
2109
  if (resources.length === 0) {
2257
- console.log(import_chalk15.default.dim(` No resources found.`));
2110
+ console.log(import_chalk16.default.dim(` No resources found.`));
2258
2111
  return;
2259
2112
  }
2260
2113
  console.log();
2261
2114
  console.log(
2262
- ` ${import_chalk15.default.bold("NAME".padEnd(24))} ${"KIND".padEnd(12)} ${"STATUS".padEnd(14)} ID`
2115
+ ` ${import_chalk16.default.bold("NAME".padEnd(24))} ${"KIND".padEnd(12)} ${"STATUS".padEnd(14)} ID`
2263
2116
  );
2264
2117
  console.log(` ${"\u2500".repeat(72)}`);
2265
2118
  for (const r of resources) {
2266
- const statusColor2 = r.status === "ready" ? import_chalk15.default.green((r.status ?? "unknown").padEnd(14)) : import_chalk15.default.yellow((r.status ?? "unknown").padEnd(14));
2119
+ const statusColor2 = r.status === "ready" ? import_chalk16.default.green((r.status ?? "unknown").padEnd(14)) : import_chalk16.default.yellow((r.status ?? "unknown").padEnd(14));
2267
2120
  console.log(
2268
- ` ${import_chalk15.default.cyan(r.name.padEnd(24))} ${"database".padEnd(12)} ${statusColor2} ${import_chalk15.default.dim(r.id)}`
2121
+ ` ${import_chalk16.default.cyan(r.name.padEnd(24))} ${"database".padEnd(12)} ${statusColor2} ${import_chalk16.default.dim(r.id)}`
2269
2122
  );
2270
2123
  }
2271
2124
  console.log();
2272
2125
  } catch (err) {
2273
- spinner.fail(import_chalk15.default.red(err instanceof Error ? err.message : String(err)));
2126
+ spinner.fail(import_chalk16.default.red(err instanceof Error ? err.message : String(err)));
2274
2127
  process.exit(1);
2275
2128
  }
2276
2129
  });
2277
- var getCmd2 = new import_commander14.Command("get").description("Get details of a resource").argument("<id>", "Resource ID").action(async (id) => {
2130
+ var getCmd2 = new import_commander15.Command("get").description("Get details of a resource").argument("<id>", "Resource ID").action(async (id) => {
2278
2131
  requireToken2();
2279
- const spinner = (0, import_ora12.default)(`Fetching resource ${id}...`).start();
2132
+ const spinner = (0, import_ora13.default)(`Fetching resource ${id}...`).start();
2280
2133
  try {
2281
2134
  const r = await api.getDatabase(id);
2282
2135
  spinner.stop();
2283
2136
  console.log();
2284
- console.log(` ${import_chalk15.default.bold("Name:")} ${import_chalk15.default.cyan(r.name)}`);
2285
- console.log(` ${import_chalk15.default.bold("ID:")} ${r.id}`);
2137
+ console.log(` ${import_chalk16.default.bold("Name:")} ${import_chalk16.default.cyan(r.name)}`);
2138
+ console.log(` ${import_chalk16.default.bold("ID:")} ${r.id}`);
2286
2139
  console.log(
2287
- ` ${import_chalk15.default.bold("Status:")} ${r.status === "ready" ? import_chalk15.default.green(r.status) : import_chalk15.default.yellow(r.status ?? "unknown")}`
2140
+ ` ${import_chalk16.default.bold("Status:")} ${r.status === "ready" ? import_chalk16.default.green(r.status) : import_chalk16.default.yellow(r.status ?? "unknown")}`
2288
2141
  );
2289
- if (r.tier) console.log(` ${import_chalk15.default.bold("Tier:")} ${r.tier}`);
2290
- if (r.host) console.log(` ${import_chalk15.default.bold("Host:")} ${r.host}${r.port ? `:${r.port}` : ""}`);
2142
+ if (r.tier) console.log(` ${import_chalk16.default.bold("Tier:")} ${r.tier}`);
2143
+ if (r.host) console.log(` ${import_chalk16.default.bold("Host:")} ${r.host}${r.port ? `:${r.port}` : ""}`);
2291
2144
  if (r.connectionString) {
2292
- console.log(` ${import_chalk15.default.bold("DSN:")} ${import_chalk15.default.dim(r.connectionString)}`);
2145
+ console.log(` ${import_chalk16.default.bold("DSN:")} ${import_chalk16.default.dim(r.connectionString)}`);
2293
2146
  }
2294
- if (r.env) console.log(` ${import_chalk15.default.bold("Env:")} ${r.env}`);
2147
+ if (r.env) console.log(` ${import_chalk16.default.bold("Env:")} ${r.env}`);
2295
2148
  console.log();
2296
2149
  } catch (err) {
2297
- spinner.fail(import_chalk15.default.red(err instanceof Error ? err.message : String(err)));
2150
+ spinner.fail(import_chalk16.default.red(err instanceof Error ? err.message : String(err)));
2298
2151
  process.exit(1);
2299
2152
  }
2300
2153
  });
2301
- var bindingsCmd = new import_commander14.Command("bindings").description("List project bindings for a resource").argument("<id>", "Resource ID").action(async (id) => {
2154
+ var bindingsCmd = new import_commander15.Command("bindings").description("List project bindings for a resource").argument("<id>", "Resource ID").action(async (id) => {
2302
2155
  requireToken2();
2303
- const spinner = (0, import_ora12.default)(`Fetching bindings for ${id}...`).start();
2156
+ const spinner = (0, import_ora13.default)(`Fetching bindings for ${id}...`).start();
2304
2157
  try {
2305
2158
  const bindings = await api.listResourceBindings(id);
2306
2159
  spinner.stop();
2307
2160
  if (bindings.length === 0) {
2308
- console.log(import_chalk15.default.dim(" No bindings. Use `sylphx resources bind <id>` to link."));
2161
+ console.log(import_chalk16.default.dim(" No bindings. Use `sylphx resources bind <id>` to link."));
2309
2162
  return;
2310
2163
  }
2311
2164
  console.log();
2312
2165
  console.log(
2313
- ` ${import_chalk15.default.bold("BINDING ID".padEnd(26))} ${"PROJECT".padEnd(24)} ${"ENV".padEnd(12)} ROLE`
2166
+ ` ${import_chalk16.default.bold("BINDING ID".padEnd(26))} ${"PROJECT".padEnd(24)} ${"ENV".padEnd(12)} ROLE`
2314
2167
  );
2315
2168
  console.log(` ${"\u2500".repeat(80)}`);
2316
2169
  for (const b of bindings) {
2317
2170
  const project = b.projectName ?? b.projectSlug ?? "\u2014";
2318
2171
  const env = b.envName ?? "\u2014";
2319
2172
  console.log(
2320
- ` ${import_chalk15.default.dim(b.id.padEnd(26))} ${project.padEnd(24)} ${env.padEnd(12)} ${b.role}`
2173
+ ` ${import_chalk16.default.dim(b.id.padEnd(26))} ${project.padEnd(24)} ${env.padEnd(12)} ${b.role}`
2321
2174
  );
2322
2175
  }
2323
2176
  console.log();
2324
2177
  } catch (err) {
2325
- spinner.fail(import_chalk15.default.red(err instanceof Error ? err.message : String(err)));
2178
+ spinner.fail(import_chalk16.default.red(err instanceof Error ? err.message : String(err)));
2326
2179
  process.exit(1);
2327
2180
  }
2328
2181
  });
2329
- var bindCmd = new import_commander14.Command("bind").description("Bind a resource to this project environment").argument("<id>", "Resource ID (e.g. res_xxx)").option("--env <env>", "Environment (default: production)", "production").option(
2182
+ var bindCmd = new import_commander15.Command("bind").description("Bind a resource to this project environment").argument("<id>", "Resource ID (e.g. res_xxx)").option("--env <env>", "Environment (default: production)", "production").option(
2330
2183
  "--role <role>",
2331
2184
  "Binding role: primary, replica, analytics, backup (default: primary)",
2332
2185
  "primary"
2333
2186
  ).action(async (id, opts) => {
2334
2187
  requireToken2();
2335
2188
  const linked = requireLinkedApp4();
2336
- const spinner = (0, import_ora12.default)(`Binding resource ${id} to ${linked.appId} [${opts.env}]...`).start();
2189
+ const spinner = (0, import_ora13.default)(`Binding resource ${id} to ${linked.appId} [${opts.env}]...`).start();
2337
2190
  try {
2338
2191
  const binding = await api.bindResource(id, {
2339
2192
  projectId: linked.appId,
2340
2193
  envType: opts.env,
2341
2194
  role: opts.role
2342
2195
  });
2343
- spinner.succeed(import_chalk15.default.green(`\u2713 Resource bound (${binding.role})`));
2196
+ spinner.succeed(import_chalk16.default.green(`\u2713 Resource bound (${binding.role})`));
2344
2197
  console.log();
2345
- console.log(` ${import_chalk15.default.dim("Binding ID:")} ${binding.id}`);
2346
- console.log(` ${import_chalk15.default.dim("Env:")} ${binding.envName ?? opts.env}`);
2198
+ console.log(` ${import_chalk16.default.dim("Binding ID:")} ${binding.id}`);
2199
+ console.log(` ${import_chalk16.default.dim("Env:")} ${binding.envName ?? opts.env}`);
2347
2200
  console.log(
2348
- import_chalk15.default.dim(
2201
+ import_chalk16.default.dim(
2349
2202
  `
2350
- Run ${import_chalk15.default.cyan("sylphx deploy")} to apply the connection vars to your deployment.`
2203
+ Run ${import_chalk16.default.cyan("sylphx deploy")} to apply the connection vars to your deployment.`
2351
2204
  )
2352
2205
  );
2353
2206
  } catch (err) {
2354
- spinner.fail(import_chalk15.default.red(err instanceof Error ? err.message : String(err)));
2207
+ spinner.fail(import_chalk16.default.red(err instanceof Error ? err.message : String(err)));
2355
2208
  process.exit(1);
2356
2209
  }
2357
2210
  });
2358
- var unbindCmd = new import_commander14.Command("unbind").description("Remove a resource binding").argument("<id>", "Resource ID").argument("<binding-id>", "Binding ID (from `sylphx resources bindings <id>`)").action(async (id, bindingId) => {
2211
+ var unbindCmd = new import_commander15.Command("unbind").description("Remove a resource binding").argument("<id>", "Resource ID").argument("<binding-id>", "Binding ID (from `sylphx resources bindings <id>`)").action(async (id, bindingId) => {
2359
2212
  requireToken2();
2360
- const spinner = (0, import_ora12.default)(`Removing binding ${bindingId}...`).start();
2213
+ const spinner = (0, import_ora13.default)(`Removing binding ${bindingId}...`).start();
2361
2214
  try {
2362
2215
  await api.unbindResource(id, bindingId);
2363
- spinner.succeed(import_chalk15.default.green(`\u2713 Binding removed`));
2216
+ spinner.succeed(import_chalk16.default.green(`\u2713 Binding removed`));
2364
2217
  } catch (err) {
2365
- spinner.fail(import_chalk15.default.red(err instanceof Error ? err.message : String(err)));
2218
+ spinner.fail(import_chalk16.default.red(err instanceof Error ? err.message : String(err)));
2366
2219
  process.exit(1);
2367
2220
  }
2368
2221
  });
2369
- var resourcesCommand = new import_commander14.Command("resources").description("Manage resources and project bindings").addCommand(listCmd2).addCommand(getCmd2).addCommand(bindingsCmd).addCommand(bindCmd).addCommand(unbindCmd).action(() => resourcesCommand.help());
2222
+ var resourcesCommand = new import_commander15.Command("resources").description("Manage resources and project bindings").addCommand(listCmd2).addCommand(getCmd2).addCommand(bindingsCmd).addCommand(bindCmd).addCommand(unbindCmd).action(() => resourcesCommand.help());
2370
2223
 
2371
2224
  // src/commands/rollback.ts
2372
- var import_chalk16 = __toESM(require("chalk"));
2373
- var import_commander15 = require("commander");
2374
- var import_ora13 = __toESM(require("ora"));
2375
- var rollbackCommand = new import_commander15.Command("rollback").description("Rollback to the previous deployment").option("--env <env>", "Environment to rollback (e.g. production, staging)").option("--deployment <id>", "Rollback to a specific deployment ID").option("--force", "Skip confirmation prompt").action(async (opts) => {
2225
+ var import_chalk17 = __toESM(require("chalk"));
2226
+ var import_commander16 = require("commander");
2227
+ var import_ora14 = __toESM(require("ora"));
2228
+ var rollbackCommand = new import_commander16.Command("rollback").description("Rollback to the previous deployment").option("--env <env>", "Environment to rollback (e.g. production, staging)").option("--deployment <id>", "Rollback to a specific deployment ID").option("--force", "Skip confirmation prompt").action(async (opts) => {
2376
2229
  const token = config.getToken();
2377
2230
  if (!token) {
2378
- console.log(import_chalk16.default.red("Not authenticated. Run `sylphx login` first."));
2231
+ console.log(import_chalk17.default.red("Not authenticated. Run `sylphx login` first."));
2379
2232
  process.exit(1);
2380
2233
  }
2381
2234
  const linked = config.getLinkedApp();
2382
2235
  if (!linked) {
2383
- console.log(import_chalk16.default.red("No app linked. Run `sylphx link` first."));
2236
+ console.log(import_chalk17.default.red("No app linked. Run `sylphx link` first."));
2384
2237
  process.exit(1);
2385
2238
  }
2386
2239
  const envType = opts.env ?? linked.defaultEnv ?? "production";
@@ -2388,13 +2241,13 @@ var rollbackCommand = new import_commander15.Command("rollback").description("Ro
2388
2241
  const readline9 = await import("readline");
2389
2242
  const rl = readline9.createInterface({ input: process.stdin, output: process.stdout });
2390
2243
  await new Promise((resolve) => {
2391
- const label = opts.deployment ? `deployment ${import_chalk16.default.bold(opts.deployment)}` : `previous deployment`;
2244
+ const label = opts.deployment ? `deployment ${import_chalk17.default.bold(opts.deployment)}` : `previous deployment`;
2392
2245
  rl.question(
2393
- import_chalk16.default.yellow(` Rollback ${import_chalk16.default.bold(linked.appId)} [${envType}] to ${label}? (y/N) `),
2246
+ import_chalk17.default.yellow(` Rollback ${import_chalk17.default.bold(linked.appId)} [${envType}] to ${label}? (y/N) `),
2394
2247
  (answer) => {
2395
2248
  rl.close();
2396
2249
  if (answer.toLowerCase() !== "y") {
2397
- console.log(import_chalk16.default.dim(" Cancelled."));
2250
+ console.log(import_chalk17.default.dim(" Cancelled."));
2398
2251
  process.exit(0);
2399
2252
  }
2400
2253
  resolve();
@@ -2402,7 +2255,7 @@ var rollbackCommand = new import_commander15.Command("rollback").description("Ro
2402
2255
  );
2403
2256
  });
2404
2257
  }
2405
- const spinner = (0, import_ora13.default)(`Rolling back ${linked.appId} [${envType}]...`).start();
2258
+ const spinner = (0, import_ora14.default)(`Rolling back ${linked.appId} [${envType}]...`).start();
2406
2259
  try {
2407
2260
  let rollbackBody;
2408
2261
  if (opts.deployment) {
@@ -2414,7 +2267,7 @@ var rollbackCommand = new import_commander15.Command("rollback").description("Ro
2414
2267
  );
2415
2268
  if (!envEntry?.envId) {
2416
2269
  spinner.fail(
2417
- import_chalk16.default.red(
2270
+ import_chalk17.default.red(
2418
2271
  `Could not find environment '${envType}'. Run \`sylphx status\` to see available environments.`
2419
2272
  )
2420
2273
  );
@@ -2423,21 +2276,21 @@ var rollbackCommand = new import_commander15.Command("rollback").description("Ro
2423
2276
  rollbackBody = { envId: envEntry.envId };
2424
2277
  }
2425
2278
  const result = await api.rollback(linked.appId, rollbackBody);
2426
- spinner.succeed(import_chalk16.default.green(`\u2713 Rollback initiated`));
2279
+ spinner.succeed(import_chalk17.default.green(`\u2713 Rollback initiated`));
2427
2280
  if (result.deploymentId) {
2428
- console.log(import_chalk16.default.dim(` Deployment ID: ${result.deploymentId}`));
2281
+ console.log(import_chalk17.default.dim(` Deployment ID: ${result.deploymentId}`));
2429
2282
  }
2430
2283
  if (result.status) {
2431
- console.log(import_chalk16.default.dim(` Status: ${result.status}`));
2284
+ console.log(import_chalk17.default.dim(` Status: ${result.status}`));
2432
2285
  }
2433
2286
  if (result.message) {
2434
- console.log(import_chalk16.default.dim(` ${result.message}`));
2287
+ console.log(import_chalk17.default.dim(` ${result.message}`));
2435
2288
  }
2436
- console.log(import_chalk16.default.dim(`
2437
- Run ${import_chalk16.default.cyan("sylphx status")} to monitor progress.`));
2289
+ console.log(import_chalk17.default.dim(`
2290
+ Run ${import_chalk17.default.cyan("sylphx status")} to monitor progress.`));
2438
2291
  } catch (err) {
2439
2292
  spinner.fail(
2440
- import_chalk16.default.red(`Rollback failed: ${err instanceof Error ? err.message : String(err)}`)
2293
+ import_chalk17.default.red(`Rollback failed: ${err instanceof Error ? err.message : String(err)}`)
2441
2294
  );
2442
2295
  process.exit(1);
2443
2296
  }
@@ -2445,13 +2298,13 @@ var rollbackCommand = new import_commander15.Command("rollback").description("Ro
2445
2298
 
2446
2299
  // src/commands/services.ts
2447
2300
  var import_node_readline5 = __toESM(require("readline"));
2448
- var import_chalk17 = __toESM(require("chalk"));
2449
- var import_commander16 = require("commander");
2450
- var import_ora14 = __toESM(require("ora"));
2301
+ var import_chalk18 = __toESM(require("chalk"));
2302
+ var import_commander17 = require("commander");
2303
+ var import_ora15 = __toESM(require("ora"));
2451
2304
  function requireLinkedApp5() {
2452
2305
  const linked = config.getLinkedApp();
2453
2306
  if (!linked) {
2454
- console.log(import_chalk17.default.red("No app linked. Run `sylphx link` first."));
2307
+ console.log(import_chalk18.default.red("No app linked. Run `sylphx link` first."));
2455
2308
  process.exit(1);
2456
2309
  }
2457
2310
  return linked;
@@ -2459,180 +2312,180 @@ function requireLinkedApp5() {
2459
2312
  function requireToken3() {
2460
2313
  const token = config.getToken();
2461
2314
  if (!token) {
2462
- console.log(import_chalk17.default.red("Not authenticated. Run `sylphx login` first."));
2315
+ console.log(import_chalk18.default.red("Not authenticated. Run `sylphx login` first."));
2463
2316
  process.exit(1);
2464
2317
  }
2465
2318
  return token;
2466
2319
  }
2467
- var listCmd3 = new import_commander16.Command("list").description("List all services in this project").action(async () => {
2320
+ var listCmd3 = new import_commander17.Command("list").description("List all services in this project").action(async () => {
2468
2321
  requireToken3();
2469
2322
  const linked = requireLinkedApp5();
2470
- const spinner = (0, import_ora14.default)("Fetching services...").start();
2323
+ const spinner = (0, import_ora15.default)("Fetching services...").start();
2471
2324
  try {
2472
2325
  const services = await api.listServices(linked.appId);
2473
2326
  spinner.stop();
2474
2327
  if (services.length === 0) {
2475
- console.log(import_chalk17.default.dim(" No services defined."));
2328
+ console.log(import_chalk18.default.dim(" No services defined."));
2476
2329
  return;
2477
2330
  }
2478
2331
  console.log();
2479
- console.log(` ${import_chalk17.default.bold("NAME".padEnd(24))} ${"REPO".padEnd(36)} ENVS`);
2332
+ console.log(` ${import_chalk18.default.bold("NAME".padEnd(24))} ${"REPO".padEnd(36)} ENVS`);
2480
2333
  console.log(` ${"\u2500".repeat(70)}`);
2481
2334
  for (const svc of services) {
2482
- const repo = svc.githubRepo ?? import_chalk17.default.dim("\u2014");
2335
+ const repo = svc.githubRepo ?? import_chalk18.default.dim("\u2014");
2483
2336
  const envs = svc.environmentCount ?? 0;
2484
- console.log(` ${import_chalk17.default.cyan(svc.name.padEnd(24))} ${repo.padEnd(36)} ${envs}`);
2337
+ console.log(` ${import_chalk18.default.cyan(svc.name.padEnd(24))} ${repo.padEnd(36)} ${envs}`);
2485
2338
  }
2486
2339
  console.log();
2487
2340
  } catch (err) {
2488
- spinner.fail(import_chalk17.default.red(err instanceof Error ? err.message : String(err)));
2341
+ spinner.fail(import_chalk18.default.red(err instanceof Error ? err.message : String(err)));
2489
2342
  process.exit(1);
2490
2343
  }
2491
2344
  });
2492
- var getCmd3 = new import_commander16.Command("get").description("Show details of a service").argument("<name>", "Service name").action(async (name) => {
2345
+ var getCmd3 = new import_commander17.Command("get").description("Show details of a service").argument("<name>", "Service name").action(async (name) => {
2493
2346
  requireToken3();
2494
2347
  const linked = requireLinkedApp5();
2495
- const spinner = (0, import_ora14.default)(`Fetching service '${name}'...`).start();
2348
+ const spinner = (0, import_ora15.default)(`Fetching service '${name}'...`).start();
2496
2349
  try {
2497
2350
  const svc = await api.getService(linked.appId, name);
2498
2351
  spinner.stop();
2499
2352
  console.log();
2500
- console.log(` ${import_chalk17.default.bold("Name:")} ${import_chalk17.default.cyan(svc.name)}`);
2501
- console.log(` ${import_chalk17.default.bold("ID:")} ${svc.id}`);
2502
- if (svc.githubRepo) console.log(` ${import_chalk17.default.bold("Repo:")} ${svc.githubRepo}`);
2503
- if (svc.githubBranch) console.log(` ${import_chalk17.default.bold("Branch:")} ${svc.githubBranch}`);
2353
+ console.log(` ${import_chalk18.default.bold("Name:")} ${import_chalk18.default.cyan(svc.name)}`);
2354
+ console.log(` ${import_chalk18.default.bold("ID:")} ${svc.id}`);
2355
+ if (svc.githubRepo) console.log(` ${import_chalk18.default.bold("Repo:")} ${svc.githubRepo}`);
2356
+ if (svc.githubBranch) console.log(` ${import_chalk18.default.bold("Branch:")} ${svc.githubBranch}`);
2504
2357
  if (svc.dockerfilePath)
2505
- console.log(` ${import_chalk17.default.bold("Dockerfile:")} ${svc.dockerfilePath}`);
2506
- if (svc.port) console.log(` ${import_chalk17.default.bold("Port:")} ${svc.port}`);
2358
+ console.log(` ${import_chalk18.default.bold("Dockerfile:")} ${svc.dockerfilePath}`);
2359
+ if (svc.port) console.log(` ${import_chalk18.default.bold("Port:")} ${svc.port}`);
2507
2360
  if (svc.publicNetworking !== void 0 && svc.publicNetworking !== null)
2508
2361
  console.log(
2509
- ` ${import_chalk17.default.bold("Public:")} ${svc.publicNetworking ? import_chalk17.default.green("yes") : import_chalk17.default.dim("no")}`
2362
+ ` ${import_chalk18.default.bold("Public:")} ${svc.publicNetworking ? import_chalk18.default.green("yes") : import_chalk18.default.dim("no")}`
2510
2363
  );
2511
2364
  console.log();
2512
2365
  } catch (err) {
2513
- spinner.fail(import_chalk17.default.red(err instanceof Error ? err.message : String(err)));
2366
+ spinner.fail(import_chalk18.default.red(err instanceof Error ? err.message : String(err)));
2514
2367
  process.exit(1);
2515
2368
  }
2516
2369
  });
2517
- var deployCmd = new import_commander16.Command("deploy").description("Deploy a specific service").argument("<name>", "Service name").option("--env <env>", "Environment (default: production)", "production").action(async (name, opts) => {
2370
+ var deployCmd = new import_commander17.Command("deploy").description("Deploy a specific service").argument("<name>", "Service name").option("--env <env>", "Environment (default: production)", "production").action(async (name, opts) => {
2518
2371
  requireToken3();
2519
2372
  const linked = requireLinkedApp5();
2520
- const spinner = (0, import_ora14.default)(`Deploying service '${name}' [${opts.env}]...`).start();
2373
+ const spinner = (0, import_ora15.default)(`Deploying service '${name}' [${opts.env}]...`).start();
2521
2374
  try {
2522
2375
  const result = await api.deployService(linked.appId, name, opts.env);
2523
- spinner.succeed(import_chalk17.default.green(`\u2713 Deploy triggered for service '${name}'`));
2376
+ spinner.succeed(import_chalk18.default.green(`\u2713 Deploy triggered for service '${name}'`));
2524
2377
  if (result.deploymentId) {
2525
- console.log(import_chalk17.default.dim(` Deployment ID: ${result.deploymentId}`));
2378
+ console.log(import_chalk18.default.dim(` Deployment ID: ${result.deploymentId}`));
2526
2379
  }
2527
- console.log(import_chalk17.default.dim(`
2528
- Run ${import_chalk17.default.cyan("sylphx status")} to monitor.`));
2380
+ console.log(import_chalk18.default.dim(`
2381
+ Run ${import_chalk18.default.cyan("sylphx status")} to monitor.`));
2529
2382
  } catch (err) {
2530
- spinner.fail(import_chalk17.default.red(err instanceof Error ? err.message : String(err)));
2383
+ spinner.fail(import_chalk18.default.red(err instanceof Error ? err.message : String(err)));
2531
2384
  process.exit(1);
2532
2385
  }
2533
2386
  });
2534
- var rmCmd2 = new import_commander16.Command("rm").description("Delete a service").argument("<name>", "Service name").option("--force", "Skip confirmation prompt").action(async (name, opts) => {
2387
+ var rmCmd2 = new import_commander17.Command("rm").description("Delete a service").argument("<name>", "Service name").option("--force", "Skip confirmation prompt").action(async (name, opts) => {
2535
2388
  requireToken3();
2536
2389
  const linked = requireLinkedApp5();
2537
2390
  if (!opts.force) {
2538
2391
  const rl = import_node_readline5.default.createInterface({ input: process.stdin, output: process.stdout });
2539
2392
  await new Promise((resolve) => {
2540
- rl.question(import_chalk17.default.yellow(` Delete service ${import_chalk17.default.bold(name)}? (y/N) `), (answer) => {
2393
+ rl.question(import_chalk18.default.yellow(` Delete service ${import_chalk18.default.bold(name)}? (y/N) `), (answer) => {
2541
2394
  rl.close();
2542
2395
  if (answer.toLowerCase() !== "y") {
2543
- console.log(import_chalk17.default.dim(" Cancelled."));
2396
+ console.log(import_chalk18.default.dim(" Cancelled."));
2544
2397
  process.exit(0);
2545
2398
  }
2546
2399
  resolve();
2547
2400
  });
2548
2401
  });
2549
2402
  }
2550
- const spinner = (0, import_ora14.default)(`Deleting service '${name}'...`).start();
2403
+ const spinner = (0, import_ora15.default)(`Deleting service '${name}'...`).start();
2551
2404
  try {
2552
2405
  await api.deleteService(linked.appId, name);
2553
- spinner.succeed(import_chalk17.default.green(`\u2713 Service '${name}' deleted`));
2406
+ spinner.succeed(import_chalk18.default.green(`\u2713 Service '${name}' deleted`));
2554
2407
  } catch (err) {
2555
- spinner.fail(import_chalk17.default.red(err instanceof Error ? err.message : String(err)));
2408
+ spinner.fail(import_chalk18.default.red(err instanceof Error ? err.message : String(err)));
2556
2409
  process.exit(1);
2557
2410
  }
2558
2411
  });
2559
- var servicesCommand = new import_commander16.Command("services").description("Manage project services").addCommand(listCmd3).addCommand(getCmd3).addCommand(deployCmd).addCommand(rmCmd2).action(() => servicesCommand.help());
2412
+ var servicesCommand = new import_commander17.Command("services").description("Manage project services").addCommand(listCmd3).addCommand(getCmd3).addCommand(deployCmd).addCommand(rmCmd2).action(() => servicesCommand.help());
2560
2413
 
2561
2414
  // src/commands/status.ts
2562
- var import_chalk18 = __toESM(require("chalk"));
2563
- var import_commander17 = require("commander");
2564
- var import_ora15 = __toESM(require("ora"));
2415
+ var import_chalk19 = __toESM(require("chalk"));
2416
+ var import_commander18 = require("commander");
2417
+ var import_ora16 = __toESM(require("ora"));
2565
2418
  function statusColor(status) {
2566
2419
  const s = status.toLowerCase();
2567
2420
  if (s === "running" || s === "active" || s === "healthy" || s === "success") {
2568
- return import_chalk18.default.green(status);
2421
+ return import_chalk19.default.green(status);
2569
2422
  }
2570
2423
  if (s === "deploying" || s === "building" || s === "pending") {
2571
- return import_chalk18.default.yellow(status);
2424
+ return import_chalk19.default.yellow(status);
2572
2425
  }
2573
2426
  if (s === "error" || s === "failed" || s === "stopped") {
2574
- return import_chalk18.default.red(status);
2427
+ return import_chalk19.default.red(status);
2575
2428
  }
2576
- return import_chalk18.default.white(status);
2429
+ return import_chalk19.default.white(status);
2577
2430
  }
2578
- var statusCommand = new import_commander17.Command("status").description("Show deployment status").option("--env <env>", "Environment (e.g. production, staging)").action(async (opts) => {
2431
+ var statusCommand = new import_commander18.Command("status").description("Show deployment status").option("--env <env>", "Environment (e.g. production, staging)").action(async (opts) => {
2579
2432
  const token = config.getToken();
2580
2433
  if (!token) {
2581
- console.log(import_chalk18.default.red("Not authenticated. Run `sylphx login` first."));
2434
+ console.log(import_chalk19.default.red("Not authenticated. Run `sylphx login` first."));
2582
2435
  process.exit(1);
2583
2436
  }
2584
2437
  const linked = config.getLinkedApp();
2585
2438
  if (!linked) {
2586
- console.log(import_chalk18.default.red("No app linked. Run `sylphx link` first."));
2439
+ console.log(import_chalk19.default.red("No app linked. Run `sylphx link` first."));
2587
2440
  process.exit(1);
2588
2441
  }
2589
2442
  const env = opts.env ?? linked.defaultEnv;
2590
- const spinner = (0, import_ora15.default)(`Fetching status [${env}]...`).start();
2443
+ const spinner = (0, import_ora16.default)(`Fetching status [${env}]...`).start();
2591
2444
  try {
2592
2445
  const status = await api.getDeploymentStatus(linked.appId);
2593
2446
  spinner.stop();
2594
2447
  console.log("");
2595
- console.log(import_chalk18.default.bold(" Deployment Status"));
2596
- console.log(import_chalk18.default.dim(` ${"\u2500".repeat(40)}`));
2448
+ console.log(import_chalk19.default.bold(" Deployment Status"));
2449
+ console.log(import_chalk19.default.dim(` ${"\u2500".repeat(40)}`));
2597
2450
  console.log("");
2598
- console.log(` App: ${import_chalk18.default.cyan(linked.appId)}`);
2599
- console.log(` Environment: ${import_chalk18.default.white(env)}`);
2451
+ console.log(` App: ${import_chalk19.default.cyan(linked.appId)}`);
2452
+ console.log(` Environment: ${import_chalk19.default.white(env)}`);
2600
2453
  console.log(` Status: ${statusColor(status.status)}`);
2601
2454
  if (status.deployedAt) {
2602
2455
  const date = new Date(status.deployedAt);
2603
- console.log(` Deployed: ${import_chalk18.default.white(date.toLocaleString())}`);
2456
+ console.log(` Deployed: ${import_chalk19.default.white(date.toLocaleString())}`);
2604
2457
  }
2605
2458
  const envMatch = status.environments?.find((e) => e.envType === env) ?? status.environments?.find((e) => e.envType === "production") ?? status.environments?.[0];
2606
2459
  const displayUrl = status.url ?? envMatch?.url ?? null;
2607
2460
  if (displayUrl) {
2608
- console.log(` URL: ${import_chalk18.default.cyan(displayUrl)}`);
2461
+ console.log(` URL: ${import_chalk19.default.cyan(displayUrl)}`);
2609
2462
  }
2610
2463
  if (envMatch?.lastDeployedAt) {
2611
2464
  console.log(
2612
- ` Deployed: ${import_chalk18.default.white(new Date(envMatch.lastDeployedAt).toLocaleString())}`
2465
+ ` Deployed: ${import_chalk19.default.white(new Date(envMatch.lastDeployedAt).toLocaleString())}`
2613
2466
  );
2614
2467
  }
2615
2468
  if (status.replicas) {
2616
2469
  const { ready, desired } = status.replicas;
2617
- const replicaColor = ready === desired ? import_chalk18.default.green : import_chalk18.default.yellow;
2470
+ const replicaColor = ready === desired ? import_chalk19.default.green : import_chalk19.default.yellow;
2618
2471
  console.log(` Replicas: ${replicaColor(`${ready}/${desired}`)}`);
2619
2472
  }
2620
2473
  console.log("");
2621
2474
  } catch (err) {
2622
- spinner.fail(import_chalk18.default.red(`Failed: ${err instanceof Error ? err.message : String(err)}`));
2475
+ spinner.fail(import_chalk19.default.red(`Failed: ${err instanceof Error ? err.message : String(err)}`));
2623
2476
  process.exit(1);
2624
2477
  }
2625
2478
  });
2626
2479
 
2627
2480
  // src/commands/storage.ts
2628
2481
  var import_node_readline6 = __toESM(require("readline"));
2629
- var import_chalk19 = __toESM(require("chalk"));
2630
- var import_commander18 = require("commander");
2631
- var import_ora16 = __toESM(require("ora"));
2482
+ var import_chalk20 = __toESM(require("chalk"));
2483
+ var import_commander19 = require("commander");
2484
+ var import_ora17 = __toESM(require("ora"));
2632
2485
  function requireLinkedApp6() {
2633
2486
  const linked = config.getLinkedApp();
2634
2487
  if (!linked) {
2635
- console.log(import_chalk19.default.red("No app linked. Run `sylphx link` first."));
2488
+ console.log(import_chalk20.default.red("No app linked. Run `sylphx link` first."));
2636
2489
  process.exit(1);
2637
2490
  }
2638
2491
  return linked;
@@ -2640,85 +2493,85 @@ function requireLinkedApp6() {
2640
2493
  function requireToken4() {
2641
2494
  const token = config.getToken();
2642
2495
  if (!token) {
2643
- console.log(import_chalk19.default.red("Not authenticated. Run `sylphx login` first."));
2496
+ console.log(import_chalk20.default.red("Not authenticated. Run `sylphx login` first."));
2644
2497
  process.exit(1);
2645
2498
  }
2646
2499
  return token;
2647
2500
  }
2648
- var listCmd4 = new import_commander18.Command("list").description("List storage resources for this project").option("--env <env>", "Environment (default: production)", "production").action(async (opts) => {
2501
+ var listCmd4 = new import_commander19.Command("list").description("List storage resources for this project").option("--env <env>", "Environment (default: production)", "production").action(async (opts) => {
2649
2502
  requireToken4();
2650
2503
  const linked = requireLinkedApp6();
2651
- const spinner = (0, import_ora16.default)("Fetching storage resources...").start();
2504
+ const spinner = (0, import_ora17.default)("Fetching storage resources...").start();
2652
2505
  try {
2653
2506
  const resources = await api.listStorage(linked.appId, opts.env);
2654
2507
  spinner.stop();
2655
2508
  if (resources.length === 0) {
2656
- console.log(import_chalk19.default.dim(" No storage resources provisioned."));
2509
+ console.log(import_chalk20.default.dim(" No storage resources provisioned."));
2657
2510
  console.log(
2658
- import_chalk19.default.dim(`
2659
- Run ${import_chalk19.default.cyan("sylphx storage create")} to provision storage.`)
2511
+ import_chalk20.default.dim(`
2512
+ Run ${import_chalk20.default.cyan("sylphx storage create")} to provision storage.`)
2660
2513
  );
2661
2514
  return;
2662
2515
  }
2663
2516
  console.log();
2664
2517
  for (const r of resources) {
2665
2518
  const label = [r.role ?? "primary", r.envType].filter(Boolean).join(" \xB7 ");
2666
- console.log(` ${import_chalk19.default.cyan(label)} ${import_chalk19.default.dim(r.id)}`);
2519
+ console.log(` ${import_chalk20.default.cyan(label)} ${import_chalk20.default.dim(r.id)}`);
2667
2520
  if (r.publicUrl) {
2668
- console.log(` ${import_chalk19.default.dim("URL:")} ${import_chalk19.default.cyan(r.publicUrl)}`);
2521
+ console.log(` ${import_chalk20.default.dim("URL:")} ${import_chalk20.default.cyan(r.publicUrl)}`);
2669
2522
  }
2670
2523
  if (r.bucket) {
2671
- console.log(` ${import_chalk19.default.dim("Bucket:")} ${r.bucket}`);
2524
+ console.log(` ${import_chalk20.default.dim("Bucket:")} ${r.bucket}`);
2672
2525
  }
2673
2526
  }
2674
2527
  console.log();
2675
2528
  } catch (err) {
2676
- spinner.fail(import_chalk19.default.red(err instanceof Error ? err.message : String(err)));
2529
+ spinner.fail(import_chalk20.default.red(err instanceof Error ? err.message : String(err)));
2677
2530
  process.exit(1);
2678
2531
  }
2679
2532
  });
2680
- var createCmd = new import_commander18.Command("create").description("Provision blob storage for this project").argument("[name]", "Storage resource name (default: primary)", "primary").option("--env <env>", "Environment (default: production)", "production").action(async (name, opts) => {
2533
+ var createCmd = new import_commander19.Command("create").description("Provision blob storage for this project").argument("[name]", "Storage resource name (default: primary)", "primary").option("--env <env>", "Environment (default: production)", "production").action(async (name, opts) => {
2681
2534
  requireToken4();
2682
2535
  const linked = requireLinkedApp6();
2683
- const spinner = (0, import_ora16.default)(`Provisioning storage '${name}' [${opts.env}]...`).start();
2536
+ const spinner = (0, import_ora17.default)(`Provisioning storage '${name}' [${opts.env}]...`).start();
2684
2537
  try {
2685
2538
  const resource = await api.createStorage(linked.appId, { name, envType: opts.env });
2686
- spinner.succeed(import_chalk19.default.green(`\u2713 Storage '${name}' provisioned`));
2539
+ spinner.succeed(import_chalk20.default.green(`\u2713 Storage '${name}' provisioned`));
2687
2540
  console.log();
2688
- console.log(` ${import_chalk19.default.dim("ID:")} ${resource.id}`);
2541
+ console.log(` ${import_chalk20.default.dim("ID:")} ${resource.id}`);
2689
2542
  if (resource.publicUrl) {
2690
- console.log(` ${import_chalk19.default.dim("Public URL:")} ${import_chalk19.default.cyan(resource.publicUrl)}`);
2543
+ console.log(` ${import_chalk20.default.dim("Public URL:")} ${import_chalk20.default.cyan(resource.publicUrl)}`);
2691
2544
  }
2692
2545
  if (resource.envVars && Object.keys(resource.envVars).length > 0) {
2693
2546
  console.log();
2694
- console.log(import_chalk19.default.bold(" Env vars to add to your project:"));
2547
+ console.log(import_chalk20.default.bold(" Env vars to add to your project:"));
2695
2548
  for (const [k, v] of Object.entries(resource.envVars)) {
2696
- console.log(` ${import_chalk19.default.cyan(k)}=${v}`);
2549
+ console.log(` ${import_chalk20.default.cyan(k)}=${v}`);
2697
2550
  }
2698
2551
  console.log();
2699
2552
  console.log(
2700
- import_chalk19.default.dim(
2701
- ` Run ${import_chalk19.default.cyan("sylphx env set KEY=VALUE")} to add these to your project.`
2553
+ import_chalk20.default.dim(
2554
+ ` Run ${import_chalk20.default.cyan("sylphx env set KEY=VALUE")} to add these to your project.`
2702
2555
  )
2703
2556
  );
2704
2557
  }
2705
2558
  } catch (err) {
2706
- spinner.fail(import_chalk19.default.red(err instanceof Error ? err.message : String(err)));
2559
+ spinner.fail(import_chalk20.default.red(err instanceof Error ? err.message : String(err)));
2707
2560
  process.exit(1);
2708
2561
  }
2709
2562
  });
2710
- var rmCmd3 = new import_commander18.Command("rm").description("Delete a storage resource").argument("<id>", "Storage resource ID").option("--force", "Skip confirmation prompt").action(async (id, opts) => {
2563
+ var rmCmd3 = new import_commander19.Command("rm").description("Delete a storage resource").argument("<id>", "Storage resource ID").option("--force", "Skip confirmation prompt").action(async (id, opts) => {
2711
2564
  requireToken4();
2712
2565
  const linked = requireLinkedApp6();
2713
2566
  if (!opts.force) {
2714
2567
  const rl = import_node_readline6.default.createInterface({ input: process.stdin, output: process.stdout });
2715
2568
  await new Promise((resolve) => {
2716
2569
  rl.question(
2717
- import_chalk19.default.yellow(` \u26A0\uFE0F Delete storage ${import_chalk19.default.bold(id)}? This is irreversible. (y/N) `),
2570
+ import_chalk20.default.yellow(` \u26A0\uFE0F Delete storage ${import_chalk20.default.bold(id)}? This is irreversible. (y/N) `),
2718
2571
  (answer) => {
2719
2572
  rl.close();
2720
2573
  if (answer.toLowerCase() !== "y") {
2721
- console.log(import_chalk19.default.dim(" Cancelled."));
2574
+ console.log(import_chalk20.default.dim(" Cancelled."));
2722
2575
  process.exit(0);
2723
2576
  }
2724
2577
  resolve();
@@ -2726,26 +2579,26 @@ var rmCmd3 = new import_commander18.Command("rm").description("Delete a storage
2726
2579
  );
2727
2580
  });
2728
2581
  }
2729
- const spinner = (0, import_ora16.default)(`Deleting storage ${id}...`).start();
2582
+ const spinner = (0, import_ora17.default)(`Deleting storage ${id}...`).start();
2730
2583
  try {
2731
2584
  await api.deleteStorage(linked.appId, id);
2732
- spinner.succeed(import_chalk19.default.green(`\u2713 Storage ${id} deleted`));
2585
+ spinner.succeed(import_chalk20.default.green(`\u2713 Storage ${id} deleted`));
2733
2586
  } catch (err) {
2734
- spinner.fail(import_chalk19.default.red(err instanceof Error ? err.message : String(err)));
2587
+ spinner.fail(import_chalk20.default.red(err instanceof Error ? err.message : String(err)));
2735
2588
  process.exit(1);
2736
2589
  }
2737
2590
  });
2738
- var storageCommand = new import_commander18.Command("storage").description("Manage blob storage resources").addCommand(listCmd4).addCommand(createCmd).addCommand(rmCmd3).action(() => storageCommand.help());
2591
+ var storageCommand = new import_commander19.Command("storage").description("Manage blob storage resources").addCommand(listCmd4).addCommand(createCmd).addCommand(rmCmd3).action(() => storageCommand.help());
2739
2592
 
2740
2593
  // src/commands/tasks.ts
2741
2594
  var import_node_readline7 = __toESM(require("readline"));
2742
- var import_chalk20 = __toESM(require("chalk"));
2743
- var import_commander19 = require("commander");
2744
- var import_ora17 = __toESM(require("ora"));
2595
+ var import_chalk21 = __toESM(require("chalk"));
2596
+ var import_commander20 = require("commander");
2597
+ var import_ora18 = __toESM(require("ora"));
2745
2598
  function requireLinkedApp7() {
2746
2599
  const linked = config.getLinkedApp();
2747
2600
  if (!linked) {
2748
- console.log(import_chalk20.default.red("No app linked. Run `sylphx link` first."));
2601
+ console.log(import_chalk21.default.red("No app linked. Run `sylphx link` first."));
2749
2602
  process.exit(1);
2750
2603
  }
2751
2604
  return linked;
@@ -2753,7 +2606,7 @@ function requireLinkedApp7() {
2753
2606
  function requireToken5() {
2754
2607
  const token = config.getToken();
2755
2608
  if (!token) {
2756
- console.log(import_chalk20.default.red("Not authenticated. Run `sylphx login` first."));
2609
+ console.log(import_chalk21.default.red("Not authenticated. Run `sylphx login` first."));
2757
2610
  process.exit(1);
2758
2611
  }
2759
2612
  return token;
@@ -2761,74 +2614,74 @@ function requireToken5() {
2761
2614
  function formatMode(mode) {
2762
2615
  switch (mode) {
2763
2616
  case "job":
2764
- return import_chalk20.default.blue("job");
2617
+ return import_chalk21.default.blue("job");
2765
2618
  case "cron":
2766
- return import_chalk20.default.magenta("cron");
2619
+ return import_chalk21.default.magenta("cron");
2767
2620
  case "service":
2768
- return import_chalk20.default.green("service");
2621
+ return import_chalk21.default.green("service");
2769
2622
  default:
2770
- return import_chalk20.default.dim(mode);
2623
+ return import_chalk21.default.dim(mode);
2771
2624
  }
2772
2625
  }
2773
- var listCmd5 = new import_commander19.Command("list").description("List task definitions for this project").option("--env <env>", "Environment (default: production)", "production").action(async (opts) => {
2626
+ var listCmd5 = new import_commander20.Command("list").description("List task definitions for this project").option("--env <env>", "Environment (default: production)", "production").action(async (opts) => {
2774
2627
  requireToken5();
2775
2628
  const linked = requireLinkedApp7();
2776
- const spinner = (0, import_ora17.default)("Fetching tasks...").start();
2629
+ const spinner = (0, import_ora18.default)("Fetching tasks...").start();
2777
2630
  try {
2778
2631
  const tasks = await api.listTasks(linked.appId, opts.env);
2779
2632
  spinner.stop();
2780
2633
  if (tasks.length === 0) {
2781
- console.log(import_chalk20.default.dim(` No task definitions for [${opts.env}].`));
2634
+ console.log(import_chalk21.default.dim(` No task definitions for [${opts.env}].`));
2782
2635
  console.log(
2783
- import_chalk20.default.dim(`
2784
- Run ${import_chalk20.default.cyan("sylphx tasks create <name>")} to define a task.`)
2636
+ import_chalk21.default.dim(`
2637
+ Run ${import_chalk21.default.cyan("sylphx tasks create <name>")} to define a task.`)
2785
2638
  );
2786
2639
  return;
2787
2640
  }
2788
2641
  console.log();
2789
2642
  console.log(
2790
- ` ${import_chalk20.default.bold("NAME".padEnd(28))} ${"MODE".padEnd(10)} ${"IMAGE / HANDLER".padEnd(40)} ID`
2643
+ ` ${import_chalk21.default.bold("NAME".padEnd(28))} ${"MODE".padEnd(10)} ${"IMAGE / HANDLER".padEnd(40)} ID`
2791
2644
  );
2792
2645
  console.log(` ${"\u2500".repeat(90)}`);
2793
2646
  for (const t of tasks) {
2794
- const label = t.imageRef ?? t.handlerPath ?? import_chalk20.default.dim("\u2014");
2647
+ const label = t.imageRef ?? t.handlerPath ?? import_chalk21.default.dim("\u2014");
2795
2648
  console.log(
2796
- ` ${import_chalk20.default.cyan(t.taskName.padEnd(28))} ${formatMode(t.executionMode ?? "job").padEnd(10)} ${String(label).padEnd(40)} ${import_chalk20.default.dim(t.id)}`
2649
+ ` ${import_chalk21.default.cyan(t.taskName.padEnd(28))} ${formatMode(t.executionMode ?? "job").padEnd(10)} ${String(label).padEnd(40)} ${import_chalk21.default.dim(t.id)}`
2797
2650
  );
2798
2651
  }
2799
2652
  console.log();
2800
2653
  } catch (err) {
2801
- spinner.fail(import_chalk20.default.red(err instanceof Error ? err.message : String(err)));
2654
+ spinner.fail(import_chalk21.default.red(err instanceof Error ? err.message : String(err)));
2802
2655
  process.exit(1);
2803
2656
  }
2804
2657
  });
2805
- var getCmd4 = new import_commander19.Command("get").description("Show details of a task definition").argument("<task-id>", "Task ID (task_xxx)").action(async (taskId) => {
2658
+ var getCmd4 = new import_commander20.Command("get").description("Show details of a task definition").argument("<task-id>", "Task ID (task_xxx)").action(async (taskId) => {
2806
2659
  requireToken5();
2807
2660
  const linked = requireLinkedApp7();
2808
- const spinner = (0, import_ora17.default)(`Fetching task ${taskId}...`).start();
2661
+ const spinner = (0, import_ora18.default)(`Fetching task ${taskId}...`).start();
2809
2662
  try {
2810
2663
  const t = await api.getTask(linked.appId, taskId);
2811
2664
  spinner.stop();
2812
2665
  console.log();
2813
- console.log(` ${import_chalk20.default.bold("Name:")} ${import_chalk20.default.cyan(t.taskName)}`);
2814
- console.log(` ${import_chalk20.default.bold("ID:")} ${t.id}`);
2815
- console.log(` ${import_chalk20.default.bold("Mode:")} ${formatMode(t.executionMode ?? "job")}`);
2816
- if (t.imageRef) console.log(` ${import_chalk20.default.bold("Image:")} ${t.imageRef}`);
2817
- if (t.handlerPath) console.log(` ${import_chalk20.default.bold("Handler:")} ${t.handlerPath}`);
2818
- if (t.command?.length) console.log(` ${import_chalk20.default.bold("Command:")} ${t.command.join(" ")}`);
2819
- if (t.timeoutSeconds) console.log(` ${import_chalk20.default.bold("Timeout:")} ${t.timeoutSeconds}s`);
2666
+ console.log(` ${import_chalk21.default.bold("Name:")} ${import_chalk21.default.cyan(t.taskName)}`);
2667
+ console.log(` ${import_chalk21.default.bold("ID:")} ${t.id}`);
2668
+ console.log(` ${import_chalk21.default.bold("Mode:")} ${formatMode(t.executionMode ?? "job")}`);
2669
+ if (t.imageRef) console.log(` ${import_chalk21.default.bold("Image:")} ${t.imageRef}`);
2670
+ if (t.handlerPath) console.log(` ${import_chalk21.default.bold("Handler:")} ${t.handlerPath}`);
2671
+ if (t.command?.length) console.log(` ${import_chalk21.default.bold("Command:")} ${t.command.join(" ")}`);
2672
+ if (t.timeoutSeconds) console.log(` ${import_chalk21.default.bold("Timeout:")} ${t.timeoutSeconds}s`);
2820
2673
  if (t.machineConfig) {
2821
2674
  const { cpu, memory, gpu } = t.machineConfig;
2822
2675
  const parts = [cpu && `cpu=${cpu}`, memory && `mem=${memory}`, gpu && `gpu=${gpu}`].filter(Boolean).join(" ");
2823
- if (parts) console.log(` ${import_chalk20.default.bold("Resources:")} ${parts}`);
2676
+ if (parts) console.log(` ${import_chalk21.default.bold("Resources:")} ${parts}`);
2824
2677
  }
2825
2678
  if (t.retryConfig) {
2826
2679
  console.log(
2827
- ` ${import_chalk20.default.bold("Retry:")} max=${t.retryConfig.maxAttempts ?? 1}, backoff=${t.retryConfig.backoff ?? "fixed"}`
2680
+ ` ${import_chalk21.default.bold("Retry:")} max=${t.retryConfig.maxAttempts ?? 1}, backoff=${t.retryConfig.backoff ?? "fixed"}`
2828
2681
  );
2829
2682
  }
2830
2683
  if (t.volumeMounts?.length) {
2831
- console.log(` ${import_chalk20.default.bold("Volumes:")}`);
2684
+ console.log(` ${import_chalk21.default.bold("Volumes:")}`);
2832
2685
  for (const m of t.volumeMounts) {
2833
2686
  const ro = m.readOnly ? " (ro)" : "";
2834
2687
  console.log(` ${m.mountPath}${ro} \u2190 ${m.volumeId}`);
@@ -2836,19 +2689,19 @@ var getCmd4 = new import_commander19.Command("get").description("Show details of
2836
2689
  }
2837
2690
  console.log();
2838
2691
  } catch (err) {
2839
- spinner.fail(import_chalk20.default.red(err instanceof Error ? err.message : String(err)));
2692
+ spinner.fail(import_chalk21.default.red(err instanceof Error ? err.message : String(err)));
2840
2693
  process.exit(1);
2841
2694
  }
2842
2695
  });
2843
- var createCmd2 = new import_commander19.Command("create").description("Create (or upsert) a task definition").argument("<name>", "Task name (unique within the environment)").option("--env <env>", "Environment (default: production)", "production").option("--mode <mode>", "Execution mode: job | cron | service (default: job)", "job").option("--image <ref>", "Docker image reference").option("--handler <path>", "Handler function path (e.g. src/tasks/send-email.ts)").option("--cmd <cmd>", 'Command to run (comma-separated, e.g. "node,dist/worker.js")').option("--timeout <secs>", "Timeout in seconds").option("--cpu <cpu>", "CPU request (e.g. 0.5, 2)").option("--memory <mem>", "Memory request (e.g. 512Mi, 2Gi)").action(
2696
+ var createCmd2 = new import_commander20.Command("create").description("Create (or upsert) a task definition").argument("<name>", "Task name (unique within the environment)").option("--env <env>", "Environment (default: production)", "production").option("--mode <mode>", "Execution mode: job | cron | service (default: job)", "job").option("--image <ref>", "Docker image reference").option("--handler <path>", "Handler function path (e.g. src/tasks/send-email.ts)").option("--cmd <cmd>", 'Command to run (comma-separated, e.g. "node,dist/worker.js")').option("--timeout <secs>", "Timeout in seconds").option("--cpu <cpu>", "CPU request (e.g. 0.5, 2)").option("--memory <mem>", "Memory request (e.g. 512Mi, 2Gi)").action(
2844
2697
  async (name, opts) => {
2845
2698
  requireToken5();
2846
2699
  const linked = requireLinkedApp7();
2847
2700
  if (!["job", "cron", "service"].includes(opts.mode)) {
2848
- console.log(import_chalk20.default.red(` --mode must be one of: job, cron, service`));
2701
+ console.log(import_chalk21.default.red(` --mode must be one of: job, cron, service`));
2849
2702
  process.exit(1);
2850
2703
  }
2851
- const spinner = (0, import_ora17.default)(`Creating task '${name}' [${opts.env}]...`).start();
2704
+ const spinner = (0, import_ora18.default)(`Creating task '${name}' [${opts.env}]...`).start();
2852
2705
  try {
2853
2706
  const task = await api.createTask(linked.appId, {
2854
2707
  taskName: name,
@@ -2860,19 +2713,19 @@ var createCmd2 = new import_commander19.Command("create").description("Create (o
2860
2713
  timeoutSeconds: opts.timeout ? Number.parseInt(opts.timeout, 10) : void 0,
2861
2714
  machineConfig: opts.cpu || opts.memory ? { cpu: opts.cpu, memory: opts.memory } : void 0
2862
2715
  });
2863
- spinner.succeed(import_chalk20.default.green(`\u2713 Task '${task.taskName}' created`));
2716
+ spinner.succeed(import_chalk21.default.green(`\u2713 Task '${task.taskName}' created`));
2864
2717
  console.log();
2865
- console.log(` ${import_chalk20.default.dim("ID:")} ${task.id}`);
2866
- console.log(` ${import_chalk20.default.dim("Mode:")} ${task.executionMode}`);
2867
- if (task.imageRef) console.log(` ${import_chalk20.default.dim("Image:")} ${task.imageRef}`);
2718
+ console.log(` ${import_chalk21.default.dim("ID:")} ${task.id}`);
2719
+ console.log(` ${import_chalk21.default.dim("Mode:")} ${task.executionMode}`);
2720
+ if (task.imageRef) console.log(` ${import_chalk21.default.dim("Image:")} ${task.imageRef}`);
2868
2721
  console.log();
2869
2722
  } catch (err) {
2870
- spinner.fail(import_chalk20.default.red(err instanceof Error ? err.message : String(err)));
2723
+ spinner.fail(import_chalk21.default.red(err instanceof Error ? err.message : String(err)));
2871
2724
  process.exit(1);
2872
2725
  }
2873
2726
  }
2874
2727
  );
2875
- var updateCmd = new import_commander19.Command("update").description("Update a task definition").argument("<task-id>", "Task ID (task_xxx)").option("--mode <mode>", "Execution mode: job | cron | service").option("--image <ref>", "Docker image reference").option("--handler <path>", "Handler function path").option("--cmd <cmd>", "Command (comma-separated)").option("--timeout <secs>", "Timeout in seconds").option("--cpu <cpu>", "CPU request").option("--memory <mem>", "Memory request").action(
2728
+ var updateCmd = new import_commander20.Command("update").description("Update a task definition").argument("<task-id>", "Task ID (task_xxx)").option("--mode <mode>", "Execution mode: job | cron | service").option("--image <ref>", "Docker image reference").option("--handler <path>", "Handler function path").option("--cmd <cmd>", "Command (comma-separated)").option("--timeout <secs>", "Timeout in seconds").option("--cpu <cpu>", "CPU request").option("--memory <mem>", "Memory request").action(
2876
2729
  async (taskId, opts) => {
2877
2730
  requireToken5();
2878
2731
  const linked = requireLinkedApp7();
@@ -2884,72 +2737,72 @@ var updateCmd = new import_commander19.Command("update").description("Update a t
2884
2737
  if (opts.timeout) patch.timeoutSeconds = Number.parseInt(opts.timeout, 10);
2885
2738
  if (opts.cpu || opts.memory) patch.machineConfig = { cpu: opts.cpu, memory: opts.memory };
2886
2739
  if (Object.keys(patch).length === 0) {
2887
- console.log(import_chalk20.default.yellow(" Nothing to update. Pass at least one option."));
2740
+ console.log(import_chalk21.default.yellow(" Nothing to update. Pass at least one option."));
2888
2741
  process.exit(1);
2889
2742
  }
2890
- const spinner = (0, import_ora17.default)(`Updating task ${taskId}...`).start();
2743
+ const spinner = (0, import_ora18.default)(`Updating task ${taskId}...`).start();
2891
2744
  try {
2892
2745
  const task = await api.updateTask(linked.appId, taskId, patch);
2893
- spinner.succeed(import_chalk20.default.green(`\u2713 Task '${task.taskName}' updated`));
2746
+ spinner.succeed(import_chalk21.default.green(`\u2713 Task '${task.taskName}' updated`));
2894
2747
  } catch (err) {
2895
- spinner.fail(import_chalk20.default.red(err instanceof Error ? err.message : String(err)));
2748
+ spinner.fail(import_chalk21.default.red(err instanceof Error ? err.message : String(err)));
2896
2749
  process.exit(1);
2897
2750
  }
2898
2751
  }
2899
2752
  );
2900
- var rmCmd4 = new import_commander19.Command("rm").description("Delete a task definition").argument("<task-id>", "Task ID (task_xxx)").option("--force", "Skip confirmation").action(async (taskId, opts) => {
2753
+ var rmCmd4 = new import_commander20.Command("rm").description("Delete a task definition").argument("<task-id>", "Task ID (task_xxx)").option("--force", "Skip confirmation").action(async (taskId, opts) => {
2901
2754
  requireToken5();
2902
2755
  const linked = requireLinkedApp7();
2903
2756
  if (!opts.force) {
2904
2757
  const rl = import_node_readline7.default.createInterface({ input: process.stdin, output: process.stdout });
2905
2758
  await new Promise((resolve) => {
2906
- rl.question(import_chalk20.default.yellow(` Delete task ${import_chalk20.default.bold(taskId)}? (y/N) `), (answer) => {
2759
+ rl.question(import_chalk21.default.yellow(` Delete task ${import_chalk21.default.bold(taskId)}? (y/N) `), (answer) => {
2907
2760
  rl.close();
2908
2761
  if (answer.toLowerCase() !== "y") {
2909
- console.log(import_chalk20.default.dim(" Cancelled."));
2762
+ console.log(import_chalk21.default.dim(" Cancelled."));
2910
2763
  process.exit(0);
2911
2764
  }
2912
2765
  resolve();
2913
2766
  });
2914
2767
  });
2915
2768
  }
2916
- const spinner = (0, import_ora17.default)(`Deleting task ${taskId}...`).start();
2769
+ const spinner = (0, import_ora18.default)(`Deleting task ${taskId}...`).start();
2917
2770
  try {
2918
2771
  await api.deleteTask(linked.appId, taskId);
2919
- spinner.succeed(import_chalk20.default.green(`\u2713 Task ${taskId} deleted`));
2772
+ spinner.succeed(import_chalk21.default.green(`\u2713 Task ${taskId} deleted`));
2920
2773
  } catch (err) {
2921
- spinner.fail(import_chalk20.default.red(err instanceof Error ? err.message : String(err)));
2774
+ spinner.fail(import_chalk21.default.red(err instanceof Error ? err.message : String(err)));
2922
2775
  process.exit(1);
2923
2776
  }
2924
2777
  });
2925
- var tasksCommand = new import_commander19.Command("tasks").description("Manage task definitions (jobs, crons, services)").addCommand(listCmd5).addCommand(getCmd4).addCommand(createCmd2).addCommand(updateCmd).addCommand(rmCmd4).action(() => tasksCommand.help());
2778
+ var tasksCommand = new import_commander20.Command("tasks").description("Manage task definitions (jobs, crons, services)").addCommand(listCmd5).addCommand(getCmd4).addCommand(createCmd2).addCommand(updateCmd).addCommand(rmCmd4).action(() => tasksCommand.help());
2926
2779
 
2927
2780
  // src/commands/unlink.ts
2928
- var import_chalk21 = __toESM(require("chalk"));
2929
- var import_commander20 = require("commander");
2930
- var unlinkCommand = new import_commander20.Command("unlink").description("Unlink current directory from its linked app").action(() => {
2781
+ var import_chalk22 = __toESM(require("chalk"));
2782
+ var import_commander21 = require("commander");
2783
+ var unlinkCommand = new import_commander21.Command("unlink").description("Unlink current directory from its linked app").action(() => {
2931
2784
  const linked = config.getLinkedApp();
2932
2785
  if (!linked) {
2933
- console.log(import_chalk21.default.yellow(" This directory is not linked to any app."));
2786
+ console.log(import_chalk22.default.yellow(" This directory is not linked to any app."));
2934
2787
  process.exit(0);
2935
2788
  }
2936
2789
  const appId = linked.appId;
2937
2790
  config.unlinkApp();
2938
2791
  console.log("");
2939
- console.log(import_chalk21.default.green(`\u2713 Unlinked from ${import_chalk21.default.bold(appId)}`));
2940
- console.log(import_chalk21.default.dim(` Directory: ${process.cwd()}`));
2792
+ console.log(import_chalk22.default.green(`\u2713 Unlinked from ${import_chalk22.default.bold(appId)}`));
2793
+ console.log(import_chalk22.default.dim(` Directory: ${process.cwd()}`));
2941
2794
  console.log("");
2942
2795
  });
2943
2796
 
2944
2797
  // src/commands/volumes.ts
2945
2798
  var import_node_readline8 = __toESM(require("readline"));
2946
- var import_chalk22 = __toESM(require("chalk"));
2947
- var import_commander21 = require("commander");
2948
- var import_ora18 = __toESM(require("ora"));
2799
+ var import_chalk23 = __toESM(require("chalk"));
2800
+ var import_commander22 = require("commander");
2801
+ var import_ora19 = __toESM(require("ora"));
2949
2802
  function requireLinkedApp8() {
2950
2803
  const linked = config.getLinkedApp();
2951
2804
  if (!linked) {
2952
- console.log(import_chalk22.default.red("No app linked. Run `sylphx link` first."));
2805
+ console.log(import_chalk23.default.red("No app linked. Run `sylphx link` first."));
2953
2806
  process.exit(1);
2954
2807
  }
2955
2808
  return linked;
@@ -2957,45 +2810,45 @@ function requireLinkedApp8() {
2957
2810
  function requireToken6() {
2958
2811
  const token = config.getToken();
2959
2812
  if (!token) {
2960
- console.log(import_chalk22.default.red("Not authenticated. Run `sylphx login` first."));
2813
+ console.log(import_chalk23.default.red("Not authenticated. Run `sylphx login` first."));
2961
2814
  process.exit(1);
2962
2815
  }
2963
2816
  return token;
2964
2817
  }
2965
- var listCmd6 = new import_commander21.Command("list").description("List persistent volumes for this project").action(async () => {
2818
+ var listCmd6 = new import_commander22.Command("list").description("List persistent volumes for this project").action(async () => {
2966
2819
  requireToken6();
2967
2820
  const linked = requireLinkedApp8();
2968
- const spinner = (0, import_ora18.default)("Fetching volumes...").start();
2821
+ const spinner = (0, import_ora19.default)("Fetching volumes...").start();
2969
2822
  try {
2970
2823
  const volumes = await api.listVolumes(linked.appId);
2971
2824
  spinner.stop();
2972
2825
  if (volumes.length === 0) {
2973
- console.log(import_chalk22.default.dim(" No volumes provisioned."));
2826
+ console.log(import_chalk23.default.dim(" No volumes provisioned."));
2974
2827
  console.log(
2975
- import_chalk22.default.dim(`
2976
- Run ${import_chalk22.default.cyan("sylphx volumes create <name>")} to provision.`)
2828
+ import_chalk23.default.dim(`
2829
+ Run ${import_chalk23.default.cyan("sylphx volumes create <name>")} to provision.`)
2977
2830
  );
2978
2831
  return;
2979
2832
  }
2980
2833
  console.log();
2981
2834
  console.log(
2982
- ` ${import_chalk22.default.bold("NAME".padEnd(24))} ${"SIZE".padEnd(8)} ${"STATUS".padEnd(14)} ID`
2835
+ ` ${import_chalk23.default.bold("NAME".padEnd(24))} ${"SIZE".padEnd(8)} ${"STATUS".padEnd(14)} ID`
2983
2836
  );
2984
2837
  console.log(` ${"\u2500".repeat(70)}`);
2985
2838
  for (const v of volumes) {
2986
- const statusColor2 = v.status === "ready" ? import_chalk22.default.green((v.status ?? "unknown").padEnd(14)) : import_chalk22.default.yellow((v.status ?? "unknown").padEnd(14));
2839
+ const statusColor2 = v.status === "ready" ? import_chalk23.default.green((v.status ?? "unknown").padEnd(14)) : import_chalk23.default.yellow((v.status ?? "unknown").padEnd(14));
2987
2840
  const size = v.sizeGb ? `${v.sizeGb}Gi`.padEnd(8) : "\u2014".padEnd(8);
2988
2841
  console.log(
2989
- ` ${import_chalk22.default.cyan(v.name.padEnd(24))} ${size} ${statusColor2} ${import_chalk22.default.dim(v.id)}`
2842
+ ` ${import_chalk23.default.cyan(v.name.padEnd(24))} ${size} ${statusColor2} ${import_chalk23.default.dim(v.id)}`
2990
2843
  );
2991
2844
  }
2992
2845
  console.log();
2993
2846
  } catch (err) {
2994
- spinner.fail(import_chalk22.default.red(err instanceof Error ? err.message : String(err)));
2847
+ spinner.fail(import_chalk23.default.red(err instanceof Error ? err.message : String(err)));
2995
2848
  process.exit(1);
2996
2849
  }
2997
2850
  });
2998
- var createCmd3 = new import_commander21.Command("create").description("Provision a persistent volume").argument("<name>", "Volume name").option("--size <gb>", "Size in GiB (default: 10)", "10").option(
2851
+ var createCmd3 = new import_commander22.Command("create").description("Provision a persistent volume").argument("<name>", "Volume name").option("--size <gb>", "Size in GiB (default: 10)", "10").option(
2999
2852
  "--access-mode <mode>",
3000
2853
  "ReadWriteOnce or ReadWriteMany (default: ReadWriteOnce)",
3001
2854
  "ReadWriteOnce"
@@ -3004,14 +2857,14 @@ var createCmd3 = new import_commander21.Command("create").description("Provision
3004
2857
  const linked = requireLinkedApp8();
3005
2858
  const sizeGb = Number.parseInt(opts.size, 10);
3006
2859
  if (Number.isNaN(sizeGb) || sizeGb < 1) {
3007
- console.log(import_chalk22.default.red(" --size must be a number >= 1"));
2860
+ console.log(import_chalk23.default.red(" --size must be a number >= 1"));
3008
2861
  process.exit(1);
3009
2862
  }
3010
2863
  if (!["ReadWriteOnce", "ReadWriteMany"].includes(opts.accessMode)) {
3011
- console.log(import_chalk22.default.red(" --access-mode must be ReadWriteOnce or ReadWriteMany"));
2864
+ console.log(import_chalk23.default.red(" --access-mode must be ReadWriteOnce or ReadWriteMany"));
3012
2865
  process.exit(1);
3013
2866
  }
3014
- const spinner = (0, import_ora18.default)(`Provisioning volume '${name}' (${sizeGb}Gi)...`).start();
2867
+ const spinner = (0, import_ora19.default)(`Provisioning volume '${name}' (${sizeGb}Gi)...`).start();
3015
2868
  try {
3016
2869
  const result = await api.createVolume(linked.appId, {
3017
2870
  name,
@@ -3020,29 +2873,29 @@ var createCmd3 = new import_commander21.Command("create").description("Provision
3020
2873
  mountPath: opts.mount
3021
2874
  });
3022
2875
  const vol = result.volume;
3023
- spinner.succeed(import_chalk22.default.green(`\u2713 Volume '${vol.name}' provisioned`));
2876
+ spinner.succeed(import_chalk23.default.green(`\u2713 Volume '${vol.name}' provisioned`));
3024
2877
  console.log();
3025
- console.log(` ${import_chalk22.default.dim("ID:")} ${vol.id}`);
3026
- console.log(` ${import_chalk22.default.dim("Size:")} ${vol.sizeGb}Gi`);
3027
- console.log(` ${import_chalk22.default.dim("Access:")} ${vol.accessMode ?? "ReadWriteOnce"}`);
2878
+ console.log(` ${import_chalk23.default.dim("ID:")} ${vol.id}`);
2879
+ console.log(` ${import_chalk23.default.dim("Size:")} ${vol.sizeGb}Gi`);
2880
+ console.log(` ${import_chalk23.default.dim("Access:")} ${vol.accessMode ?? "ReadWriteOnce"}`);
3028
2881
  console.log();
3029
2882
  } catch (err) {
3030
- spinner.fail(import_chalk22.default.red(err instanceof Error ? err.message : String(err)));
2883
+ spinner.fail(import_chalk23.default.red(err instanceof Error ? err.message : String(err)));
3031
2884
  process.exit(1);
3032
2885
  }
3033
2886
  });
3034
- var rmCmd5 = new import_commander21.Command("rm").description("Delete a persistent volume").argument("<id>", "Volume ID").option("--force", "Skip confirmation prompt").action(async (id, opts) => {
2887
+ var rmCmd5 = new import_commander22.Command("rm").description("Delete a persistent volume").argument("<id>", "Volume ID").option("--force", "Skip confirmation prompt").action(async (id, opts) => {
3035
2888
  requireToken6();
3036
2889
  const linked = requireLinkedApp8();
3037
2890
  if (!opts.force) {
3038
2891
  const rl = import_node_readline8.default.createInterface({ input: process.stdin, output: process.stdout });
3039
2892
  await new Promise((resolve) => {
3040
2893
  rl.question(
3041
- import_chalk22.default.yellow(` \u26A0\uFE0F Delete volume ${import_chalk22.default.bold(id)}? This will destroy all data. (y/N) `),
2894
+ import_chalk23.default.yellow(` \u26A0\uFE0F Delete volume ${import_chalk23.default.bold(id)}? This will destroy all data. (y/N) `),
3042
2895
  (answer) => {
3043
2896
  rl.close();
3044
2897
  if (answer.toLowerCase() !== "y") {
3045
- console.log(import_chalk22.default.dim(" Cancelled."));
2898
+ console.log(import_chalk23.default.dim(" Cancelled."));
3046
2899
  process.exit(0);
3047
2900
  }
3048
2901
  resolve();
@@ -3050,62 +2903,62 @@ var rmCmd5 = new import_commander21.Command("rm").description("Delete a persiste
3050
2903
  );
3051
2904
  });
3052
2905
  }
3053
- const spinner = (0, import_ora18.default)(`Deleting volume ${id}...`).start();
2906
+ const spinner = (0, import_ora19.default)(`Deleting volume ${id}...`).start();
3054
2907
  try {
3055
2908
  await api.deleteVolume(linked.appId, id);
3056
- spinner.succeed(import_chalk22.default.green(`\u2713 Volume ${id} deleted`));
2909
+ spinner.succeed(import_chalk23.default.green(`\u2713 Volume ${id} deleted`));
3057
2910
  } catch (err) {
3058
- spinner.fail(import_chalk22.default.red(err instanceof Error ? err.message : String(err)));
2911
+ spinner.fail(import_chalk23.default.red(err instanceof Error ? err.message : String(err)));
3059
2912
  process.exit(1);
3060
2913
  }
3061
2914
  });
3062
- var volumesCommand = new import_commander21.Command("volumes").description("Manage persistent volumes").addCommand(listCmd6).addCommand(createCmd3).addCommand(rmCmd5).action(() => volumesCommand.help());
2915
+ var volumesCommand = new import_commander22.Command("volumes").description("Manage persistent volumes").addCommand(listCmd6).addCommand(createCmd3).addCommand(rmCmd5).action(() => volumesCommand.help());
3063
2916
 
3064
2917
  // src/commands/whoami.ts
3065
- var import_chalk23 = __toESM(require("chalk"));
3066
- var import_commander22 = require("commander");
3067
- var import_ora19 = __toESM(require("ora"));
3068
- var whoamiCommand = new import_commander22.Command("whoami").description("Show current user, org, and linked app").action(async () => {
2918
+ var import_chalk24 = __toESM(require("chalk"));
2919
+ var import_commander23 = require("commander");
2920
+ var import_ora20 = __toESM(require("ora"));
2921
+ var whoamiCommand = new import_commander23.Command("whoami").description("Show current user, org, and linked app").action(async () => {
3069
2922
  const token = config.getToken();
3070
2923
  if (!token) {
3071
- console.log(import_chalk23.default.red("Not authenticated. Run `sylphx login` first."));
2924
+ console.log(import_chalk24.default.red("Not authenticated. Run `sylphx login` first."));
3072
2925
  process.exit(1);
3073
2926
  }
3074
- const spinner = (0, import_ora19.default)("Fetching account info...").start();
2927
+ const spinner = (0, import_ora20.default)("Fetching account info...").start();
3075
2928
  try {
3076
2929
  const me = await api.whoami();
3077
2930
  spinner.stop();
3078
2931
  console.log("");
3079
- console.log(import_chalk23.default.bold(" Account"));
3080
- console.log(` User: ${import_chalk23.default.cyan(me.user.email)}`);
3081
- console.log(` Name: ${import_chalk23.default.white(me.user.name)}`);
3082
- console.log(` ID: ${import_chalk23.default.dim(me.user.id)}`);
2932
+ console.log(import_chalk24.default.bold(" Account"));
2933
+ console.log(` User: ${import_chalk24.default.cyan(me.user.email)}`);
2934
+ console.log(` Name: ${import_chalk24.default.white(me.user.name)}`);
2935
+ console.log(` ID: ${import_chalk24.default.dim(me.user.id)}`);
3083
2936
  if (me.orgs.length > 0) {
3084
2937
  console.log("");
3085
- console.log(import_chalk23.default.bold(" Organizations"));
2938
+ console.log(import_chalk24.default.bold(" Organizations"));
3086
2939
  for (const org of me.orgs) {
3087
2940
  console.log(
3088
- ` ${import_chalk23.default.cyan(org.slug)} ${import_chalk23.default.dim(`(${org.name})`)}`
2941
+ ` ${import_chalk24.default.cyan(org.slug)} ${import_chalk24.default.dim(`(${org.name})`)}`
3089
2942
  );
3090
2943
  }
3091
2944
  }
3092
2945
  const linkedApp = config.getLinkedApp();
3093
2946
  if (linkedApp) {
3094
2947
  console.log("");
3095
- console.log(import_chalk23.default.bold(" Linked App"));
3096
- console.log(` App: ${import_chalk23.default.cyan(linkedApp.appId)}`);
3097
- console.log(` Org: ${import_chalk23.default.white(linkedApp.orgId)}`);
3098
- console.log(` Env: ${import_chalk23.default.white(linkedApp.defaultEnv)}`);
2948
+ console.log(import_chalk24.default.bold(" Linked App"));
2949
+ console.log(` App: ${import_chalk24.default.cyan(linkedApp.appId)}`);
2950
+ console.log(` Org: ${import_chalk24.default.white(linkedApp.orgId)}`);
2951
+ console.log(` Env: ${import_chalk24.default.white(linkedApp.defaultEnv)}`);
3099
2952
  } else {
3100
2953
  console.log("");
3101
2954
  console.log(
3102
- import_chalk23.default.dim(" No app linked. Run `sylphx link` to link one.")
2955
+ import_chalk24.default.dim(" No app linked. Run `sylphx link` to link one.")
3103
2956
  );
3104
2957
  }
3105
2958
  console.log("");
3106
2959
  } catch (err) {
3107
2960
  spinner.fail(
3108
- import_chalk23.default.red(
2961
+ import_chalk24.default.red(
3109
2962
  `Failed: ${err instanceof Error ? err.message : String(err)}`
3110
2963
  )
3111
2964
  );
@@ -3115,50 +2968,50 @@ var whoamiCommand = new import_commander22.Command("whoami").description("Show c
3115
2968
 
3116
2969
  // src/index.ts
3117
2970
  var { version: version4 } = package_default;
3118
- var program = new import_commander23.Command();
3119
- program.name("sylphx").description(`${import_chalk24.default.bold("Sylphx Platform CLI")} \u2014 deploy and manage your applications`).version(version4, "-v, --version", "Print version").helpOption("-h, --help", "Show help").addHelpText(
2971
+ var program = new import_commander24.Command();
2972
+ program.name("sylphx").description(`${import_chalk25.default.bold("Sylphx Platform CLI")} \u2014 deploy and manage your applications`).version(version4, "-v, --version", "Print version").helpOption("-h, --help", "Show help").addHelpText(
3120
2973
  "after",
3121
2974
  `
3122
- ${import_chalk24.default.bold("Examples:")}
3123
- ${import_chalk24.default.cyan("sylphx login")} Authenticate with Sylphx
3124
- ${import_chalk24.default.cyan("sylphx init my-app")} Create and link a new project
3125
- ${import_chalk24.default.cyan("sylphx link")} Link current directory to an app
3126
- ${import_chalk24.default.cyan("sylphx deploy")} Deploy to production
3127
- ${import_chalk24.default.cyan("sylphx deploy --env staging")} Deploy to staging
3128
- ${import_chalk24.default.cyan("sylphx promote --from staging")} Promote staging build \u2192 production
3129
- ${import_chalk24.default.cyan("sylphx rollback")} Rollback to previous deployment
3130
- ${import_chalk24.default.cyan("sylphx logs -f")} Stream live logs
3131
- ${import_chalk24.default.cyan("sylphx status")} Check deployment status
3132
- ${import_chalk24.default.cyan("sylphx env list")} List environment variables
3133
- ${import_chalk24.default.cyan("sylphx env set PORT=3000")} Set an env var
3134
- ${import_chalk24.default.cyan("sylphx config list")} List remote config keys
3135
- ${import_chalk24.default.cyan("sylphx config set KEY=value")} Set a remote config key
3136
- ${import_chalk24.default.cyan("sylphx db create my-db")} Provision a PostgreSQL database
3137
- ${import_chalk24.default.cyan("sylphx storage create")} Provision blob storage
3138
- ${import_chalk24.default.cyan("sylphx volumes create data --size 20")} Provision a persistent volume
3139
- ${import_chalk24.default.cyan("sylphx services list")} List project services
3140
- ${import_chalk24.default.cyan("sylphx services deploy web")} Deploy a specific service
3141
- ${import_chalk24.default.cyan("sylphx tasks list")} List task definitions
3142
- ${import_chalk24.default.cyan("sylphx tasks create <name> --image nginx")} Create a task
3143
- ${import_chalk24.default.cyan("sylphx resources bind <id>")} Bind a resource to this project
3144
- ${import_chalk24.default.cyan("sylphx projects list")} List all projects
2975
+ ${import_chalk25.default.bold("Examples:")}
2976
+ ${import_chalk25.default.cyan("sylphx login")} Authenticate with Sylphx
2977
+ ${import_chalk25.default.cyan("sylphx init my-app")} Create and link a new project
2978
+ ${import_chalk25.default.cyan("sylphx link")} Link current directory to an app
2979
+ ${import_chalk25.default.cyan("sylphx deploy")} Deploy to production
2980
+ ${import_chalk25.default.cyan("sylphx deploy --env staging")} Deploy to staging
2981
+ ${import_chalk25.default.cyan("sylphx promote --from staging")} Promote staging build \u2192 production
2982
+ ${import_chalk25.default.cyan("sylphx rollback")} Rollback to previous deployment
2983
+ ${import_chalk25.default.cyan("sylphx logs -f")} Stream live logs
2984
+ ${import_chalk25.default.cyan("sylphx status")} Check deployment status
2985
+ ${import_chalk25.default.cyan("sylphx env list")} List environment variables
2986
+ ${import_chalk25.default.cyan("sylphx env set PORT=3000")} Set an env var
2987
+ ${import_chalk25.default.cyan("sylphx config list")} List remote config keys
2988
+ ${import_chalk25.default.cyan("sylphx config set KEY=value")} Set a remote config key
2989
+ ${import_chalk25.default.cyan("sylphx db create my-db")} Provision a PostgreSQL database
2990
+ ${import_chalk25.default.cyan("sylphx storage create")} Provision blob storage
2991
+ ${import_chalk25.default.cyan("sylphx volumes create data --size 20")} Provision a persistent volume
2992
+ ${import_chalk25.default.cyan("sylphx services list")} List project services
2993
+ ${import_chalk25.default.cyan("sylphx services deploy web")} Deploy a specific service
2994
+ ${import_chalk25.default.cyan("sylphx tasks list")} List task definitions
2995
+ ${import_chalk25.default.cyan("sylphx tasks create <name> --image nginx")} Create a task
2996
+ ${import_chalk25.default.cyan("sylphx resources bind <id>")} Bind a resource to this project
2997
+ ${import_chalk25.default.cyan("sylphx projects list")} List all projects
3145
2998
 
3146
- ${import_chalk24.default.bold("Documentation:")}
3147
- ${import_chalk24.default.underline("https://docs.sylphx.com/cli")}
2999
+ ${import_chalk25.default.bold("Documentation:")}
3000
+ ${import_chalk25.default.underline("https://docs.sylphx.com/cli")}
3148
3001
  `
3149
3002
  );
3150
- program.addCommand(loginCommand).addCommand(logoutCommand).addCommand(whoamiCommand).addCommand(initCommand).addCommand(linkCommand).addCommand(unlinkCommand).addCommand(projectsCommand).addCommand(deployCommand).addCommand(promoteCommand).addCommand(rollbackCommand).addCommand(statusCommand).addCommand(logsCommand).addCommand(envCommand).addCommand(configCommand).addCommand(dbCommand).addCommand(storageCommand).addCommand(volumesCommand).addCommand(resourcesCommand).addCommand(tasksCommand).addCommand(servicesCommand).addCommand(domainsCommand).addCommand(openCommand);
3003
+ program.addCommand(loginCommand).addCommand(logoutCommand).addCommand(whoamiCommand).addCommand(initCommand).addCommand(linkCommand).addCommand(unlinkCommand).addCommand(projectsCommand).addCommand(orgsCommand).addCommand(deployCommand).addCommand(promoteCommand).addCommand(rollbackCommand).addCommand(statusCommand).addCommand(logsCommand).addCommand(envCommand).addCommand(configCommand).addCommand(dbCommand).addCommand(storageCommand).addCommand(volumesCommand).addCommand(resourcesCommand).addCommand(tasksCommand).addCommand(servicesCommand).addCommand(domainsCommand).addCommand(openCommand);
3151
3004
  program.on("command:*", (operands) => {
3152
- console.error(import_chalk24.default.red(`
3153
- Unknown command: ${import_chalk24.default.bold(operands[0] ?? "")}
3005
+ console.error(import_chalk25.default.red(`
3006
+ Unknown command: ${import_chalk25.default.bold(operands[0] ?? "")}
3154
3007
  `));
3155
- console.log(` Run ${import_chalk24.default.cyan("sylphx --help")} for usage.
3008
+ console.log(` Run ${import_chalk25.default.cyan("sylphx --help")} for usage.
3156
3009
  `);
3157
3010
  process.exit(1);
3158
3011
  });
3159
3012
  program.parseAsync(process.argv).catch((err) => {
3160
3013
  const msg = err instanceof Error ? err.message : String(err);
3161
- console.error(import_chalk24.default.red(`
3014
+ console.error(import_chalk25.default.red(`
3162
3015
  Error: ${msg}
3163
3016
  `));
3164
3017
  process.exit(1);