@stacksjs/buddy 0.70.161 → 0.70.163
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/commands/add.js +18 -26
- package/dist/commands/ai-context.d.ts +13 -0
- package/dist/commands/ai-context.js +29 -0
- package/dist/commands/create.js +1 -7
- package/dist/commands/deploy.js +7 -24
- package/dist/commands/mail.js +1 -1
- package/dist/commands/migrate.js +6 -4
- package/dist/commands/setup.d.ts +0 -1
- package/dist/commands/setup.js +19 -37
- package/dist/commands/stacks.js +10 -7
- package/dist/lazy-commands.js +1 -0
- package/dist/project-setup.js +1 -0
- package/package.json +42 -43
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ curl -Ssf stacksjs.com/install | sh # wip
|
|
|
35
35
|
|
|
36
36
|
# alternatively, if Bun >= v1.1.11 is installed already
|
|
37
37
|
# you may also get started via
|
|
38
|
-
|
|
38
|
+
panx @stacksjs/buddy new my-project
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
## Usage
|
|
@@ -79,7 +79,7 @@ buddy --help # view help menu
|
|
|
79
79
|
# `command --help` flag to review the help menu
|
|
80
80
|
|
|
81
81
|
buddy install # installs dependencies
|
|
82
|
-
buddy add #
|
|
82
|
+
buddy add calendar # pulls a registered project-shaped stack into this project
|
|
83
83
|
buddy fresh # fresh reinstall of all deps
|
|
84
84
|
buddy clean # removes all deps
|
|
85
85
|
buddy setup # sets up the project initially
|
|
@@ -154,7 +154,7 @@ buddy make:factory cars # creates a Car factory file
|
|
|
154
154
|
buddy make:table cars # bootstraps a cars data table
|
|
155
155
|
buddy make:notification welcome-email # bootstraps a welcome-email notification
|
|
156
156
|
buddy make:lang de # bootstraps a lang/de.yml language file
|
|
157
|
-
buddy make:stack my-project #
|
|
157
|
+
buddy make:stack my-project # scaffolds a project-shaped registry stack
|
|
158
158
|
|
|
159
159
|
buddy migrate # runs database migrations
|
|
160
160
|
buddy migrate:dns # sets the ./config/dns.ts file
|
package/dist/commands/add.js
CHANGED
|
@@ -1,33 +1,25 @@
|
|
|
1
1
|
import process from "node:process";
|
|
2
|
-
import {
|
|
3
|
-
import { log } from "@stacksjs/
|
|
2
|
+
import { installStack } from "@stacksjs/actions";
|
|
3
|
+
import { intro, italic, log, onUnknownSubcommand, outro } from "@stacksjs/cli";
|
|
4
4
|
import { ExitCode } from "@stacksjs/types";
|
|
5
|
-
import { onUnknownSubcommand } from "@stacksjs/cli";
|
|
6
5
|
export function add(buddy) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
6
|
+
buddy.command("add <stack>", "Pull a registered stack and merge its project files into this Stacks application").option("--force", "Overwrite existing files", { default: !1 }).option("--dry-run", "Show which files would be installed without changing the project", { default: !1 }).option("--conflict <strategy>", "Resolve existing files with skip, overwrite, or backup", { default: "skip" }).option("-p, --project <path>", "Target a specific Stacks project").option("--verbose", "Show every file copied or skipped", { default: !1 }).example("buddy add calendar").example("buddy add table --dry-run").example("buddy add calendar --conflict backup").action(async (stack, options) => {
|
|
7
|
+
const perf = await intro("buddy add");
|
|
8
|
+
if (!await installStack({
|
|
9
|
+
name: stack,
|
|
10
|
+
force: options.force,
|
|
11
|
+
dryRun: options.dryRun,
|
|
12
|
+
conflict: options.conflict,
|
|
13
|
+
project: options.project,
|
|
14
|
+
verbose: options.verbose
|
|
15
|
+
})) {
|
|
16
|
+
await outro(`Could not add stack ${italic(stack)}.`, { startTime: perf, useSeconds: !0 });
|
|
17
|
+
process.exit(ExitCode.FatalError);
|
|
18
|
+
}
|
|
19
|
+
if (options.dryRun)
|
|
20
|
+
log.info("Dry run complete. No project files were changed.");
|
|
21
|
+
await outro(`Stack ${italic(stack)} added.`, { startTime: perf, useSeconds: !0 });
|
|
21
22
|
process.exit(ExitCode.Success);
|
|
22
23
|
});
|
|
23
|
-
buddy.command("add:table", descriptions.table).option("-t, --table", descriptions.table, { default: !0 }).option("-p, --project [project]", descriptions.project, { default: !1 }).option("--verbose", descriptions.verbose, { default: !1 }).action(async (options) => {
|
|
24
|
-
await runAdd(options);
|
|
25
|
-
});
|
|
26
|
-
buddy.command("add:calendar", descriptions.calendar).option("-t, --calendar", descriptions.calendar, { default: !0 }).option("-p, --project [project]", descriptions.project, { default: !1 }).option("--verbose", descriptions.verbose, { default: !1 }).action(async (options) => {
|
|
27
|
-
await runAdd(options);
|
|
28
|
-
});
|
|
29
24
|
onUnknownSubcommand(buddy, "add");
|
|
30
25
|
}
|
|
31
|
-
function hasNoOptions(options) {
|
|
32
|
-
return !options.all && !options.table && !options.calendar;
|
|
33
|
-
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CLI, CliOptions } from '@stacksjs/types';
|
|
2
|
+
export declare function generateAiContextOutput(options?: AiContextCommandOptions, projectRoot?: string): AiContextCommandResult;
|
|
3
|
+
export declare function aiContext(buddy: CLI): void;
|
|
4
|
+
export declare interface AiContextCommandOptions extends CliOptions {
|
|
5
|
+
json?: boolean
|
|
6
|
+
output?: string
|
|
7
|
+
maxChars?: string | number
|
|
8
|
+
model?: string
|
|
9
|
+
}
|
|
10
|
+
export declare interface AiContextCommandResult {
|
|
11
|
+
output: string
|
|
12
|
+
outputPath: string | null
|
|
13
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import process from "node:process";
|
|
4
|
+
import { buildProjectContext } from "@stacksjs/ai";
|
|
5
|
+
import { onUnknownSubcommand } from "@stacksjs/cli";
|
|
6
|
+
export function generateAiContextOutput(options = {}, projectRoot = process.cwd()) {
|
|
7
|
+
const maxChars = options.maxChars === void 0 ? void 0 : Number(options.maxChars), result = buildProjectContext(projectRoot, { maxChars, model: options.model }), output = options.json ? `${JSON.stringify(result, null, 2)}
|
|
8
|
+
` : `${result.text}
|
|
9
|
+
|
|
10
|
+
Context metrics:
|
|
11
|
+
${JSON.stringify(result.metrics, null, 2)}
|
|
12
|
+
`;
|
|
13
|
+
if (!options.output)
|
|
14
|
+
return { output, outputPath: null };
|
|
15
|
+
const outputPath = resolve(projectRoot, String(options.output));
|
|
16
|
+
mkdirSync(dirname(outputPath), { recursive: !0 });
|
|
17
|
+
writeFileSync(outputPath, output);
|
|
18
|
+
return { output, outputPath };
|
|
19
|
+
}
|
|
20
|
+
export function aiContext(buddy) {
|
|
21
|
+
buddy.command("ai:context", "Generate compact deterministic project context for coding models").option("-J, --json", "Emit the versioned machine-readable context contract", { default: !1 }).option("-o, --output [path]", "Write output to a file instead of stdout").option("--max-chars [characters]", "Maximum characters in the prompt context payload", { default: 4000 }).option("--model [model]", "Model family used for the heuristic token estimate", { default: "gpt-4o" }).example("buddy ai:context").example("buddy ai:context --json").example("buddy ai:context --json --output .stacks/ai-context.json").action((options) => {
|
|
22
|
+
const generated = generateAiContextOutput(options);
|
|
23
|
+
if (generated.outputPath)
|
|
24
|
+
console.log(`Wrote AI project context to ${generated.outputPath}`);
|
|
25
|
+
else
|
|
26
|
+
process.stdout.write(generated.output);
|
|
27
|
+
});
|
|
28
|
+
onUnknownSubcommand(buddy, "ai:context");
|
|
29
|
+
}
|
package/dist/commands/create.js
CHANGED
|
@@ -103,14 +103,8 @@ async function ensureEnv(path, _options) {
|
|
|
103
103
|
}
|
|
104
104
|
async function install(path, options) {
|
|
105
105
|
log.info("Installing & setting up Stacks");
|
|
106
|
-
log.info("Running bun install...");
|
|
107
|
-
let result = await runCommand("bun install", { ...options, cwd: path });
|
|
108
|
-
if (result?.isErr) {
|
|
109
|
-
log.error(result.error);
|
|
110
|
-
process.exit(ExitCode.FatalError);
|
|
111
|
-
}
|
|
112
106
|
log.info("Copying .env.example \u2192 .env");
|
|
113
|
-
result = await runCommand("cp .env.example .env", { ...options, cwd: path });
|
|
107
|
+
let result = await runCommand("cp .env.example .env", { ...options, cwd: path });
|
|
114
108
|
if (result?.isErr) {
|
|
115
109
|
log.error(result.error);
|
|
116
110
|
process.exit(ExitCode.FatalError);
|
package/dist/commands/deploy.js
CHANGED
|
@@ -395,7 +395,7 @@ async function pollUntil(opts) {
|
|
|
395
395
|
let lastHeartbeat = 0;
|
|
396
396
|
for (;; )
|
|
397
397
|
try {
|
|
398
|
-
opts.check();
|
|
398
|
+
await opts.check();
|
|
399
399
|
return;
|
|
400
400
|
} catch {
|
|
401
401
|
const elapsedSecs = Math.floor((Date.now() - started) / 1000);
|
|
@@ -408,33 +408,18 @@ async function pollUntil(opts) {
|
|
|
408
408
|
await new Promise((r) => setTimeout(r, opts.intervalMs ?? 5000));
|
|
409
409
|
}
|
|
410
410
|
}
|
|
411
|
-
async function waitForRemoteReady(ip
|
|
412
|
-
const {
|
|
413
|
-
"-o",
|
|
414
|
-
"StrictHostKeyChecking=no",
|
|
415
|
-
"-o",
|
|
416
|
-
"UserKnownHostsFile=/dev/null",
|
|
417
|
-
"-o",
|
|
418
|
-
"BatchMode=yes",
|
|
419
|
-
"-o",
|
|
420
|
-
"ConnectTimeout=10",
|
|
421
|
-
`root@${ip}`
|
|
422
|
-
], run = (remote) => execSync(`ssh ${sshArgs.map((a) => `'${a}'`).join(" ")} '${remote.replace(/'/g, "'\\''")}'`, {
|
|
423
|
-
encoding: "utf8",
|
|
424
|
-
stdio: ["ignore", "pipe", verbose ? "inherit" : "pipe"]
|
|
425
|
-
}), sshWaitSecs = readWaitSecs("TS_CLOUD_SSH_WAIT_SECS", 480);
|
|
411
|
+
async function waitForRemoteReady(ip) {
|
|
412
|
+
const { sshExecOrThrow } = await import("@stacksjs/ts-cloud"), run = (remote) => sshExecOrThrow(ip, remote, { user: "root", connectTimeoutSec: 10 }), sshWaitSecs = readWaitSecs("TS_CLOUD_SSH_WAIT_SECS", 480);
|
|
426
413
|
await pollUntil({
|
|
427
414
|
label: "Waiting for SSH to come up",
|
|
428
415
|
timeoutSecs: sshWaitSecs,
|
|
429
|
-
check: () =>
|
|
430
|
-
run("true");
|
|
431
|
-
},
|
|
416
|
+
check: () => run("true"),
|
|
432
417
|
timeoutMessage: (elapsed) => `SSH did not become reachable on ${ip} within ${fmtDuration(sshWaitSecs)} (waited ${elapsed}s). ` + "The box may still be booting \u2014 raise TS_CLOUD_SSH_WAIT_SECS and retry."
|
|
433
418
|
});
|
|
434
419
|
log.success("SSH is up");
|
|
435
420
|
log.info("Waiting for cloud-init (installing bun + caddy)...");
|
|
436
421
|
try {
|
|
437
|
-
run("cloud-init status --wait || true");
|
|
422
|
+
await run("cloud-init status --wait || true");
|
|
438
423
|
} catch (err) {
|
|
439
424
|
log.debug("cloud-init status --wait returned non-zero (continuing):", err);
|
|
440
425
|
}
|
|
@@ -442,9 +427,7 @@ async function waitForRemoteReady(ip, verbose) {
|
|
|
442
427
|
await pollUntil({
|
|
443
428
|
label: "Waiting for the bun runtime",
|
|
444
429
|
timeoutSecs: bootWaitSecs,
|
|
445
|
-
check: () =>
|
|
446
|
-
run("test -x /usr/local/bin/bun");
|
|
447
|
-
},
|
|
430
|
+
check: () => run("test -x /usr/local/bin/bun"),
|
|
448
431
|
timeoutMessage: (elapsed) => `bun runtime did not appear at /usr/local/bin/bun within ${fmtDuration(bootWaitSecs)} (waited ${elapsed}s). ` + "cloud-init may have failed \u2014 SSH in and check /var/log/cloud-init-output.log; " + "raise TS_CLOUD_BOOT_WAIT_SECS for slow regions."
|
|
449
432
|
});
|
|
450
433
|
log.success("Server is ready (bun installed)");
|
|
@@ -716,7 +699,7 @@ async function runHetznerDeploy(args) {
|
|
|
716
699
|
log.error("Provisioned server has no public IP \u2014 cannot deploy over SSH.");
|
|
717
700
|
process.exit(ExitCode.FatalError);
|
|
718
701
|
}
|
|
719
|
-
await waitForRemoteReady(ip
|
|
702
|
+
await waitForRemoteReady(ip);
|
|
720
703
|
const { execSync } = await import("node:child_process"), { tmpdir } = await import("node:os"), sites = applyEnvironmentToSites(tsCloudConfig.sites || {}, environment, tsCloudConfig), slug = tsCloudConfig.project?.slug || "app";
|
|
721
704
|
let sha;
|
|
722
705
|
try {
|
package/dist/commands/mail.js
CHANGED
|
@@ -17,7 +17,7 @@ export function sanitizeLineCount(value) {
|
|
|
17
17
|
const count = Number.parseInt(value || "50", 10);
|
|
18
18
|
return String(Number.isFinite(count) ? Math.min(5000, Math.max(1, count)) : 50);
|
|
19
19
|
}
|
|
20
|
-
function shellQuote(
|
|
20
|
+
function shellQuote(_value) {
|
|
21
21
|
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
22
22
|
}
|
|
23
23
|
async function resolveOperationalMailHost() {
|
package/dist/commands/migrate.js
CHANGED
|
@@ -214,7 +214,7 @@ export function migrate(buddy) {
|
|
|
214
214
|
log.info(` \u2022 ${describeOp(op)}${op.destructive ? " [destructive]" : ""}`);
|
|
215
215
|
}
|
|
216
216
|
} catch (error) {
|
|
217
|
-
log.error("Failed to preview migrations:", error);
|
|
217
|
+
await log.error("Failed to preview migrations:", error);
|
|
218
218
|
}
|
|
219
219
|
await outro("Diff complete \u2014 no changes applied.", { startTime: perf, useSeconds: !0 });
|
|
220
220
|
process.exit(ExitCode.Success);
|
|
@@ -224,6 +224,7 @@ export function migrate(buddy) {
|
|
|
224
224
|
log.debug("[migrate] confirmMigrate guard skipped \u2014 non-interactive environment.");
|
|
225
225
|
else {
|
|
226
226
|
const APP_ENV = process.env.APP_ENV || "local";
|
|
227
|
+
await log.flush();
|
|
227
228
|
if (!await confirm({
|
|
228
229
|
message: `Run migrations against the ${APP_ENV} database "${currentDatabaseLabel()}"?`,
|
|
229
230
|
initial: !0
|
|
@@ -234,7 +235,7 @@ export function migrate(buddy) {
|
|
|
234
235
|
}
|
|
235
236
|
const lock = acquireMigrationLock();
|
|
236
237
|
if (!lock.acquired) {
|
|
237
|
-
log.
|
|
238
|
+
log.syncError("Another migration is already running (.stacks/migrations.lock exists). Wait for it to finish, or remove the lockfile if it is stale.");
|
|
238
239
|
process.exit(ExitCode.FatalError);
|
|
239
240
|
}
|
|
240
241
|
if (!await confirmDestructiveMigrations({ force: options.force, fromDb: options.fromDb, applyRenames })) {
|
|
@@ -303,7 +304,7 @@ export function migrate(buddy) {
|
|
|
303
304
|
}
|
|
304
305
|
const guards = await resolveMigrationGuards(), dbLabel = currentDatabaseLabel(), APP_ENV = process.env.APP_ENV || "local";
|
|
305
306
|
if (guards.migrateFresh === "disabled") {
|
|
306
|
-
log.error(`\`buddy migrate:fresh\` is disabled by your migration safety guards (it DROPS every table).
|
|
307
|
+
await log.error(`\`buddy migrate:fresh\` is disabled by your migration safety guards (it DROPS every table).
|
|
307
308
|
Target: ${APP_ENV} database "${dbLabel}"
|
|
308
309
|
To allow it, set database.safety.migrateFresh to 'allow' in config/database.ts,
|
|
309
310
|
or run once with: DB_MIGRATE_FRESH=allow ./buddy migrate:fresh`);
|
|
@@ -313,11 +314,12 @@ export function migrate(buddy) {
|
|
|
313
314
|
if (!(guards.migrateFresh === "allow" && options.force === !0)) {
|
|
314
315
|
if (isCI || !hasTTY) {
|
|
315
316
|
const hint = guards.migrateFresh === "confirm" ? 'Guard is "confirm": migrate:fresh must be run interactively.' : "Re-run with --force to drop the database non-interactively.";
|
|
316
|
-
log.error(`Refusing to drop the ${APP_ENV} database "${dbLabel}" in a non-interactive environment. ${hint}`);
|
|
317
|
+
await log.error(`Refusing to drop the ${APP_ENV} database "${dbLabel}" in a non-interactive environment. ${hint}`);
|
|
317
318
|
await outro("migrate:fresh cancelled.", { startTime: perf, useSeconds: !0 });
|
|
318
319
|
process.exit(ExitCode.FatalError);
|
|
319
320
|
}
|
|
320
321
|
log.warn(`This will DROP ALL TABLES in the ${APP_ENV} database "${dbLabel}" and rebuild them from scratch. All data will be lost.`);
|
|
322
|
+
await log.flush();
|
|
321
323
|
if ((await text({ message: `Type the database name "${dbLabel}" to confirm (blank to cancel):` })).trim() !== dbLabel) {
|
|
322
324
|
await outro("migrate:fresh cancelled \u2014 confirmation did not match.", { startTime: perf, useSeconds: !0 });
|
|
323
325
|
process.exit(ExitCode.Success);
|
package/dist/commands/setup.d.ts
CHANGED
|
@@ -2,7 +2,6 @@ import type { CLI, CliOptions } from '@stacksjs/types';
|
|
|
2
2
|
export declare function setup(buddy: CLI): void;
|
|
3
3
|
export declare function ensurePantryInstalled(): Promise<void>;
|
|
4
4
|
export declare function ensurePantryDependencies(cwd: string): Promise<void>;
|
|
5
|
-
export declare function ensureNodeDependencies(cwd: string): Promise<void>;
|
|
6
5
|
export declare function ensureAppKey(cwd: string): Promise<void>;
|
|
7
6
|
export declare function ensureIdeSettings(cwd: string): void;
|
|
8
7
|
export declare function pantryDatabasePackage(connection: string): DatabasePackage | undefined;
|
package/dist/commands/setup.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { cpSync, existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
2
3
|
import { join } from "node:path";
|
|
3
4
|
import process from "node:process";
|
|
4
5
|
import { runAction } from "@stacksjs/actions";
|
|
@@ -15,7 +16,7 @@ function getTimeoutMs(envVar, fallbackMs) {
|
|
|
15
16
|
return value;
|
|
16
17
|
return fallbackMs;
|
|
17
18
|
}
|
|
18
|
-
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),
|
|
19
|
+
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);
|
|
19
20
|
export function setup(buddy) {
|
|
20
21
|
const descriptions = {
|
|
21
22
|
setup: "This command ensures your project is setup correctly",
|
|
@@ -69,59 +70,41 @@ async function isPantryInstalled() {
|
|
|
69
70
|
}
|
|
70
71
|
}
|
|
71
72
|
async function installPantry() {
|
|
72
|
-
const
|
|
73
|
+
const bundledInstaller = p.frameworkPath("scripts/pantry-install"), command = existsSync(bundledInstaller) ? [bundledInstaller] : ["sh", "-c", "curl -fsSL https://pantry.dev | bash"], result = await runCommand(command, {
|
|
73
74
|
timeoutMs: PANTRY_INSTALL_TIMEOUT_MS
|
|
74
|
-
});
|
|
75
|
-
if (
|
|
75
|
+
}), localBin = join(homedir(), ".local", "bin");
|
|
76
|
+
if (!process.env.PATH?.split(":").includes(localBin))
|
|
77
|
+
process.env.PATH = `${localBin}:${process.env.PATH || ""}`;
|
|
78
|
+
if (result.isOk && await isPantryInstalled())
|
|
76
79
|
return;
|
|
77
|
-
|
|
80
|
+
if (result.isErr)
|
|
81
|
+
handleError(result.error);
|
|
82
|
+
else
|
|
83
|
+
log.error("Pantry installed but is not available on PATH. Open a new shell and run `buddy setup` again.");
|
|
78
84
|
process.exit(ExitCode.FatalError);
|
|
79
85
|
}
|
|
80
86
|
export async function ensurePantryInstalled() {
|
|
81
87
|
if (await isPantryInstalled())
|
|
82
88
|
return;
|
|
83
|
-
|
|
84
|
-
if (!existsSync(installer)) {
|
|
85
|
-
log.debug("Pantry is not installed and no bundled installer is present; continuing without it.");
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
89
|
+
log.info("Pantry is required. Installing it from https://pantry.dev...");
|
|
88
90
|
await installPantry();
|
|
89
91
|
}
|
|
90
92
|
export async function ensurePantryDependencies(cwd) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
log.info("Installing Pantry dependencies...");
|
|
93
|
+
await ensurePantryInstalled();
|
|
94
|
+
log.info("Installing project dependencies with Pantry...");
|
|
96
95
|
const result = await runCommand("pantry install", {
|
|
97
96
|
cwd,
|
|
98
97
|
timeoutMs: PANTRY_DEPENDENCIES_TIMEOUT_MS
|
|
99
98
|
});
|
|
100
|
-
if (result.isOk) {
|
|
101
|
-
log.success("Installed Pantry dependencies");
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
handleError(result.error);
|
|
105
|
-
process.exit(ExitCode.FatalError);
|
|
106
|
-
}
|
|
107
|
-
export async function ensureNodeDependencies(cwd) {
|
|
108
|
-
if (existsSync(join(cwd, "node_modules"))) {
|
|
109
|
-
log.success("node_modules existed, skipping bun install");
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
log.info("Running bun install...");
|
|
113
|
-
const result = await runCommand("bun install", {
|
|
114
|
-
cwd,
|
|
115
|
-
timeoutMs: BUN_INSTALL_TIMEOUT_MS
|
|
116
|
-
}).catch((error) => {
|
|
117
|
-
handleError(error);
|
|
118
|
-
process.exit(ExitCode.FatalError);
|
|
119
|
-
});
|
|
120
99
|
if (result.isErr) {
|
|
121
100
|
handleError(result.error);
|
|
122
101
|
process.exit(ExitCode.FatalError);
|
|
123
102
|
}
|
|
124
|
-
|
|
103
|
+
if (existsSync(join(cwd, "package.json")) && !existsSync(join(cwd, "node_modules"))) {
|
|
104
|
+
log.error("Pantry completed without installing the project JavaScript dependencies.");
|
|
105
|
+
process.exit(ExitCode.FatalError);
|
|
106
|
+
}
|
|
107
|
+
log.success("Installed project dependencies with Pantry");
|
|
125
108
|
}
|
|
126
109
|
function hasAppKey(cwd) {
|
|
127
110
|
const envPath = join(cwd, ".env");
|
|
@@ -167,7 +150,6 @@ async function runInitialMigration(cwd) {
|
|
|
167
150
|
async function initializeProject(options) {
|
|
168
151
|
const cwd = options.cwd || p.projectPath();
|
|
169
152
|
await ensurePantryDependencies(cwd);
|
|
170
|
-
await ensureNodeDependencies(cwd);
|
|
171
153
|
await ensureEnvIsSet(options);
|
|
172
154
|
if (!options.skipKeygen)
|
|
173
155
|
await ensureAppKey(cwd);
|
package/dist/commands/stacks.js
CHANGED
|
@@ -11,13 +11,14 @@ export function stacks(buddy) {
|
|
|
11
11
|
force: "Force overwrite existing files",
|
|
12
12
|
dryRun: "Show what would be installed without making changes",
|
|
13
13
|
conflict: "Conflict resolution strategy: skip, overwrite, or backup",
|
|
14
|
-
verbose: "Enable verbose output"
|
|
14
|
+
verbose: "Enable verbose output",
|
|
15
|
+
project: "Target a specific Stacks project"
|
|
15
16
|
};
|
|
16
|
-
buddy.command("stack:install <name>", descriptions.install).option("--force", descriptions.force, { default: !1 }).option("--dry-run", descriptions.dryRun, { default: !1 }).option("--conflict <strategy>", descriptions.conflict, { default: "skip" }).option("--verbose", descriptions.verbose, { default: !1 }).example("buddy
|
|
17
|
+
buddy.command("stack:install <name>", descriptions.install).option("--force", descriptions.force, { default: !1 }).option("--dry-run", descriptions.dryRun, { default: !1 }).option("--conflict <strategy>", descriptions.conflict, { default: "skip" }).option("-p, --project <path>", descriptions.project).option("--verbose", descriptions.verbose, { default: !1 }).example("buddy add calendar").example("buddy add table --force").example("buddy add calendar --conflict backup --verbose").example("buddy add table --dry-run").action(async (name, options) => {
|
|
17
18
|
const perf = await intro("buddy stack:install");
|
|
18
19
|
if (!name) {
|
|
19
20
|
log.error("You need to specify a stack name.");
|
|
20
|
-
log.info("Example: buddy
|
|
21
|
+
log.info("Example: buddy add calendar");
|
|
21
22
|
process.exit(ExitCode.FatalError);
|
|
22
23
|
}
|
|
23
24
|
if (!await installStack({
|
|
@@ -25,6 +26,7 @@ export function stacks(buddy) {
|
|
|
25
26
|
force: options.force,
|
|
26
27
|
dryRun: options.dryRun,
|
|
27
28
|
conflict: options.conflict || "skip",
|
|
29
|
+
project: options.project,
|
|
28
30
|
verbose: options.verbose
|
|
29
31
|
}) && !options.dryRun) {
|
|
30
32
|
await outro("Failed to install stack", { startTime: perf, useSeconds: !0 });
|
|
@@ -33,7 +35,7 @@ export function stacks(buddy) {
|
|
|
33
35
|
await outro(`Stack ${italic(name)} installed.`, { startTime: perf, useSeconds: !0 });
|
|
34
36
|
process.exit(ExitCode.Success);
|
|
35
37
|
});
|
|
36
|
-
buddy.command("stack:uninstall <name>", descriptions.uninstall).option("--force", descriptions.force, { default: !1 }).option("--verbose", descriptions.verbose, { default: !1 }).example("buddy stack:uninstall blog").example("buddy stack:uninstall blog --force").action(async (name, options) => {
|
|
38
|
+
buddy.command("stack:uninstall <name>", descriptions.uninstall).option("--force", descriptions.force, { default: !1 }).option("-p, --project <path>", descriptions.project).option("--verbose", descriptions.verbose, { default: !1 }).example("buddy stack:uninstall blog").example("buddy stack:uninstall blog --force").action(async (name, options) => {
|
|
37
39
|
const perf = await intro("buddy stack:uninstall");
|
|
38
40
|
if (!name) {
|
|
39
41
|
log.error("You need to specify a stack name.");
|
|
@@ -42,6 +44,7 @@ export function stacks(buddy) {
|
|
|
42
44
|
if (!await uninstallStack({
|
|
43
45
|
name,
|
|
44
46
|
force: options.force,
|
|
47
|
+
project: options.project,
|
|
45
48
|
verbose: options.verbose
|
|
46
49
|
})) {
|
|
47
50
|
await outro("Failed to uninstall stack", { startTime: perf, useSeconds: !0 });
|
|
@@ -50,10 +53,10 @@ export function stacks(buddy) {
|
|
|
50
53
|
await outro(`Stack ${italic(name)} uninstalled.`, { startTime: perf, useSeconds: !0 });
|
|
51
54
|
process.exit(ExitCode.Success);
|
|
52
55
|
});
|
|
53
|
-
buddy.command("stack:list", descriptions.list).alias("stack:ls").example("buddy stack:list").action(async () => {
|
|
54
|
-
const perf = await intro("buddy stack:list"), entries = await listStacks();
|
|
56
|
+
buddy.command("stack:list", descriptions.list).alias("stack:ls").option("-p, --project <path>", descriptions.project).example("buddy stack:list").action(async (options) => {
|
|
57
|
+
const perf = await intro("buddy stack:list"), entries = await listStacks(options.project);
|
|
55
58
|
if (entries.length === 0)
|
|
56
|
-
log.info("No stacks found. Install one with: buddy
|
|
59
|
+
log.info("No stacks found. Install one with: buddy add <name>");
|
|
57
60
|
else {
|
|
58
61
|
log.info(`Found ${entries.length} stack(s):`);
|
|
59
62
|
log.info("");
|
package/dist/lazy-commands.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const commandRegistry = {
|
|
2
2
|
about: { path: "./commands/about.js", exportName: "about" },
|
|
3
3
|
add: { path: "./commands/add.js", exportName: "add" },
|
|
4
|
+
"ai:context": { path: "./commands/ai-context.js", exportName: "aiContext" },
|
|
4
5
|
auth: { path: "./commands/auth.js", exportName: "auth" },
|
|
5
6
|
build: { path: "./commands/build.js", exportName: "build" },
|
|
6
7
|
cd: { path: "./commands/cd.js", exportName: "cd" },
|
package/dist/project-setup.js
CHANGED
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.163",
|
|
6
6
|
"description": "Meet Buddy. The Stacks runtime.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -64,7 +64,6 @@
|
|
|
64
64
|
"types": "dist/index.d.ts",
|
|
65
65
|
"bin": {
|
|
66
66
|
"stacks": "dist/cli.js",
|
|
67
|
-
"stx": "dist/cli.js",
|
|
68
67
|
"buddy": "dist/cli.js",
|
|
69
68
|
"bud": "dist/cli.js"
|
|
70
69
|
},
|
|
@@ -92,52 +91,52 @@
|
|
|
92
91
|
"prepublishOnly": "bun run build"
|
|
93
92
|
},
|
|
94
93
|
"dependencies": {
|
|
95
|
-
"@stacksjs/actions": "^0.70.
|
|
96
|
-
"@stacksjs/ai": "^0.70.
|
|
97
|
-
"@stacksjs/alias": "^0.70.
|
|
98
|
-
"@stacksjs/arrays": "^0.70.
|
|
99
|
-
"@stacksjs/auth": "^0.70.
|
|
100
|
-
"@stacksjs/build": "^0.70.
|
|
101
|
-
"@stacksjs/cache": "^0.70.
|
|
102
|
-
"@stacksjs/cli": "^0.70.
|
|
94
|
+
"@stacksjs/actions": "^0.70.163",
|
|
95
|
+
"@stacksjs/ai": "^0.70.163",
|
|
96
|
+
"@stacksjs/alias": "^0.70.163",
|
|
97
|
+
"@stacksjs/arrays": "^0.70.163",
|
|
98
|
+
"@stacksjs/auth": "^0.70.163",
|
|
99
|
+
"@stacksjs/build": "^0.70.163",
|
|
100
|
+
"@stacksjs/cache": "^0.70.163",
|
|
101
|
+
"@stacksjs/cli": "^0.70.163",
|
|
103
102
|
"@stacksjs/clapp": "^0.2.12",
|
|
104
|
-
"@stacksjs/cloud": "^0.70.
|
|
105
|
-
"@stacksjs/collections": "^0.70.
|
|
106
|
-
"@stacksjs/config": "^0.70.
|
|
107
|
-
"@stacksjs/database": "^0.70.
|
|
108
|
-
"@stacksjs/desktop": "^0.70.
|
|
109
|
-
"@stacksjs/dns": "^0.70.
|
|
110
|
-
"@stacksjs/email": "^0.70.
|
|
111
|
-
"@stacksjs/enums": "^0.70.
|
|
112
|
-
"@stacksjs/error-handling": "^0.70.
|
|
113
|
-
"@stacksjs/events": "^0.70.
|
|
114
|
-
"@stacksjs/git": "^0.70.
|
|
103
|
+
"@stacksjs/cloud": "^0.70.163",
|
|
104
|
+
"@stacksjs/collections": "^0.70.163",
|
|
105
|
+
"@stacksjs/config": "^0.70.163",
|
|
106
|
+
"@stacksjs/database": "^0.70.163",
|
|
107
|
+
"@stacksjs/desktop": "^0.70.163",
|
|
108
|
+
"@stacksjs/dns": "^0.70.163",
|
|
109
|
+
"@stacksjs/email": "^0.70.163",
|
|
110
|
+
"@stacksjs/enums": "^0.70.163",
|
|
111
|
+
"@stacksjs/error-handling": "^0.70.163",
|
|
112
|
+
"@stacksjs/events": "^0.70.163",
|
|
113
|
+
"@stacksjs/git": "^0.70.163",
|
|
115
114
|
"@stacksjs/gitit": "^0.2.5",
|
|
116
|
-
"@stacksjs/health": "^0.70.
|
|
115
|
+
"@stacksjs/health": "^0.70.163",
|
|
117
116
|
"@stacksjs/dnsx": "^0.2.3",
|
|
118
117
|
"@stacksjs/httx": "^0.1.10",
|
|
119
|
-
"@stacksjs/lint": "^0.70.
|
|
120
|
-
"@stacksjs/logging": "^0.70.
|
|
121
|
-
"@stacksjs/notifications": "^0.70.
|
|
122
|
-
"@stacksjs/objects": "^0.70.
|
|
123
|
-
"@stacksjs/orm": "^0.70.
|
|
124
|
-
"@stacksjs/path": "^0.70.
|
|
125
|
-
"@stacksjs/payments": "^0.70.
|
|
126
|
-
"@stacksjs/realtime": "^0.70.
|
|
127
|
-
"@stacksjs/router": "^0.70.
|
|
118
|
+
"@stacksjs/lint": "^0.70.163",
|
|
119
|
+
"@stacksjs/logging": "^0.70.163",
|
|
120
|
+
"@stacksjs/notifications": "^0.70.163",
|
|
121
|
+
"@stacksjs/objects": "^0.70.163",
|
|
122
|
+
"@stacksjs/orm": "^0.70.163",
|
|
123
|
+
"@stacksjs/path": "^0.70.163",
|
|
124
|
+
"@stacksjs/payments": "^0.70.163",
|
|
125
|
+
"@stacksjs/realtime": "^0.70.163",
|
|
126
|
+
"@stacksjs/router": "^0.70.163",
|
|
128
127
|
"@stacksjs/rpx": "^0.11.31",
|
|
129
|
-
"@stacksjs/search-engine": "^0.70.
|
|
130
|
-
"@stacksjs/security": "^0.70.
|
|
131
|
-
"@stacksjs/server": "^0.70.
|
|
132
|
-
"@stacksjs/storage": "^0.70.
|
|
133
|
-
"@stacksjs/strings": "^0.70.
|
|
134
|
-
"@stacksjs/testing": "^0.70.
|
|
135
|
-
"@stacksjs/tunnel": "^0.70.
|
|
136
|
-
"@stacksjs/types": "^0.70.
|
|
137
|
-
"@stacksjs/ui": "^0.70.
|
|
138
|
-
"@stacksjs/utils": "^0.70.
|
|
139
|
-
"@stacksjs/validation": "^0.70.
|
|
140
|
-
"@stacksjs/ts-cloud": "^0.7.
|
|
128
|
+
"@stacksjs/search-engine": "^0.70.163",
|
|
129
|
+
"@stacksjs/security": "^0.70.163",
|
|
130
|
+
"@stacksjs/server": "^0.70.163",
|
|
131
|
+
"@stacksjs/storage": "^0.70.163",
|
|
132
|
+
"@stacksjs/strings": "^0.70.163",
|
|
133
|
+
"@stacksjs/testing": "^0.70.163",
|
|
134
|
+
"@stacksjs/tunnel": "^0.70.163",
|
|
135
|
+
"@stacksjs/types": "^0.70.163",
|
|
136
|
+
"@stacksjs/ui": "^0.70.163",
|
|
137
|
+
"@stacksjs/utils": "^0.70.163",
|
|
138
|
+
"@stacksjs/validation": "^0.70.163",
|
|
139
|
+
"@stacksjs/ts-cloud": "^0.7.56"
|
|
141
140
|
},
|
|
142
141
|
"devDependencies": {
|
|
143
142
|
"better-dx": "^0.2.17"
|