@weaver-wow/cli 1.0.0 → 1.1.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/wvr.mjs +3920 -0
- package/package.json +28 -29
- package/src/cli/builder.ts +0 -280
- package/src/cli/commands/build.ts +0 -34
- package/src/cli/commands/dev.ts +0 -92
- package/src/cli/commands/init.ts +0 -228
- package/src/cli/commands/link.ts +0 -126
- package/src/cli/index.ts +0 -31
- package/src/cli/utils/config.ts +0 -16
- package/src/cli/utils/wow-path.ts +0 -44
- package/src/schema.ts +0 -18
package/src/cli/commands/link.ts
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { symlinkSync, existsSync, rmSync, statSync } from "node:fs";
|
|
3
|
-
import { join, resolve } from "node:path";
|
|
4
|
-
import { intro, outro, spinner, confirm, text } from "@clack/prompts";
|
|
5
|
-
import picocolors from "picocolors";
|
|
6
|
-
import { loadConfig } from "../utils/config";
|
|
7
|
-
import { findWoWPath } from "../utils/wow-path";
|
|
8
|
-
|
|
9
|
-
export async function linkCommand() {
|
|
10
|
-
intro(picocolors.bgBlue(" 🧵 Weaver Link "));
|
|
11
|
-
|
|
12
|
-
const s = spinner();
|
|
13
|
-
s.start("Reading configuration...");
|
|
14
|
-
|
|
15
|
-
let config = await loadConfig();
|
|
16
|
-
|
|
17
|
-
// Determine Addon Name
|
|
18
|
-
let addonName = config?.addonName;
|
|
19
|
-
if (!addonName && existsSync("package.json")) {
|
|
20
|
-
try {
|
|
21
|
-
const pkg = JSON.parse(await Bun.file("package.json").text());
|
|
22
|
-
addonName = pkg.name ? pkg.name.charAt(0).toUpperCase() + pkg.name.slice(1) : "MyAddon";
|
|
23
|
-
} catch {}
|
|
24
|
-
}
|
|
25
|
-
addonName = addonName || "MyAddon";
|
|
26
|
-
|
|
27
|
-
// Determine WoW Path
|
|
28
|
-
let wowPath = config?.wowPath;
|
|
29
|
-
if (!wowPath) {
|
|
30
|
-
s.stop("Searching for WoW installation...");
|
|
31
|
-
wowPath = await findWoWPath();
|
|
32
|
-
|
|
33
|
-
if (!wowPath) {
|
|
34
|
-
const manualPath = await text({
|
|
35
|
-
message: "Could not auto-detect WoW. Enter path manually:",
|
|
36
|
-
placeholder: "C:\\Program Files (x86)\\World of Warcraft"
|
|
37
|
-
});
|
|
38
|
-
if (typeof manualPath === 'symbol') process.exit(0);
|
|
39
|
-
wowPath = manualPath as string;
|
|
40
|
-
} else {
|
|
41
|
-
const useFound = await confirm({
|
|
42
|
-
message: `Found WoW at ${picocolors.cyan(wowPath)}. Use this?`,
|
|
43
|
-
initialValue: true
|
|
44
|
-
});
|
|
45
|
-
if (!useFound) {
|
|
46
|
-
const manualPath = await text({
|
|
47
|
-
message: "Enter path manually:",
|
|
48
|
-
placeholder: "C:\\Program Files (x86)\\World of Warcraft"
|
|
49
|
-
});
|
|
50
|
-
if (typeof manualPath === 'symbol') process.exit(0);
|
|
51
|
-
wowPath = manualPath as string;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (!wowPath) {
|
|
57
|
-
console.error(picocolors.red("WoW path is required."));
|
|
58
|
-
process.exit(1);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Determine target directory (Interface/AddOns)
|
|
62
|
-
// Default to retail for now, or use config.flavor
|
|
63
|
-
const flavor = config?.flavor || "_retail_";
|
|
64
|
-
const addonsDir = join(wowPath, flavor, "Interface", "AddOns");
|
|
65
|
-
|
|
66
|
-
if (!existsSync(addonsDir)) {
|
|
67
|
-
console.error(picocolors.red(`Could not find AddOns directory at: ${addonsDir}`));
|
|
68
|
-
console.log(picocolors.yellow(`(Make sure you have run the game at least once to create folders)`));
|
|
69
|
-
process.exit(1);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const targetLinkPath = join(addonsDir, addonName);
|
|
73
|
-
const sourceDistPath = resolve("dist"); // Absolute path to dist
|
|
74
|
-
|
|
75
|
-
if (!existsSync(sourceDistPath)) {
|
|
76
|
-
console.error(picocolors.red("dist/ folder does not exist. Run 'bun wvr build' first."));
|
|
77
|
-
process.exit(1);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
s.start(`Linking ${picocolors.cyan(addonName)} to WoW...`);
|
|
81
|
-
|
|
82
|
-
// Check if link already exists
|
|
83
|
-
if (existsSync(targetLinkPath)) {
|
|
84
|
-
const stats = statSync(targetLinkPath);
|
|
85
|
-
if (stats.isSymbolicLink()) {
|
|
86
|
-
s.stop("Link already exists.");
|
|
87
|
-
// Maybe check where it points?
|
|
88
|
-
outro("Addon is already linked.");
|
|
89
|
-
return;
|
|
90
|
-
} else {
|
|
91
|
-
// It's a real folder?
|
|
92
|
-
s.stop("Target exists as a real folder.");
|
|
93
|
-
const overwrite = await confirm({
|
|
94
|
-
message: `Folder ${targetLinkPath} already exists (not a link). Delete and link?`,
|
|
95
|
-
initialValue: false
|
|
96
|
-
});
|
|
97
|
-
if (!overwrite) {
|
|
98
|
-
outro("Aborted.");
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
s.start("Removing existing folder...");
|
|
102
|
-
try {
|
|
103
|
-
rmSync(targetLinkPath, { recursive: true, force: true }); // Dangerous?
|
|
104
|
-
} catch (e) {
|
|
105
|
-
s.stop(picocolors.red("Failed to remove existing folder."));
|
|
106
|
-
console.error(e);
|
|
107
|
-
process.exit(1);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Create Symlink
|
|
113
|
-
try {
|
|
114
|
-
// Use "junction" for Windows directory links without admin
|
|
115
|
-
const type = process.platform === "win32" ? "junction" : "dir";
|
|
116
|
-
symlinkSync(sourceDistPath, targetLinkPath, type);
|
|
117
|
-
} catch (e) {
|
|
118
|
-
s.stop(picocolors.red("Failed to create symlink"));
|
|
119
|
-
console.error("Error details:", e);
|
|
120
|
-
console.log(picocolors.yellow("Try running as Administrator if on Windows."));
|
|
121
|
-
process.exit(1);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
s.stop(picocolors.green("Linked successfully!"));
|
|
125
|
-
outro(`Dev changes in ${picocolors.bold("dist/")} will now reflect in WoW immediately.`);
|
|
126
|
-
}
|
package/src/cli/index.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import { initCommand } from "./commands/init";
|
|
3
|
-
import { buildCommand } from "./commands/build";
|
|
4
|
-
import { devCommand } from "./commands/dev";
|
|
5
|
-
import { linkCommand } from "./commands/link";
|
|
6
|
-
|
|
7
|
-
const program = new Command();
|
|
8
|
-
|
|
9
|
-
program
|
|
10
|
-
.name("wvr")
|
|
11
|
-
.description("Weaver Addon Toolchain")
|
|
12
|
-
.version("1.0.0");
|
|
13
|
-
|
|
14
|
-
program.command("init")
|
|
15
|
-
.description("Initialize a new Weaver project")
|
|
16
|
-
.option("-y, --yes", "Skip prompts and use defaults")
|
|
17
|
-
.action((options) => initCommand(options));
|
|
18
|
-
|
|
19
|
-
program.command("build")
|
|
20
|
-
.description("Build the addon for production")
|
|
21
|
-
.action(() => buildCommand());
|
|
22
|
-
|
|
23
|
-
program.command("dev")
|
|
24
|
-
.description("Start development server (watch mode)")
|
|
25
|
-
.action(() => devCommand());
|
|
26
|
-
|
|
27
|
-
program.command("link")
|
|
28
|
-
.description("Symlink dist folder to WoW AddOns")
|
|
29
|
-
.action(() => linkCommand());
|
|
30
|
-
|
|
31
|
-
program.parse(process.argv);
|
package/src/cli/utils/config.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
|
-
import { WeaverConfig } from "../../schema";
|
|
4
|
-
|
|
5
|
-
export async function loadConfig(): Promise<WeaverConfig | null> {
|
|
6
|
-
if (existsSync("weaver.config.ts")) {
|
|
7
|
-
try {
|
|
8
|
-
const configPath = Bun.pathToFileURL("weaver.config.ts").href;
|
|
9
|
-
const configModule = await import(configPath);
|
|
10
|
-
return configModule.default;
|
|
11
|
-
} catch (e) {
|
|
12
|
-
console.warn("Failed to load weaver.config.ts:", e);
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
return null;
|
|
16
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { $ } from "bun";
|
|
3
|
-
import { existsSync } from "node:fs";
|
|
4
|
-
import { join } from "node:path";
|
|
5
|
-
|
|
6
|
-
export async function findWoWPath(): Promise<string | null> {
|
|
7
|
-
// 1. Try Registry (Windows only)
|
|
8
|
-
if (process.platform === "win32") {
|
|
9
|
-
try {
|
|
10
|
-
const result = await $`reg query "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Blizzard Entertainment\\World of Warcraft" /v InstallPath`.text();
|
|
11
|
-
// Output looks like: " InstallPath REG_SZ C:\Program Files (x86)\World of Warcraft\"
|
|
12
|
-
const match = result.match(/REG_SZ\s+(.*)/);
|
|
13
|
-
if (match && match[1]) {
|
|
14
|
-
const path = match[1].trim();
|
|
15
|
-
if (existsSync(path)) return path;
|
|
16
|
-
}
|
|
17
|
-
} catch (e) {
|
|
18
|
-
// Registry key not found or error accessing reg command
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// 2. Common Path Scan
|
|
23
|
-
const commonPaths = [
|
|
24
|
-
"C:\\Games\\World of Warcraft",
|
|
25
|
-
"D:\\Games\\World of Warcraft",
|
|
26
|
-
"E:\\Games\\World of Warcraft",
|
|
27
|
-
"C:\\Program Files (x86)\\World of Warcraft",
|
|
28
|
-
"C:\\Program Files\\World of Warcraft"
|
|
29
|
-
];
|
|
30
|
-
|
|
31
|
-
for (const path of commonPaths) {
|
|
32
|
-
if (existsSync(path)) return path;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function validateWoWPath(path: string): boolean {
|
|
39
|
-
const retail = join(path, "_retail_");
|
|
40
|
-
const classic = join(path, "_classic_");
|
|
41
|
-
const classicEra = join(path, "_classic_era_");
|
|
42
|
-
|
|
43
|
-
return existsSync(retail) || existsSync(classic) || existsSync(classicEra);
|
|
44
|
-
}
|
package/src/schema.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
import type { WeaverConfig as IWeaverConfig } from "../../weaver/src/types/config";
|
|
4
|
-
|
|
5
|
-
export const WeaverConfigSchema = z.object({
|
|
6
|
-
addonName: z.string(),
|
|
7
|
-
flavor: z.enum(["_retail_", "_classic_", "_classic_era_"]),
|
|
8
|
-
interface: z.string(),
|
|
9
|
-
outDir: z.string().optional().default("Interface/AddOns"),
|
|
10
|
-
entry: z.string().optional().default("src/App.tsx"),
|
|
11
|
-
wowPath: z.string().optional().nullable(),
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
export type WeaverConfig = z.infer<typeof WeaverConfigSchema>;
|
|
15
|
-
|
|
16
|
-
// Verify it matches the interface
|
|
17
|
-
type Verification = WeaverConfig extends IWeaverConfig ? (IWeaverConfig extends WeaverConfig ? true : false) : false;
|
|
18
|
-
const _v: Verification = true;
|