@openacp/cli 2026.326.4 → 2026.327.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/README.md +2 -2
  2. package/dist/{adapter-6ANPBSVU.js → adapter-LC2QSDAS.js} +4 -5
  3. package/dist/{adapter-PQGHVG4K.js → adapter-Y55NXX6I.js} +2 -2
  4. package/dist/{api-server-3PYLRBCN.js → api-server-7G3ZUZRM.js} +2 -2
  5. package/dist/{api-server-CHVSUDBX.js → api-server-CAYNPUF2.js} +2 -2
  6. package/dist/{chunk-UNJUWWQO.js → chunk-2YCW3QDV.js} +21 -14
  7. package/dist/chunk-2YCW3QDV.js.map +1 -0
  8. package/dist/{chunk-Y64XWMJ4.js → chunk-36YQ44D7.js} +2 -2
  9. package/dist/{chunk-UB2QB6DE.js → chunk-3ASUU6WW.js} +2 -2
  10. package/dist/{chunk-V5JT5TPD.js → chunk-4GMLGCF2.js} +2 -2
  11. package/dist/chunk-CDAUYTVP.js +41 -0
  12. package/dist/chunk-CDAUYTVP.js.map +1 -0
  13. package/dist/{chunk-Q6ZXJTZB.js → chunk-HUWOFP2H.js} +9 -17
  14. package/dist/chunk-HUWOFP2H.js.map +1 -0
  15. package/dist/{chunk-P4SNGQNI.js → chunk-KMMEFXIE.js} +2 -2
  16. package/dist/{chunk-RKB2ZK6S.js → chunk-LP45RCA4.js} +579 -153
  17. package/dist/chunk-LP45RCA4.js.map +1 -0
  18. package/dist/{chunk-L7YNNBI5.js → chunk-QAQDGPB4.js} +1 -75
  19. package/dist/chunk-QAQDGPB4.js.map +1 -0
  20. package/dist/{chunk-V2M243KZ.js → chunk-TRXBJEZ5.js} +55 -53
  21. package/dist/chunk-TRXBJEZ5.js.map +1 -0
  22. package/dist/{chunk-NBFIBGAT.js → chunk-UMT7RU77.js} +45 -118
  23. package/dist/chunk-UMT7RU77.js.map +1 -0
  24. package/dist/{chunk-FQEBWOZR.js → chunk-XIBG7LSL.js} +181 -128
  25. package/dist/chunk-XIBG7LSL.js.map +1 -0
  26. package/dist/cli.js +155 -49
  27. package/dist/cli.js.map +1 -1
  28. package/dist/{config-editor-HNEKXRLQ.js → config-editor-3IKBPZA7.js} +2 -2
  29. package/dist/{core-plugins-VEUNFTMB.js → core-plugins-ROU4GPLT.js} +8 -12
  30. package/dist/{dev-loader-RDC5E2CW.js → dev-loader-DRU3R7ZM.js} +7 -18
  31. package/dist/dev-loader-DRU3R7ZM.js.map +1 -0
  32. package/dist/{doctor-H72BZOPA.js → doctor-QZQAP46W.js} +2 -2
  33. package/dist/index.d.ts +128 -66
  34. package/dist/index.js +41 -20
  35. package/dist/index.js.map +1 -1
  36. package/dist/{integrate-5C6KSU6D.js → integrate-G6CVXTGT.js} +3 -4
  37. package/dist/integrate-G6CVXTGT.js.map +1 -0
  38. package/dist/{main-T5WVCCFN.js → main-UVTZ46WP.js} +39 -185
  39. package/dist/main-UVTZ46WP.js.map +1 -0
  40. package/dist/plugin-create-5HQRF2ID.js +967 -0
  41. package/dist/plugin-create-5HQRF2ID.js.map +1 -0
  42. package/dist/plugin-installer-GQ2P3Q3E.js +23 -0
  43. package/dist/plugin-installer-GQ2P3Q3E.js.map +1 -0
  44. package/dist/plugin-search-HQ4WQKOF.js +40 -0
  45. package/dist/plugin-search-HQ4WQKOF.js.map +1 -0
  46. package/dist/{post-upgrade-XLHZ6ZB7.js → post-upgrade-3ADZRMYJ.js} +2 -2
  47. package/dist/registry-client-AVGRE4CF.js +8 -0
  48. package/dist/{setup-BAI2F24H.js → setup-EYAFK2WI.js} +77 -50
  49. package/dist/setup-EYAFK2WI.js.map +1 -0
  50. package/dist/{slack-KH7E3VBS.js → slack-37ZWBDUI.js} +2 -2
  51. package/dist/{telegram-ZDC3JQF2.js → telegram-2ZCCCZIY.js} +2 -2
  52. package/dist/{tunnel-M47I7H4B.js → tunnel-45HA72MB.js} +2 -2
  53. package/dist/{tunnel-service-WADYHREX.js → tunnel-service-QJPUYEKU.js} +11 -3
  54. package/dist/tunnel-service-QJPUYEKU.js.map +1 -0
  55. package/package.json +2 -3
  56. package/dist/action-detect-QPA775HB.js +0 -16
  57. package/dist/adapter-77ZCVABT.js +0 -2394
  58. package/dist/adapter-77ZCVABT.js.map +0 -1
  59. package/dist/admin-GBPZFFAU.js +0 -23
  60. package/dist/agents-BWU4MRRD.js +0 -15
  61. package/dist/chunk-2CX4IEEC.js +0 -124
  62. package/dist/chunk-2CX4IEEC.js.map +0 -1
  63. package/dist/chunk-4KGLKKQK.js +0 -298
  64. package/dist/chunk-4KGLKKQK.js.map +0 -1
  65. package/dist/chunk-5ZOFBTOR.js +0 -553
  66. package/dist/chunk-5ZOFBTOR.js.map +0 -1
  67. package/dist/chunk-6RXVEXF3.js +0 -23
  68. package/dist/chunk-6RXVEXF3.js.map +0 -1
  69. package/dist/chunk-FQEBWOZR.js.map +0 -1
  70. package/dist/chunk-GJOY37U7.js +0 -265
  71. package/dist/chunk-GJOY37U7.js.map +0 -1
  72. package/dist/chunk-HVBNCPAY.js +0 -71
  73. package/dist/chunk-HVBNCPAY.js.map +0 -1
  74. package/dist/chunk-I3CGU5W7.js +0 -134
  75. package/dist/chunk-I3CGU5W7.js.map +0 -1
  76. package/dist/chunk-L7YNNBI5.js.map +0 -1
  77. package/dist/chunk-MTSDOSXS.js +0 -219
  78. package/dist/chunk-MTSDOSXS.js.map +0 -1
  79. package/dist/chunk-NAM4ERUW.js +0 -203
  80. package/dist/chunk-NAM4ERUW.js.map +0 -1
  81. package/dist/chunk-NBFIBGAT.js.map +0 -1
  82. package/dist/chunk-O5RG4YZY.js +0 -122
  83. package/dist/chunk-O5RG4YZY.js.map +0 -1
  84. package/dist/chunk-Q6ZXJTZB.js.map +0 -1
  85. package/dist/chunk-QSDZDHNS.js +0 -145
  86. package/dist/chunk-QSDZDHNS.js.map +0 -1
  87. package/dist/chunk-RKB2ZK6S.js.map +0 -1
  88. package/dist/chunk-UNJUWWQO.js.map +0 -1
  89. package/dist/chunk-V2M243KZ.js.map +0 -1
  90. package/dist/chunk-WAAD23KY.js +0 -222
  91. package/dist/chunk-WAAD23KY.js.map +0 -1
  92. package/dist/chunk-WVLDNYOJ.js +0 -150
  93. package/dist/chunk-WVLDNYOJ.js.map +0 -1
  94. package/dist/dev-loader-RDC5E2CW.js.map +0 -1
  95. package/dist/discord-NOJQ5PZO.js +0 -8
  96. package/dist/doctor-RF6BHMCC.js +0 -15
  97. package/dist/doctor-RF6BHMCC.js.map +0 -1
  98. package/dist/integrate-5C6KSU6D.js.map +0 -1
  99. package/dist/main-T5WVCCFN.js.map +0 -1
  100. package/dist/new-session-AVQCNXRG.js +0 -17
  101. package/dist/new-session-AVQCNXRG.js.map +0 -1
  102. package/dist/plugin-create-AQ3B22BZ.js +0 -334
  103. package/dist/plugin-create-AQ3B22BZ.js.map +0 -1
  104. package/dist/session-KZFA6Z26.js +0 -20
  105. package/dist/session-KZFA6Z26.js.map +0 -1
  106. package/dist/settings-MFYM7CZO.js +0 -14
  107. package/dist/settings-MFYM7CZO.js.map +0 -1
  108. package/dist/setup-BAI2F24H.js.map +0 -1
  109. package/dist/slack-KH7E3VBS.js.map +0 -1
  110. package/dist/telegram-ZDC3JQF2.js.map +0 -1
  111. package/dist/tunnel-M47I7H4B.js.map +0 -1
  112. package/dist/tunnel-service-WADYHREX.js.map +0 -1
  113. package/dist/usage-WYNK6ZC5.js +0 -10
  114. package/dist/usage-WYNK6ZC5.js.map +0 -1
  115. package/dist/validators-6CLEZUBD.js +0 -8
  116. package/dist/validators-6CLEZUBD.js.map +0 -1
  117. /package/dist/{action-detect-QPA775HB.js.map → adapter-LC2QSDAS.js.map} +0 -0
  118. /package/dist/{adapter-PQGHVG4K.js.map → adapter-Y55NXX6I.js.map} +0 -0
  119. /package/dist/{adapter-6ANPBSVU.js.map → api-server-7G3ZUZRM.js.map} +0 -0
  120. /package/dist/{admin-GBPZFFAU.js.map → api-server-CAYNPUF2.js.map} +0 -0
  121. /package/dist/{chunk-Y64XWMJ4.js.map → chunk-36YQ44D7.js.map} +0 -0
  122. /package/dist/{chunk-UB2QB6DE.js.map → chunk-3ASUU6WW.js.map} +0 -0
  123. /package/dist/{chunk-V5JT5TPD.js.map → chunk-4GMLGCF2.js.map} +0 -0
  124. /package/dist/{chunk-P4SNGQNI.js.map → chunk-KMMEFXIE.js.map} +0 -0
  125. /package/dist/{agents-BWU4MRRD.js.map → config-editor-3IKBPZA7.js.map} +0 -0
  126. /package/dist/{api-server-3PYLRBCN.js.map → core-plugins-ROU4GPLT.js.map} +0 -0
  127. /package/dist/{api-server-CHVSUDBX.js.map → doctor-QZQAP46W.js.map} +0 -0
  128. /package/dist/{post-upgrade-XLHZ6ZB7.js.map → post-upgrade-3ADZRMYJ.js.map} +0 -0
  129. /package/dist/{config-editor-HNEKXRLQ.js.map → registry-client-AVGRE4CF.js.map} +0 -0
  130. /package/dist/{core-plugins-VEUNFTMB.js.map → slack-37ZWBDUI.js.map} +0 -0
  131. /package/dist/{discord-NOJQ5PZO.js.map → telegram-2ZCCCZIY.js.map} +0 -0
  132. /package/dist/{doctor-H72BZOPA.js.map → tunnel-45HA72MB.js.map} +0 -0
