@wervt/cli 0.2.11 → 0.2.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -1
- package/dist/index.mjs +93 -6
- package/package.json +1 -1
- package/skill/SKILL.md +2 -1
package/README.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
1
|
# @wervt/cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The `wervt` command: deploy and manage apps on a [wervt](https://wervt.app) server.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
vpx @wervt/cli login --url https://api.wervt.app # approve the code in the dashboard
|
|
7
|
+
vpx @wervt/cli skill install # teach your agent wervt
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
In an app (`vp create wervt my-app` adds the CLI as a dev dependency):
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
vp exec wervt deploy # build, upload, migrate, activate
|
|
14
|
+
vp exec wervt access my-app --public # or --add friend@example.com
|
|
15
|
+
vp exec wervt logs my-app
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Without [Vite+](https://viteplus.dev), use `npx @wervt/cli` and `pnpm exec wervt`. `wervt --help`
|
|
19
|
+
lists every command: `apps`, `releases`, `rollback`, `activate`, `env`, `tokens`, `members`,
|
|
20
|
+
`tasks`, `stats`, `delete`, `whoami`, … Docs: [wervt.app](https://wervt.app/getting-started/quickstart).
|
package/dist/index.mjs
CHANGED
|
@@ -463,6 +463,45 @@ const access = defineCommand({
|
|
|
463
463
|
if (result.visibility === "private") console.log(result.allow.length ? `allowed: ${result.allow.join(", ")}` : "allowed: admins only");
|
|
464
464
|
}
|
|
465
465
|
});
|
|
466
|
+
const members = defineCommand({
|
|
467
|
+
meta: {
|
|
468
|
+
name: "members",
|
|
469
|
+
description: "Show or change who manages an app (its owner and members)"
|
|
470
|
+
},
|
|
471
|
+
args: {
|
|
472
|
+
app: {
|
|
473
|
+
type: "positional",
|
|
474
|
+
required: true,
|
|
475
|
+
description: "App name"
|
|
476
|
+
},
|
|
477
|
+
add: {
|
|
478
|
+
type: "string",
|
|
479
|
+
description: "Add members by email (comma separated)"
|
|
480
|
+
},
|
|
481
|
+
remove: {
|
|
482
|
+
type: "string",
|
|
483
|
+
description: "Remove members by email (comma separated)"
|
|
484
|
+
},
|
|
485
|
+
owner: {
|
|
486
|
+
type: "string",
|
|
487
|
+
description: "Hand the app to another owner"
|
|
488
|
+
},
|
|
489
|
+
...connection
|
|
490
|
+
},
|
|
491
|
+
async run({ args }) {
|
|
492
|
+
const change = {};
|
|
493
|
+
if (args.add) change.add = toList(args.add);
|
|
494
|
+
if (args.remove) change.remove = toList(args.remove);
|
|
495
|
+
if (args.owner) change.owner = args.owner;
|
|
496
|
+
const result = await (Object.keys(change).length ? await api(`/v1/apps/${args.app}/owners`, args, {
|
|
497
|
+
method: "PATCH",
|
|
498
|
+
headers: { "content-type": "application/json" },
|
|
499
|
+
body: JSON.stringify(change)
|
|
500
|
+
}) : await api(`/v1/apps/${args.app}/owners`, args)).json();
|
|
501
|
+
console.log(`owner: ${result.owner}`);
|
|
502
|
+
console.log(`members: ${result.members.length ? result.members.join(", ") : "none"}`);
|
|
503
|
+
}
|
|
504
|
+
});
|
|
466
505
|
const env = defineCommand({
|
|
467
506
|
meta: {
|
|
468
507
|
name: "env",
|
|
@@ -504,6 +543,48 @@ const env = defineCommand({
|
|
|
504
543
|
if (Object.keys(set).length || unset.length) console.log("Applies from the next request.");
|
|
505
544
|
}
|
|
506
545
|
});
|
|
546
|
+
const accounts = defineCommand({
|
|
547
|
+
meta: {
|
|
548
|
+
name: "accounts",
|
|
549
|
+
description: "Admins: list accounts and their app limits, or set one"
|
|
550
|
+
},
|
|
551
|
+
args: {
|
|
552
|
+
email: {
|
|
553
|
+
type: "positional",
|
|
554
|
+
required: false,
|
|
555
|
+
description: "Account to change"
|
|
556
|
+
},
|
|
557
|
+
apps: {
|
|
558
|
+
type: "string",
|
|
559
|
+
description: "Apps the account may own: a number, \"none\" for no limit, \"default\""
|
|
560
|
+
},
|
|
561
|
+
...connection
|
|
562
|
+
},
|
|
563
|
+
async run({ args }) {
|
|
564
|
+
if (args.email) {
|
|
565
|
+
if (!args.apps) throw new Error("Pass --apps <n|none|default> to change the limit");
|
|
566
|
+
const apps = args.apps === "none" ? null : args.apps === "default" ? "default" : Number(args.apps);
|
|
567
|
+
const result = await (await api(`/v1/accounts/${encodeURIComponent(args.email)}`, args, {
|
|
568
|
+
method: "PATCH",
|
|
569
|
+
headers: { "content-type": "application/json" },
|
|
570
|
+
body: JSON.stringify({ apps })
|
|
571
|
+
})).json();
|
|
572
|
+
return console.log(`${result.email}: ${result.limits.apps ?? "no limit"} apps`);
|
|
573
|
+
}
|
|
574
|
+
const result = await (await api("/v1/accounts", args)).json();
|
|
575
|
+
console.log(`default: ${result.defaults.apps ?? "no limit"} apps per account`);
|
|
576
|
+
for (const account of result.accounts) {
|
|
577
|
+
const list = account.apps.length ? ` ${account.apps.join(", ")}` : "";
|
|
578
|
+
if (account.admin) {
|
|
579
|
+
console.log(`${account.email} ${account.apps.length} apps (admin)${list}`);
|
|
580
|
+
continue;
|
|
581
|
+
}
|
|
582
|
+
const limit = account.limits.apps ?? "no limit";
|
|
583
|
+
const own = "apps" in account.custom ? "" : " (default)";
|
|
584
|
+
console.log(`${account.email} ${account.apps.length}/${limit}${own}${list}`);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
});
|
|
507
588
|
const tokens = defineCommand({
|
|
508
589
|
meta: {
|
|
509
590
|
name: "tokens",
|
|
@@ -791,12 +872,16 @@ const whoami = defineCommand({
|
|
|
791
872
|
args: connection,
|
|
792
873
|
async run({ args }) {
|
|
793
874
|
const { url, token } = await resolveConfig(args);
|
|
794
|
-
const
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
role =
|
|
875
|
+
const res = await fetch(`${url}/v1/whoami`, { headers: { authorization: `Bearer ${token}` } });
|
|
876
|
+
if (res.status === 401) throw new Error(`The token is not valid for ${url}`);
|
|
877
|
+
let role;
|
|
878
|
+
if (res.ok) {
|
|
879
|
+
const me = await res.json();
|
|
880
|
+
role = me.role === "deploy" ? `deploy token for ${me.app}` : me.email ? `${me.role} (${me.email})` : me.role;
|
|
881
|
+
} else {
|
|
882
|
+
const deployApp = token.match(/^wervtd_([a-z0-9-]+)_/)?.[1];
|
|
883
|
+
const probe = deployApp ? void 0 : await fetch(`${url}/v1/databases`, { headers: { authorization: `Bearer ${token}` } });
|
|
884
|
+
role = deployApp ? `deploy token for ${deployApp}` : probe.ok ? "admin" : probe.status === 403 ? "read" : `unknown (${probe.status})`;
|
|
800
885
|
}
|
|
801
886
|
console.log(`${url}\n${role}`);
|
|
802
887
|
}
|
|
@@ -939,6 +1024,8 @@ runMain(defineCommand({
|
|
|
939
1024
|
rollback,
|
|
940
1025
|
reprovision,
|
|
941
1026
|
access,
|
|
1027
|
+
members,
|
|
1028
|
+
accounts,
|
|
942
1029
|
env,
|
|
943
1030
|
tokens,
|
|
944
1031
|
tasks,
|
package/package.json
CHANGED
package/skill/SKILL.md
CHANGED
|
@@ -63,8 +63,9 @@ existing app, work in its repository instead.
|
|
|
63
63
|
|
|
64
64
|
```bash
|
|
65
65
|
pnpm exec wervt deploy # build, upload, migrate, activate
|
|
66
|
-
pnpm exec wervt access <name> --public # new apps are private (
|
|
66
|
+
pnpm exec wervt access <name> --public # new apps are private (owner, members, admins)
|
|
67
67
|
pnpm exec wervt access <name> --add a@x.com,*@company.com # or let specific people in
|
|
68
|
+
pnpm exec wervt members <name> --add a@x.com # who may deploy and manage it (the first deploy owns it)
|
|
68
69
|
pnpm exec wervt env <name> --set KEY=value # server env vars, applied from the next request
|
|
69
70
|
```
|
|
70
71
|
|