@elaraai/e3-cloud-cli 0.0.0-stage → 1.0.89-alpha.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/LICENSE.md +54 -0
- package/README.md +433 -2
- package/dist/src/app-source.d.ts +16 -0
- package/dist/src/app-source.d.ts.map +1 -0
- package/dist/src/app-source.js +112 -0
- package/dist/src/app-source.js.map +1 -0
- package/dist/src/cli.d.ts +7 -0
- package/dist/src/cli.d.ts.map +1 -0
- package/dist/src/cli.js +472 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/commands/app.d.ts +28 -0
- package/dist/src/commands/app.d.ts.map +1 -0
- package/dist/src/commands/app.js +286 -0
- package/dist/src/commands/app.js.map +1 -0
- package/dist/src/commands/compute.d.ts +16 -0
- package/dist/src/commands/compute.d.ts.map +1 -0
- package/dist/src/commands/compute.js +110 -0
- package/dist/src/commands/compute.js.map +1 -0
- package/dist/src/commands/feedback.d.ts +27 -0
- package/dist/src/commands/feedback.d.ts.map +1 -0
- package/dist/src/commands/feedback.js +197 -0
- package/dist/src/commands/feedback.js.map +1 -0
- package/dist/src/commands/records.d.ts +42 -0
- package/dist/src/commands/records.d.ts.map +1 -0
- package/dist/src/commands/records.js +301 -0
- package/dist/src/commands/records.js.map +1 -0
- package/dist/src/commands/release.d.ts +39 -0
- package/dist/src/commands/release.d.ts.map +1 -0
- package/dist/src/commands/release.js +219 -0
- package/dist/src/commands/release.js.map +1 -0
- package/dist/src/commands/role.d.ts +24 -0
- package/dist/src/commands/role.d.ts.map +1 -0
- package/dist/src/commands/role.js +94 -0
- package/dist/src/commands/role.js.map +1 -0
- package/dist/src/commands/schedule.d.ts +18 -0
- package/dist/src/commands/schedule.d.ts.map +1 -0
- package/dist/src/commands/schedule.js +128 -0
- package/dist/src/commands/schedule.js.map +1 -0
- package/dist/src/commands/secrets.d.ts +15 -0
- package/dist/src/commands/secrets.d.ts.map +1 -0
- package/dist/src/commands/secrets.js +82 -0
- package/dist/src/commands/secrets.js.map +1 -0
- package/dist/src/commands/staging.d.ts +36 -0
- package/dist/src/commands/staging.d.ts.map +1 -0
- package/dist/src/commands/staging.js +98 -0
- package/dist/src/commands/staging.js.map +1 -0
- package/dist/src/commands/timeout.d.ts +16 -0
- package/dist/src/commands/timeout.d.ts.map +1 -0
- package/dist/src/commands/timeout.js +124 -0
- package/dist/src/commands/timeout.js.map +1 -0
- package/dist/src/commands/user-settings.d.ts +15 -0
- package/dist/src/commands/user-settings.d.ts.map +1 -0
- package/dist/src/commands/user-settings.js +74 -0
- package/dist/src/commands/user-settings.js.map +1 -0
- package/dist/src/commands/user.d.ts +26 -0
- package/dist/src/commands/user.d.ts.map +1 -0
- package/dist/src/commands/user.js +206 -0
- package/dist/src/commands/user.js.map +1 -0
- package/dist/src/commands/whoami.d.ts +6 -0
- package/dist/src/commands/whoami.d.ts.map +1 -0
- package/dist/src/commands/whoami.js +38 -0
- package/dist/src/commands/whoami.js.map +1 -0
- package/dist/src/credentials.d.ts +100 -0
- package/dist/src/credentials.d.ts.map +1 -0
- package/dist/src/credentials.js +164 -0
- package/dist/src/credentials.js.map +1 -0
- package/dist/src/utils.d.ts +38 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/utils.js +73 -0
- package/dist/src/utils.js.map +1 -0
- package/package.json +32 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../../src/commands/secrets.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Staging:
|
|
7
|
+
*
|
|
8
|
+
* - `e3-cloud staging add <repo-url> <live> <name> [--as-is] [--replace] [--plan]`
|
|
9
|
+
* - `e3-cloud staging stop <repo-url> <live>` (admins)
|
|
10
|
+
* - `e3-cloud staging list <repo-url>`
|
|
11
|
+
*
|
|
12
|
+
* A workspace's staging is where changes are tried before they go live; the
|
|
13
|
+
* workspace it releases to is then protected, as a protected branch is: its
|
|
14
|
+
* package and apps change only by a release from its staging (`e3-cloud
|
|
15
|
+
* release`), or a rollback. `add` prints its plan first, always; `--plan`
|
|
16
|
+
* stops there. A staging starts as a copy of the live workspace, and a copy
|
|
17
|
+
* replaces a workspace of its name whole, so one there is replaced only with
|
|
18
|
+
* `--replace`; `--as-is` makes the workspace of the name the staging as it
|
|
19
|
+
* stands. Only an admin stops a staging, which deletes nothing.
|
|
20
|
+
*/
|
|
21
|
+
import { type StagingPlan } from '@elaraai/e3-cloud-client';
|
|
22
|
+
/** What adding a staging does, a line for each part. */
|
|
23
|
+
export declare function stagingPlanLines(plan: StagingPlan): string[];
|
|
24
|
+
export declare const stagingCommand: {
|
|
25
|
+
/** e3-cloud staging add <repoUrl> <live> <name> [--as-is] [--replace] [--plan] */
|
|
26
|
+
add(url: string, live: string, name: string, options: {
|
|
27
|
+
asIs?: boolean;
|
|
28
|
+
replace?: boolean;
|
|
29
|
+
plan?: boolean;
|
|
30
|
+
}): Promise<void>;
|
|
31
|
+
/** e3-cloud staging stop <repoUrl> <live> */
|
|
32
|
+
stop(url: string, live: string): Promise<void>;
|
|
33
|
+
/** e3-cloud staging list <repoUrl> */
|
|
34
|
+
list(url: string): Promise<void>;
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=staging.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"staging.d.ts","sourceRoot":"","sources":["../../../src/commands/staging.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAIL,KAAK,WAAW,EAEjB,MAAM,0BAA0B,CAAC;AAYlC,wDAAwD;AACxD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,EAAE,CAW5D;AAED,eAAO,MAAM,cAAc;IACzB,kFAAkF;aACnE,MAAM,QAAQ,MAAM,QAAQ,MAAM,WAAW;QAAE,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBjI,6CAA6C;cAC7B,MAAM,QAAQ,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWpD,sCAAsC;cACtB,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAcvC,CAAC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Staging:
|
|
7
|
+
*
|
|
8
|
+
* - `e3-cloud staging add <repo-url> <live> <name> [--as-is] [--replace] [--plan]`
|
|
9
|
+
* - `e3-cloud staging stop <repo-url> <live>` (admins)
|
|
10
|
+
* - `e3-cloud staging list <repo-url>`
|
|
11
|
+
*
|
|
12
|
+
* A workspace's staging is where changes are tried before they go live; the
|
|
13
|
+
* workspace it releases to is then protected, as a protected branch is: its
|
|
14
|
+
* package and apps change only by a release from its staging (`e3-cloud
|
|
15
|
+
* release`), or a rollback. `add` prints its plan first, always; `--plan`
|
|
16
|
+
* stops there. A staging starts as a copy of the live workspace, and a copy
|
|
17
|
+
* replaces a workspace of its name whole, so one there is replaced only with
|
|
18
|
+
* `--replace`; `--as-is` makes the workspace of the name the staging as it
|
|
19
|
+
* stands. Only an admin stops a staging, which deletes nothing.
|
|
20
|
+
*/
|
|
21
|
+
import { addStaging, getRepositoryReleaseSettings, stopStaging, } from '@elaraai/e3-cloud-client';
|
|
22
|
+
import { variant } from '@elaraai/east';
|
|
23
|
+
import { getValidToken } from '../credentials.js';
|
|
24
|
+
import { exitError, formatError, parseRepoUrl } from '../utils.js';
|
|
25
|
+
/** What a workspace runs, in words: `acme@1.5.0 · ops v3, exec v1`. */
|
|
26
|
+
function runsWords(runs) {
|
|
27
|
+
const pkg = runs.package.type === 'some' ? `${runs.package.value.name}@${runs.package.value.version}` : 'no package';
|
|
28
|
+
const apps = runs.apps.map((app) => `${app.name} v${app.number}`).join(', ');
|
|
29
|
+
return apps === '' ? pkg : `${pkg} · ${apps}`;
|
|
30
|
+
}
|
|
31
|
+
/** What adding a staging does, a line for each part. */
|
|
32
|
+
export function stagingPlanLines(plan) {
|
|
33
|
+
const lines = [`Add ${plan.staging} as ${plan.live}'s staging`];
|
|
34
|
+
const row = (label, words) => lines.push(` ${label.padEnd(10)} ${words}`);
|
|
35
|
+
if (plan.start.type === 'copy') {
|
|
36
|
+
row('Starts as', `a copy of ${plan.live} as it is now: ${runsWords(plan.runs)}, and its data`);
|
|
37
|
+
if (plan.replaces.type === 'some')
|
|
38
|
+
row('Replaces', `${plan.staging} as it is: ${runsWords(plan.replaces.value)}, and its data`);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
row('Starts as', `${plan.staging} as it stands: ${runsWords(plan.runs)}`);
|
|
42
|
+
}
|
|
43
|
+
row('Protects', `${plan.live}: from then on it changes only by a release from ${plan.staging}, or a rollback`);
|
|
44
|
+
return lines;
|
|
45
|
+
}
|
|
46
|
+
export const stagingCommand = {
|
|
47
|
+
/** e3-cloud staging add <repoUrl> <live> <name> [--as-is] [--replace] [--plan] */
|
|
48
|
+
async add(url, live, name, options) {
|
|
49
|
+
try {
|
|
50
|
+
const { baseUrl, repo } = parseRepoUrl(url);
|
|
51
|
+
const token = await getValidToken(baseUrl);
|
|
52
|
+
const start = options.asIs === true ? variant('as_is', null) : variant('copy', null);
|
|
53
|
+
const planned = await addStaging(baseUrl, repo, live, { name, start, plan: true }, { token });
|
|
54
|
+
console.log(stagingPlanLines(planned.value).join('\n'));
|
|
55
|
+
if (options.plan === true)
|
|
56
|
+
return;
|
|
57
|
+
// A copy replaces a workspace of the name whole: never unasked
|
|
58
|
+
if (planned.value.replaces.type === 'some' && options.replace !== true) {
|
|
59
|
+
exitError(`${name} is there already: --replace replaces it with a copy of ${live}, its data included, or --as-is makes it ${live}'s staging as it stands`);
|
|
60
|
+
}
|
|
61
|
+
const added = await addStaging(baseUrl, repo, live, { name, start, plan: false }, { token });
|
|
62
|
+
console.log(`Done: ${added.value.staging} is ${live}'s staging, and ${live} is protected. Deploy to ${added.value.staging}, then release it with e3-cloud release`);
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
exitError(formatError(err));
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
/** e3-cloud staging stop <repoUrl> <live> */
|
|
69
|
+
async stop(url, live) {
|
|
70
|
+
try {
|
|
71
|
+
const { baseUrl, repo } = parseRepoUrl(url);
|
|
72
|
+
const token = await getValidToken(baseUrl);
|
|
73
|
+
const link = await stopStaging(baseUrl, repo, live, { token });
|
|
74
|
+
console.log(`Done: ${link.staging} is no longer ${live}'s staging, and ${live} is no longer protected. Nothing was deleted; ${live}'s history records who stopped it`);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
exitError(formatError(err));
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
/** e3-cloud staging list <repoUrl> */
|
|
81
|
+
async list(url) {
|
|
82
|
+
try {
|
|
83
|
+
const { baseUrl, repo } = parseRepoUrl(url);
|
|
84
|
+
const token = await getValidToken(baseUrl);
|
|
85
|
+
const { releasesTo } = await getRepositoryReleaseSettings(baseUrl, repo, { token });
|
|
86
|
+
if (releasesTo.size === 0) {
|
|
87
|
+
console.log(`${repo} has no staging: no workspace is protected`);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
for (const [staging, live] of releasesTo)
|
|
91
|
+
console.log(`${staging} → ${live} (${live} is protected: it changes only by a release from ${staging})`);
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
exitError(formatError(err));
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
//# sourceMappingURL=staging.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"staging.js","sourceRoot":"","sources":["../../../src/commands/staging.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
export declare const timeoutCommand: {
|
|
6
|
+
set(url: string, taskNameOrPattern: string, options: {
|
|
7
|
+
timeout: string;
|
|
8
|
+
regex?: boolean;
|
|
9
|
+
}): Promise<void>;
|
|
10
|
+
get(url: string, taskName: string): Promise<void>;
|
|
11
|
+
list(url: string): Promise<void>;
|
|
12
|
+
remove(url: string, taskNameOrPattern: string, options: {
|
|
13
|
+
regex?: boolean;
|
|
14
|
+
}): Promise<void>;
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=timeout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeout.d.ts","sourceRoot":"","sources":["../../../src/commands/timeout.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAwCH,eAAO,MAAM,cAAc;aAElB,MAAM,qBACQ,MAAM,WAChB;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAC5C,OAAO,CAAC,IAAI,CAAC;aA6BD,MAAM,YAAY,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;cAYvC,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;gBAuB/B,MAAM,qBACQ,MAAM,WAChB;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAC3B,OAAO,CAAC,IAAI,CAAC;CAyBjB,CAAC"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Task timeout management commands — set, get, list, remove.
|
|
7
|
+
*/
|
|
8
|
+
import { TIMEOUT_MIN_MINUTES, TIMEOUT_MAX_MINUTES } from '@elaraai/e3-cloud-types';
|
|
9
|
+
import { listTimeout, getTimeout, setTimeout, setTimeoutBatch, removeTimeout, removeTimeoutBatch, } from '@elaraai/e3-cloud-client';
|
|
10
|
+
import { taskList } from '@elaraai/e3-api-client';
|
|
11
|
+
import { getValidToken } from '../credentials.js';
|
|
12
|
+
import { parseWorkspaceUrl, formatError, exitError, confirm } from '../utils.js';
|
|
13
|
+
function parseTimeout(s) {
|
|
14
|
+
const match = s.match(/^(\d+)(m|h|d)?$/);
|
|
15
|
+
if (!match) {
|
|
16
|
+
exitError(`Invalid timeout: ${s}. Use minutes (e.g., 120), hours (e.g., 2h), or days (e.g., 1d)`);
|
|
17
|
+
}
|
|
18
|
+
const value = parseInt(match[1], 10);
|
|
19
|
+
const unit = match[2] ?? 'm';
|
|
20
|
+
const minutes = unit === 'h' ? value * 60 : unit === 'd' ? value * 1440 : value;
|
|
21
|
+
if (minutes < TIMEOUT_MIN_MINUTES || minutes > TIMEOUT_MAX_MINUTES) {
|
|
22
|
+
exitError(`Timeout must be between ${TIMEOUT_MIN_MINUTES} minute and ${TIMEOUT_MAX_MINUTES} minutes, got ${minutes} minutes`);
|
|
23
|
+
}
|
|
24
|
+
return BigInt(minutes);
|
|
25
|
+
}
|
|
26
|
+
function formatMinutes(minutes) {
|
|
27
|
+
const m = Number(minutes);
|
|
28
|
+
if (m >= 1440 && m % 1440 === 0)
|
|
29
|
+
return `${m / 1440}d`;
|
|
30
|
+
if (m >= 60 && m % 60 === 0)
|
|
31
|
+
return `${m / 60}h`;
|
|
32
|
+
return `${m}m`;
|
|
33
|
+
}
|
|
34
|
+
export const timeoutCommand = {
|
|
35
|
+
async set(url, taskNameOrPattern, options) {
|
|
36
|
+
try {
|
|
37
|
+
const { baseUrl, repo, workspace } = parseWorkspaceUrl(url);
|
|
38
|
+
const token = await getValidToken(baseUrl);
|
|
39
|
+
const minutes = parseTimeout(options.timeout);
|
|
40
|
+
const timeout = { minutes };
|
|
41
|
+
if (options.regex) {
|
|
42
|
+
const tasks = await taskList(baseUrl, repo, workspace, { token });
|
|
43
|
+
const regex = new RegExp(taskNameOrPattern);
|
|
44
|
+
const matched = tasks.filter(t => regex.test(t.name)).map(t => t.name);
|
|
45
|
+
if (matched.length === 0) {
|
|
46
|
+
exitError(`No tasks matched pattern: ${taskNameOrPattern}`);
|
|
47
|
+
}
|
|
48
|
+
console.log(`Matched ${matched.length} tasks: ${matched.join(', ')}`);
|
|
49
|
+
if (!await confirm(`Set timeout ${formatMinutes(minutes)} for ${matched.length} tasks?`))
|
|
50
|
+
return;
|
|
51
|
+
const configs = new Map();
|
|
52
|
+
for (const name of matched)
|
|
53
|
+
configs.set(name, timeout);
|
|
54
|
+
await setTimeoutBatch(baseUrl, repo, workspace, configs, { token });
|
|
55
|
+
console.log(`Timeout ${formatMinutes(minutes)} set for ${matched.length} tasks`);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
await setTimeout(baseUrl, repo, workspace, taskNameOrPattern, timeout, { token });
|
|
59
|
+
console.log(`Timeout ${formatMinutes(minutes)} set for task '${taskNameOrPattern}'`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
exitError(formatError(err));
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
async get(url, taskName) {
|
|
67
|
+
try {
|
|
68
|
+
const { baseUrl, repo, workspace } = parseWorkspaceUrl(url);
|
|
69
|
+
const token = await getValidToken(baseUrl);
|
|
70
|
+
const timeout = await getTimeout(baseUrl, repo, workspace, taskName, { token });
|
|
71
|
+
console.log(`Timeout for '${taskName}': ${formatMinutes(timeout.minutes)}`);
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
exitError(formatError(err));
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
async list(url) {
|
|
78
|
+
try {
|
|
79
|
+
const { baseUrl, repo, workspace } = parseWorkspaceUrl(url);
|
|
80
|
+
const token = await getValidToken(baseUrl);
|
|
81
|
+
const configs = await listTimeout(baseUrl, repo, workspace, { token });
|
|
82
|
+
const entries = [...configs.entries()];
|
|
83
|
+
if (entries.length === 0) {
|
|
84
|
+
console.log(`No timeout configs for ${repo}/${workspace} (all tasks use defaults)`);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
console.log(`Timeout configs for ${repo}/${workspace}:`);
|
|
88
|
+
for (const [taskName, timeout] of entries) {
|
|
89
|
+
console.log(` ${taskName.padEnd(32)} ${formatMinutes(timeout.minutes)}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
exitError(formatError(err));
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
async remove(url, taskNameOrPattern, options) {
|
|
97
|
+
try {
|
|
98
|
+
const { baseUrl, repo, workspace } = parseWorkspaceUrl(url);
|
|
99
|
+
const token = await getValidToken(baseUrl);
|
|
100
|
+
if (options.regex) {
|
|
101
|
+
const tasks = await taskList(baseUrl, repo, workspace, { token });
|
|
102
|
+
const regex = new RegExp(taskNameOrPattern);
|
|
103
|
+
const matched = tasks.filter(t => regex.test(t.name)).map(t => t.name);
|
|
104
|
+
if (matched.length === 0) {
|
|
105
|
+
exitError(`No tasks matched pattern: ${taskNameOrPattern}`);
|
|
106
|
+
}
|
|
107
|
+
console.log(`Matched ${matched.length} tasks: ${matched.join(', ')}`);
|
|
108
|
+
if (!await confirm(`Remove timeout config for ${matched.length} tasks?`))
|
|
109
|
+
return;
|
|
110
|
+
// One request for them all
|
|
111
|
+
await removeTimeoutBatch(baseUrl, repo, workspace, matched, { token });
|
|
112
|
+
console.log(`Timeout config removed for ${matched.length} tasks`);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
await removeTimeout(baseUrl, repo, workspace, taskNameOrPattern, { token });
|
|
116
|
+
console.log(`Timeout config removed for task '${taskNameOrPattern}'`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
exitError(formatError(err));
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
//# sourceMappingURL=timeout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeout.js","sourceRoot":"","sources":["../../../src/commands/timeout.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
export declare const settingsCommand: {
|
|
6
|
+
get(url: string, options: {
|
|
7
|
+
output?: string;
|
|
8
|
+
}): Promise<void>;
|
|
9
|
+
set(url: string, options: {
|
|
10
|
+
input?: string;
|
|
11
|
+
data?: string;
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
remove(url: string): Promise<void>;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=user-settings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-settings.d.ts","sourceRoot":"","sources":["../../../src/commands/user-settings.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAcH,eAAO,MAAM,eAAe;aACX,MAAM,WAAW;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;aAwBpD,MAAM,WAAW;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;gBA4B/D,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAWzC,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* User settings management commands — get, set, remove.
|
|
7
|
+
*/
|
|
8
|
+
import { getUserSettings, putUserSettings, deleteUserSettings, } from '@elaraai/e3-cloud-client';
|
|
9
|
+
import { getValidToken } from '../credentials.js';
|
|
10
|
+
import { parseWorkspaceUrl, formatError, exitError } from '../utils.js';
|
|
11
|
+
export const settingsCommand = {
|
|
12
|
+
async get(url, options) {
|
|
13
|
+
try {
|
|
14
|
+
const { baseUrl, repo, workspace } = parseWorkspaceUrl(url);
|
|
15
|
+
const token = await getValidToken(baseUrl);
|
|
16
|
+
const data = await getUserSettings(baseUrl, repo, workspace, { token });
|
|
17
|
+
if (!data) {
|
|
18
|
+
console.log('No settings stored.');
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (options.output) {
|
|
22
|
+
const fs = await import('node:fs');
|
|
23
|
+
fs.writeFileSync(options.output, data);
|
|
24
|
+
console.log(`Settings written to ${options.output} (${data.byteLength} bytes)`);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
// Write raw bytes to stdout
|
|
28
|
+
process.stdout.write(data);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
exitError(formatError(err));
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
async set(url, options) {
|
|
36
|
+
try {
|
|
37
|
+
const { baseUrl, repo, workspace } = parseWorkspaceUrl(url);
|
|
38
|
+
const token = await getValidToken(baseUrl);
|
|
39
|
+
let payload;
|
|
40
|
+
if (options.input) {
|
|
41
|
+
const fs = await import('node:fs');
|
|
42
|
+
payload = fs.readFileSync(options.input);
|
|
43
|
+
}
|
|
44
|
+
else if (options.data) {
|
|
45
|
+
payload = new TextEncoder().encode(options.data);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
// Read from stdin
|
|
49
|
+
const chunks = [];
|
|
50
|
+
for await (const chunk of process.stdin) {
|
|
51
|
+
chunks.push(chunk);
|
|
52
|
+
}
|
|
53
|
+
payload = new Uint8Array(Buffer.concat(chunks));
|
|
54
|
+
}
|
|
55
|
+
await putUserSettings(baseUrl, repo, workspace, payload, { token });
|
|
56
|
+
console.log(`Settings saved (${payload.byteLength} bytes)`);
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
exitError(formatError(err));
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
async remove(url) {
|
|
63
|
+
try {
|
|
64
|
+
const { baseUrl, repo, workspace } = parseWorkspaceUrl(url);
|
|
65
|
+
const token = await getValidToken(baseUrl);
|
|
66
|
+
await deleteUserSettings(baseUrl, repo, workspace, { token });
|
|
67
|
+
console.log('Settings removed.');
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
exitError(formatError(err));
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=user-settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-settings.js","sourceRoot":"","sources":["../../../src/commands/user-settings.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import type { RepoRole } from '@elaraai/e3-cloud-types';
|
|
6
|
+
/** A role in words: owner; or user and its business roles. */
|
|
7
|
+
export declare function roleWords(role: RepoRole): string;
|
|
8
|
+
export declare const userCommand: {
|
|
9
|
+
/** e3-cloud user list-all <serverUrl> — merged deployment user listing (admin) */
|
|
10
|
+
listAll(serverUrl: string): Promise<void>;
|
|
11
|
+
/** e3-cloud user disable <serverUrl> <emailOrSub> — block platform sign-in (admin) */
|
|
12
|
+
disable(serverUrl: string, emailOrSub: string): Promise<void>;
|
|
13
|
+
/** e3-cloud user enable <serverUrl> <emailOrSub> — restore platform sign-in (admin) */
|
|
14
|
+
enable(serverUrl: string, emailOrSub: string): Promise<void>;
|
|
15
|
+
/** e3-cloud user invitations <serverUrl> — list invitations (admin) */
|
|
16
|
+
invitations(serverUrl: string): Promise<void>;
|
|
17
|
+
/** e3-cloud user uninvite <serverUrl> <email> — revoke a pending invitation (admin) */
|
|
18
|
+
uninvite(serverUrl: string, email: string): Promise<void>;
|
|
19
|
+
list(url: string): Promise<void>;
|
|
20
|
+
add(url: string, email: string, options: {
|
|
21
|
+
role: string;
|
|
22
|
+
roles?: string;
|
|
23
|
+
}): Promise<void>;
|
|
24
|
+
remove(url: string, email: string): Promise<void>;
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=user.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../../src/commands/user.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAmBxD,8DAA8D;AAC9D,wBAAgB,SAAS,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAEhD;AAED,eAAO,MAAM,WAAW;IACtB,kFAAkF;uBACzD,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA4B/C,sFAAsF;uBAC7D,MAAM,cAAc,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWnE,uFAAuF;sBAC/D,MAAM,cAAc,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYlE,uEAAuE;2BAC1C,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBnD,uFAAuF;wBAC7D,MAAM,SAAS,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;cAU/C,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;aAmCvB,MAAM,SAAS,MAAM,WAAW;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;gBA+B7E,MAAM,SAAS,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CA0BxD,CAAC"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* User management commands - list, add, remove users from repositories.
|
|
7
|
+
*/
|
|
8
|
+
import { repoUsers, addUser, removeUser, repoInvitations, revokeRepoInvitation } from '@elaraai/e3-cloud-client';
|
|
9
|
+
import { listInvitations, revokeInvitation, isInvitedSentinel } from '@elaraai/e3-cloud-client';
|
|
10
|
+
import { listAdminUsers, lookupPeople, disableUser, enableUser } from '@elaraai/e3-cloud-client';
|
|
11
|
+
import { variant } from '@elaraai/east';
|
|
12
|
+
import { getValidToken } from '../credentials.js';
|
|
13
|
+
import { parseRepoUrl, formatError, exitError } from '../utils.js';
|
|
14
|
+
/**
|
|
15
|
+
* The directory account an email-or-sub argument names: a lookup of the one
|
|
16
|
+
* person, never the directory listed.
|
|
17
|
+
*/
|
|
18
|
+
async function resolvePerson(serverUrl, emailOrSub, token) {
|
|
19
|
+
const byEmail = emailOrSub.includes('@');
|
|
20
|
+
const found = await lookupPeople(serverUrl, byEmail ? { emails: [emailOrSub] } : { subs: [emailOrSub] }, { token });
|
|
21
|
+
const matches = found.filter((p) => (byEmail ? p.email.toLowerCase() === emailOrSub.toLowerCase() : p.sub === emailOrSub));
|
|
22
|
+
if (matches.length === 0) {
|
|
23
|
+
exitError(`No directory account matches '${emailOrSub}'${byEmail ? ` (someone invited who has not signed in yet has none: 'user uninvite' revokes an invitation)` : ''}`);
|
|
24
|
+
}
|
|
25
|
+
if (matches.length > 1)
|
|
26
|
+
exitError(`Several accounts hold ${emailOrSub}: name one by its sub (${matches.map((p) => p.sub).join(', ')})`);
|
|
27
|
+
return matches[0];
|
|
28
|
+
}
|
|
29
|
+
/** A role in words: owner; or user and its business roles. */
|
|
30
|
+
export function roleWords(role) {
|
|
31
|
+
return role.type === 'owner' ? 'owner' : role.value.roles.length === 0 ? 'user (no roles)' : `user: ${role.value.roles.join(', ')}`;
|
|
32
|
+
}
|
|
33
|
+
export const userCommand = {
|
|
34
|
+
/** e3-cloud user list-all <serverUrl> — merged deployment user listing (admin) */
|
|
35
|
+
async listAll(serverUrl) {
|
|
36
|
+
try {
|
|
37
|
+
const token = await getValidToken(serverUrl);
|
|
38
|
+
const users = await listAdminUsers(serverUrl, { token });
|
|
39
|
+
if (users.length === 0) {
|
|
40
|
+
console.log('No users.');
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
console.log('STATUS'.padEnd(10) + 'EMAIL'.padEnd(36) + 'REPOS'.padEnd(30) + 'LAST SEEN'.padEnd(21) + 'ONBOARDING');
|
|
44
|
+
for (const user of users) {
|
|
45
|
+
const repos = user.memberships.map((m) => `${m.repo}:${roleWords(m.role)}`).join(', ');
|
|
46
|
+
const lastSeen = user.lastSeenAt.type === 'some' ? user.lastSeenAt.value.substring(0, 19) : '-';
|
|
47
|
+
const entra = user.invitation.type === 'some' && user.invitation.value.entra.type === 'some'
|
|
48
|
+
? user.invitation.value.entra.value.status.type
|
|
49
|
+
: '';
|
|
50
|
+
console.log(user.status.type.padEnd(10)
|
|
51
|
+
+ user.email.padEnd(36)
|
|
52
|
+
+ (repos || '-').padEnd(30)
|
|
53
|
+
+ lastSeen.padEnd(21)
|
|
54
|
+
+ entra);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
exitError(formatError(err));
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
/** e3-cloud user disable <serverUrl> <emailOrSub> — block platform sign-in (admin) */
|
|
62
|
+
async disable(serverUrl, emailOrSub) {
|
|
63
|
+
try {
|
|
64
|
+
const token = await getValidToken(serverUrl);
|
|
65
|
+
const person = await resolvePerson(serverUrl, emailOrSub, token);
|
|
66
|
+
await disableUser(serverUrl, person.sub, { token });
|
|
67
|
+
console.log(`Disabled ${person.email} — platform sign-in blocked (their identity-provider account is unaffected)`);
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
exitError(formatError(err));
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
/** e3-cloud user enable <serverUrl> <emailOrSub> — restore platform sign-in (admin) */
|
|
74
|
+
async enable(serverUrl, emailOrSub) {
|
|
75
|
+
try {
|
|
76
|
+
const token = await getValidToken(serverUrl);
|
|
77
|
+
const person = await resolvePerson(serverUrl, emailOrSub, token);
|
|
78
|
+
await enableUser(serverUrl, person.sub, { token });
|
|
79
|
+
console.log(`Enabled ${person.email}`);
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
exitError(formatError(err));
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
/** e3-cloud user invitations <serverUrl> — list invitations (admin) */
|
|
86
|
+
async invitations(serverUrl) {
|
|
87
|
+
try {
|
|
88
|
+
const token = await getValidToken(serverUrl);
|
|
89
|
+
const invitations = await listInvitations(serverUrl, { token });
|
|
90
|
+
if (invitations.length === 0) {
|
|
91
|
+
console.log('No invitations.');
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
for (const inv of invitations) {
|
|
95
|
+
const grants = inv.grants.map((g) => `${g.repo}:${roleWords(g.role)}`).join(', ');
|
|
96
|
+
const entra = inv.entra.type === 'some'
|
|
97
|
+
? ` onboarding=${inv.entra.value.status.type}${inv.entra.value.detail.type === 'some' ? ` (${inv.entra.value.detail.value})` : ''}`
|
|
98
|
+
: '';
|
|
99
|
+
console.log(`${inv.status.type.padEnd(8)} ${inv.email} [${grants}] invited ${inv.invitedAt} expires ${inv.expiresAt}${entra}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
exitError(formatError(err));
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
/** e3-cloud user uninvite <serverUrl> <email> — revoke a pending invitation (admin) */
|
|
107
|
+
async uninvite(serverUrl, email) {
|
|
108
|
+
try {
|
|
109
|
+
const token = await getValidToken(serverUrl);
|
|
110
|
+
await revokeInvitation(serverUrl, email, { token });
|
|
111
|
+
console.log(`Revoked invitation for ${email}`);
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
exitError(formatError(err));
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
async list(url) {
|
|
118
|
+
try {
|
|
119
|
+
const { baseUrl, repo } = parseRepoUrl(url);
|
|
120
|
+
const token = await getValidToken(baseUrl);
|
|
121
|
+
// The people, and those added who have not signed in yet
|
|
122
|
+
const [users, invited] = await Promise.all([repoUsers(baseUrl, repo, { token }), repoInvitations(baseUrl, repo, { token })]);
|
|
123
|
+
// Table header
|
|
124
|
+
console.log('USER ID'.padEnd(20) + 'EMAIL'.padEnd(30) + 'ROLE'.padEnd(32) + 'ADDED');
|
|
125
|
+
// User rows
|
|
126
|
+
for (const user of users) {
|
|
127
|
+
const row = [
|
|
128
|
+
user.userId.substring(0, 18).padEnd(20),
|
|
129
|
+
user.email.padEnd(30),
|
|
130
|
+
roleWords(user.role).padEnd(32),
|
|
131
|
+
user.addedAt.substring(0, 19),
|
|
132
|
+
].join('');
|
|
133
|
+
console.log(row);
|
|
134
|
+
}
|
|
135
|
+
for (const invitation of invited) {
|
|
136
|
+
const row = [
|
|
137
|
+
'(not signed in)'.padEnd(20),
|
|
138
|
+
invitation.email.padEnd(30),
|
|
139
|
+
roleWords(invitation.role).padEnd(32),
|
|
140
|
+
invitation.invitedAt.substring(0, 19),
|
|
141
|
+
].join('');
|
|
142
|
+
console.log(row);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
exitError(formatError(err));
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
async add(url, email, options) {
|
|
150
|
+
try {
|
|
151
|
+
const { baseUrl, repo } = parseRepoUrl(url);
|
|
152
|
+
const token = await getValidToken(baseUrl);
|
|
153
|
+
// An owner, or a user holding business roles by name: --roles
|
|
154
|
+
// 'Rostering,Finance', the built-in 'All apps' among them; none for a
|
|
155
|
+
// user given roles later
|
|
156
|
+
let role;
|
|
157
|
+
if (options.role === 'owner') {
|
|
158
|
+
if (options.roles !== undefined)
|
|
159
|
+
exitError('An owner holds no business roles: --roles is for --role user.');
|
|
160
|
+
role = variant('owner', null);
|
|
161
|
+
}
|
|
162
|
+
else if (options.role === 'user') {
|
|
163
|
+
const roles = (options.roles ?? '').split(',').map((name) => name.trim()).filter((name) => name !== '');
|
|
164
|
+
role = variant('user', { roles });
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
exitError(`Invalid role: ${options.role}. Use 'owner', or 'user' with --roles.`);
|
|
168
|
+
}
|
|
169
|
+
const user = await addUser(baseUrl, repo, { email, role }, { token });
|
|
170
|
+
if (isInvitedSentinel(user.userId)) {
|
|
171
|
+
console.log(`Invited ${user.email} as ${roleWords(user.role)} — access activates automatically on their first login`);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
console.log(`Added ${user.email} as ${roleWords(user.role)}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
catch (err) {
|
|
178
|
+
exitError(formatError(err));
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
async remove(url, email) {
|
|
182
|
+
try {
|
|
183
|
+
const { baseUrl, repo } = parseRepoUrl(url);
|
|
184
|
+
const token = await getValidToken(baseUrl);
|
|
185
|
+
// First, find the user by email
|
|
186
|
+
const users = await repoUsers(baseUrl, repo, { token });
|
|
187
|
+
const user = users.find((u) => u.email.toLowerCase() === email.toLowerCase());
|
|
188
|
+
if (!user) {
|
|
189
|
+
// Someone added who has not signed in yet: their invitation's grant goes
|
|
190
|
+
const invited = (await repoInvitations(baseUrl, repo, { token })).find((i) => i.email === email.toLowerCase());
|
|
191
|
+
if (invited === undefined)
|
|
192
|
+
exitError(`User ${email} not found in repository`);
|
|
193
|
+
await revokeRepoInvitation(baseUrl, repo, email, { token });
|
|
194
|
+
console.log(`Revoked ${email}'s invitation: no access at their first sign-in`);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
// Remove by userId
|
|
198
|
+
await removeUser(baseUrl, repo, user.userId, { token });
|
|
199
|
+
console.log(`Removed ${email}`);
|
|
200
|
+
}
|
|
201
|
+
catch (err) {
|
|
202
|
+
exitError(formatError(err));
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
//# sourceMappingURL=user.js.map
|