@lizard-build/cli 0.1.0 → 0.3.30
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/.github/workflows/release.yml +90 -0
- package/AGENTS.md +113 -0
- package/README.md +41 -0
- package/dist/commands/add.js +318 -45
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/config.js +68 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/docs.d.ts +2 -0
- package/dist/commands/docs.js +13 -0
- package/dist/commands/docs.js.map +1 -0
- package/dist/commands/domain.d.ts +9 -0
- package/dist/commands/domain.js +195 -0
- package/dist/commands/domain.js.map +1 -0
- package/dist/commands/git.js +175 -36
- package/dist/commands/git.js.map +1 -1
- package/dist/commands/init.d.ts +24 -0
- package/dist/commands/init.js +128 -86
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/link.d.ts +7 -0
- package/dist/commands/link.js +104 -33
- package/dist/commands/link.js.map +1 -1
- package/dist/commands/login.js +4 -3
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logs.js +223 -30
- package/dist/commands/logs.js.map +1 -1
- package/dist/commands/open.js +3 -2
- package/dist/commands/open.js.map +1 -1
- package/dist/commands/port.d.ts +7 -0
- package/dist/commands/port.js +49 -0
- package/dist/commands/port.js.map +1 -0
- package/dist/commands/projects.js +36 -6
- package/dist/commands/projects.js.map +1 -1
- package/dist/commands/ps.js +32 -39
- package/dist/commands/ps.js.map +1 -1
- package/dist/commands/redeploy.js +48 -8
- package/dist/commands/redeploy.js.map +1 -1
- package/dist/commands/regions.js +2 -5
- package/dist/commands/regions.js.map +1 -1
- package/dist/commands/restart.js +84 -10
- package/dist/commands/restart.js.map +1 -1
- package/dist/commands/run.d.ts +9 -0
- package/dist/commands/run.js +61 -22
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/scale.d.ts +10 -0
- package/dist/commands/scale.js +166 -0
- package/dist/commands/scale.js.map +1 -0
- package/dist/commands/secrets.js +200 -89
- package/dist/commands/secrets.js.map +1 -1
- package/dist/commands/service-set.d.ts +49 -0
- package/dist/commands/service-set.js +552 -0
- package/dist/commands/service-set.js.map +1 -0
- package/dist/commands/service-show.d.ts +11 -0
- package/dist/commands/service-show.js +44 -0
- package/dist/commands/service-show.js.map +1 -0
- package/dist/commands/service.d.ts +8 -0
- package/dist/commands/service.js +262 -0
- package/dist/commands/service.js.map +1 -0
- package/dist/commands/skill.d.ts +2 -0
- package/dist/commands/skill.js +146 -0
- package/dist/commands/skill.js.map +1 -0
- package/dist/commands/ssh.d.ts +2 -0
- package/dist/commands/ssh.js +161 -0
- package/dist/commands/ssh.js.map +1 -0
- package/dist/commands/status.d.ts +7 -0
- package/dist/commands/status.js +49 -38
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/unlink.d.ts +5 -0
- package/dist/commands/unlink.js +18 -0
- package/dist/commands/unlink.js.map +1 -0
- package/dist/commands/up.d.ts +9 -0
- package/dist/commands/up.js +417 -0
- package/dist/commands/up.js.map +1 -0
- package/dist/commands/upgrade.d.ts +2 -0
- package/dist/commands/upgrade.js +79 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/commands/whoami.js +26 -6
- package/dist/commands/whoami.js.map +1 -1
- package/dist/commands/workspace.d.ts +8 -0
- package/dist/commands/workspace.js +36 -0
- package/dist/commands/workspace.js.map +1 -0
- package/dist/index.js +209 -82
- package/dist/index.js.map +1 -1
- package/dist/lib/api.d.ts +17 -2
- package/dist/lib/api.js +85 -51
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/auth.d.ts +3 -11
- package/dist/lib/auth.js +16 -36
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/config.d.ts +36 -15
- package/dist/lib/config.js +71 -58
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/format.d.ts +1 -0
- package/dist/lib/format.js +17 -4
- package/dist/lib/format.js.map +1 -1
- package/dist/lib/name.d.ts +11 -0
- package/dist/lib/name.js +26 -0
- package/dist/lib/name.js.map +1 -0
- package/dist/lib/picker.d.ts +32 -0
- package/dist/lib/picker.js +91 -0
- package/dist/lib/picker.js.map +1 -0
- package/dist/lib/resolve.d.ts +85 -0
- package/dist/lib/resolve.js +203 -0
- package/dist/lib/resolve.js.map +1 -0
- package/dist/lib/updater.d.ts +16 -0
- package/dist/lib/updater.js +102 -0
- package/dist/lib/updater.js.map +1 -0
- package/lizard-wrapper.sh +2 -0
- package/package.json +11 -3
- package/skill-data/core/SKILL.md +239 -0
- package/src/commands/add.ts +388 -56
- package/src/commands/config.ts +80 -0
- package/src/commands/docs.ts +15 -0
- package/src/commands/domain.ts +248 -0
- package/src/commands/git.ts +201 -40
- package/src/commands/init.ts +149 -100
- package/src/commands/link.ts +127 -35
- package/src/commands/login.ts +4 -3
- package/src/commands/logs.ts +283 -27
- package/src/commands/open.ts +3 -2
- package/src/commands/port.ts +57 -0
- package/src/commands/projects.ts +43 -6
- package/src/commands/ps.ts +39 -60
- package/src/commands/redeploy.ts +51 -10
- package/src/commands/regions.ts +2 -6
- package/src/commands/restart.ts +84 -10
- package/src/commands/run.ts +68 -24
- package/src/commands/scale.ts +216 -0
- package/src/commands/secrets.ts +277 -100
- package/src/commands/service-set.ts +669 -0
- package/src/commands/service-show.ts +52 -0
- package/src/commands/service.ts +298 -0
- package/src/commands/skill.ts +157 -0
- package/src/commands/ssh.ts +176 -0
- package/src/commands/status.ts +51 -46
- package/src/commands/unlink.ts +17 -0
- package/src/commands/up.ts +461 -0
- package/src/commands/upgrade.ts +87 -0
- package/src/commands/whoami.ts +34 -6
- package/src/commands/workspace.ts +44 -0
- package/src/index.ts +219 -85
- package/src/lib/api.ts +114 -51
- package/src/lib/auth.ts +22 -46
- package/src/lib/config.ts +100 -65
- package/src/lib/format.ts +18 -4
- package/src/lib/name.ts +27 -0
- package/src/lib/picker.ts +133 -0
- package/src/lib/resolve.ts +285 -0
- package/src/lib/updater.ts +106 -0
- package/test/cli.test.ts +491 -0
- package/test/fixtures/hello-app/Dockerfile +5 -0
- package/test/fixtures/hello-app/index.js +5 -0
- package/test/unit/api.test.ts +66 -0
- package/test/unit/config.test.ts +94 -0
- package/test/unit/init.test.ts +211 -0
- package/test/unit/json.test.ts +208 -0
- package/test/unit/picker.test.ts +161 -0
- package/test/unit/resolve.test.ts +124 -0
- package/test/unit/service-set.test.ts +355 -0
- package/vitest.config.ts +10 -0
- package/dist/commands/connect.d.ts +0 -2
- package/dist/commands/connect.js +0 -117
- package/dist/commands/connect.js.map +0 -1
- package/dist/commands/context.d.ts +0 -2
- package/dist/commands/context.js +0 -71
- package/dist/commands/context.js.map +0 -1
- package/dist/commands/deploy.d.ts +0 -2
- package/dist/commands/deploy.js +0 -120
- package/dist/commands/deploy.js.map +0 -1
- package/dist/commands/destroy.d.ts +0 -2
- package/dist/commands/destroy.js +0 -51
- package/dist/commands/destroy.js.map +0 -1
- package/dist/commands/update.d.ts +0 -2
- package/dist/commands/update.js +0 -41
- package/dist/commands/update.js.map +0 -1
- package/dist/commands/version.d.ts +0 -2
- package/dist/commands/version.js +0 -37
- package/dist/commands/version.js.map +0 -1
- package/src/commands/connect.ts +0 -145
- package/src/commands/context.ts +0 -93
- package/src/commands/deploy.ts +0 -153
- package/src/commands/destroy.ts +0 -51
- package/src/commands/update.ts +0 -44
- package/src/commands/version.ts +0 -37
package/src/commands/whoami.ts
CHANGED
|
@@ -1,27 +1,55 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { Command } from "commander";
|
|
3
3
|
import { api } from "../lib/api.js";
|
|
4
|
+
import { getProjectLink } from "../lib/config.js";
|
|
4
5
|
import { isJSONMode, printJSON } from "../lib/format.js";
|
|
5
6
|
|
|
6
7
|
export function registerWhoami(program: Command) {
|
|
7
8
|
program
|
|
8
9
|
.command("whoami")
|
|
9
|
-
.description("Show current user")
|
|
10
|
+
.description("Show current user, active workspace, and linked project")
|
|
10
11
|
.action(async () => {
|
|
11
12
|
const user = await api.get<{
|
|
12
13
|
id: string;
|
|
13
14
|
username: string;
|
|
14
15
|
avatarUrl?: string;
|
|
15
16
|
hasGithubApp?: boolean;
|
|
17
|
+
activeWorkspaceId?: string | null;
|
|
18
|
+
activeWorkspaceName?: string | null;
|
|
19
|
+
defaultWorkspaceId?: string | null;
|
|
16
20
|
}>("/api/auth/me");
|
|
17
21
|
|
|
22
|
+
const link = getProjectLink();
|
|
23
|
+
const project = link
|
|
24
|
+
? {
|
|
25
|
+
id: link.projectId,
|
|
26
|
+
name: link.projectName,
|
|
27
|
+
workspaceId: link.workspaceId ?? null,
|
|
28
|
+
workspaceName: link.workspaceName ?? null,
|
|
29
|
+
}
|
|
30
|
+
: null;
|
|
31
|
+
|
|
18
32
|
if (isJSONMode()) {
|
|
19
|
-
printJSON(user);
|
|
33
|
+
printJSON({ ...user, project });
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
console.log(chalk.bold(user.username));
|
|
38
|
+
if (user.hasGithubApp) {
|
|
39
|
+
console.log(chalk.dim("GitHub App: connected"));
|
|
40
|
+
}
|
|
41
|
+
if (user.activeWorkspaceName) {
|
|
42
|
+
console.log(chalk.dim("Workspace: ") + user.activeWorkspaceName);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (project) {
|
|
46
|
+
const label = project.name || project.id;
|
|
47
|
+
const wsTag = project.workspaceName ? chalk.dim(` (${project.workspaceName})`) : "";
|
|
48
|
+
console.log(chalk.dim("Project: ") + label + wsTag + chalk.dim(" (linked here)"));
|
|
20
49
|
} else {
|
|
21
|
-
console.log(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
50
|
+
console.log(
|
|
51
|
+
chalk.dim("Project: none — run `lizard init` in a project directory"),
|
|
52
|
+
);
|
|
25
53
|
}
|
|
26
54
|
});
|
|
27
55
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { fetchWorkspaces } from "../lib/picker.js";
|
|
4
|
+
import { isJSONMode, printJSON, table } from "../lib/format.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `lizard workspace` — workspace info.
|
|
8
|
+
*
|
|
9
|
+
* Member management (invite/remove/rename) intentionally lives in the
|
|
10
|
+
* dashboard, not here, to keep CLI surface narrow (Railway model).
|
|
11
|
+
*/
|
|
12
|
+
export function registerWorkspace(program: Command) {
|
|
13
|
+
const ws = program
|
|
14
|
+
.command("workspace")
|
|
15
|
+
.description("Workspace info");
|
|
16
|
+
|
|
17
|
+
ws.command("list")
|
|
18
|
+
.alias("ls")
|
|
19
|
+
.description("List workspaces you belong to")
|
|
20
|
+
.action(async () => {
|
|
21
|
+
const list = await fetchWorkspaces();
|
|
22
|
+
|
|
23
|
+
if (isJSONMode()) {
|
|
24
|
+
printJSON(list);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (list.length === 0) {
|
|
29
|
+
console.log("No workspaces. The backend should always return a personal workspace.");
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
table(
|
|
34
|
+
["Name", "Slug", "Role", "Projects", "Personal"],
|
|
35
|
+
list.map((w) => [
|
|
36
|
+
w.name,
|
|
37
|
+
w.slug,
|
|
38
|
+
w.role,
|
|
39
|
+
String(w.projectCount ?? 0),
|
|
40
|
+
w.isPersonal ? chalk.green("✓") : "",
|
|
41
|
+
]),
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,126 +1,252 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { Command } from "commander";
|
|
4
|
+
import chalk from "chalk";
|
|
4
5
|
import { setJSONMode, isJSONMode, error } from "./lib/format.js";
|
|
5
|
-
import {
|
|
6
|
-
import { setBaseURL, setAccessToken } from "./lib/api.js";
|
|
6
|
+
import { requireAuth, isLoggedIn } from "./lib/auth.js";
|
|
7
|
+
import { setBaseURL, setAccessToken, APIError } from "./lib/api.js";
|
|
8
|
+
import { checkForUpdateInBackground, CURRENT_VERSION } from "./lib/updater.js";
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
const BANNER = chalk.rgb(16, 185, 129)(
|
|
11
|
+
[
|
|
12
|
+
"╔═══════════════════════════════════════════════════╗",
|
|
13
|
+
"║ ║",
|
|
14
|
+
"║ ██╗ ██╗███████╗ █████╗ ██████╗ ██████╗ ║",
|
|
15
|
+
"║ ██║ ██║╚══███╔╝██╔══██╗██╔══██╗██╔══██╗ ║",
|
|
16
|
+
"║ ██║ ██║ ███╔╝ ███████║██████╔╝██║ ██║ ║",
|
|
17
|
+
"║ ██║ ██║ ███╔╝ ██╔══██║██╔══██╗██║ ██║ ║",
|
|
18
|
+
"║ ███████╗██║███████╗██║ ██║██║ ██║██████╔╝ ║",
|
|
19
|
+
"║ ╚══════╝╚═╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ║",
|
|
20
|
+
"║ ║",
|
|
21
|
+
"╚═══════════════════════════════════════════════════╝",
|
|
22
|
+
].join("\n"),
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
// Commands (alphabetical by command name)
|
|
26
|
+
import { registerAdd } from "./commands/add.js";
|
|
27
|
+
import { registerConfig } from "./commands/config.js";
|
|
28
|
+
import { registerDocs } from "./commands/docs.js";
|
|
29
|
+
import { registerDomain } from "./commands/domain.js";
|
|
30
|
+
import { registerGit } from "./commands/git.js";
|
|
12
31
|
import { registerInit } from "./commands/init.js";
|
|
13
32
|
import { registerLink } from "./commands/link.js";
|
|
33
|
+
import { registerLogin } from "./commands/login.js";
|
|
34
|
+
import { registerLogout } from "./commands/logout.js";
|
|
35
|
+
import { registerLogs } from "./commands/logs.js";
|
|
36
|
+
import { registerOpen } from "./commands/open.js";
|
|
37
|
+
import { registerPort } from "./commands/port.js";
|
|
14
38
|
import { registerProjects } from "./commands/projects.js";
|
|
15
|
-
import { registerDeploy } from "./commands/deploy.js";
|
|
16
39
|
import { registerPs } from "./commands/ps.js";
|
|
17
|
-
import { registerAdd } from "./commands/add.js";
|
|
18
|
-
import { registerDestroy } from "./commands/destroy.js";
|
|
19
|
-
import { registerRestart } from "./commands/restart.js";
|
|
20
40
|
import { registerRedeploy } from "./commands/redeploy.js";
|
|
21
|
-
import { registerLogs } from "./commands/logs.js";
|
|
22
|
-
import { registerSecrets } from "./commands/secrets.js";
|
|
23
41
|
import { registerRegions } from "./commands/regions.js";
|
|
24
|
-
import {
|
|
25
|
-
import { registerOpen } from "./commands/open.js";
|
|
42
|
+
import { registerRestart } from "./commands/restart.js";
|
|
26
43
|
import { registerRun } from "./commands/run.js";
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
44
|
+
import { registerScale } from "./commands/scale.js";
|
|
45
|
+
import { registerSecrets } from "./commands/secrets.js";
|
|
46
|
+
import { registerService } from "./commands/service.js";
|
|
47
|
+
import { registerSkill } from "./commands/skill.js";
|
|
48
|
+
import { registerSSH } from "./commands/ssh.js";
|
|
49
|
+
import { registerStatus } from "./commands/status.js";
|
|
50
|
+
import { registerUnlink } from "./commands/unlink.js";
|
|
51
|
+
import { registerUp } from "./commands/up.js";
|
|
52
|
+
import { registerUpgrade } from "./commands/upgrade.js";
|
|
53
|
+
import { registerWhoami } from "./commands/whoami.js";
|
|
54
|
+
import { registerWorkspace } from "./commands/workspace.js";
|
|
32
55
|
|
|
33
56
|
const program = new Command();
|
|
34
57
|
|
|
35
58
|
program
|
|
36
59
|
.name("lizard")
|
|
37
60
|
.description("Lizard CLI — deploy and manage apps on Lizard")
|
|
38
|
-
.version(
|
|
39
|
-
.
|
|
40
|
-
.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
.option("--
|
|
47
|
-
.option("--verbose", "Verbose output")
|
|
61
|
+
.version(CURRENT_VERSION)
|
|
62
|
+
.addHelpText("before", BANNER + "\n")
|
|
63
|
+
.configureHelp({
|
|
64
|
+
subcommandTerm: (cmd) => {
|
|
65
|
+
const alias = cmd.aliases()[0];
|
|
66
|
+
return alias ? `${cmd.name()}|${alias}` : cmd.name();
|
|
67
|
+
},
|
|
68
|
+
})
|
|
69
|
+
.option("--json", "Output in JSON format (combine with --help to dump machine-readable command schema for agents)")
|
|
48
70
|
.hook("preAction", async (thisCommand, actionCommand) => {
|
|
49
71
|
const opts = thisCommand.opts();
|
|
50
72
|
|
|
73
|
+
// Check for updates silently in background (shows notice after command)
|
|
74
|
+
if (actionCommand.name() !== "upgrade") {
|
|
75
|
+
checkForUpdateInBackground();
|
|
76
|
+
}
|
|
77
|
+
|
|
51
78
|
// JSON mode: explicit flag or non-TTY stdout
|
|
52
79
|
if (opts.json || !process.stdout.isTTY) {
|
|
53
80
|
setJSONMode(true);
|
|
54
81
|
}
|
|
55
82
|
|
|
56
|
-
// Token override
|
|
57
|
-
if (opts.token) {
|
|
58
|
-
setTokenOverride(opts.token);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
83
|
// API URL override
|
|
62
84
|
if (process.env.LIZARD_API_URL) {
|
|
63
85
|
setBaseURL(process.env.LIZARD_API_URL);
|
|
64
86
|
}
|
|
65
87
|
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
|
|
88
|
+
// Top-level commands that don't need auth. `status` prints the local link;
|
|
89
|
+
// the optional workspace backfill silently no-ops when not authed.
|
|
90
|
+
//
|
|
91
|
+
// Walk up to the top-level ancestor so subcommands inherit (`skill list`
|
|
92
|
+
// matches via `skill`). Leaf names like `git status` don't false-positive
|
|
93
|
+
// because we check the ancestor's name, not the action's.
|
|
94
|
+
const noAuth = new Set(["login", "logout", "upgrade", "help", "docs", "status", "skill"]);
|
|
95
|
+
let topLevel: Command = actionCommand;
|
|
96
|
+
while (topLevel.parent && topLevel.parent !== thisCommand) {
|
|
97
|
+
topLevel = topLevel.parent;
|
|
98
|
+
}
|
|
99
|
+
if (noAuth.has(topLevel.name())) return;
|
|
69
100
|
|
|
70
101
|
// Require auth — auto-triggers login flow if not logged in
|
|
71
102
|
const creds = await requireAuth();
|
|
72
103
|
setAccessToken(creds.accessToken);
|
|
73
104
|
});
|
|
74
105
|
|
|
75
|
-
// Register all commands
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
106
|
+
// Register all commands (alphabetical)
|
|
107
|
+
registerAdd(program);
|
|
108
|
+
registerConfig(program);
|
|
109
|
+
registerDocs(program);
|
|
110
|
+
registerDomain(program);
|
|
111
|
+
registerGit(program);
|
|
79
112
|
registerInit(program);
|
|
80
113
|
registerLink(program);
|
|
114
|
+
registerLogin(program);
|
|
115
|
+
registerLogout(program);
|
|
116
|
+
registerLogs(program);
|
|
117
|
+
registerOpen(program);
|
|
118
|
+
registerPort(program);
|
|
81
119
|
registerProjects(program);
|
|
82
|
-
registerDeploy(program);
|
|
83
120
|
registerPs(program);
|
|
84
|
-
registerAdd(program);
|
|
85
|
-
registerDestroy(program);
|
|
86
|
-
registerRestart(program);
|
|
87
121
|
registerRedeploy(program);
|
|
88
|
-
registerLogs(program);
|
|
89
|
-
registerSecrets(program);
|
|
90
122
|
registerRegions(program);
|
|
91
|
-
|
|
92
|
-
registerOpen(program);
|
|
123
|
+
registerRestart(program);
|
|
93
124
|
registerRun(program);
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
program
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
.action((shell: string) => {
|
|
106
|
-
// Commander doesn't have built-in completion like Cobra
|
|
107
|
-
// Point users to manual setup
|
|
108
|
-
console.log(`# Add to your .${shell}rc:`);
|
|
109
|
-
if (shell === "bash") {
|
|
110
|
-
console.log(`eval "$(lizard completion bash)"`);
|
|
111
|
-
} else if (shell === "zsh") {
|
|
112
|
-
console.log(`# lizard completion is not yet available for zsh`);
|
|
113
|
-
console.log(`# Coming soon`);
|
|
114
|
-
} else if (shell === "fish") {
|
|
115
|
-
console.log(`# lizard completion is not yet available for fish`);
|
|
116
|
-
console.log(`# Coming soon`);
|
|
117
|
-
}
|
|
118
|
-
});
|
|
125
|
+
registerScale(program);
|
|
126
|
+
registerSecrets(program);
|
|
127
|
+
registerService(program);
|
|
128
|
+
registerSkill(program);
|
|
129
|
+
registerSSH(program);
|
|
130
|
+
registerStatus(program);
|
|
131
|
+
registerUnlink(program);
|
|
132
|
+
registerUp(program);
|
|
133
|
+
registerUpgrade(program);
|
|
134
|
+
registerWhoami(program);
|
|
135
|
+
registerWorkspace(program);
|
|
119
136
|
|
|
120
137
|
// Error handling
|
|
121
138
|
program.exitOverride();
|
|
122
139
|
|
|
140
|
+
const EXIT_CODES: Record<string, string> = {
|
|
141
|
+
"0": "success",
|
|
142
|
+
"1": "generic error",
|
|
143
|
+
"2": "auth (401/403)",
|
|
144
|
+
"3": "not found (404)",
|
|
145
|
+
"4": "timeout (408/504)",
|
|
146
|
+
"5": "cancelled by user",
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
function isHelpJsonRequest(argv: string[]): boolean {
|
|
150
|
+
const hasHelp = argv.some((a) => a === "--help" || a === "-h");
|
|
151
|
+
const hasJson = argv.some((a) => a === "--json");
|
|
152
|
+
return hasHelp && hasJson;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function collectValueFlags(cmd: Command, acc: Set<string>) {
|
|
156
|
+
for (const opt of cmd.options as any[]) {
|
|
157
|
+
if (opt.required || opt.optional) {
|
|
158
|
+
if (opt.short) acc.add(opt.short);
|
|
159
|
+
if (opt.long) acc.add(opt.long);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
for (const sub of cmd.commands) collectValueFlags(sub, acc);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function findTargetCommand(argv: string[], root: Command): Command {
|
|
166
|
+
const valueFlags = new Set<string>();
|
|
167
|
+
collectValueFlags(root, valueFlags);
|
|
168
|
+
|
|
169
|
+
let cur: Command = root;
|
|
170
|
+
for (let i = 2; i < argv.length; i++) {
|
|
171
|
+
const tok = argv[i];
|
|
172
|
+
if (tok === "--help" || tok === "-h" || tok === "--json") continue;
|
|
173
|
+
if (tok.startsWith("-")) {
|
|
174
|
+
if (tok.includes("=")) continue;
|
|
175
|
+
if (valueFlags.has(tok) && i + 1 < argv.length) i++;
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const sub = cur.commands.find(
|
|
179
|
+
(c) => c.name() === tok || c.aliases().includes(tok),
|
|
180
|
+
);
|
|
181
|
+
if (!sub) break;
|
|
182
|
+
cur = sub;
|
|
183
|
+
}
|
|
184
|
+
return cur;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function dumpOption(o: any) {
|
|
188
|
+
return {
|
|
189
|
+
flags: o.flags,
|
|
190
|
+
long: o.long ?? null,
|
|
191
|
+
short: o.short ?? null,
|
|
192
|
+
description: o.description ?? "",
|
|
193
|
+
takesValue: Boolean(o.required || o.optional),
|
|
194
|
+
valueRequired: Boolean(o.required),
|
|
195
|
+
defaultValue: o.defaultValue ?? null,
|
|
196
|
+
choices: o.argChoices ?? null,
|
|
197
|
+
negate: Boolean(o.negate),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function dumpCommand(cmd: Command): any {
|
|
202
|
+
const args = ((cmd as any).registeredArguments ?? []).map((a: any) => ({
|
|
203
|
+
name: a.name(),
|
|
204
|
+
description: a.description ?? "",
|
|
205
|
+
required: Boolean(a.required),
|
|
206
|
+
variadic: Boolean(a.variadic),
|
|
207
|
+
defaultValue: a.defaultValue ?? null,
|
|
208
|
+
choices: a.argChoices ?? null,
|
|
209
|
+
}));
|
|
210
|
+
return {
|
|
211
|
+
name: cmd.name(),
|
|
212
|
+
aliases: cmd.aliases(),
|
|
213
|
+
description: cmd.description(),
|
|
214
|
+
usage: cmd.usage(),
|
|
215
|
+
arguments: args,
|
|
216
|
+
options: (cmd.options as any[])
|
|
217
|
+
.filter((o) => !o.hidden)
|
|
218
|
+
.map(dumpOption),
|
|
219
|
+
subcommands: cmd.commands
|
|
220
|
+
.filter((c: any) => !c._hidden)
|
|
221
|
+
.map(dumpCommand),
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
123
225
|
async function main() {
|
|
226
|
+
// Set JSON mode from argv *before* parseAsync so the catch block below
|
|
227
|
+
// honors --json even when commander rejects before our preAction hook
|
|
228
|
+
// fires (e.g. unknown command, malformed global flag). Non-TTY auto-mode
|
|
229
|
+
// stays in preAction — `lizard --help | less` shouldn't suddenly emit JSON.
|
|
230
|
+
if (process.argv.includes("--json")) {
|
|
231
|
+
setJSONMode(true);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (isHelpJsonRequest(process.argv)) {
|
|
235
|
+
const target = findTargetCommand(process.argv, program);
|
|
236
|
+
const isRoot = target === program;
|
|
237
|
+
const out = {
|
|
238
|
+
cli: "lizard",
|
|
239
|
+
version: CURRENT_VERSION,
|
|
240
|
+
command: dumpCommand(target),
|
|
241
|
+
globalOptions: isRoot
|
|
242
|
+
? []
|
|
243
|
+
: (program.options as any[]).filter((o) => !o.hidden).map(dumpOption),
|
|
244
|
+
exitCodes: EXIT_CODES,
|
|
245
|
+
};
|
|
246
|
+
process.stdout.write(JSON.stringify(out, null, 2) + "\n");
|
|
247
|
+
process.exit(0);
|
|
248
|
+
}
|
|
249
|
+
|
|
124
250
|
try {
|
|
125
251
|
await program.parseAsync(process.argv);
|
|
126
252
|
} catch (err: any) {
|
|
@@ -133,14 +259,19 @@ async function main() {
|
|
|
133
259
|
}
|
|
134
260
|
|
|
135
261
|
const msg = err.message || String(err);
|
|
262
|
+
const apiErr = err instanceof APIError ? err : undefined;
|
|
263
|
+
const status = apiErr?.status;
|
|
264
|
+
const code = apiErr?.code || err.code || "ERROR";
|
|
136
265
|
|
|
137
266
|
if (isJSONMode()) {
|
|
138
267
|
console.log(
|
|
139
268
|
JSON.stringify(
|
|
140
269
|
{
|
|
141
270
|
error: {
|
|
142
|
-
code
|
|
271
|
+
code,
|
|
272
|
+
status: status ?? null,
|
|
143
273
|
message: msg,
|
|
274
|
+
body: apiErr?.body ?? null,
|
|
144
275
|
},
|
|
145
276
|
},
|
|
146
277
|
null,
|
|
@@ -151,16 +282,19 @@ async function main() {
|
|
|
151
282
|
error(msg);
|
|
152
283
|
}
|
|
153
284
|
|
|
154
|
-
// Exit codes
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
285
|
+
// Exit codes derived from APIError.status (or tagged error codes), not message text
|
|
286
|
+
const isAuth = status === 401 || status === 403 || code === "NOT_AUTHENTICATED";
|
|
287
|
+
const isNotFound = status === 404;
|
|
288
|
+
const isTimeout =
|
|
289
|
+
status === 408 ||
|
|
290
|
+
status === 504 ||
|
|
291
|
+
err.name === "AbortError" ||
|
|
292
|
+
err.code === "ETIMEDOUT" ||
|
|
293
|
+
err.code === "UND_ERR_CONNECT_TIMEOUT";
|
|
294
|
+
|
|
295
|
+
if (isAuth) process.exit(2);
|
|
296
|
+
if (isNotFound) process.exit(3);
|
|
297
|
+
if (isTimeout) process.exit(4);
|
|
164
298
|
process.exit(1);
|
|
165
299
|
}
|
|
166
300
|
}
|