@stacksjs/buddy 0.70.88 → 0.70.90
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/cli.d.ts +1 -0
- package/dist/cli.js +165 -0
- package/dist/commands/about.d.ts +2 -0
- package/dist/commands/about.js +35 -0
- package/dist/commands/add.d.ts +2 -0
- package/dist/commands/add.js +33 -0
- package/dist/commands/auth.d.ts +2 -0
- package/dist/commands/auth.js +68 -0
- package/dist/commands/build.d.ts +2 -0
- package/dist/commands/build.js +153 -0
- package/dist/commands/cd.d.ts +20 -0
- package/dist/commands/cd.js +39 -0
- package/dist/commands/changelog.d.ts +2 -0
- package/dist/commands/changelog.js +32 -0
- package/dist/commands/clean.d.ts +2 -0
- package/dist/commands/clean.js +37 -0
- package/dist/commands/cloud.d.ts +2 -0
- package/dist/commands/cloud.js +503 -0
- package/dist/commands/commit.d.ts +2 -0
- package/dist/commands/commit.js +16 -0
- package/dist/commands/completion.d.ts +2 -0
- package/dist/commands/completion.js +143 -0
- package/dist/commands/config-migrate.d.ts +26 -0
- package/dist/commands/config-migrate.js +94 -0
- package/dist/commands/configure.d.ts +2 -0
- package/dist/commands/configure.js +48 -0
- package/dist/commands/create.d.ts +2 -0
- package/dist/commands/create.js +141 -0
- package/dist/commands/deploy.d.ts +107 -0
- package/dist/commands/deploy.js +1439 -0
- package/dist/commands/dev.d.ts +10 -0
- package/dist/commands/dev.js +907 -0
- package/dist/commands/dns.d.ts +2 -0
- package/dist/commands/dns.js +102 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.js +285 -0
- package/dist/commands/domains.d.ts +2 -0
- package/dist/commands/domains.js +159 -0
- package/dist/commands/email.d.ts +2 -0
- package/dist/commands/email.js +524 -0
- package/dist/commands/env.d.ts +2 -0
- package/dist/commands/env.js +246 -0
- package/dist/commands/extension.d.ts +8 -0
- package/dist/commands/extension.js +78 -0
- package/dist/commands/features.d.ts +180 -0
- package/dist/commands/features.js +422 -0
- package/dist/commands/fresh.d.ts +2 -0
- package/dist/commands/fresh.js +39 -0
- package/dist/commands/generate.d.ts +2 -0
- package/dist/commands/generate.js +104 -0
- package/dist/commands/http.d.ts +2 -0
- package/dist/commands/http.js +33 -0
- package/dist/commands/index.d.ts +53 -0
- package/dist/commands/index.js +53 -0
- package/dist/commands/install.d.ts +2 -0
- package/dist/commands/install.js +22 -0
- package/dist/commands/key.d.ts +2 -0
- package/dist/commands/key.js +23 -0
- package/dist/commands/lint.d.ts +2 -0
- package/dist/commands/lint.js +46 -0
- package/dist/commands/list.d.ts +2 -0
- package/dist/commands/list.js +108 -0
- package/dist/commands/mail.d.ts +2 -0
- package/dist/commands/mail.js +693 -0
- package/dist/commands/maintenance.d.ts +2 -0
- package/dist/commands/maintenance.js +141 -0
- package/dist/commands/make.d.ts +2 -0
- package/dist/commands/make.js +375 -0
- package/dist/commands/migrate-project.d.ts +2 -0
- package/dist/commands/migrate-project.js +49 -0
- package/dist/commands/migrate.d.ts +4 -0
- package/dist/commands/migrate.js +455 -0
- package/dist/commands/outdated.d.ts +2 -0
- package/dist/commands/outdated.js +19 -0
- package/dist/commands/package.d.ts +2 -0
- package/dist/commands/package.js +17 -0
- package/dist/commands/phone.d.ts +2 -0
- package/dist/commands/phone.js +188 -0
- package/dist/commands/ports.d.ts +2 -0
- package/dist/commands/ports.js +118 -0
- package/dist/commands/prepublish.d.ts +2 -0
- package/dist/commands/prepublish.js +17 -0
- package/dist/commands/projects.d.ts +2 -0
- package/dist/commands/projects.js +29 -0
- package/dist/commands/publish.d.ts +2 -0
- package/dist/commands/publish.js +172 -0
- package/dist/commands/queue.d.ts +2 -0
- package/dist/commands/queue.js +248 -0
- package/dist/commands/release.d.ts +2 -0
- package/dist/commands/release.js +30 -0
- package/dist/commands/route.d.ts +2 -0
- package/dist/commands/route.js +21 -0
- package/dist/commands/saas.d.ts +2 -0
- package/dist/commands/saas.js +25 -0
- package/dist/commands/schedule.d.ts +2 -0
- package/dist/commands/schedule.js +61 -0
- package/dist/commands/search.d.ts +2 -0
- package/dist/commands/search.js +84 -0
- package/dist/commands/seed.d.ts +2 -0
- package/dist/commands/seed.js +71 -0
- package/dist/commands/serve.d.ts +25 -0
- package/dist/commands/serve.js +182 -0
- package/dist/commands/setup.d.ts +12 -0
- package/dist/commands/setup.js +215 -0
- package/dist/commands/share.d.ts +2 -0
- package/dist/commands/share.js +214 -0
- package/dist/commands/sms.d.ts +2 -0
- package/dist/commands/sms.js +328 -0
- package/dist/commands/stacks.d.ts +2 -0
- package/dist/commands/stacks.js +69 -0
- package/dist/commands/telemetry.d.ts +2 -0
- package/dist/commands/telemetry.js +74 -0
- package/dist/commands/test.d.ts +2 -0
- package/dist/commands/test.js +130 -0
- package/dist/commands/tinker.d.ts +2 -0
- package/dist/commands/tinker.js +37 -0
- package/dist/commands/types.d.ts +2 -0
- package/dist/commands/types.js +18 -0
- package/dist/commands/upgrade.d.ts +2 -0
- package/dist/commands/upgrade.js +98 -0
- package/dist/commands/version.d.ts +2 -0
- package/dist/commands/version.js +16 -0
- package/dist/config.d.ts +43 -0
- package/dist/config.js +223 -0
- package/dist/custom-cli.d.ts +1 -0
- package/dist/custom-cli.js +23 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/lazy-commands.d.ts +61 -0
- package/dist/lazy-commands.js +188 -0
- package/dist/migrators/index.d.ts +9 -0
- package/dist/migrators/index.js +62 -0
- package/dist/migrators/laravel/index.d.ts +2 -0
- package/dist/migrators/laravel/index.js +148 -0
- package/dist/migrators/laravel/migrations.d.ts +52 -0
- package/dist/migrators/laravel/migrations.js +232 -0
- package/dist/migrators/laravel/models.d.ts +34 -0
- package/dist/migrators/laravel/models.js +134 -0
- package/dist/migrators/rails/index.d.ts +2 -0
- package/dist/migrators/rails/index.js +11 -0
- package/dist/migrators/types.d.ts +44 -0
- package/dist/migrators/types.js +0 -0
- package/package.json +2 -2
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { generateTypes } from "@stacksjs/actions";
|
|
3
|
+
import { log } from "@stacksjs/logging";
|
|
4
|
+
import { onUnknownSubcommand } from "@stacksjs/cli";
|
|
5
|
+
export function types(buddy) {
|
|
6
|
+
const descriptions = {
|
|
7
|
+
generate: "Generate the types of & for your library/libraries",
|
|
8
|
+
fix: "wip",
|
|
9
|
+
project: "Target a specific project",
|
|
10
|
+
verbose: "Enable verbose output"
|
|
11
|
+
};
|
|
12
|
+
buddy.command("types:generate", descriptions.generate).option("-p, --project [project]", descriptions.project, { default: !1 }).option("--verbose", descriptions.verbose, { default: !1 }).action(async (options) => {
|
|
13
|
+
log.debug("Running `buddy types:generate` ...", options);
|
|
14
|
+
await generateTypes(options);
|
|
15
|
+
});
|
|
16
|
+
buddy.command("types:fix", descriptions.fix).option("-p, --project [project]", descriptions.project, { default: !1 }).option("--verbose", descriptions.verbose, { default: !1 }).action(async () => {});
|
|
17
|
+
onUnknownSubcommand(buddy, "types");
|
|
18
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { runAction } from "@stacksjs/actions";
|
|
3
|
+
import { intro, log, onUnknownSubcommand, outro } from "@stacksjs/cli";
|
|
4
|
+
import { Action } from "@stacksjs/enums";
|
|
5
|
+
import { ExitCode } from "@stacksjs/types";
|
|
6
|
+
export function upgrade(buddy) {
|
|
7
|
+
const descriptions = {
|
|
8
|
+
upgrade: "Upgrade the Stacks framework to the latest version",
|
|
9
|
+
version: "Install a specific version (e.g., 0.70.23)",
|
|
10
|
+
canary: "Upgrade to the latest canary (bleeding-edge `main`) build",
|
|
11
|
+
stable: "Switch to the latest vetted stable release",
|
|
12
|
+
dryRun: "Preview the upgrade (which dependencies would change) without writing or installing",
|
|
13
|
+
force: "Force re-download, bypassing cache and version checks",
|
|
14
|
+
from: "Sync from a local stacks checkout (e.g. ~/Code/stacks). Skips GitHub.",
|
|
15
|
+
noPostinstall: "Skip post-sync hooks (auto-imports, bun install, migrate)",
|
|
16
|
+
verbose: "Enable verbose output",
|
|
17
|
+
dependencies: "Upgrade your dependencies (pantry.yaml & package.json)",
|
|
18
|
+
bun: "Upgrade Bun to the latest version",
|
|
19
|
+
shell: "Upgrade the shell integration (currently only supports Oh My Zsh)",
|
|
20
|
+
binary: "Upgrade the `stacks` binary to the latest version",
|
|
21
|
+
project: "Target a specific project",
|
|
22
|
+
all: "Upgrade framework, dependencies, Bun, and binary"
|
|
23
|
+
};
|
|
24
|
+
buddy.command("upgrade", descriptions.upgrade).option("-v, --version <version>", descriptions.version).option("--canary", descriptions.canary, { default: !1 }).option("--stable", descriptions.stable, { default: !1 }).option("--dry-run", descriptions.dryRun, { default: !1 }).option("-f, --force", descriptions.force, { default: !1 }).option("--from <path>", descriptions.from).option("--no-postinstall", descriptions.noPostinstall).option("--verbose", descriptions.verbose, { default: !1 }).alias("update").example("buddy upgrade").example("buddy update").example("buddy upgrade --from ~/Code/stacks").example("buddy upgrade --version 0.70.23").example("buddy upgrade --dry-run").example("buddy upgrade --canary").example("buddy upgrade --stable").example("buddy upgrade --force").action(async (options) => {
|
|
25
|
+
log.debug("Running `buddy upgrade` ...", options);
|
|
26
|
+
const opts = { ...options };
|
|
27
|
+
if (opts.postinstall === !1) {
|
|
28
|
+
delete opts.postinstall;
|
|
29
|
+
opts.noPostinstall = !0;
|
|
30
|
+
}
|
|
31
|
+
const perf = await intro("buddy upgrade"), result = await runAction(Action.UpgradeFramework, opts);
|
|
32
|
+
if (result.isErr) {
|
|
33
|
+
await outro("While running buddy upgrade, there was an issue", { startTime: perf, useSeconds: !0 }, result.error);
|
|
34
|
+
process.exit(ExitCode.FatalError);
|
|
35
|
+
}
|
|
36
|
+
await outro("Upgrade complete.", { startTime: perf, useSeconds: !0 });
|
|
37
|
+
process.exit(ExitCode.Success);
|
|
38
|
+
});
|
|
39
|
+
buddy.command("upgrade:all", descriptions.all).option("--canary", descriptions.canary, { default: !1 }).option("-f, --force", descriptions.force, { default: !1 }).option("-p, --project [project]", descriptions.project, { default: !1 }).option("--verbose", descriptions.verbose, { default: !1 }).example("buddy upgrade:all").action(async (options) => {
|
|
40
|
+
log.debug("Running `buddy upgrade:all` ...", options);
|
|
41
|
+
const perf = await intro("buddy upgrade:all");
|
|
42
|
+
options.all = !0;
|
|
43
|
+
const result = await runAction(Action.Upgrade, options);
|
|
44
|
+
if (result.isErr) {
|
|
45
|
+
await outro("While running buddy upgrade:all, there was an issue", { startTime: perf, useSeconds: !0 }, result.error);
|
|
46
|
+
process.exit(ExitCode.FatalError);
|
|
47
|
+
}
|
|
48
|
+
await outro("All upgrades complete.", { startTime: perf, useSeconds: !0 });
|
|
49
|
+
process.exit(ExitCode.Success);
|
|
50
|
+
});
|
|
51
|
+
buddy.command("upgrade:dependencies", descriptions.dependencies).option("-p, --project [project]", descriptions.project, { default: !1 }).option("--verbose", descriptions.verbose, { default: !1 }).alias("upgrade:deps").example("buddy upgrade:dependencies").action(async (options) => {
|
|
52
|
+
log.debug("Running `buddy upgrade:dependencies` ...", options);
|
|
53
|
+
const perf = await intro("buddy upgrade:dependencies");
|
|
54
|
+
options.dependencies = !0;
|
|
55
|
+
const result = await runAction(Action.Upgrade, options);
|
|
56
|
+
if (result.isErr) {
|
|
57
|
+
await outro("While running buddy upgrade:dependencies, there was an issue", { startTime: perf, useSeconds: !0 }, result.error);
|
|
58
|
+
process.exit(ExitCode.FatalError);
|
|
59
|
+
}
|
|
60
|
+
await outro("Dependencies upgraded.", { startTime: perf, useSeconds: !0 });
|
|
61
|
+
process.exit(ExitCode.Success);
|
|
62
|
+
});
|
|
63
|
+
buddy.command("upgrade:bun", descriptions.bun).option("--verbose", descriptions.verbose, { default: !1 }).example("buddy upgrade:bun").action(async (options) => {
|
|
64
|
+
log.debug("Running `buddy upgrade:bun` ...", options);
|
|
65
|
+
const perf = await intro("buddy upgrade:bun"), result = await runAction(Action.UpgradeBun, options);
|
|
66
|
+
if (result.isErr) {
|
|
67
|
+
await outro("While running buddy upgrade:bun, there was an issue", { startTime: perf, useSeconds: !0 }, result.error);
|
|
68
|
+
process.exit(ExitCode.FatalError);
|
|
69
|
+
}
|
|
70
|
+
await outro("Bun upgraded.", { startTime: perf, useSeconds: !0 });
|
|
71
|
+
process.exit(ExitCode.Success);
|
|
72
|
+
});
|
|
73
|
+
buddy.command("upgrade:shell", descriptions.shell).option("--verbose", descriptions.verbose, { default: !1 }).example("buddy upgrade:shell").action(async (options) => {
|
|
74
|
+
log.debug("Running `buddy upgrade:shell` ...", options);
|
|
75
|
+
const perf = await intro("buddy upgrade:shell"), result = await runAction(Action.UpgradeShell, options);
|
|
76
|
+
if (result.isErr) {
|
|
77
|
+
await outro("While running buddy upgrade:shell, there was an issue", { startTime: perf, useSeconds: !0 }, result.error);
|
|
78
|
+
process.exit(ExitCode.FatalError);
|
|
79
|
+
}
|
|
80
|
+
await outro("Shell integration upgraded.", { startTime: perf, useSeconds: !0 });
|
|
81
|
+
process.exit(ExitCode.Success);
|
|
82
|
+
});
|
|
83
|
+
buddy.command("upgrade:binary", descriptions.binary).option("--verbose", descriptions.verbose, { default: !1 }).example("buddy upgrade:binary").action(async (options) => {
|
|
84
|
+
if (process.getuid && process.getuid() !== 0) {
|
|
85
|
+
log.warn("To upgrade the binary, you need to run this command with sudo, or as root.");
|
|
86
|
+
process.exit(ExitCode.FatalError);
|
|
87
|
+
}
|
|
88
|
+
log.debug("Running `buddy upgrade:binary` ...", options);
|
|
89
|
+
const perf = await intro("buddy upgrade:binary"), result = await runAction(Action.UpgradeBinary, options);
|
|
90
|
+
if (result.isErr) {
|
|
91
|
+
await outro("While running buddy upgrade:binary, there was an issue", { startTime: perf, useSeconds: !0 }, result.error);
|
|
92
|
+
process.exit(ExitCode.FatalError);
|
|
93
|
+
}
|
|
94
|
+
await outro("Binary upgraded.", { startTime: perf, useSeconds: !0 });
|
|
95
|
+
process.exit(ExitCode.Success);
|
|
96
|
+
});
|
|
97
|
+
onUnknownSubcommand(buddy, "upgrade");
|
|
98
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { bold, dim, green, intro, log, onUnknownSubcommand } from "@stacksjs/cli";
|
|
3
|
+
import { storage } from "@stacksjs/storage";
|
|
4
|
+
export function version(buddy) {
|
|
5
|
+
const descriptions = {
|
|
6
|
+
version: "Retrieving Stacks build version"
|
|
7
|
+
};
|
|
8
|
+
buddy.command("version", descriptions.version).action(async () => {
|
|
9
|
+
log.debug("Running `buddy version` ...");
|
|
10
|
+
await intro("buddy version");
|
|
11
|
+
const pkg = await storage.readPackageJson("./package.json"), bunVersion = "wip", stacksVersion = pkg.version;
|
|
12
|
+
log.info(green(bold("@stacksjs/ ")) + dim(` ${stacksVersion}`));
|
|
13
|
+
log.info(green(bold("Bun: ")) + dim(` ${bunVersion}`));
|
|
14
|
+
});
|
|
15
|
+
onUnknownSubcommand(buddy, "version");
|
|
16
|
+
}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { CLI } from '@stacksjs/cli';
|
|
2
|
+
/**
|
|
3
|
+
* Validate the buddy config structure
|
|
4
|
+
*/
|
|
5
|
+
export declare function validateConfig(config: any): ValidationError[];
|
|
6
|
+
/**
|
|
7
|
+
* Load buddy.config.ts from the project root
|
|
8
|
+
*/
|
|
9
|
+
export declare function loadBuddyConfig(): Promise<BuddyConfig>;
|
|
10
|
+
/**
|
|
11
|
+
* Load and initialize plugins
|
|
12
|
+
*/
|
|
13
|
+
export declare function loadPlugins(cli: CLI, config: BuddyConfig): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Apply buddy config to CLI instance
|
|
16
|
+
*/
|
|
17
|
+
export declare function applyBuddyConfig(buddy: CLI): Promise<void>;
|
|
18
|
+
export declare interface BuddyPlugin {
|
|
19
|
+
name: string
|
|
20
|
+
version?: string
|
|
21
|
+
setup: (cli: CLI) => void | Promise<void>
|
|
22
|
+
hooks?: {
|
|
23
|
+
beforeCommand?: (context: any) => void | Promise<void>
|
|
24
|
+
afterCommand?: (context: any) => void | Promise<void>
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export declare interface BuddyConfig {
|
|
28
|
+
theme?: string
|
|
29
|
+
emoji?: boolean
|
|
30
|
+
commands?: Array<(cli: CLI) => void>
|
|
31
|
+
defaultFlags?: {
|
|
32
|
+
verbose?: boolean
|
|
33
|
+
quiet?: boolean
|
|
34
|
+
debug?: boolean
|
|
35
|
+
}
|
|
36
|
+
aliases?: Record<string, string>
|
|
37
|
+
plugins?: Array<BuddyPlugin | string>
|
|
38
|
+
}
|
|
39
|
+
declare interface ValidationError {
|
|
40
|
+
path: string
|
|
41
|
+
message: string
|
|
42
|
+
value?: any
|
|
43
|
+
}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { log } from "@stacksjs/cli";
|
|
3
|
+
import { path as p } from "@stacksjs/path";
|
|
4
|
+
export function validateConfig(config) {
|
|
5
|
+
const errors = [];
|
|
6
|
+
if (typeof config !== "object" || config === null) {
|
|
7
|
+
errors.push({
|
|
8
|
+
path: "config",
|
|
9
|
+
message: "Config must be an object",
|
|
10
|
+
value: config
|
|
11
|
+
});
|
|
12
|
+
return errors;
|
|
13
|
+
}
|
|
14
|
+
if (config.theme !== void 0) {
|
|
15
|
+
const validThemes = ["default", "dracula", "nord", "solarized", "monokai"];
|
|
16
|
+
if (typeof config.theme !== "string" || !validThemes.includes(config.theme))
|
|
17
|
+
errors.push({
|
|
18
|
+
path: "theme",
|
|
19
|
+
message: `Theme must be one of: ${validThemes.join(", ")}`,
|
|
20
|
+
value: config.theme
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
if (config.emoji !== void 0 && typeof config.emoji !== "boolean")
|
|
24
|
+
errors.push({
|
|
25
|
+
path: "emoji",
|
|
26
|
+
message: "Emoji must be a boolean",
|
|
27
|
+
value: config.emoji
|
|
28
|
+
});
|
|
29
|
+
if (config.commands !== void 0)
|
|
30
|
+
if (!Array.isArray(config.commands))
|
|
31
|
+
errors.push({
|
|
32
|
+
path: "commands",
|
|
33
|
+
message: "Commands must be an array",
|
|
34
|
+
value: config.commands
|
|
35
|
+
});
|
|
36
|
+
else
|
|
37
|
+
config.commands.forEach((cmd, index) => {
|
|
38
|
+
if (typeof cmd !== "function")
|
|
39
|
+
errors.push({
|
|
40
|
+
path: `commands[${index}]`,
|
|
41
|
+
message: "Each command must be a function",
|
|
42
|
+
value: cmd
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
if (config.defaultFlags !== void 0)
|
|
46
|
+
if (typeof config.defaultFlags !== "object" || config.defaultFlags === null)
|
|
47
|
+
errors.push({
|
|
48
|
+
path: "defaultFlags",
|
|
49
|
+
message: "Default flags must be an object",
|
|
50
|
+
value: config.defaultFlags
|
|
51
|
+
});
|
|
52
|
+
else {
|
|
53
|
+
const flagKeys = ["verbose", "quiet", "debug"];
|
|
54
|
+
for (const key of Object.keys(config.defaultFlags))
|
|
55
|
+
if (!flagKeys.includes(key))
|
|
56
|
+
errors.push({
|
|
57
|
+
path: `defaultFlags.${key}`,
|
|
58
|
+
message: `Unknown flag. Valid flags are: ${flagKeys.join(", ")}`,
|
|
59
|
+
value: config.defaultFlags[key]
|
|
60
|
+
});
|
|
61
|
+
else if (typeof config.defaultFlags[key] !== "boolean")
|
|
62
|
+
errors.push({
|
|
63
|
+
path: `defaultFlags.${key}`,
|
|
64
|
+
message: "Flag value must be a boolean",
|
|
65
|
+
value: config.defaultFlags[key]
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
if (config.aliases !== void 0) {
|
|
69
|
+
if (typeof config.aliases !== "object" || config.aliases === null || Array.isArray(config.aliases))
|
|
70
|
+
errors.push({
|
|
71
|
+
path: "aliases",
|
|
72
|
+
message: "Aliases must be an object mapping alias names to command names",
|
|
73
|
+
value: config.aliases
|
|
74
|
+
});
|
|
75
|
+
else
|
|
76
|
+
for (const [alias, command] of Object.entries(config.aliases))
|
|
77
|
+
if (typeof command !== "string")
|
|
78
|
+
errors.push({
|
|
79
|
+
path: `aliases.${alias}`,
|
|
80
|
+
message: "Alias target must be a string",
|
|
81
|
+
value: command
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
if (config.plugins !== void 0)
|
|
85
|
+
if (!Array.isArray(config.plugins))
|
|
86
|
+
errors.push({
|
|
87
|
+
path: "plugins",
|
|
88
|
+
message: "Plugins must be an array",
|
|
89
|
+
value: config.plugins
|
|
90
|
+
});
|
|
91
|
+
else
|
|
92
|
+
config.plugins.forEach((plugin, index) => {
|
|
93
|
+
if (typeof plugin === "string")
|
|
94
|
+
return;
|
|
95
|
+
if (typeof plugin !== "object" || plugin === null) {
|
|
96
|
+
errors.push({
|
|
97
|
+
path: `plugins[${index}]`,
|
|
98
|
+
message: "Each plugin must be an object or a string (module path)",
|
|
99
|
+
value: plugin
|
|
100
|
+
});
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (!plugin.name || typeof plugin.name !== "string")
|
|
104
|
+
errors.push({
|
|
105
|
+
path: `plugins[${index}].name`,
|
|
106
|
+
message: "Plugin must have a name property of type string",
|
|
107
|
+
value: plugin.name
|
|
108
|
+
});
|
|
109
|
+
if (!plugin.setup || typeof plugin.setup !== "function")
|
|
110
|
+
errors.push({
|
|
111
|
+
path: `plugins[${index}].setup`,
|
|
112
|
+
message: "Plugin must have a setup function",
|
|
113
|
+
value: plugin.setup
|
|
114
|
+
});
|
|
115
|
+
if (plugin.hooks !== void 0) {
|
|
116
|
+
if (typeof plugin.hooks !== "object" || plugin.hooks === null)
|
|
117
|
+
errors.push({
|
|
118
|
+
path: `plugins[${index}].hooks`,
|
|
119
|
+
message: "Plugin hooks must be an object",
|
|
120
|
+
value: plugin.hooks
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
const validKeys = ["theme", "emoji", "commands", "defaultFlags", "aliases", "plugins"];
|
|
125
|
+
for (const key of Object.keys(config))
|
|
126
|
+
if (!validKeys.includes(key))
|
|
127
|
+
errors.push({
|
|
128
|
+
path: key,
|
|
129
|
+
message: `Unknown configuration key. Valid keys are: ${validKeys.join(", ")}`,
|
|
130
|
+
value: config[key]
|
|
131
|
+
});
|
|
132
|
+
return errors;
|
|
133
|
+
}
|
|
134
|
+
let cachedConfig = null;
|
|
135
|
+
export async function loadBuddyConfig() {
|
|
136
|
+
if (cachedConfig)
|
|
137
|
+
return cachedConfig;
|
|
138
|
+
const configPaths = [
|
|
139
|
+
p.projectPath("buddy.config.ts"),
|
|
140
|
+
p.projectPath("buddy.config.js"),
|
|
141
|
+
p.projectPath(".buddy.config.ts"),
|
|
142
|
+
p.projectPath(".buddy.config.js")
|
|
143
|
+
];
|
|
144
|
+
for (const configPath of configPaths)
|
|
145
|
+
if (existsSync(configPath))
|
|
146
|
+
try {
|
|
147
|
+
log.debug(`Loading buddy config from ${configPath}`);
|
|
148
|
+
const configModule = await import(configPath), config = configModule.default || configModule, validationErrors = validateConfig(config);
|
|
149
|
+
if (validationErrors.length > 0) {
|
|
150
|
+
log.error("Invalid buddy.config.ts:");
|
|
151
|
+
for (const error of validationErrors)
|
|
152
|
+
log.error(` - ${error.path}: ${error.message}`);
|
|
153
|
+
throw Error("Configuration validation failed");
|
|
154
|
+
}
|
|
155
|
+
cachedConfig = config;
|
|
156
|
+
return config;
|
|
157
|
+
} catch (error) {
|
|
158
|
+
log.warn(`Failed to load buddy config from ${configPath}:`, error);
|
|
159
|
+
}
|
|
160
|
+
cachedConfig = {};
|
|
161
|
+
return cachedConfig;
|
|
162
|
+
}
|
|
163
|
+
export async function loadPlugins(cli, config) {
|
|
164
|
+
if (!config.plugins || config.plugins.length === 0)
|
|
165
|
+
return;
|
|
166
|
+
log.debug(`Loading ${config.plugins.length} plugin(s)`);
|
|
167
|
+
for (const pluginConfig of config.plugins) {
|
|
168
|
+
let plugin;
|
|
169
|
+
if (typeof pluginConfig === "string")
|
|
170
|
+
try {
|
|
171
|
+
const pluginModule = await import(pluginConfig);
|
|
172
|
+
plugin = pluginModule.default || pluginModule;
|
|
173
|
+
} catch (error) {
|
|
174
|
+
log.error(`Failed to load plugin from ${pluginConfig}:`, error);
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
else
|
|
178
|
+
plugin = pluginConfig;
|
|
179
|
+
try {
|
|
180
|
+
log.debug(`Initializing plugin: ${plugin.name}${plugin.version ? ` v${plugin.version}` : ""}`);
|
|
181
|
+
await plugin.setup(cli);
|
|
182
|
+
if (plugin.hooks) {
|
|
183
|
+
if (plugin.hooks.beforeCommand)
|
|
184
|
+
cli.on("command:*", async (command) => {
|
|
185
|
+
if (plugin.hooks?.beforeCommand)
|
|
186
|
+
await plugin.hooks.beforeCommand({ command });
|
|
187
|
+
});
|
|
188
|
+
if (plugin.hooks.afterCommand)
|
|
189
|
+
cli.on("command:*", async (command) => {
|
|
190
|
+
if (plugin.hooks?.afterCommand)
|
|
191
|
+
await plugin.hooks.afterCommand({ command });
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
log.debug(`Plugin ${plugin.name} initialized successfully`);
|
|
195
|
+
} catch (error) {
|
|
196
|
+
log.error(`Failed to initialize plugin ${plugin.name}:`, error);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
export async function applyBuddyConfig(buddy) {
|
|
201
|
+
const config = await loadBuddyConfig();
|
|
202
|
+
if (config.emoji !== void 0 && buddy.options.noEmoji === void 0)
|
|
203
|
+
buddy.useEmoji = config.emoji;
|
|
204
|
+
if (config.defaultFlags) {
|
|
205
|
+
if (config.defaultFlags.verbose && !buddy.isVerbose)
|
|
206
|
+
buddy.isVerbose = !0;
|
|
207
|
+
if (config.defaultFlags.quiet && !buddy.isQuiet)
|
|
208
|
+
buddy.isQuiet = !0;
|
|
209
|
+
if (config.defaultFlags.debug && !buddy.isDebug)
|
|
210
|
+
buddy.isDebug = !0;
|
|
211
|
+
}
|
|
212
|
+
if (config.commands && Array.isArray(config.commands)) {
|
|
213
|
+
for (const registerCommand of config.commands)
|
|
214
|
+
if (typeof registerCommand === "function")
|
|
215
|
+
registerCommand(buddy);
|
|
216
|
+
}
|
|
217
|
+
if (config.aliases)
|
|
218
|
+
for (const [alias, command] of Object.entries(config.aliases)) {
|
|
219
|
+
const targetCommand = buddy.commands.find((cmd) => cmd.name === command);
|
|
220
|
+
if (targetCommand && !targetCommand.aliasNames.includes(alias))
|
|
221
|
+
targetCommand.aliasNames.push(alias);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { cli } from "@stacksjs/cli";
|
|
3
|
+
import { config } from "@stacksjs/config";
|
|
4
|
+
import { handleError } from "@stacksjs/error-handling";
|
|
5
|
+
import { path as p } from "@stacksjs/path";
|
|
6
|
+
import { fs } from "@stacksjs/storage";
|
|
7
|
+
process.on("uncaughtException", handleError);
|
|
8
|
+
process.on("unhandledRejection", handleError);
|
|
9
|
+
async function main() {
|
|
10
|
+
const buddy = cli(config.cli.name);
|
|
11
|
+
if (!fs.existsSync(p.projectPath(config.cli.command)))
|
|
12
|
+
fs.writeFileSync(p.projectPath(config.cli.command), "import('./storage/framework/core/buddy/src/custom-cli')");
|
|
13
|
+
const commandsDir = p.appPath("Commands"), commandFiles = fs.readdirSync(commandsDir).filter((file) => file.endsWith(".ts"));
|
|
14
|
+
for (const file of commandFiles) {
|
|
15
|
+
const dynamicImport = await import(`${commandsDir}/${file}`);
|
|
16
|
+
if (typeof dynamicImport.default === "function")
|
|
17
|
+
dynamicImport.default(buddy);
|
|
18
|
+
else
|
|
19
|
+
console.error(`Expected a default export function in ${file}, but got:`, dynamicImport.default);
|
|
20
|
+
}
|
|
21
|
+
buddy.parse();
|
|
22
|
+
}
|
|
23
|
+
await main();
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './commands/index';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./commands";
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { CLI } from '@stacksjs/types';
|
|
2
|
+
/** Mark a registrar as already invoked for this CLI so loadCommand skips it. */
|
|
3
|
+
export declare function markLoaded(buddy: CLI, commandName: string): void;
|
|
4
|
+
/**
|
|
5
|
+
* Load a specific command lazily
|
|
6
|
+
*/
|
|
7
|
+
export declare function loadCommand(commandName: string, buddy: CLI): Promise<boolean>;
|
|
8
|
+
/**
|
|
9
|
+
* Load multiple commands with timeout.
|
|
10
|
+
*
|
|
11
|
+
* Many registry entries point at the same module (e.g. `down`, `up`, `status`,
|
|
12
|
+
* `maintenance` all share `./commands/maintenance.ts`, and `cloud:*` aliases
|
|
13
|
+
* share `./commands/cloud.ts`). Calling each registrar more than once would
|
|
14
|
+
* register the same sub-commands multiple times, which is what produces
|
|
15
|
+
* duplicate rows in `buddy list`. Dedupe by loader identity so each module's
|
|
16
|
+
* registrar runs at most once per CLI instance.
|
|
17
|
+
*/
|
|
18
|
+
export declare function loadCommands(commandNames: string[], buddy: CLI): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Load a group of related commands
|
|
21
|
+
*/
|
|
22
|
+
export declare function loadCommandGroup(groupName: keyof typeof commandGroups, buddy: CLI): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Load all commands (for interactive mode or list command)
|
|
25
|
+
*/
|
|
26
|
+
export declare function loadAllCommands(buddy: CLI): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Get command names for autocomplete/suggestions
|
|
29
|
+
* (without actually loading the commands)
|
|
30
|
+
*/
|
|
31
|
+
export declare function getCommandNames(): string[];
|
|
32
|
+
/**
|
|
33
|
+
* Determine which commands to load based on CLI arguments.
|
|
34
|
+
*
|
|
35
|
+
* Help / no-command paths must load the full registry so the rendered help
|
|
36
|
+
* lists every command. Pure version flags only need `version`. A specific
|
|
37
|
+
* command (with or without `--help`) only needs that command's loader.
|
|
38
|
+
*/
|
|
39
|
+
export declare function getCommandsToLoad(args: string[]): string[];
|
|
40
|
+
/**
|
|
41
|
+
* Commands that are commonly used together (for batch loading optimization)
|
|
42
|
+
* @defaultValue
|
|
43
|
+
* ```ts
|
|
44
|
+
* {
|
|
45
|
+
* 'minimal': ['version', 'help'],
|
|
46
|
+
* 'development': ['dev', 'build', 'test', 'lint'],
|
|
47
|
+
* 'database': ['migrate', 'seed', 'fresh'],
|
|
48
|
+
* 'scaffolding': ['make', 'generate'],
|
|
49
|
+
* 'deployment': ['deploy', 'release', 'cloud'],
|
|
50
|
+
* 'info': ['about', 'doctor', 'list']
|
|
51
|
+
* }
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
declare const commandGroups: {
|
|
55
|
+
'minimal': string[];
|
|
56
|
+
'development': string[];
|
|
57
|
+
'database': string[];
|
|
58
|
+
'scaffolding': string[];
|
|
59
|
+
'deployment': string[];
|
|
60
|
+
'info': string[]
|
|
61
|
+
};
|