@openacp/cli 0.2.22 → 0.2.24

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.
Files changed (44) hide show
  1. package/dist/autostart-YBYXQA77.js +18 -0
  2. package/dist/autostart-YBYXQA77.js.map +1 -0
  3. package/dist/{setup-XQBEZZQB.js → chunk-4BN7NSKB.js} +140 -9
  4. package/dist/chunk-4BN7NSKB.js.map +1 -0
  5. package/dist/chunk-CQMS5U7Z.js +63 -0
  6. package/dist/chunk-CQMS5U7Z.js.map +1 -0
  7. package/dist/{chunk-XOVJLTEC.js → chunk-FGXG3H3F.js} +14 -58
  8. package/dist/chunk-FGXG3H3F.js.map +1 -0
  9. package/dist/{chunk-HTXK4NLG.js → chunk-IX63F4JG.js} +463 -44
  10. package/dist/chunk-IX63F4JG.js.map +1 -0
  11. package/dist/{chunk-ZATQZUJT.js → chunk-MNJDYDGH.js} +9 -1
  12. package/dist/{chunk-ZATQZUJT.js.map → chunk-MNJDYDGH.js.map} +1 -1
  13. package/dist/chunk-PQRVTUNH.js +145 -0
  14. package/dist/chunk-PQRVTUNH.js.map +1 -0
  15. package/dist/chunk-QWUJIKTX.js +527 -0
  16. package/dist/chunk-QWUJIKTX.js.map +1 -0
  17. package/dist/chunk-S6O7SM6A.js +129 -0
  18. package/dist/chunk-S6O7SM6A.js.map +1 -0
  19. package/dist/chunk-WXS6ONOD.js +103 -0
  20. package/dist/chunk-WXS6ONOD.js.map +1 -0
  21. package/dist/cli.js +354 -4
  22. package/dist/cli.js.map +1 -1
  23. package/dist/config-2XALNLAA.js +14 -0
  24. package/dist/config-2XALNLAA.js.map +1 -0
  25. package/dist/config-editor-56B6YU7B.js +11 -0
  26. package/dist/config-editor-56B6YU7B.js.map +1 -0
  27. package/dist/daemon-3E5OMLT3.js +29 -0
  28. package/dist/daemon-3E5OMLT3.js.map +1 -0
  29. package/dist/index.d.ts +96 -18
  30. package/dist/index.js +35 -6
  31. package/dist/install-cloudflared-57NRTI4E.js +8 -0
  32. package/dist/install-cloudflared-57NRTI4E.js.map +1 -0
  33. package/dist/{main-GC6JY7DS.js → main-YNCSLYVV.js} +43 -11
  34. package/dist/main-YNCSLYVV.js.map +1 -0
  35. package/dist/setup-FTNJACSC.js +27 -0
  36. package/dist/setup-FTNJACSC.js.map +1 -0
  37. package/dist/{tunnel-service-I6NUMBT4.js → tunnel-service-I6WM6USB.js} +10 -10
  38. package/dist/tunnel-service-I6WM6USB.js.map +1 -0
  39. package/package.json +2 -2
  40. package/dist/chunk-HTXK4NLG.js.map +0 -1
  41. package/dist/chunk-XOVJLTEC.js.map +0 -1
  42. package/dist/main-GC6JY7DS.js.map +0 -1
  43. package/dist/setup-XQBEZZQB.js.map +0 -1
  44. package/dist/tunnel-service-I6NUMBT4.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/config-editor.ts"],"sourcesContent":["import { select, input } from '@inquirer/prompts'\nimport type { Config, ConfigManager } from './config.js'\nimport { validateBotToken, validateChatId } from './setup.js'\nimport { installAutoStart, uninstallAutoStart, isAutoStartInstalled, isAutoStartSupported } from './autostart.js'\nimport { expandHome } from './config.js'\n\n// ANSI color helpers\nconst c = {\n reset: '\\x1b[0m',\n bold: '\\x1b[1m',\n dim: '\\x1b[2m',\n green: '\\x1b[32m',\n yellow: '\\x1b[33m',\n cyan: '\\x1b[36m',\n}\n\nconst ok = (msg: string) => `${c.green}${c.bold}✓${c.reset} ${c.green}${msg}${c.reset}`\nconst warn = (msg: string) => `${c.yellow}⚠ ${msg}${c.reset}`\nconst dim = (msg: string) => `${c.dim}${msg}${c.reset}`\nconst header = (title: string) => `\\n${c.cyan}${c.bold}[${title}]${c.reset}\\n`\n\ntype ConfigUpdates = Record<string, unknown>\n\n// --- Edit: Telegram ---\n\nasync function editTelegram(config: Config, updates: ConfigUpdates): Promise<void> {\n const tg = (config.channels?.telegram ?? {}) as Record<string, unknown>\n const currentToken = (tg.botToken as string) ?? ''\n const currentChatId = (tg.chatId as number) ?? 0\n\n console.log(header('Telegram'))\n const tokenDisplay = currentToken.length > 12\n ? currentToken.slice(0, 6) + '...' + currentToken.slice(-6)\n : currentToken || dim('(not set)')\n console.log(` Bot Token : ${tokenDisplay}`)\n console.log(` Chat ID : ${currentChatId || dim('(not set)')}`)\n console.log('')\n\n while (true) {\n const choice = await select({\n message: 'Telegram settings:',\n choices: [\n { name: 'Change Bot Token', value: 'token' },\n { name: 'Change Chat ID', value: 'chatid' },\n { name: 'Back', value: 'back' },\n ],\n })\n\n if (choice === 'back') break\n\n if (choice === 'token') {\n const token = await input({\n message: 'New bot token:',\n default: currentToken,\n validate: (val) => val.trim().length > 0 || 'Token cannot be empty',\n })\n\n const result = await validateBotToken(token.trim())\n if (result.ok) {\n console.log(ok(`Connected to @${result.botUsername}`))\n } else {\n console.log(warn(`Validation failed: ${result.error} — saving anyway`))\n }\n\n if (!updates.channels) updates.channels = {}\n if (!(updates.channels as Record<string, unknown>).telegram) {\n (updates.channels as Record<string, unknown>).telegram = {}\n }\n ;((updates.channels as Record<string, unknown>).telegram as Record<string, unknown>).botToken = token.trim()\n }\n\n if (choice === 'chatid') {\n const chatIdStr = await input({\n message: 'New chat ID (e.g. -1001234567890):',\n default: String(currentChatId),\n validate: (val) => {\n const n = Number(val.trim())\n if (isNaN(n) || !Number.isInteger(n)) return 'Chat ID must be an integer'\n return true\n },\n })\n\n const chatId = Number(chatIdStr.trim())\n\n // Use the current (or already-updated) token for validation\n const tokenForValidation = (() => {\n if (updates.channels) {\n const ch = updates.channels as Record<string, unknown>\n if (ch.telegram) {\n const tgUp = ch.telegram as Record<string, unknown>\n if (typeof tgUp.botToken === 'string') return tgUp.botToken\n }\n }\n return currentToken\n })()\n\n const result = await validateChatId(tokenForValidation, chatId)\n if (result.ok) {\n console.log(ok(`Group: ${result.title}${result.isForum ? '' : warn(' (topics not enabled)')}`))\n } else {\n console.log(warn(`Validation failed: ${result.error} — saving anyway`))\n }\n\n if (!updates.channels) updates.channels = {}\n if (!(updates.channels as Record<string, unknown>).telegram) {\n (updates.channels as Record<string, unknown>).telegram = {}\n }\n ;((updates.channels as Record<string, unknown>).telegram as Record<string, unknown>).chatId = chatId\n }\n }\n}\n\n// --- Edit: Agent ---\n\nasync function editAgent(config: Config, updates: ConfigUpdates): Promise<void> {\n const agentNames = Object.keys(config.agents ?? {})\n const currentDefault = config.defaultAgent\n\n console.log(header('Agent'))\n console.log(` Default agent : ${c.bold}${currentDefault}${c.reset}`)\n console.log(` Available : ${agentNames.join(', ') || dim('(none)')}`)\n console.log('')\n\n while (true) {\n const choice = await select({\n message: 'Agent settings:',\n choices: [\n { name: 'Change default agent', value: 'default' },\n { name: 'Back', value: 'back' },\n ],\n })\n\n if (choice === 'back') break\n\n if (choice === 'default') {\n if (agentNames.length === 0) {\n console.log(warn('No agents configured.'))\n continue\n }\n\n const chosen = await select({\n message: 'Select default agent:',\n choices: agentNames.map((name) => ({ name, value: name })),\n })\n\n updates.defaultAgent = chosen\n console.log(ok(`Default agent set to ${chosen}`))\n }\n }\n}\n\n// --- Edit: Workspace ---\n\nasync function editWorkspace(config: Config, updates: ConfigUpdates): Promise<void> {\n const currentDir = config.workspace?.baseDir ?? '~/openacp-workspace'\n\n console.log(header('Workspace'))\n console.log(` Base directory : ${currentDir}`)\n console.log('')\n\n const newDir = await input({\n message: 'Workspace base directory:',\n default: currentDir,\n validate: (val) => val.trim().length > 0 || 'Path cannot be empty',\n })\n\n updates.workspace = { baseDir: newDir.trim() }\n console.log(ok(`Workspace set to ${newDir.trim()}`))\n}\n\n// --- Edit: Security ---\n\nasync function editSecurity(config: Config, updates: ConfigUpdates): Promise<void> {\n const sec = config.security ?? { allowedUserIds: [], maxConcurrentSessions: 5, sessionTimeoutMinutes: 60 }\n\n console.log(header('Security'))\n console.log(` Allowed user IDs : ${sec.allowedUserIds?.length ? sec.allowedUserIds.join(', ') : dim('(all users allowed)')}`)\n console.log(` Max concurrent sessions : ${sec.maxConcurrentSessions}`)\n console.log(` Session timeout (min) : ${sec.sessionTimeoutMinutes}`)\n console.log('')\n\n while (true) {\n const choice = await select({\n message: 'Security settings:',\n choices: [\n { name: 'Max concurrent sessions', value: 'maxSessions' },\n { name: 'Session timeout (minutes)', value: 'timeout' },\n { name: 'Back', value: 'back' },\n ],\n })\n\n if (choice === 'back') break\n\n if (choice === 'maxSessions') {\n const val = await input({\n message: 'Max concurrent sessions:',\n default: String(sec.maxConcurrentSessions),\n validate: (v) => {\n const n = Number(v.trim())\n if (!Number.isInteger(n) || n < 1) return 'Must be a positive integer'\n return true\n },\n })\n\n if (!updates.security) updates.security = {}\n ;(updates.security as Record<string, unknown>).maxConcurrentSessions = Number(val.trim())\n console.log(ok(`Max concurrent sessions set to ${val.trim()}`))\n }\n\n if (choice === 'timeout') {\n const val = await input({\n message: 'Session timeout in minutes:',\n default: String(sec.sessionTimeoutMinutes),\n validate: (v) => {\n const n = Number(v.trim())\n if (!Number.isInteger(n) || n < 1) return 'Must be a positive integer'\n return true\n },\n })\n\n if (!updates.security) updates.security = {}\n ;(updates.security as Record<string, unknown>).sessionTimeoutMinutes = Number(val.trim())\n console.log(ok(`Session timeout set to ${val.trim()} minutes`))\n }\n }\n}\n\n// --- Edit: Logging ---\n\nasync function editLogging(config: Config, updates: ConfigUpdates): Promise<void> {\n const logging = config.logging ?? { level: 'info', logDir: '~/.openacp/logs', maxFileSize: '10m', maxFiles: 7, sessionLogRetentionDays: 30 }\n\n console.log(header('Logging'))\n console.log(` Log level : ${logging.level}`)\n console.log(` Log dir : ${logging.logDir}`)\n console.log('')\n\n while (true) {\n const choice = await select({\n message: 'Logging settings:',\n choices: [\n { name: 'Log level', value: 'level' },\n { name: 'Log directory', value: 'logDir' },\n { name: 'Back', value: 'back' },\n ],\n })\n\n if (choice === 'back') break\n\n if (choice === 'level') {\n const level = await select({\n message: 'Select log level:',\n choices: [\n { name: 'silent', value: 'silent' },\n { name: 'debug', value: 'debug' },\n { name: 'info', value: 'info' },\n { name: 'warn', value: 'warn' },\n { name: 'error', value: 'error' },\n { name: 'fatal', value: 'fatal' },\n ],\n })\n\n if (!updates.logging) updates.logging = {}\n ;(updates.logging as Record<string, unknown>).level = level\n console.log(ok(`Log level set to ${level}`))\n }\n\n if (choice === 'logDir') {\n const dir = await input({\n message: 'Log directory:',\n default: logging.logDir,\n validate: (val) => val.trim().length > 0 || 'Path cannot be empty',\n })\n\n if (!updates.logging) updates.logging = {}\n ;(updates.logging as Record<string, unknown>).logDir = dir.trim()\n console.log(ok(`Log directory set to ${dir.trim()}`))\n }\n }\n}\n\n// --- Edit: Run Mode ---\n\nasync function editRunMode(config: Config, updates: ConfigUpdates): Promise<void> {\n const currentMode = config.runMode ?? 'foreground'\n const currentAutoStart = config.autoStart ?? false\n const autoStartInstalled = isAutoStartInstalled()\n const autoStartSupported = isAutoStartSupported()\n\n console.log(header('Run Mode'))\n console.log(` Current mode : ${c.bold}${currentMode}${c.reset}`)\n console.log(` Auto-start : ${currentAutoStart ? ok('enabled') : dim('disabled')}${autoStartInstalled ? ` ${dim('(installed)')}` : ''}`)\n console.log('')\n\n while (true) {\n const isDaemon = (() => {\n if ('runMode' in updates) return updates.runMode === 'daemon'\n return currentMode === 'daemon'\n })()\n\n const choices = [\n isDaemon\n ? { name: 'Switch to foreground mode', value: 'foreground' }\n : { name: 'Switch to daemon mode', value: 'daemon' },\n ]\n\n if (autoStartSupported) {\n const autoStartCurrent = (() => {\n if ('autoStart' in updates) return updates.autoStart as boolean\n return currentAutoStart\n })()\n choices.push({\n name: autoStartCurrent ? 'Disable auto-start' : 'Enable auto-start',\n value: 'toggleAutoStart',\n })\n }\n\n choices.push({ name: 'Back', value: 'back' })\n\n const choice = await select({\n message: 'Run mode settings:',\n choices,\n })\n\n if (choice === 'back') break\n\n if (choice === 'daemon') {\n updates.runMode = 'daemon'\n const logDir = (config.logging?.logDir) ?? '~/.openacp/logs'\n const result = installAutoStart(expandHome(logDir))\n if (result.success) {\n updates.autoStart = true\n console.log(ok('Switched to daemon mode with auto-start'))\n } else {\n console.log(warn(`Switched to daemon mode (auto-start failed: ${result.error})`))\n }\n }\n\n if (choice === 'foreground') {\n updates.runMode = 'foreground'\n updates.autoStart = false\n uninstallAutoStart()\n console.log(ok('Switched to foreground mode'))\n }\n\n if (choice === 'toggleAutoStart') {\n const autoStartCurrent = (() => {\n if ('autoStart' in updates) return updates.autoStart as boolean\n return currentAutoStart\n })()\n\n if (autoStartCurrent) {\n const result = uninstallAutoStart()\n updates.autoStart = false\n if (result.success) {\n console.log(ok('Auto-start disabled'))\n } else {\n console.log(warn(`Auto-start uninstall failed: ${result.error}`))\n }\n } else {\n const logDir = (config.logging?.logDir) ?? '~/.openacp/logs'\n const result = installAutoStart(expandHome(logDir))\n updates.autoStart = result.success\n if (result.success) {\n console.log(ok('Auto-start enabled'))\n } else {\n console.log(warn(`Auto-start install failed: ${result.error}`))\n }\n }\n }\n }\n}\n\n// --- Edit: API ---\n\nasync function editApi(config: Config, updates: ConfigUpdates): Promise<void> {\n const api = config.api ?? { port: 21420, host: '127.0.0.1' }\n\n console.log(header('API'))\n console.log(` Port : ${api.port}`)\n console.log(` Host : ${api.host} ${dim('(localhost only)')}`)\n console.log('')\n\n const newPort = await input({\n message: 'API port:',\n default: String(api.port),\n validate: (v) => {\n const n = Number(v.trim())\n if (!Number.isInteger(n) || n < 1 || n > 65535) return 'Must be a valid port (1-65535)'\n return true\n },\n })\n\n updates.api = { port: Number(newPort.trim()) }\n console.log(ok(`API port set to ${newPort.trim()}`))\n}\n\n// --- Edit: Tunnel ---\n\nasync function editTunnel(config: Config, updates: ConfigUpdates): Promise<void> {\n const tunnel = config.tunnel ?? { enabled: false, port: 3100, provider: 'cloudflare', options: {}, storeTtlMinutes: 60, auth: { enabled: false } }\n const currentUpdates = (updates.tunnel ?? {}) as Record<string, unknown>\n\n const getVal = <T>(key: string, fallback: T): T =>\n (key in currentUpdates ? currentUpdates[key] : (tunnel as Record<string, unknown>)[key] ?? fallback) as T\n\n console.log(header('Tunnel'))\n console.log(` Enabled : ${getVal('enabled', false) ? ok('yes') : dim('no')}`)\n console.log(` Provider : ${c.bold}${getVal('provider', 'cloudflare')}${c.reset}`)\n console.log(` Port : ${getVal('port', 3100)}`)\n const authEnabled = (getVal('auth', { enabled: false }) as { enabled: boolean }).enabled\n console.log(` Auth : ${authEnabled ? ok('enabled') : dim('disabled')}`)\n console.log('')\n\n while (true) {\n const choice = await select({\n message: 'Tunnel settings:',\n choices: [\n { name: getVal('enabled', false) ? 'Disable tunnel' : 'Enable tunnel', value: 'toggle' },\n { name: 'Change provider', value: 'provider' },\n { name: 'Change port', value: 'port' },\n { name: 'Provider options', value: 'options' },\n { name: authEnabled ? 'Disable auth' : 'Enable auth', value: 'auth' },\n { name: 'Back', value: 'back' },\n ],\n })\n\n if (choice === 'back') break\n\n if (!updates.tunnel) updates.tunnel = { ...tunnel }\n const tun = updates.tunnel as Record<string, unknown>\n\n if (choice === 'toggle') {\n const current = getVal('enabled', false)\n tun.enabled = !current\n console.log(!current ? ok('Tunnel enabled') : ok('Tunnel disabled'))\n }\n\n if (choice === 'provider') {\n const provider = await select({\n message: 'Select tunnel provider:',\n choices: [\n { name: 'Cloudflare (default)', value: 'cloudflare' },\n { name: 'ngrok', value: 'ngrok' },\n { name: 'bore', value: 'bore' },\n { name: 'Tailscale Funnel', value: 'tailscale' },\n ],\n })\n tun.provider = provider\n tun.options = {} // reset options when switching provider\n console.log(ok(`Provider set to ${provider}`))\n }\n\n if (choice === 'port') {\n const val = await input({\n message: 'Tunnel port:',\n default: String(getVal('port', 3100)),\n validate: (v) => {\n const n = Number(v.trim())\n if (!Number.isInteger(n) || n < 1 || n > 65535) return 'Must be a valid port (1-65535)'\n return true\n },\n })\n tun.port = Number(val.trim())\n console.log(ok(`Tunnel port set to ${val.trim()}`))\n }\n\n if (choice === 'options') {\n const provider = getVal('provider', 'cloudflare')\n const currentOptions = getVal('options', {}) as Record<string, unknown>\n await editProviderOptions(provider, currentOptions, tun)\n }\n\n if (choice === 'auth') {\n const currentAuth = getVal('auth', { enabled: false }) as { enabled: boolean; token?: string }\n if (currentAuth.enabled) {\n tun.auth = { enabled: false }\n console.log(ok('Tunnel auth disabled'))\n } else {\n const token = await input({\n message: 'Auth token (leave empty to auto-generate):',\n default: '',\n })\n tun.auth = token.trim()\n ? { enabled: true, token: token.trim() }\n : { enabled: true }\n console.log(ok('Tunnel auth enabled'))\n }\n }\n }\n}\n\nasync function editProviderOptions(\n provider: string,\n currentOptions: Record<string, unknown>,\n tun: Record<string, unknown>,\n): Promise<void> {\n if (provider === 'cloudflare') {\n const domain = await input({\n message: 'Custom domain (leave empty for random):',\n default: (currentOptions.domain as string) ?? '',\n })\n tun.options = domain.trim() ? { domain: domain.trim() } : {}\n if (domain.trim()) console.log(ok(`Domain set to ${domain.trim()}`))\n else console.log(dim('Using random cloudflare domain'))\n } else if (provider === 'ngrok') {\n const authtoken = await input({\n message: 'ngrok authtoken (leave empty to skip):',\n default: (currentOptions.authtoken as string) ?? '',\n })\n const domain = await input({\n message: 'ngrok domain (leave empty for random):',\n default: (currentOptions.domain as string) ?? '',\n })\n const region = await input({\n message: 'ngrok region (us, eu, ap — leave empty for default):',\n default: (currentOptions.region as string) ?? '',\n })\n const opts: Record<string, string> = {}\n if (authtoken.trim()) opts.authtoken = authtoken.trim()\n if (domain.trim()) opts.domain = domain.trim()\n if (region.trim()) opts.region = region.trim()\n tun.options = opts\n console.log(ok('ngrok options saved'))\n } else if (provider === 'bore') {\n const server = await input({\n message: 'bore server:',\n default: (currentOptions.server as string) ?? 'bore.pub',\n })\n const port = await input({\n message: 'bore port (leave empty for auto):',\n default: currentOptions.port ? String(currentOptions.port) : '',\n })\n const secret = await input({\n message: 'bore secret (leave empty to skip):',\n default: (currentOptions.secret as string) ?? '',\n })\n const opts: Record<string, unknown> = { server: server.trim() }\n if (port.trim()) opts.port = Number(port.trim())\n if (secret.trim()) opts.secret = secret.trim()\n tun.options = opts\n console.log(ok('bore options saved'))\n } else if (provider === 'tailscale') {\n const bg = await select({\n message: 'Run Tailscale Funnel in background?',\n choices: [\n { name: 'No', value: 'no' },\n { name: 'Yes', value: 'yes' },\n ],\n })\n tun.options = bg === 'yes' ? { bg: true } : {}\n console.log(ok('Tailscale options saved'))\n } else {\n console.log(dim(`No configurable options for provider \"${provider}\"`))\n }\n}\n\n// --- Main Config Editor ---\n\nexport async function runConfigEditor(configManager: ConfigManager): Promise<void> {\n await configManager.load()\n const config = configManager.get()\n const updates: ConfigUpdates = {}\n\n console.log(`\\n${c.cyan}${c.bold}OpenACP Config Editor${c.reset}`)\n console.log(dim(`Config: ${configManager.getConfigPath()}`))\n console.log('')\n\n try {\n while (true) {\n const hasChanges = Object.keys(updates).length > 0\n const choice = await select({\n message: `What would you like to edit?${hasChanges ? ` ${c.yellow}(unsaved changes)${c.reset}` : ''}`,\n choices: [\n { name: 'Telegram', value: 'telegram' },\n { name: 'Agent', value: 'agent' },\n { name: 'Workspace', value: 'workspace' },\n { name: 'Security', value: 'security' },\n { name: 'Logging', value: 'logging' },\n { name: 'Run Mode', value: 'runMode' },\n { name: 'API', value: 'api' },\n { name: 'Tunnel', value: 'tunnel' },\n { name: hasChanges ? 'Save & Exit' : 'Exit', value: 'exit' },\n ],\n })\n\n if (choice === 'exit') {\n if (hasChanges) {\n await configManager.save(updates)\n console.log(ok(`Config saved to ${configManager.getConfigPath()}`))\n } else {\n console.log(dim('No changes made.'))\n }\n break\n }\n\n if (choice === 'telegram') await editTelegram(config, updates)\n else if (choice === 'agent') await editAgent(config, updates)\n else if (choice === 'workspace') await editWorkspace(config, updates)\n else if (choice === 'security') await editSecurity(config, updates)\n else if (choice === 'logging') await editLogging(config, updates)\n else if (choice === 'runMode') await editRunMode(config, updates)\n else if (choice === 'api') await editApi(config, updates)\n else if (choice === 'tunnel') await editTunnel(config, updates)\n }\n } catch (err) {\n if ((err as Error).name === 'ExitPromptError') {\n console.log(dim('\\nConfig editor cancelled. Changes discarded.'))\n return\n }\n throw err\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,129 @@
