@platforma-sdk/pl-cli 0.2.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/bin/run.js +8 -0
- package/dist/base_command.d.ts +43 -0
- package/dist/cli.js +308 -0
- package/dist/cli.js.map +1 -0
- package/dist/cmd/admin/copy-project.d.ts +16 -0
- package/dist/cmd/index.d.ts +14 -0
- package/dist/cmd/project/delete.d.ts +18 -0
- package/dist/cmd/project/duplicate.d.ts +19 -0
- package/dist/cmd/project/info.d.ts +17 -0
- package/dist/cmd/project/list.d.ts +14 -0
- package/dist/cmd/project/rename.d.ts +18 -0
- package/dist/cmd-opts.d.ts +19 -0
- package/dist/connection.d.ts +15 -0
- package/dist/index.js +2 -0
- package/dist/lib.d.ts +3 -0
- package/dist/output-INk3CKvr.js +174 -0
- package/dist/output-INk3CKvr.js.map +1 -0
- package/dist/output.d.ts +9 -0
- package/dist/project_ops.d.ts +47 -0
- package/package.json +70 -0
- package/src/base_command.ts +90 -0
- package/src/cmd/admin/copy-project.ts +101 -0
- package/src/cmd/index.ts +17 -0
- package/src/cmd/project/delete.ts +58 -0
- package/src/cmd/project/duplicate.ts +80 -0
- package/src/cmd/project/info.ts +52 -0
- package/src/cmd/project/list.ts +47 -0
- package/src/cmd/project/rename.ts +39 -0
- package/src/cmd-opts.ts +60 -0
- package/src/connection.ts +54 -0
- package/src/lib.ts +21 -0
- package/src/output.ts +35 -0
- package/src/project_ops.ts +251 -0
package/bin/run.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
import { PlClient, ResourceId } from '@milaboratories/pl-client';
|
|
3
|
+
/** Base command with dual-mode connection: user auth or admin + target-user. */
|
|
4
|
+
export declare abstract class PlCommand extends Command {
|
|
5
|
+
static baseFlags: {
|
|
6
|
+
"admin-user": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
7
|
+
"admin-password": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
8
|
+
"target-user": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
9
|
+
user: import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
10
|
+
password: import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
11
|
+
address: import('@oclif/core/interfaces').OptionFlag<string, import('@oclif/core/interfaces').CustomOptions>;
|
|
12
|
+
format: import('@oclif/core/interfaces').OptionFlag<string, import('@oclif/core/interfaces').CustomOptions>;
|
|
13
|
+
};
|
|
14
|
+
private _pl?;
|
|
15
|
+
/**
|
|
16
|
+
* Low-level: get an authenticated PlClient without resolving a project list.
|
|
17
|
+
* Use this for commands that navigate to multiple users (e.g. admin copy-project).
|
|
18
|
+
*/
|
|
19
|
+
protected connectClient(flags: {
|
|
20
|
+
address: string;
|
|
21
|
+
user?: string;
|
|
22
|
+
password?: string;
|
|
23
|
+
"admin-user"?: string;
|
|
24
|
+
"admin-password"?: string;
|
|
25
|
+
}): Promise<PlClient>;
|
|
26
|
+
/**
|
|
27
|
+
* Connect and resolve the project list for a single user.
|
|
28
|
+
* In admin mode (--admin-user + --admin-password + --target-user), operates on the target user's data.
|
|
29
|
+
* In user mode, operates on the authenticated user's own data.
|
|
30
|
+
*/
|
|
31
|
+
protected connect(flags: {
|
|
32
|
+
address: string;
|
|
33
|
+
user?: string;
|
|
34
|
+
password?: string;
|
|
35
|
+
"admin-user"?: string;
|
|
36
|
+
"admin-password"?: string;
|
|
37
|
+
"target-user"?: string;
|
|
38
|
+
}): Promise<{
|
|
39
|
+
pl: PlClient;
|
|
40
|
+
projectListRid: ResourceId;
|
|
41
|
+
}>;
|
|
42
|
+
protected finally(_: Error | undefined): Promise<void>;
|
|
43
|
+
}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { a as e, c as t, d as n, f as r, g as i, h as a, i as o, l as s, m as c, n as l, o as u, p as d, r as f, s as p, t as m, u as h } from "./output-INk3CKvr.js";
|
|
2
|
+
import { Args as g, Command as _, Flags as v } from "@oclif/core";
|
|
3
|
+
import { field as y, toGlobalResourceId 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";
|
|
7
|
+
const w = {
|
|
8
|
+
address: v.string({
|
|
9
|
+
char: "a",
|
|
10
|
+
summary: "Platforma server address",
|
|
11
|
+
helpValue: "<url>",
|
|
12
|
+
env: "PL_ADDRESS",
|
|
13
|
+
required: !0
|
|
14
|
+
}),
|
|
15
|
+
format: v.string({
|
|
16
|
+
char: "f",
|
|
17
|
+
summary: "Output format",
|
|
18
|
+
options: ["text", "json"],
|
|
19
|
+
default: "text"
|
|
20
|
+
})
|
|
21
|
+
}, T = {
|
|
22
|
+
user: v.string({
|
|
23
|
+
char: "u",
|
|
24
|
+
summary: "Username for authentication",
|
|
25
|
+
env: "PL_USER"
|
|
26
|
+
}),
|
|
27
|
+
password: v.string({
|
|
28
|
+
char: "p",
|
|
29
|
+
summary: "Password for authentication",
|
|
30
|
+
env: "PL_PASSWORD"
|
|
31
|
+
})
|
|
32
|
+
}, E = {
|
|
33
|
+
"admin-user": v.string({
|
|
34
|
+
summary: "Admin/controller username",
|
|
35
|
+
env: "PL_ADMIN_USER",
|
|
36
|
+
required: !0
|
|
37
|
+
}),
|
|
38
|
+
"admin-password": v.string({
|
|
39
|
+
summary: "Admin/controller password",
|
|
40
|
+
env: "PL_ADMIN_PASSWORD",
|
|
41
|
+
required: !0
|
|
42
|
+
})
|
|
43
|
+
}, D = {
|
|
44
|
+
"admin-user": v.string({
|
|
45
|
+
summary: "Admin/controller username (enables admin mode)",
|
|
46
|
+
env: "PL_ADMIN_USER"
|
|
47
|
+
}),
|
|
48
|
+
"admin-password": v.string({
|
|
49
|
+
summary: "Admin/controller password",
|
|
50
|
+
env: "PL_ADMIN_PASSWORD"
|
|
51
|
+
}),
|
|
52
|
+
"target-user": v.string({
|
|
53
|
+
summary: "Operate on this user's data (requires admin credentials)",
|
|
54
|
+
env: "PL_TARGET_USER"
|
|
55
|
+
})
|
|
56
|
+
};
|
|
57
|
+
/** Base command with dual-mode connection: user auth or admin + target-user. */
|
|
58
|
+
var O = class extends _ {
|
|
59
|
+
static baseFlags = {
|
|
60
|
+
...w,
|
|
61
|
+
...T,
|
|
62
|
+
...D
|
|
63
|
+
};
|
|
64
|
+
_pl;
|
|
65
|
+
/**
|
|
66
|
+
* Low-level: get an authenticated PlClient without resolving a project list.
|
|
67
|
+
* Use this for commands that navigate to multiple users (e.g. admin copy-project).
|
|
68
|
+
*/
|
|
69
|
+
async connectClient(e) {
|
|
70
|
+
if (this._pl) throw Error("connectClient() called twice");
|
|
71
|
+
return e["admin-user"] && e["admin-password"] ? this._pl = await a({
|
|
72
|
+
address: e.address,
|
|
73
|
+
adminUser: e["admin-user"],
|
|
74
|
+
adminPassword: e["admin-password"]
|
|
75
|
+
}) : this._pl = await i({
|
|
76
|
+
address: e.address,
|
|
77
|
+
user: e.user,
|
|
78
|
+
password: e.password
|
|
79
|
+
}), this._pl;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Connect and resolve the project list for a single user.
|
|
83
|
+
* In admin mode (--admin-user + --admin-password + --target-user), operates on the target user's data.
|
|
84
|
+
* In user mode, operates on the authenticated user's own data.
|
|
85
|
+
*/
|
|
86
|
+
async connect(e) {
|
|
87
|
+
let t = !!e["admin-user"], n = !!e["admin-password"], i = !!e["target-user"];
|
|
88
|
+
if (i && !(t && n)) throw Error("--target-user requires --admin-user and --admin-password");
|
|
89
|
+
if ((t || n) && !i) throw Error("--admin-user/--admin-password require --target-user for project commands");
|
|
90
|
+
let a = await this.connectClient(e), o;
|
|
91
|
+
return o = i ? (await r(a, e["target-user"])).projectListRid : await h(a), {
|
|
92
|
+
pl: a,
|
|
93
|
+
projectListRid: o
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
async finally(e) {
|
|
97
|
+
this._pl && await this._pl.close();
|
|
98
|
+
}
|
|
99
|
+
}, k = class e extends O {
|
|
100
|
+
static description = "List all projects for the authenticated user.";
|
|
101
|
+
static flags = { ...O.baseFlags };
|
|
102
|
+
async run() {
|
|
103
|
+
let { flags: t } = await this.parse(e), { pl: r, projectListRid: i } = await this.connect(t), a = await n(r, i);
|
|
104
|
+
if (t.format === "json") f(a.map((e) => ({
|
|
105
|
+
id: e.id,
|
|
106
|
+
rid: e.rid,
|
|
107
|
+
label: e.label,
|
|
108
|
+
created: e.created.toISOString(),
|
|
109
|
+
lastModified: e.lastModified.toISOString()
|
|
110
|
+
})));
|
|
111
|
+
else {
|
|
112
|
+
if (a.length === 0) {
|
|
113
|
+
o("No projects found.");
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
o(l([
|
|
117
|
+
"ID",
|
|
118
|
+
"LABEL",
|
|
119
|
+
"CREATED",
|
|
120
|
+
"LAST MODIFIED"
|
|
121
|
+
], a.map((e) => [
|
|
122
|
+
e.id.substring(0, 8) + "...",
|
|
123
|
+
e.label,
|
|
124
|
+
m(e.created),
|
|
125
|
+
m(e.lastModified)
|
|
126
|
+
]))), o(`\n${a.length} project(s)`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}, A = class e extends O {
|
|
130
|
+
static description = "Show detailed information about a project.";
|
|
131
|
+
static args = { project: g.string({
|
|
132
|
+
description: "Project ID or label",
|
|
133
|
+
required: !0
|
|
134
|
+
}) };
|
|
135
|
+
static flags = { ...O.baseFlags };
|
|
136
|
+
async run() {
|
|
137
|
+
let { args: t, flags: n } = await this.parse(e), { pl: r, projectListRid: i } = await this.connect(n), { id: a } = await c(r, i, t.project), l = await s(r, i, a);
|
|
138
|
+
if (n.format === "json") f({
|
|
139
|
+
id: l.id,
|
|
140
|
+
rid: l.rid,
|
|
141
|
+
label: l.label,
|
|
142
|
+
schemaVersion: l.schemaVersion,
|
|
143
|
+
blockCount: l.blockCount,
|
|
144
|
+
blockIds: l.blockIds,
|
|
145
|
+
created: l.created.toISOString(),
|
|
146
|
+
lastModified: l.lastModified.toISOString()
|
|
147
|
+
});
|
|
148
|
+
else {
|
|
149
|
+
if (o(`Project: ${l.label}`), o(`ID: ${l.id}`), o(`RID: ${l.rid}`), o(`Schema: ${l.schemaVersion ?? "(unknown)"}`), o(`Blocks: ${l.blockCount}`), l.blockIds.length > 0) for (let e of l.blockIds) o(` - ${e}`);
|
|
150
|
+
o(`Created: ${m(l.created)}`), o(`Last Modified: ${m(l.lastModified)}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}, j = class n extends O {
|
|
154
|
+
static description = "Duplicate a project within the same user. Auto-renames on collision by default.";
|
|
155
|
+
static args = { project: g.string({
|
|
156
|
+
description: "Project ID or label",
|
|
157
|
+
required: !0
|
|
158
|
+
}) };
|
|
159
|
+
static flags = {
|
|
160
|
+
...O.baseFlags,
|
|
161
|
+
name: v.string({
|
|
162
|
+
char: "n",
|
|
163
|
+
summary: "Name for the duplicate",
|
|
164
|
+
helpValue: "<name>"
|
|
165
|
+
}),
|
|
166
|
+
"auto-rename": v.boolean({
|
|
167
|
+
summary: "Auto-rename on collision (default: true)",
|
|
168
|
+
default: !0,
|
|
169
|
+
allowNo: !0
|
|
170
|
+
})
|
|
171
|
+
};
|
|
172
|
+
async run() {
|
|
173
|
+
let { args: r, flags: i } = await this.parse(n), { pl: a, projectListRid: s } = await this.connect(i), { rid: l } = await c(a, s, r.project), u = S(), d = await a.withWriteTx("duplicateProject", async (n) => {
|
|
174
|
+
let r = await n.getKValueString(l, x), a = JSON.parse(r).label, o = await t(n, s), c;
|
|
175
|
+
if (i.name) {
|
|
176
|
+
if (!i["auto-rename"] && o.includes(i.name)) throw Error(`Project name "${i.name}" already exists.`);
|
|
177
|
+
c = o.includes(i.name) ? e(i.name, o) : i.name;
|
|
178
|
+
} else c = e(a, o);
|
|
179
|
+
let d = await p(n, l, { label: c });
|
|
180
|
+
return n.createField(y(s, u), "Dynamic", d), await n.commit(), {
|
|
181
|
+
rid: await b(d),
|
|
182
|
+
label: c
|
|
183
|
+
};
|
|
184
|
+
});
|
|
185
|
+
i.format === "json" ? f({
|
|
186
|
+
id: u,
|
|
187
|
+
rid: String(d.rid),
|
|
188
|
+
label: d.label
|
|
189
|
+
}) : o(`Duplicated project as "${d.label}" (id: ${u})`);
|
|
190
|
+
}
|
|
191
|
+
}, M = class e extends O {
|
|
192
|
+
static description = "Rename a project.";
|
|
193
|
+
static args = { project: g.string({
|
|
194
|
+
description: "Project ID or label",
|
|
195
|
+
required: !0
|
|
196
|
+
}) };
|
|
197
|
+
static flags = {
|
|
198
|
+
...O.baseFlags,
|
|
199
|
+
name: v.string({
|
|
200
|
+
char: "n",
|
|
201
|
+
summary: "New name for the project",
|
|
202
|
+
helpValue: "<name>",
|
|
203
|
+
required: !0
|
|
204
|
+
})
|
|
205
|
+
};
|
|
206
|
+
async run() {
|
|
207
|
+
let { args: t, flags: n } = await this.parse(e), { pl: r, projectListRid: i } = await this.connect(n), { id: a, rid: s } = await c(r, i, t.project);
|
|
208
|
+
await d(r, s, n.name), n.format === "json" ? f({
|
|
209
|
+
id: a,
|
|
210
|
+
rid: String(s),
|
|
211
|
+
label: n.name
|
|
212
|
+
}) : o(`Renamed project to "${n.name}"`);
|
|
213
|
+
}
|
|
214
|
+
}, N = class e extends O {
|
|
215
|
+
static description = "Delete a project. This permanently destroys all project data.";
|
|
216
|
+
static args = { project: g.string({
|
|
217
|
+
description: "Project ID or label",
|
|
218
|
+
required: !0
|
|
219
|
+
}) };
|
|
220
|
+
static flags = {
|
|
221
|
+
...O.baseFlags,
|
|
222
|
+
force: v.boolean({
|
|
223
|
+
summary: "Skip confirmation",
|
|
224
|
+
default: !1
|
|
225
|
+
})
|
|
226
|
+
};
|
|
227
|
+
async run() {
|
|
228
|
+
let { args: t, flags: n } = await this.parse(e), { pl: r, projectListRid: i } = await this.connect(n), { id: a } = await c(r, i, t.project), l = await s(r, i, a);
|
|
229
|
+
if (!n.force) {
|
|
230
|
+
let e = C({
|
|
231
|
+
input: process.stdin,
|
|
232
|
+
output: process.stderr
|
|
233
|
+
});
|
|
234
|
+
try {
|
|
235
|
+
if ((await new Promise((t) => {
|
|
236
|
+
e.question(`Delete project "${l.label}" (${l.blockCount} blocks)? [y/N] `, t);
|
|
237
|
+
})).toLowerCase() !== "y") {
|
|
238
|
+
o("Aborted.");
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
} finally {
|
|
242
|
+
e.close();
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
await u(r, i, a), n.format === "json" ? f({
|
|
246
|
+
deleted: !0,
|
|
247
|
+
id: a,
|
|
248
|
+
label: l.label
|
|
249
|
+
}) : o(`Deleted project "${l.label}"`);
|
|
250
|
+
}
|
|
251
|
+
}, P = class n extends O {
|
|
252
|
+
static description = "Copy a project from one user to another. Requires admin/controller credentials.";
|
|
253
|
+
static flags = {
|
|
254
|
+
...w,
|
|
255
|
+
...E,
|
|
256
|
+
"source-user": v.string({
|
|
257
|
+
summary: "Username of the source project owner",
|
|
258
|
+
required: !0
|
|
259
|
+
}),
|
|
260
|
+
"source-project": v.string({
|
|
261
|
+
summary: "Source project ID or label",
|
|
262
|
+
required: !0
|
|
263
|
+
}),
|
|
264
|
+
"target-user": v.string({ summary: "Username of the target user (defaults to source-user for same-user copy)" }),
|
|
265
|
+
name: v.string({
|
|
266
|
+
char: "n",
|
|
267
|
+
summary: "Name for the copied project",
|
|
268
|
+
helpValue: "<name>"
|
|
269
|
+
}),
|
|
270
|
+
"auto-rename": v.boolean({
|
|
271
|
+
summary: "Auto-rename on collision (default: true)",
|
|
272
|
+
default: !0,
|
|
273
|
+
allowNo: !0
|
|
274
|
+
})
|
|
275
|
+
};
|
|
276
|
+
async run() {
|
|
277
|
+
let { flags: i } = await this.parse(n), a = await this.connectClient(i), s = i["target-user"] ?? i["source-user"], l = await r(a, i["source-user"]), { rid: u } = await c(a, l.projectListRid, i["source-project"]), d = s === i["source-user"] ? l : await r(a, s), m = S(), h = await a.withWriteTx("adminCopyProject", async (n) => {
|
|
278
|
+
let r = await n.getKValueString(u, x), a = JSON.parse(r).label, o = await t(n, d.projectListRid), s = i.name ?? a;
|
|
279
|
+
if (o.includes(s)) {
|
|
280
|
+
if (!i["auto-rename"]) throw Error(`Project name "${s}" already exists for target user.`);
|
|
281
|
+
s = e(i.name ?? a, o);
|
|
282
|
+
}
|
|
283
|
+
let c = await p(n, u, { label: s });
|
|
284
|
+
return n.createField(y(d.projectListRid, m), "Dynamic", c), await n.commit(), {
|
|
285
|
+
rid: await b(c),
|
|
286
|
+
label: s
|
|
287
|
+
};
|
|
288
|
+
});
|
|
289
|
+
i.format === "json" ? f({
|
|
290
|
+
id: m,
|
|
291
|
+
rid: String(h.rid),
|
|
292
|
+
label: h.label,
|
|
293
|
+
sourceUser: i["source-user"],
|
|
294
|
+
targetUser: s
|
|
295
|
+
}) : o(`Copied project from ${i["source-user"]} to ${s} as "${h.label}" (id: ${m})`);
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
const F = {
|
|
299
|
+
"project:list": k,
|
|
300
|
+
"project:info": A,
|
|
301
|
+
"project:duplicate": j,
|
|
302
|
+
"project:rename": M,
|
|
303
|
+
"project:delete": N,
|
|
304
|
+
"admin:copy-project": P
|
|
305
|
+
};
|
|
306
|
+
export { F as COMMANDS };
|
|
307
|
+
|
|
308
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","names":[],"sources":["../src/cmd-opts.ts","../src/base_command.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/index.ts"],"sourcesContent":["import { Flags } from \"@oclif/core\";\n\nexport const GlobalFlags = {\n address: Flags.string({\n char: \"a\",\n summary: \"Platforma server address\",\n helpValue: \"<url>\",\n env: \"PL_ADDRESS\",\n required: true,\n }),\n format: Flags.string({\n char: \"f\",\n summary: \"Output format\",\n options: [\"text\", \"json\"],\n default: \"text\",\n }),\n};\n\nexport const UserAuthFlags = {\n user: Flags.string({\n char: \"u\",\n summary: \"Username for authentication\",\n env: \"PL_USER\",\n }),\n password: Flags.string({\n char: \"p\",\n summary: \"Password for authentication\",\n env: \"PL_PASSWORD\",\n }),\n};\n\n/** Admin credentials only (for purely admin commands like copy-project). */\nexport const AdminAuthFlags = {\n \"admin-user\": Flags.string({\n summary: \"Admin/controller username\",\n env: \"PL_ADMIN_USER\",\n required: true,\n }),\n \"admin-password\": Flags.string({\n summary: \"Admin/controller password\",\n env: \"PL_ADMIN_PASSWORD\",\n required: true,\n }),\n};\n\n/** Admin credentials + target user (for regular commands that can optionally operate on another user). */\nexport const AdminTargetFlags = {\n \"admin-user\": Flags.string({\n summary: \"Admin/controller username (enables admin mode)\",\n env: \"PL_ADMIN_USER\",\n }),\n \"admin-password\": Flags.string({\n summary: \"Admin/controller password\",\n env: \"PL_ADMIN_PASSWORD\",\n }),\n \"target-user\": Flags.string({\n summary: \"Operate on this user's data (requires admin credentials)\",\n env: \"PL_TARGET_USER\",\n }),\n};\n","import { Command } from \"@oclif/core\";\nimport type { PlClient, ResourceId } from \"@milaboratories/pl-client\";\nimport { createPlConnection, createAdminPlConnection } from \"./connection\";\nimport { getProjectListRid, navigateToUserRoot } from \"./project_ops\";\nimport { GlobalFlags, UserAuthFlags, AdminTargetFlags } from \"./cmd-opts\";\n\n/** Base command with dual-mode connection: user auth or admin + target-user. */\nexport abstract class PlCommand extends Command {\n static baseFlags = {\n ...GlobalFlags,\n ...UserAuthFlags,\n ...AdminTargetFlags,\n };\n\n private _pl?: PlClient;\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 protected async connectClient(flags: {\n address: string;\n user?: string;\n password?: string;\n \"admin-user\"?: string;\n \"admin-password\"?: string;\n }): Promise<PlClient> {\n if (this._pl) throw new Error(\"connectClient() called twice\");\n\n if (flags[\"admin-user\"] && flags[\"admin-password\"]) {\n this._pl = await createAdminPlConnection({\n address: flags.address,\n adminUser: flags[\"admin-user\"],\n adminPassword: flags[\"admin-password\"],\n });\n } else {\n this._pl = await createPlConnection({\n address: flags.address,\n user: flags.user,\n password: flags.password,\n });\n }\n\n return this._pl;\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 protected async connect(flags: {\n address: string;\n user?: string;\n password?: string;\n \"admin-user\"?: string;\n \"admin-password\"?: string;\n \"target-user\"?: string;\n }): Promise<{ pl: PlClient; projectListRid: ResourceId }> {\n const hasAdminUser = !!flags[\"admin-user\"];\n const hasAdminPassword = !!flags[\"admin-password\"];\n const hasTarget = !!flags[\"target-user\"];\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 this.connectClient(flags);\n\n let projectListRid: ResourceId;\n if (hasTarget) {\n const nav = await navigateToUserRoot(pl, flags[\"target-user\"]!);\n projectListRid = nav.projectListRid;\n } else {\n projectListRid = await getProjectListRid(pl);\n }\n\n return { pl, projectListRid };\n }\n\n protected async finally(_: Error | undefined): Promise<void> {\n if (this._pl) {\n await this._pl.close();\n }\n }\n}\n","import { PlCommand } from \"../../base_command\";\nimport { listProjects } from \"../../project_ops\";\nimport { formatTable, formatDate, outputJson, outputText } from \"../../output\";\n\nexport default class ProjectList extends PlCommand {\n static override description = \"List all projects for the authenticated user.\";\n\n static override flags = {\n ...PlCommand.baseFlags,\n };\n\n public async run(): Promise<void> {\n const { flags } = await this.parse(ProjectList);\n const { pl, projectListRid } = await this.connect(flags);\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: 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\", \"LABEL\", \"CREATED\", \"LAST MODIFIED\"],\n projects.map((p) => [\n p.id.substring(0, 8) + \"...\",\n p.label,\n formatDate(p.created),\n formatDate(p.lastModified),\n ]),\n ),\n );\n outputText(`\\n${projects.length} project(s)`);\n }\n }\n}\n","import { Args } from \"@oclif/core\";\nimport { PlCommand } from \"../../base_command\";\nimport { resolveProject, getProjectInfo } from \"../../project_ops\";\nimport { formatDate, outputJson, outputText } from \"../../output\";\n\nexport default class ProjectInfo extends PlCommand {\n static override description = \"Show detailed information about a project.\";\n\n static override args = {\n project: Args.string({\n description: \"Project ID or label\",\n required: true,\n }),\n };\n\n static override flags = {\n ...PlCommand.baseFlags,\n };\n\n public async run(): Promise<void> {\n const { args, flags } = await this.parse(ProjectInfo);\n const { pl, projectListRid } = await this.connect(flags);\n const { id } = await resolveProject(pl, projectListRid, args.project);\n const info = await getProjectInfo(pl, projectListRid, id);\n\n if (flags.format === \"json\") {\n outputJson({\n id: info.id,\n rid: 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: ${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 }\n}\n","import { Args, Flags } from \"@oclif/core\";\nimport { field, toGlobalResourceId } from \"@milaboratories/pl-client\";\nimport { ProjectMetaKey } from \"@milaboratories/pl-middle-layer\";\nimport { randomUUID } from \"node:crypto\";\nimport { PlCommand } from \"../../base_command\";\nimport {\n resolveProject,\n deduplicateName,\n duplicateProject,\n getExistingLabelsInTx,\n} from \"../../project_ops\";\nimport { outputJson, outputText } from \"../../output\";\n\nexport default class ProjectDuplicate extends PlCommand {\n static override description =\n \"Duplicate a project within the same user. Auto-renames on collision by default.\";\n\n static override args = {\n project: Args.string({\n description: \"Project ID or label\",\n required: true,\n }),\n };\n\n static override flags = {\n ...PlCommand.baseFlags,\n name: Flags.string({\n char: \"n\",\n summary: \"Name for the duplicate\",\n helpValue: \"<name>\",\n }),\n \"auto-rename\": Flags.boolean({\n summary: \"Auto-rename on collision (default: true)\",\n default: true,\n allowNo: true,\n }),\n };\n\n public async run(): Promise<void> {\n const { args, flags } = await this.parse(ProjectDuplicate);\n const { pl, projectListRid } = await this.connect(flags);\n\n const { rid: sourceRid } = await resolveProject(pl, projectListRid, args.project);\n\n const newId = randomUUID();\n\n const newRid = 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[\"auto-rename\"] && 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 return { rid: await toGlobalResourceId(newPrj), label: newLabel };\n });\n\n if (flags.format === \"json\") {\n outputJson({ id: newId, rid: String(newRid.rid), label: newRid.label });\n } else {\n outputText(`Duplicated project as \"${newRid.label}\" (id: ${newId})`);\n }\n }\n}\n","import { Args, Flags } from \"@oclif/core\";\nimport { PlCommand } from \"../../base_command\";\nimport { resolveProject, renameProject } from \"../../project_ops\";\nimport { outputJson, outputText } from \"../../output\";\n\nexport default class ProjectRename extends PlCommand {\n static override description = \"Rename a project.\";\n\n static override args = {\n project: Args.string({\n description: \"Project ID or label\",\n required: true,\n }),\n };\n\n static override flags = {\n ...PlCommand.baseFlags,\n name: Flags.string({\n char: \"n\",\n summary: \"New name for the project\",\n helpValue: \"<name>\",\n required: true,\n }),\n };\n\n public async run(): Promise<void> {\n const { args, flags } = await this.parse(ProjectRename);\n const { pl, projectListRid } = await this.connect(flags);\n const { id, rid } = await resolveProject(pl, projectListRid, args.project);\n\n await renameProject(pl, rid, flags.name);\n\n if (flags.format === \"json\") {\n outputJson({ id, rid: String(rid), label: flags.name });\n } else {\n outputText(`Renamed project to \"${flags.name}\"`);\n }\n }\n}\n","import { Args, Flags } from \"@oclif/core\";\nimport { createInterface } from \"node:readline\";\nimport { PlCommand } from \"../../base_command\";\nimport { resolveProject, deleteProject, getProjectInfo } from \"../../project_ops\";\nimport { outputJson, outputText } from \"../../output\";\n\nexport default class ProjectDelete extends PlCommand {\n static override description = \"Delete a project. This permanently destroys all project data.\";\n\n static override args = {\n project: Args.string({\n description: \"Project ID or label\",\n required: true,\n }),\n };\n\n static override flags = {\n ...PlCommand.baseFlags,\n force: Flags.boolean({\n summary: \"Skip confirmation\",\n default: false,\n }),\n };\n\n public async run(): Promise<void> {\n const { args, flags } = await this.parse(ProjectDelete);\n const { pl, projectListRid } = await this.connect(flags);\n const { id } = await resolveProject(pl, projectListRid, args.project);\n\n const info = await getProjectInfo(pl, projectListRid, id);\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, id);\n\n if (flags.format === \"json\") {\n outputJson({ deleted: true, id, label: info.label });\n } else {\n outputText(`Deleted project \"${info.label}\"`);\n }\n }\n}\n","import { Flags } from \"@oclif/core\";\nimport { field, toGlobalResourceId } from \"@milaboratories/pl-client\";\nimport { ProjectMetaKey } from \"@milaboratories/pl-middle-layer\";\nimport { randomUUID } from \"node:crypto\";\nimport { PlCommand } from \"../../base_command\";\nimport { GlobalFlags, AdminAuthFlags } 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 class AdminCopyProject extends PlCommand {\n static override description =\n \"Copy a project from one user to another. Requires admin/controller credentials.\";\n\n static override flags = {\n ...GlobalFlags,\n ...AdminAuthFlags,\n \"source-user\": Flags.string({\n summary: \"Username of the source project owner\",\n required: true,\n }),\n \"source-project\": Flags.string({\n summary: \"Source project ID or label\",\n required: true,\n }),\n \"target-user\": Flags.string({\n summary: \"Username of the target user (defaults to source-user for same-user copy)\",\n }),\n name: Flags.string({\n char: \"n\",\n summary: \"Name for the copied project\",\n helpValue: \"<name>\",\n }),\n \"auto-rename\": Flags.boolean({\n summary: \"Auto-rename on collision (default: true)\",\n default: true,\n allowNo: true,\n }),\n };\n\n public async run(): Promise<void> {\n const { flags } = await this.parse(AdminCopyProject);\n const pl = await this.connectClient(flags);\n\n const targetUser = flags[\"target-user\"] ?? flags[\"source-user\"];\n\n const source = await navigateToUserRoot(pl, flags[\"source-user\"]);\n const { rid: sourceRid } = await resolveProject(\n pl,\n source.projectListRid,\n flags[\"source-project\"],\n );\n\n const target =\n targetUser === flags[\"source-user\"] ? 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[\"auto-rename\"]) {\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 return { rid: await toGlobalResourceId(newPrj), label: newLabel };\n });\n\n if (flags.format === \"json\") {\n outputJson({\n id: newId,\n rid: String(result.rid),\n label: result.label,\n sourceUser: flags[\"source-user\"],\n targetUser,\n });\n } else {\n outputText(\n `Copied project from ${flags[\"source-user\"]} to ${targetUser} as \"${result.label}\" (id: ${newId})`,\n );\n }\n }\n}\n","// Command index for oclif. Run `pnpm run oclif:index` to regenerate.\n\nimport ProjectList from \"./project/list\";\nimport ProjectInfo from \"./project/info\";\nimport ProjectDuplicate from \"./project/duplicate\";\nimport ProjectRename from \"./project/rename\";\nimport ProjectDelete from \"./project/delete\";\nimport AdminCopyProject from \"./admin/copy-project\";\n\nexport const COMMANDS = {\n \"project:list\": ProjectList,\n \"project:info\": ProjectInfo,\n \"project:duplicate\": ProjectDuplicate,\n \"project:rename\": ProjectRename,\n \"project:delete\": ProjectDelete,\n \"admin:copy-project\": AdminCopyProject,\n};\n"],"mappings":";;;;;;AAEA,MAAa,IAAc;CACzB,SAAS,EAAM,OAAO;EACpB,MAAM;EACN,SAAS;EACT,WAAW;EACX,KAAK;EACL,UAAU;EACX,CAAC;CACF,QAAQ,EAAM,OAAO;EACnB,MAAM;EACN,SAAS;EACT,SAAS,CAAC,QAAQ,OAAO;EACzB,SAAS;EACV,CAAC;CACH,EAEY,IAAgB;CAC3B,MAAM,EAAM,OAAO;EACjB,MAAM;EACN,SAAS;EACT,KAAK;EACN,CAAC;CACF,UAAU,EAAM,OAAO;EACrB,MAAM;EACN,SAAS;EACT,KAAK;EACN,CAAC;CACH,EAGY,IAAiB;CAC5B,cAAc,EAAM,OAAO;EACzB,SAAS;EACT,KAAK;EACL,UAAU;EACX,CAAC;CACF,kBAAkB,EAAM,OAAO;EAC7B,SAAS;EACT,KAAK;EACL,UAAU;EACX,CAAC;CACH,EAGY,IAAmB;CAC9B,cAAc,EAAM,OAAO;EACzB,SAAS;EACT,KAAK;EACN,CAAC;CACF,kBAAkB,EAAM,OAAO;EAC7B,SAAS;EACT,KAAK;EACN,CAAC;CACF,eAAe,EAAM,OAAO;EAC1B,SAAS;EACT,KAAK;EACN,CAAC;CACH;;ACpDD,IAAsB,IAAtB,cAAwC,EAAQ;CAC9C,OAAO,YAAY;EACjB,GAAG;EACH,GAAG;EACH,GAAG;EACJ;CAED;;;;;CAMA,MAAgB,cAAc,GAMR;AACpB,MAAI,KAAK,IAAK,OAAU,MAAM,+BAA+B;AAgB7D,SAdI,EAAM,iBAAiB,EAAM,oBAC/B,KAAK,MAAM,MAAM,EAAwB;GACvC,SAAS,EAAM;GACf,WAAW,EAAM;GACjB,eAAe,EAAM;GACtB,CAAC,GAEF,KAAK,MAAM,MAAM,EAAmB;GAClC,SAAS,EAAM;GACf,MAAM,EAAM;GACZ,UAAU,EAAM;GACjB,CAAC,EAGG,KAAK;;;;;;;CAQd,MAAgB,QAAQ,GAOkC;EACxD,IAAM,IAAe,CAAC,CAAC,EAAM,eACvB,IAAmB,CAAC,CAAC,EAAM,mBAC3B,IAAY,CAAC,CAAC,EAAM;AAG1B,MAAI,KAAa,EAAE,KAAgB,GACjC,OAAU,MAAM,2DAA2D;AAE7E,OAAK,KAAgB,MAAqB,CAAC,EACzC,OAAU,MAAM,2EAA2E;EAG7F,IAAM,IAAK,MAAM,KAAK,cAAc,EAAM,EAEtC;AAQJ,SAPA,AAIE,IAJE,KACU,MAAM,EAAmB,GAAI,EAAM,eAAgB,EAC1C,iBAEJ,MAAM,EAAkB,EAAG,EAGvC;GAAE;GAAI;GAAgB;;CAG/B,MAAgB,QAAQ,GAAqC;AAC3D,EAAI,KAAK,OACP,MAAM,KAAK,IAAI,OAAO;;GClFP,IAArB,MAAqB,UAAoB,EAAU;CACjD,OAAgB,cAAc;CAE9B,OAAgB,QAAQ,EACtB,GAAG,EAAU,WACd;CAED,MAAa,MAAqB;EAChC,IAAM,EAAE,aAAU,MAAM,KAAK,MAAM,EAAY,EACzC,EAAE,OAAI,sBAAmB,MAAM,KAAK,QAAQ,EAAM,EAClD,IAAW,MAAM,EAAa,GAAI,EAAe;AAEvD,MAAI,EAAM,WAAW,OACnB,GACE,EAAS,KAAK,OAAO;GACnB,IAAI,EAAE;GACN,KAAK,EAAE;GACP,OAAO,EAAE;GACT,SAAS,EAAE,QAAQ,aAAa;GAChC,cAAc,EAAE,aAAa,aAAa;GAC3C,EAAE,CACJ;OACI;AACL,OAAI,EAAS,WAAW,GAAG;AACzB,MAAW,qBAAqB;AAChC;;AAcF,GAXA,EACE,EACE;IAAC;IAAM;IAAS;IAAW;IAAgB,EAC3C,EAAS,KAAK,MAAM;IAClB,EAAE,GAAG,UAAU,GAAG,EAAE,GAAG;IACvB,EAAE;IACF,EAAW,EAAE,QAAQ;IACrB,EAAW,EAAE,aAAa;IAC3B,CAAC,CACH,CACF,EACD,EAAW,KAAK,EAAS,OAAO,aAAa;;;GCtC9B,IAArB,MAAqB,UAAoB,EAAU;CACjD,OAAgB,cAAc;CAE9B,OAAgB,OAAO,EACrB,SAAS,EAAK,OAAO;EACnB,aAAa;EACb,UAAU;EACX,CAAC,EACH;CAED,OAAgB,QAAQ,EACtB,GAAG,EAAU,WACd;CAED,MAAa,MAAqB;EAChC,IAAM,EAAE,SAAM,aAAU,MAAM,KAAK,MAAM,EAAY,EAC/C,EAAE,OAAI,sBAAmB,MAAM,KAAK,QAAQ,EAAM,EAClD,EAAE,UAAO,MAAM,EAAe,GAAI,GAAgB,EAAK,QAAQ,EAC/D,IAAO,MAAM,EAAe,GAAI,GAAgB,EAAG;AAEzD,MAAI,EAAM,WAAW,OACnB,GAAW;GACT,IAAI,EAAK;GACT,KAAK,EAAK;GACV,OAAO,EAAK;GACZ,eAAe,EAAK;GACpB,YAAY,EAAK;GACjB,UAAU,EAAK;GACf,SAAS,EAAK,QAAQ,aAAa;GACnC,cAAc,EAAK,aAAa,aAAa;GAC9C,CAAC;OACG;AAML,OALA,EAAW,YAAY,EAAK,QAAQ,EACpC,EAAW,YAAY,EAAK,KAAK,EACjC,EAAW,YAAY,EAAK,MAAM,EAClC,EAAW,YAAY,EAAK,iBAAiB,cAAc,EAC3D,EAAW,YAAY,EAAK,aAAa,EACrC,EAAK,SAAS,SAAS,EACzB,MAAK,IAAM,KAAO,EAAK,SACrB,GAAW,OAAO,IAAM;AAI5B,GADA,EAAW,kBAAkB,EAAW,EAAK,QAAQ,GAAG,EACxD,EAAW,kBAAkB,EAAW,EAAK,aAAa,GAAG;;;GCnC9C,IAArB,MAAqB,UAAyB,EAAU;CACtD,OAAgB,cACd;CAEF,OAAgB,OAAO,EACrB,SAAS,EAAK,OAAO;EACnB,aAAa;EACb,UAAU;EACX,CAAC,EACH;CAED,OAAgB,QAAQ;EACtB,GAAG,EAAU;EACb,MAAM,EAAM,OAAO;GACjB,MAAM;GACN,SAAS;GACT,WAAW;GACZ,CAAC;EACF,eAAe,EAAM,QAAQ;GAC3B,SAAS;GACT,SAAS;GACT,SAAS;GACV,CAAC;EACH;CAED,MAAa,MAAqB;EAChC,IAAM,EAAE,SAAM,aAAU,MAAM,KAAK,MAAM,EAAiB,EACpD,EAAE,OAAI,sBAAmB,MAAM,KAAK,QAAQ,EAAM,EAElD,EAAE,KAAK,MAAc,MAAM,EAAe,GAAI,GAAgB,EAAK,QAAQ,EAE3E,IAAQ,GAAY,EAEpB,IAAS,MAAM,EAAG,YAAY,oBAAoB,OAAO,MAAO;GACpE,IAAM,IAAgB,MAAM,EAAG,gBAAgB,GAAW,EAAe,EAEnE,IADa,KAAK,MAAM,EAAc,CACL,OAEjC,IAAiB,MAAM,EAAsB,GAAI,EAAe,EAGlE;AACJ,OAAI,EAAM,MAAM;AACd,QAAI,CAAC,EAAM,kBAAkB,EAAe,SAAS,EAAM,KAAK,CAC9D,OAAU,MAAM,iBAAiB,EAAM,KAAK,mBAAmB;AAEjE,QAAW,EAAe,SAAS,EAAM,KAAK,GAC1C,EAAgB,EAAM,MAAM,EAAe,GAC3C,EAAM;SAEV,KAAW,EAAgB,GAAa,EAAe;GAGzD,IAAM,IAAS,MAAM,EAAiB,GAAI,GAAW,EAAE,OAAO,GAAU,CAAC;AAIzE,UAHA,EAAG,YAAY,EAAM,GAAgB,EAAM,EAAE,WAAW,EAAO,EAC/D,MAAM,EAAG,QAAQ,EAEV;IAAE,KAAK,MAAM,EAAmB,EAAO;IAAE,OAAO;IAAU;IACjE;AAEF,EAAI,EAAM,WAAW,SACnB,EAAW;GAAE,IAAI;GAAO,KAAK,OAAO,EAAO,IAAI;GAAE,OAAO,EAAO;GAAO,CAAC,GAEvE,EAAW,0BAA0B,EAAO,MAAM,SAAS,EAAM,GAAG;;GCvErD,IAArB,MAAqB,UAAsB,EAAU;CACnD,OAAgB,cAAc;CAE9B,OAAgB,OAAO,EACrB,SAAS,EAAK,OAAO;EACnB,aAAa;EACb,UAAU;EACX,CAAC,EACH;CAED,OAAgB,QAAQ;EACtB,GAAG,EAAU;EACb,MAAM,EAAM,OAAO;GACjB,MAAM;GACN,SAAS;GACT,WAAW;GACX,UAAU;GACX,CAAC;EACH;CAED,MAAa,MAAqB;EAChC,IAAM,EAAE,SAAM,aAAU,MAAM,KAAK,MAAM,EAAc,EACjD,EAAE,OAAI,sBAAmB,MAAM,KAAK,QAAQ,EAAM,EAClD,EAAE,OAAI,WAAQ,MAAM,EAAe,GAAI,GAAgB,EAAK,QAAQ;AAI1E,EAFA,MAAM,EAAc,GAAI,GAAK,EAAM,KAAK,EAEpC,EAAM,WAAW,SACnB,EAAW;GAAE;GAAI,KAAK,OAAO,EAAI;GAAE,OAAO,EAAM;GAAM,CAAC,GAEvD,EAAW,uBAAuB,EAAM,KAAK,GAAG;;GC7BjC,IAArB,MAAqB,UAAsB,EAAU;CACnD,OAAgB,cAAc;CAE9B,OAAgB,OAAO,EACrB,SAAS,EAAK,OAAO;EACnB,aAAa;EACb,UAAU;EACX,CAAC,EACH;CAED,OAAgB,QAAQ;EACtB,GAAG,EAAU;EACb,OAAO,EAAM,QAAQ;GACnB,SAAS;GACT,SAAS;GACV,CAAC;EACH;CAED,MAAa,MAAqB;EAChC,IAAM,EAAE,SAAM,aAAU,MAAM,KAAK,MAAM,EAAc,EACjD,EAAE,OAAI,sBAAmB,MAAM,KAAK,QAAQ,EAAM,EAClD,EAAE,UAAO,MAAM,EAAe,GAAI,GAAgB,EAAK,QAAQ,EAE/D,IAAO,MAAM,EAAe,GAAI,GAAgB,EAAG;AAEzD,MAAI,CAAC,EAAM,OAAO;GAChB,IAAM,IAAK,EAAgB;IAAE,OAAO,QAAQ;IAAO,QAAQ,QAAQ;IAAQ,CAAC;AAC5E,OAAI;AAOF,SANe,MAAM,IAAI,SAAiB,MAAY;AACpD,OAAG,SACD,mBAAmB,EAAK,MAAM,KAAK,EAAK,WAAW,mBACnD,EACD;MACD,EACS,aAAa,KAAK,KAAK;AAChC,OAAW,WAAW;AACtB;;aAEM;AACR,MAAG,OAAO;;;AAMd,EAFA,MAAM,EAAc,GAAI,GAAgB,EAAG,EAEvC,EAAM,WAAW,SACnB,EAAW;GAAE,SAAS;GAAM;GAAI,OAAO,EAAK;GAAO,CAAC,GAEpD,EAAW,oBAAoB,EAAK,MAAM,GAAG;;GCvC9B,IAArB,MAAqB,UAAyB,EAAU;CACtD,OAAgB,cACd;CAEF,OAAgB,QAAQ;EACtB,GAAG;EACH,GAAG;EACH,eAAe,EAAM,OAAO;GAC1B,SAAS;GACT,UAAU;GACX,CAAC;EACF,kBAAkB,EAAM,OAAO;GAC7B,SAAS;GACT,UAAU;GACX,CAAC;EACF,eAAe,EAAM,OAAO,EAC1B,SAAS,4EACV,CAAC;EACF,MAAM,EAAM,OAAO;GACjB,MAAM;GACN,SAAS;GACT,WAAW;GACZ,CAAC;EACF,eAAe,EAAM,QAAQ;GAC3B,SAAS;GACT,SAAS;GACT,SAAS;GACV,CAAC;EACH;CAED,MAAa,MAAqB;EAChC,IAAM,EAAE,aAAU,MAAM,KAAK,MAAM,EAAiB,EAC9C,IAAK,MAAM,KAAK,cAAc,EAAM,EAEpC,IAAa,EAAM,kBAAkB,EAAM,gBAE3C,IAAS,MAAM,EAAmB,GAAI,EAAM,eAAe,EAC3D,EAAE,KAAK,MAAc,MAAM,EAC/B,GACA,EAAO,gBACP,EAAM,kBACP,EAEK,IACJ,MAAe,EAAM,iBAAiB,IAAS,MAAM,EAAmB,GAAI,EAAW,EAEnF,IAAQ,GAAY,EAEpB,IAAS,MAAM,EAAG,YAAY,oBAAoB,OAAO,MAAO;GACpE,IAAM,IAAgB,MAAM,EAAG,gBAAgB,GAAW,EAAe,EAEnE,IADa,KAAK,MAAM,EAAc,CACL,OAEjC,IAAiB,MAAM,EAAsB,GAAI,EAAO,eAAe,EAEzE,IAAmB,EAAM,QAAQ;AAErC,OAAI,EAAe,SAAS,EAAS,EAAE;AACrC,QAAI,CAAC,EAAM,eACT,OAAU,MAAM,iBAAiB,EAAS,mCAAmC;AAE/E,QAAW,EAAgB,EAAM,QAAQ,GAAa,EAAe;;GAGvE,IAAM,IAAS,MAAM,EAAiB,GAAI,GAAW,EAAE,OAAO,GAAU,CAAC;AAIzE,UAHA,EAAG,YAAY,EAAM,EAAO,gBAAgB,EAAM,EAAE,WAAW,EAAO,EACtE,MAAM,EAAG,QAAQ,EAEV;IAAE,KAAK,MAAM,EAAmB,EAAO;IAAE,OAAO;IAAU;IACjE;AAEF,EAAI,EAAM,WAAW,SACnB,EAAW;GACT,IAAI;GACJ,KAAK,OAAO,EAAO,IAAI;GACvB,OAAO,EAAO;GACd,YAAY,EAAM;GAClB;GACD,CAAC,GAEF,EACE,uBAAuB,EAAM,eAAe,MAAM,EAAW,OAAO,EAAO,MAAM,SAAS,EAAM,GACjG;;;ACxFP,MAAa,IAAW;CACtB,gBAAgB;CAChB,gBAAgB;CAChB,qBAAqB;CACrB,kBAAkB;CAClB,kBAAkB;CAClB,sBAAsB;CACvB"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { PlCommand } from '../../base_command';
|
|
2
|
+
export default class AdminCopyProject extends PlCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static flags: {
|
|
5
|
+
"source-user": import('@oclif/core/interfaces').OptionFlag<string, import('@oclif/core/interfaces').CustomOptions>;
|
|
6
|
+
"source-project": import('@oclif/core/interfaces').OptionFlag<string, import('@oclif/core/interfaces').CustomOptions>;
|
|
7
|
+
"target-user": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
8
|
+
name: import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
9
|
+
"auto-rename": import('@oclif/core/interfaces').BooleanFlag<boolean>;
|
|
10
|
+
"admin-user": import('@oclif/core/interfaces').OptionFlag<string, import('@oclif/core/interfaces').CustomOptions>;
|
|
11
|
+
"admin-password": import('@oclif/core/interfaces').OptionFlag<string, import('@oclif/core/interfaces').CustomOptions>;
|
|
12
|
+
address: import('@oclif/core/interfaces').OptionFlag<string, import('@oclif/core/interfaces').CustomOptions>;
|
|
13
|
+
format: import('@oclif/core/interfaces').OptionFlag<string, import('@oclif/core/interfaces').CustomOptions>;
|
|
14
|
+
};
|
|
15
|
+
run(): Promise<void>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { default as ProjectList } from './project/list';
|
|
2
|
+
import { default as ProjectInfo } from './project/info';
|
|
3
|
+
import { default as ProjectDuplicate } from './project/duplicate';
|
|
4
|
+
import { default as ProjectRename } from './project/rename';
|
|
5
|
+
import { default as ProjectDelete } from './project/delete';
|
|
6
|
+
import { default as AdminCopyProject } from './admin/copy-project';
|
|
7
|
+
export declare const COMMANDS: {
|
|
8
|
+
"project:list": typeof ProjectList;
|
|
9
|
+
"project:info": typeof ProjectInfo;
|
|
10
|
+
"project:duplicate": typeof ProjectDuplicate;
|
|
11
|
+
"project:rename": typeof ProjectRename;
|
|
12
|
+
"project:delete": typeof ProjectDelete;
|
|
13
|
+
"admin:copy-project": typeof AdminCopyProject;
|
|
14
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { PlCommand } from '../../base_command';
|
|
2
|
+
export default class ProjectDelete extends PlCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static args: {
|
|
5
|
+
project: import('@oclif/core/interfaces').Arg<string, Record<string, unknown>>;
|
|
6
|
+
};
|
|
7
|
+
static flags: {
|
|
8
|
+
force: import('@oclif/core/interfaces').BooleanFlag<boolean>;
|
|
9
|
+
"admin-user": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
10
|
+
"admin-password": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
11
|
+
"target-user": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
12
|
+
user: import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
13
|
+
password: import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
14
|
+
address: import('@oclif/core/interfaces').OptionFlag<string, import('@oclif/core/interfaces').CustomOptions>;
|
|
15
|
+
format: import('@oclif/core/interfaces').OptionFlag<string, import('@oclif/core/interfaces').CustomOptions>;
|
|
16
|
+
};
|
|
17
|
+
run(): Promise<void>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { PlCommand } from '../../base_command';
|
|
2
|
+
export default class ProjectDuplicate extends PlCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static args: {
|
|
5
|
+
project: import('@oclif/core/interfaces').Arg<string, Record<string, unknown>>;
|
|
6
|
+
};
|
|
7
|
+
static flags: {
|
|
8
|
+
name: import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
9
|
+
"auto-rename": import('@oclif/core/interfaces').BooleanFlag<boolean>;
|
|
10
|
+
"admin-user": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
11
|
+
"admin-password": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
12
|
+
"target-user": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
13
|
+
user: import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
14
|
+
password: import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
15
|
+
address: import('@oclif/core/interfaces').OptionFlag<string, import('@oclif/core/interfaces').CustomOptions>;
|
|
16
|
+
format: import('@oclif/core/interfaces').OptionFlag<string, import('@oclif/core/interfaces').CustomOptions>;
|
|
17
|
+
};
|
|
18
|
+
run(): Promise<void>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { PlCommand } from '../../base_command';
|
|
2
|
+
export default class ProjectInfo extends PlCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static args: {
|
|
5
|
+
project: import('@oclif/core/interfaces').Arg<string, Record<string, unknown>>;
|
|
6
|
+
};
|
|
7
|
+
static flags: {
|
|
8
|
+
"admin-user": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
9
|
+
"admin-password": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
10
|
+
"target-user": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
11
|
+
user: import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
12
|
+
password: import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
13
|
+
address: import('@oclif/core/interfaces').OptionFlag<string, import('@oclif/core/interfaces').CustomOptions>;
|
|
14
|
+
format: import('@oclif/core/interfaces').OptionFlag<string, import('@oclif/core/interfaces').CustomOptions>;
|
|
15
|
+
};
|
|
16
|
+
run(): Promise<void>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { PlCommand } from '../../base_command';
|
|
2
|
+
export default class ProjectList extends PlCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static flags: {
|
|
5
|
+
"admin-user": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
6
|
+
"admin-password": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
7
|
+
"target-user": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
8
|
+
user: import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
9
|
+
password: import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
10
|
+
address: import('@oclif/core/interfaces').OptionFlag<string, import('@oclif/core/interfaces').CustomOptions>;
|
|
11
|
+
format: import('@oclif/core/interfaces').OptionFlag<string, import('@oclif/core/interfaces').CustomOptions>;
|
|
12
|
+
};
|
|
13
|
+
run(): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { PlCommand } from '../../base_command';
|
|
2
|
+
export default class ProjectRename extends PlCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static args: {
|
|
5
|
+
project: import('@oclif/core/interfaces').Arg<string, Record<string, unknown>>;
|
|
6
|
+
};
|
|
7
|
+
static flags: {
|
|
8
|
+
name: import('@oclif/core/interfaces').OptionFlag<string, import('@oclif/core/interfaces').CustomOptions>;
|
|
9
|
+
"admin-user": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
10
|
+
"admin-password": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
11
|
+
"target-user": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
12
|
+
user: import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
13
|
+
password: import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
14
|
+
address: import('@oclif/core/interfaces').OptionFlag<string, import('@oclif/core/interfaces').CustomOptions>;
|
|
15
|
+
format: import('@oclif/core/interfaces').OptionFlag<string, import('@oclif/core/interfaces').CustomOptions>;
|
|
16
|
+
};
|
|
17
|
+
run(): Promise<void>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const GlobalFlags: {
|
|
2
|
+
address: import('@oclif/core/interfaces').OptionFlag<string, import('@oclif/core/interfaces').CustomOptions>;
|
|
3
|
+
format: import('@oclif/core/interfaces').OptionFlag<string, import('@oclif/core/interfaces').CustomOptions>;
|
|
4
|
+
};
|
|
5
|
+
export declare const UserAuthFlags: {
|
|
6
|
+
user: import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
7
|
+
password: import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
8
|
+
};
|
|
9
|
+
/** Admin credentials only (for purely admin commands like copy-project). */
|
|
10
|
+
export declare const AdminAuthFlags: {
|
|
11
|
+
"admin-user": import('@oclif/core/interfaces').OptionFlag<string, import('@oclif/core/interfaces').CustomOptions>;
|
|
12
|
+
"admin-password": import('@oclif/core/interfaces').OptionFlag<string, import('@oclif/core/interfaces').CustomOptions>;
|
|
13
|
+
};
|
|
14
|
+
/** Admin credentials + target user (for regular commands that can optionally operate on another user). */
|
|
15
|
+
export declare const AdminTargetFlags: {
|
|
16
|
+
"admin-user": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
17
|
+
"admin-password": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
18
|
+
"target-user": import('@oclif/core/interfaces').OptionFlag<string | undefined, import('@oclif/core/interfaces').CustomOptions>;
|
|
19
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { PlClient } from '@milaboratories/pl-client';
|
|
2
|
+
export interface PlConnectionOptions {
|
|
3
|
+
address: string;
|
|
4
|
+
user?: string;
|
|
5
|
+
password?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface AdminConnectionOptions {
|
|
8
|
+
address: string;
|
|
9
|
+
adminUser: string;
|
|
10
|
+
adminPassword: string;
|
|
11
|
+
}
|
|
12
|
+
/** Creates an authenticated PlClient from address + credentials. */
|
|
13
|
+
export declare function createPlConnection(opts: PlConnectionOptions): Promise<PlClient>;
|
|
14
|
+
/** Creates a PlClient with admin/controller credentials. */
|
|
15
|
+
export declare function createAdminPlConnection(opts: AdminConnectionOptions): Promise<PlClient>;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as e, c as t, d as n, f as r, g as i, h as a, i as o, l as s, m as c, n as l, o as u, p as d, r as f, s as p, t as m, u as h } from "./output-INk3CKvr.js";
|
|
2
|
+
export { a as createAdminPlConnection, i as createPlConnection, e as deduplicateName, u as deleteProject, p as duplicateProject, m as formatDate, l as formatTable, t as getExistingLabelsInTx, s as getProjectInfo, h as getProjectListRid, n as listProjects, r as navigateToUserRoot, f as outputJson, o as outputText, d as renameProject, c as resolveProject };
|
package/dist/lib.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { createPlConnection, createAdminPlConnection, type PlConnectionOptions, type AdminConnectionOptions, } from './connection';
|
|
2
|
+
export { listProjects, getProjectInfo, getProjectListRid, getExistingLabelsInTx, resolveProject, renameProject, deleteProject, deduplicateName, navigateToUserRoot, duplicateProject, type ProjectEntry, type ProjectInfo, } from './project_ops';
|
|
3
|
+
export { type OutputFormat, outputText, outputJson, formatTable, formatDate } from './output';
|