@openacp/cli 0.6.9 → 2026.326.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.
- package/README.md +100 -154
- package/dist/{action-detect-P7ZE4NEM.js → action-detect-QPA775HB.js} +2 -2
- package/dist/adapter-6ANPBSVU.js +16 -0
- package/dist/{discord-7IVQKB2H.js → adapter-77ZCVABT.js} +659 -348
- package/dist/adapter-77ZCVABT.js.map +1 -0
- package/dist/{adapter-LNEGLMOE.js → adapter-PQGHVG4K.js} +300 -93
- package/dist/adapter-PQGHVG4K.js.map +1 -0
- package/dist/{admin-6SYB6XCZ.js → admin-GBPZFFAU.js} +3 -3
- package/dist/agent-catalog-YHBFERYO.js +11 -0
- package/dist/{agent-dependencies-4OWBMZWZ.js → agent-dependencies-WS7Z2DFW.js} +2 -2
- package/dist/agent-registry-5LZT7CUB.js +9 -0
- package/dist/agent-store-VSHNY5GT.js +9 -0
- package/dist/{agents-QO7DKARJ.js → agents-BWU4MRRD.js} +3 -3
- package/dist/{api-client-CFQT5U7D.js → api-client-AQPNKXI2.js} +2 -2
- package/dist/api-server-3PYLRBCN.js +8 -0
- package/dist/api-server-CHVSUDBX.js +11 -0
- package/dist/{autostart-X33OGMX6.js → autostart-6JS565RY.js} +3 -3
- package/dist/chunk-2CX4IEEC.js +124 -0
- package/dist/chunk-2CX4IEEC.js.map +1 -0
- package/dist/{chunk-O7CPGUAI.js → chunk-4KGLKKQK.js} +4 -4
- package/dist/chunk-4KGLKKQK.js.map +1 -0
- package/dist/{chunk-W3EYKZNQ.js → chunk-4WXALZA3.js} +2 -2
- package/dist/chunk-4WXALZA3.js.map +1 -0
- package/dist/chunk-5OCGO27U.js +125 -0
- package/dist/chunk-5OCGO27U.js.map +1 -0
- package/dist/{chunk-JUYDFUSN.js → chunk-5ZOFBTOR.js} +117 -237
- package/dist/chunk-5ZOFBTOR.js.map +1 -0
- package/dist/chunk-6RXVEXF3.js +23 -0
- package/dist/chunk-6RXVEXF3.js.map +1 -0
- package/dist/{chunk-34M4OS5P.js → chunk-A6Y4GZM3.js} +3 -3
- package/dist/chunk-A6Y4GZM3.js.map +1 -0
- package/dist/chunk-AD3X6DGK.js +166 -0
- package/dist/chunk-AD3X6DGK.js.map +1 -0
- package/dist/{chunk-7QJS2XBD.js → chunk-AFKX424Q.js} +2 -2
- package/dist/chunk-AFKX424Q.js.map +1 -0
- package/dist/chunk-APS6UEFU.js +259 -0
- package/dist/chunk-APS6UEFU.js.map +1 -0
- package/dist/chunk-BLQUXO7S.js +113 -0
- package/dist/chunk-BLQUXO7S.js.map +1 -0
- package/dist/{chunk-WTZDAYZX.js → chunk-BQ6FR32N.js} +3 -3
- package/dist/chunk-BQ6FR32N.js.map +1 -0
- package/dist/chunk-FNRSWA2K.js +1 -0
- package/dist/chunk-FQEBWOZR.js +3557 -0
- package/dist/chunk-FQEBWOZR.js.map +1 -0
- package/dist/{chunk-4CTX774K.js → chunk-GJOY37U7.js} +4 -4
- package/dist/chunk-GJOY37U7.js.map +1 -0
- package/dist/{chunk-I7WC6E5S.js → chunk-HVBNCPAY.js} +2 -2
- package/dist/chunk-HVBNCPAY.js.map +1 -0
- package/dist/{chunk-2HMQOC7N.js → chunk-I3CGU5W7.js} +4 -4
- package/dist/chunk-I3CGU5W7.js.map +1 -0
- package/dist/{chunk-NVPG6JCL.js → chunk-L7YNNBI5.js} +3 -3
- package/dist/chunk-L7YNNBI5.js.map +1 -0
- package/dist/chunk-LGFWH3AE.js +26 -0
- package/dist/chunk-LGFWH3AE.js.map +1 -0
- package/dist/chunk-MLF4W5R6.js +101 -0
- package/dist/chunk-MLF4W5R6.js.map +1 -0
- package/dist/{chunk-KIRH7TUJ.js → chunk-MTSDOSXS.js} +3 -3
- package/dist/chunk-MTSDOSXS.js.map +1 -0
- package/dist/{chunk-J4SJTKIK.js → chunk-NAM4ERUW.js} +3 -3
- package/dist/chunk-NAM4ERUW.js.map +1 -0
- package/dist/{chunk-BN3X7UXB.js → chunk-NBFIBGAT.js} +39 -25
- package/dist/chunk-NBFIBGAT.js.map +1 -0
- package/dist/{chunk-BNLGTZ34.js → chunk-O5RG4YZY.js} +3 -3
- package/dist/chunk-O5RG4YZY.js.map +1 -0
- package/dist/{chunk-JHYXKVV2.js → chunk-ODUM3D6X.js} +2 -2
- package/dist/chunk-ODUM3D6X.js.map +1 -0
- package/dist/chunk-OYSAN7UX.js +15 -0
- package/dist/chunk-OYSAN7UX.js.map +1 -0
- package/dist/chunk-P4SNGQNI.js +158 -0
- package/dist/chunk-P4SNGQNI.js.map +1 -0
- package/dist/{chunk-2CJ46J3C.js → chunk-PPSMUECX.js} +3 -3
- package/dist/chunk-PPSMUECX.js.map +1 -0
- package/dist/chunk-Q6ZXJTZB.js +56 -0
- package/dist/chunk-Q6ZXJTZB.js.map +1 -0
- package/dist/{chunk-XANPHG7W.js → chunk-QSDZDHNS.js} +7 -7
- package/dist/chunk-QSDZDHNS.js.map +1 -0
- package/dist/{chunk-33RP6K2O.js → chunk-QVMEF6FB.js} +6 -6
- package/dist/chunk-QVMEF6FB.js.map +1 -0
- package/dist/chunk-QWP76EBW.js +536 -0
- package/dist/chunk-QWP76EBW.js.map +1 -0
- package/dist/{chunk-V5GZQEIY.js → chunk-RBYBSSGO.js} +4 -4
- package/dist/chunk-RBYBSSGO.js.map +1 -0
- package/dist/{chunk-H5P2C6H4.js → chunk-RKB2ZK6S.js} +628 -408
- package/dist/chunk-RKB2ZK6S.js.map +1 -0
- package/dist/{chunk-UKT3G5IA.js → chunk-SHTGQGAU.js} +7 -7
- package/dist/chunk-SHTGQGAU.js.map +1 -0
- package/dist/chunk-SNPYTMPR.js +51 -0
- package/dist/chunk-SNPYTMPR.js.map +1 -0
- package/dist/chunk-UB2QB6DE.js +124 -0
- package/dist/chunk-UB2QB6DE.js.map +1 -0
- package/dist/chunk-UNJUWWQO.js +1108 -0
- package/dist/chunk-UNJUWWQO.js.map +1 -0
- package/dist/chunk-V2M243KZ.js +445 -0
- package/dist/chunk-V2M243KZ.js.map +1 -0
- package/dist/chunk-V5JT5TPD.js +97 -0
- package/dist/chunk-V5JT5TPD.js.map +1 -0
- package/dist/chunk-W26AUH5B.js +61 -0
- package/dist/chunk-W26AUH5B.js.map +1 -0
- package/dist/chunk-WAAD23KY.js +222 -0
- package/dist/chunk-WAAD23KY.js.map +1 -0
- package/dist/chunk-WIIZNPCR.js +150 -0
- package/dist/chunk-WIIZNPCR.js.map +1 -0
- package/dist/chunk-WQCJTU2C.js +84 -0
- package/dist/chunk-WQCJTU2C.js.map +1 -0
- package/dist/chunk-WVLDNYOJ.js +150 -0
- package/dist/chunk-WVLDNYOJ.js.map +1 -0
- package/dist/chunk-WXVT3AOY.js +22 -0
- package/dist/chunk-WXVT3AOY.js.map +1 -0
- package/dist/{chunk-GAK6PIBW.js → chunk-XMMAGAT4.js} +2 -2
- package/dist/chunk-XMMAGAT4.js.map +1 -0
- package/dist/chunk-Y64XWMJ4.js +212 -0
- package/dist/chunk-Y64XWMJ4.js.map +1 -0
- package/dist/chunk-YEULD3SG.js +62 -0
- package/dist/chunk-YEULD3SG.js.map +1 -0
- package/dist/chunk-ZHGPZBS4.js +49 -0
- package/dist/chunk-ZHGPZBS4.js.map +1 -0
- package/dist/{chunk-JKBFUAJK.js → chunk-ZSLHHQPQ.js} +2 -2
- package/dist/chunk-ZSLHHQPQ.js.map +1 -0
- package/dist/cli.js +501 -150
- package/dist/cli.js.map +1 -1
- package/dist/{config-6S355X75.js → config-I4FMCJGZ.js} +3 -3
- package/dist/config-editor-HNEKXRLQ.js +11 -0
- package/dist/{config-registry-AHYI4MYL.js → config-registry-CUMNXFGK.js} +2 -2
- package/dist/context-XM6E22LM.js +10 -0
- package/dist/core-plugins-VEUNFTMB.js +27 -0
- package/dist/{daemon-4CS6HMB5.js → daemon-PXO5QPCR.js} +4 -4
- package/dist/dev-loader-RDC5E2CW.js +50 -0
- package/dist/dev-loader-RDC5E2CW.js.map +1 -0
- package/dist/discord-NOJQ5PZO.js +8 -0
- package/dist/doctor-H72BZOPA.js +10 -0
- package/dist/{doctor-OLYBO3V3.js → doctor-RF6BHMCC.js} +5 -5
- package/dist/file-service-EUODJAIT.js +9 -0
- package/dist/file-service-EUODJAIT.js.map +1 -0
- package/dist/index.d.ts +1293 -188
- package/dist/index.js +387 -48
- package/dist/index.js.map +1 -1
- package/dist/{install-cloudflared-Z7VCGOVG.js → install-cloudflared-AN24L4DP.js} +5 -5
- package/dist/install-cloudflared-AN24L4DP.js.map +1 -0
- package/dist/install-context-XPWTFT3J.js +78 -0
- package/dist/install-context-XPWTFT3J.js.map +1 -0
- package/dist/{install-jq-HUYSQWKR.js → install-jq-CRVDJGF3.js} +5 -5
- package/dist/install-jq-CRVDJGF3.js.map +1 -0
- package/dist/{integrate-PNEHRY2I.js → integrate-5C6KSU6D.js} +2 -2
- package/dist/integrate-5C6KSU6D.js.map +1 -0
- package/dist/{log-NXABYJTT.js → log-LZ7FTRKG.js} +2 -2
- package/dist/log-LZ7FTRKG.js.map +1 -0
- package/dist/main-T5WVCCFN.js +715 -0
- package/dist/main-T5WVCCFN.js.map +1 -0
- package/dist/{menu-YY5MKHEK.js → menu-YDQ2LWAR.js} +2 -2
- package/dist/menu-YDQ2LWAR.js.map +1 -0
- package/dist/{new-session-FEO4J4VU.js → new-session-AVQCNXRG.js} +5 -5
- package/dist/new-session-AVQCNXRG.js.map +1 -0
- package/dist/notifications-D5BRDNSU.js +9 -0
- package/dist/notifications-D5BRDNSU.js.map +1 -0
- package/dist/plugin-create-JVCVUG6V.js +331 -0
- package/dist/plugin-create-JVCVUG6V.js.map +1 -0
- package/dist/plugin-registry-WB3DR67H.js +8 -0
- package/dist/plugin-registry-WB3DR67H.js.map +1 -0
- package/dist/{post-upgrade-CJG5I7M2.js → post-upgrade-XLHZ6ZB7.js} +8 -8
- package/dist/post-upgrade-XLHZ6ZB7.js.map +1 -0
- package/dist/read-text-file-IRZM3QLM.js +8 -0
- package/dist/read-text-file-IRZM3QLM.js.map +1 -0
- package/dist/security-YNRBW6S7.js +9 -0
- package/dist/security-YNRBW6S7.js.map +1 -0
- package/dist/{session-IUSI7P5S.js → session-KZFA6Z26.js} +4 -4
- package/dist/session-KZFA6Z26.js.map +1 -0
- package/dist/{settings-RQPAM4KC.js → settings-MFYM7CZO.js} +4 -4
- package/dist/settings-MFYM7CZO.js.map +1 -0
- package/dist/settings-manager-MD2U4ZV2.js +8 -0
- package/dist/settings-manager-MD2U4ZV2.js.map +1 -0
- package/dist/setup-BAI2F24H.js +747 -0
- package/dist/setup-BAI2F24H.js.map +1 -0
- package/dist/slack-KH7E3VBS.js +8 -0
- package/dist/slack-KH7E3VBS.js.map +1 -0
- package/dist/speech-2GHQNRIO.js +9 -0
- package/dist/speech-2GHQNRIO.js.map +1 -0
- package/dist/telegram-ZDC3JQF2.js +8 -0
- package/dist/telegram-ZDC3JQF2.js.map +1 -0
- package/dist/tunnel-M47I7H4B.js +8 -0
- package/dist/tunnel-M47I7H4B.js.map +1 -0
- package/dist/{tunnel-service-CJLUH6SZ.js → tunnel-service-WADYHREX.js} +17 -17
- package/dist/tunnel-service-WADYHREX.js.map +1 -0
- package/dist/usage-WYNK6ZC5.js +10 -0
- package/dist/usage-WYNK6ZC5.js.map +1 -0
- package/dist/validators-6CLEZUBD.js +8 -0
- package/dist/validators-6CLEZUBD.js.map +1 -0
- package/dist/validators-WSTBNKRW.js +12 -0
- package/dist/validators-WSTBNKRW.js.map +1 -0
- package/package.json +1 -1
- package/dist/adapter-LNEGLMOE.js.map +0 -1
- package/dist/agent-catalog-FC3HGDEQ.js +0 -11
- package/dist/agent-registry-WT4NXPYG.js +0 -9
- package/dist/agent-store-VZLFPTZU.js +0 -9
- package/dist/chunk-2CJ46J3C.js.map +0 -1
- package/dist/chunk-2HMQOC7N.js.map +0 -1
- package/dist/chunk-33RP6K2O.js.map +0 -1
- package/dist/chunk-34M4OS5P.js.map +0 -1
- package/dist/chunk-4CTX774K.js.map +0 -1
- package/dist/chunk-7QJS2XBD.js.map +0 -1
- package/dist/chunk-BDYVCIBH.js +0 -735
- package/dist/chunk-BDYVCIBH.js.map +0 -1
- package/dist/chunk-BN3X7UXB.js.map +0 -1
- package/dist/chunk-BNLGTZ34.js.map +0 -1
- package/dist/chunk-GAK6PIBW.js.map +0 -1
- package/dist/chunk-H5P2C6H4.js.map +0 -1
- package/dist/chunk-I7WC6E5S.js.map +0 -1
- package/dist/chunk-J4SJTKIK.js.map +0 -1
- package/dist/chunk-JHYXKVV2.js.map +0 -1
- package/dist/chunk-JKBFUAJK.js.map +0 -1
- package/dist/chunk-JUYDFUSN.js.map +0 -1
- package/dist/chunk-KIRH7TUJ.js.map +0 -1
- package/dist/chunk-LBIKITQT.js +0 -22
- package/dist/chunk-LBIKITQT.js.map +0 -1
- package/dist/chunk-LGP2YGRL.js +0 -4880
- package/dist/chunk-LGP2YGRL.js.map +0 -1
- package/dist/chunk-NAMYZIS5.js +0 -1
- package/dist/chunk-NVPG6JCL.js.map +0 -1
- package/dist/chunk-O7CPGUAI.js.map +0 -1
- package/dist/chunk-UKT3G5IA.js.map +0 -1
- package/dist/chunk-V5GZQEIY.js.map +0 -1
- package/dist/chunk-VOIJ6OY4.js +0 -63
- package/dist/chunk-VOIJ6OY4.js.map +0 -1
- package/dist/chunk-W3EYKZNQ.js.map +0 -1
- package/dist/chunk-WTZDAYZX.js.map +0 -1
- package/dist/chunk-XANPHG7W.js.map +0 -1
- package/dist/config-editor-RVLWZLVB.js +0 -13
- package/dist/discord-7IVQKB2H.js.map +0 -1
- package/dist/doctor-HZZ5BSHB.js +0 -10
- package/dist/install-cloudflared-Z7VCGOVG.js.map +0 -1
- package/dist/install-jq-HUYSQWKR.js.map +0 -1
- package/dist/integrate-PNEHRY2I.js.map +0 -1
- package/dist/main-ZK4MPMBG.js +0 -238
- package/dist/main-ZK4MPMBG.js.map +0 -1
- package/dist/post-upgrade-CJG5I7M2.js.map +0 -1
- package/dist/setup-3GQSYBE4.js +0 -35
- package/dist/tunnel-service-CJLUH6SZ.js.map +0 -1
- /package/dist/{action-detect-P7ZE4NEM.js.map → action-detect-QPA775HB.js.map} +0 -0
- /package/dist/{admin-6SYB6XCZ.js.map → adapter-6ANPBSVU.js.map} +0 -0
- /package/dist/{agent-catalog-FC3HGDEQ.js.map → admin-GBPZFFAU.js.map} +0 -0
- /package/dist/{agent-dependencies-4OWBMZWZ.js.map → agent-catalog-YHBFERYO.js.map} +0 -0
- /package/dist/{agent-registry-WT4NXPYG.js.map → agent-dependencies-WS7Z2DFW.js.map} +0 -0
- /package/dist/{agent-store-VZLFPTZU.js.map → agent-registry-5LZT7CUB.js.map} +0 -0
- /package/dist/{agents-QO7DKARJ.js.map → agent-store-VSHNY5GT.js.map} +0 -0
- /package/dist/{api-client-CFQT5U7D.js.map → agents-BWU4MRRD.js.map} +0 -0
- /package/dist/{autostart-X33OGMX6.js.map → api-client-AQPNKXI2.js.map} +0 -0
- /package/dist/{chunk-NAMYZIS5.js.map → api-server-3PYLRBCN.js.map} +0 -0
- /package/dist/{config-6S355X75.js.map → api-server-CHVSUDBX.js.map} +0 -0
- /package/dist/{config-editor-RVLWZLVB.js.map → autostart-6JS565RY.js.map} +0 -0
- /package/dist/{config-registry-AHYI4MYL.js.map → chunk-FNRSWA2K.js.map} +0 -0
- /package/dist/{daemon-4CS6HMB5.js.map → config-I4FMCJGZ.js.map} +0 -0
- /package/dist/{doctor-HZZ5BSHB.js.map → config-editor-HNEKXRLQ.js.map} +0 -0
- /package/dist/{doctor-OLYBO3V3.js.map → config-registry-CUMNXFGK.js.map} +0 -0
- /package/dist/{log-NXABYJTT.js.map → context-XM6E22LM.js.map} +0 -0
- /package/dist/{menu-YY5MKHEK.js.map → core-plugins-VEUNFTMB.js.map} +0 -0
- /package/dist/{new-session-FEO4J4VU.js.map → daemon-PXO5QPCR.js.map} +0 -0
- /package/dist/{session-IUSI7P5S.js.map → discord-NOJQ5PZO.js.map} +0 -0
- /package/dist/{settings-RQPAM4KC.js.map → doctor-H72BZOPA.js.map} +0 -0
- /package/dist/{setup-3GQSYBE4.js.map → doctor-RF6BHMCC.js.map} +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
deleteSessionThread
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-O5RG4YZY.js";
|
|
4
4
|
import {
|
|
5
5
|
log
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-XMMAGAT4.js";
|
|
7
7
|
|
|
8
|
-
// src/
|
|
8
|
+
// src/plugins/discord/commands/session.ts
|
|
9
9
|
import {
|
|
10
10
|
ActionRowBuilder,
|
|
11
11
|
ButtonBuilder,
|
|
@@ -262,4 +262,4 @@ export {
|
|
|
262
262
|
executeCancelSession,
|
|
263
263
|
handleCleanupButton
|
|
264
264
|
};
|
|
265
|
-
//# sourceMappingURL=chunk-
|
|
265
|
+
//# sourceMappingURL=chunk-GJOY37U7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/plugins/discord/commands/session.ts"],"sourcesContent":["import {\n ActionRowBuilder,\n ButtonBuilder,\n ButtonStyle,\n} from 'discord.js'\nimport type { ChatInputCommandInteraction, ButtonInteraction } from 'discord.js'\nimport type { Session } from '../../../core/sessions/session.js'\nimport { log } from '../../../core/utils/log.js'\nimport { deleteSessionThread } from '../forums.js'\nimport type { DiscordAdapter } from '../adapter.js'\n\nconst STATUS_EMOJI: Record<string, string> = {\n active: '🟢',\n initializing: '🟡',\n finished: '✅',\n error: '❌',\n cancelled: '⛔',\n}\n\nconst STATUS_ORDER: Record<string, number> = {\n active: 0,\n initializing: 1,\n error: 2,\n finished: 3,\n cancelled: 4,\n}\n\nexport async function handleCancel(\n interaction: ChatInputCommandInteraction,\n adapter: DiscordAdapter,\n): Promise<void> {\n await interaction.deferReply({ ephemeral: true })\n\n const channelId = interaction.channelId\n const session = adapter.core.sessionManager.getSessionByThread('discord', channelId)\n\n if (session) {\n log.info({ sessionId: session.id }, '[discord-session] Cancel command')\n await session.abortPrompt()\n await interaction.editReply('⛔ Session cancelled.')\n return\n }\n\n // Fallback: cancel from store when session not in memory\n const record = adapter.core.sessionManager.getRecordByThread('discord', channelId)\n if (record && record.status !== 'cancelled' && record.status !== 'error') {\n log.info({ sessionId: record.sessionId }, '[discord-session] Cancel command (from store)')\n await adapter.core.sessionManager.cancelSession(record.sessionId)\n await interaction.editReply('⛔ Session cancelled.')\n return\n }\n\n await interaction.editReply('No active session in this channel.')\n}\n\nexport async function handleStatus(\n interaction: ChatInputCommandInteraction,\n adapter: DiscordAdapter,\n): Promise<void> {\n await interaction.deferReply({ ephemeral: true })\n\n const channelId = interaction.channelId\n const session = adapter.core.sessionManager.getSessionByThread('discord', channelId)\n\n if (session) {\n await interaction.editReply(\n `**Session:** ${session.name || session.id}\\n` +\n `**Agent:** ${session.agentName}\\n` +\n `**Status:** ${session.status}\\n` +\n `**Workspace:** \\`${session.workingDirectory}\\`\\n` +\n `**Queue:** ${session.queueDepth} pending`,\n )\n return\n }\n\n // Try stored record\n const record = adapter.core.sessionManager.getRecordByThread('discord', channelId)\n if (record) {\n await interaction.editReply(\n `**Session:** ${record.name || record.sessionId}\\n` +\n `**Agent:** ${record.agentName}\\n` +\n `**Status:** ${record.status} (not loaded)\\n` +\n `**Workspace:** \\`${record.workingDir}\\``,\n )\n return\n }\n\n // Global status\n const sessions = adapter.core.sessionManager.listSessions('discord')\n const active = sessions.filter(\n (s: Session) => s.status === 'active' || s.status === 'initializing',\n )\n await interaction.editReply(\n `**OpenACP Status**\\n` +\n `Active sessions: ${active.length}\\n` +\n `Total sessions: ${sessions.length}`,\n )\n}\n\nexport async function handleSessions(\n interaction: ChatInputCommandInteraction,\n adapter: DiscordAdapter,\n): Promise<void> {\n await interaction.deferReply({ ephemeral: true })\n\n try {\n const allRecords = adapter.core.sessionManager.listRecords()\n\n // Only show sessions that have a Discord thread\n const records = allRecords.filter((r: any) => {\n const platform = r.platform as { topicId?: string | number }\n return !!platform?.topicId\n })\n const headlessCount = allRecords.length - records.length\n\n if (records.length === 0) {\n const extra = headlessCount > 0 ? ` (${headlessCount} headless hidden)` : ''\n await interaction.editReply(`No sessions found.${extra}`)\n return\n }\n\n records.sort(\n (a: any, b: any) => (STATUS_ORDER[a.status] ?? 5) - (STATUS_ORDER[b.status] ?? 5),\n )\n\n const MAX_DISPLAY = 25\n const displayed = records.slice(0, MAX_DISPLAY)\n\n const lines = displayed.map((r: any) => {\n const emoji = STATUS_EMOJI[r.status] || '⚪'\n const name = r.name?.trim() || `${r.agentName} session`\n return `${emoji} **${name}** \\`[${r.status}]\\``\n })\n\n const header =\n `**Sessions: ${records.length}**` +\n (headlessCount > 0 ? ` (${headlessCount} headless hidden)` : '')\n const truncated =\n records.length > MAX_DISPLAY\n ? `\\n\\n*...and ${records.length - MAX_DISPLAY} more*`\n : ''\n\n // Cleanup buttons\n const finishedCount = allRecords.filter((r: any) => r.status === 'finished').length\n const errorCount = allRecords.filter(\n (r: any) => r.status === 'error' || r.status === 'cancelled',\n ).length\n\n const rows: ActionRowBuilder<ButtonBuilder>[] = []\n\n if (finishedCount + errorCount > 0) {\n const cleanupRow = new ActionRowBuilder<ButtonBuilder>()\n if (finishedCount > 0) {\n cleanupRow.addComponents(\n new ButtonBuilder()\n .setCustomId('m:cleanup:finished')\n .setLabel(`Cleanup finished (${finishedCount})`)\n .setStyle(ButtonStyle.Secondary),\n )\n }\n if (errorCount > 0) {\n cleanupRow.addComponents(\n new ButtonBuilder()\n .setCustomId('m:cleanup:errors')\n .setLabel(`Cleanup errors (${errorCount})`)\n .setStyle(ButtonStyle.Secondary),\n )\n }\n rows.push(cleanupRow)\n\n const cleanupAllRow = new ActionRowBuilder<ButtonBuilder>()\n cleanupAllRow.addComponents(\n new ButtonBuilder()\n .setCustomId('m:cleanup:all')\n .setLabel(`Cleanup all non-active (${finishedCount + errorCount})`)\n .setStyle(ButtonStyle.Secondary),\n )\n rows.push(cleanupAllRow)\n }\n\n await interaction.editReply({\n content: `${header}\\n\\n${lines.join('\\n')}${truncated}`,\n components: rows,\n })\n } catch (err) {\n log.error({ err }, '[discord-session] handleSessions error')\n await interaction.editReply('❌ Failed to list sessions.').catch(() => {})\n }\n}\n\nexport async function handleHandoff(\n interaction: ChatInputCommandInteraction,\n adapter: DiscordAdapter,\n): Promise<void> {\n await interaction.deferReply({ ephemeral: true })\n\n const channelId = interaction.channelId\n const session = adapter.core.sessionManager.getSessionByThread('discord', channelId)\n\n if (!session) {\n const record = adapter.core.sessionManager.getRecordByThread('discord', channelId)\n if (!record) {\n await interaction.editReply('No session found in this channel.')\n return\n }\n const cmd = `openacp agents run ${record.agentName} --resume ${record.agentSessionId} -- --continue`\n await interaction.editReply(\n `**Resume in terminal:**\\n\\`\\`\\`\\n${cmd}\\n\\`\\`\\`\\n\\n*Run this from your project directory:* \\`${record.workingDir}\\``,\n )\n return\n }\n\n const cmd = `openacp agents run ${session.agentName} --resume ${session.agentSessionId} -- --continue`\n await interaction.editReply(\n `**Resume in terminal:**\\n\\`\\`\\`\\n${cmd}\\n\\`\\`\\`\\n\\n*Run this from your project directory:* \\`${session.workingDirectory}\\``,\n )\n}\n\nexport async function executeCancelSession(\n interaction: ButtonInteraction,\n adapter: DiscordAdapter,\n): Promise<void> {\n const sessions: Session[] = adapter.core.sessionManager\n .listSessions('discord')\n .filter((s: Session) => s.status === 'active')\n .sort((a: Session, b: Session) => b.createdAt.getTime() - a.createdAt.getTime())\n\n const session = sessions[0]\n if (!session) {\n await interaction.reply({ content: 'No active sessions to cancel.', ephemeral: true })\n return\n }\n\n await session.abortPrompt()\n await interaction.reply({ content: `⛔ Cancelled session: **${session.name || session.id}**`, ephemeral: true })\n}\n\nexport async function handleCleanupButton(\n interaction: ButtonInteraction,\n adapter: DiscordAdapter,\n): Promise<void> {\n const { customId } = interaction\n\n switch (customId) {\n case 'm:cleanup:all':\n await interaction.deferReply({ ephemeral: true })\n await runCleanup(interaction, adapter, ['finished', 'error', 'cancelled'])\n break\n\n case 'm:cleanup:finished':\n await interaction.deferReply({ ephemeral: true })\n await runCleanup(interaction, adapter, ['finished'])\n break\n\n case 'm:cleanup:errors':\n await interaction.deferReply({ ephemeral: true })\n await runCleanup(interaction, adapter, ['error', 'cancelled'])\n break\n\n case 'm:cleanup:confirm':\n await interaction.deferReply({ ephemeral: true })\n await runCleanup(interaction, adapter, ['finished', 'error', 'cancelled', 'active', 'initializing'])\n break\n\n case 'm:cleanup:cancel':\n try { await interaction.update({ components: [] }) } catch { /* ignore */ }\n break\n\n default:\n // Unknown cleanup variant — ignore\n try { await interaction.reply({ content: 'Unknown cleanup action.', ephemeral: true }) } catch { /* ignore */ }\n }\n}\n\nasync function runCleanup(\n interaction: ButtonInteraction,\n adapter: DiscordAdapter,\n statuses: string[],\n): Promise<void> {\n const allRecords = adapter.core.sessionManager.listRecords()\n const cleanable = allRecords.filter((r: any) => statuses.includes(r.status))\n\n if (cleanable.length === 0) {\n await interaction.editReply('Nothing to clean up.')\n return\n }\n\n let deleted = 0\n let failed = 0\n\n for (const record of cleanable) {\n try {\n // Cancel active sessions first\n if (record.status === 'active' || record.status === 'initializing') {\n try {\n await adapter.core.sessionManager.cancelSession(record.sessionId)\n } catch (err) {\n log.warn({ err, sessionId: record.sessionId }, '[discord-session] Failed to cancel session during cleanup')\n }\n }\n\n const platform = record.platform as { topicId?: string | number; threadId?: string } | undefined\n const threadId = platform?.threadId ?? (platform?.topicId != null ? String(platform.topicId) : undefined)\n if (threadId) {\n try {\n await deleteSessionThread(adapter.getGuild(), threadId)\n } catch (err) {\n log.warn({ err, sessionId: record.sessionId, threadId }, '[discord-session] Failed to delete thread during cleanup')\n }\n }\n await adapter.core.sessionManager.removeRecord(record.sessionId)\n deleted++\n } catch (err) {\n log.error({ err, sessionId: record.sessionId }, '[discord-session] Failed to cleanup session')\n failed++\n }\n }\n\n await interaction.editReply(\n `🗑 Cleaned up **${deleted}** sessions${failed > 0 ? ` (${failed} failed)` : ''}.`,\n )\n}\n"],"mappings":"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","names":["cmd"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/
|
|
1
|
+
// src/plugins/discord/action-detect.ts
|
|
2
2
|
import { nanoid } from "nanoid";
|
|
3
3
|
import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
|
|
4
4
|
var CMD_NEW_RE = /\/new(?:\s+([^\s\u0080-\uFFFF]+)(?:\s+([^\s\u0080-\uFFFF]+))?)?/;
|
|
@@ -68,4 +68,4 @@ export {
|
|
|
68
68
|
removeAction,
|
|
69
69
|
buildActionKeyboard
|
|
70
70
|
};
|
|
71
|
-
//# sourceMappingURL=chunk-
|
|
71
|
+
//# sourceMappingURL=chunk-HVBNCPAY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/plugins/discord/action-detect.ts"],"sourcesContent":["import { nanoid } from 'nanoid'\nimport { ActionRowBuilder, ButtonBuilder, ButtonStyle } from 'discord.js'\n\nexport interface DetectedAction {\n type: 'new_session' | 'cancel_session'\n agent?: string\n workspace?: string\n}\n\n// Command patterns: /new [agent] [workspace], /cancel\n// Agent and workspace are ASCII-only tokens (no Unicode letters) to avoid matching non-ASCII words\nconst CMD_NEW_RE = /\\/new(?:\\s+([^\\s\\u0080-\\uFFFF]+)(?:\\s+([^\\s\\u0080-\\uFFFF]+))?)?/\nconst CMD_CANCEL_RE = /\\/cancel\\b/\n\n// Keyword patterns (compound phrases only to avoid false positives)\nconst KW_NEW_RE = /(?:create|new)\\s+session/i\nconst KW_CANCEL_RE = /(?:cancel|stop)\\s+session/i\n\nexport function detectAction(text: string): DetectedAction | null {\n if (!text) return null\n\n // Priority 1: command pattern\n const cancelCmd = CMD_CANCEL_RE.exec(text)\n if (cancelCmd) return { type: 'cancel_session' }\n\n const newCmd = CMD_NEW_RE.exec(text)\n if (newCmd) {\n return {\n type: 'new_session',\n agent: newCmd[1] || undefined,\n workspace: newCmd[2] || undefined,\n }\n }\n\n // Priority 2: keyword matching\n if (KW_CANCEL_RE.test(text)) return { type: 'cancel_session' }\n if (KW_NEW_RE.test(text)) return { type: 'new_session', agent: undefined, workspace: undefined }\n\n return null\n}\n\n// --- TTL action map ---\n\nconst ACTION_TTL_MS = 5 * 60 * 1000 // 5 minutes\nconst actionMap: Map<string, { action: DetectedAction; createdAt: number }> = new Map()\n\nexport function storeAction(action: DetectedAction): string {\n const id = nanoid(8)\n actionMap.set(id, { action, createdAt: Date.now() })\n // Cleanup expired entries\n for (const [key, entry] of actionMap) {\n if (Date.now() - entry.createdAt > ACTION_TTL_MS) {\n actionMap.delete(key)\n }\n }\n return id\n}\n\nexport function getAction(id: string): DetectedAction | undefined {\n const entry = actionMap.get(id)\n if (!entry) return undefined\n if (Date.now() - entry.createdAt > ACTION_TTL_MS) {\n actionMap.delete(id)\n return undefined\n }\n return entry.action\n}\n\nexport function removeAction(id: string): void {\n actionMap.delete(id)\n}\n\nexport function buildActionKeyboard(\n actionId: string,\n action: DetectedAction,\n): ActionRowBuilder<ButtonBuilder> {\n const row = new ActionRowBuilder<ButtonBuilder>()\n\n if (action.type === 'new_session') {\n row.addComponents(\n new ButtonBuilder()\n .setCustomId(`a:${actionId}`)\n .setLabel('✅ Create session')\n .setStyle(ButtonStyle.Success),\n new ButtonBuilder()\n .setCustomId(`a:dismiss:${actionId}`)\n .setLabel('❌ Cancel')\n .setStyle(ButtonStyle.Secondary),\n )\n } else {\n row.addComponents(\n new ButtonBuilder()\n .setCustomId(`a:${actionId}`)\n .setLabel('⛔ Cancel session')\n .setStyle(ButtonStyle.Danger),\n new ButtonBuilder()\n .setCustomId(`a:dismiss:${actionId}`)\n .setLabel('❌ No')\n .setStyle(ButtonStyle.Secondary),\n )\n }\n\n return row\n}\n"],"mappings":";AAAA,SAAS,cAAc;AACvB,SAAS,kBAAkB,eAAe,mBAAmB;AAU7D,IAAM,aAAa;AACnB,IAAM,gBAAgB;AAGtB,IAAM,YAAY;AAClB,IAAM,eAAe;AAEd,SAAS,aAAa,MAAqC;AAChE,MAAI,CAAC,KAAM,QAAO;AAGlB,QAAM,YAAY,cAAc,KAAK,IAAI;AACzC,MAAI,UAAW,QAAO,EAAE,MAAM,iBAAiB;AAE/C,QAAM,SAAS,WAAW,KAAK,IAAI;AACnC,MAAI,QAAQ;AACV,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO,OAAO,CAAC,KAAK;AAAA,MACpB,WAAW,OAAO,CAAC,KAAK;AAAA,IAC1B;AAAA,EACF;AAGA,MAAI,aAAa,KAAK,IAAI,EAAG,QAAO,EAAE,MAAM,iBAAiB;AAC7D,MAAI,UAAU,KAAK,IAAI,EAAG,QAAO,EAAE,MAAM,eAAe,OAAO,QAAW,WAAW,OAAU;AAE/F,SAAO;AACT;AAIA,IAAM,gBAAgB,IAAI,KAAK;AAC/B,IAAM,YAAwE,oBAAI,IAAI;AAE/E,SAAS,YAAY,QAAgC;AAC1D,QAAM,KAAK,OAAO,CAAC;AACnB,YAAU,IAAI,IAAI,EAAE,QAAQ,WAAW,KAAK,IAAI,EAAE,CAAC;AAEnD,aAAW,CAAC,KAAK,KAAK,KAAK,WAAW;AACpC,QAAI,KAAK,IAAI,IAAI,MAAM,YAAY,eAAe;AAChD,gBAAU,OAAO,GAAG;AAAA,IACtB;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,UAAU,IAAwC;AAChE,QAAM,QAAQ,UAAU,IAAI,EAAE;AAC9B,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,KAAK,IAAI,IAAI,MAAM,YAAY,eAAe;AAChD,cAAU,OAAO,EAAE;AACnB,WAAO;AAAA,EACT;AACA,SAAO,MAAM;AACf;AAEO,SAAS,aAAa,IAAkB;AAC7C,YAAU,OAAO,EAAE;AACrB;AAEO,SAAS,oBACd,UACA,QACiC;AACjC,QAAM,MAAM,IAAI,iBAAgC;AAEhD,MAAI,OAAO,SAAS,eAAe;AACjC,QAAI;AAAA,MACF,IAAI,cAAc,EACf,YAAY,KAAK,QAAQ,EAAE,EAC3B,SAAS,uBAAkB,EAC3B,SAAS,YAAY,OAAO;AAAA,MAC/B,IAAI,cAAc,EACf,YAAY,aAAa,QAAQ,EAAE,EACnC,SAAS,eAAU,EACnB,SAAS,YAAY,SAAS;AAAA,IACnC;AAAA,EACF,OAAO;AACL,QAAI;AAAA,MACF,IAAI,cAAc,EACf,YAAY,KAAK,QAAQ,EAAE,EAC3B,SAAS,uBAAkB,EAC3B,SAAS,YAAY,MAAM;AAAA,MAC9B,IAAI,cAAc,EACf,YAAY,aAAa,QAAQ,EAAE,EACnC,SAAS,WAAM,EACf,SAAS,YAAY,SAAS;AAAA,IACnC;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DoctorEngine
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-L7YNNBI5.js";
|
|
4
4
|
import {
|
|
5
5
|
log
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-XMMAGAT4.js";
|
|
7
7
|
|
|
8
|
-
// src/
|
|
8
|
+
// src/plugins/discord/commands/doctor.ts
|
|
9
9
|
import {
|
|
10
10
|
ActionRowBuilder,
|
|
11
11
|
ButtonBuilder,
|
|
@@ -131,4 +131,4 @@ export {
|
|
|
131
131
|
runDoctorInline,
|
|
132
132
|
handleDoctorButton
|
|
133
133
|
};
|
|
134
|
-
//# sourceMappingURL=chunk-
|
|
134
|
+
//# sourceMappingURL=chunk-I3CGU5W7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/plugins/discord/commands/doctor.ts"],"sourcesContent":["import {\n ActionRowBuilder,\n ButtonBuilder,\n ButtonStyle,\n} from 'discord.js'\nimport type { ChatInputCommandInteraction, ButtonInteraction } from 'discord.js'\nimport { DoctorEngine } from '../../../core/doctor/index.js'\nimport type { DoctorReport, PendingFix } from '../../../core/doctor/types.js'\nimport { log } from '../../../core/utils/log.js'\nimport type { DiscordAdapter } from '../adapter.js'\n\n// In-memory store of pending fixes keyed by \"guildId:channelId:messageId\"\nconst pendingFixesStore = new Map<string, PendingFix[]>()\n\nfunction renderReport(report: DoctorReport): {\n content: string\n components: ActionRowBuilder<ButtonBuilder>[]\n} {\n const icons = { pass: '✅', warn: '⚠️', fail: '❌' }\n const lines: string[] = ['🩺 **OpenACP Doctor**\\n']\n\n for (const category of report.categories) {\n lines.push(`**${category.name}**`)\n for (const result of category.results) {\n lines.push(` ${icons[result.status]} ${result.message}`)\n }\n lines.push('')\n }\n\n const { passed, warnings, failed, fixed } = report.summary\n const fixedStr = fixed > 0 ? `, ${fixed} fixed` : ''\n lines.push(`**Result:** ${passed} passed, ${warnings} warnings, ${failed} failed${fixedStr}`)\n\n const components: ActionRowBuilder<ButtonBuilder>[] = []\n\n if (report.pendingFixes.length > 0) {\n const row = new ActionRowBuilder<ButtonBuilder>()\n for (let i = 0; i < Math.min(report.pendingFixes.length, 5); i++) {\n row.addComponents(\n new ButtonBuilder()\n .setCustomId(`m:doctor:fix:${i}`)\n .setLabel(`🔧 Fix: ${report.pendingFixes[i].message.slice(0, 30)}`)\n .setStyle(ButtonStyle.Primary),\n )\n }\n components.push(row)\n }\n\n return { content: lines.join('\\n'), components }\n}\n\nexport async function handleDoctor(\n interaction: ChatInputCommandInteraction,\n _adapter: DiscordAdapter,\n): Promise<void> {\n await interaction.deferReply({ ephemeral: true })\n\n try {\n const engine = new DoctorEngine()\n const report = await engine.runAll()\n const { content, components } = renderReport(report)\n\n // Store pending fixes for button callbacks\n const storeKey = `${interaction.guildId}:${interaction.channelId}`\n if (report.pendingFixes.length > 0) {\n pendingFixesStore.set(storeKey, report.pendingFixes)\n }\n\n await interaction.editReply({ content, components })\n } catch (err) {\n log.error({ err }, '[discord-doctor] Doctor command failed')\n await interaction.editReply(\n `❌ Doctor failed: ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n}\n\nexport async function runDoctorInline(\n interaction: ButtonInteraction,\n _adapter: DiscordAdapter,\n): Promise<void> {\n try {\n const engine = new DoctorEngine()\n const report = await engine.runAll()\n const { content, components } = renderReport(report)\n\n const storeKey = `${interaction.guildId}:${interaction.channelId}`\n if (report.pendingFixes.length > 0) {\n pendingFixesStore.set(storeKey, report.pendingFixes)\n }\n\n await interaction.followUp({ content, components, ephemeral: true })\n } catch (err) {\n log.error({ err }, '[discord-doctor] Doctor inline failed')\n await interaction.followUp({\n content: `❌ Doctor failed: ${err instanceof Error ? err.message : String(err)}`,\n ephemeral: true,\n })\n }\n}\n\nexport async function handleDoctorButton(\n interaction: ButtonInteraction,\n _adapter: DiscordAdapter,\n): Promise<void> {\n const { customId } = interaction\n\n if (customId === 'm:doctor') {\n try { await interaction.deferUpdate() } catch { /* ignore */ }\n await runDoctorInline(interaction, _adapter)\n return\n }\n\n if (customId.startsWith('m:doctor:fix:')) {\n const index = parseInt(customId.replace('m:doctor:fix:', ''), 10)\n const storeKey = `${interaction.guildId}:${interaction.channelId}`\n const fixes = pendingFixesStore.get(storeKey)\n\n try { await interaction.deferUpdate() } catch { /* ignore */ }\n\n if (!fixes || index < 0 || index >= fixes.length) {\n try { await interaction.followUp({ content: '⚠️ Fix no longer available.', ephemeral: true }) } catch { /* */ }\n return\n }\n\n const pending = fixes[index]\n try {\n const result = await pending.fix()\n if (result.success) {\n // Re-run doctor to show updated status\n const engine = new DoctorEngine()\n const report = await engine.runAll()\n const { content, components } = renderReport(report)\n\n if (report.pendingFixes.length > 0) {\n pendingFixesStore.set(storeKey, report.pendingFixes)\n } else {\n pendingFixesStore.delete(storeKey)\n }\n\n try { await interaction.followUp({ content, components, ephemeral: true }) } catch { /* ignore */ }\n } else {\n try { await interaction.followUp({ content: `❌ Fix failed: ${result.message}`, ephemeral: true }) } catch { /* */ }\n }\n } catch (err) {\n log.error({ err, index }, '[discord-doctor] Doctor fix callback failed')\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
ConfigSchema,
|
|
4
4
|
applyMigrations,
|
|
5
5
|
expandHome
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-QVMEF6FB.js";
|
|
7
7
|
|
|
8
8
|
// src/core/doctor/index.ts
|
|
9
9
|
import * as fs8 from "fs";
|
|
@@ -605,7 +605,7 @@ var tunnelCheck = {
|
|
|
605
605
|
fixRisk: "safe",
|
|
606
606
|
fix: async () => {
|
|
607
607
|
try {
|
|
608
|
-
const { ensureCloudflared } = await import("./install-cloudflared-
|
|
608
|
+
const { ensureCloudflared } = await import("./install-cloudflared-AN24L4DP.js");
|
|
609
609
|
await ensureCloudflared();
|
|
610
610
|
return { success: true, message: "installed cloudflared" };
|
|
611
611
|
} catch (err) {
|
|
@@ -721,4 +721,4 @@ var DoctorEngine = class {
|
|
|
721
721
|
export {
|
|
722
722
|
DoctorEngine
|
|
723
723
|
};
|
|
724
|
-
//# sourceMappingURL=chunk-
|
|
724
|
+
//# sourceMappingURL=chunk-L7YNNBI5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/doctor/index.ts","../../src/core/doctor/checks/config.ts","../../src/core/doctor/checks/agents.ts","../../src/core/doctor/checks/telegram.ts","../../src/core/doctor/checks/discord.ts","../../src/core/doctor/checks/storage.ts","../../src/core/doctor/checks/workspace.ts","../../src/core/doctor/checks/plugins.ts","../../src/core/doctor/checks/daemon.ts","../../src/core/doctor/checks/tunnel.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\nimport type { DoctorCheck, DoctorContext, DoctorReport, CategoryResult, PendingFix, CheckResult } from \"./types.js\";\nimport { ConfigManager, expandHome } from \"../config/config.js\";\n\nimport { configCheck } from \"./checks/config.js\";\nimport { agentsCheck } from \"./checks/agents.js\";\nimport { telegramCheck } from \"./checks/telegram.js\";\nimport { discordCheck } from \"./checks/discord.js\";\nimport { storageCheck } from \"./checks/storage.js\";\nimport { workspaceCheck } from \"./checks/workspace.js\";\nimport { pluginsCheck } from \"./checks/plugins.js\";\nimport { daemonCheck } from \"./checks/daemon.js\";\nimport { tunnelCheck } from \"./checks/tunnel.js\";\n\nconst ALL_CHECKS: DoctorCheck[] = [\n configCheck,\n agentsCheck,\n telegramCheck,\n discordCheck,\n storageCheck,\n workspaceCheck,\n pluginsCheck,\n daemonCheck,\n tunnelCheck,\n];\n\nconst CHECK_TIMEOUT_MS = 10_000;\n\nexport class DoctorEngine {\n private dryRun: boolean;\n\n constructor(options?: { dryRun?: boolean }) {\n this.dryRun = options?.dryRun ?? false;\n }\n\n async runAll(): Promise<DoctorReport> {\n const ctx = await this.buildContext();\n const checks = [...ALL_CHECKS].sort((a, b) => a.order - b.order);\n\n const categories: CategoryResult[] = [];\n const pendingFixes: PendingFix[] = [];\n const summary = { passed: 0, warnings: 0, failed: 0, fixed: 0 };\n\n for (const check of checks) {\n let results: CheckResult[];\n try {\n results = await Promise.race([\n check.run(ctx),\n new Promise<CheckResult[]>((_, reject) =>\n setTimeout(() => reject(new Error(\"timeout\")), CHECK_TIMEOUT_MS),\n ),\n ]);\n } catch {\n results = [{ status: \"fail\", message: `${check.name} check timed out` }];\n }\n\n for (const result of results) {\n if (result.fixable && result.fix) {\n if (result.fixRisk === \"safe\" && !this.dryRun) {\n try {\n const fixResult = await result.fix();\n if (fixResult.success) {\n result.message += ` → Fixed (${fixResult.message})`;\n result.status = \"warn\";\n delete result.fix;\n summary.fixed++;\n }\n } catch {\n // Fix failed, leave as-is\n }\n } else if (result.fixRisk === \"risky\") {\n pendingFixes.push({\n category: check.name,\n message: result.message,\n fix: result.fix,\n });\n }\n }\n\n if (result.status === \"pass\") summary.passed++;\n else if (result.status === \"warn\") summary.warnings++;\n else if (result.status === \"fail\") summary.failed++;\n }\n\n categories.push({ name: check.name, results });\n }\n\n return { categories, summary, pendingFixes };\n }\n\n private async buildContext(): Promise<DoctorContext> {\n const dataDir = path.join(os.homedir(), \".openacp\");\n const configPath = process.env.OPENACP_CONFIG_PATH || path.join(dataDir, \"config.json\");\n\n let config = null;\n let rawConfig: unknown = null;\n\n try {\n const content = fs.readFileSync(configPath, \"utf-8\");\n rawConfig = JSON.parse(content);\n const cm = new ConfigManager();\n await cm.load();\n config = cm.get();\n } catch {\n // Config may not exist or may be invalid — checks will handle this\n }\n\n const logsDir = config\n ? expandHome(config.logging.logDir)\n : path.join(dataDir, \"logs\");\n\n return {\n config,\n rawConfig,\n configPath,\n dataDir,\n sessionsPath: path.join(dataDir, \"sessions.json\"),\n pidPath: path.join(dataDir, \"openacp.pid\"),\n portFilePath: path.join(dataDir, \"api.port\"),\n pluginsDir: path.join(dataDir, \"plugins\"),\n logsDir,\n };\n }\n}\n\nexport type { DoctorReport, CategoryResult, PendingFix, CheckResult, DoctorContext } from \"./types.js\";\n","import * as fs from \"node:fs\";\nimport { ConfigSchema } from \"../../config/config.js\";\nimport { applyMigrations } from \"../../config/config-migrations.js\";\nimport type { DoctorCheck, CheckResult } from \"../types.js\";\n\nexport const configCheck: DoctorCheck = {\n name: \"Config\",\n order: 1,\n async run(ctx) {\n const results: CheckResult[] = [];\n\n if (!fs.existsSync(ctx.configPath)) {\n results.push({ status: \"fail\", message: \"Config file not found\" });\n return results;\n }\n results.push({ status: \"pass\", message: \"Config file exists\" });\n\n let raw: Record<string, unknown>;\n try {\n raw = JSON.parse(fs.readFileSync(ctx.configPath, \"utf-8\"));\n } catch (err) {\n results.push({\n status: \"fail\",\n message: `Config JSON invalid: ${err instanceof Error ? err.message : String(err)}`,\n });\n return results;\n }\n results.push({ status: \"pass\", message: \"JSON valid\" });\n\n const testRaw = structuredClone(raw);\n const { changed } = applyMigrations(testRaw);\n if (changed) {\n results.push({\n status: \"warn\",\n message: \"Pending config migrations\",\n fixable: true,\n fixRisk: \"safe\",\n fix: async () => {\n applyMigrations(raw);\n fs.writeFileSync(ctx.configPath, JSON.stringify(raw, null, 2));\n return { success: true, message: \"applied migrations\" };\n },\n });\n }\n\n const result = ConfigSchema.safeParse(raw);\n if (!result.success) {\n for (const issue of result.error.issues) {\n results.push({\n status: \"fail\",\n message: `Validation: ${issue.path.join(\".\")} — ${issue.message}`,\n });\n }\n } else {\n results.push({ status: \"pass\", message: \"Schema valid\" });\n }\n\n return results;\n },\n};\n","import { execFileSync } from \"node:child_process\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { DoctorCheck, CheckResult } from \"../types.js\";\n\nfunction commandExists(cmd: string): boolean {\n try {\n execFileSync(\"which\", [cmd], { stdio: \"pipe\" });\n return true;\n } catch {\n // not in PATH\n }\n let dir = process.cwd();\n while (true) {\n const binPath = path.join(dir, \"node_modules\", \".bin\", cmd);\n if (fs.existsSync(binPath)) return true;\n const parent = path.dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return false;\n}\n\nexport const agentsCheck: DoctorCheck = {\n name: \"Agents\",\n order: 2,\n async run(ctx) {\n const results: CheckResult[] = [];\n if (!ctx.config) {\n results.push({ status: \"fail\", message: \"Cannot check agents — config not loaded\" });\n return results;\n }\n\n const agents = ctx.config.agents;\n const defaultAgent = ctx.config.defaultAgent;\n\n if (!agents[defaultAgent]) {\n results.push({\n status: \"fail\",\n message: `Default agent \"${defaultAgent}\" not found in agents config`,\n });\n }\n\n for (const [name, agent] of Object.entries(agents)) {\n const isDefault = name === defaultAgent;\n if (commandExists(agent.command)) {\n results.push({\n status: \"pass\",\n message: `${agent.command} found${isDefault ? \" (default)\" : \"\"}`,\n });\n } else {\n results.push({\n status: isDefault ? \"fail\" : \"warn\",\n message: `${agent.command} not found in PATH${isDefault ? \" (default agent!)\" : \"\"}`,\n });\n }\n }\n\n return results;\n },\n};\n","import type { DoctorCheck, CheckResult } from \"../types.js\";\n\nconst BOT_TOKEN_REGEX = /^\\d+:[A-Za-z0-9_-]{35,}$/;\n\nexport const telegramCheck: DoctorCheck = {\n name: \"Telegram\",\n order: 3,\n async run(ctx) {\n const results: CheckResult[] = [];\n\n if (!ctx.config) {\n results.push({ status: \"fail\", message: \"Cannot check Telegram — config not loaded\" });\n return results;\n }\n\n const tgConfig = ctx.config.channels.telegram as Record<string, unknown> | undefined;\n if (!tgConfig || !tgConfig.enabled) {\n results.push({ status: \"pass\", message: \"Telegram not enabled (skipped)\" });\n return results;\n }\n\n const botToken = tgConfig.botToken as string | undefined;\n const chatId = tgConfig.chatId as number | undefined;\n\n if (!botToken || !BOT_TOKEN_REGEX.test(botToken)) {\n results.push({ status: \"fail\", message: \"Bot token format invalid\" });\n return results;\n }\n results.push({ status: \"pass\", message: \"Bot token format valid\" });\n\n let botId: number | undefined;\n try {\n const res = await fetch(`https://api.telegram.org/bot${botToken}/getMe`);\n const data = (await res.json()) as { ok: boolean; result?: { id: number; username: string }; description?: string };\n if (data.ok && data.result) {\n botId = data.result.id;\n results.push({ status: \"pass\", message: `Bot token valid (@${data.result.username})` });\n } else {\n results.push({ status: \"fail\", message: `Bot token rejected: ${data.description || \"unknown error\"}` });\n return results;\n }\n } catch (err) {\n results.push({ status: \"fail\", message: `Cannot reach Telegram API: ${err instanceof Error ? err.message : String(err)}` });\n return results;\n }\n\n if (!chatId || chatId === 0) {\n results.push({ status: \"fail\", message: \"Chat ID not configured\" });\n return results;\n }\n\n try {\n const res = await fetch(`https://api.telegram.org/bot${botToken}/getChat`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ chat_id: chatId }),\n });\n const data = (await res.json()) as {\n ok: boolean;\n result?: { type: string; is_forum?: boolean; title: string };\n description?: string;\n };\n if (!data.ok || !data.result) {\n results.push({ status: \"fail\", message: `Chat ID invalid: ${data.description || \"unknown error\"}` });\n return results;\n }\n if (data.result.type !== \"supergroup\") {\n results.push({ status: \"fail\", message: `Chat is \"${data.result.type}\", must be a supergroup` });\n return results;\n }\n if (!data.result.is_forum) {\n results.push({ status: \"warn\", message: \"Chat does not have topics enabled\" });\n } else {\n results.push({ status: \"pass\", message: `Chat is supergroup with topics (\"${data.result.title}\")` });\n }\n } catch (err) {\n results.push({ status: \"fail\", message: `Cannot validate chat: ${err instanceof Error ? err.message : String(err)}` });\n return results;\n }\n\n try {\n const res = await fetch(`https://api.telegram.org/bot${botToken}/getChatMember`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ chat_id: chatId, user_id: botId }),\n });\n const data = (await res.json()) as { ok: boolean; result?: { status: string }; description?: string };\n if (!data.ok || !data.result) {\n results.push({ status: \"fail\", message: `Cannot check bot membership: ${data.description || \"unknown\"}` });\n } else if (data.result.status === \"administrator\" || data.result.status === \"creator\") {\n results.push({ status: \"pass\", message: \"Bot is admin in group\" });\n } else {\n results.push({\n status: \"fail\",\n message: `Bot is \"${data.result.status}\" — must be admin. Promote bot in group settings.`,\n });\n }\n } catch (err) {\n results.push({ status: \"fail\", message: `Admin check failed: ${err instanceof Error ? err.message : String(err)}` });\n }\n\n return results;\n },\n};\n","import type { DoctorCheck, CheckResult } from \"../types.js\";\n\n// Discord bot tokens are base64-encoded and follow a recognizable pattern:\n// <user_id>.<timestamp>.<hmac> — the user_id part is a base64-encoded snowflake\nconst BOT_TOKEN_REGEX = /^[A-Za-z0-9_-]{24,28}\\.[A-Za-z0-9_-]{6,7}\\.[A-Za-z0-9_-]{27,}$/;\n\nexport const discordCheck: DoctorCheck = {\n name: \"Discord\",\n order: 3.5,\n async run(ctx) {\n const results: CheckResult[] = [];\n\n if (!ctx.config) {\n results.push({ status: \"fail\", message: \"Cannot check Discord — config not loaded\" });\n return results;\n }\n\n const discordConfig = (ctx.config.channels as Record<string, unknown>).discord as Record<string, unknown> | undefined;\n if (!discordConfig || !discordConfig.enabled) {\n results.push({ status: \"pass\", message: \"Discord not enabled (skipped)\" });\n return results;\n }\n\n // Check 1: Bot token format/presence\n const botToken = discordConfig.botToken as string | undefined;\n if (!botToken || !BOT_TOKEN_REGEX.test(botToken)) {\n results.push({ status: \"fail\", message: \"Discord bot token format invalid or missing\" });\n return results;\n }\n results.push({ status: \"pass\", message: \"Discord bot token format valid\" });\n\n // Check 2: Token validity via GET https://discord.com/api/v10/users/@me\n let botUsername: string | undefined;\n try {\n const res = await fetch(\"https://discord.com/api/v10/users/@me\", {\n headers: { Authorization: `Bot ${botToken}` },\n });\n if (res.status === 200) {\n const data = (await res.json()) as { username: string; id: string };\n botUsername = data.username;\n results.push({ status: \"pass\", message: `Bot token valid (@${data.username}, id: ${data.id})` });\n } else if (res.status === 401) {\n results.push({ status: \"fail\", message: \"Bot token rejected by Discord (401 Unauthorized)\" });\n return results;\n } else {\n const text = await res.text();\n results.push({ status: \"fail\", message: `Discord API error ${res.status}: ${text.slice(0, 100)}` });\n return results;\n }\n } catch (err) {\n results.push({ status: \"fail\", message: `Cannot reach Discord API: ${err instanceof Error ? err.message : String(err)}` });\n return results;\n }\n\n // Check 3: Guild access via GET https://discord.com/api/v10/guilds/{guildId}\n const guildId = discordConfig.guildId as string | undefined;\n if (!guildId) {\n results.push({ status: \"fail\", message: \"Guild ID not configured\" });\n return results;\n }\n\n try {\n const res = await fetch(`https://discord.com/api/v10/guilds/${guildId}`, {\n headers: { Authorization: `Bot ${botToken}` },\n });\n if (res.status === 200) {\n const data = (await res.json()) as { name: string; id: string };\n results.push({ status: \"pass\", message: `Bot has access to guild \"${data.name}\" (id: ${data.id})` });\n } else if (res.status === 403) {\n results.push({\n status: \"fail\",\n message: `Bot (${botUsername ?? \"unknown\"}) is not a member of guild ${guildId} or lacks access. Invite the bot to your server.`,\n });\n } else if (res.status === 404) {\n results.push({ status: \"fail\", message: `Guild ${guildId} not found — check the guild ID` });\n } else {\n const text = await res.text();\n results.push({ status: \"fail\", message: `Guild check error ${res.status}: ${text.slice(0, 100)}` });\n }\n } catch (err) {\n results.push({ status: \"fail\", message: `Cannot validate guild: ${err instanceof Error ? err.message : String(err)}` });\n }\n\n return results;\n },\n};\n","import * as fs from \"node:fs\";\nimport type { DoctorCheck, CheckResult } from \"../types.js\";\n\nexport const storageCheck: DoctorCheck = {\n name: \"Storage\",\n order: 4,\n async run(ctx) {\n const results: CheckResult[] = [];\n\n if (!fs.existsSync(ctx.dataDir)) {\n results.push({\n status: \"fail\",\n message: \"Data directory ~/.openacp does not exist\",\n fixable: true,\n fixRisk: \"safe\",\n fix: async () => {\n fs.mkdirSync(ctx.dataDir, { recursive: true });\n return { success: true, message: \"created directory\" };\n },\n });\n } else {\n try {\n fs.accessSync(ctx.dataDir, fs.constants.W_OK);\n results.push({ status: \"pass\", message: \"Data directory exists and writable\" });\n } catch {\n results.push({ status: \"fail\", message: \"Data directory not writable\" });\n }\n }\n\n if (fs.existsSync(ctx.sessionsPath)) {\n try {\n const content = fs.readFileSync(ctx.sessionsPath, \"utf-8\");\n const data = JSON.parse(content);\n if (typeof data === \"object\" && data !== null && \"sessions\" in data) {\n results.push({ status: \"pass\", message: \"Sessions file valid\" });\n } else {\n results.push({\n status: \"fail\",\n message: \"Sessions file has invalid structure\",\n fixable: true,\n fixRisk: \"risky\",\n fix: async () => {\n fs.writeFileSync(ctx.sessionsPath, JSON.stringify({ version: 1, sessions: {} }, null, 2));\n return { success: true, message: \"reset sessions file\" };\n },\n });\n }\n } catch {\n results.push({\n status: \"fail\",\n message: \"Sessions file corrupt (invalid JSON)\",\n fixable: true,\n fixRisk: \"risky\",\n fix: async () => {\n fs.writeFileSync(ctx.sessionsPath, JSON.stringify({ version: 1, sessions: {} }, null, 2));\n return { success: true, message: \"reset sessions file\" };\n },\n });\n }\n } else {\n results.push({ status: \"pass\", message: \"Sessions file not present yet (created on first session)\" });\n }\n\n if (!fs.existsSync(ctx.logsDir)) {\n results.push({\n status: \"warn\",\n message: \"Log directory does not exist\",\n fixable: true,\n fixRisk: \"safe\",\n fix: async () => {\n fs.mkdirSync(ctx.logsDir, { recursive: true });\n return { success: true, message: \"created log directory\" };\n },\n });\n } else {\n try {\n fs.accessSync(ctx.logsDir, fs.constants.W_OK);\n results.push({ status: \"pass\", message: \"Log directory exists and writable\" });\n } catch {\n results.push({ status: \"fail\", message: \"Log directory not writable\" });\n }\n }\n\n return results;\n },\n};\n","import * as fs from \"node:fs\";\nimport { expandHome } from \"../../config/config.js\";\nimport type { DoctorCheck, CheckResult } from \"../types.js\";\n\nexport const workspaceCheck: DoctorCheck = {\n name: \"Workspace\",\n order: 5,\n async run(ctx) {\n const results: CheckResult[] = [];\n\n if (!ctx.config) {\n results.push({ status: \"fail\", message: \"Cannot check workspace — config not loaded\" });\n return results;\n }\n\n const baseDir = expandHome(ctx.config.workspace.baseDir);\n\n if (!fs.existsSync(baseDir)) {\n results.push({\n status: \"warn\",\n message: `Workspace directory does not exist: ${baseDir}`,\n fixable: true,\n fixRisk: \"safe\",\n fix: async () => {\n fs.mkdirSync(baseDir, { recursive: true });\n return { success: true, message: \"created directory\" };\n },\n });\n } else {\n try {\n fs.accessSync(baseDir, fs.constants.W_OK);\n results.push({ status: \"pass\", message: `Workspace directory exists: ${baseDir}` });\n } catch {\n results.push({ status: \"fail\", message: `Workspace directory not writable: ${baseDir}` });\n }\n }\n\n return results;\n },\n};\n","import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { DoctorCheck, CheckResult } from \"../types.js\";\n\nexport const pluginsCheck: DoctorCheck = {\n name: \"Plugins\",\n order: 6,\n async run(ctx) {\n const results: CheckResult[] = [];\n\n if (!fs.existsSync(ctx.pluginsDir)) {\n results.push({\n status: \"warn\",\n message: \"Plugins directory does not exist\",\n fixable: true,\n fixRisk: \"safe\",\n fix: async () => {\n fs.mkdirSync(ctx.pluginsDir, { recursive: true });\n fs.writeFileSync(\n path.join(ctx.pluginsDir, \"package.json\"),\n JSON.stringify({ name: \"openacp-plugins\", private: true, dependencies: {} }, null, 2),\n );\n return { success: true, message: \"initialized plugins directory\" };\n },\n });\n return results;\n }\n results.push({ status: \"pass\", message: \"Plugins directory exists\" });\n\n const pkgPath = path.join(ctx.pluginsDir, \"package.json\");\n if (!fs.existsSync(pkgPath)) {\n results.push({\n status: \"warn\",\n message: \"Plugins package.json missing\",\n fixable: true,\n fixRisk: \"safe\",\n fix: async () => {\n fs.writeFileSync(\n pkgPath,\n JSON.stringify({ name: \"openacp-plugins\", private: true, dependencies: {} }, null, 2),\n );\n return { success: true, message: \"created package.json\" };\n },\n });\n return results;\n }\n\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n const deps = pkg.dependencies || {};\n const count = Object.keys(deps).length;\n results.push({ status: \"pass\", message: `Plugins package.json valid (${count} plugins)` });\n } catch {\n results.push({\n status: \"fail\",\n message: \"Plugins package.json is invalid JSON\",\n fixable: true,\n fixRisk: \"risky\",\n fix: async () => {\n fs.writeFileSync(\n pkgPath,\n JSON.stringify({ name: \"openacp-plugins\", private: true, dependencies: {} }, null, 2),\n );\n return { success: true, message: \"reset package.json\" };\n },\n });\n }\n\n return results;\n },\n};\n","import * as fs from \"node:fs\";\nimport * as net from \"node:net\";\nimport type { DoctorCheck, CheckResult } from \"../types.js\";\n\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction checkPortInUse(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const server = net.createServer();\n server.once(\"error\", () => resolve(true));\n server.once(\"listening\", () => {\n server.close();\n resolve(false);\n });\n server.listen(port, \"127.0.0.1\");\n });\n}\n\nexport const daemonCheck: DoctorCheck = {\n name: \"Daemon\",\n order: 7,\n async run(ctx) {\n const results: CheckResult[] = [];\n\n if (fs.existsSync(ctx.pidPath)) {\n const content = fs.readFileSync(ctx.pidPath, \"utf-8\").trim();\n const pid = parseInt(content, 10);\n if (isNaN(pid)) {\n results.push({\n status: \"warn\",\n message: \"PID file contains invalid data\",\n fixable: true,\n fixRisk: \"safe\",\n fix: async () => {\n fs.unlinkSync(ctx.pidPath);\n return { success: true, message: \"removed invalid PID file\" };\n },\n });\n } else if (!isProcessAlive(pid)) {\n results.push({\n status: \"warn\",\n message: `Stale PID file (PID ${pid} not running)`,\n fixable: true,\n fixRisk: \"safe\",\n fix: async () => {\n fs.unlinkSync(ctx.pidPath);\n return { success: true, message: \"removed stale PID file\" };\n },\n });\n } else {\n results.push({ status: \"pass\", message: `Daemon running (PID ${pid})` });\n }\n }\n\n if (fs.existsSync(ctx.portFilePath)) {\n const content = fs.readFileSync(ctx.portFilePath, \"utf-8\").trim();\n const port = parseInt(content, 10);\n if (isNaN(port)) {\n results.push({\n status: \"warn\",\n message: \"Port file contains invalid data\",\n fixable: true,\n fixRisk: \"safe\",\n fix: async () => {\n fs.unlinkSync(ctx.portFilePath);\n return { success: true, message: \"removed invalid port file\" };\n },\n });\n } else {\n results.push({ status: \"pass\", message: `Port file valid (port ${port})` });\n }\n }\n\n if (ctx.config) {\n const apiPort = ctx.config.api.port;\n const inUse = await checkPortInUse(apiPort);\n if (inUse) {\n if (fs.existsSync(ctx.pidPath)) {\n const pid = parseInt(fs.readFileSync(ctx.pidPath, \"utf-8\").trim(), 10);\n if (!isNaN(pid) && isProcessAlive(pid)) {\n results.push({ status: \"pass\", message: `API port ${apiPort} in use by OpenACP daemon` });\n } else {\n results.push({ status: \"warn\", message: `API port ${apiPort} in use by another process` });\n }\n } else {\n results.push({ status: \"warn\", message: `API port ${apiPort} in use by another process` });\n }\n } else {\n results.push({ status: \"pass\", message: `API port ${apiPort} available` });\n }\n }\n\n return results;\n },\n};\n","import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\nimport { execFileSync } from \"node:child_process\";\nimport type { DoctorCheck, CheckResult } from \"../types.js\";\n\nconst BIN_DIR = path.join(os.homedir(), \".openacp\", \"bin\");\nconst BIN_NAME = os.platform() === \"win32\" ? \"cloudflared.exe\" : \"cloudflared\";\nconst BIN_PATH = path.join(BIN_DIR, BIN_NAME);\n\nexport const tunnelCheck: DoctorCheck = {\n name: \"Tunnel\",\n order: 8,\n async run(ctx) {\n const results: CheckResult[] = [];\n\n if (!ctx.config) {\n results.push({ status: \"fail\", message: \"Cannot check tunnel — config not loaded\" });\n return results;\n }\n\n if (!ctx.config.tunnel.enabled) {\n results.push({ status: \"pass\", message: \"Tunnel not enabled (skipped)\" });\n return results;\n }\n\n const provider = ctx.config.tunnel.provider;\n results.push({ status: \"pass\", message: `Tunnel provider: ${provider}` });\n\n if (provider === \"cloudflare\") {\n let found = false;\n if (fs.existsSync(BIN_PATH)) {\n found = true;\n } else {\n try {\n execFileSync(\"which\", [\"cloudflared\"], { stdio: \"pipe\" });\n found = true;\n } catch {\n // not found\n }\n }\n\n if (found) {\n results.push({ status: \"pass\", message: \"cloudflared binary found\" });\n } else {\n results.push({\n status: \"warn\",\n message: \"cloudflared binary not found\",\n fixable: true,\n fixRisk: \"safe\",\n fix: async () => {\n try {\n const { ensureCloudflared } = await import(\"../../../plugins/tunnel/providers/install-cloudflared.js\");\n await ensureCloudflared();\n return { success: true, message: \"installed cloudflared\" };\n } catch (err) {\n return { success: false, message: err instanceof Error ? err.message : String(err) };\n }\n },\n });\n }\n }\n\n const tunnelPort = ctx.config.tunnel.port;\n if (tunnelPort < 1 || tunnelPort > 65535) {\n results.push({ status: \"fail\", message: `Invalid tunnel port: ${tunnelPort}` });\n } else {\n results.push({ status: \"pass\", message: `Tunnel port: ${tunnelPort}` });\n }\n\n return results;\n },\n};\n"],"mappings":";;;;;;;;AAAA,YAAYA,SAAQ;AACpB,YAAYC,WAAU;AACtB,YAAYC,SAAQ;;;ACFpB,YAAY,QAAQ;AAKb,IAAM,cAA2B;AAAA,EACtC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM,IAAI,KAAK;AACb,UAAM,UAAyB,CAAC;AAEhC,QAAI,CAAI,cAAW,IAAI,UAAU,GAAG;AAClC,cAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,wBAAwB,CAAC;AACjE,aAAO;AAAA,IACT;AACA,YAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,qBAAqB,CAAC;AAE9D,QAAI;AACJ,QAAI;AACF,YAAM,KAAK,MAAS,gBAAa,IAAI,YAAY,OAAO,CAAC;AAAA,IAC3D,SAAS,KAAK;AACZ,cAAQ,KAAK;AAAA,QACX,QAAQ;AAAA,QACR,SAAS,wBAAwB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MACnF,CAAC;AACD,aAAO;AAAA,IACT;AACA,YAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,aAAa,CAAC;AAEtD,UAAM,UAAU,gBAAgB,GAAG;AACnC,UAAM,EAAE,QAAQ,IAAI,gBAAgB,OAAO;AAC3C,QAAI,SAAS;AACX,cAAQ,KAAK;AAAA,QACX,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,SAAS;AAAA,QACT,SAAS;AAAA,QACT,KAAK,YAAY;AACf,0BAAgB,GAAG;AACnB,UAAG,iBAAc,IAAI,YAAY,KAAK,UAAU,KAAK,MAAM,CAAC,CAAC;AAC7D,iBAAO,EAAE,SAAS,MAAM,SAAS,qBAAqB;AAAA,QACxD;AAAA,MACF,CAAC;AAAA,IACH;AAEA,UAAM,SAAS,aAAa,UAAU,GAAG;AACzC,QAAI,CAAC,OAAO,SAAS;AACnB,iBAAW,SAAS,OAAO,MAAM,QAAQ;AACvC,gBAAQ,KAAK;AAAA,UACX,QAAQ;AAAA,UACR,SAAS,eAAe,MAAM,KAAK,KAAK,GAAG,CAAC,WAAM,MAAM,OAAO;AAAA,QACjE,CAAC;AAAA,MACH;AAAA,IACF,OAAO;AACL,cAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,eAAe,CAAC;AAAA,IAC1D;AAEA,WAAO;AAAA,EACT;AACF;;;AC3DA,SAAS,oBAAoB;AAC7B,YAAYC,SAAQ;AACpB,YAAY,UAAU;AAGtB,SAAS,cAAc,KAAsB;AAC3C,MAAI;AACF,iBAAa,SAAS,CAAC,GAAG,GAAG,EAAE,OAAO,OAAO,CAAC;AAC9C,WAAO;AAAA,EACT,QAAQ;AAAA,EAER;AACA,MAAI,MAAM,QAAQ,IAAI;AACtB,SAAO,MAAM;AACX,UAAM,UAAe,UAAK,KAAK,gBAAgB,QAAQ,GAAG;AAC1D,QAAO,eAAW,OAAO,EAAG,QAAO;AACnC,UAAM,SAAc,aAAQ,GAAG;AAC/B,QAAI,WAAW,IAAK;AACpB,UAAM;AAAA,EACR;AACA,SAAO;AACT;AAEO,IAAM,cAA2B;AAAA,EACtC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM,IAAI,KAAK;AACb,UAAM,UAAyB,CAAC;AAChC,QAAI,CAAC,IAAI,QAAQ;AACf,cAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,+CAA0C,CAAC;AACnF,aAAO;AAAA,IACT;AAEA,UAAM,SAAS,IAAI,OAAO;AAC1B,UAAM,eAAe,IAAI,OAAO;AAEhC,QAAI,CAAC,OAAO,YAAY,GAAG;AACzB,cAAQ,KAAK;AAAA,QACX,QAAQ;AAAA,QACR,SAAS,kBAAkB,YAAY;AAAA,MACzC,CAAC;AAAA,IACH;AAEA,eAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AAClD,YAAM,YAAY,SAAS;AAC3B,UAAI,cAAc,MAAM,OAAO,GAAG;AAChC,gBAAQ,KAAK;AAAA,UACX,QAAQ;AAAA,UACR,SAAS,GAAG,MAAM,OAAO,SAAS,YAAY,eAAe,EAAE;AAAA,QACjE,CAAC;AAAA,MACH,OAAO;AACL,gBAAQ,KAAK;AAAA,UACX,QAAQ,YAAY,SAAS;AAAA,UAC7B,SAAS,GAAG,MAAM,OAAO,qBAAqB,YAAY,sBAAsB,EAAE;AAAA,QACpF,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;;;AC1DA,IAAM,kBAAkB;AAEjB,IAAM,gBAA6B;AAAA,EACxC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM,IAAI,KAAK;AACb,UAAM,UAAyB,CAAC;AAEhC,QAAI,CAAC,IAAI,QAAQ;AACf,cAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,iDAA4C,CAAC;AACrF,aAAO;AAAA,IACT;AAEA,UAAM,WAAW,IAAI,OAAO,SAAS;AACrC,QAAI,CAAC,YAAY,CAAC,SAAS,SAAS;AAClC,cAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,iCAAiC,CAAC;AAC1E,aAAO;AAAA,IACT;AAEA,UAAM,WAAW,SAAS;AAC1B,UAAM,SAAS,SAAS;AAExB,QAAI,CAAC,YAAY,CAAC,gBAAgB,KAAK,QAAQ,GAAG;AAChD,cAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,2BAA2B,CAAC;AACpE,aAAO;AAAA,IACT;AACA,YAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,yBAAyB,CAAC;AAElE,QAAI;AACJ,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,+BAA+B,QAAQ,QAAQ;AACvE,YAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,UAAI,KAAK,MAAM,KAAK,QAAQ;AAC1B,gBAAQ,KAAK,OAAO;AACpB,gBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,qBAAqB,KAAK,OAAO,QAAQ,IAAI,CAAC;AAAA,MACxF,OAAO;AACL,gBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,uBAAuB,KAAK,eAAe,eAAe,GAAG,CAAC;AACtG,eAAO;AAAA,MACT;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,8BAA8B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,GAAG,CAAC;AAC1H,aAAO;AAAA,IACT;AAEA,QAAI,CAAC,UAAU,WAAW,GAAG;AAC3B,cAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,yBAAyB,CAAC;AAClE,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,+BAA+B,QAAQ,YAAY;AAAA,QACzE,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,SAAS,OAAO,CAAC;AAAA,MAC1C,CAAC;AACD,YAAM,OAAQ,MAAM,IAAI,KAAK;AAK7B,UAAI,CAAC,KAAK,MAAM,CAAC,KAAK,QAAQ;AAC5B,gBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,oBAAoB,KAAK,eAAe,eAAe,GAAG,CAAC;AACnG,eAAO;AAAA,MACT;AACA,UAAI,KAAK,OAAO,SAAS,cAAc;AACrC,gBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,YAAY,KAAK,OAAO,IAAI,0BAA0B,CAAC;AAC/F,eAAO;AAAA,MACT;AACA,UAAI,CAAC,KAAK,OAAO,UAAU;AACzB,gBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,oCAAoC,CAAC;AAAA,MAC/E,OAAO;AACL,gBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,oCAAoC,KAAK,OAAO,KAAK,KAAK,CAAC;AAAA,MACrG;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,yBAAyB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,GAAG,CAAC;AACrH,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,+BAA+B,QAAQ,kBAAkB;AAAA,QAC/E,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,SAAS,QAAQ,SAAS,MAAM,CAAC;AAAA,MAC1D,CAAC;AACD,YAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,UAAI,CAAC,KAAK,MAAM,CAAC,KAAK,QAAQ;AAC5B,gBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,gCAAgC,KAAK,eAAe,SAAS,GAAG,CAAC;AAAA,MAC3G,WAAW,KAAK,OAAO,WAAW,mBAAmB,KAAK,OAAO,WAAW,WAAW;AACrF,gBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,wBAAwB,CAAC;AAAA,MACnE,OAAO;AACL,gBAAQ,KAAK;AAAA,UACX,QAAQ;AAAA,UACR,SAAS,WAAW,KAAK,OAAO,MAAM;AAAA,QACxC,CAAC;AAAA,MACH;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,uBAAuB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,GAAG,CAAC;AAAA,IACrH;AAEA,WAAO;AAAA,EACT;AACF;;;ACnGA,IAAMC,mBAAkB;AAEjB,IAAM,eAA4B;AAAA,EACvC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM,IAAI,KAAK;AACb,UAAM,UAAyB,CAAC;AAEhC,QAAI,CAAC,IAAI,QAAQ;AACf,cAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,gDAA2C,CAAC;AACpF,aAAO;AAAA,IACT;AAEA,UAAM,gBAAiB,IAAI,OAAO,SAAqC;AACvE,QAAI,CAAC,iBAAiB,CAAC,cAAc,SAAS;AAC5C,cAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,gCAAgC,CAAC;AACzE,aAAO;AAAA,IACT;AAGA,UAAM,WAAW,cAAc;AAC/B,QAAI,CAAC,YAAY,CAACA,iBAAgB,KAAK,QAAQ,GAAG;AAChD,cAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,8CAA8C,CAAC;AACvF,aAAO;AAAA,IACT;AACA,YAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,iCAAiC,CAAC;AAG1E,QAAI;AACJ,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,yCAAyC;AAAA,QAC/D,SAAS,EAAE,eAAe,OAAO,QAAQ,GAAG;AAAA,MAC9C,CAAC;AACD,UAAI,IAAI,WAAW,KAAK;AACtB,cAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,sBAAc,KAAK;AACnB,gBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,qBAAqB,KAAK,QAAQ,SAAS,KAAK,EAAE,IAAI,CAAC;AAAA,MACjG,WAAW,IAAI,WAAW,KAAK;AAC7B,gBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,mDAAmD,CAAC;AAC5F,eAAO;AAAA,MACT,OAAO;AACL,cAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,gBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,qBAAqB,IAAI,MAAM,KAAK,KAAK,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC;AAClG,eAAO;AAAA,MACT;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,6BAA6B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,GAAG,CAAC;AACzH,aAAO;AAAA,IACT;AAGA,UAAM,UAAU,cAAc;AAC9B,QAAI,CAAC,SAAS;AACZ,cAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,0BAA0B,CAAC;AACnE,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,sCAAsC,OAAO,IAAI;AAAA,QACvE,SAAS,EAAE,eAAe,OAAO,QAAQ,GAAG;AAAA,MAC9C,CAAC;AACD,UAAI,IAAI,WAAW,KAAK;AACtB,cAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,gBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,4BAA4B,KAAK,IAAI,UAAU,KAAK,EAAE,IAAI,CAAC;AAAA,MACrG,WAAW,IAAI,WAAW,KAAK;AAC7B,gBAAQ,KAAK;AAAA,UACX,QAAQ;AAAA,UACR,SAAS,QAAQ,eAAe,SAAS,8BAA8B,OAAO;AAAA,QAChF,CAAC;AAAA,MACH,WAAW,IAAI,WAAW,KAAK;AAC7B,gBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,SAAS,OAAO,uCAAkC,CAAC;AAAA,MAC7F,OAAO;AACL,cAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,gBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,qBAAqB,IAAI,MAAM,KAAK,KAAK,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC;AAAA,MACpG;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,0BAA0B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,GAAG,CAAC;AAAA,IACxH;AAEA,WAAO;AAAA,EACT;AACF;;;ACrFA,YAAYC,SAAQ;AAGb,IAAM,eAA4B;AAAA,EACvC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM,IAAI,KAAK;AACb,UAAM,UAAyB,CAAC;AAEhC,QAAI,CAAI,eAAW,IAAI,OAAO,GAAG;AAC/B,cAAQ,KAAK;AAAA,QACX,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,SAAS;AAAA,QACT,SAAS;AAAA,QACT,KAAK,YAAY;AACf,UAAG,cAAU,IAAI,SAAS,EAAE,WAAW,KAAK,CAAC;AAC7C,iBAAO,EAAE,SAAS,MAAM,SAAS,oBAAoB;AAAA,QACvD;AAAA,MACF,CAAC;AAAA,IACH,OAAO;AACL,UAAI;AACF,QAAG,eAAW,IAAI,SAAY,cAAU,IAAI;AAC5C,gBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,qCAAqC,CAAC;AAAA,MAChF,QAAQ;AACN,gBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,8BAA8B,CAAC;AAAA,MACzE;AAAA,IACF;AAEA,QAAO,eAAW,IAAI,YAAY,GAAG;AACnC,UAAI;AACF,cAAM,UAAa,iBAAa,IAAI,cAAc,OAAO;AACzD,cAAM,OAAO,KAAK,MAAM,OAAO;AAC/B,YAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,cAAc,MAAM;AACnE,kBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,sBAAsB,CAAC;AAAA,QACjE,OAAO;AACL,kBAAQ,KAAK;AAAA,YACX,QAAQ;AAAA,YACR,SAAS;AAAA,YACT,SAAS;AAAA,YACT,SAAS;AAAA,YACT,KAAK,YAAY;AACf,cAAG,kBAAc,IAAI,cAAc,KAAK,UAAU,EAAE,SAAS,GAAG,UAAU,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC;AACxF,qBAAO,EAAE,SAAS,MAAM,SAAS,sBAAsB;AAAA,YACzD;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF,QAAQ;AACN,gBAAQ,KAAK;AAAA,UACX,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,SAAS;AAAA,UACT,SAAS;AAAA,UACT,KAAK,YAAY;AACf,YAAG,kBAAc,IAAI,cAAc,KAAK,UAAU,EAAE,SAAS,GAAG,UAAU,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC;AACxF,mBAAO,EAAE,SAAS,MAAM,SAAS,sBAAsB;AAAA,UACzD;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,OAAO;AACL,cAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,2DAA2D,CAAC;AAAA,IACtG;AAEA,QAAI,CAAI,eAAW,IAAI,OAAO,GAAG;AAC/B,cAAQ,KAAK;AAAA,QACX,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,SAAS;AAAA,QACT,SAAS;AAAA,QACT,KAAK,YAAY;AACf,UAAG,cAAU,IAAI,SAAS,EAAE,WAAW,KAAK,CAAC;AAC7C,iBAAO,EAAE,SAAS,MAAM,SAAS,wBAAwB;AAAA,QAC3D;AAAA,MACF,CAAC;AAAA,IACH,OAAO;AACL,UAAI;AACF,QAAG,eAAW,IAAI,SAAY,cAAU,IAAI;AAC5C,gBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,oCAAoC,CAAC;AAAA,MAC/E,QAAQ;AACN,gBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,6BAA6B,CAAC;AAAA,MACxE;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;;;ACrFA,YAAYC,SAAQ;AAIb,IAAM,iBAA8B;AAAA,EACzC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM,IAAI,KAAK;AACb,UAAM,UAAyB,CAAC;AAEhC,QAAI,CAAC,IAAI,QAAQ;AACf,cAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,kDAA6C,CAAC;AACtF,aAAO;AAAA,IACT;AAEA,UAAM,UAAU,WAAW,IAAI,OAAO,UAAU,OAAO;AAEvD,QAAI,CAAI,eAAW,OAAO,GAAG;AAC3B,cAAQ,KAAK;AAAA,QACX,QAAQ;AAAA,QACR,SAAS,uCAAuC,OAAO;AAAA,QACvD,SAAS;AAAA,QACT,SAAS;AAAA,QACT,KAAK,YAAY;AACf,UAAG,cAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AACzC,iBAAO,EAAE,SAAS,MAAM,SAAS,oBAAoB;AAAA,QACvD;AAAA,MACF,CAAC;AAAA,IACH,OAAO;AACL,UAAI;AACF,QAAG,eAAW,SAAY,cAAU,IAAI;AACxC,gBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,+BAA+B,OAAO,GAAG,CAAC;AAAA,MACpF,QAAQ;AACN,gBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,qCAAqC,OAAO,GAAG,CAAC;AAAA,MAC1F;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;;;ACvCA,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AAGf,IAAM,eAA4B;AAAA,EACvC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM,IAAI,KAAK;AACb,UAAM,UAAyB,CAAC;AAEhC,QAAI,CAAI,eAAW,IAAI,UAAU,GAAG;AAClC,cAAQ,KAAK;AAAA,QACX,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,SAAS;AAAA,QACT,SAAS;AAAA,QACT,KAAK,YAAY;AACf,UAAG,cAAU,IAAI,YAAY,EAAE,WAAW,KAAK,CAAC;AAChD,UAAG;AAAA,YACI,WAAK,IAAI,YAAY,cAAc;AAAA,YACxC,KAAK,UAAU,EAAE,MAAM,mBAAmB,SAAS,MAAM,cAAc,CAAC,EAAE,GAAG,MAAM,CAAC;AAAA,UACtF;AACA,iBAAO,EAAE,SAAS,MAAM,SAAS,gCAAgC;AAAA,QACnE;AAAA,MACF,CAAC;AACD,aAAO;AAAA,IACT;AACA,YAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,2BAA2B,CAAC;AAEpE,UAAM,UAAe,WAAK,IAAI,YAAY,cAAc;AACxD,QAAI,CAAI,eAAW,OAAO,GAAG;AAC3B,cAAQ,KAAK;AAAA,QACX,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,SAAS;AAAA,QACT,SAAS;AAAA,QACT,KAAK,YAAY;AACf,UAAG;AAAA,YACD;AAAA,YACA,KAAK,UAAU,EAAE,MAAM,mBAAmB,SAAS,MAAM,cAAc,CAAC,EAAE,GAAG,MAAM,CAAC;AAAA,UACtF;AACA,iBAAO,EAAE,SAAS,MAAM,SAAS,uBAAuB;AAAA,QAC1D;AAAA,MACF,CAAC;AACD,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,MAAM,KAAK,MAAS,iBAAa,SAAS,OAAO,CAAC;AACxD,YAAM,OAAO,IAAI,gBAAgB,CAAC;AAClC,YAAM,QAAQ,OAAO,KAAK,IAAI,EAAE;AAChC,cAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,+BAA+B,KAAK,YAAY,CAAC;AAAA,IAC3F,QAAQ;AACN,cAAQ,KAAK;AAAA,QACX,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,SAAS;AAAA,QACT,SAAS;AAAA,QACT,KAAK,YAAY;AACf,UAAG;AAAA,YACD;AAAA,YACA,KAAK,UAAU,EAAE,MAAM,mBAAmB,SAAS,MAAM,cAAc,CAAC,EAAE,GAAG,MAAM,CAAC;AAAA,UACtF;AACA,iBAAO,EAAE,SAAS,MAAM,SAAS,qBAAqB;AAAA,QACxD;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AACF;;;ACtEA,YAAYC,SAAQ;AACpB,YAAY,SAAS;AAGrB,SAAS,eAAe,KAAsB;AAC5C,MAAI;AACF,YAAQ,KAAK,KAAK,CAAC;AACnB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,eAAe,MAAgC;AACtD,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAM,SAAa,iBAAa;AAChC,WAAO,KAAK,SAAS,MAAM,QAAQ,IAAI,CAAC;AACxC,WAAO,KAAK,aAAa,MAAM;AAC7B,aAAO,MAAM;AACb,cAAQ,KAAK;AAAA,IACf,CAAC;AACD,WAAO,OAAO,MAAM,WAAW;AAAA,EACjC,CAAC;AACH;AAEO,IAAM,cAA2B;AAAA,EACtC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM,IAAI,KAAK;AACb,UAAM,UAAyB,CAAC;AAEhC,QAAO,eAAW,IAAI,OAAO,GAAG;AAC9B,YAAM,UAAa,iBAAa,IAAI,SAAS,OAAO,EAAE,KAAK;AAC3D,YAAM,MAAM,SAAS,SAAS,EAAE;AAChC,UAAI,MAAM,GAAG,GAAG;AACd,gBAAQ,KAAK;AAAA,UACX,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,SAAS;AAAA,UACT,SAAS;AAAA,UACT,KAAK,YAAY;AACf,YAAG,eAAW,IAAI,OAAO;AACzB,mBAAO,EAAE,SAAS,MAAM,SAAS,2BAA2B;AAAA,UAC9D;AAAA,QACF,CAAC;AAAA,MACH,WAAW,CAAC,eAAe,GAAG,GAAG;AAC/B,gBAAQ,KAAK;AAAA,UACX,QAAQ;AAAA,UACR,SAAS,uBAAuB,GAAG;AAAA,UACnC,SAAS;AAAA,UACT,SAAS;AAAA,UACT,KAAK,YAAY;AACf,YAAG,eAAW,IAAI,OAAO;AACzB,mBAAO,EAAE,SAAS,MAAM,SAAS,yBAAyB;AAAA,UAC5D;AAAA,QACF,CAAC;AAAA,MACH,OAAO;AACL,gBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,uBAAuB,GAAG,IAAI,CAAC;AAAA,MACzE;AAAA,IACF;AAEA,QAAO,eAAW,IAAI,YAAY,GAAG;AACnC,YAAM,UAAa,iBAAa,IAAI,cAAc,OAAO,EAAE,KAAK;AAChE,YAAM,OAAO,SAAS,SAAS,EAAE;AACjC,UAAI,MAAM,IAAI,GAAG;AACf,gBAAQ,KAAK;AAAA,UACX,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,SAAS;AAAA,UACT,SAAS;AAAA,UACT,KAAK,YAAY;AACf,YAAG,eAAW,IAAI,YAAY;AAC9B,mBAAO,EAAE,SAAS,MAAM,SAAS,4BAA4B;AAAA,UAC/D;AAAA,QACF,CAAC;AAAA,MACH,OAAO;AACL,gBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,yBAAyB,IAAI,IAAI,CAAC;AAAA,MAC5E;AAAA,IACF;AAEA,QAAI,IAAI,QAAQ;AACd,YAAM,UAAU,IAAI,OAAO,IAAI;AAC/B,YAAM,QAAQ,MAAM,eAAe,OAAO;AAC1C,UAAI,OAAO;AACT,YAAO,eAAW,IAAI,OAAO,GAAG;AAC9B,gBAAM,MAAM,SAAY,iBAAa,IAAI,SAAS,OAAO,EAAE,KAAK,GAAG,EAAE;AACrE,cAAI,CAAC,MAAM,GAAG,KAAK,eAAe,GAAG,GAAG;AACtC,oBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,YAAY,OAAO,4BAA4B,CAAC;AAAA,UAC1F,OAAO;AACL,oBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,YAAY,OAAO,6BAA6B,CAAC;AAAA,UAC3F;AAAA,QACF,OAAO;AACL,kBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,YAAY,OAAO,6BAA6B,CAAC;AAAA,QAC3F;AAAA,MACF,OAAO;AACL,gBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,YAAY,OAAO,aAAa,CAAC;AAAA,MAC3E;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;;;ACrGA,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AACtB,YAAY,QAAQ;AACpB,SAAS,gBAAAC,qBAAoB;AAG7B,IAAM,UAAe,WAAQ,WAAQ,GAAG,YAAY,KAAK;AACzD,IAAM,WAAc,YAAS,MAAM,UAAU,oBAAoB;AACjE,IAAM,WAAgB,WAAK,SAAS,QAAQ;AAErC,IAAM,cAA2B;AAAA,EACtC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM,IAAI,KAAK;AACb,UAAM,UAAyB,CAAC;AAEhC,QAAI,CAAC,IAAI,QAAQ;AACf,cAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,+CAA0C,CAAC;AACnF,aAAO;AAAA,IACT;AAEA,QAAI,CAAC,IAAI,OAAO,OAAO,SAAS;AAC9B,cAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,+BAA+B,CAAC;AACxE,aAAO;AAAA,IACT;AAEA,UAAM,WAAW,IAAI,OAAO,OAAO;AACnC,YAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,oBAAoB,QAAQ,GAAG,CAAC;AAExE,QAAI,aAAa,cAAc;AAC7B,UAAI,QAAQ;AACZ,UAAO,eAAW,QAAQ,GAAG;AAC3B,gBAAQ;AAAA,MACV,OAAO;AACL,YAAI;AACF,UAAAA,cAAa,SAAS,CAAC,aAAa,GAAG,EAAE,OAAO,OAAO,CAAC;AACxD,kBAAQ;AAAA,QACV,QAAQ;AAAA,QAER;AAAA,MACF;AAEA,UAAI,OAAO;AACT,gBAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,2BAA2B,CAAC;AAAA,MACtE,OAAO;AACL,gBAAQ,KAAK;AAAA,UACX,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,SAAS;AAAA,UACT,SAAS;AAAA,UACT,KAAK,YAAY;AACf,gBAAI;AACF,oBAAM,EAAE,kBAAkB,IAAI,MAAM,OAAO,mCAA0D;AACrG,oBAAM,kBAAkB;AACxB,qBAAO,EAAE,SAAS,MAAM,SAAS,wBAAwB;AAAA,YAC3D,SAAS,KAAK;AACZ,qBAAO,EAAE,SAAS,OAAO,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,EAAE;AAAA,YACrF;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAEA,UAAM,aAAa,IAAI,OAAO,OAAO;AACrC,QAAI,aAAa,KAAK,aAAa,OAAO;AACxC,cAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,wBAAwB,UAAU,GAAG,CAAC;AAAA,IAChF,OAAO;AACL,cAAQ,KAAK,EAAE,QAAQ,QAAQ,SAAS,gBAAgB,UAAU,GAAG,CAAC;AAAA,IACxE;AAEA,WAAO;AAAA,EACT;AACF;;;ATxDA,IAAM,aAA4B;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,mBAAmB;AAElB,IAAM,eAAN,MAAmB;AAAA,EAChB;AAAA,EAER,YAAY,SAAgC;AAC1C,SAAK,SAAS,SAAS,UAAU;AAAA,EACnC;AAAA,EAEA,MAAM,SAAgC;AACpC,UAAM,MAAM,MAAM,KAAK,aAAa;AACpC,UAAM,SAAS,CAAC,GAAG,UAAU,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAE/D,UAAM,aAA+B,CAAC;AACtC,UAAM,eAA6B,CAAC;AACpC,UAAM,UAAU,EAAE,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,OAAO,EAAE;AAE9D,eAAW,SAAS,QAAQ;AAC1B,UAAI;AACJ,UAAI;AACF,kBAAU,MAAM,QAAQ,KAAK;AAAA,UAC3B,MAAM,IAAI,GAAG;AAAA,UACb,IAAI;AAAA,YAAuB,CAAC,GAAG,WAC7B,WAAW,MAAM,OAAO,IAAI,MAAM,SAAS,CAAC,GAAG,gBAAgB;AAAA,UACjE;AAAA,QACF,CAAC;AAAA,MACH,QAAQ;AACN,kBAAU,CAAC,EAAE,QAAQ,QAAQ,SAAS,GAAG,MAAM,IAAI,mBAAmB,CAAC;AAAA,MACzE;AAEA,iBAAW,UAAU,SAAS;AAC5B,YAAI,OAAO,WAAW,OAAO,KAAK;AAChC,cAAI,OAAO,YAAY,UAAU,CAAC,KAAK,QAAQ;AAC7C,gBAAI;AACF,oBAAM,YAAY,MAAM,OAAO,IAAI;AACnC,kBAAI,UAAU,SAAS;AACrB,uBAAO,WAAW,kBAAa,UAAU,OAAO;AAChD,uBAAO,SAAS;AAChB,uBAAO,OAAO;AACd,wBAAQ;AAAA,cACV;AAAA,YACF,QAAQ;AAAA,YAER;AAAA,UACF,WAAW,OAAO,YAAY,SAAS;AACrC,yBAAa,KAAK;AAAA,cAChB,UAAU,MAAM;AAAA,cAChB,SAAS,OAAO;AAAA,cAChB,KAAK,OAAO;AAAA,YACd,CAAC;AAAA,UACH;AAAA,QACF;AAEA,YAAI,OAAO,WAAW,OAAQ,SAAQ;AAAA,iBAC7B,OAAO,WAAW,OAAQ,SAAQ;AAAA,iBAClC,OAAO,WAAW,OAAQ,SAAQ;AAAA,MAC7C;AAEA,iBAAW,KAAK,EAAE,MAAM,MAAM,MAAM,QAAQ,CAAC;AAAA,IAC/C;AAEA,WAAO,EAAE,YAAY,SAAS,aAAa;AAAA,EAC7C;AAAA,EAEA,MAAc,eAAuC;AACnD,UAAM,UAAe,WAAQ,YAAQ,GAAG,UAAU;AAClD,UAAM,aAAa,QAAQ,IAAI,uBAA4B,WAAK,SAAS,aAAa;AAEtF,QAAI,SAAS;AACb,QAAI,YAAqB;AAEzB,QAAI;AACF,YAAM,UAAa,iBAAa,YAAY,OAAO;AACnD,kBAAY,KAAK,MAAM,OAAO;AAC9B,YAAM,KAAK,IAAI,cAAc;AAC7B,YAAM,GAAG,KAAK;AACd,eAAS,GAAG,IAAI;AAAA,IAClB,QAAQ;AAAA,IAER;AAEA,UAAM,UAAU,SACZ,WAAW,OAAO,QAAQ,MAAM,IAC3B,WAAK,SAAS,MAAM;AAE7B,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,cAAmB,WAAK,SAAS,eAAe;AAAA,MAChD,SAAc,WAAK,SAAS,aAAa;AAAA,MACzC,cAAmB,WAAK,SAAS,UAAU;AAAA,MAC3C,YAAiB,WAAK,SAAS,SAAS;AAAA,MACxC;AAAA,IACF;AAAA,EACF;AACF;","names":["fs","path","os","fs","BOT_TOKEN_REGEX","fs","fs","fs","path","fs","fs","path","execFileSync"]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// src/plugins/security/security-guard.ts
|
|
2
|
+
var SecurityGuard = class {
|
|
3
|
+
constructor(configManager, sessionManager) {
|
|
4
|
+
this.configManager = configManager;
|
|
5
|
+
this.sessionManager = sessionManager;
|
|
6
|
+
}
|
|
7
|
+
checkAccess(message) {
|
|
8
|
+
const config = this.configManager.get();
|
|
9
|
+
if (config.security.allowedUserIds.length > 0) {
|
|
10
|
+
const userId = String(message.userId);
|
|
11
|
+
if (!config.security.allowedUserIds.includes(userId)) {
|
|
12
|
+
return { allowed: false, reason: "Unauthorized user" };
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const active = this.sessionManager.listSessions().filter((s) => s.status === "active" || s.status === "initializing");
|
|
16
|
+
if (active.length >= config.security.maxConcurrentSessions) {
|
|
17
|
+
return { allowed: false, reason: `Session limit reached (${config.security.maxConcurrentSessions})` };
|
|
18
|
+
}
|
|
19
|
+
return { allowed: true };
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export {
|
|
24
|
+
SecurityGuard
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=chunk-LGFWH3AE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/plugins/security/security-guard.ts"],"sourcesContent":["import type { ConfigManager } from \"../../core/config/config.js\";\nimport type { SessionManager } from \"../../core/sessions/session-manager.js\";\nimport type { IncomingMessage } from \"../../core/types.js\";\n\nexport class SecurityGuard {\n constructor(\n private configManager: ConfigManager,\n private sessionManager: SessionManager,\n ) {}\n\n checkAccess(message: IncomingMessage):\n | { allowed: true }\n | { allowed: false; reason: string }\n {\n const config = this.configManager.get();\n if (config.security.allowedUserIds.length > 0) {\n const userId = String(message.userId);\n if (!config.security.allowedUserIds.includes(userId)) {\n return { allowed: false, reason: \"Unauthorized user\" };\n }\n }\n const active = this.sessionManager.listSessions()\n .filter(s => s.status === \"active\" || s.status === \"initializing\");\n if (active.length >= config.security.maxConcurrentSessions) {\n return { allowed: false, reason: `Session limit reached (${config.security.maxConcurrentSessions})` };\n }\n return { allowed: true };\n }\n}\n"],"mappings":";AAIO,IAAM,gBAAN,MAAoB;AAAA,EACzB,YACU,eACA,gBACR;AAFQ;AACA;AAAA,EACP;AAAA,EAEH,YAAY,SAGZ;AACE,UAAM,SAAS,KAAK,cAAc,IAAI;AACtC,QAAI,OAAO,SAAS,eAAe,SAAS,GAAG;AAC7C,YAAM,SAAS,OAAO,QAAQ,MAAM;AACpC,UAAI,CAAC,OAAO,SAAS,eAAe,SAAS,MAAM,GAAG;AACpD,eAAO,EAAE,SAAS,OAAO,QAAQ,oBAAoB;AAAA,MACvD;AAAA,IACF;AACA,UAAM,SAAS,KAAK,eAAe,aAAa,EAC7C,OAAO,OAAK,EAAE,WAAW,YAAY,EAAE,WAAW,cAAc;AACnE,QAAI,OAAO,UAAU,OAAO,SAAS,uBAAuB;AAC1D,aAAO,EAAE,SAAS,OAAO,QAAQ,0BAA0B,OAAO,SAAS,qBAAqB,IAAI;AAAA,IACtG;AACA,WAAO,EAAE,SAAS,KAAK;AAAA,EACzB;AACF;","names":[]}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// src/core/plugin/settings-manager.ts
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
var SettingsManager = class {
|
|
5
|
+
constructor(basePath) {
|
|
6
|
+
this.basePath = basePath;
|
|
7
|
+
}
|
|
8
|
+
getBasePath() {
|
|
9
|
+
return this.basePath;
|
|
10
|
+
}
|
|
11
|
+
createAPI(pluginName) {
|
|
12
|
+
const settingsPath = this.getSettingsPath(pluginName);
|
|
13
|
+
return new SettingsAPIImpl(settingsPath);
|
|
14
|
+
}
|
|
15
|
+
async loadSettings(pluginName) {
|
|
16
|
+
const settingsPath = this.getSettingsPath(pluginName);
|
|
17
|
+
try {
|
|
18
|
+
const content = fs.readFileSync(settingsPath, "utf-8");
|
|
19
|
+
return JSON.parse(content);
|
|
20
|
+
} catch {
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
validateSettings(_pluginName, settings, schema) {
|
|
25
|
+
if (!schema) return { valid: true };
|
|
26
|
+
const result = schema.safeParse(settings);
|
|
27
|
+
if (result.success) return { valid: true };
|
|
28
|
+
return {
|
|
29
|
+
valid: false,
|
|
30
|
+
errors: result.error.errors.map(
|
|
31
|
+
(e) => `${e.path.join(".")}: ${e.message}`
|
|
32
|
+
)
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
getSettingsPath(pluginName) {
|
|
36
|
+
return path.join(this.basePath, pluginName, "settings.json");
|
|
37
|
+
}
|
|
38
|
+
async getPluginSettings(pluginName) {
|
|
39
|
+
return this.loadSettings(pluginName);
|
|
40
|
+
}
|
|
41
|
+
async updatePluginSettings(pluginName, updates) {
|
|
42
|
+
const api = this.createAPI(pluginName);
|
|
43
|
+
const current = await api.getAll();
|
|
44
|
+
await api.setAll({ ...current, ...updates });
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
var SettingsAPIImpl = class {
|
|
48
|
+
constructor(settingsPath) {
|
|
49
|
+
this.settingsPath = settingsPath;
|
|
50
|
+
}
|
|
51
|
+
cache = null;
|
|
52
|
+
readFile() {
|
|
53
|
+
if (this.cache !== null) return this.cache;
|
|
54
|
+
try {
|
|
55
|
+
const content = fs.readFileSync(this.settingsPath, "utf-8");
|
|
56
|
+
this.cache = JSON.parse(content);
|
|
57
|
+
return this.cache;
|
|
58
|
+
} catch {
|
|
59
|
+
this.cache = {};
|
|
60
|
+
return this.cache;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
writeFile(data) {
|
|
64
|
+
const dir = path.dirname(this.settingsPath);
|
|
65
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
66
|
+
fs.writeFileSync(this.settingsPath, JSON.stringify(data, null, 2));
|
|
67
|
+
this.cache = data;
|
|
68
|
+
}
|
|
69
|
+
async get(key) {
|
|
70
|
+
const data = this.readFile();
|
|
71
|
+
return data[key];
|
|
72
|
+
}
|
|
73
|
+
async set(key, value) {
|
|
74
|
+
const data = this.readFile();
|
|
75
|
+
data[key] = value;
|
|
76
|
+
this.writeFile(data);
|
|
77
|
+
}
|
|
78
|
+
async getAll() {
|
|
79
|
+
return { ...this.readFile() };
|
|
80
|
+
}
|
|
81
|
+
async setAll(settings) {
|
|
82
|
+
this.writeFile({ ...settings });
|
|
83
|
+
}
|
|
84
|
+
async delete(key) {
|
|
85
|
+
const data = this.readFile();
|
|
86
|
+
delete data[key];
|
|
87
|
+
this.writeFile(data);
|
|
88
|
+
}
|
|
89
|
+
async clear() {
|
|
90
|
+
this.writeFile({});
|
|
91
|
+
}
|
|
92
|
+
async has(key) {
|
|
93
|
+
const data = this.readFile();
|
|
94
|
+
return key in data;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export {
|
|
99
|
+
SettingsManager
|
|
100
|
+
};
|
|
101
|
+
//# sourceMappingURL=chunk-MLF4W5R6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/plugin/settings-manager.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport type { SettingsAPI } from './types.js'\nimport type { ZodSchema } from 'zod'\n\nexport interface ValidationResult {\n valid: boolean\n errors?: string[]\n}\n\nexport class SettingsManager {\n constructor(private basePath: string) {}\n\n getBasePath(): string {\n return this.basePath\n }\n\n createAPI(pluginName: string): SettingsAPI {\n const settingsPath = this.getSettingsPath(pluginName)\n return new SettingsAPIImpl(settingsPath)\n }\n\n async loadSettings(pluginName: string): Promise<Record<string, unknown>> {\n const settingsPath = this.getSettingsPath(pluginName)\n try {\n const content = fs.readFileSync(settingsPath, 'utf-8')\n return JSON.parse(content)\n } catch {\n return {}\n }\n }\n\n validateSettings(\n _pluginName: string,\n settings: unknown,\n schema?: ZodSchema,\n ): ValidationResult {\n if (!schema) return { valid: true }\n const result = schema.safeParse(settings)\n if (result.success) return { valid: true }\n return {\n valid: false,\n errors: result.error.errors.map(\n (e: { path: (string | number)[]; message: string }) =>\n `${e.path.join('.')}: ${e.message}`,\n ),\n }\n }\n\n getSettingsPath(pluginName: string): string {\n return path.join(this.basePath, pluginName, 'settings.json')\n }\n\n async getPluginSettings(pluginName: string): Promise<Record<string, unknown>> {\n return this.loadSettings(pluginName)\n }\n\n async updatePluginSettings(pluginName: string, updates: Record<string, unknown>): Promise<void> {\n const api = this.createAPI(pluginName)\n const current = await api.getAll()\n await api.setAll({ ...current, ...updates })\n }\n}\n\nclass SettingsAPIImpl implements SettingsAPI {\n private cache: Record<string, unknown> | null = null\n\n constructor(private settingsPath: string) {}\n\n private readFile(): Record<string, unknown> {\n if (this.cache !== null) return this.cache\n try {\n const content = fs.readFileSync(this.settingsPath, 'utf-8')\n this.cache = JSON.parse(content)\n return this.cache!\n } catch {\n this.cache = {}\n return this.cache\n }\n }\n\n private writeFile(data: Record<string, unknown>): void {\n const dir = path.dirname(this.settingsPath)\n fs.mkdirSync(dir, { recursive: true })\n fs.writeFileSync(this.settingsPath, JSON.stringify(data, null, 2))\n this.cache = data\n }\n\n async get<T = unknown>(key: string): Promise<T | undefined> {\n const data = this.readFile()\n return data[key] as T | undefined\n }\n\n async set<T = unknown>(key: string, value: T): Promise<void> {\n const data = this.readFile()\n data[key] = value\n this.writeFile(data)\n }\n\n async getAll(): Promise<Record<string, unknown>> {\n return { ...this.readFile() }\n }\n\n async setAll(settings: Record<string, unknown>): Promise<void> {\n this.writeFile({ ...settings })\n }\n\n async delete(key: string): Promise<void> {\n const data = this.readFile()\n delete data[key]\n this.writeFile(data)\n }\n\n async clear(): Promise<void> {\n this.writeFile({})\n }\n\n async has(key: string): Promise<boolean> {\n const data = this.readFile()\n return key in data\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
log
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-XMMAGAT4.js";
|
|
4
4
|
|
|
5
|
-
// src/
|
|
5
|
+
// src/plugins/discord/commands/admin.ts
|
|
6
6
|
import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
|
|
7
7
|
async function handleDangerous(interaction, adapter) {
|
|
8
8
|
await interaction.deferReply({ ephemeral: true });
|
|
@@ -216,4 +216,4 @@ export {
|
|
|
216
216
|
handleUpdate,
|
|
217
217
|
handleVerbosity
|
|
218
218
|
};
|
|
219
|
-
//# sourceMappingURL=chunk-
|
|
219
|
+
//# sourceMappingURL=chunk-MTSDOSXS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/plugins/discord/commands/admin.ts"],"sourcesContent":["import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from \"discord.js\";\nimport type {\n ChatInputCommandInteraction,\n ButtonInteraction,\n} from \"discord.js\";\nimport { log } from \"../../../core/utils/log.js\";\nimport type { DiscordAdapter } from \"../adapter.js\";\n\nexport async function handleDangerous(\n interaction: ChatInputCommandInteraction,\n adapter: DiscordAdapter,\n): Promise<void> {\n await interaction.deferReply({ ephemeral: true });\n\n const channelId = interaction.channelId;\n const session = adapter.core.sessionManager.getSessionByThread(\n \"discord\",\n channelId,\n );\n\n if (session) {\n session.dangerousMode = !session.dangerousMode;\n adapter.core.sessionManager\n .patchRecord(session.id, { dangerousMode: session.dangerousMode })\n .catch(() => {});\n log.info(\n { sessionId: session.id, dangerousMode: session.dangerousMode },\n \"[discord-admin] Dangerous mode toggled via command\",\n );\n\n const msg = session.dangerousMode\n ? \"☠️ **Dangerous mode enabled** — All permission requests will be auto-approved.\"\n : \"🔐 **Dangerous mode disabled** — Permission requests will be shown normally.\";\n await interaction.editReply(msg);\n return;\n }\n\n // Session not in memory — update store directly\n const record = adapter.core.sessionManager.getRecordByThread(\n \"discord\",\n channelId,\n );\n if (!record || record.status === \"cancelled\" || record.status === \"error\") {\n await interaction.editReply(\"⚠️ No active session in this channel.\");\n return;\n }\n\n const newDangerousMode = !(record.dangerousMode ?? false);\n adapter.core.sessionManager\n .patchRecord(record.sessionId, { dangerousMode: newDangerousMode })\n .catch(() => {});\n log.info(\n { sessionId: record.sessionId, dangerousMode: newDangerousMode },\n \"[discord-admin] Dangerous mode toggled via command (store-only)\",\n );\n\n const msg = newDangerousMode\n ? \"☠️ **Dangerous mode enabled** — All permission requests will be auto-approved.\"\n : \"🔐 **Dangerous mode disabled** — Permission requests will be shown normally.\";\n await interaction.editReply(msg);\n}\n\nexport async function handleDangerousButton(\n interaction: ButtonInteraction,\n adapter: DiscordAdapter,\n): Promise<void> {\n const sessionId = interaction.customId.slice(2); // strip 'd:'\n const session = adapter.core.sessionManager.getSession(sessionId);\n\n // Session live in memory — toggle directly\n if (session) {\n session.dangerousMode = !session.dangerousMode;\n adapter.core.sessionManager\n .patchRecord(sessionId, { dangerousMode: session.dangerousMode })\n .catch(() => {});\n log.info(\n { sessionId, dangerousMode: session.dangerousMode },\n \"[discord-admin] Dangerous mode toggled via button\",\n );\n\n const toastText = session.dangerousMode\n ? \"☠️ Dangerous mode enabled — permissions auto-approved\"\n : \"🔐 Dangerous mode disabled — permissions shown normally\";\n\n try {\n await interaction.update({\n components: [\n buildSessionControlKeyboard(\n sessionId,\n session.dangerousMode,\n session.voiceMode === \"on\",\n ),\n ],\n });\n } catch {\n /* ignore */\n }\n\n try {\n await interaction.followUp({ content: toastText, ephemeral: true });\n } catch {\n /* ignore */\n }\n return;\n }\n\n // Session not in memory — toggle in store\n const record = adapter.core.sessionManager.getSessionRecord(sessionId);\n if (!record || record.status === \"cancelled\" || record.status === \"error\") {\n await interaction.reply({\n content: \"⚠️ Session not found or already ended.\",\n ephemeral: true,\n });\n return;\n }\n\n const newDangerousMode = !(record.dangerousMode ?? false);\n adapter.core.sessionManager\n .patchRecord(sessionId, { dangerousMode: newDangerousMode })\n .catch(() => {});\n log.info(\n { sessionId, dangerousMode: newDangerousMode },\n \"[discord-admin] Dangerous mode toggled via button (store-only)\",\n );\n\n const toastText = newDangerousMode\n ? \"☠️ Dangerous mode enabled — permissions auto-approved\"\n : \"🔐 Dangerous mode disabled — permissions shown normally\";\n\n try {\n // Store-only path: voiceMode unknown, default to off\n await interaction.update({\n components: [\n buildSessionControlKeyboard(sessionId, newDangerousMode, false),\n ],\n });\n } catch {\n /* ignore */\n }\n\n try {\n await interaction.followUp({ content: toastText, ephemeral: true });\n } catch {\n /* ignore */\n }\n}\n\n// ─── TTS ──────────────────────────────────────────────────────────────────────\n\nexport function buildSessionControlKeyboard(\n sessionId: string,\n dangerousMode: boolean,\n voiceMode: boolean,\n): ActionRowBuilder<ButtonBuilder> {\n return new ActionRowBuilder<ButtonBuilder>().addComponents(\n new ButtonBuilder()\n .setCustomId(`d:${sessionId}`)\n .setLabel(\n dangerousMode\n ? \"🔐 Disable Dangerous Mode\"\n : \"☠️ Enable Dangerous Mode\",\n )\n .setStyle(dangerousMode ? ButtonStyle.Secondary : ButtonStyle.Danger),\n new ButtonBuilder()\n .setCustomId(`v:${sessionId}`)\n .setLabel(voiceMode ? \"🔊 Text to Speech\" : \"🔇 Text to Speech\")\n .setStyle(voiceMode ? ButtonStyle.Success : ButtonStyle.Secondary),\n );\n}\n\nexport async function handleTTS(\n interaction: ChatInputCommandInteraction,\n adapter: DiscordAdapter,\n): Promise<void> {\n await interaction.deferReply({ ephemeral: true });\n\n const channelId = interaction.channelId;\n const session = adapter.core.sessionManager.getSessionByThread(\n \"discord\",\n channelId,\n );\n\n if (!session) {\n await interaction.editReply(\"⚠️ No active session in this channel.\");\n return;\n }\n\n const mode = interaction.options.getString(\"mode\");\n\n if (mode === \"on\") {\n session.setVoiceMode(\"on\");\n await interaction.editReply(\"🔊 Text to Speech enabled for this session.\");\n } else if (mode === \"off\") {\n session.setVoiceMode(\"off\");\n await interaction.editReply(\"🔇 Text to Speech disabled.\");\n } else {\n session.setVoiceMode(\"next\");\n await interaction.editReply(\n \"🔊 Text to Speech enabled for the next message.\",\n );\n }\n}\n\nexport async function handleTTSButton(\n interaction: ButtonInteraction,\n adapter: DiscordAdapter,\n): Promise<void> {\n const sessionId = interaction.customId.slice(2); // strip 'v:'\n const session = adapter.core.sessionManager.getSession(sessionId);\n\n if (!session) {\n await interaction.reply({\n content: \"⚠️ Session not found or not active.\",\n ephemeral: true,\n });\n return;\n }\n\n const newMode = session.voiceMode === \"on\" ? \"off\" : \"on\";\n session.setVoiceMode(newMode);\n\n const toastText =\n newMode === \"on\"\n ? \"🔊 Text to Speech enabled\"\n : \"🔇 Text to Speech disabled\";\n\n try {\n await interaction.update({\n components: [\n buildSessionControlKeyboard(\n sessionId,\n session.dangerousMode,\n newMode === \"on\",\n ),\n ],\n });\n } catch {\n /* ignore */\n }\n\n try {\n await interaction.followUp({ content: toastText, ephemeral: true });\n } catch {\n /* ignore */\n }\n}\n\nexport async function handleRestart(\n interaction: ChatInputCommandInteraction,\n adapter: DiscordAdapter,\n): Promise<void> {\n await interaction.deferReply({ ephemeral: true });\n\n if (!adapter.core.requestRestart) {\n await interaction.editReply(\n \"⚠️ Restart is not available (no restart handler registered).\",\n );\n return;\n }\n\n await interaction.editReply(\n \"🔄 **Restarting OpenACP...**\\nRebuilding and restarting. Be back shortly.\",\n );\n await new Promise((r) => setTimeout(r, 500));\n await adapter.core.requestRestart();\n}\n\nexport async function handleUpdate(\n interaction: ChatInputCommandInteraction,\n adapter: DiscordAdapter,\n): Promise<void> {\n await interaction.deferReply({ ephemeral: true });\n // Stub: not implemented yet\n await interaction.editReply(\n \"⚠️ Update via Discord is not implemented yet. Run `npm install -g @openacp/cli@latest` in your terminal, then use `/restart`.\",\n );\n}\n\n// ─── Verbosity ─────────────────────────────────────────────────────────────\n\nconst VERBOSITY_LABELS: Record<string, string> = {\n low: \"🔇 Low\",\n medium: \"📊 Medium\",\n high: \"📖 High\",\n};\n\nexport async function handleVerbosity(\n interaction: ChatInputCommandInteraction,\n adapter: DiscordAdapter,\n): Promise<void> {\n await interaction.deferReply({ ephemeral: true });\n\n const level = interaction.options.getString(\"level\", true);\n if (level !== \"low\" && level !== \"medium\" && level !== \"high\") {\n await interaction.editReply(\n \"⚠️ Invalid level. Use `low`, `medium`, or `high`.\",\n );\n return;\n }\n\n await adapter.core.configManager.save(\n { channels: { discord: { displayVerbosity: level } } },\n \"channels.discord.displayVerbosity\",\n );\n\n await interaction.editReply(\n `${VERBOSITY_LABELS[level]} Display verbosity set to **${level}**.`,\n );\n}\n"],"mappings":"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","names":["msg","toastText"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
log
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-XMMAGAT4.js";
|
|
4
4
|
|
|
5
|
-
// src/
|
|
5
|
+
// src/plugins/discord/commands/agents.ts
|
|
6
6
|
import {
|
|
7
7
|
ActionRowBuilder,
|
|
8
8
|
ButtonBuilder,
|
|
@@ -200,4 +200,4 @@ export {
|
|
|
200
200
|
handleInstall,
|
|
201
201
|
handleAgentButton
|
|
202
202
|
};
|
|
203
|
-
//# sourceMappingURL=chunk-
|
|
203
|
+
//# sourceMappingURL=chunk-NAM4ERUW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/plugins/discord/commands/agents.ts"],"sourcesContent":["import {\n ActionRowBuilder,\n ButtonBuilder,\n ButtonStyle,\n} from 'discord.js'\nimport type { ChatInputCommandInteraction, ButtonInteraction } from 'discord.js'\nimport { log } from '../../../core/utils/log.js'\nimport type { InstallProgress } from '../../../core/types.js'\nimport type { DiscordAdapter } from '../adapter.js'\n\nconst AGENTS_PER_PAGE = 5\n\nfunction buildProgressBar(percent: number): string {\n const filled = Math.round(percent / 10)\n const empty = 10 - filled\n return '█'.repeat(filled) + '░'.repeat(empty)\n}\n\nfunction truncate(text: string, maxLen: number): string {\n if (text.length <= maxLen) return text\n return text.slice(0, maxLen - 1) + '…'\n}\n\nexport async function handleAgents(\n interaction: ChatInputCommandInteraction,\n adapter: DiscordAdapter,\n page = 0,\n): Promise<void> {\n await interaction.deferReply({ ephemeral: true })\n const { content, components } = buildAgentsContent(adapter, page)\n await interaction.editReply({ content, components })\n}\n\nexport async function showAgentsList(\n interaction: ButtonInteraction,\n adapter: DiscordAdapter,\n page = 0,\n): Promise<void> {\n const { content, components } = buildAgentsContent(adapter, page)\n await interaction.followUp({ content, components, ephemeral: true })\n}\n\nfunction buildAgentsContent(\n adapter: DiscordAdapter,\n page: number,\n): { content: string; components: ActionRowBuilder<ButtonBuilder>[] } {\n const catalog = adapter.core.agentCatalog\n const items = catalog.getAvailable()\n\n const installed = items.filter((i: any) => i.installed)\n const available = items.filter((i: any) => !i.installed)\n\n let content = '**🤖 Agents**\\n\\n'\n\n if (installed.length > 0) {\n content += '**Installed:**\\n'\n for (const item of installed) {\n content += `✅ **${item.name}**`\n if (item.description) content += ` — *${truncate(item.description, 50)}*`\n content += '\\n'\n }\n content += '\\n'\n }\n\n const components: ActionRowBuilder<ButtonBuilder>[] = []\n\n if (available.length > 0) {\n const totalPages = Math.ceil(available.length / AGENTS_PER_PAGE)\n const safePage = Math.max(0, Math.min(page, totalPages - 1))\n const pageItems = available.slice(safePage * AGENTS_PER_PAGE, (safePage + 1) * AGENTS_PER_PAGE)\n\n content += `**Available to install:**`\n if (totalPages > 1) content += ` (${safePage + 1}/${totalPages})`\n content += '\\n'\n\n for (const item of pageItems) {\n if (item.available) {\n content += `⬇️ **${item.name}**`\n } else {\n const deps = item.missingDeps?.join(', ') ?? 'requirements not met'\n content += `⚠️ **${item.name}** *(needs: ${deps})*`\n }\n if (item.description) content += `\\n *${truncate(item.description, 60)}*`\n content += '\\n'\n }\n\n // Install buttons row\n const installable = pageItems.filter((i: any) => i.available)\n if (installable.length > 0) {\n const installRow = new ActionRowBuilder<ButtonBuilder>()\n for (const item of installable) {\n installRow.addComponents(\n new ButtonBuilder()\n .setCustomId(`ag:install:${item.key}`)\n .setLabel(`⬇️ ${item.name}`)\n .setStyle(ButtonStyle.Secondary),\n )\n }\n components.push(installRow)\n }\n\n // Pagination row\n if (totalPages > 1) {\n const pageRow = new ActionRowBuilder<ButtonBuilder>()\n if (safePage > 0) {\n pageRow.addComponents(\n new ButtonBuilder()\n .setCustomId(`ag:page:${safePage - 1}`)\n .setLabel('◀️ Prev')\n .setStyle(ButtonStyle.Secondary),\n )\n }\n if (safePage < totalPages - 1) {\n pageRow.addComponents(\n new ButtonBuilder()\n .setCustomId(`ag:page:${safePage + 1}`)\n .setLabel('Next ▶️')\n .setStyle(ButtonStyle.Secondary),\n )\n }\n if (pageRow.components.length > 0) components.push(pageRow)\n }\n } else {\n content += '*All agents are already installed!*'\n }\n\n return { content, components }\n}\n\nexport async function handleInstall(\n interaction: ChatInputCommandInteraction,\n adapter: DiscordAdapter,\n): Promise<void> {\n await interaction.deferReply({ ephemeral: true })\n\n const nameOrId = interaction.options.getString('name', true)\n await installAgentWithProgress(interaction, adapter, nameOrId)\n}\n\nexport async function handleAgentButton(\n interaction: ButtonInteraction,\n adapter: DiscordAdapter,\n): Promise<void> {\n const { customId } = interaction\n\n if (customId.startsWith('ag:install:')) {\n const nameOrId = customId.replace('ag:install:', '')\n try { await interaction.deferReply({ ephemeral: true }) } catch { /* ignore */ }\n await installAgentWithProgress(interaction, adapter, nameOrId)\n return\n }\n\n if (customId.startsWith('ag:page:')) {\n const page = parseInt(customId.replace('ag:page:', ''), 10)\n const { content, components } = buildAgentsContent(adapter, page)\n try {\n await interaction.update({ content, components })\n } catch (err) {\n log.warn({ err }, '[discord-agents] Failed to update page')\n }\n }\n}\n\nasync function installAgentWithProgress(\n interaction: ChatInputCommandInteraction | ButtonInteraction,\n adapter: DiscordAdapter,\n nameOrId: string,\n): Promise<void> {\n const catalog = adapter.core.agentCatalog\n\n // Track the latest status for periodic edits\n let statusText = `⏳ Installing **${nameOrId}**...`\n let lastEdit = 0\n const EDIT_THROTTLE_MS = 1500\n\n const editStatus = async (text: string) => {\n const now = Date.now()\n if (now - lastEdit > EDIT_THROTTLE_MS) {\n lastEdit = now\n statusText = text\n try {\n if (interaction.deferred || interaction.replied) {\n await interaction.editReply(text)\n }\n } catch { /* rate limit or unchanged */ }\n } else {\n statusText = text\n }\n }\n\n // Set initial message\n try {\n if (interaction.deferred || interaction.replied) {\n await interaction.editReply(statusText)\n }\n } catch { /* ignore */ }\n\n const progress: InstallProgress = {\n onStart(_id, _name) { /* initial message already sent */ },\n async onStep(step) { await editStatus(`⏳ **${nameOrId}**: ${step}`) },\n async onDownloadProgress(percent) {\n const bar = buildProgressBar(percent)\n await editStatus(`⏳ **${nameOrId}**\\nDownloading... ${bar} ${percent}%`)\n },\n async onSuccess(name) {\n const row = new ActionRowBuilder<ButtonBuilder>().addComponents(\n new ButtonBuilder()\n .setCustomId(`na:${nameOrId}`)\n .setLabel(`🚀 Start session with ${name}`)\n .setStyle(ButtonStyle.Primary),\n )\n try {\n if (interaction.deferred || interaction.replied) {\n await interaction.editReply({\n content: `✅ **${name}** installed!`,\n components: [row],\n })\n }\n } catch { /* ignore */ }\n },\n async onError(error) {\n try {\n if (interaction.deferred || interaction.replied) {\n await interaction.editReply(`❌ ${error}`)\n }\n } catch { /* ignore */ }\n },\n }\n\n const result = await catalog.install(nameOrId, progress)\n\n // Show setup steps as a follow-up message\n if (result.ok && result.setupSteps?.length) {\n let setupText = `📋 **Setup for ${result.agentKey}:**\\n\\n`\n for (const step of result.setupSteps) {\n setupText += `→ ${step}\\n`\n }\n setupText += `\\n*Run in terminal: \\`openacp agents info ${result.agentKey}\\`*`\n try {\n await interaction.followUp({ content: setupText, ephemeral: true })\n } catch { /* ignore */ }\n }\n}\n"],"mappings":"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","names":[]}
|