@spike-forms/cli 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +22 -1686
- package/package.json +2 -2
- package/dist/index.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spike-forms/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Command-line interface for the Spike Forms API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"author": "",
|
|
30
30
|
"license": "MIT",
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@spike-forms/sdk": "
|
|
32
|
+
"@spike-forms/sdk": "workspace:*",
|
|
33
33
|
"chalk": "^5.4.1",
|
|
34
34
|
"commander": "^13.1.0"
|
|
35
35
|
},
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config.ts","../src/output.ts","../src/commands/config.ts","../src/server/live-preview-server.ts","../src/utils/browser.ts","../src/commands/forms.ts","../src/commands/submissions.ts","../src/commands/projects.ts","../src/commands/teams.ts","../src/commands/user.ts","../src/utils/state.ts","../src/server/callback.ts","../src/commands/login.ts","../src/commands/agent.ts","../src/index.ts"],"names":["os","path","fs","resolve","path2","fs2","error","Command","handleGet","createClient","SpikeClient","handleError","SpikeError","handleList","handleCreate","handleUpdate","handleDelete","http2","os3","path4","fs4","spawn"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * CLI Configuration Manager\n *\n * Handles loading and saving CLI configuration from:\n * 1. Environment variables (SPIKE_API_KEY, SPIKE_TOKEN, SPIKE_API_URL)\n * 2. Config file (~/.spike/config.json)\n *\n * Environment variables take priority over config file values.\n * For API key, SPIKE_API_KEY takes priority over SPIKE_TOKEN.\n *\n * @module config\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\n\n/**\n * CLI configuration interface\n */\nexport interface CLIConfig {\n apiKey: string;\n baseUrl: string;\n}\n\n/**\n * Default configuration values\n */\nconst DEFAULT_CONFIG: CLIConfig = {\n apiKey: '',\n baseUrl: 'https://api.spike.ac',\n};\n\n/**\n * Environment variable names\n */\nconst ENV_VARS = {\n API_KEY: 'SPIKE_API_KEY',\n TOKEN: 'SPIKE_TOKEN',\n API_URL: 'SPIKE_API_URL',\n} as const;\n\n/**\n * Gets the path to the config file.\n *\n * @returns The absolute path to ~/.spike/config.json\n *\n * @example\n * ```typescript\n * const configPath = getConfigPath();\n * // Returns: /home/user/.spike/config.json (on Linux)\n * // Returns: C:\\Users\\user\\.spike\\config.json (on Windows)\n * ```\n */\nexport function getConfigPath(): string {\n const homeDir = os.homedir();\n return path.join(homeDir, '.spike', 'config.json');\n}\n\n/**\n * Gets the path to the config directory.\n *\n * @returns The absolute path to ~/.spike/\n */\nfunction getConfigDir(): string {\n const homeDir = os.homedir();\n return path.join(homeDir, '.spike');\n}\n\n/**\n * Loads configuration from the config file.\n *\n * @returns The configuration from file, or empty object if file doesn't exist\n */\nfunction loadConfigFromFile(): Partial<CLIConfig> {\n const configPath = getConfigPath();\n\n try {\n if (!fs.existsSync(configPath)) {\n return {};\n }\n\n const fileContent = fs.readFileSync(configPath, 'utf-8');\n const parsed = JSON.parse(fileContent);\n\n // Validate and extract only known config keys\n const config: Partial<CLIConfig> = {};\n\n if (typeof parsed.apiKey === 'string') {\n config.apiKey = parsed.apiKey;\n }\n\n if (typeof parsed.baseUrl === 'string') {\n config.baseUrl = parsed.baseUrl;\n }\n\n return config;\n } catch {\n // If file doesn't exist or is invalid JSON, return empty config\n return {};\n }\n}\n\n/**\n * Loads configuration from environment variables.\n *\n * Checks SPIKE_API_KEY first, then SPIKE_TOKEN as a fallback for the API key.\n *\n * @returns The configuration from environment variables\n */\nfunction loadConfigFromEnv(): Partial<CLIConfig> {\n const config: Partial<CLIConfig> = {};\n\n // Check SPIKE_API_KEY first, then SPIKE_TOKEN as fallback\n const apiKey = process.env[ENV_VARS.API_KEY] || process.env[ENV_VARS.TOKEN];\n if (apiKey) {\n config.apiKey = apiKey;\n }\n\n const apiUrl = process.env[ENV_VARS.API_URL];\n if (apiUrl) {\n config.baseUrl = apiUrl;\n }\n\n return config;\n}\n\n/**\n * Loads the CLI configuration.\n *\n * Configuration is loaded from multiple sources with the following priority:\n * 1. Environment variables (highest priority)\n * 2. Config file (~/.spike/config.json)\n * 3. Default values (lowest priority)\n *\n * For API key, the priority is: SPIKE_API_KEY > SPIKE_TOKEN > config file\n *\n * @returns The merged configuration\n *\n * @example\n * ```typescript\n * const config = loadConfig();\n * console.log(config.apiKey); // From env var or config file\n * console.log(config.baseUrl); // From env var, config file, or default\n * ```\n *\n * @remarks\n * - Environment variables: SPIKE_API_KEY, SPIKE_TOKEN, SPIKE_API_URL\n * - Config file: ~/.spike/config.json\n * - Default baseUrl: https://api.spike.ac\n */\nexport function loadConfig(): CLIConfig {\n // Load from file first (lower priority)\n const fileConfig = loadConfigFromFile();\n\n // Load from environment variables (higher priority)\n const envConfig = loadConfigFromEnv();\n\n // Merge with priority: env > file > defaults\n return {\n ...DEFAULT_CONFIG,\n ...fileConfig,\n ...envConfig,\n };\n}\n\n/**\n * Saves configuration to the config file.\n *\n * Creates the ~/.spike directory if it doesn't exist.\n * Merges the provided config with existing config file values.\n *\n * @param config - Partial configuration to save\n *\n * @example\n * ```typescript\n * // Save API key\n * saveConfig({ apiKey: 'sk_test_123' });\n *\n * // Save custom base URL\n * saveConfig({ baseUrl: 'https://custom.spike.ac' });\n *\n * // Save multiple values\n * saveConfig({ apiKey: 'sk_test_123', baseUrl: 'https://custom.spike.ac' });\n * ```\n *\n * @throws {Error} If unable to create directory or write file\n */\nexport function saveConfig(config: Partial<CLIConfig>): void {\n const configDir = getConfigDir();\n const configPath = getConfigPath();\n\n // Create the config directory if it doesn't exist\n if (!fs.existsSync(configDir)) {\n fs.mkdirSync(configDir, { recursive: true });\n }\n\n // Load existing config from file (not env vars)\n const existingConfig = loadConfigFromFile();\n\n // Merge with new config\n const mergedConfig: Partial<CLIConfig> = {\n ...existingConfig,\n ...config,\n };\n\n // Remove undefined values\n const cleanConfig: Record<string, string> = {};\n if (mergedConfig.apiKey) {\n cleanConfig.apiKey = mergedConfig.apiKey;\n }\n if (mergedConfig.baseUrl) {\n cleanConfig.baseUrl = mergedConfig.baseUrl;\n }\n\n // Write to file with pretty formatting\n fs.writeFileSync(configPath, JSON.stringify(cleanConfig, null, 2) + '\\n', 'utf-8');\n}\n","/**\n * CLI Output Formatter\n *\n * Provides utilities for formatting CLI output in different formats (JSON, table)\n * and colored message functions for success, error, warning, and info messages.\n *\n * @module output\n */\n\nimport chalk from 'chalk';\n\n/**\n * Output format type\n */\nexport type OutputFormat = 'json' | 'table';\n\n/**\n * Outputs data in the specified format.\n *\n * @param data - The data to output\n * @param format - The output format ('json' or 'table')\n *\n * @example\n * ```typescript\n * // JSON output\n * output({ name: 'My Form', id: '123' }, 'json');\n * // Outputs: {\"name\":\"My Form\",\"id\":\"123\"}\n *\n * // Table output for array\n * output([{ name: 'Form 1', id: '1' }, { name: 'Form 2', id: '2' }], 'table');\n * // Outputs formatted table\n * ```\n */\nexport function output(data: unknown, format: OutputFormat = 'table'): void {\n if (format === 'json') {\n outputJson(data);\n } else {\n outputTable(data);\n }\n}\n\n/**\n * Outputs data as formatted JSON.\n *\n * @param data - The data to output as JSON\n */\nfunction outputJson(data: unknown): void {\n console.log(JSON.stringify(data, null, 2));\n}\n\n/**\n * Outputs data as a formatted table.\n *\n * Handles different data types:\n * - Arrays: Displays as a table with headers from object keys\n * - Objects: Displays as key-value pairs\n * - Primitives: Displays the value directly\n *\n * @param data - The data to output as a table\n */\nfunction outputTable(data: unknown): void {\n if (data === null || data === undefined) {\n console.log('No data');\n return;\n }\n\n if (Array.isArray(data)) {\n outputArrayAsTable(data);\n } else if (typeof data === 'object') {\n outputObjectAsTable(data as Record<string, unknown>);\n } else {\n console.log(String(data));\n }\n}\n\n/**\n * Outputs an array of objects as a formatted table.\n *\n * @param data - Array of objects to display\n */\nfunction outputArrayAsTable(data: unknown[]): void {\n if (data.length === 0) {\n console.log('No items found');\n return;\n }\n\n // Get all unique keys from all objects\n const keys = new Set<string>();\n for (const item of data) {\n if (item && typeof item === 'object') {\n Object.keys(item).forEach((key) => keys.add(key));\n }\n }\n\n const columns = Array.from(keys);\n\n if (columns.length === 0) {\n // If no object keys, just output the values\n data.forEach((item) => console.log(String(item)));\n return;\n }\n\n // Calculate column widths\n const columnWidths = new Map<string, number>();\n for (const col of columns) {\n let maxWidth = col.length;\n for (const item of data) {\n if (item && typeof item === 'object') {\n const value = formatCellValue((item as Record<string, unknown>)[col]);\n maxWidth = Math.max(maxWidth, value.length);\n }\n }\n // Cap column width at 50 characters for readability\n columnWidths.set(col, Math.min(maxWidth, 50));\n }\n\n // Print header\n const headerRow = columns\n .map((col) => padRight(col.toUpperCase(), columnWidths.get(col)!))\n .join(' ');\n console.log(chalk.bold(headerRow));\n\n // Print separator\n const separator = columns\n .map((col) => '-'.repeat(columnWidths.get(col)!))\n .join(' ');\n console.log(separator);\n\n // Print rows\n for (const item of data) {\n if (item && typeof item === 'object') {\n const row = columns\n .map((col) => {\n const value = formatCellValue((item as Record<string, unknown>)[col]);\n return padRight(truncate(value, columnWidths.get(col)!), columnWidths.get(col)!);\n })\n .join(' ');\n console.log(row);\n }\n }\n\n // Print count\n console.log('');\n console.log(chalk.dim(`${data.length} item${data.length === 1 ? '' : 's'}`));\n}\n\n/**\n * Outputs a single object as key-value pairs.\n *\n * @param data - Object to display\n */\nfunction outputObjectAsTable(data: Record<string, unknown>): void {\n const entries = Object.entries(data);\n\n if (entries.length === 0) {\n console.log('No data');\n return;\n }\n\n // Calculate max key length for alignment\n const maxKeyLength = Math.max(...entries.map(([key]) => key.length));\n\n for (const [key, value] of entries) {\n const formattedKey = chalk.bold(padRight(key, maxKeyLength));\n const formattedValue = formatCellValue(value);\n console.log(`${formattedKey} ${formattedValue}`);\n }\n}\n\n/**\n * Formats a cell value for table display.\n *\n * @param value - The value to format\n * @returns Formatted string representation\n */\nfunction formatCellValue(value: unknown): string {\n if (value === null || value === undefined) {\n return '-';\n }\n\n if (typeof value === 'boolean') {\n return value ? chalk.green('yes') : chalk.dim('no');\n }\n\n if (typeof value === 'object') {\n if (Array.isArray(value)) {\n return `[${value.length} items]`;\n }\n return JSON.stringify(value);\n }\n\n return String(value);\n}\n\n/**\n * Pads a string to the right with spaces.\n *\n * @param str - String to pad\n * @param length - Target length\n * @returns Padded string\n */\nfunction padRight(str: string, length: number): string {\n // Strip ANSI codes for length calculation\n const visibleLength = stripAnsi(str).length;\n if (visibleLength >= length) {\n return str;\n }\n return str + ' '.repeat(length - visibleLength);\n}\n\n/**\n * Truncates a string to the specified length.\n *\n * @param str - String to truncate\n * @param maxLength - Maximum length\n * @returns Truncated string with ellipsis if needed\n */\nfunction truncate(str: string, maxLength: number): string {\n const visibleLength = stripAnsi(str).length;\n if (visibleLength <= maxLength) {\n return str;\n }\n return str.slice(0, maxLength - 3) + '...';\n}\n\n/**\n * Strips ANSI escape codes from a string.\n *\n * @param str - String with potential ANSI codes\n * @returns String without ANSI codes\n */\nfunction stripAnsi(str: string): string {\n // eslint-disable-next-line no-control-regex\n return str.replace(/\\x1B\\[[0-9;]*[a-zA-Z]/g, '');\n}\n\n/**\n * Prints a success message in green.\n *\n * @param message - The success message to display\n *\n * @example\n * ```typescript\n * success('Form created successfully');\n * // Outputs: ✓ Form created successfully (in green)\n * ```\n */\nexport function success(message: string): void {\n console.log(chalk.green(`✓ ${message}`));\n}\n\n/**\n * Prints an error message in red.\n *\n * @param message - The error message to display\n *\n * @example\n * ```typescript\n * error('Failed to create form');\n * // Outputs: ✗ Failed to create form (in red)\n * ```\n */\nexport function error(message: string): void {\n console.error(chalk.red(`✗ ${message}`));\n}\n\n/**\n * Prints a warning message in yellow.\n *\n * @param message - The warning message to display\n *\n * @example\n * ```typescript\n * warn('API key will expire soon');\n * // Outputs: ⚠ API key will expire soon (in yellow)\n * ```\n */\nexport function warn(message: string): void {\n console.log(chalk.yellow(`⚠ ${message}`));\n}\n\n/**\n * Prints an info message in cyan.\n *\n * @param message - The info message to display\n *\n * @example\n * ```typescript\n * info('Loading configuration...');\n * // Outputs: ℹ Loading configuration... (in cyan)\n * ```\n */\nexport function info(message: string): void {\n console.log(chalk.cyan(`ℹ ${message}`));\n}\n\n/**\n * Masks an API key for display, showing only the first 7 and last 4 characters.\n *\n * This is used when displaying API keys to prevent accidental exposure\n * while still allowing identification of the key.\n *\n * @param apiKey - The API key to mask\n * @returns The masked API key (e.g., \"sk_test_...abc1\")\n *\n * @example\n * ```typescript\n * maskApiKey('sk_test_1234567890abcdef');\n * // Returns: 'sk_test_...cdef'\n *\n * maskApiKey('sk_live_abcdefghijklmnop');\n * // Returns: 'sk_live...mnop'\n * ```\n *\n * @remarks\n * - If the API key is shorter than 11 characters, returns the key with partial masking\n * - The first 7 characters typically include the key prefix (e.g., \"sk_test_\" or \"sk_live_\")\n * - The last 4 characters help identify which key is being referenced\n */\nexport function maskApiKey(apiKey: string): string {\n if (!apiKey) {\n return '';\n }\n\n // For very short keys, just mask most of it\n if (apiKey.length <= 11) {\n const visibleStart = Math.min(4, apiKey.length - 1);\n return apiKey.slice(0, visibleStart) + '...';\n }\n\n // Show first 7 characters and last 4 characters\n const prefix = apiKey.slice(0, 7);\n const suffix = apiKey.slice(-4);\n\n return `${prefix}...${suffix}`;\n}\n","/**\n * CLI Config Command\n *\n * Provides commands for managing CLI configuration:\n * - `config set <key> <value>`: Set a configuration value\n * - `config get [key]`: Get configuration value(s)\n *\n * Supported configuration keys:\n * - api-key: The API key for authentication\n * - base-url: The base URL for the API\n *\n * @module commands/config\n */\n\nimport { Command } from 'commander';\nimport { loadConfig, saveConfig, getConfigPath } from '../config.js';\nimport { success, error, info, maskApiKey, output, OutputFormat } from '../output.js';\n\n/**\n * Valid configuration keys that can be set/get\n */\nconst VALID_KEYS = ['api-key', 'base-url'] as const;\ntype ConfigKey = (typeof VALID_KEYS)[number];\n\n/**\n * Maps CLI config keys to internal config property names\n */\nconst KEY_MAP: Record<ConfigKey, 'apiKey' | 'baseUrl'> = {\n 'api-key': 'apiKey',\n 'base-url': 'baseUrl',\n};\n\n/**\n * Checks if a key is a valid configuration key\n *\n * @param key - The key to validate\n * @returns True if the key is valid\n */\nfunction isValidKey(key: string): key is ConfigKey {\n return VALID_KEYS.includes(key as ConfigKey);\n}\n\n/**\n * Creates the config command with set and get subcommands.\n *\n * @returns The configured Commander command\n *\n * @example\n * ```bash\n * # Set API key\n * spike config set api-key sk_test_1234567890\n *\n * # Set base URL\n * spike config set base-url https://custom.spike.ac\n *\n * # Get all configuration\n * spike config get\n *\n * # Get specific configuration value\n * spike config get api-key\n * ```\n */\nexport function createConfigCommand(): Command {\n const configCommand = new Command('config')\n .description('Manage CLI configuration');\n\n // config set <key> <value>\n configCommand\n .command('set')\n .description('Set a configuration value')\n .argument('<key>', `Configuration key (${VALID_KEYS.join(', ')})`)\n .argument('<value>', 'Configuration value')\n .action((key: string, value: string) => {\n handleSet(key, value);\n });\n\n // config get [key]\n configCommand\n .command('get')\n .description('Get configuration value(s)')\n .argument('[key]', `Configuration key (${VALID_KEYS.join(', ')})`)\n .option('-f, --format <format>', 'Output format (json, table)', 'table')\n .action((key: string | undefined, options: { format: string }) => {\n handleGet(key, options.format as OutputFormat);\n });\n\n return configCommand;\n}\n\n/**\n * Handles the `config set` command.\n *\n * @param key - The configuration key to set\n * @param value - The value to set\n */\nfunction handleSet(key: string, value: string): void {\n // Validate the key\n if (!isValidKey(key)) {\n error(`Invalid configuration key: ${key}`);\n info(`Valid keys are: ${VALID_KEYS.join(', ')}`);\n process.exit(1);\n }\n\n // Map the CLI key to the internal property name\n const internalKey = KEY_MAP[key];\n\n // Save the configuration\n try {\n saveConfig({ [internalKey]: value });\n success(`Configuration '${key}' has been set`);\n } catch (err) {\n error(`Failed to save configuration: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n}\n\n/**\n * Handles the `config get` command.\n *\n * @param key - Optional configuration key to get (if not provided, shows all)\n * @param format - Output format\n */\nfunction handleGet(key: string | undefined, format: OutputFormat): void {\n const config = loadConfig();\n\n if (key !== undefined) {\n // Get specific key\n if (!isValidKey(key)) {\n error(`Invalid configuration key: ${key}`);\n info(`Valid keys are: ${VALID_KEYS.join(', ')}`);\n process.exit(1);\n }\n\n const internalKey = KEY_MAP[key];\n let value = config[internalKey];\n\n // Mask API key when displaying\n if (key === 'api-key' && value) {\n value = maskApiKey(value);\n }\n\n if (!value) {\n info(`Configuration '${key}' is not set`);\n return;\n }\n\n if (format === 'json') {\n output({ [key]: value }, format);\n } else {\n console.log(value);\n }\n } else {\n // Get all configuration\n const displayConfig: Record<string, string> = {};\n\n // Add api-key (masked)\n if (config.apiKey) {\n displayConfig['api-key'] = maskApiKey(config.apiKey);\n } else {\n displayConfig['api-key'] = '(not set)';\n }\n\n // Add base-url\n displayConfig['base-url'] = config.baseUrl || '(not set)';\n\n // Show config file path\n info(`Configuration file: ${getConfigPath()}`);\n console.log('');\n\n output(displayConfig, format);\n }\n}\n\nexport default createConfigCommand;\n","/**\n * Live Preview Server\n *\n * Provides an HTTP server for live previewing HTML form templates with\n * Server-Sent Events (SSE) for automatic hot-reload on file changes.\n *\n * @module server/live-preview-server\n */\n\nimport * as http from 'node:http';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\n/**\n * The SSE client script that gets injected into HTML pages.\n * Creates an EventSource connection to /__live-reload and reloads\n * the page when a 'reload' message is received.\n */\nconst SSE_SCRIPT = `<script>\n(function() {\n var es = new EventSource('/__live-reload');\n es.onmessage = function(event) {\n if (event.data === 'reload') {\n location.reload();\n }\n };\n es.onerror = function() {\n console.log('[Live Preview] Connection lost, attempting to reconnect...');\n };\n})();\n</script>`;\n\n/**\n * Inject SSE live-reload script into HTML content.\n *\n * Inserts the SSE client script before the closing `</body>` tag if present,\n * otherwise appends it at the end of the content.\n *\n * @param html - The HTML content to inject the script into\n * @returns The HTML content with the SSE script injected\n *\n * @example\n * ```typescript\n * // With </body> tag\n * const html = '<html><body><h1>Hello</h1></body></html>';\n * const result = injectLiveReload(html);\n * // Result: '<html><body><h1>Hello</h1><script>...</script></body></html>'\n *\n * // Without </body> tag\n * const partial = '<h1>Hello</h1>';\n * const result2 = injectLiveReload(partial);\n * // Result: '<h1>Hello</h1><script>...</script>'\n * ```\n *\n * @remarks\n * - The injection is case-insensitive for the </body> tag\n * - The script creates an EventSource connection to /__live-reload\n * - On receiving a 'reload' message, the page automatically refreshes\n *\n * @see Requirements 4.4 - Preview_Server SHALL inject SSE client script before </body>\n * @see Requirements 4.5 - Preview_Server SHALL append script if no </body> tag\n * @see Requirements 5.4 - Injected script SHALL create EventSource and reload on message\n */\nexport function injectLiveReload(html: string): string {\n // Case-insensitive search for </body> tag\n const bodyCloseRegex = /<\\/body>/i;\n const match = html.match(bodyCloseRegex);\n\n if (match && match.index !== undefined) {\n // Insert script before </body>\n return html.slice(0, match.index) + SSE_SCRIPT + html.slice(match.index);\n }\n\n // No </body> tag found, append at the end\n return html + SSE_SCRIPT;\n}\n\n/**\n * Interface for managing the live preview server.\n */\nexport interface LivePreviewServer {\n /** The port the server is listening on */\n port: number;\n /** Stop the server and clean up resources */\n stop(): Promise<void>;\n}\n\n/**\n * Start a live preview HTTP server for an HTML file.\n *\n * The server:\n * - Serves HTML with injected SSE script on GET /\n * - Provides SSE endpoint at /__live-reload\n * - Watches the file for changes with 100ms debounce\n * - Notifies all connected SSE clients on file change\n * - Manages SSE client list, removing disconnected clients\n *\n * @param filePath - Path to the HTML file to serve\n * @returns Promise resolving to the port the server is listening on\n *\n * @example\n * ```typescript\n * const port = await startLivePreviewServer('./form.html');\n * console.log(`Preview server running at http://127.0.0.1:${port}`);\n * // Edit form.html and the browser will automatically reload\n * ```\n *\n * @remarks\n * - The server binds to 127.0.0.1 only (no external access)\n * - Uses port 0 for OS-assigned dynamic port\n * - File changes are debounced to prevent rapid reloads\n * - SSE clients receive 'connected' on initial connection\n * - SSE clients receive 'reload' when file changes\n *\n * @see Requirements 4.3 - Preview_Server SHALL start HTTP server on 127.0.0.1:0\n * @see Requirements 4.6 - Preview_Server SHALL notify clients within 100ms debounce\n * @see Requirements 5.1 - SSE endpoint SHALL respond with text/event-stream\n * @see Requirements 5.2 - Preview_Server SHALL send reload event on file change\n * @see Requirements 5.3 - Preview_Server SHALL remove disconnected clients\n */\nexport function startLivePreviewServer(filePath: string): Promise<number> {\n return new Promise((resolve, reject) => {\n // Resolve to absolute path\n const absolutePath = path.resolve(filePath);\n\n // SSE client management\n const sseClients: http.ServerResponse[] = [];\n let debounceTimer: NodeJS.Timeout | null = null;\n\n /**\n * Send a message to all connected SSE clients.\n */\n function broadcastToClients(message: string): void {\n const data = `data: ${message}\\n\\n`;\n // Iterate in reverse to safely remove disconnected clients\n for (let i = sseClients.length - 1; i >= 0; i--) {\n const client = sseClients[i];\n if (!client) continue;\n try {\n if (!client.writableEnded) {\n client.write(data);\n } else {\n // Client disconnected, remove from list\n sseClients.splice(i, 1);\n }\n } catch {\n // Error writing to client, remove from list\n sseClients.splice(i, 1);\n }\n }\n }\n\n /**\n * Handle file change events with debouncing.\n */\n function onFileChange(): void {\n // Clear existing debounce timer\n if (debounceTimer) {\n clearTimeout(debounceTimer);\n }\n\n // Set new debounce timer (100ms as per requirements)\n debounceTimer = setTimeout(() => {\n broadcastToClients('reload');\n debounceTimer = null;\n }, 100);\n }\n\n /**\n * Handle incoming HTTP requests.\n */\n function handleRequest(req: http.IncomingMessage, res: http.ServerResponse): void {\n const url = req.url || '/';\n\n // SSE endpoint\n if (url === '/__live-reload') {\n // Set SSE headers\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n 'Access-Control-Allow-Origin': '*',\n });\n\n // Send initial connected message\n res.write('data: connected\\n\\n');\n\n // Add client to list\n sseClients.push(res);\n\n // Remove client on disconnect\n req.on('close', () => {\n const index = sseClients.indexOf(res);\n if (index !== -1) {\n sseClients.splice(index, 1);\n }\n });\n\n return;\n }\n\n // Serve HTML on root path\n if (url === '/' && req.method === 'GET') {\n try {\n const html = fs.readFileSync(absolutePath, 'utf-8');\n const injectedHtml = injectLiveReload(html);\n\n res.writeHead(200, {\n 'Content-Type': 'text/html; charset=utf-8',\n 'Cache-Control': 'no-cache',\n });\n res.end(injectedHtml);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Unknown error';\n res.writeHead(500, { 'Content-Type': 'text/plain' });\n res.end(`Error reading file: ${errorMessage}`);\n }\n return;\n }\n\n // 404 for all other paths\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not Found');\n }\n\n // Create HTTP server\n const server = http.createServer(handleRequest);\n\n server.on('error', (err) => {\n reject(err);\n });\n\n // Start file watcher\n let watcher: fs.FSWatcher | null = null;\n try {\n watcher = fs.watch(absolutePath, (eventType) => {\n if (eventType === 'change') {\n onFileChange();\n }\n });\n\n watcher.on('error', (err) => {\n console.error('[Live Preview] File watcher error:', err.message);\n });\n } catch (err) {\n // File might not exist yet, that's okay - we'll serve an error page\n console.warn('[Live Preview] Could not start file watcher:', err instanceof Error ? err.message : 'Unknown error');\n }\n\n // Bind to 127.0.0.1 only with port 0 for dynamic assignment\n server.listen(0, '127.0.0.1', () => {\n const address = server.address();\n if (address && typeof address === 'object') {\n const port = address.port;\n resolve(port);\n } else {\n reject(new Error('Failed to get server address'));\n }\n });\n });\n}\n","/**\n * Browser Utilities\n *\n * Provides cross-platform browser opening functionality for the CLI.\n * Used during the browser login flow to open the authorization page.\n *\n * @module utils/browser\n */\n\nimport { exec } from 'node:child_process';\nimport { platform } from 'node:os';\n\n/**\n * Opens a URL in the user's default browser.\n *\n * Uses platform-specific commands to open the browser:\n * - macOS: `open <url>`\n * - Linux: `xdg-open <url>`\n * - Windows: `start \"\" \"<url>\"`\n *\n * @param url - The URL to open in the browser\n * @returns A promise that resolves to `true` if the browser opened successfully, `false` otherwise\n *\n * @example\n * ```typescript\n * const success = await openBrowser('http://localhost:3000/authorize');\n * if (!success) {\n * console.log('Please open the URL manually');\n * }\n * ```\n *\n * @remarks\n * - The function is asynchronous and waits for the command to complete\n * - On Windows, the URL is wrapped in quotes to handle special characters\n * - Returns `false` for unsupported platforms or if the command fails\n * - Does not throw errors; failures are indicated by returning `false`\n *\n * @see Requirements 1.2 - CLI shall open the user's default browser\n * @see Requirements 1.3 - CLI shall display URL if browser fails to open\n */\nexport async function openBrowser(url: string): Promise<boolean> {\n const currentPlatform = platform();\n\n let command: string;\n\n switch (currentPlatform) {\n case 'darwin':\n // macOS: use 'open' command\n command = `open \"${url}\"`;\n break;\n case 'linux':\n // Linux: use 'xdg-open' command\n command = `xdg-open \"${url}\"`;\n break;\n case 'win32':\n // Windows: use 'start' command with empty title and quoted URL\n // The empty string \"\" is the window title, required when URL contains special chars\n command = `start \"\" \"${url}\"`;\n break;\n default:\n // Unsupported platform\n return false;\n }\n\n return new Promise<boolean>((resolve) => {\n exec(command, (error) => {\n if (error) {\n resolve(false);\n } else {\n resolve(true);\n }\n });\n });\n}\n","/**\n * CLI Forms Command\n *\n * Provides commands for managing forms:\n * - `forms list`: List all forms with filtering options\n * - `forms get <id>`: Get a specific form by ID\n * - `forms create`: Create a new form\n * - `forms update <id>`: Update a form\n * - `forms delete <id>`: Delete a form\n * - `forms edit <id>`: Edit a form with live preview (fetches HTML from server)\n * - `forms save <id>`: Save local HTML changes to server\n * - `forms stop-preview`: Stop the background preview server\n * - `forms create-page --name <name>`: Create a form and generate HTML page (beta)\n *\n * @module commands/forms\n * @see Requirements 15.1, 15.2, 15.3, 15.4, 15.5, 3.1, 3.2, 3.3, 3.4, 3.5, 4.1, 4.2, 4.7, 4.8, 4.9, 4.10, 4.11\n */\n\nimport { Command } from 'commander';\nimport { SpikeClient, SpikeError } from '@spike-forms/sdk';\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { spawn } from 'node:child_process';\nimport { loadConfig } from '../config.js';\nimport { output, success, error, info, OutputFormat } from '../output.js';\nimport { startLivePreviewServer } from '../server/live-preview-server.js';\nimport { openBrowser } from '../utils/browser.js';\n\n/**\n * Creates a SpikeClient instance using the loaded configuration.\n *\n * @returns A configured SpikeClient instance\n * @throws Error if API key is not configured\n */\nfunction createClient(): SpikeClient {\n const config = loadConfig();\n\n if (!config.apiKey) {\n error('API key not configured. Run `spike config set api-key <your-key>` to set it.');\n process.exit(1);\n }\n\n return new SpikeClient({\n apiKey: config.apiKey,\n baseUrl: config.baseUrl,\n });\n}\n\n/**\n * Handles errors from SDK operations.\n *\n * @param err - The error to handle\n */\nfunction handleError(err: unknown): never {\n if (err instanceof SpikeError) {\n error(err.message);\n if (err.code) {\n info(`Error code: ${err.code}`);\n }\n } else if (err instanceof Error) {\n error(err.message);\n } else {\n error('An unexpected error occurred');\n }\n process.exit(1);\n}\n\n/**\n * Temp file paths for background preview server.\n */\nconst PREVIEW_PID_FILE = path.join(os.tmpdir(), 'spike-preview.pid');\nconst PREVIEW_PORT_FILE = path.join(os.tmpdir(), 'spike-preview.port');\nconst PREVIEW_FORM_ID_FILE = path.join(os.tmpdir(), 'spike-preview.formid');\n\n/**\n * Generates default HTML form page content for a form.\n * Used as fallback when no HTML exists on server.\n *\n * @param form - The form object with slug and name\n * @returns HTML string with form template\n */\nfunction generateFormHtml(form: { slug: string; name: string }): string {\n const config = loadConfig();\n const baseUrl = config.baseUrl || 'https://api.spike.ac';\n const actionUrl = `${baseUrl}/f/${form.slug}`;\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${form.name}</title>\n <style>\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n max-width: 600px;\n margin: 40px auto;\n padding: 20px;\n background: #f5f5f5;\n }\n form {\n background: white;\n padding: 30px;\n border-radius: 8px;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n }\n h1 {\n margin-top: 0;\n color: #333;\n }\n label {\n display: block;\n margin-bottom: 5px;\n font-weight: 500;\n color: #555;\n }\n input, textarea {\n width: 100%;\n padding: 10px;\n margin-bottom: 20px;\n border: 1px solid #ddd;\n border-radius: 4px;\n box-sizing: border-box;\n font-size: 16px;\n }\n textarea {\n min-height: 100px;\n resize: vertical;\n }\n button {\n background: #0070f3;\n color: white;\n padding: 12px 24px;\n border: none;\n border-radius: 4px;\n font-size: 16px;\n cursor: pointer;\n transition: background 0.2s;\n }\n button:hover {\n background: #0051a8;\n }\n </style>\n</head>\n<body>\n <form action=\"${actionUrl}\" method=\"POST\">\n <h1>${form.name}</h1>\n \n <label for=\"name\">Name</label>\n <input type=\"text\" id=\"name\" name=\"name\" required>\n \n <label for=\"email\">Email</label>\n <input type=\"email\" id=\"email\" name=\"email\" required>\n \n <label for=\"message\">Message</label>\n <textarea id=\"message\" name=\"message\" required></textarea>\n \n <button type=\"submit\">Submit</button>\n </form>\n</body>\n</html>`;\n}\n\n/**\n * Kills an existing background preview server if running.\n * Reads PID from temp file and sends SIGTERM.\n *\n * @returns true if a server was killed, false otherwise\n */\nfunction killExistingPreviewServer(): boolean {\n try {\n if (!fs.existsSync(PREVIEW_PID_FILE)) {\n return false;\n }\n\n const pidStr = fs.readFileSync(PREVIEW_PID_FILE, 'utf-8').trim();\n const pid = parseInt(pidStr, 10);\n\n if (isNaN(pid)) {\n // Invalid PID, clean up the file\n cleanupPreviewTempFiles();\n return false;\n }\n\n // Try to kill the process\n try {\n process.kill(pid, 'SIGTERM');\n info(`Stopped existing preview server (PID: ${pid})`);\n } catch {\n // Process might not exist anymore, that's okay\n }\n\n // Clean up temp files\n cleanupPreviewTempFiles();\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Cleans up preview server temp files.\n */\nfunction cleanupPreviewTempFiles(): void {\n try {\n if (fs.existsSync(PREVIEW_PID_FILE)) {\n fs.unlinkSync(PREVIEW_PID_FILE);\n }\n } catch {\n // Ignore errors\n }\n try {\n if (fs.existsSync(PREVIEW_PORT_FILE)) {\n fs.unlinkSync(PREVIEW_PORT_FILE);\n }\n } catch {\n // Ignore errors\n }\n try {\n if (fs.existsSync(PREVIEW_FORM_ID_FILE)) {\n fs.unlinkSync(PREVIEW_FORM_ID_FILE);\n }\n } catch {\n // Ignore errors\n }\n}\n\n/**\n * Creates the forms command with all subcommands.\n *\n * @returns The configured Commander command\n *\n * @example\n * ```bash\n * # List all forms\n * spike forms list\n *\n * # List forms with options\n * spike forms list --limit 10 --project-id proj_123 --include-inactive\n *\n * # Get a specific form\n * spike forms get form_123\n *\n * # Create a new form\n * spike forms create --name \"Contact Form\"\n * spike forms create --name \"Feedback\" --project-id proj_123\n *\n * # Update a form\n * spike forms update form_123 --name \"New Name\"\n * spike forms update form_123 --is-active false\n *\n * # Delete a form\n * spike forms delete form_123\n * ```\n */\nexport function createFormsCommand(): Command {\n const formsCommand = new Command('forms')\n .description('Manage forms');\n\n // forms list\n formsCommand\n .command('list')\n .description('List all forms')\n .option('-l, --limit <number>', 'Maximum number of forms to return', parseInt)\n .option('-p, --project-id <id>', 'Filter forms by project ID')\n .option('-i, --include-inactive', 'Include inactive forms in the results')\n .option('-f, --format <format>', 'Output format (json, table)', 'table')\n .action(async (options: {\n limit?: number;\n projectId?: string;\n includeInactive?: boolean;\n format: string;\n }) => {\n await handleList(options);\n });\n\n // forms get <id>\n formsCommand\n .command('get')\n .description('Get a specific form by ID')\n .argument('<id>', 'Form ID')\n .option('-f, --format <format>', 'Output format (json, table)', 'table')\n .action(async (id: string, options: { format: string }) => {\n await handleGet(id, options.format as OutputFormat);\n });\n\n // forms create\n formsCommand\n .command('create')\n .description('Create a new form')\n .requiredOption('-n, --name <name>', 'Name for the form')\n .option('-p, --project-id <id>', 'Project ID to add the form to')\n .option('-f, --format <format>', 'Output format (json, table)', 'table')\n .action(async (options: {\n name: string;\n projectId?: string;\n format: string;\n }) => {\n await handleCreate(options);\n });\n\n // forms update <id>\n formsCommand\n .command('update')\n .description('Update a form')\n .argument('<id>', 'Form ID')\n .option('-n, --name <name>', 'New name for the form')\n .option('-p, --project-id <id>', 'Project ID to move the form to')\n .option('--is-active <boolean>', 'Whether the form should be active', (value) => {\n if (value === 'true') return true;\n if (value === 'false') return false;\n throw new Error('--is-active must be \"true\" or \"false\"');\n })\n .option('-f, --format <format>', 'Output format (json, table)', 'table')\n .action(async (id: string, options: {\n name?: string;\n projectId?: string;\n isActive?: boolean;\n format: string;\n }) => {\n await handleUpdate(id, options);\n });\n\n // forms delete <id>\n formsCommand\n .command('delete')\n .description('Delete a form')\n .argument('<id>', 'Form ID')\n .action(async (id: string) => {\n await handleDelete(id);\n });\n\n // forms edit <id>\n formsCommand\n .command('edit')\n .description('Edit a form with live preview')\n .argument('<id>', 'Form ID')\n .option('--file <path>', 'Output file path for the HTML', './form.html')\n .option('--background', 'Run preview server as a detached background process')\n .action(async (id: string, options: {\n file: string;\n background?: boolean;\n }) => {\n await handleEdit(id, options);\n });\n\n // forms stop-preview\n formsCommand\n .command('stop-preview')\n .description('Stop the background preview server')\n .action(async () => {\n await handleStopPreview();\n });\n\n // forms save <id>\n formsCommand\n .command('save')\n .description('Save local HTML changes to server')\n .argument('[id]', 'Form ID (optional if preview server is running)')\n .option('--file <path>', 'Path to the HTML file', './form.html')\n .action(async (id: string | undefined, options: { file: string }) => {\n await handleSave(id, options);\n });\n\n // forms create-page --name <name>\n formsCommand\n .command('create-page')\n .description('Create a new form and generate an HTML form page (beta)')\n .requiredOption('-n, --name <name>', 'Name for the form')\n .option('-p, --project-id <id>', 'Project ID to add the form to')\n .option('--file <path>', 'Output file path for the HTML', './form.html')\n .option('--preview', 'Start preview server after creation')\n .action(async (options: {\n name: string;\n projectId?: string;\n file: string;\n preview?: boolean;\n }) => {\n await handleCreatePage(options);\n });\n\n return formsCommand;\n}\n\n/**\n * Handles the `forms list` command.\n *\n * @param options - Command options\n * @see Requirements 15.1\n */\nasync function handleList(options: {\n limit?: number;\n projectId?: string;\n includeInactive?: boolean;\n format: string;\n}): Promise<void> {\n try {\n const client = createClient();\n\n const forms = await client.forms.list({\n limit: options.limit,\n project_id: options.projectId,\n include_inactive: options.includeInactive,\n });\n\n if (forms.length === 0) {\n info('No forms found');\n return;\n }\n\n output(forms, options.format as OutputFormat);\n } catch (err) {\n handleError(err);\n }\n}\n\n/**\n * Handles the `forms get <id>` command.\n *\n * @param id - Form ID\n * @param format - Output format\n * @see Requirements 15.2\n */\nasync function handleGet(id: string, format: OutputFormat): Promise<void> {\n try {\n const client = createClient();\n const form = await client.forms.get(id);\n output(form, format);\n } catch (err) {\n handleError(err);\n }\n}\n\n/**\n * Handles the `forms create` command.\n *\n * @param options - Command options\n * @see Requirements 15.3\n */\nasync function handleCreate(options: {\n name: string;\n projectId?: string;\n format: string;\n}): Promise<void> {\n try {\n const client = createClient();\n\n const form = await client.forms.create({\n name: options.name,\n project_id: options.projectId,\n });\n\n success(`Form \"${form.name}\" created successfully`);\n console.log('');\n output(form, options.format as OutputFormat);\n } catch (err) {\n handleError(err);\n }\n}\n\n/**\n * Handles the `forms update <id>` command.\n *\n * @param id - Form ID\n * @param options - Command options\n * @see Requirements 15.4\n */\nasync function handleUpdate(id: string, options: {\n name?: string;\n projectId?: string;\n isActive?: boolean;\n format: string;\n}): Promise<void> {\n try {\n // Check if any update options were provided\n if (options.name === undefined && options.projectId === undefined && options.isActive === undefined) {\n error('No update options provided. Use --name, --project-id, or --is-active to update the form.');\n process.exit(1);\n }\n\n const client = createClient();\n\n const updateData: {\n name?: string;\n project_id?: string | null;\n is_active?: boolean;\n } = {};\n\n if (options.name !== undefined) {\n updateData.name = options.name;\n }\n\n if (options.projectId !== undefined) {\n updateData.project_id = options.projectId;\n }\n\n if (options.isActive !== undefined) {\n updateData.is_active = options.isActive;\n }\n\n const form = await client.forms.update(id, updateData);\n\n success(`Form \"${form.name}\" updated successfully`);\n console.log('');\n output(form, options.format as OutputFormat);\n } catch (err) {\n handleError(err);\n }\n}\n\n/**\n * Handles the `forms delete <id>` command.\n *\n * @param id - Form ID\n * @see Requirements 15.5\n */\nasync function handleDelete(id: string): Promise<void> {\n try {\n const client = createClient();\n await client.forms.delete(id);\n success(`Form \"${id}\" deleted successfully`);\n } catch (err) {\n handleError(err);\n }\n}\n\n/**\n * Handles the `forms stop-preview` command.\n *\n * Reads PID from temp file, sends SIGTERM to the preview server process,\n * and cleans up temp files. Handles the case where no server is running gracefully.\n *\n * @see Requirements 4.9, 4.10\n */\nasync function handleStopPreview(): Promise<void> {\n try {\n // Check if PID file exists\n if (!fs.existsSync(PREVIEW_PID_FILE)) {\n info('No preview server is currently running');\n return;\n }\n\n // Read PID from temp file\n const pidStr = fs.readFileSync(PREVIEW_PID_FILE, 'utf-8').trim();\n const pid = parseInt(pidStr, 10);\n\n if (isNaN(pid)) {\n // Invalid PID in file, clean up and report\n cleanupPreviewTempFiles();\n info('No preview server is currently running');\n return;\n }\n\n // Try to send SIGTERM to the process\n try {\n process.kill(pid, 'SIGTERM');\n success(`Preview server stopped (PID: ${pid})`);\n } catch (killError: unknown) {\n // Process might not exist anymore\n if (killError instanceof Error && 'code' in killError && killError.code === 'ESRCH') {\n // Process doesn't exist, just clean up\n info('Preview server was not running');\n } else {\n // Some other error occurred\n throw killError;\n }\n }\n\n // Clean up temp files\n cleanupPreviewTempFiles();\n } catch (err) {\n handleError(err);\n }\n}\n\n/**\n * Handles the `forms create-page --name <name>` command.\n *\n * Creates a new form via the API, generates a default HTML form page,\n * saves it to the server (S3), and writes to local file.\n * Displays a beta warning message. Optionally starts the preview server after creation.\n *\n * @param options - Command options\n * @see Requirements 3.1, 3.2, 3.3, 3.4, 3.5\n */\nasync function handleCreatePage(options: {\n name: string;\n projectId?: string;\n file: string;\n preview?: boolean;\n}): Promise<void> {\n try {\n // Display beta warning message (Requirement 3.4)\n console.log('⚠️ Note: The create-page command is currently in beta.\\n');\n\n const client = createClient();\n\n // Create form via SDK (Requirement 3.1)\n info(`Creating form \"${options.name}\"...`);\n const form = await client.forms.create({\n name: options.name,\n project_id: options.projectId,\n });\n\n success(`Form \"${form.name}\" created successfully`);\n\n // Generate HTML content with correct action URL (Requirement 3.5)\n const html = generateFormHtml(form);\n\n // Save HTML to server (S3)\n info('Saving form HTML to server...');\n const saveResult = await client.forms.saveHtml(form.id, html);\n if (saveResult.success) {\n success('Form HTML saved to server');\n }\n\n // Resolve file path (Requirement 3.2)\n const filePath = path.resolve(options.file);\n\n // Write HTML to local file\n fs.writeFileSync(filePath, html, 'utf-8');\n success(`Form HTML saved locally to ${filePath}`);\n\n // Save form ID for later use with `forms save`\n fs.writeFileSync(PREVIEW_FORM_ID_FILE, form.id, 'utf-8');\n\n // Start preview server if --preview flag is provided (Requirement 3.3)\n if (options.preview) {\n // Kill any existing background preview server\n killExistingPreviewServer();\n\n info('\\nMake changes to the HTML file and save to see them in the browser.');\n info('When done, run `spike forms save` to upload changes to the server.\\n');\n\n // Start foreground preview server\n await startForegroundPreviewServer(filePath);\n }\n } catch (err) {\n handleError(err);\n }\n}\n\n/**\n * Handles the `forms edit <id>` command.\n *\n * Fetches form HTML from API (stored in S3), saves to local file, and starts a live preview server.\n * In background mode, spawns a detached process and exits immediately.\n *\n * @param id - Form ID\n * @param options - Command options\n * @see Requirements 4.1, 4.2, 4.7, 4.8, 4.11\n */\nasync function handleEdit(id: string, options: {\n file: string;\n background?: boolean;\n}): Promise<void> {\n try {\n const client = createClient();\n\n // Fetch form from API\n info(`Fetching form ${id}...`);\n const form = await client.forms.get(id);\n\n // Fetch HTML from API (stored in S3)\n info('Fetching form HTML from server...');\n const { html } = await client.forms.getHtml(id);\n\n // Resolve file path\n const filePath = path.resolve(options.file);\n\n // Write HTML to file\n fs.writeFileSync(filePath, html, 'utf-8');\n success(`Form HTML saved to ${filePath}`);\n\n // Save form ID for later use with `forms save`\n fs.writeFileSync(PREVIEW_FORM_ID_FILE, id, 'utf-8');\n\n // Kill any existing background preview server\n killExistingPreviewServer();\n\n info(`\\nEditing form: ${form.name}`);\n info('Make changes to the HTML file and save to see them in the browser.');\n info('When done, run `spike forms save` to upload changes to the server.\\n');\n\n if (options.background) {\n // Background mode: spawn detached process\n await startBackgroundPreviewServer(filePath);\n } else {\n // Foreground mode: start server in current process\n await startForegroundPreviewServer(filePath);\n }\n } catch (err) {\n handleError(err);\n }\n}\n\n/**\n * Handles the `forms save` command.\n *\n * Reads local HTML file and uploads it to the server (S3).\n * If no form ID is provided, uses the form ID from the current preview session.\n *\n * @param id - Form ID (optional)\n * @param options - Command options\n */\nasync function handleSave(id: string | undefined, options: { file: string }): Promise<void> {\n try {\n // If no ID provided, try to get it from the preview session\n let formId = id;\n if (!formId) {\n if (fs.existsSync(PREVIEW_FORM_ID_FILE)) {\n formId = fs.readFileSync(PREVIEW_FORM_ID_FILE, 'utf-8').trim();\n }\n if (!formId) {\n error('No form ID provided and no active preview session found.');\n info('Usage: spike forms save <form-id> --file ./form.html');\n process.exit(1);\n }\n }\n\n const filePath = path.resolve(options.file);\n\n // Check if file exists\n if (!fs.existsSync(filePath)) {\n error(`File not found: ${filePath}`);\n process.exit(1);\n }\n\n // Read HTML from file\n const html = fs.readFileSync(filePath, 'utf-8');\n\n if (!html.trim()) {\n error('HTML file is empty');\n process.exit(1);\n }\n\n const client = createClient();\n\n // Upload HTML to server\n info(`Saving form HTML to server...`);\n const result = await client.forms.saveHtml(formId, html);\n\n if (result.success) {\n success('Form HTML saved successfully!');\n if (result.html_url) {\n info(`Stored at: ${result.html_url}`);\n }\n } else {\n error('Failed to save form HTML');\n process.exit(1);\n }\n } catch (err) {\n handleError(err);\n }\n}\n\n/**\n * Starts the preview server in foreground mode.\n * Server runs in the current process and blocks until terminated.\n *\n * @param filePath - Path to the HTML file to serve\n */\nasync function startForegroundPreviewServer(filePath: string): Promise<void> {\n const port = await startLivePreviewServer(filePath);\n const previewUrl = `http://127.0.0.1:${port}`;\n\n success(`Preview server running at ${previewUrl}`);\n info('Press Ctrl+C to stop the server');\n\n // Open browser\n const browserOpened = await openBrowser(previewUrl);\n if (!browserOpened) {\n info(`Open ${previewUrl} in your browser to preview the form`);\n }\n\n // Keep the process running\n await new Promise<void>(() => {\n // This promise never resolves - server runs until process is killed\n process.on('SIGINT', () => {\n info('\\nStopping preview server...');\n process.exit(0);\n });\n process.on('SIGTERM', () => {\n info('\\nStopping preview server...');\n process.exit(0);\n });\n });\n}\n\n/**\n * Starts the preview server in background mode.\n * Spawns a detached Node process, writes PID/port to temp files, and exits.\n *\n * @param filePath - Path to the HTML file to serve\n */\nasync function startBackgroundPreviewServer(filePath: string): Promise<void> {\n // Inline server code that will be executed by the detached process\n const serverCode = `\nconst http = require('node:http');\nconst fs = require('node:fs');\nconst path = require('node:path');\nconst os = require('node:os');\n\nconst filePath = ${JSON.stringify(filePath)};\nconst pidFile = path.join(os.tmpdir(), 'spike-preview.pid');\nconst portFile = path.join(os.tmpdir(), 'spike-preview.port');\n\nconst SSE_SCRIPT = \\`<script>\n(function() {\n var es = new EventSource('/__live-reload');\n es.onmessage = function(event) {\n if (event.data === 'reload') {\n location.reload();\n }\n };\n es.onerror = function() {\n console.log('[Live Preview] Connection lost, attempting to reconnect...');\n };\n})();\n</script>\\`;\n\nfunction injectLiveReload(html) {\n const bodyCloseRegex = /<\\\\/body>/i;\n const match = html.match(bodyCloseRegex);\n if (match && match.index !== undefined) {\n return html.slice(0, match.index) + SSE_SCRIPT + html.slice(match.index);\n }\n return html + SSE_SCRIPT;\n}\n\nconst sseClients = [];\nlet debounceTimer = null;\n\nfunction broadcastToClients(message) {\n const data = 'data: ' + message + '\\\\n\\\\n';\n for (let i = sseClients.length - 1; i >= 0; i--) {\n const client = sseClients[i];\n if (!client) continue;\n try {\n if (!client.writableEnded) {\n client.write(data);\n } else {\n sseClients.splice(i, 1);\n }\n } catch {\n sseClients.splice(i, 1);\n }\n }\n}\n\nfunction onFileChange() {\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n broadcastToClients('reload');\n debounceTimer = null;\n }, 100);\n}\n\nfunction cleanup() {\n try { fs.unlinkSync(pidFile); } catch {}\n try { fs.unlinkSync(portFile); } catch {}\n process.exit(0);\n}\n\nprocess.on('SIGTERM', cleanup);\nprocess.on('SIGINT', cleanup);\n\nconst server = http.createServer((req, res) => {\n const url = req.url || '/';\n \n if (url === '/__live-reload') {\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n 'Access-Control-Allow-Origin': '*'\n });\n res.write('data: connected\\\\n\\\\n');\n sseClients.push(res);\n req.on('close', () => {\n const index = sseClients.indexOf(res);\n if (index !== -1) sseClients.splice(index, 1);\n });\n return;\n }\n \n if (url === '/' && req.method === 'GET') {\n try {\n const html = fs.readFileSync(filePath, 'utf-8');\n const injectedHtml = injectLiveReload(html);\n res.writeHead(200, {\n 'Content-Type': 'text/html; charset=utf-8',\n 'Cache-Control': 'no-cache'\n });\n res.end(injectedHtml);\n } catch (err) {\n res.writeHead(500, { 'Content-Type': 'text/plain' });\n res.end('Error reading file: ' + err.message);\n }\n return;\n }\n \n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not Found');\n});\n\ntry {\n fs.watch(filePath, (eventType) => {\n if (eventType === 'change') onFileChange();\n });\n} catch {}\n\nserver.listen(0, '127.0.0.1', () => {\n const address = server.address();\n const port = address.port;\n \n // Write PID and port to temp files\n fs.writeFileSync(pidFile, process.pid.toString(), 'utf-8');\n fs.writeFileSync(portFile, port.toString(), 'utf-8');\n \n // Output port for parent process to read\n console.log('PORT:' + port);\n});\n`;\n\n return new Promise<void>((resolve, reject) => {\n // Spawn detached Node process\n const child = spawn('node', ['-e', serverCode], {\n detached: true,\n stdio: ['ignore', 'pipe', 'ignore'],\n });\n\n let portReceived = false;\n let outputBuffer = '';\n\n child.stdout?.on('data', (data: Buffer) => {\n outputBuffer += data.toString();\n\n // Look for PORT:XXXX in output\n const match = outputBuffer.match(/PORT:(\\d+)/);\n if (match && !portReceived) {\n portReceived = true;\n const port = parseInt(match[1], 10);\n const previewUrl = `http://127.0.0.1:${port}`;\n\n success(`Background preview server started at ${previewUrl}`);\n info(`PID: ${child.pid}`);\n info('Run `spike forms stop-preview` to stop the server');\n\n // Open browser\n openBrowser(previewUrl).then((browserOpened) => {\n if (!browserOpened) {\n info(`Open ${previewUrl} in your browser to preview the form`);\n }\n\n // Detach the child process\n child.unref();\n resolve();\n });\n }\n });\n\n child.on('error', (err) => {\n reject(new Error(`Failed to start background server: ${err.message}`));\n });\n\n // Timeout if we don't receive port within 10 seconds\n setTimeout(() => {\n if (!portReceived) {\n child.kill();\n reject(new Error('Timeout waiting for background server to start'));\n }\n }, 10000);\n });\n}\n\nexport default createFormsCommand;\n","/**\n * CLI Submissions Command\n *\n * Provides commands for managing form submissions:\n * - `submissions list <form-id>`: List submissions with filtering options\n * - `submissions export <form-id>`: Export submissions as JSON\n * - `submissions stats <form-id>`: Display submission statistics\n *\n * @module commands/submissions\n * @see Requirements 16.1, 16.2, 16.3\n */\n\nimport { Command } from 'commander';\nimport { SpikeClient, SpikeError } from '@spike-forms/sdk';\nimport { loadConfig } from '../config.js';\nimport { output, success, error, info, OutputFormat } from '../output.js';\n\n/**\n * Creates a SpikeClient instance using the loaded configuration.\n *\n * @returns A configured SpikeClient instance\n * @throws Error if API key is not configured\n */\nfunction createClient(): SpikeClient {\n const config = loadConfig();\n\n if (!config.apiKey) {\n error('API key not configured. Run `spike config set api-key <your-key>` to set it.');\n process.exit(1);\n }\n\n return new SpikeClient({\n apiKey: config.apiKey,\n baseUrl: config.baseUrl,\n });\n}\n\n/**\n * Handles errors from SDK operations.\n *\n * @param err - The error to handle\n */\nfunction handleError(err: unknown): never {\n if (err instanceof SpikeError) {\n error(err.message);\n if (err.code) {\n info(`Error code: ${err.code}`);\n }\n } else if (err instanceof Error) {\n error(err.message);\n } else {\n error('An unexpected error occurred');\n }\n process.exit(1);\n}\n\n/**\n * Creates the submissions command with all subcommands.\n *\n * @returns The configured Commander command\n *\n * @example\n * ```bash\n * # List submissions for a form\n * spike submissions list form_123\n *\n * # List submissions with filtering options\n * spike submissions list form_123 --limit 10 --status unread --from 2024-01-01 --to 2024-12-31\n *\n * # Export submissions as JSON\n * spike submissions export form_123\n * spike submissions export form_123 --format json\n *\n * # Get submission statistics\n * spike submissions stats form_123\n * ```\n */\nexport function createSubmissionsCommand(): Command {\n const submissionsCommand = new Command('submissions')\n .description('Manage form submissions');\n\n // submissions list <form-id>\n submissionsCommand\n .command('list')\n .description('List submissions for a form')\n .argument('<form-id>', 'Form ID')\n .option('-l, --limit <number>', 'Maximum number of submissions to return', parseInt)\n .option('-s, --status <status>', 'Filter by status (read, unread, spam, starred)')\n .option('--from <date>', 'Filter submissions from this date (ISO 8601 format)')\n .option('--to <date>', 'Filter submissions to this date (ISO 8601 format)')\n .option('-o, --order <order>', 'Sort order (asc, desc)', 'desc')\n .option('-f, --format <format>', 'Output format (json, table)', 'table')\n .action(async (formId: string, options: {\n limit?: number;\n status?: string;\n from?: string;\n to?: string;\n order?: string;\n format: string;\n }) => {\n await handleList(formId, options);\n });\n\n // submissions export <form-id>\n submissionsCommand\n .command('export')\n .description('Export all submissions for a form')\n .argument('<form-id>', 'Form ID')\n .option('-f, --format <format>', 'Output format (json, csv)', 'json')\n .action(async (formId: string, options: { format: string }) => {\n await handleExport(formId, options.format);\n });\n\n // submissions stats <form-id>\n submissionsCommand\n .command('stats')\n .description('Display submission statistics for a form')\n .argument('<form-id>', 'Form ID')\n .option('-f, --format <format>', 'Output format (json, table)', 'table')\n .action(async (formId: string, options: { format: string }) => {\n await handleStats(formId, options.format as OutputFormat);\n });\n\n return submissionsCommand;\n}\n\n/**\n * Handles the `submissions list <form-id>` command.\n *\n * @param formId - Form ID\n * @param options - Command options\n * @see Requirements 16.1\n */\nasync function handleList(formId: string, options: {\n limit?: number;\n status?: string;\n from?: string;\n to?: string;\n order?: string;\n format: string;\n}): Promise<void> {\n try {\n const client = createClient();\n\n // Build filter parameters based on status option\n const params: {\n limit?: number;\n since?: string;\n order?: 'asc' | 'desc';\n is_spam?: boolean;\n is_read?: boolean;\n } = {};\n\n if (options.limit !== undefined) {\n params.limit = options.limit;\n }\n\n if (options.from) {\n params.since = options.from;\n }\n\n if (options.order === 'asc' || options.order === 'desc') {\n params.order = options.order;\n }\n\n // Map status option to API parameters\n if (options.status) {\n switch (options.status.toLowerCase()) {\n case 'read':\n params.is_read = true;\n break;\n case 'unread':\n params.is_read = false;\n break;\n case 'spam':\n params.is_spam = true;\n break;\n case 'starred':\n // Note: The API doesn't have a direct is_starred filter in list params\n // We'll filter client-side if needed\n break;\n default:\n error(`Invalid status: ${options.status}. Valid values are: read, unread, spam, starred`);\n process.exit(1);\n }\n }\n\n const submissions = await client.submissions.list(formId, params);\n\n // Client-side filtering for starred (if API doesn't support it directly)\n let filteredSubmissions = submissions;\n if (options.status?.toLowerCase() === 'starred') {\n filteredSubmissions = submissions.filter(s => s.is_starred);\n }\n\n // Client-side filtering for --to date\n if (options.to) {\n const toDate = new Date(options.to);\n filteredSubmissions = filteredSubmissions.filter(s => new Date(s.created_at) <= toDate);\n }\n\n if (filteredSubmissions.length === 0) {\n info('No submissions found');\n return;\n }\n\n // Format submissions for display\n const displayData = filteredSubmissions.map(s => ({\n id: s.id,\n created_at: s.created_at,\n is_read: s.is_read,\n is_spam: s.is_spam,\n is_starred: s.is_starred,\n data: JSON.stringify(s.data).slice(0, 50) + (JSON.stringify(s.data).length > 50 ? '...' : ''),\n }));\n\n output(displayData, options.format as OutputFormat);\n } catch (err) {\n handleError(err);\n }\n}\n\n/**\n * Handles the `submissions export <form-id>` command.\n *\n * @param formId - Form ID\n * @param format - Export format (json or csv)\n * @see Requirements 16.2\n */\nasync function handleExport(formId: string, format: string): Promise<void> {\n try {\n const client = createClient();\n const submissions = await client.submissions.export(formId);\n\n if (submissions.length === 0) {\n info('No submissions to export');\n return;\n }\n\n if (format === 'csv') {\n // Export as CSV\n outputCsv(submissions);\n } else {\n // Export as JSON (default)\n console.log(JSON.stringify(submissions, null, 2));\n }\n\n success(`Exported ${submissions.length} submission${submissions.length === 1 ? '' : 's'}`);\n } catch (err) {\n handleError(err);\n }\n}\n\n/**\n * Outputs submissions as CSV format.\n *\n * @param submissions - Array of submissions to output\n */\nfunction outputCsv(submissions: Array<{\n id: string;\n form_id: string;\n data: Record<string, unknown>;\n is_spam: boolean;\n is_read: boolean;\n is_starred: boolean;\n ip_address: string | null;\n user_agent: string | null;\n created_at: string;\n}>): void {\n if (submissions.length === 0) {\n return;\n }\n\n // Collect all unique data keys from all submissions\n const dataKeys = new Set<string>();\n for (const submission of submissions) {\n Object.keys(submission.data).forEach(key => dataKeys.add(key));\n }\n\n // Build CSV header\n const baseHeaders = ['id', 'form_id', 'is_spam', 'is_read', 'is_starred', 'ip_address', 'user_agent', 'created_at'];\n const allHeaders = [...baseHeaders, ...Array.from(dataKeys)];\n\n // Output header row\n console.log(allHeaders.map(escapeCsvValue).join(','));\n\n // Output data rows\n for (const submission of submissions) {\n const row = [\n submission.id,\n submission.form_id,\n String(submission.is_spam),\n String(submission.is_read),\n String(submission.is_starred),\n submission.ip_address || '',\n submission.user_agent || '',\n submission.created_at,\n ...Array.from(dataKeys).map(key => {\n const value = submission.data[key];\n if (value === undefined || value === null) {\n return '';\n }\n if (typeof value === 'object') {\n return JSON.stringify(value);\n }\n return String(value);\n }),\n ];\n\n console.log(row.map(escapeCsvValue).join(','));\n }\n}\n\n/**\n * Escapes a value for CSV output.\n *\n * @param value - The value to escape\n * @returns The escaped CSV value\n */\nfunction escapeCsvValue(value: string): string {\n // If the value contains comma, quote, or newline, wrap in quotes and escape quotes\n if (value.includes(',') || value.includes('\"') || value.includes('\\n') || value.includes('\\r')) {\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\n }\n return value;\n}\n\n/**\n * Handles the `submissions stats <form-id>` command.\n *\n * @param formId - Form ID\n * @param format - Output format\n * @see Requirements 16.3\n */\nasync function handleStats(formId: string, format: OutputFormat): Promise<void> {\n try {\n const client = createClient();\n const stats = await client.submissions.getStats(formId);\n\n output(stats, format);\n } catch (err) {\n handleError(err);\n }\n}\n\nexport default createSubmissionsCommand;\n","/**\n * CLI Projects Command\n *\n * Provides commands for managing projects:\n * - `projects list`: List all projects\n * - `projects get <id>`: Get a specific project by ID\n * - `projects create`: Create a new project\n * - `projects update <id>`: Update a project\n * - `projects delete <id>`: Delete a project\n *\n * @module commands/projects\n * @see Requirements 17.1, 17.2, 17.3, 17.4, 17.5\n */\n\nimport { Command } from 'commander';\nimport { SpikeClient, SpikeError } from '@spike-forms/sdk';\nimport { loadConfig } from '../config.js';\nimport { output, success, error, info, OutputFormat } from '../output.js';\n\n/**\n * Creates a SpikeClient instance using the loaded configuration.\n *\n * @returns A configured SpikeClient instance\n * @throws Error if API key is not configured\n */\nfunction createClient(): SpikeClient {\n const config = loadConfig();\n\n if (!config.apiKey) {\n error('API key not configured. Run `spike config set api-key <your-key>` to set it.');\n process.exit(1);\n }\n\n return new SpikeClient({\n apiKey: config.apiKey,\n baseUrl: config.baseUrl,\n });\n}\n\n/**\n * Handles errors from SDK operations.\n *\n * @param err - The error to handle\n */\nfunction handleError(err: unknown): never {\n if (err instanceof SpikeError) {\n error(err.message);\n if (err.code) {\n info(`Error code: ${err.code}`);\n }\n } else if (err instanceof Error) {\n error(err.message);\n } else {\n error('An unexpected error occurred');\n }\n process.exit(1);\n}\n\n/**\n * Creates the projects command with all subcommands.\n *\n * @returns The configured Commander command\n *\n * @example\n * ```bash\n * # List all projects\n * spike projects list\n *\n * # Get a specific project\n * spike projects get proj_123\n *\n * # Create a new project\n * spike projects create --name \"Marketing Forms\"\n *\n * # Update a project\n * spike projects update proj_123 --name \"New Name\"\n *\n * # Delete a project\n * spike projects delete proj_123\n * ```\n */\nexport function createProjectsCommand(): Command {\n const projectsCommand = new Command('projects')\n .description('Manage projects');\n\n // projects list\n projectsCommand\n .command('list')\n .description('List all projects')\n .option('-f, --format <format>', 'Output format (json, table)', 'table')\n .action(async (options: { format: string }) => {\n await handleList(options.format as OutputFormat);\n });\n\n // projects get <id>\n projectsCommand\n .command('get')\n .description('Get a specific project by ID')\n .argument('<id>', 'Project ID')\n .option('-f, --format <format>', 'Output format (json, table)', 'table')\n .action(async (id: string, options: { format: string }) => {\n await handleGet(id, options.format as OutputFormat);\n });\n\n // projects create\n projectsCommand\n .command('create')\n .description('Create a new project')\n .requiredOption('-n, --name <name>', 'Name for the project')\n .option('-f, --format <format>', 'Output format (json, table)', 'table')\n .action(async (options: { name: string; format: string }) => {\n await handleCreate(options);\n });\n\n // projects update <id>\n projectsCommand\n .command('update')\n .description('Update a project')\n .argument('<id>', 'Project ID')\n .option('-n, --name <name>', 'New name for the project')\n .option('-f, --format <format>', 'Output format (json, table)', 'table')\n .action(async (id: string, options: { name?: string; format: string }) => {\n await handleUpdate(id, options);\n });\n\n // projects delete <id>\n projectsCommand\n .command('delete')\n .description('Delete a project')\n .argument('<id>', 'Project ID')\n .action(async (id: string) => {\n await handleDelete(id);\n });\n\n return projectsCommand;\n}\n\n/**\n * Handles the `projects list` command.\n *\n * @param format - Output format\n * @see Requirements 17.1\n */\nasync function handleList(format: OutputFormat): Promise<void> {\n try {\n const client = createClient();\n const projects = await client.projects.list();\n\n if (projects.length === 0) {\n info('No projects found');\n return;\n }\n\n output(projects, format);\n } catch (err) {\n handleError(err);\n }\n}\n\n/**\n * Handles the `projects get <id>` command.\n *\n * @param id - Project ID\n * @param format - Output format\n * @see Requirements 17.2\n */\nasync function handleGet(id: string, format: OutputFormat): Promise<void> {\n try {\n const client = createClient();\n const project = await client.projects.get(id);\n output(project, format);\n } catch (err) {\n handleError(err);\n }\n}\n\n/**\n * Handles the `projects create` command.\n *\n * @param options - Command options\n * @see Requirements 17.3\n */\nasync function handleCreate(options: { name: string; format: string }): Promise<void> {\n try {\n const client = createClient();\n\n const project = await client.projects.create({\n name: options.name,\n });\n\n success(`Project \"${project.name}\" created successfully`);\n console.log('');\n output(project, options.format as OutputFormat);\n } catch (err) {\n handleError(err);\n }\n}\n\n/**\n * Handles the `projects update <id>` command.\n *\n * @param id - Project ID\n * @param options - Command options\n * @see Requirements 17.4\n */\nasync function handleUpdate(id: string, options: { name?: string; format: string }): Promise<void> {\n try {\n // Check if any update options were provided\n if (options.name === undefined) {\n error('No update options provided. Use --name to update the project.');\n process.exit(1);\n }\n\n const client = createClient();\n\n const updateData: { name?: string } = {};\n\n if (options.name !== undefined) {\n updateData.name = options.name;\n }\n\n const project = await client.projects.update(id, updateData);\n\n success(`Project \"${project.name}\" updated successfully`);\n console.log('');\n output(project, options.format as OutputFormat);\n } catch (err) {\n handleError(err);\n }\n}\n\n/**\n * Handles the `projects delete <id>` command.\n *\n * @param id - Project ID\n * @see Requirements 17.5\n */\nasync function handleDelete(id: string): Promise<void> {\n try {\n const client = createClient();\n await client.projects.delete(id);\n success(`Project \"${id}\" deleted successfully`);\n } catch (err) {\n handleError(err);\n }\n}\n\nexport default createProjectsCommand;\n","/**\n * CLI Teams Command\n *\n * Provides commands for managing teams:\n * - `teams list`: List all teams\n * - `teams get <id>`: Get a specific team by ID\n * - `teams create`: Create a new team\n * - `teams members <id>`: List team members\n * - `teams invite <id>`: Invite a user to a team\n *\n * @module commands/teams\n * @see Requirements 18.1, 18.2, 18.3, 18.4, 18.5\n */\n\nimport { Command } from 'commander';\nimport { SpikeClient, SpikeError } from '@spike-forms/sdk';\nimport { loadConfig } from '../config.js';\nimport { output, success, error, info, OutputFormat } from '../output.js';\n\n/**\n * Creates a SpikeClient instance using the loaded configuration.\n *\n * @returns A configured SpikeClient instance\n * @throws Error if API key is not configured\n */\nfunction createClient(): SpikeClient {\n const config = loadConfig();\n\n if (!config.apiKey) {\n error('API key not configured. Run `spike config set api-key <your-key>` to set it.');\n process.exit(1);\n }\n\n return new SpikeClient({\n apiKey: config.apiKey,\n baseUrl: config.baseUrl,\n });\n}\n\n/**\n * Handles errors from SDK operations.\n *\n * @param err - The error to handle\n */\nfunction handleError(err: unknown): never {\n if (err instanceof SpikeError) {\n error(err.message);\n if (err.code) {\n info(`Error code: ${err.code}`);\n }\n } else if (err instanceof Error) {\n error(err.message);\n } else {\n error('An unexpected error occurred');\n }\n process.exit(1);\n}\n\n/**\n * Creates the teams command with all subcommands.\n *\n * @returns The configured Commander command\n *\n * @example\n * ```bash\n * # List all teams\n * spike teams list\n *\n * # Get a specific team\n * spike teams get team_123\n *\n * # Create a new team\n * spike teams create --name \"Marketing Team\"\n *\n * # List team members\n * spike teams members team_123\n *\n * # Invite a user to a team\n * spike teams invite team_123 --email user@example.com --role member\n * ```\n */\nexport function createTeamsCommand(): Command {\n const teamsCommand = new Command('teams')\n .description('Manage teams');\n\n // teams list\n teamsCommand\n .command('list')\n .description('List all teams')\n .option('-f, --format <format>', 'Output format (json, table)', 'table')\n .action(async (options: { format: string }) => {\n await handleList(options.format as OutputFormat);\n });\n\n // teams get <id>\n teamsCommand\n .command('get')\n .description('Get a specific team by ID')\n .argument('<id>', 'Team ID')\n .option('-f, --format <format>', 'Output format (json, table)', 'table')\n .action(async (id: string, options: { format: string }) => {\n await handleGet(id, options.format as OutputFormat);\n });\n\n // teams create\n teamsCommand\n .command('create')\n .description('Create a new team')\n .requiredOption('-n, --name <name>', 'Name for the team')\n .option('-f, --format <format>', 'Output format (json, table)', 'table')\n .action(async (options: { name: string; format: string }) => {\n await handleCreate(options);\n });\n\n // teams members <id>\n teamsCommand\n .command('members')\n .description('List members of a team')\n .argument('<id>', 'Team ID')\n .option('-f, --format <format>', 'Output format (json, table)', 'table')\n .action(async (id: string, options: { format: string }) => {\n await handleMembers(id, options.format as OutputFormat);\n });\n\n // teams invite <id>\n teamsCommand\n .command('invite')\n .description('Invite a user to a team')\n .argument('<id>', 'Team ID')\n .requiredOption('-e, --email <email>', 'Email address of the user to invite')\n .requiredOption('-r, --role <role>', 'Role for the invited user (admin, member)')\n .option('-f, --format <format>', 'Output format (json, table)', 'table')\n .action(async (id: string, options: { email: string; role: string; format: string }) => {\n await handleInvite(id, options);\n });\n\n return teamsCommand;\n}\n\n/**\n * Handles the `teams list` command.\n *\n * @param format - Output format\n * @see Requirements 18.1\n */\nasync function handleList(format: OutputFormat): Promise<void> {\n try {\n const client = createClient();\n const teams = await client.teams.list();\n\n if (teams.length === 0) {\n info('No teams found');\n return;\n }\n\n output(teams, format);\n } catch (err) {\n handleError(err);\n }\n}\n\n/**\n * Handles the `teams get <id>` command.\n *\n * @param id - Team ID\n * @param format - Output format\n * @see Requirements 18.2\n */\nasync function handleGet(id: string, format: OutputFormat): Promise<void> {\n try {\n const client = createClient();\n const team = await client.teams.get(id);\n output(team, format);\n } catch (err) {\n handleError(err);\n }\n}\n\n/**\n * Handles the `teams create` command.\n *\n * @param options - Command options\n * @see Requirements 18.3\n */\nasync function handleCreate(options: { name: string; format: string }): Promise<void> {\n try {\n const client = createClient();\n\n const team = await client.teams.create({\n name: options.name,\n });\n\n success(`Team \"${team.name}\" created successfully`);\n console.log('');\n output(team, options.format as OutputFormat);\n } catch (err) {\n handleError(err);\n }\n}\n\n/**\n * Handles the `teams members <id>` command.\n *\n * @param id - Team ID\n * @param format - Output format\n * @see Requirements 18.4\n */\nasync function handleMembers(id: string, format: OutputFormat): Promise<void> {\n try {\n const client = createClient();\n const members = await client.teams.listMembers(id);\n\n if (members.length === 0) {\n info('No members found');\n return;\n }\n\n // Format members for display\n const displayData = members.map(member => ({\n id: member.id,\n user_id: member.user_id,\n name: member.user.name,\n email: member.user.email,\n role: member.role,\n created_at: member.created_at,\n }));\n\n output(displayData, format);\n } catch (err) {\n handleError(err);\n }\n}\n\n/**\n * Handles the `teams invite <id>` command.\n *\n * @param id - Team ID\n * @param options - Command options\n * @see Requirements 18.5\n */\nasync function handleInvite(\n id: string,\n options: { email: string; role: string; format: string }\n): Promise<void> {\n try {\n // Validate role\n const role = options.role.toLowerCase();\n if (role !== 'admin' && role !== 'member') {\n error('Invalid role. Valid values are: admin, member');\n process.exit(1);\n }\n\n const client = createClient();\n\n const invitation = await client.teams.invite(id, {\n email: options.email,\n role: role as 'admin' | 'member',\n });\n\n success(`Invitation sent to \"${options.email}\" as ${role}`);\n console.log('');\n output(invitation, options.format as OutputFormat);\n } catch (err) {\n handleError(err);\n }\n}\n\nexport default createTeamsCommand;\n","/**\n * CLI User Command\n *\n * Provides commands for managing user profile and API keys:\n * - `user`: Display current user profile\n * - `user update`: Update user profile\n * - `user api-keys`: List user API keys\n * - `user api-keys create`: Create a new API key\n * - `user api-keys delete <id>`: Delete an API key\n *\n * @module commands/user\n * @see Requirements 19.1, 19.2, 19.3, 19.4, 19.5\n */\n\nimport { Command } from 'commander';\nimport { SpikeClient, SpikeError } from '@spike-forms/sdk';\nimport { loadConfig } from '../config.js';\nimport { output, success, error, info, maskApiKey, OutputFormat } from '../output.js';\n\n/**\n * Creates a SpikeClient instance using the loaded configuration.\n *\n * @returns A configured SpikeClient instance\n * @throws Error if API key is not configured\n */\nfunction createClient(): SpikeClient {\n const config = loadConfig();\n\n if (!config.apiKey) {\n error('API key not configured. Run `spike config set api-key <your-key>` to set it.');\n process.exit(1);\n }\n\n return new SpikeClient({\n apiKey: config.apiKey,\n baseUrl: config.baseUrl,\n });\n}\n\n/**\n * Handles errors from SDK operations.\n *\n * @param err - The error to handle\n */\nfunction handleError(err: unknown): never {\n if (err instanceof SpikeError) {\n error(err.message);\n if (err.code) {\n info(`Error code: ${err.code}`);\n }\n } else if (err instanceof Error) {\n error(err.message);\n } else {\n error('An unexpected error occurred');\n }\n process.exit(1);\n}\n\n/**\n * Creates the user command with all subcommands.\n *\n * @returns The configured Commander command\n *\n * @example\n * ```bash\n * # Display current user profile\n * spike user\n *\n * # Update user profile\n * spike user update --name \"New Name\"\n * spike user update --email \"new@example.com\"\n *\n * # List API keys\n * spike user api-keys\n *\n * # Create a new API key\n * spike user api-keys create --name \"My App\"\n *\n * # Delete an API key\n * spike user api-keys delete key_123\n * ```\n */\nexport function createUserCommand(): Command {\n const userCommand = new Command('user')\n .description('Manage user profile and API keys');\n\n // user (display profile) - default action when no subcommand\n userCommand\n .option('-f, --format <format>', 'Output format (json, table)', 'table')\n .action(async (options: { format: string }) => {\n await handleGetProfile(options.format as OutputFormat);\n });\n\n // user update\n userCommand\n .command('update')\n .description('Update user profile')\n .option('-n, --name <name>', 'New name for the user')\n .option('-e, --email <email>', 'New email address for the user')\n .option('-f, --format <format>', 'Output format (json, table)', 'table')\n .action(async (options: {\n name?: string;\n email?: string;\n format: string;\n }) => {\n await handleUpdateProfile(options);\n });\n\n // user api-keys (subcommand group)\n const apiKeysCommand = new Command('api-keys')\n .description('Manage user API keys');\n\n // user api-keys (list) - default action\n apiKeysCommand\n .option('-f, --format <format>', 'Output format (json, table)', 'table')\n .action(async (options: { format: string }) => {\n await handleListApiKeys(options.format as OutputFormat);\n });\n\n // user api-keys create\n apiKeysCommand\n .command('create')\n .description('Create a new API key')\n .requiredOption('-n, --name <name>', 'Name for the API key')\n .option('-f, --format <format>', 'Output format (json, table)', 'table')\n .action(async (options: { name: string; format: string }) => {\n await handleCreateApiKey(options);\n });\n\n // user api-keys delete <id>\n apiKeysCommand\n .command('delete')\n .description('Delete an API key')\n .argument('<id>', 'API key ID')\n .action(async (id: string) => {\n await handleDeleteApiKey(id);\n });\n\n userCommand.addCommand(apiKeysCommand);\n\n return userCommand;\n}\n\n/**\n * Handles the `user` command (display profile).\n *\n * @param format - Output format\n * @see Requirements 19.1\n */\nasync function handleGetProfile(format: OutputFormat): Promise<void> {\n try {\n const client = createClient();\n const user = await client.user.get();\n output(user, format);\n } catch (err) {\n handleError(err);\n }\n}\n\n/**\n * Handles the `user update` command.\n *\n * @param options - Command options\n * @see Requirements 19.2\n */\nasync function handleUpdateProfile(options: {\n name?: string;\n email?: string;\n format: string;\n}): Promise<void> {\n try {\n // Check if any update options were provided\n if (options.name === undefined && options.email === undefined) {\n error('No update options provided. Use --name or --email to update the profile.');\n process.exit(1);\n }\n\n const client = createClient();\n\n const updateData: {\n name?: string;\n email?: string;\n } = {};\n\n if (options.name !== undefined) {\n updateData.name = options.name;\n }\n\n if (options.email !== undefined) {\n updateData.email = options.email;\n }\n\n const user = await client.user.update(updateData);\n\n success('Profile updated successfully');\n console.log('');\n output(user, options.format as OutputFormat);\n } catch (err) {\n handleError(err);\n }\n}\n\n/**\n * Handles the `user api-keys` command (list API keys).\n *\n * @param format - Output format\n * @see Requirements 19.3\n */\nasync function handleListApiKeys(format: OutputFormat): Promise<void> {\n try {\n const client = createClient();\n const apiKeys = await client.user.listApiKeys();\n\n if (apiKeys.length === 0) {\n info('No API keys found');\n return;\n }\n\n // Mask API keys for display\n const displayData = apiKeys.map(key => ({\n id: key.id,\n name: key.name,\n key: key.key ? maskApiKey(key.key) : '-',\n last_used_at: key.last_used_at || 'Never',\n created_at: key.created_at,\n }));\n\n output(displayData, format);\n } catch (err) {\n handleError(err);\n }\n}\n\n/**\n * Handles the `user api-keys create` command.\n *\n * @param options - Command options\n * @see Requirements 19.4\n */\nasync function handleCreateApiKey(options: { name: string; format: string }): Promise<void> {\n try {\n const client = createClient();\n\n const apiKey = await client.user.createApiKey({\n name: options.name,\n });\n\n success(`API key \"${apiKey.name}\" created successfully`);\n console.log('');\n\n // Show the full key only on creation (it won't be shown again)\n if (options.format === 'json') {\n output(apiKey, 'json');\n } else {\n // For table format, show the key prominently since this is the only time it's visible\n console.log('Your new API key (save this - it will not be shown again):');\n console.log('');\n console.log(` ${apiKey.key}`);\n console.log('');\n output({\n id: apiKey.id,\n name: apiKey.name,\n created_at: apiKey.created_at,\n }, 'table');\n }\n } catch (err) {\n handleError(err);\n }\n}\n\n/**\n * Handles the `user api-keys delete <id>` command.\n *\n * @param id - API key ID\n * @see Requirements 19.5\n */\nasync function handleDeleteApiKey(id: string): Promise<void> {\n try {\n const client = createClient();\n await client.user.deleteApiKey(id);\n success(`API key \"${id}\" deleted successfully`);\n } catch (err) {\n handleError(err);\n }\n}\n\nexport default createUserCommand;\n","/**\n * State Token Utilities\n *\n * Provides cryptographically secure state token generation and verification\n * for CSRF protection during the browser login flow.\n *\n * @module utils/state\n */\n\nimport * as crypto from 'node:crypto';\n\n/**\n * Generates a cryptographically secure state token.\n *\n * Uses `crypto.randomBytes(32)` to produce a 64-character hexadecimal string.\n * This token is used for CSRF protection during the OAuth-like browser login flow.\n *\n * @returns A 64-character hex string (32 bytes)\n *\n * @example\n * ```typescript\n * const state = generateState();\n * // Returns: \"a1b2c3d4e5f6...\" (64 hex characters)\n * ```\n *\n * @remarks\n * - The token is generated using Node.js crypto module for cryptographic security\n * - Each call produces a unique, unpredictable token\n * - The 32-byte (256-bit) length provides sufficient entropy for CSRF protection\n *\n * @see Requirements 7.1 - State tokens must be generated using crypto.randomBytes(32)\n */\nexport function generateState(): string {\n return crypto.randomBytes(32).toString('hex');\n}\n\n/**\n * Verifies that a received state token matches the expected value.\n *\n * Performs exact string comparison to validate the state parameter\n * returned from the authorization callback matches the original token.\n *\n * @param received - The state token received from the callback\n * @param expected - The original state token that was generated\n * @returns `true` if the tokens match exactly, `false` otherwise\n *\n * @example\n * ```typescript\n * const originalState = generateState();\n * const callbackState = \"...\"; // from callback URL\n *\n * if (verifyState(callbackState, originalState)) {\n * // State is valid, proceed with authentication\n * } else {\n * // State mismatch, reject the callback\n * }\n * ```\n *\n * @remarks\n * - Uses exact string comparison (===) for verification\n * - Both parameters must be non-null strings for a valid comparison\n * - Returns false if either parameter is undefined or null\n *\n * @see Requirements 7.2 - State verification must use exact string comparison\n * @see Requirements 7.3 - Callbacks with missing or mismatched state must be rejected\n */\nexport function verifyState(received: string, expected: string): boolean {\n return received === expected;\n}\n","/**\n * Callback Server\n *\n * Provides a temporary HTTP server for receiving OAuth-like callbacks\n * during the browser login flow. The server binds to localhost only\n * and handles the callback with API key and state verification.\n *\n * @module server/callback\n */\n\nimport * as http from 'node:http';\nimport { verifyState } from '../utils/state';\n\n/**\n * Result of a callback operation.\n */\nexport interface CallbackResult {\n /** Whether the callback was successful */\n success: boolean;\n /** The API key received from the callback (if successful) */\n apiKey?: string;\n /** Error message (if unsuccessful) */\n error?: string;\n}\n\n/**\n * Parameters extracted from a callback URL.\n */\nexport interface CallbackParams {\n /** The API key parameter */\n key?: string;\n /** The state token parameter */\n state?: string;\n /** Error code parameter */\n error?: string;\n /** Error message parameter */\n message?: string;\n}\n\n/**\n * Interface for the callback server.\n */\nexport interface CallbackServer {\n /**\n * Starts the callback server.\n * @returns Promise resolving to the port and URL the server is listening on\n */\n start(): Promise<{ port: number; url: string }>;\n\n /**\n * Waits for a callback with the expected state token.\n * @param state - The expected state token\n * @param timeoutMs - Timeout in milliseconds\n * @returns Promise resolving to the callback result\n */\n waitForCallback(state: string, timeoutMs: number): Promise<CallbackResult>;\n\n /**\n * Stops the callback server.\n */\n stop(): Promise<void>;\n}\n\n/**\n * Parses callback parameters from a URL.\n *\n * Extracts the `key`, `state`, `error`, and `message` query parameters\n * from a callback URL.\n *\n * @param url - The URL string to parse (can be full URL or just path with query)\n * @returns Object containing the extracted parameters (undefined for missing params)\n *\n * @example\n * ```typescript\n * const params = parseCallbackParams('http://localhost:3000/callback?key=sk_123&state=abc');\n * // Returns: { key: 'sk_123', state: 'abc', error: undefined, message: undefined }\n *\n * const errorParams = parseCallbackParams('/callback?error=access_denied&message=User%20cancelled');\n * // Returns: { key: undefined, state: undefined, error: 'access_denied', message: 'User cancelled' }\n * ```\n *\n * @remarks\n * - Uses URLSearchParams for robust query string parsing\n * - Handles URL-encoded values automatically\n * - Returns undefined for missing parameters (not null or empty string)\n *\n * @see Requirements 1.7 - Callback server shall verify state parameter\n * @see Requirements 1.9 - CLI shall save key from valid callback\n * @see Requirements 1.10 - Dashboard shall redirect with error parameter on cancel\n */\nexport function parseCallbackParams(url: string): CallbackParams {\n try {\n // Handle both full URLs and relative paths with query strings\n let searchParams: URLSearchParams;\n\n if (url.startsWith('http://') || url.startsWith('https://')) {\n // Full URL - use URL constructor\n const parsed = new URL(url);\n searchParams = parsed.searchParams;\n } else {\n // Relative path - extract query string manually\n const queryIndex = url.indexOf('?');\n if (queryIndex === -1) {\n return {};\n }\n searchParams = new URLSearchParams(url.slice(queryIndex + 1));\n }\n\n return {\n key: searchParams.get('key') ?? undefined,\n state: searchParams.get('state') ?? undefined,\n error: searchParams.get('error') ?? undefined,\n message: searchParams.get('message') ?? undefined,\n };\n } catch {\n // Return empty object for unparseable URLs\n return {};\n }\n}\n\n/**\n * HTML template for the success page shown in the browser after successful login.\n */\nconst SUCCESS_HTML = `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Login Successful - Spike CLI</title>\n <style>\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n display: flex;\n justify-content: center;\n align-items: center;\n min-height: 100vh;\n margin: 0;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n }\n .container {\n text-align: center;\n padding: 2rem;\n background: rgba(255, 255, 255, 0.1);\n border-radius: 16px;\n backdrop-filter: blur(10px);\n max-width: 400px;\n }\n .icon {\n font-size: 4rem;\n margin-bottom: 1rem;\n }\n h1 {\n margin: 0 0 0.5rem 0;\n font-size: 1.5rem;\n }\n p {\n margin: 0;\n opacity: 0.9;\n }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"icon\">✓</div>\n <h1>Login Successful!</h1>\n <p>You can close this window and return to the terminal.</p>\n </div>\n</body>\n</html>`;\n\n/**\n * HTML template for the error page shown in the browser when login fails.\n * @param errorMessage - The error message to display\n */\nfunction getErrorHtml(errorMessage: string): string {\n const escapedMessage = errorMessage\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Login Failed - Spike CLI</title>\n <style>\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n display: flex;\n justify-content: center;\n align-items: center;\n min-height: 100vh;\n margin: 0;\n background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);\n color: white;\n }\n .container {\n text-align: center;\n padding: 2rem;\n background: rgba(255, 255, 255, 0.1);\n border-radius: 16px;\n backdrop-filter: blur(10px);\n max-width: 400px;\n }\n .icon {\n font-size: 4rem;\n margin-bottom: 1rem;\n }\n h1 {\n margin: 0 0 0.5rem 0;\n font-size: 1.5rem;\n }\n p {\n margin: 0;\n opacity: 0.9;\n }\n .error-message {\n margin-top: 1rem;\n padding: 1rem;\n background: rgba(0, 0, 0, 0.2);\n border-radius: 8px;\n font-family: monospace;\n font-size: 0.9rem;\n }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"icon\">✗</div>\n <h1>Login Failed</h1>\n <p>Something went wrong during authentication.</p>\n <div class=\"error-message\">${escapedMessage}</div>\n </div>\n</body>\n</html>`;\n}\n\n/**\n * Creates a callback server for the browser login flow.\n *\n * The server:\n * - Binds to `127.0.0.1` only (no external access)\n * - Uses port `0` for OS-assigned dynamic port\n * - Handles GET `/callback` with key/state/error params\n * - Returns HTML success/error pages to the browser\n * - Resolves the waitForCallback promise on first valid callback\n * - Times out after configurable duration\n *\n * @returns A CallbackServer instance\n *\n * @example\n * ```typescript\n * const server = createCallbackServer();\n * const { port, url } = await server.start();\n * console.log(`Callback server listening at ${url}`);\n *\n * try {\n * const result = await server.waitForCallback(expectedState, 120000);\n * if (result.success) {\n * console.log(`Received API key: ${result.apiKey}`);\n * } else {\n * console.error(`Login failed: ${result.error}`);\n * }\n * } finally {\n * await server.stop();\n * }\n * ```\n *\n * @remarks\n * - Only accepts callbacks from localhost URLs for security\n * - Verifies state parameter to prevent CSRF attacks\n * - The server automatically handles cleanup on stop()\n *\n * @see Requirements 1.1 - CLI shall start a Callback_Server bound to 127.0.0.1\n * @see Requirements 1.7 - Callback_Server shall verify state parameter\n * @see Requirements 1.8 - Callback_Server shall reject mismatched state\n * @see Requirements 1.9 - CLI shall save key from valid callback\n * @see Requirements 1.11 - CLI shall terminate server on timeout\n * @see Requirements 1.12 - Callback_Server shall only accept localhost URLs\n */\nexport function createCallbackServer(): CallbackServer {\n let server: http.Server | null = null;\n let port = 0;\n let expectedState: string | null = null;\n let callbackResolve: ((result: CallbackResult) => void) | null = null;\n let timeoutId: NodeJS.Timeout | null = null;\n let callbackReceived = false;\n\n /**\n * Handles incoming HTTP requests to the callback server.\n */\n function handleRequest(req: http.IncomingMessage, res: http.ServerResponse): void {\n // Only handle GET requests to /callback\n if (req.method !== 'GET' || !req.url?.startsWith('/callback')) {\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not Found');\n return;\n }\n\n // Parse callback parameters\n const params = parseCallbackParams(req.url);\n\n // Check if this is an error callback (user cancelled or other error)\n if (params.error) {\n const errorMessage = params.message || params.error;\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(getErrorHtml(errorMessage));\n\n if (callbackResolve && !callbackReceived) {\n callbackReceived = true;\n callbackResolve({\n success: false,\n error: errorMessage,\n });\n }\n return;\n }\n\n // Verify state parameter\n if (!params.state || !expectedState || !verifyState(params.state, expectedState)) {\n const errorMessage = 'State verification failed. This may be a security issue.';\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end(getErrorHtml(errorMessage));\n\n if (callbackResolve && !callbackReceived) {\n callbackReceived = true;\n callbackResolve({\n success: false,\n error: errorMessage,\n });\n }\n return;\n }\n\n // Check for API key\n if (!params.key) {\n const errorMessage = 'No API key received in callback.';\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end(getErrorHtml(errorMessage));\n\n if (callbackResolve && !callbackReceived) {\n callbackReceived = true;\n callbackResolve({\n success: false,\n error: errorMessage,\n });\n }\n return;\n }\n\n // Success! Return success page and resolve promise\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(SUCCESS_HTML);\n\n if (callbackResolve && !callbackReceived) {\n callbackReceived = true;\n callbackResolve({\n success: true,\n apiKey: params.key,\n });\n }\n }\n\n return {\n async start(): Promise<{ port: number; url: string }> {\n return new Promise((resolve, reject) => {\n server = http.createServer(handleRequest);\n\n server.on('error', (err) => {\n reject(err);\n });\n\n // Bind to 127.0.0.1 only (no external access) with port 0 for dynamic assignment\n server.listen(0, '127.0.0.1', () => {\n const address = server!.address();\n if (address && typeof address === 'object') {\n port = address.port;\n const url = `http://127.0.0.1:${port}`;\n resolve({ port, url });\n } else {\n reject(new Error('Failed to get server address'));\n }\n });\n });\n },\n\n async waitForCallback(state: string, timeoutMs: number): Promise<CallbackResult> {\n expectedState = state;\n callbackReceived = false;\n\n return new Promise((resolve) => {\n callbackResolve = resolve;\n\n // Set up timeout\n timeoutId = setTimeout(() => {\n if (!callbackReceived) {\n callbackReceived = true;\n resolve({\n success: false,\n error: 'Login timed out. Please try again.',\n });\n }\n }, timeoutMs);\n });\n },\n\n async stop(): Promise<void> {\n // Clear timeout if set\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n // Close server if running\n if (server) {\n return new Promise((resolve) => {\n server!.close(() => {\n server = null;\n resolve();\n });\n });\n }\n },\n };\n}\n","/**\n * CLI Login Command\n *\n * Provides browser-based authentication for the CLI.\n * Starts a local callback server, opens the dashboard consent page,\n * receives an API key via redirect, and saves it to config.\n *\n * @module commands/login\n */\n\nimport { Command } from 'commander';\nimport { generateState } from '../utils/state.js';\nimport { openBrowser } from '../utils/browser.js';\nimport { createCallbackServer } from '../server/callback.js';\nimport { saveConfig } from '../config.js';\nimport { success, error, info } from '../output.js';\n\n/**\n * Default timeout for the login flow in seconds.\n */\nconst DEFAULT_TIMEOUT_SECONDS = 120;\n\n/**\n * Default dashboard base URL.\n */\nconst DEFAULT_DASHBOARD_URL = 'https://app.spike.ac';\n\n/**\n * Gets the dashboard base URL from environment variable or default.\n *\n * @returns The dashboard base URL\n */\nfunction getDashboardUrl(): string {\n return process.env.SPIKE_DASHBOARD_URL || DEFAULT_DASHBOARD_URL;\n}\n\n/**\n * Builds the authorization URL for the browser login flow.\n *\n * Constructs a URL to the dashboard consent page with the state token\n * and callback URL as query parameters.\n *\n * @param state - The CSRF state token\n * @param callbackPort - The port the callback server is listening on\n * @returns The full authorization URL\n *\n * @example\n * ```typescript\n * const url = buildAuthorizationUrl('abc123...', 54321);\n * // Returns: 'https://app.spike.ac/cli/authorize?state=abc123...&callback_url=http://127.0.0.1:54321/callback'\n * ```\n *\n * @remarks\n * - The dashboard base URL can be configured via SPIKE_DASHBOARD_URL env var\n * - The callback URL always uses http://127.0.0.1 for security\n * - Both state and callback_url are URL-encoded\n *\n * @see Requirements 1.2 - CLI shall open browser with state and callback_url params\n */\nexport function buildAuthorizationUrl(state: string, callbackPort: number): string {\n const dashboardUrl = getDashboardUrl();\n const callbackUrl = `http://127.0.0.1:${callbackPort}/callback`;\n\n const url = new URL('/cli/authorize', dashboardUrl);\n url.searchParams.set('state', state);\n url.searchParams.set('callback_url', callbackUrl);\n\n return url.toString();\n}\n\n/**\n * Creates the login command for browser-based authentication.\n *\n * The login flow:\n * 1. Generate a cryptographically secure state token\n * 2. Start a callback server on localhost\n * 3. Open the browser to the dashboard consent page\n * 4. Wait for the callback with the API key\n * 5. Save the API key to config\n *\n * @returns The configured Commander command\n *\n * @example\n * ```bash\n * # Standard login flow\n * spike login\n *\n * # Login with custom timeout\n * spike login --timeout 60\n *\n * # Login without automatic browser opening\n * spike login --no-browser\n * ```\n *\n * @remarks\n * - The callback server binds to 127.0.0.1 only for security\n * - If browser fails to open, the URL is displayed for manual opening\n * - The flow times out after the configured duration (default 120 seconds)\n *\n * @see Requirements 1.1 - CLI shall generate state token and start callback server\n * @see Requirements 1.2 - CLI shall open browser to consent page\n * @see Requirements 1.3 - CLI shall display URL if browser fails to open\n * @see Requirements 1.9 - CLI shall save key from valid callback\n * @see Requirements 1.11 - CLI shall terminate on timeout\n * @see Requirements 1.13 - --no-browser flag skips automatic browser opening\n */\nexport function createLoginCommand(): Command {\n const loginCommand = new Command('login')\n .description('Authenticate the CLI via browser')\n .option(\n '-t, --timeout <seconds>',\n 'Timeout for the login flow in seconds',\n String(DEFAULT_TIMEOUT_SECONDS)\n )\n .option(\n '--no-browser',\n 'Skip automatic browser opening and display URL only'\n )\n .action(async (options: { timeout: string; browser: boolean }) => {\n await handleLogin(options);\n });\n\n return loginCommand;\n}\n\n/**\n * Handles the login command execution.\n *\n * @param options - Command options\n */\nasync function handleLogin(options: { timeout: string; browser: boolean }): Promise<void> {\n const timeoutSeconds = parseInt(options.timeout, 10);\n\n // Validate timeout\n if (isNaN(timeoutSeconds) || timeoutSeconds <= 0) {\n error('Invalid timeout value. Please provide a positive number of seconds.');\n process.exit(1);\n }\n\n const timeoutMs = timeoutSeconds * 1000;\n\n // Step 1: Generate state token\n info('Starting login flow...');\n const state = generateState();\n\n // Step 2: Start callback server\n const callbackServer = createCallbackServer();\n let serverInfo: { port: number; url: string };\n\n try {\n serverInfo = await callbackServer.start();\n } catch (err) {\n error(`Failed to start callback server: ${err instanceof Error ? err.message : String(err)}`);\n info('You can manually configure your API key with: spike config set api-key <your-key>');\n process.exit(1);\n }\n\n // Step 3: Build authorization URL\n const authUrl = buildAuthorizationUrl(state, serverInfo.port);\n\n // Step 4: Open browser or display URL\n if (options.browser) {\n info('Opening browser for authentication...');\n const browserOpened = await openBrowser(authUrl);\n\n if (!browserOpened) {\n info('Could not open browser automatically.');\n console.log('');\n info('Please open the following URL in your browser:');\n console.log('');\n console.log(` ${authUrl}`);\n console.log('');\n }\n } else {\n // --no-browser flag was provided\n info('Please open the following URL in your browser:');\n console.log('');\n console.log(` ${authUrl}`);\n console.log('');\n }\n\n info(`Waiting for authentication (timeout: ${timeoutSeconds}s)...`);\n\n // Step 5: Wait for callback\n try {\n const result = await callbackServer.waitForCallback(state, timeoutMs);\n\n if (result.success && result.apiKey) {\n // Step 6: Save API key to config\n saveConfig({ apiKey: result.apiKey });\n console.log('');\n success('Login successful! API key has been saved.');\n info('You can now use the CLI to manage your forms and submissions.');\n } else {\n console.log('');\n error(result.error || 'Login failed. Please try again.');\n process.exit(1);\n }\n } catch (err) {\n error(`Login error: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n } finally {\n // Always stop the callback server\n await callbackServer.stop();\n }\n}\n\nexport default createLoginCommand;\n","/**\n * CLI Agent Command\n *\n * Provides OpenCode AI agent integration for the Spike Forms CLI.\n * Installs a skill file that teaches the agent about all CLI commands\n * and launches OpenCode with Spike Forms knowledge.\n *\n * @module commands/agent\n * @see Requirements 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7\n */\n\nimport { Command } from 'commander';\nimport { execSync, spawn } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\nimport { success, error, info, warn } from '../output.js';\n\n/**\n * The skill file content that documents all Spike Forms CLI commands.\n * This is installed to ~/.config/opencode/skills/spike/SKILL.md\n *\n * @see Requirements 6.4, 6.5\n */\nconst SKILL_FILE_CONTENT = `# Spike Forms CLI Skill\n\nThis skill provides knowledge about the Spike Forms CLI (\\`spike\\`) commands for managing forms, submissions, projects, teams, and configuration.\n\n## Overview\n\nSpike Forms is a form backend service that handles form submissions. The CLI provides commands to manage all aspects of the service.\n\n## Authentication\n\n### Login via Browser\n\n\\`\\`\\`bash\n# Authenticate via browser (recommended)\nspike login\n\n# Login with custom timeout (in seconds)\nspike login --timeout 60\n\n# Login without automatic browser opening (displays URL to copy)\nspike login --no-browser\n\\`\\`\\`\n\nThe login command opens your browser to authorize the CLI and automatically saves your API key.\n\n### Manual Configuration\n\n\\`\\`\\`bash\n# Set API key manually\nspike config set api-key <your-api-key>\n\n# View current configuration\nspike config get api-key\nspike config get base-url\n\n# Set custom API base URL\nspike config set base-url https://custom.api.url\n\\`\\`\\`\n\n## Forms Management\n\n### List Forms\n\n\\`\\`\\`bash\n# List all forms\nspike forms list\n\n# List with options\nspike forms list --limit 10\nspike forms list --project-id <project-id>\nspike forms list --include-inactive\nspike forms list --format json\n\\`\\`\\`\n\n### Get Form Details\n\n\\`\\`\\`bash\n# Get a specific form\nspike forms get <form-id>\nspike forms get <form-id> --format json\n\\`\\`\\`\n\n### Create Forms\n\n\\`\\`\\`bash\n# Create a new form\nspike forms create --name \"Contact Form\"\nspike forms create --name \"Feedback\" --project-id <project-id>\n\\`\\`\\`\n\n### Update Forms\n\n\\`\\`\\`bash\n# Update form name\nspike forms update <form-id> --name \"New Name\"\n\n# Update form status\nspike forms update <form-id> --is-active true\nspike forms update <form-id> --is-active false\n\n# Move form to a project\nspike forms update <form-id> --project-id <project-id>\n\\`\\`\\`\n\n### Delete Forms\n\n\\`\\`\\`bash\n# Delete a form\nspike forms delete <form-id>\n\\`\\`\\`\n\n## Live Preview Workflow (Form Editing)\n\nThe CLI provides a live preview server with hot-reload for editing form HTML templates.\n\n### Edit Existing Form\n\n\\`\\`\\`bash\n# Fetch form and start live preview (foreground)\nspike forms edit <form-id>\n\n# Save to custom file path\nspike forms edit <form-id> --file ./my-form.html\n\n# Run preview server in background\nspike forms edit <form-id> --background\n\\`\\`\\`\n\n### Create Form Page (Beta)\n\n\\`\\`\\`bash\n# Create a new form and generate HTML page\nspike forms create-page --name \"Contact Form\"\n\n# Save to custom file path\nspike forms create-page --name \"Contact Form\" --file ./contact.html\n\n# Create and immediately start preview\nspike forms create-page --name \"Contact Form\" --preview\n\n# Create in a specific project\nspike forms create-page --name \"Contact Form\" --project-id <project-id>\n\\`\\`\\`\n\n### Stop Background Preview\n\n\\`\\`\\`bash\n# Stop the background preview server\nspike forms stop-preview\n\\`\\`\\`\n\n### Live Preview Features\n\n- **Hot Reload**: Changes to the HTML file automatically refresh the browser\n- **SSE Connection**: Uses Server-Sent Events for instant updates\n- **Local Server**: Runs on http://127.0.0.1 with a dynamic port\n- **Background Mode**: Run the server detached and continue working\n\n## Submissions Management\n\n### List Submissions\n\n\\`\\`\\`bash\n# List submissions for a form\nspike submissions list --form-id <form-id>\n\n# List with options\nspike submissions list --form-id <form-id> --limit 20\nspike submissions list --form-id <form-id> --format json\n\\`\\`\\`\n\n### Get Submission Details\n\n\\`\\`\\`bash\n# Get a specific submission\nspike submissions get <submission-id>\nspike submissions get <submission-id> --format json\n\\`\\`\\`\n\n### Delete Submissions\n\n\\`\\`\\`bash\n# Delete a submission\nspike submissions delete <submission-id>\n\\`\\`\\`\n\n## Projects Management\n\n### List Projects\n\n\\`\\`\\`bash\n# List all projects\nspike projects list\nspike projects list --format json\n\\`\\`\\`\n\n### Get Project Details\n\n\\`\\`\\`bash\n# Get a specific project\nspike projects get <project-id>\n\\`\\`\\`\n\n### Create Projects\n\n\\`\\`\\`bash\n# Create a new project\nspike projects create --name \"My Project\"\nspike projects create --name \"My Project\" --team-id <team-id>\n\\`\\`\\`\n\n### Update Projects\n\n\\`\\`\\`bash\n# Update project name\nspike projects update <project-id> --name \"New Name\"\n\\`\\`\\`\n\n### Delete Projects\n\n\\`\\`\\`bash\n# Delete a project\nspike projects delete <project-id>\n\\`\\`\\`\n\n## Teams Management\n\n### List Teams\n\n\\`\\`\\`bash\n# List all teams\nspike teams list\nspike teams list --format json\n\\`\\`\\`\n\n### Get Team Details\n\n\\`\\`\\`bash\n# Get a specific team\nspike teams get <team-id>\n\\`\\`\\`\n\n### Create Teams\n\n\\`\\`\\`bash\n# Create a new team\nspike teams create --name \"My Team\"\n\\`\\`\\`\n\n### Update Teams\n\n\\`\\`\\`bash\n# Update team name\nspike teams update <team-id> --name \"New Name\"\n\\`\\`\\`\n\n### Delete Teams\n\n\\`\\`\\`bash\n# Delete a team\nspike teams delete <team-id>\n\\`\\`\\`\n\n## Configuration Commands\n\n\\`\\`\\`bash\n# Get configuration values\nspike config get api-key\nspike config get base-url\n\n# Set configuration values\nspike config set api-key <your-api-key>\nspike config set base-url <api-url>\n\n# Configuration file location: ~/.spike/config.json\n\\`\\`\\`\n\n## Global Options\n\nAll commands support these global options:\n\n\\`\\`\\`bash\n# Output format (json or table)\nspike <command> --format json\nspike <command> --format table\n\n# Help\nspike --help\nspike <command> --help\n\\`\\`\\`\n\n## Common Workflows\n\n### Setting Up a New Form\n\n1. Login to authenticate: \\`spike login\\`\n2. Create a form: \\`spike forms create --name \"Contact Form\"\\`\n3. Edit with live preview: \\`spike forms edit <form-id>\\`\n4. Make changes to the HTML file and see them instantly in the browser\n\n### Managing Form Submissions\n\n1. List forms: \\`spike forms list\\`\n2. View submissions: \\`spike submissions list --form-id <form-id>\\`\n3. Get submission details: \\`spike submissions get <submission-id>\\`\n\n### Organizing with Projects and Teams\n\n1. Create a team: \\`spike teams create --name \"Marketing\"\\`\n2. Create a project: \\`spike projects create --name \"Website Forms\" --team-id <team-id>\\`\n3. Create forms in the project: \\`spike forms create --name \"Contact\" --project-id <project-id>\\`\n\n## Environment Variables\n\n- \\`SPIKE_API_KEY\\` or \\`SPIKE_TOKEN\\`: API key for authentication\n- \\`SPIKE_API_URL\\`: Custom API base URL\n- \\`SPIKE_DASHBOARD_URL\\`: Custom dashboard URL for login flow\n`;\n\n/**\n * Gets the path to the OpenCode skills directory for Spike.\n *\n * @returns The absolute path to ~/.config/opencode/skills/spike/\n */\nfunction getSkillsDir(): string {\n const homeDir = os.homedir();\n return path.join(homeDir, '.config', 'opencode', 'skills', 'spike');\n}\n\n/**\n * Gets the path to the skill file.\n *\n * @returns The absolute path to ~/.config/opencode/skills/spike/SKILL.md\n */\nfunction getSkillFilePath(): string {\n return path.join(getSkillsDir(), 'SKILL.md');\n}\n\n/**\n * Checks if OpenCode is installed on the system.\n *\n * Uses `which opencode` on macOS/Linux or `where opencode` on Windows\n * to check if the opencode binary is available in the PATH.\n *\n * @returns true if OpenCode is installed, false otherwise\n *\n * @example\n * ```typescript\n * if (isOpenCodeInstalled()) {\n * console.log('OpenCode is available');\n * } else {\n * console.log('OpenCode is not installed');\n * }\n * ```\n *\n * @see Requirements 6.1\n */\nexport function isOpenCodeInstalled(): boolean {\n try {\n const command = process.platform === 'win32' ? 'where opencode' : 'which opencode';\n execSync(command, { stdio: 'ignore' });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Ensures the Spike Forms skill file is installed for OpenCode.\n *\n * Creates the skills directory if it doesn't exist and writes\n * the SKILL.md file with documentation for all CLI commands.\n *\n * @throws Error if unable to create directory or write file\n *\n * @example\n * ```typescript\n * ensureSkillInstalled();\n * // Skill file is now at ~/.config/opencode/skills/spike/SKILL.md\n * ```\n *\n * @see Requirements 6.4, 6.5\n */\nexport function ensureSkillInstalled(): void {\n const skillsDir = getSkillsDir();\n const skillFilePath = getSkillFilePath();\n\n // Create the skills directory if it doesn't exist\n if (!fs.existsSync(skillsDir)) {\n fs.mkdirSync(skillsDir, { recursive: true });\n }\n\n // Write the skill file\n fs.writeFileSync(skillFilePath, SKILL_FILE_CONTENT, 'utf-8');\n}\n\n/**\n * Installs OpenCode via npm.\n *\n * @returns true if installation succeeded, false otherwise\n */\nfunction installOpenCode(): boolean {\n try {\n info('Installing OpenCode via npm...');\n execSync('npm install -g opencode', { stdio: 'inherit' });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Creates the agent command for OpenCode integration.\n *\n * The agent command:\n * 1. Checks if OpenCode is installed\n * 2. Optionally installs OpenCode if --install flag is provided\n * 3. Installs the Spike Forms skill file\n * 4. Launches OpenCode with the specified model (if provided)\n * 5. Exits with the same code as OpenCode\n *\n * @returns The configured Commander command\n *\n * @example\n * ```bash\n * # Launch OpenCode with Spike Forms knowledge\n * spike agent\n *\n * # Install OpenCode if not present and launch\n * spike agent --install\n *\n * # Launch with a specific model\n * spike agent --model gpt-4\n * ```\n *\n * @see Requirements 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7\n */\nexport function createAgentCommand(): Command {\n const agentCommand = new Command('agent')\n .description('Launch OpenCode AI agent with Spike Forms knowledge')\n .option('--install', 'Install OpenCode via npm if not already installed')\n .option('--model <model>', 'Model to use with OpenCode')\n .action(async (options: { install?: boolean; model?: string }) => {\n await handleAgent(options);\n });\n\n return agentCommand;\n}\n\n/**\n * Handles the agent command execution.\n *\n * @param options - Command options\n */\nasync function handleAgent(options: { install?: boolean; model?: string }): Promise<void> {\n // Step 1: Check if OpenCode is installed\n if (!isOpenCodeInstalled()) {\n if (options.install) {\n // Step 2: Try to install OpenCode\n const installed = installOpenCode();\n if (!installed) {\n error('Failed to install OpenCode via npm.');\n info('Please install OpenCode manually:');\n console.log('');\n console.log(' npm install -g opencode');\n console.log('');\n info('Or visit: https://opencode.ai for more installation options.');\n process.exit(1);\n }\n success('OpenCode installed successfully');\n } else {\n // Step 3: Display installation instructions\n error('OpenCode is not installed.');\n info('Install OpenCode using one of these methods:');\n console.log('');\n console.log(' # Install via npm');\n console.log(' npm install -g opencode');\n console.log('');\n console.log(' # Or use the --install flag');\n console.log(' spike agent --install');\n console.log('');\n info('Or visit: https://opencode.ai for more installation options.');\n process.exit(1);\n }\n }\n\n // Step 4: Install the skill file\n try {\n ensureSkillInstalled();\n info('Spike Forms skill installed for OpenCode');\n } catch (err) {\n // Display warning but continue launching OpenCode\n warn(`Could not install skill file: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n // Step 5: Build OpenCode command arguments\n const args: string[] = [];\n if (options.model) {\n args.push('--model', options.model);\n }\n\n // Step 6: Launch OpenCode with stdio: 'inherit'\n info('Launching OpenCode...');\n console.log('');\n\n const opencode = spawn('opencode', args, {\n stdio: 'inherit',\n });\n\n // Step 7: Exit with the same code as OpenCode\n opencode.on('close', (code) => {\n process.exit(code ?? 0);\n });\n\n opencode.on('error', (err) => {\n error(`Failed to launch OpenCode: ${err.message}`);\n process.exit(1);\n });\n}\n\nexport default createAgentCommand;\n","/**\n * @spike-forms/cli - Command-line interface for the Spike Forms API\n *\n * This is the main entry point for the CLI. It sets up the Commander program\n * and registers all command modules.\n *\n * @module index\n * @see Requirements 14.4\n */\n\nimport { Command } from 'commander';\nimport { createConfigCommand } from './commands/config.js';\nimport { createFormsCommand } from './commands/forms.js';\nimport { createSubmissionsCommand } from './commands/submissions.js';\nimport { createProjectsCommand } from './commands/projects.js';\nimport { createTeamsCommand } from './commands/teams.js';\nimport { createUserCommand } from './commands/user.js';\nimport { createLoginCommand } from './commands/login.js';\nimport { createAgentCommand } from './commands/agent.js';\nimport { error } from './output.js';\n\n/**\n * The main Commander program instance.\n */\nconst program = new Command();\n\n/**\n * Configure the main program with name, description, and version.\n */\nprogram\n .name('spike')\n .description('Command-line interface for the Spike Forms API')\n .version('0.1.0');\n\n/**\n * Add global --format option that applies to all commands.\n * Individual commands can override this with their own --format option.\n *\n * @see Requirements 14.1, 14.2\n */\nprogram.option(\n '-f, --format <format>',\n 'Output format (json, table)',\n 'table'\n);\n\n/**\n * Register all command modules.\n */\nprogram.addCommand(createConfigCommand());\nprogram.addCommand(createFormsCommand());\nprogram.addCommand(createSubmissionsCommand());\nprogram.addCommand(createProjectsCommand());\nprogram.addCommand(createTeamsCommand());\nprogram.addCommand(createUserCommand());\nprogram.addCommand(createLoginCommand());\nprogram.addCommand(createAgentCommand());\n\n/**\n * Main execution function.\n *\n * Parses command-line arguments and handles any unhandled errors.\n * Sets appropriate exit codes based on success or failure.\n *\n * @see Requirements 14.4 - CLI exits with code 0 on success, 1 on error\n */\nasync function main(): Promise<void> {\n try {\n await program.parseAsync(process.argv);\n // If we reach here without an error, the command succeeded\n // Exit code defaults to 0 (success)\n } catch (err) {\n // Handle any unhandled errors from command execution\n handleFatalError(err);\n }\n}\n\n/**\n * Handles fatal errors that occur during command execution.\n *\n * Displays an error message and sets the exit code to 1.\n *\n * @param err - The error that occurred\n */\nfunction handleFatalError(err: unknown): void {\n if (err instanceof Error) {\n error(err.message);\n } else {\n error('An unexpected error occurred');\n }\n\n // Use process.exitCode for cleaner handling\n // This allows any pending I/O to complete before exiting\n process.exitCode = 1;\n}\n\n/**\n * Handle uncaught exceptions at the process level.\n *\n * This ensures that any uncaught exceptions result in exit code 1.\n */\nprocess.on('uncaughtException', (err) => {\n handleFatalError(err);\n // For uncaught exceptions, we need to exit immediately\n process.exit(1);\n});\n\n/**\n * Handle unhandled promise rejections at the process level.\n *\n * This ensures that any unhandled rejections result in exit code 1.\n */\nprocess.on('unhandledRejection', (reason) => {\n handleFatalError(reason instanceof Error ? reason : new Error(String(reason)));\n // For unhandled rejections, we need to exit immediately\n process.exit(1);\n});\n\n// Execute the main function\nmain();\n"]}
|