@ashx-j/lunr 0.2.21 → 0.2.23
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/CHANGELOG.md +4 -2
- package/README.md +23 -5
- package/dist/builtin-extensions/index.d.ts.map +1 -1
- package/dist/builtin-extensions/index.js +1 -0
- package/dist/builtin-extensions/index.js.map +1 -1
- package/dist/builtin-extensions/lunr-browser.d.ts +9 -0
- package/dist/builtin-extensions/lunr-browser.d.ts.map +1 -0
- package/dist/builtin-extensions/lunr-browser.js +169 -0
- package/dist/builtin-extensions/lunr-browser.js.map +1 -0
- package/dist/builtin-extensions/lunr-todos.d.ts.map +1 -1
- package/dist/builtin-extensions/lunr-todos.js +15 -0
- package/dist/builtin-extensions/lunr-todos.js.map +1 -1
- package/dist/builtin-extensions/pi-intercom/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-intercom/index.js +3 -0
- package/dist/builtin-extensions/pi-intercom/index.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/control-notices.d.ts +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/control-notices.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/control-notices.js +5 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/control-notices.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts +2 -2
- package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.js +18 -5
- package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts +4 -3
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js +3 -0
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/intercom/communication.d.ts +17 -0
- package/dist/builtin-extensions/pi-subagents/src/intercom/communication.d.ts.map +1 -0
- package/dist/builtin-extensions/pi-subagents/src/intercom/communication.js +45 -0
- package/dist/builtin-extensions/pi-subagents/src/intercom/communication.js.map +1 -0
- package/dist/builtin-extensions/pi-subagents/src/intercom/intercom-bridge.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/intercom/intercom-bridge.js +4 -11
- package/dist/builtin-extensions/pi-subagents/src/intercom/intercom-bridge.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.d.ts +4 -1
- package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.js +160 -51
- package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-ask.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-ask.js +5 -0
- package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-ask.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.d.ts +2 -0
- package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.js +3 -2
- package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/auto-drain.d.ts +1 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/background/auto-drain.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/auto-drain.js +2 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/auto-drain.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.d.ts +3 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.js +11 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.js +41 -3
- package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js +4 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.js +3 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-control.d.ts +1 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-control.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-control.js +3 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-control.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.js +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts +1 -0
- package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/types.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/communication.d.ts +18 -0
- package/dist/builtin-extensions/pi-subagents/src/tui/communication.d.ts.map +1 -0
- package/dist/builtin-extensions/pi-subagents/src/tui/communication.js +48 -0
- package/dist/builtin-extensions/pi-subagents/src/tui/communication.js.map +1 -0
- package/dist/builtin-extensions/pi-web-access/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-web-access/index.js +11 -7
- package/dist/builtin-extensions/pi-web-access/index.js.map +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +2 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/install-cli.d.ts.map +1 -1
- package/dist/cli/install-cli.js +15 -45
- package/dist/cli/install-cli.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts +9 -0
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +126 -29
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session.d.ts +22 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +250 -105
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/browser/network.d.ts +9 -0
- package/dist/core/browser/network.d.ts.map +1 -0
- package/dist/core/browser/network.js +146 -0
- package/dist/core/browser/network.js.map +1 -0
- package/dist/core/browser/runtime.d.ts +24 -0
- package/dist/core/browser/runtime.d.ts.map +1 -0
- package/dist/core/browser/runtime.js +289 -0
- package/dist/core/browser/runtime.js.map +1 -0
- package/dist/core/browser/schema.d.ts +16 -0
- package/dist/core/browser/schema.d.ts.map +1 -0
- package/dist/core/browser/schema.js +36 -0
- package/dist/core/browser/schema.js.map +1 -0
- package/dist/core/browser/settings.d.ts +8 -0
- package/dist/core/browser/settings.d.ts.map +1 -0
- package/dist/core/browser/settings.js +30 -0
- package/dist/core/browser/settings.js.map +1 -0
- package/dist/core/browser/setup.d.ts +2 -0
- package/dist/core/browser/setup.d.ts.map +1 -0
- package/dist/core/browser/setup.js +16 -0
- package/dist/core/browser/setup.js.map +1 -0
- package/dist/core/customize.d.ts.map +1 -1
- package/dist/core/customize.js +15 -14
- package/dist/core/customize.js.map +1 -1
- package/dist/core/export-html/index.d.ts.map +1 -1
- package/dist/core/export-html/index.js +1 -1
- package/dist/core/export-html/index.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +1 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +1 -1
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +1 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/install-features.d.ts.map +1 -1
- package/dist/core/install-features.js +10 -8
- package/dist/core/install-features.js.map +1 -1
- package/dist/core/memory-cap.d.ts.map +1 -1
- package/dist/core/memory-cap.js +5 -3
- package/dist/core/memory-cap.js.map +1 -1
- package/dist/core/model-tiers.d.ts.map +1 -1
- package/dist/core/model-tiers.js +9 -6
- package/dist/core/model-tiers.js.map +1 -1
- package/dist/core/permissions.d.ts.map +1 -1
- package/dist/core/permissions.js +9 -0
- package/dist/core/permissions.js.map +1 -1
- package/dist/core/plan-mode.d.ts.map +1 -1
- package/dist/core/plan-mode.js +3 -0
- package/dist/core/plan-mode.js.map +1 -1
- package/dist/core/process-registry.d.ts.map +1 -1
- package/dist/core/process-registry.js +6 -4
- package/dist/core/process-registry.js.map +1 -1
- package/dist/core/runtime-scope.d.ts +11 -0
- package/dist/core/runtime-scope.d.ts.map +1 -0
- package/dist/core/runtime-scope.js +3 -0
- package/dist/core/runtime-scope.js.map +1 -0
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +13 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-handoff.d.ts +35 -0
- package/dist/core/session-handoff.d.ts.map +1 -0
- package/dist/core/session-handoff.js +214 -0
- package/dist/core/session-handoff.js.map +1 -0
- package/dist/core/session-manager.d.ts +20 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +184 -22
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-ownership.d.ts +28 -0
- package/dist/core/session-ownership.d.ts.map +1 -0
- package/dist/core/session-ownership.js +138 -0
- package/dist/core/session-ownership.js.map +1 -0
- package/dist/core/session-retention.d.ts.map +1 -1
- package/dist/core/session-retention.js +11 -2
- package/dist/core/session-retention.js.map +1 -1
- package/dist/core/settings-manager.d.ts +11 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +27 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +2 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/subagent-wait-interruption.d.ts +11 -0
- package/dist/core/subagent-wait-interruption.d.ts.map +1 -0
- package/dist/core/subagent-wait-interruption.js +19 -0
- package/dist/core/subagent-wait-interruption.js.map +1 -0
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +7 -2
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/todo-settings.d.ts +5 -0
- package/dist/core/todo-settings.d.ts.map +1 -0
- package/dist/core/todo-settings.js +7 -0
- package/dist/core/todo-settings.js.map +1 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +4 -4
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +5 -3
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +4 -4
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +4 -4
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +4 -4
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +4 -4
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts +14 -5
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js +34 -7
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +4 -4
- package/dist/core/tools/write.js.map +1 -1
- package/dist/core/usage-service.d.ts.map +1 -1
- package/dist/core/usage-service.js +5 -3
- package/dist/core/usage-service.js.map +1 -1
- package/dist/gateway/adapters/discord.d.ts +12 -1
- package/dist/gateway/adapters/discord.d.ts.map +1 -1
- package/dist/gateway/adapters/discord.js +112 -17
- package/dist/gateway/adapters/discord.js.map +1 -1
- package/dist/gateway/adapters/telegram.d.ts +4 -2
- package/dist/gateway/adapters/telegram.d.ts.map +1 -1
- package/dist/gateway/adapters/telegram.js +34 -11
- package/dist/gateway/adapters/telegram.js.map +1 -1
- package/dist/gateway/agent-bridge.d.ts +14 -3
- package/dist/gateway/agent-bridge.d.ts.map +1 -1
- package/dist/gateway/agent-bridge.js +252 -60
- package/dist/gateway/agent-bridge.js.map +1 -1
- package/dist/gateway/approval.d.ts +1 -0
- package/dist/gateway/approval.d.ts.map +1 -1
- package/dist/gateway/approval.js +60 -18
- package/dist/gateway/approval.js.map +1 -1
- package/dist/gateway/authz.d.ts +2 -0
- package/dist/gateway/authz.d.ts.map +1 -1
- package/dist/gateway/authz.js +13 -0
- package/dist/gateway/authz.js.map +1 -1
- package/dist/gateway/buttons.d.ts +3 -1
- package/dist/gateway/buttons.d.ts.map +1 -1
- package/dist/gateway/buttons.js +18 -3
- package/dist/gateway/buttons.js.map +1 -1
- package/dist/gateway/command.d.ts.map +1 -1
- package/dist/gateway/command.js +49 -4
- package/dist/gateway/command.js.map +1 -1
- package/dist/gateway/commands.d.ts.map +1 -1
- package/dist/gateway/commands.js +18 -3
- package/dist/gateway/commands.js.map +1 -1
- package/dist/gateway/config.d.ts +5 -0
- package/dist/gateway/config.d.ts.map +1 -1
- package/dist/gateway/config.js +5 -0
- package/dist/gateway/config.js.map +1 -1
- package/dist/gateway/conversations.d.ts +14 -0
- package/dist/gateway/conversations.d.ts.map +1 -0
- package/dist/gateway/conversations.js +30 -0
- package/dist/gateway/conversations.js.map +1 -0
- package/dist/gateway/download.d.ts +2 -0
- package/dist/gateway/download.d.ts.map +1 -0
- package/dist/gateway/download.js +36 -0
- package/dist/gateway/download.js.map +1 -0
- package/dist/gateway/index.d.ts.map +1 -1
- package/dist/gateway/index.js +85 -26
- package/dist/gateway/index.js.map +1 -1
- package/dist/gateway/mobile-commands.d.ts +24 -0
- package/dist/gateway/mobile-commands.d.ts.map +1 -0
- package/dist/gateway/mobile-commands.js +422 -0
- package/dist/gateway/mobile-commands.js.map +1 -0
- package/dist/gateway/presenter.d.ts +16 -0
- package/dist/gateway/presenter.d.ts.map +1 -0
- package/dist/gateway/presenter.js +210 -0
- package/dist/gateway/presenter.js.map +1 -0
- package/dist/gateway/router.d.ts +1 -0
- package/dist/gateway/router.d.ts.map +1 -1
- package/dist/gateway/router.js +32 -3
- package/dist/gateway/router.js.map +1 -1
- package/dist/gateway/service.d.ts +46 -0
- package/dist/gateway/service.d.ts.map +1 -0
- package/dist/gateway/service.js +395 -0
- package/dist/gateway/service.js.map +1 -0
- package/dist/gateway/setup.d.ts +4 -0
- package/dist/gateway/setup.d.ts.map +1 -0
- package/dist/gateway/setup.js +146 -0
- package/dist/gateway/setup.js.map +1 -0
- package/dist/gateway/types.d.ts +4 -2
- package/dist/gateway/types.d.ts.map +1 -1
- package/dist/gateway/types.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +2 -1
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +19 -2
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +78 -17
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/copyable-text.d.ts +27 -0
- package/dist/modes/interactive/components/copyable-text.d.ts.map +1 -0
- package/dist/modes/interactive/components/copyable-text.js +156 -0
- package/dist/modes/interactive/components/copyable-text.js.map +1 -0
- package/dist/modes/interactive/components/custom-entry.d.ts +1 -0
- package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-entry.js +8 -0
- package/dist/modes/interactive/components/custom-entry.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts +1 -0
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +8 -0
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +16 -0
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +8 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +51 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/thinking-tail.d.ts +9 -2
- package/dist/modes/interactive/components/thinking-tail.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-tail.js +43 -1
- package/dist/modes/interactive/components/thinking-tail.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +4 -3
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +34 -45
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +9 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +267 -44
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts +1 -0
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +23 -0
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/node-runtime/agent-session-services-GZVSOGYR.js +49 -0
- package/dist/node-runtime/{builtin-extensions-JCOPAAB5.js → builtin-extensions-QVCXNQT4.js} +6 -5
- package/dist/node-runtime/{chunk-LTYWTR3V.js → chunk-2MI5OPMN.js} +17 -2
- package/dist/node-runtime/{chunk-W3CVH5RX.js → chunk-2TKODGBZ.js} +11 -6
- package/dist/node-runtime/chunk-4EULYYR4.js +62 -0
- package/dist/node-runtime/{chunk-6N22HULO.js → chunk-5D7LC2ZQ.js} +7 -2
- package/dist/node-runtime/{chunk-KBKMCJDU.js → chunk-5ZQXRPMC.js} +19 -4
- package/dist/node-runtime/{chunk-BOHIDQT4.js → chunk-6VYZ5UFP.js} +1 -1
- package/dist/node-runtime/chunk-AZJHNQKQ.js +205 -0
- package/dist/node-runtime/{chunk-A3KMVBZV.js → chunk-BBUVIEZB.js} +1 -10
- package/dist/node-runtime/{chunk-IRPJXI6U.js → chunk-BX2RB477.js} +1 -1
- package/dist/node-runtime/chunk-CCCN2UCX.js +14 -0
- package/dist/node-runtime/{chunk-25I2BHAA.js → chunk-CSUZVNYE.js} +1 -1
- package/dist/node-runtime/chunk-DD5YWFSJ.js +708 -0
- package/dist/node-runtime/chunk-DQMGU675.js +3409 -0
- package/dist/node-runtime/{chunk-QZMODZQ2.js → chunk-E24EO34J.js} +2 -1
- package/dist/node-runtime/chunk-EKVFP6YF.js +355 -0
- package/dist/node-runtime/chunk-GJ2RDBRL.js +672 -0
- package/dist/node-runtime/{chunk-W3SILANP.js → chunk-GMHJCCEN.js} +8 -8
- package/dist/node-runtime/{chunk-DDWHZ633.js → chunk-GS42T6MX.js} +1 -1
- package/dist/node-runtime/chunk-GS66LV4M.js +2830 -0
- package/dist/node-runtime/chunk-H4K3JDRB.js +47 -0
- package/dist/node-runtime/{chunk-2SJB2AWP.js → chunk-HMBGROQK.js} +3 -3
- package/dist/node-runtime/{chunk-GB2MGFLI.js → chunk-HPUP7E4T.js} +216 -201
- package/dist/node-runtime/{chunk-YMEAYRBE.js → chunk-HTFRRDSF.js} +2 -7
- package/dist/node-runtime/{chunk-OPEK5RRY.js → chunk-IF24A3FH.js} +1 -1
- package/dist/node-runtime/chunk-IMLCWLPI.js +9 -0
- package/dist/node-runtime/chunk-KKUTQQV7.js +144 -0
- package/dist/node-runtime/chunk-LFZDVKSP.js +521 -0
- package/dist/node-runtime/{chunk-2BUAYZ7K.js → chunk-LLUIPGDR.js} +581 -197
- package/dist/node-runtime/{chunk-7NBZ5P7I.js → chunk-NAY6UUQZ.js} +1 -1
- package/dist/node-runtime/chunk-OAR4TYZE.js +146 -0
- package/dist/node-runtime/{chunk-STERBGUB.js → chunk-OFKSVRV7.js} +2 -2
- package/dist/node-runtime/{chunk-JZQ7F36T.js → chunk-PCEW76PM.js} +19 -3
- package/dist/node-runtime/{chunk-WLLDXJRT.js → chunk-QAZOULTU.js} +29 -1014
- package/dist/node-runtime/{chunk-6KDIOJL3.js → chunk-QH6YL7VK.js} +3 -3
- package/dist/node-runtime/chunk-R3K2F5GI.js +122 -0
- package/dist/node-runtime/{chunk-RNBHABBA.js → chunk-RDDAZOMU.js} +23 -0
- package/dist/node-runtime/{chunk-SY2TFMLO.js → chunk-RIR5EDDJ.js} +46 -151
- package/dist/node-runtime/chunk-RMQZU2YU.js +117 -0
- package/dist/node-runtime/{chunk-6BEIBLQ3.js → chunk-RWTKOC3B.js} +1 -1
- package/dist/node-runtime/{chunk-G6LRAP36.js → chunk-TQGPP4SC.js} +1 -1
- package/dist/node-runtime/{chunk-Y5KOEMBH.js → chunk-TVJUOJZJ.js} +9 -674
- package/dist/node-runtime/chunk-UAEOTO52.js +119 -0
- package/dist/node-runtime/{chunk-AY6CAJSL.js → chunk-UJOCPOMX.js} +6 -3
- package/dist/node-runtime/chunk-UP2XBVH5.js +40 -0
- package/dist/node-runtime/{chunk-WJVFOIB5.js → chunk-UQUCFAJ3.js} +1 -1
- package/dist/node-runtime/chunk-URD2SLIT.js +1019 -0
- package/dist/node-runtime/chunk-US544NN6.js +13 -0
- package/dist/node-runtime/chunk-UWPJL22I.js +341 -0
- package/dist/node-runtime/{chunk-4I23VTC4.js → chunk-VWCE2HSZ.js} +21 -124
- package/dist/node-runtime/{chunk-VZR3NCM7.js → chunk-W64JC4E7.js} +18 -14
- package/dist/node-runtime/{chunk-AWVD5IEY.js → chunk-X3URCYCU.js} +23 -12
- package/dist/node-runtime/{chunk-GKLEQ3I4.js → chunk-XLTL257W.js} +126 -27
- package/dist/node-runtime/{chunk-WKDK4C5P.js → chunk-YDO2F2IA.js} +38 -164
- package/dist/node-runtime/{chunk-PDNXVXMD.js → chunk-YHQ3NBB3.js} +58 -48
- package/dist/node-runtime/chunk-YPHAIRZT.js +10 -0
- package/dist/node-runtime/cli-runtime.js +2 -2
- package/dist/node-runtime/command-PDVTBRWA.js +45 -0
- package/dist/node-runtime/{commands-MV5KOZ64.js → commands-KAMO2T6P.js} +10 -10
- package/dist/node-runtime/commands-XDCFGIGW.js +36 -0
- package/dist/node-runtime/config-RORQUQFG.js +20 -0
- package/dist/node-runtime/{customize-LF5VST47.js → customize-VFJV3U6A.js} +2 -1
- package/dist/node-runtime/{direct-tool-executor-BK7CLEBX.js → direct-tool-executor-YAVOLDFY.js} +8 -8
- package/dist/node-runtime/{export-html-TEXVV5RP.js → export-html-KSOIMVPI.js} +4 -3
- package/dist/node-runtime/{extension-input-O4HSAEM4.js → extension-input-E7BJZ35H.js} +4 -4
- package/dist/node-runtime/{extension-selector-X5FCX43D.js → extension-selector-WU42XDTU.js} +4 -4
- package/dist/node-runtime/{extract-XLQSJN4V.js → extract-EQJE7FZZ.js} +2 -2
- package/dist/node-runtime/{gateway-BM6NLOH4.js → gateway-AYWM5DIO.js} +275 -994
- package/dist/node-runtime/{gemini-search-U7SUMPQA.js → gemini-search-35OCRFLN.js} +1 -1
- package/dist/node-runtime/{gemini-url-context-PXWCBQHK.js → gemini-url-context-UQY3PHHW.js} +2 -2
- package/dist/node-runtime/index.js +104 -65
- package/dist/node-runtime/{init-3C7Z24OI.js → init-X2LIUB2H.js} +3 -3
- package/dist/node-runtime/{install-cli-EXMJQESX.js → install-cli-3BO4MMQ6.js} +21 -82
- package/dist/node-runtime/interactive-mode-4MFRKAHG.js +72 -0
- package/dist/node-runtime/{interactive-view-ILS6TAN5.js → interactive-view-TUZHCQM3.js} +8 -8
- package/dist/node-runtime/lunr-browser-RYFIIVJN.js +174 -0
- package/dist/node-runtime/{lunr-cron-4VHP4E4B.js → lunr-cron-YWXEPZMQ.js} +19 -5
- package/dist/node-runtime/main.js +44 -31
- package/dist/node-runtime/{memory-cap-3S4XRLNP.js → memory-cap-EL3KL4JJ.js} +2 -1
- package/dist/node-runtime/mobile-commands-LVHDAUDP.js +32 -0
- package/dist/node-runtime/model-runtime-PLQKAG4B.js +16 -0
- package/dist/node-runtime/{model-tiers-NJLHUEGK.js → model-tiers-OU3U5CZG.js} +2 -1
- package/dist/node-runtime/{package-manager-cli-N37546V5.js → package-manager-cli-6GT3Z3CK.js} +22 -15
- package/dist/node-runtime/{pi-intercom-NV2LW6X7.js → pi-intercom-HBPK5HSJ.js} +4 -1
- package/dist/node-runtime/{pi-mcp-adapter-GUFZWW54.js → pi-mcp-adapter-E6WULBKF.js} +4 -4
- package/dist/node-runtime/{pi-subagents-6MUIFNDM.js → pi-subagents-CDWK2AKY.js} +236 -79
- package/dist/node-runtime/{pi-web-access-2CQGFLT2.js → pi-web-access-WTGMNZ32.js} +15 -15
- package/dist/node-runtime/process-registry-4FAKZQOL.js +31 -0
- package/dist/node-runtime/{proxy-modes-V6YVFH3C.js → proxy-modes-OSQCWRBI.js} +9 -9
- package/dist/node-runtime/rpc-entry.js +44 -31
- package/dist/node-runtime/{rpc-mode-W5ZTLTMZ.js → rpc-mode-O3XV4SID.js} +2 -2
- package/dist/node-runtime/runtime-4VA6JKNF.js +373 -0
- package/dist/node-runtime/{runtime-bridges-2VQTLPOZ.js → runtime-bridges-3XUQ46XW.js} +6 -5
- package/dist/node-runtime/service-ISSP6VHE.js +36 -0
- package/dist/node-runtime/session-handoff-HC7R5E24.js +33 -0
- package/dist/node-runtime/{session-manager-E7AREDTV.js → session-manager-CFN4UFM2.js} +2 -1
- package/dist/node-runtime/{session-selector-FJ7M2AIX.js → session-selector-GIM4DHQ2.js} +5 -4
- package/dist/node-runtime/{settings-manager-CUGAZWAB.js → settings-manager-6VEMXRDL.js} +7 -2
- package/dist/node-runtime/setup-5SR2J35A.js +155 -0
- package/dist/node-runtime/setup-JBKOLJ6F.js +18 -0
- package/dist/node-runtime/{subagent-executor-MH4A7CCF.js → subagent-executor-M5VWB3D3.js} +26 -18
- package/dist/node-runtime/theme-UOO5RVFN.js +68 -0
- package/dist/node-runtime/trust-manager-MMISNCYO.js +17 -0
- package/dist/node-runtime/{update-cli-XTZMZGOL.js → update-cli-UVKJWRRJ.js} +7 -2
- package/dist/node-runtime/usage-service-LFB2SWYV.js +37 -0
- package/dist/node-runtime/{video-extract-OYT5WKS5.js → video-extract-OOZHR7SU.js} +2 -2
- package/dist/node-runtime/{youtube-extract-TQYKGFGS.js → youtube-extract-FNPAUNHU.js} +6 -6
- package/docs/browser.md +86 -0
- package/docs/extensions.md +2 -0
- package/docs/features.md +96 -16
- package/docs/interactive-startup.md +2 -1
- package/docs/sessions.md +10 -0
- package/docs/settings.md +2 -0
- package/docs/tui.md +2 -0
- package/docs/usage.md +16 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +7 -4
- package/scripts/install-browser.mjs +20 -0
- package/dist/node-runtime/agent-session-services-C743TYQE.js +0 -37
- package/dist/node-runtime/chunk-VGYZ3APQ.js +0 -59
- package/dist/node-runtime/chunk-XI77KVKA.js +0 -6009
- package/dist/node-runtime/command-P4NYCJ2M.js +0 -13
- package/dist/node-runtime/interactive-mode-EVVBA64D.js +0 -59
- package/dist/node-runtime/{chunk-UWQYRSYQ.js → chunk-YJMMG7C6.js} +25 -25
- package/dist/node-runtime/{mcp-panel-IIGMXQGP.js → mcp-panel-KTTFXJZ4.js} +3 -3
- package/dist/node-runtime/{src-BPQFJR76.js → src-IVPNZ2BX.js} +9 -9
|
@@ -2,46 +2,103 @@ import { createRequire as __lunrRequire } from "node:module"; const require = __
|
|
|
2
2
|
import {
|
|
3
3
|
AgentBridge,
|
|
4
4
|
QUEUED,
|
|
5
|
-
listSessions,
|
|
6
|
-
splitMessage,
|
|
7
5
|
startGatewayCron
|
|
8
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-HPUP7E4T.js";
|
|
9
7
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
} from "./chunk-4I23VTC4.js";
|
|
17
|
-
import "./chunk-CJECDQKP.js";
|
|
8
|
+
CHAT_COMMANDS,
|
|
9
|
+
botCommandSpecs,
|
|
10
|
+
runChatCommand,
|
|
11
|
+
sendCommandReply
|
|
12
|
+
} from "./chunk-LFZDVKSP.js";
|
|
13
|
+
import "./chunk-EKVFP6YF.js";
|
|
18
14
|
import {
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
acceptGatewayInput,
|
|
16
|
+
addAllowedUser,
|
|
17
|
+
bindConversation,
|
|
18
|
+
conversationBinding,
|
|
19
|
+
handleApprovalCallback,
|
|
20
|
+
handleCallback,
|
|
21
|
+
invalidateGatewayDialogs,
|
|
22
|
+
isAuthorized,
|
|
23
|
+
isGatewayOwner,
|
|
24
|
+
listSessions,
|
|
25
|
+
registerGatewayApprovalHandler,
|
|
26
|
+
requireGatewayOwner,
|
|
27
|
+
runWithApprovalContext,
|
|
28
|
+
splitMessage,
|
|
29
|
+
startButtonSweeper,
|
|
30
|
+
startGatewayPresenter,
|
|
31
|
+
stopButtonSweeper,
|
|
32
|
+
stopGatewayPresenter
|
|
33
|
+
} from "./chunk-DD5YWFSJ.js";
|
|
21
34
|
import {
|
|
22
|
-
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
import "./chunk-CGBXPL3E.js";
|
|
35
|
+
createPairingStore
|
|
36
|
+
} from "./chunk-RMQZU2YU.js";
|
|
25
37
|
import {
|
|
26
|
-
|
|
27
|
-
} from "./chunk-
|
|
28
|
-
import "./chunk-
|
|
38
|
+
claimGateway
|
|
39
|
+
} from "./chunk-UWPJL22I.js";
|
|
40
|
+
import "./chunk-CJECDQKP.js";
|
|
41
|
+
import "./chunk-TQGPP4SC.js";
|
|
29
42
|
import "./chunk-AD6VXAO7.js";
|
|
30
43
|
import {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
44
|
+
isFeatureEnabled
|
|
45
|
+
} from "./chunk-VWCE2HSZ.js";
|
|
46
|
+
import "./chunk-OFKSVRV7.js";
|
|
47
|
+
import "./chunk-GJ2RDBRL.js";
|
|
48
|
+
import "./chunk-CGBXPL3E.js";
|
|
49
|
+
import "./chunk-BBUVIEZB.js";
|
|
50
|
+
import "./chunk-5D7LC2ZQ.js";
|
|
34
51
|
import "./chunk-M3LZLQW2.js";
|
|
52
|
+
import "./chunk-KKUTQQV7.js";
|
|
53
|
+
import "./chunk-CSFI6YXL.js";
|
|
54
|
+
import "./chunk-AZJHNQKQ.js";
|
|
55
|
+
import "./chunk-XLTL257W.js";
|
|
56
|
+
import "./chunk-FVDOXRUD.js";
|
|
57
|
+
import "./chunk-IMLCWLPI.js";
|
|
58
|
+
import "./chunk-UAEOTO52.js";
|
|
35
59
|
import "./chunk-RQ2Q5IYR.js";
|
|
36
|
-
import "./chunk-QZMODZQ2.js";
|
|
37
60
|
import {
|
|
38
|
-
|
|
39
|
-
|
|
61
|
+
gatewayConfigPath,
|
|
62
|
+
loadGatewayConfig,
|
|
63
|
+
platformConfigFor,
|
|
64
|
+
resolvePlatformToken
|
|
65
|
+
} from "./chunk-R3K2F5GI.js";
|
|
66
|
+
import "./chunk-E24EO34J.js";
|
|
67
|
+
import "./chunk-RDDAZOMU.js";
|
|
68
|
+
import "./chunk-FQMM2EZ2.js";
|
|
40
69
|
import "./chunk-Q4Q6D4IY.js";
|
|
41
70
|
import "./chunk-BRJX2PRC.js";
|
|
42
71
|
|
|
43
72
|
// packages/coding-agent/dist/gateway/adapters/discord.js
|
|
44
|
-
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, ChannelType, Client, Events, GatewayIntentBits } from "discord.js";
|
|
73
|
+
import { ActionRowBuilder, ApplicationCommandOptionType, ButtonBuilder, ButtonStyle, ChannelType, Client, Events, GatewayIntentBits } from "discord.js";
|
|
74
|
+
|
|
75
|
+
// packages/coding-agent/dist/gateway/download.js
|
|
76
|
+
async function downloadAttachment(url, limit = 8 * 1024 * 1024) {
|
|
77
|
+
let response = await fetch(url, { signal: AbortSignal.timeout(3e4) });
|
|
78
|
+
if (!response.ok || !response.body)
|
|
79
|
+
throw new Error(`Attachment request failed with HTTP ${response.status}.`);
|
|
80
|
+
if (Number(response.headers.get("content-length")) > limit)
|
|
81
|
+
throw await response.body.cancel(), new Error("Attachment exceeds the 8 MB limit.");
|
|
82
|
+
let reader = response.body.getReader(), parts = [], size = 0;
|
|
83
|
+
try {
|
|
84
|
+
for (; ; ) {
|
|
85
|
+
let part = await reader.read();
|
|
86
|
+
if (part.done)
|
|
87
|
+
break;
|
|
88
|
+
if (size += part.value.byteLength, size > limit)
|
|
89
|
+
throw await reader.cancel(), new Error("Attachment exceeds the 8 MB limit.");
|
|
90
|
+
parts.push(part.value);
|
|
91
|
+
}
|
|
92
|
+
} finally {
|
|
93
|
+
reader.releaseLock();
|
|
94
|
+
}
|
|
95
|
+
let bytes = new Uint8Array(size), offset = 0;
|
|
96
|
+
for (let part of parts)
|
|
97
|
+
bytes.set(part, offset), offset += part.byteLength;
|
|
98
|
+
return bytes;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// packages/coding-agent/dist/gateway/adapters/discord.js
|
|
45
102
|
var DEFAULT_DEBOUNCE_MS = 600, TYPING_INTERVAL_MS = 8e3, TYPING_SAFETY_MS = 12e4, REPLY_TO_TEXT_MAX = 500, THREAD_NAME_MAX = 40, SEEN_CAP = 500, SENT_CHANNEL_CAP = 500, CALLBACK_INTERACTION_CAP = 500, CHANNEL_CACHE_CAP = 500, PARTICIPATING_THREAD_CAP = 500, ERR_INVALID_FORM_BODY = 50035, ERR_UNKNOWN_MESSAGE = 10008, THREAD_TYPES = [
|
|
46
103
|
ChannelType.PublicThread,
|
|
47
104
|
ChannelType.PrivateThread,
|
|
@@ -50,12 +107,6 @@ var DEFAULT_DEBOUNCE_MS = 600, TYPING_INTERVAL_MS = 8e3, TYPING_SAFETY_MS = 12e4
|
|
|
50
107
|
function errMessage(err) {
|
|
51
108
|
return err instanceof Error ? err.message : String(err);
|
|
52
109
|
}
|
|
53
|
-
async function defaultDownloadAttachment(url) {
|
|
54
|
-
let res = await fetch(url);
|
|
55
|
-
if (!res.ok)
|
|
56
|
-
throw new Error(`attachment download HTTP ${res.status}`);
|
|
57
|
-
return new Uint8Array(await res.arrayBuffer());
|
|
58
|
-
}
|
|
59
110
|
function discordErrorCode(err) {
|
|
60
111
|
let code = err?.code;
|
|
61
112
|
return typeof code == "number" ? code : void 0;
|
|
@@ -64,14 +115,14 @@ function isImageContentType(contentType) {
|
|
|
64
115
|
return typeof contentType == "string" && contentType.split(";")[0]?.trim().toLowerCase().startsWith("image/");
|
|
65
116
|
}
|
|
66
117
|
function collectDiscordImageAttachments(message) {
|
|
67
|
-
return (message.attachments ?? []).filter((attachment) => isImageContentType(attachment.contentType));
|
|
118
|
+
return Array.from(message.attachments?.values() ?? []).filter((attachment) => isImageContentType(attachment.contentType));
|
|
68
119
|
}
|
|
69
120
|
function messageToEvent(message, botUser, options = {}) {
|
|
70
121
|
let author = message.author;
|
|
71
122
|
if (!author || author.id === botUser.id || author.bot || message.system)
|
|
72
123
|
return null;
|
|
73
124
|
let content = (message.content ?? "").trim(), imageAttachments = collectDiscordImageAttachments(message);
|
|
74
|
-
if (content === "" && imageAttachments.length === 0)
|
|
125
|
+
if (content === "" && imageAttachments.length === 0 && !Array.from(message.attachments?.values() ?? []).length)
|
|
75
126
|
return null;
|
|
76
127
|
let channel = message.channel, ignored = options.ignoredChannels ?? [];
|
|
77
128
|
if (ignored.includes(channel.id) || channel.parentId != null && ignored.includes(channel.parentId))
|
|
@@ -181,6 +232,7 @@ var DiscordAdapter = class {
|
|
|
181
232
|
client;
|
|
182
233
|
botUserId;
|
|
183
234
|
handler;
|
|
235
|
+
commandSuggestions;
|
|
184
236
|
callbackHandler;
|
|
185
237
|
pending = /* @__PURE__ */ new Map();
|
|
186
238
|
typing = /* @__PURE__ */ new Map();
|
|
@@ -199,7 +251,10 @@ var DiscordAdapter = class {
|
|
|
199
251
|
throw new Error("DiscordAdapter: no bot token (set discord.token or LUNR_DISCORD_BOT_TOKEN)");
|
|
200
252
|
this.clientFactory = defaultClientFactory;
|
|
201
253
|
}
|
|
202
|
-
this.downloadAttachment = options.downloadAttachment ??
|
|
254
|
+
this.downloadAttachment = options.downloadAttachment ?? downloadAttachment, this.maxMediaBytes = options.maxMediaBytes ?? 10 * 1024 * 1024;
|
|
255
|
+
}
|
|
256
|
+
setCommandSuggestions(handler) {
|
|
257
|
+
this.commandSuggestions = handler;
|
|
203
258
|
}
|
|
204
259
|
onMessage(handler) {
|
|
205
260
|
this.handler = handler;
|
|
@@ -216,7 +271,8 @@ var DiscordAdapter = class {
|
|
|
216
271
|
console.error(`[gateway] discord message handling error: ${errMessage(err)}`);
|
|
217
272
|
});
|
|
218
273
|
}), client.on(Events.InteractionCreate, (interaction) => {
|
|
219
|
-
|
|
274
|
+
let event = interaction;
|
|
275
|
+
(event.isButton() ? this.handleInteraction(interaction) : this.handleNativeCommand(event)).catch((err) => {
|
|
220
276
|
console.error(`[gateway] discord interaction handling error: ${errMessage(err)}`);
|
|
221
277
|
});
|
|
222
278
|
});
|
|
@@ -245,11 +301,17 @@ var DiscordAdapter = class {
|
|
|
245
301
|
ignoredChannels: this.cfg.ignoredChannels,
|
|
246
302
|
participatingThreads: this.participatingThreads
|
|
247
303
|
});
|
|
248
|
-
|
|
304
|
+
if (event) {
|
|
305
|
+
if (!isAuthorized(event.source, { ...loadGatewayConfig(), discord: this.cfg }, createPairingStore())) {
|
|
306
|
+
this.dispatchEvent(event);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
await this.resolveReplyToText(message, event), await this.maybeAutoThread(message, event), await this.downloadAttachments(message, event), this.dispatchEvent(event);
|
|
310
|
+
}
|
|
249
311
|
}
|
|
250
|
-
/**
|
|
312
|
+
/** Download and encode attachments after authorization. */
|
|
251
313
|
async downloadAttachments(message, event) {
|
|
252
|
-
let imageAttachments =
|
|
314
|
+
let imageAttachments = Array.from(message.attachments?.values() ?? []);
|
|
253
315
|
if (imageAttachments.length === 0)
|
|
254
316
|
return;
|
|
255
317
|
let attachments = [];
|
|
@@ -261,13 +323,72 @@ var DiscordAdapter = class {
|
|
|
261
323
|
continue;
|
|
262
324
|
attachments.push({
|
|
263
325
|
data: Buffer.from(bytes).toString("base64"),
|
|
264
|
-
mimeType: attachment.contentType ?? "
|
|
326
|
+
mimeType: attachment.contentType ?? "application/octet-stream",
|
|
265
327
|
...attachment.name ? { filename: attachment.name } : {}
|
|
266
328
|
});
|
|
267
329
|
} catch {
|
|
268
330
|
}
|
|
269
331
|
attachments.length > 0 && (event.attachments = attachments);
|
|
270
332
|
}
|
|
333
|
+
async registerCommands(commands) {
|
|
334
|
+
this.client?.application && await this.client.application.commands.set(commands.slice(0, 95).map((command) => ({
|
|
335
|
+
name: command.name,
|
|
336
|
+
description: command.description.slice(0, 100),
|
|
337
|
+
options: [
|
|
338
|
+
{
|
|
339
|
+
name: "args",
|
|
340
|
+
description: "Command arguments or search",
|
|
341
|
+
type: ApplicationCommandOptionType.String,
|
|
342
|
+
required: !1,
|
|
343
|
+
autocomplete: ["mode", "thinking", "project", "sessions"].includes(command.name)
|
|
344
|
+
}
|
|
345
|
+
]
|
|
346
|
+
})));
|
|
347
|
+
}
|
|
348
|
+
async handleNativeCommand(interaction) {
|
|
349
|
+
if (!interaction.isChatInputCommand?.() && !interaction.isAutocomplete?.() || !interaction.isChatInputCommand() && !interaction.isAutocomplete())
|
|
350
|
+
return !1;
|
|
351
|
+
let thread = interaction.channel?.isThread() ? interaction.channel : void 0, source = {
|
|
352
|
+
platform: "discord",
|
|
353
|
+
chatId: thread?.parentId ?? interaction.channelId ?? interaction.user.id,
|
|
354
|
+
threadId: thread?.id,
|
|
355
|
+
chatType: thread ? "thread" : interaction.inGuild() ? "channel" : "dm",
|
|
356
|
+
userId: interaction.user.id,
|
|
357
|
+
userName: interaction.user.username
|
|
358
|
+
}, cfg = loadGatewayConfig(), authorized = isAuthorized(source, cfg, createPairingStore());
|
|
359
|
+
if (interaction.isAutocomplete()) {
|
|
360
|
+
if (!authorized || !isGatewayOwner(source, cfg))
|
|
361
|
+
return await interaction.respond([]), !0;
|
|
362
|
+
let query = String(interaction.options.getFocused()).toLowerCase(), values = [];
|
|
363
|
+
if (interaction.commandName === "mode" && (values = ["manual", "yolo", "plan", "auto"]), this.commandSuggestions && ["thinking", "model"].includes(interaction.commandName) && (values = [...await this.commandSuggestions(source, interaction.commandName)]), interaction.commandName === "project" && (values = cfg.projectRoots ?? []), interaction.commandName === "sessions") {
|
|
364
|
+
let { SessionManager } = await import("./session-manager-CFN4UFM2.js");
|
|
365
|
+
values = (await Promise.race([
|
|
366
|
+
SessionManager.listAll(),
|
|
367
|
+
new Promise((resolve) => setTimeout(() => resolve([]), 1500))
|
|
368
|
+
])).map((s) => s.name || s.id);
|
|
369
|
+
}
|
|
370
|
+
return await interaction.respond(values.filter((s) => s.toLowerCase().includes(query)).slice(0, 25).map((value) => ({ name: value.slice(0, 100), value: value.slice(0, 100) }))), !0;
|
|
371
|
+
}
|
|
372
|
+
return await interaction.reply({
|
|
373
|
+
content: authorized ? "Command received." : "Pair your account before using this command. Send the bot a private message for a pairing code.",
|
|
374
|
+
ephemeral: !0
|
|
375
|
+
}), authorized && this.handler?.({
|
|
376
|
+
text: `/${interaction.commandName}${interaction.options.getString("args") ? ` ${interaction.options.getString("args")}` : ""}`,
|
|
377
|
+
source,
|
|
378
|
+
messageId: "",
|
|
379
|
+
metadata: { mentionedBot: !0, nativeCommand: !0 }
|
|
380
|
+
}), !0;
|
|
381
|
+
}
|
|
382
|
+
async sendFile(chatId, file, opts) {
|
|
383
|
+
let channel = await this.fetchChannel(opts?.threadId ?? chatId);
|
|
384
|
+
if (!channel?.send)
|
|
385
|
+
return { success: !1, error: "Channel is unavailable." };
|
|
386
|
+
try {
|
|
387
|
+
return { success: !0, messageId: (await channel.send({ content: "", files: [file] })).id };
|
|
388
|
+
} catch (error) {
|
|
389
|
+
return { success: !1, error: errMessage(error) };
|
|
390
|
+
}
|
|
391
|
+
}
|
|
271
392
|
async handleInteraction(interaction) {
|
|
272
393
|
if (!this.callbackHandler || !interaction.isButton())
|
|
273
394
|
return;
|
|
@@ -466,8 +587,9 @@ ${event.text}`,
|
|
|
466
587
|
};
|
|
467
588
|
|
|
468
589
|
// packages/coding-agent/dist/gateway/adapters/telegram.js
|
|
469
|
-
|
|
470
|
-
|
|
590
|
+
import { readFileSync } from "node:fs";
|
|
591
|
+
import { basename } from "node:path";
|
|
592
|
+
var API_BASE = "https://api.telegram.org", DEFAULT_DEBOUNCE_MS2 = 300, TYPING_INTERVAL_MS2 = 4e3, TYPING_SAFETY_MS2 = 12e4, REPLY_TO_TEXT_MAX2 = 500, MARKDOWN_PARSE_ERROR_RE = /can't parse|parse entities/i, NOT_MODIFIED_RE = /message is not modified/i, TelegramApiError = class extends Error {
|
|
471
593
|
status;
|
|
472
594
|
retryAfter;
|
|
473
595
|
constructor(status, description, retryAfter) {
|
|
@@ -505,10 +627,7 @@ async function defaultCallApi(token, method, body, signal) {
|
|
|
505
627
|
return data.result;
|
|
506
628
|
}
|
|
507
629
|
async function defaultDownloadFile(token, filePath) {
|
|
508
|
-
|
|
509
|
-
if (!res.ok)
|
|
510
|
-
throw new TelegramApiError(res.status, `file download HTTP ${res.status}`);
|
|
511
|
-
return new Uint8Array(await res.arrayBuffer());
|
|
630
|
+
return downloadAttachment(`${API_BASE}/file/bot${token}/${filePath}`);
|
|
512
631
|
}
|
|
513
632
|
function errMessage2(err) {
|
|
514
633
|
return err instanceof Error ? err.message : String(err);
|
|
@@ -550,9 +669,6 @@ function extractMention(text, entities, botInfo) {
|
|
|
550
669
|
out += text.slice(pos, start), pos = Math.max(pos, end);
|
|
551
670
|
return out += text.slice(pos), { text: out.trim(), mentioned };
|
|
552
671
|
}
|
|
553
|
-
function isImageMimeType(mimeType) {
|
|
554
|
-
return typeof mimeType == "string" && mimeType.split(";")[0]?.trim().toLowerCase().startsWith("image/");
|
|
555
|
-
}
|
|
556
672
|
function collectTelegramMedia(message) {
|
|
557
673
|
let descriptors = [];
|
|
558
674
|
if (message.photo && message.photo.length > 0) {
|
|
@@ -563,9 +679,9 @@ function collectTelegramMedia(message) {
|
|
|
563
679
|
...largest.file_size !== void 0 ? { fileSize: largest.file_size } : {}
|
|
564
680
|
});
|
|
565
681
|
}
|
|
566
|
-
return message.document &&
|
|
682
|
+
return message.document && descriptors.push({
|
|
567
683
|
fileId: message.document.file_id,
|
|
568
|
-
mimeType: message.document.mime_type ?? "
|
|
684
|
+
mimeType: message.document.mime_type ?? "application/octet-stream",
|
|
569
685
|
...message.document.file_name ? { filename: message.document.file_name } : {},
|
|
570
686
|
...message.document.file_size !== void 0 ? { fileSize: message.document.file_size } : {}
|
|
571
687
|
}), descriptors;
|
|
@@ -587,7 +703,7 @@ function updateToEvent(update, botInfo) {
|
|
|
587
703
|
return {
|
|
588
704
|
text,
|
|
589
705
|
messageId: String(message.message_id),
|
|
590
|
-
replyToText: replyText !== void 0 ? replyText.slice(0,
|
|
706
|
+
replyToText: replyText !== void 0 ? replyText.slice(0, REPLY_TO_TEXT_MAX2) : void 0,
|
|
591
707
|
source: {
|
|
592
708
|
platform: "telegram",
|
|
593
709
|
chatId: String(message.chat.id),
|
|
@@ -630,8 +746,9 @@ var TelegramAdapter = class {
|
|
|
630
746
|
abortController;
|
|
631
747
|
pending = /* @__PURE__ */ new Map();
|
|
632
748
|
typing = /* @__PURE__ */ new Map();
|
|
749
|
+
cfg;
|
|
633
750
|
constructor(cfg, options = {}) {
|
|
634
|
-
if (this.scheduler = options.scheduler ?? defaultScheduler2, this.debounceMs = options.debounceMs ??
|
|
751
|
+
if (this.cfg = cfg, this.scheduler = options.scheduler ?? defaultScheduler2, this.debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS2, this.now = options.now ?? Date.now, options.callApi)
|
|
635
752
|
this.callApi = options.callApi;
|
|
636
753
|
else {
|
|
637
754
|
if (!cfg.token)
|
|
@@ -708,7 +825,7 @@ var TelegramAdapter = class {
|
|
|
708
825
|
let event = updateToEvent(update, this.botInfo);
|
|
709
826
|
if (!event)
|
|
710
827
|
return;
|
|
711
|
-
if (update.message) {
|
|
828
|
+
if (update.message && isAuthorized(event.source, { ...loadGatewayConfig(), telegram: this.cfg }, createPairingStore())) {
|
|
712
829
|
let attachments = await this.downloadMedia(update.message);
|
|
713
830
|
attachments.length > 0 && (event.attachments = attachments);
|
|
714
831
|
}
|
|
@@ -793,6 +910,20 @@ ${event.text}`,
|
|
|
793
910
|
});
|
|
794
911
|
}
|
|
795
912
|
/** lunr: register the bot's slash-command menu (Telegram client autocomplete). Best-effort — caller catches. */
|
|
913
|
+
async sendFile(chatId, file, opts) {
|
|
914
|
+
try {
|
|
915
|
+
let data = new FormData();
|
|
916
|
+
data.set("chat_id", chatId), opts?.threadId && data.set("message_thread_id", opts.threadId), data.set("document", new Blob([new Uint8Array(readFileSync(file))]), basename(file));
|
|
917
|
+
let response = await fetch(`${API_BASE}/bot${this.cfg.token}/sendDocument`, {
|
|
918
|
+
method: "POST",
|
|
919
|
+
body: data,
|
|
920
|
+
signal: AbortSignal.timeout(3e4)
|
|
921
|
+
});
|
|
922
|
+
return response.ok ? { success: !0 } : { success: !1, error: `Telegram file delivery failed: HTTP ${response.status}` };
|
|
923
|
+
} catch {
|
|
924
|
+
return { success: !1, error: "Telegram file delivery failed. Check your connection." };
|
|
925
|
+
}
|
|
926
|
+
}
|
|
796
927
|
async registerCommands(commands) {
|
|
797
928
|
let valid = commands.filter((c) => /^[a-z0-9_]{1,32}$/.test(c.name) && c.description.trim().length > 0).map((c) => ({ command: c.name, description: c.description.trim().slice(0, 256) }));
|
|
798
929
|
valid.length !== 0 && await this.callApi("setMyCommands", { commands: valid });
|
|
@@ -864,14 +995,14 @@ ${event.text}`,
|
|
|
864
995
|
let interval = this.scheduler.setInterval(() => {
|
|
865
996
|
let entry = this.typing.get(key);
|
|
866
997
|
if (entry) {
|
|
867
|
-
if (this.now() - entry.lastRefresh >
|
|
998
|
+
if (this.now() - entry.lastRefresh > TYPING_SAFETY_MS2) {
|
|
868
999
|
this.stopTyping(key);
|
|
869
1000
|
return;
|
|
870
1001
|
}
|
|
871
1002
|
this.callApi("sendChatAction", body).catch(() => {
|
|
872
1003
|
});
|
|
873
1004
|
}
|
|
874
|
-
},
|
|
1005
|
+
}, TYPING_INTERVAL_MS2);
|
|
875
1006
|
this.typing.set(key, { interval, lastRefresh: this.now() });
|
|
876
1007
|
}
|
|
877
1008
|
stopTyping(key) {
|
|
@@ -883,907 +1014,8 @@ function typingKey2(chatId, threadId) {
|
|
|
883
1014
|
return `${chatId}:${threadId ?? ""}`;
|
|
884
1015
|
}
|
|
885
1016
|
|
|
886
|
-
// packages/coding-agent/dist/gateway/approval.js
|
|
887
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
888
|
-
import { randomBytes } from "node:crypto";
|
|
889
|
-
var CALLBACK_PREFIX = "ap:", ID_LENGTH = 8, CODE_ALPHABET = "ABCDEFGHJKMNPQRSTUVWXYZ23456789", DEFAULT_TIMEOUT_MS = 300 * 1e3, approvalContext = new AsyncLocalStorage(), pending = /* @__PURE__ */ new Map();
|
|
890
|
-
function generateId() {
|
|
891
|
-
let id = "", bytes = randomBytes(ID_LENGTH);
|
|
892
|
-
for (let i = 0; i < ID_LENGTH; i++)
|
|
893
|
-
id += CODE_ALPHABET[bytes[i] % CODE_ALPHABET.length];
|
|
894
|
-
return id;
|
|
895
|
-
}
|
|
896
|
-
function makeCallbackData(id, action) {
|
|
897
|
-
return `${CALLBACK_PREFIX}${id}:${action}`;
|
|
898
|
-
}
|
|
899
|
-
function parseCallbackData(data) {
|
|
900
|
-
if (!data.startsWith(CALLBACK_PREFIX))
|
|
901
|
-
return null;
|
|
902
|
-
let rest = data.slice(CALLBACK_PREFIX.length), colon = rest.indexOf(":");
|
|
903
|
-
if (colon === -1)
|
|
904
|
-
return null;
|
|
905
|
-
let id = rest.slice(0, colon), action = rest.slice(colon + 1);
|
|
906
|
-
return action === "once" || action === "session" || action === "reject" || action === "cancel" ? { id, action } : null;
|
|
907
|
-
}
|
|
908
|
-
function runWithApprovalContext(ctx, fn) {
|
|
909
|
-
return approvalContext.run(ctx, fn);
|
|
910
|
-
}
|
|
911
|
-
async function createApprovalPrompt(adapter, source, req, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
912
|
-
let id = generateId(), title = req.kind === "large-subagent-launch" ? `Approve large subagent launch?
|
|
913
|
-
${req.detail}` : `Approve ${req.toolName}?
|
|
914
|
-
${req.detail}`, rows = [
|
|
915
|
-
[
|
|
916
|
-
{ label: "\u2713 Approve once", data: makeCallbackData(id, "once") },
|
|
917
|
-
{ label: "\u2713 Approve session", data: makeCallbackData(id, "session") }
|
|
918
|
-
],
|
|
919
|
-
[{ label: "\u2717 Reject", data: makeCallbackData(id, "reject") }]
|
|
920
|
-
];
|
|
921
|
-
return new Promise((resolve, reject) => {
|
|
922
|
-
let messageId, timeout = setTimeout(() => {
|
|
923
|
-
pending.delete(id), reject(new Error("Approval request timed out")), messageId && adapter.editMessage(source.chatId, messageId, "\u23F1 Approval expired.", []).catch(() => {
|
|
924
|
-
});
|
|
925
|
-
}, timeoutMs);
|
|
926
|
-
(async () => {
|
|
927
|
-
try {
|
|
928
|
-
let result = await adapter.sendButtons(source.chatId, title, rows, { threadId: source.threadId });
|
|
929
|
-
if (!result.success || !result.messageId) {
|
|
930
|
-
clearTimeout(timeout), reject(new Error(result.error ?? "Failed to send approval prompt"));
|
|
931
|
-
return;
|
|
932
|
-
}
|
|
933
|
-
messageId = result.messageId, pending.set(id, {
|
|
934
|
-
resolve,
|
|
935
|
-
reject,
|
|
936
|
-
timeout,
|
|
937
|
-
messageId,
|
|
938
|
-
adapter,
|
|
939
|
-
chatId: source.chatId,
|
|
940
|
-
threadId: source.threadId,
|
|
941
|
-
userId: source.userId
|
|
942
|
-
});
|
|
943
|
-
} catch (err) {
|
|
944
|
-
clearTimeout(timeout), reject(err);
|
|
945
|
-
}
|
|
946
|
-
})();
|
|
947
|
-
});
|
|
948
|
-
}
|
|
949
|
-
async function createGatewayApprovalRequest(req) {
|
|
950
|
-
let ctx = approvalContext.getStore();
|
|
951
|
-
if (!ctx)
|
|
952
|
-
throw new Error(NO_HANDLER_REASON);
|
|
953
|
-
return createApprovalPrompt(ctx.adapter, ctx.source, req, ctx.timeoutMs);
|
|
954
|
-
}
|
|
955
|
-
function registerGatewayApprovalHandler() {
|
|
956
|
-
registerApprovalHandler(createGatewayApprovalRequest);
|
|
957
|
-
}
|
|
958
|
-
async function handleApprovalCallback(event, adapter) {
|
|
959
|
-
let parsed = parseCallbackData(event.data);
|
|
960
|
-
if (!parsed)
|
|
961
|
-
return !1;
|
|
962
|
-
let entry = pending.get(parsed.id);
|
|
963
|
-
if (!entry)
|
|
964
|
-
return await adapter?.answerCallback(event.id, "Approval expired.").catch(() => {
|
|
965
|
-
}), !0;
|
|
966
|
-
if (event.userId !== entry.userId)
|
|
967
|
-
return await entry.adapter.answerCallback(event.id, "\u26D4 Not your approval.").catch(() => {
|
|
968
|
-
}), !0;
|
|
969
|
-
clearTimeout(entry.timeout), pending.delete(parsed.id);
|
|
970
|
-
let response = parsed.action === "reject" || parsed.action === "cancel" ? "reject" : parsed.action;
|
|
971
|
-
entry.resolve(response);
|
|
972
|
-
let label = parsed.action === "reject" || parsed.action === "cancel" ? "Rejected." : `Approved (${parsed.action}).`;
|
|
973
|
-
return await entry.adapter.editMessage(entry.chatId, entry.messageId ?? "", label, []).catch(() => {
|
|
974
|
-
}), await entry.adapter.answerCallback(event.id).catch(() => {
|
|
975
|
-
}), !0;
|
|
976
|
-
}
|
|
977
|
-
|
|
978
|
-
// packages/coding-agent/dist/gateway/authz.js
|
|
979
|
-
function envFlagEnabled(name) {
|
|
980
|
-
let raw = process.env[name];
|
|
981
|
-
return raw === void 0 ? !1 : ["1", "true", "yes", "on"].includes(raw.toLowerCase());
|
|
982
|
-
}
|
|
983
|
-
function globalAllowedUsers() {
|
|
984
|
-
let raw = process.env.LUNR_GATEWAY_ALLOWED_USERS;
|
|
985
|
-
return raw ? raw.split(",").map((u) => u.trim()).filter((u) => u.length > 0) : [];
|
|
986
|
-
}
|
|
987
|
-
function isAuthorized(source, cfg, pairing) {
|
|
988
|
-
if (envFlagEnabled("LUNR_GATEWAY_ALLOW_ALL_USERS"))
|
|
989
|
-
return !0;
|
|
990
|
-
let platformCfg = platformConfigFor(cfg, source.platform);
|
|
991
|
-
return !!(platformCfg?.allowedChats.includes(source.chatId) || source.roleAuthorized === !0 || source.userId && pairing.isPaired(source.platform, source.userId) || source.userId && (platformCfg?.allowedUsers.includes(source.userId) || globalAllowedUsers().includes(source.userId)));
|
|
992
|
-
}
|
|
993
|
-
function addAllowedUser(platform, userId) {
|
|
994
|
-
let cfg = loadGatewayConfig(), platformCfg = platformConfigFor(cfg, platform);
|
|
995
|
-
if (!platformCfg)
|
|
996
|
-
throw new Error(`Unknown platform "${platform}"`);
|
|
997
|
-
platformCfg.allowedUsers.includes(userId) || (platformCfg.allowedUsers.push(userId), saveGatewayConfig(cfg));
|
|
998
|
-
}
|
|
999
|
-
|
|
1000
|
-
// packages/coding-agent/dist/gateway/buttons.js
|
|
1001
|
-
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
1002
|
-
var PICKER_TTL_MS = 900 * 1e3, SWEEP_INTERVAL_MS = 60 * 1e3, DEFAULT_PER_PAGE = 8, BUTTONS_PER_ROW = 2, CODE_ALPHABET2 = "ABCDEFGHJKMNPQRSTUVWXYZ23456789", CODE_LENGTH = 8, CALLBACK_PREFIX2 = "cp:", registry = /* @__PURE__ */ new Map(), sweeper;
|
|
1003
|
-
function generatePickerId() {
|
|
1004
|
-
let id = "", bytes = randomBytes2(CODE_LENGTH);
|
|
1005
|
-
for (let i = 0; i < CODE_LENGTH; i++)
|
|
1006
|
-
id += CODE_ALPHABET2[bytes[i] % CODE_ALPHABET2.length];
|
|
1007
|
-
return id;
|
|
1008
|
-
}
|
|
1009
|
-
function makeCallbackData2(id, action, payload) {
|
|
1010
|
-
return action === "noop" ? `${CALLBACK_PREFIX2}${id}:` : action === "cancel" ? `${CALLBACK_PREFIX2}${id}:x` : action === "page" ? `${CALLBACK_PREFIX2}${id}:p${payload ?? "0"}` : `${CALLBACK_PREFIX2}${id}:${payload ?? ""}`;
|
|
1011
|
-
}
|
|
1012
|
-
function parseCallbackData2(data) {
|
|
1013
|
-
if (!data.startsWith(CALLBACK_PREFIX2))
|
|
1014
|
-
return null;
|
|
1015
|
-
let rest = data.slice(CALLBACK_PREFIX2.length), colon = rest.indexOf(":");
|
|
1016
|
-
if (colon === -1)
|
|
1017
|
-
return null;
|
|
1018
|
-
let id = rest.slice(0, colon), tail = rest.slice(colon + 1);
|
|
1019
|
-
return tail === "" ? { id, action: "noop" } : tail === "x" ? { id, action: "cancel" } : tail.startsWith("p") ? { id, action: "page", payload: tail.slice(1) } : { id, action: "select", payload: tail };
|
|
1020
|
-
}
|
|
1021
|
-
function isSameChat(a, b) {
|
|
1022
|
-
return a.platform === b.platform && a.chatId === b.chatId && a.threadId === b.threadId;
|
|
1023
|
-
}
|
|
1024
|
-
function sourceForAuth(picker, cb) {
|
|
1025
|
-
return {
|
|
1026
|
-
platform: picker.source.platform,
|
|
1027
|
-
chatId: cb.chatId,
|
|
1028
|
-
chatType: picker.source.chatType,
|
|
1029
|
-
userId: cb.userId,
|
|
1030
|
-
userName: cb.userName,
|
|
1031
|
-
threadId: cb.threadId,
|
|
1032
|
-
// Do NOT inherit the original invoker's role authorization.
|
|
1033
|
-
roleAuthorized: void 0
|
|
1034
|
-
};
|
|
1035
|
-
}
|
|
1036
|
-
function renderPage(picker) {
|
|
1037
|
-
let { id, title, breadcrumbs, items, page, perPage } = picker, totalPages = Math.max(1, Math.ceil(items.length / perPage)), clampedPage = Math.max(0, Math.min(page, totalPages - 1)), start = clampedPage * perPage, pageItems = items.slice(start, start + perPage), rows = [];
|
|
1038
|
-
for (let i = 0; i < pageItems.length; i += BUTTONS_PER_ROW) {
|
|
1039
|
-
let row = [];
|
|
1040
|
-
for (let j = 0; j < BUTTONS_PER_ROW && i + j < pageItems.length; j++) {
|
|
1041
|
-
let index = start + i + j;
|
|
1042
|
-
row.push({ label: pageItems[i + j].label, data: makeCallbackData2(id, "select", String(index)) });
|
|
1043
|
-
}
|
|
1044
|
-
rows.push(row);
|
|
1045
|
-
}
|
|
1046
|
-
if (totalPages > 1) {
|
|
1047
|
-
let nav = [];
|
|
1048
|
-
clampedPage > 0 && nav.push({ label: "\u25C0 Prev", data: makeCallbackData2(id, "page", String(clampedPage - 1)) }), nav.push({ label: `${clampedPage + 1}/${totalPages}`, data: makeCallbackData2(id, "noop") }), clampedPage < totalPages - 1 && nav.push({ label: "Next \u25B6", data: makeCallbackData2(id, "page", String(clampedPage + 1)) }), rows.push(nav);
|
|
1049
|
-
}
|
|
1050
|
-
rows.push([{ label: "\u2717 Cancel", data: makeCallbackData2(id, "cancel") }]);
|
|
1051
|
-
let header = breadcrumbs ? `${title} \xB7 ${breadcrumbs}` : title;
|
|
1052
|
-
return { text: items.length === 0 ? `${header}
|
|
1053
|
-
|
|
1054
|
-
No options available.` : `${header} (${clampedPage + 1}/${totalPages}):`, buttons: rows };
|
|
1055
|
-
}
|
|
1056
|
-
async function createPicker(adapter, source, spec, opts) {
|
|
1057
|
-
let id = generatePickerId(), pending2 = {
|
|
1058
|
-
...spec,
|
|
1059
|
-
id,
|
|
1060
|
-
chatId: source.chatId,
|
|
1061
|
-
source,
|
|
1062
|
-
adapter,
|
|
1063
|
-
messageId: "",
|
|
1064
|
-
page: 0,
|
|
1065
|
-
perPage: spec.perPage ?? DEFAULT_PER_PAGE,
|
|
1066
|
-
createdAt: Date.now()
|
|
1067
|
-
}, { text, buttons } = renderPage(pending2), result = await adapter.sendButtons(source.chatId, text, buttons, opts);
|
|
1068
|
-
return result.success && result.messageId && (pending2.messageId = result.messageId, registry.set(id, pending2)), result;
|
|
1069
|
-
}
|
|
1070
|
-
async function answerExpired(adapter, cb) {
|
|
1071
|
-
await adapter.answerCallback(cb.id, "Picker expired \u2014 run the command again.").catch(() => {
|
|
1072
|
-
});
|
|
1073
|
-
}
|
|
1074
|
-
async function answerUnauthorized(adapter, cb) {
|
|
1075
|
-
await adapter.answerCallback(cb.id, "\u26D4 Not authorized.").catch(() => {
|
|
1076
|
-
});
|
|
1077
|
-
}
|
|
1078
|
-
async function answerNotYourPicker(adapter, cb) {
|
|
1079
|
-
await adapter.answerCallback(cb.id, "\u26D4 Not your picker.").catch(() => {
|
|
1080
|
-
});
|
|
1081
|
-
}
|
|
1082
|
-
async function handleCallback(cb, deps) {
|
|
1083
|
-
let { adapter, cfg, pairing } = deps, parsed = parseCallbackData2(cb.data);
|
|
1084
|
-
if (!parsed)
|
|
1085
|
-
return;
|
|
1086
|
-
let picker = registry.get(parsed.id);
|
|
1087
|
-
if (!picker) {
|
|
1088
|
-
await answerExpired(adapter, cb);
|
|
1089
|
-
return;
|
|
1090
|
-
}
|
|
1091
|
-
if (Date.now() > picker.createdAt + PICKER_TTL_MS) {
|
|
1092
|
-
registry.delete(parsed.id);
|
|
1093
|
-
try {
|
|
1094
|
-
await picker.adapter.editMessage(picker.chatId, picker.messageId, "\u23F1 Expired \u2014 run the command again.", []);
|
|
1095
|
-
} catch {
|
|
1096
|
-
}
|
|
1097
|
-
await answerExpired(adapter, cb);
|
|
1098
|
-
return;
|
|
1099
|
-
}
|
|
1100
|
-
if (!isSameChat(picker.source, sourceForAuth(picker, cb))) {
|
|
1101
|
-
await answerExpired(adapter, cb);
|
|
1102
|
-
return;
|
|
1103
|
-
}
|
|
1104
|
-
if (cb.userId !== picker.invokerId) {
|
|
1105
|
-
await answerNotYourPicker(adapter, cb);
|
|
1106
|
-
return;
|
|
1107
|
-
}
|
|
1108
|
-
if (!isAuthorized(sourceForAuth(picker, cb), cfg, pairing)) {
|
|
1109
|
-
await answerUnauthorized(adapter, cb);
|
|
1110
|
-
return;
|
|
1111
|
-
}
|
|
1112
|
-
if (parsed.action === "cancel") {
|
|
1113
|
-
registry.delete(parsed.id);
|
|
1114
|
-
try {
|
|
1115
|
-
await picker.adapter.editMessage(picker.chatId, picker.messageId, "Cancelled.", []);
|
|
1116
|
-
} catch {
|
|
1117
|
-
}
|
|
1118
|
-
await adapter.answerCallback(cb.id).catch(() => {
|
|
1119
|
-
});
|
|
1120
|
-
return;
|
|
1121
|
-
}
|
|
1122
|
-
if (parsed.action === "noop") {
|
|
1123
|
-
await adapter.answerCallback(cb.id).catch(() => {
|
|
1124
|
-
});
|
|
1125
|
-
return;
|
|
1126
|
-
}
|
|
1127
|
-
if (parsed.action === "page") {
|
|
1128
|
-
let page = Number.parseInt(parsed.payload ?? "0", 10), totalPages = Math.max(1, Math.ceil(picker.items.length / picker.perPage));
|
|
1129
|
-
picker.page = Math.max(0, Math.min(page, totalPages - 1));
|
|
1130
|
-
let { text, buttons } = renderPage(picker);
|
|
1131
|
-
try {
|
|
1132
|
-
await picker.adapter.editMessage(picker.chatId, picker.messageId, text, buttons);
|
|
1133
|
-
} catch {
|
|
1134
|
-
}
|
|
1135
|
-
await adapter.answerCallback(cb.id).catch(() => {
|
|
1136
|
-
});
|
|
1137
|
-
return;
|
|
1138
|
-
}
|
|
1139
|
-
let index = Number.parseInt(parsed.payload ?? "", 10), item = picker.items[index];
|
|
1140
|
-
if (!item) {
|
|
1141
|
-
await adapter.answerCallback(cb.id, "Invalid selection.").catch(() => {
|
|
1142
|
-
});
|
|
1143
|
-
return;
|
|
1144
|
-
}
|
|
1145
|
-
try {
|
|
1146
|
-
let result = await picker.resolve(item);
|
|
1147
|
-
if (!result.done) {
|
|
1148
|
-
picker.items = result.items, picker.title = result.title, picker.breadcrumbs = result.breadcrumbs, picker.page = 0;
|
|
1149
|
-
let { text, buttons } = renderPage(picker);
|
|
1150
|
-
try {
|
|
1151
|
-
await picker.adapter.editMessage(picker.chatId, picker.messageId, text, buttons);
|
|
1152
|
-
} catch {
|
|
1153
|
-
}
|
|
1154
|
-
await adapter.answerCallback(cb.id).catch(() => {
|
|
1155
|
-
});
|
|
1156
|
-
return;
|
|
1157
|
-
}
|
|
1158
|
-
registry.delete(parsed.id);
|
|
1159
|
-
try {
|
|
1160
|
-
await picker.adapter.editMessage(picker.chatId, picker.messageId, result.text, []);
|
|
1161
|
-
} catch {
|
|
1162
|
-
}
|
|
1163
|
-
await adapter.answerCallback(cb.id).catch(() => {
|
|
1164
|
-
});
|
|
1165
|
-
} catch (err) {
|
|
1166
|
-
registry.delete(parsed.id);
|
|
1167
|
-
let message = err instanceof Error ? err.message : String(err);
|
|
1168
|
-
try {
|
|
1169
|
-
await picker.adapter.editMessage(picker.chatId, picker.messageId, `\u26A0 ${message}`, []);
|
|
1170
|
-
} catch {
|
|
1171
|
-
}
|
|
1172
|
-
await adapter.answerCallback(cb.id).catch(() => {
|
|
1173
|
-
});
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
1176
|
-
function startButtonSweeper() {
|
|
1177
|
-
sweeper || (sweeper = setInterval(() => {
|
|
1178
|
-
let cutoff = Date.now() - PICKER_TTL_MS;
|
|
1179
|
-
for (let [id, entry] of registry)
|
|
1180
|
-
if (!(entry.createdAt > cutoff)) {
|
|
1181
|
-
registry.delete(id);
|
|
1182
|
-
try {
|
|
1183
|
-
entry.adapter.editMessage(entry.chatId, entry.messageId, "\u23F1 Expired \u2014 run the command again.", []);
|
|
1184
|
-
} catch {
|
|
1185
|
-
}
|
|
1186
|
-
}
|
|
1187
|
-
}, SWEEP_INTERVAL_MS), sweeper.unref?.());
|
|
1188
|
-
}
|
|
1189
|
-
function stopButtonSweeper() {
|
|
1190
|
-
sweeper && (clearInterval(sweeper), sweeper = void 0);
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
// packages/coding-agent/dist/gateway/commands.js
|
|
1194
|
-
var MODEL_CACHE_TTL_MS = 300 * 1e3, SESSIONS_CACHE_TTL_MS = 300 * 1e3, MAX_MODEL_LIST_LINES = 15, PROVIDER_PER_PAGE = 10;
|
|
1195
|
-
var MAX_MODELS_PER_PROVIDER = 50, MODEL_ID_MAX = 38, MODEL_CACHE_CAP = 100, SESSIONS_CACHE_CAP = 100, modelCache = /* @__PURE__ */ new Map(), sessionsCache = /* @__PURE__ */ new Map();
|
|
1196
|
-
function evictLRU(map, cap) {
|
|
1197
|
-
for (; map.size > cap; ) {
|
|
1198
|
-
let first = map.keys().next().value;
|
|
1199
|
-
first !== void 0 && map.delete(first);
|
|
1200
|
-
}
|
|
1201
|
-
}
|
|
1202
|
-
function getCachedModels(key) {
|
|
1203
|
-
let cached = modelCache.get(key);
|
|
1204
|
-
if (cached) {
|
|
1205
|
-
if (Date.now() > cached.expires) {
|
|
1206
|
-
modelCache.delete(key);
|
|
1207
|
-
return;
|
|
1208
|
-
}
|
|
1209
|
-
return modelCache.delete(key), modelCache.set(key, cached), cached.models;
|
|
1210
|
-
}
|
|
1211
|
-
}
|
|
1212
|
-
function setCachedModels(key, models) {
|
|
1213
|
-
modelCache.set(key, { models, expires: Date.now() + MODEL_CACHE_TTL_MS }), evictLRU(modelCache, MODEL_CACHE_CAP);
|
|
1214
|
-
}
|
|
1215
|
-
function getCachedSessions(key) {
|
|
1216
|
-
let cached = sessionsCache.get(key);
|
|
1217
|
-
if (cached) {
|
|
1218
|
-
if (Date.now() > cached.expires) {
|
|
1219
|
-
sessionsCache.delete(key);
|
|
1220
|
-
return;
|
|
1221
|
-
}
|
|
1222
|
-
return sessionsCache.delete(key), sessionsCache.set(key, cached), cached.sessions;
|
|
1223
|
-
}
|
|
1224
|
-
}
|
|
1225
|
-
function setCachedSessions(key, sessions) {
|
|
1226
|
-
sessionsCache.set(key, { sessions, expires: Date.now() + SESSIONS_CACHE_TTL_MS }), evictLRU(sessionsCache, SESSIONS_CACHE_CAP);
|
|
1227
|
-
}
|
|
1228
|
-
function oneLine(text) {
|
|
1229
|
-
return text.replace(/\s+/g, " ").trim().slice(0, 200);
|
|
1230
|
-
}
|
|
1231
|
-
function prefixLines(text, prefix) {
|
|
1232
|
-
return text.split(`
|
|
1233
|
-
`).map((line, index) => (index === 0 ? prefix : " ") + line).join(`
|
|
1234
|
-
`);
|
|
1235
|
-
}
|
|
1236
|
-
function truncate(text, max) {
|
|
1237
|
-
return text.length <= max ? text : `${text.slice(0, max - 1)}\u2026`;
|
|
1238
|
-
}
|
|
1239
|
-
function formatRelativeTime(date) {
|
|
1240
|
-
let seconds = Math.max(0, Math.floor((Date.now() - date.getTime()) / 1e3));
|
|
1241
|
-
if (seconds < 60)
|
|
1242
|
-
return `${seconds}s ago`;
|
|
1243
|
-
let minutes = Math.floor(seconds / 60);
|
|
1244
|
-
if (minutes < 60)
|
|
1245
|
-
return `${minutes}m ago`;
|
|
1246
|
-
let hours = Math.floor(minutes / 60);
|
|
1247
|
-
return hours < 24 ? `${hours}h ago` : `${Math.floor(hours / 24)}d ago`;
|
|
1248
|
-
}
|
|
1249
|
-
function formatModelList(models, maxLines = MAX_MODEL_LIST_LINES) {
|
|
1250
|
-
if (models.length === 0)
|
|
1251
|
-
return ["No models available."];
|
|
1252
|
-
let byProvider = /* @__PURE__ */ new Map();
|
|
1253
|
-
for (let model of models) {
|
|
1254
|
-
let list = byProvider.get(model.provider) ?? [];
|
|
1255
|
-
list.push(model), byProvider.set(model.provider, list);
|
|
1256
|
-
}
|
|
1257
|
-
let providers = [...byProvider.keys()].sort(), lines = [], index = 1;
|
|
1258
|
-
for (let provider of providers) {
|
|
1259
|
-
let list = (byProvider.get(provider) ?? []).sort((a, b) => a.id.localeCompare(b.id));
|
|
1260
|
-
for (let model of list)
|
|
1261
|
-
lines.push(`${index}) ${provider}/${model.id}`), index++;
|
|
1262
|
-
}
|
|
1263
|
-
return lines.length <= maxLines ? lines : [
|
|
1264
|
-
`${models.length} models across ${providers.length} providers.`,
|
|
1265
|
-
"Use /model <provider/id> or /model <query>.",
|
|
1266
|
-
...providers.map((p) => `- ${p}`)
|
|
1267
|
-
];
|
|
1268
|
-
}
|
|
1269
|
-
function groupModelsByProvider(models) {
|
|
1270
|
-
let byProvider = /* @__PURE__ */ new Map();
|
|
1271
|
-
for (let model of models) {
|
|
1272
|
-
let list = byProvider.get(model.provider) ?? [];
|
|
1273
|
-
list.push(model), byProvider.set(model.provider, list);
|
|
1274
|
-
}
|
|
1275
|
-
for (let list of byProvider.values())
|
|
1276
|
-
list.sort((a, b) => a.id.localeCompare(b.id));
|
|
1277
|
-
return byProvider;
|
|
1278
|
-
}
|
|
1279
|
-
function truncateModelId(id) {
|
|
1280
|
-
let lastSlash = id.lastIndexOf("/"), name = lastSlash >= 0 ? id.slice(lastSlash + 1) : id;
|
|
1281
|
-
return truncate(name, MODEL_ID_MAX);
|
|
1282
|
-
}
|
|
1283
|
-
async function refreshAndCacheModels(session, key) {
|
|
1284
|
-
let runtime = session.modelRuntime;
|
|
1285
|
-
await runtime.refresh();
|
|
1286
|
-
let models = [...await runtime.getAvailable()].sort((a, b) => a.provider.localeCompare(b.provider) || a.id.localeCompare(b.id));
|
|
1287
|
-
return setCachedModels(key, models), models;
|
|
1288
|
-
}
|
|
1289
|
-
async function setModelAndReply(ctx, model) {
|
|
1290
|
-
let session = ctx.session;
|
|
1291
|
-
try {
|
|
1292
|
-
await session.setModel(model);
|
|
1293
|
-
} catch (error) {
|
|
1294
|
-
if ((error instanceof Error ? error.message : String(error)).includes("No API key")) {
|
|
1295
|
-
await ctx.reply(`No API key for ${model.provider}.`);
|
|
1296
|
-
return;
|
|
1297
|
-
}
|
|
1298
|
-
throw error;
|
|
1299
|
-
}
|
|
1300
|
-
await ctx.reply(`Model \u2192 ${model.provider}/${model.id} (thinking level re-clamped to ${session.thinkingLevel})`);
|
|
1301
|
-
}
|
|
1302
|
-
var newCommand = {
|
|
1303
|
-
name: "new",
|
|
1304
|
-
aliases: ["reset"],
|
|
1305
|
-
description: "start a fresh session for this chat",
|
|
1306
|
-
// lunr: busy-session /new must bypass the guard (same as /stop).
|
|
1307
|
-
bypassBusy: !0,
|
|
1308
|
-
needsSession: !1,
|
|
1309
|
-
async handler(ctx) {
|
|
1310
|
-
await ctx.bridge.reset(ctx.key), await ctx.reply("Session reset \u2014 next message starts a fresh session.");
|
|
1311
|
-
}
|
|
1312
|
-
}, undoCommand = {
|
|
1313
|
-
name: "undo",
|
|
1314
|
-
description: "rewind the session tree before the last user turn",
|
|
1315
|
-
bypassBusy: !1,
|
|
1316
|
-
needsSession: !0,
|
|
1317
|
-
async handler(ctx) {
|
|
1318
|
-
let { userText } = await ctx.bridge.undo(ctx.key), text = userText ? ` "${truncate(userText, 60)}"` : "";
|
|
1319
|
-
await ctx.reply(`Undone \u2014 rewound before${text}. /redo to restore.`);
|
|
1320
|
-
}
|
|
1321
|
-
}, redoCommand = {
|
|
1322
|
-
name: "redo",
|
|
1323
|
-
description: "restore the last undone turn",
|
|
1324
|
-
bypassBusy: !1,
|
|
1325
|
-
needsSession: !0,
|
|
1326
|
-
async handler(ctx) {
|
|
1327
|
-
await ctx.bridge.redo(ctx.key), await ctx.reply("Redone.");
|
|
1328
|
-
}
|
|
1329
|
-
}, stopCommand = {
|
|
1330
|
-
name: "stop",
|
|
1331
|
-
description: "abort the running turn",
|
|
1332
|
-
bypassBusy: !0,
|
|
1333
|
-
needsSession: !1,
|
|
1334
|
-
async handler(ctx) {
|
|
1335
|
-
await ctx.bridge.abort(ctx.key), await ctx.reply("Stopped.");
|
|
1336
|
-
}
|
|
1337
|
-
}, statusCommand = {
|
|
1338
|
-
name: "status",
|
|
1339
|
-
description: "session status",
|
|
1340
|
-
bypassBusy: !0,
|
|
1341
|
-
needsSession: !1,
|
|
1342
|
-
async handler(ctx) {
|
|
1343
|
-
let status = ctx.bridge.getStatus(ctx.key), age = status.createdAt ? `${Math.max(0, Math.round((Date.now() - Date.parse(status.createdAt)) / 1e3))}s` : "no session yet";
|
|
1344
|
-
await ctx.reply(`${ctx.event.source.platform} \xB7 session age ${age} \xB7 ${status.busy ? "busy" : "idle"} \xB7 queue ${status.queueDepth}`);
|
|
1345
|
-
}
|
|
1346
|
-
}, whoamiCommand = {
|
|
1347
|
-
name: "whoami",
|
|
1348
|
-
description: "your ids and session key",
|
|
1349
|
-
bypassBusy: !0,
|
|
1350
|
-
needsSession: !1,
|
|
1351
|
-
async handler(ctx) {
|
|
1352
|
-
let { userId, chatId } = ctx.event.source;
|
|
1353
|
-
await ctx.reply(`userId: ${userId}
|
|
1354
|
-
chatId: ${chatId}
|
|
1355
|
-
key: ${ctx.key}`);
|
|
1356
|
-
}
|
|
1357
|
-
}, helpCommand = {
|
|
1358
|
-
name: "help",
|
|
1359
|
-
description: "this message",
|
|
1360
|
-
bypassBusy: !0,
|
|
1361
|
-
needsSession: !1,
|
|
1362
|
-
async handler(ctx) {
|
|
1363
|
-
await ctx.reply(formatHelpText());
|
|
1364
|
-
}
|
|
1365
|
-
}, modelCommand = {
|
|
1366
|
-
name: "model",
|
|
1367
|
-
description: "list or switch models",
|
|
1368
|
-
bypassBusy: !1,
|
|
1369
|
-
needsSession: !0,
|
|
1370
|
-
async handler(ctx) {
|
|
1371
|
-
let session = ctx.session, arg = ctx.args.trim();
|
|
1372
|
-
if (!arg) {
|
|
1373
|
-
let models2 = getCachedModels(ctx.key) ?? await refreshAndCacheModels(session, ctx.key), byProvider = groupModelsByProvider(models2), current = session.model, currentRef = current ? `${current.provider}/${current.id}` : "", providerItems = [...byProvider.keys()].sort().map((provider) => ({
|
|
1374
|
-
label: `${current?.provider === provider ? "\u2713 " : ""}${provider} (${byProvider.get(provider)?.length ?? 0})`,
|
|
1375
|
-
value: provider
|
|
1376
|
-
})), pickerOpts = {
|
|
1377
|
-
replyTo: ctx.event.messageId,
|
|
1378
|
-
threadId: ctx.event.source.threadId
|
|
1379
|
-
};
|
|
1380
|
-
if (!(await createPicker(ctx.adapter, ctx.event.source, {
|
|
1381
|
-
kind: "model",
|
|
1382
|
-
sessionKey: ctx.key,
|
|
1383
|
-
invokerId: ctx.event.source.userId,
|
|
1384
|
-
items: providerItems,
|
|
1385
|
-
perPage: PROVIDER_PER_PAGE,
|
|
1386
|
-
title: "Pick a model provider",
|
|
1387
|
-
async resolve(item) {
|
|
1388
|
-
if (item.value === "__back__")
|
|
1389
|
-
return { done: !1, items: providerItems, title: "Pick a model provider" };
|
|
1390
|
-
if (!item.value.includes("/")) {
|
|
1391
|
-
let provider = item.value, list = byProvider.get(provider) ?? [], capped = list.slice(0, MAX_MODELS_PER_PROVIDER), note = list.length > MAX_MODELS_PER_PROVIDER ? ` \u2014 ${list.length - MAX_MODELS_PER_PROVIDER} more available` : "", modelItems = [];
|
|
1392
|
-
for (let m of capped) {
|
|
1393
|
-
let ref = `${provider}/${m.id}`;
|
|
1394
|
-
modelItems.push({
|
|
1395
|
-
label: `${currentRef === ref ? "\u2713 " : ""}${truncateModelId(m.id)}`,
|
|
1396
|
-
value: ref
|
|
1397
|
-
});
|
|
1398
|
-
}
|
|
1399
|
-
return modelItems.unshift({ label: "\u25C0 Back", value: "__back__" }), {
|
|
1400
|
-
done: !1,
|
|
1401
|
-
items: modelItems,
|
|
1402
|
-
title: `${provider} (${list.length})${note}`,
|
|
1403
|
-
breadcrumbs: provider
|
|
1404
|
-
};
|
|
1405
|
-
}
|
|
1406
|
-
let exact2 = findExactModelReferenceMatch(item.value, models2);
|
|
1407
|
-
if (!exact2)
|
|
1408
|
-
return { done: !0, text: "That model is no longer available." };
|
|
1409
|
-
try {
|
|
1410
|
-
await session.setModel(exact2);
|
|
1411
|
-
} catch (error) {
|
|
1412
|
-
if ((error instanceof Error ? error.message : String(error)).includes("No API key"))
|
|
1413
|
-
return { done: !0, text: `No API key for ${exact2.provider}.` };
|
|
1414
|
-
throw error;
|
|
1415
|
-
}
|
|
1416
|
-
return {
|
|
1417
|
-
done: !0,
|
|
1418
|
-
text: `\u263E Model \u2192 ${exact2.provider}/${exact2.id} (thinking level re-clamped to ${session.thinkingLevel})`
|
|
1419
|
-
};
|
|
1420
|
-
}
|
|
1421
|
-
}, pickerOpts)).success) {
|
|
1422
|
-
let currentText = `${current?.provider ?? "none"}/${current?.id ?? "none"}`, lines = formatModelList(models2);
|
|
1423
|
-
await ctx.reply([`Current: ${currentText}`, ...lines, "Use /model <n> or /model <provider/id>"].join(`
|
|
1424
|
-
`));
|
|
1425
|
-
}
|
|
1426
|
-
return;
|
|
1427
|
-
}
|
|
1428
|
-
let numeric = Number.parseInt(arg, 10);
|
|
1429
|
-
if (!Number.isNaN(numeric) && /^\d+$/.test(arg)) {
|
|
1430
|
-
let cached = getCachedModels(ctx.key);
|
|
1431
|
-
if (!cached || numeric < 1 || numeric > cached.length) {
|
|
1432
|
-
await ctx.reply("Invalid selection \u2014 run /model to see the current list.");
|
|
1433
|
-
return;
|
|
1434
|
-
}
|
|
1435
|
-
await setModelAndReply(ctx, cached[numeric - 1]);
|
|
1436
|
-
return;
|
|
1437
|
-
}
|
|
1438
|
-
let models = getCachedModels(ctx.key) ?? await refreshAndCacheModels(session, ctx.key), exact = findExactModelReferenceMatch(arg, models);
|
|
1439
|
-
if (exact) {
|
|
1440
|
-
await setModelAndReply(ctx, exact);
|
|
1441
|
-
return;
|
|
1442
|
-
}
|
|
1443
|
-
let query = arg.toLowerCase(), matches = models.filter((m) => m.id.toLowerCase().includes(query) || `${m.provider}/${m.id}`.toLowerCase().includes(query) || (m.name?.toLowerCase().includes(query) ?? !1));
|
|
1444
|
-
if (matches.length === 0) {
|
|
1445
|
-
await ctx.reply(`No model matches "${arg}".`);
|
|
1446
|
-
return;
|
|
1447
|
-
}
|
|
1448
|
-
if (matches.length > 1) {
|
|
1449
|
-
await ctx.reply(formatModelList(matches).join(`
|
|
1450
|
-
`));
|
|
1451
|
-
return;
|
|
1452
|
-
}
|
|
1453
|
-
await setModelAndReply(ctx, matches[0]);
|
|
1454
|
-
}
|
|
1455
|
-
}, sessionsCommand = {
|
|
1456
|
-
name: "sessions",
|
|
1457
|
-
description: "list or switch sessions",
|
|
1458
|
-
bypassBusy: !1,
|
|
1459
|
-
needsSession: !0,
|
|
1460
|
-
async handler(ctx) {
|
|
1461
|
-
let session = ctx.session, arg = ctx.args.trim(), currentFile = session.sessionManager?.getSessionFile();
|
|
1462
|
-
if (!arg) {
|
|
1463
|
-
let all = await SessionManager.list(process.cwd());
|
|
1464
|
-
all.sort((a, b) => b.modified.getTime() - a.modified.getTime());
|
|
1465
|
-
let sessions = all.slice(0, 10);
|
|
1466
|
-
setCachedSessions(ctx.key, sessions);
|
|
1467
|
-
let items = sessions.map((s) => ({
|
|
1468
|
-
label: `${s.path === currentFile ? "\u263E " : ""}${s.name ? truncate(s.name, 30) : truncate(s.firstMessage, 30) || "(empty)"}`,
|
|
1469
|
-
value: s.path
|
|
1470
|
-
}));
|
|
1471
|
-
if (!(await createPicker(ctx.adapter, ctx.event.source, {
|
|
1472
|
-
kind: "sessions",
|
|
1473
|
-
sessionKey: ctx.key,
|
|
1474
|
-
invokerId: ctx.event.source.userId,
|
|
1475
|
-
items,
|
|
1476
|
-
perPage: 8,
|
|
1477
|
-
title: "Pick a session",
|
|
1478
|
-
async resolve(item) {
|
|
1479
|
-
await ctx.bridge.switchSession(ctx.key, item.value);
|
|
1480
|
-
let switched2 = await ctx.bridge.getSession(ctx.key), name2 = switched2?.sessionManager?.getSessionName() ?? "unnamed", count2 = switched2?.sessionManager?.getEntries().length ?? 0;
|
|
1481
|
-
return { done: !0, text: `\u263E Switched to "${name2}" (${count2} msgs). History continues here.` };
|
|
1482
|
-
}
|
|
1483
|
-
}, { replyTo: ctx.event.messageId, threadId: ctx.event.source.threadId })).success) {
|
|
1484
|
-
let lines = sessions.map((s, i) => {
|
|
1485
|
-
let marker = s.path === currentFile ? " \u263E" : "", label = s.name ? truncate(s.name, 40) : truncate(s.firstMessage, 40) || "(empty)";
|
|
1486
|
-
return `${i + 1}) ${label}${marker} \xB7 ${formatRelativeTime(s.modified)} \xB7 ${s.messageCount} msgs`;
|
|
1487
|
-
});
|
|
1488
|
-
await ctx.reply([`Sessions for ${process.cwd()}`, ...lines, "Use /sessions <n> or /sessions <id-prefix>"].join(`
|
|
1489
|
-
`));
|
|
1490
|
-
}
|
|
1491
|
-
return;
|
|
1492
|
-
}
|
|
1493
|
-
let path, numeric = Number.parseInt(arg, 10), cached = getCachedSessions(ctx.key);
|
|
1494
|
-
if (!Number.isNaN(numeric) && /^\d+$/.test(arg)) {
|
|
1495
|
-
if (!cached || numeric < 1 || numeric > cached.length) {
|
|
1496
|
-
await ctx.reply("Invalid selection \u2014 run /sessions to see the current list.");
|
|
1497
|
-
return;
|
|
1498
|
-
}
|
|
1499
|
-
path = cached[numeric - 1].path;
|
|
1500
|
-
} else {
|
|
1501
|
-
let matches = (cached ?? await SessionManager.list(process.cwd())).filter((s) => s.id.startsWith(arg) || s.path.startsWith(arg));
|
|
1502
|
-
if (matches.length === 0) {
|
|
1503
|
-
await ctx.reply(`No session matches "${arg}".`);
|
|
1504
|
-
return;
|
|
1505
|
-
}
|
|
1506
|
-
if (matches.length > 1) {
|
|
1507
|
-
await ctx.reply(`Multiple sessions match "${arg}" \u2014 use a longer prefix.`);
|
|
1508
|
-
return;
|
|
1509
|
-
}
|
|
1510
|
-
path = matches[0].path;
|
|
1511
|
-
}
|
|
1512
|
-
if (!path) {
|
|
1513
|
-
await ctx.reply("No session selected.");
|
|
1514
|
-
return;
|
|
1515
|
-
}
|
|
1516
|
-
await ctx.bridge.switchSession(ctx.key, path);
|
|
1517
|
-
let switched = await ctx.bridge.getSession(ctx.key), name = switched?.sessionManager?.getSessionName() ?? "unnamed", count = switched?.sessionManager?.getEntries().length ?? 0;
|
|
1518
|
-
await ctx.reply(`Switched to "${name}" (${count} msgs). History continues here.`);
|
|
1519
|
-
}
|
|
1520
|
-
}, titleCommand = {
|
|
1521
|
-
name: "title",
|
|
1522
|
-
aliases: ["name"],
|
|
1523
|
-
description: "name the current session",
|
|
1524
|
-
bypassBusy: !0,
|
|
1525
|
-
needsSession: !0,
|
|
1526
|
-
async handler(ctx) {
|
|
1527
|
-
let session = ctx.session, name = ctx.args.trim();
|
|
1528
|
-
if (!name) {
|
|
1529
|
-
let current = session.sessionManager?.getSessionName();
|
|
1530
|
-
await ctx.reply(current ? `Session title: ${current}` : "(unnamed)");
|
|
1531
|
-
return;
|
|
1532
|
-
}
|
|
1533
|
-
session.setSessionName(name);
|
|
1534
|
-
let readBack = session.sessionManager?.getSessionName() ?? name;
|
|
1535
|
-
await ctx.reply(`Session titled "${readBack}".`);
|
|
1536
|
-
}
|
|
1537
|
-
}, contextCommand = {
|
|
1538
|
-
name: "context",
|
|
1539
|
-
description: "estimated context window breakdown",
|
|
1540
|
-
bypassBusy: !0,
|
|
1541
|
-
needsSession: !0,
|
|
1542
|
-
async handler(ctx) {
|
|
1543
|
-
let session = ctx.session, model = session.model;
|
|
1544
|
-
if (!model) {
|
|
1545
|
-
await ctx.reply("No model selected.");
|
|
1546
|
-
return;
|
|
1547
|
-
}
|
|
1548
|
-
let contextWindow = model.contextWindow ?? 0;
|
|
1549
|
-
if (contextWindow <= 0) {
|
|
1550
|
-
await ctx.reply("Context window unknown for this model.");
|
|
1551
|
-
return;
|
|
1552
|
-
}
|
|
1553
|
-
let tools = session.getActiveToolNames().map((name) => session.getToolDefinition(name)).filter((d) => d !== void 0), breakdown = computeContextBreakdown({
|
|
1554
|
-
systemPrompt: session.systemPrompt,
|
|
1555
|
-
tools,
|
|
1556
|
-
messages: session.messages,
|
|
1557
|
-
contextWindow
|
|
1558
|
-
}), usage = session.getContextUsage(), tokens = usage?.tokens ?? breakdown.total, percent = usage?.percent ?? (contextWindow > 0 ? tokens / contextWindow * 100 : 0), messageTokens = breakdown.user + breakdown.assistantText + breakdown.thinking + breakdown.toolCalls + breakdown.toolResults + breakdown.summaries, stats = session.getSessionStats();
|
|
1559
|
-
await ctx.reply([
|
|
1560
|
-
`Context: ${tokens.toLocaleString("en-US")} / ${contextWindow.toLocaleString("en-US")} tokens (${Math.round(percent)}%)`,
|
|
1561
|
-
` system ${breakdown.systemPrompt.toLocaleString("en-US")} \xB7 tools ${breakdown.toolDefinitions.toLocaleString("en-US")} \xB7 messages ${messageTokens.toLocaleString("en-US")}`,
|
|
1562
|
-
`Session: ${stats.totalMessages} messages \xB7 ${stats.userMessages} turns \xB7 model ${model.provider}/${model.id}`
|
|
1563
|
-
].join(`
|
|
1564
|
-
`));
|
|
1565
|
-
}
|
|
1566
|
-
}, compactCommand = {
|
|
1567
|
-
name: "compact",
|
|
1568
|
-
description: "summarize and compress session context",
|
|
1569
|
-
bypassBusy: !0,
|
|
1570
|
-
needsSession: !0,
|
|
1571
|
-
async handler(ctx) {
|
|
1572
|
-
let session = ctx.session, instructions = ctx.args.trim() || void 0;
|
|
1573
|
-
try {
|
|
1574
|
-
let result = await session.compact(instructions), before = result.tokensBefore.toLocaleString("en-US"), after = result.estimatedTokensAfter !== void 0 ? `~${result.estimatedTokensAfter.toLocaleString("en-US")}` : "~?";
|
|
1575
|
-
await ctx.reply(`Compacted: ${before} \u2192 ${after} tokens.`);
|
|
1576
|
-
} catch (error) {
|
|
1577
|
-
let message = error instanceof Error ? error.message : String(error);
|
|
1578
|
-
if (message.includes("Nothing to compact") || message.includes("Already compacted") || message.includes("No model selected")) {
|
|
1579
|
-
await ctx.reply(message);
|
|
1580
|
-
return;
|
|
1581
|
-
}
|
|
1582
|
-
throw error;
|
|
1583
|
-
}
|
|
1584
|
-
}
|
|
1585
|
-
}, thinkingCommand = {
|
|
1586
|
-
name: "thinking",
|
|
1587
|
-
aliases: ["effort", "reasoning"],
|
|
1588
|
-
description: "get or set the thinking level",
|
|
1589
|
-
bypassBusy: !1,
|
|
1590
|
-
needsSession: !0,
|
|
1591
|
-
async handler(ctx) {
|
|
1592
|
-
let session = ctx.session, levels = session.getAvailableThinkingLevels();
|
|
1593
|
-
if (!session.supportsThinking()) {
|
|
1594
|
-
await ctx.reply(`Model ${session.model?.provider ?? "none"}/${session.model?.id ?? "none"} doesn't support thinking.`);
|
|
1595
|
-
return;
|
|
1596
|
-
}
|
|
1597
|
-
let arg = ctx.args.trim().toLowerCase();
|
|
1598
|
-
if (!arg) {
|
|
1599
|
-
let current = session.thinkingLevel, items = levels.map((level) => ({
|
|
1600
|
-
label: `${level === current ? "\u2713 " : ""}${level}`,
|
|
1601
|
-
value: level
|
|
1602
|
-
}));
|
|
1603
|
-
(await createPicker(ctx.adapter, ctx.event.source, {
|
|
1604
|
-
kind: "thinking",
|
|
1605
|
-
sessionKey: ctx.key,
|
|
1606
|
-
invokerId: ctx.event.source.userId,
|
|
1607
|
-
items,
|
|
1608
|
-
perPage: levels.length,
|
|
1609
|
-
title: "Pick a thinking level",
|
|
1610
|
-
async resolve(item) {
|
|
1611
|
-
let level = item.value;
|
|
1612
|
-
return session.setThinkingLevel(level), { done: !0, text: `\u263E Thinking \u2192 ${level}` };
|
|
1613
|
-
}
|
|
1614
|
-
}, { replyTo: ctx.event.messageId, threadId: ctx.event.source.threadId })).success || await ctx.reply(`Level: ${current} \u2014 available: ${levels.join(", ")}`);
|
|
1615
|
-
return;
|
|
1616
|
-
}
|
|
1617
|
-
if (!levels.includes(arg)) {
|
|
1618
|
-
await ctx.reply(`Invalid level. Available: ${levels.join(", ")}`);
|
|
1619
|
-
return;
|
|
1620
|
-
}
|
|
1621
|
-
session.setThinkingLevel(arg), await ctx.reply(`Thinking \u2192 ${arg}`);
|
|
1622
|
-
}
|
|
1623
|
-
}, CHAT_COMMANDS = [
|
|
1624
|
-
newCommand,
|
|
1625
|
-
undoCommand,
|
|
1626
|
-
redoCommand,
|
|
1627
|
-
stopCommand,
|
|
1628
|
-
statusCommand,
|
|
1629
|
-
whoamiCommand,
|
|
1630
|
-
helpCommand,
|
|
1631
|
-
modelCommand,
|
|
1632
|
-
sessionsCommand,
|
|
1633
|
-
titleCommand,
|
|
1634
|
-
contextCommand,
|
|
1635
|
-
compactCommand,
|
|
1636
|
-
thinkingCommand
|
|
1637
|
-
];
|
|
1638
|
-
function botCommandSpecs() {
|
|
1639
|
-
return CHAT_COMMANDS.map((c) => ({ name: c.name, description: c.description }));
|
|
1640
|
-
}
|
|
1641
|
-
function formatHelpText() {
|
|
1642
|
-
let lines = ["lunR gateway commands:"];
|
|
1643
|
-
for (let cmd of CHAT_COMMANDS) {
|
|
1644
|
-
let names = [cmd.name, ...cmd.aliases ?? []].map((a) => `/${a}`).join(" | ");
|
|
1645
|
-
lines.push(`${names} \u2014 ${cmd.description}`);
|
|
1646
|
-
}
|
|
1647
|
-
return lines.push(""), lines.push("Tap to pick: /model, /thinking, /sessions (run without args to see buttons)."), lines.join(`
|
|
1648
|
-
`);
|
|
1649
|
-
}
|
|
1650
|
-
async function runChatCommand(cmd, ctx) {
|
|
1651
|
-
if (!cmd.bypassBusy && ctx.bridge.getStatus(ctx.key).busy)
|
|
1652
|
-
return await ctx.reply("\u23F3 busy \u2014 /stop first or wait"), !0;
|
|
1653
|
-
if (cmd.needsSession) {
|
|
1654
|
-
let session = await ctx.bridge.getSession(ctx.key);
|
|
1655
|
-
if (!session)
|
|
1656
|
-
return await ctx.reply("No session yet \u2014 send a message first."), !0;
|
|
1657
|
-
ctx.session = session;
|
|
1658
|
-
}
|
|
1659
|
-
try {
|
|
1660
|
-
return await cmd.handler(ctx) ?? !0;
|
|
1661
|
-
} catch (err) {
|
|
1662
|
-
let message = err instanceof Error ? err.message : String(err);
|
|
1663
|
-
return await ctx.adapter.send(ctx.event.source.chatId, `\u26A0 ${oneLine(message)}`, {
|
|
1664
|
-
replyTo: ctx.event.messageId,
|
|
1665
|
-
threadId: ctx.event.source.threadId
|
|
1666
|
-
}), !0;
|
|
1667
|
-
}
|
|
1668
|
-
}
|
|
1669
|
-
async function sendCommandReply(adapter, event, text) {
|
|
1670
|
-
await adapter.send(event.source.chatId, prefixLines(text, "\u263E "), {
|
|
1671
|
-
replyTo: event.messageId,
|
|
1672
|
-
threadId: event.source.threadId
|
|
1673
|
-
});
|
|
1674
|
-
}
|
|
1675
|
-
|
|
1676
|
-
// packages/coding-agent/dist/gateway/pairing.js
|
|
1677
|
-
import { randomInt } from "node:crypto";
|
|
1678
|
-
import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
1679
|
-
import { join } from "node:path";
|
|
1680
|
-
var CODE_ALPHABET3 = "ABCDEFGHJKMNPQRSTUVWXYZ23456789", CODE_LENGTH2 = 8, DEFAULT_TTL_MS = 3600 * 1e3, DEFAULT_RATE_LIMIT_MS = 600 * 1e3, DEFAULT_MAX_PENDING = 3, DEFAULT_MAX_FAILS = 5, DEFAULT_LOCKOUT_MS = 3600 * 1e3;
|
|
1681
|
-
function normalizeCode(code) {
|
|
1682
|
-
return code.replace(/-/g, "").trim().toUpperCase();
|
|
1683
|
-
}
|
|
1684
|
-
function generateCode() {
|
|
1685
|
-
let code = "";
|
|
1686
|
-
for (let i = 0; i < CODE_LENGTH2; i++)
|
|
1687
|
-
code += CODE_ALPHABET3[randomInt(0, CODE_ALPHABET3.length)];
|
|
1688
|
-
return code;
|
|
1689
|
-
}
|
|
1690
|
-
function createPairingStore(options = {}) {
|
|
1691
|
-
let dir = options.dir ?? join(getAgentDir(), "pairing"), ttlMs = options.ttlMs ?? DEFAULT_TTL_MS, rateLimitMs = options.rateLimitMs ?? DEFAULT_RATE_LIMIT_MS, maxPending = options.maxPending ?? DEFAULT_MAX_PENDING, maxFails = options.maxFails ?? DEFAULT_MAX_FAILS, lockoutMs = options.lockoutMs ?? DEFAULT_LOCKOUT_MS, now = options.now ?? (() => Date.now());
|
|
1692
|
-
function storeFile() {
|
|
1693
|
-
return join(dir, "store.json");
|
|
1694
|
-
}
|
|
1695
|
-
function read() {
|
|
1696
|
-
let path = storeFile();
|
|
1697
|
-
if (!existsSync(path))
|
|
1698
|
-
return { pending: [], approved: [] };
|
|
1699
|
-
try {
|
|
1700
|
-
let parsed = JSON.parse(readFileSync(path, "utf-8"));
|
|
1701
|
-
if (parsed == null || typeof parsed != "object" || Array.isArray(parsed))
|
|
1702
|
-
return { pending: [], approved: [] };
|
|
1703
|
-
let p = parsed, pending2 = Array.isArray(p.pending) ? p.pending : [], approved = Array.isArray(p.approved) ? p.approved : [];
|
|
1704
|
-
return {
|
|
1705
|
-
pending: pending2.filter((c) => typeof c?.code == "string" && typeof c?.platform == "string" && typeof c?.userId == "string"),
|
|
1706
|
-
approved: approved.filter((u) => typeof u?.platform == "string" && typeof u?.userId == "string"),
|
|
1707
|
-
failedAttempts: typeof p.failedAttempts == "object" && p.failedAttempts !== null && !Array.isArray(p.failedAttempts) ? p.failedAttempts : void 0,
|
|
1708
|
-
lockedOutUntil: typeof p.lockedOutUntil == "object" && p.lockedOutUntil !== null && !Array.isArray(p.lockedOutUntil) ? p.lockedOutUntil : void 0
|
|
1709
|
-
};
|
|
1710
|
-
} catch {
|
|
1711
|
-
return { pending: [], approved: [] };
|
|
1712
|
-
}
|
|
1713
|
-
}
|
|
1714
|
-
function write(data) {
|
|
1715
|
-
existsSync(dir) || mkdirSync(dir, { recursive: !0 });
|
|
1716
|
-
let path = storeFile(), tmp = `${path}.tmp-${process.pid}`;
|
|
1717
|
-
writeFileSync(tmp, `${JSON.stringify(data, null, 2)}
|
|
1718
|
-
`, "utf-8"), renameSync(tmp, path);
|
|
1719
|
-
try {
|
|
1720
|
-
chmodSync(path, 384);
|
|
1721
|
-
} catch {
|
|
1722
|
-
}
|
|
1723
|
-
}
|
|
1724
|
-
function isLockedOut(platform) {
|
|
1725
|
-
let until = read().lockedOutUntil?.[platform] ?? 0;
|
|
1726
|
-
return now() < until;
|
|
1727
|
-
}
|
|
1728
|
-
function recordFailedAttempt(platform) {
|
|
1729
|
-
let data = read(), failed = data.failedAttempts ?? {};
|
|
1730
|
-
if (failed[platform] = (failed[platform] ?? 0) + 1, failed[platform] >= maxFails) {
|
|
1731
|
-
let locked = data.lockedOutUntil ?? {};
|
|
1732
|
-
locked[platform] = now() + lockoutMs, failed[platform] = 0, data.lockedOutUntil = locked;
|
|
1733
|
-
}
|
|
1734
|
-
data.failedAttempts = failed, write(data);
|
|
1735
|
-
}
|
|
1736
|
-
function livePending(data) {
|
|
1737
|
-
let cutoff = now() - ttlMs;
|
|
1738
|
-
return data.pending.filter((c) => c.issuedAt >= cutoff);
|
|
1739
|
-
}
|
|
1740
|
-
return {
|
|
1741
|
-
issueCode(platform, userId) {
|
|
1742
|
-
if (isLockedOut(platform))
|
|
1743
|
-
return null;
|
|
1744
|
-
let data = read(), lastIssued = data.pending.filter((c) => c.platform === platform && c.userId === userId).reduce((max, c) => Math.max(max, c.issuedAt), 0);
|
|
1745
|
-
if (lastIssued > 0 && now() - lastIssued < rateLimitMs)
|
|
1746
|
-
return null;
|
|
1747
|
-
let live = livePending(data);
|
|
1748
|
-
if (live.filter((c) => c.platform === platform).length >= maxPending)
|
|
1749
|
-
return null;
|
|
1750
|
-
let entry = {
|
|
1751
|
-
code: generateCode(),
|
|
1752
|
-
platform,
|
|
1753
|
-
userId,
|
|
1754
|
-
issuedAt: now()
|
|
1755
|
-
};
|
|
1756
|
-
return data.pending = [...live, entry], write(data), entry.code;
|
|
1757
|
-
},
|
|
1758
|
-
approve(platform, code) {
|
|
1759
|
-
if (isLockedOut(platform))
|
|
1760
|
-
return null;
|
|
1761
|
-
let data = read(), live = livePending(data), normalized = normalizeCode(code), match = live.find((c) => c.platform === platform && c.code === normalized);
|
|
1762
|
-
return match ? (data.pending = live.filter((c) => c !== match), data.approved = [
|
|
1763
|
-
...data.approved.filter((u) => !(u.platform === platform && u.userId === match.userId)),
|
|
1764
|
-
{ platform, userId: match.userId, approvedAt: now() }
|
|
1765
|
-
], write(data), match.userId) : (recordFailedAttempt(platform), null);
|
|
1766
|
-
},
|
|
1767
|
-
isPaired(platform, userId) {
|
|
1768
|
-
return read().approved.some((u) => u.platform === platform && u.userId === userId);
|
|
1769
|
-
},
|
|
1770
|
-
listPending() {
|
|
1771
|
-
let data = read();
|
|
1772
|
-
return livePending(data).map((c) => ({
|
|
1773
|
-
code: c.code,
|
|
1774
|
-
platform: c.platform,
|
|
1775
|
-
userId: c.userId,
|
|
1776
|
-
expiresAt: c.issuedAt + ttlMs
|
|
1777
|
-
}));
|
|
1778
|
-
},
|
|
1779
|
-
listApproved() {
|
|
1780
|
-
return read().approved.map((u) => ({ platform: u.platform, userId: u.userId, approvedAt: u.approvedAt }));
|
|
1781
|
-
}
|
|
1782
|
-
};
|
|
1783
|
-
}
|
|
1784
|
-
|
|
1785
1017
|
// packages/coding-agent/dist/gateway/router.js
|
|
1786
|
-
import { existsSync
|
|
1018
|
+
import { existsSync } from "node:fs";
|
|
1787
1019
|
|
|
1788
1020
|
// packages/coding-agent/dist/gateway/session-keys.js
|
|
1789
1021
|
var SESSION_KEY_PREFIX = "agent:main";
|
|
@@ -1864,7 +1096,7 @@ var StreamConsumer = class {
|
|
|
1864
1096
|
};
|
|
1865
1097
|
|
|
1866
1098
|
// packages/coding-agent/dist/gateway/router.js
|
|
1867
|
-
function
|
|
1099
|
+
function oneLine(text) {
|
|
1868
1100
|
return text.replace(/\s+/g, " ").trim().slice(0, 200);
|
|
1869
1101
|
}
|
|
1870
1102
|
function formatPairingCode(code) {
|
|
@@ -1880,14 +1112,14 @@ function createRouter(deps) {
|
|
|
1880
1112
|
if (!reloadConfig)
|
|
1881
1113
|
return initialCfg;
|
|
1882
1114
|
try {
|
|
1883
|
-
if (
|
|
1115
|
+
if (existsSync(gatewayConfigPath()))
|
|
1884
1116
|
return loadGatewayConfig();
|
|
1885
1117
|
} catch {
|
|
1886
1118
|
}
|
|
1887
1119
|
return initialCfg;
|
|
1888
1120
|
}
|
|
1889
1121
|
async function sendError(adapter, event, message) {
|
|
1890
|
-
await adapter.send(event.source.chatId, `\u26A0 ${
|
|
1122
|
+
await adapter.send(event.source.chatId, `\u26A0 ${oneLine(message)}`, {
|
|
1891
1123
|
replyTo: event.messageId,
|
|
1892
1124
|
threadId: event.source.threadId
|
|
1893
1125
|
});
|
|
@@ -1915,15 +1147,30 @@ function createRouter(deps) {
|
|
|
1915
1147
|
let text = event.text.trim();
|
|
1916
1148
|
if (!text.startsWith("/"))
|
|
1917
1149
|
return !1;
|
|
1918
|
-
let firstToken = text.split(/\s+/, 1)[0].toLowerCase(), commandWord = firstToken.split("@")[0].slice(1), args = text.slice(firstToken.length).trim()
|
|
1919
|
-
|
|
1150
|
+
let firstToken = text.split(/\s+/, 1)[0].toLowerCase(), commandWord = firstToken.split("@")[0].slice(1), args = text.slice(firstToken.length).trim();
|
|
1151
|
+
if (deps.remoteControls) {
|
|
1152
|
+
let { handleMobileCommand, cancelMobileTransfer } = await import("./mobile-commands-LVHDAUDP.js");
|
|
1153
|
+
if (["stop", "stopall", "new", "cancel"].includes(commandWord) && cancelMobileTransfer(key), commandWord === "cancel")
|
|
1154
|
+
return invalidateGatewayDialogs(key), await adapter.send(event.source.chatId, "Cancelled the pending selection or transfer.", {
|
|
1155
|
+
threadId: event.source.threadId
|
|
1156
|
+
}), !0;
|
|
1157
|
+
if (await runWithApprovalContext({ key, adapter, source: event.source }, () => handleMobileCommand({ key, event, adapter, bridge, cfg: freshCfg() }, commandWord, args)))
|
|
1158
|
+
return !0;
|
|
1159
|
+
if (!event.text.startsWith("/"))
|
|
1160
|
+
return !1;
|
|
1161
|
+
}
|
|
1162
|
+
let cmd = CHAT_COMMANDS.find((c) => c.name === commandWord || c.aliases?.includes(commandWord));
|
|
1163
|
+
if (!cmd)
|
|
1164
|
+
return event.source.chatType !== "dm";
|
|
1165
|
+
let ctx = {
|
|
1920
1166
|
event,
|
|
1921
1167
|
key,
|
|
1922
1168
|
adapter,
|
|
1923
1169
|
bridge,
|
|
1924
1170
|
args,
|
|
1925
1171
|
reply: (message) => sendCommandReply(adapter, event, message)
|
|
1926
|
-
}
|
|
1172
|
+
};
|
|
1173
|
+
return runWithApprovalContext({ key, adapter, source: event.source }, () => runChatCommand(cmd, ctx));
|
|
1927
1174
|
}
|
|
1928
1175
|
async function deliver(adapter, event, text, opts) {
|
|
1929
1176
|
let filtered = applySilenceFilter(text);
|
|
@@ -1990,6 +1237,13 @@ function createRouter(deps) {
|
|
|
1990
1237
|
if (isGroupGated(event, cfg) || await isDenied(adapter, event, cfg))
|
|
1991
1238
|
return;
|
|
1992
1239
|
let key = buildSessionKey(event.source, { groupSessionsPerUser: cfg.groupSessionsPerUser });
|
|
1240
|
+
if (deps.remoteControls) {
|
|
1241
|
+
let binding = conversationBinding(key);
|
|
1242
|
+
if (binding?.owner && (requireGatewayOwner(event.source, cfg), binding.owner !== event.source.userId))
|
|
1243
|
+
throw new Error("This session belongs to a different owner.");
|
|
1244
|
+
if (bindConversation(key, event.source), acceptGatewayInput(key, event))
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
1993
1247
|
if (await handleSlash(adapter, event, key))
|
|
1994
1248
|
return;
|
|
1995
1249
|
await adapter.sendTyping(event.source.chatId, event.source.threadId).catch(() => {
|
|
@@ -2040,11 +1294,11 @@ async function runPairApprove(platform, code) {
|
|
|
2040
1294
|
return console.log(`Approved ${platform} user ${userId} (added to ${platform}.allowedUsers in gateway.json).`), 0;
|
|
2041
1295
|
}
|
|
2042
1296
|
function runPairList() {
|
|
2043
|
-
let pairing = createPairingStore(),
|
|
2044
|
-
if (console.log("Pending pairing codes:"),
|
|
1297
|
+
let pairing = createPairingStore(), pending = pairing.listPending(), approved = pairing.listApproved();
|
|
1298
|
+
if (console.log("Pending pairing codes:"), pending.length === 0)
|
|
2045
1299
|
console.log(" (none)");
|
|
2046
1300
|
else
|
|
2047
|
-
for (let p of
|
|
1301
|
+
for (let p of pending)
|
|
2048
1302
|
console.log(` ${p.platform} ${p.code} user=${p.userId} expires ${new Date(p.expiresAt).toISOString()}`);
|
|
2049
1303
|
if (console.log("Paired users:"), approved.length === 0)
|
|
2050
1304
|
console.log(" (none)");
|
|
@@ -2088,40 +1342,67 @@ async function runDaemon() {
|
|
|
2088
1342
|
}
|
|
2089
1343
|
if (adapters.size === 0)
|
|
2090
1344
|
return printSetupInstructions(skipped), 1;
|
|
2091
|
-
let pairing = createPairingStore(), bridge = new AgentBridge()
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
1345
|
+
let pairing = createPairingStore(), bridge = new AgentBridge();
|
|
1346
|
+
for (let adapter of adapters.values())
|
|
1347
|
+
adapter.setCommandSuggestions?.(async (source, command) => {
|
|
1348
|
+
let session = bridge.peekSession(buildSessionKey(source, loadGatewayConfig()));
|
|
1349
|
+
return session ? command === "thinking" ? session.getAvailableThinkingLevels() : command === "model" ? (await session.modelRuntime.getAvailable()).map((model) => `${model.provider}/${model.id}`) : [] : [];
|
|
1350
|
+
});
|
|
1351
|
+
let router = createRouter({ adapters, cfg, pairing, bridge, reloadConfig: !0, remoteControls: !0 }), finish, stopped = new Promise((resolve) => {
|
|
1352
|
+
finish = resolve;
|
|
1353
|
+
}), stopping = !1, cron, platformStatus = {}, retries = /* @__PURE__ */ new Set(), shutdown = () => {
|
|
1354
|
+
if (!stopping) {
|
|
1355
|
+
stopping = !0, owner.update(platformStatus, "stopping"), cron?.stop();
|
|
1356
|
+
for (let timer of retries)
|
|
1357
|
+
clearTimeout(timer);
|
|
1358
|
+
stopButtonSweeper(), (async () => {
|
|
1359
|
+
await bridge.shutdown(), await Promise.all([...adapters.values()].map((adapter) => adapter.disconnect().catch(() => {
|
|
1360
|
+
}))), stopGatewayPresenter(), owner.release(), process.removeListener("SIGINT", shutdown), process.removeListener("SIGTERM", shutdown), finish();
|
|
1361
|
+
})().catch((error) => {
|
|
1362
|
+
console.error("Gateway shutdown failed:", error instanceof Error ? error.message : String(error)), stopping = !1, owner.update(platformStatus, "ready"), startButtonSweeper(), cron = startGatewayCron({ adapters, cfg });
|
|
1363
|
+
for (let [platform, adapter] of adapters)
|
|
1364
|
+
platformStatus[platform] !== "connected" && connect(platform, adapter);
|
|
2103
1365
|
});
|
|
1366
|
+
}
|
|
1367
|
+
}, owner = claimGateway(shutdown);
|
|
1368
|
+
process.on("SIGINT", shutdown), process.on("SIGTERM", shutdown), startGatewayPresenter(adapters);
|
|
1369
|
+
let connected = [];
|
|
1370
|
+
startButtonSweeper();
|
|
1371
|
+
let connect = async (platform, adapter) => {
|
|
1372
|
+
if (!stopping) {
|
|
2104
1373
|
try {
|
|
2105
|
-
await adapter.
|
|
2106
|
-
|
|
2107
|
-
|
|
1374
|
+
if (platformStatus[platform] = "connecting", owner.update(platformStatus, "starting"), !await adapter.connect())
|
|
1375
|
+
throw new Error("Connection failed");
|
|
1376
|
+
adapter.onMessage((event) => {
|
|
1377
|
+
router.handleEvent(event);
|
|
1378
|
+
}), adapter.onCallback(async (event) => {
|
|
1379
|
+
await handleApprovalCallback(event, adapter) || handleCallback(event, { adapters, cfg: loadGatewayConfig(), pairing, bridge, adapter });
|
|
1380
|
+
});
|
|
1381
|
+
try {
|
|
1382
|
+
await adapter.registerCommands?.(botCommandSpecs());
|
|
1383
|
+
} catch (err) {
|
|
1384
|
+
console.error(`[gateway] ${platform}: command menu registration failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1385
|
+
}
|
|
1386
|
+
if (stopping) {
|
|
1387
|
+
await adapter.disconnect();
|
|
1388
|
+
return;
|
|
1389
|
+
}
|
|
1390
|
+
connected.push(adapter), platformStatus[platform] = "connected", console.log(`lunR gateway: ${platform} connected`);
|
|
1391
|
+
} catch {
|
|
1392
|
+
if (platformStatus[platform] = "disconnected, retrying", await adapter.disconnect().catch(() => {
|
|
1393
|
+
}), !stopping) {
|
|
1394
|
+
let retry = setTimeout(() => {
|
|
1395
|
+
retries.delete(retry), connect(platform, adapter);
|
|
1396
|
+
}, 5e3);
|
|
1397
|
+
retries.add(retry);
|
|
1398
|
+
}
|
|
2108
1399
|
}
|
|
2109
|
-
|
|
2110
|
-
} catch (err) {
|
|
2111
|
-
console.error(`[gateway] ${platform}: connect failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1400
|
+
stopping || owner.update(platformStatus);
|
|
2112
1401
|
}
|
|
2113
|
-
if (connected.length === 0)
|
|
2114
|
-
return console.error("lunR gateway: every configured platform failed to connect."), stopButtonSweeper(), 1;
|
|
2115
|
-
let cron = startGatewayCron({ adapters, cfg });
|
|
2116
|
-
console.log(`lunR gateway: cron scheduler started (${cron.intervalMs / 1e3}s interval)`);
|
|
2117
|
-
let shutdown = () => {
|
|
2118
|
-
cron.stop(), stopButtonSweeper(), Promise.all(connected.map((adapter) => adapter.disconnect().catch(() => {
|
|
2119
|
-
}))).finally(() => {
|
|
2120
|
-
process.exit(0);
|
|
2121
|
-
});
|
|
2122
1402
|
};
|
|
2123
|
-
|
|
2124
|
-
|
|
1403
|
+
for (let [platform, adapter] of adapters)
|
|
1404
|
+
connect(platform, adapter);
|
|
1405
|
+
return cron = startGatewayCron({ adapters, cfg }), console.log(`lunR gateway: cron scheduler started (${cron.intervalMs / 1e3}s interval)`), owner.update(platformStatus), await stopped, 0;
|
|
2125
1406
|
}
|
|
2126
1407
|
async function runGateway(args) {
|
|
2127
1408
|
let [sub, ...rest] = args;
|