@openacp/cli 2026.330.2 → 2026.331.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/dist/adapter-ELG3VRZ3.js +14 -0
- package/dist/{agent-catalog-SZQQERV7.js → agent-catalog-UYD26QDK.js} +3 -3
- package/dist/{api-client-XTLRRFPX.js → api-client-PEMHYL5U.js} +2 -2
- package/dist/{api-server-JLBDKCU4.js → api-server-DATG2KBR.js} +3 -3
- package/dist/api-server-L5Z7XACW.js +7 -0
- package/dist/chunk-23SRIVG4.js +50 -0
- package/dist/chunk-23SRIVG4.js.map +1 -0
- package/dist/{chunk-YIGBJFJL.js → chunk-7GXEMMEV.js} +15 -15
- package/dist/{chunk-QWVHCTCA.js → chunk-7U6IZIJP.js} +37 -23
- package/dist/chunk-7U6IZIJP.js.map +1 -0
- package/dist/{chunk-FCTC7KDT.js → chunk-7YIKTRSM.js} +14 -10
- package/dist/chunk-7YIKTRSM.js.map +1 -0
- package/dist/{chunk-MITTQMGZ.js → chunk-BYCJQPMN.js} +5 -5
- package/dist/chunk-BYCJQPMN.js.map +1 -0
- package/dist/{chunk-5ZNBNIK3.js → chunk-EWVXSTQK.js} +193 -53
- package/dist/chunk-EWVXSTQK.js.map +1 -0
- package/dist/{chunk-UWH7KIAA.js → chunk-FPKQYCQS.js} +88 -13
- package/dist/chunk-FPKQYCQS.js.map +1 -0
- package/dist/{chunk-GEOXPGCO.js → chunk-K6UY5M75.js} +12 -9
- package/dist/chunk-K6UY5M75.js.map +1 -0
- package/dist/{chunk-KDU3ZEWT.js → chunk-KGAQW6F4.js} +12 -3
- package/dist/chunk-KGAQW6F4.js.map +1 -0
- package/dist/{chunk-7RKPIM3E.js → chunk-LRV56K2M.js} +205 -16
- package/dist/chunk-LRV56K2M.js.map +1 -0
- package/dist/{chunk-V2YZWYXT.js → chunk-MDJHCCFS.js} +18 -17
- package/dist/chunk-MDJHCCFS.js.map +1 -0
- package/dist/chunk-NHD5XDD2.js +686 -0
- package/dist/chunk-NHD5XDD2.js.map +1 -0
- package/dist/{chunk-APS6UEFU.js → chunk-NJX75BLK.js} +1 -1
- package/dist/chunk-NJX75BLK.js.map +1 -0
- package/dist/{chunk-5HKQCYOI.js → chunk-NOEAJNTK.js} +14 -3
- package/dist/chunk-NOEAJNTK.js.map +1 -0
- package/dist/chunk-ON7HB5O7.js +58 -0
- package/dist/chunk-ON7HB5O7.js.map +1 -0
- package/dist/{chunk-5OCGO27U.js → chunk-OSBZXY2W.js} +2 -1
- package/dist/chunk-OSBZXY2W.js.map +1 -0
- package/dist/{chunk-PA6MNBG4.js → chunk-P3HHJANC.js} +32 -13
- package/dist/chunk-P3HHJANC.js.map +1 -0
- package/dist/{chunk-BTJHGSLM.js → chunk-R2YLDQLI.js} +9 -10
- package/dist/chunk-R2YLDQLI.js.map +1 -0
- package/dist/{chunk-CFUJGWOP.js → chunk-SSLVNCEA.js} +27 -3
- package/dist/chunk-SSLVNCEA.js.map +1 -0
- package/dist/{chunk-MPGEHTGE.js → chunk-TGP34LQN.js} +9 -7
- package/dist/chunk-TGP34LQN.js.map +1 -0
- package/dist/{chunk-TMVTSWVH.js → chunk-VUSCVRJL.js} +2 -1
- package/dist/chunk-VUSCVRJL.js.map +1 -0
- package/dist/chunk-XRJUS6FE.js +53 -0
- package/dist/chunk-XRJUS6FE.js.map +1 -0
- package/dist/{chunk-W4LK6WJP.js → chunk-YZCKSNRN.js} +24 -17
- package/dist/chunk-YZCKSNRN.js.map +1 -0
- package/dist/{chunk-3NAFXVQM.js → chunk-ZIRH6QWW.js} +7 -5
- package/dist/chunk-ZIRH6QWW.js.map +1 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.js +334 -140
- package/dist/cli.js.map +1 -1
- package/dist/config-X4UP7H6R.js +13 -0
- package/dist/config-editor-7BENRVG5.js +11 -0
- package/dist/{config-registry-ZXAIJNYB.js → config-registry-M3FFWEVM.js} +3 -2
- package/dist/context-FVGCU5TI.js +9 -0
- package/dist/core-plugins-JSY2I44L.js +25 -0
- package/dist/{daemon-XFEMMJSZ.js → daemon-UOSRDEXW.js} +8 -3
- package/dist/doctor-6DLACBR4.js +10 -0
- package/dist/{file-service-HHB3JQIO.js → file-service-FQQYME7M.js} +2 -2
- package/dist/index.d.ts +265 -32
- package/dist/index.js +44 -33
- package/dist/index.js.map +1 -1
- package/dist/{install-cloudflared-JRJ4BSOM.js → install-cloudflared-LNS5L5FR.js} +5 -4
- package/dist/install-cloudflared-LNS5L5FR.js.map +1 -0
- package/dist/{install-context-EHYV5WRY.js → install-context-KZO5FR4D.js} +4 -3
- package/dist/install-context-KZO5FR4D.js.map +1 -0
- package/dist/{install-jq-ISTGT263.js → install-jq-SN4IA5K4.js} +3 -3
- package/dist/instance-context-FLCE7VZ4.js +13 -0
- package/dist/instance-registry-SW5FWKHO.js +7 -0
- package/dist/{main-L2M4NTJY.js → main-D7M2AKRM.js} +91 -48
- package/dist/main-D7M2AKRM.js.map +1 -0
- package/dist/{plugin-create-EHL76ZZG.js → plugin-create-HFKS23JY.js} +4 -2
- package/dist/{plugin-create-EHL76ZZG.js.map → plugin-create-HFKS23JY.js.map} +1 -1
- package/dist/{post-upgrade-Y26S2ZQ7.js → post-upgrade-F4YPMTUT.js} +6 -6
- package/dist/{security-2BA265LN.js → security-O4XGN2CM.js} +2 -2
- package/dist/{setup-E6BNEYCS.js → setup-44WLBIOT.js} +209 -22
- package/dist/setup-44WLBIOT.js.map +1 -0
- package/dist/{speech-SG62JYIF.js → speech-GHTSWDAN.js} +2 -2
- package/dist/telegram-D7ASLVEB.js +7 -0
- package/dist/telegram-D7ASLVEB.js.map +1 -0
- package/dist/tunnel-ALJDPFDQ.js +10 -0
- package/dist/tunnel-ALJDPFDQ.js.map +1 -0
- package/dist/{tunnel-service-ZMO4THKE.js → tunnel-service-TBAHDXMF.js} +41 -547
- package/dist/tunnel-service-TBAHDXMF.js.map +1 -0
- package/package.json +1 -1
- package/dist/adapter-4U6MC5ZS.js +0 -13
- package/dist/api-server-5VNYFWJE.js +0 -7
- package/dist/chunk-3NAFXVQM.js.map +0 -1
- package/dist/chunk-4WXALZA3.js +0 -45
- package/dist/chunk-4WXALZA3.js.map +0 -1
- package/dist/chunk-5HKQCYOI.js.map +0 -1
- package/dist/chunk-5OCGO27U.js.map +0 -1
- package/dist/chunk-5ZNBNIK3.js.map +0 -1
- package/dist/chunk-7RKPIM3E.js.map +0 -1
- package/dist/chunk-APS6UEFU.js.map +0 -1
- package/dist/chunk-BTJHGSLM.js.map +0 -1
- package/dist/chunk-CFUJGWOP.js.map +0 -1
- package/dist/chunk-FCTC7KDT.js.map +0 -1
- package/dist/chunk-GEOXPGCO.js.map +0 -1
- package/dist/chunk-KDU3ZEWT.js.map +0 -1
- package/dist/chunk-MITTQMGZ.js.map +0 -1
- package/dist/chunk-MPGEHTGE.js.map +0 -1
- package/dist/chunk-PA6MNBG4.js.map +0 -1
- package/dist/chunk-QWVHCTCA.js.map +0 -1
- package/dist/chunk-TMVTSWVH.js.map +0 -1
- package/dist/chunk-UWH7KIAA.js.map +0 -1
- package/dist/chunk-V2YZWYXT.js.map +0 -1
- package/dist/chunk-W4LK6WJP.js.map +0 -1
- package/dist/config-KN6NKKPF.js +0 -20
- package/dist/config-editor-76RVZS4B.js +0 -10
- package/dist/context-NXXW62NJ.js +0 -9
- package/dist/core-plugins-OCHKGCIZ.js +0 -22
- package/dist/doctor-AV6AUO22.js +0 -9
- package/dist/install-cloudflared-JRJ4BSOM.js.map +0 -1
- package/dist/install-context-EHYV5WRY.js.map +0 -1
- package/dist/main-L2M4NTJY.js.map +0 -1
- package/dist/setup-E6BNEYCS.js.map +0 -1
- package/dist/telegram-EAVRDNFU.js +0 -7
- package/dist/tunnel-HWJ27WDH.js +0 -7
- package/dist/tunnel-service-ZMO4THKE.js.map +0 -1
- /package/dist/{adapter-4U6MC5ZS.js.map → adapter-ELG3VRZ3.js.map} +0 -0
- /package/dist/{agent-catalog-SZQQERV7.js.map → agent-catalog-UYD26QDK.js.map} +0 -0
- /package/dist/{api-client-XTLRRFPX.js.map → api-client-PEMHYL5U.js.map} +0 -0
- /package/dist/{api-server-5VNYFWJE.js.map → api-server-DATG2KBR.js.map} +0 -0
- /package/dist/{api-server-JLBDKCU4.js.map → api-server-L5Z7XACW.js.map} +0 -0
- /package/dist/{chunk-YIGBJFJL.js.map → chunk-7GXEMMEV.js.map} +0 -0
- /package/dist/{config-KN6NKKPF.js.map → config-X4UP7H6R.js.map} +0 -0
- /package/dist/{config-editor-76RVZS4B.js.map → config-editor-7BENRVG5.js.map} +0 -0
- /package/dist/{config-registry-ZXAIJNYB.js.map → config-registry-M3FFWEVM.js.map} +0 -0
- /package/dist/{context-NXXW62NJ.js.map → context-FVGCU5TI.js.map} +0 -0
- /package/dist/{core-plugins-OCHKGCIZ.js.map → core-plugins-JSY2I44L.js.map} +0 -0
- /package/dist/{daemon-XFEMMJSZ.js.map → daemon-UOSRDEXW.js.map} +0 -0
- /package/dist/{doctor-AV6AUO22.js.map → doctor-6DLACBR4.js.map} +0 -0
- /package/dist/{file-service-HHB3JQIO.js.map → file-service-FQQYME7M.js.map} +0 -0
- /package/dist/{install-jq-ISTGT263.js.map → install-jq-SN4IA5K4.js.map} +0 -0
- /package/dist/{security-2BA265LN.js.map → instance-context-FLCE7VZ4.js.map} +0 -0
- /package/dist/{speech-SG62JYIF.js.map → instance-registry-SW5FWKHO.js.map} +0 -0
- /package/dist/{post-upgrade-Y26S2ZQ7.js.map → post-upgrade-F4YPMTUT.js.map} +0 -0
- /package/dist/{telegram-EAVRDNFU.js.map → security-O4XGN2CM.js.map} +0 -0
- /package/dist/{tunnel-HWJ27WDH.js.map → speech-GHTSWDAN.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/main.ts","../../src/core/commands/session.ts","../../src/core/commands/agents.ts","../../src/core/commands/admin.ts","../../src/core/commands/help.ts","../../src/core/commands/menu.ts","../../src/core/commands/switch.ts","../../src/core/commands/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport path from 'node:path'\nimport { ConfigManager } from './core/config/config.js'\nimport type { InstanceContext } from './core/instance-context.js'\nimport { createInstanceContext, getGlobalRoot } from './core/instance-context.js'\nimport { OpenACPCore } from './core/core.js'\nimport { initLogger, shutdownLogger, cleanupOldSessionLogs, log, muteLogger, unmuteLogger } from './core/utils/log.js'\nimport { corePlugins } from './plugins/core-plugins.js'\nimport { SettingsManager } from './core/plugin/settings-manager.js'\nimport { PluginRegistry } from './core/plugin/plugin-registry.js'\nimport { CommandRegistry } from './core/command-registry.js'\nimport { registerSystemCommands } from './core/commands/index.js'\nimport type { IChannelAdapter } from './core/channel.js'\nimport type { TunnelService } from './plugins/tunnel/tunnel-service.js'\nimport { InstanceRegistry } from './core/instance-registry.js'\nimport fs from 'node:fs'\n\nexport const RESTART_EXIT_CODE = 75\nlet shuttingDown = false\n\n\nexport interface StartServerOptions {\n devPluginPath?: string\n noWatch?: boolean\n instanceContext?: InstanceContext\n}\n\nexport async function startServer(opts?: StartServerOptions) {\n const ctx = opts?.instanceContext ?? createInstanceContext({\n id: 'main',\n root: getGlobalRoot(),\n isGlobal: true,\n })\n\n // 0. If running as daemon child, check state and write PID file\n if (process.argv.includes('--daemon-child')) {\n const { writePidFile, readPidFile, shouldAutoStart } = await import('./cli/daemon.js')\n\n // Only auto-start if the daemon was previously running (user started it)\n if (!shouldAutoStart(ctx.root)) {\n process.exit(0)\n }\n\n const pidPath = ctx.paths.pid\n const existingPid = readPidFile(pidPath)\n if (existingPid !== null && existingPid !== process.pid) {\n try {\n process.kill(existingPid, 0)\n console.error(`Another OpenACP instance is already running (PID ${existingPid}). Exiting.`)\n process.exit(1)\n } catch {\n // Stale PID file — safe to overwrite\n }\n }\n writePidFile(pidPath, process.pid)\n }\n\n // Create SettingsManager and PluginRegistry early (needed by wizard + boot)\n const settingsManager = new SettingsManager(ctx.paths.pluginsData)\n const pluginRegistry = new PluginRegistry(ctx.paths.pluginRegistry)\n await pluginRegistry.load()\n\n // 1. Check config exists, run setup if not\n const configManager = new ConfigManager(ctx.paths.config)\n const configExists = await configManager.exists()\n\n if (!configExists) {\n const { runSetup } = await import('./core/setup/index.js')\n const shouldStart = await runSetup(configManager, { settingsManager, pluginRegistry })\n if (!shouldStart) process.exit(0)\n }\n\n // 2. Load config (validates with Zod)\n await configManager.load()\n const config = configManager.get()\n initLogger(config.logging)\n log.debug({ configPath: configManager.getConfigPath() }, 'Config loaded')\n\n // First boot: auto-register built-in plugins if registry is empty\n if (pluginRegistry.list().size === 0) {\n await autoRegisterBuiltinPlugins(settingsManager, pluginRegistry, configManager)\n }\n\n // Show banner in foreground TTY mode (not daemon, not piped)\n const isForegroundTTY = !!(process.stdout.isTTY && !process.env.NO_COLOR && config.runMode !== 'daemon')\n if (isForegroundTTY) {\n const { printStartBanner } = await import('./core/setup/index.js')\n await printStartBanner()\n }\n\n // Mute pino during startup, show spinner instead\n let spinner: ReturnType<typeof import('ora').default> | undefined\n if (isForegroundTTY) {\n muteLogger()\n const ora = (await import('ora')).default\n spinner = ora({ text: 'Starting OpenACP...', spinner: 'dots' }).start()\n }\n\n // Post-upgrade dependency check (blocking — must complete before server start)\n try {\n const { runPostUpgradeChecks } = await import('./cli/post-upgrade.js')\n await runPostUpgradeChecks(config)\n } catch (err) {\n log.warn({ err }, 'Post-upgrade check failed')\n }\n\n // Async cleanup of old session logs (non-blocking)\n cleanupOldSessionLogs(config.logging.sessionLogRetentionDays).catch(err =>\n log.warn({ err }, 'Session log cleanup failed')\n )\n\n // 3. Create core\n const core = new OpenACPCore(configManager, ctx)\n\n // 3b. Create CommandRegistry and register as service\n const commandRegistry = new CommandRegistry()\n const serviceRegistry = core.lifecycleManager.serviceRegistry\n serviceRegistry.register('command-registry', commandRegistry, 'core')\n\n // 3c. Register system commands\n registerSystemCommands(commandRegistry, core)\n\n // 4. Boot all plugins (services, infrastructure, adapters)\n try {\n // Emit kernel:booted before plugin boot\n core.eventBus.emit('kernel:booted')\n\n // Pass settingsManager and pluginRegistry to LifecycleManager\n ;(core.lifecycleManager as any).settingsManager = settingsManager\n ;(core.lifecycleManager as any).pluginRegistry = pluginRegistry\n\n // Boot all built-in plugins in dependency order\n await core.lifecycleManager.boot(corePlugins)\n\n // Load community plugins from registry (npm and local sources)\n try {\n const communityPlugins: import('./core/plugin/types.js').OpenACPPlugin[] = []\n const npmPlugins = pluginRegistry.listBySource('npm')\n const localPlugins = pluginRegistry.listBySource('local')\n const allCommunityEntries = new Map([...npmPlugins, ...localPlugins])\n\n for (const [name, entry] of allCommunityEntries) {\n if (!entry.enabled) continue\n\n try {\n let modulePath: string\n\n if (name.startsWith('/') || name.startsWith('.')) {\n // Absolute or relative path (local install via `plugin add /path/to/plugin`)\n const resolved = path.resolve(name)\n const pkgPath = path.join(resolved, 'package.json')\n const pkg = JSON.parse(await fs.promises.readFile(pkgPath, 'utf-8'))\n modulePath = path.join(resolved, pkg.main || 'dist/index.js')\n } else {\n // npm package: try direct name first, then scan node_modules for matching plugin name\n const nodeModulesDir = path.join(ctx.paths.plugins, 'node_modules')\n let pkgDir = path.join(nodeModulesDir, name)\n\n if (!fs.existsSync(path.join(pkgDir, 'package.json'))) {\n // Plugin name doesn't match npm package name — scan installed packages\n // Match by openacp.pluginName field in package.json (no code execution)\n let found = false\n const scopes = fs.existsSync(nodeModulesDir)\n ? fs.readdirSync(nodeModulesDir).filter(d => d.startsWith('@'))\n : []\n for (const scope of scopes) {\n const scopeDir = path.join(nodeModulesDir, scope)\n const pkgs = fs.readdirSync(scopeDir)\n for (const pkg of pkgs) {\n const candidateDir = path.join(scopeDir, pkg)\n const candidatePkgPath = path.join(candidateDir, 'package.json')\n if (fs.existsSync(candidatePkgPath)) {\n try {\n const candidatePkg = JSON.parse(fs.readFileSync(candidatePkgPath, 'utf-8'))\n const pluginName = candidatePkg.openacp?.pluginName as string | undefined\n if (pluginName === name) {\n pkgDir = candidateDir\n found = true\n break\n }\n } catch { /* skip */ }\n }\n }\n if (found) break\n }\n }\n\n const pkgJsonPath = path.join(pkgDir, 'package.json')\n const pkg = JSON.parse(await fs.promises.readFile(pkgJsonPath, 'utf-8'))\n modulePath = path.join(pkgDir, pkg.main || 'dist/index.js')\n }\n\n log.debug({ plugin: name, modulePath }, 'Loading community plugin')\n const mod = await import(modulePath)\n const plugin = mod.default\n\n if (!plugin || !plugin.name || !plugin.setup) {\n log.warn({ plugin: name }, 'Community plugin has invalid exports (missing name or setup), skipping')\n continue\n }\n\n communityPlugins.push(plugin)\n } catch (err) {\n log.warn({ err, plugin: name }, 'Failed to load community plugin, skipping')\n }\n }\n\n if (communityPlugins.length > 0) {\n log.debug({ plugins: communityPlugins.map(p => p.name) }, 'Booting community plugins')\n await core.lifecycleManager.boot(communityPlugins)\n }\n } catch (err) {\n log.warn({ err }, 'Community plugin loading failed')\n }\n\n // Load dev plugin if running in dev mode\n if (opts?.devPluginPath) {\n const { DevPluginLoader } = await import('./core/plugin/dev-loader.js')\n const devLoader = new DevPluginLoader(opts.devPluginPath)\n\n try {\n const devPlugin = await devLoader.load()\n await core.lifecycleManager.boot([devPlugin])\n log.info({ plugin: devPlugin.name, version: devPlugin.version }, 'Dev plugin loaded')\n\n // Watch dist/ directory for changes and hot-reload\n if (!opts.noWatch) {\n const distPath = devLoader.getDistPath()\n let reloadTimer: ReturnType<typeof setTimeout> | null = null\n\n fs.watch(distPath, { recursive: true }, (_eventType, filename) => {\n if (!filename?.endsWith('.js')) return\n\n // Debounce: wait 500ms after last change\n if (reloadTimer) clearTimeout(reloadTimer)\n reloadTimer = setTimeout(async () => {\n try {\n log.info({ filename }, 'Dev plugin changed, reloading...')\n await core.lifecycleManager.unloadPlugin(devPlugin.name)\n const reloaded = await devLoader.load()\n await core.lifecycleManager.boot([reloaded])\n log.info({ plugin: reloaded.name, version: reloaded.version }, 'Dev plugin reloaded')\n } catch (err) {\n log.error({ err }, 'Dev plugin reload failed')\n }\n }, 500)\n })\n\n log.info({ distPath }, 'Watching dev plugin for changes')\n }\n } catch (err) {\n log.error({ err, pluginPath: opts.devPluginPath }, 'Failed to load dev plugin')\n }\n }\n\n // Wire adapters from service registry into core (discovered dynamically)\n for (const { name } of serviceRegistry.list()) {\n if (!name.startsWith('adapter:')) continue\n const adapterName = name.slice('adapter:'.length)\n const adapter = serviceRegistry.get<IChannelAdapter>(name)\n if (adapter) {\n core.registerAdapter(adapterName, adapter)\n log.info({ adapter: adapterName }, 'Adapter registered')\n }\n }\n\n // Wire tunnel service from service registry into core\n const tunnelSvc = serviceRegistry.get<TunnelService>('tunnel')\n if (tunnelSvc) {\n core.tunnelService = tunnelSvc\n }\n\n // Emit system:commands-ready with all registered commands\n core.eventBus.emit('system:commands-ready', { commands: commandRegistry.getAll() })\n\n core.eventBus.emit('system:ready')\n } catch (err) {\n if (spinner) {\n spinner.fail('Plugin boot failed')\n spinner = undefined\n }\n unmuteLogger()\n log.error({ err }, 'Plugin boot failed')\n }\n\n if (core.adapters.size === 0) {\n log.error('No channels enabled. Enable at least one channel in config.')\n process.exit(1)\n }\n\n // 5. Setup shutdown handler\n const shutdown = async (signal: string, exitCode = 0) => {\n if (shuttingDown) return\n shuttingDown = true\n log.info({ signal, exitCode }, 'Signal received, shutting down')\n\n try {\n // 1. Send shutdown notification while plugins are still running\n try {\n const nm = serviceRegistry.get<import('./plugins/notifications/notification.js').NotificationManager>('notifications')\n if (nm) {\n await nm.notifyAll({\n sessionId: 'system',\n type: 'error',\n summary: 'OpenACP is shutting down',\n })\n }\n } catch {\n /* best effort */\n }\n\n // 2. Persist session state (don't kill agent subprocesses — they exit with parent)\n await core.sessionManager.shutdownAll()\n\n // 3. Lifecycle teardown stops all plugins (adapters, api-server, tunnel, etc.)\n await core.lifecycleManager.shutdown()\n // Note: do NOT call core.stop() here — it would double-stop adapters and\n // try to use the notification plugin after it has already been torn down.\n } catch (err) {\n log.error({ err }, 'Error during shutdown')\n }\n\n const isDaemon = process.argv.includes('--daemon-child')\n\n // Clean up PID file if running as daemon\n if (isDaemon) {\n const { removePidFile } = await import('./cli/daemon.js')\n removePidFile(ctx.paths.pid)\n }\n\n // Self-respawn on restart\n if (exitCode === RESTART_EXIT_CODE) {\n if (isDaemon) {\n // Daemon mode: spawn detached child writing to log file\n const { spawn: spawnChild } = await import('node:child_process')\n const { expandHome } = await import('./core/config/config.js')\n const fs = await import('node:fs')\n const pathMod = await import('node:path')\n\n const cliPath = pathMod.resolve(process.argv[1])\n const resolvedLogDir = expandHome(config.logging.logDir)\n fs.mkdirSync(resolvedLogDir, { recursive: true })\n const logFile = pathMod.join(resolvedLogDir, 'openacp.log')\n const out = fs.openSync(logFile, 'a')\n const err = fs.openSync(logFile, 'a')\n\n const child = spawnChild(process.execPath, [cliPath, '--daemon-child'], {\n detached: true,\n stdio: ['ignore', out, err],\n env: { ...process.env, OPENACP_SKIP_UPDATE_CHECK: '1' },\n })\n fs.closeSync(out)\n fs.closeSync(err)\n child.unref()\n log.info({ newPid: child.pid }, 'Respawned daemon for restart')\n } else if (!process.env.OPENACP_DEV_LOOP) {\n // Foreground production mode: spawn replacement process with inherited stdio\n const { spawn: spawnChild } = await import('node:child_process')\n const child = spawnChild(process.execPath, process.argv.slice(1), {\n stdio: 'inherit',\n env: { ...process.env, OPENACP_SKIP_UPDATE_CHECK: '1' },\n })\n await shutdownLogger()\n child.on('exit', (code) => process.exit(code ?? 0))\n return\n }\n }\n\n await shutdownLogger()\n process.exit(exitCode)\n }\n\n // Expose restart trigger for adapters (e.g. /restart command)\n core.requestRestart = () => shutdown('restart', RESTART_EXIT_CODE)\n\n process.on('SIGINT', () => shutdown('SIGINT'))\n process.on('SIGTERM', () => shutdown('SIGTERM'))\n\n process.on('uncaughtException', (err) => {\n log.error({ err }, 'Uncaught exception')\n })\n\n process.on('unhandledRejection', (err) => {\n log.error({ err }, 'Unhandled rejection')\n })\n\n await core.start()\n\n // Auto-register this instance in the global instance registry (backward compat for existing installs)\n try {\n const globalRoot = getGlobalRoot()\n const registryPath = path.join(globalRoot, 'instances.json')\n const instanceReg = new InstanceRegistry(registryPath)\n await instanceReg.load()\n if (!instanceReg.getByRoot(ctx.root)) {\n instanceReg.register(ctx.id, ctx.root)\n await instanceReg.save()\n }\n } catch {\n // Non-critical — don't fail startup if registry write fails\n }\n\n // 6. Log ready\n if (isForegroundTTY) {\n if (spinner) spinner.stop()\n const ok = (msg: string) => console.log(`\\x1b[32m✓\\x1b[0m ${msg}`)\n ok('Config loaded')\n ok('Dependencies checked')\n const tunnelSvc = core.lifecycleManager.serviceRegistry.get<TunnelService>('tunnel')\n if (tunnelSvc) {\n const tunnelUrl = tunnelSvc.getPublicUrl()\n const tunnelErr = tunnelSvc.getStartError()\n if (tunnelErr) {\n console.log(`\\x1b[33m⚠\\x1b[0m Tunnel failed (${tunnelErr}) — viewer links unavailable`)\n } else {\n ok(`Tunnel ready → ${tunnelUrl}`)\n }\n }\n for (const [name] of core.adapters) ok(`${name.charAt(0).toUpperCase() + name.slice(1)} connected`)\n const apiPort = config.api?.port ?? 21420\n if (core.lifecycleManager.serviceRegistry.get('api-server')) ok(`API server on port ${apiPort}`)\n console.log(`\\nOpenACP is running. Press Ctrl+C to stop.\\n`)\n unmuteLogger()\n }\n log.debug({ agents: Object.keys(config.agents) }, 'OpenACP started')\n}\n\n/**\n * Auto-register all built-in plugins when the registry is empty (first boot with new plugin system,\n * or upgrade from legacy config). Also runs legacy config migration for each plugin.\n */\nasync function autoRegisterBuiltinPlugins(\n settingsManager: SettingsManager,\n pluginRegistry: PluginRegistry,\n configManager: ConfigManager,\n): Promise<void> {\n const allPlugins = [\n { name: '@openacp/security', version: '1.0.0', description: 'User access control and session limits' },\n { name: '@openacp/file-service', version: '1.0.0', description: 'File storage and management' },\n { name: '@openacp/context', version: '1.0.0', description: 'Conversation context management' },\n { name: '@openacp/speech', version: '1.0.0', description: 'Text-to-speech and speech-to-text' },\n { name: '@openacp/notifications', version: '1.0.0', description: 'Cross-session notification routing' },\n { name: '@openacp/tunnel', version: '1.0.0', description: 'Expose local services via tunnel' },\n { name: '@openacp/api-server', version: '1.0.0', description: 'REST API + SSE streaming server' },\n { name: '@openacp/telegram', version: '1.0.0', description: 'Telegram adapter with forum topics' },\n ]\n\n // Try to read legacy config for migration\n let legacyConfig: Record<string, unknown> | undefined\n try {\n const cfg = configManager.get()\n if (cfg && typeof cfg === 'object') {\n legacyConfig = cfg as unknown as Record<string, unknown>\n }\n } catch {\n // No config loaded yet — skip migration\n }\n\n // Run legacy migration for each plugin silently\n if (legacyConfig) {\n const pluginModules = await Promise.allSettled([\n import('./plugins/security/index.js'),\n import('./plugins/file-service/index.js'),\n import('./plugins/context/index.js'),\n import('./plugins/speech/index.js'),\n import('./plugins/notifications/index.js'),\n import('./plugins/tunnel/index.js'),\n import('./plugins/api-server/index.js'),\n import('./plugins/telegram/index.js'),\n ])\n\n for (const result of pluginModules) {\n if (result.status !== 'fulfilled') continue\n const plugin = result.value.default\n if (plugin?.install) {\n try {\n // Check if settings already exist\n const existing = await settingsManager.loadSettings(plugin.name)\n if (Object.keys(existing).length > 0) continue\n\n // Create a silent install context for migration only\n const { createInstallContext } = await import('./core/plugin/install-context.js')\n const ctx = createInstallContext({\n pluginName: plugin.name,\n settingsManager,\n basePath: settingsManager.getBasePath(),\n legacyConfig,\n })\n // Override terminal to be silent\n ctx.terminal = createSilentTerminal()\n await plugin.install(ctx)\n } catch {\n // Silently skip — migration is best-effort\n }\n }\n }\n }\n\n for (const p of allPlugins) {\n pluginRegistry.register(p.name, {\n version: p.version,\n source: 'builtin',\n enabled: true,\n settingsPath: settingsManager.getSettingsPath(p.name),\n description: p.description,\n })\n }\n await pluginRegistry.save()\n log.info('Built-in plugins registered in plugin registry')\n}\n\n/**\n * Create a no-op terminal for silent migration (no user interaction).\n */\nfunction createSilentTerminal(): import('./core/plugin/types.js').TerminalIO {\n const noop = () => {}\n // Throw on interactive prompts — silent migration should only use log/spinner/note.\n // If a plugin enters interactive mode (no legacy config to migrate), this aborts it\n // so the try-catch in autoRegisterBuiltinPlugins skips it gracefully.\n const abort = () => { throw new Error('Silent migration: no interactive input available') }\n return {\n text: async () => abort() as never,\n select: async () => abort() as never,\n confirm: async () => abort() as never,\n password: async () => abort() as never,\n multiselect: async () => abort() as never,\n log: { info: noop, success: noop, warning: noop, error: noop, step: noop },\n spinner: () => ({ start: noop, stop: noop, fail: noop }),\n note: noop,\n cancel: noop,\n }\n}\n\n// Direct execution for dev (node dist/main.js)\nconst isDirectExecution = process.argv[1]?.endsWith('main.js')\nif (isDirectExecution) {\n startServer().catch((err) => {\n log.error({ err }, 'Fatal error')\n process.exit(1)\n })\n}\n","import type { CommandRegistry } from '../command-registry.js'\nimport type { CommandResponse } from '../plugin/types.js'\n\n/**\n * System session commands — these are placeholder registrations for discovery\n * (autocomplete, help text, etc.). The actual logic lives in adapter-specific\n * handlers. Handlers return 'silent' so the generic dispatch passes through\n * to the adapter's dedicated handler via next().\n */\nexport function registerSessionCommands(registry: CommandRegistry, _core: unknown): void {\n registry.register({\n name: 'new',\n description: 'Start a new session',\n usage: '[agent-name]',\n category: 'system',\n handler: async () => {\n return { type: 'silent' } satisfies CommandResponse\n },\n })\n\n registry.register({\n name: 'cancel',\n description: 'Cancel the current agent turn',\n category: 'system',\n handler: async () => {\n return { type: 'silent' } satisfies CommandResponse\n },\n })\n\n registry.register({\n name: 'status',\n description: 'Show current session status',\n category: 'system',\n handler: async () => {\n return { type: 'silent' } satisfies CommandResponse\n },\n })\n\n registry.register({\n name: 'sessions',\n description: 'List all active sessions',\n category: 'system',\n handler: async () => {\n return { type: 'silent' } satisfies CommandResponse\n },\n })\n\n registry.register({\n name: 'clear',\n description: 'Clear session history',\n category: 'system',\n handler: async () => {\n return { type: 'silent' } satisfies CommandResponse\n },\n })\n\n registry.register({\n name: 'newchat',\n description: 'New chat, same agent & workspace',\n category: 'system',\n handler: async () => {\n return { type: 'silent' } satisfies CommandResponse\n },\n })\n\n registry.register({\n name: 'resume',\n description: 'Resume a previous session',\n usage: '<session-number>',\n category: 'system',\n handler: async () => {\n return { type: 'silent' } satisfies CommandResponse\n },\n })\n\n registry.register({\n name: 'handoff',\n description: 'Hand off session to another agent',\n usage: '<agent-name>',\n category: 'system',\n handler: async () => {\n return { type: 'silent' } satisfies CommandResponse\n },\n })\n}\n","import type { CommandRegistry } from '../command-registry.js'\nimport type { CommandResponse } from '../plugin/types.js'\n\nexport function registerAgentCommands(registry: CommandRegistry, _core: unknown): void {\n registry.register({\n name: 'agents',\n description: 'List available agents',\n category: 'system',\n handler: async () => {\n return { type: 'text', text: 'No agents configured.' } satisfies CommandResponse\n },\n })\n\n registry.register({\n name: 'install',\n description: 'Install a plugin',\n usage: '<plugin-name>',\n category: 'system',\n handler: async (args) => {\n const plugin = args.raw.trim()\n if (!plugin) {\n return { type: 'error', message: 'Usage: /install <plugin-name>' } satisfies CommandResponse\n }\n return { type: 'text', text: `Installing plugin: ${plugin}...` } satisfies CommandResponse\n },\n })\n}\n","import type { CommandRegistry } from '../command-registry.js'\nimport type { CommandResponse } from '../plugin/types.js'\n\nexport function registerAdminCommands(registry: CommandRegistry, _core: unknown): void {\n registry.register({\n name: 'restart',\n description: 'Restart the server',\n category: 'system',\n handler: async () => {\n return { type: 'silent' } satisfies CommandResponse\n },\n })\n\n registry.register({\n name: 'update',\n description: 'Check for and apply updates',\n category: 'system',\n handler: async () => {\n return { type: 'text', text: 'Checking for updates...' } satisfies CommandResponse\n },\n })\n\n registry.register({\n name: 'doctor',\n description: 'Run system diagnostics',\n category: 'system',\n handler: async () => {\n return { type: 'text', text: 'Running diagnostics...' } satisfies CommandResponse\n },\n })\n\n registry.register({\n name: 'integrate',\n description: 'Set up a new channel integration',\n usage: '<channel>',\n category: 'system',\n handler: async (args) => {\n const channel = args.raw.trim()\n if (!channel) {\n return {\n type: 'menu',\n title: 'Available Integrations',\n options: [\n { label: 'Telegram', command: '/integrate telegram' },\n { label: 'Discord', command: '/integrate discord' },\n ],\n } satisfies CommandResponse\n }\n return { type: 'text', text: `Setting up ${channel} integration...` } satisfies CommandResponse\n },\n })\n}\n","import type { CommandRegistry } from '../command-registry.js'\nimport type { CommandResponse } from '../plugin/types.js'\n\nexport function registerHelpCommand(registry: CommandRegistry, _core: unknown): void {\n registry.register({\n name: 'help',\n description: 'Show available commands',\n usage: '[command]',\n category: 'system',\n handler: async (args) => {\n const query = args.raw.trim()\n\n if (query) {\n const cmd = registry.get(query)\n if (!cmd) {\n return { type: 'error', message: `Unknown command: /${query}` } satisfies CommandResponse\n }\n let text = `/${cmd.name}`\n if (cmd.usage) text += ` ${cmd.usage}`\n text += `\\n${cmd.description}`\n return { type: 'text', text } satisfies CommandResponse\n }\n\n // Auto-generate help from registry at invocation time\n const systemCmds = registry.getByCategory('system')\n const pluginCmds = registry.getByCategory('plugin')\n\n const lines: string[] = []\n\n if (systemCmds.length > 0) {\n lines.push('System Commands:')\n for (const cmd of systemCmds) {\n const usage = cmd.usage ? ` ${cmd.usage}` : ''\n lines.push(` /${cmd.name}${usage} — ${cmd.description}`)\n }\n }\n\n if (pluginCmds.length > 0) {\n if (lines.length > 0) lines.push('')\n lines.push('Plugin Commands:')\n for (const cmd of pluginCmds) {\n const usage = cmd.usage ? ` ${cmd.usage}` : ''\n lines.push(` /${cmd.name}${usage} — ${cmd.description}`)\n }\n }\n\n if (lines.length === 0) {\n return { type: 'text', text: 'No commands registered.' } satisfies CommandResponse\n }\n\n return { type: 'text', text: lines.join('\\n') } satisfies CommandResponse\n },\n })\n}\n","import type { CommandRegistry } from '../command-registry.js'\nimport type { CommandResponse } from '../plugin/types.js'\n\nexport function registerMenuCommand(registry: CommandRegistry, _core: unknown): void {\n registry.register({\n name: 'menu',\n description: 'Show the main menu',\n category: 'system',\n handler: async () => {\n return {\n type: 'menu',\n title: 'Main Menu',\n options: [\n { label: 'New Session', command: '/new' },\n { label: 'Active Sessions', command: '/sessions' },\n { label: 'Available Agents', command: '/agents' },\n { label: 'Usage', command: '/usage' },\n { label: 'Help', command: '/help' },\n ],\n } satisfies CommandResponse\n },\n })\n}\n","import type { CommandRegistry } from '../command-registry.js'\nimport type { CommandResponse } from '../plugin/types.js'\n\nexport function registerSwitchCommands(registry: CommandRegistry): void {\n registry.register({\n name: 'switch',\n description: 'Switch to a different agent',\n usage: '[agent-name | label on|off]',\n category: 'system',\n handler: async (args) => {\n const raw = args.raw.trim()\n\n // /switch label on|off\n if (raw.startsWith('label ')) {\n const value = raw.slice(6).trim().toLowerCase()\n if (value !== 'on' && value !== 'off') {\n return { type: 'error', message: 'Usage: /switch label on|off' } satisfies CommandResponse\n }\n return { type: 'silent' } satisfies CommandResponse\n }\n\n // /switch (no args) → show menu, or /switch <agent> → direct switch\n // Both delegated to adapter handler\n return { type: 'silent' } satisfies CommandResponse\n },\n })\n}\n","import type { CommandRegistry } from '../command-registry.js'\nimport { registerSessionCommands } from './session.js'\nimport { registerAgentCommands } from './agents.js'\nimport { registerAdminCommands } from './admin.js'\nimport { registerHelpCommand } from './help.js'\nimport { registerMenuCommand } from './menu.js'\nimport { registerSwitchCommands } from './switch.js'\n\nexport function registerSystemCommands(registry: CommandRegistry, core: unknown): void {\n registerSessionCommands(registry, core)\n registerAgentCommands(registry, core)\n registerAdminCommands(registry, core)\n registerHelpCommand(registry, core)\n registerMenuCommand(registry, core)\n registerSwitchCommands(registry)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,OAAO,UAAU;;;ACOV,SAAS,wBAAwB,UAA2B,OAAsB;AACvF,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS,YAAY;AACnB,aAAO,EAAE,MAAM,SAAS;AAAA,IAC1B;AAAA,EACF,CAAC;AAED,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,SAAS,YAAY;AACnB,aAAO,EAAE,MAAM,SAAS;AAAA,IAC1B;AAAA,EACF,CAAC;AAED,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,SAAS,YAAY;AACnB,aAAO,EAAE,MAAM,SAAS;AAAA,IAC1B;AAAA,EACF,CAAC;AAED,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,SAAS,YAAY;AACnB,aAAO,EAAE,MAAM,SAAS;AAAA,IAC1B;AAAA,EACF,CAAC;AAED,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,SAAS,YAAY;AACnB,aAAO,EAAE,MAAM,SAAS;AAAA,IAC1B;AAAA,EACF,CAAC;AAED,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,SAAS,YAAY;AACnB,aAAO,EAAE,MAAM,SAAS;AAAA,IAC1B;AAAA,EACF,CAAC;AAED,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS,YAAY;AACnB,aAAO,EAAE,MAAM,SAAS;AAAA,IAC1B;AAAA,EACF,CAAC;AAED,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS,YAAY;AACnB,aAAO,EAAE,MAAM,SAAS;AAAA,IAC1B;AAAA,EACF,CAAC;AACH;;;ACjFO,SAAS,sBAAsB,UAA2B,OAAsB;AACrF,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,SAAS,YAAY;AACnB,aAAO,EAAE,MAAM,QAAQ,MAAM,wBAAwB;AAAA,IACvD;AAAA,EACF,CAAC;AAED,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS,OAAO,SAAS;AACvB,YAAM,SAAS,KAAK,IAAI,KAAK;AAC7B,UAAI,CAAC,QAAQ;AACX,eAAO,EAAE,MAAM,SAAS,SAAS,gCAAgC;AAAA,MACnE;AACA,aAAO,EAAE,MAAM,QAAQ,MAAM,sBAAsB,MAAM,MAAM;AAAA,IACjE;AAAA,EACF,CAAC;AACH;;;ACvBO,SAAS,sBAAsB,UAA2B,OAAsB;AACrF,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,SAAS,YAAY;AACnB,aAAO,EAAE,MAAM,SAAS;AAAA,IAC1B;AAAA,EACF,CAAC;AAED,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,SAAS,YAAY;AACnB,aAAO,EAAE,MAAM,QAAQ,MAAM,0BAA0B;AAAA,IACzD;AAAA,EACF,CAAC;AAED,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,SAAS,YAAY;AACnB,aAAO,EAAE,MAAM,QAAQ,MAAM,yBAAyB;AAAA,IACxD;AAAA,EACF,CAAC;AAED,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS,OAAO,SAAS;AACvB,YAAM,UAAU,KAAK,IAAI,KAAK;AAC9B,UAAI,CAAC,SAAS;AACZ,eAAO;AAAA,UACL,MAAM;AAAA,UACN,OAAO;AAAA,UACP,SAAS;AAAA,YACP,EAAE,OAAO,YAAY,SAAS,sBAAsB;AAAA,YACpD,EAAE,OAAO,WAAW,SAAS,qBAAqB;AAAA,UACpD;AAAA,QACF;AAAA,MACF;AACA,aAAO,EAAE,MAAM,QAAQ,MAAM,cAAc,OAAO,kBAAkB;AAAA,IACtE;AAAA,EACF,CAAC;AACH;;;AChDO,SAAS,oBAAoB,UAA2B,OAAsB;AACnF,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS,OAAO,SAAS;AACvB,YAAM,QAAQ,KAAK,IAAI,KAAK;AAE5B,UAAI,OAAO;AACT,cAAM,MAAM,SAAS,IAAI,KAAK;AAC9B,YAAI,CAAC,KAAK;AACR,iBAAO,EAAE,MAAM,SAAS,SAAS,qBAAqB,KAAK,GAAG;AAAA,QAChE;AACA,YAAI,OAAO,IAAI,IAAI,IAAI;AACvB,YAAI,IAAI,MAAO,SAAQ,IAAI,IAAI,KAAK;AACpC,gBAAQ;AAAA,EAAK,IAAI,WAAW;AAC5B,eAAO,EAAE,MAAM,QAAQ,KAAK;AAAA,MAC9B;AAGA,YAAM,aAAa,SAAS,cAAc,QAAQ;AAClD,YAAM,aAAa,SAAS,cAAc,QAAQ;AAElD,YAAM,QAAkB,CAAC;AAEzB,UAAI,WAAW,SAAS,GAAG;AACzB,cAAM,KAAK,kBAAkB;AAC7B,mBAAW,OAAO,YAAY;AAC5B,gBAAM,QAAQ,IAAI,QAAQ,IAAI,IAAI,KAAK,KAAK;AAC5C,gBAAM,KAAK,MAAM,IAAI,IAAI,GAAG,KAAK,WAAM,IAAI,WAAW,EAAE;AAAA,QAC1D;AAAA,MACF;AAEA,UAAI,WAAW,SAAS,GAAG;AACzB,YAAI,MAAM,SAAS,EAAG,OAAM,KAAK,EAAE;AACnC,cAAM,KAAK,kBAAkB;AAC7B,mBAAW,OAAO,YAAY;AAC5B,gBAAM,QAAQ,IAAI,QAAQ,IAAI,IAAI,KAAK,KAAK;AAC5C,gBAAM,KAAK,MAAM,IAAI,IAAI,GAAG,KAAK,WAAM,IAAI,WAAW,EAAE;AAAA,QAC1D;AAAA,MACF;AAEA,UAAI,MAAM,WAAW,GAAG;AACtB,eAAO,EAAE,MAAM,QAAQ,MAAM,0BAA0B;AAAA,MACzD;AAEA,aAAO,EAAE,MAAM,QAAQ,MAAM,MAAM,KAAK,IAAI,EAAE;AAAA,IAChD;AAAA,EACF,CAAC;AACH;;;AClDO,SAAS,oBAAoB,UAA2B,OAAsB;AACnF,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,SAAS,YAAY;AACnB,aAAO;AAAA,QACL,MAAM;AAAA,QACN,OAAO;AAAA,QACP,SAAS;AAAA,UACP,EAAE,OAAO,eAAe,SAAS,OAAO;AAAA,UACxC,EAAE,OAAO,mBAAmB,SAAS,YAAY;AAAA,UACjD,EAAE,OAAO,oBAAoB,SAAS,UAAU;AAAA,UAChD,EAAE,OAAO,SAAS,SAAS,SAAS;AAAA,UACpC,EAAE,OAAO,QAAQ,SAAS,QAAQ;AAAA,QACpC;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AACH;;;ACnBO,SAAS,uBAAuB,UAAiC;AACtE,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS,OAAO,SAAS;AACvB,YAAM,MAAM,KAAK,IAAI,KAAK;AAG1B,UAAI,IAAI,WAAW,QAAQ,GAAG;AAC5B,cAAM,QAAQ,IAAI,MAAM,CAAC,EAAE,KAAK,EAAE,YAAY;AAC9C,YAAI,UAAU,QAAQ,UAAU,OAAO;AACrC,iBAAO,EAAE,MAAM,SAAS,SAAS,8BAA8B;AAAA,QACjE;AACA,eAAO,EAAE,MAAM,SAAS;AAAA,MAC1B;AAIA,aAAO,EAAE,MAAM,SAAS;AAAA,IAC1B;AAAA,EACF,CAAC;AACH;;;AClBO,SAAS,uBAAuB,UAA2B,MAAqB;AACrF,0BAAwB,UAAU,IAAI;AACtC,wBAAsB,UAAU,IAAI;AACpC,wBAAsB,UAAU,IAAI;AACpC,sBAAoB,UAAU,IAAI;AAClC,sBAAoB,UAAU,IAAI;AAClC,yBAAuB,QAAQ;AACjC;;;APCA,OAAO,QAAQ;AAER,IAAM,oBAAoB;AACjC,IAAI,eAAe;AASnB,eAAsB,YAAY,MAA2B;AAC3D,QAAM,MAAM,MAAM,mBAAmB,sBAAsB;AAAA,IACzD,IAAI;AAAA,IACJ,MAAM,cAAc;AAAA,IACpB,UAAU;AAAA,EACZ,CAAC;AAGD,MAAI,QAAQ,KAAK,SAAS,gBAAgB,GAAG;AAC3C,UAAM,EAAE,cAAc,aAAa,gBAAgB,IAAI,MAAM,OAAO,sBAAiB;AAGrF,QAAI,CAAC,gBAAgB,IAAI,IAAI,GAAG;AAC9B,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,UAAU,IAAI,MAAM;AAC1B,UAAM,cAAc,YAAY,OAAO;AACvC,QAAI,gBAAgB,QAAQ,gBAAgB,QAAQ,KAAK;AACvD,UAAI;AACF,gBAAQ,KAAK,aAAa,CAAC;AAC3B,gBAAQ,MAAM,oDAAoD,WAAW,aAAa;AAC1F,gBAAQ,KAAK,CAAC;AAAA,MAChB,QAAQ;AAAA,MAER;AAAA,IACF;AACA,iBAAa,SAAS,QAAQ,GAAG;AAAA,EACnC;AAGA,QAAM,kBAAkB,IAAI,gBAAgB,IAAI,MAAM,WAAW;AACjE,QAAM,iBAAiB,IAAI,eAAe,IAAI,MAAM,cAAc;AAClE,QAAM,eAAe,KAAK;AAG1B,QAAM,gBAAgB,IAAI,cAAc,IAAI,MAAM,MAAM;AACxD,QAAM,eAAe,MAAM,cAAc,OAAO;AAEhD,MAAI,CAAC,cAAc;AACjB,UAAM,EAAE,SAAS,IAAI,MAAM,OAAO,qBAAuB;AACzD,UAAM,cAAc,MAAM,SAAS,eAAe,EAAE,iBAAiB,eAAe,CAAC;AACrF,QAAI,CAAC,YAAa,SAAQ,KAAK,CAAC;AAAA,EAClC;AAGA,QAAM,cAAc,KAAK;AACzB,QAAM,SAAS,cAAc,IAAI;AACjC,aAAW,OAAO,OAAO;AACzB,MAAI,MAAM,EAAE,YAAY,cAAc,cAAc,EAAE,GAAG,eAAe;AAGxE,MAAI,eAAe,KAAK,EAAE,SAAS,GAAG;AACpC,UAAM,2BAA2B,iBAAiB,gBAAgB,aAAa;AAAA,EACjF;AAGA,QAAM,kBAAkB,CAAC,EAAE,QAAQ,OAAO,SAAS,CAAC,QAAQ,IAAI,YAAY,OAAO,YAAY;AAC/F,MAAI,iBAAiB;AACnB,UAAM,EAAE,iBAAiB,IAAI,MAAM,OAAO,qBAAuB;AACjE,UAAM,iBAAiB;AAAA,EACzB;AAGA,MAAI;AACJ,MAAI,iBAAiB;AACnB,eAAW;AACX,UAAM,OAAO,MAAM,OAAO,KAAK,GAAG;AAClC,cAAU,IAAI,EAAE,MAAM,uBAAuB,SAAS,OAAO,CAAC,EAAE,MAAM;AAAA,EACxE;AAGA,MAAI;AACF,UAAM,EAAE,qBAAqB,IAAI,MAAM,OAAO,4BAAuB;AACrE,UAAM,qBAAqB,MAAM;AAAA,EACnC,SAAS,KAAK;AACZ,QAAI,KAAK,EAAE,IAAI,GAAG,2BAA2B;AAAA,EAC/C;AAGA,wBAAsB,OAAO,QAAQ,uBAAuB,EAAE;AAAA,IAAM,SAClE,IAAI,KAAK,EAAE,IAAI,GAAG,4BAA4B;AAAA,EAChD;AAGA,QAAM,OAAO,IAAI,YAAY,eAAe,GAAG;AAG/C,QAAM,kBAAkB,IAAI,gBAAgB;AAC5C,QAAM,kBAAkB,KAAK,iBAAiB;AAC9C,kBAAgB,SAAS,oBAAoB,iBAAiB,MAAM;AAGpE,yBAAuB,iBAAiB,IAAI;AAG5C,MAAI;AAEF,SAAK,SAAS,KAAK,eAAe;AAGjC,IAAC,KAAK,iBAAyB,kBAAkB;AACjD,IAAC,KAAK,iBAAyB,iBAAiB;AAGjD,UAAM,KAAK,iBAAiB,KAAK,WAAW;AAG5C,QAAI;AACF,YAAM,mBAAqE,CAAC;AAC5E,YAAM,aAAa,eAAe,aAAa,KAAK;AACpD,YAAM,eAAe,eAAe,aAAa,OAAO;AACxD,YAAM,sBAAsB,IAAI,IAAI,CAAC,GAAG,YAAY,GAAG,YAAY,CAAC;AAEpE,iBAAW,CAAC,MAAM,KAAK,KAAK,qBAAqB;AAC/C,YAAI,CAAC,MAAM,QAAS;AAEpB,YAAI;AACF,cAAI;AAEJ,cAAI,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,GAAG,GAAG;AAEhD,kBAAM,WAAW,KAAK,QAAQ,IAAI;AAClC,kBAAM,UAAU,KAAK,KAAK,UAAU,cAAc;AAClD,kBAAM,MAAM,KAAK,MAAM,MAAM,GAAG,SAAS,SAAS,SAAS,OAAO,CAAC;AACnE,yBAAa,KAAK,KAAK,UAAU,IAAI,QAAQ,eAAe;AAAA,UAC9D,OAAO;AAEL,kBAAM,iBAAiB,KAAK,KAAK,IAAI,MAAM,SAAS,cAAc;AAClE,gBAAI,SAAS,KAAK,KAAK,gBAAgB,IAAI;AAE3C,gBAAI,CAAC,GAAG,WAAW,KAAK,KAAK,QAAQ,cAAc,CAAC,GAAG;AAGrD,kBAAI,QAAQ;AACZ,oBAAM,SAAS,GAAG,WAAW,cAAc,IACvC,GAAG,YAAY,cAAc,EAAE,OAAO,OAAK,EAAE,WAAW,GAAG,CAAC,IAC5D,CAAC;AACL,yBAAW,SAAS,QAAQ;AAC1B,sBAAM,WAAW,KAAK,KAAK,gBAAgB,KAAK;AAChD,sBAAM,OAAO,GAAG,YAAY,QAAQ;AACpC,2BAAWA,QAAO,MAAM;AACtB,wBAAM,eAAe,KAAK,KAAK,UAAUA,IAAG;AAC5C,wBAAM,mBAAmB,KAAK,KAAK,cAAc,cAAc;AAC/D,sBAAI,GAAG,WAAW,gBAAgB,GAAG;AACnC,wBAAI;AACF,4BAAM,eAAe,KAAK,MAAM,GAAG,aAAa,kBAAkB,OAAO,CAAC;AAC1E,4BAAM,aAAa,aAAa,SAAS;AACzC,0BAAI,eAAe,MAAM;AACvB,iCAAS;AACT,gCAAQ;AACR;AAAA,sBACF;AAAA,oBACF,QAAQ;AAAA,oBAAa;AAAA,kBACvB;AAAA,gBACF;AACA,oBAAI,MAAO;AAAA,cACb;AAAA,YACF;AAEA,kBAAM,cAAc,KAAK,KAAK,QAAQ,cAAc;AACpD,kBAAM,MAAM,KAAK,MAAM,MAAM,GAAG,SAAS,SAAS,aAAa,OAAO,CAAC;AACvE,yBAAa,KAAK,KAAK,QAAQ,IAAI,QAAQ,eAAe;AAAA,UAC5D;AAEA,cAAI,MAAM,EAAE,QAAQ,MAAM,WAAW,GAAG,0BAA0B;AAClE,gBAAM,MAAM,MAAM,OAAO;AACzB,gBAAM,SAAS,IAAI;AAEnB,cAAI,CAAC,UAAU,CAAC,OAAO,QAAQ,CAAC,OAAO,OAAO;AAC5C,gBAAI,KAAK,EAAE,QAAQ,KAAK,GAAG,wEAAwE;AACnG;AAAA,UACF;AAEA,2BAAiB,KAAK,MAAM;AAAA,QAC9B,SAAS,KAAK;AACZ,cAAI,KAAK,EAAE,KAAK,QAAQ,KAAK,GAAG,2CAA2C;AAAA,QAC7E;AAAA,MACF;AAEA,UAAI,iBAAiB,SAAS,GAAG;AAC/B,YAAI,MAAM,EAAE,SAAS,iBAAiB,IAAI,OAAK,EAAE,IAAI,EAAE,GAAG,2BAA2B;AACrF,cAAM,KAAK,iBAAiB,KAAK,gBAAgB;AAAA,MACnD;AAAA,IACF,SAAS,KAAK;AACZ,UAAI,KAAK,EAAE,IAAI,GAAG,iCAAiC;AAAA,IACrD;AAGA,QAAI,MAAM,eAAe;AACvB,YAAM,EAAE,gBAAgB,IAAI,MAAM,OAAO,0BAA6B;AACtE,YAAM,YAAY,IAAI,gBAAgB,KAAK,aAAa;AAExD,UAAI;AACF,cAAM,YAAY,MAAM,UAAU,KAAK;AACvC,cAAM,KAAK,iBAAiB,KAAK,CAAC,SAAS,CAAC;AAC5C,YAAI,KAAK,EAAE,QAAQ,UAAU,MAAM,SAAS,UAAU,QAAQ,GAAG,mBAAmB;AAGpF,YAAI,CAAC,KAAK,SAAS;AACjB,gBAAM,WAAW,UAAU,YAAY;AACvC,cAAI,cAAoD;AAExD,aAAG,MAAM,UAAU,EAAE,WAAW,KAAK,GAAG,CAAC,YAAY,aAAa;AAChE,gBAAI,CAAC,UAAU,SAAS,KAAK,EAAG;AAGhC,gBAAI,YAAa,cAAa,WAAW;AACzC,0BAAc,WAAW,YAAY;AACnC,kBAAI;AACF,oBAAI,KAAK,EAAE,SAAS,GAAG,kCAAkC;AACzD,sBAAM,KAAK,iBAAiB,aAAa,UAAU,IAAI;AACvD,sBAAM,WAAW,MAAM,UAAU,KAAK;AACtC,sBAAM,KAAK,iBAAiB,KAAK,CAAC,QAAQ,CAAC;AAC3C,oBAAI,KAAK,EAAE,QAAQ,SAAS,MAAM,SAAS,SAAS,QAAQ,GAAG,qBAAqB;AAAA,cACtF,SAAS,KAAK;AACZ,oBAAI,MAAM,EAAE,IAAI,GAAG,0BAA0B;AAAA,cAC/C;AAAA,YACF,GAAG,GAAG;AAAA,UACR,CAAC;AAED,cAAI,KAAK,EAAE,SAAS,GAAG,iCAAiC;AAAA,QAC1D;AAAA,MACF,SAAS,KAAK;AACZ,YAAI,MAAM,EAAE,KAAK,YAAY,KAAK,cAAc,GAAG,2BAA2B;AAAA,MAChF;AAAA,IACF;AAGA,eAAW,EAAE,KAAK,KAAK,gBAAgB,KAAK,GAAG;AAC7C,UAAI,CAAC,KAAK,WAAW,UAAU,EAAG;AAClC,YAAM,cAAc,KAAK,MAAM,WAAW,MAAM;AAChD,YAAM,UAAU,gBAAgB,IAAqB,IAAI;AACzD,UAAI,SAAS;AACX,aAAK,gBAAgB,aAAa,OAAO;AACzC,YAAI,KAAK,EAAE,SAAS,YAAY,GAAG,oBAAoB;AAAA,MACzD;AAAA,IACF;AAGA,UAAM,YAAY,gBAAgB,IAAmB,QAAQ;AAC7D,QAAI,WAAW;AACb,WAAK,gBAAgB;AAAA,IACvB;AAGA,SAAK,SAAS,KAAK,yBAAyB,EAAE,UAAU,gBAAgB,OAAO,EAAE,CAAC;AAElF,SAAK,SAAS,KAAK,cAAc;AAAA,EACnC,SAAS,KAAK;AACZ,QAAI,SAAS;AACX,cAAQ,KAAK,oBAAoB;AACjC,gBAAU;AAAA,IACZ;AACA,iBAAa;AACb,QAAI,MAAM,EAAE,IAAI,GAAG,oBAAoB;AAAA,EACzC;AAEA,MAAI,KAAK,SAAS,SAAS,GAAG;AAC5B,QAAI,MAAM,6DAA6D;AACvE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,WAAW,OAAO,QAAgB,WAAW,MAAM;AACvD,QAAI,aAAc;AAClB,mBAAe;AACf,QAAI,KAAK,EAAE,QAAQ,SAAS,GAAG,gCAAgC;AAE/D,QAAI;AAEF,UAAI;AACF,cAAM,KAAK,gBAAgB,IAA2E,eAAe;AACrH,YAAI,IAAI;AACN,gBAAM,GAAG,UAAU;AAAA,YACjB,WAAW;AAAA,YACX,MAAM;AAAA,YACN,SAAS;AAAA,UACX,CAAC;AAAA,QACH;AAAA,MACF,QAAQ;AAAA,MAER;AAGA,YAAM,KAAK,eAAe,YAAY;AAGtC,YAAM,KAAK,iBAAiB,SAAS;AAAA,IAGvC,SAAS,KAAK;AACZ,UAAI,MAAM,EAAE,IAAI,GAAG,uBAAuB;AAAA,IAC5C;AAEA,UAAM,WAAW,QAAQ,KAAK,SAAS,gBAAgB;AAGvD,QAAI,UAAU;AACZ,YAAM,EAAE,cAAc,IAAI,MAAM,OAAO,sBAAiB;AACxD,oBAAc,IAAI,MAAM,GAAG;AAAA,IAC7B;AAGA,QAAI,aAAa,mBAAmB;AAClC,UAAI,UAAU;AAEZ,cAAM,EAAE,OAAO,WAAW,IAAI,MAAM,OAAO,eAAoB;AAC/D,cAAM,EAAE,WAAW,IAAI,MAAM,OAAO,sBAAyB;AAC7D,cAAMC,MAAK,MAAM,OAAO,IAAS;AACjC,cAAM,UAAU,MAAM,OAAO,MAAW;AAExC,cAAM,UAAU,QAAQ,QAAQ,QAAQ,KAAK,CAAC,CAAC;AAC/C,cAAM,iBAAiB,WAAW,OAAO,QAAQ,MAAM;AACvD,QAAAA,IAAG,UAAU,gBAAgB,EAAE,WAAW,KAAK,CAAC;AAChD,cAAM,UAAU,QAAQ,KAAK,gBAAgB,aAAa;AAC1D,cAAM,MAAMA,IAAG,SAAS,SAAS,GAAG;AACpC,cAAM,MAAMA,IAAG,SAAS,SAAS,GAAG;AAEpC,cAAM,QAAQ,WAAW,QAAQ,UAAU,CAAC,SAAS,gBAAgB,GAAG;AAAA,UACtE,UAAU;AAAA,UACV,OAAO,CAAC,UAAU,KAAK,GAAG;AAAA,UAC1B,KAAK,EAAE,GAAG,QAAQ,KAAK,2BAA2B,IAAI;AAAA,QACxD,CAAC;AACD,QAAAA,IAAG,UAAU,GAAG;AAChB,QAAAA,IAAG,UAAU,GAAG;AAChB,cAAM,MAAM;AACZ,YAAI,KAAK,EAAE,QAAQ,MAAM,IAAI,GAAG,8BAA8B;AAAA,MAChE,WAAW,CAAC,QAAQ,IAAI,kBAAkB;AAExC,cAAM,EAAE,OAAO,WAAW,IAAI,MAAM,OAAO,eAAoB;AAC/D,cAAM,QAAQ,WAAW,QAAQ,UAAU,QAAQ,KAAK,MAAM,CAAC,GAAG;AAAA,UAChE,OAAO;AAAA,UACP,KAAK,EAAE,GAAG,QAAQ,KAAK,2BAA2B,IAAI;AAAA,QACxD,CAAC;AACD,cAAM,eAAe;AACrB,cAAM,GAAG,QAAQ,CAAC,SAAS,QAAQ,KAAK,QAAQ,CAAC,CAAC;AAClD;AAAA,MACF;AAAA,IACF;AAEA,UAAM,eAAe;AACrB,YAAQ,KAAK,QAAQ;AAAA,EACvB;AAGA,OAAK,iBAAiB,MAAM,SAAS,WAAW,iBAAiB;AAEjE,UAAQ,GAAG,UAAU,MAAM,SAAS,QAAQ,CAAC;AAC7C,UAAQ,GAAG,WAAW,MAAM,SAAS,SAAS,CAAC;AAE/C,UAAQ,GAAG,qBAAqB,CAAC,QAAQ;AACvC,QAAI,MAAM,EAAE,IAAI,GAAG,oBAAoB;AAAA,EACzC,CAAC;AAED,UAAQ,GAAG,sBAAsB,CAAC,QAAQ;AACxC,QAAI,MAAM,EAAE,IAAI,GAAG,qBAAqB;AAAA,EAC1C,CAAC;AAED,QAAM,KAAK,MAAM;AAGjB,MAAI;AACF,UAAM,aAAa,cAAc;AACjC,UAAM,eAAe,KAAK,KAAK,YAAY,gBAAgB;AAC3D,UAAM,cAAc,IAAI,iBAAiB,YAAY;AACrD,UAAM,YAAY,KAAK;AACvB,QAAI,CAAC,YAAY,UAAU,IAAI,IAAI,GAAG;AACpC,kBAAY,SAAS,IAAI,IAAI,IAAI,IAAI;AACrC,YAAM,YAAY,KAAK;AAAA,IACzB;AAAA,EACF,QAAQ;AAAA,EAER;AAGA,MAAI,iBAAiB;AACnB,QAAI,QAAS,SAAQ,KAAK;AAC1B,UAAM,KAAK,CAAC,QAAgB,QAAQ,IAAI,yBAAoB,GAAG,EAAE;AACjE,OAAG,eAAe;AAClB,OAAG,sBAAsB;AACzB,UAAM,YAAY,KAAK,iBAAiB,gBAAgB,IAAmB,QAAQ;AACnF,QAAI,WAAW;AACb,YAAM,YAAY,UAAU,aAAa;AACzC,YAAM,YAAY,UAAU,cAAc;AAC1C,UAAI,WAAW;AACb,gBAAQ,IAAI,yCAAoC,SAAS,mCAA8B;AAAA,MACzF,OAAO;AACL,WAAG,uBAAkB,SAAS,EAAE;AAAA,MAClC;AAAA,IACF;AACA,eAAW,CAAC,IAAI,KAAK,KAAK,SAAU,IAAG,GAAG,KAAK,OAAO,CAAC,EAAE,YAAY,IAAI,KAAK,MAAM,CAAC,CAAC,YAAY;AAClG,UAAM,UAAU,OAAO,KAAK,QAAQ;AACpC,QAAI,KAAK,iBAAiB,gBAAgB,IAAI,YAAY,EAAG,IAAG,sBAAsB,OAAO,EAAE;AAC/F,YAAQ,IAAI;AAAA;AAAA,CAA+C;AAC3D,iBAAa;AAAA,EACf;AACA,MAAI,MAAM,EAAE,QAAQ,OAAO,KAAK,OAAO,MAAM,EAAE,GAAG,iBAAiB;AACrE;AAMA,eAAe,2BACb,iBACA,gBACA,eACe;AACf,QAAM,aAAa;AAAA,IACjB,EAAE,MAAM,qBAAqB,SAAS,SAAS,aAAa,yCAAyC;AAAA,IACrG,EAAE,MAAM,yBAAyB,SAAS,SAAS,aAAa,8BAA8B;AAAA,IAC9F,EAAE,MAAM,oBAAoB,SAAS,SAAS,aAAa,kCAAkC;AAAA,IAC7F,EAAE,MAAM,mBAAmB,SAAS,SAAS,aAAa,oCAAoC;AAAA,IAC9F,EAAE,MAAM,0BAA0B,SAAS,SAAS,aAAa,qCAAqC;AAAA,IACtG,EAAE,MAAM,mBAAmB,SAAS,SAAS,aAAa,mCAAmC;AAAA,IAC7F,EAAE,MAAM,uBAAuB,SAAS,SAAS,aAAa,kCAAkC;AAAA,IAChG,EAAE,MAAM,qBAAqB,SAAS,SAAS,aAAa,qCAAqC;AAAA,EACnG;AAGA,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,cAAc,IAAI;AAC9B,QAAI,OAAO,OAAO,QAAQ,UAAU;AAClC,qBAAe;AAAA,IACjB;AAAA,EACF,QAAQ;AAAA,EAER;AAGA,MAAI,cAAc;AAChB,UAAM,gBAAgB,MAAM,QAAQ,WAAW;AAAA,MAC7C,OAAO,wBAA6B;AAAA,MACpC,OAAO,4BAAiC;AAAA,MACxC,OAAO,uBAA4B;AAAA,MACnC,OAAO,sBAA2B;AAAA,MAClC,OAAO,6BAAkC;AAAA,MACzC,OAAO,sBAA2B;AAAA,MAClC,OAAO,0BAA+B;AAAA,MACtC,OAAO,wBAA6B;AAAA,IACtC,CAAC;AAED,eAAW,UAAU,eAAe;AAClC,UAAI,OAAO,WAAW,YAAa;AACnC,YAAM,SAAS,OAAO,MAAM;AAC5B,UAAI,QAAQ,SAAS;AACnB,YAAI;AAEF,gBAAM,WAAW,MAAM,gBAAgB,aAAa,OAAO,IAAI;AAC/D,cAAI,OAAO,KAAK,QAAQ,EAAE,SAAS,EAAG;AAGtC,gBAAM,EAAE,qBAAqB,IAAI,MAAM,OAAO,+BAAkC;AAChF,gBAAM,MAAM,qBAAqB;AAAA,YAC/B,YAAY,OAAO;AAAA,YACnB;AAAA,YACA,UAAU,gBAAgB,YAAY;AAAA,YACtC;AAAA,UACF,CAAC;AAED,cAAI,WAAW,qBAAqB;AACpC,gBAAM,OAAO,QAAQ,GAAG;AAAA,QAC1B,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,aAAW,KAAK,YAAY;AAC1B,mBAAe,SAAS,EAAE,MAAM;AAAA,MAC9B,SAAS,EAAE;AAAA,MACX,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,cAAc,gBAAgB,gBAAgB,EAAE,IAAI;AAAA,MACpD,aAAa,EAAE;AAAA,IACjB,CAAC;AAAA,EACH;AACA,QAAM,eAAe,KAAK;AAC1B,MAAI,KAAK,gDAAgD;AAC3D;AAKA,SAAS,uBAAoE;AAC3E,QAAM,OAAO,MAAM;AAAA,EAAC;AAIpB,QAAM,QAAQ,MAAM;AAAE,UAAM,IAAI,MAAM,kDAAkD;AAAA,EAAE;AAC1F,SAAO;AAAA,IACL,MAAM,YAAY,MAAM;AAAA,IACxB,QAAQ,YAAY,MAAM;AAAA,IAC1B,SAAS,YAAY,MAAM;AAAA,IAC3B,UAAU,YAAY,MAAM;AAAA,IAC5B,aAAa,YAAY,MAAM;AAAA,IAC/B,KAAK,EAAE,MAAM,MAAM,SAAS,MAAM,SAAS,MAAM,OAAO,MAAM,MAAM,KAAK;AAAA,IACzE,SAAS,OAAO,EAAE,OAAO,MAAM,MAAM,MAAM,MAAM,KAAK;AAAA,IACtD,MAAM;AAAA,IACN,QAAQ;AAAA,EACV;AACF;AAGA,IAAM,oBAAoB,QAAQ,KAAK,CAAC,GAAG,SAAS,SAAS;AAC7D,IAAI,mBAAmB;AACrB,cAAY,EAAE,MAAM,CAAC,QAAQ;AAC3B,QAAI,MAAM,EAAE,IAAI,GAAG,aAAa;AAChC,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AACH;","names":["pkg","fs"]}
|
|
@@ -486,7 +486,7 @@ Declare in \`permissions\` array. Only request what you need.
|
|
|
486
486
|
|
|
487
487
|
Calling a method without the required permission throws \`PluginPermissionError\`.
|
|
488
488
|
|
|
489
|
-
## Middleware Hooks (
|
|
489
|
+
## Middleware Hooks (20 total)
|
|
490
490
|
|
|
491
491
|
Register with \`ctx.registerMiddleware(hook, { priority?, handler })\`. Return \`null\` to block the flow, call \`next()\` to continue.
|
|
492
492
|
|
|
@@ -524,6 +524,8 @@ Register with \`ctx.registerMiddleware(hook, { priority?, handler })\`. Return \
|
|
|
524
524
|
- \`config:beforeChange\` \u2014 before config change (sessionId, configId, oldValue, newValue)
|
|
525
525
|
- \`model:beforeChange\` \u2014 before model change (sessionId, fromModel, toModel)
|
|
526
526
|
- \`agent:beforeCancel\` \u2014 before agent cancellation (sessionId, reason)
|
|
527
|
+
- \`agent:beforeSwitch\` \u2014 **blocking** before agent switch (sessionId, fromAgent, toAgent). Return null/false to block.
|
|
528
|
+
- \`agent:afterSwitch\` \u2014 **fire-and-forget** after agent switch (sessionId, fromAgent, toAgent, resumed). Observational only.
|
|
527
529
|
|
|
528
530
|
## Plugin Events (subscribe with ctx.on)
|
|
529
531
|
|
|
@@ -963,4 +965,4 @@ async function cmdPluginCreate() {
|
|
|
963
965
|
export {
|
|
964
966
|
cmdPluginCreate
|
|
965
967
|
};
|
|
966
|
-
//# sourceMappingURL=plugin-create-
|
|
968
|
+
//# sourceMappingURL=plugin-create-HFKS23JY.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/commands/plugin-create.ts","../../src/cli/plugin-template/package-json.ts","../../src/cli/plugin-template/tsconfig.ts","../../src/cli/plugin-template/dotfiles.ts","../../src/cli/plugin-template/readme.ts","../../src/cli/plugin-template/plugin-source.ts","../../src/cli/plugin-template/plugin-test.ts","../../src/cli/plugin-template/claude-md.ts","../../src/cli/plugin-template/plugin-guide.ts"],"sourcesContent":["import * as p from '@clack/prompts'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { getCurrentVersion } from '../version.js'\nimport {\n type TemplateParams,\n generatePackageJson,\n generateTsconfig,\n generateGitignore,\n generateNpmignore,\n generateEditorconfig,\n generateReadme,\n generatePluginSource,\n generatePluginTest,\n generateClaudeMd,\n generatePluginGuide,\n} from '../plugin-template/index.js'\n\nexport async function cmdPluginCreate(): Promise<void> {\n p.intro('Create a new OpenACP plugin')\n\n const result = await p.group(\n {\n name: () =>\n p.text({\n message: 'Plugin name (e.g., @myorg/adapter-matrix)',\n placeholder: '@myorg/my-plugin',\n validate: (value: string | undefined) => {\n if (!value || !value.trim()) return 'Plugin name is required'\n if (!/^(@[a-z0-9-]+\\/)?[a-z0-9-]+$/.test(value.trim())) {\n return 'Must be a valid npm package name (lowercase, hyphens, optional @scope/)'\n }\n return undefined\n },\n }),\n description: () =>\n p.text({\n message: 'Description',\n placeholder: 'A short description of your plugin',\n }),\n author: () =>\n p.text({\n message: 'Author',\n placeholder: 'Your Name <email@example.com>',\n }),\n license: () =>\n p.select({\n message: 'License',\n options: [\n { value: 'MIT', label: 'MIT' },\n { value: 'Apache-2.0', label: 'Apache 2.0' },\n { value: 'ISC', label: 'ISC' },\n { value: 'UNLICENSED', label: 'Unlicensed (private)' },\n ],\n }),\n },\n {\n onCancel: () => {\n p.cancel('Plugin creation cancelled.')\n process.exit(0)\n },\n },\n )\n\n const pluginName = result.name.trim()\n const dirName = pluginName.replace(/^@[^/]+\\//, '') // strip scope for directory name\n const targetDir = path.resolve(process.cwd(), dirName)\n\n if (fs.existsSync(targetDir)) {\n p.cancel(`Directory \"${dirName}\" already exists.`)\n process.exit(1)\n }\n\n const spinner = p.spinner()\n spinner.start('Scaffolding plugin...')\n\n // Create directory structure\n fs.mkdirSync(path.join(targetDir, 'src', '__tests__'), { recursive: true })\n\n // Collect template params\n const params: TemplateParams = {\n pluginName,\n description: (result.description as string) || '',\n author: (result.author as string) || '',\n license: result.license as string,\n cliVersion: getCurrentVersion(),\n }\n\n // Generate and write all files\n const files: Array<{ relativePath: string; content: string }> = [\n { relativePath: 'package.json', content: generatePackageJson(params) },\n { relativePath: 'tsconfig.json', content: generateTsconfig() },\n { relativePath: '.gitignore', content: generateGitignore() },\n { relativePath: '.npmignore', content: generateNpmignore() },\n { relativePath: '.editorconfig', content: generateEditorconfig() },\n { relativePath: 'README.md', content: generateReadme(params) },\n { relativePath: 'CLAUDE.md', content: generateClaudeMd(params) },\n { relativePath: 'PLUGIN_GUIDE.md', content: generatePluginGuide(params) },\n { relativePath: path.join('src', 'index.ts'), content: generatePluginSource(params) },\n { relativePath: path.join('src', '__tests__', 'index.test.ts'), content: generatePluginTest(params) },\n ]\n\n for (const file of files) {\n fs.writeFileSync(path.join(targetDir, file.relativePath), file.content)\n }\n\n spinner.stop('Plugin scaffolded!')\n\n p.note(\n [\n `cd ${dirName}`,\n 'npm install',\n 'npm run build',\n 'npm test',\n '',\n '# Start development with hot-reload:',\n `openacp dev .`,\n ].join('\\n'),\n 'Next steps',\n )\n\n p.outro(`Plugin ${pluginName} created in ./${dirName}`)\n}\n","export interface TemplateParams {\n pluginName: string\n description: string\n author: string\n license: string\n cliVersion: string\n}\n\nexport function generatePackageJson(params: TemplateParams): string {\n const packageJson = {\n name: params.pluginName,\n version: '0.1.0',\n description: params.description || '',\n type: 'module',\n main: 'dist/index.js',\n types: 'dist/index.d.ts',\n scripts: {\n build: 'tsc',\n dev: 'tsc --watch',\n test: 'vitest',\n prepublishOnly: 'npm run build',\n },\n author: params.author || '',\n license: params.license,\n keywords: ['openacp', 'openacp-plugin'],\n engines: {\n openacp: `>=${params.cliVersion}`,\n },\n peerDependencies: {\n '@openacp/cli': `>=${params.cliVersion}`,\n },\n devDependencies: {\n '@openacp/plugin-sdk': params.cliVersion,\n typescript: '^5.4.0',\n vitest: '^3.0.0',\n },\n }\n return JSON.stringify(packageJson, null, 2) + '\\n'\n}\n","export function generateTsconfig(): string {\n const tsconfig = {\n compilerOptions: {\n target: 'ES2022',\n module: 'NodeNext',\n moduleResolution: 'NodeNext',\n declaration: true,\n outDir: 'dist',\n rootDir: 'src',\n strict: true,\n esModuleInterop: true,\n skipLibCheck: true,\n forceConsistentCasingInFileNames: true,\n },\n include: ['src'],\n exclude: ['node_modules', 'dist', 'src/**/__tests__'],\n }\n return JSON.stringify(tsconfig, null, 2) + '\\n'\n}\n","export function generateGitignore(): string {\n return ['node_modules/', 'dist/', '*.tsbuildinfo', '.DS_Store', ''].join('\\n')\n}\n\nexport function generateNpmignore(): string {\n return ['src/', 'tsconfig.json', '.editorconfig', '.gitignore', '*.test.ts', '__tests__/', ''].join('\\n')\n}\n\nexport function generateEditorconfig(): string {\n return [\n 'root = true',\n '',\n '[*]',\n 'indent_style = space',\n 'indent_size = 2',\n 'end_of_line = lf',\n 'charset = utf-8',\n 'trim_trailing_whitespace = true',\n 'insert_final_newline = true',\n '',\n ].join('\\n')\n}\n","import type { TemplateParams } from './package-json.js'\n\nexport function generateReadme(params: TemplateParams): string {\n return [\n `# ${params.pluginName}`,\n '',\n params.description || 'An OpenACP plugin.',\n '',\n '## Installation',\n '',\n '```bash',\n `openacp plugin add ${params.pluginName}`,\n '```',\n '',\n '## Development',\n '',\n '```bash',\n 'npm install',\n 'npm run build',\n 'npm test',\n '',\n '# Live development with hot-reload:',\n `openacp dev .`,\n '```',\n '',\n '## License',\n '',\n params.license,\n '',\n ].join('\\n')\n}\n","import type { TemplateParams } from './package-json.js'\n\nexport function generatePluginSource(params: TemplateParams): string {\n const dirName = params.pluginName.replace(/^@[^/]+\\//, '')\n const escapedDescription = (params.description || '').replace(/'/g, \"\\\\'\")\n\n return `import type { OpenACPPlugin, PluginContext, InstallContext, MigrateContext } from '@openacp/plugin-sdk'\n\nconst plugin: OpenACPPlugin = {\n name: '${params.pluginName}',\n version: '0.1.0',\n description: '${escapedDescription}',\n\n // Declare which permissions your plugin needs.\n // Available: events:read, events:emit, services:register, services:use,\n // middleware:register, commands:register, storage:read, storage:write, kernel:access\n permissions: ['events:read', 'services:register'],\n\n // Dependencies on other plugins (loaded before this one).\n // pluginDependencies: { '@openacp/security': '>=1.0.0' },\n\n // Optional dependencies (used if available, gracefully degrade if not).\n // optionalPluginDependencies: { '@openacp/usage': '>=1.0.0' },\n\n /**\n * Called during server startup in dependency order.\n * Register services, middleware, commands, and event listeners here.\n */\n async setup(ctx: PluginContext): Promise<void> {\n ctx.log.info('Plugin setup started')\n\n // Example: register a service\n // ctx.registerService('my-service', myServiceImpl)\n\n // Example: listen to events\n // ctx.on('session:created', (event) => { ... })\n\n // Example: register a slash command\n // ctx.registerCommand({\n // name: 'mycommand',\n // description: 'Does something useful',\n // category: 'plugin',\n // async handler(args) {\n // return { type: 'text', text: 'Hello from ${params.pluginName}!' }\n // },\n // })\n\n ctx.log.info('Plugin setup complete')\n },\n\n /**\n * Called during server shutdown in reverse dependency order.\n * Clean up resources, close connections, stop timers here.\n * Has a 10-second timeout.\n */\n async teardown(): Promise<void> {\n // Clean up resources here\n },\n\n /**\n * Called when user runs \\`openacp plugin add ${params.pluginName}\\`.\n * Use ctx.terminal for interactive prompts to gather configuration.\n */\n async install(ctx: InstallContext): Promise<void> {\n ctx.terminal.log.info('Installing ${params.pluginName}...')\n\n // Example: prompt for configuration\n // const apiKey = await ctx.terminal.text({\n // message: 'Enter your API key',\n // validate: (v) => v.length === 0 ? 'Required' : undefined,\n // })\n // await ctx.settings.set('apiKey', apiKey)\n\n ctx.terminal.log.success('Installation complete!')\n },\n\n /**\n * Called when user runs \\`openacp plugin configure ${params.pluginName}\\`.\n * Re-run configuration prompts to update settings.\n */\n async configure(ctx: InstallContext): Promise<void> {\n ctx.terminal.log.info('Configuring ${params.pluginName}...')\n\n // Re-run configuration prompts, pre-filling with current values\n // const current = await ctx.settings.getAll()\n // ...\n\n ctx.terminal.log.success('Configuration updated!')\n },\n\n /**\n * Called during boot when the plugin version has changed.\n * Migrate settings from the old format to the new format.\n */\n async migrate(ctx: MigrateContext, oldSettings: unknown, oldVersion: string): Promise<unknown> {\n ctx.log.info(\\`Migrating from v\\${oldVersion}\\`)\n // Return the migrated settings object\n return oldSettings\n },\n\n /**\n * Called when user runs \\`openacp plugin remove ${params.pluginName}\\`.\n * Clean up any external resources. If opts.purge is true, delete all data.\n */\n async uninstall(ctx: InstallContext, opts: { purge: boolean }): Promise<void> {\n ctx.terminal.log.info('Uninstalling ${params.pluginName}...')\n if (opts.purge) {\n await ctx.settings.clear()\n }\n ctx.terminal.log.success('Uninstalled!')\n },\n}\n\nexport default plugin\n`\n}\n","import type { TemplateParams } from './package-json.js'\n\nexport function generatePluginTest(params: TemplateParams): string {\n return `import { describe, it, expect } from 'vitest'\nimport { createTestContext, createTestInstallContext } from '@openacp/plugin-sdk/testing'\nimport plugin from '../index.js'\n\ndescribe('${params.pluginName}', () => {\n it('has correct metadata', () => {\n expect(plugin.name).toBe('${params.pluginName}')\n expect(plugin.version).toBeDefined()\n expect(plugin.setup).toBeInstanceOf(Function)\n })\n\n it('sets up without errors', async () => {\n const ctx = createTestContext({\n pluginName: '${params.pluginName}',\n pluginConfig: { enabled: true },\n permissions: plugin.permissions,\n })\n await expect(plugin.setup(ctx)).resolves.not.toThrow()\n })\n\n it('tears down without errors', async () => {\n if (plugin.teardown) {\n await expect(plugin.teardown()).resolves.not.toThrow()\n }\n })\n\n it('installs without errors', async () => {\n if (plugin.install) {\n const ctx = createTestInstallContext({\n pluginName: '${params.pluginName}',\n terminalResponses: { password: [''], confirm: [true], select: ['apiKey'] },\n })\n await expect(plugin.install(ctx)).resolves.not.toThrow()\n }\n })\n})\n`\n}\n","import type { TemplateParams } from './package-json.js'\n\nexport function generateClaudeMd(params: TemplateParams): string {\n return `# CLAUDE.md\n\nThis file provides context for AI coding agents (Claude, Cursor, etc.) working on this plugin.\n\n## What is OpenACP?\n\nOpenACP is an open-source platform that bridges AI coding agents (Claude Code, Codex, etc.) to messaging platforms (Telegram, Discord, Slack) and custom UIs via the Agent Client Protocol (ACP). It features a microkernel plugin architecture where all features — adapters, services, commands — are plugins.\n\n- **Website & Docs**: https://openacp.gitbook.io/docs\n- **GitHub**: https://github.com/Open-ACP/OpenACP\n- **Plugin Registry**: https://github.com/Open-ACP/plugin-registry\n\nKey documentation pages:\n- [Getting Started](https://openacp.gitbook.io/docs/getting-started) — What is OpenACP, quickstart\n- [Plugin Development](https://openacp.gitbook.io/docs/extending/building-plugins) — How to build plugins\n- [Architecture](https://openacp.gitbook.io/docs/extending/architecture) — System design, plugin lifecycle\n- [Dev Mode](https://openacp.gitbook.io/docs/extending/dev-mode) — Hot-reload development workflow\n- [CLI Commands](https://openacp.gitbook.io/docs/api-reference/cli-commands) — Full CLI reference\n- [Platform Setup](https://openacp.gitbook.io/docs/platform-setup) — Telegram, Discord, Slack guides\n- [Configuration](https://openacp.gitbook.io/docs/self-hosting/configuration) — Config and settings reference\n\n## Project Overview\n\nThis is an OpenACP plugin. Plugins extend OpenACP with new adapters, services, commands, and middleware.\n\n- **Package**: ${params.pluginName}\n- **SDK**: \\`@openacp/plugin-sdk\\` (types, base classes, testing utilities)\n- **Entry point**: \\`src/index.ts\\` (default export of \\`OpenACPPlugin\\` object)\n\n## Build & Run\n\n\\`\\`\\`bash\nnpm install # Install dependencies\nnpm run build # Compile TypeScript (tsc)\nnpm run dev # Watch mode (tsc --watch)\nnpm test # Run tests (vitest)\n\\`\\`\\`\n\n### Development with hot-reload\n\n\\`\\`\\`bash\nopenacp dev . # Compiles, watches, and reloads plugin on changes\n\\`\\`\\`\n\n## File Structure\n\n\\`\\`\\`\nsrc/\n index.ts — Plugin entry point (exports OpenACPPlugin)\n __tests__/\n index.test.ts — Tests using @openacp/plugin-sdk/testing\npackage.json — engines.openacp declares minimum CLI version\ntsconfig.json — ES2022, NodeNext, strict mode\nCLAUDE.md — This file (AI agent context)\nPLUGIN_GUIDE.md — Human-readable developer guide\n\\`\\`\\`\n\n## Architecture: How OpenACP Plugins Work\n\n### Plugin Lifecycle\n\n\\`\\`\\`\ninstall ──> [reboot] ──> migrate? ──> setup ──> [running] ──> teardown ──> uninstall\n\\`\\`\\`\n\n| Hook | Trigger | Interactive? | Has Services? |\n|------|---------|-------------|---------------|\n| \\`install(ctx)\\` | \\`openacp plugin add <name>\\` | Yes | No |\n| \\`migrate(ctx, oldSettings, oldVersion)\\` | Boot — stored version differs from plugin version | No | No |\n| \\`configure(ctx)\\` | \\`openacp plugin configure <name>\\` | Yes | No |\n| \\`setup(ctx)\\` | Every boot, after migrate | No | Yes |\n| \\`teardown()\\` | Shutdown (10s timeout) | No | Yes |\n| \\`uninstall(ctx, opts)\\` | \\`openacp plugin remove <name>\\` | Yes | No |\n\n### OpenACPPlugin Interface\n\n\\`\\`\\`typescript\ninterface OpenACPPlugin {\n name: string // unique identifier, e.g. '@myorg/my-plugin'\n version: string // semver\n description?: string\n permissions?: PluginPermission[]\n pluginDependencies?: Record<string, string> // name -> semver range\n optionalPluginDependencies?: Record<string, string> // used if available\n overrides?: string // replace a built-in plugin entirely\n settingsSchema?: ZodSchema // Zod validation for settings\n essential?: boolean // true = needs setup before system can run\n\n setup(ctx: PluginContext): Promise<void>\n teardown?(): Promise<void>\n install?(ctx: InstallContext): Promise<void>\n configure?(ctx: InstallContext): Promise<void>\n migrate?(ctx: MigrateContext, oldSettings: unknown, oldVersion: string): Promise<unknown>\n uninstall?(ctx: InstallContext, opts: { purge: boolean }): Promise<void>\n}\n\\`\\`\\`\n\n### PluginContext API (available in setup)\n\n\\`\\`\\`typescript\ninterface PluginContext {\n pluginName: string\n pluginConfig: Record<string, unknown> // from settings.json\n\n // Events (requires 'events:read' / 'events:emit')\n on(event: string, handler: (...args: unknown[]) => void): void\n off(event: string, handler: (...args: unknown[]) => void): void\n emit(event: string, payload: unknown): void\n\n // Services (requires 'services:register' / 'services:use')\n registerService<T>(name: string, implementation: T): void\n getService<T>(name: string): T | undefined\n\n // Middleware (requires 'middleware:register')\n registerMiddleware<H extends MiddlewareHook>(hook: H, opts: MiddlewareOptions<MiddlewarePayloadMap[H]>): void\n\n // Commands (requires 'commands:register')\n registerCommand(def: CommandDef): void\n\n // Storage (requires 'storage:read' / 'storage:write')\n storage: PluginStorage // get, set, delete, list, getDataDir\n\n // Messaging (requires 'services:use')\n sendMessage(sessionId: string, content: OutgoingMessage): Promise<void>\n\n // Kernel access (requires 'kernel:access')\n sessions: SessionManager\n config: ConfigManager\n eventBus: EventBus\n\n // Always available\n log: Logger // trace, debug, info, warn, error, fatal, child\n}\n\\`\\`\\`\n\n### CommandDef and CommandResponse\n\n\\`\\`\\`typescript\ninterface CommandDef {\n name: string // command name without slash\n description: string // shown in /help\n usage?: string // e.g. '<city>' or 'on|off'\n category: 'system' | 'plugin'\n handler(args: CommandArgs): Promise<CommandResponse | void>\n}\n\ninterface CommandArgs {\n raw: string // text after command name\n sessionId: string | null\n channelId: string // 'telegram', 'discord', 'slack'\n userId: string\n reply(content: string | CommandResponse): Promise<void>\n}\n\ntype CommandResponse =\n | { type: 'text'; text: string }\n | { type: 'menu'; title: string; options: MenuOption[] }\n | { type: 'list'; title: string; items: ListItem[] }\n | { type: 'confirm'; question: string; onYes: string; onNo: string }\n | { type: 'error'; message: string }\n | { type: 'silent' }\n\\`\\`\\`\n\n### Settings System\n\n- \\`settingsSchema\\`: Zod schema for validation\n- \\`SettingsAPI\\` (in InstallContext): get, set, getAll, setAll, delete, clear, has\n- Settings stored at \\`~/.openacp/plugins/@scope/name/settings.json\\`\n- \\`PluginStorage\\` (in PluginContext): key-value store at \\`~/.openacp/plugins/data/@scope/name/kv.json\\`\n- \\`storage.getDataDir()\\`: returns path for large files, databases, caches\n\n### InstallContext (for install/configure/uninstall)\n\n\\`\\`\\`typescript\ninterface InstallContext {\n pluginName: string\n terminal: TerminalIO // text, select, confirm, password, multiselect, log, spinner, note\n settings: SettingsAPI\n legacyConfig?: Record<string, unknown>\n dataDir: string\n log: Logger\n}\n\\`\\`\\`\n\n### Service Interfaces (available via ctx.getService)\n\n| Service name | Interface | Description |\n|---|---|---|\n| \\`security\\` | \\`SecurityService\\` | Access control, session limits, user roles |\n| \\`file-service\\` | \\`FileServiceInterface\\` | File saving, resolving, format conversion |\n| \\`notifications\\` | \\`NotificationService\\` | Send notifications to users |\n| \\`usage\\` | \\`UsageService\\` | Token/cost tracking and budget checking |\n| \\`speech\\` | \\`SpeechServiceInterface\\` | Text-to-speech and speech-to-text |\n| \\`tunnel\\` | \\`TunnelServiceInterface\\` | Port tunneling and public URL management |\n| \\`context\\` | \\`ContextService\\` | Context building for agent sessions |\n\n## Plugin Permissions\n\nDeclare in \\`permissions\\` array. Only request what you need.\n\n| Permission | Allows |\n|---|---|\n| \\`events:read\\` | \\`ctx.on()\\` — subscribe to events |\n| \\`events:emit\\` | \\`ctx.emit()\\` — emit custom events (must prefix with plugin name) |\n| \\`services:register\\` | \\`ctx.registerService()\\` — provide services to other plugins |\n| \\`services:use\\` | \\`ctx.getService()\\`, \\`ctx.sendMessage()\\` — consume services |\n| \\`middleware:register\\` | \\`ctx.registerMiddleware()\\` — intercept and modify flows |\n| \\`commands:register\\` | \\`ctx.registerCommand()\\` — add chat commands |\n| \\`storage:read\\` | \\`ctx.storage.get()\\`, \\`ctx.storage.list()\\` |\n| \\`storage:write\\` | \\`ctx.storage.set()\\`, \\`ctx.storage.delete()\\` |\n| \\`kernel:access\\` | \\`ctx.sessions\\`, \\`ctx.config\\`, \\`ctx.eventBus\\`, \\`ctx.core\\` |\n\nCalling a method without the required permission throws \\`PluginPermissionError\\`.\n\n## Middleware Hooks (18 total)\n\nRegister with \\`ctx.registerMiddleware(hook, { priority?, handler })\\`. Return \\`null\\` to block the flow, call \\`next()\\` to continue.\n\n### Message flow\n- \\`message:incoming\\` — incoming user message (channelId, threadId, userId, text, attachments)\n- \\`message:outgoing\\` — outgoing message to user (sessionId, message)\n\n### Agent flow\n- \\`agent:beforePrompt\\` — before prompt is sent to agent (sessionId, text, attachments)\n- \\`agent:beforeEvent\\` — before agent event is processed (sessionId, event)\n- \\`agent:afterEvent\\` — after agent event, before delivery (sessionId, event, outgoingMessage)\n\n### Turn lifecycle\n- \\`turn:start\\` — agent turn begins (sessionId, promptText, promptNumber)\n- \\`turn:end\\` — agent turn ends (sessionId, stopReason, durationMs)\n\n### File system\n- \\`fs:beforeRead\\` — before file read (sessionId, path, line, limit)\n- \\`fs:beforeWrite\\` — before file write (sessionId, path, content)\n\n### Terminal\n- \\`terminal:beforeCreate\\` — before terminal process spawned (sessionId, command, args, env, cwd)\n- \\`terminal:afterExit\\` — after terminal process exits (sessionId, terminalId, command, exitCode, durationMs)\n\n### Permission\n- \\`permission:beforeRequest\\` — before permission prompt (sessionId, request, autoResolve)\n- \\`permission:afterResolve\\` — after permission resolved (sessionId, requestId, decision, userId, durationMs)\n\n### Session\n- \\`session:beforeCreate\\` — before session creation (agentName, workingDir, userId, channelId, threadId)\n- \\`session:afterDestroy\\` — after session destroyed (sessionId, reason, durationMs, promptCount)\n\n### Control\n- \\`mode:beforeChange\\` — before mode change (sessionId, fromMode, toMode)\n- \\`config:beforeChange\\` — before config change (sessionId, configId, oldValue, newValue)\n- \\`model:beforeChange\\` — before model change (sessionId, fromModel, toModel)\n- \\`agent:beforeCancel\\` — before agent cancellation (sessionId, reason)\n\n## Plugin Events (subscribe with ctx.on)\n\n### System\n- \\`kernel:booted\\`, \\`system:ready\\`, \\`system:shutdown\\`, \\`system:commands-ready\\`\n\n### Plugin lifecycle\n- \\`plugin:loaded\\`, \\`plugin:failed\\`, \\`plugin:disabled\\`, \\`plugin:unloaded\\`\n\n### Session\n- \\`session:created\\`, \\`session:ended\\`, \\`session:named\\`, \\`session:updated\\`\n\n### Agent\n- \\`agent:event\\`, \\`agent:prompt\\`\n\n### Permission\n- \\`permission:request\\`, \\`permission:resolved\\`\n\n## Testing\n\nUse \\`@openacp/plugin-sdk/testing\\`:\n\n\\`\\`\\`typescript\nimport { createTestContext, createTestInstallContext, mockServices } from '@openacp/plugin-sdk/testing'\n\\`\\`\\`\n\n### createTestContext(opts)\n\nCreates a test \\`PluginContext\\`. All state is in-memory.\n\n\\`\\`\\`typescript\nconst ctx = createTestContext({\n pluginName: '${params.pluginName}',\n pluginConfig: { enabled: true },\n permissions: plugin.permissions,\n services: { security: mockServices.security() },\n})\nawait plugin.setup(ctx)\nexpect(ctx.registeredCommands.has('mycommand')).toBe(true)\nconst response = await ctx.executeCommand('mycommand', { raw: 'test' })\n\\`\\`\\`\n\nInspection properties: \\`registeredServices\\`, \\`registeredCommands\\`, \\`registeredMiddleware\\`, \\`emittedEvents\\`, \\`sentMessages\\`, \\`executeCommand()\\`.\n\n### createTestInstallContext(opts)\n\nCreates a test \\`InstallContext\\`. Terminal prompts auto-answered from \\`terminalResponses\\`.\n\n\\`\\`\\`typescript\nconst ctx = createTestInstallContext({\n pluginName: '${params.pluginName}',\n terminalResponses: { password: ['sk-test-key'], select: ['en'] },\n})\nawait plugin.install!(ctx)\nexpect(ctx.settingsData.get('apiKey')).toBe('sk-test-key')\n\\`\\`\\`\n\n### mockServices\n\nFactory functions for mock service implementations:\n\n\\`\\`\\`typescript\nmockServices.security(overrides?) // checkAccess, checkSessionLimit, getUserRole\nmockServices.fileService(overrides?) // saveFile, resolveFile, readTextFileWithRange\nmockServices.notifications(overrides?) // notify, notifyAll\nmockServices.usage(overrides?) // trackUsage, checkBudget, getSummary\nmockServices.speech(overrides?) // textToSpeech, speechToText, register*\nmockServices.tunnel(overrides?) // getPublicUrl, start, stop, getStore, fileUrl, diffUrl\nmockServices.context(overrides?) // buildContext, registerProvider\n\\`\\`\\`\n\n## Conventions\n\n- **ESM-only**: \\`\"type\": \"module\"\\` in package.json\n- **Import extensions**: All imports must use \\`.js\\` extension (e.g., \\`import x from './util.js'\\`)\n- **TypeScript strict mode**: \\`strict: true\\` in tsconfig.json\n- **Target**: ES2022, module NodeNext\n- **Test framework**: Vitest\n- **Test files**: \\`src/**/__tests__/*.test.ts\\`\n\n## How to Add a Command\n\n\\`\\`\\`typescript\n// In setup():\nctx.registerCommand({\n name: 'mycommand',\n description: 'Does something useful',\n usage: '<arg>',\n category: 'plugin',\n async handler(args) {\n const input = args.raw.trim()\n if (!input) return { type: 'error', message: 'Usage: /mycommand <arg>' }\n return { type: 'text', text: \\\\\\`Result: \\\\\\${input}\\\\\\` }\n },\n})\n\\`\\`\\`\n\nRequires \\`commands:register\\` permission. Available as \\`/mycommand\\` (if no conflict) and \\`/pluginscope:mycommand\\` (always).\n\n## How to Add a Service\n\n\\`\\`\\`typescript\n// In setup():\nconst myService = new MyService()\nctx.registerService('my-service', myService)\n\\`\\`\\`\n\nRequires \\`services:register\\` permission. Other plugins consume with \\`ctx.getService<MyService>('my-service')\\`.\n\n## How to Add Middleware\n\n\\`\\`\\`typescript\n// In setup():\nctx.registerMiddleware('message:outgoing', {\n priority: 50, // lower = earlier execution\n handler: async (payload, next) => {\n payload.message.text = modifyText(payload.message.text)\n return next() // continue chain; return null to block\n },\n})\n\\`\\`\\`\n\nRequires \\`middleware:register\\` permission.\n\n## How Settings Work\n\n1. Define \\`settingsSchema\\` (Zod) on the plugin object\n2. In \\`install()\\`: use \\`ctx.terminal\\` for interactive prompts, save with \\`ctx.settings.set()\\`\n3. In \\`configure()\\`: re-run prompts with current values pre-filled\n4. In \\`setup()\\`: read settings from \\`ctx.pluginConfig\\`\n5. In \\`migrate()\\`: transform old settings to new format on version change\n\n## Version Compatibility\n\nThe \\`engines.openacp\\` field in package.json declares the minimum CLI version. OpenACP checks this on install and warns if incompatible.\n`\n}\n","import type { TemplateParams } from './package-json.js'\n\nexport function generatePluginGuide(params: TemplateParams): string {\n return `# Plugin Developer Guide\n\n## Overview\n\n**${params.pluginName}** is an OpenACP plugin.\n\n> TODO: Describe what this plugin does.\n\n## Project Structure\n\n\\`\\`\\`\nsrc/\n index.ts — Plugin entry point (exports OpenACPPlugin object)\n __tests__/\n index.test.ts — Tests using Vitest + @openacp/plugin-sdk/testing\npackage.json — npm package config with engines.openacp constraint\ntsconfig.json — TypeScript strict mode, ES2022, NodeNext\nCLAUDE.md — Full technical reference for AI coding agents\nPLUGIN_GUIDE.md — This file\n\\`\\`\\`\n\n## Development Workflow\n\n1. **Edit** \\`src/index.ts\\` — implement your plugin logic\n2. **Dev mode**: \\`openacp dev .\\` — compiles, watches, and hot-reloads your plugin\n3. **Test**: \\`npm test\\` — runs Vitest with SDK testing utilities\n4. **Build**: \\`npm run build\\` — compiles TypeScript to \\`dist/\\`\n\n\\`\\`\\`bash\nnpm install\nopenacp dev . # start developing with hot-reload\nnpm test # run tests\nnpm run build # compile for publishing\n\\`\\`\\`\n\n## Adding a Command\n\nRegister commands in your \\`setup()\\` function. Requires \\`commands:register\\` permission.\n\n\\`\\`\\`typescript\nasync setup(ctx: PluginContext) {\n ctx.registerCommand({\n name: 'greet',\n description: 'Send a greeting',\n usage: '[name]',\n category: 'plugin',\n async handler(args) {\n const name = args.raw.trim() || 'World'\n return { type: 'text', text: \\\\\\`Hello, \\\\\\${name}!\\\\\\` }\n },\n })\n}\n\\`\\`\\`\n\nThe command will be available as \\`/greet\\` in all messaging platforms.\n\n## Adding a Service\n\nProvide a service that other plugins can consume. Requires \\`services:register\\` permission.\n\n\\`\\`\\`typescript\nasync setup(ctx: PluginContext) {\n const myService = {\n doSomething(input: string): string {\n return input.toUpperCase()\n },\n }\n ctx.registerService('my-service', myService)\n}\n\\`\\`\\`\n\nOther plugins access it with \\`ctx.getService<MyServiceType>('my-service')\\`.\n\n## Adding Middleware\n\nIntercept and modify message flows. Requires \\`middleware:register\\` permission.\n\n\\`\\`\\`typescript\nasync setup(ctx: PluginContext) {\n ctx.registerMiddleware('message:outgoing', {\n priority: 50,\n handler: async (payload, next) => {\n // Modify the message before delivery\n payload.message.text += '\\\\n-- sent via ${params.pluginName}'\n return next() // continue the chain\n // return null to block the message entirely\n },\n })\n}\n\\`\\`\\`\n\n## Handling Settings\n\n### Install flow (first-time setup)\n\n\\`\\`\\`typescript\nasync install(ctx: InstallContext) {\n const apiKey = await ctx.terminal.password({\n message: 'Enter your API key:',\n validate: (v) => v.length > 0 ? undefined : 'Required',\n })\n await ctx.settings.set('apiKey', apiKey)\n ctx.terminal.log.success('Configured!')\n}\n\\`\\`\\`\n\n### Configure flow (reconfiguration)\n\n\\`\\`\\`typescript\nasync configure(ctx: InstallContext) {\n const current = await ctx.settings.getAll()\n const apiKey = await ctx.terminal.password({\n message: \\\\\\`API key (current: \\\\\\${current.apiKey ? '***' : 'not set'}):\\\\\\`,\n })\n if (apiKey) await ctx.settings.set('apiKey', apiKey)\n ctx.terminal.log.success('Updated!')\n}\n\\`\\`\\`\n\n### Reading settings at runtime\n\n\\`\\`\\`typescript\nasync setup(ctx: PluginContext) {\n const apiKey = ctx.pluginConfig.apiKey as string\n if (!apiKey) {\n ctx.log.warn('Not configured — run: openacp plugin configure ${params.pluginName}')\n return\n }\n // Use apiKey...\n}\n\\`\\`\\`\n\n## Testing\n\nTests use Vitest and \\`@openacp/plugin-sdk/testing\\`.\n\n\\`\\`\\`typescript\nimport { describe, it, expect } from 'vitest'\nimport { createTestContext, createTestInstallContext, mockServices } from '@openacp/plugin-sdk/testing'\nimport plugin from '../index.js'\n\ndescribe('${params.pluginName}', () => {\n it('registers commands on setup', async () => {\n const ctx = createTestContext({ pluginName: '${params.pluginName}' })\n await plugin.setup(ctx)\n expect(ctx.registeredCommands.has('greet')).toBe(true)\n })\n\n it('command returns expected response', async () => {\n const ctx = createTestContext({ pluginName: '${params.pluginName}' })\n await plugin.setup(ctx)\n const res = await ctx.executeCommand('greet', { raw: 'Alice' })\n expect(res).toEqual({ type: 'text', text: 'Hello, Alice!' })\n })\n\n it('install saves settings', async () => {\n const ctx = createTestInstallContext({\n pluginName: '${params.pluginName}',\n terminalResponses: { password: ['sk-test-key'] },\n })\n await plugin.install!(ctx)\n expect(ctx.settingsData.get('apiKey')).toBe('sk-test-key')\n })\n})\n\\`\\`\\`\n\n### Available mock services\n\n\\`\\`\\`typescript\nconst ctx = createTestContext({\n pluginName: '${params.pluginName}',\n services: {\n security: mockServices.security(),\n usage: mockServices.usage({ async checkBudget() { return { ok: false, percent: 100 } } }),\n },\n})\n\\`\\`\\`\n\n## Publishing\n\n1. Update \\`version\\` in both \\`package.json\\` and \\`src/index.ts\\`\n2. Build and test:\n \\`\\`\\`bash\n npm run build\n npm test\n \\`\\`\\`\n3. Publish:\n \\`\\`\\`bash\n npm publish --access public\n \\`\\`\\`\n4. Users install with:\n \\`\\`\\`bash\n openacp plugin install ${params.pluginName}\n \\`\\`\\`\n5. Submit to the [OpenACP Plugin Registry](https://github.com/Open-ACP/plugin-registry) for discoverability.\n\n## Useful Links\n\n- [Architecture: Plugin System](https://docs.openacp.dev/architecture/plugin-system)\n- [Architecture: Writing Plugins](https://docs.openacp.dev/architecture/writing-plugins)\n- [Architecture: Command System](https://docs.openacp.dev/architecture/command-system)\n- [Plugin SDK Reference](https://docs.openacp.dev/extending/plugin-sdk-reference)\n- [Getting Started: Your First Plugin](https://docs.openacp.dev/extending/getting-started-plugin)\n- [Dev Mode](https://docs.openacp.dev/extending/dev-mode)\n- [Contributing](https://github.com/Open-ACP/OpenACP/blob/main/CONTRIBUTING.md)\n`\n}\n"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAmQjB,OAAO,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAkBjB,OAAO,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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","names":["spinner"]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/commands/plugin-create.ts","../../src/cli/plugin-template/package-json.ts","../../src/cli/plugin-template/tsconfig.ts","../../src/cli/plugin-template/dotfiles.ts","../../src/cli/plugin-template/readme.ts","../../src/cli/plugin-template/plugin-source.ts","../../src/cli/plugin-template/plugin-test.ts","../../src/cli/plugin-template/claude-md.ts","../../src/cli/plugin-template/plugin-guide.ts"],"sourcesContent":["import * as p from '@clack/prompts'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { getCurrentVersion } from '../version.js'\nimport {\n type TemplateParams,\n generatePackageJson,\n generateTsconfig,\n generateGitignore,\n generateNpmignore,\n generateEditorconfig,\n generateReadme,\n generatePluginSource,\n generatePluginTest,\n generateClaudeMd,\n generatePluginGuide,\n} from '../plugin-template/index.js'\n\nexport async function cmdPluginCreate(): Promise<void> {\n p.intro('Create a new OpenACP plugin')\n\n const result = await p.group(\n {\n name: () =>\n p.text({\n message: 'Plugin name (e.g., @myorg/adapter-matrix)',\n placeholder: '@myorg/my-plugin',\n validate: (value: string | undefined) => {\n if (!value || !value.trim()) return 'Plugin name is required'\n if (!/^(@[a-z0-9-]+\\/)?[a-z0-9-]+$/.test(value.trim())) {\n return 'Must be a valid npm package name (lowercase, hyphens, optional @scope/)'\n }\n return undefined\n },\n }),\n description: () =>\n p.text({\n message: 'Description',\n placeholder: 'A short description of your plugin',\n }),\n author: () =>\n p.text({\n message: 'Author',\n placeholder: 'Your Name <email@example.com>',\n }),\n license: () =>\n p.select({\n message: 'License',\n options: [\n { value: 'MIT', label: 'MIT' },\n { value: 'Apache-2.0', label: 'Apache 2.0' },\n { value: 'ISC', label: 'ISC' },\n { value: 'UNLICENSED', label: 'Unlicensed (private)' },\n ],\n }),\n },\n {\n onCancel: () => {\n p.cancel('Plugin creation cancelled.')\n process.exit(0)\n },\n },\n )\n\n const pluginName = result.name.trim()\n const dirName = pluginName.replace(/^@[^/]+\\//, '') // strip scope for directory name\n const targetDir = path.resolve(process.cwd(), dirName)\n\n if (fs.existsSync(targetDir)) {\n p.cancel(`Directory \"${dirName}\" already exists.`)\n process.exit(1)\n }\n\n const spinner = p.spinner()\n spinner.start('Scaffolding plugin...')\n\n // Create directory structure\n fs.mkdirSync(path.join(targetDir, 'src', '__tests__'), { recursive: true })\n\n // Collect template params\n const params: TemplateParams = {\n pluginName,\n description: (result.description as string) || '',\n author: (result.author as string) || '',\n license: result.license as string,\n cliVersion: getCurrentVersion(),\n }\n\n // Generate and write all files\n const files: Array<{ relativePath: string; content: string }> = [\n { relativePath: 'package.json', content: generatePackageJson(params) },\n { relativePath: 'tsconfig.json', content: generateTsconfig() },\n { relativePath: '.gitignore', content: generateGitignore() },\n { relativePath: '.npmignore', content: generateNpmignore() },\n { relativePath: '.editorconfig', content: generateEditorconfig() },\n { relativePath: 'README.md', content: generateReadme(params) },\n { relativePath: 'CLAUDE.md', content: generateClaudeMd(params) },\n { relativePath: 'PLUGIN_GUIDE.md', content: generatePluginGuide(params) },\n { relativePath: path.join('src', 'index.ts'), content: generatePluginSource(params) },\n { relativePath: path.join('src', '__tests__', 'index.test.ts'), content: generatePluginTest(params) },\n ]\n\n for (const file of files) {\n fs.writeFileSync(path.join(targetDir, file.relativePath), file.content)\n }\n\n spinner.stop('Plugin scaffolded!')\n\n p.note(\n [\n `cd ${dirName}`,\n 'npm install',\n 'npm run build',\n 'npm test',\n '',\n '# Start development with hot-reload:',\n `openacp dev .`,\n ].join('\\n'),\n 'Next steps',\n )\n\n p.outro(`Plugin ${pluginName} created in ./${dirName}`)\n}\n","export interface TemplateParams {\n pluginName: string\n description: string\n author: string\n license: string\n cliVersion: string\n}\n\nexport function generatePackageJson(params: TemplateParams): string {\n const packageJson = {\n name: params.pluginName,\n version: '0.1.0',\n description: params.description || '',\n type: 'module',\n main: 'dist/index.js',\n types: 'dist/index.d.ts',\n scripts: {\n build: 'tsc',\n dev: 'tsc --watch',\n test: 'vitest',\n prepublishOnly: 'npm run build',\n },\n author: params.author || '',\n license: params.license,\n keywords: ['openacp', 'openacp-plugin'],\n engines: {\n openacp: `>=${params.cliVersion}`,\n },\n peerDependencies: {\n '@openacp/cli': `>=${params.cliVersion}`,\n },\n devDependencies: {\n '@openacp/plugin-sdk': params.cliVersion,\n typescript: '^5.4.0',\n vitest: '^3.0.0',\n },\n }\n return JSON.stringify(packageJson, null, 2) + '\\n'\n}\n","export function generateTsconfig(): string {\n const tsconfig = {\n compilerOptions: {\n target: 'ES2022',\n module: 'NodeNext',\n moduleResolution: 'NodeNext',\n declaration: true,\n outDir: 'dist',\n rootDir: 'src',\n strict: true,\n esModuleInterop: true,\n skipLibCheck: true,\n forceConsistentCasingInFileNames: true,\n },\n include: ['src'],\n exclude: ['node_modules', 'dist', 'src/**/__tests__'],\n }\n return JSON.stringify(tsconfig, null, 2) + '\\n'\n}\n","export function generateGitignore(): string {\n return ['node_modules/', 'dist/', '*.tsbuildinfo', '.DS_Store', ''].join('\\n')\n}\n\nexport function generateNpmignore(): string {\n return ['src/', 'tsconfig.json', '.editorconfig', '.gitignore', '*.test.ts', '__tests__/', ''].join('\\n')\n}\n\nexport function generateEditorconfig(): string {\n return [\n 'root = true',\n '',\n '[*]',\n 'indent_style = space',\n 'indent_size = 2',\n 'end_of_line = lf',\n 'charset = utf-8',\n 'trim_trailing_whitespace = true',\n 'insert_final_newline = true',\n '',\n ].join('\\n')\n}\n","import type { TemplateParams } from './package-json.js'\n\nexport function generateReadme(params: TemplateParams): string {\n return [\n `# ${params.pluginName}`,\n '',\n params.description || 'An OpenACP plugin.',\n '',\n '## Installation',\n '',\n '```bash',\n `openacp plugin add ${params.pluginName}`,\n '```',\n '',\n '## Development',\n '',\n '```bash',\n 'npm install',\n 'npm run build',\n 'npm test',\n '',\n '# Live development with hot-reload:',\n `openacp dev .`,\n '```',\n '',\n '## License',\n '',\n params.license,\n '',\n ].join('\\n')\n}\n","import type { TemplateParams } from './package-json.js'\n\nexport function generatePluginSource(params: TemplateParams): string {\n const dirName = params.pluginName.replace(/^@[^/]+\\//, '')\n const escapedDescription = (params.description || '').replace(/'/g, \"\\\\'\")\n\n return `import type { OpenACPPlugin, PluginContext, InstallContext, MigrateContext } from '@openacp/plugin-sdk'\n\nconst plugin: OpenACPPlugin = {\n name: '${params.pluginName}',\n version: '0.1.0',\n description: '${escapedDescription}',\n\n // Declare which permissions your plugin needs.\n // Available: events:read, events:emit, services:register, services:use,\n // middleware:register, commands:register, storage:read, storage:write, kernel:access\n permissions: ['events:read', 'services:register'],\n\n // Dependencies on other plugins (loaded before this one).\n // pluginDependencies: { '@openacp/security': '>=1.0.0' },\n\n // Optional dependencies (used if available, gracefully degrade if not).\n // optionalPluginDependencies: { '@openacp/usage': '>=1.0.0' },\n\n /**\n * Called during server startup in dependency order.\n * Register services, middleware, commands, and event listeners here.\n */\n async setup(ctx: PluginContext): Promise<void> {\n ctx.log.info('Plugin setup started')\n\n // Example: register a service\n // ctx.registerService('my-service', myServiceImpl)\n\n // Example: listen to events\n // ctx.on('session:created', (event) => { ... })\n\n // Example: register a slash command\n // ctx.registerCommand({\n // name: 'mycommand',\n // description: 'Does something useful',\n // category: 'plugin',\n // async handler(args) {\n // return { type: 'text', text: 'Hello from ${params.pluginName}!' }\n // },\n // })\n\n ctx.log.info('Plugin setup complete')\n },\n\n /**\n * Called during server shutdown in reverse dependency order.\n * Clean up resources, close connections, stop timers here.\n * Has a 10-second timeout.\n */\n async teardown(): Promise<void> {\n // Clean up resources here\n },\n\n /**\n * Called when user runs \\`openacp plugin add ${params.pluginName}\\`.\n * Use ctx.terminal for interactive prompts to gather configuration.\n */\n async install(ctx: InstallContext): Promise<void> {\n ctx.terminal.log.info('Installing ${params.pluginName}...')\n\n // Example: prompt for configuration\n // const apiKey = await ctx.terminal.text({\n // message: 'Enter your API key',\n // validate: (v) => v.length === 0 ? 'Required' : undefined,\n // })\n // await ctx.settings.set('apiKey', apiKey)\n\n ctx.terminal.log.success('Installation complete!')\n },\n\n /**\n * Called when user runs \\`openacp plugin configure ${params.pluginName}\\`.\n * Re-run configuration prompts to update settings.\n */\n async configure(ctx: InstallContext): Promise<void> {\n ctx.terminal.log.info('Configuring ${params.pluginName}...')\n\n // Re-run configuration prompts, pre-filling with current values\n // const current = await ctx.settings.getAll()\n // ...\n\n ctx.terminal.log.success('Configuration updated!')\n },\n\n /**\n * Called during boot when the plugin version has changed.\n * Migrate settings from the old format to the new format.\n */\n async migrate(ctx: MigrateContext, oldSettings: unknown, oldVersion: string): Promise<unknown> {\n ctx.log.info(\\`Migrating from v\\${oldVersion}\\`)\n // Return the migrated settings object\n return oldSettings\n },\n\n /**\n * Called when user runs \\`openacp plugin remove ${params.pluginName}\\`.\n * Clean up any external resources. If opts.purge is true, delete all data.\n */\n async uninstall(ctx: InstallContext, opts: { purge: boolean }): Promise<void> {\n ctx.terminal.log.info('Uninstalling ${params.pluginName}...')\n if (opts.purge) {\n await ctx.settings.clear()\n }\n ctx.terminal.log.success('Uninstalled!')\n },\n}\n\nexport default plugin\n`\n}\n","import type { TemplateParams } from './package-json.js'\n\nexport function generatePluginTest(params: TemplateParams): string {\n return `import { describe, it, expect } from 'vitest'\nimport { createTestContext, createTestInstallContext } from '@openacp/plugin-sdk/testing'\nimport plugin from '../index.js'\n\ndescribe('${params.pluginName}', () => {\n it('has correct metadata', () => {\n expect(plugin.name).toBe('${params.pluginName}')\n expect(plugin.version).toBeDefined()\n expect(plugin.setup).toBeInstanceOf(Function)\n })\n\n it('sets up without errors', async () => {\n const ctx = createTestContext({\n pluginName: '${params.pluginName}',\n pluginConfig: { enabled: true },\n permissions: plugin.permissions,\n })\n await expect(plugin.setup(ctx)).resolves.not.toThrow()\n })\n\n it('tears down without errors', async () => {\n if (plugin.teardown) {\n await expect(plugin.teardown()).resolves.not.toThrow()\n }\n })\n\n it('installs without errors', async () => {\n if (plugin.install) {\n const ctx = createTestInstallContext({\n pluginName: '${params.pluginName}',\n terminalResponses: { password: [''], confirm: [true], select: ['apiKey'] },\n })\n await expect(plugin.install(ctx)).resolves.not.toThrow()\n }\n })\n})\n`\n}\n","import type { TemplateParams } from './package-json.js'\n\nexport function generateClaudeMd(params: TemplateParams): string {\n return `# CLAUDE.md\n\nThis file provides context for AI coding agents (Claude, Cursor, etc.) working on this plugin.\n\n## What is OpenACP?\n\nOpenACP is an open-source platform that bridges AI coding agents (Claude Code, Codex, etc.) to messaging platforms (Telegram, Discord, Slack) and custom UIs via the Agent Client Protocol (ACP). It features a microkernel plugin architecture where all features — adapters, services, commands — are plugins.\n\n- **Website & Docs**: https://openacp.gitbook.io/docs\n- **GitHub**: https://github.com/Open-ACP/OpenACP\n- **Plugin Registry**: https://github.com/Open-ACP/plugin-registry\n\nKey documentation pages:\n- [Getting Started](https://openacp.gitbook.io/docs/getting-started) — What is OpenACP, quickstart\n- [Plugin Development](https://openacp.gitbook.io/docs/extending/building-plugins) — How to build plugins\n- [Architecture](https://openacp.gitbook.io/docs/extending/architecture) — System design, plugin lifecycle\n- [Dev Mode](https://openacp.gitbook.io/docs/extending/dev-mode) — Hot-reload development workflow\n- [CLI Commands](https://openacp.gitbook.io/docs/api-reference/cli-commands) — Full CLI reference\n- [Platform Setup](https://openacp.gitbook.io/docs/platform-setup) — Telegram, Discord, Slack guides\n- [Configuration](https://openacp.gitbook.io/docs/self-hosting/configuration) — Config and settings reference\n\n## Project Overview\n\nThis is an OpenACP plugin. Plugins extend OpenACP with new adapters, services, commands, and middleware.\n\n- **Package**: ${params.pluginName}\n- **SDK**: \\`@openacp/plugin-sdk\\` (types, base classes, testing utilities)\n- **Entry point**: \\`src/index.ts\\` (default export of \\`OpenACPPlugin\\` object)\n\n## Build & Run\n\n\\`\\`\\`bash\nnpm install # Install dependencies\nnpm run build # Compile TypeScript (tsc)\nnpm run dev # Watch mode (tsc --watch)\nnpm test # Run tests (vitest)\n\\`\\`\\`\n\n### Development with hot-reload\n\n\\`\\`\\`bash\nopenacp dev . # Compiles, watches, and reloads plugin on changes\n\\`\\`\\`\n\n## File Structure\n\n\\`\\`\\`\nsrc/\n index.ts — Plugin entry point (exports OpenACPPlugin)\n __tests__/\n index.test.ts — Tests using @openacp/plugin-sdk/testing\npackage.json — engines.openacp declares minimum CLI version\ntsconfig.json — ES2022, NodeNext, strict mode\nCLAUDE.md — This file (AI agent context)\nPLUGIN_GUIDE.md — Human-readable developer guide\n\\`\\`\\`\n\n## Architecture: How OpenACP Plugins Work\n\n### Plugin Lifecycle\n\n\\`\\`\\`\ninstall ──> [reboot] ──> migrate? ──> setup ──> [running] ──> teardown ──> uninstall\n\\`\\`\\`\n\n| Hook | Trigger | Interactive? | Has Services? |\n|------|---------|-------------|---------------|\n| \\`install(ctx)\\` | \\`openacp plugin add <name>\\` | Yes | No |\n| \\`migrate(ctx, oldSettings, oldVersion)\\` | Boot — stored version differs from plugin version | No | No |\n| \\`configure(ctx)\\` | \\`openacp plugin configure <name>\\` | Yes | No |\n| \\`setup(ctx)\\` | Every boot, after migrate | No | Yes |\n| \\`teardown()\\` | Shutdown (10s timeout) | No | Yes |\n| \\`uninstall(ctx, opts)\\` | \\`openacp plugin remove <name>\\` | Yes | No |\n\n### OpenACPPlugin Interface\n\n\\`\\`\\`typescript\ninterface OpenACPPlugin {\n name: string // unique identifier, e.g. '@myorg/my-plugin'\n version: string // semver\n description?: string\n permissions?: PluginPermission[]\n pluginDependencies?: Record<string, string> // name -> semver range\n optionalPluginDependencies?: Record<string, string> // used if available\n overrides?: string // replace a built-in plugin entirely\n settingsSchema?: ZodSchema // Zod validation for settings\n essential?: boolean // true = needs setup before system can run\n\n setup(ctx: PluginContext): Promise<void>\n teardown?(): Promise<void>\n install?(ctx: InstallContext): Promise<void>\n configure?(ctx: InstallContext): Promise<void>\n migrate?(ctx: MigrateContext, oldSettings: unknown, oldVersion: string): Promise<unknown>\n uninstall?(ctx: InstallContext, opts: { purge: boolean }): Promise<void>\n}\n\\`\\`\\`\n\n### PluginContext API (available in setup)\n\n\\`\\`\\`typescript\ninterface PluginContext {\n pluginName: string\n pluginConfig: Record<string, unknown> // from settings.json\n\n // Events (requires 'events:read' / 'events:emit')\n on(event: string, handler: (...args: unknown[]) => void): void\n off(event: string, handler: (...args: unknown[]) => void): void\n emit(event: string, payload: unknown): void\n\n // Services (requires 'services:register' / 'services:use')\n registerService<T>(name: string, implementation: T): void\n getService<T>(name: string): T | undefined\n\n // Middleware (requires 'middleware:register')\n registerMiddleware<H extends MiddlewareHook>(hook: H, opts: MiddlewareOptions<MiddlewarePayloadMap[H]>): void\n\n // Commands (requires 'commands:register')\n registerCommand(def: CommandDef): void\n\n // Storage (requires 'storage:read' / 'storage:write')\n storage: PluginStorage // get, set, delete, list, getDataDir\n\n // Messaging (requires 'services:use')\n sendMessage(sessionId: string, content: OutgoingMessage): Promise<void>\n\n // Kernel access (requires 'kernel:access')\n sessions: SessionManager\n config: ConfigManager\n eventBus: EventBus\n\n // Always available\n log: Logger // trace, debug, info, warn, error, fatal, child\n}\n\\`\\`\\`\n\n### CommandDef and CommandResponse\n\n\\`\\`\\`typescript\ninterface CommandDef {\n name: string // command name without slash\n description: string // shown in /help\n usage?: string // e.g. '<city>' or 'on|off'\n category: 'system' | 'plugin'\n handler(args: CommandArgs): Promise<CommandResponse | void>\n}\n\ninterface CommandArgs {\n raw: string // text after command name\n sessionId: string | null\n channelId: string // 'telegram', 'discord', 'slack'\n userId: string\n reply(content: string | CommandResponse): Promise<void>\n}\n\ntype CommandResponse =\n | { type: 'text'; text: string }\n | { type: 'menu'; title: string; options: MenuOption[] }\n | { type: 'list'; title: string; items: ListItem[] }\n | { type: 'confirm'; question: string; onYes: string; onNo: string }\n | { type: 'error'; message: string }\n | { type: 'silent' }\n\\`\\`\\`\n\n### Settings System\n\n- \\`settingsSchema\\`: Zod schema for validation\n- \\`SettingsAPI\\` (in InstallContext): get, set, getAll, setAll, delete, clear, has\n- Settings stored at \\`~/.openacp/plugins/@scope/name/settings.json\\`\n- \\`PluginStorage\\` (in PluginContext): key-value store at \\`~/.openacp/plugins/data/@scope/name/kv.json\\`\n- \\`storage.getDataDir()\\`: returns path for large files, databases, caches\n\n### InstallContext (for install/configure/uninstall)\n\n\\`\\`\\`typescript\ninterface InstallContext {\n pluginName: string\n terminal: TerminalIO // text, select, confirm, password, multiselect, log, spinner, note\n settings: SettingsAPI\n legacyConfig?: Record<string, unknown>\n dataDir: string\n log: Logger\n}\n\\`\\`\\`\n\n### Service Interfaces (available via ctx.getService)\n\n| Service name | Interface | Description |\n|---|---|---|\n| \\`security\\` | \\`SecurityService\\` | Access control, session limits, user roles |\n| \\`file-service\\` | \\`FileServiceInterface\\` | File saving, resolving, format conversion |\n| \\`notifications\\` | \\`NotificationService\\` | Send notifications to users |\n| \\`usage\\` | \\`UsageService\\` | Token/cost tracking and budget checking |\n| \\`speech\\` | \\`SpeechServiceInterface\\` | Text-to-speech and speech-to-text |\n| \\`tunnel\\` | \\`TunnelServiceInterface\\` | Port tunneling and public URL management |\n| \\`context\\` | \\`ContextService\\` | Context building for agent sessions |\n\n## Plugin Permissions\n\nDeclare in \\`permissions\\` array. Only request what you need.\n\n| Permission | Allows |\n|---|---|\n| \\`events:read\\` | \\`ctx.on()\\` — subscribe to events |\n| \\`events:emit\\` | \\`ctx.emit()\\` — emit custom events (must prefix with plugin name) |\n| \\`services:register\\` | \\`ctx.registerService()\\` — provide services to other plugins |\n| \\`services:use\\` | \\`ctx.getService()\\`, \\`ctx.sendMessage()\\` — consume services |\n| \\`middleware:register\\` | \\`ctx.registerMiddleware()\\` — intercept and modify flows |\n| \\`commands:register\\` | \\`ctx.registerCommand()\\` — add chat commands |\n| \\`storage:read\\` | \\`ctx.storage.get()\\`, \\`ctx.storage.list()\\` |\n| \\`storage:write\\` | \\`ctx.storage.set()\\`, \\`ctx.storage.delete()\\` |\n| \\`kernel:access\\` | \\`ctx.sessions\\`, \\`ctx.config\\`, \\`ctx.eventBus\\`, \\`ctx.core\\` |\n\nCalling a method without the required permission throws \\`PluginPermissionError\\`.\n\n## Middleware Hooks (20 total)\n\nRegister with \\`ctx.registerMiddleware(hook, { priority?, handler })\\`. Return \\`null\\` to block the flow, call \\`next()\\` to continue.\n\n### Message flow\n- \\`message:incoming\\` — incoming user message (channelId, threadId, userId, text, attachments)\n- \\`message:outgoing\\` — outgoing message to user (sessionId, message)\n\n### Agent flow\n- \\`agent:beforePrompt\\` — before prompt is sent to agent (sessionId, text, attachments)\n- \\`agent:beforeEvent\\` — before agent event is processed (sessionId, event)\n- \\`agent:afterEvent\\` — after agent event, before delivery (sessionId, event, outgoingMessage)\n\n### Turn lifecycle\n- \\`turn:start\\` — agent turn begins (sessionId, promptText, promptNumber)\n- \\`turn:end\\` — agent turn ends (sessionId, stopReason, durationMs)\n\n### File system\n- \\`fs:beforeRead\\` — before file read (sessionId, path, line, limit)\n- \\`fs:beforeWrite\\` — before file write (sessionId, path, content)\n\n### Terminal\n- \\`terminal:beforeCreate\\` — before terminal process spawned (sessionId, command, args, env, cwd)\n- \\`terminal:afterExit\\` — after terminal process exits (sessionId, terminalId, command, exitCode, durationMs)\n\n### Permission\n- \\`permission:beforeRequest\\` — before permission prompt (sessionId, request, autoResolve)\n- \\`permission:afterResolve\\` — after permission resolved (sessionId, requestId, decision, userId, durationMs)\n\n### Session\n- \\`session:beforeCreate\\` — before session creation (agentName, workingDir, userId, channelId, threadId)\n- \\`session:afterDestroy\\` — after session destroyed (sessionId, reason, durationMs, promptCount)\n\n### Control\n- \\`mode:beforeChange\\` — before mode change (sessionId, fromMode, toMode)\n- \\`config:beforeChange\\` — before config change (sessionId, configId, oldValue, newValue)\n- \\`model:beforeChange\\` — before model change (sessionId, fromModel, toModel)\n- \\`agent:beforeCancel\\` — before agent cancellation (sessionId, reason)\n- \\`agent:beforeSwitch\\` — **blocking** before agent switch (sessionId, fromAgent, toAgent). Return null/false to block.\n- \\`agent:afterSwitch\\` — **fire-and-forget** after agent switch (sessionId, fromAgent, toAgent, resumed). Observational only.\n\n## Plugin Events (subscribe with ctx.on)\n\n### System\n- \\`kernel:booted\\`, \\`system:ready\\`, \\`system:shutdown\\`, \\`system:commands-ready\\`\n\n### Plugin lifecycle\n- \\`plugin:loaded\\`, \\`plugin:failed\\`, \\`plugin:disabled\\`, \\`plugin:unloaded\\`\n\n### Session\n- \\`session:created\\`, \\`session:ended\\`, \\`session:named\\`, \\`session:updated\\`\n\n### Agent\n- \\`agent:event\\`, \\`agent:prompt\\`\n\n### Permission\n- \\`permission:request\\`, \\`permission:resolved\\`\n\n## Testing\n\nUse \\`@openacp/plugin-sdk/testing\\`:\n\n\\`\\`\\`typescript\nimport { createTestContext, createTestInstallContext, mockServices } from '@openacp/plugin-sdk/testing'\n\\`\\`\\`\n\n### createTestContext(opts)\n\nCreates a test \\`PluginContext\\`. All state is in-memory.\n\n\\`\\`\\`typescript\nconst ctx = createTestContext({\n pluginName: '${params.pluginName}',\n pluginConfig: { enabled: true },\n permissions: plugin.permissions,\n services: { security: mockServices.security() },\n})\nawait plugin.setup(ctx)\nexpect(ctx.registeredCommands.has('mycommand')).toBe(true)\nconst response = await ctx.executeCommand('mycommand', { raw: 'test' })\n\\`\\`\\`\n\nInspection properties: \\`registeredServices\\`, \\`registeredCommands\\`, \\`registeredMiddleware\\`, \\`emittedEvents\\`, \\`sentMessages\\`, \\`executeCommand()\\`.\n\n### createTestInstallContext(opts)\n\nCreates a test \\`InstallContext\\`. Terminal prompts auto-answered from \\`terminalResponses\\`.\n\n\\`\\`\\`typescript\nconst ctx = createTestInstallContext({\n pluginName: '${params.pluginName}',\n terminalResponses: { password: ['sk-test-key'], select: ['en'] },\n})\nawait plugin.install!(ctx)\nexpect(ctx.settingsData.get('apiKey')).toBe('sk-test-key')\n\\`\\`\\`\n\n### mockServices\n\nFactory functions for mock service implementations:\n\n\\`\\`\\`typescript\nmockServices.security(overrides?) // checkAccess, checkSessionLimit, getUserRole\nmockServices.fileService(overrides?) // saveFile, resolveFile, readTextFileWithRange\nmockServices.notifications(overrides?) // notify, notifyAll\nmockServices.usage(overrides?) // trackUsage, checkBudget, getSummary\nmockServices.speech(overrides?) // textToSpeech, speechToText, register*\nmockServices.tunnel(overrides?) // getPublicUrl, start, stop, getStore, fileUrl, diffUrl\nmockServices.context(overrides?) // buildContext, registerProvider\n\\`\\`\\`\n\n## Conventions\n\n- **ESM-only**: \\`\"type\": \"module\"\\` in package.json\n- **Import extensions**: All imports must use \\`.js\\` extension (e.g., \\`import x from './util.js'\\`)\n- **TypeScript strict mode**: \\`strict: true\\` in tsconfig.json\n- **Target**: ES2022, module NodeNext\n- **Test framework**: Vitest\n- **Test files**: \\`src/**/__tests__/*.test.ts\\`\n\n## How to Add a Command\n\n\\`\\`\\`typescript\n// In setup():\nctx.registerCommand({\n name: 'mycommand',\n description: 'Does something useful',\n usage: '<arg>',\n category: 'plugin',\n async handler(args) {\n const input = args.raw.trim()\n if (!input) return { type: 'error', message: 'Usage: /mycommand <arg>' }\n return { type: 'text', text: \\\\\\`Result: \\\\\\${input}\\\\\\` }\n },\n})\n\\`\\`\\`\n\nRequires \\`commands:register\\` permission. Available as \\`/mycommand\\` (if no conflict) and \\`/pluginscope:mycommand\\` (always).\n\n## How to Add a Service\n\n\\`\\`\\`typescript\n// In setup():\nconst myService = new MyService()\nctx.registerService('my-service', myService)\n\\`\\`\\`\n\nRequires \\`services:register\\` permission. Other plugins consume with \\`ctx.getService<MyService>('my-service')\\`.\n\n## How to Add Middleware\n\n\\`\\`\\`typescript\n// In setup():\nctx.registerMiddleware('message:outgoing', {\n priority: 50, // lower = earlier execution\n handler: async (payload, next) => {\n payload.message.text = modifyText(payload.message.text)\n return next() // continue chain; return null to block\n },\n})\n\\`\\`\\`\n\nRequires \\`middleware:register\\` permission.\n\n## How Settings Work\n\n1. Define \\`settingsSchema\\` (Zod) on the plugin object\n2. In \\`install()\\`: use \\`ctx.terminal\\` for interactive prompts, save with \\`ctx.settings.set()\\`\n3. In \\`configure()\\`: re-run prompts with current values pre-filled\n4. In \\`setup()\\`: read settings from \\`ctx.pluginConfig\\`\n5. In \\`migrate()\\`: transform old settings to new format on version change\n\n## Version Compatibility\n\nThe \\`engines.openacp\\` field in package.json declares the minimum CLI version. OpenACP checks this on install and warns if incompatible.\n`\n}\n","import type { TemplateParams } from './package-json.js'\n\nexport function generatePluginGuide(params: TemplateParams): string {\n return `# Plugin Developer Guide\n\n## Overview\n\n**${params.pluginName}** is an OpenACP plugin.\n\n> TODO: Describe what this plugin does.\n\n## Project Structure\n\n\\`\\`\\`\nsrc/\n index.ts — Plugin entry point (exports OpenACPPlugin object)\n __tests__/\n index.test.ts — Tests using Vitest + @openacp/plugin-sdk/testing\npackage.json — npm package config with engines.openacp constraint\ntsconfig.json — TypeScript strict mode, ES2022, NodeNext\nCLAUDE.md — Full technical reference for AI coding agents\nPLUGIN_GUIDE.md — This file\n\\`\\`\\`\n\n## Development Workflow\n\n1. **Edit** \\`src/index.ts\\` — implement your plugin logic\n2. **Dev mode**: \\`openacp dev .\\` — compiles, watches, and hot-reloads your plugin\n3. **Test**: \\`npm test\\` — runs Vitest with SDK testing utilities\n4. **Build**: \\`npm run build\\` — compiles TypeScript to \\`dist/\\`\n\n\\`\\`\\`bash\nnpm install\nopenacp dev . # start developing with hot-reload\nnpm test # run tests\nnpm run build # compile for publishing\n\\`\\`\\`\n\n## Adding a Command\n\nRegister commands in your \\`setup()\\` function. Requires \\`commands:register\\` permission.\n\n\\`\\`\\`typescript\nasync setup(ctx: PluginContext) {\n ctx.registerCommand({\n name: 'greet',\n description: 'Send a greeting',\n usage: '[name]',\n category: 'plugin',\n async handler(args) {\n const name = args.raw.trim() || 'World'\n return { type: 'text', text: \\\\\\`Hello, \\\\\\${name}!\\\\\\` }\n },\n })\n}\n\\`\\`\\`\n\nThe command will be available as \\`/greet\\` in all messaging platforms.\n\n## Adding a Service\n\nProvide a service that other plugins can consume. Requires \\`services:register\\` permission.\n\n\\`\\`\\`typescript\nasync setup(ctx: PluginContext) {\n const myService = {\n doSomething(input: string): string {\n return input.toUpperCase()\n },\n }\n ctx.registerService('my-service', myService)\n}\n\\`\\`\\`\n\nOther plugins access it with \\`ctx.getService<MyServiceType>('my-service')\\`.\n\n## Adding Middleware\n\nIntercept and modify message flows. Requires \\`middleware:register\\` permission.\n\n\\`\\`\\`typescript\nasync setup(ctx: PluginContext) {\n ctx.registerMiddleware('message:outgoing', {\n priority: 50,\n handler: async (payload, next) => {\n // Modify the message before delivery\n payload.message.text += '\\\\n-- sent via ${params.pluginName}'\n return next() // continue the chain\n // return null to block the message entirely\n },\n })\n}\n\\`\\`\\`\n\n## Handling Settings\n\n### Install flow (first-time setup)\n\n\\`\\`\\`typescript\nasync install(ctx: InstallContext) {\n const apiKey = await ctx.terminal.password({\n message: 'Enter your API key:',\n validate: (v) => v.length > 0 ? undefined : 'Required',\n })\n await ctx.settings.set('apiKey', apiKey)\n ctx.terminal.log.success('Configured!')\n}\n\\`\\`\\`\n\n### Configure flow (reconfiguration)\n\n\\`\\`\\`typescript\nasync configure(ctx: InstallContext) {\n const current = await ctx.settings.getAll()\n const apiKey = await ctx.terminal.password({\n message: \\\\\\`API key (current: \\\\\\${current.apiKey ? '***' : 'not set'}):\\\\\\`,\n })\n if (apiKey) await ctx.settings.set('apiKey', apiKey)\n ctx.terminal.log.success('Updated!')\n}\n\\`\\`\\`\n\n### Reading settings at runtime\n\n\\`\\`\\`typescript\nasync setup(ctx: PluginContext) {\n const apiKey = ctx.pluginConfig.apiKey as string\n if (!apiKey) {\n ctx.log.warn('Not configured — run: openacp plugin configure ${params.pluginName}')\n return\n }\n // Use apiKey...\n}\n\\`\\`\\`\n\n## Testing\n\nTests use Vitest and \\`@openacp/plugin-sdk/testing\\`.\n\n\\`\\`\\`typescript\nimport { describe, it, expect } from 'vitest'\nimport { createTestContext, createTestInstallContext, mockServices } from '@openacp/plugin-sdk/testing'\nimport plugin from '../index.js'\n\ndescribe('${params.pluginName}', () => {\n it('registers commands on setup', async () => {\n const ctx = createTestContext({ pluginName: '${params.pluginName}' })\n await plugin.setup(ctx)\n expect(ctx.registeredCommands.has('greet')).toBe(true)\n })\n\n it('command returns expected response', async () => {\n const ctx = createTestContext({ pluginName: '${params.pluginName}' })\n await plugin.setup(ctx)\n const res = await ctx.executeCommand('greet', { raw: 'Alice' })\n expect(res).toEqual({ type: 'text', text: 'Hello, Alice!' })\n })\n\n it('install saves settings', async () => {\n const ctx = createTestInstallContext({\n pluginName: '${params.pluginName}',\n terminalResponses: { password: ['sk-test-key'] },\n })\n await plugin.install!(ctx)\n expect(ctx.settingsData.get('apiKey')).toBe('sk-test-key')\n })\n})\n\\`\\`\\`\n\n### Available mock services\n\n\\`\\`\\`typescript\nconst ctx = createTestContext({\n pluginName: '${params.pluginName}',\n services: {\n security: mockServices.security(),\n usage: mockServices.usage({ async checkBudget() { return { ok: false, percent: 100 } } }),\n },\n})\n\\`\\`\\`\n\n## Publishing\n\n1. Update \\`version\\` in both \\`package.json\\` and \\`src/index.ts\\`\n2. Build and test:\n \\`\\`\\`bash\n npm run build\n npm test\n \\`\\`\\`\n3. Publish:\n \\`\\`\\`bash\n npm publish --access public\n \\`\\`\\`\n4. Users install with:\n \\`\\`\\`bash\n openacp plugin install ${params.pluginName}\n \\`\\`\\`\n5. Submit to the [OpenACP Plugin Registry](https://github.com/Open-ACP/plugin-registry) for discoverability.\n\n## Useful Links\n\n- [Architecture: Plugin System](https://docs.openacp.dev/architecture/plugin-system)\n- [Architecture: Writing Plugins](https://docs.openacp.dev/architecture/writing-plugins)\n- [Architecture: Command System](https://docs.openacp.dev/architecture/command-system)\n- [Plugin SDK Reference](https://docs.openacp.dev/extending/plugin-sdk-reference)\n- [Getting Started: Your First Plugin](https://docs.openacp.dev/extending/getting-started-plugin)\n- [Dev Mode](https://docs.openacp.dev/extending/dev-mode)\n- [Contributing](https://github.com/Open-ACP/OpenACP/blob/main/CONTRIBUTING.md)\n`\n}\n"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAqQjB,OAAO,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAkBjB,OAAO,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsFlC;;;ACvYO,SAAS,oBAAoB,QAAgC;AAClE,SAAO;AAAA;AAAA;AAAA;AAAA,IAIL,OAAO,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gDA+E2B,OAAO,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wEA0CE,OAAO,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAgBxE,OAAO,UAAU;AAAA;AAAA,mDAEsB,OAAO,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mDAMjB,OAAO,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAQ/C,OAAO,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAarB,OAAO,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4BAsBN,OAAO,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAc7C;;;AR/LA,eAAsB,kBAAiC;AACrD,EAAE,QAAM,6BAA6B;AAErC,QAAM,SAAS,MAAQ;AAAA,IACrB;AAAA,MACE,MAAM,MACF,OAAK;AAAA,QACL,SAAS;AAAA,QACT,aAAa;AAAA,QACb,UAAU,CAAC,UAA8B;AACvC,cAAI,CAAC,SAAS,CAAC,MAAM,KAAK,EAAG,QAAO;AACpC,cAAI,CAAC,+BAA+B,KAAK,MAAM,KAAK,CAAC,GAAG;AACtD,mBAAO;AAAA,UACT;AACA,iBAAO;AAAA,QACT;AAAA,MACF,CAAC;AAAA,MACH,aAAa,MACT,OAAK;AAAA,QACL,SAAS;AAAA,QACT,aAAa;AAAA,MACf,CAAC;AAAA,MACH,QAAQ,MACJ,OAAK;AAAA,QACL,SAAS;AAAA,QACT,aAAa;AAAA,MACf,CAAC;AAAA,MACH,SAAS,MACL,SAAO;AAAA,QACP,SAAS;AAAA,QACT,SAAS;AAAA,UACP,EAAE,OAAO,OAAO,OAAO,MAAM;AAAA,UAC7B,EAAE,OAAO,cAAc,OAAO,aAAa;AAAA,UAC3C,EAAE,OAAO,OAAO,OAAO,MAAM;AAAA,UAC7B,EAAE,OAAO,cAAc,OAAO,uBAAuB;AAAA,QACvD;AAAA,MACF,CAAC;AAAA,IACL;AAAA,IACA;AAAA,MACE,UAAU,MAAM;AACd,QAAE,SAAO,4BAA4B;AACrC,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAa,OAAO,KAAK,KAAK;AACpC,QAAM,UAAU,WAAW,QAAQ,aAAa,EAAE;AAClD,QAAM,YAAY,KAAK,QAAQ,QAAQ,IAAI,GAAG,OAAO;AAErD,MAAI,GAAG,WAAW,SAAS,GAAG;AAC5B,IAAE,SAAO,cAAc,OAAO,mBAAmB;AACjD,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAMA,WAAY,UAAQ;AAC1B,EAAAA,SAAQ,MAAM,uBAAuB;AAGrC,KAAG,UAAU,KAAK,KAAK,WAAW,OAAO,WAAW,GAAG,EAAE,WAAW,KAAK,CAAC;AAG1E,QAAM,SAAyB;AAAA,IAC7B;AAAA,IACA,aAAc,OAAO,eAA0B;AAAA,IAC/C,QAAS,OAAO,UAAqB;AAAA,IACrC,SAAS,OAAO;AAAA,IAChB,YAAY,kBAAkB;AAAA,EAChC;AAGA,QAAM,QAA0D;AAAA,IAC9D,EAAE,cAAc,gBAAgB,SAAS,oBAAoB,MAAM,EAAE;AAAA,IACrE,EAAE,cAAc,iBAAiB,SAAS,iBAAiB,EAAE;AAAA,IAC7D,EAAE,cAAc,cAAc,SAAS,kBAAkB,EAAE;AAAA,IAC3D,EAAE,cAAc,cAAc,SAAS,kBAAkB,EAAE;AAAA,IAC3D,EAAE,cAAc,iBAAiB,SAAS,qBAAqB,EAAE;AAAA,IACjE,EAAE,cAAc,aAAa,SAAS,eAAe,MAAM,EAAE;AAAA,IAC7D,EAAE,cAAc,aAAa,SAAS,iBAAiB,MAAM,EAAE;AAAA,IAC/D,EAAE,cAAc,mBAAmB,SAAS,oBAAoB,MAAM,EAAE;AAAA,IACxE,EAAE,cAAc,KAAK,KAAK,OAAO,UAAU,GAAG,SAAS,qBAAqB,MAAM,EAAE;AAAA,IACpF,EAAE,cAAc,KAAK,KAAK,OAAO,aAAa,eAAe,GAAG,SAAS,mBAAmB,MAAM,EAAE;AAAA,EACtG;AAEA,aAAW,QAAQ,OAAO;AACxB,OAAG,cAAc,KAAK,KAAK,WAAW,KAAK,YAAY,GAAG,KAAK,OAAO;AAAA,EACxE;AAEA,EAAAA,SAAQ,KAAK,oBAAoB;AAEjC,EAAE;AAAA,IACA;AAAA,MACE,MAAM,OAAO;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,IACX;AAAA,EACF;AAEA,EAAE,QAAM,UAAU,UAAU,iBAAiB,OAAO,EAAE;AACxD;","names":["spinner"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
commandExists
|
|
3
|
-
} from "./chunk-ZSLHHQPQ.js";
|
|
4
1
|
import {
|
|
5
2
|
createChildLogger
|
|
6
3
|
} from "./chunk-R6KZYF7D.js";
|
|
4
|
+
import {
|
|
5
|
+
commandExists
|
|
6
|
+
} from "./chunk-ZSLHHQPQ.js";
|
|
7
7
|
|
|
8
8
|
// src/cli/post-upgrade.ts
|
|
9
9
|
var log = createChildLogger({ module: "post-upgrade" });
|
|
@@ -11,7 +11,7 @@ async function runPostUpgradeChecks(config) {
|
|
|
11
11
|
if (config.tunnel.enabled) {
|
|
12
12
|
if (config.tunnel.provider === "cloudflare") {
|
|
13
13
|
try {
|
|
14
|
-
const { ensureCloudflared } = await import("./install-cloudflared-
|
|
14
|
+
const { ensureCloudflared } = await import("./install-cloudflared-LNS5L5FR.js");
|
|
15
15
|
await ensureCloudflared();
|
|
16
16
|
} catch (err) {
|
|
17
17
|
log.warn(
|
|
@@ -40,7 +40,7 @@ async function runPostUpgradeChecks(config) {
|
|
|
40
40
|
const handoff = integration.items.find((i) => i.id === "handoff");
|
|
41
41
|
if (handoff?.isInstalled() && !commandExists("jq")) {
|
|
42
42
|
try {
|
|
43
|
-
const { ensureJq } = await import("./install-jq-
|
|
43
|
+
const { ensureJq } = await import("./install-jq-SN4IA5K4.js");
|
|
44
44
|
await ensureJq();
|
|
45
45
|
} catch (err) {
|
|
46
46
|
log.warn(
|
|
@@ -76,4 +76,4 @@ async function runPostUpgradeChecks(config) {
|
|
|
76
76
|
export {
|
|
77
77
|
runPostUpgradeChecks
|
|
78
78
|
};
|
|
79
|
-
//# sourceMappingURL=post-upgrade-
|
|
79
|
+
//# sourceMappingURL=post-upgrade-F4YPMTUT.js.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
security_default
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-OSBZXY2W.js";
|
|
4
4
|
import "./chunk-LGFWH3AE.js";
|
|
5
5
|
export {
|
|
6
6
|
security_default as default
|
|
7
7
|
};
|
|
8
|
-
//# sourceMappingURL=security-
|
|
8
|
+
//# sourceMappingURL=security-O4XGN2CM.js.map
|