@wervt/cli 0.2.15 → 0.2.16

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.mjs +124 -11
  2. package/package.json +2 -2
package/dist/index.mjs CHANGED
@@ -8,7 +8,7 @@ import { defineCommand, runMain } from "citty";
8
8
  import { detectPackageManager } from "nypm";
9
9
  import { x } from "tinyexec";
10
10
  import { packTar } from "modern-tar";
11
- //#region src/bundle.ts
11
+ // src/bundle.ts
12
12
  /** Files under `dir`. Follows symlinks: Nitro can leave traced dependencies in
13
13
  * server/node_modules as links into the local pnpm store, which won't exist on the server. */
14
14
  async function walk(dir) {
@@ -51,8 +51,7 @@ async function createBundle(appDir) {
51
51
  files: files.length
52
52
  };
53
53
  }
54
- //#endregion
55
- //#region src/config.ts
54
+ // src/config.ts
56
55
  const file = join(process.env.XDG_CONFIG_HOME ?? join(homedir(), ".config"), "wervt", "config.json");
57
56
  /** Flags > WERVT_URL / WERVT_TOKEN > ~/.config/wervt/config.json. */
58
57
  async function resolveConfig(flags) {
@@ -74,8 +73,7 @@ async function saveConfig(config) {
74
73
  await writeFile(file, `${JSON.stringify(config, null, 2)}\n`, { mode: 384 });
75
74
  return file;
76
75
  }
77
- //#endregion
78
- //#region src/format.ts
76
+ // src/format.ts
79
77
  function formatBytes(bytes) {
80
78
  if (bytes < 1024) return `${bytes} B`;
81
79
  const units = [
@@ -123,12 +121,14 @@ function auditSummary(entry) {
123
121
  ].filter(Boolean).join("; ");
124
122
  case "token.create":
125
123
  case "token.revoke": return text(d.name) || text(d.id);
124
+ case "client.create":
125
+ case "client.link":
126
+ case "client.delete": return text(d.name) || text(d.clientId);
126
127
  case "app.delete": return `database ${text(d.database)}`;
127
128
  default: return entry.account ?? "";
128
129
  }
129
130
  }
130
- //#endregion
131
- //#region src/source.ts
131
+ // src/source.ts
132
132
  async function git(dir, ...args) {
133
133
  try {
134
134
  const result = await x("git", args, {
@@ -173,8 +173,7 @@ async function deploySource(dir) {
173
173
  actor: await git(dir, "config", "user.name")
174
174
  };
175
175
  }
176
- //#endregion
177
- //#region src/index.ts
176
+ // src/index.ts
178
177
  const interactive = process.stdout.isTTY === true && !process.env.CI;
179
178
  function progress() {
180
179
  if (interactive) return p.spinner();
@@ -805,6 +804,120 @@ const tokens = defineCommand({
805
804
  }
806
805
  }
807
806
  });
807
+ const appArg = {
808
+ type: "positional",
809
+ required: true,
810
+ description: "App name"
811
+ };
812
+ const clients = defineCommand({
813
+ meta: {
814
+ name: "clients",
815
+ description: "Manage the OAuth clients of an app's native apps (sign-in with wervt)"
816
+ },
817
+ subCommands: {
818
+ list: defineCommand({
819
+ meta: {
820
+ name: "list",
821
+ description: "List the app's native app clients"
822
+ },
823
+ args: {
824
+ app: appArg,
825
+ ...connection
826
+ },
827
+ async run({ args }) {
828
+ const list = await (await api(`/v1/apps/${args.app}/clients`, args)).json();
829
+ if (!list.length) return console.log(`No native app clients for ${args.app}.`);
830
+ for (const client of list) {
831
+ const used = client.lastUsedAt ? `used ${client.lastUsedAt.slice(0, 10)}` : "never used";
832
+ console.log(`${client.clientId} ${client.name} created ${client.createdAt.slice(0, 10)} ${used}`);
833
+ for (const uri of client.redirectUris) console.log(styleText("dim", ` ${uri}`));
834
+ }
835
+ }
836
+ }),
837
+ create: defineCommand({
838
+ meta: {
839
+ name: "create",
840
+ description: "Register a native app for sign-in, e.g. --redirect dev.example.app:/auth"
841
+ },
842
+ args: {
843
+ app: appArg,
844
+ name: {
845
+ type: "string",
846
+ required: true,
847
+ description: "Shown on the consent page"
848
+ },
849
+ redirect: {
850
+ type: "string",
851
+ required: true,
852
+ description: "Redirect URI; comma-separated for several"
853
+ },
854
+ ...connection
855
+ },
856
+ async run({ args }) {
857
+ const client = await (await api(`/v1/apps/${args.app}/clients`, args, {
858
+ method: "POST",
859
+ headers: { "content-type": "application/json" },
860
+ body: JSON.stringify({
861
+ name: args.name,
862
+ redirectUris: toList(args.redirect)
863
+ })
864
+ })).json();
865
+ console.error(`Client "${client.name}" for ${args.app}:`);
866
+ console.log(client.clientId);
867
+ console.error(styleText("dim", "A public client (PKCE, no secret): put the id in the app config."));
868
+ }
869
+ }),
870
+ delete: defineCommand({
871
+ meta: {
872
+ name: "delete",
873
+ description: "Delete a client; everyone signed in through it is signed out"
874
+ },
875
+ args: {
876
+ app: appArg,
877
+ clientId: {
878
+ type: "positional",
879
+ required: true,
880
+ description: "Client id"
881
+ },
882
+ yes: {
883
+ type: "boolean",
884
+ description: "Skip the confirmation"
885
+ },
886
+ ...connection
887
+ },
888
+ async run({ args }) {
889
+ if (!args.yes) {
890
+ const ok = await p.confirm({
891
+ message: `Delete ${args.clientId}? Every install signed in through it is signed out.`,
892
+ initialValue: false
893
+ });
894
+ if (p.isCancel(ok) || !ok) return p.cancel("Cancelled");
895
+ }
896
+ await api(`/v1/apps/${args.app}/clients/${args.clientId}`, args, { method: "DELETE" });
897
+ console.log(`Deleted ${args.clientId}`);
898
+ }
899
+ }),
900
+ link: defineCommand({
901
+ meta: {
902
+ name: "link",
903
+ description: "Admins: assign a client that registered itself to the app"
904
+ },
905
+ args: {
906
+ app: appArg,
907
+ clientId: {
908
+ type: "positional",
909
+ required: true,
910
+ description: "Client id"
911
+ },
912
+ ...connection
913
+ },
914
+ async run({ args }) {
915
+ await api(`/v1/apps/${args.app}/clients/${args.clientId}/link`, args, { method: "POST" });
916
+ console.log(`${args.clientId} belongs to ${args.app} now`);
917
+ }
918
+ })
919
+ }
920
+ });
808
921
  const token = defineCommand({
809
922
  meta: {
810
923
  name: "token",
@@ -1001,7 +1114,7 @@ const remove = defineCommand({
1001
1114
  const dropDb = Boolean(args["drop-database"]);
1002
1115
  if (!args.yes) {
1003
1116
  const ok = await p.confirm({
1004
- message: `Delete ${args.app}${dropDb ? " and ALL its data" : " (database is kept)"}?`,
1117
+ message: `Delete ${args.app}${dropDb ? " and ALL its data" : " (data is kept, the name stays yours)"}?`,
1005
1118
  initialValue: false
1006
1119
  });
1007
1120
  if (p.isCancel(ok) || !ok) return p.cancel("Cancelled");
@@ -1320,6 +1433,7 @@ runMain(defineCommand({
1320
1433
  env,
1321
1434
  tokens,
1322
1435
  token,
1436
+ clients,
1323
1437
  identity,
1324
1438
  tasks,
1325
1439
  stats,
@@ -1329,5 +1443,4 @@ runMain(defineCommand({
1329
1443
  skill
1330
1444
  }
1331
1445
  }));
1332
- //#endregion
1333
1446
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wervt/cli",
3
- "version": "0.2.15",
3
+ "version": "0.2.16",
4
4
  "description": "Deploy and manage apps on wervt.",
5
5
  "keywords": [
6
6
  "agents",
@@ -31,7 +31,7 @@
31
31
  "@clack/prompts": "^1.8.1",
32
32
  "citty": "^0.2.2",
33
33
  "modern-tar": "^0.8.6",
34
- "nypm": "^0.6.10",
34
+ "nypm": "^0.6.12",
35
35
  "tinyexec": "^1.3.1"
36
36
  },
37
37
  "scripts": {