mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-04 21:04:37 +08:00
CLI init (#1242)
<!-- Make sure you've read the CONTRIBUTING.md guidelines: https://github.com/stack-auth/stack-auth/blob/dev/CONTRIBUTING.md --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Interactive init workflow (create, link-config, link-cloud) with safe non-interactive behavior; writes/updates project config and .env, and prints STACK AUTH setup instructions. * CLI assistant/agent with a progress UI for long-running tasks. * Backend AI proxy endpoint that validates and forwards AI requests to an external provider. * **Tests** * End-to-end tests covering all init modes, outputs, env linking, and error cases. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
8e03677aad
commit
f016cd8993
@ -0,0 +1,68 @@
|
||||
import { handleApiRequest } from "@/route-handlers/smart-route-handler";
|
||||
import { getEnvVariable } from "@stackframe/stack-shared/dist/utils/env";
|
||||
import { StatusError } from "@stackframe/stack-shared/dist/utils/errors";
|
||||
import { NextRequest } from "next/server";
|
||||
|
||||
const OPENROUTER_BASE_URL = "https://openrouter.ai/api";
|
||||
const OPENROUTER_MODEL = "anthropic/claude-sonnet-4.6";
|
||||
|
||||
function sanitizeBody(raw: ArrayBuffer): Uint8Array {
|
||||
const text = new TextDecoder().decode(raw);
|
||||
let parsed;
|
||||
try {
|
||||
parsed = JSON.parse(text);
|
||||
} catch {
|
||||
throw new StatusError(400, "Request body must be valid JSON");
|
||||
}
|
||||
|
||||
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
||||
throw new StatusError(400, "Request body must be a JSON object");
|
||||
}
|
||||
|
||||
parsed.model = OPENROUTER_MODEL;
|
||||
|
||||
// OpenRouter limits metadata.user_id to 128 characters
|
||||
if (parsed.metadata?.user_id && parsed.metadata.user_id.length > 128) {
|
||||
parsed.metadata.user_id = parsed.metadata.user_id.slice(0, 128);
|
||||
}
|
||||
|
||||
return new TextEncoder().encode(JSON.stringify(parsed));
|
||||
}
|
||||
|
||||
async function proxyToOpenRouter(req: NextRequest, options: { params: Promise<{ path?: string[] }> }) {
|
||||
const apiKey = getEnvVariable("STACK_OPENROUTER_API_KEY");
|
||||
const params = await options.params;
|
||||
const subpath = params.path?.join("/") ?? "";
|
||||
const targetUrl = `${OPENROUTER_BASE_URL}/${subpath}${req.nextUrl.search}`;
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
"Authorization": `Bearer ${apiKey}`,
|
||||
"anthropic-version": "2023-06-01",
|
||||
};
|
||||
|
||||
const contentType = req.headers.get("Content-Type");
|
||||
if (contentType) {
|
||||
headers["Content-Type"] = contentType;
|
||||
}
|
||||
|
||||
const body = req.method !== "GET" && req.method !== "HEAD"
|
||||
? Buffer.from(sanitizeBody(await req.arrayBuffer()))
|
||||
: undefined;
|
||||
|
||||
const response = await fetch(targetUrl, {
|
||||
method: req.method,
|
||||
headers,
|
||||
body,
|
||||
});
|
||||
|
||||
return new Response(response.body, {
|
||||
status: response.status,
|
||||
headers: {
|
||||
"Content-Type": response.headers.get("Content-Type") ?? "application/json",
|
||||
"Cache-Control": "no-cache",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export const GET = handleApiRequest(proxyToOpenRouter);
|
||||
export const POST = handleApiRequest(proxyToOpenRouter);
|
||||
@ -345,4 +345,119 @@ describe("Stack CLI", () => {
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("plain `config` object");
|
||||
});
|
||||
|
||||
// --- init command tests ---
|
||||
|
||||
it("init create writes stack.config.ts with selected apps", async ({ expect }) => {
|
||||
const initDir = path.join(tmpDir, "init-create");
|
||||
fs.mkdirSync(initDir, { recursive: true });
|
||||
|
||||
const { stdout, exitCode } = await runCli([
|
||||
"init", "--mode", "create", "--apps", "authentication,teams", "--output-dir", initDir,
|
||||
]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toContain("Config file written to");
|
||||
|
||||
const content = fs.readFileSync(path.join(initDir, "stack.config.ts"), "utf-8");
|
||||
expect(content).toContain("export const config");
|
||||
const configMatch = content.match(/export const config = (.+);/s);
|
||||
expect(configMatch).toBeTruthy();
|
||||
const parsed = JSON.parse(configMatch![1]);
|
||||
expect(parsed.apps.installed.authentication).toEqual({ enabled: true });
|
||||
expect(parsed.apps.installed.teams).toEqual({ enabled: true });
|
||||
});
|
||||
|
||||
it("init create with single app", async ({ expect }) => {
|
||||
const initDir = path.join(tmpDir, "init-create-single");
|
||||
fs.mkdirSync(initDir, { recursive: true });
|
||||
|
||||
const { stdout, exitCode } = await runCli([
|
||||
"init", "--mode", "create", "--apps", "authentication", "--output-dir", initDir,
|
||||
]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toContain("Config file written to");
|
||||
|
||||
const content = fs.readFileSync(path.join(initDir, "stack.config.ts"), "utf-8");
|
||||
const configMatch = content.match(/export const config = (.+);/s);
|
||||
const parsed = JSON.parse(configMatch![1]);
|
||||
expect(Object.keys(parsed.apps.installed)).toEqual(["authentication"]);
|
||||
});
|
||||
|
||||
it("init link-config with valid path", async ({ expect }) => {
|
||||
// Create a dummy config file to link to
|
||||
const dummyConfig = path.join(tmpDir, "dummy-stack.config.ts");
|
||||
fs.writeFileSync(dummyConfig, "export const config = {};\n");
|
||||
|
||||
const { stdout, exitCode } = await runCli([
|
||||
"init", "--mode", "link-config", "--config-file", dummyConfig,
|
||||
]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toContain("Linked to config file");
|
||||
expect(stdout).toContain(dummyConfig);
|
||||
});
|
||||
|
||||
it("init link-config with invalid path fails", async ({ expect }) => {
|
||||
const { stderr, exitCode } = await runCli([
|
||||
"init", "--mode", "link-config", "--config-file", "/nonexistent/stack.config.ts",
|
||||
]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("File not found");
|
||||
});
|
||||
|
||||
it("init link-cloud creates .env with API keys", async ({ expect }) => {
|
||||
expect(createdProjectId).toBeDefined();
|
||||
|
||||
const initDir = path.join(tmpDir, "init-cloud");
|
||||
fs.mkdirSync(initDir, { recursive: true });
|
||||
|
||||
const { stdout, exitCode } = await runCli([
|
||||
"init", "--mode", "link-cloud", "--select-project-id", createdProjectId, "--output-dir", initDir,
|
||||
]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toContain("Created .env with Stack Auth keys");
|
||||
|
||||
const envContent = fs.readFileSync(path.join(initDir, ".env"), "utf-8");
|
||||
expect(envContent).toContain("# Stack Auth");
|
||||
expect(envContent).toContain(`NEXT_PUBLIC_STACK_PROJECT_ID=${createdProjectId}`);
|
||||
expect(envContent).toContain("NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=");
|
||||
expect(envContent).toContain("STACK_SECRET_SERVER_KEY=");
|
||||
});
|
||||
|
||||
it("init link-cloud appends to existing .env", async ({ expect }) => {
|
||||
expect(createdProjectId).toBeDefined();
|
||||
|
||||
const initDir = path.join(tmpDir, "init-cloud-append");
|
||||
fs.mkdirSync(initDir, { recursive: true });
|
||||
fs.writeFileSync(path.join(initDir, ".env"), "EXISTING_VAR=hello\n");
|
||||
|
||||
const { stdout, exitCode } = await runCli([
|
||||
"init", "--mode", "link-cloud", "--select-project-id", createdProjectId, "--output-dir", initDir,
|
||||
]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toContain("Appended Stack Auth keys to .env");
|
||||
|
||||
const envContent = fs.readFileSync(path.join(initDir, ".env"), "utf-8");
|
||||
expect(envContent).toContain("EXISTING_VAR=hello");
|
||||
expect(envContent).toContain("# Stack Auth");
|
||||
expect(envContent).toContain(`NEXT_PUBLIC_STACK_PROJECT_ID=${createdProjectId}`);
|
||||
});
|
||||
|
||||
it("init link-cloud fails with invalid project ID", async ({ expect }) => {
|
||||
const { stderr, exitCode } = await runCli([
|
||||
"init", "--mode", "link-cloud", "--select-project-id", "nonexistent-project-id",
|
||||
]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("not found");
|
||||
});
|
||||
|
||||
it("init outputs setup instructions", async ({ expect }) => {
|
||||
const initDir = path.join(tmpDir, "init-instructions");
|
||||
fs.mkdirSync(initDir, { recursive: true });
|
||||
|
||||
const { stdout, exitCode } = await runCli([
|
||||
"init", "--mode", "create", "--apps", "authentication", "--output-dir", initDir,
|
||||
]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toContain("STACK AUTH SETUP INSTRUCTIONS");
|
||||
});
|
||||
});
|
||||
|
||||
@ -26,7 +26,10 @@
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/claude-agent-sdk": "^0.2.73",
|
||||
"@inquirer/prompts": "^7.0.0",
|
||||
"@stackframe/js": "workspace:*",
|
||||
"@stackframe/stack-shared": "workspace:*",
|
||||
"commander": "^13.1.0",
|
||||
"jiti": "^2.4.2"
|
||||
},
|
||||
|
||||
@ -1,16 +1,299 @@
|
||||
import { Command } from "commander";
|
||||
import { execFileSync } from "child_process";
|
||||
import { select, input, checkbox, confirm } from "@inquirer/prompts";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import { StackClientApp } from "@stackframe/js";
|
||||
import { ALL_APPS } from "@stackframe/stack-shared/dist/apps/apps-config";
|
||||
import { resolveLoginConfig, resolveSessionAuth, DEFAULT_PUBLISHABLE_CLIENT_KEY } from "../lib/auth.js";
|
||||
import { getInternalUser } from "../lib/app.js";
|
||||
import { writeConfigValue } from "../lib/config.js";
|
||||
import { CliError, AuthError } from "../lib/errors.js";
|
||||
import { isNonInteractiveEnv } from "../lib/interactive.js";
|
||||
import { createInitPrompt } from "../lib/init-prompt.js";
|
||||
import { runClaudeAgent } from "../lib/claude-agent.js";
|
||||
|
||||
type InitOptions = {
|
||||
mode?: "create" | "link-config" | "link-cloud",
|
||||
apps?: string,
|
||||
configFile?: string,
|
||||
selectProjectId?: string,
|
||||
outputDir?: string,
|
||||
agent?: boolean,
|
||||
};
|
||||
|
||||
export function registerInitCommand(program: Command) {
|
||||
program
|
||||
.command("init")
|
||||
.description("Initialize Stack Auth in your project (delegates to @stackframe/init-stack)")
|
||||
.allowUnknownOption(true)
|
||||
.helpOption(false)
|
||||
.action((_opts, cmd) => {
|
||||
const args = cmd.args as string[];
|
||||
execFileSync("npx", ["@stackframe/init-stack@latest", ...args], {
|
||||
stdio: "inherit",
|
||||
});
|
||||
.description("Initialize Stack Auth in your project")
|
||||
.option("--mode <mode>", "Mode: create, link-config, or link-cloud (skips interactive prompts)")
|
||||
.option("--apps <apps>", "Comma-separated app IDs to enable (for create mode)")
|
||||
.option("--config-file <path>", "Path to existing config file (for link-config mode)")
|
||||
.option("--select-project-id <id>", "Project ID to link (for link-cloud mode)")
|
||||
.option("--output-dir <dir>", "Directory to write output files (defaults to cwd)")
|
||||
.option("--no-agent", "Skip Claude agent and print setup instructions instead")
|
||||
.action(async (opts: InitOptions) => {
|
||||
const hasFlags = opts.mode != null;
|
||||
|
||||
if (!hasFlags && isNonInteractiveEnv()) {
|
||||
throw new CliError("stack init requires an interactive terminal. Use --mode flag for non-interactive usage.");
|
||||
}
|
||||
|
||||
try {
|
||||
await runInit(program, opts);
|
||||
} catch (error: unknown) {
|
||||
if (error != null && typeof error === "object" && "name" in error && error.name === "ExitPromptError") {
|
||||
console.log("\nAborted.");
|
||||
process.exit(0);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function runInit(program: Command, opts: InitOptions) {
|
||||
const flags = program.opts();
|
||||
const outputDir = opts.outputDir ? path.resolve(opts.outputDir) : process.cwd();
|
||||
|
||||
console.log("Welcome to Stack Auth!\n");
|
||||
|
||||
const mode: string = opts.mode ?? await select({
|
||||
message: "Would you like to link to an existing project, or create a new one?",
|
||||
choices: [
|
||||
{ name: "Create a new project (local emulator)", value: "create" as const },
|
||||
{ name: "Link an existing project", value: "link" as const },
|
||||
],
|
||||
});
|
||||
|
||||
let configPath: string | undefined;
|
||||
|
||||
if (mode === "link" || mode === "link-config" || mode === "link-cloud") {
|
||||
const result = await handleLink(flags, opts, outputDir);
|
||||
configPath = result.configPath;
|
||||
} else if (mode === "create") {
|
||||
const result = await handleCreate(opts, outputDir);
|
||||
configPath = result.configPath;
|
||||
} else {
|
||||
throw new CliError(`Unknown mode: ${mode}`);
|
||||
}
|
||||
|
||||
const initPrompt = createInitPrompt(false, configPath);
|
||||
const useAgent = opts.agent !== false && !isNonInteractiveEnv();
|
||||
|
||||
if (useAgent) {
|
||||
const success = await runClaudeAgent({
|
||||
prompt: `Execute ALL of the following setup steps in my project now. Do not ask questions — just detect the framework and package manager from existing files and proceed.\n\n${initPrompt}`,
|
||||
cwd: outputDir,
|
||||
});
|
||||
if (!success) {
|
||||
console.log("\nFalling back to manual instructions:\n");
|
||||
console.log(initPrompt);
|
||||
}
|
||||
} else {
|
||||
console.log("\n" + initPrompt);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleLink(flags: Record<string, unknown>, opts: InitOptions, outputDir: string): Promise<{ configPath?: string }> {
|
||||
let source: "config-file" | "cloud";
|
||||
|
||||
if (opts.mode === "link-config") {
|
||||
source = "config-file";
|
||||
} else if (opts.mode === "link-cloud") {
|
||||
source = "cloud";
|
||||
} else {
|
||||
source = await select({
|
||||
message: "How would you like to link your project?",
|
||||
choices: [
|
||||
{ name: "Link from config file", value: "config-file" as const },
|
||||
{ name: "Link from app.stack-auth.com", value: "cloud" as const },
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
if (source === "config-file") {
|
||||
return await handleLinkFromConfigFile(opts);
|
||||
}
|
||||
return await handleLinkFromCloud(flags, opts, outputDir);
|
||||
}
|
||||
|
||||
async function handleLinkFromConfigFile(opts: InitOptions): Promise<{ configPath: string }> {
|
||||
const filePath = opts.configFile ?? await input({
|
||||
message: "Path to your existing stack.config.ts:",
|
||||
validate: (value) => {
|
||||
const resolved = path.resolve(value);
|
||||
if (!fs.existsSync(resolved)) {
|
||||
return `File not found: ${resolved}`;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
const configPath = path.resolve(filePath);
|
||||
if (!fs.existsSync(configPath)) {
|
||||
throw new CliError(`File not found: ${configPath}`);
|
||||
}
|
||||
|
||||
console.log(`\nLinked to config file: ${configPath}`);
|
||||
return { configPath };
|
||||
}
|
||||
|
||||
async function handleLinkFromCloud(flags: Record<string, unknown>, opts: InitOptions, outputDir: string): Promise<{ configPath?: string }> {
|
||||
let sessionAuth;
|
||||
try {
|
||||
sessionAuth = resolveSessionAuth(flags as { projectId?: string });
|
||||
} catch (e) {
|
||||
if (e instanceof AuthError) {
|
||||
if (isNonInteractiveEnv()) {
|
||||
throw new CliError("Not logged in. Run `stack login` first or set STACK_CLI_REFRESH_TOKEN.");
|
||||
}
|
||||
console.log("You need to log in first.\n");
|
||||
await performLogin(flags);
|
||||
sessionAuth = resolveSessionAuth(flags as { projectId?: string });
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
const user = await getInternalUser(sessionAuth);
|
||||
const projects = await user.listOwnedProjects();
|
||||
|
||||
if (projects.length === 0) {
|
||||
throw new CliError("You don't own any projects. Create one at app.stack-auth.com first.");
|
||||
}
|
||||
|
||||
let projectId: string;
|
||||
if (opts.selectProjectId) {
|
||||
const found = projects.find((p) => p.id === opts.selectProjectId);
|
||||
if (!found) {
|
||||
throw new CliError(`Project '${opts.selectProjectId}' not found among your owned projects.`);
|
||||
}
|
||||
projectId = opts.selectProjectId;
|
||||
} else {
|
||||
projectId = await select({
|
||||
message: "Select a project:",
|
||||
choices: projects.map((p) => ({
|
||||
name: `${p.displayName} (${p.id})`,
|
||||
value: p.id,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
const project = projects.find((p) => p.id === projectId)!;
|
||||
const apiKey = await project.app.createInternalApiKey({
|
||||
description: "Created by CLI init script",
|
||||
expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365 * 200), // 200 years
|
||||
hasPublishableClientKey: true,
|
||||
hasSecretServerKey: true,
|
||||
hasSuperSecretAdminKey: false,
|
||||
});
|
||||
|
||||
const envLines = [
|
||||
"# Stack Auth",
|
||||
`NEXT_PUBLIC_STACK_PROJECT_ID=${projectId}`,
|
||||
`NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=${apiKey.publishableClientKey ?? ""}`,
|
||||
`STACK_SECRET_SERVER_KEY=${apiKey.secretServerKey ?? ""}`,
|
||||
].join("\n");
|
||||
|
||||
const envPath = path.resolve(outputDir, ".env");
|
||||
|
||||
if (fs.existsSync(envPath)) {
|
||||
const existing = fs.readFileSync(envPath, "utf-8");
|
||||
const separator = existing.endsWith("\n") ? "\n" : "\n\n";
|
||||
|
||||
if (isNonInteractiveEnv()) {
|
||||
fs.appendFileSync(envPath, separator + envLines + "\n");
|
||||
console.log("\nAppended Stack Auth keys to .env");
|
||||
} else {
|
||||
const shouldAppend = await confirm({
|
||||
message: `.env file already exists. Append Stack Auth keys?`,
|
||||
default: true,
|
||||
});
|
||||
|
||||
if (shouldAppend) {
|
||||
fs.appendFileSync(envPath, separator + envLines + "\n");
|
||||
console.log("\nAppended Stack Auth keys to .env");
|
||||
} else {
|
||||
console.log("\nHere are your environment variables:\n");
|
||||
console.log(envLines);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fs.writeFileSync(envPath, envLines + "\n");
|
||||
console.log("\nCreated .env with Stack Auth keys");
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
async function performLogin(flags: Record<string, unknown>) {
|
||||
const config = resolveLoginConfig(flags as { projectId?: string });
|
||||
|
||||
const app = new StackClientApp({
|
||||
projectId: "internal",
|
||||
publishableClientKey: DEFAULT_PUBLISHABLE_CLIENT_KEY,
|
||||
baseUrl: config.apiUrl,
|
||||
tokenStore: "memory",
|
||||
noAutomaticPrefetch: true,
|
||||
});
|
||||
|
||||
console.log("Waiting for browser authentication...");
|
||||
|
||||
const result = await app.promptCliLogin({
|
||||
appUrl: config.dashboardUrl,
|
||||
});
|
||||
|
||||
if (result.status === "error") {
|
||||
throw new CliError(`Login failed: ${result.error.message}`);
|
||||
}
|
||||
|
||||
writeConfigValue("STACK_CLI_REFRESH_TOKEN", result.data);
|
||||
console.log("Login successful!\n");
|
||||
}
|
||||
|
||||
async function handleCreate(opts: InitOptions, outputDir: string): Promise<{ configPath: string }> {
|
||||
const configPath = path.resolve(outputDir, "stack.config.ts");
|
||||
|
||||
console.log(`\nCreating a new config file at ${configPath}!\n`);
|
||||
|
||||
let selectedApps: string[];
|
||||
|
||||
if (opts.apps) {
|
||||
selectedApps = opts.apps.split(",").map((s) => s.trim()).filter(Boolean);
|
||||
const validAppIds = Object.keys(ALL_APPS);
|
||||
const invalidApps = selectedApps.filter((id) => !validAppIds.includes(id));
|
||||
if (invalidApps.length > 0) {
|
||||
throw new CliError(`Unknown app IDs: ${invalidApps.join(", ")}. Valid IDs: ${validAppIds.join(", ")}`);
|
||||
}
|
||||
} else {
|
||||
const stageOrder = { stable: 0, beta: 1 } as const;
|
||||
const appEntries = Object.entries(ALL_APPS)
|
||||
.filter(([, app]) => app.stage !== "alpha")
|
||||
.sort((a, b) => stageOrder[a[1].stage as keyof typeof stageOrder] - stageOrder[b[1].stage as keyof typeof stageOrder]);
|
||||
|
||||
selectedApps = await checkbox({
|
||||
message: "Select apps to enable:",
|
||||
choices: appEntries.map(([id, app]) => ({
|
||||
name: `${app.displayName} - ${app.subtitle}${app.stage !== "stable" ? ` (${app.stage})` : ""}`,
|
||||
value: id,
|
||||
checked: id === "authentication",
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
const installed = Object.fromEntries(
|
||||
selectedApps.map((appId) => [appId, { enabled: true }])
|
||||
);
|
||||
|
||||
const config = {
|
||||
apps: {
|
||||
installed,
|
||||
},
|
||||
};
|
||||
|
||||
const content = `export const config = ${JSON.stringify(config, null, 2)};\n`;
|
||||
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
||||
fs.writeFileSync(configPath, content);
|
||||
|
||||
console.log(`\nConfig file written to ${configPath}`);
|
||||
return { configPath };
|
||||
}
|
||||
|
||||
207
packages/stack-cli/src/lib/claude-agent.ts
Normal file
207
packages/stack-cli/src/lib/claude-agent.ts
Normal file
@ -0,0 +1,207 @@
|
||||
import { query } from "@anthropic-ai/claude-agent-sdk";
|
||||
|
||||
const DEFAULT_PROXY_URL = "https://api.stack-auth.com/api/v1/integrations/ai-proxy";
|
||||
const ANTHROPIC_PROXY_BASE_URL: string = process.env.STACK_CLAUDE_PROXY_URL ?? DEFAULT_PROXY_URL;
|
||||
|
||||
const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
||||
|
||||
class AgentProgressUI {
|
||||
private mainLabel: string;
|
||||
private spinnerFrame = 0;
|
||||
private spinnerTimer: ReturnType<typeof setInterval> | null = null;
|
||||
private activeSpinners = new Map<string, string>(); // id -> label
|
||||
private flushedCount = 0; // number of completed items already printed above the spinner area
|
||||
private pendingCompleted: string[] = []; // completed items not yet flushed
|
||||
private lastLineCount = 0;
|
||||
|
||||
constructor(mainLabel: string) {
|
||||
this.mainLabel = mainLabel;
|
||||
}
|
||||
|
||||
start() {
|
||||
this.spinnerTimer = setInterval(() => {
|
||||
this.spinnerFrame = (this.spinnerFrame + 1) % SPINNER_FRAMES.length;
|
||||
this.render();
|
||||
}, 80);
|
||||
this.render();
|
||||
}
|
||||
|
||||
stop(success: boolean) {
|
||||
if (this.spinnerTimer) {
|
||||
clearInterval(this.spinnerTimer);
|
||||
this.spinnerTimer = null;
|
||||
}
|
||||
this.completeAllActive();
|
||||
this.clearLines();
|
||||
const icon = success ? "\x1b[32m✔\x1b[0m" : "\x1b[31m✖\x1b[0m";
|
||||
// Re-print header + all completed items as final output
|
||||
console.log(`${icon} ${this.mainLabel}`);
|
||||
for (const label of this.pendingCompleted) {
|
||||
console.log(` \x1b[32m✔\x1b[0m ${label}`);
|
||||
}
|
||||
this.pendingCompleted = [];
|
||||
}
|
||||
|
||||
setSpinner(id: string, label: string) {
|
||||
this.activeSpinners.set(id, label);
|
||||
}
|
||||
|
||||
complete(id: string, label?: string) {
|
||||
const existing = this.activeSpinners.get(id);
|
||||
this.activeSpinners.delete(id);
|
||||
const finalLabel = label ?? existing;
|
||||
if (finalLabel) {
|
||||
this.pendingCompleted.push(finalLabel);
|
||||
}
|
||||
}
|
||||
|
||||
completeAllActive() {
|
||||
for (const label of this.activeSpinners.values()) {
|
||||
this.pendingCompleted.push(label);
|
||||
}
|
||||
this.activeSpinners.clear();
|
||||
}
|
||||
|
||||
private clearLines() {
|
||||
if (this.lastLineCount > 0) {
|
||||
process.stdout.write(`\x1b[${this.lastLineCount}A\x1b[J`);
|
||||
}
|
||||
}
|
||||
|
||||
private flushCompleted() {
|
||||
if (this.pendingCompleted.length === 0) {
|
||||
return;
|
||||
}
|
||||
// Clear the spinner area, print completed items permanently, then re-render spinner below
|
||||
this.clearLines();
|
||||
// Re-print the header line if this is the first flush
|
||||
if (this.flushedCount === 0) {
|
||||
const frame = SPINNER_FRAMES[this.spinnerFrame];
|
||||
process.stdout.write(`\x1b[36m${frame}\x1b[0m ${this.mainLabel}\n`);
|
||||
}
|
||||
for (const label of this.pendingCompleted) {
|
||||
process.stdout.write(` \x1b[32m✔\x1b[0m ${label}\n`);
|
||||
}
|
||||
this.flushedCount += this.pendingCompleted.length;
|
||||
this.pendingCompleted = [];
|
||||
this.lastLineCount = 0; // reset since we printed permanent lines
|
||||
}
|
||||
|
||||
private render() {
|
||||
this.flushCompleted();
|
||||
this.clearLines();
|
||||
|
||||
const frame = SPINNER_FRAMES[this.spinnerFrame];
|
||||
const lines: string[] = [];
|
||||
|
||||
// Only show header in spinner area if nothing has been flushed yet
|
||||
if (this.flushedCount === 0) {
|
||||
lines.push(`\x1b[36m${frame}\x1b[0m ${this.mainLabel}`);
|
||||
}
|
||||
|
||||
for (const label of this.activeSpinners.values()) {
|
||||
lines.push(` \x1b[36m${frame}\x1b[0m ${label}`);
|
||||
}
|
||||
|
||||
if (lines.length > 0) {
|
||||
const output = lines.join("\n") + "\n";
|
||||
process.stdout.write(output);
|
||||
}
|
||||
this.lastLineCount = lines.length;
|
||||
}
|
||||
}
|
||||
|
||||
function getToolLabel(toolName: string, input: Record<string, unknown>): string {
|
||||
switch (toolName) {
|
||||
case "Read": {
|
||||
return `Reading ${input.file_path ?? "file"}`;
|
||||
}
|
||||
case "Write": {
|
||||
return `Writing ${input.file_path ?? "file"}`;
|
||||
}
|
||||
case "Edit": {
|
||||
return `Editing ${input.file_path ?? "file"}`;
|
||||
}
|
||||
case "Bash": {
|
||||
return `Running \`${truncate(String(input.command ?? ""), 40)}\``;
|
||||
}
|
||||
case "Glob": {
|
||||
return `Searching for ${input.pattern ?? "files"}`;
|
||||
}
|
||||
case "Grep": {
|
||||
return `Searching for "${truncate(String(input.pattern ?? ""), 30)}"`;
|
||||
}
|
||||
default: {
|
||||
return toolName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function truncate(str: string, maxLen: number): string {
|
||||
return str.length > maxLen ? str.slice(0, maxLen - 1) + "…" : str;
|
||||
}
|
||||
|
||||
function stripClaudeCodeEnv(): Record<string, string> {
|
||||
const env = { ...process.env };
|
||||
delete env.CLAUDECODE;
|
||||
return env as Record<string, string>;
|
||||
}
|
||||
|
||||
export async function runClaudeAgent(options: {
|
||||
prompt: string,
|
||||
cwd: string,
|
||||
}): Promise<boolean> {
|
||||
const ui = new AgentProgressUI("Setting up Stack Auth...");
|
||||
ui.start();
|
||||
|
||||
try {
|
||||
let resultText = "";
|
||||
|
||||
for await (const message of query({
|
||||
prompt: options.prompt,
|
||||
options: {
|
||||
allowedTools: ["Read", "Write", "Edit", "Bash", "Glob", "Grep"],
|
||||
permissionMode: "dontAsk",
|
||||
cwd: options.cwd,
|
||||
// stripClaudeCodeEnv removes CLAUDECODE env var to prevent nested agent detection
|
||||
env: { ...stripClaudeCodeEnv(), ANTHROPIC_BASE_URL: ANTHROPIC_PROXY_BASE_URL, ANTHROPIC_API_KEY: "" },
|
||||
stderr: (data: string) => { process.stderr.write(data); },
|
||||
},
|
||||
})) {
|
||||
if ("result" in message) {
|
||||
resultText = message.result;
|
||||
} else if (message.type === "assistant" && message.parent_tool_use_id === null) {
|
||||
// New parent assistant turn — previous tools are done
|
||||
ui.completeAllActive();
|
||||
// Register new tool calls from this turn
|
||||
for (const block of message.message.content) {
|
||||
if (block.type === "tool_use") {
|
||||
ui.setSpinner(block.id, getToolLabel(block.name, block.input as Record<string, unknown>));
|
||||
}
|
||||
}
|
||||
} else if (message.type === "system") {
|
||||
// Subagent task lifecycle
|
||||
const msg = message as Record<string, unknown>;
|
||||
const taskId = msg.task_id as string | undefined;
|
||||
|
||||
if (msg.subtype === "task_started" && taskId) {
|
||||
ui.setSpinner(taskId, String(msg.description ?? "Working..."));
|
||||
} else if (msg.subtype === "task_progress" && taskId) {
|
||||
ui.setSpinner(taskId, String(msg.description ?? "Working..."));
|
||||
} else if (msg.subtype === "task_notification" && taskId) {
|
||||
ui.complete(taskId, String(msg.summary ?? msg.description ?? "Done"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui.stop(true);
|
||||
if (resultText) {
|
||||
console.log(`\n${resultText}`);
|
||||
}
|
||||
return true;
|
||||
} catch (error) {
|
||||
ui.stop(false);
|
||||
console.error("\nClaude agent encountered an error:", error instanceof Error ? error.message : error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
122
packages/stack-cli/src/lib/init-prompt.ts
Normal file
122
packages/stack-cli/src/lib/init-prompt.ts
Normal file
@ -0,0 +1,122 @@
|
||||
// TODO: Use configPath in the prompt once local emulator is set up:
|
||||
// Add "npx @stackframe/stack-cli emulator run --config-file ${configPath}" to project dev command
|
||||
export const createInitPrompt = (web: boolean, configPath?: string) => `=============================
|
||||
STACK AUTH SETUP INSTRUCTIONS
|
||||
=============================
|
||||
|
||||
These instructions describe how to set up Stack Auth.
|
||||
${web ? `
|
||||
First of all, if you have access to a terminal, it is better to use the \`npx @stackframe/stack-cli init\`` : ""}
|
||||
|
||||
Install mcp server from https://mcp.stack-auth.com if not already installed
|
||||
|
||||
For reference, questions, or information on Stack Auth, you can query the docs on https://docs.stack-auth.com via curl or any tools that you have
|
||||
|
||||
## Setup
|
||||
|
||||
### 1) Install the package
|
||||
|
||||
Run the install command using whatever package manager the project uses (npm, yarn, pnpm, bun):
|
||||
|
||||
| Framework | Package |
|
||||
|-----------|---------|
|
||||
| Next.js | \`@stackframe/stack\` |
|
||||
| React | \`@stackframe/react\` |
|
||||
| Vanilla JS | \`@stackframe/js\` |
|
||||
|
||||
### 2) Create the Stack apps
|
||||
|
||||
Depending on whether you're on a client or a server, you will want to create stackClientApp or stackServerApp. Some environments, like Next.js, have both, so create both files.
|
||||
|
||||
The stack client app has client-level permissions. It contains most of the useful methods and hooks for your client-side code.
|
||||
The stack server app has full read and write access to all users. It requires STACK_SECRET_SERVER_KEY env variable and should only be used in secure context
|
||||
|
||||
In Next.js, env vars are auto-detected (NEXT_PUBLIC_STACK_PROJECT_ID etc.), so the constructor needs no explicit config. For other frameworks, you must pass projectId and publishableClientKey explicitly using the framework's env var access method.
|
||||
|
||||
The tokenStore should be "nextjs-cookie" for Next.js, or "cookie" for all other frameworks.
|
||||
|
||||
\`\`\`ts
|
||||
// src/stack/client.ts
|
||||
import { StackClientApp } from "@stackframe/stack"; // or "@stackframe/react" or "@stackframe/js"
|
||||
|
||||
export const stackClientApp = new StackClientApp({
|
||||
// Next.js: omit projectId/publishableClientKey (auto-detected from NEXT_PUBLIC_ env vars)
|
||||
// Other frameworks: pass explicitly, e.g. for Vite:
|
||||
// projectId: import.meta.env.VITE_STACK_PROJECT_ID,
|
||||
// publishableClientKey: import.meta.env.VITE_STACK_PUBLISHABLE_CLIENT_KEY,
|
||||
tokenStore: "nextjs-cookie", // or "cookie" for non-Next.js
|
||||
});
|
||||
\`\`\`
|
||||
|
||||
If the framework has server-side support (e.g. Next.js), also create a server app:
|
||||
|
||||
\`\`\`ts
|
||||
// src/stack/server.ts
|
||||
import "server-only";
|
||||
import { StackServerApp } from "@stackframe/stack";
|
||||
import { stackClientApp } from "./client";
|
||||
|
||||
export const stackServerApp = new StackServerApp({
|
||||
inheritsFrom: stackClientApp,
|
||||
});
|
||||
\`\`\`
|
||||
|
||||
### 3) Create the Stack handler (if available in framework)
|
||||
|
||||
This sets up pages for sign in, sign up, password reset, etc.
|
||||
|
||||
\`\`\`tsx
|
||||
import { StackHandler } from "@stackframe/stack"; // Next.js
|
||||
// import { StackHandler } from "@stackframe/react"; // React
|
||||
|
||||
export default function Handler() {
|
||||
return <StackHandler fullPage />;
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
### 4) Create a Suspense boundary
|
||||
|
||||
Suspense is necessary for many stack auth hooks such as useUser to function. Add a loading component with a custom loading indicator for the current project. Don't add if one already exists
|
||||
|
||||
For example:
|
||||
\`\`\`tsx
|
||||
//src/loading.tsx
|
||||
|
||||
export default function Loading() {
|
||||
return <p>Loading...</p>
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
### 5) Link environment variables
|
||||
|
||||
This is only necessary if not using local emulator. Ensure these are ignored by git.
|
||||
|
||||
Rename the env var keys in .env to match the framework's convention for client-exposed variables. For example, Vite requires VITE_ prefix, Next.js uses NEXT_PUBLIC_, etc. The values should stay the same — only rename the keys.
|
||||
|
||||
The required variables are:
|
||||
- Project ID (e.g. NEXT_PUBLIC_STACK_PROJECT_ID, VITE_STACK_PROJECT_ID, etc.)
|
||||
- Publishable client key (e.g. NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY, VITE_STACK_PUBLISHABLE_CLIENT_KEY, etc.)
|
||||
- Secret server key: STACK_SECRET_SERVER_KEY (only for frameworks with server-side support, no prefix needed)
|
||||
|
||||
### 6) React only: Wrap the entire page in a Stack provider
|
||||
|
||||
This is used for the useUser and useStackApp hooks.
|
||||
|
||||
\`\`\`tsx
|
||||
import { StackProvider, StackTheme } from "@stackframe/stack";
|
||||
import { stackClientApp } from "../stack/client"; // adjust relative path
|
||||
\`\`\`
|
||||
|
||||
Then wrap the body content:
|
||||
|
||||
\`\`\`tsx
|
||||
return (
|
||||
<body>
|
||||
<StackProvider app={stackClientApp}>
|
||||
<StackTheme>{children}</StackTheme>
|
||||
</StackProvider>
|
||||
</body>
|
||||
);
|
||||
\`\`\`
|
||||
`;
|
||||
|
||||
@ -6,6 +6,7 @@ const config: UserConfig = {
|
||||
clean: false,
|
||||
dts: true,
|
||||
outDir: 'dist',
|
||||
external: ['@anthropic-ai/claude-agent-sdk'],
|
||||
format: {
|
||||
esm: {
|
||||
outExtensions: () => ({ js: '.js', dts: '.d.ts' }),
|
||||
|
||||
389
pnpm-lock.yaml
389
pnpm-lock.yaml
@ -722,7 +722,7 @@ importers:
|
||||
version: 1.163.2(crossws@0.4.4(srvx@0.8.16))
|
||||
nitro:
|
||||
specifier: ^3.0.0
|
||||
version: 3.0.0(@electric-sql/pglite@0.3.2)(chokidar@4.0.3)(lru-cache@11.2.2)(mysql2@3.15.3)(rolldown@1.0.0-rc.3)(vite@7.3.1(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.0))
|
||||
version: 3.0.0(@electric-sql/pglite@0.3.2)(chokidar@4.0.3)(lru-cache@11.2.2)(mysql2@3.15.3)(vite@7.3.1(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.0))
|
||||
react:
|
||||
specifier: 19.2.1
|
||||
version: 19.2.1
|
||||
@ -1471,10 +1471,10 @@ importers:
|
||||
version: link:../../packages/stack
|
||||
'@supabase/ssr':
|
||||
specifier: latest
|
||||
version: 0.9.0(@supabase/supabase-js@2.98.0)
|
||||
version: 0.9.0(@supabase/supabase-js@2.99.0)
|
||||
'@supabase/supabase-js':
|
||||
specifier: latest
|
||||
version: 2.98.0
|
||||
version: 2.99.0
|
||||
jose:
|
||||
specifier: ^5.2.2
|
||||
version: 5.6.3
|
||||
@ -1906,9 +1906,18 @@ importers:
|
||||
|
||||
packages/stack-cli:
|
||||
dependencies:
|
||||
'@anthropic-ai/claude-agent-sdk':
|
||||
specifier: ^0.2.73
|
||||
version: 0.2.73(zod@4.1.12)
|
||||
'@inquirer/prompts':
|
||||
specifier: ^7.0.0
|
||||
version: 7.10.1(@types/node@20.17.6)
|
||||
'@stackframe/js':
|
||||
specifier: workspace:*
|
||||
version: link:../js
|
||||
'@stackframe/stack-shared':
|
||||
specifier: workspace:*
|
||||
version: link:../stack-shared
|
||||
commander:
|
||||
specifier: ^13.1.0
|
||||
version: 13.1.0
|
||||
@ -2424,6 +2433,12 @@ packages:
|
||||
'@antfu/utils@8.1.1':
|
||||
resolution: {integrity: sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ==}
|
||||
|
||||
'@anthropic-ai/claude-agent-sdk@0.2.73':
|
||||
resolution: {integrity: sha512-JrHeMl93Q5ai9GMPAffQkSisbbDvD1skU2x6sf6WRzEZw0sK6aTG+XSiZHY2F5aSrfd4G2qUogLHEm6Y8obyOQ==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
peerDependencies:
|
||||
zod: ^4.0.0
|
||||
|
||||
'@apidevtools/json-schema-ref-parser@11.9.3':
|
||||
resolution: {integrity: sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==}
|
||||
engines: {node: '>= 16'}
|
||||
@ -4763,10 +4778,144 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@inquirer/ansi@1.0.2':
|
||||
resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@inquirer/checkbox@4.3.2':
|
||||
resolution: {integrity: sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
'@types/node': '>=18'
|
||||
peerDependenciesMeta:
|
||||
'@types/node':
|
||||
optional: true
|
||||
|
||||
'@inquirer/confirm@5.1.21':
|
||||
resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
'@types/node': '>=18'
|
||||
peerDependenciesMeta:
|
||||
'@types/node':
|
||||
optional: true
|
||||
|
||||
'@inquirer/core@10.3.2':
|
||||
resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
'@types/node': '>=18'
|
||||
peerDependenciesMeta:
|
||||
'@types/node':
|
||||
optional: true
|
||||
|
||||
'@inquirer/editor@4.2.23':
|
||||
resolution: {integrity: sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
'@types/node': '>=18'
|
||||
peerDependenciesMeta:
|
||||
'@types/node':
|
||||
optional: true
|
||||
|
||||
'@inquirer/expand@4.0.23':
|
||||
resolution: {integrity: sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
'@types/node': '>=18'
|
||||
peerDependenciesMeta:
|
||||
'@types/node':
|
||||
optional: true
|
||||
|
||||
'@inquirer/external-editor@1.0.3':
|
||||
resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
'@types/node': '>=18'
|
||||
peerDependenciesMeta:
|
||||
'@types/node':
|
||||
optional: true
|
||||
|
||||
'@inquirer/figures@1.0.15':
|
||||
resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@inquirer/figures@1.0.3':
|
||||
resolution: {integrity: sha512-ErXXzENMH5pJt5/ssXV0DfWUZqly8nGzf0UcBV9xTnP+KyffE2mqyxIMBrZ8ijQck2nU0TQm40EQB53YreyWHw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@inquirer/input@4.3.1':
|
||||
resolution: {integrity: sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
'@types/node': '>=18'
|
||||
peerDependenciesMeta:
|
||||
'@types/node':
|
||||
optional: true
|
||||
|
||||
'@inquirer/number@3.0.23':
|
||||
resolution: {integrity: sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
'@types/node': '>=18'
|
||||
peerDependenciesMeta:
|
||||
'@types/node':
|
||||
optional: true
|
||||
|
||||
'@inquirer/password@4.0.23':
|
||||
resolution: {integrity: sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
'@types/node': '>=18'
|
||||
peerDependenciesMeta:
|
||||
'@types/node':
|
||||
optional: true
|
||||
|
||||
'@inquirer/prompts@7.10.1':
|
||||
resolution: {integrity: sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
'@types/node': '>=18'
|
||||
peerDependenciesMeta:
|
||||
'@types/node':
|
||||
optional: true
|
||||
|
||||
'@inquirer/rawlist@4.1.11':
|
||||
resolution: {integrity: sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
'@types/node': '>=18'
|
||||
peerDependenciesMeta:
|
||||
'@types/node':
|
||||
optional: true
|
||||
|
||||
'@inquirer/search@3.2.2':
|
||||
resolution: {integrity: sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
'@types/node': '>=18'
|
||||
peerDependenciesMeta:
|
||||
'@types/node':
|
||||
optional: true
|
||||
|
||||
'@inquirer/select@4.4.2':
|
||||
resolution: {integrity: sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
'@types/node': '>=18'
|
||||
peerDependenciesMeta:
|
||||
'@types/node':
|
||||
optional: true
|
||||
|
||||
'@inquirer/type@3.0.10':
|
||||
resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
'@types/node': '>=18'
|
||||
peerDependenciesMeta:
|
||||
'@types/node':
|
||||
optional: true
|
||||
|
||||
'@isaacs/cliui@8.0.2':
|
||||
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
|
||||
engines: {node: '>=12'}
|
||||
@ -8386,20 +8535,20 @@ packages:
|
||||
resolution: {integrity: sha512-SXuhqhuR5FXaYgKTXzZJeqtVA6JKb9IZWaGeEUxHHiOcFy2p51wccO72bYpXwoK4D5pzQOIYLTuAc7etxyMmwg==}
|
||||
engines: {node: '>=12.16'}
|
||||
|
||||
'@supabase/auth-js@2.98.0':
|
||||
resolution: {integrity: sha512-GBH361T0peHU91AQNzOlIrjUZw9TZbB9YDRiyFgk/3Kvr3/Z1NWUZ2athWTfHhwNNi8IrW00foyFxQD9IO/Trg==}
|
||||
'@supabase/auth-js@2.99.0':
|
||||
resolution: {integrity: sha512-tHiIST/OEoLmWBE+3X69xRY5srJM/lL86KltmMlIfDo9ePJLo14vQQV9T4NF+P+MoGhCwQL1GTmk51zuAFMXKw==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
|
||||
'@supabase/functions-js@2.98.0':
|
||||
resolution: {integrity: sha512-N/xEyiNU5Org+d+PNCpv+TWniAXRzxIURxDYsS/m2I/sfAB/HcM9aM2Dmf5edj5oWb9GxID1OBaZ8NMmPXL+Lg==}
|
||||
'@supabase/functions-js@2.99.0':
|
||||
resolution: {integrity: sha512-zA9oad6EqGwMLLu2LfP1bXbqKcJGiotAdbdTfZG7YS7619YZQAEgejj9mp+E5vglKE1yMWbKK+S1J3PbuUtgLg==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
|
||||
'@supabase/postgrest-js@2.98.0':
|
||||
resolution: {integrity: sha512-v6e9WeZuJijzUut8HyXu6gMqWFepIbaeaMIm1uKzei4yLg9bC9OtEW9O14LE/9ezqNbSAnSLO5GtOLFdm7Bpkg==}
|
||||
'@supabase/postgrest-js@2.99.0':
|
||||
resolution: {integrity: sha512-8qfOMi2pu9y0IQhUAeFqjrvR49G4ELGevXCWV9qAHXFQ/h2FFh0I8PYjFQj4rHcHSq6hrpozDnS1vbQU8NAQ/A==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
|
||||
'@supabase/realtime-js@2.98.0':
|
||||
resolution: {integrity: sha512-rOWt28uGyFipWOSd+n0WVMr9kUXiWaa7J4hvyLCIHjRFqWm1z9CaaKAoYyfYMC1Exn3WT8WePCgiVhlAtWC2yw==}
|
||||
'@supabase/realtime-js@2.99.0':
|
||||
resolution: {integrity: sha512-7nFTZhNeANR7FvEY6PfWLCfE8dHqcaJd9SuR7IPEZvBPG9K4uEHMivpjZx4NWRSU7Eji7ZbKy2LG+cJ48DhwHg==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
|
||||
'@supabase/ssr@0.9.0':
|
||||
@ -8407,12 +8556,12 @@ packages:
|
||||
peerDependencies:
|
||||
'@supabase/supabase-js': ^2.97.0
|
||||
|
||||
'@supabase/storage-js@2.98.0':
|
||||
resolution: {integrity: sha512-tzr2mG+v7ILSAZSfZMSL9OPyIH4z1ikgQ8EcQTKfMRz4EwmlFt3UnJaGzSOxyvF5b+fc9So7qdSUWTqGgeLokQ==}
|
||||
'@supabase/storage-js@2.99.0':
|
||||
resolution: {integrity: sha512-mAEEbfsght5EEALejYrwAP9k8sFBGjfMZT8n4SyMXk2iYuWVeRMs1kA/uKg0uDMctWdZ0bL+L4jZzksUJpCjMA==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
|
||||
'@supabase/supabase-js@2.98.0':
|
||||
resolution: {integrity: sha512-Ohc97CtInLwZyiSASz7tT9/Abm/vqnIbO9REp+PivVUII8UZsuI3bngRQnYgJdFoOIwvaEII1fX1qy8x0CyNiw==}
|
||||
'@supabase/supabase-js@2.99.0':
|
||||
resolution: {integrity: sha512-SP9Sn9tsHDB7N4u2gT13rdeZJewE4xibAxasG7vOz+fYi92+XkMMbWNx0uGK53zKTnAnvTs16isRooyBy4sn5w==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
|
||||
'@swc/counter@0.1.3':
|
||||
@ -10010,6 +10159,9 @@ packages:
|
||||
chardet@0.7.0:
|
||||
resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==}
|
||||
|
||||
chardet@2.1.1:
|
||||
resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==}
|
||||
|
||||
check-error@1.0.3:
|
||||
resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==}
|
||||
|
||||
@ -13374,6 +13526,10 @@ packages:
|
||||
resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==}
|
||||
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
|
||||
|
||||
mute-stream@2.0.0:
|
||||
resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==}
|
||||
engines: {node: ^18.17.0 || >=20.5.0}
|
||||
|
||||
mysql2@3.15.3:
|
||||
resolution: {integrity: sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==}
|
||||
engines: {node: '>= 8.0'}
|
||||
@ -16647,6 +16803,10 @@ packages:
|
||||
resolution: {integrity: sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==}
|
||||
engines: {node: '>=12.20'}
|
||||
|
||||
yoctocolors-cjs@2.1.3:
|
||||
resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
yup@1.7.1:
|
||||
resolution: {integrity: sha512-GKHFX2nXul2/4Dtfxhozv701jLQHdf6J34YDh2cEkpqoo8le5Mg6/LrdseVLrFarmFygZTlfIhHx/QKfb/QWXw==}
|
||||
|
||||
@ -16806,6 +16966,20 @@ snapshots:
|
||||
|
||||
'@antfu/utils@8.1.1': {}
|
||||
|
||||
'@anthropic-ai/claude-agent-sdk@0.2.73(zod@4.1.12)':
|
||||
dependencies:
|
||||
zod: 4.1.12
|
||||
optionalDependencies:
|
||||
'@img/sharp-darwin-arm64': 0.34.4
|
||||
'@img/sharp-darwin-x64': 0.34.4
|
||||
'@img/sharp-linux-arm': 0.34.4
|
||||
'@img/sharp-linux-arm64': 0.34.4
|
||||
'@img/sharp-linux-x64': 0.34.4
|
||||
'@img/sharp-linuxmusl-arm64': 0.34.4
|
||||
'@img/sharp-linuxmusl-x64': 0.34.4
|
||||
'@img/sharp-win32-arm64': 0.34.4
|
||||
'@img/sharp-win32-x64': 0.34.4
|
||||
|
||||
'@apidevtools/json-schema-ref-parser@11.9.3':
|
||||
dependencies:
|
||||
'@jsdevtools/ono': 7.1.3
|
||||
@ -19417,8 +19591,133 @@ snapshots:
|
||||
'@img/sharp-win32-x64@0.34.4':
|
||||
optional: true
|
||||
|
||||
'@inquirer/ansi@1.0.2': {}
|
||||
|
||||
'@inquirer/checkbox@4.3.2(@types/node@20.17.6)':
|
||||
dependencies:
|
||||
'@inquirer/ansi': 1.0.2
|
||||
'@inquirer/core': 10.3.2(@types/node@20.17.6)
|
||||
'@inquirer/figures': 1.0.15
|
||||
'@inquirer/type': 3.0.10(@types/node@20.17.6)
|
||||
yoctocolors-cjs: 2.1.3
|
||||
optionalDependencies:
|
||||
'@types/node': 20.17.6
|
||||
|
||||
'@inquirer/confirm@5.1.21(@types/node@20.17.6)':
|
||||
dependencies:
|
||||
'@inquirer/core': 10.3.2(@types/node@20.17.6)
|
||||
'@inquirer/type': 3.0.10(@types/node@20.17.6)
|
||||
optionalDependencies:
|
||||
'@types/node': 20.17.6
|
||||
|
||||
'@inquirer/core@10.3.2(@types/node@20.17.6)':
|
||||
dependencies:
|
||||
'@inquirer/ansi': 1.0.2
|
||||
'@inquirer/figures': 1.0.15
|
||||
'@inquirer/type': 3.0.10(@types/node@20.17.6)
|
||||
cli-width: 4.1.0
|
||||
mute-stream: 2.0.0
|
||||
signal-exit: 4.1.0
|
||||
wrap-ansi: 6.2.0
|
||||
yoctocolors-cjs: 2.1.3
|
||||
optionalDependencies:
|
||||
'@types/node': 20.17.6
|
||||
|
||||
'@inquirer/editor@4.2.23(@types/node@20.17.6)':
|
||||
dependencies:
|
||||
'@inquirer/core': 10.3.2(@types/node@20.17.6)
|
||||
'@inquirer/external-editor': 1.0.3(@types/node@20.17.6)
|
||||
'@inquirer/type': 3.0.10(@types/node@20.17.6)
|
||||
optionalDependencies:
|
||||
'@types/node': 20.17.6
|
||||
|
||||
'@inquirer/expand@4.0.23(@types/node@20.17.6)':
|
||||
dependencies:
|
||||
'@inquirer/core': 10.3.2(@types/node@20.17.6)
|
||||
'@inquirer/type': 3.0.10(@types/node@20.17.6)
|
||||
yoctocolors-cjs: 2.1.3
|
||||
optionalDependencies:
|
||||
'@types/node': 20.17.6
|
||||
|
||||
'@inquirer/external-editor@1.0.3(@types/node@20.17.6)':
|
||||
dependencies:
|
||||
chardet: 2.1.1
|
||||
iconv-lite: 0.7.0
|
||||
optionalDependencies:
|
||||
'@types/node': 20.17.6
|
||||
|
||||
'@inquirer/figures@1.0.15': {}
|
||||
|
||||
'@inquirer/figures@1.0.3': {}
|
||||
|
||||
'@inquirer/input@4.3.1(@types/node@20.17.6)':
|
||||
dependencies:
|
||||
'@inquirer/core': 10.3.2(@types/node@20.17.6)
|
||||
'@inquirer/type': 3.0.10(@types/node@20.17.6)
|
||||
optionalDependencies:
|
||||
'@types/node': 20.17.6
|
||||
|
||||
'@inquirer/number@3.0.23(@types/node@20.17.6)':
|
||||
dependencies:
|
||||
'@inquirer/core': 10.3.2(@types/node@20.17.6)
|
||||
'@inquirer/type': 3.0.10(@types/node@20.17.6)
|
||||
optionalDependencies:
|
||||
'@types/node': 20.17.6
|
||||
|
||||
'@inquirer/password@4.0.23(@types/node@20.17.6)':
|
||||
dependencies:
|
||||
'@inquirer/ansi': 1.0.2
|
||||
'@inquirer/core': 10.3.2(@types/node@20.17.6)
|
||||
'@inquirer/type': 3.0.10(@types/node@20.17.6)
|
||||
optionalDependencies:
|
||||
'@types/node': 20.17.6
|
||||
|
||||
'@inquirer/prompts@7.10.1(@types/node@20.17.6)':
|
||||
dependencies:
|
||||
'@inquirer/checkbox': 4.3.2(@types/node@20.17.6)
|
||||
'@inquirer/confirm': 5.1.21(@types/node@20.17.6)
|
||||
'@inquirer/editor': 4.2.23(@types/node@20.17.6)
|
||||
'@inquirer/expand': 4.0.23(@types/node@20.17.6)
|
||||
'@inquirer/input': 4.3.1(@types/node@20.17.6)
|
||||
'@inquirer/number': 3.0.23(@types/node@20.17.6)
|
||||
'@inquirer/password': 4.0.23(@types/node@20.17.6)
|
||||
'@inquirer/rawlist': 4.1.11(@types/node@20.17.6)
|
||||
'@inquirer/search': 3.2.2(@types/node@20.17.6)
|
||||
'@inquirer/select': 4.4.2(@types/node@20.17.6)
|
||||
optionalDependencies:
|
||||
'@types/node': 20.17.6
|
||||
|
||||
'@inquirer/rawlist@4.1.11(@types/node@20.17.6)':
|
||||
dependencies:
|
||||
'@inquirer/core': 10.3.2(@types/node@20.17.6)
|
||||
'@inquirer/type': 3.0.10(@types/node@20.17.6)
|
||||
yoctocolors-cjs: 2.1.3
|
||||
optionalDependencies:
|
||||
'@types/node': 20.17.6
|
||||
|
||||
'@inquirer/search@3.2.2(@types/node@20.17.6)':
|
||||
dependencies:
|
||||
'@inquirer/core': 10.3.2(@types/node@20.17.6)
|
||||
'@inquirer/figures': 1.0.15
|
||||
'@inquirer/type': 3.0.10(@types/node@20.17.6)
|
||||
yoctocolors-cjs: 2.1.3
|
||||
optionalDependencies:
|
||||
'@types/node': 20.17.6
|
||||
|
||||
'@inquirer/select@4.4.2(@types/node@20.17.6)':
|
||||
dependencies:
|
||||
'@inquirer/ansi': 1.0.2
|
||||
'@inquirer/core': 10.3.2(@types/node@20.17.6)
|
||||
'@inquirer/figures': 1.0.15
|
||||
'@inquirer/type': 3.0.10(@types/node@20.17.6)
|
||||
yoctocolors-cjs: 2.1.3
|
||||
optionalDependencies:
|
||||
'@types/node': 20.17.6
|
||||
|
||||
'@inquirer/type@3.0.10(@types/node@20.17.6)':
|
||||
optionalDependencies:
|
||||
'@types/node': 20.17.6
|
||||
|
||||
'@isaacs/cliui@8.0.2':
|
||||
dependencies:
|
||||
string-width: 5.1.2
|
||||
@ -24614,19 +24913,19 @@ snapshots:
|
||||
|
||||
'@stripe/stripe-js@7.7.0': {}
|
||||
|
||||
'@supabase/auth-js@2.98.0':
|
||||
'@supabase/auth-js@2.99.0':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
'@supabase/functions-js@2.98.0':
|
||||
'@supabase/functions-js@2.99.0':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
'@supabase/postgrest-js@2.98.0':
|
||||
'@supabase/postgrest-js@2.99.0':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
'@supabase/realtime-js@2.98.0':
|
||||
'@supabase/realtime-js@2.99.0':
|
||||
dependencies:
|
||||
'@types/phoenix': 1.6.6
|
||||
'@types/ws': 8.18.1
|
||||
@ -24636,23 +24935,23 @@ snapshots:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
|
||||
'@supabase/ssr@0.9.0(@supabase/supabase-js@2.98.0)':
|
||||
'@supabase/ssr@0.9.0(@supabase/supabase-js@2.99.0)':
|
||||
dependencies:
|
||||
'@supabase/supabase-js': 2.98.0
|
||||
'@supabase/supabase-js': 2.99.0
|
||||
cookie: 1.0.2
|
||||
|
||||
'@supabase/storage-js@2.98.0':
|
||||
'@supabase/storage-js@2.99.0':
|
||||
dependencies:
|
||||
iceberg-js: 0.8.1
|
||||
tslib: 2.8.1
|
||||
|
||||
'@supabase/supabase-js@2.98.0':
|
||||
'@supabase/supabase-js@2.99.0':
|
||||
dependencies:
|
||||
'@supabase/auth-js': 2.98.0
|
||||
'@supabase/functions-js': 2.98.0
|
||||
'@supabase/postgrest-js': 2.98.0
|
||||
'@supabase/realtime-js': 2.98.0
|
||||
'@supabase/storage-js': 2.98.0
|
||||
'@supabase/auth-js': 2.99.0
|
||||
'@supabase/functions-js': 2.99.0
|
||||
'@supabase/postgrest-js': 2.99.0
|
||||
'@supabase/realtime-js': 2.99.0
|
||||
'@supabase/storage-js': 2.99.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
@ -26658,6 +26957,8 @@ snapshots:
|
||||
|
||||
chardet@0.7.0: {}
|
||||
|
||||
chardet@2.1.1: {}
|
||||
|
||||
check-error@1.0.3:
|
||||
dependencies:
|
||||
get-func-name: 2.0.2
|
||||
@ -28083,7 +28384,7 @@ snapshots:
|
||||
debug: 4.4.3
|
||||
enhanced-resolve: 5.17.1
|
||||
eslint: 8.57.1
|
||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.56.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
||||
fast-glob: 3.3.3
|
||||
get-tsconfig: 4.8.1
|
||||
is-bun-module: 1.2.1
|
||||
@ -28096,25 +28397,6 @@ snapshots:
|
||||
- eslint-import-resolver-webpack
|
||||
- supports-color
|
||||
|
||||
eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.56.1(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.56.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1):
|
||||
dependencies:
|
||||
'@nolyfill/is-core-module': 1.0.39
|
||||
debug: 4.4.3
|
||||
enhanced-resolve: 5.17.1
|
||||
eslint: 8.57.1
|
||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.56.1(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
||||
fast-glob: 3.3.3
|
||||
get-tsconfig: 4.8.1
|
||||
is-bun-module: 1.2.1
|
||||
is-glob: 4.0.3
|
||||
optionalDependencies:
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.56.1(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
||||
transitivePeerDependencies:
|
||||
- '@typescript-eslint/parser'
|
||||
- eslint-import-resolver-node
|
||||
- eslint-import-resolver-webpack
|
||||
- supports-color
|
||||
|
||||
eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.56.1(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1):
|
||||
dependencies:
|
||||
'@nolyfill/is-core-module': 1.0.39
|
||||
@ -28145,7 +28427,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1):
|
||||
eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.56.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1):
|
||||
dependencies:
|
||||
debug: 3.2.7
|
||||
optionalDependencies:
|
||||
@ -28223,7 +28505,7 @@ snapshots:
|
||||
doctrine: 2.1.0
|
||||
eslint: 8.57.1
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.56.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
||||
hasown: 2.0.2
|
||||
is-core-module: 2.15.1
|
||||
is-glob: 4.0.3
|
||||
@ -31082,6 +31364,8 @@ snapshots:
|
||||
|
||||
mute-stream@1.0.0: {}
|
||||
|
||||
mute-stream@2.0.0: {}
|
||||
|
||||
mysql2@3.15.3:
|
||||
dependencies:
|
||||
aws-ssl-profiles: 1.1.2
|
||||
@ -31424,7 +31708,7 @@ snapshots:
|
||||
|
||||
nice-try@1.0.5: {}
|
||||
|
||||
nitro@3.0.0(@electric-sql/pglite@0.3.2)(chokidar@4.0.3)(lru-cache@11.2.2)(mysql2@3.15.3)(rolldown@1.0.0-rc.3)(vite@7.3.1(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.0)):
|
||||
nitro@3.0.0(@electric-sql/pglite@0.3.2)(chokidar@4.0.3)(lru-cache@11.2.2)(mysql2@3.15.3)(vite@7.3.1(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.0)):
|
||||
dependencies:
|
||||
consola: 3.4.2
|
||||
cookie-es: 2.0.0
|
||||
@ -31444,7 +31728,6 @@ snapshots:
|
||||
unenv: 2.0.0-rc.21
|
||||
unstorage: 2.0.0-alpha.3(chokidar@4.0.3)(db0@0.3.4(@electric-sql/pglite@0.3.2)(mysql2@3.15.3))(lru-cache@11.2.2)(ofetch@1.5.1)
|
||||
optionalDependencies:
|
||||
rolldown: 1.0.0-rc.3
|
||||
vite: 7.3.1(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.0)
|
||||
transitivePeerDependencies:
|
||||
- '@azure/app-configuration'
|
||||
@ -35142,6 +35425,8 @@ snapshots:
|
||||
|
||||
yocto-queue@1.1.1: {}
|
||||
|
||||
yoctocolors-cjs@2.1.3: {}
|
||||
|
||||
yup@1.7.1:
|
||||
dependencies:
|
||||
property-expr: 2.0.6
|
||||
|
||||
@ -8,6 +8,7 @@ packages:
|
||||
|
||||
minimumReleaseAge: 2880
|
||||
minimumReleaseAgeExclude:
|
||||
- '@anthropic-ai/claude-agent-sdk'
|
||||
- ai
|
||||
- '@ai-sdk/openai'
|
||||
- '@ai-sdk/react'
|
||||
|
||||
Loading…
Reference in New Issue
Block a user