@stacksjs/buddy 0.70.264 → 0.70.266
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.js +2 -2
- package/dist/commands/auth.js +1 -1
- package/dist/commands/build.js +1 -1
- package/dist/commands/changelog.js +1 -1
- package/dist/commands/clean.js +1 -1
- package/dist/commands/cloud.js +1 -1
- package/dist/commands/configure.js +2 -2
- package/dist/commands/create.js +1 -1
- package/dist/commands/deploy.js +2 -2
- package/dist/commands/desktop-apple.js +2 -2
- package/dist/commands/dev.js +1 -1
- package/dist/commands/domains.js +2 -2
- package/dist/commands/fresh.js +1 -1
- package/dist/commands/generate.js +2 -2
- package/dist/commands/install.js +1 -1
- package/dist/commands/key.js +1 -1
- package/dist/commands/migrate.js +5 -5
- package/dist/commands/queue.js +1 -1
- package/dist/commands/release.js +1 -1
- package/dist/commands/route.js +1 -1
- package/dist/commands/saas.js +1 -1
- package/dist/commands/schedule.js +1 -1
- package/dist/commands/search.js +1 -1
- package/dist/commands/setup.js +1 -1
- package/dist/commands/test.js +1 -1
- package/dist/commands/upgrade.js +1 -1
- package/dist/result.d.ts +18 -0
- package/dist/result.js +1 -0
- package/package.json +44 -44
package/dist/commands/setup.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{cpSync,existsSync,readFileSync,writeFileSync}from"node:fs";import{homedir}from"node:os";import{join}from"node:path";import process from"node:process";import{runAction}from"@stacksjs/actions";import{log,onUnknownSubcommand,runCommand}from"@stacksjs/cli";import{Action}from"@stacksjs/enums";import{handleError}from"@stacksjs/error-handling";import{path as p}from"@stacksjs/path";import{copyFile,storage}from"@stacksjs/storage";import{ExitCode}from"@stacksjs/types";import{setupPrettyDevEnvironment}from"./dev";function getTimeoutMs(envVar,fallbackMs){const value=Number(process.env[envVar]);if(Number.isFinite(value)&&value>0)return value;return fallbackMs}const PANTRY_CHECK_TIMEOUT_MS=getTimeoutMs("PANTRY_CHECK_TIMEOUT_MS",15000),PANTRY_INSTALL_TIMEOUT_MS=getTimeoutMs("PANTRY_INSTALL_TIMEOUT_MS",600000),PANTRY_DEPENDENCIES_TIMEOUT_MS=getTimeoutMs("PANTRY_DEPENDENCIES_TIMEOUT_MS",1200000),KEYGEN_TIMEOUT_MS=getTimeoutMs("KEYGEN_TIMEOUT_MS",120000),AWS_CONFIG_TIMEOUT_MS=getTimeoutMs("AWS_CONFIG_TIMEOUT_MS",900000);export function setup(buddy){const descriptions={setup:"This command ensures your project is setup correctly",ssl:"Setup SSL certificates and hosts file for HTTPS development",ai:"Set the project up for an AI coding agent (Claude Code, Codex, Cursor, Copilot, Gemini)",copy:"Copy the agent files instead of symlinking them, so they can be edited per project",force:"Overwrite files that already exist",ohMyZsh:"Enable Oh My Zsh",aws:"Ensures AWS is connected to the project",project:"Target a specific project",verbose:"Enable verbose output",domain:"Custom domain to setup (defaults to APP_URL)",skipHosts:"Skip adding domain to hosts file",skipTrust:"Skip trusting the certificate",skipAws:"Skip AWS configuration during setup",skipKeygen:"Skip generating an application key during setup"};buddy.command("setup",descriptions.setup).alias("ensure").option("-p, --project [project]",descriptions.project,{default:!1}).option("--skip-aws",descriptions.skipAws,{default:!1}).option("--skip-keygen",descriptions.skipKeygen,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(options)=>{log.debug("Running `buddy setup` ...",options);await ensurePantryInstalled();await optimizePantryDeps();await initializeProject(options)});buddy.command("setup:ssl",descriptions.ssl).alias("ssl:setup").option("-d, --domain [domain]",descriptions.domain).option("--skip-hosts",descriptions.skipHosts,{default:!1}).option("--skip-trust",descriptions.skipTrust,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(options)=>{log.debug("Running `buddy setup:ssl` ...",options);if(!await setupPrettyDevEnvironment({domain:options.domain,skipHosts:options.skipHosts,skipTrust:options.skipTrust,verbose:options.verbose})){log.warn("SSL setup completed with warnings");log.info("You may need to manually trust certificates or update hosts file")}});buddy.command("setup:ai [provider]",descriptions.ai).alias("ai:setup").option("--copy",descriptions.copy,{default:!1}).option("--force",descriptions.force,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(provider,options)=>{log.debug("Running `buddy setup:ai` ...",options);const{AI_PROVIDERS,isAiProvider,reportAiSetup,setupAiProvider}=await import("./setup-ai");let id=provider;if(!id){const{select}=await import("@stacksjs/cli");id=await select({message:"Which AI coding agent do you use?",choices:AI_PROVIDERS.map((entry)=>({value:entry.id,label:entry.label})),initial:0})}if(!id||!isAiProvider(id)){log.error(`Unknown AI provider: ${id}. Expected one of: ${AI_PROVIDERS.map((entry)=>entry.id).join(", ")}`);process.exit(ExitCode.InvalidArgument)}const definition=AI_PROVIDERS.find((entry)=>entry.id===id);reportAiSetup(definition,setupAiProvider(id,{copy:options.copy,force:options.force}))});buddy.command("setup:oh-my-zsh",descriptions.ohMyZsh).alias("upgrade:oh-my-zsh").option("--verbose",descriptions.verbose,{default:!1}).action(async(_options)=>{log.debug("Running `buddy setup:oh-my-zsh` ...",_options);const result=await runAction(Action.UpgradeShell);if(result.isErr){log.error(result.error);process.exit(ExitCode.FatalError)}});onUnknownSubcommand(buddy,"setup")}async function isPantryInstalled(){try{return(await runCommand("pantry --version",{silent:!0,timeoutMs:PANTRY_CHECK_TIMEOUT_MS})).isOk}catch{return!1}}async function installPantry(){const bundledInstaller=p.frameworkPath("scripts/pantry-install"),command=existsSync(bundledInstaller)?[bundledInstaller]:["sh","-c","curl -fsSL https://pantry.dev | bash"],result=await runCommand(command,{timeoutMs:PANTRY_INSTALL_TIMEOUT_MS}),localBin=join(homedir(),".local","bin");if(!process.env.PATH?.split(":").includes(localBin))process.env.PATH=`${localBin}:${process.env.PATH||""}`;if(result.isOk&&await isPantryInstalled())return;if(result.isErr)handleError(result.error);else log.error("Pantry installed but is not available on PATH. Open a new shell and run `buddy setup` again.");process.exit(ExitCode.FatalError)}export async function ensurePantryInstalled(){if(await isPantryInstalled())return;log.info("Pantry is required. Installing it from https://pantry.dev...");await installPantry()}export async function ensurePantryDependencies(cwd){await ensurePantryInstalled();log.info("Installing project dependencies with Pantry...");const result=await runCommand("pantry install",{cwd,timeoutMs:PANTRY_DEPENDENCIES_TIMEOUT_MS});if(result.isErr){handleError(result.error);process.exit(ExitCode.FatalError)}if(existsSync(join(cwd,"package.json"))&&!existsSync(join(cwd,"node_modules"))){log.error("Pantry completed without installing the project JavaScript dependencies.");process.exit(ExitCode.FatalError)}log.success("Installed project dependencies with Pantry")}function hasAppKey(cwd){const envPath=join(cwd,".env");if(!existsSync(envPath))return!1;return/^APP_KEY=.+$/m.test(readFileSync(envPath,"utf-8"))}export async function ensureAppKey(cwd){if(hasAppKey(cwd)||process.env.APP_KEY&&process.env.APP_KEY.length>0){log.success("APP_KEY existed");return}const keyResult=await runCommand("./buddy key:generate",{cwd,timeoutMs:KEYGEN_TIMEOUT_MS});if(keyResult.isErr){handleError(keyResult.error);process.exit(ExitCode.FatalError)}log.success("Generated application key")}async function runInitialMigration(cwd){const appEnv=(process.env.APP_ENV||process.env.NODE_ENV||"local").toLowerCase();if(!["local","development","dev","test"].includes(appEnv)){log.info(`Skipping initial migration in the ${appEnv} environment`);return}log.info("Running initial database migration...");try{const result=await runAction(Action.Migrate,{cwd});if(result.isErr){log.warn("Initial migration did not complete - you can run it later via ./buddy migrate");log.debug(result.error);return}log.success("Database is migrated")}catch(error){log.warn("Initial migration did not complete - you can run it later via ./buddy migrate");log.debug(error)}}async function initializeProject(options){const cwd=options.cwd||p.projectPath();await ensurePantryDependencies(cwd);await ensureEnvIsSet(options);if(!options.skipKeygen)await ensureAppKey(cwd);await runInitialMigration(cwd);ensureIdeSettings(cwd);if(!options.skipAws){log.info("Ensuring AWS is connected...");try{const awsResult=await runCommand("./buddy configure:aws",{cwd,timeoutMs:AWS_CONFIG_TIMEOUT_MS});if(awsResult.isErr){log.warn("AWS not configured - you can do this later via ./buddy configure:aws");log.debug(awsResult.error)}else log.success("Configured AWS")}catch(error){log.warn("AWS not configured - you can do this later via ./buddy configure:aws");log.debug(error)}}log.success("Project is setup");log.info("Run `./buddy doctor` anytime to check your setup. Happy coding! \uD83D\uDC99")}export function ensureIdeSettings(cwd){const source=p.frameworkPath("defaults/ide/vscode/.vscode"),destination=join(cwd,".vscode");if(existsSync(destination)){log.debug(".vscode already exists; keeping the project settings");return}if(!existsSync(source)){log.debug("No bundled VS Code settings found; skipping IDE setup");return}cpSync(source,destination,{recursive:!0});log.success("Installed project VS Code settings")}const DB_CONNECTION_PACKAGES={postgres:{name:"postgresql.org",version:"^17.10",service:"postgres"},mysql:{name:"mysql.com",version:"*",service:"mysql"},sqlite:{name:"sqlite.org",version:"^3.47.2"}};function databaseAliases(connection,pkg){return[connection,pkg.name]}export function pantryDatabasePackage(connection){return DB_CONNECTION_PACKAGES[connection]}function detectDbPackage(cwd){const envPath=join(cwd,".env"),envExamplePath=join(cwd,".env.example"),filePath=existsSync(envPath)?envPath:existsSync(envExamplePath)?envExamplePath:void 0;if(!filePath)return;const match=readFileSync(filePath,"utf-8").match(/^DB_CONNECTION=(.+)$/m);if(!match)return;const value=match[1].trim().replace(/['"]/g,"");return pantryDatabasePackage(value)}export async function optimizePantryDeps(){const cwd=p.projectPath(),depsConfigPath=join(cwd,"config","deps.ts");if(!existsSync(depsConfigPath)){log.debug("No config/deps.ts found, skipping dependency optimization");return}let configDeps={},configServices=[];try{const mod=await import(depsConfigPath),config=mod.config||mod.default;if(config?.dependencies)configDeps={...config.dependencies};if(Array.isArray(config?.services?.autoStart))configServices=config.services.autoStart.filter((name)=>typeof name==="string")}catch(err){log.debug("Could not load config/deps.ts, skipping dependency optimization");return}const dbPackage=detectDbPackage(cwd),autoStart=[...configServices];if(dbPackage){const selected=new Set(Object.entries(DB_CONNECTION_PACKAGES).filter(([,pkg])=>pkg.name===dbPackage.name).flatMap(([connection,pkg])=>databaseAliases(connection,pkg))),unused=new Set(Object.entries(DB_CONNECTION_PACKAGES).flatMap(([connection,pkg])=>databaseAliases(connection,pkg)).filter((alias)=>!selected.has(alias)));for(const pkg of Object.keys(configDeps)){const domain=pkg.split("/")[0];if(unused.has(domain)){log.info(`DB_CONNECTION selects ${dbPackage.name}, dropping unused ${pkg}`);delete configDeps[pkg]}}if(!Object.keys(configDeps).some((key)=>{const domain=key.split("/")[0];return selected.has(domain)})){log.info(`Detected DB_CONNECTION requires ${dbPackage.name}, adding to dependencies`);configDeps[dbPackage.name]=dbPackage.version}if(dbPackage.service&&!autoStart.includes(dbPackage.service))autoStart.push(dbPackage.service)}const lines=["# Auto-generated from config/deps.ts and .env sniffing.","# This file is regenerated on each `buddy setup` run.","#","# To learn more, please visit:","# https://stacksjs.com/docs/dependency-management","","dependencies:"];for(const[pkg,version]of Object.entries(configDeps))lines.push(` ${pkg}: ${version}`);if(autoStart.length>0){lines.push("","services:"," enabled: true"," autoStart:");for(const service of autoStart)lines.push(` - ${service}`)}const depsYamlPath=join(cwd,"deps.yaml");writeFileSync(depsYamlPath,`${lines.join(`
|
|
1
|
+
import{cpSync,existsSync,readFileSync,writeFileSync}from"node:fs";import{homedir}from"node:os";import{join}from"node:path";import process from"node:process";import{runAction}from"@stacksjs/actions";import{log,onUnknownSubcommand,runCommand}from"@stacksjs/cli";import{Action}from"@stacksjs/enums";import{handleError}from"@stacksjs/error-handling";import{path as p}from"@stacksjs/path";import{copyFile,storage}from"@stacksjs/storage";import{ExitCode}from"@stacksjs/types";import{setupPrettyDevEnvironment}from"./dev";import{resultFailed}from"../result";function getTimeoutMs(envVar,fallbackMs){const value=Number(process.env[envVar]);if(Number.isFinite(value)&&value>0)return value;return fallbackMs}const PANTRY_CHECK_TIMEOUT_MS=getTimeoutMs("PANTRY_CHECK_TIMEOUT_MS",15000),PANTRY_INSTALL_TIMEOUT_MS=getTimeoutMs("PANTRY_INSTALL_TIMEOUT_MS",600000),PANTRY_DEPENDENCIES_TIMEOUT_MS=getTimeoutMs("PANTRY_DEPENDENCIES_TIMEOUT_MS",1200000),KEYGEN_TIMEOUT_MS=getTimeoutMs("KEYGEN_TIMEOUT_MS",120000),AWS_CONFIG_TIMEOUT_MS=getTimeoutMs("AWS_CONFIG_TIMEOUT_MS",900000);export function setup(buddy){const descriptions={setup:"This command ensures your project is setup correctly",ssl:"Setup SSL certificates and hosts file for HTTPS development",ai:"Set the project up for an AI coding agent (Claude Code, Codex, Cursor, Copilot, Gemini)",copy:"Copy the agent files instead of symlinking them, so they can be edited per project",force:"Overwrite files that already exist",ohMyZsh:"Enable Oh My Zsh",aws:"Ensures AWS is connected to the project",project:"Target a specific project",verbose:"Enable verbose output",domain:"Custom domain to setup (defaults to APP_URL)",skipHosts:"Skip adding domain to hosts file",skipTrust:"Skip trusting the certificate",skipAws:"Skip AWS configuration during setup",skipKeygen:"Skip generating an application key during setup"};buddy.command("setup",descriptions.setup).alias("ensure").option("-p, --project [project]",descriptions.project,{default:!1}).option("--skip-aws",descriptions.skipAws,{default:!1}).option("--skip-keygen",descriptions.skipKeygen,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(options)=>{log.debug("Running `buddy setup` ...",options);await ensurePantryInstalled();await optimizePantryDeps();await initializeProject(options)});buddy.command("setup:ssl",descriptions.ssl).alias("ssl:setup").option("-d, --domain [domain]",descriptions.domain).option("--skip-hosts",descriptions.skipHosts,{default:!1}).option("--skip-trust",descriptions.skipTrust,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(options)=>{log.debug("Running `buddy setup:ssl` ...",options);if(!await setupPrettyDevEnvironment({domain:options.domain,skipHosts:options.skipHosts,skipTrust:options.skipTrust,verbose:options.verbose})){log.warn("SSL setup completed with warnings");log.info("You may need to manually trust certificates or update hosts file")}});buddy.command("setup:ai [provider]",descriptions.ai).alias("ai:setup").option("--copy",descriptions.copy,{default:!1}).option("--force",descriptions.force,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(provider,options)=>{log.debug("Running `buddy setup:ai` ...",options);const{AI_PROVIDERS,isAiProvider,reportAiSetup,setupAiProvider}=await import("./setup-ai");let id=provider;if(!id){const{select}=await import("@stacksjs/cli");id=await select({message:"Which AI coding agent do you use?",choices:AI_PROVIDERS.map((entry)=>({value:entry.id,label:entry.label})),initial:0})}if(!id||!isAiProvider(id)){log.error(`Unknown AI provider: ${id}. Expected one of: ${AI_PROVIDERS.map((entry)=>entry.id).join(", ")}`);process.exit(ExitCode.InvalidArgument)}const definition=AI_PROVIDERS.find((entry)=>entry.id===id);reportAiSetup(definition,setupAiProvider(id,{copy:options.copy,force:options.force}))});buddy.command("setup:oh-my-zsh",descriptions.ohMyZsh).alias("upgrade:oh-my-zsh").option("--verbose",descriptions.verbose,{default:!1}).action(async(_options)=>{log.debug("Running `buddy setup:oh-my-zsh` ...",_options);const result=await runAction(Action.UpgradeShell);if(resultFailed(result)){log.error(result.error);process.exit(ExitCode.FatalError)}});onUnknownSubcommand(buddy,"setup")}async function isPantryInstalled(){try{return(await runCommand("pantry --version",{silent:!0,timeoutMs:PANTRY_CHECK_TIMEOUT_MS})).isOk}catch{return!1}}async function installPantry(){const bundledInstaller=p.frameworkPath("scripts/pantry-install"),command=existsSync(bundledInstaller)?[bundledInstaller]:["sh","-c","curl -fsSL https://pantry.dev | bash"],result=await runCommand(command,{timeoutMs:PANTRY_INSTALL_TIMEOUT_MS}),localBin=join(homedir(),".local","bin");if(!process.env.PATH?.split(":").includes(localBin))process.env.PATH=`${localBin}:${process.env.PATH||""}`;if(result.isOk&&await isPantryInstalled())return;if(resultFailed(result))handleError(result.error);else log.error("Pantry installed but is not available on PATH. Open a new shell and run `buddy setup` again.");process.exit(ExitCode.FatalError)}export async function ensurePantryInstalled(){if(await isPantryInstalled())return;log.info("Pantry is required. Installing it from https://pantry.dev...");await installPantry()}export async function ensurePantryDependencies(cwd){await ensurePantryInstalled();log.info("Installing project dependencies with Pantry...");const result=await runCommand("pantry install",{cwd,timeoutMs:PANTRY_DEPENDENCIES_TIMEOUT_MS});if(resultFailed(result)){handleError(result.error);process.exit(ExitCode.FatalError)}if(existsSync(join(cwd,"package.json"))&&!existsSync(join(cwd,"node_modules"))){log.error("Pantry completed without installing the project JavaScript dependencies.");process.exit(ExitCode.FatalError)}log.success("Installed project dependencies with Pantry")}function hasAppKey(cwd){const envPath=join(cwd,".env");if(!existsSync(envPath))return!1;return/^APP_KEY=.+$/m.test(readFileSync(envPath,"utf-8"))}export async function ensureAppKey(cwd){if(hasAppKey(cwd)||process.env.APP_KEY&&process.env.APP_KEY.length>0){log.success("APP_KEY existed");return}const keyResult=await runCommand("./buddy key:generate",{cwd,timeoutMs:KEYGEN_TIMEOUT_MS});if(resultFailed(keyResult)){handleError(keyResult.error);process.exit(ExitCode.FatalError)}log.success("Generated application key")}async function runInitialMigration(cwd){const appEnv=(process.env.APP_ENV||process.env.NODE_ENV||"local").toLowerCase();if(!["local","development","dev","test"].includes(appEnv)){log.info(`Skipping initial migration in the ${appEnv} environment`);return}log.info("Running initial database migration...");try{const result=await runAction(Action.Migrate,{cwd});if(resultFailed(result)){log.warn("Initial migration did not complete - you can run it later via ./buddy migrate");log.debug(result.error);return}log.success("Database is migrated")}catch(error){log.warn("Initial migration did not complete - you can run it later via ./buddy migrate");log.debug(error)}}async function initializeProject(options){const cwd=options.cwd||p.projectPath();await ensurePantryDependencies(cwd);await ensureEnvIsSet(options);if(!options.skipKeygen)await ensureAppKey(cwd);await runInitialMigration(cwd);ensureIdeSettings(cwd);if(!options.skipAws){log.info("Ensuring AWS is connected...");try{const awsResult=await runCommand("./buddy configure:aws",{cwd,timeoutMs:AWS_CONFIG_TIMEOUT_MS});if(resultFailed(awsResult)){log.warn("AWS not configured - you can do this later via ./buddy configure:aws");log.debug(awsResult.error)}else log.success("Configured AWS")}catch(error){log.warn("AWS not configured - you can do this later via ./buddy configure:aws");log.debug(error)}}log.success("Project is setup");log.info("Run `./buddy doctor` anytime to check your setup. Happy coding! \uD83D\uDC99")}export function ensureIdeSettings(cwd){const source=p.frameworkPath("defaults/ide/vscode/.vscode"),destination=join(cwd,".vscode");if(existsSync(destination)){log.debug(".vscode already exists; keeping the project settings");return}if(!existsSync(source)){log.debug("No bundled VS Code settings found; skipping IDE setup");return}cpSync(source,destination,{recursive:!0});log.success("Installed project VS Code settings")}const DB_CONNECTION_PACKAGES={postgres:{name:"postgresql.org",version:"^17.10",service:"postgres"},mysql:{name:"mysql.com",version:"*",service:"mysql"},sqlite:{name:"sqlite.org",version:"^3.47.2"}};function databaseAliases(connection,pkg){return[connection,pkg.name]}export function pantryDatabasePackage(connection){return DB_CONNECTION_PACKAGES[connection]}function detectDbPackage(cwd){const envPath=join(cwd,".env"),envExamplePath=join(cwd,".env.example"),filePath=existsSync(envPath)?envPath:existsSync(envExamplePath)?envExamplePath:void 0;if(!filePath)return;const match=readFileSync(filePath,"utf-8").match(/^DB_CONNECTION=(.+)$/m);if(!match)return;const value=match[1].trim().replace(/['"]/g,"");return pantryDatabasePackage(value)}export async function optimizePantryDeps(){const cwd=p.projectPath(),depsConfigPath=join(cwd,"config","deps.ts");if(!existsSync(depsConfigPath)){log.debug("No config/deps.ts found, skipping dependency optimization");return}let configDeps={},configServices=[];try{const mod=await import(depsConfigPath),config=mod.config||mod.default;if(config?.dependencies)configDeps={...config.dependencies};if(Array.isArray(config?.services?.autoStart))configServices=config.services.autoStart.filter((name)=>typeof name==="string")}catch(err){log.debug("Could not load config/deps.ts, skipping dependency optimization");return}const dbPackage=detectDbPackage(cwd),autoStart=[...configServices];if(dbPackage){const selected=new Set(Object.entries(DB_CONNECTION_PACKAGES).filter(([,pkg])=>pkg.name===dbPackage.name).flatMap(([connection,pkg])=>databaseAliases(connection,pkg))),unused=new Set(Object.entries(DB_CONNECTION_PACKAGES).flatMap(([connection,pkg])=>databaseAliases(connection,pkg)).filter((alias)=>!selected.has(alias)));for(const pkg of Object.keys(configDeps)){const domain=pkg.split("/")[0];if(unused.has(domain)){log.info(`DB_CONNECTION selects ${dbPackage.name}, dropping unused ${pkg}`);delete configDeps[pkg]}}if(!Object.keys(configDeps).some((key)=>{const domain=key.split("/")[0];return selected.has(domain)})){log.info(`Detected DB_CONNECTION requires ${dbPackage.name}, adding to dependencies`);configDeps[dbPackage.name]=dbPackage.version}if(dbPackage.service&&!autoStart.includes(dbPackage.service))autoStart.push(dbPackage.service)}const lines=["# Auto-generated from config/deps.ts and .env sniffing.","# This file is regenerated on each `buddy setup` run.","#","# To learn more, please visit:","# https://stacksjs.com/docs/dependency-management","","dependencies:"];for(const[pkg,version]of Object.entries(configDeps))lines.push(` ${pkg}: ${version}`);if(autoStart.length>0){lines.push("","services:"," enabled: true"," autoStart:");for(const service of autoStart)lines.push(` - ${service}`)}const depsYamlPath=join(cwd,"deps.yaml");writeFileSync(depsYamlPath,`${lines.join(`
|
|
2
2
|
`)}
|
|
3
3
|
`);log.success("Generated deps.yaml from config/deps.ts")}export async function ensureEnvIsSet(options){log.info("Ensuring .env exists...");const cwd=options.cwd||p.projectPath(),envPath=`${cwd}/.env`,envExamplePath=`${cwd}/.env.example`;if(storage.doesNotExist(envPath)){try{copyFile(envExamplePath,envPath)}catch(error){handleError(error);process.exit(ExitCode.FatalError)}log.success(".env created")}else log.success(".env existed")}
|
package/dist/commands/test.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import process from"node:process";import{runAction}from"@stacksjs/actions";import{intro,log,onUnknownSubcommand,outro}from"@stacksjs/cli";import{Action}from"@stacksjs/enums";import{projectPath}from"@stacksjs/path";import{ExitCode}from"@stacksjs/types";export function test(buddy){const descriptions={command:"Runs your test suite",types:"Typechecks your codebase",coverage:"Generates a test coverage report",ui:"Runs your test suite in the browser",unit:"Runs your unit tests",feature:"Runs your feature tests",showReport:"Show the test report",project:"Target a specific project",verbose:"Enable verbose output"};buddy.command("test",descriptions.command).option("-f, --feature",descriptions.feature,{default:!1}).option("-u, --unit",descriptions.unit,{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!0}).action(async(options)=>{const perf=await intro("buddy test");if(options.feature&&options.unit){const result=await runAction(Action.Test,{...options,cwd:projectPath()});if(result
|
|
1
|
+
import process from"node:process";import{runAction}from"@stacksjs/actions";import{intro,log,onUnknownSubcommand,outro}from"@stacksjs/cli";import{Action}from"@stacksjs/enums";import{projectPath}from"@stacksjs/path";import{ExitCode}from"@stacksjs/types";import{resultFailed}from"../result";export function test(buddy){const descriptions={command:"Runs your test suite",types:"Typechecks your codebase",coverage:"Generates a test coverage report",ui:"Runs your test suite in the browser",unit:"Runs your unit tests",feature:"Runs your feature tests",showReport:"Show the test report",project:"Target a specific project",verbose:"Enable verbose output"};buddy.command("test",descriptions.command).option("-f, --feature",descriptions.feature,{default:!1}).option("-u, --unit",descriptions.unit,{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!0}).action(async(options)=>{const perf=await intro("buddy test");if(options.feature&&options.unit){const result=await runAction(Action.Test,{...options,cwd:projectPath()});if(resultFailed(result)){await outro("While running `buddy test`, there was an issue",{startTime:perf,useSeconds:!0},result.error);process.exit(ExitCode.FatalError)}}if(options.feature&&!options.unit){log.info("Running Feature tests...");const result=await runAction(Action.TestFeature,{...options,cwd:projectPath()});if(resultFailed(result)){await outro("While running `buddy test`, there was an issue",{startTime:perf,useSeconds:!0},result.error);process.exit(ExitCode.FatalError)}}if(!options.feature&&options.unit){log.info("Running Unit tests...");const result=await runAction(Action.TestUnit,{...options,cwd:projectPath()});if(resultFailed(result)){await outro("While running `buddy test`, there was an issue",{startTime:perf,useSeconds:!0},result.error);process.exit(ExitCode.FatalError)}}if(!options.feature&&!options.unit){const result=await runAction(Action.Test,{...options,cwd:projectPath()});if(resultFailed(result)){await outro("While running `buddy test`, there was an issue",{startTime:perf,useSeconds:!0},result.error);process.exit(ExitCode.FatalError)}}await outro("Finished running tests",{startTime:perf,useSeconds:!0});process.exit(ExitCode.Success)});buddy.command("test:unit",descriptions.unit).option("--verbose",descriptions.verbose,{default:!1}).action(async(options)=>{const perf=await intro("buddy test:unit"),result=await runAction(Action.TestUnit,{...options,verbose:!0,cwd:projectPath()});if(resultFailed(result)){await outro("While running `buddy test:unit`, there was an issue",{startTime:perf,useSeconds:!0},result.error);process.exit(ExitCode.FatalError)}await outro("Finished running unit tests",{startTime:perf,useSeconds:!0})});buddy.command("test:feature",descriptions.feature).option("--verbose",descriptions.verbose,{default:!1}).action(async(options)=>{const perf=await intro("buddy test:feature"),result=await runAction(Action.TestFeature,{...options,verbose:!0,cwd:projectPath()});if(resultFailed(result)){await outro("While running `buddy test:feature`, there was an issue",{startTime:perf,useSeconds:!0},result.error);process.exit(ExitCode.FatalError)}await outro("Finished running feature tests",{startTime:perf,useSeconds:!0})});buddy.command("test:ui",descriptions.command).option("--verbose",descriptions.verbose,{default:!1}).action(async(options)=>{const perf=await intro("buddy test:ui"),result=await runAction(Action.TestUi,{...options,verbose:!0,cwd:projectPath()});if(resultFailed(result)){await outro("While running `buddy test:ui`, there was an issue",{startTime:perf,useSeconds:!0},result.error);process.exit(ExitCode.FatalError)}await outro("Finished running tests in the browser",{startTime:perf,useSeconds:!0})});buddy.command("test:types",descriptions.types).alias("typecheck").option("--verbose",descriptions.verbose,{default:!1}).action(async(options)=>{const perf=await intro("buddy test:types"),result=await runAction(Action.Typecheck,{...options,verbose:!0,cwd:projectPath()});if(resultFailed(result)){await outro("While running `buddy test:types`, there was an issue",{startTime:perf,useSeconds:!0},result.error);process.exit(ExitCode.FatalError)}await outro("Finished running typecheck",{startTime:perf,useSeconds:!0})});onUnknownSubcommand(buddy,"test")}
|
package/dist/commands/upgrade.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import process from"node:process";import{runAction}from"@stacksjs/actions";import{intro,log,onUnknownSubcommand,outro}from"@stacksjs/cli";import{Action}from"@stacksjs/enums";import{ExitCode}from"@stacksjs/types";export function upgrade(buddy){const descriptions={upgrade:"Upgrade the Stacks framework to the latest version",version:"Install a specific version (e.g., 0.70.23)",canary:"Upgrade to the latest canary (bleeding-edge `main`) build",stable:"Switch to the latest vetted stable release",dryRun:"Preview the upgrade (which dependencies would change) without writing or installing",force:"Force re-download, bypassing cache and version checks",from:"Sync from a local stacks checkout (e.g. ~/Code/stacks). Skips GitHub.",noPostinstall:"Skip post-sync hooks (auto-imports, bun install, migrate)",verbose:"Enable verbose output",dependencies:"Upgrade your dependencies (pantry.yaml & package.json)",bun:"Upgrade Bun to the latest version",shell:"Upgrade the shell integration (currently only supports Oh My Zsh)",binary:"Upgrade the `stacks` binary to the latest version",project:"Target a specific project",all:"Upgrade framework, dependencies, Bun, and binary"};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)=>{log.debug("Running `buddy upgrade` ...",options);const opts={...options};if(opts.postinstall===!1){delete opts.postinstall;opts.noPostinstall=!0}const perf=await intro("buddy upgrade"),result=await runAction(Action.UpgradeFramework,opts);if(result
|
|
1
|
+
import process from"node:process";import{runAction}from"@stacksjs/actions";import{intro,log,onUnknownSubcommand,outro}from"@stacksjs/cli";import{Action}from"@stacksjs/enums";import{ExitCode}from"@stacksjs/types";import{resultFailed}from"../result";export function upgrade(buddy){const descriptions={upgrade:"Upgrade the Stacks framework to the latest version",version:"Install a specific version (e.g., 0.70.23)",canary:"Upgrade to the latest canary (bleeding-edge `main`) build",stable:"Switch to the latest vetted stable release",dryRun:"Preview the upgrade (which dependencies would change) without writing or installing",force:"Force re-download, bypassing cache and version checks",from:"Sync from a local stacks checkout (e.g. ~/Code/stacks). Skips GitHub.",noPostinstall:"Skip post-sync hooks (auto-imports, bun install, migrate)",verbose:"Enable verbose output",dependencies:"Upgrade your dependencies (pantry.yaml & package.json)",bun:"Upgrade Bun to the latest version",shell:"Upgrade the shell integration (currently only supports Oh My Zsh)",binary:"Upgrade the `stacks` binary to the latest version",project:"Target a specific project",all:"Upgrade framework, dependencies, Bun, and binary"};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)=>{log.debug("Running `buddy upgrade` ...",options);const opts={...options};if(opts.postinstall===!1){delete opts.postinstall;opts.noPostinstall=!0}const perf=await intro("buddy upgrade"),result=await runAction(Action.UpgradeFramework,opts);if(resultFailed(result)){await outro("While running buddy upgrade, there was an issue",{startTime:perf,useSeconds:!0},result.error);process.exit(ExitCode.FatalError)}await outro("Upgrade complete.",{startTime:perf,useSeconds:!0});process.exit(ExitCode.Success)});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)=>{log.debug("Running `buddy upgrade:all` ...",options);const perf=await intro("buddy upgrade:all");options.all=!0;const result=await runAction(Action.Upgrade,options);if(resultFailed(result)){await outro("While running buddy upgrade:all, there was an issue",{startTime:perf,useSeconds:!0},result.error);process.exit(ExitCode.FatalError)}await outro("All upgrades complete.",{startTime:perf,useSeconds:!0});process.exit(ExitCode.Success)});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)=>{log.debug("Running `buddy upgrade:dependencies` ...",options);const perf=await intro("buddy upgrade:dependencies");options.dependencies=!0;const result=await runAction(Action.Upgrade,options);if(resultFailed(result)){await outro("While running buddy upgrade:dependencies, there was an issue",{startTime:perf,useSeconds:!0},result.error);process.exit(ExitCode.FatalError)}await outro("Dependencies upgraded.",{startTime:perf,useSeconds:!0});process.exit(ExitCode.Success)});buddy.command("upgrade:bun",descriptions.bun).option("--verbose",descriptions.verbose,{default:!1}).example("buddy upgrade:bun").action(async(options)=>{log.debug("Running `buddy upgrade:bun` ...",options);const perf=await intro("buddy upgrade:bun"),result=await runAction(Action.UpgradeBun,options);if(resultFailed(result)){await outro("While running buddy upgrade:bun, there was an issue",{startTime:perf,useSeconds:!0},result.error);process.exit(ExitCode.FatalError)}await outro("Bun upgraded.",{startTime:perf,useSeconds:!0});process.exit(ExitCode.Success)});buddy.command("upgrade:shell",descriptions.shell).option("--verbose",descriptions.verbose,{default:!1}).example("buddy upgrade:shell").action(async(options)=>{log.debug("Running `buddy upgrade:shell` ...",options);const perf=await intro("buddy upgrade:shell"),result=await runAction(Action.UpgradeShell,options);if(resultFailed(result)){await outro("While running buddy upgrade:shell, there was an issue",{startTime:perf,useSeconds:!0},result.error);process.exit(ExitCode.FatalError)}await outro("Shell integration upgraded.",{startTime:perf,useSeconds:!0});process.exit(ExitCode.Success)});buddy.command("upgrade:binary",descriptions.binary).option("--verbose",descriptions.verbose,{default:!1}).example("buddy upgrade:binary").action(async(options)=>{if(process.getuid&&process.getuid()!==0){log.warn("To upgrade the binary, you need to run this command with sudo, or as root.");process.exit(ExitCode.FatalError)}log.debug("Running `buddy upgrade:binary` ...",options);const perf=await intro("buddy upgrade:binary"),result=await runAction(Action.UpgradeBinary,options);if(resultFailed(result)){await outro("While running buddy upgrade:binary, there was an issue",{startTime:perf,useSeconds:!0},result.error);process.exit(ExitCode.FatalError)}await outro("Binary upgraded.",{startTime:perf,useSeconds:!0});process.exit(ExitCode.Success)});onUnknownSubcommand(buddy,"upgrade")}
|
package/dist/result.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a result - of either shape - is a failure.
|
|
3
|
+
*
|
|
4
|
+
* Declared as a type predicate rather than as `boolean` so it narrows the way
|
|
5
|
+
* `result.isErr()` does. Without that, every call site that goes on to read
|
|
6
|
+
* `result.error` stops compiling, and the fix for a runtime bug would have
|
|
7
|
+
* cost the type safety around it.
|
|
8
|
+
*/
|
|
9
|
+
export declare function resultFailed(result: unknown): result is { error?: unknown };
|
|
10
|
+
/**
|
|
11
|
+
* The message to show, as a sentence rather than as an object.
|
|
12
|
+
*
|
|
13
|
+
* A command that refuses usually names the fix in its message - a dialect
|
|
14
|
+
* mismatch, a model that would drop columns, a missing key - and passing the
|
|
15
|
+
* error as a second argument to a logger throws that away and leaves a bare
|
|
16
|
+
* exit code. This is what gets printed.
|
|
17
|
+
*/
|
|
18
|
+
export declare function resultError(result: unknown, fallback?: string): string;
|
package/dist/result.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function resultFailed(result){if(!result||typeof result!=="object")return!1;const candidate=result;return typeof candidate.isErr==="function"?candidate.isErr():Boolean(candidate.isErr)}export function resultError(result,fallback="Unknown error"){if(!result||typeof result!=="object")return fallback;const error=result.error;if(error instanceof Error)return error.message;if(typeof error==="string"&&error)return error;return error===void 0||error===null?fallback:String(error)}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/buddy",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.70.
|
|
5
|
+
"version": "0.70.266",
|
|
6
6
|
"description": "Meet Buddy. The Stacks runtime.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -95,54 +95,54 @@
|
|
|
95
95
|
"prepublishOnly": "bun run build"
|
|
96
96
|
},
|
|
97
97
|
"dependencies": {
|
|
98
|
-
"@stacksjs/actions": "^0.70.
|
|
99
|
-
"@stacksjs/ai": "^0.70.
|
|
100
|
-
"@stacksjs/alias": "^0.70.
|
|
101
|
-
"@stacksjs/arrays": "^0.70.
|
|
102
|
-
"@stacksjs/auth": "^0.70.
|
|
103
|
-
"@stacksjs/build": "^0.70.
|
|
104
|
-
"@stacksjs/cache": "^0.70.
|
|
105
|
-
"@stacksjs/cli": "^0.70.
|
|
98
|
+
"@stacksjs/actions": "^0.70.266",
|
|
99
|
+
"@stacksjs/ai": "^0.70.266",
|
|
100
|
+
"@stacksjs/alias": "^0.70.266",
|
|
101
|
+
"@stacksjs/arrays": "^0.70.266",
|
|
102
|
+
"@stacksjs/auth": "^0.70.266",
|
|
103
|
+
"@stacksjs/build": "^0.70.266",
|
|
104
|
+
"@stacksjs/cache": "^0.70.266",
|
|
105
|
+
"@stacksjs/cli": "^0.70.266",
|
|
106
106
|
"@stacksjs/clapp": "^0.2.12",
|
|
107
|
-
"@stacksjs/cloud": "^0.70.
|
|
108
|
-
"@stacksjs/collections": "^0.70.
|
|
109
|
-
"@stacksjs/config": "^0.70.
|
|
110
|
-
"@stacksjs/database": "^0.70.
|
|
111
|
-
"@stacksjs/desktop-build": "^0.70.
|
|
112
|
-
"@stacksjs/dns": "^0.70.
|
|
113
|
-
"@stacksjs/email": "^0.70.
|
|
114
|
-
"@stacksjs/enums": "^0.70.
|
|
115
|
-
"@stacksjs/error-handling": "^0.70.
|
|
116
|
-
"@stacksjs/events": "^0.70.
|
|
117
|
-
"@stacksjs/git": "^0.70.
|
|
107
|
+
"@stacksjs/cloud": "^0.70.266",
|
|
108
|
+
"@stacksjs/collections": "^0.70.266",
|
|
109
|
+
"@stacksjs/config": "^0.70.266",
|
|
110
|
+
"@stacksjs/database": "^0.70.266",
|
|
111
|
+
"@stacksjs/desktop-build": "^0.70.266",
|
|
112
|
+
"@stacksjs/dns": "^0.70.266",
|
|
113
|
+
"@stacksjs/email": "^0.70.266",
|
|
114
|
+
"@stacksjs/enums": "^0.70.266",
|
|
115
|
+
"@stacksjs/error-handling": "^0.70.266",
|
|
116
|
+
"@stacksjs/events": "^0.70.266",
|
|
117
|
+
"@stacksjs/git": "^0.70.266",
|
|
118
118
|
"@stacksjs/gitit": "^0.2.5",
|
|
119
|
-
"@stacksjs/health": "^0.70.
|
|
119
|
+
"@stacksjs/health": "^0.70.266",
|
|
120
120
|
"@stacksjs/dnsx": "^0.2.3",
|
|
121
121
|
"@stacksjs/httx": "^0.1.10",
|
|
122
|
-
"@stacksjs/image": "^0.70.
|
|
123
|
-
"@stacksjs/lint": "^0.70.
|
|
124
|
-
"@stacksjs/logging": "^0.70.
|
|
125
|
-
"@stacksjs/notifications": "^0.70.
|
|
126
|
-
"@stacksjs/objects": "^0.70.
|
|
127
|
-
"@stacksjs/orm": "^0.70.
|
|
128
|
-
"@stacksjs/path": "^0.70.
|
|
129
|
-
"@stacksjs/skills": "^0.70.
|
|
130
|
-
"@stacksjs/payments": "^0.70.
|
|
131
|
-
"@stacksjs/realtime": "^0.70.
|
|
132
|
-
"@stacksjs/router": "^0.70.
|
|
122
|
+
"@stacksjs/image": "^0.70.266",
|
|
123
|
+
"@stacksjs/lint": "^0.70.266",
|
|
124
|
+
"@stacksjs/logging": "^0.70.266",
|
|
125
|
+
"@stacksjs/notifications": "^0.70.266",
|
|
126
|
+
"@stacksjs/objects": "^0.70.266",
|
|
127
|
+
"@stacksjs/orm": "^0.70.266",
|
|
128
|
+
"@stacksjs/path": "^0.70.266",
|
|
129
|
+
"@stacksjs/skills": "^0.70.266",
|
|
130
|
+
"@stacksjs/payments": "^0.70.266",
|
|
131
|
+
"@stacksjs/realtime": "^0.70.266",
|
|
132
|
+
"@stacksjs/router": "^0.70.266",
|
|
133
133
|
"@stacksjs/rpx": "^0.11.42",
|
|
134
|
-
"@stacksjs/search-engine": "^0.70.
|
|
135
|
-
"@stacksjs/security": "^0.70.
|
|
136
|
-
"@stacksjs/server": "^0.70.
|
|
137
|
-
"@stacksjs/storage": "^0.70.
|
|
138
|
-
"@stacksjs/strings": "^0.70.
|
|
139
|
-
"@stacksjs/testing": "^0.70.
|
|
140
|
-
"@stacksjs/tunnel": "^0.70.
|
|
141
|
-
"@stacksjs/types": "^0.70.
|
|
142
|
-
"@stacksjs/ui": "^0.70.
|
|
143
|
-
"@stacksjs/utils": "^0.70.
|
|
144
|
-
"@stacksjs/validation": "^0.70.
|
|
145
|
-
"@stacksjs/ts-cloud": "^0.7.
|
|
134
|
+
"@stacksjs/search-engine": "^0.70.266",
|
|
135
|
+
"@stacksjs/security": "^0.70.266",
|
|
136
|
+
"@stacksjs/server": "^0.70.266",
|
|
137
|
+
"@stacksjs/storage": "^0.70.266",
|
|
138
|
+
"@stacksjs/strings": "^0.70.266",
|
|
139
|
+
"@stacksjs/testing": "^0.70.266",
|
|
140
|
+
"@stacksjs/tunnel": "^0.70.266",
|
|
141
|
+
"@stacksjs/types": "^0.70.266",
|
|
142
|
+
"@stacksjs/ui": "^0.70.266",
|
|
143
|
+
"@stacksjs/utils": "^0.70.266",
|
|
144
|
+
"@stacksjs/validation": "^0.70.266",
|
|
145
|
+
"@stacksjs/ts-cloud": "^0.7.97",
|
|
146
146
|
"ajv": "^8.20.0",
|
|
147
147
|
"ajv-formats": "^3.0.1",
|
|
148
148
|
"ts-pantry": "^0.11.0"
|