@@ -0,0 +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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AA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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;A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","names":["spinner"]}
@@ -0,0 +1,23 @@
1
+ import "./chunk-VUNV25KB.js";
2
+
3
+ // src/core/plugin/plugin-installer.ts
4
+ import { exec } from "child_process";
5
+ import { promisify } from "util";
6
+ import * as os from "os";
7
+ import * as path from "path";
8
+ var execAsync = promisify(exec);
9
+ async function installNpmPlugin(packageName, pluginsDir) {
10
+ try {
11
+ return await import(packageName);
12
+ } catch {
13
+ }
14
+ const dir = pluginsDir ?? path.join(os.homedir(), ".openacp", "plugins");
15
+ await execAsync(`npm install ${packageName} --prefix "${dir}" --save`, {
16
+ timeout: 6e4
17
+ });
18
+ return await import(packageName);
19
+ }
20
+ export {
21
+ installNpmPlugin
22
+ };
23
+ //# sourceMappingURL=plugin-installer-GQ2P3Q3E.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/plugin/plugin-installer.ts"],"sourcesContent":["import { exec } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport * as os from 'node:os'\nimport * as path from 'node:path'\n\nconst execAsync = promisify(exec)\n\n/**\n * Install an npm package to the plugins directory and return the loaded module.\n * Tries to import first; if not installed, runs npm install asynchronously.\n */\nexport async function installNpmPlugin(packageName: string, pluginsDir?: string): Promise<any> {\n // Try import first — already installed\n try {\n return await import(packageName)\n } catch {\n // Not installed, proceed with install\n }\n\n const dir = pluginsDir ?? path.join(os.homedir(), '.openacp', 'plugins')\n\n await execAsync(`npm install ${packageName} --prefix \"${dir}\" --save`, {\n timeout: 60000,\n })\n\n return await import(packageName)\n}\n"],"mappings":";;;AAAA,SAAS,YAAY;AACrB,SAAS,iBAAiB;AAC1B,YAAY,QAAQ;AACpB,YAAY,UAAU;AAEtB,IAAM,YAAY,UAAU,IAAI;AAMhC,eAAsB,iBAAiB,aAAqB,YAAmC;AAE7F,MAAI;AACF,WAAO,MAAM,OAAO;AAAA,EACtB,QAAQ;AAAA,EAER;AAEA,QAAM,MAAM,cAAmB,UAAQ,WAAQ,GAAG,YAAY,SAAS;AAEvE,QAAM,UAAU,eAAe,WAAW,cAAc,GAAG,YAAY;AAAA,IACrE,SAAS;AAAA,EACX,CAAC;AAED,SAAO,MAAM,OAAO;AACtB;","names":[]}
@@ -0,0 +1,40 @@
1
+ import {
2
+ RegistryClient
3
+ } from "./chunk-CDAUYTVP.js";
4
+ import "./chunk-VUNV25KB.js";
5
+
6
+ // src/cli/commands/plugin-search.ts
7
+ async function cmdPluginSearch(args) {
8
+ const query = args.join(" ").trim();
9
+ if (!query) {
10
+ console.error("Usage: openacp plugin search <query>");
11
+ process.exit(1);
12
+ }
13
+ const client = new RegistryClient();
14
+ try {
15
+ const results = await client.search(query);
16
+ if (results.length === 0) {
17
+ console.log(`No plugins found matching "${query}"`);
18
+ return;
19
+ }
20
+ console.log(`
21
+ Found ${results.length} plugin${results.length > 1 ? "s" : ""} matching "${query}":
22
+ `);
23
+ for (const p of results) {
24
+ const verified = p.verified ? " \u2713" : "";
25
+ const featured = p.featured ? " \u2B50" : "";
26
+ console.log(` ${p.icon || "\u{1F4E6}"} ${p.displayName ?? p.name}${verified}${featured}`);
27
+ console.log(` ${p.description}`);
28
+ console.log(` ${p.category} | v${p.version} | npm: ${p.npm}`);
29
+ console.log(` Install: openacp plugin install ${p.name}`);
30
+ console.log();
31
+ }
32
+ } catch (err) {
33
+ console.error(`Failed to search registry: ${err}`);
34
+ process.exit(1);
35
+ }
36
+ }
37
+ export {
38
+ cmdPluginSearch
39
+ };
40
+ //# sourceMappingURL=plugin-search-HQ4WQKOF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/commands/plugin-search.ts"],"sourcesContent":["import { RegistryClient } from '../../core/plugin/registry-client.js'\n\nexport async function cmdPluginSearch(args: string[]): Promise<void> {\n const query = args.join(' ').trim()\n if (!query) {\n console.error('Usage: openacp plugin search <query>')\n process.exit(1)\n }\n\n const client = new RegistryClient()\n\n try {\n const results = await client.search(query)\n\n if (results.length === 0) {\n console.log(`No plugins found matching \"${query}\"`)\n return\n }\n\n console.log(`\\nFound ${results.length} plugin${results.length > 1 ? 's' : ''} matching \"${query}\":\\n`)\n for (const p of results) {\n const verified = p.verified ? ' ✓' : ''\n const featured = p.featured ? ' ⭐' : ''\n console.log(` ${p.icon || '📦'} ${p.displayName ?? p.name}${verified}${featured}`)\n console.log(` ${p.description}`)\n console.log(` ${p.category} | v${p.version} | npm: ${p.npm}`)\n console.log(` Install: openacp plugin install ${p.name}`)\n console.log()\n }\n } catch (err) {\n console.error(`Failed to search registry: ${err}`)\n process.exit(1)\n }\n}\n"],"mappings":";;;;;;AAEA,eAAsB,gBAAgB,MAA+B;AACnE,QAAM,QAAQ,KAAK,KAAK,GAAG,EAAE,KAAK;AAClC,MAAI,CAAC,OAAO;AACV,YAAQ,MAAM,sCAAsC;AACpD,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,SAAS,IAAI,eAAe;AAElC,MAAI;AACF,UAAM,UAAU,MAAM,OAAO,OAAO,KAAK;AAEzC,QAAI,QAAQ,WAAW,GAAG;AACxB,cAAQ,IAAI,8BAA8B,KAAK,GAAG;AAClD;AAAA,IACF;AAEA,YAAQ,IAAI;AAAA,QAAW,QAAQ,MAAM,UAAU,QAAQ,SAAS,IAAI,MAAM,EAAE,cAAc,KAAK;AAAA,CAAM;AACrG,eAAW,KAAK,SAAS;AACvB,YAAM,WAAW,EAAE,WAAW,YAAO;AACrC,YAAM,WAAW,EAAE,WAAW,YAAO;AACrC,cAAQ,IAAI,KAAK,EAAE,QAAQ,WAAI,IAAI,EAAE,eAAe,EAAE,IAAI,GAAG,QAAQ,GAAG,QAAQ,EAAE;AAClF,cAAQ,IAAI,QAAQ,EAAE,WAAW,EAAE;AACnC,cAAQ,IAAI,QAAQ,EAAE,QAAQ,OAAO,EAAE,OAAO,WAAW,EAAE,GAAG,EAAE;AAChE,cAAQ,IAAI,wCAAwC,EAAE,IAAI,EAAE;AAC5D,cAAQ,IAAI;AAAA,IACd;AAAA,EACF,SAAS,KAAK;AACZ,YAAQ,MAAM,8BAA8B,GAAG,EAAE;AACjD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;","names":[]}
@@ -29,7 +29,7 @@ async function runPostUpgradeChecks(config) {
29
29
  }
