@openacp/cli 0.6.10 → 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/dist/{action-detect-P7ZE4NEM.js → action-detect-QPA775HB.js} +2 -2
- package/dist/adapter-6ANPBSVU.js +16 -0
- package/dist/{discord-OMC52Y54.js → adapter-77ZCVABT.js} +520 -365
- package/dist/adapter-77ZCVABT.js.map +1 -0
- package/dist/{adapter-ZOANORGM.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-OWP7RZ62.js → chunk-5ZOFBTOR.js} +118 -262
- 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-MKHUZLII.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-CS3KCJ5D.js → chunk-RKB2ZK6S.js} +555 -383
- 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 +496 -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/{chunk-LCRLAV4G.js → setup-BAI2F24H.js} +154 -492
- 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-ZOANORGM.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-BNLGTZ34.js.map +0 -1
- package/dist/chunk-CS3KCJ5D.js.map +0 -1
- package/dist/chunk-GAK6PIBW.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-KIRH7TUJ.js.map +0 -1
- package/dist/chunk-LBIKITQT.js +0 -22
- package/dist/chunk-LBIKITQT.js.map +0 -1
- package/dist/chunk-LCRLAV4G.js.map +0 -1
- package/dist/chunk-LGP2YGRL.js +0 -4880
- package/dist/chunk-LGP2YGRL.js.map +0 -1
- package/dist/chunk-MKHUZLII.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-OWP7RZ62.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-QQTZMWGD.js +0 -13
- package/dist/discord-OMC52Y54.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-XOZCLFUK.js +0 -238
- package/dist/main-XOZCLFUK.js.map +0 -1
- package/dist/post-upgrade-CJG5I7M2.js.map +0 -1
- package/dist/setup-XHS4OMPM.js +0 -37
- 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-QQTZMWGD.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-XHS4OMPM.js.map → doctor-RF6BHMCC.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/adapter-primitives/format-types.ts","../../src/core/adapter-primitives/message-formatter.ts","../../src/core/adapter-primitives/messaging-adapter.ts","../../src/core/adapter-primitives/format-utils.ts","../../src/core/adapter-primitives/rendering/renderer.ts"],"sourcesContent":["// src/adapters/shared/format-types.ts\n\nexport type DisplayVerbosity = \"low\" | \"medium\" | \"high\";\n\nexport type NoiseAction = \"hide\" | \"collapse\";\n\nexport interface NoiseRule {\n match: (name: string, kind: string, rawInput: unknown) => boolean;\n action: NoiseAction;\n}\n\nexport type MessageStyle =\n | \"text\"\n | \"thought\"\n | \"tool\"\n | \"plan\"\n | \"usage\"\n | \"system\"\n | \"error\"\n | \"attachment\";\n\nexport interface MessageMetadata {\n toolName?: string;\n toolStatus?: string;\n toolKind?: string;\n filePath?: string;\n command?: string;\n planEntries?: { content: string; status: string }[];\n tokens?: number;\n contextSize?: number;\n cost?: number;\n viewerLinks?: ViewerLinks;\n viewerFilePath?: string;\n}\n\n/** summary and detail are always plain text (never pre-escaped HTML/markdown) — renderers handle escaping */\nexport interface FormattedMessage {\n summary: string;\n detail?: string;\n viewerLinks?: ViewerLinks;\n icon: string;\n originalType: string;\n style: MessageStyle;\n metadata?: MessageMetadata;\n}\n\nexport const STATUS_ICONS: Record<string, string> = {\n pending: \"⏳\",\n in_progress: \"🔄\",\n completed: \"✅\",\n failed: \"❌\",\n cancelled: \"🚫\",\n running: \"🔄\",\n done: \"✅\",\n error: \"❌\",\n};\n\nexport const KIND_ICONS: Record<string, string> = {\n read: \"📖\",\n edit: \"✏️\",\n write: \"✏️\",\n delete: \"🗑️\",\n execute: \"▶️\",\n command: \"▶️\",\n bash: \"▶️\",\n search: \"🔍\",\n web: \"🌐\",\n fetch: \"🌐\",\n agent: \"🧠\",\n think: \"🧠\",\n install: \"📦\",\n move: \"📦\",\n other: \"🛠️\",\n};\n\nexport interface ViewerLinks {\n file?: string;\n diff?: string;\n}\n\nexport interface ToolCallMeta {\n id: string;\n name: string;\n kind?: string;\n status?: string;\n content?: unknown;\n rawInput?: unknown;\n viewerLinks?: ViewerLinks;\n viewerFilePath?: string;\n displaySummary?: string;\n displayTitle?: string;\n displayKind?: string;\n}\n\nexport interface ToolUpdateMeta extends ToolCallMeta {\n status: string;\n}\n","import type { NoiseAction, NoiseRule } from \"./format-types.js\";\nimport { STATUS_ICONS, KIND_ICONS } from \"./format-types.js\";\n\nexport function extractContentText(content: unknown, depth = 0): string {\n if (!content || depth > 5) return \"\";\n if (typeof content === \"string\") return content;\n if (Array.isArray(content)) {\n return content\n .map((c) => extractContentText(c, depth + 1))\n .filter(Boolean)\n .join(\"\\n\");\n }\n if (typeof content !== \"object\") return String(content);\n\n const obj = content as Record<string, unknown>;\n if (obj.text && typeof obj.text === \"string\") return obj.text;\n if (obj.content) {\n if (typeof obj.content === \"string\") return obj.content;\n if (Array.isArray(obj.content)) {\n return obj.content\n .map((c) => extractContentText(c, depth + 1))\n .filter(Boolean)\n .join(\"\\n\");\n }\n return extractContentText(obj.content, depth + 1);\n }\n if (obj.input) return extractContentText(obj.input, depth + 1);\n if (obj.output) return extractContentText(obj.output, depth + 1);\n\n // Skip objects with only a 'type' key and no content fields\n const keys = Object.keys(obj).filter((k) => k !== \"type\");\n if (keys.length === 0) return \"\";\n\n // Fallback: serialize unrecognized objects so edge-case agent responses are not silently dropped\n try {\n return JSON.stringify(obj, null, 2);\n } catch {\n return \"\";\n }\n}\n\nfunction parseRawInput(rawInput: unknown): Record<string, unknown> {\n try {\n if (typeof rawInput === \"string\") {\n return JSON.parse(rawInput) as Record<string, unknown>;\n }\n if (typeof rawInput === \"object\" && rawInput !== null) {\n return rawInput as Record<string, unknown>;\n }\n } catch {\n // fall through\n }\n return {};\n}\n\n// --- Step 5: formatToolSummary with displaySummary override ---\n\nexport function formatToolSummary(\n name: string,\n rawInput: unknown,\n displaySummary?: string,\n): string {\n if (displaySummary && typeof displaySummary === \"string\") {\n return displaySummary;\n }\n\n const args = parseRawInput(rawInput);\n const lowerName = name.toLowerCase();\n\n if (lowerName === \"read\") {\n const fp = args.file_path ?? args.filePath ?? \"\";\n const limit = args.limit ? ` (${args.limit} lines)` : \"\";\n return fp ? `📖 Read ${fp}${limit}` : `🔧 ${name}`;\n }\n if (lowerName === \"edit\") {\n const fp = args.file_path ?? args.filePath ?? \"\";\n return fp ? `✏️ Edit ${fp}` : `🔧 ${name}`;\n }\n if (lowerName === \"write\") {\n const fp = args.file_path ?? args.filePath ?? \"\";\n return fp ? `📝 Write ${fp}` : `🔧 ${name}`;\n }\n if (lowerName === \"bash\") {\n const cmd = String(args.command ?? \"\").slice(0, 60);\n return cmd ? `▶️ Run: ${cmd}` : `🔧 ${name}`;\n }\n if (lowerName === \"grep\") {\n const pattern = args.pattern ?? \"\";\n const path = args.path ?? \"\";\n return pattern\n ? `🔍 Grep \"${pattern}\"${path ? ` in ${path}` : \"\"}`\n : `🔧 ${name}`;\n }\n if (lowerName === \"glob\") {\n const pattern = args.pattern ?? \"\";\n return pattern ? `🔍 Glob ${pattern}` : `🔧 ${name}`;\n }\n if (lowerName === \"agent\") {\n const desc = String(args.description ?? \"\").slice(0, 60);\n return desc ? `🧠 Agent: ${desc}` : `🔧 ${name}`;\n }\n if (lowerName === \"webfetch\" || lowerName === \"web_fetch\") {\n const url = String(args.url ?? \"\").slice(0, 60);\n return url ? `🌐 Fetch ${url}` : `🔧 ${name}`;\n }\n if (lowerName === \"websearch\" || lowerName === \"web_search\") {\n const query = String(args.query ?? \"\").slice(0, 60);\n return query ? `🌐 Search \"${query}\"` : `🔧 ${name}`;\n }\n\n return `🔧 ${name}`;\n}\n\n// --- Step 6: formatToolTitle for low verbosity ---\n\nexport function formatToolTitle(\n name: string,\n rawInput: unknown,\n displayTitle?: string,\n): string {\n if (displayTitle && typeof displayTitle === \"string\") {\n return displayTitle;\n }\n\n const args = parseRawInput(rawInput);\n const lowerName = name.toLowerCase();\n\n if ([\"read\", \"edit\", \"write\"].includes(lowerName)) {\n return String(args.file_path ?? args.filePath ?? name);\n }\n if (lowerName === \"bash\") {\n return String(args.command ?? name).slice(0, 60);\n }\n if (lowerName === \"grep\") {\n const pattern = args.pattern ?? \"\";\n const path = args.path ?? \"\";\n return pattern ? `\"${pattern}\"${path ? ` in ${path}` : \"\"}` : name;\n }\n if (lowerName === \"glob\") {\n return String(args.pattern ?? name);\n }\n if (lowerName === \"agent\") {\n return String(args.description ?? name).slice(0, 60);\n }\n if ([\"webfetch\", \"web_fetch\"].includes(lowerName)) {\n return String(args.url ?? name).slice(0, 60);\n }\n if ([\"websearch\", \"web_search\"].includes(lowerName)) {\n return String(args.query ?? name).slice(0, 60);\n }\n\n return name;\n}\n\n// --- Step 7: resolveToolIcon ---\n\nexport function resolveToolIcon(tool: {\n status?: string;\n displayKind?: string;\n kind?: string;\n}): string {\n const statusIcon = STATUS_ICONS[tool.status || \"\"];\n if (statusIcon) return statusIcon;\n const kind = tool.displayKind ?? tool.kind;\n if (kind && KIND_ICONS[kind]) return KIND_ICONS[kind];\n return \"🔧\";\n}\n\n// --- Step 8: Noise filtering ---\n\nconst NOISE_RULES: NoiseRule[] = [\n {\n match: (name) => name.toLowerCase() === \"ls\",\n action: \"hide\",\n },\n {\n match: (_name, kind, rawInput) => {\n if (kind !== \"read\") return false;\n const args = parseRawInput(rawInput);\n const p = String(args.file_path ?? args.filePath ?? args.path ?? \"\");\n return p.endsWith(\"/\");\n },\n action: \"hide\",\n },\n {\n match: (name) => name.toLowerCase() === \"glob\",\n action: \"collapse\",\n },\n];\n\nexport function evaluateNoise(\n name: string,\n kind: string,\n rawInput: unknown,\n): NoiseAction | null {\n for (const rule of NOISE_RULES) {\n if (rule.match(name, kind, rawInput)) return rule.action;\n }\n return null;\n}\n","import type {\n IChannelAdapter,\n ChannelConfig,\n AdapterCapabilities,\n} from '../channel.js'\nimport type {\n OutgoingMessage,\n PermissionRequest,\n NotificationMessage,\n} from '../types.js'\nimport type { DisplayVerbosity, ToolCallMeta } from './format-types.js'\nimport type { IRenderer } from './rendering/renderer.js'\nimport { evaluateNoise } from './message-formatter.js'\n\nexport interface AdapterContext {\n configManager: { get(): Record<string, unknown> }\n fileService?: unknown\n}\n\nexport interface MessagingAdapterConfig extends ChannelConfig {\n maxMessageLength: number\n flushInterval?: number\n sendInterval?: number\n thinkingRefreshInterval?: number\n thinkingDuration?: number\n displayVerbosity?: DisplayVerbosity\n}\n\nexport interface SentMessage {\n messageId: string\n}\n\nconst HIDDEN_ON_LOW = new Set(['thought', 'plan', 'usage'])\n\nexport abstract class MessagingAdapter implements IChannelAdapter {\n abstract readonly name: string\n abstract readonly renderer: IRenderer\n abstract readonly capabilities: AdapterCapabilities\n\n constructor(\n protected context: AdapterContext,\n protected adapterConfig: MessagingAdapterConfig,\n ) {}\n\n // === Message dispatch flow ===\n\n async sendMessage(sessionId: string, content: OutgoingMessage): Promise<void> {\n const verbosity = this.getVerbosity()\n if (!this.shouldDisplay(content, verbosity)) return\n await this.dispatchMessage(sessionId, content, verbosity)\n }\n\n protected async dispatchMessage(\n sessionId: string,\n content: OutgoingMessage,\n verbosity: DisplayVerbosity,\n ): Promise<void> {\n switch (content.type) {\n case 'text': return this.handleText(sessionId, content)\n case 'thought': return this.handleThought(sessionId, content, verbosity)\n case 'tool_call': return this.handleToolCall(sessionId, content, verbosity)\n case 'tool_update': return this.handleToolUpdate(sessionId, content, verbosity)\n case 'plan': return this.handlePlan(sessionId, content, verbosity)\n case 'usage': return this.handleUsage(sessionId, content, verbosity)\n case 'error': return this.handleError(sessionId, content)\n case 'attachment': return this.handleAttachment(sessionId, content)\n case 'system_message': return this.handleSystem(sessionId, content)\n case 'session_end': return this.handleSessionEnd(sessionId, content)\n case 'mode_change': return this.handleModeChange(sessionId, content)\n case 'config_update': return this.handleConfigUpdate(sessionId, content)\n case 'model_update': return this.handleModelUpdate(sessionId, content)\n case 'user_replay': return this.handleUserReplay(sessionId, content)\n case 'resource': return this.handleResource(sessionId, content)\n case 'resource_link': return this.handleResourceLink(sessionId, content)\n }\n }\n\n // === Default handlers — all protected, all overridable ===\n\n protected async handleText(_sessionId: string, _content: OutgoingMessage): Promise<void> {}\n protected async handleThought(_sessionId: string, _content: OutgoingMessage, _verbosity: DisplayVerbosity): Promise<void> {}\n protected async handleToolCall(_sessionId: string, _content: OutgoingMessage, _verbosity: DisplayVerbosity): Promise<void> {}\n protected async handleToolUpdate(_sessionId: string, _content: OutgoingMessage, _verbosity: DisplayVerbosity): Promise<void> {}\n protected async handlePlan(_sessionId: string, _content: OutgoingMessage, _verbosity: DisplayVerbosity): Promise<void> {}\n protected async handleUsage(_sessionId: string, _content: OutgoingMessage, _verbosity: DisplayVerbosity): Promise<void> {}\n protected async handleError(_sessionId: string, _content: OutgoingMessage): Promise<void> {}\n protected async handleAttachment(_sessionId: string, _content: OutgoingMessage): Promise<void> {}\n protected async handleSystem(_sessionId: string, _content: OutgoingMessage): Promise<void> {}\n protected async handleSessionEnd(_sessionId: string, _content: OutgoingMessage): Promise<void> {}\n protected async handleModeChange(_sessionId: string, _content: OutgoingMessage): Promise<void> {}\n protected async handleConfigUpdate(_sessionId: string, _content: OutgoingMessage): Promise<void> {}\n protected async handleModelUpdate(_sessionId: string, _content: OutgoingMessage): Promise<void> {}\n protected async handleUserReplay(_sessionId: string, _content: OutgoingMessage): Promise<void> {}\n protected async handleResource(_sessionId: string, _content: OutgoingMessage): Promise<void> {}\n protected async handleResourceLink(_sessionId: string, _content: OutgoingMessage): Promise<void> {}\n\n // === Helpers ===\n\n protected getVerbosity(): DisplayVerbosity {\n const config = this.context.configManager.get()\n const channelConfig = (config as Record<string, unknown>).channels as Record<string, Record<string, unknown>> | undefined\n const v = channelConfig?.[this.name]?.displayVerbosity ?? this.adapterConfig.displayVerbosity\n if (v === 'low' || v === 'high') return v\n return 'medium'\n }\n\n protected shouldDisplay(content: OutgoingMessage, verbosity: DisplayVerbosity): boolean {\n if (verbosity === 'low' && HIDDEN_ON_LOW.has(content.type)) return false\n\n if (content.type === 'tool_call') {\n const meta = (content.metadata ?? {}) as Partial<ToolCallMeta>\n const toolName = meta.name ?? content.text ?? ''\n const toolKind = String(meta.kind ?? 'other')\n const noiseAction = evaluateNoise(toolName, toolKind, meta.rawInput)\n if (noiseAction === 'hide' && verbosity !== 'high') return false\n if (noiseAction === 'collapse' && verbosity === 'low') return false\n }\n\n return true\n }\n\n // === Abstract — adapter MUST implement ===\n\n abstract start(): Promise<void>\n abstract stop(): Promise<void>\n abstract createSessionThread(sessionId: string, name: string): Promise<string>\n abstract renameSessionThread(sessionId: string, newName: string): Promise<void>\n abstract sendPermissionRequest(sessionId: string, request: PermissionRequest): Promise<void>\n abstract sendNotification(notification: NotificationMessage): Promise<void>\n}\n","export function progressBar(ratio: number, length = 10): string {\n const filled = Math.round(Math.min(ratio, 1) * length);\n return \"▓\".repeat(filled) + \"░\".repeat(length - filled);\n}\n\nexport function formatTokens(n: number): string {\n return n >= 1000 ? `${Math.round(n / 1000)}k` : String(n);\n}\n\nexport function stripCodeFences(text: string): string {\n return text\n .replace(/```\\w*\\n?/g, \"\")\n .replace(/```$/gm, \"\")\n .trim();\n}\n\nexport function truncateContent(text: string, maxLen: number): string {\n if (text.length <= maxLen) return text;\n return text.slice(0, maxLen) + \"\\n… (truncated)\";\n}\n\nexport function splitMessage(text: string, maxLength: number): string[] {\n if (text.length <= maxLength) return [text];\n const chunks: string[] = [];\n let remaining = text;\n while (remaining.length > 0) {\n if (remaining.length <= maxLength) {\n chunks.push(remaining);\n break;\n }\n\n const wouldLeaveSmall = remaining.length < maxLength * 1.3;\n const searchLimit = wouldLeaveSmall\n ? Math.floor(remaining.length / 2) + 300\n : maxLength;\n\n const threshold = maxLength * 0.2;\n let splitAt = remaining.lastIndexOf(\"\\n\\n\", searchLimit);\n if (splitAt === -1 || splitAt < threshold) {\n splitAt = remaining.lastIndexOf(\"\\n\", searchLimit);\n }\n if (splitAt === -1 || splitAt < threshold) {\n splitAt = searchLimit;\n }\n\n const candidate = remaining.slice(0, splitAt);\n const fences = candidate.match(/```/g);\n if (fences && fences.length % 2 !== 0) {\n const closingFence = remaining.indexOf(\"```\", splitAt);\n if (closingFence !== -1) {\n const afterFence = remaining.indexOf(\"\\n\", closingFence + 3);\n const fenceSplit =\n afterFence !== -1 ? afterFence + 1 : closingFence + 3;\n // Only extend to include the closing fence if it doesn't exceed 2x maxLength\n if (fenceSplit <= maxLength * 2) {\n splitAt = fenceSplit;\n }\n }\n }\n\n chunks.push(remaining.slice(0, splitAt));\n remaining = remaining.slice(splitAt).replace(/^\\n+/, \"\");\n }\n return chunks;\n}\n","import type { OutgoingMessage, PermissionRequest, NotificationMessage } from '../../types.js'\nimport type { DisplayVerbosity, ToolCallMeta, ToolUpdateMeta } from '../format-types.js'\nimport {\n formatToolSummary,\n formatToolTitle,\n resolveToolIcon,\n} from '../message-formatter.js'\nimport { progressBar, formatTokens } from '../format-utils.js'\n\nexport interface RenderedMessage<TComponents = unknown> {\n body: string\n format: 'html' | 'markdown' | 'plain' | 'structured'\n attachments?: RenderedAttachment[]\n components?: TComponents\n}\n\nexport interface RenderedPermission<TComponents = unknown> extends RenderedMessage<TComponents> {\n actions: RenderedAction[]\n}\n\nexport interface RenderedAction {\n id: string\n label: string\n isAllow?: boolean\n}\n\nexport interface RenderedAttachment {\n type: 'file' | 'image' | 'audio'\n data: Buffer | string\n mimeType?: string\n filename?: string\n}\n\nexport interface IRenderer {\n renderText(content: OutgoingMessage, verbosity: DisplayVerbosity): RenderedMessage\n renderToolCall(content: OutgoingMessage, verbosity: DisplayVerbosity): RenderedMessage\n renderToolUpdate(content: OutgoingMessage, verbosity: DisplayVerbosity): RenderedMessage\n renderPlan(content: OutgoingMessage, verbosity: DisplayVerbosity): RenderedMessage\n renderUsage(content: OutgoingMessage, verbosity: DisplayVerbosity): RenderedMessage\n renderPermission(request: PermissionRequest): RenderedPermission\n renderError(content: OutgoingMessage): RenderedMessage\n renderNotification(notification: NotificationMessage): RenderedMessage\n renderThought?(content: OutgoingMessage, verbosity: DisplayVerbosity): RenderedMessage\n renderAttachment?(content: OutgoingMessage): RenderedMessage\n renderSessionEnd?(content: OutgoingMessage): RenderedMessage\n renderSystemMessage?(content: OutgoingMessage): RenderedMessage\n renderModeChange?(content: OutgoingMessage, verbosity: DisplayVerbosity): RenderedMessage\n renderConfigUpdate?(content: OutgoingMessage, verbosity: DisplayVerbosity): RenderedMessage\n renderModelUpdate?(content: OutgoingMessage, verbosity: DisplayVerbosity): RenderedMessage\n renderResource?(content: OutgoingMessage): RenderedMessage\n renderResourceLink?(content: OutgoingMessage): RenderedMessage\n}\n\n/**\n * BaseRenderer — plain text defaults. Extend for platform-specific rendering.\n */\nexport class BaseRenderer implements IRenderer {\n renderText(content: OutgoingMessage): RenderedMessage {\n return { body: content.text, format: 'plain' }\n }\n\n renderToolCall(content: OutgoingMessage, verbosity: DisplayVerbosity): RenderedMessage {\n const meta = (content.metadata ?? {}) as Partial<ToolCallMeta>\n const name = meta.name ?? content.text ?? 'Tool'\n const icon = resolveToolIcon(meta)\n const label = verbosity === 'low'\n ? formatToolTitle(name, meta.rawInput, meta.displayTitle as string | undefined)\n : formatToolSummary(name, meta.rawInput, meta.displaySummary as string | undefined)\n return { body: `${icon} ${label}`, format: 'plain' }\n }\n\n renderToolUpdate(content: OutgoingMessage, verbosity: DisplayVerbosity): RenderedMessage {\n const meta = (content.metadata ?? {}) as Partial<ToolUpdateMeta>\n const name = meta.name ?? content.text ?? 'Tool'\n const icon = resolveToolIcon(meta)\n const label = verbosity === 'low'\n ? formatToolTitle(name, meta.rawInput, meta.displayTitle as string | undefined)\n : formatToolSummary(name, meta.rawInput, meta.displaySummary as string | undefined)\n return { body: `${icon} ${label}`, format: 'plain' }\n }\n\n renderPlan(content: OutgoingMessage, verbosity: DisplayVerbosity): RenderedMessage {\n const entries = (content.metadata as { entries?: Array<{ content: string; status: string }> })?.entries ?? []\n const done = entries.filter(e => e.status === 'completed').length\n if (verbosity === 'medium' || verbosity === 'low') {\n return { body: `📋 Plan: ${done}/${entries.length} steps completed`, format: 'plain' }\n }\n const lines = entries.map((e, i) => {\n const icon = e.status === 'completed' ? '✅' : e.status === 'in_progress' ? '🔄' : '⬜'\n return `${icon} ${i + 1}. ${e.content}`\n })\n return { body: `📋 Plan\\n${lines.join('\\n')}`, format: 'plain' }\n }\n\n renderUsage(content: OutgoingMessage, verbosity: DisplayVerbosity): RenderedMessage {\n const meta = content.metadata as { tokensUsed?: number; contextSize?: number; cost?: number } | undefined\n if (!meta?.tokensUsed) return { body: '📊 Usage data unavailable', format: 'plain' }\n const costStr = meta.cost != null ? ` · $${meta.cost.toFixed(2)}` : ''\n if (verbosity === 'medium') {\n return { body: `📊 ${formatTokens(meta.tokensUsed)} tokens${costStr}`, format: 'plain' }\n }\n if (!meta.contextSize) return { body: `📊 ${formatTokens(meta.tokensUsed)} tokens`, format: 'plain' }\n const ratio = meta.tokensUsed / meta.contextSize\n const pct = Math.round(ratio * 100)\n const bar = progressBar(ratio)\n let text = `📊 ${formatTokens(meta.tokensUsed)} / ${formatTokens(meta.contextSize)} tokens\\n${bar} ${pct}%`\n if (meta.cost != null) text += `\\n💰 $${meta.cost.toFixed(2)}`\n return { body: text, format: 'plain' }\n }\n\n renderPermission(request: PermissionRequest): RenderedPermission {\n return {\n body: request.description,\n format: 'plain',\n actions: request.options.map(o => ({ id: o.id, label: o.label, isAllow: o.isAllow })),\n }\n }\n\n renderError(content: OutgoingMessage): RenderedMessage {\n return { body: `❌ Error: ${content.text}`, format: 'plain' }\n }\n\n renderNotification(notification: NotificationMessage): RenderedMessage {\n const emoji: Record<string, string> = {\n completed: '✅', error: '❌', permission: '🔐', input_required: '💬', budget_warning: '⚠️',\n }\n return {\n body: `${emoji[notification.type] || 'ℹ️'} ${notification.sessionName || 'Session'}\\n${notification.summary}`,\n format: 'plain',\n }\n }\n\n renderSystemMessage(content: OutgoingMessage): RenderedMessage {\n return { body: content.text, format: 'plain' }\n }\n\n renderModeChange(content: OutgoingMessage): RenderedMessage {\n const modeId = (content.metadata as Record<string, unknown>)?.modeId ?? ''\n return { body: `🔄 Mode: ${modeId}`, format: 'plain' }\n }\n\n renderConfigUpdate(): RenderedMessage {\n return { body: '⚙️ Config updated', format: 'plain' }\n }\n\n renderModelUpdate(content: OutgoingMessage): RenderedMessage {\n const modelId = (content.metadata as Record<string, unknown>)?.modelId ?? ''\n return { body: `🤖 Model: ${modelId}`, format: 'plain' }\n }\n\n renderResource(content: OutgoingMessage): RenderedMessage {\n const uri = (content.metadata as Record<string, unknown>)?.uri ?? ''\n return { body: `📄 Resource: ${content.text} (${uri})`, format: 'plain' }\n }\n\n renderResourceLink(content: OutgoingMessage): RenderedMessage {\n const uri = (content.metadata as Record<string, unknown>)?.uri ?? ''\n return { body: `🔗 ${content.text}: ${uri}`, format: 'plain' }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// src/plugins/api-server/index.ts
|
|
2
|
+
function createApiServerPlugin() {
|
|
3
|
+
let server = null;
|
|
4
|
+
return {
|
|
5
|
+
name: "@openacp/api-server",
|
|
6
|
+
version: "1.0.0",
|
|
7
|
+
description: "REST API + SSE streaming server",
|
|
8
|
+
essential: false,
|
|
9
|
+
permissions: ["services:register", "kernel:access", "events:read"],
|
|
10
|
+
async install(ctx) {
|
|
11
|
+
const { settings, legacyConfig, terminal } = ctx;
|
|
12
|
+
if (legacyConfig) {
|
|
13
|
+
const apiCfg = legacyConfig.api;
|
|
14
|
+
if (apiCfg) {
|
|
15
|
+
await settings.setAll({
|
|
16
|
+
port: apiCfg.port ?? 21420,
|
|
17
|
+
host: apiCfg.host ?? "127.0.0.1"
|
|
18
|
+
});
|
|
19
|
+
terminal.log.success("API server settings migrated from legacy config");
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
await settings.setAll({
|
|
24
|
+
port: 21420,
|
|
25
|
+
host: "127.0.0.1"
|
|
26
|
+
});
|
|
27
|
+
terminal.log.success("API server defaults saved");
|
|
28
|
+
},
|
|
29
|
+
async configure(ctx) {
|
|
30
|
+
const { terminal, settings } = ctx;
|
|
31
|
+
const current = await settings.getAll();
|
|
32
|
+
const choice = await terminal.select({
|
|
33
|
+
message: "What to configure?",
|
|
34
|
+
options: [
|
|
35
|
+
{ value: "port", label: `Change port (current: ${current.port ?? 21420})` },
|
|
36
|
+
{ value: "host", label: `Change host (current: ${current.host ?? "127.0.0.1"})` },
|
|
37
|
+
{ value: "done", label: "Done" }
|
|
38
|
+
]
|
|
39
|
+
});
|
|
40
|
+
if (choice === "port") {
|
|
41
|
+
const val = await terminal.text({
|
|
42
|
+
message: "API port:",
|
|
43
|
+
defaultValue: String(current.port ?? 21420),
|
|
44
|
+
validate: (v) => {
|
|
45
|
+
const n = Number(v.trim());
|
|
46
|
+
if (isNaN(n) || n < 1 || n > 65535) return "Port must be 1-65535";
|
|
47
|
+
return void 0;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
await settings.set("port", Number(val.trim()));
|
|
51
|
+
terminal.log.success("Port updated");
|
|
52
|
+
} else if (choice === "host") {
|
|
53
|
+
const val = await terminal.text({
|
|
54
|
+
message: "API host:",
|
|
55
|
+
defaultValue: current.host ?? "127.0.0.1"
|
|
56
|
+
});
|
|
57
|
+
await settings.set("host", val.trim());
|
|
58
|
+
terminal.log.success("Host updated");
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
async uninstall(ctx, opts) {
|
|
62
|
+
if (opts.purge) {
|
|
63
|
+
await ctx.settings.clear();
|
|
64
|
+
ctx.terminal.log.success("API server settings cleared");
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
async setup(ctx) {
|
|
68
|
+
const config = ctx.pluginConfig;
|
|
69
|
+
const { ApiServer } = await import("./api-server-CHVSUDBX.js");
|
|
70
|
+
const apiConfig = {
|
|
71
|
+
port: config.port ?? 0,
|
|
72
|
+
host: config.host ?? "127.0.0.1"
|
|
73
|
+
};
|
|
74
|
+
server = new ApiServer(ctx.core, apiConfig);
|
|
75
|
+
ctx.registerService("api-server", server);
|
|
76
|
+
ctx.on("system:ready", async () => {
|
|
77
|
+
try {
|
|
78
|
+
await server.start();
|
|
79
|
+
ctx.log.info("API server started");
|
|
80
|
+
} catch (err) {
|
|
81
|
+
ctx.log.error(`API server failed to start: ${err}`);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
},
|
|
85
|
+
async teardown() {
|
|
86
|
+
if (server) {
|
|
87
|
+
await server.stop?.();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
var api_server_default = createApiServerPlugin();
|
|
93
|
+
|
|
94
|
+
export {
|
|
95
|
+
api_server_default
|
|
96
|
+
};
|
|
97
|
+
//# sourceMappingURL=chunk-V5JT5TPD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/plugins/api-server/index.ts"],"sourcesContent":["import type { OpenACPPlugin, InstallContext } from '../../core/plugin/types.js'\nimport type { OpenACPCore } from '../../core/core.js'\nimport type { ApiConfig } from './api-server.js'\n\nfunction createApiServerPlugin(): OpenACPPlugin {\n let server: { start(): Promise<void>; stop?(): Promise<void> } | null = null\n\n return {\n name: '@openacp/api-server',\n version: '1.0.0',\n description: 'REST API + SSE streaming server',\n essential: false,\n permissions: ['services:register', 'kernel:access', 'events:read'],\n\n async install(ctx: InstallContext) {\n const { settings, legacyConfig, terminal } = ctx\n\n // Migrate from legacy config if present\n if (legacyConfig) {\n const apiCfg = legacyConfig.api as Record<string, unknown> | undefined\n if (apiCfg) {\n await settings.setAll({\n port: apiCfg.port ?? 21420,\n host: apiCfg.host ?? '127.0.0.1',\n })\n terminal.log.success('API server settings migrated from legacy config')\n return\n }\n }\n\n // Save defaults\n await settings.setAll({\n port: 21420,\n host: '127.0.0.1',\n })\n terminal.log.success('API server defaults saved')\n },\n\n async configure(ctx: InstallContext) {\n const { terminal, settings } = ctx\n const current = await settings.getAll()\n\n const choice = await terminal.select({\n message: 'What to configure?',\n options: [\n { value: 'port', label: `Change port (current: ${current.port ?? 21420})` },\n { value: 'host', label: `Change host (current: ${current.host ?? '127.0.0.1'})` },\n { value: 'done', label: 'Done' },\n ],\n })\n\n if (choice === 'port') {\n const val = await terminal.text({\n message: 'API port:',\n defaultValue: String(current.port ?? 21420),\n validate: (v) => {\n const n = Number(v.trim())\n if (isNaN(n) || n < 1 || n > 65535) return 'Port must be 1-65535'\n return undefined\n },\n })\n await settings.set('port', Number(val.trim()))\n terminal.log.success('Port updated')\n } else if (choice === 'host') {\n const val = await terminal.text({\n message: 'API host:',\n defaultValue: (current.host as string) ?? '127.0.0.1',\n })\n await settings.set('host', val.trim())\n terminal.log.success('Host updated')\n }\n },\n\n async uninstall(ctx: InstallContext, opts: { purge: boolean }) {\n if (opts.purge) {\n await ctx.settings.clear()\n ctx.terminal.log.success('API server settings cleared')\n }\n },\n\n async setup(ctx) {\n const config = ctx.pluginConfig as Record<string, unknown>\n\n // Lazy import to avoid loading unless needed\n const { ApiServer } = await import('./api-server.js')\n\n const apiConfig: ApiConfig = {\n port: (config.port as number) ?? 0,\n host: (config.host as string) ?? '127.0.0.1',\n }\n\n server = new ApiServer(ctx.core as OpenACPCore, apiConfig)\n\n ctx.registerService('api-server', server)\n\n // Start on system:ready\n ctx.on('system:ready', async () => {\n try {\n await server!.start()\n ctx.log.info('API server started')\n } catch (err) {\n ctx.log.error(`API server failed to start: ${err}`)\n }\n })\n },\n\n async teardown() {\n if (server) {\n await server.stop?.()\n }\n },\n }\n}\n\nexport default createApiServerPlugin()\n"],"mappings":";AAIA,SAAS,wBAAuC;AAC9C,MAAI,SAAoE;AAExE,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aAAa;AAAA,IACb,WAAW;AAAA,IACX,aAAa,CAAC,qBAAqB,iBAAiB,aAAa;AAAA,IAEjE,MAAM,QAAQ,KAAqB;AACjC,YAAM,EAAE,UAAU,cAAc,SAAS,IAAI;AAG7C,UAAI,cAAc;AAChB,cAAM,SAAS,aAAa;AAC5B,YAAI,QAAQ;AACV,gBAAM,SAAS,OAAO;AAAA,YACpB,MAAM,OAAO,QAAQ;AAAA,YACrB,MAAM,OAAO,QAAQ;AAAA,UACvB,CAAC;AACD,mBAAS,IAAI,QAAQ,iDAAiD;AACtE;AAAA,QACF;AAAA,MACF;AAGA,YAAM,SAAS,OAAO;AAAA,QACpB,MAAM;AAAA,QACN,MAAM;AAAA,MACR,CAAC;AACD,eAAS,IAAI,QAAQ,2BAA2B;AAAA,IAClD;AAAA,IAEA,MAAM,UAAU,KAAqB;AACnC,YAAM,EAAE,UAAU,SAAS,IAAI;AAC/B,YAAM,UAAU,MAAM,SAAS,OAAO;AAEtC,YAAM,SAAS,MAAM,SAAS,OAAO;AAAA,QACnC,SAAS;AAAA,QACT,SAAS;AAAA,UACP,EAAE,OAAO,QAAQ,OAAO,yBAAyB,QAAQ,QAAQ,KAAK,IAAI;AAAA,UAC1E,EAAE,OAAO,QAAQ,OAAO,yBAAyB,QAAQ,QAAQ,WAAW,IAAI;AAAA,UAChF,EAAE,OAAO,QAAQ,OAAO,OAAO;AAAA,QACjC;AAAA,MACF,CAAC;AAED,UAAI,WAAW,QAAQ;AACrB,cAAM,MAAM,MAAM,SAAS,KAAK;AAAA,UAC9B,SAAS;AAAA,UACT,cAAc,OAAO,QAAQ,QAAQ,KAAK;AAAA,UAC1C,UAAU,CAAC,MAAM;AACf,kBAAM,IAAI,OAAO,EAAE,KAAK,CAAC;AACzB,gBAAI,MAAM,CAAC,KAAK,IAAI,KAAK,IAAI,MAAO,QAAO;AAC3C,mBAAO;AAAA,UACT;AAAA,QACF,CAAC;AACD,cAAM,SAAS,IAAI,QAAQ,OAAO,IAAI,KAAK,CAAC,CAAC;AAC7C,iBAAS,IAAI,QAAQ,cAAc;AAAA,MACrC,WAAW,WAAW,QAAQ;AAC5B,cAAM,MAAM,MAAM,SAAS,KAAK;AAAA,UAC9B,SAAS;AAAA,UACT,cAAe,QAAQ,QAAmB;AAAA,QAC5C,CAAC;AACD,cAAM,SAAS,IAAI,QAAQ,IAAI,KAAK,CAAC;AACrC,iBAAS,IAAI,QAAQ,cAAc;AAAA,MACrC;AAAA,IACF;AAAA,IAEA,MAAM,UAAU,KAAqB,MAA0B;AAC7D,UAAI,KAAK,OAAO;AACd,cAAM,IAAI,SAAS,MAAM;AACzB,YAAI,SAAS,IAAI,QAAQ,6BAA6B;AAAA,MACxD;AAAA,IACF;AAAA,IAEA,MAAM,MAAM,KAAK;AACf,YAAM,SAAS,IAAI;AAGnB,YAAM,EAAE,UAAU,IAAI,MAAM,OAAO,0BAAiB;AAEpD,YAAM,YAAuB;AAAA,QAC3B,MAAO,OAAO,QAAmB;AAAA,QACjC,MAAO,OAAO,QAAmB;AAAA,MACnC;AAEA,eAAS,IAAI,UAAU,IAAI,MAAqB,SAAS;AAEzD,UAAI,gBAAgB,cAAc,MAAM;AAGxC,UAAI,GAAG,gBAAgB,YAAY;AACjC,YAAI;AACF,gBAAM,OAAQ,MAAM;AACpB,cAAI,IAAI,KAAK,oBAAoB;AAAA,QACnC,SAAS,KAAK;AACZ,cAAI,IAAI,MAAM,+BAA+B,GAAG,EAAE;AAAA,QACpD;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,WAAW;AACf,UAAI,QAAQ;AACV,cAAM,OAAO,OAAO;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,qBAAQ,sBAAsB;","names":[]}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// src/core/plugin/plugin-registry.ts
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
var PluginRegistry = class {
|
|
5
|
+
constructor(registryPath) {
|
|
6
|
+
this.registryPath = registryPath;
|
|
7
|
+
}
|
|
8
|
+
data = { installed: {} };
|
|
9
|
+
list() {
|
|
10
|
+
return new Map(Object.entries(this.data.installed));
|
|
11
|
+
}
|
|
12
|
+
get(name) {
|
|
13
|
+
return this.data.installed[name];
|
|
14
|
+
}
|
|
15
|
+
register(name, entry) {
|
|
16
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
17
|
+
this.data.installed[name] = { ...entry, installedAt: now, updatedAt: now };
|
|
18
|
+
}
|
|
19
|
+
remove(name) {
|
|
20
|
+
delete this.data.installed[name];
|
|
21
|
+
}
|
|
22
|
+
setEnabled(name, enabled) {
|
|
23
|
+
const entry = this.data.installed[name];
|
|
24
|
+
if (!entry) return;
|
|
25
|
+
entry.enabled = enabled;
|
|
26
|
+
entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
27
|
+
}
|
|
28
|
+
updateVersion(name, version) {
|
|
29
|
+
const entry = this.data.installed[name];
|
|
30
|
+
if (!entry) return;
|
|
31
|
+
entry.version = version;
|
|
32
|
+
entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
33
|
+
}
|
|
34
|
+
listEnabled() {
|
|
35
|
+
return new Map(Object.entries(this.data.installed).filter(([, e]) => e.enabled));
|
|
36
|
+
}
|
|
37
|
+
listBySource(source) {
|
|
38
|
+
return new Map(Object.entries(this.data.installed).filter(([, e]) => e.source === source));
|
|
39
|
+
}
|
|
40
|
+
async load() {
|
|
41
|
+
try {
|
|
42
|
+
const content = fs.readFileSync(this.registryPath, "utf-8");
|
|
43
|
+
const parsed = JSON.parse(content);
|
|
44
|
+
if (parsed && typeof parsed.installed === "object") {
|
|
45
|
+
this.data = parsed;
|
|
46
|
+
}
|
|
47
|
+
} catch {
|
|
48
|
+
this.data = { installed: {} };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async save() {
|
|
52
|
+
const dir = path.dirname(this.registryPath);
|
|
53
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
54
|
+
fs.writeFileSync(this.registryPath, JSON.stringify(this.data, null, 2));
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export {
|
|
59
|
+
PluginRegistry
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=chunk-W26AUH5B.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/plugin/plugin-registry.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\n\nexport interface PluginEntry {\n version: string\n installedAt: string\n updatedAt: string\n source: 'builtin' | 'npm' | 'local'\n enabled: boolean\n settingsPath: string\n description?: string\n}\n\ntype RegisterInput = Omit<PluginEntry, 'installedAt' | 'updatedAt'>\n\ninterface RegistryData {\n installed: Record<string, PluginEntry>\n}\n\nexport class PluginRegistry {\n private data: RegistryData = { installed: {} }\n\n constructor(private registryPath: string) {}\n\n list(): Map<string, PluginEntry> {\n return new Map(Object.entries(this.data.installed))\n }\n\n get(name: string): PluginEntry | undefined {\n return this.data.installed[name]\n }\n\n register(name: string, entry: RegisterInput): void {\n const now = new Date().toISOString()\n this.data.installed[name] = { ...entry, installedAt: now, updatedAt: now }\n }\n\n remove(name: string): void {\n delete this.data.installed[name]\n }\n\n setEnabled(name: string, enabled: boolean): void {\n const entry = this.data.installed[name]\n if (!entry) return\n entry.enabled = enabled\n entry.updatedAt = new Date().toISOString()\n }\n\n updateVersion(name: string, version: string): void {\n const entry = this.data.installed[name]\n if (!entry) return\n entry.version = version\n entry.updatedAt = new Date().toISOString()\n }\n\n listEnabled(): Map<string, PluginEntry> {\n return new Map(Object.entries(this.data.installed).filter(([, e]) => e.enabled))\n }\n\n listBySource(source: PluginEntry['source']): Map<string, PluginEntry> {\n return new Map(Object.entries(this.data.installed).filter(([, e]) => e.source === source))\n }\n\n async load(): Promise<void> {\n try {\n const content = fs.readFileSync(this.registryPath, 'utf-8')\n const parsed = JSON.parse(content)\n if (parsed && typeof parsed.installed === 'object') {\n this.data = parsed\n }\n } catch {\n this.data = { installed: {} }\n }\n }\n\n async save(): Promise<void> {\n const dir = path.dirname(this.registryPath)\n fs.mkdirSync(dir, { recursive: true })\n fs.writeFileSync(this.registryPath, JSON.stringify(this.data, null, 2))\n }\n}\n"],"mappings":";AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AAkBV,IAAM,iBAAN,MAAqB;AAAA,EAG1B,YAAoB,cAAsB;AAAtB;AAAA,EAAuB;AAAA,EAFnC,OAAqB,EAAE,WAAW,CAAC,EAAE;AAAA,EAI7C,OAAiC;AAC/B,WAAO,IAAI,IAAI,OAAO,QAAQ,KAAK,KAAK,SAAS,CAAC;AAAA,EACpD;AAAA,EAEA,IAAI,MAAuC;AACzC,WAAO,KAAK,KAAK,UAAU,IAAI;AAAA,EACjC;AAAA,EAEA,SAAS,MAAc,OAA4B;AACjD,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,SAAK,KAAK,UAAU,IAAI,IAAI,EAAE,GAAG,OAAO,aAAa,KAAK,WAAW,IAAI;AAAA,EAC3E;AAAA,EAEA,OAAO,MAAoB;AACzB,WAAO,KAAK,KAAK,UAAU,IAAI;AAAA,EACjC;AAAA,EAEA,WAAW,MAAc,SAAwB;AAC/C,UAAM,QAAQ,KAAK,KAAK,UAAU,IAAI;AACtC,QAAI,CAAC,MAAO;AACZ,UAAM,UAAU;AAChB,UAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,EAC3C;AAAA,EAEA,cAAc,MAAc,SAAuB;AACjD,UAAM,QAAQ,KAAK,KAAK,UAAU,IAAI;AACtC,QAAI,CAAC,MAAO;AACZ,UAAM,UAAU;AAChB,UAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,EAC3C;AAAA,EAEA,cAAwC;AACtC,WAAO,IAAI,IAAI,OAAO,QAAQ,KAAK,KAAK,SAAS,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;AAAA,EACjF;AAAA,EAEA,aAAa,QAAyD;AACpE,WAAO,IAAI,IAAI,OAAO,QAAQ,KAAK,KAAK,SAAS,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,MAAM,CAAC;AAAA,EAC3F;AAAA,EAEA,MAAM,OAAsB;AAC1B,QAAI;AACF,YAAM,UAAU,GAAG,aAAa,KAAK,cAAc,OAAO;AAC1D,YAAM,SAAS,KAAK,MAAM,OAAO;AACjC,UAAI,UAAU,OAAO,OAAO,cAAc,UAAU;AAClD,aAAK,OAAO;AAAA,MACd;AAAA,IACF,QAAQ;AACN,WAAK,OAAO,EAAE,WAAW,CAAC,EAAE;AAAA,IAC9B;AAAA,EACF;AAAA,EAEA,MAAM,OAAsB;AAC1B,UAAM,MAAM,KAAK,QAAQ,KAAK,YAAY;AAC1C,OAAG,UAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AACrC,OAAG,cAAc,KAAK,cAAc,KAAK,UAAU,KAAK,MAAM,MAAM,CAAC,CAAC;AAAA,EACxE;AACF;","names":[]}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createChildLogger
|
|
3
|
+
} from "./chunk-XMMAGAT4.js";
|
|
4
|
+
|
|
5
|
+
// src/plugins/usage/usage-store.ts
|
|
6
|
+
import fs from "fs";
|
|
7
|
+
import path from "path";
|
|
8
|
+
var log = createChildLogger({ module: "usage-store" });
|
|
9
|
+
var DEBOUNCE_MS = 2e3;
|
|
10
|
+
var UsageStore = class {
|
|
11
|
+
constructor(filePath, retentionDays) {
|
|
12
|
+
this.filePath = filePath;
|
|
13
|
+
this.retentionDays = retentionDays;
|
|
14
|
+
this.load();
|
|
15
|
+
this.cleanup();
|
|
16
|
+
this.cleanupInterval = setInterval(
|
|
17
|
+
() => this.cleanup(),
|
|
18
|
+
24 * 60 * 60 * 1e3
|
|
19
|
+
);
|
|
20
|
+
this.flushHandler = () => {
|
|
21
|
+
try {
|
|
22
|
+
this.flushSync();
|
|
23
|
+
} catch {
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
process.on("SIGTERM", this.flushHandler);
|
|
27
|
+
process.on("SIGINT", this.flushHandler);
|
|
28
|
+
process.on("exit", this.flushHandler);
|
|
29
|
+
}
|
|
30
|
+
records = [];
|
|
31
|
+
debounceTimer = null;
|
|
32
|
+
cleanupInterval = null;
|
|
33
|
+
flushHandler = null;
|
|
34
|
+
append(record) {
|
|
35
|
+
this.records.push(record);
|
|
36
|
+
this.scheduleDiskWrite();
|
|
37
|
+
}
|
|
38
|
+
query(period) {
|
|
39
|
+
const cutoff = this.getCutoff(period);
|
|
40
|
+
const filtered = cutoff ? this.records.filter((r) => new Date(r.timestamp).getTime() >= cutoff) : this.records;
|
|
41
|
+
const totalTokens = filtered.reduce((sum, r) => sum + r.tokensUsed, 0);
|
|
42
|
+
const totalCost = filtered.reduce(
|
|
43
|
+
(sum, r) => sum + (r.cost?.amount ?? 0),
|
|
44
|
+
0
|
|
45
|
+
);
|
|
46
|
+
const sessionIds = new Set(filtered.map((r) => r.sessionId));
|
|
47
|
+
const currency = filtered.find((r) => r.cost?.currency)?.cost?.currency ?? "USD";
|
|
48
|
+
return {
|
|
49
|
+
period,
|
|
50
|
+
totalTokens,
|
|
51
|
+
totalCost,
|
|
52
|
+
currency,
|
|
53
|
+
sessionCount: sessionIds.size,
|
|
54
|
+
recordCount: filtered.length
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
getMonthlyTotal() {
|
|
58
|
+
const now = /* @__PURE__ */ new Date();
|
|
59
|
+
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
|
|
60
|
+
const cutoff = startOfMonth.getTime();
|
|
61
|
+
const filtered = this.records.filter(
|
|
62
|
+
(r) => new Date(r.timestamp).getTime() >= cutoff
|
|
63
|
+
);
|
|
64
|
+
const totalCost = filtered.reduce(
|
|
65
|
+
(sum, r) => sum + (r.cost?.amount ?? 0),
|
|
66
|
+
0
|
|
67
|
+
);
|
|
68
|
+
const currency = filtered.find((r) => r.cost?.currency)?.cost?.currency ?? "USD";
|
|
69
|
+
return { totalCost, currency };
|
|
70
|
+
}
|
|
71
|
+
cleanup() {
|
|
72
|
+
const cutoff = Date.now() - this.retentionDays * 24 * 60 * 60 * 1e3;
|
|
73
|
+
const before = this.records.length;
|
|
74
|
+
this.records = this.records.filter(
|
|
75
|
+
(r) => new Date(r.timestamp).getTime() >= cutoff
|
|
76
|
+
);
|
|
77
|
+
const removed = before - this.records.length;
|
|
78
|
+
if (removed > 0) {
|
|
79
|
+
log.info({ removed }, "Cleaned up expired usage records");
|
|
80
|
+
this.scheduleDiskWrite();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
flushSync() {
|
|
84
|
+
if (this.debounceTimer) {
|
|
85
|
+
clearTimeout(this.debounceTimer);
|
|
86
|
+
this.debounceTimer = null;
|
|
87
|
+
}
|
|
88
|
+
const data = { version: 1, records: this.records };
|
|
89
|
+
const dir = path.dirname(this.filePath);
|
|
90
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
91
|
+
fs.writeFileSync(this.filePath, JSON.stringify(data, null, 2));
|
|
92
|
+
}
|
|
93
|
+
destroy() {
|
|
94
|
+
if (this.debounceTimer) this.flushSync();
|
|
95
|
+
if (this.cleanupInterval) clearInterval(this.cleanupInterval);
|
|
96
|
+
if (this.flushHandler) {
|
|
97
|
+
process.removeListener("SIGTERM", this.flushHandler);
|
|
98
|
+
process.removeListener("SIGINT", this.flushHandler);
|
|
99
|
+
process.removeListener("exit", this.flushHandler);
|
|
100
|
+
this.flushHandler = null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
load() {
|
|
104
|
+
if (!fs.existsSync(this.filePath)) return;
|
|
105
|
+
try {
|
|
106
|
+
const raw = JSON.parse(
|
|
107
|
+
fs.readFileSync(this.filePath, "utf-8")
|
|
108
|
+
);
|
|
109
|
+
if (raw.version !== 1) {
|
|
110
|
+
log.warn(
|
|
111
|
+
{ version: raw.version },
|
|
112
|
+
"Unknown usage store version, skipping load"
|
|
113
|
+
);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
this.records = raw.records || [];
|
|
117
|
+
log.debug({ count: this.records.length }, "Loaded usage records");
|
|
118
|
+
} catch (err) {
|
|
119
|
+
log.error({ err }, "Failed to load usage store, backing up corrupt file");
|
|
120
|
+
try {
|
|
121
|
+
fs.copyFileSync(this.filePath, this.filePath + ".bak");
|
|
122
|
+
} catch {
|
|
123
|
+
}
|
|
124
|
+
this.records = [];
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
getCutoff(period) {
|
|
128
|
+
const now = /* @__PURE__ */ new Date();
|
|
129
|
+
switch (period) {
|
|
130
|
+
case "today": {
|
|
131
|
+
const start = new Date(now);
|
|
132
|
+
start.setHours(0, 0, 0, 0);
|
|
133
|
+
return start.getTime();
|
|
134
|
+
}
|
|
135
|
+
case "week":
|
|
136
|
+
return Date.now() - 7 * 24 * 60 * 60 * 1e3;
|
|
137
|
+
case "month": {
|
|
138
|
+
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
|
|
139
|
+
return startOfMonth.getTime();
|
|
140
|
+
}
|
|
141
|
+
case "all":
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
scheduleDiskWrite() {
|
|
146
|
+
if (this.debounceTimer) clearTimeout(this.debounceTimer);
|
|
147
|
+
this.debounceTimer = setTimeout(() => {
|
|
148
|
+
this.flushSync();
|
|
149
|
+
}, DEBOUNCE_MS);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// src/plugins/usage/usage-budget.ts
|
|
154
|
+
var UsageBudget = class {
|
|
155
|
+
constructor(store, config, now = () => /* @__PURE__ */ new Date()) {
|
|
156
|
+
this.store = store;
|
|
157
|
+
this.config = config;
|
|
158
|
+
this.now = now;
|
|
159
|
+
this.lastNotifiedMonth = this.now().getMonth();
|
|
160
|
+
}
|
|
161
|
+
lastNotifiedStatus = "ok";
|
|
162
|
+
lastNotifiedMonth;
|
|
163
|
+
check() {
|
|
164
|
+
if (!this.config.monthlyBudget) {
|
|
165
|
+
return { status: "ok" };
|
|
166
|
+
}
|
|
167
|
+
const currentMonth = this.now().getMonth();
|
|
168
|
+
if (currentMonth !== this.lastNotifiedMonth) {
|
|
169
|
+
this.lastNotifiedStatus = "ok";
|
|
170
|
+
this.lastNotifiedMonth = currentMonth;
|
|
171
|
+
}
|
|
172
|
+
const { totalCost } = this.store.getMonthlyTotal();
|
|
173
|
+
const budget = this.config.monthlyBudget;
|
|
174
|
+
const threshold = this.config.warningThreshold;
|
|
175
|
+
let status;
|
|
176
|
+
if (totalCost >= budget) {
|
|
177
|
+
status = "exceeded";
|
|
178
|
+
} else if (totalCost >= threshold * budget) {
|
|
179
|
+
status = "warning";
|
|
180
|
+
} else {
|
|
181
|
+
status = "ok";
|
|
182
|
+
}
|
|
183
|
+
let message;
|
|
184
|
+
if (status !== "ok" && status !== this.lastNotifiedStatus) {
|
|
185
|
+
const pct = Math.round(totalCost / budget * 100);
|
|
186
|
+
const filled = Math.round(Math.min(totalCost / budget, 1) * 10);
|
|
187
|
+
const bar = "\u2593".repeat(filled) + "\u2591".repeat(10 - filled);
|
|
188
|
+
if (status === "warning") {
|
|
189
|
+
message = `\u26A0\uFE0F <b>Budget Warning</b>
|
|
190
|
+
Monthly usage: $${totalCost.toFixed(2)} / $${budget.toFixed(2)} (${pct}%)
|
|
191
|
+
${bar} ${pct}%`;
|
|
192
|
+
} else {
|
|
193
|
+
message = `\u{1F6A8} <b>Budget Exceeded</b>
|
|
194
|
+
Monthly usage: $${totalCost.toFixed(2)} / $${budget.toFixed(2)} (${pct}%)
|
|
195
|
+
${bar} ${pct}%
|
|
196
|
+
Sessions are NOT blocked \u2014 this is a warning only.`;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
this.lastNotifiedStatus = status;
|
|
200
|
+
return { status, message };
|
|
201
|
+
}
|
|
202
|
+
getStatus() {
|
|
203
|
+
const { totalCost } = this.store.getMonthlyTotal();
|
|
204
|
+
const budget = this.config.monthlyBudget ?? 0;
|
|
205
|
+
let status = "ok";
|
|
206
|
+
if (budget > 0) {
|
|
207
|
+
if (totalCost >= budget) {
|
|
208
|
+
status = "exceeded";
|
|
209
|
+
} else if (totalCost >= this.config.warningThreshold * budget) {
|
|
210
|
+
status = "warning";
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
const percent = budget > 0 ? Math.round(totalCost / budget * 100) : 0;
|
|
214
|
+
return { status, used: totalCost, budget, percent };
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
export {
|
|
219
|
+
UsageStore,
|
|
220
|
+
UsageBudget
|
|
221
|
+
};
|
|
222
|
+
//# sourceMappingURL=chunk-WAAD23KY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/plugins/usage/usage-store.ts","../../src/plugins/usage/usage-budget.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { UsageRecord, UsageSummary } from \"../../core/types.js\";\nimport { createChildLogger } from \"../../core/utils/log.js\";\n\nconst log = createChildLogger({ module: \"usage-store\" });\n\ninterface StoreFile {\n version: number;\n records: UsageRecord[];\n}\n\nconst DEBOUNCE_MS = 2000;\n\nexport class UsageStore {\n private records: UsageRecord[] = [];\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\n private cleanupInterval: ReturnType<typeof setInterval> | null = null;\n private flushHandler: (() => void) | null = null;\n\n constructor(\n private filePath: string,\n private retentionDays: number,\n ) {\n this.load();\n this.cleanup();\n\n this.cleanupInterval = setInterval(\n () => this.cleanup(),\n 24 * 60 * 60 * 1000,\n );\n\n this.flushHandler = () => {\n try {\n this.flushSync();\n } catch {\n // Best effort — don't block other exit handlers (e.g., session store flush)\n }\n };\n process.on(\"SIGTERM\", this.flushHandler);\n process.on(\"SIGINT\", this.flushHandler);\n process.on(\"exit\", this.flushHandler);\n }\n\n append(record: UsageRecord): void {\n this.records.push(record);\n this.scheduleDiskWrite();\n }\n\n query(period: \"today\" | \"week\" | \"month\" | \"all\"): UsageSummary {\n const cutoff = this.getCutoff(period);\n const filtered = cutoff\n ? this.records.filter((r) => new Date(r.timestamp).getTime() >= cutoff)\n : this.records;\n\n const totalTokens = filtered.reduce((sum, r) => sum + r.tokensUsed, 0);\n const totalCost = filtered.reduce(\n (sum, r) => sum + (r.cost?.amount ?? 0),\n 0,\n );\n const sessionIds = new Set(filtered.map((r) => r.sessionId));\n const currency =\n filtered.find((r) => r.cost?.currency)?.cost?.currency ?? \"USD\";\n\n return {\n period,\n totalTokens,\n totalCost,\n currency,\n sessionCount: sessionIds.size,\n recordCount: filtered.length,\n };\n }\n\n getMonthlyTotal(): { totalCost: number; currency: string } {\n const now = new Date();\n const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);\n const cutoff = startOfMonth.getTime();\n\n const filtered = this.records.filter(\n (r) => new Date(r.timestamp).getTime() >= cutoff,\n );\n const totalCost = filtered.reduce(\n (sum, r) => sum + (r.cost?.amount ?? 0),\n 0,\n );\n const currency =\n filtered.find((r) => r.cost?.currency)?.cost?.currency ?? \"USD\";\n\n return { totalCost, currency };\n }\n\n cleanup(): void {\n const cutoff =\n Date.now() - this.retentionDays * 24 * 60 * 60 * 1000;\n const before = this.records.length;\n this.records = this.records.filter(\n (r) => new Date(r.timestamp).getTime() >= cutoff,\n );\n const removed = before - this.records.length;\n if (removed > 0) {\n log.info({ removed }, \"Cleaned up expired usage records\");\n this.scheduleDiskWrite();\n }\n }\n\n flushSync(): void {\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = null;\n }\n const data: StoreFile = { version: 1, records: this.records };\n const dir = path.dirname(this.filePath);\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(this.filePath, JSON.stringify(data, null, 2));\n }\n\n destroy(): void {\n if (this.debounceTimer) this.flushSync();\n if (this.cleanupInterval) clearInterval(this.cleanupInterval);\n if (this.flushHandler) {\n process.removeListener(\"SIGTERM\", this.flushHandler);\n process.removeListener(\"SIGINT\", this.flushHandler);\n process.removeListener(\"exit\", this.flushHandler);\n this.flushHandler = null;\n }\n }\n\n private load(): void {\n if (!fs.existsSync(this.filePath)) return;\n try {\n const raw = JSON.parse(\n fs.readFileSync(this.filePath, \"utf-8\"),\n ) as StoreFile;\n if (raw.version !== 1) {\n log.warn(\n { version: raw.version },\n \"Unknown usage store version, skipping load\",\n );\n return;\n }\n this.records = raw.records || [];\n log.debug({ count: this.records.length }, \"Loaded usage records\");\n } catch (err) {\n log.error({ err }, \"Failed to load usage store, backing up corrupt file\");\n try {\n fs.copyFileSync(this.filePath, this.filePath + \".bak\");\n } catch {\n /* best effort */\n }\n this.records = [];\n }\n }\n\n private getCutoff(\n period: \"today\" | \"week\" | \"month\" | \"all\",\n ): number | null {\n const now = new Date();\n switch (period) {\n case \"today\": {\n const start = new Date(now);\n start.setHours(0, 0, 0, 0);\n return start.getTime();\n }\n case \"week\":\n return Date.now() - 7 * 24 * 60 * 60 * 1000;\n case \"month\": {\n // Use current calendar month (1st of month), consistent with getMonthlyTotal()\n const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);\n return startOfMonth.getTime();\n }\n case \"all\":\n return null;\n }\n }\n\n private scheduleDiskWrite(): void {\n if (this.debounceTimer) clearTimeout(this.debounceTimer);\n this.debounceTimer = setTimeout(() => {\n this.flushSync();\n }, DEBOUNCE_MS);\n }\n}\n","import type { UsageConfig } from \"../../core/config/config.js\";\nimport type { UsageStore } from \"./usage-store.js\";\n\nexport class UsageBudget {\n private lastNotifiedStatus: \"ok\" | \"warning\" | \"exceeded\" = \"ok\";\n private lastNotifiedMonth: number;\n\n constructor(\n private store: UsageStore,\n private config: UsageConfig,\n private now: () => Date = () => new Date(),\n ) {\n this.lastNotifiedMonth = this.now().getMonth();\n }\n\n check(): { status: \"ok\" | \"warning\" | \"exceeded\"; message?: string } {\n if (!this.config.monthlyBudget) {\n return { status: \"ok\" };\n }\n\n // Reset de-duplication at month boundary\n const currentMonth = this.now().getMonth();\n if (currentMonth !== this.lastNotifiedMonth) {\n this.lastNotifiedStatus = \"ok\";\n this.lastNotifiedMonth = currentMonth;\n }\n\n const { totalCost } = this.store.getMonthlyTotal();\n const budget = this.config.monthlyBudget;\n const threshold = this.config.warningThreshold;\n\n let status: \"ok\" | \"warning\" | \"exceeded\";\n if (totalCost >= budget) {\n status = \"exceeded\";\n } else if (totalCost >= threshold * budget) {\n status = \"warning\";\n } else {\n status = \"ok\";\n }\n\n // Only emit message on status change (prevents spam)\n let message: string | undefined;\n if (status !== \"ok\" && status !== this.lastNotifiedStatus) {\n const pct = Math.round((totalCost / budget) * 100);\n const filled = Math.round(Math.min(totalCost / budget, 1) * 10);\n const bar = \"▓\".repeat(filled) + \"░\".repeat(10 - filled);\n\n if (status === \"warning\") {\n message =\n `⚠️ <b>Budget Warning</b>\\n` +\n `Monthly usage: $${totalCost.toFixed(2)} / $${budget.toFixed(2)} (${pct}%)\\n` +\n `${bar} ${pct}%`;\n } else {\n message =\n `🚨 <b>Budget Exceeded</b>\\n` +\n `Monthly usage: $${totalCost.toFixed(2)} / $${budget.toFixed(2)} (${pct}%)\\n` +\n `${bar} ${pct}%\\n` +\n `Sessions are NOT blocked — this is a warning only.`;\n }\n }\n\n this.lastNotifiedStatus = status;\n return { status, message };\n }\n\n getStatus(): {\n status: \"ok\" | \"warning\" | \"exceeded\";\n used: number;\n budget: number;\n percent: number;\n } {\n const { totalCost } = this.store.getMonthlyTotal();\n const budget = this.config.monthlyBudget ?? 0;\n\n let status: \"ok\" | \"warning\" | \"exceeded\" = \"ok\";\n if (budget > 0) {\n if (totalCost >= budget) {\n status = \"exceeded\";\n } else if (totalCost >= this.config.warningThreshold * budget) {\n status = \"warning\";\n }\n }\n\n const percent = budget > 0 ? Math.round((totalCost / budget) * 100) : 0;\n return { status, used: totalCost, budget, percent };\n }\n}\n"],"mappings":"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","names":[]}
|