@platforma-sdk/pl-cli 0.8.29 → 0.9.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.
package/dist/cli.js CHANGED
@@ -1,75 +1,75 @@
1
- import { _ as e, a as t, c as n, d as r, f as i, g as a, h as o, i as s, l as c, m as l, n as u, o as d, p as f, r as p, s as m, t as h, u as g } from "./output-KEq0q5fS.js";
2
- import { Command as _, Option as v } from "commander";
3
- import { field as y, resourceIdToString as b } from "@milaboratories/pl-client";
4
- import { ProjectMetaKey as x } from "@milaboratories/pl-middle-layer";
5
- import { randomUUID as S } from "node:crypto";
6
- import { createInterface as C } from "node:readline";
1
+ import { _ as e, a as t, b as n, c as r, d as i, f as a, g as o, h as s, i as c, l, m as u, n as d, o as f, p, r as m, s as h, t as g, u as _, v, x as y, y as b } from "./output-BAuWMUzX.js";
2
+ import { Command as x, Option as S } from "commander";
3
+ import { field as C, resourceIdToString as w } from "@milaboratories/pl-client";
4
+ import { randomUUID as T } from "node:crypto";
5
+ import { ProjectMetaKey as E } from "@milaboratories/pl-middle-layer";
6
+ import { createInterface as D } from "node:readline";
7
7
  //#region src/base_command.ts
