@studiometa/forge-cli 0.4.4 → 0.4.6
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/README.md +14 -0
- package/dist/cli.js +576 -34
- package/dist/cli.js.map +1 -1
- package/dist/commands/completion.d.ts.map +1 -1
- package/dist/commands/daemons/command.d.ts.map +1 -1
- package/dist/commands/daemons/handlers.d.ts +1 -0
- package/dist/commands/daemons/handlers.d.ts.map +1 -1
- package/dist/commands/daemons/help.d.ts.map +1 -1
- package/dist/commands/deployments/command.d.ts.map +1 -1
- package/dist/commands/deployments/handlers.d.ts +1 -0
- package/dist/commands/deployments/handlers.d.ts.map +1 -1
- package/dist/commands/deployments/help.d.ts.map +1 -1
- package/dist/commands/services/command.d.ts +2 -0
- package/dist/commands/services/command.d.ts.map +1 -0
- package/dist/commands/services/handlers.d.ts +10 -0
- package/dist/commands/services/handlers.d.ts.map +1 -0
- package/dist/commands/services/help.d.ts +2 -0
- package/dist/commands/services/help.d.ts.map +1 -0
- package/dist/commands/services/index.d.ts +3 -0
- package/dist/commands/services/index.d.ts.map +1 -0
- package/dist/commands/ssh/command.d.ts +9 -0
- package/dist/commands/ssh/command.d.ts.map +1 -0
- package/dist/commands/ssh/handlers.d.ts +16 -0
- package/dist/commands/ssh/handlers.d.ts.map +1 -0
- package/dist/commands/ssh/help.d.ts +2 -0
- package/dist/commands/ssh/help.d.ts.map +1 -0
- package/dist/commands/ssh/index.d.ts +3 -0
- package/dist/commands/ssh/index.d.ts.map +1 -0
- package/dist/commands/ssh/ssh-target.d.ts +36 -0
- package/dist/commands/ssh/ssh-target.d.ts.map +1 -0
- package/dist/{error-handler-ByMitiOr.js → error-handler-BA357jIr.js} +34 -3
- package/dist/error-handler-BA357jIr.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/output.d.ts +5 -4
- package/dist/output.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/error-handler-ByMitiOr.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"completion.d.ts","sourceRoot":"","sources":["../../src/commands/completion.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"completion.d.ts","sourceRoot":"","sources":["../../src/commands/completion.ts"],"names":[],"mappings":"AAAA;;GAEG;AAurBH,wBAAgB,kBAAkB,IAAI,IAAI,CA2CzC;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,CAAM,GACxD,IAAI,CAoEN"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../src/commands/daemons/command.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,oBAAoB,
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../src/commands/daemons/command.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,oBAAoB,6GAY/B,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CommandContext } from "../../context.ts";
|
|
2
2
|
export declare function daemonsList(ctx: CommandContext): Promise<void>;
|
|
3
3
|
export declare function daemonsGet(args: string[], ctx: CommandContext): Promise<void>;
|
|
4
|
+
export declare function daemonsLogs(args: string[], ctx: CommandContext): Promise<void>;
|
|
4
5
|
export declare function daemonsUpdate(args: string[], ctx: CommandContext): Promise<void>;
|
|
5
6
|
export declare function daemonsRestart(args: string[], ctx: CommandContext): Promise<void>;
|
|
6
7
|
//# sourceMappingURL=handlers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../../src/commands/daemons/handlers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../../src/commands/daemons/handlers.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAKvD,wBAAsB,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBpE;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAmCnF;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BpF;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAgDtF;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BvF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../../src/commands/daemons/help.ts"],"names":[],"mappings":"AAEA,wBAAgB,eAAe,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../../src/commands/daemons/help.ts"],"names":[],"mappings":"AAEA,wBAAgB,eAAe,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAyDzD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../src/commands/deployments/command.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,wBAAwB,
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../src/commands/deployments/command.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,wBAAwB,6GAUnC,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CommandContext } from "../../context.ts";
|
|
2
2
|
export declare function deploymentsList(ctx: CommandContext): Promise<void>;
|
|
3
|
+
export declare function deploymentsLogs(args: string[], ctx: CommandContext): Promise<void>;
|
|
3
4
|
export declare function deploymentsDeploy(ctx: CommandContext): Promise<void>;
|
|
4
5
|
//# sourceMappingURL=handlers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../../src/commands/deployments/handlers.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAMvD,wBAAsB,eAAe,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAkCxE;AAED,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAqE1E"}
|
|
1
|
+
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../../src/commands/deployments/handlers.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAMvD,wBAAsB,eAAe,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAkCxE;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA4CxF;AAED,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAqE1E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../../src/commands/deployments/help.ts"],"names":[],"mappings":"AAEA,wBAAgB,mBAAmB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../../src/commands/deployments/help.ts"],"names":[],"mappings":"AAEA,wBAAgB,mBAAmB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CA6D7D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../src/commands/services/command.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,qBAAqB,6GAQhC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CommandContext } from "../../context.ts";
|
|
2
|
+
/**
|
|
3
|
+
* List services on a server with a derived availability flag.
|
|
4
|
+
*/
|
|
5
|
+
export declare function servicesList(args: string[], ctx: CommandContext): Promise<void>;
|
|
6
|
+
/**
|
|
7
|
+
* Restart a service on a server.
|
|
8
|
+
*/
|
|
9
|
+
export declare function servicesRestart(args: string[], ctx: CommandContext): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=handlers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../../src/commands/services/handlers.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAMvD;;GAEG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBrF;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAsCxF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../../src/commands/services/help.ts"],"names":[],"mappings":"AAEA,wBAAgB,gBAAgB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAwD1D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/services/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CommandOptions } from "../../context.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Route the top-level `forge ssh` command.
|
|
4
|
+
*
|
|
5
|
+
* Unlike resource commands there is no sub-action: the first positional is the
|
|
6
|
+
* server, and any remaining positionals form an optional remote command.
|
|
7
|
+
*/
|
|
8
|
+
export declare function handleSshCommand(server: string | undefined, remote: string[], options: CommandOptions): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../src/commands/ssh/command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAKvD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,IAAI,CAAC,CAGf"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI handler for `forge ssh` — open an interactive SSH session to a server.
|
|
3
|
+
*
|
|
4
|
+
* Resolves the server, reads its connection details from the API, then hands
|
|
5
|
+
* off to the local `ssh` binary with an inherited stdio (interactive) session.
|
|
6
|
+
*/
|
|
7
|
+
import type { CommandContext } from "../../context.ts";
|
|
8
|
+
/**
|
|
9
|
+
* Connect to a server over SSH.
|
|
10
|
+
*
|
|
11
|
+
* @param server - Server ID or name (resolved via {@link resolveServerId}).
|
|
12
|
+
* @param remote - Optional remote command to run instead of an interactive shell.
|
|
13
|
+
* @param ctx - CLI command context.
|
|
14
|
+
*/
|
|
15
|
+
export declare function sshConnect(server: string | undefined, remote: string[], ctx: CommandContext): Promise<void>;
|
|
16
|
+
//# sourceMappingURL=handlers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../../src/commands/ssh/handlers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAOvD;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,MAAM,EAAE,MAAM,EAAE,EAChB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,IAAI,CAAC,CAiEf"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../../src/commands/ssh/help.ts"],"names":[],"mappings":"AAEA,wBAAgB,WAAW,IAAI,IAAI,CAuClC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/ssh/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers for resolving SSH connection details from a Forge server.
|
|
3
|
+
*
|
|
4
|
+
* Kept free of side effects so the resolution logic is fully unit-testable
|
|
5
|
+
* without spawning a real `ssh` process.
|
|
6
|
+
*/
|
|
7
|
+
import type { ServerAttributes } from "@studiometa/forge-api";
|
|
8
|
+
/** Forge's conventional default provisioning user. */
|
|
9
|
+
export declare const DEFAULT_SSH_USER = "forge";
|
|
10
|
+
export interface SshTargetOptions {
|
|
11
|
+
/** SSH user (defaults to {@link DEFAULT_SSH_USER}). */
|
|
12
|
+
user?: string;
|
|
13
|
+
/** Connect over the private network (`private_ip_address`) instead of the public IP. */
|
|
14
|
+
private?: boolean;
|
|
15
|
+
/** Override the server's `ssh_port` (string as parsed from the CLI). */
|
|
16
|
+
port?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface SshTarget {
|
|
19
|
+
user: string;
|
|
20
|
+
host: string;
|
|
21
|
+
port: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Resolve the concrete user/host/port to connect to.
|
|
25
|
+
*
|
|
26
|
+
* @throws {ValidationError} when the selected IP is not available yet, or the port override is invalid.
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolveSshTarget(server: ServerAttributes, options?: SshTargetOptions): SshTarget;
|
|
29
|
+
/**
|
|
30
|
+
* Build the argument list passed to the `ssh` binary.
|
|
31
|
+
*
|
|
32
|
+
* Any {@link remoteCommand} is appended after the connection flags, so
|
|
33
|
+
* `forge ssh web uptime` runs `uptime` remotely and exits.
|
|
34
|
+
*/
|
|
35
|
+
export declare function buildSshArgs(target: SshTarget, remoteCommand?: string[]): string[];
|
|
36
|
+
//# sourceMappingURL=ssh-target.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh-target.d.ts","sourceRoot":"","sources":["../../../src/commands/ssh/ssh-target.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAI9D,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,UAAU,CAAC;AAExC,MAAM,WAAW,gBAAgB;IAC/B,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wFAAwF;IACxF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wEAAwE;IACxE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,gBAAgB,EACxB,OAAO,GAAE,gBAAqB,GAC7B,SAAS,CA4BX;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,EAAE,aAAa,GAAE,MAAM,EAAO,GAAG,MAAM,EAAE,CAMtF"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { HttpClient, createConfigStore, createConfigStore as createConfigStore$1, deleteToken, getOrganizationSlug, getToken, getToken as getToken$1, setOrganizationSlug, setToken } from "@studiometa/forge-api";
|
|
2
|
+
//#region src/types.ts
|
|
2
3
|
function isOutputFormat(value) {
|
|
3
4
|
return value === "json" || value === "human" || value === "table";
|
|
4
5
|
}
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/errors.ts
|
|
5
8
|
/**
|
|
6
9
|
* Error types for forge.
|
|
7
10
|
*
|
|
@@ -12,6 +15,8 @@ function isOutputFormat(value) {
|
|
|
12
15
|
* Base error class for all CLI errors.
|
|
13
16
|
*/
|
|
14
17
|
var CliError = class extends Error {
|
|
18
|
+
hints;
|
|
19
|
+
cause;
|
|
15
20
|
constructor(message, hints, cause) {
|
|
16
21
|
super(message);
|
|
17
22
|
this.hints = hints;
|
|
@@ -47,6 +52,7 @@ var ConfigError = class ConfigError extends CliError {
|
|
|
47
52
|
}
|
|
48
53
|
};
|
|
49
54
|
var ValidationError = class ValidationError extends CliError {
|
|
55
|
+
field;
|
|
50
56
|
code = "VALIDATION_ERROR";
|
|
51
57
|
isRecoverable = true;
|
|
52
58
|
constructor(message, field, hints, cause) {
|
|
@@ -64,6 +70,7 @@ var ValidationError = class ValidationError extends CliError {
|
|
|
64
70
|
}
|
|
65
71
|
};
|
|
66
72
|
var ApiError = class ApiError extends CliError {
|
|
73
|
+
statusCode;
|
|
67
74
|
code = "API_ERROR";
|
|
68
75
|
isRecoverable;
|
|
69
76
|
constructor(message, statusCode, hints, cause) {
|
|
@@ -101,6 +108,8 @@ function getApiErrorHints(statusCode) {
|
|
|
101
108
|
function isCliError(error) {
|
|
102
109
|
return error instanceof CliError;
|
|
103
110
|
}
|
|
111
|
+
//#endregion
|
|
112
|
+
//#region src/config.ts
|
|
104
113
|
/**
|
|
105
114
|
* Config loading for forge.
|
|
106
115
|
*
|
|
@@ -117,6 +126,8 @@ function getConfig(cliOptions) {
|
|
|
117
126
|
const storedToken = getToken(createConfigStore());
|
|
118
127
|
return { apiToken: typeof cliToken === "string" ? cliToken : storedToken ?? void 0 };
|
|
119
128
|
}
|
|
129
|
+
//#endregion
|
|
130
|
+
//#region src/utils/colors.ts
|
|
120
131
|
/**
|
|
121
132
|
* ANSI color utilities using native Node.js.
|
|
122
133
|
* Provides terminal colors without external dependencies.
|
|
@@ -137,7 +148,7 @@ function colorize(text, code) {
|
|
|
137
148
|
if (!colorEnabled) return text;
|
|
138
149
|
return `${code}${text}${RESET}`;
|
|
139
150
|
}
|
|
140
|
-
|
|
151
|
+
var colors = {
|
|
141
152
|
reset: (text) => colorEnabled ? `${RESET}${text}` : text,
|
|
142
153
|
bold: (text) => colorize(text, BOLD),
|
|
143
154
|
dim: (text) => colorize(text, DIM),
|
|
@@ -147,11 +158,15 @@ const colors = {
|
|
|
147
158
|
cyan: (text) => colorize(text, FG_CYAN),
|
|
148
159
|
gray: (text) => colorize(text, FG_GRAY)
|
|
149
160
|
};
|
|
161
|
+
//#endregion
|
|
162
|
+
//#region src/output.ts
|
|
150
163
|
/**
|
|
151
164
|
* Output formatter for CLI commands.
|
|
152
165
|
* Supports human-readable, JSON, and table formats.
|
|
153
166
|
*/
|
|
154
167
|
var OutputFormatter = class {
|
|
168
|
+
format;
|
|
169
|
+
noColor;
|
|
155
170
|
constructor(format = "human", noColor = false) {
|
|
156
171
|
this.format = format;
|
|
157
172
|
this.noColor = noColor;
|
|
@@ -180,6 +195,17 @@ var OutputFormatter = class {
|
|
|
180
195
|
}
|
|
181
196
|
}
|
|
182
197
|
/**
|
|
198
|
+
* Output raw text such as a log. Human and table formats print the text
|
|
199
|
+
* verbatim (a log is not tabular data); JSON wraps it as a JSON string.
|
|
200
|
+
*/
|
|
201
|
+
outputText(text) {
|
|
202
|
+
if (this.format === "json") {
|
|
203
|
+
console.log(JSON.stringify(text));
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
console.log(text);
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
183
209
|
* Output a list with a human-readable one-liner per item and a table for table format.
|
|
184
210
|
* Falls back to JSON for json format.
|
|
185
211
|
*
|
|
@@ -290,6 +316,8 @@ var OutputFormatter = class {
|
|
|
290
316
|
}
|
|
291
317
|
}
|
|
292
318
|
};
|
|
319
|
+
//#endregion
|
|
320
|
+
//#region src/context.ts
|
|
293
321
|
/**
|
|
294
322
|
* Creates a command context from CLI options.
|
|
295
323
|
*/
|
|
@@ -346,10 +374,12 @@ function createTestContext(overrides) {
|
|
|
346
374
|
}
|
|
347
375
|
};
|
|
348
376
|
}
|
|
377
|
+
//#endregion
|
|
378
|
+
//#region src/error-handler.ts
|
|
349
379
|
/**
|
|
350
380
|
* Exit codes for different error categories.
|
|
351
381
|
*/
|
|
352
|
-
|
|
382
|
+
var ExitCode = {
|
|
353
383
|
SUCCESS: 0,
|
|
354
384
|
GENERAL_ERROR: 1,
|
|
355
385
|
AUTHENTICATION_ERROR: 2,
|
|
@@ -402,6 +432,7 @@ function exitWithValidationError(field, usage, formatter) {
|
|
|
402
432
|
handleError(error, formatter);
|
|
403
433
|
throw error;
|
|
404
434
|
}
|
|
435
|
+
//#endregion
|
|
405
436
|
export { isOutputFormat as S, ApiError as _, createContext as a, ValidationError as b, colors as c, deleteToken as d, getConfig as f, setToken as g, setOrganizationSlug as h, runCommand as i, setColorEnabled as l, getToken$1 as m, exitWithValidationError as n, createTestContext as o, getOrganizationSlug as p, handleError as r, OutputFormatter as s, ExitCode as t, createConfigStore$1 as u, CliError as v, isCliError as x, ConfigError as y };
|
|
406
437
|
|
|
407
|
-
//# sourceMappingURL=error-handler-
|
|
438
|
+
//# sourceMappingURL=error-handler-BA357jIr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-handler-BA357jIr.js","names":[],"sources":["../src/types.ts","../src/errors.ts","../src/config.ts","../src/utils/colors.ts","../src/output.ts","../src/context.ts","../src/error-handler.ts"],"sourcesContent":["// CLI-specific types for forge\n\nexport type OutputFormat = \"json\" | \"human\" | \"table\";\n\nexport function isOutputFormat(value: unknown): value is OutputFormat {\n return value === \"json\" || value === \"human\" || value === \"table\";\n}\n\nexport interface CliOptions {\n format?: OutputFormat;\n quiet?: boolean;\n noColor?: boolean;\n}\n","/**\n * Error types for forge.\n *\n * Provides specific error types for different failure scenarios with\n * recovery hints for both humans and AI agents.\n */\n\n/**\n * Base error class for all CLI errors.\n */\nexport abstract class CliError extends Error {\n abstract readonly code: string;\n abstract readonly isRecoverable: boolean;\n\n constructor(\n message: string,\n public readonly hints?: string[],\n public readonly cause?: unknown,\n ) {\n super(message);\n this.name = this.constructor.name;\n\n Error.captureStackTrace?.(this, this.constructor);\n }\n\n toJSON(): Record<string, unknown> {\n return {\n error: this.code,\n name: this.name,\n message: this.message,\n isRecoverable: this.isRecoverable,\n ...(this.hints && this.hints.length > 0 ? { hints: this.hints } : {}),\n ...(this.cause instanceof Error ? { cause: { message: this.cause.message } } : {}),\n };\n }\n\n toFormattedMessage(): string {\n let msg = this.message;\n if (this.hints && this.hints.length > 0) {\n msg += \"\\n\\nHints:\\n\" + this.hints.map((h) => ` • ${h}`).join(\"\\n\");\n }\n return msg;\n }\n}\n\n// ── Config Errors ────────────────────────────────────\n\nexport class ConfigError extends CliError {\n readonly code = \"CONFIG_ERROR\";\n readonly isRecoverable = true;\n\n static missingToken(): ConfigError {\n return new ConfigError(\"API token not configured\", [\n \"Set via CLI flag: --token <token>\",\n \"Set via environment: export FORGE_API_TOKEN=<token>\",\n \"Set via config: forge config set YOUR_TOKEN\",\n ]);\n }\n}\n\n// ── Validation Errors ────────────────────────────────\n\nexport class ValidationError extends CliError {\n readonly code = \"VALIDATION_ERROR\";\n readonly isRecoverable = true;\n\n constructor(\n message: string,\n public readonly field?: string,\n hints?: string[],\n cause?: unknown,\n ) {\n super(message, hints, cause);\n }\n\n override toJSON() {\n return { ...super.toJSON(), field: this.field };\n }\n\n static required(field: string, hints?: string[]): ValidationError {\n return new ValidationError(`${field} is required`, field, hints);\n }\n}\n\n// ── API Errors ───────────────────────────────────────\n\nexport class ApiError extends CliError {\n readonly code = \"API_ERROR\";\n readonly isRecoverable: boolean;\n\n constructor(\n message: string,\n public readonly statusCode?: number,\n hints?: string[],\n cause?: unknown,\n ) {\n super(message, hints ?? getApiErrorHints(statusCode), cause);\n this.isRecoverable = statusCode === undefined || (statusCode >= 500 && statusCode < 600);\n }\n\n override toJSON() {\n return { ...super.toJSON(), statusCode: this.statusCode };\n }\n\n static fromForgeError(error: unknown): ApiError {\n if (error instanceof Error && \"statusCode\" in error) {\n const code = (error as { statusCode: unknown }).statusCode;\n return new ApiError(\n error.message,\n typeof code === \"number\" ? code : undefined,\n undefined,\n error,\n );\n }\n if (error instanceof Error) {\n return new ApiError(error.message, undefined, undefined, error);\n }\n return new ApiError(String(error));\n }\n}\n\nfunction getApiErrorHints(statusCode?: number): string[] {\n if (statusCode === 401) {\n return [\"Check that your API token is valid\", \"Set via: export FORGE_API_TOKEN=<token>\"];\n }\n if (statusCode === 403) {\n return [\"You may not have permission to access this resource\"];\n }\n if (statusCode === 404) {\n return [\n \"The resource may not exist\",\n \"Verify the ID is correct\",\n \"Use the list command to find valid IDs\",\n ];\n }\n if (statusCode === 429) {\n return [\"Too many requests — wait before retrying\"];\n }\n if (statusCode !== undefined && statusCode >= 500) {\n return [\"Server error — try again later\"];\n }\n return [];\n}\n\n// ── Type Guards ──────────────────────────────────────\n\nexport function isCliError(error: unknown): error is CliError {\n return error instanceof CliError;\n}\n","/**\n * Config loading for forge.\n *\n * Resolution priority (highest to lowest):\n * 1. CLI arguments (--token)\n * 2. Environment variable (FORGE_API_TOKEN)\n * 3. Config file (XDG-compliant)\n */\n\nimport { createConfigStore, getToken } from \"@studiometa/forge-api\";\n\nexport interface ForgeCliConfig {\n /** Forge API token */\n apiToken: string | undefined;\n}\n\n/**\n * Resolve config from multiple sources with priority order.\n */\nexport function getConfig(\n cliOptions?: Record<string, string | boolean | string[]>,\n): ForgeCliConfig {\n // 1. CLI argument --token\n const cliToken = cliOptions?.token;\n\n // 2. Environment variable / config file (handled by getToken)\n const storedToken = getToken(createConfigStore());\n\n return {\n apiToken: typeof cliToken === \"string\" ? cliToken : (storedToken ?? undefined),\n };\n}\n\nexport {\n createConfigStore,\n getToken,\n setToken,\n deleteToken,\n getOrganizationSlug,\n setOrganizationSlug,\n} from \"@studiometa/forge-api\";\n","/**\n * ANSI color utilities using native Node.js.\n * Provides terminal colors without external dependencies.\n */\n\n// ANSI escape codes\nconst RESET = \"\\x1b[0m\";\nconst BOLD = \"\\x1b[1m\";\nconst DIM = \"\\x1b[2m\";\n\n// Foreground colors\nconst FG_RED = \"\\x1b[31m\";\nconst FG_GREEN = \"\\x1b[32m\";\nconst FG_YELLOW = \"\\x1b[33m\";\nconst FG_CYAN = \"\\x1b[36m\";\nconst FG_GRAY = \"\\x1b[90m\";\n\n// Colors enabled by default, disabled by NO_COLOR env var\nlet colorEnabled = process.env.NO_COLOR === undefined;\n\nexport function setColorEnabled(enabled: boolean): void {\n colorEnabled = enabled;\n}\n\nexport function isColorEnabled(): boolean {\n return colorEnabled;\n}\n\nfunction colorize(text: string, code: string): string {\n if (!colorEnabled) return text;\n return `${code}${text}${RESET}`;\n}\n\nexport const colors = {\n reset: (text: string) => (colorEnabled ? `${RESET}${text}` : text),\n bold: (text: string) => colorize(text, BOLD),\n dim: (text: string) => colorize(text, DIM),\n red: (text: string) => colorize(text, FG_RED),\n green: (text: string) => colorize(text, FG_GREEN),\n yellow: (text: string) => colorize(text, FG_YELLOW),\n cyan: (text: string) => colorize(text, FG_CYAN),\n gray: (text: string) => colorize(text, FG_GRAY),\n};\n","/* eslint-disable typescript-eslint/no-base-to-string -- generic formatter converts unknown values to strings */\nimport type { OutputFormat } from \"./types.ts\";\n\nimport { colors } from \"./utils/colors.ts\";\n\n/**\n * Output formatter for CLI commands.\n * Supports human-readable, JSON, and table formats.\n */\nexport class OutputFormatter {\n constructor(\n private format: OutputFormat = \"human\",\n private noColor: boolean = false,\n ) {}\n\n /**\n * Returns true when the current format is JSON.\n */\n isJson(): boolean {\n return this.format === \"json\";\n }\n\n /**\n * Output data in the configured format.\n * Use format='json' for AI agents and structured data.\n */\n output(data: unknown): void {\n switch (this.format) {\n case \"json\":\n console.log(JSON.stringify(data, null, 2));\n break;\n case \"table\":\n this.outputTable(data);\n break;\n default:\n console.log(data);\n break;\n }\n }\n\n /**\n * Output raw text such as a log. Human and table formats print the text\n * verbatim (a log is not tabular data); JSON wraps it as a JSON string.\n */\n outputText(text: string): void {\n if (this.format === \"json\") {\n console.log(JSON.stringify(text));\n return;\n }\n console.log(text);\n }\n\n /**\n * Output a list with a human-readable one-liner per item and a table for table format.\n * Falls back to JSON for json format.\n *\n * @param data - Array of items to display\n * @param columns - Ordered list of field names to include in human/table output\n * @param emptyMessage - Message shown when data is empty (human format only)\n * @param lineFormat - Optional custom line formatter for human format\n */\n outputList<T extends object>(\n data: T[],\n columns: (keyof T & string)[],\n emptyMessage: string,\n lineFormat?: (item: T) => string,\n ): void {\n if (this.format === \"json\") {\n console.log(JSON.stringify(data, null, 2));\n return;\n }\n\n if (this.format === \"table\") {\n this.outputTable(data.map((item) => Object.fromEntries(columns.map((c) => [c, item[c]]))));\n return;\n }\n\n // human\n if (data.length === 0) {\n console.log(colors.cyan(emptyMessage));\n return;\n }\n\n if (lineFormat) {\n for (const item of data) {\n console.log(lineFormat(item));\n }\n return;\n }\n\n // Default: padded columns\n const widths = columns.map((col) =>\n Math.max(\n col.length,\n ...data.map((item) => String((item as Record<string, unknown>)[col] ?? \"\").length),\n ),\n );\n for (const item of data) {\n const row = item as Record<string, unknown>;\n const line = columns.map((col, i) => String(row[col] ?? \"\").padEnd(widths[i])).join(\" \");\n console.log(line.trimEnd());\n }\n }\n\n /**\n * Output a single resource in human-readable format.\n * For json format, uses JSON.stringify. For table format, uses a two-column key/value table.\n *\n * @param data - Object to display\n * @param fields - Ordered list of fields to display (defaults to all keys)\n */\n outputOne<T extends object>(data: T, fields?: (keyof T & string)[]): void {\n if (this.format === \"json\") {\n console.log(JSON.stringify(data, null, 2));\n return;\n }\n\n const record = data as Record<string, unknown>;\n const keys = fields ?? (Object.keys(record) as (keyof T & string)[]);\n\n if (this.format === \"table\") {\n const rows = keys.map((k) => ({ field: k, value: String(record[k] ?? \"\") }));\n this.outputTable(rows);\n return;\n }\n\n // human: key: value pairs\n const keyWidth = Math.max(...keys.map((k) => k.length));\n for (const key of keys) {\n const value = record[key];\n const valueStr =\n value !== null && typeof value === \"object\" ? JSON.stringify(value) : String(value ?? \"\");\n console.log(`${colors.cyan(key.padEnd(keyWidth))} ${valueStr}`);\n }\n }\n\n success(message: string): void {\n if (this.format === \"json\") {\n console.log(JSON.stringify({ status: \"success\", message }));\n } else {\n console.log(colors.green(`✓ ${message}`));\n }\n }\n\n error(message: string, details?: unknown): void {\n if (this.format === \"json\") {\n console.error(JSON.stringify({ status: \"error\", message, details }));\n } else {\n console.error(colors.red(`✗ ${message}`));\n if (details !== undefined) {\n console.error(details);\n }\n }\n }\n\n warning(message: string): void {\n if (this.format === \"json\") {\n console.log(JSON.stringify({ status: \"warning\", message }));\n } else {\n console.log(colors.yellow(`⚠ ${message}`));\n }\n }\n\n info(message: string): void {\n if (this.format === \"json\") {\n console.log(JSON.stringify({ status: \"info\", message }));\n } else {\n console.log(colors.cyan(message));\n }\n }\n\n private outputTable(data: unknown): void {\n if (Array.isArray(data) && data.length > 0) {\n const headers = Object.keys(data[0] as Record<string, unknown>);\n const colWidths = headers.map((h) => {\n const maxDataWidth = Math.max(\n ...data.map((row) => String((row as Record<string, unknown>)[h] ?? \"\").length),\n );\n return Math.max(h.length, maxDataWidth);\n });\n\n // Header\n const headerRow = headers.map((h, i) => h.padEnd(colWidths[i])).join(\" | \");\n console.log(headerRow);\n console.log(colWidths.map((w) => \"-\".repeat(w)).join(\"-+-\"));\n\n // Rows\n for (const row of data) {\n const rowStr = headers\n .map((h, i) => String((row as Record<string, unknown>)[h] ?? \"\").padEnd(colWidths[i]))\n .join(\" | \");\n console.log(rowStr);\n }\n }\n }\n}\n","/**\n * CLI execution context with dependency injection.\n *\n * Instead of hidden dependencies in command handlers, this module provides\n * explicit dependency passing for testability and transparency.\n */\n\nimport type { HttpClient } from \"@studiometa/forge-api\";\nimport type { ExecutorContext } from \"@studiometa/forge-core\";\n\nimport { type OutputFormat, isOutputFormat } from \"./types.ts\";\n\nimport { HttpClient as ForgeHttpClient } from \"@studiometa/forge-api\";\nimport { ConfigError } from \"./errors.ts\";\nimport { createConfigStore, getToken, getOrganizationSlug } from \"./config.ts\";\nimport { OutputFormatter } from \"./output.ts\";\n\nexport interface CommandOptions {\n [key: string]: string | boolean | string[] | undefined;\n format?: string;\n f?: string;\n token?: string;\n \"no-color\"?: boolean;\n}\n\n/**\n * Context containing all dependencies needed by command handlers.\n */\nexport interface CommandContext {\n /** Output formatter for the current format */\n readonly formatter: OutputFormatter;\n /** Raw CLI options */\n readonly options: CommandOptions;\n /** Create an ExecutorContext from this command context */\n createExecutorContext(token: string): ExecutorContext;\n /** Resolve the API token or throw ConfigError */\n getToken(): string;\n}\n\n/**\n * Creates a command context from CLI options.\n */\nexport function createContext(options: CommandOptions = {}): CommandContext {\n const rawFormat = options.format ?? options.f ?? \"human\";\n const format: OutputFormat = isOutputFormat(rawFormat) ? rawFormat : \"human\";\n const noColor = options[\"no-color\"] === true;\n const formatter = new OutputFormatter(format, noColor);\n\n return {\n formatter,\n options,\n\n createExecutorContext(token: string): ExecutorContext {\n const client: HttpClient = new ForgeHttpClient({ token });\n const orgSlug =\n (typeof options.org === \"string\" && options.org) ||\n getOrganizationSlug(createConfigStore()) ||\n undefined;\n return { client, organizationSlug: orgSlug };\n },\n\n getToken(): string {\n // 1. CLI arg\n if (typeof options.token === \"string\" && options.token) {\n return options.token;\n }\n // 2. Env var / config file\n const stored = getToken(createConfigStore());\n if (stored) {\n return stored;\n }\n // 3. Not found — throw\n throw ConfigError.missingToken();\n },\n };\n}\n\n/**\n * Creates a test context for unit tests.\n *\n * @example\n * ```typescript\n * const ctx = createTestContext({\n * mockClient: { get: async () => ({ servers: [] }) } as never,\n * });\n * ```\n */\nexport function createTestContext(overrides: {\n options?: CommandOptions;\n formatter?: OutputFormatter;\n token?: string;\n mockClient?: HttpClient;\n}): CommandContext {\n const opts: CommandOptions = overrides.options ?? {\n format: \"json\",\n \"no-color\": true,\n };\n const rawFormat = opts.format ?? \"json\";\n const format: OutputFormat = isOutputFormat(rawFormat) ? rawFormat : \"json\";\n const formatter = overrides.formatter ?? new OutputFormatter(format, true);\n\n return {\n formatter,\n options: opts,\n createExecutorContext(_token: string): ExecutorContext {\n if (!overrides.mockClient) {\n throw new Error(\n \"createTestContext: provide mockClient to use createExecutorContext in tests\",\n );\n }\n return { client: overrides.mockClient, organizationSlug: \"test-org\" };\n },\n getToken(): string {\n if (overrides.token) return overrides.token;\n if (typeof opts.token === \"string\") return opts.token;\n return \"test-token\";\n },\n };\n}\n","/**\n * Centralized error handling for forge.\n */\n\nimport type { OutputFormatter } from \"./output.ts\";\n\nimport { ApiError, CliError, ConfigError, ValidationError, isCliError } from \"./errors.ts\";\n\n/**\n * Exit codes for different error categories.\n */\nexport const ExitCode = {\n SUCCESS: 0,\n GENERAL_ERROR: 1,\n AUTHENTICATION_ERROR: 2,\n VALIDATION_ERROR: 3,\n CONFIG_ERROR: 4,\n NOT_FOUND_ERROR: 5,\n} as const;\n\nexport type ExitCode = (typeof ExitCode)[keyof typeof ExitCode];\n\n/**\n * Determine the appropriate exit code for an error.\n */\nexport function getExitCode(error: unknown): ExitCode {\n if (error instanceof ValidationError) {\n return ExitCode.VALIDATION_ERROR;\n }\n if (error instanceof ApiError) {\n if (error.statusCode === 401) return ExitCode.AUTHENTICATION_ERROR;\n if (error.statusCode === 404) return ExitCode.NOT_FOUND_ERROR;\n }\n if (isCliError(error) && error.code === \"CONFIG_ERROR\") {\n return ExitCode.CONFIG_ERROR;\n }\n return ExitCode.GENERAL_ERROR;\n}\n\n/**\n * Central error handler for all commands.\n */\nexport function handleError(\n error: unknown,\n formatter: OutputFormatter,\n options?: { exit?: boolean },\n): ExitCode {\n const shouldExit = options?.exit ?? true;\n\n let cliError: CliError;\n if (isCliError(error)) {\n cliError = error;\n } else {\n cliError = ApiError.fromForgeError(error);\n }\n\n // Output error in appropriate format\n if (formatter.isJson()) {\n formatter.output(cliError.toJSON());\n } else {\n formatter.error(cliError.toFormattedMessage());\n }\n\n const exitCode = getExitCode(cliError);\n\n if (shouldExit) {\n process.exit(exitCode);\n }\n\n return exitCode;\n}\n\n/**\n * Wraps a command function with automatic error handling.\n */\nexport async function runCommand<T>(\n fn: () => Promise<T>,\n formatter: OutputFormatter,\n): Promise<T | undefined> {\n try {\n return await fn();\n } catch (error) {\n handleError(error, formatter);\n return undefined; // unreachable due to process.exit\n }\n}\n\n/**\n * Exits with a validation error for a missing required argument.\n */\nexport function exitWithValidationError(\n field: string,\n usage: string,\n formatter: OutputFormatter,\n): never {\n const error = ValidationError.required(field, [`Usage: ${usage}`]);\n handleError(error, formatter);\n // Unreachable in production\n throw error;\n}\n\n/**\n * Exits with a config error when token is missing.\n */\nexport function exitWithConfigError(formatter: OutputFormatter): never {\n const error = ConfigError.missingToken();\n handleError(error, formatter);\n throw error;\n}\n"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as ApiError, a as createContext, b as ValidationError, f as getConfig, i as runCommand, o as createTestContext, r as handleError, s as OutputFormatter, t as ExitCode, v as CliError, x as isCliError, y as ConfigError } from "./error-handler-
|
|
1
|
+
import { _ as ApiError, a as createContext, b as ValidationError, f as getConfig, i as runCommand, o as createTestContext, r as handleError, s as OutputFormatter, t as ExitCode, v as CliError, x as isCliError, y as ConfigError } from "./error-handler-BA357jIr.js";
|
|
2
2
|
export { ApiError, CliError, ConfigError, ExitCode, OutputFormatter, ValidationError, createContext, createTestContext, getConfig, handleError, isCliError, runCommand };
|
package/dist/output.d.ts
CHANGED
|
@@ -16,6 +16,11 @@ export declare class OutputFormatter {
|
|
|
16
16
|
* Use format='json' for AI agents and structured data.
|
|
17
17
|
*/
|
|
18
18
|
output(data: unknown): void;
|
|
19
|
+
/**
|
|
20
|
+
* Output raw text such as a log. Human and table formats print the text
|
|
21
|
+
* verbatim (a log is not tabular data); JSON wraps it as a JSON string.
|
|
22
|
+
*/
|
|
23
|
+
outputText(text: string): void;
|
|
19
24
|
/**
|
|
20
25
|
* Output a list with a human-readable one-liner per item and a table for table format.
|
|
21
26
|
* Falls back to JSON for json format.
|
|
@@ -40,8 +45,4 @@ export declare class OutputFormatter {
|
|
|
40
45
|
info(message: string): void;
|
|
41
46
|
private outputTable;
|
|
42
47
|
}
|
|
43
|
-
export declare const x: {
|
|
44
|
-
a: number;
|
|
45
|
-
b: number;
|
|
46
|
-
};
|
|
47
48
|
//# sourceMappingURL=output.d.ts.map
|
package/dist/output.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI/C;;;GAGG;AACH,qBAAa,eAAe;IAExB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,OAAO;IAFjB,YACU,MAAM,GAAE,YAAsB,EAC9B,OAAO,GAAE,OAAe,EAC9B;IAEJ;;OAEG;IACH,MAAM,IAAI,OAAO,CAEhB;IAED;;;OAGG;IACH,MAAM,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAY1B;IAED;;;;;;;;OAQG;IACH,UAAU,CAAC,CAAC,SAAS,MAAM,EACzB,IAAI,EAAE,CAAC,EAAE,EACT,OAAO,EAAE,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,EAAE,EAC7B,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,GAC/B,IAAI,CAoCN;IAED;;;;;;OAMG;IACH,SAAS,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,EAAE,GAAG,IAAI,CAuBxE;IAED,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAM7B;IAED,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAS9C;IAED,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAM7B;IAED,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAM1B;IAED,OAAO,CAAC,WAAW;CAwBpB
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI/C;;;GAGG;AACH,qBAAa,eAAe;IAExB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,OAAO;IAFjB,YACU,MAAM,GAAE,YAAsB,EAC9B,OAAO,GAAE,OAAe,EAC9B;IAEJ;;OAEG;IACH,MAAM,IAAI,OAAO,CAEhB;IAED;;;OAGG;IACH,MAAM,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAY1B;IAED;;;OAGG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAM7B;IAED;;;;;;;;OAQG;IACH,UAAU,CAAC,CAAC,SAAS,MAAM,EACzB,IAAI,EAAE,CAAC,EAAE,EACT,OAAO,EAAE,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,EAAE,EAC7B,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,GAC/B,IAAI,CAoCN;IAED;;;;;;OAMG;IACH,SAAS,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,EAAE,GAAG,IAAI,CAuBxE;IAED,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAM7B;IAED,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAS9C;IAED,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAM7B;IAED,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAM1B;IAED,OAAO,CAAC,WAAW;CAwBpB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@studiometa/forge-cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.6",
|
|
4
4
|
"description": "CLI tool for managing Laravel Forge servers, sites, and deployments",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-agent",
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
"typecheck": "tsgo -p tsconfig.typecheck.json --noEmit"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@studiometa/forge-api": "0.4.
|
|
52
|
-
"@studiometa/forge-core": "0.4.
|
|
51
|
+
"@studiometa/forge-api": "0.4.6",
|
|
52
|
+
"@studiometa/forge-core": "0.4.6"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@types/node": "^24.0.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"error-handler-ByMitiOr.js","names":[],"sources":["../src/types.ts","../src/errors.ts","../src/config.ts","../src/utils/colors.ts","../src/output.ts","../src/context.ts","../src/error-handler.ts"],"sourcesContent":["// CLI-specific types for forge\n\nexport type OutputFormat = \"json\" | \"human\" | \"table\";\n\nexport function isOutputFormat(value: unknown): value is OutputFormat {\n return value === \"json\" || value === \"human\" || value === \"table\";\n}\n\nexport interface CliOptions {\n format?: OutputFormat;\n quiet?: boolean;\n noColor?: boolean;\n}\n","/**\n * Error types for forge.\n *\n * Provides specific error types for different failure scenarios with\n * recovery hints for both humans and AI agents.\n */\n\n/**\n * Base error class for all CLI errors.\n */\nexport abstract class CliError extends Error {\n abstract readonly code: string;\n abstract readonly isRecoverable: boolean;\n\n constructor(\n message: string,\n public readonly hints?: string[],\n public readonly cause?: unknown,\n ) {\n super(message);\n this.name = this.constructor.name;\n\n Error.captureStackTrace?.(this, this.constructor);\n }\n\n toJSON(): Record<string, unknown> {\n return {\n error: this.code,\n name: this.name,\n message: this.message,\n isRecoverable: this.isRecoverable,\n ...(this.hints && this.hints.length > 0 ? { hints: this.hints } : {}),\n ...(this.cause instanceof Error ? { cause: { message: this.cause.message } } : {}),\n };\n }\n\n toFormattedMessage(): string {\n let msg = this.message;\n if (this.hints && this.hints.length > 0) {\n msg += \"\\n\\nHints:\\n\" + this.hints.map((h) => ` • ${h}`).join(\"\\n\");\n }\n return msg;\n }\n}\n\n// ── Config Errors ────────────────────────────────────\n\nexport class ConfigError extends CliError {\n readonly code = \"CONFIG_ERROR\";\n readonly isRecoverable = true;\n\n static missingToken(): ConfigError {\n return new ConfigError(\"API token not configured\", [\n \"Set via CLI flag: --token <token>\",\n \"Set via environment: export FORGE_API_TOKEN=<token>\",\n \"Set via config: forge config set YOUR_TOKEN\",\n ]);\n }\n}\n\n// ── Validation Errors ────────────────────────────────\n\nexport class ValidationError extends CliError {\n readonly code = \"VALIDATION_ERROR\";\n readonly isRecoverable = true;\n\n constructor(\n message: string,\n public readonly field?: string,\n hints?: string[],\n cause?: unknown,\n ) {\n super(message, hints, cause);\n }\n\n override toJSON() {\n return { ...super.toJSON(), field: this.field };\n }\n\n static required(field: string, hints?: string[]): ValidationError {\n return new ValidationError(`${field} is required`, field, hints);\n }\n}\n\n// ── API Errors ───────────────────────────────────────\n\nexport class ApiError extends CliError {\n readonly code = \"API_ERROR\";\n readonly isRecoverable: boolean;\n\n constructor(\n message: string,\n public readonly statusCode?: number,\n hints?: string[],\n cause?: unknown,\n ) {\n super(message, hints ?? getApiErrorHints(statusCode), cause);\n this.isRecoverable = statusCode === undefined || (statusCode >= 500 && statusCode < 600);\n }\n\n override toJSON() {\n return { ...super.toJSON(), statusCode: this.statusCode };\n }\n\n static fromForgeError(error: unknown): ApiError {\n if (error instanceof Error && \"statusCode\" in error) {\n const code = (error as { statusCode: unknown }).statusCode;\n return new ApiError(\n error.message,\n typeof code === \"number\" ? code : undefined,\n undefined,\n error,\n );\n }\n if (error instanceof Error) {\n return new ApiError(error.message, undefined, undefined, error);\n }\n return new ApiError(String(error));\n }\n}\n\nfunction getApiErrorHints(statusCode?: number): string[] {\n if (statusCode === 401) {\n return [\"Check that your API token is valid\", \"Set via: export FORGE_API_TOKEN=<token>\"];\n }\n if (statusCode === 403) {\n return [\"You may not have permission to access this resource\"];\n }\n if (statusCode === 404) {\n return [\n \"The resource may not exist\",\n \"Verify the ID is correct\",\n \"Use the list command to find valid IDs\",\n ];\n }\n if (statusCode === 429) {\n return [\"Too many requests — wait before retrying\"];\n }\n if (statusCode !== undefined && statusCode >= 500) {\n return [\"Server error — try again later\"];\n }\n return [];\n}\n\n// ── Type Guards ──────────────────────────────────────\n\nexport function isCliError(error: unknown): error is CliError {\n return error instanceof CliError;\n}\n","/**\n * Config loading for forge.\n *\n * Resolution priority (highest to lowest):\n * 1. CLI arguments (--token)\n * 2. Environment variable (FORGE_API_TOKEN)\n * 3. Config file (XDG-compliant)\n */\n\nimport { createConfigStore, getToken } from \"@studiometa/forge-api\";\n\nexport interface ForgeCliConfig {\n /** Forge API token */\n apiToken: string | undefined;\n}\n\n/**\n * Resolve config from multiple sources with priority order.\n */\nexport function getConfig(\n cliOptions?: Record<string, string | boolean | string[]>,\n): ForgeCliConfig {\n // 1. CLI argument --token\n const cliToken = cliOptions?.token;\n\n // 2. Environment variable / config file (handled by getToken)\n const storedToken = getToken(createConfigStore());\n\n return {\n apiToken: typeof cliToken === \"string\" ? cliToken : (storedToken ?? undefined),\n };\n}\n\nexport {\n createConfigStore,\n getToken,\n setToken,\n deleteToken,\n getOrganizationSlug,\n setOrganizationSlug,\n} from \"@studiometa/forge-api\";\n","/**\n * ANSI color utilities using native Node.js.\n * Provides terminal colors without external dependencies.\n */\n\n// ANSI escape codes\nconst RESET = \"\\x1b[0m\";\nconst BOLD = \"\\x1b[1m\";\nconst DIM = \"\\x1b[2m\";\n\n// Foreground colors\nconst FG_RED = \"\\x1b[31m\";\nconst FG_GREEN = \"\\x1b[32m\";\nconst FG_YELLOW = \"\\x1b[33m\";\nconst FG_CYAN = \"\\x1b[36m\";\nconst FG_GRAY = \"\\x1b[90m\";\n\n// Colors enabled by default, disabled by NO_COLOR env var\nlet colorEnabled = process.env.NO_COLOR === undefined;\n\nexport function setColorEnabled(enabled: boolean): void {\n colorEnabled = enabled;\n}\n\nexport function isColorEnabled(): boolean {\n return colorEnabled;\n}\n\nfunction colorize(text: string, code: string): string {\n if (!colorEnabled) return text;\n return `${code}${text}${RESET}`;\n}\n\nexport const colors = {\n reset: (text: string) => (colorEnabled ? `${RESET}${text}` : text),\n bold: (text: string) => colorize(text, BOLD),\n dim: (text: string) => colorize(text, DIM),\n red: (text: string) => colorize(text, FG_RED),\n green: (text: string) => colorize(text, FG_GREEN),\n yellow: (text: string) => colorize(text, FG_YELLOW),\n cyan: (text: string) => colorize(text, FG_CYAN),\n gray: (text: string) => colorize(text, FG_GRAY),\n};\n","/* eslint-disable typescript-eslint/no-base-to-string -- generic formatter converts unknown values to strings */\nimport type { OutputFormat } from \"./types.ts\";\n\nimport { colors } from \"./utils/colors.ts\";\n\n/**\n * Output formatter for CLI commands.\n * Supports human-readable, JSON, and table formats.\n */\nexport class OutputFormatter {\n constructor(\n private format: OutputFormat = \"human\",\n private noColor: boolean = false,\n ) {}\n\n /**\n * Returns true when the current format is JSON.\n */\n isJson(): boolean {\n return this.format === \"json\";\n }\n\n /**\n * Output data in the configured format.\n * Use format='json' for AI agents and structured data.\n */\n output(data: unknown): void {\n switch (this.format) {\n case \"json\":\n console.log(JSON.stringify(data, null, 2));\n break;\n case \"table\":\n this.outputTable(data);\n break;\n default:\n console.log(data);\n break;\n }\n }\n\n /**\n * Output a list with a human-readable one-liner per item and a table for table format.\n * Falls back to JSON for json format.\n *\n * @param data - Array of items to display\n * @param columns - Ordered list of field names to include in human/table output\n * @param emptyMessage - Message shown when data is empty (human format only)\n * @param lineFormat - Optional custom line formatter for human format\n */\n outputList<T extends object>(\n data: T[],\n columns: (keyof T & string)[],\n emptyMessage: string,\n lineFormat?: (item: T) => string,\n ): void {\n if (this.format === \"json\") {\n console.log(JSON.stringify(data, null, 2));\n return;\n }\n\n if (this.format === \"table\") {\n this.outputTable(data.map((item) => Object.fromEntries(columns.map((c) => [c, item[c]]))));\n return;\n }\n\n // human\n if (data.length === 0) {\n console.log(colors.cyan(emptyMessage));\n return;\n }\n\n if (lineFormat) {\n for (const item of data) {\n console.log(lineFormat(item));\n }\n return;\n }\n\n // Default: padded columns\n const widths = columns.map((col) =>\n Math.max(\n col.length,\n ...data.map((item) => String((item as Record<string, unknown>)[col] ?? \"\").length),\n ),\n );\n for (const item of data) {\n const row = item as Record<string, unknown>;\n const line = columns.map((col, i) => String(row[col] ?? \"\").padEnd(widths[i])).join(\" \");\n console.log(line.trimEnd());\n }\n }\n\n /**\n * Output a single resource in human-readable format.\n * For json format, uses JSON.stringify. For table format, uses a two-column key/value table.\n *\n * @param data - Object to display\n * @param fields - Ordered list of fields to display (defaults to all keys)\n */\n outputOne<T extends object>(data: T, fields?: (keyof T & string)[]): void {\n if (this.format === \"json\") {\n console.log(JSON.stringify(data, null, 2));\n return;\n }\n\n const record = data as Record<string, unknown>;\n const keys = fields ?? (Object.keys(record) as (keyof T & string)[]);\n\n if (this.format === \"table\") {\n const rows = keys.map((k) => ({ field: k, value: String(record[k] ?? \"\") }));\n this.outputTable(rows);\n return;\n }\n\n // human: key: value pairs\n const keyWidth = Math.max(...keys.map((k) => k.length));\n for (const key of keys) {\n const value = record[key];\n const valueStr =\n value !== null && typeof value === \"object\" ? JSON.stringify(value) : String(value ?? \"\");\n console.log(`${colors.cyan(key.padEnd(keyWidth))} ${valueStr}`);\n }\n }\n\n success(message: string): void {\n if (this.format === \"json\") {\n console.log(JSON.stringify({ status: \"success\", message }));\n } else {\n console.log(colors.green(`✓ ${message}`));\n }\n }\n\n error(message: string, details?: unknown): void {\n if (this.format === \"json\") {\n console.error(JSON.stringify({ status: \"error\", message, details }));\n } else {\n console.error(colors.red(`✗ ${message}`));\n if (details !== undefined) {\n console.error(details);\n }\n }\n }\n\n warning(message: string): void {\n if (this.format === \"json\") {\n console.log(JSON.stringify({ status: \"warning\", message }));\n } else {\n console.log(colors.yellow(`⚠ ${message}`));\n }\n }\n\n info(message: string): void {\n if (this.format === \"json\") {\n console.log(JSON.stringify({ status: \"info\", message }));\n } else {\n console.log(colors.cyan(message));\n }\n }\n\n private outputTable(data: unknown): void {\n if (Array.isArray(data) && data.length > 0) {\n const headers = Object.keys(data[0] as Record<string, unknown>);\n const colWidths = headers.map((h) => {\n const maxDataWidth = Math.max(\n ...data.map((row) => String((row as Record<string, unknown>)[h] ?? \"\").length),\n );\n return Math.max(h.length, maxDataWidth);\n });\n\n // Header\n const headerRow = headers.map((h, i) => h.padEnd(colWidths[i])).join(\" | \");\n console.log(headerRow);\n console.log(colWidths.map((w) => \"-\".repeat(w)).join(\"-+-\"));\n\n // Rows\n for (const row of data) {\n const rowStr = headers\n .map((h, i) => String((row as Record<string, unknown>)[h] ?? \"\").padEnd(colWidths[i]))\n .join(\" | \");\n console.log(rowStr);\n }\n }\n }\n}\nexport const x = { a: 1, b: 2 };\n","/**\n * CLI execution context with dependency injection.\n *\n * Instead of hidden dependencies in command handlers, this module provides\n * explicit dependency passing for testability and transparency.\n */\n\nimport type { HttpClient } from \"@studiometa/forge-api\";\nimport type { ExecutorContext } from \"@studiometa/forge-core\";\n\nimport { type OutputFormat, isOutputFormat } from \"./types.ts\";\n\nimport { HttpClient as ForgeHttpClient } from \"@studiometa/forge-api\";\nimport { ConfigError } from \"./errors.ts\";\nimport { createConfigStore, getToken, getOrganizationSlug } from \"./config.ts\";\nimport { OutputFormatter } from \"./output.ts\";\n\nexport interface CommandOptions {\n [key: string]: string | boolean | string[] | undefined;\n format?: string;\n f?: string;\n token?: string;\n \"no-color\"?: boolean;\n}\n\n/**\n * Context containing all dependencies needed by command handlers.\n */\nexport interface CommandContext {\n /** Output formatter for the current format */\n readonly formatter: OutputFormatter;\n /** Raw CLI options */\n readonly options: CommandOptions;\n /** Create an ExecutorContext from this command context */\n createExecutorContext(token: string): ExecutorContext;\n /** Resolve the API token or throw ConfigError */\n getToken(): string;\n}\n\n/**\n * Creates a command context from CLI options.\n */\nexport function createContext(options: CommandOptions = {}): CommandContext {\n const rawFormat = options.format ?? options.f ?? \"human\";\n const format: OutputFormat = isOutputFormat(rawFormat) ? rawFormat : \"human\";\n const noColor = options[\"no-color\"] === true;\n const formatter = new OutputFormatter(format, noColor);\n\n return {\n formatter,\n options,\n\n createExecutorContext(token: string): ExecutorContext {\n const client: HttpClient = new ForgeHttpClient({ token });\n const orgSlug =\n (typeof options.org === \"string\" && options.org) ||\n getOrganizationSlug(createConfigStore()) ||\n undefined;\n return { client, organizationSlug: orgSlug };\n },\n\n getToken(): string {\n // 1. CLI arg\n if (typeof options.token === \"string\" && options.token) {\n return options.token;\n }\n // 2. Env var / config file\n const stored = getToken(createConfigStore());\n if (stored) {\n return stored;\n }\n // 3. Not found — throw\n throw ConfigError.missingToken();\n },\n };\n}\n\n/**\n * Creates a test context for unit tests.\n *\n * @example\n * ```typescript\n * const ctx = createTestContext({\n * mockClient: { get: async () => ({ servers: [] }) } as never,\n * });\n * ```\n */\nexport function createTestContext(overrides: {\n options?: CommandOptions;\n formatter?: OutputFormatter;\n token?: string;\n mockClient?: HttpClient;\n}): CommandContext {\n const opts: CommandOptions = overrides.options ?? {\n format: \"json\",\n \"no-color\": true,\n };\n const rawFormat = opts.format ?? \"json\";\n const format: OutputFormat = isOutputFormat(rawFormat) ? rawFormat : \"json\";\n const formatter = overrides.formatter ?? new OutputFormatter(format, true);\n\n return {\n formatter,\n options: opts,\n createExecutorContext(_token: string): ExecutorContext {\n if (!overrides.mockClient) {\n throw new Error(\n \"createTestContext: provide mockClient to use createExecutorContext in tests\",\n );\n }\n return { client: overrides.mockClient, organizationSlug: \"test-org\" };\n },\n getToken(): string {\n if (overrides.token) return overrides.token;\n if (typeof opts.token === \"string\") return opts.token;\n return \"test-token\";\n },\n };\n}\n","/**\n * Centralized error handling for forge.\n */\n\nimport type { OutputFormatter } from \"./output.ts\";\n\nimport { ApiError, CliError, ConfigError, ValidationError, isCliError } from \"./errors.ts\";\n\n/**\n * Exit codes for different error categories.\n */\nexport const ExitCode = {\n SUCCESS: 0,\n GENERAL_ERROR: 1,\n AUTHENTICATION_ERROR: 2,\n VALIDATION_ERROR: 3,\n CONFIG_ERROR: 4,\n NOT_FOUND_ERROR: 5,\n} as const;\n\nexport type ExitCode = (typeof ExitCode)[keyof typeof ExitCode];\n\n/**\n * Determine the appropriate exit code for an error.\n */\nexport function getExitCode(error: unknown): ExitCode {\n if (error instanceof ValidationError) {\n return ExitCode.VALIDATION_ERROR;\n }\n if (error instanceof ApiError) {\n if (error.statusCode === 401) return ExitCode.AUTHENTICATION_ERROR;\n if (error.statusCode === 404) return ExitCode.NOT_FOUND_ERROR;\n }\n if (isCliError(error) && error.code === \"CONFIG_ERROR\") {\n return ExitCode.CONFIG_ERROR;\n }\n return ExitCode.GENERAL_ERROR;\n}\n\n/**\n * Central error handler for all commands.\n */\nexport function handleError(\n error: unknown,\n formatter: OutputFormatter,\n options?: { exit?: boolean },\n): ExitCode {\n const shouldExit = options?.exit ?? true;\n\n let cliError: CliError;\n if (isCliError(error)) {\n cliError = error;\n } else {\n cliError = ApiError.fromForgeError(error);\n }\n\n // Output error in appropriate format\n if (formatter.isJson()) {\n formatter.output(cliError.toJSON());\n } else {\n formatter.error(cliError.toFormattedMessage());\n }\n\n const exitCode = getExitCode(cliError);\n\n if (shouldExit) {\n process.exit(exitCode);\n }\n\n return exitCode;\n}\n\n/**\n * Wraps a command function with automatic error handling.\n */\nexport async function runCommand<T>(\n fn: () => Promise<T>,\n formatter: OutputFormatter,\n): Promise<T | undefined> {\n try {\n return await fn();\n } catch (error) {\n handleError(error, formatter);\n return undefined; // unreachable due to process.exit\n }\n}\n\n/**\n * Exits with a validation error for a missing required argument.\n */\nexport function exitWithValidationError(\n field: string,\n usage: string,\n formatter: OutputFormatter,\n): never {\n const error = ValidationError.required(field, [`Usage: ${usage}`]);\n handleError(error, formatter);\n // Unreachable in production\n throw error;\n}\n\n/**\n * Exits with a config error when token is missing.\n */\nexport function exitWithConfigError(formatter: OutputFormatter): never {\n const error = ConfigError.missingToken();\n handleError(error, formatter);\n throw error;\n}\n"],"mappings":"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"}
|