@wervt/cli 0.2.3 → 0.2.5

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.mjs CHANGED
@@ -220,6 +220,7 @@ const deploy = defineCommand({
220
220
  const labels = {
221
221
  extract: "Extracting",
222
222
  migrate: "Migrating database",
223
+ storage: "Setting up storage",
223
224
  activate: "Activating"
224
225
  };
225
226
  const decoder = new TextDecoder();
@@ -241,6 +242,10 @@ const deploy = defineCommand({
241
242
  if (process.env.GITHUB_OUTPUT) await appendFile(process.env.GITHUB_OUTPUT, `url=${event.url}\nrelease=${event.release}\n`);
242
243
  return;
243
244
  }
245
+ if (event.step === "storage-failed") {
246
+ p.log.warn(`Storage isn't set up: ${event.message}. The app runs; files won't work yet.`);
247
+ continue;
248
+ }
244
249
  spinner.message(labels[event.step] ?? event.step);
245
250
  }
246
251
  }
@@ -493,6 +498,61 @@ const tokens = defineCommand({
493
498
  }
494
499
  }
495
500
  });
501
+ const tasks = defineCommand({
502
+ meta: {
503
+ name: "tasks",
504
+ description: "List an app's tasks and schedules, or run one now"
505
+ },
506
+ args: {
507
+ app: {
508
+ type: "positional",
509
+ required: true,
510
+ description: "App name"
511
+ },
512
+ run: {
513
+ type: "string",
514
+ description: "Run this task now and wait for it"
515
+ },
516
+ payload: {
517
+ type: "string",
518
+ description: "JSON payload for --run"
519
+ },
520
+ json: {
521
+ type: "boolean",
522
+ description: "Print JSON"
523
+ },
524
+ ...connection
525
+ },
526
+ async run({ args }) {
527
+ if (args.run) {
528
+ const payload = args.payload ? JSON.parse(args.payload) : {};
529
+ const result = await (await api(`/v1/apps/${args.app}/tasks/${encodeURIComponent(args.run)}/run`, args, {
530
+ method: "POST",
531
+ headers: { "content-type": "application/json" },
532
+ body: JSON.stringify({ payload })
533
+ })).json();
534
+ if (args.json) console.log(JSON.stringify(result));
535
+ else {
536
+ const color = result.status === "ok" ? "green" : result.status === "error" ? "red" : "yellow";
537
+ const took = result.durationMs === void 0 ? "" : ` in ${result.durationMs} ms`;
538
+ console.log(`${styleText(color, result.status)}${took}${result.error ? `: ${result.error}` : ""}`);
539
+ if (result.result !== void 0 && result.result !== null) console.log(JSON.stringify(result.result, null, 2));
540
+ }
541
+ if (result.status !== "ok") process.exitCode = 1;
542
+ return;
543
+ }
544
+ const list = await (await api(`/v1/apps/${args.app}/tasks`, args)).json();
545
+ if (args.json) return console.log(JSON.stringify(list));
546
+ if (!list.tasks.length) return console.log(`${args.app} has no tasks.`);
547
+ console.log(styleText("dim", `Schedules in ${list.timezone}`));
548
+ for (const task of list.tasks) {
549
+ const schedules = task.schedules.length ? task.schedules.map((s) => `${s.cron}${s.next ? styleText("dim", ` (next ${s.next})`) : ""}`).join(", ") : styleText("dim", "manual only");
550
+ console.log(`${styleText("bold", task.name)}${task.running ? styleText("cyan", " running") : ""} ${schedules}`);
551
+ if (task.description) console.log(` ${styleText("dim", task.description)}`);
552
+ }
553
+ console.log(styleText("dim", `\nRecent runs: wervt logs ${args.app} 'type:=Task' --since 1d`));
554
+ }
555
+ });
496
556
  const remove = defineCommand({
497
557
  meta: {
498
558
  name: "delete",
@@ -506,7 +566,7 @@ const remove = defineCommand({
506
566
  },
507
567
  "drop-database": {
508
568
  type: "boolean",
509
- description: "Also drop the app's schema and all its data"
569
+ description: "Also drop the app's schema, its files and all its data"
510
570
  },
511
571
  yes: {
512
572
  type: "boolean",
@@ -762,6 +822,7 @@ runMain(defineCommand({
762
822
  access,
763
823
  env,
764
824
  tokens,
825
+ tasks,
765
826
  delete: remove,
766
827
  login,
767
828
  whoami,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wervt/cli",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "Deploy and manage apps on wervt.",
5
5
  "keywords": [
6
6
  "agents",
package/skill/SKILL.md CHANGED
@@ -33,7 +33,9 @@ cd <name>
33
33
  The app comes with `AGENTS.md`, skills in `.claude/skills/` and a deploy workflow. **Read
34
34
  `AGENTS.md` before writing code** and follow it: server routes, valibot validation, Drizzle schema
35
35
  and migrations, live data with shapes, users, logging, and what the isolate runtime can't do
36
- (no filesystem, no child processes, no long-running work, no WebSockets, no cron).
36
+ (no filesystem, no child processes, no long-running work, no WebSockets). Periodic work goes
37
+ into tasks (`defineTask` + `nitro.scheduledTasks`), which wervt runs on schedule. Files go into
38
+ the app's own bucket with ablage (`pnpm add ablage`, no configuration).
37
39
 
38
40
  Before picking a name, run `wervt apps` so you don't overwrite an existing app. If the user named an
39
41
  existing app, work in its repository instead.
@@ -90,6 +92,8 @@ release lists the commit.
90
92
  pnpm exec wervt apps # every app, active release, URL
91
93
  pnpm exec wervt releases <name> # newest first, with commit and author
92
94
  pnpm exec wervt logs <name> 'status:>=500' --since 1d --json
95
+ pnpm exec wervt tasks <name> # tasks, schedules, next runs
96
+ pnpm exec wervt tasks <name> --run <task> # run one now
93
97
  pnpm exec wervt rollback <name> # the previous release (migrations stay)
94
98
  ```
95
99