@kzheart_/mc-pilot 0.8.0 → 0.9.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/chat.js +3 -3
- package/dist/commands/client.d.ts +1 -1
- package/dist/commands/client.js +3 -3
- package/dist/commands/gui.js +8 -3
- package/dist/commands/plugin.js +3 -3
- package/dist/commands/project.js +22 -30
- package/dist/commands/request-helpers.d.ts +2 -0
- package/dist/commands/request-helpers.js +18 -0
- package/dist/commands/screenshot.js +10 -7
- package/dist/commands/server.js +7 -7
- package/dist/index.js +4 -1
- package/dist/util/command.js +2 -2
- package/dist/util/context.d.ts +3 -0
- package/dist/util/context.js +10 -3
- package/dist/util/paths.d.ts +2 -0
- package/dist/util/paths.js +6 -0
- package/dist/util/project.d.ts +16 -4
- package/dist/util/project.js +63 -8
- package/package.json +1 -1
package/dist/commands/chat.js
CHANGED
|
@@ -11,7 +11,7 @@ function normalizeChatCommand(text) {
|
|
|
11
11
|
return command;
|
|
12
12
|
}
|
|
13
13
|
async function executeServerCommand(context, serverName, command) {
|
|
14
|
-
const manager = new ServerInstanceManager(context.globalState, context.
|
|
14
|
+
const manager = new ServerInstanceManager(context.globalState, context.projectId);
|
|
15
15
|
const result = await manager.exec(serverName, command);
|
|
16
16
|
return {
|
|
17
17
|
...result,
|
|
@@ -50,7 +50,7 @@ export function createChatCommand() {
|
|
|
50
50
|
if (preferredClient) {
|
|
51
51
|
return sendClientRequest(context, preferredClient, "chat.command", { command: commandText });
|
|
52
52
|
}
|
|
53
|
-
if (!context.
|
|
53
|
+
if (!context.projectId) {
|
|
54
54
|
return sendClientRequest(context, undefined, "chat.command", { command: commandText });
|
|
55
55
|
}
|
|
56
56
|
const serverName = options.server ?? context.activeProfile?.server;
|
|
@@ -65,7 +65,7 @@ export function createChatCommand() {
|
|
|
65
65
|
if (via !== "server") {
|
|
66
66
|
throw new MctError({ code: "INVALID_PARAMS", message: `--via must be \"auto\", \"server\" or \"client\", got: ${via}` }, 4);
|
|
67
67
|
}
|
|
68
|
-
if (!context.
|
|
68
|
+
if (!context.projectId) {
|
|
69
69
|
throw new MctError({ code: "NO_PROJECT", message: "--via server requires a project context. Use --via client or run inside an mct project." }, 4);
|
|
70
70
|
}
|
|
71
71
|
const serverName = options.server ?? context.activeProfile?.server;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
2
|
import type { CommandContext } from "../util/context.js";
|
|
3
|
-
export declare function resolveProfileServerAddress(context: Pick<CommandContext, "
|
|
3
|
+
export declare function resolveProfileServerAddress(context: Pick<CommandContext, "projectId" | "activeProfile" | "globalState">, explicitServer: string | undefined, loadPort?: (projectId: string, serverName: string) => Promise<number>): Promise<string | undefined>;
|
|
4
4
|
export declare function createClientCommand(): Command;
|
package/dist/commands/client.js
CHANGED
|
@@ -17,13 +17,13 @@ export async function resolveProfileServerAddress(context, explicitServer, loadP
|
|
|
17
17
|
if (explicitServer) {
|
|
18
18
|
return explicitServer;
|
|
19
19
|
}
|
|
20
|
-
if (!context.
|
|
20
|
+
if (!context.projectId || !context.activeProfile?.server) {
|
|
21
21
|
return undefined;
|
|
22
22
|
}
|
|
23
23
|
try {
|
|
24
24
|
const port = loadPort
|
|
25
|
-
? await loadPort(context.
|
|
26
|
-
: (await new ServerInstanceManager(context.globalState, context.
|
|
25
|
+
? await loadPort(context.projectId, context.activeProfile.server)
|
|
26
|
+
: (await new ServerInstanceManager(context.globalState, context.projectId).loadMeta(context.activeProfile.server)).port;
|
|
27
27
|
return `127.0.0.1:${port}`;
|
|
28
28
|
}
|
|
29
29
|
catch {
|
package/dist/commands/gui.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
-
import {
|
|
2
|
+
import { wrapCommand } from "../util/command.js";
|
|
3
|
+
import { createRequestAction, parseNumberList, resolveScreenshotOutputPath, sendClientRequest, withTransportTimeoutBuffer } from "./request-helpers.js";
|
|
3
4
|
export function createGuiCommand() {
|
|
4
5
|
const command = new Command("gui").description("GUI / container interaction (use \"gui snapshot\" to inspect slot indices and contents)");
|
|
5
6
|
command.command("info").description("Get current GUI info (title, type, slot count)").action(createRequestAction("gui.info", () => ({})));
|
|
@@ -43,7 +44,11 @@ export function createGuiCommand() {
|
|
|
43
44
|
command
|
|
44
45
|
.command("screenshot")
|
|
45
46
|
.description("Take a screenshot of the current GUI")
|
|
46
|
-
.
|
|
47
|
-
.action(
|
|
47
|
+
.option("--output <path>", "Output file path (default: project screenshot directory)")
|
|
48
|
+
.action(wrapCommand(async (context, { options, globalOptions }) => {
|
|
49
|
+
return sendClientRequest(context, globalOptions.client ?? context.activeProfile?.clients[0], "gui.screenshot", {
|
|
50
|
+
output: resolveScreenshotOutputPath(context, options.output, "gui")
|
|
51
|
+
});
|
|
52
|
+
}));
|
|
48
53
|
return command;
|
|
49
54
|
}
|
package/dist/commands/plugin.js
CHANGED
|
@@ -69,11 +69,11 @@ export function createPluginCommand() {
|
|
|
69
69
|
.description("Install a plugin (with dependencies) to a server")
|
|
70
70
|
.argument("<id>", "Plugin ID")
|
|
71
71
|
.requiredOption("--server <name>", "Target server instance name")
|
|
72
|
-
.option("--project <
|
|
72
|
+
.option("--project <id>", "Project ID")
|
|
73
73
|
.action(wrapCommand(async (context, { args, options }) => {
|
|
74
|
-
const project = options.project ?? context.
|
|
74
|
+
const project = options.project ?? context.projectId;
|
|
75
75
|
if (!project) {
|
|
76
|
-
throw new MctError({ code: "NO_PROJECT", message: "No project specified. Use --project or run from a project directory." }, 4);
|
|
76
|
+
throw new MctError({ code: "NO_PROJECT", message: "No project specified. Use --project <id> or run from a project directory." }, 4);
|
|
77
77
|
}
|
|
78
78
|
const manager = new PluginCatalogManager();
|
|
79
79
|
return manager.install(args[0], project, options.server);
|
package/dist/commands/project.js
CHANGED
|
@@ -4,34 +4,26 @@ import { ServerInstanceManager } from "../instance/ServerInstanceManager.js";
|
|
|
4
4
|
import { ClientInstanceManager } from "../instance/ClientInstanceManager.js";
|
|
5
5
|
import { MctError } from "../util/errors.js";
|
|
6
6
|
import { wrapCommand } from "../util/command.js";
|
|
7
|
-
import {
|
|
7
|
+
import { createDefaultProjectFile, loadProjectFileForCwd, resolveProjectFilePath, resolveProfile, writeProjectFile, } from "../util/project.js";
|
|
8
8
|
export function createInitCommand() {
|
|
9
9
|
return new Command("init")
|
|
10
|
-
.description("Initialize a new MC Pilot project
|
|
10
|
+
.description("Initialize a new MC Pilot project for the current directory")
|
|
11
11
|
.option("--name <name>", "Project name (default: directory name)")
|
|
12
12
|
.action(wrapCommand(async (context, { options }) => {
|
|
13
|
-
const existing = await
|
|
13
|
+
const existing = await loadProjectFileForCwd(context.cwd);
|
|
14
14
|
if (existing) {
|
|
15
|
-
throw new MctError({ code: "PROJECT_EXISTS", message:
|
|
15
|
+
throw new MctError({ code: "PROJECT_EXISTS", message: `Project config already exists for this directory: ${existing.filePath}` }, 4);
|
|
16
16
|
}
|
|
17
17
|
const projectName = options.name ?? path.basename(context.cwd);
|
|
18
|
-
const project =
|
|
19
|
-
|
|
20
|
-
profiles: {},
|
|
21
|
-
screenshot: {
|
|
22
|
-
outputDir: "./screenshots"
|
|
23
|
-
},
|
|
24
|
-
timeout: {
|
|
25
|
-
serverReady: 120,
|
|
26
|
-
clientReady: 60,
|
|
27
|
-
default: 10
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
await writeProjectFile(context.cwd, project);
|
|
18
|
+
const project = createDefaultProjectFile(context.cwd, projectName);
|
|
19
|
+
await writeProjectFile(project.projectId, project);
|
|
31
20
|
return {
|
|
32
21
|
created: true,
|
|
22
|
+
projectId: project.projectId,
|
|
33
23
|
project: projectName,
|
|
34
|
-
|
|
24
|
+
rootDir: project.rootDir,
|
|
25
|
+
file: resolveProjectFilePath(project.projectId),
|
|
26
|
+
configPath: resolveProjectFilePath(project.projectId)
|
|
35
27
|
};
|
|
36
28
|
}));
|
|
37
29
|
}
|
|
@@ -40,8 +32,8 @@ export function createDeployCommand() {
|
|
|
40
32
|
.description("Deploy plugin JARs to the server instance")
|
|
41
33
|
.option("--profile <name>", "Profile name")
|
|
42
34
|
.action(wrapCommand(async (context, { options }) => {
|
|
43
|
-
const { projectFile,
|
|
44
|
-
if (!projectFile || !
|
|
35
|
+
const { projectFile, projectId, projectRootDir } = context;
|
|
36
|
+
if (!projectFile || !projectId || !projectRootDir) {
|
|
45
37
|
throw new MctError({ code: "NO_PROJECT", message: "No project context. Run 'mct init' first." }, 4);
|
|
46
38
|
}
|
|
47
39
|
const profile = resolveProfile(projectFile, options.profile ?? projectFile.defaultProfile);
|
|
@@ -51,8 +43,8 @@ export function createDeployCommand() {
|
|
|
51
43
|
if (!profile.deployPlugins || profile.deployPlugins.length === 0) {
|
|
52
44
|
return { deployed: [], message: "No deployPlugins configured in profile" };
|
|
53
45
|
}
|
|
54
|
-
const manager = new ServerInstanceManager(context.globalState,
|
|
55
|
-
const deployed = await manager.deploy(profile.server, profile.deployPlugins,
|
|
46
|
+
const manager = new ServerInstanceManager(context.globalState, projectId);
|
|
47
|
+
const deployed = await manager.deploy(profile.server, profile.deployPlugins, projectRootDir);
|
|
56
48
|
return { deployed, server: profile.server };
|
|
57
49
|
}));
|
|
58
50
|
}
|
|
@@ -62,20 +54,20 @@ export function createUpCommand() {
|
|
|
62
54
|
.option("--profile <name>", "Profile name")
|
|
63
55
|
.option("--eula", "Auto-accept EULA")
|
|
64
56
|
.action(wrapCommand(async (context, { options }) => {
|
|
65
|
-
const { projectFile,
|
|
66
|
-
if (!projectFile || !
|
|
57
|
+
const { projectFile, projectId, projectRootDir } = context;
|
|
58
|
+
if (!projectFile || !projectId || !projectRootDir) {
|
|
67
59
|
throw new MctError({ code: "NO_PROJECT", message: "No project context. Run 'mct init' first." }, 4);
|
|
68
60
|
}
|
|
69
61
|
const profile = resolveProfile(projectFile, options.profile ?? projectFile.defaultProfile);
|
|
70
62
|
if (!profile) {
|
|
71
63
|
throw new MctError({ code: "NO_PROFILE", message: "No profile specified and no defaultProfile set" }, 4);
|
|
72
64
|
}
|
|
73
|
-
const serverManager = new ServerInstanceManager(context.globalState,
|
|
65
|
+
const serverManager = new ServerInstanceManager(context.globalState, projectId);
|
|
74
66
|
const clientManager = new ClientInstanceManager(context.globalState);
|
|
75
67
|
const results = {};
|
|
76
68
|
// 1. Deploy plugins
|
|
77
69
|
if (profile.deployPlugins && profile.deployPlugins.length > 0) {
|
|
78
|
-
results.deployed = await serverManager.deploy(profile.server, profile.deployPlugins,
|
|
70
|
+
results.deployed = await serverManager.deploy(profile.server, profile.deployPlugins, projectRootDir);
|
|
79
71
|
}
|
|
80
72
|
// 2. Start server
|
|
81
73
|
results.server = await serverManager.start(profile.server, { eula: options.eula });
|
|
@@ -109,15 +101,15 @@ export function createDownCommand() {
|
|
|
109
101
|
.description("Stop server and clients for the active profile")
|
|
110
102
|
.option("--profile <name>", "Profile name")
|
|
111
103
|
.action(wrapCommand(async (context, { options }) => {
|
|
112
|
-
const { projectFile,
|
|
113
|
-
if (!projectFile || !
|
|
104
|
+
const { projectFile, projectId } = context;
|
|
105
|
+
if (!projectFile || !projectId) {
|
|
114
106
|
throw new MctError({ code: "NO_PROJECT", message: "No project context. Run 'mct init' first." }, 4);
|
|
115
107
|
}
|
|
116
108
|
const profile = resolveProfile(projectFile, options.profile ?? projectFile.defaultProfile);
|
|
117
109
|
if (!profile) {
|
|
118
110
|
throw new MctError({ code: "NO_PROFILE", message: "No profile specified and no defaultProfile set" }, 4);
|
|
119
111
|
}
|
|
120
|
-
const serverManager = new ServerInstanceManager(context.globalState,
|
|
112
|
+
const serverManager = new ServerInstanceManager(context.globalState, projectId);
|
|
121
113
|
const clientManager = new ClientInstanceManager(context.globalState);
|
|
122
114
|
const results = {};
|
|
123
115
|
// Stop clients first
|
|
@@ -155,7 +147,7 @@ export function createUseCommand() {
|
|
|
155
147
|
}, 4);
|
|
156
148
|
}
|
|
157
149
|
projectFile.defaultProfile = profileName;
|
|
158
|
-
await writeProjectFile(
|
|
150
|
+
await writeProjectFile(projectFile.projectId, projectFile);
|
|
159
151
|
return {
|
|
160
152
|
defaultProfile: profileName,
|
|
161
153
|
profile: projectFile.profiles[profileName]
|
|
@@ -7,6 +7,8 @@ export interface RequestPayload<TOptions> {
|
|
|
7
7
|
}
|
|
8
8
|
export declare function sendClientRequest(context: CommandContext, clientName: string | undefined, action: string, params: Record<string, unknown>, timeoutSeconds?: number): Promise<unknown>;
|
|
9
9
|
export declare function resolvePreferredClientName(context: CommandContext, globalOptions: GlobalOptions): string | undefined;
|
|
10
|
+
export declare function resolveProjectRelativePath(context: CommandContext, targetPath: string): string;
|
|
11
|
+
export declare function resolveScreenshotOutputPath(context: CommandContext, output: string | undefined, prefix: "screenshot" | "gui"): string;
|
|
10
12
|
export declare function createRequestAction<TOptions = Record<string, any>>(action: string, buildParams: (payload: RequestPayload<TOptions>) => Record<string, unknown>, timeoutSelector?: (payload: RequestPayload<TOptions>, context: CommandContext) => number | undefined): (this: Command, ...input: unknown[]) => Promise<void>;
|
|
11
13
|
export declare function parseJson(text: string, fieldName: string): Record<string, unknown>;
|
|
12
14
|
export declare function parseNumberList(text: string): number[];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
+
import path from "node:path";
|
|
2
3
|
import { ClientInstanceManager } from "../instance/ClientInstanceManager.js";
|
|
3
4
|
import { WebSocketClient } from "../client/WebSocketClient.js";
|
|
4
5
|
import { MctError } from "../util/errors.js";
|
|
@@ -12,6 +13,23 @@ export async function sendClientRequest(context, clientName, action, params, tim
|
|
|
12
13
|
export function resolvePreferredClientName(context, globalOptions) {
|
|
13
14
|
return globalOptions.client ?? context.activeProfile?.clients[0];
|
|
14
15
|
}
|
|
16
|
+
export function resolveProjectRelativePath(context, targetPath) {
|
|
17
|
+
if (path.isAbsolute(targetPath)) {
|
|
18
|
+
return targetPath;
|
|
19
|
+
}
|
|
20
|
+
return path.resolve(context.projectRootDir ?? context.cwd, targetPath);
|
|
21
|
+
}
|
|
22
|
+
export function resolveScreenshotOutputPath(context, output, prefix) {
|
|
23
|
+
if (output) {
|
|
24
|
+
return resolveProjectRelativePath(context, output);
|
|
25
|
+
}
|
|
26
|
+
const outputDir = context.projectFile?.screenshot?.outputDir;
|
|
27
|
+
if (!outputDir) {
|
|
28
|
+
throw new MctError({ code: "INVALID_PARAMS", message: "--output is required outside a project context." }, 4);
|
|
29
|
+
}
|
|
30
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
31
|
+
return path.join(outputDir, `${prefix}-${timestamp}.png`);
|
|
32
|
+
}
|
|
15
33
|
export function createRequestAction(action, buildParams, timeoutSelector) {
|
|
16
34
|
return wrapCommand(async (context, payload) => {
|
|
17
35
|
const timeout = timeoutSelector?.(payload, context);
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
-
import {
|
|
2
|
+
import { wrapCommand } from "../util/command.js";
|
|
3
|
+
import { resolveScreenshotOutputPath, sendClientRequest } from "./request-helpers.js";
|
|
3
4
|
export function createScreenshotCommand() {
|
|
4
5
|
return new Command("screenshot")
|
|
5
6
|
.description("Take a screenshot")
|
|
6
|
-
.
|
|
7
|
+
.option("--output <path>", "Output file path (default: project screenshot directory)")
|
|
7
8
|
.option("--region <region>", "Capture a sub-region, format: x,y,w,h")
|
|
8
9
|
.option("--gui", "Capture the current GUI screen")
|
|
9
|
-
.action(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
.action(wrapCommand(async (context, { options, globalOptions }) => {
|
|
11
|
+
return sendClientRequest(context, globalOptions.client ?? context.activeProfile?.clients[0], "capture.screenshot", {
|
|
12
|
+
output: resolveScreenshotOutputPath(context, options.output, "screenshot"),
|
|
13
|
+
region: options.region,
|
|
14
|
+
gui: Boolean(options.gui)
|
|
15
|
+
});
|
|
16
|
+
}));
|
|
14
17
|
}
|
package/dist/commands/server.js
CHANGED
|
@@ -5,10 +5,10 @@ import { ServerInstanceManager } from "../instance/ServerInstanceManager.js";
|
|
|
5
5
|
import { MctError } from "../util/errors.js";
|
|
6
6
|
import { wrapCommand } from "../util/command.js";
|
|
7
7
|
function requireProject(context) {
|
|
8
|
-
if (!context.
|
|
9
|
-
throw new MctError({ code: "NO_PROJECT", message: "No project context. Run 'mct init' first or use --project <
|
|
8
|
+
if (!context.projectId) {
|
|
9
|
+
throw new MctError({ code: "NO_PROJECT", message: "No project context. Run 'mct init' first or use --project <id>" }, 4);
|
|
10
10
|
}
|
|
11
|
-
return context.
|
|
11
|
+
return context.projectId;
|
|
12
12
|
}
|
|
13
13
|
function resolveServerName(context, explicit) {
|
|
14
14
|
if (explicit)
|
|
@@ -90,13 +90,13 @@ export function createServerCommand() {
|
|
|
90
90
|
.argument("[name]", "Server instance name (omit to show all in project)")
|
|
91
91
|
.option("--all", "Show running servers across all projects")
|
|
92
92
|
.action(wrapCommand(async (context, { args, options }) => {
|
|
93
|
-
if (options.all || (!context.
|
|
93
|
+
if (options.all || (!context.projectId && !args[0])) {
|
|
94
94
|
return ServerInstanceManager.statusAll(context.globalState);
|
|
95
95
|
}
|
|
96
|
-
if (!context.
|
|
97
|
-
throw new MctError({ code: "NO_PROJECT", message: "No project context. Omit the name to inspect all running servers, or use --project <
|
|
96
|
+
if (!context.projectId) {
|
|
97
|
+
throw new MctError({ code: "NO_PROJECT", message: "No project context. Omit the name to inspect all running servers, or use --project <id>." }, 4);
|
|
98
98
|
}
|
|
99
|
-
const manager = new ServerInstanceManager(context.globalState, context.
|
|
99
|
+
const manager = new ServerInstanceManager(context.globalState, context.projectId);
|
|
100
100
|
return manager.status(args[0]);
|
|
101
101
|
}));
|
|
102
102
|
command
|
package/dist/index.js
CHANGED
|
@@ -37,7 +37,7 @@ export function buildProgram() {
|
|
|
37
37
|
"Control a real Minecraft client via CLI to simulate player actions and verify plugin behavior.\n" +
|
|
38
38
|
"All commands output JSON by default. Use --human for human-readable output.\n\n" +
|
|
39
39
|
"Quick start:\n" +
|
|
40
|
-
" mct init --
|
|
40
|
+
" mct init --name my-plugin\n" +
|
|
41
41
|
" mct server create paper-1.20.4 --type paper --version 1.20.4\n" +
|
|
42
42
|
" mct client create fabric-1.20.4 --version 1.20.4\n" +
|
|
43
43
|
" mct up --profile 1.20\n" +
|
|
@@ -53,7 +53,10 @@ export function buildProgram() {
|
|
|
53
53
|
.action(wrapCommand(async (context) => {
|
|
54
54
|
return {
|
|
55
55
|
cwd: context.cwd,
|
|
56
|
+
projectId: context.projectId,
|
|
56
57
|
project: context.projectName,
|
|
58
|
+
projectRootDir: context.projectRootDir,
|
|
59
|
+
projectConfigPath: context.projectConfigPath,
|
|
57
60
|
activeProfile: context.activeProfile,
|
|
58
61
|
globalStateDir: context.globalState.getRootDir()
|
|
59
62
|
};
|
package/dist/util/command.js
CHANGED
|
@@ -5,8 +5,8 @@ import { printError, printSuccess } from "./output.js";
|
|
|
5
5
|
export function attachGlobalOptions(command) {
|
|
6
6
|
return command
|
|
7
7
|
.option("--human", "Human-readable output (default: JSON)")
|
|
8
|
-
.option("--project <
|
|
9
|
-
.option("--profile <name>", "Profile name (default: from mct
|
|
8
|
+
.option("--project <id>", "Project ID (default: derived from cwd and loaded from ~/.mct/projects/<id>/project.json)")
|
|
9
|
+
.option("--profile <name>", "Profile name (default: from ~/.mct/projects/<id>/project.json)")
|
|
10
10
|
.option("--client <name>", "Target client name (required when multiple clients are running)");
|
|
11
11
|
}
|
|
12
12
|
export function wrapCommand(action) {
|
package/dist/util/context.d.ts
CHANGED
|
@@ -13,7 +13,10 @@ export interface CommandContext {
|
|
|
13
13
|
globalState: GlobalStateStore;
|
|
14
14
|
projectFile: MctProjectFile | null;
|
|
15
15
|
activeProfile: MctProfile | null;
|
|
16
|
+
projectId: string | null;
|
|
16
17
|
projectName: string | null;
|
|
18
|
+
projectRootDir: string | null;
|
|
19
|
+
projectConfigPath: string | null;
|
|
17
20
|
timeout(key: "serverReady" | "clientReady" | "default"): number;
|
|
18
21
|
}
|
|
19
22
|
export declare function createCommandContext(options: GlobalOptions): Promise<CommandContext>;
|
package/dist/util/context.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import process from "node:process";
|
|
2
2
|
import { GlobalStateStore } from "./global-state.js";
|
|
3
|
-
import {
|
|
3
|
+
import { loadProjectFileForCwd, loadProjectFileForId, resolveProfile } from "./project.js";
|
|
4
4
|
const TIMEOUT_DEFAULTS = {
|
|
5
5
|
serverReady: 120,
|
|
6
6
|
clientReady: 60,
|
|
@@ -9,8 +9,12 @@ const TIMEOUT_DEFAULTS = {
|
|
|
9
9
|
export async function createCommandContext(options) {
|
|
10
10
|
const cwd = process.cwd();
|
|
11
11
|
const globalState = new GlobalStateStore();
|
|
12
|
-
const
|
|
13
|
-
|
|
12
|
+
const resolvedProject = options.project
|
|
13
|
+
? await loadProjectFileForId(options.project)
|
|
14
|
+
: await loadProjectFileForCwd(cwd);
|
|
15
|
+
const projectFile = resolvedProject?.projectFile ?? null;
|
|
16
|
+
const projectId = options.project ?? resolvedProject?.projectId ?? null;
|
|
17
|
+
const projectName = projectFile?.project ?? null;
|
|
14
18
|
const activeProfile = projectFile
|
|
15
19
|
? resolveProfile(projectFile, options.profile)
|
|
16
20
|
: null;
|
|
@@ -20,7 +24,10 @@ export async function createCommandContext(options) {
|
|
|
20
24
|
globalState,
|
|
21
25
|
projectFile,
|
|
22
26
|
activeProfile,
|
|
27
|
+
projectId,
|
|
23
28
|
projectName,
|
|
29
|
+
projectRootDir: projectFile?.rootDir ?? null,
|
|
30
|
+
projectConfigPath: resolvedProject?.filePath ?? null,
|
|
24
31
|
timeout(key) {
|
|
25
32
|
return projectFile?.timeout?.[key] ?? TIMEOUT_DEFAULTS[key];
|
|
26
33
|
}
|
package/dist/util/paths.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ export declare function resolveClientsDir(): string;
|
|
|
3
3
|
export declare function resolveClientInstanceDir(name: string): string;
|
|
4
4
|
export declare function resolveProjectsDir(): string;
|
|
5
5
|
export declare function resolveProjectDir(project: string): string;
|
|
6
|
+
export declare function resolveProjectConfigPath(project: string): string;
|
|
7
|
+
export declare function resolveProjectScreenshotsDir(project: string): string;
|
|
6
8
|
export declare function resolveServerInstanceDir(project: string, server: string): string;
|
|
7
9
|
export declare function resolveGlobalStateDir(): string;
|
|
8
10
|
export declare function resolvePluginsDir(): string;
|
package/dist/util/paths.js
CHANGED
|
@@ -15,6 +15,12 @@ export function resolveProjectsDir() {
|
|
|
15
15
|
export function resolveProjectDir(project) {
|
|
16
16
|
return path.join(resolveProjectsDir(), project);
|
|
17
17
|
}
|
|
18
|
+
export function resolveProjectConfigPath(project) {
|
|
19
|
+
return path.join(resolveProjectDir(project), "project.json");
|
|
20
|
+
}
|
|
21
|
+
export function resolveProjectScreenshotsDir(project) {
|
|
22
|
+
return path.join(resolveProjectDir(project), "screenshots");
|
|
23
|
+
}
|
|
18
24
|
export function resolveServerInstanceDir(project, server) {
|
|
19
25
|
return path.join(resolveProjectDir(project), server);
|
|
20
26
|
}
|
package/dist/util/project.d.ts
CHANGED
|
@@ -4,7 +4,9 @@ export interface MctProfile {
|
|
|
4
4
|
deployPlugins?: string[];
|
|
5
5
|
}
|
|
6
6
|
export interface MctProjectFile {
|
|
7
|
+
projectId: string;
|
|
7
8
|
project: string;
|
|
9
|
+
rootDir: string;
|
|
8
10
|
profiles: Record<string, MctProfile>;
|
|
9
11
|
defaultProfile?: string;
|
|
10
12
|
screenshot?: {
|
|
@@ -16,8 +18,18 @@ export interface MctProjectFile {
|
|
|
16
18
|
default?: number;
|
|
17
19
|
};
|
|
18
20
|
}
|
|
19
|
-
export
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
export interface ResolvedProjectConfig {
|
|
22
|
+
projectId: string;
|
|
23
|
+
filePath: string;
|
|
24
|
+
projectFile: MctProjectFile;
|
|
25
|
+
}
|
|
26
|
+
export declare const PROJECT_FILE_NAME = "project.json";
|
|
27
|
+
export declare function normalizeProjectRoot(cwd: string): string;
|
|
28
|
+
export declare function slugifyProjectId(cwd: string): string;
|
|
29
|
+
export declare function resolveProjectFilePath(projectId: string): string;
|
|
30
|
+
export declare function loadProjectFileById(projectId: string): Promise<MctProjectFile | null>;
|
|
31
|
+
export declare function loadProjectFileForCwd(cwd: string): Promise<ResolvedProjectConfig | null>;
|
|
32
|
+
export declare function loadProjectFileForId(projectId: string): Promise<ResolvedProjectConfig | null>;
|
|
33
|
+
export declare function writeProjectFile(projectId: string, project: MctProjectFile): Promise<void>;
|
|
34
|
+
export declare function createDefaultProjectFile(cwd: string, projectName: string): MctProjectFile;
|
|
23
35
|
export declare function resolveProfile(projectFile: MctProjectFile, profileName?: string): MctProfile | null;
|
package/dist/util/project.js
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { realpathSync } from "node:fs";
|
|
2
|
+
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
3
|
import path from "node:path";
|
|
3
|
-
|
|
4
|
-
export
|
|
5
|
-
|
|
4
|
+
import { resolveProjectConfigPath, resolveProjectScreenshotsDir } from "./paths.js";
|
|
5
|
+
export const PROJECT_FILE_NAME = "project.json";
|
|
6
|
+
export function normalizeProjectRoot(cwd) {
|
|
7
|
+
try {
|
|
8
|
+
return realpathSync(cwd);
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return path.resolve(cwd);
|
|
12
|
+
}
|
|
6
13
|
}
|
|
7
|
-
export
|
|
8
|
-
|
|
14
|
+
export function slugifyProjectId(cwd) {
|
|
15
|
+
return cwd.replace(/[^A-Za-z0-9._-]/g, "-").replace(/-+/g, "-");
|
|
16
|
+
}
|
|
17
|
+
export function resolveProjectFilePath(projectId) {
|
|
18
|
+
return resolveProjectConfigPath(projectId);
|
|
19
|
+
}
|
|
20
|
+
export async function loadProjectFileById(projectId) {
|
|
21
|
+
const filePath = resolveProjectFilePath(projectId);
|
|
9
22
|
try {
|
|
10
23
|
await access(filePath);
|
|
11
24
|
}
|
|
@@ -15,10 +28,52 @@ export async function loadProjectFile(cwd) {
|
|
|
15
28
|
const raw = await readFile(filePath, "utf8");
|
|
16
29
|
return JSON.parse(raw);
|
|
17
30
|
}
|
|
18
|
-
export async function
|
|
19
|
-
const
|
|
31
|
+
export async function loadProjectFileForCwd(cwd) {
|
|
32
|
+
const projectId = slugifyProjectId(normalizeProjectRoot(cwd));
|
|
33
|
+
const projectFile = await loadProjectFileById(projectId);
|
|
34
|
+
if (!projectFile) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
projectId,
|
|
39
|
+
filePath: resolveProjectFilePath(projectId),
|
|
40
|
+
projectFile
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export async function loadProjectFileForId(projectId) {
|
|
44
|
+
const projectFile = await loadProjectFileById(projectId);
|
|
45
|
+
if (!projectFile) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
projectId,
|
|
50
|
+
filePath: resolveProjectFilePath(projectId),
|
|
51
|
+
projectFile
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export async function writeProjectFile(projectId, project) {
|
|
55
|
+
const filePath = resolveProjectFilePath(projectId);
|
|
56
|
+
await mkdir(path.dirname(filePath), { recursive: true });
|
|
20
57
|
await writeFile(filePath, `${JSON.stringify(project, null, 2)}\n`, "utf8");
|
|
21
58
|
}
|
|
59
|
+
export function createDefaultProjectFile(cwd, projectName) {
|
|
60
|
+
const rootDir = normalizeProjectRoot(cwd);
|
|
61
|
+
const projectId = slugifyProjectId(rootDir);
|
|
62
|
+
return {
|
|
63
|
+
projectId,
|
|
64
|
+
project: projectName,
|
|
65
|
+
rootDir,
|
|
66
|
+
profiles: {},
|
|
67
|
+
screenshot: {
|
|
68
|
+
outputDir: resolveProjectScreenshotsDir(projectId)
|
|
69
|
+
},
|
|
70
|
+
timeout: {
|
|
71
|
+
serverReady: 120,
|
|
72
|
+
clientReady: 60,
|
|
73
|
+
default: 10
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
}
|
|
22
77
|
export function resolveProfile(projectFile, profileName) {
|
|
23
78
|
const name = profileName ?? projectFile.defaultProfile;
|
|
24
79
|
if (!name) {
|