30
30
  }
31
31
  try {
32
- const { getIntegration } = await import("./integrate-5C6KSU6D.js");
32
+ const { getIntegration } = await import("./integrate-G6CVXTGT.js");
33
33
  const integration = getIntegration("claude");
34
34
  if (integration) {
35
35
  const allInstalled = integration.items.every((item) => item.isInstalled());
@@ -77,4 +77,4 @@ async function runPostUpgradeChecks(config) {
77
77
  export {
78
78
  runPostUpgradeChecks
79
79
  };
80
- //# sourceMappingURL=post-upgrade-XLHZ6ZB7.js.map
80
+ //# sourceMappingURL=post-upgrade-3ADZRMYJ.js.map
@@ -0,0 +1,8 @@
1
+ import {
2
+ RegistryClient
3
+ } from "./chunk-CDAUYTVP.js";
4
+ import "./chunk-VUNV25KB.js";
5
+ export {
6
+ RegistryClient
7
+ };
8
+ //# sourceMappingURL=registry-client-AVGRE4CF.js.map
@@ -1,6 +1,3 @@
1
- import {
2
- validateDiscordToken
3
- } from "./chunk-6RXVEXF3.js";
4
1
  import {
5
2
  validateBotAdmin,
6
3
  validateBotToken,
@@ -340,7 +337,7 @@ async function setupIntegrations(config) {
340
337
  );
341
338
  if (installClaude) {
342
339
  try {
343
- const { getIntegration } = await import("./integrate-5C6KSU6D.js");
340
+ const { getIntegration } = await import("./integrate-G6CVXTGT.js");
344
341
  const integration = getIntegration("claude");
345
342
  if (integration) {
346
343
  for (const item of integration.items) {
@@ -404,17 +401,29 @@ async function promptConfiguredAction(label) {
404
401
  );
405
402
  }
406
403
  async function configureViaPlugin(channelId) {
407
- const pluginMap = {
408
- telegram: { importPath: "../../plugins/telegram/index.js", name: "@openacp/telegram" },
409
- discord: { importPath: "../../plugins/discord/index.js", name: "@openacp/discord" }
404
+ const pluginImports = {
405
+ telegram: () => import("./telegram-2ZCCCZIY.js"),
406
+ discord: async () => {
407
+ const pkg = "@openacp/adapter-discord";
408
+ try {
409
+ return await import(
410
+ /* webpackIgnore: true */
411
+ pkg
412
+ );
413
+ } catch {
414
+ throw new Error(
415
+ `${pkg} is not installed. Run: openacp plugin add ${pkg}`
416
+ );
417
+ }
418
+ }
410
419
  };
411
- const pluginInfo = pluginMap[channelId];
412
- if (!pluginInfo) return;
420
+ const importer = pluginImports[channelId];
421
+ if (!importer) return;
413
422
  const { SettingsManager } = await import("./settings-manager-MD2U4ZV2.js");
414
423
  const { createInstallContext } = await import("./install-context-XPWTFT3J.js");
415
424
  const basePath = path.join(os.homedir(), ".openacp", "plugins");
416
425
  const settingsManager = new SettingsManager(basePath);
417
- const pluginModule = await import(pluginInfo.importPath);
426
+ const pluginModule = await importer();
418
427
  const plugin = pluginModule.default;
419
428
  if (plugin?.configure) {
420
429
  const ctx = createInstallContext({
@@ -489,25 +498,30 @@ async function runSetup(configManager, opts) {
489
498
  clack7.intro("Let's set up OpenACP");
490
499
  const { settingsManager, pluginRegistry } = opts ?? {};
491
500
  try {
492
- const channelChoice = guardCancel(
493
- await clack7.select({
494
- message: "Which messaging platform do you want to use?",
501
+ if (!settingsManager || !pluginRegistry) {
502
+ console.log(fail("Plugin system not initialized. Cannot set up channels."));
503
+ return false;
504
+ }
505
+ const channelChoices = guardCancel(
506
+ await clack7.multiselect({
507
+ message: "Which channels do you want to set up?",
495
508
  options: [
496
- { label: "Telegram", value: "telegram" },
497
- { label: "Discord", value: "discord" },
498
- { label: "Both", value: "both" }
499
- ]
509
+ { value: "telegram", label: "Telegram", hint: "built-in" },
510
+ { value: "discord", label: "Discord", hint: "will install @openacp/adapter-discord" }
511
+ ],
512
+ required: true,
513
+ initialValues: ["telegram"]
500
514
  })
501
515
  );
502
- const channelSteps = channelChoice === "both" ? 2 : 1;
516
+ const channelSteps = channelChoices.length;
503
517
  const runModeSteps = opts?.skipRunMode ? 0 : 1;
504
518
  const totalSteps = channelSteps + 1 + runModeSteps;
505
519
  let currentStep = 0;
506
- if (channelChoice === "telegram" || channelChoice === "both") {
520
+ const { createInstallContext } = await import("./install-context-XPWTFT3J.js");
521
+ for (const channelId of channelChoices) {
507
522
  currentStep++;
508
- if (settingsManager && pluginRegistry) {
509
- const { createInstallContext } = await import("./install-context-XPWTFT3J.js");
510
- const telegramPlugin = (await import("./telegram-ZDC3JQF2.js")).default;
523
+ if (channelId === "telegram") {
524
+ const telegramPlugin = (await import("./telegram-2ZCCCZIY.js")).default;
511
525
  const ctx = createInstallContext({
512
526
  pluginName: telegramPlugin.name,
513
527
  settingsManager,
@@ -521,32 +535,9 @@ async function runSetup(configManager, opts) {
521
535
  settingsPath: settingsManager.getSettingsPath(telegramPlugin.name),
522
536
  description: telegramPlugin.description
523
537
  });
524
- } else {
525
- console.log(fail("Plugin system not initialized. Cannot set up Telegram."));
526
- return false;
527
538
  }
528
- }
529
- if (channelChoice === "discord" || channelChoice === "both") {
530
- currentStep++;
531
- if (settingsManager && pluginRegistry) {
532
- const { createInstallContext } = await import("./install-context-XPWTFT3J.js");
533
- const discordPlugin = (await import("./discord-NOJQ5PZO.js")).default;
534
- const ctx = createInstallContext({
535
- pluginName: discordPlugin.name,
536
- settingsManager,
537
- basePath: settingsManager.getBasePath()
538
- });
539
- await discordPlugin.install(ctx);
540
- pluginRegistry.register(discordPlugin.name, {
541
- version: discordPlugin.version,
542
- source: "builtin",
543
- enabled: true,
544
- settingsPath: settingsManager.getSettingsPath(discordPlugin.name),
545
- description: discordPlugin.description
546
- });
547
- } else {
548
- console.log(fail("Plugin system not initialized. Cannot set up Discord."));
549
- return false;
539
+ if (channelId === "discord") {
540
+ await installAndSetupDiscord(settingsManager, pluginRegistry);
550
541
  }
551
542
  }
552
543
  const { defaultAgent } = await setupAgents();
@@ -633,6 +624,43 @@ async function runSetup(configManager, opts) {
633
624
  throw err;
634
625
  }
635
626
  }
627
+ async function installAndSetupDiscord(settingsManager, pluginRegistry) {
628
+ const packageName = "@openacp/adapter-discord";
629
+ let discordPlugin;
630
+ try {
631
+ discordPlugin = (await import(packageName)).default;
632
+ } catch {
633
+ const spinner3 = clack7.spinner();
634
+ spinner3.start(`Installing ${packageName}...`);
635
+ try {
636
+ const { installNpmPlugin } = await import("./plugin-installer-GQ2P3Q3E.js");
637
+ const pluginsDir = settingsManager.getBasePath();
638
+ const mod = await installNpmPlugin(packageName, pluginsDir);
639
+ discordPlugin = mod.default;
640
+ spinner3.stop(ok(`${packageName} installed`));
641
+ } catch (installErr) {
642
+ spinner3.stop(fail(`Failed to install ${packageName}: ${installErr.message}`));
643
+ console.log(fail("You can install it later with: openacp plugin add @openacp/adapter-discord"));
644
+ return;
645
+ }
646
+ }
647
+ const { createInstallContext } = await import("./install-context-XPWTFT3J.js");
648
+ const ctx = createInstallContext({
649
+ pluginName: discordPlugin.name,
650
+ settingsManager,
651
+ basePath: settingsManager.getBasePath()
652
+ });
653
+ if (discordPlugin.install) {
654
+ await discordPlugin.install(ctx);
655
+ }
656
+ pluginRegistry.register(discordPlugin.name, {
657
+ version: discordPlugin.version,
658
+ source: "npm",
659
+ enabled: true,
660
+ settingsPath: settingsManager.getSettingsPath(discordPlugin.name),
661
+ description: discordPlugin.description
662
+ });
663
+ }
636
664
  async function registerBuiltinPlugins(settingsManager, pluginRegistry) {
637
665
  const builtinPlugins = [
638
666
  { name: "@openacp/security", version: "1.0.0", description: "User access control and session limits" },
@@ -741,7 +769,6 @@ export {
741
769
  validateAgentCommand,
742
770
  validateBotAdmin,
743
771
  validateBotToken,
744
- validateChatId,
745
- validateDiscordToken
772
+ validateChatId
746
773
  };
747
- //# sourceMappingURL=setup-BAI2F24H.js.map
774
+ //# sourceMappingURL=setup-EYAFK2WI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/setup/wizard.ts","../../src/core/setup/types.ts","../../src/core/setup/helpers.ts","../../src/core/setup/setup-agents.ts","../../src/core/setup/setup-workspace.ts","../../src/core/setup/setup-run-mode.ts","../../src/core/setup/setup-integrations.ts","../../src/core/setup/setup-channels.ts"],"sourcesContent":["import * as clack from \"@clack/prompts\";\nimport type { Config, ConfigManager } from \"../config/config.js\";\nimport type { ChannelId } from \"./types.js\";\nimport type { OnboardSection } from \"./types.js\";\nimport { ONBOARD_SECTION_OPTIONS } from \"./types.js\";\nimport { guardCancel, ok, fail, printStartBanner, summarizeConfig } from \"./helpers.js\";\nimport { setupAgents } from \"./setup-agents.js\";\nimport { setupWorkspace } from \"./setup-workspace.js\";\nimport { setupRunMode } from \"./setup-run-mode.js\";\nimport { setupIntegrations } from \"./setup-integrations.js\";\nimport { configureChannels } from \"./setup-channels.js\";\nimport type { SettingsManager } from \"../plugin/settings-manager.js\";\nimport type { PluginRegistry } from \"../plugin/plugin-registry.js\";\n\n// ─── First-run setup ───\n\nexport async function runSetup(\n configManager: ConfigManager,\n opts?: { skipRunMode?: boolean; settingsManager?: SettingsManager; pluginRegistry?: PluginRegistry },\n): Promise<boolean> {\n await printStartBanner();\n clack.intro(\"Let's set up OpenACP\");\n\n const { settingsManager, pluginRegistry } = opts ?? {};\n\n try {\n if (!settingsManager || !pluginRegistry) {\n console.log(fail('Plugin system not initialized. Cannot set up channels.'));\n return false;\n }\n\n // Ask user which channels to set up\n const channelChoices = guardCancel(\n await clack.multiselect({\n message: 'Which channels do you want to set up?',\n options: [\n { value: 'telegram' as const, label: 'Telegram', hint: 'built-in' },\n { value: 'discord' as const, label: 'Discord', hint: 'will install @openacp/adapter-discord' },\n ],\n required: true,\n initialValues: ['telegram' as const],\n }),\n ) as ChannelId[];\n\n // Calculate total steps dynamically: channel(s) + workspace + run mode\n const channelSteps = channelChoices.length;\n const runModeSteps = opts?.skipRunMode ? 0 : 1;\n const totalSteps = channelSteps + 1 + runModeSteps; // + workspace + optional run mode\n\n let currentStep = 0;\n\n const { createInstallContext } = await import('../plugin/install-context.js');\n\n for (const channelId of channelChoices) {\n currentStep++;\n\n if (channelId === 'telegram') {\n const telegramPlugin = (await import('../../plugins/telegram/index.js')).default;\n const ctx = createInstallContext({\n pluginName: telegramPlugin.name,\n settingsManager,\n basePath: settingsManager.getBasePath(),\n });\n await telegramPlugin.install!(ctx);\n pluginRegistry.register(telegramPlugin.name, {\n version: telegramPlugin.version,\n source: 'builtin',\n enabled: true,\n settingsPath: settingsManager.getSettingsPath(telegramPlugin.name),\n description: telegramPlugin.description,\n });\n }\n\n if (channelId === 'discord') {\n await installAndSetupDiscord(settingsManager, pluginRegistry);\n }\n }\n\n const { defaultAgent } = await setupAgents();\n\n // Offer Claude CLI integration\n await setupIntegrations();\n\n currentStep++;\n const workspace = await setupWorkspace({ stepNum: currentStep, totalSteps });\n\n let runMode: 'foreground' | 'daemon' = 'foreground';\n let autoStart = false;\n if (!opts?.skipRunMode) {\n currentStep++;\n const result = await setupRunMode({ stepNum: currentStep, totalSteps });\n runMode = result.runMode;\n autoStart = result.autoStart;\n }\n\n const security = {\n allowedUserIds: [] as string[],\n maxConcurrentSessions: 20,\n sessionTimeoutMinutes: 60,\n };\n\n const config: Config = {\n channels: {},\n agents: {},\n defaultAgent,\n workspace,\n security,\n logging: {\n level: \"info\",\n logDir: \"~/.openacp/logs\",\n maxFileSize: \"10m\",\n maxFiles: 7,\n sessionLogRetentionDays: 30,\n },\n runMode,\n autoStart,\n api: {\n port: 21420,\n host: '127.0.0.1',\n },\n sessionStore: { ttlDays: 30 },\n tunnel: {\n enabled: true,\n port: 3100,\n provider: \"cloudflare\",\n options: {},\n maxUserTunnels: 5,\n storeTtlMinutes: 60,\n auth: { enabled: false },\n },\n usage: {\n enabled: true,\n warningThreshold: 0.8,\n currency: \"USD\",\n retentionDays: 90,\n },\n integrations: {},\n speech: {\n stt: { provider: null, providers: {} },\n tts: { provider: null, providers: {} },\n },\n };\n\n try {\n await configManager.writeNew(config);\n } catch (writeErr) {\n console.log(\n fail(`Could not save config: ${(writeErr as Error).message}`),\n );\n return false;\n }\n\n // Auto-register remaining built-in plugins in the registry\n if (settingsManager && pluginRegistry) {\n await registerBuiltinPlugins(settingsManager, pluginRegistry);\n await pluginRegistry.save();\n }\n\n clack.outro(`Config saved to ${configManager.getConfigPath()}`);\n\n if (!opts?.skipRunMode) {\n console.log(ok(\"Starting OpenACP...\"));\n console.log(\"\");\n }\n\n return true;\n } catch (err) {\n if ((err as Error).name === \"ExitPromptError\") {\n clack.cancel(\"Setup cancelled.\");\n return false;\n }\n throw err;\n }\n}\n\n/**\n * Install @openacp/adapter-discord from npm if needed, then run its install() hook.\n */\nasync function installAndSetupDiscord(\n settingsManager: SettingsManager,\n pluginRegistry: PluginRegistry,\n): Promise<void> {\n const packageName = '@openacp/adapter-discord';\n\n // Try to import first — if not installed, install it\n let discordPlugin: any;\n try {\n discordPlugin = (await import(packageName)).default;\n } catch {\n const spinner = clack.spinner();\n spinner.start(`Installing ${packageName}...`);\n try {\n const { installNpmPlugin } = await import('../plugin/plugin-installer.js');\n const pluginsDir = settingsManager.getBasePath();\n const mod = await installNpmPlugin(packageName, pluginsDir);\n discordPlugin = mod.default;\n spinner.stop(ok(`${packageName} installed`));\n } catch (installErr) {\n spinner.stop(fail(`Failed to install ${packageName}: ${(installErr as Error).message}`));\n console.log(fail('You can install it later with: openacp plugin add @openacp/adapter-discord'));\n return;\n }\n }\n\n const { createInstallContext } = await import('../plugin/install-context.js');\n const ctx = createInstallContext({\n pluginName: discordPlugin.name,\n settingsManager,\n basePath: settingsManager.getBasePath(),\n });\n\n if (discordPlugin.install) {\n await discordPlugin.install(ctx);\n }\n\n pluginRegistry.register(discordPlugin.name, {\n version: discordPlugin.version,\n source: 'npm',\n enabled: true,\n settingsPath: settingsManager.getSettingsPath(discordPlugin.name),\n description: discordPlugin.description,\n });\n}\n\n/**\n * Register all built-in plugins that haven't been registered yet.\n * Called after first-run setup to populate the registry with defaults.\n */\nasync function registerBuiltinPlugins(\n settingsManager: SettingsManager,\n pluginRegistry: PluginRegistry,\n): Promise<void> {\n const builtinPlugins = [\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/usage', version: '1.0.0', description: 'Token usage tracking and budget enforcement' },\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 ];\n\n for (const p of builtinPlugins) {\n if (!pluginRegistry.get(p.name)) {\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 }\n}\n\n// ─── Reconfigure (section-based, for existing config) ───\n\ntype ReconfigureSection = OnboardSection | \"__continue\";\n\nasync function selectSection(hasSelection: boolean): Promise<ReconfigureSection> {\n return guardCancel(\n await clack.select({\n message: \"Select sections to configure\",\n options: [\n ...ONBOARD_SECTION_OPTIONS,\n {\n value: \"__continue\" as const,\n label: \"Continue\",\n hint: hasSelection ? \"Done\" : \"Skip for now\",\n },\n ],\n initialValue: ONBOARD_SECTION_OPTIONS[0].value,\n }),\n ) as ReconfigureSection;\n}\n\nexport async function runReconfigure(configManager: ConfigManager): Promise<void> {\n await printStartBanner();\n clack.intro(\"OpenACP — Reconfigure\");\n\n try {\n await configManager.load();\n let config = configManager.get();\n\n // Show current config summary\n clack.note(summarizeConfig(config), \"Current configuration\");\n\n let ranSection = false;\n\n while (true) {\n const choice = await selectSection(ranSection);\n if (choice === \"__continue\") break;\n ranSection = true;\n\n if (choice === \"channels\") {\n const result = await configureChannels(config);\n if (result.changed) {\n // IMPORTANT: Use writeNew() instead of save() because save() uses deepMerge\n // which cannot delete keys. Channel deletion (delete next.channels.telegram)\n // would be silently ignored by deepMerge. writeNew() overwrites the full config.\n config = { ...config, channels: result.config.channels };\n await configManager.writeNew(config);\n }\n }\n\n if (choice === \"agents\") {\n const { defaultAgent } = await setupAgents();\n await configManager.save({ defaultAgent });\n config = configManager.get();\n }\n\n if (choice === \"workspace\") {\n const { baseDir } = await setupWorkspace({\n existing: config.workspace.baseDir,\n });\n await configManager.save({ workspace: { baseDir } });\n config = configManager.get();\n }\n\n if (choice === \"runMode\") {\n const result = await setupRunMode({\n existing: { runMode: config.runMode, autoStart: config.autoStart },\n });\n await configManager.save({\n runMode: result.runMode,\n autoStart: result.autoStart,\n });\n config = configManager.get();\n }\n\n if (choice === \"integrations\") {\n await setupIntegrations(config);\n }\n }\n\n if (!ranSection) {\n clack.outro(\"No changes made.\");\n return;\n }\n\n clack.outro(`Config saved to ${configManager.getConfigPath()}`);\n } catch (err) {\n if ((err as Error).name === \"ExitPromptError\") {\n clack.cancel(\"Setup cancelled.\");\n return;\n }\n throw err;\n }\n}\n","export type OnboardSection =\n | \"channels\"\n | \"agents\"\n | \"workspace\"\n | \"runMode\"\n | \"integrations\";\n\nexport type ConfiguredChannelAction = \"modify\" | \"disable\" | \"delete\" | \"skip\";\n\nexport type ChannelId = string;\n\nexport type ChannelStatus = {\n id: ChannelId;\n label: string;\n configured: boolean;\n enabled: boolean;\n hint?: string;\n};\n\nexport const ONBOARD_SECTION_OPTIONS: Array<{\n value: OnboardSection;\n label: string;\n hint: string;\n}> = [\n { value: \"channels\", label: \"Channels\", hint: \"Link/update messaging platforms\" },\n { value: \"agents\", label: \"Agents\", hint: \"Install agents, change default\" },\n { value: \"workspace\", label: \"Workspace\", hint: \"Set workspace directory\" },\n { value: \"runMode\", label: \"Run mode\", hint: \"Foreground/daemon, auto-start\" },\n { value: \"integrations\", label: \"Integrations\", hint: \"Claude CLI session transfer\" },\n];\n\nexport const CHANNEL_META: Record<string, { label: string; method: string }> = {\n telegram: { label: \"Telegram\", method: \"Bot API\" },\n discord: { label: \"Discord\", method: \"Bot API\" },\n};\n\n","import * as clack from \"@clack/prompts\";\nimport type { Config } from \"../config/config.js\";\n\n// --- ANSI colors ---\n\nexport const c = {\n reset: \"\\x1b[0m\",\n bold: \"\\x1b[1m\",\n dim: \"\\x1b[2m\",\n green: \"\\x1b[32m\",\n yellow: \"\\x1b[33m\",\n red: \"\\x1b[31m\",\n cyan: \"\\x1b[36m\",\n white: \"\\x1b[37m\",\n};\n\nexport const ok = (msg: string) =>\n `${c.green}${c.bold}✓${c.reset} ${c.green}${msg}${c.reset}`;\nexport const warn = (msg: string) => `${c.yellow}⚠ ${msg}${c.reset}`;\nexport const fail = (msg: string) => `${c.red}✗ ${msg}${c.reset}`;\nexport const step = (n: number, total: number, title: string) =>\n `\\n${c.cyan}${c.bold}[${n}/${total}]${c.reset} ${c.bold}${title}${c.reset}\\n`;\nexport const dim = (msg: string) => `${c.dim}${msg}${c.reset}`;\n\nexport function guardCancel<T>(value: T | symbol): T {\n if (clack.isCancel(value)) {\n clack.cancel(\"Setup cancelled.\");\n process.exit(0);\n }\n return value as T;\n}\n\n// --- Banner ---\n\nfunction applyGradient(text: string): string {\n const colors = [135, 99, 63, 33, 39, 44, 44];\n const lines = text.split(\"\\n\");\n return lines\n .map((line, i) => {\n const colorIdx = Math.min(i, colors.length - 1);\n return `\\x1b[38;5;${colors[colorIdx]}m${line}\\x1b[0m`;\n })\n .join(\"\\n\");\n}\n\nconst BANNER = `\n ██████╗ ██████╗ ███████╗███╗ ██╗ █████╗ ██████╗██████╗\n ██╔═══██╗██╔══██╗██╔════╝████╗ ██║██╔══██╗██╔════╝██╔══██╗\n ██║ ██║██████╔╝█████╗ ██╔██╗ ██║███████║██║ ██████╔╝\n ██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║██╔══██║██║ ██╔═══╝\n ╚██████╔╝██║ ███████╗██║ ╚████║██║ ██║╚██████╗██║\n ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═════╝╚═╝\n`;\n\nexport async function printStartBanner(): Promise<void> {\n let version = \"0.0.0\";\n try {\n const { getCurrentVersion } = await import(\"../../cli/version.js\");\n version = getCurrentVersion();\n } catch {\n // ignore\n }\n console.log(applyGradient(BANNER));\n console.log(`${c.dim} AI coding agents, anywhere. v${version}${c.reset}\\n`);\n}\n\n// --- Config summary ---\n\nexport function summarizeConfig(config: Config): string {\n const lines: string[] = [];\n\n // Channels\n const channelStatuses: string[] = [];\n for (const [id, meta] of Object.entries({\n telegram: \"Telegram\",\n discord: \"Discord\",\n })) {\n const ch = config.channels[id] as { enabled?: boolean } | undefined;\n if (ch?.enabled) {\n channelStatuses.push(`${meta} (enabled)`);\n } else if (ch && Object.keys(ch).length > 1) {\n channelStatuses.push(`${meta} (disabled)`);\n } else {\n channelStatuses.push(`${meta} (not configured)`);\n }\n }\n lines.push(`Channels: ${channelStatuses.join(\", \")}`);\n\n // Default agent\n lines.push(`Default agent: ${config.defaultAgent}`);\n\n // Workspace\n lines.push(`Workspace: ${config.workspace.baseDir}`);\n\n // Run mode\n lines.push(`Run mode: ${config.runMode}${config.autoStart ? \" (auto-start)\" : \"\"}`);\n\n return lines.join(\"\\n\");\n}\n","import { execFileSync } from \"node:child_process\";\nimport * as clack from \"@clack/prompts\";\nimport { commandExists } from \"../agents/agent-dependencies.js\";\nimport { guardCancel, ok, warn, c } from \"./helpers.js\";\n\nconst KNOWN_AGENTS: Array<{ name: string; commands: string[] }> = [\n // claude-agent-acp is bundled as a dependency — no detection needed, but\n // kept here so detectAgents() still returns it for display purposes.\n { name: \"claude\", commands: [\"claude-agent-acp\"] },\n { name: \"codex\", commands: [\"codex\"] },\n];\n\nexport async function detectAgents(): Promise<\n Array<{ name: string; command: string }>\n> {\n const found: Array<{ name: string; command: string }> = [];\n for (const agent of KNOWN_AGENTS) {\n // Find all available commands for this agent (PATH + node_modules/.bin)\n const available: string[] = [];\n for (const cmd of agent.commands) {\n if (commandExists(cmd)) {\n available.push(cmd);\n }\n }\n if (available.length > 0) {\n // Prefer claude-agent-acp over claude/claude-code (priority order)\n found.push({ name: agent.name, command: available[0] });\n }\n }\n return found;\n}\n\nexport async function validateAgentCommand(command: string): Promise<boolean> {\n try {\n execFileSync(\"which\", [command], { stdio: \"pipe\" });\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function setupAgents(): Promise<{\n defaultAgent: string;\n}> {\n const { AgentCatalog } = await import(\"../agents/agent-catalog.js\");\n const { muteLogger, unmuteLogger } = await import(\"../utils/log.js\");\n\n muteLogger();\n const catalog = new AgentCatalog();\n catalog.load();\n\n const s = clack.spinner();\n s.start(\"Checking available agents...\");\n await catalog.refreshRegistryIfStale();\n\n // Claude is always pre-installed (bundled dependency)\n if (!catalog.getInstalledAgent(\"claude\")) {\n const claudeRegistry = catalog.findRegistryAgent(\"claude-acp\");\n if (claudeRegistry) {\n await catalog.install(\"claude-acp\");\n } else {\n // Fallback: register bundled claude-agent-acp directly\n const { AgentStore } = await import(\"../agents/agent-store.js\");\n const store = new AgentStore();\n store.load();\n store.addAgent(\"claude\", {\n registryId: \"claude-acp\",\n name: \"Claude Agent\",\n version: \"bundled\",\n distribution: \"npx\",\n command: \"npx\",\n args: [\"@zed-industries/claude-agent-acp\"],\n env: {},\n installedAt: new Date().toISOString(),\n binaryPath: null,\n });\n }\n }\n s.stop(ok(\"Claude Agent ready\"));\n unmuteLogger();\n\n const available = catalog.getAvailable();\n const installed = available.filter((a) => a.installed);\n const installable = available.filter((a) => !a.installed && a.available);\n\n // Offer agent selection — show installed agents as pre-checked + installable agents\n if (installed.length > 0 || installable.length > 0) {\n // Deduplicate by key AND name\n const seen = new Set<string>();\n const options: Array<{ label: string; value: string }> = [];\n\n for (const a of installed) {\n const dedupeKey = `${a.key}::${a.name}`;\n if (seen.has(dedupeKey)) continue;\n seen.add(dedupeKey);\n options.push({\n label: `${a.name} (installed)`,\n value: a.key,\n });\n }\n for (const a of installable) {\n const dedupeKey = `${a.key}::${a.name}`;\n if (seen.has(dedupeKey)) continue;\n seen.add(dedupeKey);\n options.push({\n label: `${a.name} (${a.distribution})`,\n value: a.key,\n });\n }\n\n const installedKeys = installed.map(a => a.key);\n const selected = guardCancel(\n await clack.autocompleteMultiselect({\n message: \"Install additional agents? (type to search, Space to select)\",\n options,\n initialValues: installedKeys,\n required: false,\n }),\n ) as string[];\n\n for (const key of selected) {\n const regAgent = catalog.findRegistryAgent(key);\n if (regAgent) {\n const installSpinner = clack.spinner();\n installSpinner.start(`Installing ${regAgent.name}...`);\n muteLogger();\n const result = await catalog.install(key);\n unmuteLogger();\n if (result.ok) {\n installSpinner.stop(ok(\"done\"));\n } else {\n installSpinner.stop(warn(`skipped: ${result.error}`));\n }\n }\n }\n }\n\n // Choose default agent\n const installedAgents = Object.keys(catalog.getInstalledEntries());\n let defaultAgent = \"claude\";\n\n if (installedAgents.length > 1) {\n defaultAgent = guardCancel(\n await clack.select({\n message: \"Which agent should be the default?\",\n options: installedAgents.map((key) => {\n const agent = catalog.getInstalledAgent(key)!;\n return { label: `${agent.name} (${key})`, value: key };\n }),\n initialValue: \"claude\",\n }),\n ) as string;\n }\n\n console.log(ok(`Default agent: ${c.bold}${defaultAgent}${c.reset}`));\n return { defaultAgent };\n}\n","import * as clack from \"@clack/prompts\";\nimport { guardCancel, step } from \"./helpers.js\";\n\nexport async function setupWorkspace(opts?: {\n existing?: string;\n stepNum?: number;\n totalSteps?: number;\n}): Promise<{ baseDir: string }> {\n const { existing, stepNum, totalSteps } = opts ?? {};\n if (stepNum != null && totalSteps != null) {\n console.log(step(stepNum, totalSteps, \"Workspace\"));\n }\n\n const baseDir = guardCancel(\n await clack.text({\n message: \"Base directory for workspaces:\",\n initialValue: existing ?? \"~/openacp-workspace\",\n validate: (val) =>\n (val ?? \"\").toString().trim().length > 0 ? undefined : \"Path cannot be empty\",\n }),\n ) as string;\n\n return { baseDir: baseDir.trim().replace(/^['\"]|['\"]$/g, \"\") };\n}\n","import * as clack from \"@clack/prompts\";\nimport { expandHome } from \"../config/config.js\";\nimport { guardCancel, ok, warn, dim, step } from \"./helpers.js\";\n\nexport async function setupRunMode(opts?: {\n existing?: { runMode: string; autoStart: boolean };\n stepNum?: number;\n totalSteps?: number;\n}): Promise<{ runMode: 'foreground' | 'daemon'; autoStart: boolean }> {\n const { existing, stepNum, totalSteps } = opts ?? {};\n if (stepNum != null && totalSteps != null) {\n console.log(step(stepNum, totalSteps, 'Run Mode'));\n }\n\n // Don't show daemon option on Windows\n if (process.platform === 'win32') {\n console.log(dim(' (Daemon mode not available on Windows)'));\n return { runMode: 'foreground', autoStart: false };\n }\n\n const initialValue = (existing?.runMode === 'daemon' ? 'daemon' : 'foreground') as 'foreground' | 'daemon';\n\n const mode = guardCancel(\n await clack.select({\n message: 'How would you like to run OpenACP?',\n options: [\n {\n label: 'Background (daemon)',\n value: 'daemon' as const,\n hint: 'Runs silently, auto-starts on boot. Manage with: openacp status | stop | logs',\n },\n {\n label: 'Foreground (terminal)',\n value: 'foreground' as const,\n hint: 'Runs in current terminal session. Start with: openacp',\n },\n ],\n initialValue,\n }),\n );\n\n const wasDaemon = existing?.runMode === 'daemon';\n\n if (mode === 'daemon') {\n const { installAutoStart, isAutoStartSupported } = await import('../../cli/autostart.js');\n const { muteLogger, unmuteLogger } = await import('../utils/log.js');\n const autoStart = isAutoStartSupported();\n if (autoStart) {\n muteLogger();\n const result = installAutoStart(expandHome('~/.openacp/logs'));\n unmuteLogger();\n if (result.success) {\n console.log(ok('Auto-start on boot enabled'));\n } else {\n console.log(warn(`Auto-start failed: ${result.error}`));\n }\n }\n return { runMode: 'daemon', autoStart };\n }\n\n // Switching from daemon → foreground: stop daemon + uninstall autostart\n if (wasDaemon) {\n const { muteLogger, unmuteLogger } = await import('../utils/log.js');\n muteLogger();\n try {\n const { stopDaemon } = await import('../../cli/daemon.js');\n const result = await stopDaemon();\n unmuteLogger();\n if (result.stopped) {\n console.log(ok(`Daemon stopped (was PID ${result.pid})`));\n }\n } catch {\n unmuteLogger();\n // Daemon may not be running\n }\n muteLogger();\n try {\n const { uninstallAutoStart } = await import('../../cli/autostart.js');\n uninstallAutoStart();\n unmuteLogger();\n } catch {\n unmuteLogger();\n // ignore\n }\n }\n\n return { runMode: 'foreground', autoStart: false };\n}\n","import * as clack from \"@clack/prompts\";\nimport type { Config } from \"../config/config.js\";\nimport { guardCancel } from \"./helpers.js\";\n\nexport async function setupIntegrations(config?: Config): Promise<void> {\n const claudeIntegration = (config?.integrations as Record<string, unknown> | undefined)?.claude as { installed?: boolean } | undefined;\n const isInstalled = claudeIntegration?.installed === true;\n\n const installClaude = guardCancel(\n await clack.confirm({\n message: isInstalled\n ? \"Claude CLI integration is installed. Reinstall?\"\n : \"Install session transfer for Claude? (enables /openacp:handoff in your terminal)\",\n initialValue: !isInstalled,\n }),\n );\n\n if (installClaude) {\n try {\n const { getIntegration } = await import(\"../../cli/integrate.js\");\n const integration = getIntegration(\"claude\");\n if (integration) {\n for (const item of integration.items) {\n const result = await item.install();\n for (const log of result.logs) console.log(` ${log}`);\n }\n }\n console.log(\"Claude CLI integration installed.\\n\");\n } catch (err) {\n console.log(`Could not install Claude CLI integration: ${err instanceof Error ? err.message : err}`);\n console.log(\" You can install it later with: openacp integrate claude\\n\");\n }\n }\n}\n","import * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport * as clack from \"@clack/prompts\";\nimport type { Config } from \"../config/config.js\";\nimport type { ConfiguredChannelAction, ChannelId, ChannelStatus } from \"./types.js\";\nimport { CHANNEL_META } from \"./types.js\";\nimport { guardCancel, ok, c } from \"./helpers.js\";\n\nexport function getChannelStatuses(config: Config): ChannelStatus[] {\n const statuses: ChannelStatus[] = [];\n\n for (const [id, meta] of Object.entries(CHANNEL_META) as [ChannelId, typeof CHANNEL_META[ChannelId]][]) {\n const ch = config.channels[id] as Record<string, unknown> | undefined;\n const enabled = ch?.enabled === true;\n const configured = !!ch && Object.keys(ch).length > 1;\n\n let hint: string | undefined;\n if (id === \"telegram\" && ch?.botToken && typeof ch.botToken === \"string\" && ch.botToken !== \"YOUR_BOT_TOKEN_HERE\") {\n hint = `Chat ID: ${ch.chatId}`;\n }\n if (id === \"discord\" && ch?.guildId) {\n hint = `Guild: ${ch.guildId}`;\n }\n\n statuses.push({ id, label: meta.label, configured, enabled, hint });\n }\n\n return statuses;\n}\n\nexport function noteChannelStatus(config: Config): void {\n const statuses = getChannelStatuses(config);\n const lines = statuses.map((s) => {\n const status = s.enabled ? \"enabled\" : s.configured ? \"disabled\" : \"not configured\";\n const hintStr = s.hint ? ` — ${s.hint}` : \"\";\n return ` ${s.label}: ${status}${hintStr}`;\n });\n\n console.log(\"\");\n console.log(`${c.bold} Channel status${c.reset}`);\n for (const line of lines) console.log(line);\n console.log(\"\");\n}\n\nasync function promptConfiguredAction(label: string): Promise<ConfiguredChannelAction> {\n return guardCancel(\n await clack.select({\n message: `${label} already configured. What do you want to do?`,\n options: [\n { value: \"modify\" as const, label: \"Modify settings\" },\n { value: \"disable\" as const, label: \"Disable bot\" },\n { value: \"delete\" as const, label: \"Delete config\" },\n { value: \"skip\" as const, label: \"Skip (leave as-is)\" },\n ],\n initialValue: \"modify\" as const,\n }),\n );\n}\n\nasync function configureViaPlugin(channelId: ChannelId): Promise<void> {\n const pluginImports: Record<ChannelId, () => Promise<any>> = {\n telegram: () => import('../../plugins/telegram/index.js'),\n discord: async () => {\n const pkg = '@openacp/adapter-discord';\n try {\n return await import(/* webpackIgnore: true */ pkg);\n } catch {\n throw new Error(\n `${pkg} is not installed. Run: openacp plugin add ${pkg}`,\n );\n }\n },\n };\n\n const importer = pluginImports[channelId];\n if (!importer) return;\n\n const { SettingsManager } = await import('../plugin/settings-manager.js');\n const { createInstallContext } = await import('../plugin/install-context.js');\n const basePath = path.join(os.homedir(), '.openacp', 'plugins');\n const settingsManager = new SettingsManager(basePath);\n\n const pluginModule = await importer();\n const plugin = pluginModule.default;\n\n if (plugin?.configure) {\n const ctx = createInstallContext({\n pluginName: plugin.name,\n settingsManager,\n basePath,\n });\n await plugin.configure(ctx);\n }\n}\n\nexport async function configureChannels(config: Config): Promise<{ config: Config; changed: boolean }> {\n const next = structuredClone(config);\n let changed = false;\n\n noteChannelStatus(next);\n\n while (true) {\n const statuses = getChannelStatuses(next);\n const options = statuses.map((s) => {\n const status = s.enabled ? \"enabled\" : s.configured ? \"disabled\" : \"not configured\";\n return {\n value: s.id,\n label: `${s.label} (${CHANNEL_META[s.id].method})`,\n hint: status + (s.hint ? ` · ${s.hint}` : \"\"),\n };\n });\n\n const choice = guardCancel(\n await clack.select({\n message: \"Select a channel\",\n options: [\n ...options,\n { value: \"__done__\" as const, label: \"Finished\" },\n ],\n }),\n );\n\n if (choice === \"__done__\") break;\n\n const channelId = choice as ChannelId;\n const meta = CHANNEL_META[channelId];\n const existing = next.channels[channelId] as Record<string, unknown> | undefined;\n const isConfigured = !!existing && Object.keys(existing).length > 1;\n\n if (isConfigured) {\n const action = await promptConfiguredAction(meta.label);\n\n if (action === \"skip\") continue;\n if (action === \"disable\") {\n (next.channels[channelId] as Record<string, unknown>).enabled = false;\n changed = true;\n console.log(ok(`${meta.label} disabled`));\n continue;\n }\n if (action === \"delete\") {\n const confirmed = guardCancel(\n await clack.confirm({\n message: `Delete ${meta.label} config? This cannot be undone.`,\n initialValue: false,\n }),\n );\n if (confirmed) {\n delete next.channels[channelId];\n changed = true;\n console.log(ok(`${meta.label} config deleted`));\n }\n continue;\n }\n // action === \"modify\" — fall through to plugin configure\n }\n\n // Run channel configuration via plugin configure()\n await configureViaPlugin(channelId);\n changed = true;\n }\n\n return { config: next, changed };\n}\n"],"mappings":"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","names":["clack","text","clack","clack","clack","clack","clack","spinner"]}
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  slack_default
3
- } from "./chunk-UB2QB6DE.js";
3
+ } from "./chunk-3ASUU6WW.js";
4
4
  import "./chunk-VUNV25KB.js";
5
5
  export {
6
6
  slack_default as default
7
7
  };
8
- //# sourceMappingURL=slack-KH7E3VBS.js.map
8
+ //# sourceMappingURL=slack-37ZWBDUI.js.map
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  telegram_default
3
- } from "./chunk-Y64XWMJ4.js";
3
+ } from "./chunk-36YQ44D7.js";
4
4
  import "./chunk-VUNV25KB.js";
5
5
  export {
6
6
  telegram_default as default
7
7
  };
8
- //# sourceMappingURL=telegram-ZDC3JQF2.js.map
8
+ //# sourceMappingURL=telegram-2ZCCCZIY.js.map
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  tunnel_default
3
- } from "./chunk-P4SNGQNI.js";
3
+ } from "./chunk-KMMEFXIE.js";
4
4
  import "./chunk-VUNV25KB.js";
5
5
  export {
6
6
  tunnel_default as default
7
7
  };
8
- //# sourceMappingURL=tunnel-M47I7H4B.js.map
8
+ //# sourceMappingURL=tunnel-45HA72MB.js.map
@@ -523,6 +523,7 @@ var TunnelRegistry = class {
523
523
  };
524
524
 
525
525
  // src/plugins/tunnel/viewer-store.ts
526
+ import * as fs3 from "fs";
526
527
  import * as path3 from "path";
527
528
  import { nanoid } from "nanoid";
528
529
  var log6 = createChildLogger({ module: "viewer-store" });
@@ -646,8 +647,15 @@ var ViewerStore = class {
646
647
  }
647
648
  }
648
649
  isPathAllowed(filePath, workingDirectory) {
649
- const resolved = path3.resolve(workingDirectory, filePath);
650
- return resolved.startsWith(path3.resolve(workingDirectory));
650
+ try {
651
+ const resolved = fs3.realpathSync(path3.resolve(workingDirectory, filePath));
652
+ const workspace = fs3.realpathSync(path3.resolve(workingDirectory));
653
+ return resolved.startsWith(workspace + path3.sep) || resolved === workspace;
654
+ } catch {
655
+ const resolved = path3.resolve(workingDirectory, filePath);
656
+ const workspace = path3.resolve(workingDirectory);
657
+ return resolved.startsWith(workspace + path3.sep) || resolved === workspace;
658
+ }
651
659
  }
652
660
  detectLanguage(filePath) {
653
661
  const ext = path3.extname(filePath).toLowerCase();
@@ -1171,4 +1179,4 @@ var TunnelService = class {
1171
1179
  export {
1172
1180
  TunnelService
1173
1181
  };
1174
- //# sourceMappingURL=tunnel-service-WADYHREX.js.map
1182
+ //# sourceMappingURL=tunnel-service-QJPUYEKU.js.map