@sylphx/cli 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +370 -133
- package/package.json +1 -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
|
|
28
|
-
var
|
|
27
|
+
var import_chalk24 = __toESM(require("chalk"));
|
|
28
|
+
var import_commander23 = require("commander");
|
|
29
29
|
|
|
30
30
|
// package.json
|
|
31
31
|
var package_default = {
|
|
32
32
|
name: "@sylphx/cli",
|
|
33
|
-
version: "0.
|
|
33
|
+
version: "0.3.0",
|
|
34
34
|
description: "Sylphx Platform CLI \u2014 deploy, manage logs, env vars, and more",
|
|
35
35
|
type: "commonjs",
|
|
36
36
|
bin: {
|
|
@@ -254,73 +254,54 @@ var api = {
|
|
|
254
254
|
// ── Domain Management (Unified System) ──────────────────────────────────
|
|
255
255
|
/** List all apex domains for a project environment */
|
|
256
256
|
async listDomains(projectId, envType = "production") {
|
|
257
|
-
return request("GET", `/
|
|
257
|
+
return request("GET", `/projects/${projectId}/domains`, {
|
|
258
258
|
query: { envType }
|
|
259
259
|
});
|
|
260
260
|
},
|
|
261
|
-
/** Add a custom domain to a project */
|
|
262
|
-
async addDomain(projectId, domain, envType = "production") {
|
|
263
|
-
return request(
|
|
264
|
-
"POST",
|
|
265
|
-
`/domains/projects/${projectId}/domains`,
|
|
266
|
-
{ query: { envType }, body: { domain } }
|
|
267
|
-
);
|
|
268
|
-
},
|
|
269
|
-
/** Remove a custom domain from a project */
|
|
270
|
-
async removeDomain(projectId, domain, envType = "production") {
|
|
271
|
-
return request(
|
|
272
|
-
"DELETE",
|
|
273
|
-
`/domains/projects/${projectId}/domains/${encodeURIComponent(domain)}`,
|
|
274
|
-
{ query: { envType } }
|
|
275
|
-
);
|
|
276
|
-
},
|
|
277
261
|
/** Register an apex domain for a project (full domain object with DNS records) */
|
|
278
262
|
async createDomain(projectId, apexDomain, envType = "production") {
|
|
279
|
-
return request("POST", `/
|
|
263
|
+
return request("POST", `/projects/${projectId}/domains`, {
|
|
280
264
|
body: { apexDomain, envType }
|
|
281
265
|
});
|
|
282
266
|
},
|
|
283
267
|
/** Add a hostname binding to an existing domain */
|
|
284
268
|
async addHostname(projectId, domainId, hostname, opts) {
|
|
285
269
|
const { envType = "production", ...bodyOpts } = opts ?? {};
|
|
286
|
-
return request(
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
);
|
|
270
|
+
return request("POST", `/projects/${projectId}/domains/${domainId}/hostnames`, {
|
|
271
|
+
query: { envType },
|
|
272
|
+
body: { hostname, ...bodyOpts }
|
|
273
|
+
});
|
|
291
274
|
},
|
|
292
275
|
/** Remove a hostname binding */
|
|
293
276
|
async removeHostname(projectId, domainId, hostnameId) {
|
|
294
277
|
return request(
|
|
295
278
|
"DELETE",
|
|
296
|
-
`/
|
|
279
|
+
`/projects/${projectId}/domains/${domainId}/hostnames/${hostnameId}`
|
|
297
280
|
);
|
|
298
281
|
},
|
|
299
282
|
/** Trigger DNS check for a hostname */
|
|
300
283
|
async checkHostname(projectId, domainId, hostnameId) {
|
|
301
284
|
return request(
|
|
302
285
|
"POST",
|
|
303
|
-
`/
|
|
286
|
+
`/projects/${projectId}/domains/${domainId}/hostnames/${hostnameId}/check`
|
|
304
287
|
);
|
|
305
288
|
},
|
|
306
289
|
/** Enable email sending for a domain (generates DKIM keypair) */
|
|
307
290
|
async enableEmail(projectId, domainId, opts) {
|
|
308
|
-
return request(
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
{ body: opts ?? {} }
|
|
312
|
-
);
|
|
291
|
+
return request("POST", `/projects/${projectId}/domains/${domainId}/email`, {
|
|
292
|
+
body: opts ?? {}
|
|
293
|
+
});
|
|
313
294
|
},
|
|
314
295
|
/** Check DKIM DNS propagation and load into Stalwart */
|
|
315
296
|
async checkEmail(projectId, domainId) {
|
|
316
297
|
return request(
|
|
317
298
|
"POST",
|
|
318
|
-
`/
|
|
299
|
+
`/projects/${projectId}/domains/${domainId}/email/check`
|
|
319
300
|
);
|
|
320
301
|
},
|
|
321
302
|
/** Disable email sending for a domain */
|
|
322
303
|
async disableEmail(projectId, domainId) {
|
|
323
|
-
return request("DELETE", `/
|
|
304
|
+
return request("DELETE", `/projects/${projectId}/domains/${domainId}/email`);
|
|
324
305
|
},
|
|
325
306
|
/** Get current user and orgs */
|
|
326
307
|
async whoami() {
|
|
@@ -597,6 +578,64 @@ var api = {
|
|
|
597
578
|
"DELETE",
|
|
598
579
|
`/resources/${encodeURIComponent(resourceId)}/bindings/${encodeURIComponent(bindingId)}`
|
|
599
580
|
);
|
|
581
|
+
},
|
|
582
|
+
// ── Tasks ─────────────────────────────────────────────────────────────────
|
|
583
|
+
/**
|
|
584
|
+
* List task definitions for a project environment.
|
|
585
|
+
* Uses ?envId=<envId> (resolved from envType automatically).
|
|
586
|
+
*/
|
|
587
|
+
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 ?? [];
|
|
599
|
+
},
|
|
600
|
+
/**
|
|
601
|
+
* Create or update a task definition (upserts on taskName + environmentId).
|
|
602
|
+
* Backend requires envId — resolves from envType automatically.
|
|
603
|
+
*/
|
|
604
|
+
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;
|
|
615
|
+
},
|
|
616
|
+
/** Get a single task definition */
|
|
617
|
+
async getTask(projectId, taskId) {
|
|
618
|
+
const res = await request(
|
|
619
|
+
"GET",
|
|
620
|
+
`/projects/${encodeURIComponent(projectId)}/tasks/${encodeURIComponent(taskId)}`
|
|
621
|
+
);
|
|
622
|
+
return res.task;
|
|
623
|
+
},
|
|
624
|
+
/** Update a task definition */
|
|
625
|
+
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;
|
|
632
|
+
},
|
|
633
|
+
/** Delete a task definition */
|
|
634
|
+
async deleteTask(projectId, taskId) {
|
|
635
|
+
await request(
|
|
636
|
+
"DELETE",
|
|
637
|
+
`/projects/${encodeURIComponent(projectId)}/tasks/${encodeURIComponent(taskId)}`
|
|
638
|
+
);
|
|
600
639
|
}
|
|
601
640
|
};
|
|
602
641
|
function createLogStream(projectId, envType) {
|
|
@@ -800,14 +839,23 @@ var dbListCommand = new import_commander2.Command("list").description("List all
|
|
|
800
839
|
process.exit(1);
|
|
801
840
|
}
|
|
802
841
|
});
|
|
803
|
-
var dbCreateCommand = new import_commander2.Command("create").description("Provision a new database").argument("<name>", "Database name").option(
|
|
842
|
+
var dbCreateCommand = new import_commander2.Command("create").description("Provision a new database").argument("<name>", "Database name").option(
|
|
843
|
+
"--tier <tier>",
|
|
844
|
+
"Database tier: starter | standard | performance | enterprise1 | enterprise2 (default: standard)",
|
|
845
|
+
"standard"
|
|
846
|
+
).option("--storage <gb>", "Storage in GB (default: 10)", "10").option("--env <env>", "Environment (default: production)", "production").action(async (name, opts) => {
|
|
804
847
|
requireAuth();
|
|
805
848
|
const storageGb = Number.parseInt(opts.storage, 10);
|
|
806
849
|
if (Number.isNaN(storageGb) || storageGb < 5) {
|
|
807
850
|
console.log(import_chalk2.default.red("Storage must be at least 5 GB."));
|
|
808
851
|
process.exit(1);
|
|
809
852
|
}
|
|
853
|
+
const VALID_TIERS = ["starter", "standard", "performance", "enterprise1", "enterprise2"];
|
|
810
854
|
const tier = opts.tier === "pro" ? "performance" : opts.tier;
|
|
855
|
+
if (!VALID_TIERS.includes(tier)) {
|
|
856
|
+
console.log(import_chalk2.default.red(`Invalid tier '${tier}'. Valid: ${VALID_TIERS.join(", ")}`));
|
|
857
|
+
process.exit(1);
|
|
858
|
+
}
|
|
811
859
|
const spinner = (0, import_ora2.default)(
|
|
812
860
|
`Provisioning database ${import_chalk2.default.bold(name)} (${tier}, ${storageGb} GB)...`
|
|
813
861
|
).start();
|
|
@@ -2117,8 +2165,8 @@ var promoteCommand = new import_commander13.Command("promote").description("Prom
|
|
|
2117
2165
|
process.exit(1);
|
|
2118
2166
|
}
|
|
2119
2167
|
if (!opts.force) {
|
|
2120
|
-
const
|
|
2121
|
-
const rl =
|
|
2168
|
+
const readline9 = await import("readline");
|
|
2169
|
+
const rl = readline9.createInterface({ input: process.stdin, output: process.stdout });
|
|
2122
2170
|
await new Promise((resolve) => {
|
|
2123
2171
|
rl.question(
|
|
2124
2172
|
import_chalk14.default.yellow(
|
|
@@ -2337,8 +2385,8 @@ var rollbackCommand = new import_commander15.Command("rollback").description("Ro
|
|
|
2337
2385
|
}
|
|
2338
2386
|
const envType = opts.env ?? linked.defaultEnv ?? "production";
|
|
2339
2387
|
if (!opts.force) {
|
|
2340
|
-
const
|
|
2341
|
-
const rl =
|
|
2388
|
+
const readline9 = await import("readline");
|
|
2389
|
+
const rl = readline9.createInterface({ input: process.stdin, output: process.stdout });
|
|
2342
2390
|
await new Promise((resolve) => {
|
|
2343
2391
|
const label = opts.deployment ? `deployment ${import_chalk16.default.bold(opts.deployment)}` : `previous deployment`;
|
|
2344
2392
|
rl.question(
|
|
@@ -2689,94 +2737,281 @@ var rmCmd3 = new import_commander18.Command("rm").description("Delete a storage
|
|
|
2689
2737
|
});
|
|
2690
2738
|
var storageCommand = new import_commander18.Command("storage").description("Manage blob storage resources").addCommand(listCmd4).addCommand(createCmd).addCommand(rmCmd3).action(() => storageCommand.help());
|
|
2691
2739
|
|
|
2692
|
-
// src/commands/
|
|
2740
|
+
// src/commands/tasks.ts
|
|
2741
|
+
var import_node_readline7 = __toESM(require("readline"));
|
|
2693
2742
|
var import_chalk20 = __toESM(require("chalk"));
|
|
2694
2743
|
var import_commander19 = require("commander");
|
|
2695
|
-
var
|
|
2744
|
+
var import_ora17 = __toESM(require("ora"));
|
|
2745
|
+
function requireLinkedApp7() {
|
|
2746
|
+
const linked = config.getLinkedApp();
|
|
2747
|
+
if (!linked) {
|
|
2748
|
+
console.log(import_chalk20.default.red("No app linked. Run `sylphx link` first."));
|
|
2749
|
+
process.exit(1);
|
|
2750
|
+
}
|
|
2751
|
+
return linked;
|
|
2752
|
+
}
|
|
2753
|
+
function requireToken5() {
|
|
2754
|
+
const token = config.getToken();
|
|
2755
|
+
if (!token) {
|
|
2756
|
+
console.log(import_chalk20.default.red("Not authenticated. Run `sylphx login` first."));
|
|
2757
|
+
process.exit(1);
|
|
2758
|
+
}
|
|
2759
|
+
return token;
|
|
2760
|
+
}
|
|
2761
|
+
function formatMode(mode) {
|
|
2762
|
+
switch (mode) {
|
|
2763
|
+
case "job":
|
|
2764
|
+
return import_chalk20.default.blue("job");
|
|
2765
|
+
case "cron":
|
|
2766
|
+
return import_chalk20.default.magenta("cron");
|
|
2767
|
+
case "service":
|
|
2768
|
+
return import_chalk20.default.green("service");
|
|
2769
|
+
default:
|
|
2770
|
+
return import_chalk20.default.dim(mode);
|
|
2771
|
+
}
|
|
2772
|
+
}
|
|
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) => {
|
|
2774
|
+
requireToken5();
|
|
2775
|
+
const linked = requireLinkedApp7();
|
|
2776
|
+
const spinner = (0, import_ora17.default)("Fetching tasks...").start();
|
|
2777
|
+
try {
|
|
2778
|
+
const tasks = await api.listTasks(linked.appId, opts.env);
|
|
2779
|
+
spinner.stop();
|
|
2780
|
+
if (tasks.length === 0) {
|
|
2781
|
+
console.log(import_chalk20.default.dim(` No task definitions for [${opts.env}].`));
|
|
2782
|
+
console.log(
|
|
2783
|
+
import_chalk20.default.dim(`
|
|
2784
|
+
Run ${import_chalk20.default.cyan("sylphx tasks create <name>")} to define a task.`)
|
|
2785
|
+
);
|
|
2786
|
+
return;
|
|
2787
|
+
}
|
|
2788
|
+
console.log();
|
|
2789
|
+
console.log(
|
|
2790
|
+
` ${import_chalk20.default.bold("NAME".padEnd(28))} ${"MODE".padEnd(10)} ${"IMAGE / HANDLER".padEnd(40)} ID`
|
|
2791
|
+
);
|
|
2792
|
+
console.log(` ${"\u2500".repeat(90)}`);
|
|
2793
|
+
for (const t of tasks) {
|
|
2794
|
+
const label = t.imageRef ?? t.handlerPath ?? import_chalk20.default.dim("\u2014");
|
|
2795
|
+
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)}`
|
|
2797
|
+
);
|
|
2798
|
+
}
|
|
2799
|
+
console.log();
|
|
2800
|
+
} catch (err) {
|
|
2801
|
+
spinner.fail(import_chalk20.default.red(err instanceof Error ? err.message : String(err)));
|
|
2802
|
+
process.exit(1);
|
|
2803
|
+
}
|
|
2804
|
+
});
|
|
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) => {
|
|
2806
|
+
requireToken5();
|
|
2807
|
+
const linked = requireLinkedApp7();
|
|
2808
|
+
const spinner = (0, import_ora17.default)(`Fetching task ${taskId}...`).start();
|
|
2809
|
+
try {
|
|
2810
|
+
const t = await api.getTask(linked.appId, taskId);
|
|
2811
|
+
spinner.stop();
|
|
2812
|
+
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`);
|
|
2820
|
+
if (t.machineConfig) {
|
|
2821
|
+
const { cpu, memory, gpu } = t.machineConfig;
|
|
2822
|
+
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}`);
|
|
2824
|
+
}
|
|
2825
|
+
if (t.retryConfig) {
|
|
2826
|
+
console.log(
|
|
2827
|
+
` ${import_chalk20.default.bold("Retry:")} max=${t.retryConfig.maxAttempts ?? 1}, backoff=${t.retryConfig.backoff ?? "fixed"}`
|
|
2828
|
+
);
|
|
2829
|
+
}
|
|
2830
|
+
if (t.volumeMounts?.length) {
|
|
2831
|
+
console.log(` ${import_chalk20.default.bold("Volumes:")}`);
|
|
2832
|
+
for (const m of t.volumeMounts) {
|
|
2833
|
+
const ro = m.readOnly ? " (ro)" : "";
|
|
2834
|
+
console.log(` ${m.mountPath}${ro} \u2190 ${m.volumeId}`);
|
|
2835
|
+
}
|
|
2836
|
+
}
|
|
2837
|
+
console.log();
|
|
2838
|
+
} catch (err) {
|
|
2839
|
+
spinner.fail(import_chalk20.default.red(err instanceof Error ? err.message : String(err)));
|
|
2840
|
+
process.exit(1);
|
|
2841
|
+
}
|
|
2842
|
+
});
|
|
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(
|
|
2844
|
+
async (name, opts) => {
|
|
2845
|
+
requireToken5();
|
|
2846
|
+
const linked = requireLinkedApp7();
|
|
2847
|
+
if (!["job", "cron", "service"].includes(opts.mode)) {
|
|
2848
|
+
console.log(import_chalk20.default.red(` --mode must be one of: job, cron, service`));
|
|
2849
|
+
process.exit(1);
|
|
2850
|
+
}
|
|
2851
|
+
const spinner = (0, import_ora17.default)(`Creating task '${name}' [${opts.env}]...`).start();
|
|
2852
|
+
try {
|
|
2853
|
+
const task = await api.createTask(linked.appId, {
|
|
2854
|
+
taskName: name,
|
|
2855
|
+
envType: opts.env,
|
|
2856
|
+
executionMode: opts.mode,
|
|
2857
|
+
imageRef: opts.image,
|
|
2858
|
+
handlerPath: opts.handler,
|
|
2859
|
+
command: opts.cmd ? opts.cmd.split(",").map((s) => s.trim()) : void 0,
|
|
2860
|
+
timeoutSeconds: opts.timeout ? Number.parseInt(opts.timeout, 10) : void 0,
|
|
2861
|
+
machineConfig: opts.cpu || opts.memory ? { cpu: opts.cpu, memory: opts.memory } : void 0
|
|
2862
|
+
});
|
|
2863
|
+
spinner.succeed(import_chalk20.default.green(`\u2713 Task '${task.taskName}' created`));
|
|
2864
|
+
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}`);
|
|
2868
|
+
console.log();
|
|
2869
|
+
} catch (err) {
|
|
2870
|
+
spinner.fail(import_chalk20.default.red(err instanceof Error ? err.message : String(err)));
|
|
2871
|
+
process.exit(1);
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
);
|
|
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(
|
|
2876
|
+
async (taskId, opts) => {
|
|
2877
|
+
requireToken5();
|
|
2878
|
+
const linked = requireLinkedApp7();
|
|
2879
|
+
const patch = {};
|
|
2880
|
+
if (opts.mode) patch.executionMode = opts.mode;
|
|
2881
|
+
if (opts.image) patch.imageRef = opts.image;
|
|
2882
|
+
if (opts.handler) patch.handlerPath = opts.handler;
|
|
2883
|
+
if (opts.cmd) patch.command = opts.cmd.split(",").map((s) => s.trim());
|
|
2884
|
+
if (opts.timeout) patch.timeoutSeconds = Number.parseInt(opts.timeout, 10);
|
|
2885
|
+
if (opts.cpu || opts.memory) patch.machineConfig = { cpu: opts.cpu, memory: opts.memory };
|
|
2886
|
+
if (Object.keys(patch).length === 0) {
|
|
2887
|
+
console.log(import_chalk20.default.yellow(" Nothing to update. Pass at least one option."));
|
|
2888
|
+
process.exit(1);
|
|
2889
|
+
}
|
|
2890
|
+
const spinner = (0, import_ora17.default)(`Updating task ${taskId}...`).start();
|
|
2891
|
+
try {
|
|
2892
|
+
const task = await api.updateTask(linked.appId, taskId, patch);
|
|
2893
|
+
spinner.succeed(import_chalk20.default.green(`\u2713 Task '${task.taskName}' updated`));
|
|
2894
|
+
} catch (err) {
|
|
2895
|
+
spinner.fail(import_chalk20.default.red(err instanceof Error ? err.message : String(err)));
|
|
2896
|
+
process.exit(1);
|
|
2897
|
+
}
|
|
2898
|
+
}
|
|
2899
|
+
);
|
|
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) => {
|
|
2901
|
+
requireToken5();
|
|
2902
|
+
const linked = requireLinkedApp7();
|
|
2903
|
+
if (!opts.force) {
|
|
2904
|
+
const rl = import_node_readline7.default.createInterface({ input: process.stdin, output: process.stdout });
|
|
2905
|
+
await new Promise((resolve) => {
|
|
2906
|
+
rl.question(import_chalk20.default.yellow(` Delete task ${import_chalk20.default.bold(taskId)}? (y/N) `), (answer) => {
|
|
2907
|
+
rl.close();
|
|
2908
|
+
if (answer.toLowerCase() !== "y") {
|
|
2909
|
+
console.log(import_chalk20.default.dim(" Cancelled."));
|
|
2910
|
+
process.exit(0);
|
|
2911
|
+
}
|
|
2912
|
+
resolve();
|
|
2913
|
+
});
|
|
2914
|
+
});
|
|
2915
|
+
}
|
|
2916
|
+
const spinner = (0, import_ora17.default)(`Deleting task ${taskId}...`).start();
|
|
2917
|
+
try {
|
|
2918
|
+
await api.deleteTask(linked.appId, taskId);
|
|
2919
|
+
spinner.succeed(import_chalk20.default.green(`\u2713 Task ${taskId} deleted`));
|
|
2920
|
+
} catch (err) {
|
|
2921
|
+
spinner.fail(import_chalk20.default.red(err instanceof Error ? err.message : String(err)));
|
|
2922
|
+
process.exit(1);
|
|
2923
|
+
}
|
|
2924
|
+
});
|
|
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());
|
|
2926
|
+
|
|
2927
|
+
// 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(() => {
|
|
2696
2931
|
const linked = config.getLinkedApp();
|
|
2697
2932
|
if (!linked) {
|
|
2698
|
-
console.log(
|
|
2933
|
+
console.log(import_chalk21.default.yellow(" This directory is not linked to any app."));
|
|
2699
2934
|
process.exit(0);
|
|
2700
2935
|
}
|
|
2701
2936
|
const appId = linked.appId;
|
|
2702
2937
|
config.unlinkApp();
|
|
2703
2938
|
console.log("");
|
|
2704
|
-
console.log(
|
|
2705
|
-
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()}`));
|
|
2706
2941
|
console.log("");
|
|
2707
2942
|
});
|
|
2708
2943
|
|
|
2709
2944
|
// src/commands/volumes.ts
|
|
2710
|
-
var
|
|
2711
|
-
var
|
|
2712
|
-
var
|
|
2713
|
-
var
|
|
2714
|
-
function
|
|
2945
|
+
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"));
|
|
2949
|
+
function requireLinkedApp8() {
|
|
2715
2950
|
const linked = config.getLinkedApp();
|
|
2716
2951
|
if (!linked) {
|
|
2717
|
-
console.log(
|
|
2952
|
+
console.log(import_chalk22.default.red("No app linked. Run `sylphx link` first."));
|
|
2718
2953
|
process.exit(1);
|
|
2719
2954
|
}
|
|
2720
2955
|
return linked;
|
|
2721
2956
|
}
|
|
2722
|
-
function
|
|
2957
|
+
function requireToken6() {
|
|
2723
2958
|
const token = config.getToken();
|
|
2724
2959
|
if (!token) {
|
|
2725
|
-
console.log(
|
|
2960
|
+
console.log(import_chalk22.default.red("Not authenticated. Run `sylphx login` first."));
|
|
2726
2961
|
process.exit(1);
|
|
2727
2962
|
}
|
|
2728
2963
|
return token;
|
|
2729
2964
|
}
|
|
2730
|
-
var
|
|
2731
|
-
|
|
2732
|
-
const linked =
|
|
2733
|
-
const spinner = (0,
|
|
2965
|
+
var listCmd6 = new import_commander21.Command("list").description("List persistent volumes for this project").action(async () => {
|
|
2966
|
+
requireToken6();
|
|
2967
|
+
const linked = requireLinkedApp8();
|
|
2968
|
+
const spinner = (0, import_ora18.default)("Fetching volumes...").start();
|
|
2734
2969
|
try {
|
|
2735
2970
|
const volumes = await api.listVolumes(linked.appId);
|
|
2736
2971
|
spinner.stop();
|
|
2737
2972
|
if (volumes.length === 0) {
|
|
2738
|
-
console.log(
|
|
2973
|
+
console.log(import_chalk22.default.dim(" No volumes provisioned."));
|
|
2739
2974
|
console.log(
|
|
2740
|
-
|
|
2741
|
-
Run ${
|
|
2975
|
+
import_chalk22.default.dim(`
|
|
2976
|
+
Run ${import_chalk22.default.cyan("sylphx volumes create <name>")} to provision.`)
|
|
2742
2977
|
);
|
|
2743
2978
|
return;
|
|
2744
2979
|
}
|
|
2745
2980
|
console.log();
|
|
2746
2981
|
console.log(
|
|
2747
|
-
` ${
|
|
2982
|
+
` ${import_chalk22.default.bold("NAME".padEnd(24))} ${"SIZE".padEnd(8)} ${"STATUS".padEnd(14)} ID`
|
|
2748
2983
|
);
|
|
2749
2984
|
console.log(` ${"\u2500".repeat(70)}`);
|
|
2750
2985
|
for (const v of volumes) {
|
|
2751
|
-
const statusColor2 = v.status === "ready" ?
|
|
2986
|
+
const statusColor2 = v.status === "ready" ? import_chalk22.default.green((v.status ?? "unknown").padEnd(14)) : import_chalk22.default.yellow((v.status ?? "unknown").padEnd(14));
|
|
2752
2987
|
const size = v.sizeGb ? `${v.sizeGb}Gi`.padEnd(8) : "\u2014".padEnd(8);
|
|
2753
2988
|
console.log(
|
|
2754
|
-
` ${
|
|
2989
|
+
` ${import_chalk22.default.cyan(v.name.padEnd(24))} ${size} ${statusColor2} ${import_chalk22.default.dim(v.id)}`
|
|
2755
2990
|
);
|
|
2756
2991
|
}
|
|
2757
2992
|
console.log();
|
|
2758
2993
|
} catch (err) {
|
|
2759
|
-
spinner.fail(
|
|
2994
|
+
spinner.fail(import_chalk22.default.red(err instanceof Error ? err.message : String(err)));
|
|
2760
2995
|
process.exit(1);
|
|
2761
2996
|
}
|
|
2762
2997
|
});
|
|
2763
|
-
var
|
|
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(
|
|
2764
2999
|
"--access-mode <mode>",
|
|
2765
3000
|
"ReadWriteOnce or ReadWriteMany (default: ReadWriteOnce)",
|
|
2766
3001
|
"ReadWriteOnce"
|
|
2767
3002
|
).option("--mount <path>", "Default mount path (optional)").action(async (name, opts) => {
|
|
2768
|
-
|
|
2769
|
-
const linked =
|
|
3003
|
+
requireToken6();
|
|
3004
|
+
const linked = requireLinkedApp8();
|
|
2770
3005
|
const sizeGb = Number.parseInt(opts.size, 10);
|
|
2771
3006
|
if (Number.isNaN(sizeGb) || sizeGb < 1) {
|
|
2772
|
-
console.log(
|
|
3007
|
+
console.log(import_chalk22.default.red(" --size must be a number >= 1"));
|
|
2773
3008
|
process.exit(1);
|
|
2774
3009
|
}
|
|
2775
3010
|
if (!["ReadWriteOnce", "ReadWriteMany"].includes(opts.accessMode)) {
|
|
2776
|
-
console.log(
|
|
3011
|
+
console.log(import_chalk22.default.red(" --access-mode must be ReadWriteOnce or ReadWriteMany"));
|
|
2777
3012
|
process.exit(1);
|
|
2778
3013
|
}
|
|
2779
|
-
const spinner = (0,
|
|
3014
|
+
const spinner = (0, import_ora18.default)(`Provisioning volume '${name}' (${sizeGb}Gi)...`).start();
|
|
2780
3015
|
try {
|
|
2781
3016
|
const result = await api.createVolume(linked.appId, {
|
|
2782
3017
|
name,
|
|
@@ -2785,29 +3020,29 @@ var createCmd2 = new import_commander20.Command("create").description("Provision
|
|
|
2785
3020
|
mountPath: opts.mount
|
|
2786
3021
|
});
|
|
2787
3022
|
const vol = result.volume;
|
|
2788
|
-
spinner.succeed(
|
|
3023
|
+
spinner.succeed(import_chalk22.default.green(`\u2713 Volume '${vol.name}' provisioned`));
|
|
2789
3024
|
console.log();
|
|
2790
|
-
console.log(` ${
|
|
2791
|
-
console.log(` ${
|
|
2792
|
-
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"}`);
|
|
2793
3028
|
console.log();
|
|
2794
3029
|
} catch (err) {
|
|
2795
|
-
spinner.fail(
|
|
3030
|
+
spinner.fail(import_chalk22.default.red(err instanceof Error ? err.message : String(err)));
|
|
2796
3031
|
process.exit(1);
|
|
2797
3032
|
}
|
|
2798
3033
|
});
|
|
2799
|
-
var
|
|
2800
|
-
|
|
2801
|
-
const linked =
|
|
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) => {
|
|
3035
|
+
requireToken6();
|
|
3036
|
+
const linked = requireLinkedApp8();
|
|
2802
3037
|
if (!opts.force) {
|
|
2803
|
-
const rl =
|
|
3038
|
+
const rl = import_node_readline8.default.createInterface({ input: process.stdin, output: process.stdout });
|
|
2804
3039
|
await new Promise((resolve) => {
|
|
2805
3040
|
rl.question(
|
|
2806
|
-
|
|
3041
|
+
import_chalk22.default.yellow(` \u26A0\uFE0F Delete volume ${import_chalk22.default.bold(id)}? This will destroy all data. (y/N) `),
|
|
2807
3042
|
(answer) => {
|
|
2808
3043
|
rl.close();
|
|
2809
3044
|
if (answer.toLowerCase() !== "y") {
|
|
2810
|
-
console.log(
|
|
3045
|
+
console.log(import_chalk22.default.dim(" Cancelled."));
|
|
2811
3046
|
process.exit(0);
|
|
2812
3047
|
}
|
|
2813
3048
|
resolve();
|
|
@@ -2815,62 +3050,62 @@ var rmCmd4 = new import_commander20.Command("rm").description("Delete a persiste
|
|
|
2815
3050
|
);
|
|
2816
3051
|
});
|
|
2817
3052
|
}
|
|
2818
|
-
const spinner = (0,
|
|
3053
|
+
const spinner = (0, import_ora18.default)(`Deleting volume ${id}...`).start();
|
|
2819
3054
|
try {
|
|
2820
3055
|
await api.deleteVolume(linked.appId, id);
|
|
2821
|
-
spinner.succeed(
|
|
3056
|
+
spinner.succeed(import_chalk22.default.green(`\u2713 Volume ${id} deleted`));
|
|
2822
3057
|
} catch (err) {
|
|
2823
|
-
spinner.fail(
|
|
3058
|
+
spinner.fail(import_chalk22.default.red(err instanceof Error ? err.message : String(err)));
|
|
2824
3059
|
process.exit(1);
|
|
2825
3060
|
}
|
|
2826
3061
|
});
|
|
2827
|
-
var volumesCommand = new
|
|
3062
|
+
var volumesCommand = new import_commander21.Command("volumes").description("Manage persistent volumes").addCommand(listCmd6).addCommand(createCmd3).addCommand(rmCmd5).action(() => volumesCommand.help());
|
|
2828
3063
|
|
|
2829
3064
|
// src/commands/whoami.ts
|
|
2830
|
-
var
|
|
2831
|
-
var
|
|
2832
|
-
var
|
|
2833
|
-
var whoamiCommand = new
|
|
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 () => {
|
|
2834
3069
|
const token = config.getToken();
|
|
2835
3070
|
if (!token) {
|
|
2836
|
-
console.log(
|
|
3071
|
+
console.log(import_chalk23.default.red("Not authenticated. Run `sylphx login` first."));
|
|
2837
3072
|
process.exit(1);
|
|
2838
3073
|
}
|
|
2839
|
-
const spinner = (0,
|
|
3074
|
+
const spinner = (0, import_ora19.default)("Fetching account info...").start();
|
|
2840
3075
|
try {
|
|
2841
3076
|
const me = await api.whoami();
|
|
2842
3077
|
spinner.stop();
|
|
2843
3078
|
console.log("");
|
|
2844
|
-
console.log(
|
|
2845
|
-
console.log(` User: ${
|
|
2846
|
-
console.log(` Name: ${
|
|
2847
|
-
console.log(` ID: ${
|
|
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)}`);
|
|
2848
3083
|
if (me.orgs.length > 0) {
|
|
2849
3084
|
console.log("");
|
|
2850
|
-
console.log(
|
|
3085
|
+
console.log(import_chalk23.default.bold(" Organizations"));
|
|
2851
3086
|
for (const org of me.orgs) {
|
|
2852
3087
|
console.log(
|
|
2853
|
-
` ${
|
|
3088
|
+
` ${import_chalk23.default.cyan(org.slug)} ${import_chalk23.default.dim(`(${org.name})`)}`
|
|
2854
3089
|
);
|
|
2855
3090
|
}
|
|
2856
3091
|
}
|
|
2857
3092
|
const linkedApp = config.getLinkedApp();
|
|
2858
3093
|
if (linkedApp) {
|
|
2859
3094
|
console.log("");
|
|
2860
|
-
console.log(
|
|
2861
|
-
console.log(` App: ${
|
|
2862
|
-
console.log(` Org: ${
|
|
2863
|
-
console.log(` Env: ${
|
|
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)}`);
|
|
2864
3099
|
} else {
|
|
2865
3100
|
console.log("");
|
|
2866
3101
|
console.log(
|
|
2867
|
-
|
|
3102
|
+
import_chalk23.default.dim(" No app linked. Run `sylphx link` to link one.")
|
|
2868
3103
|
);
|
|
2869
3104
|
}
|
|
2870
3105
|
console.log("");
|
|
2871
3106
|
} catch (err) {
|
|
2872
3107
|
spinner.fail(
|
|
2873
|
-
|
|
3108
|
+
import_chalk23.default.red(
|
|
2874
3109
|
`Failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2875
3110
|
)
|
|
2876
3111
|
);
|
|
@@ -2880,48 +3115,50 @@ var whoamiCommand = new import_commander21.Command("whoami").description("Show c
|
|
|
2880
3115
|
|
|
2881
3116
|
// src/index.ts
|
|
2882
3117
|
var { version: version4 } = package_default;
|
|
2883
|
-
var program = new
|
|
2884
|
-
program.name("sylphx").description(`${
|
|
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(
|
|
2885
3120
|
"after",
|
|
2886
3121
|
`
|
|
2887
|
-
${
|
|
2888
|
-
${
|
|
2889
|
-
${
|
|
2890
|
-
${
|
|
2891
|
-
${
|
|
2892
|
-
${
|
|
2893
|
-
${
|
|
2894
|
-
${
|
|
2895
|
-
${
|
|
2896
|
-
${
|
|
2897
|
-
${
|
|
2898
|
-
${
|
|
2899
|
-
${
|
|
2900
|
-
${
|
|
2901
|
-
${
|
|
2902
|
-
${
|
|
2903
|
-
${
|
|
2904
|
-
${
|
|
2905
|
-
${
|
|
2906
|
-
${
|
|
2907
|
-
${
|
|
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
|
|
2908
3145
|
|
|
2909
|
-
${
|
|
2910
|
-
${
|
|
3146
|
+
${import_chalk24.default.bold("Documentation:")}
|
|
3147
|
+
${import_chalk24.default.underline("https://docs.sylphx.com/cli")}
|
|
2911
3148
|
`
|
|
2912
3149
|
);
|
|
2913
|
-
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(servicesCommand).addCommand(domainsCommand).addCommand(openCommand);
|
|
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);
|
|
2914
3151
|
program.on("command:*", (operands) => {
|
|
2915
|
-
console.error(
|
|
2916
|
-
Unknown command: ${
|
|
3152
|
+
console.error(import_chalk24.default.red(`
|
|
3153
|
+
Unknown command: ${import_chalk24.default.bold(operands[0] ?? "")}
|
|
2917
3154
|
`));
|
|
2918
|
-
console.log(` Run ${
|
|
3155
|
+
console.log(` Run ${import_chalk24.default.cyan("sylphx --help")} for usage.
|
|
2919
3156
|
`);
|
|
2920
3157
|
process.exit(1);
|
|
2921
3158
|
});
|
|
2922
3159
|
program.parseAsync(process.argv).catch((err) => {
|
|
2923
3160
|
const msg = err instanceof Error ? err.message : String(err);
|
|
2924
|
-
console.error(
|
|
3161
|
+
console.error(import_chalk24.default.red(`
|
|
2925
3162
|
Error: ${msg}
|
|
2926
3163
|
`));
|
|
2927
3164
|
process.exit(1);
|