diff --git a/.gitignore b/.gitignore index 981873e..5db94f7 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,9 @@ examples/**/.prod.vars # Ignore test apps cli/test-apps/** !cli/test-apps/.gitkeep +# Ignore test apps in create-fiberplane +create-fiberplane/test-apps/** +!create-fiberplane/test-apps/.gitkeep # Ignore macOS DS_Store files .DS_Store diff --git a/biome.jsonc b/biome.jsonc index 8a42c72..b92b32a 100644 --- a/biome.jsonc +++ b/biome.jsonc @@ -63,7 +63,11 @@ "dist", // ignore all tsconfig.json files - "tsconfig.json" + "tsconfig.json", + + // ignore all test-apps + "cli/test-apps/**", + "create-fiberplane/test-apps/**" ] } } diff --git a/cli/package.json b/cli/package.json index d16a87e..5c67c1d 100644 --- a/cli/package.json +++ b/cli/package.json @@ -5,7 +5,7 @@ "description": "An interactive CLI to create modular typesafe data APIs using TypeScript", "scripts": { "build": "pnpm clean && tsup", - "dev": "tsup --watch && node dist/index.js", + "dev": "tsup --watch --onSuccess 'node dist/index.js'", "dev:target": "tsup --watch --onSuccess 'node dist/index.js test-name'", "format": "biome format . --write", "typecheck": "tsc --noEmit", diff --git a/create-fiberplane/.gitignore b/create-fiberplane/.gitignore new file mode 100644 index 0000000..e319e06 --- /dev/null +++ b/create-fiberplane/.gitignore @@ -0,0 +1,33 @@ +# prod +dist/ + +# dev +.yarn/ +!.yarn/releases +.vscode/* +!.vscode/launch.json +!.vscode/*.code-snippets +.idea/workspace.xml +.idea/usage.statistics.xml +.idea/shelf + +# deps +node_modules/ +.wrangler + +# env +.env +.env.production +.dev.vars + +# logs +logs/ +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +# misc +.DS_Store diff --git a/create-fiberplane/README.md b/create-fiberplane/README.md new file mode 100644 index 0000000..ac5c907 --- /dev/null +++ b/create-fiberplane/README.md @@ -0,0 +1,75 @@ +# create-fiberplane + +An interactive CLI to create MCP (Model Context Protocol) projects with Fiberplane. + +## Usage + +```bash +npm create fiberplane@latest [project-name] +``` + +## Features + +- ๐Ÿš€ Interactive project setup +- ๐Ÿ“ฆ Automatic dependency installation +- ๐Ÿค– AI assistant integration (Cursor, Claude Code, VSCode, Windsurf) +- ๐Ÿ”ง Git initialization +- โ˜๏ธ Fiberplane deployment configuration +- ๐Ÿ“‹ MCP template scaffolding + +## Flow + +1. **Target directory?** - Project directory name (default: "echo-mcp") +2. **Install AI assistance?** - Choose your preferred AI coding assistant +3. **Install dependencies?** - Automatically install project dependencies +4. **Initialize git?** - Set up git repository (skipped if already in a git repo) +5. **"Make it live" (Deploy with Fiberplane?)** - Configure Fiberplane deployment + +## Debugging + +The CLI includes comprehensive logging to help debug issues. Logs are automatically saved to: + +- **macOS**: `~/Library/Logs/create-fiberplane/` +- **Linux**: `~/.local/state/create-fiberplane/logs/` +- **Windows**: `%LOCALAPPDATA%\create-fiberplane\Logs\` + +### View Debug Logs + +All CLI operations are automatically logged to files for debugging: + +```bash +# Check the logs (macOS example) +tail -f ~/Library/Logs/create-fiberplane/create-fiberplane-*.log + +# Or view the latest log file +ls -t ~/Library/Logs/create-fiberplane/ | head -1 | xargs -I {} cat ~/Library/Logs/create-fiberplane/{} +``` + +### Environment Variables + +- `CFP_LOG_DIR=/custom/path` - Override log directory (optional) + +**Note**: All debug information is automatically logged to files to avoid interfering with the interactive CLI prompts. + +## Development + +```bash +# Install dependencies +pnpm install + +# Build the CLI +pnpm build + +# Test locally +pnpm dev + +# Test locally (check log files for debug output) +pnpm dev + +# Format code +pnpm format +``` + +## License + +MIT diff --git a/create-fiberplane/biome.jsonc b/create-fiberplane/biome.jsonc new file mode 100644 index 0000000..abbea7d --- /dev/null +++ b/create-fiberplane/biome.jsonc @@ -0,0 +1,3 @@ +{ + "extends": ["../biome.jsonc"] +} diff --git a/create-fiberplane/package.json b/create-fiberplane/package.json new file mode 100644 index 0000000..cbc87b0 --- /dev/null +++ b/create-fiberplane/package.json @@ -0,0 +1,49 @@ +{ + "name": "create-fiberplane", + "type": "module", + "version": "0.0.1", + "description": "An interactive CLI to create MCP (Model Context Protocol) projects with Fiberplane", + "scripts": { + "build": "pnpm clean && tsup", + "dev": "tsup --watch --onSuccess 'node dist/index.js'", + "dev:target": "tsup --watch --onSuccess 'node dist/index.js test-name'", + "test:auth": "tsx test-auth.ts", + "format": "biome format . --write", + "typecheck": "tsc --noEmit", + "clean": "rimraf dist", + "clean:test-apps": "rimraf test-apps/* && touch test-apps/.gitkeep" + }, + "exports": "./dist/index.js", + "files": ["dist", "README.md", "LICENSE", ".gitignore"], + "bin": { + "create-fiberplane": "dist/index.js" + }, + "author": "Fiberplane", + "license": "MIT", + "repository": { + "url": "https://github.com/fiberplane/create-honc-app", + "type": "git" + }, + "dependencies": { + "@clack/core": "^0.3.4", + "@clack/prompts": "^0.7.0", + "@oslojs/oauth2": "^0.5.0", + "giget": "^1.2.3", + "open": "^10.1.0", + "picocolors": "^1.0.1", + "pino": "^9.9.4", + "pino-pretty": "^13.1.1" + }, + "devDependencies": { + "@types/node": "^22.2.0", + "rimraf": "^6.0.1", + "tsup": "^8.2.3", + "tsx": "^4.19.2" + }, + "engines": { + "node": ">=18.17.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/create-fiberplane/src/actions/ai-assistant/ai-assistant.ts b/create-fiberplane/src/actions/ai-assistant/ai-assistant.ts new file mode 100644 index 0000000..810629e --- /dev/null +++ b/create-fiberplane/src/actions/ai-assistant/ai-assistant.ts @@ -0,0 +1,48 @@ +import { note, select } from "@clack/prompts"; +import pico from "picocolors"; +import type { Context } from "../../context"; +import type { AIAssistant } from "../../types"; +import { actionCursor } from "./cursor"; +import { actionClaudeCode } from "./claude-code"; +import { actionVSCode } from "./vscode"; +import { actionWindsurf } from "./windsurf"; + +export async function promptAIAssistant(context: Context) { + const aiAssistant = await select({ + message: "Who is your copilot?", + options: [ + { value: "cursor", label: "Cursor" }, + { value: "claude-code", label: "Claude Code" }, + { value: "vscode", label: "VSCode" }, + { value: "windsurf", label: "Windsurf" }, + { value: "none", label: "I do it old school" }, + ], + initialValue: "cursor", + }); + + if (typeof aiAssistant === "string") { + context.aiAssistant = aiAssistant as AIAssistant; + } + + return aiAssistant; +} + +export async function actionAIAssistant(context: Context) { + if (!context.aiAssistant || context.aiAssistant === "none") { + return; + } + + switch (context.aiAssistant) { + case "cursor": + return await actionCursor(context); + case "claude-code": + return await actionClaudeCode(context); + case "vscode": + return await actionVSCode(context); + case "windsurf": + return await actionWindsurf(context); + default: + note(`${pico.gray("No AI assistant selected - skipping setup")}`); + return; + } +} diff --git a/create-fiberplane/src/actions/ai-assistant/claude-code.ts b/create-fiberplane/src/actions/ai-assistant/claude-code.ts new file mode 100644 index 0000000..d5c51b3 --- /dev/null +++ b/create-fiberplane/src/actions/ai-assistant/claude-code.ts @@ -0,0 +1,62 @@ +import { note, spinner } from "@clack/prompts"; +import { existsSync, writeFileSync } from "node:fs"; +import { join } from "node:path"; +import pico from "picocolors"; +import type { Context } from "../../context"; +import { + AGENTS_MD, + FIBERPLANE_MCP_NAME, + FIBERPLANE_MCP_URL, +} from "./constants"; + +// NOTE - CC needs the `type: "http"` property +const CLAUDE_CODE_FIBERPLANE_MCP_CONFIG = { + mcpServers: { + [FIBERPLANE_MCP_NAME]: { + type: "http", + url: FIBERPLANE_MCP_URL, + }, + }, +}; + +export async function actionClaudeCode(context: Context) { + if (!context.path) { + throw new Error("Path not set"); + } + + const s = spinner(); + s.start("Setting up Claude Code configuration..."); + + try { + const mcpJsonPath = join(context.path, ".mcp.json"); + const claudePath = join(context.path, "CLAUDE.md"); + + // Create .mcp.json if it doesn't exist + if (!existsSync(mcpJsonPath)) { + const mcpConfig = CLAUDE_CODE_FIBERPLANE_MCP_CONFIG; + + writeFileSync(mcpJsonPath, JSON.stringify(mcpConfig, null, 2)); + } + + // Create CLAUDE.md if it doesn't exist + if (!existsSync(claudePath)) { + const claudeContent = AGENTS_MD; + + writeFileSync(claudePath, claudeContent); + } + + s.stop(`${pico.green("โœ“")} Claude Code configuration created`); + + note(`${pico.cyan("Claude Code setup complete!")} + +${pico.dim("Created:")} +โ€ข CLAUDE.md +โ€ข .mcp.json with Fiberplane MCP server + +Claude Code is ready to use Fiberplane. +`); + } catch (error) { + s.stop(`${pico.red("โœ—")} Failed to set up Claude Code configuration`); + throw error; + } +} diff --git a/create-fiberplane/src/actions/ai-assistant/constants.ts b/create-fiberplane/src/actions/ai-assistant/constants.ts new file mode 100644 index 0000000..35cf047 --- /dev/null +++ b/create-fiberplane/src/actions/ai-assistant/constants.ts @@ -0,0 +1,38 @@ +export const FIBERPLANE_MCP_NAME = "fiberplane-mcp-server"; +export const FIBERPLANE_MCP_URL = "https://fiberplane.com/mcp"; + +export const FIBERPLANE_MCP_CONFIG = { + mcpServers: { + [FIBERPLANE_MCP_NAME]: { + url: FIBERPLANE_MCP_URL, + headers: {}, + }, + }, +}; + +export const AGENTS_MD = `# AI Coding Agent Instructions + +This is a modern Typescript web application. + +It creates a Model Context Protocol (MCP) server, which can be connected to by MCP Clients (AI assistants) such as: + +- Claude Desktop +- Claude Code +- Cursor +- VSCode + GitHub Copilot +- Windsurf + +## Stack + +This project is deployed to Fiberplane, which is equivalent to a Cloudflare serverless runtime. + +## Workflow + +Keep this file up to date with succinct descriptions of the project purpose, architecture, integrations, and other important information. + +### Development + +This project does not support local development. + +Your workflow should be that, after you make changes, you run \`pnpm run deploy\` to deploy the changes to Fiberplane. +`; diff --git a/create-fiberplane/src/actions/ai-assistant/cursor.ts b/create-fiberplane/src/actions/ai-assistant/cursor.ts new file mode 100644 index 0000000..1f10bde --- /dev/null +++ b/create-fiberplane/src/actions/ai-assistant/cursor.ts @@ -0,0 +1,59 @@ +import { note, spinner } from "@clack/prompts"; +import { existsSync, mkdirSync, writeFileSync } from "node:fs"; +import { join } from "node:path"; +import pico from "picocolors"; +import type { Context } from "../../context"; +import { AGENTS_MD, FIBERPLANE_MCP_CONFIG } from "./constants"; + +/** + * @NOTE - As of writing, nested AGENTS.md within a project are not supported + * So if someone installs this as a package-within-a-project, then AGENTS.md will not get pickedup. + * @TODO - Add a `.cursor/rule` file... + */ +export async function actionCursor(context: Context) { + if (!context.path) { + throw new Error("Path not set"); + } + + const s = spinner(); + s.start("Setting up Cursor configuration..."); + + try { + const cursorDir = join(context.path, ".cursor"); + const mcpJsonPath = join(cursorDir, "mcp.json"); + const agentsPath = join(context.path, "AGENTS.md"); + + // Create .cursor directory if it doesn't exist + if (!existsSync(cursorDir)) { + mkdirSync(cursorDir, { recursive: true }); + } + + // Create mcp.json if it doesn't exist + if (!existsSync(mcpJsonPath)) { + const mcpConfig = FIBERPLANE_MCP_CONFIG; + + writeFileSync(mcpJsonPath, JSON.stringify(mcpConfig, null, 2)); + } + + // Create AGENTS.md if it doesn't exist + if (!existsSync(agentsPath)) { + const agentsContent = AGENTS_MD; + + writeFileSync(agentsPath, agentsContent); + } + + s.stop(`${pico.green("โœ“")} Cursor configuration created`); + + note(`${pico.cyan("Cursor setup complete!")} + +${pico.dim("Created:")} +โ€ข AGENTS.md +โ€ข .cursor/mcp.json + +Cursor is ready to use Fiberplane. +`); + } catch (error) { + s.stop(`${pico.red("โœ—")} Failed to set up Cursor configuration`); + throw error; + } +} diff --git a/create-fiberplane/src/actions/ai-assistant/index.ts b/create-fiberplane/src/actions/ai-assistant/index.ts new file mode 100644 index 0000000..250dc1d --- /dev/null +++ b/create-fiberplane/src/actions/ai-assistant/index.ts @@ -0,0 +1,4 @@ +export { actionCursor } from "./cursor"; +export { actionClaudeCode } from "./claude-code"; +export { actionVSCode } from "./vscode"; +export { actionWindsurf } from "./windsurf"; diff --git a/create-fiberplane/src/actions/ai-assistant/vscode.ts b/create-fiberplane/src/actions/ai-assistant/vscode.ts new file mode 100644 index 0000000..3d60544 --- /dev/null +++ b/create-fiberplane/src/actions/ai-assistant/vscode.ts @@ -0,0 +1,72 @@ +import { note, spinner } from "@clack/prompts"; +import { existsSync, mkdirSync, writeFileSync } from "node:fs"; +import { join } from "node:path"; +import pico from "picocolors"; +import type { Context } from "../../context"; +import { + AGENTS_MD, + FIBERPLANE_MCP_NAME, + FIBERPLANE_MCP_URL, +} from "./constants"; + +export async function actionVSCode(context: Context) { + if (!context.path) { + throw new Error("Path not set"); + } + + const s = spinner(); + s.start("Setting up VSCode configuration..."); + + try { + const vscodeDir = join(context.path, ".vscode"); + const mcpJsonPath = join(vscodeDir, "mcp.json"); + const githubDir = join(context.path, ".github"); + const copilotInstructionsPath = join(githubDir, "copilot-instructions.md"); + + // Create .vscode directory if it doesn't exist + if (!existsSync(vscodeDir)) { + mkdirSync(vscodeDir, { recursive: true }); + } + + // Create .vscode/mcp.json if it doesn't exist + if (!existsSync(mcpJsonPath)) { + const mcpConfig = { + servers: { + [FIBERPLANE_MCP_NAME]: { + type: "http", + url: FIBERPLANE_MCP_URL, + headers: {}, + }, + }, + } as const; + + writeFileSync(mcpJsonPath, JSON.stringify(mcpConfig, null, 2)); + } + + // Ensure .github directory exists + if (!existsSync(githubDir)) { + mkdirSync(githubDir, { recursive: true }); + } + + // Create .github/copilot-instructions.md if it doesn't exist + if (!existsSync(copilotInstructionsPath)) { + const agentsContent = AGENTS_MD; + + writeFileSync(copilotInstructionsPath, agentsContent); + } + + s.stop(`${pico.green("โœ“")} VSCode configuration created`); + + note(`${pico.cyan("VSCode setup complete!")} + +${pico.dim("Created:")} +โ€ข .github/copilot-instructions.md +โ€ข .vscode/mcp.json + +VSCode is ready to use Fiberplane. +`); + } catch (error) { + s.stop(`${pico.red("โœ—")} Failed to set up VSCode configuration`); + throw error; + } +} diff --git a/create-fiberplane/src/actions/ai-assistant/windsurf.ts b/create-fiberplane/src/actions/ai-assistant/windsurf.ts new file mode 100644 index 0000000..faa3f2e --- /dev/null +++ b/create-fiberplane/src/actions/ai-assistant/windsurf.ts @@ -0,0 +1,90 @@ +import { note, spinner } from "@clack/prompts"; +import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; +import { join } from "node:path"; +import { homedir } from "node:os"; +import pico from "picocolors"; +import type { Context } from "../../context"; +import { AGENTS_MD, FIBERPLANE_MCP_CONFIG } from "./constants"; + +function ensureDir(path: string) { + if (!existsSync(path)) { + mkdirSync(path, { recursive: true }); + } +} + +function upsertMcpConfig(targetDir: string, targetPath: string) { + ensureDir(targetDir); + + try { + if (existsSync(targetPath)) { + const raw = readFileSync(targetPath, "utf8"); + const existing = raw ? JSON.parse(raw) : {}; + const merged = { + ...existing, + mcpServers: { + ...(existing?.mcpServers ?? {}), + ...FIBERPLANE_MCP_CONFIG.mcpServers, + }, + }; + writeFileSync(targetPath, JSON.stringify(merged, null, 2)); + return "updated" as const; + } + } catch { + // Fall through to write fresh config + } + + writeFileSync(targetPath, JSON.stringify(FIBERPLANE_MCP_CONFIG, null, 2)); + return "created" as const; +} + +export async function actionWindsurf(context: Context) { + if (!context.path) { + throw new Error("Path not set"); + } + + const s = spinner(); + s.start("Setting up Windsurf MCP integration..."); + + try { + const agentsPath = join(context.path, "AGENTS.md"); + + if (!existsSync(agentsPath)) { + writeFileSync(agentsPath, AGENTS_MD); + } + + const home = homedir(); + const primaryDir = join(home, ".codeium", "windsurf"); + const primaryPath = join(primaryDir, "mcp_config.json"); + + const altDir = join(home, ".config", "Codeium", "Windsurf"); + const altPath = join(altDir, "mcp_config.json"); + + const createdOrUpdated: string[] = []; + + const primaryResult = upsertMcpConfig(primaryDir, primaryPath); + createdOrUpdated.push( + `~/.codeium/windsurf/mcp_config.json (${primaryResult})`, + ); + + // If the alternative location already exists, mirror the configuration there as well. + if (existsSync(altDir) || existsSync(altPath)) { + const altResult = upsertMcpConfig(altDir, altPath); + createdOrUpdated.push( + `~/.config/Codeium/Windsurf/mcp_config.json (${altResult})`, + ); + } + + s.stop(`${pico.green("โœ“")} Windsurf MCP configured`); + + note(`${pico.cyan("Windsurf setup complete!")} + +${pico.dim("Created/Updated:")} +โ€ข AGENTS.md +โ€ข ${createdOrUpdated.join("\nโ€ข ")} + +Windsurf will now connect to the Fiberplane MCP server.`); + } catch (error) { + s.stop(`${pico.red("โœ—")} Failed to set up Windsurf configuration`); + throw error; + } +} diff --git a/create-fiberplane/src/actions/dependencies.ts b/create-fiberplane/src/actions/dependencies.ts new file mode 100644 index 0000000..9b8029a --- /dev/null +++ b/create-fiberplane/src/actions/dependencies.ts @@ -0,0 +1,41 @@ +import { spinner } from "@clack/prompts"; +import { execSync } from "node:child_process"; +import pico from "picocolors"; +import type { Context } from "../context"; + +export async function promptDependencies(context: Context) { + // NOTE - Minimize questions, just install dependencies + const installDeps = true; + + // const installDeps = await confirm({ + // message: "Install dependencies?", + // initialValue: true, + // }); + + if (installDeps) { + context.flags.push("install-dependencies"); + } + + return installDeps; +} + +export async function actionDependencies(context: Context) { + if (!context.flags.includes("install-dependencies") || !context.path) { + return; + } + + const s = spinner(); + s.start("Installing dependencies..."); + + try { + execSync(`${context.packageManager} install`, { + cwd: context.path, + stdio: "ignore", + }); + + s.stop(`${pico.green("โœ“")} Dependencies installed successfully`); + } catch (error) { + s.stop(`${pico.red("โœ—")} Failed to install dependencies`); + throw error; + } +} diff --git a/create-fiberplane/src/actions/deploy.ts b/create-fiberplane/src/actions/deploy.ts new file mode 100644 index 0000000..069ce12 --- /dev/null +++ b/create-fiberplane/src/actions/deploy.ts @@ -0,0 +1,60 @@ +import { confirm, spinner } from "@clack/prompts"; +import { execSync } from "node:child_process"; +import pico from "picocolors"; +import type { Context } from "../context"; + +export async function promptDeploy(context: Context) { + const deployFiberplane = await confirm({ + message: "Should we deploy this thing now?", + initialValue: true, + }); + + if (deployFiberplane) { + context.flags.push("deploy-fiberplane"); + } + + return deployFiberplane; +} + +export async function actionDeploy(context: Context) { + if (!context.flags.includes("deploy-fiberplane") || !context.path) { + return; + } + + const s = spinner(); + s.start("Deploying to Fiberplane..."); + + try { + // HACK - force login flow here until deploy does it automatically + execSync(`${context.packageManager} fiberplane-cli auth login`, { + cwd: context.path, + stdio: "inherit", // Show output to user + }); + + // Execute the deploy script in the target project + execSync(`${context.packageManager} run deploy`, { + cwd: context.path, + stdio: "inherit", // Show output to user + }); + + s.stop(`${pico.green("โœ“")} Deployment completed successfully`); + + console.log(` +${pico.cyan("๐Ÿš€ Your MCP project is now live!")} + +Your MCP server has been deployed to Fiberplane. +Visit your Fiberplane dashboard to manage your deployment. +`); + } catch (error) { + s.stop(`${pico.red("โœ—")} Deployment failed`); + console.error(` +${pico.red("Deployment error:")} ${error instanceof Error ? error.message : "Unknown error"} + +${pico.dim("Make sure:")} +โ€ข The template includes a "deploy" script in package.json +โ€ข You have proper Fiberplane credentials configured +โ€ข All dependencies are installed +`); + throw error; + } +} diff --git a/create-fiberplane/src/actions/git.ts b/create-fiberplane/src/actions/git.ts new file mode 100644 index 0000000..cc1fa63 --- /dev/null +++ b/create-fiberplane/src/actions/git.ts @@ -0,0 +1,115 @@ +import { spinner } from "@clack/prompts"; +import { execSync } from "node:child_process"; +import pico from "picocolors"; +import type { Context } from "../context"; +import { debugGit } from "../logger"; +import { isInGitRepo } from "../utils"; + +export async function promptGit(context: Context) { + // Skip if we're already in a git repo + if (isInGitRepo(context.path)) { + debugGit.info( + { cwd: process.cwd(), targetPath: context.path }, + "Git initialization skipped - already in git repository", + ); + return; + } + + // const initGit = await confirm({ + // message: "Initialize git?", + // initialValue: true, + // }); + + // NOTE - Minimize questions, just initialize git + const initGit = true; + + if (initGit) { + context.flags.push("initialize-git"); + } + + return initGit; +} + +export async function actionGit(context: Context) { + if (!context.flags.includes("initialize-git")) { + debugGit.info( + { flags: context.flags, targetPath: context.path }, + "Git initialization skipped - not flagged for initialization", + ); + return; + } + + if (!context.path) { + debugGit.error( + { flags: context.flags, targetPath: context.path }, + "Git initialization failed - no target path provided", + ); + return; + } + + debugGit.info( + { targetPath: context.path, cwd: process.cwd() }, + "Starting git initialization", + ); + + const s = spinner(); + s.start("Initializing git repository..."); + + try { + debugGit.debug( + { command: "git init", cwd: context.path }, + "Executing git init", + ); + execSync("git init", { + cwd: context.path, + stdio: "ignore", + }); + debugGit.debug( + { command: "git init", cwd: context.path }, + "Git init completed successfully", + ); + + debugGit.debug( + { command: "git add .", cwd: context.path }, + "Executing git add", + ); + execSync("git add .", { + cwd: context.path, + stdio: "ignore", + }); + debugGit.debug( + { command: "git add .", cwd: context.path }, + "Git add completed successfully", + ); + + const commitMessage = "Initial commit: ๐Ÿค– create-fiberplane"; + debugGit.debug( + { command: `git commit -m "${commitMessage}"`, cwd: context.path }, + "Executing git commit", + ); + execSync(`git commit -m "${commitMessage}"`, { + cwd: context.path, + stdio: "ignore", + }); + debugGit.debug( + { command: `git commit -m "${commitMessage}"`, cwd: context.path }, + "Git commit completed successfully", + ); + + debugGit.info( + { targetPath: context.path }, + "Git repository initialization completed successfully", + ); + s.stop(`${pico.green("โœ“")} Git repository initialized`); + } catch (error) { + debugGit.error( + { + targetPath: context.path, + error: error instanceof Error ? error.message : String(error), + }, + "Git repository initialization failed", + ); + s.stop(`${pico.red("โœ—")} Failed to initialize git repository`); + throw error; + } +} diff --git a/create-fiberplane/src/actions/path.ts b/create-fiberplane/src/actions/path.ts new file mode 100644 index 0000000..07eff70 --- /dev/null +++ b/create-fiberplane/src/actions/path.ts @@ -0,0 +1,31 @@ +import { text } from "@clack/prompts"; +import { existsSync } from "node:fs"; +import { join } from "node:path"; +import pico from "picocolors"; +import type { Context } from "../context"; + +export async function promptPath(context: Context) { + let path = await text({ + message: "Target directory?", + placeholder: context.name, + defaultValue: context.name, + validate: (value) => { + const cleanedValue = value?.trim(); + if (!cleanedValue) { + return "Please enter a folder name"; + } + if (existsSync(join(context.cwd, cleanedValue))) { + return `Folder ${pico.red(cleanedValue)} already exists`; + } + return undefined; + }, + }); + + if (typeof path === "string") { + path = path.trim(); + context.name = path; + context.path = join(context.cwd, path); + } + + return path; +} diff --git a/create-fiberplane/src/actions/template.ts b/create-fiberplane/src/actions/template.ts new file mode 100644 index 0000000..e8a2b4f --- /dev/null +++ b/create-fiberplane/src/actions/template.ts @@ -0,0 +1,58 @@ +import { spinner } from "@clack/prompts"; +import { downloadTemplate } from "giget"; +import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; +import { basename, join } from "node:path"; +import pico from "picocolors"; +import type { Context } from "../context"; + +const MCP_TEMPLATE_URL = "github:brettimus/moncy-bars/apps/echo"; // This would be the actual template URL + +export async function actionTemplate(context: Context) { + if (!context.path) { + throw new Error("Path not set"); + } + + const s = spinner(); + s.start("Creating MCP project from template..."); + + try { + // Ensure the directory exists + if (!existsSync(context.path)) { + mkdirSync(context.path, { recursive: true }); + } + + // Download the MCP template + await downloadTemplate(MCP_TEMPLATE_URL, { + dir: context.path, + force: true, + }); + + // Update package.json name field with the project directory name + const packageJsonPath = join(context.path, "package.json"); + if (existsSync(packageJsonPath)) { + try { + const packageJsonContent = readFileSync(packageJsonPath, "utf-8"); + const packageJson = JSON.parse(packageJsonContent); + + // Set the name to the basename of the path (project directory name) + packageJson.name = basename(context.path); + + // Write back the updated package.json + writeFileSync( + packageJsonPath, + `${JSON.stringify(packageJson, null, 2)}\n`, + ); + } catch (error) { + // If package.json parsing fails, continue without updating + console.warn( + `${pico.yellow("โš ")} Could not update package.json name field`, + ); + } + } + + s.stop(`${pico.green("โœ“")} MCP template downloaded successfully`); + } catch (error) { + s.stop(`${pico.red("โœ—")} Failed to download template`); + throw error; + } +} diff --git a/create-fiberplane/src/const.ts b/create-fiberplane/src/const.ts new file mode 100644 index 0000000..baeef49 --- /dev/null +++ b/create-fiberplane/src/const.ts @@ -0,0 +1,12 @@ +export const FIBERPLANE_TITLE = ` + ______ __ ______ ______ ______ +/\\ ___\\ /\\ \\ /\\ == \\ /\\ ___\\ /\\ ___\\ +\\ \\ __\\ \\ \\ \\ \\ \\ __< \\ \\ __\\ \\ \\___ \\ + \\ \\_\\ \\ \\_\\ \\ \\_____\\ \\ \\_____\\ \\/\\_____\\ + \\/_/ \\/_/ \\/_____/ \\/_____/ \\/_____/ + +`; + +export const CANCEL_MESSAGE = "create-fiberplane cancelled! ๐Ÿ™ˆ"; + +export const PROJECT_NAME = "echo-mcp"; diff --git a/create-fiberplane/src/context.ts b/create-fiberplane/src/context.ts new file mode 100644 index 0000000..20cddc2 --- /dev/null +++ b/create-fiberplane/src/context.ts @@ -0,0 +1,39 @@ +import { PROJECT_NAME } from "./const"; +import type { AIAssistant, Flags } from "./types"; +import { getPackageManager } from "./utils"; + +export interface Context { + cwd: string; + packageManager: string; + name: string; + path?: string; + description?: string; + aiAssistant?: AIAssistant; + flags: Flags; +} + +export function initContext(): Context { + const projectName = parseProjectName(process.argv); + + return { + cwd: process.cwd(), + name: projectName ?? PROJECT_NAME, + packageManager: getPackageManager() ?? "npm", + flags: [], + }; +} + +/** + * Checks first (non-system) argument for existence, ignoring flags + * @param args - An array of command line arguments. + * @returns The `string` project name if matched, or `undefined` + */ +function parseProjectName(args: string[]): string | undefined { + const projectName = args.at(2); + + if (!projectName || projectName.startsWith("-")) { + return undefined; + } + + return projectName; +} diff --git a/create-fiberplane/src/index.ts b/create-fiberplane/src/index.ts new file mode 100644 index 0000000..bca4860 --- /dev/null +++ b/create-fiberplane/src/index.ts @@ -0,0 +1,95 @@ +#!/usr/bin/env node +import { intro, isCancel, outro } from "@clack/prompts"; +import pico from "picocolors"; +import { + actionAIAssistant, + promptAIAssistant, +} from "./actions/ai-assistant/ai-assistant"; +import { actionDependencies, promptDependencies } from "./actions/dependencies"; +import { actionDeploy, promptDeploy } from "./actions/deploy"; +import { actionGit, promptGit } from "./actions/git"; +import { promptPath } from "./actions/path"; +import { actionTemplate } from "./actions/template"; +import { FIBERPLANE_TITLE } from "./const"; +import { initContext } from "./context"; +import { isError } from "./types"; +import { handleCancel, handleError } from "./utils"; + +async function main() { + console.log(""); + console.log(pico.cyan(FIBERPLANE_TITLE)); + console.log(""); + + intro("๐Ÿš€ create-fiberplane"); + + const context = initContext(); + + const prompts = [ + promptPath, + promptAIAssistant, + promptDependencies, + promptGit, + promptDeploy, + ]; + + for (const prompt of prompts) { + if (!prompt) { + continue; + } + + const result = await prompt(context); + if (isCancel(result)) { + handleCancel(); + } + + if (isError(result)) { + handleError(result); + } + } + + const actions = [ + actionTemplate, + actionAIAssistant, + actionDependencies, + actionGit, + actionDeploy, + ]; + + for (const action of actions) { + const result = await action(context); + + if (isCancel(result)) { + handleCancel(); + } + + if (isError(result)) { + handleError(result); + } + } + + outro(`๐Ÿš€ MCP project created successfully in ${context.path}! + +${pico.cyan("Next steps:")} + +# Navigate to your project: +cd ${context.name} + +# As you develop, deploy: +${context.packageManager} fp deploy + +# Learn more about Fiberplane: +open https://docs.fiberplane.com + +${ + context.flags.includes("deploy-fiberplane") + ? `\n${pico.green("โœ“")} Fiberplane deployment is configured and ready!` + : "" +} +`); + process.exit(0); +} + +main().catch((err) => { + console.error("Unhandled error:", err); + process.exit(1); +}); diff --git a/create-fiberplane/src/integrations/fiberplane.ts b/create-fiberplane/src/integrations/fiberplane.ts new file mode 100644 index 0000000..963e193 --- /dev/null +++ b/create-fiberplane/src/integrations/fiberplane.ts @@ -0,0 +1,170 @@ +import { createServer } from "node:http"; +import type { AddressInfo } from "node:net"; +import { randomBytes } from "node:crypto"; +import open from "open"; +import { TokenRequestResult } from "@oslojs/oauth2"; + +// const AUTH_HOST = "https://auth.fiberplane.com"; +// const FP_API_HOST = "https://fiberplane.com"; +const AUTH_HOST = "http://localhost:7777"; +const FP_API_HOST = "http://localhost:7676"; +const FP_CLIENT_ID = "fp-cli"; // arbitrary string; no pre-registration needed +const AUTH_TIMEOUT_MS = 200000; +const REDIRECT_URI = (port: number) => `http://127.0.0.1:${port}/callback`; + +// Helper functions for OAuth2 PKCE +function generateState(): string { + return randomBytes(32).toString("base64url"); +} + +function generateCodeVerifier(): string { + return randomBytes(32).toString("base64url"); +} + +async function generateCodeChallenge(codeVerifier: string): Promise { + const encoder = new TextEncoder(); + const data = encoder.encode(codeVerifier); + const digest = await crypto.subtle.digest("SHA-256", data); + return btoa(String.fromCharCode(...new Uint8Array(digest))) + .replace(/\+/g, "-") + .replace(/\//g, "_") + .replace(/=/g, ""); +} + +async function exchangeForCliToken( + servicesAuthAccessToken: string, +): Promise { + const resp = await fetch(`${FP_API_HOST}/api/auth/tokens/cli-exchange`, { + method: "POST", + headers: { + Authorization: `Bearer ${servicesAuthAccessToken}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ + name: "CLI", + scopes: ["projects:read", "projects:create"], // server validates + ttlSeconds: 60 * 60 * 24 * 30, // server caps it + }), + }); + + if (!resp.ok) { + throw new Error(`Exchange failed: ${resp.status}`); + } + + const responseData = await resp.json(); + console.log("Exchange responseData:", responseData); + + const { token } = responseData.data; + return token; // Use this PAT as Authorization: Bearer fp_xxx for services-api +} + +export async function getFpAuthToken(): Promise { + const server = createServer(); + server.listen(0, "127.0.0.1"); + await new Promise((resolve) => server.once("listening", resolve)); + const listenPort = (server.address() as AddressInfo).port; + + const state = generateState(); + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + // Manually construct the authorization URL + const authorizationURL = new URL(`${AUTH_HOST}/authorize`); + authorizationURL.searchParams.set("response_type", "code"); + authorizationURL.searchParams.set("client_id", FP_CLIENT_ID); + authorizationURL.searchParams.set("redirect_uri", REDIRECT_URI(listenPort)); + authorizationURL.searchParams.set("state", state); + authorizationURL.searchParams.set("code_challenge", codeChallenge); + authorizationURL.searchParams.set("code_challenge_method", "S256"); + authorizationURL.searchParams.set("scope", "openid profile"); + // Optional: pick provider explicitly (not required if only one) + authorizationURL.searchParams.set("provider", "github"); + + return new Promise((resolve, reject) => { + const timer = setTimeout(() => { + reject( + new Error( + `Authentication timed out after ${AUTH_TIMEOUT_MS / 1000} seconds`, + ), + ); + }, AUTH_TIMEOUT_MS); + + server.on("request", async (req, res) => { + if (!req.url?.startsWith("/callback")) { + res.writeHead(404); + res.end(); + return; + } + + const url = new URL(req.url, REDIRECT_URI(listenPort)); + const code = url.searchParams.get("code"); + const returnedState = url.searchParams.get("state"); + + if (returnedState !== state) { + reject(new Error("State mismatch")); + return; + } + + if (code) { + try { + // Create the token request body + const body = new URLSearchParams({ + grant_type: "authorization_code", + code, + client_id: FP_CLIENT_ID, + redirect_uri: REDIRECT_URI(listenPort), + code_verifier: codeVerifier, + }); + + // Make the token request + const response = await fetch(`${AUTH_HOST}/token`, { + method: "POST", + body, + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + }); + + const data = await response.json(); + if (typeof data !== "object" || data === null) { + throw new Error("Unexpected response"); + } + + // Use TokenRequestResult to parse the response + const result = new TokenRequestResult(data); + if (result.hasErrorCode()) { + const error = result.errorCode(); + throw new Error(`Request failed: ${error}`); + } + + // Get the services auth access token + const servicesAuthAccessToken = result.accessToken(); + + // Exchange the services auth token for a CLI token + const cliToken = await exchangeForCliToken(servicesAuthAccessToken); + + res.writeHead(200, { "Content-Type": "text/html" }); + res.end( + "Authentication successful! You can close this window.", + ); + clearTimeout(timer); + console.log("CLI token:", cliToken); + resolve(cliToken); + server.close(); + } catch (error) { + reject(error); + } + } else { + reject(new Error("No code received")); + } + }); + + open(authorizationURL.toString()).catch(() => { + // Fall back to manual copy/paste + console.error( + "Failed to open browser. Please copy & paste:", + authorizationURL.toString(), + ); + }); + }); +} diff --git a/create-fiberplane/src/logger.ts b/create-fiberplane/src/logger.ts new file mode 100644 index 0000000..6788976 --- /dev/null +++ b/create-fiberplane/src/logger.ts @@ -0,0 +1,95 @@ +import { mkdirSync } from "node:fs"; +import { homedir, platform } from "node:os"; +import { join } from "node:path"; +import pino from "pino"; + +/** + * Get the OS-appropriate log directory for create-fiberplane + */ +function getLogDirectory(): string { + const home = homedir(); + + switch (platform()) { + case "darwin": // macOS + return join(home, "Library", "Logs", "create-fiberplane"); + case "win32": { + // Windows + const localAppData = + process.env.LOCALAPPDATA || join(home, "AppData", "Local"); + return join(localAppData, "create-fiberplane", "Logs"); + } + default: { + // Linux and others + const xdgStateHome = + process.env.XDG_STATE_HOME || join(home, ".local", "state"); + return join(xdgStateHome, "create-fiberplane", "logs"); + } + } +} + +/** + * Create log directory if it doesn't exist + */ +function ensureLogDirectory(logDir: string): void { + try { + mkdirSync(logDir, { recursive: true }); + } catch (error) { + // If we can't create the log directory, logging will be disabled + console.warn(`Warning: Could not create log directory ${logDir}:`, error); + } +} + +/** + * Generate log filename with timestamp and PID + */ +function getLogFileName(): string { + const now = new Date(); + const timestamp = now.toISOString().replace(/[:.]/g, "-").slice(0, 19); // YYYY-MM-DDTHH-MM-SS + const pid = process.pid; + return `create-fiberplane-${timestamp}-${pid}.log`; +} + +/** + * Create and configure the Pino logger + */ +function createLogger() { + const logDir = getLogDirectory(); + ensureLogDirectory(logDir); + + const logFile = join(logDir, getLogFileName()); + + // Create transport for file logging only + // Console logging is disabled to avoid interfering with Clack prompts + const transport = pino.transport({ + target: "pino/file", + options: { destination: logFile }, + level: "debug", // Log everything to file + }); + + const logger = pino( + { + level: "debug", // Allow all levels, transport will filter + base: { + pid: process.pid, + version: process.env.npm_package_version || "unknown", + node: process.version, + platform: platform(), + }, + }, + transport, + ); + + // Log the log file location on startup + logger.info({ logFile }, "Logging initialized"); + + return logger; +} + +// Create singleton logger instance +export const logger = createLogger(); + +// Export debug-specific loggers for different namespaces +export const debugGit = logger.child({ namespace: "git" }); +export const debugHttp = logger.child({ namespace: "http" }); +export const debugDeps = logger.child({ namespace: "deps" }); +export const debugAI = logger.child({ namespace: "ai-assistant" }); diff --git a/create-fiberplane/src/types.ts b/create-fiberplane/src/types.ts new file mode 100644 index 0000000..81cbb64 --- /dev/null +++ b/create-fiberplane/src/types.ts @@ -0,0 +1,14 @@ +export type AIAssistant = + | "cursor" + | "claude-code" + | "vscode" + | "windsurf" + | "none"; + +export type Flags = Array< + "install-dependencies" | "initialize-git" | "deploy-fiberplane" +>; + +export const isError = (error: unknown): error is Error => { + return error instanceof Error; +}; diff --git a/create-fiberplane/src/utils.ts b/create-fiberplane/src/utils.ts new file mode 100644 index 0000000..75d23a6 --- /dev/null +++ b/create-fiberplane/src/utils.ts @@ -0,0 +1,50 @@ +import { cancel } from "@clack/prompts"; +import { execSync } from "node:child_process"; +import { existsSync } from "node:fs"; +import { join } from "node:path"; +import pico from "picocolors"; +import { CANCEL_MESSAGE } from "./const"; + +export function handleCancel(): never { + cancel(CANCEL_MESSAGE); + process.exit(0); +} + +export function handleError(error: Error): never { + console.error(pico.red(`โŒ ${error.message}`)); + process.exit(1); +} + +export function getPackageManager(): string | undefined { + const userAgent = process.env.npm_config_user_agent; + + if (userAgent) { + if (userAgent.startsWith("pnpm")) { + return "pnpm"; + } + if (userAgent.startsWith("yarn")) { + return "yarn"; + } + if (userAgent.startsWith("bun")) { + return "bun"; + } + } + + return "npm"; +} + +export function isInGitRepo(path?: string): boolean { + try { + execSync("git rev-parse --is-inside-work-tree", { + stdio: "ignore", + cwd: path, + }); + return true; + } catch { + return false; + } +} + +export function hasPackageJson(path: string): boolean { + return existsSync(join(path, "package.json")); +} diff --git a/create-fiberplane/test-apps/.gitkeep b/create-fiberplane/test-apps/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/create-fiberplane/test-auth.ts b/create-fiberplane/test-auth.ts new file mode 100644 index 0000000..b5843d8 --- /dev/null +++ b/create-fiberplane/test-auth.ts @@ -0,0 +1,49 @@ +import { getFpAuthToken } from "./src/integrations/fiberplane.ts"; + +const FP_API_HOST = "http://localhost:7676"; +const FP_AUTH_HOST = "http://localhost:7777"; + +async function testAuth() { + console.log("๐Ÿ” Starting Fiberplane authentication test...\n"); + + try { + console.log("๐Ÿ“ This will open your browser for authentication"); + console.log("๐Ÿ”„ Initiating OAuth flow...\n"); + + const token = await getFpAuthToken(); + + console.log("\nโœ… Authentication successful!"); + console.log(`๐Ÿ“‹ Token received: ${token.substring(0, 20)}...`); + console.log(`๐Ÿ“ Token length: ${token.length} characters`); + console.log(`๐Ÿท๏ธ Token prefix: ${token.substring(0, 3)}`); + + // Optional: Test a simple API call with the token + console.log("\n๐Ÿงช Testing token with a simple API call..."); + + const testResp = await fetch(`${FP_API_HOST}/api/projects`, { + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json", + }, + }); + + if (testResp.ok) { + const user = await testResp.json(); + console.log("โœ… Token is valid! User info:", user); + } else { + console.log( + `โš ๏ธ Token test failed: ${testResp.status} ${testResp.statusText}`, + ); + const errorBody = await testResp.text(); + console.log("Error response:", errorBody); + } + } catch (error) { + console.error("\nโŒ Authentication failed:"); + console.error(error.message); + console.error("\nFull error:", error); + process.exit(1); + } +} + +// Run the test +testAuth().catch(console.error); diff --git a/create-fiberplane/tsconfig.json b/create-fiberplane/tsconfig.json new file mode 100644 index 0000000..9e4f19b --- /dev/null +++ b/create-fiberplane/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "skipLibCheck": true, + "esModuleInterop": true, + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "strict": true, + "noUnusedParameters": true, + "noUnusedLocals": true, + "noImplicitReturns": true, + "noImplicitAny": true, + "noFallthroughCasesInSwitch": true, + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src"] +} diff --git a/create-fiberplane/tsup.config.ts b/create-fiberplane/tsup.config.ts new file mode 100644 index 0000000..84df7fd --- /dev/null +++ b/create-fiberplane/tsup.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm"], + target: "node18", + clean: true, + minify: false, + bundle: true, + splitting: false, + dts: false, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5da1733..ac5bc50 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -55,6 +55,46 @@ importers: specifier: ^8.2.3 version: 8.2.4(jiti@2.4.2)(postcss@8.5.3)(tsx@4.19.2)(typescript@5.7.3)(yaml@2.7.0) + create-fiberplane: + dependencies: + '@clack/core': + specifier: ^0.3.4 + version: 0.3.4 + '@clack/prompts': + specifier: ^0.7.0 + version: 0.7.0 + '@oslojs/oauth2': + specifier: ^0.5.0 + version: 0.5.0 + giget: + specifier: ^1.2.3 + version: 1.2.3 + open: + specifier: ^10.1.0 + version: 10.1.0 + picocolors: + specifier: ^1.0.1 + version: 1.1.1 + pino: + specifier: ^9.9.4 + version: 9.9.4 + pino-pretty: + specifier: ^13.1.1 + version: 13.1.1 + devDependencies: + '@types/node': + specifier: ^22.2.0 + version: 22.13.10 + rimraf: + specifier: ^6.0.1 + version: 6.0.1 + tsup: + specifier: ^8.2.3 + version: 8.2.4(jiti@2.4.2)(postcss@8.5.3)(tsx@4.19.2)(typescript@5.7.3)(yaml@2.7.0) + tsx: + specifier: ^4.19.2 + version: 4.19.2 + docs: dependencies: '@astrojs/check': @@ -2443,6 +2483,9 @@ packages: '@oslojs/encoding@1.1.0': resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} + '@oslojs/oauth2@0.5.0': + resolution: {integrity: sha512-t70+e4EgnzTbU4MrUWXzqWN2A6RJrlSSvwwuBv6E0Ap6/nsIXrjsdRWeTcSvvXTcC6fi0YdWaqEWLipcEm2Cgw==} + '@pagefind/darwin-arm64@1.3.0': resolution: {integrity: sha512-365BEGl6ChOsauRjyVpBjXybflXAOvoMROw3TucAROHIcdBvXk9/2AmEvGFU0r75+vdQI4LJdJdpH4Y6Yqaj4A==} cpu: [arm64] @@ -2787,9 +2830,6 @@ packages: '@types/node@18.19.64': resolution: {integrity: sha512-955mDqvO2vFf/oL7V3WiUtiz+BugyX8uVbaT2H8oj3+8dRyH2FLiNdowe7eNqRM7IOIZvzDH76EoAT+gwm6aIQ==} - '@types/node@22.13.1': - resolution: {integrity: sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew==} - '@types/node@22.13.10': resolution: {integrity: sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==} @@ -3011,6 +3051,10 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + axios@1.7.9: resolution: {integrity: sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==} @@ -3168,6 +3212,9 @@ packages: resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} engines: {node: '>=12.5.0'} + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -3238,6 +3285,9 @@ packages: resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} engines: {node: '>= 12'} + dateformat@4.6.3: + resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} + debug@4.3.6: resolution: {integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==} engines: {node: '>=6.0'} @@ -3668,6 +3718,9 @@ packages: encoding@0.1.13: resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} @@ -3804,6 +3857,13 @@ packages: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} + fast-redact@3.5.0: + resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} + engines: {node: '>=6'} + + fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + fast-uri@3.0.6: resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} @@ -3993,6 +4053,9 @@ packages: hastscript@9.0.1: resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} + help-me@5.0.0: + resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} + hono-rate-limiter@0.4.0: resolution: {integrity: sha512-7RWU2HZvxPtfBrvjXKDiQ3F6ZH8k49JhxVkHquUz5UZKjauj5PrP29MvISykThtfpy4mGG6kqxFBHW1ed9wwnA==} peerDependencies: @@ -4205,10 +4268,12 @@ packages: libsql@0.4.7: resolution: {integrity: sha512-T9eIRCs6b0J1SHKYIvD8+KCJMcWZ900iZyxdnSCdqxN12Z1ijzT+jY5nrk72Jw4B0HGzms2NgpryArlJqvc3Lw==} + cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] libsql@0.5.1: resolution: {integrity: sha512-ePnm5zj6T//GKiTY/v5b0a272NX73hqdRORmD8gzz1nUui9051dtTt6t0XCrIqxwJAHSmQiZcfAx3YSASn9Y+A==} + cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] lightningcss-darwin-arm64@1.29.2: @@ -4558,6 +4623,9 @@ packages: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minipass@3.3.6: resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} engines: {node: '>=8'} @@ -4696,6 +4764,13 @@ packages: ohash@2.0.11: resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + on-exit-leak-free@2.1.2: + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} + engines: {node: '>=14.0.0'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + onetime@5.1.2: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} @@ -4863,6 +4938,20 @@ packages: resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} engines: {node: '>=12'} + pino-abstract-transport@2.0.0: + resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} + + pino-pretty@13.1.1: + resolution: {integrity: sha512-TNNEOg0eA0u+/WuqH0MH0Xui7uqVk9D74ESOpjtebSQYbNWJk/dIxCXIxFsNfeN53JmtWqYHP2OrIZjT/CBEnA==} + hasBin: true + + pino-std-serializers@7.0.0: + resolution: {integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==} + + pino@9.9.4: + resolution: {integrity: sha512-d1XorUQ7sSKqVcYdXuEYs2h1LKxejSorMEJ76XoZ0pPDf8VzJMe7GlPXpMBZeQ9gE4ZPIp5uGD+5Nw7scxiigg==} + hasBin: true + pirates@4.0.6: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} @@ -4956,6 +5045,9 @@ packages: process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + process-warning@5.0.0: + resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} + progress-stream@2.0.0: resolution: {integrity: sha512-xJwOWR46jcXUq6EH9yYyqp+I52skPySOeHfkxOZ2IY1AiBi/sFJhbhAKHoV3OTw/omQ45KTio9215dRJ2Yxd3Q==} @@ -4979,6 +5071,9 @@ packages: proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + pump@3.0.3: + resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -4997,6 +5092,9 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + radix3@1.1.2: resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} @@ -5022,6 +5120,10 @@ packages: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} + real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + recma-build-jsx@1.0.0: resolution: {integrity: sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==} @@ -5155,6 +5257,10 @@ packages: safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} + engines: {node: '>=10'} + safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -5164,6 +5270,9 @@ packages: secure-json-parse@2.7.0: resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + secure-json-parse@4.0.0: + resolution: {integrity: sha512-dxtLJO6sc35jWidmLxo7ij+Eg48PM/kleBsxpC8QJE0qJICe+KawkDQmvCMZUr9u7WKVHgMW6vy3fQ7zMiFZMA==} + semver@7.7.1: resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} engines: {node: '>=10'} @@ -5228,6 +5337,9 @@ packages: snappyjs@0.6.1: resolution: {integrity: sha512-YIK6I2lsH072UE0aOFxxY1dPDCS43I5ktqHpeAsuLNYWkE5pGxRGWfDM4/vSUfNzXjC1Ivzt3qx31PCLmc9yqg==} + sonic-boom@4.2.0: + resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -5246,6 +5358,7 @@ packages: source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} + deprecated: The work that was done in this beta branch won't be included in future versions space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} @@ -5313,6 +5426,10 @@ packages: resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} engines: {node: '>=12'} + strip-json-comments@5.0.3: + resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} + engines: {node: '>=14.16'} + style-to-js@1.1.16: resolution: {integrity: sha512-/Q6ld50hKYPH3d/r6nr117TZkHR0w0kGGIVfpG9N6D8NymRPM9RqCUv4pRpJ62E5DqOYx2AFpbZMyCPnjQCnOw==} @@ -5352,6 +5469,9 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + thread-stream@3.1.0: + resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} + thrift@0.11.0: resolution: {integrity: sha512-UpsBhOC45a45TpeHOXE4wwYwL8uD2apbHTbtBvkwtUU4dNwCjC7DpQTjw2Q6eIdfNtw+dKthdwq94uLXTJPfFw==} engines: {node: '>= 4.1.0'} @@ -5409,9 +5529,6 @@ packages: typescript: optional: true - tslib@2.7.0: - resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} - tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -5852,6 +5969,9 @@ packages: resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} engines: {node: '>=18'} + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + ws@8.18.0: resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} @@ -6237,13 +6357,13 @@ snapshots: '@clack/core@0.3.4': dependencies: - picocolors: 1.0.1 + picocolors: 1.1.1 sisteransi: 1.0.5 '@clack/prompts@0.7.0': dependencies: '@clack/core': 0.3.4 - picocolors: 1.0.1 + picocolors: 1.1.1 sisteransi: 1.0.5 '@cloudflare/kv-asset-handler@0.4.0': @@ -6306,12 +6426,12 @@ snapshots: '@emnapi/core@0.45.0': dependencies: - tslib: 2.7.0 + tslib: 2.8.1 optional: true '@emnapi/runtime@0.45.0': dependencies: - tslib: 2.7.0 + tslib: 2.8.1 optional: true '@emnapi/runtime@1.3.1': @@ -7612,6 +7732,8 @@ snapshots: '@oslojs/encoding@1.1.0': {} + '@oslojs/oauth2@0.5.0': {} + '@pagefind/darwin-arm64@1.3.0': optional: true @@ -7823,7 +7945,7 @@ snapshots: '@tybys/wasm-util@0.8.3': dependencies: - tslib: 2.7.0 + tslib: 2.8.1 optional: true '@types/debug@4.1.12': @@ -7866,12 +7988,12 @@ snapshots: '@types/node-fetch@2.6.11': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.13.10 form-data: 4.0.0 '@types/node-int64@0.4.32': dependencies: - '@types/node': 22.13.1 + '@types/node': 22.13.10 '@types/node@17.0.45': {} @@ -7879,10 +8001,6 @@ snapshots: dependencies: undici-types: 5.26.5 - '@types/node@22.13.1': - dependencies: - undici-types: 6.20.0 - '@types/node@22.13.10': dependencies: undici-types: 6.20.0 @@ -7908,7 +8026,7 @@ snapshots: '@types/pg@8.11.6': dependencies: - '@types/node': 22.13.1 + '@types/node': 22.13.10 pg-protocol: 1.7.0 pg-types: 4.0.2 @@ -7916,7 +8034,7 @@ snapshots: '@types/progress-stream@2.0.5': dependencies: - '@types/node': 22.13.1 + '@types/node': 22.13.10 '@types/sax@1.2.7': dependencies: @@ -7930,7 +8048,7 @@ snapshots: '@types/ws@8.5.14': dependencies: - '@types/node': 22.13.1 + '@types/node': 22.13.10 '@ungap/structured-clone@1.3.0': {} @@ -8237,6 +8355,8 @@ snapshots: asynckit@0.4.0: {} + atomic-sleep@1.0.0: {} + axios@1.7.9: dependencies: follow-redirects: 1.15.9 @@ -8384,6 +8504,8 @@ snapshots: color-convert: 2.0.1 color-string: 1.9.1 + colorette@2.0.20: {} + combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 @@ -8439,6 +8561,8 @@ snapshots: data-uri-to-buffer@4.0.1: {} + dateformat@4.6.3: {} + debug@4.3.6: dependencies: ms: 2.1.2 @@ -8617,6 +8741,10 @@ snapshots: iconv-lite: 0.6.3 optional: true + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + entities@4.5.0: {} entities@6.0.0: {} @@ -8907,6 +9035,10 @@ snapshots: merge2: 1.4.1 micromatch: 4.0.7 + fast-redact@3.5.0: {} + + fast-safe-stringify@2.1.1: {} + fast-uri@3.0.6: {} fastq@1.17.1: @@ -9254,6 +9386,8 @@ snapshots: property-information: 7.1.0 space-separated-tokens: 2.0.2 + help-me@5.0.0: {} + hono-rate-limiter@0.4.0(hono@4.6.11): dependencies: hono: 4.6.11 @@ -10059,6 +10193,8 @@ snapshots: dependencies: brace-expansion: 2.0.1 + minimist@1.2.8: {} + minipass@3.3.6: dependencies: yallist: 4.0.0 @@ -10177,6 +10313,12 @@ snapshots: ohash@2.0.11: {} + on-exit-leak-free@2.1.2: {} + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + onetime@5.1.2: dependencies: mimic-fn: 2.1.0 @@ -10370,6 +10512,42 @@ snapshots: picomatch@4.0.2: {} + pino-abstract-transport@2.0.0: + dependencies: + split2: 4.2.0 + + pino-pretty@13.1.1: + dependencies: + colorette: 2.0.20 + dateformat: 4.6.3 + fast-copy: 3.0.2 + fast-safe-stringify: 2.1.1 + help-me: 5.0.0 + joycon: 3.1.1 + minimist: 1.2.8 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pump: 3.0.3 + secure-json-parse: 4.0.0 + sonic-boom: 4.2.0 + strip-json-comments: 5.0.3 + + pino-std-serializers@7.0.0: {} + + pino@9.9.4: + dependencies: + atomic-sleep: 1.0.0 + fast-redact: 3.5.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.0.0 + process-warning: 5.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.0 + thread-stream: 3.1.0 + pirates@4.0.6: {} pkg-types@1.1.3: @@ -10437,6 +10615,8 @@ snapshots: process-nextick-args@2.0.1: {} + process-warning@5.0.0: {} + progress-stream@2.0.0: dependencies: speedometer: 1.0.0 @@ -10465,11 +10645,16 @@ snapshots: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 - '@types/node': 22.13.1 + '@types/node': 22.13.10 long: 5.3.0 proxy-from-env@1.1.0: {} + pump@3.0.3: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + punycode@2.3.1: {} pure-rand@6.1.0: {} @@ -10478,6 +10663,8 @@ snapshots: queue-microtask@1.2.3: {} + quick-format-unescaped@4.0.4: {} + radix3@1.1.2: {} railroad-diagrams@1.0.0: {} @@ -10507,6 +10694,8 @@ snapshots: readdirp@4.1.2: {} + real-require@0.2.0: {} + recma-build-jsx@1.0.0: dependencies: '@types/estree': 1.0.6 @@ -10750,6 +10939,8 @@ snapshots: safe-buffer@5.1.2: {} + safe-stable-stringify@2.5.0: {} + safer-buffer@2.1.2: optional: true @@ -10757,6 +10948,8 @@ snapshots: secure-json-parse@2.7.0: {} + secure-json-parse@4.0.0: {} + semver@7.7.1: {} sharp@0.33.5: @@ -10861,6 +11054,10 @@ snapshots: snappyjs@0.6.1: {} + sonic-boom@4.2.0: + dependencies: + atomic-sleep: 1.0.0 + source-map-js@1.2.1: {} source-map-support@0.5.21: @@ -10940,6 +11137,8 @@ snapshots: strip-final-newline@3.0.0: {} + strip-json-comments@5.0.3: {} + style-to-js@1.1.16: dependencies: style-to-object: 1.0.8 @@ -11003,6 +11202,10 @@ snapshots: dependencies: any-promise: 1.3.0 + thread-stream@3.1.0: + dependencies: + real-require: 0.2.0 + thrift@0.11.0: dependencies: node-int64: 0.4.0 @@ -11070,9 +11273,6 @@ snapshots: optionalDependencies: typescript: 5.7.3 - tslib@2.7.0: - optional: true - tslib@2.8.1: {} tsup@8.2.4(jiti@2.4.2)(postcss@8.5.3)(tsx@4.19.2)(typescript@5.7.3)(yaml@2.7.0): @@ -11086,7 +11286,7 @@ snapshots: execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 - picocolors: 1.0.1 + picocolors: 1.1.1 postcss-load-config: 6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.19.2)(yaml@2.7.0) resolve-from: 5.0.0 rollup: 4.20.0 @@ -11478,6 +11678,8 @@ snapshots: string-width: 7.2.0 strip-ansi: 7.1.0 + wrappy@1.0.2: {} + ws@8.18.0: {} xtend@4.0.2: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 192f4a3..cda37b1 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,4 +2,5 @@ packages: - "ascuii" - "cli" - "docs" - - "examples/*" \ No newline at end of file + - "examples/*" + - "create-fiberplane" \ No newline at end of file