@uic-coe-connect/cli 0.3.1 → 0.6.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/dist/commands/apps.js +3 -1
- package/dist/commands/logs.js +2 -2
- package/dist/commands/pipelines.js +11 -2
- package/dist/commands/vms.d.ts +1 -0
- package/dist/commands/vms.js +29 -0
- package/dist/index.js +2 -2
- package/dist/types.d.ts +13 -24
- package/package.json +2 -2
package/dist/commands/apps.js
CHANGED
|
@@ -34,9 +34,10 @@ export function registerAppCommands() {
|
|
|
34
34
|
table(apps.map((a) => ({
|
|
35
35
|
id: a.id,
|
|
36
36
|
name: a.name,
|
|
37
|
+
vm: a.vmId ?? "—",
|
|
37
38
|
url: a.url,
|
|
38
39
|
pipelines: String(a.pipelines?.length ?? 0),
|
|
39
|
-
})), ["id", "name", "url", "pipelines"]);
|
|
40
|
+
})), ["id", "name", "vm", "url", "pipelines"]);
|
|
40
41
|
});
|
|
41
42
|
},
|
|
42
43
|
}, {
|
|
@@ -49,6 +50,7 @@ export function registerAppCommands() {
|
|
|
49
50
|
details([
|
|
50
51
|
["Id", app.id],
|
|
51
52
|
["Name", app.name],
|
|
53
|
+
["VM", app.vmId ?? "—"],
|
|
52
54
|
["URL", app.url],
|
|
53
55
|
["Repo", app.repo ?? "—"],
|
|
54
56
|
["Branch", app.branch ?? "—"],
|
package/dist/commands/logs.js
CHANGED
|
@@ -46,9 +46,9 @@ export function registerLogCommands() {
|
|
|
46
46
|
}
|
|
47
47
|
};
|
|
48
48
|
for (const block of first.logs) {
|
|
49
|
-
info(`── ${block.process} (${block.status}
|
|
49
|
+
info(`── ${block.process} (${block.status}${block.restarts === undefined ? "" : `, ${block.restarts} restarts`}) · ${stream === "out" ? "stdout" : "stderr"} ──`);
|
|
50
50
|
if (block.lines.length === 0) {
|
|
51
|
-
info(" (empty)");
|
|
51
|
+
info(block.error ? ` (${block.error})` : " (empty)");
|
|
52
52
|
}
|
|
53
53
|
else {
|
|
54
54
|
render(block, block.lines);
|
|
@@ -24,6 +24,13 @@ function parseStep(token) {
|
|
|
24
24
|
return { type: "chown" };
|
|
25
25
|
case "env":
|
|
26
26
|
return { type: "env", subdir: arg || subdir || undefined };
|
|
27
|
+
case "docker": {
|
|
28
|
+
const action = (arg || "up");
|
|
29
|
+
if (!["up", "restart", "build"].includes(action)) {
|
|
30
|
+
throw new CliError(`docker step action must be up, restart or build: got "${arg}"`, 6);
|
|
31
|
+
}
|
|
32
|
+
return { type: "docker", action, subdir: subdir || undefined };
|
|
33
|
+
}
|
|
27
34
|
case "npm":
|
|
28
35
|
if (!arg)
|
|
29
36
|
throw new CliError(`npm step needs a script: npm:ci or npm:build@subdir`, 6);
|
|
@@ -35,7 +42,7 @@ function parseStep(token) {
|
|
|
35
42
|
throw new CliError(`pm2 step needs an action: pm2:restart@process-name`, 6);
|
|
36
43
|
return { type: "pm2", action: arg, process: subdir || undefined };
|
|
37
44
|
default:
|
|
38
|
-
throw new CliError(`Unknown step "${token}".`, 6, "Valid: pull, scan, env[:subdir], chown, npm:<script>[@subdir], migrate[:subdir], pm2:<action>[@process]");
|
|
45
|
+
throw new CliError(`Unknown step "${token}".`, 6, "Valid: pull, scan, env[:subdir], chown, npm:<script>[@subdir], migrate[:subdir], docker[:<up|restart|build>][@subdir], pm2:<action>[@process]");
|
|
39
46
|
}
|
|
40
47
|
}
|
|
41
48
|
function describeStep(step) {
|
|
@@ -46,6 +53,8 @@ function describeStep(step) {
|
|
|
46
53
|
return `migrate${step.subdir ? ` (${step.subdir})` : ""}`;
|
|
47
54
|
case "env":
|
|
48
55
|
return `write .env${step.subdir ? ` (${step.subdir})` : ""}`;
|
|
56
|
+
case "docker":
|
|
57
|
+
return `docker compose ${step.action ?? "up"}${step.subdir ? ` (${step.subdir})` : ""}`;
|
|
49
58
|
case "pm2":
|
|
50
59
|
return `pm2 ${step.action}${step.process ? ` ${step.process}` : ""}`;
|
|
51
60
|
default:
|
|
@@ -118,7 +127,7 @@ export function registerPipelineCommands() {
|
|
|
118
127
|
summary: "Create a pipeline from a step list",
|
|
119
128
|
usage: 'pipelines create <app> --name "Full deploy" <step>... | --steps-file <f.json>',
|
|
120
129
|
details: [
|
|
121
|
-
"Steps: pull, scan, env[:subdir], chown, npm:<script>[@subdir], migrate[:subdir], pm2:<action>[@process]",
|
|
130
|
+
"Steps: pull, scan, env[:subdir], chown, npm:<script>[@subdir], migrate[:subdir], docker[:<up|restart|build>][@subdir], pm2:<action>[@process]",
|
|
122
131
|
'Example: coe pipelines create myapp --name "Full" pull scan npm:ci@backend pm2:restart@myapp-api',
|
|
123
132
|
],
|
|
124
133
|
async run({ args, client }) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function registerVmCommands(): void;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { emit, info, table } from "../output.js";
|
|
2
|
+
import { register } from "../registry.js";
|
|
3
|
+
export function registerVmCommands() {
|
|
4
|
+
register({
|
|
5
|
+
name: "vms list",
|
|
6
|
+
summary: "The VMs this COEConnect knows about, and which it can act on",
|
|
7
|
+
usage: "vms list",
|
|
8
|
+
details: [
|
|
9
|
+
"An app runs on exactly one VM; deploys, logs and env all act there.",
|
|
10
|
+
"`managed` means this COEConnect instance may act on that VM — the dev",
|
|
11
|
+
"deployment manages only itself, so a prod app shows managed=no there.",
|
|
12
|
+
],
|
|
13
|
+
async run({ client }) {
|
|
14
|
+
const result = await client().request("GET", "/vms");
|
|
15
|
+
emit(result, () => {
|
|
16
|
+
table(result.vms.map((v) => ({
|
|
17
|
+
id: v.id,
|
|
18
|
+
hostname: v.hostname,
|
|
19
|
+
label: v.label ?? "—",
|
|
20
|
+
here: v.local ? "yes" : "",
|
|
21
|
+
managed: v.managed ? "yes" : "no",
|
|
22
|
+
agent: v.tokenPrefix ? `${v.tokenPrefix}…` : "no token",
|
|
23
|
+
})), ["id", "hostname", "label", "here", "managed", "agent"]);
|
|
24
|
+
info("");
|
|
25
|
+
info(`This server runs on ${result.localVmId}; it manages ${result.managed.join(", ")}.`);
|
|
26
|
+
});
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { registerEnvCommands } from "./commands/env.js";
|
|
|
8
8
|
import { registerLogCommands } from "./commands/logs.js";
|
|
9
9
|
import { registerPipelineCommands } from "./commands/pipelines.js";
|
|
10
10
|
import { registerResourceCommands } from "./commands/resources.js";
|
|
11
|
-
import {
|
|
11
|
+
import { registerVmCommands } from "./commands/vms.js";
|
|
12
12
|
import { info, setJsonMode } from "./output.js";
|
|
13
13
|
import { allCommands, findCommand, register } from "./registry.js";
|
|
14
14
|
registerAuthCommands();
|
|
@@ -18,8 +18,8 @@ registerDeployCommands();
|
|
|
18
18
|
registerAccessCommands();
|
|
19
19
|
registerEnvCommands();
|
|
20
20
|
registerResourceCommands();
|
|
21
|
-
registerRoleCommands();
|
|
22
21
|
registerLogCommands();
|
|
22
|
+
registerVmCommands();
|
|
23
23
|
function parseArgs(argv) {
|
|
24
24
|
const positional = [];
|
|
25
25
|
const flags = {};
|
package/dist/types.d.ts
CHANGED
|
@@ -18,6 +18,10 @@ export type DeployStep = {
|
|
|
18
18
|
} | {
|
|
19
19
|
type: "migrate";
|
|
20
20
|
subdir?: string;
|
|
21
|
+
} | {
|
|
22
|
+
type: "docker";
|
|
23
|
+
subdir?: string;
|
|
24
|
+
action?: "up" | "restart" | "build";
|
|
21
25
|
} | {
|
|
22
26
|
type: "chown";
|
|
23
27
|
} | {
|
|
@@ -33,50 +37,36 @@ export interface NamedPipeline {
|
|
|
33
37
|
name: string;
|
|
34
38
|
config: DeployConfig;
|
|
35
39
|
}
|
|
36
|
-
export type
|
|
37
|
-
export interface
|
|
40
|
+
export type AccessOperator = "equals" | "contains" | "startsWith" | "regex";
|
|
41
|
+
export interface AccessCondition {
|
|
38
42
|
attribute: string;
|
|
39
|
-
operator:
|
|
43
|
+
operator: AccessOperator;
|
|
40
44
|
value: string;
|
|
41
45
|
}
|
|
42
46
|
/**
|
|
43
|
-
* A rule matches when ALL its conditions hold;
|
|
47
|
+
* A rule matches when ALL its conditions hold; access is granted when ANY rule
|
|
44
48
|
* matches. The property is `all`, not `conditions` — the server reads `.all`
|
|
45
49
|
* and silently drops rules shaped any other way.
|
|
46
50
|
*/
|
|
47
|
-
export interface
|
|
48
|
-
all:
|
|
49
|
-
}
|
|
50
|
-
export interface AppRole {
|
|
51
|
-
key: string;
|
|
52
|
-
label: string;
|
|
53
|
-
description?: string;
|
|
54
|
-
members: string[];
|
|
55
|
-
rules: RoleRule[];
|
|
51
|
+
export interface AccessRule {
|
|
52
|
+
all: AccessCondition[];
|
|
56
53
|
}
|
|
57
54
|
export interface StaffAccess {
|
|
58
55
|
everyone: boolean;
|
|
59
56
|
members: string[];
|
|
60
|
-
rules:
|
|
57
|
+
rules: AccessRule[];
|
|
61
58
|
exceptions: string[];
|
|
62
59
|
}
|
|
63
60
|
export interface AppAccess {
|
|
64
61
|
devTeam: string[];
|
|
65
62
|
staff: StaffAccess;
|
|
66
63
|
}
|
|
67
|
-
/** An app's role-resolve token, minus anything that could reconstruct it. */
|
|
68
|
-
export interface RolesTokenInfo {
|
|
69
|
-
appId: string;
|
|
70
|
-
/** Leading characters only — enough to recognise which token is deployed. */
|
|
71
|
-
prefix: string;
|
|
72
|
-
createdAt: string;
|
|
73
|
-
createdBy: string;
|
|
74
|
-
lastUsedAt?: string;
|
|
75
|
-
}
|
|
76
64
|
export interface RegisteredApp {
|
|
77
65
|
id: string;
|
|
78
66
|
name: string;
|
|
79
67
|
url: string;
|
|
68
|
+
/** Which VM hosts this app — deploys, logs and env all act on that machine. */
|
|
69
|
+
vmId: string;
|
|
80
70
|
repo?: string;
|
|
81
71
|
branch?: string;
|
|
82
72
|
/**
|
|
@@ -86,7 +76,6 @@ export interface RegisteredApp {
|
|
|
86
76
|
*/
|
|
87
77
|
envKeys: string[];
|
|
88
78
|
pipelines?: NamedPipeline[];
|
|
89
|
-
roles?: AppRole[];
|
|
90
79
|
access?: AppAccess;
|
|
91
80
|
createdAt: string;
|
|
92
81
|
updatedAt: string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uic-coe-connect/cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "The coe CLI
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "The coe CLI — manage COEConnect apps (pipelines, deploys, access, env) from a terminal, with browser-approved auth. Designed to be driven by an AI agent.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"coe": "./dist/index.js"
|