1
+ import {
2
+ expandHome
3
+ } from "./chunk-FGXG3H3F.js";
4
+
5
+ // src/core/daemon.ts
6
+ import { spawn } from "child_process";
7
+ import * as fs from "fs";
8
+ import * as path from "path";
9
+ import * as os from "os";
10
+ var DEFAULT_PID_PATH = path.join(os.homedir(), ".openacp", "openacp.pid");
11
+ var DEFAULT_LOG_DIR = path.join(os.homedir(), ".openacp", "logs");
12
+ var RUNNING_MARKER = path.join(os.homedir(), ".openacp", "running");
13
+ function writePidFile(pidPath, pid) {
14
+ const dir = path.dirname(pidPath);
15
+ fs.mkdirSync(dir, { recursive: true });
16
+ fs.writeFileSync(pidPath, String(pid));
17
+ }
18
+ function readPidFile(pidPath) {
19
+ try {
20
+ const content = fs.readFileSync(pidPath, "utf-8").trim();
21
+ const pid = parseInt(content, 10);
22
+ return isNaN(pid) ? null : pid;
23
+ } catch {
24
+ return null;
25
+ }
26
+ }
27
+ function removePidFile(pidPath) {
28
+ try {
29
+ fs.unlinkSync(pidPath);
30
+ } catch {
31
+ }
32
+ }
33
+ function isProcessRunning(pidPath) {
34
+ const pid = readPidFile(pidPath);
35
+ if (pid === null) return false;
36
+ try {
37
+ process.kill(pid, 0);
38
+ return true;
39
+ } catch {
40
+ removePidFile(pidPath);
41
+ return false;
42
+ }
43
+ }
44
+ function getStatus(pidPath = DEFAULT_PID_PATH) {
45
+ const pid = readPidFile(pidPath);
46
+ if (pid === null) return { running: false };
47
+ try {
48
+ process.kill(pid, 0);
49
+ return { running: true, pid };
50
+ } catch {
51
+ removePidFile(pidPath);
52
+ return { running: false };
53
+ }
54
+ }
55
+ function startDaemon(pidPath = DEFAULT_PID_PATH, logDir) {
56
+ markRunning();
57
+ if (isProcessRunning(pidPath)) {
58
+ const pid = readPidFile(pidPath);
59
+ return { error: `Already running (PID ${pid})` };
60
+ }
61
+ const resolvedLogDir = logDir ? expandHome(logDir) : DEFAULT_LOG_DIR;
62
+ fs.mkdirSync(resolvedLogDir, { recursive: true });
63
+ const logFile = path.join(resolvedLogDir, "openacp.log");
64
+ const cliPath = path.resolve(process.argv[1]);
65
+ const nodePath = process.execPath;
66
+ const out = fs.openSync(logFile, "a");
67
+ const err = fs.openSync(logFile, "a");
68
+ const child = spawn(nodePath, [cliPath, "--daemon-child"], {
69
+ detached: true,
70
+ stdio: ["ignore", out, err]
71
+ });
72
+ fs.closeSync(out);
73
+ fs.closeSync(err);
74
+ if (!child.pid) {
75
+ return { error: "Failed to spawn daemon process" };
76
+ }
77
+ writePidFile(pidPath, child.pid);
78
+ child.unref();
79
+ return { pid: child.pid };
80
+ }
81
+ function stopDaemon(pidPath = DEFAULT_PID_PATH) {
82
+ const pid = readPidFile(pidPath);
83
+ if (pid === null) return { stopped: false, error: "Not running (no PID file)" };
84
+ try {
85
+ process.kill(pid, 0);
86
+ } catch {
87
+ removePidFile(pidPath);
88
+ return { stopped: false, error: "Not running (stale PID file removed)" };
89
+ }
90
+ try {
91
+ process.kill(pid, "SIGTERM");
92
+ clearRunning();
93
+ removePidFile(pidPath);
94
+ return { stopped: true, pid };
95
+ } catch (e) {
96
+ return { stopped: false, error: `Failed to stop: ${e.message}` };
97
+ }
98
+ }
99
+ function getPidPath() {
100
+ return DEFAULT_PID_PATH;
101
+ }
102
+ function markRunning() {
103
+ fs.mkdirSync(path.dirname(RUNNING_MARKER), { recursive: true });
104
+ fs.writeFileSync(RUNNING_MARKER, "");
105
+ }
106
+ function clearRunning() {
107
+ try {
108
+ fs.unlinkSync(RUNNING_MARKER);
109
+ } catch {
110
+ }
111
+ }
112
+ function shouldAutoStart() {
113
+ return fs.existsSync(RUNNING_MARKER);
114
+ }
115
+
116
+ export {
117
+ writePidFile,
118
+ readPidFile,
119
+ removePidFile,
120
+ isProcessRunning,
121
+ getStatus,
122
+ startDaemon,
123
+ stopDaemon,
124
+ getPidPath,
125
+ markRunning,
126
+ clearRunning,
127
+ shouldAutoStart
128
+ };
129
+ //# sourceMappingURL=chunk-S6O7SM6A.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/daemon.ts"],"sourcesContent":["import { spawn } from 'node:child_process'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport * as os from 'node:os'\nimport { expandHome } from './config.js'\n\nconst DEFAULT_PID_PATH = path.join(os.homedir(), '.openacp', 'openacp.pid')\nconst DEFAULT_LOG_DIR = path.join(os.homedir(), '.openacp', 'logs')\nconst RUNNING_MARKER = path.join(os.homedir(), '.openacp', 'running')\n\nexport function writePidFile(pidPath: string, pid: number): void {\n const dir = path.dirname(pidPath)\n fs.mkdirSync(dir, { recursive: true })\n fs.writeFileSync(pidPath, String(pid))\n}\n\nexport function readPidFile(pidPath: string): number | null {\n try {\n const content = fs.readFileSync(pidPath, 'utf-8').trim()\n const pid = parseInt(content, 10)\n return isNaN(pid) ? null : pid\n } catch {\n return null\n }\n}\n\nexport function removePidFile(pidPath: string): void {\n try {\n fs.unlinkSync(pidPath)\n } catch {\n // ignore if already gone\n }\n}\n\nexport function isProcessRunning(pidPath: string): boolean {\n const pid = readPidFile(pidPath)\n if (pid === null) return false\n try {\n process.kill(pid, 0)\n return true\n } catch {\n // Process not running, clean up stale PID file\n removePidFile(pidPath)\n return false\n }\n}\n\nexport function getStatus(pidPath: string = DEFAULT_PID_PATH): { running: boolean; pid?: number } {\n const pid = readPidFile(pidPath)\n if (pid === null) return { running: false }\n try {\n process.kill(pid, 0)\n return { running: true, pid }\n } catch {\n removePidFile(pidPath)\n return { running: false }\n }\n}\n\nexport function startDaemon(pidPath: string = DEFAULT_PID_PATH, logDir?: string): { pid: number } | { error: string } {\n // Mark as running so auto-start works on next boot\n markRunning()\n\n // Check if already running\n if (isProcessRunning(pidPath)) {\n const pid = readPidFile(pidPath)!\n return { error: `Already running (PID ${pid})` }\n }\n\n const resolvedLogDir = logDir ? expandHome(logDir) : DEFAULT_LOG_DIR\n fs.mkdirSync(resolvedLogDir, { recursive: true })\n const logFile = path.join(resolvedLogDir, 'openacp.log')\n\n // Find the CLI entry point\n const cliPath = path.resolve(process.argv[1])\n const nodePath = process.execPath\n\n const out = fs.openSync(logFile, 'a')\n const err = fs.openSync(logFile, 'a')\n\n const child = spawn(nodePath, [cliPath, '--daemon-child'], {\n detached: true,\n stdio: ['ignore', out, err],\n })\n\n // Close file descriptors in parent — child has its own copies\n fs.closeSync(out)\n fs.closeSync(err)\n\n if (!child.pid) {\n return { error: 'Failed to spawn daemon process' }\n }\n\n // PID file is written by the child process itself (in main.ts startServer)\n // to avoid race conditions and ensure consistency with LaunchAgent/systemd starts.\n // We still write it here as a fallback in case the child hasn't written it yet\n // when the parent needs to report the PID.\n writePidFile(pidPath, child.pid)\n child.unref()\n\n return { pid: child.pid }\n}\n\nexport function stopDaemon(pidPath: string = DEFAULT_PID_PATH): { stopped: boolean; pid?: number; error?: string } {\n const pid = readPidFile(pidPath)\n if (pid === null) return { stopped: false, error: 'Not running (no PID file)' }\n\n try {\n process.kill(pid, 0) // check alive\n } catch {\n removePidFile(pidPath)\n return { stopped: false, error: 'Not running (stale PID file removed)' }\n }\n\n try {\n process.kill(pid, 'SIGTERM')\n // Remove running marker so auto-start won't restart on next boot\n clearRunning()\n // PID file is cleaned up by the child process on SIGTERM (see main.ts shutdown handler).\n // Also remove here in case child crashes before cleanup.\n removePidFile(pidPath)\n return { stopped: true, pid }\n } catch (e) {\n return { stopped: false, error: `Failed to stop: ${(e as Error).message}` }\n }\n}\n\nexport function getPidPath(): string {\n return DEFAULT_PID_PATH\n}\n\n/** Mark that the daemon should auto-start on boot */\nexport function markRunning(): void {\n fs.mkdirSync(path.dirname(RUNNING_MARKER), { recursive: true })\n fs.writeFileSync(RUNNING_MARKER, '')\n}\n\n/** Remove running marker — daemon won't auto-start on boot */\nexport function clearRunning(): void {\n try { fs.unlinkSync(RUNNING_MARKER) } catch { /* ignore */ }\n}\n\n/** Check if the daemon was running before (should auto-start on boot) */\nexport function shouldAutoStart(): boolean {\n return fs.existsSync(RUNNING_MARKER)\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,103 @@
1
+ import {
2
+ createChildLogger
3
+ } from "./chunk-MNJDYDGH.js";
4
+
5
+ // src/tunnel/providers/install-cloudflared.ts
6
+ import fs from "fs";
7
+ import path from "path";
8
+ import https from "https";
9
+ import os from "os";
10
+ import { execSync } from "child_process";
11
+ var log = createChildLogger({ module: "cloudflared-install" });
12
+ var BIN_DIR = path.join(os.homedir(), ".openacp", "bin");
13
+ var IS_WINDOWS = os.platform() === "win32";
14
+ var BIN_NAME = IS_WINDOWS ? "cloudflared.exe" : "cloudflared";
15
+ var BIN_PATH = path.join(BIN_DIR, BIN_NAME);
16
+ var GITHUB_BASE_URL = "https://github.com/cloudflare/cloudflared/releases/latest/download";
17
+ var PLATFORM_MAPPINGS = {
18
+ darwin: {
19
+ x64: "cloudflared-darwin-amd64.tgz",
20
+ arm64: "cloudflared-darwin-amd64.tgz"
21
+ },
22
+ win32: {
23
+ x64: "cloudflared-windows-amd64.exe"
24
+ },
25
+ linux: {
26
+ x64: "cloudflared-linux-amd64",
27
+ arm64: "cloudflared-linux-arm64"
28
+ }
29
+ };
30
+ function getDownloadUrl() {
31
+ const platform = os.platform();
32
+ const arch = os.arch();
33
+ const mapping = PLATFORM_MAPPINGS[platform];
34
+ if (!mapping) throw new Error(`Unsupported platform: ${platform}`);
35
+ const binary = mapping[arch];
36
+ if (!binary) throw new Error(`Unsupported architecture: ${arch} for ${platform}`);
37
+ return `${GITHUB_BASE_URL}/${binary}`;
38
+ }
39
+ function downloadFile(url, dest) {
40
+ return new Promise((resolve, reject) => {
41
+ const file = fs.createWriteStream(dest);
42
+ https.get(url, (response) => {
43
+ if (response.statusCode === 301 || response.statusCode === 302) {
44
+ file.close();
45
+ fs.unlinkSync(dest);
46
+ downloadFile(response.headers.location, dest).then(resolve).catch(reject);
47
+ return;
48
+ }
49
+ if (response.statusCode !== 200) {
50
+ file.close();
51
+ fs.unlinkSync(dest);
52
+ reject(new Error(`Download failed with status ${response.statusCode}`));
53
+ return;
54
+ }
55
+ response.pipe(file);
56
+ file.on("finish", () => file.close(() => resolve(dest)));
57
+ file.on("error", (err) => {
58
+ file.close();
59
+ if (fs.existsSync(dest)) fs.unlinkSync(dest);
60
+ reject(err);
61
+ });
62
+ }).on("error", (err) => {
63
+ file.close();
64
+ if (fs.existsSync(dest)) fs.unlinkSync(dest);
65
+ reject(err);
66
+ });
67
+ });
68
+ }
69
+ async function ensureCloudflared() {
70
+ try {
71
+ const systemPath = execSync("which cloudflared", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
72
+ if (systemPath) {
73
+ log.debug({ path: systemPath }, "cloudflared found in PATH");
74
+ return systemPath;
75
+ }
76
+ } catch {
77
+ }
78
+ if (fs.existsSync(BIN_PATH)) {
79
+ if (!IS_WINDOWS) fs.chmodSync(BIN_PATH, "755");
80
+ log.debug({ path: BIN_PATH }, "cloudflared found in ~/.openacp/bin");
81
+ return BIN_PATH;
82
+ }
83
+ log.info("cloudflared not found, downloading from GitHub...");
84
+ fs.mkdirSync(BIN_DIR, { recursive: true });
85
+ const url = getDownloadUrl();
86
+ const isArchive = url.endsWith(".tgz");
87
+ const downloadDest = isArchive ? path.join(BIN_DIR, "cloudflared.tgz") : BIN_PATH;
88
+ await downloadFile(url, downloadDest);
89
+ if (isArchive) {
90
+ execSync(`tar -xzf "${downloadDest}" -C "${BIN_DIR}"`, { stdio: "pipe" });
91
+ fs.unlinkSync(downloadDest);
92
+ }
93
+ if (!IS_WINDOWS) {
94
+ fs.chmodSync(BIN_PATH, "755");
95
+ }
96
+ log.info({ path: BIN_PATH }, "cloudflared installed successfully");
97
+ return BIN_PATH;
98
+ }
99
+
100
+ export {
101
+ ensureCloudflared
102
+ };
103
+ //# sourceMappingURL=chunk-WXS6ONOD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/tunnel/providers/install-cloudflared.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport https from 'node:https'\nimport os from 'node:os'\nimport { execSync } from 'node:child_process'\nimport { createChildLogger } from '../../core/log.js'\n\nconst log = createChildLogger({ module: 'cloudflared-install' })\n\nconst BIN_DIR = path.join(os.homedir(), '.openacp', 'bin')\nconst IS_WINDOWS = os.platform() === 'win32'\nconst BIN_NAME = IS_WINDOWS ? 'cloudflared.exe' : 'cloudflared'\nconst BIN_PATH = path.join(BIN_DIR, BIN_NAME)\n\nconst GITHUB_BASE_URL = 'https://github.com/cloudflare/cloudflared/releases/latest/download'\n\nconst PLATFORM_MAPPINGS: Record<string, Record<string, string>> = {\n darwin: {\n x64: 'cloudflared-darwin-amd64.tgz',\n arm64: 'cloudflared-darwin-amd64.tgz',\n },\n win32: {\n x64: 'cloudflared-windows-amd64.exe',\n },\n linux: {\n x64: 'cloudflared-linux-amd64',\n arm64: 'cloudflared-linux-arm64',\n },\n}\n\nfunction getDownloadUrl(): string {\n const platform = os.platform()\n const arch = os.arch()\n const mapping = PLATFORM_MAPPINGS[platform]\n if (!mapping) throw new Error(`Unsupported platform: ${platform}`)\n const binary = mapping[arch]\n if (!binary) throw new Error(`Unsupported architecture: ${arch} for ${platform}`)\n return `${GITHUB_BASE_URL}/${binary}`\n}\n\nfunction downloadFile(url: string, dest: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const file = fs.createWriteStream(dest)\n\n https.get(url, (response) => {\n // Follow redirects\n if (response.statusCode === 301 || response.statusCode === 302) {\n file.close()\n fs.unlinkSync(dest)\n downloadFile(response.headers.location!, dest).then(resolve).catch(reject)\n return\n }\n\n if (response.statusCode !== 200) {\n file.close()\n fs.unlinkSync(dest)\n reject(new Error(`Download failed with status ${response.statusCode}`))\n return\n }\n\n response.pipe(file)\n file.on('finish', () => file.close(() => resolve(dest)))\n file.on('error', (err) => {\n file.close()\n if (fs.existsSync(dest)) fs.unlinkSync(dest)\n reject(err)\n })\n }).on('error', (err) => {\n file.close()\n if (fs.existsSync(dest)) fs.unlinkSync(dest)\n reject(err)\n })\n })\n}\n\n/**\n * Ensure cloudflared binary is available.\n * 1. Check if already installed in PATH\n * 2. Check if downloaded to ~/.openacp/bin/\n * 3. If not, download from GitHub releases\n * Returns the path to the cloudflared binary.\n */\nexport async function ensureCloudflared(): Promise<string> {\n // 1. Check PATH first\n try {\n const systemPath = execSync('which cloudflared', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim()\n if (systemPath) {\n log.debug({ path: systemPath }, 'cloudflared found in PATH')\n return systemPath\n }\n } catch {\n // Not in PATH\n }\n\n // 2. Check our bin directory\n if (fs.existsSync(BIN_PATH)) {\n if (!IS_WINDOWS) fs.chmodSync(BIN_PATH, '755')\n log.debug({ path: BIN_PATH }, 'cloudflared found in ~/.openacp/bin')\n return BIN_PATH\n }\n\n // 3. Download\n log.info('cloudflared not found, downloading from GitHub...')\n fs.mkdirSync(BIN_DIR, { recursive: true })\n\n const url = getDownloadUrl()\n const isArchive = url.endsWith('.tgz')\n const downloadDest = isArchive ? path.join(BIN_DIR, 'cloudflared.tgz') : BIN_PATH\n\n await downloadFile(url, downloadDest)\n\n if (isArchive) {\n execSync(`tar -xzf \"${downloadDest}\" -C \"${BIN_DIR}\"`, { stdio: 'pipe' })\n fs.unlinkSync(downloadDest)\n }\n\n if (!IS_WINDOWS) {\n fs.chmodSync(BIN_PATH, '755')\n }\n\n log.info({ path: BIN_PATH }, 'cloudflared installed successfully')\n return BIN_PATH\n}\n"],"mappings":"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","names":[]}