8
- async function w(t) {
9
- return t.adminUser && t.adminPassword ? a({
10
- address: t.address,
11
- adminUser: t.adminUser,
12
- adminPassword: t.adminPassword
13
- }) : e({
14
- address: t.address,
15
- user: t.user,
16
- password: t.password
8
+ async function O(e) {
9
+ return e.adminUser && e.adminPassword ? n({
10
+ address: e.address,
11
+ adminUser: e.adminUser,
12
+ adminPassword: e.adminPassword
13
+ }) : y({
14
+ address: e.address,
15
+ user: e.user,
16
+ password: e.password
17
17
  });
18
18
  }
19
- async function T(e) {
20
- let t = !!e.adminUser, n = !!e.adminPassword, i = !!e.targetUser;
21
- if (i && !(t && n)) throw Error("--target-user requires --admin-user and --admin-password");
22
- if ((t || n) && !i) throw Error("--admin-user/--admin-password require --target-user for project commands");
23
- let a = await w(e), o;
24
- return o = i ? (await f(a, e.targetUser)).projectListRid : await r(a), {
25
- pl: a,
26
- projectListRid: o
19
+ async function k(e) {
20
+ let t = !!e.adminUser, n = !!e.adminPassword, r = !!e.targetUser;
21
+ if (r && !(t && n)) throw Error("--target-user requires --admin-user and --admin-password");
22
+ if ((t || n) && !r) throw Error("--admin-user/--admin-password require --target-user for project commands");
23
+ let i = await O(e), s;
24
+ return s = r ? (await o(i, e.targetUser)).projectListRid : await a(i), {
25
+ pl: i,
26
+ projectListRid: s
27
27
  };
28
28
  }
29
29
  //#endregion
30
30
  //#region src/cmd-opts.ts
31
- function E(e, ...t) {
31
+ function A(e, ...t) {
32
32
  for (let n of t) for (let t of n) e.addOption(t);
33
33
  return e;
34
34
  }
35
- var D = (e = "text", t = ["text", "json"]) => [new v("-a, --address <url>", "Platforma server address").env("PL_ADDRESS").makeOptionMandatory(), new v("-f, --format <format>", "Output format").choices(t).default(e)], O = () => [new v("-u, --user <user>", "Username for authentication").env("PL_USER"), new v("-p, --password <password>", "Password for authentication").env("PL_PASSWORD")], k = () => [new v("--admin-user <user>", "Admin/controller username").env("PL_ADMIN_USER").makeOptionMandatory(), new v("--admin-password <password>", "Admin/controller password").env("PL_ADMIN_PASSWORD").makeOptionMandatory()], A = () => [
36
- new v("--admin-user <user>", "Admin/controller username (enables admin mode)").env("PL_ADMIN_USER"),
37
- new v("--admin-password <password>", "Admin/controller password").env("PL_ADMIN_PASSWORD"),
38
- new v("--target-user <user>", "Operate on this user's data (requires admin credentials)").env("PL_TARGET_USER")
35
+ var j = (e = "text", t = ["text", "json"]) => [new S("-a, --address <url>", "Platforma server address").env("PL_ADDRESS").makeOptionMandatory(), new S("-f, --format <format>", "Output format").choices(t).default(e)], M = () => [new S("-u, --user <user>", "Username for authentication").env("PL_USER"), new S("-p, --password <password>", "Password for authentication").env("PL_PASSWORD")], N = () => [new S("--admin-user <user>", "Admin/controller username").env("PL_ADMIN_USER").makeOptionMandatory(), new S("--admin-password <password>", "Admin/controller password").env("PL_ADMIN_PASSWORD").makeOptionMandatory()], P = () => [
36
+ new S("--admin-user <user>", "Admin/controller username (enables admin mode)").env("PL_ADMIN_USER"),
37
+ new S("--admin-password <password>", "Admin/controller password").env("PL_ADMIN_PASSWORD"),
38
+ new S("--target-user <user>", "Operate on this user's data (requires admin credentials)").env("PL_TARGET_USER")
39
39
  ];
40
40
  //#endregion
41
41
  //#region src/cmd/project/list.ts
42
- function j() {
43
- let e = new _("list").description("List all projects for the authenticated user.");
44
- return E(e, D(), O(), A()), e.action(async (e) => {
45
- let { pl: n, projectListRid: r } = await T(e);
42
+ function F() {
43
+ let e = new x("list").description("List all projects for the authenticated user.");
44
+ return A(e, j(), M(), P()), e.action(async (e) => {
45
+ let { pl: n, projectListRid: r } = await k(e);
46
46
  try {
47
- let a = await i(n, r);
48
- if (e.format === "json") s(a.map((e) => ({
47
+ let i = await u(n, r);
48
+ if (e.format === "json") c(i.map((e) => ({
49
49
  id: e.id,
50
- rid: b(e.rid),
50
+ rid: w(e.rid),
51
51
  label: e.label,
52
52
  created: e.created.toISOString(),
53
53
  lastModified: e.lastModified.toISOString()
54
54
  })));
55
55
  else {
56
- if (a.length === 0) {
56
+ if (i.length === 0) {
57
57
  t("No projects found.");
58
58
  return;
59
59
  }
60
- t(u([
60
+ t(d([
61
61
  "ID",
62
62
  "RID",
63
63
  "LABEL",
64
64
  "CREATED",
65
65
  "LAST MODIFIED"
66
- ], a.map((e) => [
66
+ ], i.map((e) => [
67
67
  e.id,
68
- b(e.rid),
68
+ w(e.rid),
69
69
  e.label,
70
- h(e.created),
71
- h(e.lastModified)
72
- ]))), t(`\n${a.length} project(s)`);
70
+ g(e.created),
71
+ g(e.lastModified)
72
+ ]))), t(`\n${i.length} project(s)`);
73
73
  }
74
74
  } finally {
75
75
  await n.close();
@@ -78,15 +78,15 @@ function j() {
78
78
  }
79
79
  //#endregion
80
80
  //#region src/cmd/project/info.ts
81
- function M() {
82
- let e = new _("info").description("Show detailed information about a project.");
83
- return e.argument("<project>", "Project ID or label"), E(e, D(), O(), A()), e.action(async (e, n) => {
84
- let { pl: r, projectListRid: i } = await T(n);
81
+ function I() {
82
+ let e = new x("info").description("Show detailed information about a project.");
83
+ return e.argument("<project>", "Project ID or label"), A(e, j(), M(), P()), e.action(async (e, n) => {
84
+ let { pl: r, projectListRid: a } = await k(n);
85
85
  try {
86
- let { id: a, rid: c } = await o(r, i, e), l = await g(r, a, c);
87
- if (n.format === "json") s({
86
+ let { id: o, rid: s } = await b(r, a, e), l = await i(r, o, s);
87
+ if (n.format === "json") c({
88
88
  id: l.id,
89
- rid: b(l.rid),
89
+ rid: w(l.rid),
90
90
  label: l.label,
91
91
  schemaVersion: l.schemaVersion,
92
92
  blockCount: l.blockCount,
@@ -95,8 +95,8 @@ function M() {
95
95
  lastModified: l.lastModified.toISOString()
96
96
  });
97
97
  else {
98
- if (t(`Project: ${l.label}`), t(`ID: ${l.id}`), t(`RID: ${b(l.rid)}`), t(`Schema: ${l.schemaVersion ?? "(unknown)"}`), t(`Blocks: ${l.blockCount}`), l.blockIds.length > 0) for (let e of l.blockIds) t(` - ${e}`);
99
- t(`Created: ${h(l.created)}`), t(`Last Modified: ${h(l.lastModified)}`);
98
+ if (t(`Project: ${l.label}`), t(`ID: ${l.id}`), t(`RID: ${w(l.rid)}`), t(`Schema: ${l.schemaVersion ?? "(unknown)"}`), t(`Blocks: ${l.blockCount}`), l.blockIds.length > 0) for (let e of l.blockIds) t(` - ${e}`);
99
+ t(`Created: ${g(l.created)}`), t(`Last Modified: ${g(l.lastModified)}`);
100
100
  }
101
101
  } finally {
102
102
  await r.close();
@@ -105,31 +105,31 @@ function M() {
105
105
  }
106
106
  //#endregion
107
107
  //#region src/cmd/project/duplicate.ts
108
- function N() {
109
- let e = new _("duplicate").description("Duplicate a project within the same user. Auto-renames on collision by default.");
110
- return e.argument("<project>", "Project ID or label"), E(e, D(), O(), A()), e.option("-n, --name <name>", "Name for the duplicate"), e.addOption(new v("--auto-rename", "Auto-rename on collision (default: true)").default(!0)), e.option("--no-auto-rename", "Fail on name collision instead of auto-renaming"), e.action(async (e, r) => {
111
- let { pl: i, projectListRid: a } = await T(r);
108
+ function L() {
109
+ let e = new x("duplicate").description("Duplicate a project within the same user. Auto-renames on collision by default.");
110
+ return e.argument("<project>", "Project ID or label"), A(e, j(), M(), P()), e.option("-n, --name <name>", "Name for the duplicate"), e.addOption(new S("--auto-rename", "Auto-rename on collision (default: true)").default(!0)), e.option("--no-auto-rename", "Fail on name collision instead of auto-renaming"), e.action(async (e, n) => {
111
+ let { pl: i, projectListRid: a } = await k(n);
112
112
  try {
113
- let { rid: l } = await o(i, a, e), u = S(), f = await i.withWriteTx("duplicateProject", async (e) => {
114
- let t = await e.getKValueString(l, x), i = JSON.parse(t).label, o = await c(e, a), s;
115
- if (r.name) {
116
- if (!r.autoRename && o.includes(r.name)) throw Error(`Project name "${r.name}" already exists.`);
117
- s = o.includes(r.name) ? d(r.name, o) : r.name;
118
- } else s = d(i, o);
119
- let f = await n(e, l, { label: s });
120
- e.createField(y(a, u), "Dynamic", f), await e.commit();
121
- let p = await f.globalId;
113
+ let { rid: o } = await b(i, a, e), s = T(), l = await i.withWriteTx("duplicateProject", async (e) => {
114
+ let t = await e.getKValueString(o, E), i = JSON.parse(t).label, c = await _(e, a), l;
115
+ if (n.name) {
116
+ if (!n.autoRename && c.includes(n.name)) throw Error(`Project name "${n.name}" already exists.`);
117
+ l = c.includes(n.name) ? f(n.name, c) : n.name;
118
+ } else l = f(i, c);
119
+ let u = await r(e, o, { label: l });
120
+ e.createField(C(a, s), "Dynamic", u), await e.commit();
121
+ let d = await u.globalId;
122
122
  return {
123
- id: b(p),
124
- rid: p,
125
- label: s
123
+ id: w(d),
124
+ rid: d,
125
+ label: l
126
126
  };
127
127
  });
128
- r.format === "json" ? s({
129
- id: f.id,
130
- rid: b(f.rid),
131
- label: f.label
132
- }) : t(`Duplicated project as "${f.label}" (id: ${f.id})`);
128
+ n.format === "json" ? c({
129
+ id: l.id,
130
+ rid: w(l.rid),
131
+ label: l.label
132
+ }) : t(`Duplicated project as "${l.label}" (id: ${l.id})`);
133
133
  } finally {
134
134
  await i.close();
135
135
  }
@@ -137,15 +137,15 @@ function N() {
137
137
  }
138
138
  //#endregion
139
139
  //#region src/cmd/project/rename.ts
140
- function P() {
141
- let e = new _("rename").description("Rename a project.");
142
- return e.argument("<project>", "Project ID or label"), E(e, D(), O(), A()), e.addOption(new v("-n, --name <name>", "New name for the project").makeOptionMandatory()), e.action(async (e, n) => {
143
- let { pl: r, projectListRid: i } = await T(n);
140
+ function R() {
141
+ let e = new x("rename").description("Rename a project.");
142
+ return e.argument("<project>", "Project ID or label"), A(e, j(), M(), P()), e.addOption(new S("-n, --name <name>", "New name for the project").makeOptionMandatory()), e.action(async (e, n) => {
143
+ let { pl: r, projectListRid: i } = await k(n);
144
144
  try {
145
- let { id: a, rid: c } = await o(r, i, e);
146
- await l(r, c, n.name), n.format === "json" ? s({
145
+ let { id: a, rid: o } = await b(r, i, e);
146
+ await v(r, o, n.name), n.format === "json" ? c({
147
147
  id: a,
148
- rid: b(c),
148
+ rid: w(o),
149
149
  label: n.name
150
150
  }) : t(`Renamed project to "${n.name}"`);
151
151
  } finally {
@@ -155,14 +155,14 @@ function P() {
155
155
  }
156
156
  //#endregion
157
157
  //#region src/cmd/project/delete.ts
158
- function F() {
159
- let e = new _("delete").description("Delete a project. This permanently destroys all project data.");
160
- return e.argument("<project>", "Project ID or label"), E(e, D(), O(), A()), e.option("--force", "Skip confirmation", !1), e.action(async (e, n) => {
161
- let { pl: r, projectListRid: i } = await T(n);
158
+ function z() {
159
+ let e = new x("delete").description("Delete a project. This permanently destroys all project data.");
160
+ return e.argument("<project>", "Project ID or label"), A(e, j(), M(), P()), e.option("--force", "Skip confirmation", !1), e.action(async (e, n) => {
161
+ let { pl: r, projectListRid: a } = await k(n);
162
162
  try {
163
- let { id: a, rid: c, fieldName: l } = await o(r, i, e), u = await g(r, a, c);
163
+ let { id: o, rid: s, fieldName: l } = await b(r, a, e), u = await i(r, o, s);
164
164
  if (!n.force) {
165
- let e = C({
165
+ let e = D({
166
166
  input: process.stdin,
167
167
  output: process.stderr
168
168
  });
@@ -177,9 +177,9 @@ function F() {
177
177
  e.close();
178
178
  }
179
179
  }
180
- await m(r, i, l), n.format === "json" ? s({
180
+ await h(r, a, l), n.format === "json" ? c({
181
181
  deleted: !0,
182
- id: a,
182
+ id: o,
183
183
  label: u.label
184
184
  }) : t(`Deleted project "${u.label}"`);
185
185
  } finally {
@@ -189,70 +189,146 @@ function F() {
189
189
  }
190
190
  //#endregion
191
191
  //#region src/cmd/admin/copy-project.ts
192
- function I() {
193
- let e = new _("copy-project").description("Copy a project from one user to another. Requires admin/controller credentials.");
194
- return E(e, D(), k()), e.addOption(new v("--source-user <user>", "Username of the source project owner").makeOptionMandatory()), e.addOption(new v("--source-project <project>", "Source project ID or label").makeOptionMandatory()), e.option("--target-user <user>", "Username of the target user (defaults to source-user for same-user copy)"), e.option("-n, --name <name>", "Name for the copied project"), e.addOption(new v("--auto-rename", "Auto-rename on collision (default: true)").default(!0)), e.option("--no-auto-rename", "Fail on name collision instead of auto-renaming"), e.action(async (e) => {
195
- let r = await w(e);
192
+ function B() {
193
+ let e = new x("copy-project").description("Copy a project from one user to another. Requires admin/controller credentials.");
194
+ return A(e, j(), N()), e.addOption(new S("--source-user <user>", "Username of the source project owner").makeOptionMandatory()), e.addOption(new S("--source-project <project>", "Source project ID or label").makeOptionMandatory()), e.option("--target-user <user>", "Username of the target user (defaults to source-user for same-user copy)"), e.option("-n, --name <name>", "Name for the copied project"), e.addOption(new S("--auto-rename", "Auto-rename on collision (default: true)").default(!0)), e.option("--no-auto-rename", "Fail on name collision instead of auto-renaming"), e.action(async (e) => {
195
+ let n = await O(e);
196
196
  try {
197
- let i = e.targetUser ?? e.sourceUser, a = await f(r, e.sourceUser), { rid: l } = await o(r, a.projectListRid, e.sourceProject), u = i === e.sourceUser ? a : await f(r, i), p = S(), m = await r.withWriteTx("adminCopyProject", async (t) => {
198
- let r = await t.getKValueString(l, x), i = JSON.parse(r).label, a = await c(t, u.projectListRid), o = e.name ?? i;
197
+ let i = e.targetUser ?? e.sourceUser, a = await o(n, e.sourceUser), { rid: s } = await b(n, a.projectListRid, e.sourceProject), l = i === e.sourceUser ? a : await o(n, i), u = T(), d = await n.withWriteTx("adminCopyProject", async (t) => {
198
+ let n = await t.getKValueString(s, E), i = JSON.parse(n).label, a = await _(t, l.projectListRid), o = e.name ?? i;
199
199
  if (a.includes(o)) {
200
200
  if (!e.autoRename) throw Error(`Project name "${o}" already exists for target user.`);
201
- o = d(e.name ?? i, a);
201
+ o = f(e.name ?? i, a);
202
202
  }
203
- let s = await n(t, l, { label: o });
204
- t.createField(y(u.projectListRid, p), "Dynamic", s), await t.commit();
205
- let f = await s.globalId;
203
+ let c = await r(t, s, { label: o });
204
+ t.createField(C(l.projectListRid, u), "Dynamic", c), await t.commit();
205
+ let d = await c.globalId;
206
206
  return {
207
- id: b(f),
208
- rid: f,
207
+ id: w(d),
208
+ rid: d,
209
209
  label: o
210
210
  };
211
211
  });
212
- e.format === "json" ? s({
213
- id: m.id,
214
- rid: b(m.rid),
215
- label: m.label,
212
+ e.format === "json" ? c({
213
+ id: d.id,
214
+ rid: w(d.rid),
215
+ label: d.label,
216
216
  sourceUser: e.sourceUser,
217
217
  targetUser: i
218
- }) : t(`Copied project from ${e.sourceUser} to ${i} as "${m.label}" (id: ${m.id}, rid: ${b(m.rid)})`);
218
+ }) : t(`Copied project from ${e.sourceUser} to ${i} as "${d.label}" (id: ${d.id}, rid: ${w(d.rid)})`);
219
219
  } finally {
220
- await r.close();
220
+ await n.close();
221
221
  }
222
222
  }), e;
223
223
  }
224
224
  //#endregion
225
225
  //#region src/cmd/admin/user-list.ts
226
- function L() {
227
- let e = new _("user-list").description("List all known users' logins from a live server. Requires admin/controller credentials.");
228
- return E(e, D("csv", [
226
+ function V() {
227
+ let e = new x("user-list").description("List all known users' logins from a live server. Requires admin/controller credentials.");
228
+ return A(e, j("csv", [
229
229
  "text",
230
230
  "json",
231
231
  "csv"
232
- ]), k()), e.action(async (e) => {
233
- let n = await w(e);
232
+ ]), N()), e.action(async (e) => {
233
+ let n = await O(e);
234
234
  try {
235
235
  let r = (await n.listUsers()).map((e) => e.login).sort();
236
- e.format === "json" ? s(r) : e.format === "text" ? t(r.join("\n")) : p(["login"], r.map((e) => [e]));
236
+ e.format === "json" ? c(r) : e.format === "text" ? t(r.join("\n")) : m(["login"], r.map((e) => [e]));
237
237
  } finally {
238
238
  await n.close();
239
239
  }
240
240
  }), e;
241
241
  }
242
242
  //#endregion
243
+ //#region src/cmd/admin/delete-user.ts
244
+ function H() {
245
+ let n = new x("delete-user").description("Delete a user account. Optionally re-homes the user's projects to another user first. Requires admin/controller credentials.");
246
+ return n.argument("<user>", "Username of the account to delete"), A(n, j(), N()), n.addOption(new S("--move-projects-to <user>", "Re-home the deleted user's projects to this user before deleting the account")), n.addOption(new S("--delete-projects", "Delete the user's projects along with the account, losing their data")), n.option("--force", "Skip confirmation", !1), n.action(async (n, r) => {
247
+ if (r.moveProjectsTo && r.deleteProjects) throw Error("--move-projects-to and --delete-projects are mutually exclusive");
248
+ if (r.moveProjectsTo === n) throw Error("--move-projects-to must name a different user than the one being deleted");
249
+ if (r.adminUser === n) throw Error(`Refusing to delete "${n}" — it is the account these credentials authenticate as.`);
250
+ let i = await O(r);
251
+ try {
252
+ let a = await e(i, n), o = a.projectListRid === void 0 ? [] : await p(i, a.projectListRid);
253
+ if (o.length > 0 && !r.moveProjectsTo && !r.deleteProjects) throw Error(`User "${n}" owns ${o.length} project(s). Pass --move-projects-to <user> to re-home them, or --delete-projects to delete them with the account.`);
254
+ if (!await W(n, o, r)) {
255
+ t("Aborted.");
256
+ return;
257
+ }
258
+ let u = [];
259
+ if (r.moveProjectsTo && o.length > 0) {
260
+ let t = await l(i, (await e(i, r.moveProjectsTo)).userRoot);
261
+ u = await s(i, a.projectListRid, t);
262
+ }
263
+ let d = a.projectListRid === void 0 ? [] : await p(i, a.projectListRid);
264
+ U(n, r, o, d);
265
+ let f = await i.deleteUser(n);
266
+ r.format === "json" ? c({
267
+ deleted: !0,
268
+ user: n,
269
+ movedTo: r.moveProjectsTo ?? null,
270
+ movedProjects: u,
271
+ deletedProjects: r.moveProjectsTo ? [] : d.map((e) => e.label),
272
+ userRootId: f.userRootId === void 0 ? null : f.userRootId.toString(),
273
+ userRootDeleted: f.userRootDeleted,
274
+ revokedGrants: f.revokedGrants,
275
+ removedIdentityIndexEntries: f.removedIdentityIndexEntries
276
+ }) : t(G(n, r.moveProjectsTo, u, d));
277
+ } finally {
278
+ await i.close();
279
+ }
280
+ }), n;
281
+ }
282
+ function U(e, t, n, r) {
283
+ if (t.moveProjectsTo) {
284
+ if (r.length === 0) return;
285
+ throw Error(`User "${e}" still owns ${r.length} project(s) after the move: ${r.map((e) => e.label).join(", ")}. The account was NOT deleted — the projects were attached while the move ran. Re-run the command to move them too.`);
286
+ }
287
+ let i = new Set(n.map((e) => e.id)), a = r.filter((e) => !i.has(e.id));
288
+ if (a.length !== 0) throw Error(`User "${e}" gained ${a.length} project(s) since the list you confirmed: ${a.map((e) => e.label).join(", ")}. The account was NOT deleted — deleting it now would destroy them unreviewed. Re-run the command to see the current list.`);
289
+ }
290
+ async function W(e, t, n) {
291
+ if (n.force) return !0;
292
+ let r = n.moveProjectsTo ? `${t.length} project(s) will move to "${n.moveProjectsTo}"` : t.length > 0 ? `${t.length} project(s) will be PERMANENTLY DELETED` : "the account owns no projects";
293
+ process.stderr.write(`Delete user "${e}"? ${r}.\n`), t.length > 0 && process.stderr.write(t.map((e) => ` - ${e.label}`).join("\n") + "\n");
294
+ let i = D({
295
+ input: process.stdin,
296
+ output: process.stderr
297
+ });
298
+ try {
299
+ return (await new Promise((e) => {
300
+ i.question("Proceed? [y/N] ", e);
301
+ })).toLowerCase() === "y";
302
+ } finally {
303
+ i.close();
304
+ }
305
+ }
306
+ function G(e, t, n, r) {
307
+ let i = [];
308
+ return t ? n.length > 0 ? (i.push(`Moved ${n.length} project(s) from ${e} to ${t}:`), i.push(d([
309
+ "id",
310
+ "name",
311
+ "name in target"
312
+ ], n.map((e) => [
313
+ e.id,
314
+ e.sourceLabel,
315
+ e.targetLabel
316
+ ])))) : i.push(`User ${e} had no projects to move.`) : r.length > 0 && (i.push(`Deleted ${r.length} project(s) belonging to ${e}:`), i.push(r.map((e) => ` - ${e.label}`).join("\n"))), i.push(`Deleted user "${e}".`), i.join("\n");
317
+ }
318
+ //#endregion
243
319
  //#region src/cli.ts
244
- function R() {
245
- let e = new _();
320
+ function K() {
321
+ let e = new x();
246
322
  e.name("pl-cli").description("Platforma command-line client");
247
- let t = new _("project").description("Manage projects");
248
- t.addCommand(j()), t.addCommand(M()), t.addCommand(N()), t.addCommand(P()), t.addCommand(F()), e.addCommand(t);
249
- let n = new _("admin").description("Admin operations (requires controller credentials)");
250
- return n.addCommand(I()), n.addCommand(L()), e.addCommand(n), e;
323
+ let t = new x("project").description("Manage projects");
324
+ t.addCommand(F()), t.addCommand(I()), t.addCommand(L()), t.addCommand(R()), t.addCommand(z()), e.addCommand(t);
325
+ let n = new x("admin").description("Admin operations (requires controller credentials)");
326
+ return n.addCommand(B()), n.addCommand(V()), n.addCommand(H()), e.addCommand(n), e;
251
327
  }
252
- async function z(e = process.argv) {
253
- await R().parseAsync(e);
328
+ async function q(e = process.argv) {
329
+ await K().parseAsync(e);
254
330
  }
255
331
  //#endregion
256
- export { R as buildProgram, z as run };
332
+ export { K as buildProgram, q as run };
257
333
 
258
334
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","names":[],"sources":["../src/base_command.ts","../src/cmd-opts.ts","../src/cmd/project/list.ts","../src/cmd/project/info.ts","../src/cmd/project/duplicate.ts","../src/cmd/project/rename.ts","../src/cmd/project/delete.ts","../src/cmd/admin/copy-project.ts","../src/cmd/admin/user-list.ts","../src/cli.ts"],"sourcesContent":["import type { PlClient, SignedResourceId } from \"@milaboratories/pl-client\";\nimport { createPlConnection, createAdminPlConnection } from \"./connection\";\nimport { getProjectListRid, navigateToUserRoot } from \"./project_ops\";\n\n/**\n * Low-level: get an authenticated PlClient without resolving a project list.\n * Use this for commands that navigate to multiple users (e.g. admin copy-project).\n *\n * Callers own the returned client and must `await pl.close()` when done.\n */\nexport async function connectClient(flags: {\n address: string;\n user?: string;\n password?: string;\n adminUser?: string;\n adminPassword?: string;\n}): Promise<PlClient> {\n if (flags.adminUser && flags.adminPassword) {\n return createAdminPlConnection({\n address: flags.address,\n adminUser: flags.adminUser,\n adminPassword: flags.adminPassword,\n });\n }\n return createPlConnection({\n address: flags.address,\n user: flags.user,\n password: flags.password,\n });\n}\n\n/**\n * Connect and resolve the project list for a single user.\n * In admin mode (--admin-user + --admin-password + --target-user), operates on the target user's data.\n * In user mode, operates on the authenticated user's own data.\n *\n * Callers own the returned client and must `await pl.close()` when done.\n */\nexport async function connect(flags: {\n address: string;\n user?: string;\n password?: string;\n adminUser?: string;\n adminPassword?: string;\n targetUser?: string;\n}): Promise<{ pl: PlClient; projectListRid: SignedResourceId }> {\n const hasAdminUser = !!flags.adminUser;\n const hasAdminPassword = !!flags.adminPassword;\n const hasTarget = !!flags.targetUser;\n\n // Validate flag combinations\n if (hasTarget && !(hasAdminUser && hasAdminPassword)) {\n throw new Error(\"--target-user requires --admin-user and --admin-password\");\n }\n if ((hasAdminUser || hasAdminPassword) && !hasTarget) {\n throw new Error(\"--admin-user/--admin-password require --target-user for project commands\");\n }\n\n const pl = await connectClient(flags);\n\n let projectListRid: SignedResourceId;\n if (hasTarget) {\n const nav = await navigateToUserRoot(pl, flags.targetUser!);\n projectListRid = nav.projectListRid;\n } else {\n projectListRid = await getProjectListRid(pl);\n }\n\n return { pl, projectListRid };\n}\n","import { Command, Option } from \"commander\";\nimport type { OutputFormat } from \"./output\";\n\n/** Add one or more groups of options to a command, preserving group order. */\nexport function addOptions(cmd: Command, ...optionGroups: Option[][]): Command {\n for (const group of optionGroups) {\n for (const opt of group) cmd.addOption(opt);\n }\n return cmd;\n}\n\nexport const GlobalOptions = (\n formatDefault: OutputFormat = \"text\",\n allowedFormats: OutputFormat[] = [\"text\", \"json\"],\n): Option[] => [\n new Option(\"-a, --address <url>\", \"Platforma server address\")\n .env(\"PL_ADDRESS\")\n .makeOptionMandatory(),\n new Option(\"-f, --format <format>\", \"Output format\")\n .choices(allowedFormats)\n .default(formatDefault),\n];\n\nexport const UserAuthOptions = (): Option[] => [\n new Option(\"-u, --user <user>\", \"Username for authentication\").env(\"PL_USER\"),\n new Option(\"-p, --password <password>\", \"Password for authentication\").env(\"PL_PASSWORD\"),\n];\n\n/** Admin credentials only (for purely admin commands like copy-project). */\nexport const AdminAuthOptions = (): Option[] => [\n new Option(\"--admin-user <user>\", \"Admin/controller username\")\n .env(\"PL_ADMIN_USER\")\n .makeOptionMandatory(),\n new Option(\"--admin-password <password>\", \"Admin/controller password\")\n .env(\"PL_ADMIN_PASSWORD\")\n .makeOptionMandatory(),\n];\n\n/** Admin credentials + target user (for regular commands that can optionally operate on another user). */\nexport const AdminTargetOptions = (): Option[] => [\n new Option(\"--admin-user <user>\", \"Admin/controller username (enables admin mode)\").env(\n \"PL_ADMIN_USER\",\n ),\n new Option(\"--admin-password <password>\", \"Admin/controller password\").env(\"PL_ADMIN_PASSWORD\"),\n new Option(\n \"--target-user <user>\",\n \"Operate on this user's data (requires admin credentials)\",\n ).env(\"PL_TARGET_USER\"),\n];\n","import { Command } from \"commander\";\nimport { connect } from \"../../base_command\";\nimport { addOptions, GlobalOptions, UserAuthOptions, AdminTargetOptions } from \"../../cmd-opts\";\nimport { listProjects } from \"../../project_ops\";\nimport { formatTable, formatDate, outputJson, outputText } from \"../../output\";\nimport { resourceIdToString } from \"@milaboratories/pl-client\";\n\nexport default function projectListCommand(): Command {\n const cmd = new Command(\"list\").description(\"List all projects for the authenticated user.\");\n\n addOptions(cmd, GlobalOptions(), UserAuthOptions(), AdminTargetOptions());\n\n cmd.action(async (flags) => {\n const { pl, projectListRid } = await connect(flags);\n try {\n const projects = await listProjects(pl, projectListRid);\n\n if (flags.format === \"json\") {\n outputJson(\n projects.map((p) => ({\n id: p.id,\n rid: resourceIdToString(p.rid),\n label: p.label,\n created: p.created.toISOString(),\n lastModified: p.lastModified.toISOString(),\n })),\n );\n } else {\n if (projects.length === 0) {\n outputText(\"No projects found.\");\n return;\n }\n\n outputText(\n formatTable(\n [\"ID\", \"RID\", \"LABEL\", \"CREATED\", \"LAST MODIFIED\"],\n projects.map((p) => [\n p.id,\n resourceIdToString(p.rid),\n p.label,\n formatDate(p.created),\n formatDate(p.lastModified),\n ]),\n ),\n );\n outputText(`\\n${projects.length} project(s)`);\n }\n } finally {\n await pl.close();\n }\n });\n\n return cmd;\n}\n","import { Command } from \"commander\";\nimport { connect } from \"../../base_command\";\nimport { addOptions, GlobalOptions, UserAuthOptions, AdminTargetOptions } from \"../../cmd-opts\";\nimport { resolveProject, getProjectInfo } from \"../../project_ops\";\nimport { formatDate, outputJson, outputText } from \"../../output\";\nimport { resourceIdToString } from \"@milaboratories/pl-client\";\n\nexport default function projectInfoCommand(): Command {\n const cmd = new Command(\"info\").description(\"Show detailed information about a project.\");\n\n cmd.argument(\"<project>\", \"Project ID or label\");\n addOptions(cmd, GlobalOptions(), UserAuthOptions(), AdminTargetOptions());\n\n cmd.action(async (project: string, flags) => {\n const { pl, projectListRid } = await connect(flags);\n try {\n const { id, rid } = await resolveProject(pl, projectListRid, project);\n const info = await getProjectInfo(pl, id, rid);\n\n if (flags.format === \"json\") {\n outputJson({\n id: info.id,\n rid: resourceIdToString(info.rid),\n label: info.label,\n schemaVersion: info.schemaVersion,\n blockCount: info.blockCount,\n blockIds: info.blockIds,\n created: info.created.toISOString(),\n lastModified: info.lastModified.toISOString(),\n });\n } else {\n outputText(`Project: ${info.label}`);\n outputText(`ID: ${info.id}`);\n outputText(`RID: ${resourceIdToString(info.rid)}`);\n outputText(`Schema: ${info.schemaVersion ?? \"(unknown)\"}`);\n outputText(`Blocks: ${info.blockCount}`);\n if (info.blockIds.length > 0) {\n for (const bid of info.blockIds) {\n outputText(` - ${bid}`);\n }\n }\n outputText(`Created: ${formatDate(info.created)}`);\n outputText(`Last Modified: ${formatDate(info.lastModified)}`);\n }\n } finally {\n await pl.close();\n }\n });\n\n return cmd;\n}\n","import { Command, Option } from \"commander\";\nimport { field, resourceIdToString } from \"@milaboratories/pl-client\";\nimport { ProjectMetaKey } from \"@milaboratories/pl-middle-layer\";\nimport { randomUUID } from \"node:crypto\";\nimport { connect } from \"../../base_command\";\nimport { addOptions, GlobalOptions, UserAuthOptions, AdminTargetOptions } from \"../../cmd-opts\";\nimport {\n resolveProject,\n deduplicateName,\n duplicateProject,\n getExistingLabelsInTx,\n} from \"../../project_ops\";\nimport { outputJson, outputText } from \"../../output\";\n\nexport default function projectDuplicateCommand(): Command {\n const cmd = new Command(\"duplicate\").description(\n \"Duplicate a project within the same user. Auto-renames on collision by default.\",\n );\n\n cmd.argument(\"<project>\", \"Project ID or label\");\n addOptions(cmd, GlobalOptions(), UserAuthOptions(), AdminTargetOptions());\n cmd.option(\"-n, --name <name>\", \"Name for the duplicate\");\n cmd.addOption(\n new Option(\"--auto-rename\", \"Auto-rename on collision (default: true)\").default(true),\n );\n cmd.option(\"--no-auto-rename\", \"Fail on name collision instead of auto-renaming\");\n\n cmd.action(async (project: string, flags) => {\n const { pl, projectListRid } = await connect(flags);\n try {\n const { rid: sourceRid } = await resolveProject(pl, projectListRid, project);\n\n const newId = randomUUID();\n\n const result = await pl.withWriteTx(\"duplicateProject\", async (tx) => {\n const sourceMetaStr = await tx.getKValueString(sourceRid, ProjectMetaKey);\n const sourceMeta = JSON.parse(sourceMetaStr);\n const sourceLabel: string = sourceMeta.label;\n\n const existingLabels = await getExistingLabelsInTx(tx, projectListRid);\n\n // Compute new label\n let newLabel: string;\n if (flags.name) {\n if (!flags.autoRename && existingLabels.includes(flags.name)) {\n throw new Error(`Project name \"${flags.name}\" already exists.`);\n }\n newLabel = existingLabels.includes(flags.name)\n ? deduplicateName(flags.name, existingLabels)\n : flags.name;\n } else {\n newLabel = deduplicateName(sourceLabel, existingLabels);\n }\n\n const newPrj = await duplicateProject(tx, sourceRid, { label: newLabel });\n tx.createField(field(projectListRid, newId), \"Dynamic\", newPrj);\n await tx.commit();\n\n const projectResourceId = await newPrj.globalId;\n const projectId = resourceIdToString(projectResourceId);\n return { id: projectId, rid: projectResourceId, label: newLabel };\n });\n\n if (flags.format === \"json\") {\n outputJson({ id: result.id, rid: resourceIdToString(result.rid), label: result.label });\n } else {\n outputText(`Duplicated project as \"${result.label}\" (id: ${result.id})`);\n }\n } finally {\n await pl.close();\n }\n });\n\n return cmd;\n}\n","import { Command, Option } from \"commander\";\nimport { connect } from \"../../base_command\";\nimport { addOptions, GlobalOptions, UserAuthOptions, AdminTargetOptions } from \"../../cmd-opts\";\nimport { resolveProject, renameProject } from \"../../project_ops\";\nimport { outputJson, outputText } from \"../../output\";\nimport { resourceIdToString } from \"@milaboratories/pl-client\";\n\nexport default function projectRenameCommand(): Command {\n const cmd = new Command(\"rename\").description(\"Rename a project.\");\n\n cmd.argument(\"<project>\", \"Project ID or label\");\n addOptions(cmd, GlobalOptions(), UserAuthOptions(), AdminTargetOptions());\n cmd.addOption(new Option(\"-n, --name <name>\", \"New name for the project\").makeOptionMandatory());\n\n cmd.action(async (project: string, flags) => {\n const { pl, projectListRid } = await connect(flags);\n try {\n const { id, rid } = await resolveProject(pl, projectListRid, project);\n\n await renameProject(pl, rid, flags.name);\n\n if (flags.format === \"json\") {\n outputJson({ id, rid: resourceIdToString(rid), label: flags.name });\n } else {\n outputText(`Renamed project to \"${flags.name}\"`);\n }\n } finally {\n await pl.close();\n }\n });\n\n return cmd;\n}\n","import { Command } from \"commander\";\nimport { createInterface } from \"node:readline\";\nimport { connect } from \"../../base_command\";\nimport { addOptions, GlobalOptions, UserAuthOptions, AdminTargetOptions } from \"../../cmd-opts\";\nimport { resolveProject, deleteProject, getProjectInfo } from \"../../project_ops\";\nimport { outputJson, outputText } from \"../../output\";\n\nexport default function projectDeleteCommand(): Command {\n const cmd = new Command(\"delete\").description(\n \"Delete a project. This permanently destroys all project data.\",\n );\n\n cmd.argument(\"<project>\", \"Project ID or label\");\n addOptions(cmd, GlobalOptions(), UserAuthOptions(), AdminTargetOptions());\n cmd.option(\"--force\", \"Skip confirmation\", false);\n\n cmd.action(async (project: string, flags) => {\n const { pl, projectListRid } = await connect(flags);\n try {\n const { id, rid, fieldName } = await resolveProject(pl, projectListRid, project);\n\n const info = await getProjectInfo(pl, id, rid);\n\n if (!flags.force) {\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n try {\n const answer = await new Promise<string>((resolve) => {\n rl.question(\n `Delete project \"${info.label}\" (${info.blockCount} blocks)? [y/N] `,\n resolve,\n );\n });\n if (answer.toLowerCase() !== \"y\") {\n outputText(\"Aborted.\");\n return;\n }\n } finally {\n rl.close();\n }\n }\n\n await deleteProject(pl, projectListRid, fieldName);\n\n if (flags.format === \"json\") {\n outputJson({ deleted: true, id, label: info.label });\n } else {\n outputText(`Deleted project \"${info.label}\"`);\n }\n } finally {\n await pl.close();\n }\n });\n\n return cmd;\n}\n","import { Command, Option } from \"commander\";\nimport { field, resourceIdToString } from \"@milaboratories/pl-client\";\nimport { ProjectMetaKey } from \"@milaboratories/pl-middle-layer\";\nimport { randomUUID } from \"node:crypto\";\nimport { connectClient } from \"../../base_command\";\nimport { addOptions, GlobalOptions, AdminAuthOptions } from \"../../cmd-opts\";\nimport {\n resolveProject,\n deduplicateName,\n duplicateProject,\n getExistingLabelsInTx,\n navigateToUserRoot,\n} from \"../../project_ops\";\nimport { outputJson, outputText } from \"../../output\";\n\nexport default function adminCopyProjectCommand(): Command {\n const cmd = new Command(\"copy-project\").description(\n \"Copy a project from one user to another. Requires admin/controller credentials.\",\n );\n\n addOptions(cmd, GlobalOptions(), AdminAuthOptions());\n cmd.addOption(\n new Option(\n \"--source-user <user>\",\n \"Username of the source project owner\",\n ).makeOptionMandatory(),\n );\n cmd.addOption(\n new Option(\"--source-project <project>\", \"Source project ID or label\").makeOptionMandatory(),\n );\n cmd.option(\n \"--target-user <user>\",\n \"Username of the target user (defaults to source-user for same-user copy)\",\n );\n cmd.option(\"-n, --name <name>\", \"Name for the copied project\");\n cmd.addOption(\n new Option(\"--auto-rename\", \"Auto-rename on collision (default: true)\").default(true),\n );\n cmd.option(\"--no-auto-rename\", \"Fail on name collision instead of auto-renaming\");\n\n cmd.action(async (flags) => {\n const pl = await connectClient(flags);\n try {\n const targetUser = flags.targetUser ?? flags.sourceUser;\n\n const source = await navigateToUserRoot(pl, flags.sourceUser);\n const { rid: sourceRid } = await resolveProject(\n pl,\n source.projectListRid,\n flags.sourceProject,\n );\n\n const target =\n targetUser === flags.sourceUser ? source : await navigateToUserRoot(pl, targetUser);\n\n const newId = randomUUID();\n\n const result = await pl.withWriteTx(\"adminCopyProject\", async (tx) => {\n const sourceMetaStr = await tx.getKValueString(sourceRid, ProjectMetaKey);\n const sourceMeta = JSON.parse(sourceMetaStr);\n const sourceLabel: string = sourceMeta.label;\n\n const existingLabels = await getExistingLabelsInTx(tx, target.projectListRid);\n\n let newLabel: string = flags.name ?? sourceLabel;\n\n if (existingLabels.includes(newLabel)) {\n if (!flags.autoRename) {\n throw new Error(`Project name \"${newLabel}\" already exists for target user.`);\n }\n newLabel = deduplicateName(flags.name ?? sourceLabel, existingLabels);\n }\n\n const newPrj = await duplicateProject(tx, sourceRid, { label: newLabel });\n tx.createField(field(target.projectListRid, newId), \"Dynamic\", newPrj);\n await tx.commit();\n\n const prjResourceId = await newPrj.globalId;\n const prjId = resourceIdToString(prjResourceId);\n return { id: prjId, rid: prjResourceId, label: newLabel };\n });\n\n if (flags.format === \"json\") {\n outputJson({\n id: result.id,\n rid: resourceIdToString(result.rid),\n label: result.label,\n sourceUser: flags.sourceUser,\n targetUser,\n });\n } else {\n outputText(\n `Copied project from ${flags.sourceUser} to ${targetUser} as \"${result.label}\" (id: ${result.id}, rid: ${resourceIdToString(result.rid)})`,\n );\n }\n } finally {\n await pl.close();\n }\n });\n\n return cmd;\n}\n","import { Command } from \"commander\";\nimport { connectClient } from \"../../base_command\";\nimport { addOptions, GlobalOptions, AdminAuthOptions } from \"../../cmd-opts\";\nimport { outputJson, outputText, outputCsv } from \"../../output\";\n\nexport default function adminUserListCommand(): Command {\n const cmd = new Command(\"user-list\").description(\n \"List all known users' logins from a live server. Requires admin/controller credentials.\",\n );\n\n addOptions(cmd, GlobalOptions(\"csv\", [\"text\", \"json\", \"csv\"]), AdminAuthOptions());\n\n cmd.action(async (flags) => {\n const pl = await connectClient(flags);\n try {\n const logins = (await pl.listUsers()).map((u) => u.login).sort();\n if (flags.format === \"json\") outputJson(logins);\n else if (flags.format === \"text\") outputText(logins.join(\"\\n\"));\n else\n outputCsv(\n [\"login\"],\n logins.map((l) => [l]),\n );\n } finally {\n await pl.close();\n }\n });\n\n return cmd;\n}\n","import { Command } from \"commander\";\nimport projectListCommand from \"./cmd/project/list\";\nimport projectInfoCommand from \"./cmd/project/info\";\nimport projectDuplicateCommand from \"./cmd/project/duplicate\";\nimport projectRenameCommand from \"./cmd/project/rename\";\nimport projectDeleteCommand from \"./cmd/project/delete\";\nimport adminCopyProjectCommand from \"./cmd/admin/copy-project\";\nimport adminUserListCommand from \"./cmd/admin/user-list\";\n\nexport function buildProgram(): Command {\n const program = new Command();\n program.name(\"pl-cli\").description(\"Platforma command-line client\");\n\n const project = new Command(\"project\").description(\"Manage projects\");\n project.addCommand(projectListCommand());\n project.addCommand(projectInfoCommand());\n project.addCommand(projectDuplicateCommand());\n project.addCommand(projectRenameCommand());\n project.addCommand(projectDeleteCommand());\n program.addCommand(project);\n\n const admin = new Command(\"admin\").description(\n \"Admin operations (requires controller credentials)\",\n );\n admin.addCommand(adminCopyProjectCommand());\n admin.addCommand(adminUserListCommand());\n program.addCommand(admin);\n\n return program;\n}\n\nexport async function run(argv: string[] = process.argv): Promise<void> {\n await buildProgram().parseAsync(argv);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","names":[],"sources":["../src/base_command.ts","../src/cmd-opts.ts","../src/cmd/project/list.ts","../src/cmd/project/info.ts","../src/cmd/project/duplicate.ts","../src/cmd/project/rename.ts","../src/cmd/project/delete.ts","../src/cmd/admin/copy-project.ts","../src/cmd/admin/user-list.ts","../src/cmd/admin/delete-user.ts","../src/cli.ts"],"sourcesContent":["import type { PlClient, SignedResourceId } from \"@milaboratories/pl-client\";\nimport { createPlConnection, createAdminPlConnection } from \"./connection\";\nimport { getProjectListRid, navigateToUserRoot } from \"./project_ops\";\n\n/**\n * Low-level: get an authenticated PlClient without resolving a project list.\n * Use this for commands that navigate to multiple users (e.g. admin copy-project).\n *\n * Callers own the returned client and must `await pl.close()` when done.\n */\nexport async function connectClient(flags: {\n address: string;\n user?: string;\n password?: string;\n adminUser?: string;\n adminPassword?: string;\n}): Promise<PlClient> {\n if (flags.adminUser && flags.adminPassword) {\n return createAdminPlConnection({\n address: flags.address,\n adminUser: flags.adminUser,\n adminPassword: flags.adminPassword,\n });\n }\n return createPlConnection({\n address: flags.address,\n user: flags.user,\n password: flags.password,\n });\n}\n\n/**\n * Connect and resolve the project list for a single user.\n * In admin mode (--admin-user + --admin-password + --target-user), operates on the target user's data.\n * In user mode, operates on the authenticated user's own data.\n *\n * Callers own the returned client and must `await pl.close()` when done.\n */\nexport async function connect(flags: {\n address: string;\n user?: string;\n password?: string;\n adminUser?: string;\n adminPassword?: string;\n targetUser?: string;\n}): Promise<{ pl: PlClient; projectListRid: SignedResourceId }> {\n const hasAdminUser = !!flags.adminUser;\n const hasAdminPassword = !!flags.adminPassword;\n const hasTarget = !!flags.targetUser;\n\n // Validate flag combinations\n if (hasTarget && !(hasAdminUser && hasAdminPassword)) {\n throw new Error(\"--target-user requires --admin-user and --admin-password\");\n }\n if ((hasAdminUser || hasAdminPassword) && !hasTarget) {\n throw new Error(\"--admin-user/--admin-password require --target-user for project commands\");\n }\n\n const pl = await connectClient(flags);\n\n let projectListRid: SignedResourceId;\n if (hasTarget) {\n const nav = await navigateToUserRoot(pl, flags.targetUser!);\n projectListRid = nav.projectListRid;\n } else {\n projectListRid = await getProjectListRid(pl);\n }\n\n return { pl, projectListRid };\n}\n","import { Command, Option } from \"commander\";\nimport type { OutputFormat } from \"./output\";\n\n/** Add one or more groups of options to a command, preserving group order. */\nexport function addOptions(cmd: Command, ...optionGroups: Option[][]): Command {\n for (const group of optionGroups) {\n for (const opt of group) cmd.addOption(opt);\n }\n return cmd;\n}\n\nexport const GlobalOptions = (\n formatDefault: OutputFormat = \"text\",\n allowedFormats: OutputFormat[] = [\"text\", \"json\"],\n): Option[] => [\n new Option(\"-a, --address <url>\", \"Platforma server address\")\n .env(\"PL_ADDRESS\")\n .makeOptionMandatory(),\n new Option(\"-f, --format <format>\", \"Output format\")\n .choices(allowedFormats)\n .default(formatDefault),\n];\n\nexport const UserAuthOptions = (): Option[] => [\n new Option(\"-u, --user <user>\", \"Username for authentication\").env(\"PL_USER\"),\n new Option(\"-p, --password <password>\", \"Password for authentication\").env(\"PL_PASSWORD\"),\n];\n\n/** Admin credentials only (for purely admin commands like copy-project). */\nexport const AdminAuthOptions = (): Option[] => [\n new Option(\"--admin-user <user>\", \"Admin/controller username\")\n .env(\"PL_ADMIN_USER\")\n .makeOptionMandatory(),\n new Option(\"--admin-password <password>\", \"Admin/controller password\")\n .env(\"PL_ADMIN_PASSWORD\")\n .makeOptionMandatory(),\n];\n\n/** Admin credentials + target user (for regular commands that can optionally operate on another user). */\nexport const AdminTargetOptions = (): Option[] => [\n new Option(\"--admin-user <user>\", \"Admin/controller username (enables admin mode)\").env(\n \"PL_ADMIN_USER\",\n ),\n new Option(\"--admin-password <password>\", \"Admin/controller password\").env(\"PL_ADMIN_PASSWORD\"),\n new Option(\n \"--target-user <user>\",\n \"Operate on this user's data (requires admin credentials)\",\n ).env(\"PL_TARGET_USER\"),\n];\n","import { Command } from \"commander\";\nimport { connect } from \"../../base_command\";\nimport { addOptions, GlobalOptions, UserAuthOptions, AdminTargetOptions } from \"../../cmd-opts\";\nimport { listProjects } from \"../../project_ops\";\nimport { formatTable, formatDate, outputJson, outputText } from \"../../output\";\nimport { resourceIdToString } from \"@milaboratories/pl-client\";\n\nexport default function projectListCommand(): Command {\n const cmd = new Command(\"list\").description(\"List all projects for the authenticated user.\");\n\n addOptions(cmd, GlobalOptions(), UserAuthOptions(), AdminTargetOptions());\n\n cmd.action(async (flags) => {\n const { pl, projectListRid } = await connect(flags);\n try {\n const projects = await listProjects(pl, projectListRid);\n\n if (flags.format === \"json\") {\n outputJson(\n projects.map((p) => ({\n id: p.id,\n rid: resourceIdToString(p.rid),\n label: p.label,\n created: p.created.toISOString(),\n lastModified: p.lastModified.toISOString(),\n })),\n );\n } else {\n if (projects.length === 0) {\n outputText(\"No projects found.\");\n return;\n }\n\n outputText(\n formatTable(\n [\"ID\", \"RID\", \"LABEL\", \"CREATED\", \"LAST MODIFIED\"],\n projects.map((p) => [\n p.id,\n resourceIdToString(p.rid),\n p.label,\n formatDate(p.created),\n formatDate(p.lastModified),\n ]),\n ),\n );\n outputText(`\\n${projects.length} project(s)`);\n }\n } finally {\n await pl.close();\n }\n });\n\n return cmd;\n}\n","import { Command } from \"commander\";\nimport { connect } from \"../../base_command\";\nimport { addOptions, GlobalOptions, UserAuthOptions, AdminTargetOptions } from \"../../cmd-opts\";\nimport { resolveProject, getProjectInfo } from \"../../project_ops\";\nimport { formatDate, outputJson, outputText } from \"../../output\";\nimport { resourceIdToString } from \"@milaboratories/pl-client\";\n\nexport default function projectInfoCommand(): Command {\n const cmd = new Command(\"info\").description(\"Show detailed information about a project.\");\n\n cmd.argument(\"<project>\", \"Project ID or label\");\n addOptions(cmd, GlobalOptions(), UserAuthOptions(), AdminTargetOptions());\n\n cmd.action(async (project: string, flags) => {\n const { pl, projectListRid } = await connect(flags);\n try {\n const { id, rid } = await resolveProject(pl, projectListRid, project);\n const info = await getProjectInfo(pl, id, rid);\n\n if (flags.format === \"json\") {\n outputJson({\n id: info.id,\n rid: resourceIdToString(info.rid),\n label: info.label,\n schemaVersion: info.schemaVersion,\n blockCount: info.blockCount,\n blockIds: info.blockIds,\n created: info.created.toISOString(),\n lastModified: info.lastModified.toISOString(),\n });\n } else {\n outputText(`Project: ${info.label}`);\n outputText(`ID: ${info.id}`);\n outputText(`RID: ${resourceIdToString(info.rid)}`);\n outputText(`Schema: ${info.schemaVersion ?? \"(unknown)\"}`);\n outputText(`Blocks: ${info.blockCount}`);\n if (info.blockIds.length > 0) {\n for (const bid of info.blockIds) {\n outputText(` - ${bid}`);\n }\n }\n outputText(`Created: ${formatDate(info.created)}`);\n outputText(`Last Modified: ${formatDate(info.lastModified)}`);\n }\n } finally {\n await pl.close();\n }\n });\n\n return cmd;\n}\n","import { Command, Option } from \"commander\";\nimport { field, resourceIdToString } from \"@milaboratories/pl-client\";\nimport { ProjectMetaKey } from \"@milaboratories/pl-middle-layer\";\nimport { randomUUID } from \"node:crypto\";\nimport { connect } from \"../../base_command\";\nimport { addOptions, GlobalOptions, UserAuthOptions, AdminTargetOptions } from \"../../cmd-opts\";\nimport {\n resolveProject,\n deduplicateName,\n duplicateProject,\n getExistingLabelsInTx,\n} from \"../../project_ops\";\nimport { outputJson, outputText } from \"../../output\";\n\nexport default function projectDuplicateCommand(): Command {\n const cmd = new Command(\"duplicate\").description(\n \"Duplicate a project within the same user. Auto-renames on collision by default.\",\n );\n\n cmd.argument(\"<project>\", \"Project ID or label\");\n addOptions(cmd, GlobalOptions(), UserAuthOptions(), AdminTargetOptions());\n cmd.option(\"-n, --name <name>\", \"Name for the duplicate\");\n cmd.addOption(\n new Option(\"--auto-rename\", \"Auto-rename on collision (default: true)\").default(true),\n );\n cmd.option(\"--no-auto-rename\", \"Fail on name collision instead of auto-renaming\");\n\n cmd.action(async (project: string, flags) => {\n const { pl, projectListRid } = await connect(flags);\n try {\n const { rid: sourceRid } = await resolveProject(pl, projectListRid, project);\n\n const newId = randomUUID();\n\n const result = await pl.withWriteTx(\"duplicateProject\", async (tx) => {\n const sourceMetaStr = await tx.getKValueString(sourceRid, ProjectMetaKey);\n const sourceMeta = JSON.parse(sourceMetaStr);\n const sourceLabel: string = sourceMeta.label;\n\n const existingLabels = await getExistingLabelsInTx(tx, projectListRid);\n\n // Compute new label\n let newLabel: string;\n if (flags.name) {\n if (!flags.autoRename && existingLabels.includes(flags.name)) {\n throw new Error(`Project name \"${flags.name}\" already exists.`);\n }\n newLabel = existingLabels.includes(flags.name)\n ? deduplicateName(flags.name, existingLabels)\n : flags.name;\n } else {\n newLabel = deduplicateName(sourceLabel, existingLabels);\n }\n\n const newPrj = await duplicateProject(tx, sourceRid, { label: newLabel });\n tx.createField(field(projectListRid, newId), \"Dynamic\", newPrj);\n await tx.commit();\n\n const projectResourceId = await newPrj.globalId;\n const projectId = resourceIdToString(projectResourceId);\n return { id: projectId, rid: projectResourceId, label: newLabel };\n });\n\n if (flags.format === \"json\") {\n outputJson({ id: result.id, rid: resourceIdToString(result.rid), label: result.label });\n } else {\n outputText(`Duplicated project as \"${result.label}\" (id: ${result.id})`);\n }\n } finally {\n await pl.close();\n }\n });\n\n return cmd;\n}\n","import { Command, Option } from \"commander\";\nimport { connect } from \"../../base_command\";\nimport { addOptions, GlobalOptions, UserAuthOptions, AdminTargetOptions } from \"../../cmd-opts\";\nimport { resolveProject, renameProject } from \"../../project_ops\";\nimport { outputJson, outputText } from \"../../output\";\nimport { resourceIdToString } from \"@milaboratories/pl-client\";\n\nexport default function projectRenameCommand(): Command {\n const cmd = new Command(\"rename\").description(\"Rename a project.\");\n\n cmd.argument(\"<project>\", \"Project ID or label\");\n addOptions(cmd, GlobalOptions(), UserAuthOptions(), AdminTargetOptions());\n cmd.addOption(new Option(\"-n, --name <name>\", \"New name for the project\").makeOptionMandatory());\n\n cmd.action(async (project: string, flags) => {\n const { pl, projectListRid } = await connect(flags);\n try {\n const { id, rid } = await resolveProject(pl, projectListRid, project);\n\n await renameProject(pl, rid, flags.name);\n\n if (flags.format === \"json\") {\n outputJson({ id, rid: resourceIdToString(rid), label: flags.name });\n } else {\n outputText(`Renamed project to \"${flags.name}\"`);\n }\n } finally {\n await pl.close();\n }\n });\n\n return cmd;\n}\n","import { Command } from \"commander\";\nimport { createInterface } from \"node:readline\";\nimport { connect } from \"../../base_command\";\nimport { addOptions, GlobalOptions, UserAuthOptions, AdminTargetOptions } from \"../../cmd-opts\";\nimport { resolveProject, deleteProject, getProjectInfo } from \"../../project_ops\";\nimport { outputJson, outputText } from \"../../output\";\n\nexport default function projectDeleteCommand(): Command {\n const cmd = new Command(\"delete\").description(\n \"Delete a project. This permanently destroys all project data.\",\n );\n\n cmd.argument(\"<project>\", \"Project ID or label\");\n addOptions(cmd, GlobalOptions(), UserAuthOptions(), AdminTargetOptions());\n cmd.option(\"--force\", \"Skip confirmation\", false);\n\n cmd.action(async (project: string, flags) => {\n const { pl, projectListRid } = await connect(flags);\n try {\n const { id, rid, fieldName } = await resolveProject(pl, projectListRid, project);\n\n const info = await getProjectInfo(pl, id, rid);\n\n if (!flags.force) {\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n try {\n const answer = await new Promise<string>((resolve) => {\n rl.question(\n `Delete project \"${info.label}\" (${info.blockCount} blocks)? [y/N] `,\n resolve,\n );\n });\n if (answer.toLowerCase() !== \"y\") {\n outputText(\"Aborted.\");\n return;\n }\n } finally {\n rl.close();\n }\n }\n\n await deleteProject(pl, projectListRid, fieldName);\n\n if (flags.format === \"json\") {\n outputJson({ deleted: true, id, label: info.label });\n } else {\n outputText(`Deleted project \"${info.label}\"`);\n }\n } finally {\n await pl.close();\n }\n });\n\n return cmd;\n}\n","import { Command, Option } from \"commander\";\nimport { field, resourceIdToString } from \"@milaboratories/pl-client\";\nimport { ProjectMetaKey } from \"@milaboratories/pl-middle-layer\";\nimport { randomUUID } from \"node:crypto\";\nimport { connectClient } from \"../../base_command\";\nimport { addOptions, GlobalOptions, AdminAuthOptions } from \"../../cmd-opts\";\nimport {\n resolveProject,\n deduplicateName,\n duplicateProject,\n getExistingLabelsInTx,\n navigateToUserRoot,\n} from \"../../project_ops\";\nimport { outputJson, outputText } from \"../../output\";\n\nexport default function adminCopyProjectCommand(): Command {\n const cmd = new Command(\"copy-project\").description(\n \"Copy a project from one user to another. Requires admin/controller credentials.\",\n );\n\n addOptions(cmd, GlobalOptions(), AdminAuthOptions());\n cmd.addOption(\n new Option(\n \"--source-user <user>\",\n \"Username of the source project owner\",\n ).makeOptionMandatory(),\n );\n cmd.addOption(\n new Option(\"--source-project <project>\", \"Source project ID or label\").makeOptionMandatory(),\n );\n cmd.option(\n \"--target-user <user>\",\n \"Username of the target user (defaults to source-user for same-user copy)\",\n );\n cmd.option(\"-n, --name <name>\", \"Name for the copied project\");\n cmd.addOption(\n new Option(\"--auto-rename\", \"Auto-rename on collision (default: true)\").default(true),\n );\n cmd.option(\"--no-auto-rename\", \"Fail on name collision instead of auto-renaming\");\n\n cmd.action(async (flags) => {\n const pl = await connectClient(flags);\n try {\n const targetUser = flags.targetUser ?? flags.sourceUser;\n\n const source = await navigateToUserRoot(pl, flags.sourceUser);\n const { rid: sourceRid } = await resolveProject(\n pl,\n source.projectListRid,\n flags.sourceProject,\n );\n\n const target =\n targetUser === flags.sourceUser ? source : await navigateToUserRoot(pl, targetUser);\n\n const newId = randomUUID();\n\n const result = await pl.withWriteTx(\"adminCopyProject\", async (tx) => {\n const sourceMetaStr = await tx.getKValueString(sourceRid, ProjectMetaKey);\n const sourceMeta = JSON.parse(sourceMetaStr);\n const sourceLabel: string = sourceMeta.label;\n\n const existingLabels = await getExistingLabelsInTx(tx, target.projectListRid);\n\n let newLabel: string = flags.name ?? sourceLabel;\n\n if (existingLabels.includes(newLabel)) {\n if (!flags.autoRename) {\n throw new Error(`Project name \"${newLabel}\" already exists for target user.`);\n }\n newLabel = deduplicateName(flags.name ?? sourceLabel, existingLabels);\n }\n\n const newPrj = await duplicateProject(tx, sourceRid, { label: newLabel });\n tx.createField(field(target.projectListRid, newId), \"Dynamic\", newPrj);\n await tx.commit();\n\n const prjResourceId = await newPrj.globalId;\n const prjId = resourceIdToString(prjResourceId);\n return { id: prjId, rid: prjResourceId, label: newLabel };\n });\n\n if (flags.format === \"json\") {\n outputJson({\n id: result.id,\n rid: resourceIdToString(result.rid),\n label: result.label,\n sourceUser: flags.sourceUser,\n targetUser,\n });\n } else {\n outputText(\n `Copied project from ${flags.sourceUser} to ${targetUser} as \"${result.label}\" (id: ${result.id}, rid: ${resourceIdToString(result.rid)})`,\n );\n }\n } finally {\n await pl.close();\n }\n });\n\n return cmd;\n}\n","import { Command } from \"commander\";\nimport { connectClient } from \"../../base_command\";\nimport { addOptions, GlobalOptions, AdminAuthOptions } from \"../../cmd-opts\";\nimport { outputJson, outputText, outputCsv } from \"../../output\";\n\nexport default function adminUserListCommand(): Command {\n const cmd = new Command(\"user-list\").description(\n \"List all known users' logins from a live server. Requires admin/controller credentials.\",\n );\n\n addOptions(cmd, GlobalOptions(\"csv\", [\"text\", \"json\", \"csv\"]), AdminAuthOptions());\n\n cmd.action(async (flags) => {\n const pl = await connectClient(flags);\n try {\n const logins = (await pl.listUsers()).map((u) => u.login).sort();\n if (flags.format === \"json\") outputJson(logins);\n else if (flags.format === \"text\") outputText(logins.join(\"\\n\"));\n else\n outputCsv(\n [\"login\"],\n logins.map((l) => [l]),\n );\n } finally {\n await pl.close();\n }\n });\n\n return cmd;\n}\n","import { Command, Option } from \"commander\";\nimport { createInterface } from \"node:readline\";\nimport { connectClient } from \"../../base_command\";\nimport { addOptions, GlobalOptions, AdminAuthOptions } from \"../../cmd-opts\";\nimport {\n ensureUserProjectList,\n listProjectIdentities,\n moveProjects,\n openUserRoot,\n} from \"../../project_ops\";\nimport type { MovedProject, ProjectIdentityWithLabel } from \"../../project_ops\";\nimport { formatTable, outputJson, outputText } from \"../../output\";\n\nexport default function adminDeleteUserCommand(): Command {\n const cmd = new Command(\"delete-user\").description(\n \"Delete a user account. Optionally re-homes the user's projects to another user first. \" +\n \"Requires admin/controller credentials.\",\n );\n\n cmd.argument(\"<user>\", \"Username of the account to delete\");\n addOptions(cmd, GlobalOptions(), AdminAuthOptions());\n cmd.addOption(\n new Option(\n \"--move-projects-to <user>\",\n \"Re-home the deleted user's projects to this user before deleting the account\",\n ),\n );\n cmd.addOption(\n new Option(\n \"--delete-projects\",\n \"Delete the user's projects along with the account, losing their data\",\n ),\n );\n cmd.option(\"--force\", \"Skip confirmation\", false);\n\n cmd.action(async (user: string, flags) => {\n // The two modes are alternatives, not a combination: one keeps the projects, the other\n // destroys them, and a request for both says nothing about which was meant.\n if (flags.moveProjectsTo && flags.deleteProjects) {\n throw new Error(\"--move-projects-to and --delete-projects are mutually exclusive\");\n }\n if (flags.moveProjectsTo === user) {\n throw new Error(\"--move-projects-to must name a different user than the one being deleted\");\n }\n // Caught here as well as server-side, where it is authoritative: the operator gets the reason\n // instead of a failure from whichever lookup happens to run first.\n if (flags.adminUser === user) {\n throw new Error(\n `Refusing to delete \"${user}\" — it is the account these credentials authenticate as.`,\n );\n }\n\n const pl = await connectClient(flags);\n try {\n const source = await openUserRoot(pl, user);\n // No project list means the account never opened the app, so it owns nothing — a state to\n // delete straight through, not to fail on.\n const projects =\n source.projectListRid === undefined\n ? []\n : await listProjectIdentities(pl, source.projectListRid);\n\n // Neither mode given while the account still owns projects: refuse rather than pick. Both\n // defaults are wrong to assume — one silently destroys data, the other silently hands it to\n // someone. An account with no projects has nothing to decide about, so it just proceeds.\n if (projects.length > 0 && !flags.moveProjectsTo && !flags.deleteProjects) {\n throw new Error(\n `User \"${user}\" owns ${projects.length} project(s). Pass --move-projects-to <user> to ` +\n \"re-home them, or --delete-projects to delete them with the account.\",\n );\n }\n\n const confirmed = await confirmDeletion(user, projects, flags);\n if (!confirmed) {\n outputText(\"Aborted.\");\n return;\n }\n\n let moved: MovedProject[] = [];\n if (flags.moveProjectsTo && projects.length > 0) {\n const target = await openUserRoot(pl, flags.moveProjectsTo);\n // Created if the target has none, so re-homing to a user who has never opened the app\n // works rather than failing halfway with the account still present.\n const targetList = await ensureUserProjectList(pl, target.userRoot);\n moved = await moveProjects(pl, source.projectListRid!, targetList);\n }\n\n // deleteUser takes the root and everything still attached to it. The listing, the prompt and\n // the move each ran in an earlier transaction, so re-read: a project attached since then would\n // be destroyed without ever being reviewed.\n const remaining =\n source.projectListRid === undefined\n ? []\n : await listProjectIdentities(pl, source.projectListRid);\n assertProjectsAccountedFor(user, flags, projects, remaining);\n\n const report = await pl.deleteUser(user);\n\n if (flags.format === \"json\") {\n outputJson({\n deleted: true,\n user,\n movedTo: flags.moveProjectsTo ?? null,\n movedProjects: moved,\n deletedProjects: flags.moveProjectsTo ? [] : remaining.map((p) => p.label),\n userRootId: report.userRootId === undefined ? null : report.userRootId.toString(),\n userRootDeleted: report.userRootDeleted,\n revokedGrants: report.revokedGrants,\n removedIdentityIndexEntries: report.removedIdentityIndexEntries,\n });\n } else {\n outputText(renderResult(user, flags.moveProjectsTo, moved, remaining));\n }\n } finally {\n await pl.close();\n }\n });\n\n return cmd;\n}\n\n/**\n * Refuses while the root holds a project the operator never agreed to lose — attached after the\n * listing, or left behind by the move.\n *\n * A last read, not a lock: it closes the prompt-sized window, not the round trip that follows.\n */\nfunction assertProjectsAccountedFor(\n user: string,\n flags: { moveProjectsTo?: string },\n approved: ProjectIdentityWithLabel[],\n remaining: ProjectIdentityWithLabel[],\n): void {\n if (flags.moveProjectsTo) {\n if (remaining.length === 0) return;\n throw new Error(\n `User \"${user}\" still owns ${remaining.length} project(s) after the move: ` +\n `${remaining.map((p) => p.label).join(\", \")}. The account was NOT deleted — ` +\n \"the projects were attached while the move ran. Re-run the command to move them too.\",\n );\n }\n\n const approvedIds = new Set(approved.map((p) => p.id));\n const unapproved = remaining.filter((p) => !approvedIds.has(p.id));\n if (unapproved.length === 0) return;\n throw new Error(\n `User \"${user}\" gained ${unapproved.length} project(s) since the list you confirmed: ` +\n `${unapproved.map((p) => p.label).join(\", \")}. The account was NOT deleted — ` +\n \"deleting it now would destroy them unreviewed. Re-run the command to see the current list.\",\n );\n}\n\n/** Asks the operator to confirm, naming the affected projects and their fate. */\nasync function confirmDeletion(\n user: string,\n projects: ProjectIdentityWithLabel[],\n flags: { moveProjectsTo?: string; force?: boolean },\n): Promise<boolean> {\n if (flags.force) return true;\n\n const fate = flags.moveProjectsTo\n ? `${projects.length} project(s) will move to \"${flags.moveProjectsTo}\"`\n : projects.length > 0\n ? `${projects.length} project(s) will be PERMANENTLY DELETED`\n : \"the account owns no projects\";\n\n process.stderr.write(`Delete user \"${user}\"? ${fate}.\\n`);\n if (projects.length > 0) {\n process.stderr.write(projects.map((p) => ` - ${p.label}`).join(\"\\n\") + \"\\n\");\n }\n\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n try {\n const answer = await new Promise<string>((resolve) => {\n rl.question(\"Proceed? [y/N] \", resolve);\n });\n return answer.toLowerCase() === \"y\";\n } finally {\n rl.close();\n }\n}\n\nfunction renderResult(\n user: string,\n movedTo: string | undefined,\n moved: MovedProject[],\n projects: ProjectIdentityWithLabel[],\n): string {\n const lines: string[] = [];\n\n if (movedTo) {\n if (moved.length > 0) {\n lines.push(`Moved ${moved.length} project(s) from ${user} to ${movedTo}:`);\n lines.push(\n formatTable(\n [\"id\", \"name\", \"name in target\"],\n moved.map((p) => [p.id, p.sourceLabel, p.targetLabel]),\n ),\n );\n } else {\n lines.push(`User ${user} had no projects to move.`);\n }\n } else if (projects.length > 0) {\n lines.push(`Deleted ${projects.length} project(s) belonging to ${user}:`);\n lines.push(projects.map((p) => ` - ${p.label}`).join(\"\\n\"));\n }\n\n lines.push(`Deleted user \"${user}\".`);\n return lines.join(\"\\n\");\n}\n","import { Command } from \"commander\";\nimport projectListCommand from \"./cmd/project/list\";\nimport projectInfoCommand from \"./cmd/project/info\";\nimport projectDuplicateCommand from \"./cmd/project/duplicate\";\nimport projectRenameCommand from \"./cmd/project/rename\";\nimport projectDeleteCommand from \"./cmd/project/delete\";\nimport adminCopyProjectCommand from \"./cmd/admin/copy-project\";\nimport adminUserListCommand from \"./cmd/admin/user-list\";\nimport adminDeleteUserCommand from \"./cmd/admin/delete-user\";\n\nexport function buildProgram(): Command {\n const program = new Command();\n program.name(\"pl-cli\").description(\"Platforma command-line client\");\n\n const project = new Command(\"project\").description(\"Manage projects\");\n project.addCommand(projectListCommand());\n project.addCommand(projectInfoCommand());\n project.addCommand(projectDuplicateCommand());\n project.addCommand(projectRenameCommand());\n project.addCommand(projectDeleteCommand());\n program.addCommand(project);\n\n const admin = new Command(\"admin\").description(\n \"Admin operations (requires controller credentials)\",\n );\n admin.addCommand(adminCopyProjectCommand());\n admin.addCommand(adminUserListCommand());\n admin.addCommand(adminDeleteUserCommand());\n program.addCommand(admin);\n\n return program;\n}\n\nexport async function run(argv: string[] = process.argv): Promise<void> {\n await buildProgram().parseAsync(argv);\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export default function adminDeleteUserCommand(): Command;