@0xmaxma/claude-gateway 1.8.13 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -1605
- package/config.template.json +7 -1
- package/dist/agent/runner.d.ts +394 -0
- package/dist/agent/runner.d.ts.map +1 -1
- package/dist/agent/runner.js +867 -38
- package/dist/agent/runner.js.map +1 -1
- package/dist/agent/skill-learning/index.d.ts +6 -4
- package/dist/agent/skill-learning/index.d.ts.map +1 -1
- package/dist/agent/skill-learning/index.js +3 -3
- package/dist/agent/skill-learning/index.js.map +1 -1
- package/dist/agent/skill-learning/notifier.d.ts +3 -4
- package/dist/agent/skill-learning/notifier.d.ts.map +1 -1
- package/dist/agent/skill-learning/notifier.js +15 -13
- package/dist/agent/skill-learning/notifier.js.map +1 -1
- package/dist/agent/skill-learning/reviewer.d.ts.map +1 -1
- package/dist/agent/skill-learning/reviewer.js +3 -1
- package/dist/agent/skill-learning/reviewer.js.map +1 -1
- package/dist/api/connectors-router.d.ts.map +1 -1
- package/dist/api/connectors-router.js +110 -4
- package/dist/api/connectors-router.js.map +1 -1
- package/dist/api/gateway-router.d.ts +1 -0
- package/dist/api/gateway-router.d.ts.map +1 -1
- package/dist/api/gateway-router.js +13 -1
- package/dist/api/gateway-router.js.map +1 -1
- package/dist/api/line-webhook-router.d.ts +2 -2
- package/dist/api/line-webhook-router.d.ts.map +1 -1
- package/dist/api/line-webhook-router.js +264 -230
- package/dist/api/line-webhook-router.js.map +1 -1
- package/dist/api/router.d.ts.map +1 -1
- package/dist/api/router.js +372 -11
- package/dist/api/router.js.map +1 -1
- package/dist/api/share-router.d.ts.map +1 -1
- package/dist/api/share-router.js +29 -10
- package/dist/api/share-router.js.map +1 -1
- package/dist/api/slack-client.d.ts +2 -0
- package/dist/api/slack-client.d.ts.map +1 -1
- package/dist/api/slack-client.js +6 -2
- package/dist/api/slack-client.js.map +1 -1
- package/dist/api/slack-webhook-router.d.ts +3 -0
- package/dist/api/slack-webhook-router.d.ts.map +1 -1
- package/dist/api/slack-webhook-router.js +226 -131
- package/dist/api/slack-webhook-router.js.map +1 -1
- package/dist/api/voice-router.d.ts +21 -0
- package/dist/api/voice-router.d.ts.map +1 -0
- package/dist/api/voice-router.js +372 -0
- package/dist/api/voice-router.js.map +1 -0
- package/dist/api/voice-settings-router.d.ts +5 -0
- package/dist/api/voice-settings-router.d.ts.map +1 -0
- package/dist/api/voice-settings-router.js +318 -0
- package/dist/api/voice-settings-router.js.map +1 -0
- package/dist/api/wechat-access.d.ts +45 -0
- package/dist/api/wechat-access.d.ts.map +1 -0
- package/dist/api/wechat-access.js +48 -0
- package/dist/api/wechat-access.js.map +1 -0
- package/dist/apps/agent-container-migration.d.ts +11 -0
- package/dist/apps/agent-container-migration.d.ts.map +1 -0
- package/dist/apps/agent-container-migration.js +85 -0
- package/dist/apps/agent-container-migration.js.map +1 -0
- package/dist/apps/installer.d.ts +1 -1
- package/dist/apps/installer.d.ts.map +1 -1
- package/dist/apps/installer.js +2 -1
- package/dist/apps/installer.js.map +1 -1
- package/dist/cli/commands/tasks.d.ts +5 -0
- package/dist/cli/commands/tasks.d.ts.map +1 -0
- package/dist/cli/commands/tasks.js +92 -0
- package/dist/cli/commands/tasks.js.map +1 -0
- package/dist/cli/http-client.d.ts +2 -0
- package/dist/cli/http-client.d.ts.map +1 -1
- package/dist/cli/http-client.js +8 -3
- package/dist/cli/http-client.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +5 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/config/config-write-lock.d.ts +2 -0
- package/dist/config/config-write-lock.d.ts.map +1 -1
- package/dist/config/config-write-lock.js +5 -0
- package/dist/config/config-write-lock.js.map +1 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +87 -2
- package/dist/config/loader.js.map +1 -1
- package/dist/config/migrator.d.ts.map +1 -1
- package/dist/config/migrator.js +12 -1
- package/dist/config/migrator.js.map +1 -1
- package/dist/config/watcher.d.ts.map +1 -1
- package/dist/config/watcher.js +6 -0
- package/dist/config/watcher.js.map +1 -1
- package/dist/connectors/resolve.d.ts.map +1 -1
- package/dist/connectors/resolve.js +3 -1
- package/dist/connectors/resolve.js.map +1 -1
- package/dist/connectors/types.d.ts +8 -0
- package/dist/connectors/types.d.ts.map +1 -1
- package/dist/cron/manager.d.ts.map +1 -1
- package/dist/cron/manager.js +21 -2
- package/dist/cron/manager.js.map +1 -1
- package/dist/discord/receiver.d.ts +2 -1
- package/dist/discord/receiver.d.ts.map +1 -1
- package/dist/discord/receiver.js +5 -1
- package/dist/discord/receiver.js.map +1 -1
- package/dist/history/db.d.ts +3 -0
- package/dist/history/db.d.ts.map +1 -1
- package/dist/history/db.js +21 -1
- package/dist/history/db.js.map +1 -1
- package/dist/history/types.d.ts +12 -1
- package/dist/history/types.d.ts.map +1 -1
- package/dist/history/types.js +10 -1
- package/dist/history/types.js.map +1 -1
- package/dist/index.js +48 -9
- package/dist/index.js.map +1 -1
- package/dist/orchestration/bounded-queue.d.ts +15 -0
- package/dist/orchestration/bounded-queue.d.ts.map +1 -0
- package/dist/orchestration/bounded-queue.js +58 -0
- package/dist/orchestration/bounded-queue.js.map +1 -0
- package/dist/orchestration/bridge.d.ts +55 -0
- package/dist/orchestration/bridge.d.ts.map +1 -0
- package/dist/orchestration/bridge.js +234 -0
- package/dist/orchestration/bridge.js.map +1 -0
- package/dist/orchestration/browser-routing.d.ts +7 -0
- package/dist/orchestration/browser-routing.d.ts.map +1 -0
- package/dist/orchestration/browser-routing.js +22 -0
- package/dist/orchestration/browser-routing.js.map +1 -0
- package/dist/orchestration/capabilities.d.ts +49 -0
- package/dist/orchestration/capabilities.d.ts.map +1 -0
- package/dist/orchestration/capabilities.js +417 -0
- package/dist/orchestration/capabilities.js.map +1 -0
- package/dist/orchestration/capacity.d.ts +14 -0
- package/dist/orchestration/capacity.d.ts.map +1 -0
- package/dist/orchestration/capacity.js +52 -0
- package/dist/orchestration/capacity.js.map +1 -0
- package/dist/orchestration/channel-activity.d.ts +21 -0
- package/dist/orchestration/channel-activity.d.ts.map +1 -0
- package/dist/orchestration/channel-activity.js +72 -0
- package/dist/orchestration/channel-activity.js.map +1 -0
- package/dist/orchestration/channel-controls.d.ts +32 -0
- package/dist/orchestration/channel-controls.d.ts.map +1 -0
- package/dist/orchestration/channel-controls.js +105 -0
- package/dist/orchestration/channel-controls.js.map +1 -0
- package/dist/orchestration/channel-input-media.d.ts +11 -0
- package/dist/orchestration/channel-input-media.d.ts.map +1 -0
- package/dist/orchestration/channel-input-media.js +54 -0
- package/dist/orchestration/channel-input-media.js.map +1 -0
- package/dist/orchestration/channel-media.d.ts +4 -0
- package/dist/orchestration/channel-media.d.ts.map +1 -0
- package/dist/orchestration/channel-media.js +70 -0
- package/dist/orchestration/channel-media.js.map +1 -0
- package/dist/orchestration/channel-speech.d.ts +7 -0
- package/dist/orchestration/channel-speech.d.ts.map +1 -0
- package/dist/orchestration/channel-speech.js +65 -0
- package/dist/orchestration/channel-speech.js.map +1 -0
- package/dist/orchestration/cli-skills.d.ts +12 -0
- package/dist/orchestration/cli-skills.d.ts.map +1 -0
- package/dist/orchestration/cli-skills.js +132 -0
- package/dist/orchestration/cli-skills.js.map +1 -0
- package/dist/orchestration/config.d.ts +256 -0
- package/dist/orchestration/config.d.ts.map +1 -0
- package/dist/orchestration/config.js +110 -0
- package/dist/orchestration/config.js.map +1 -0
- package/dist/orchestration/container.d.ts +21 -0
- package/dist/orchestration/container.d.ts.map +1 -0
- package/dist/orchestration/container.js +195 -0
- package/dist/orchestration/container.js.map +1 -0
- package/dist/orchestration/control-delivery.d.ts +5 -0
- package/dist/orchestration/control-delivery.d.ts.map +1 -0
- package/dist/orchestration/control-delivery.js +50 -0
- package/dist/orchestration/control-delivery.js.map +1 -0
- package/dist/orchestration/conversation-intake.d.ts +32 -0
- package/dist/orchestration/conversation-intake.d.ts.map +1 -0
- package/dist/orchestration/conversation-intake.js +92 -0
- package/dist/orchestration/conversation-intake.js.map +1 -0
- package/dist/orchestration/decisions.d.ts +27 -0
- package/dist/orchestration/decisions.d.ts.map +1 -0
- package/dist/orchestration/decisions.js +148 -0
- package/dist/orchestration/decisions.js.map +1 -0
- package/dist/orchestration/delivery.d.ts +30 -0
- package/dist/orchestration/delivery.d.ts.map +1 -0
- package/dist/orchestration/delivery.js +219 -0
- package/dist/orchestration/delivery.js.map +1 -0
- package/dist/orchestration/display-stream.d.ts +4 -0
- package/dist/orchestration/display-stream.d.ts.map +1 -0
- package/dist/orchestration/display-stream.js +77 -0
- package/dist/orchestration/display-stream.js.map +1 -0
- package/dist/orchestration/events.d.ts +30 -0
- package/dist/orchestration/events.d.ts.map +1 -0
- package/dist/orchestration/events.js +65 -0
- package/dist/orchestration/events.js.map +1 -0
- package/dist/orchestration/execution-observation.d.ts +38 -0
- package/dist/orchestration/execution-observation.d.ts.map +1 -0
- package/dist/orchestration/execution-observation.js +25 -0
- package/dist/orchestration/execution-observation.js.map +1 -0
- package/dist/orchestration/file-delivery.d.ts +16 -0
- package/dist/orchestration/file-delivery.d.ts.map +1 -0
- package/dist/orchestration/file-delivery.js +139 -0
- package/dist/orchestration/file-delivery.js.map +1 -0
- package/dist/orchestration/gateway-config.d.ts +17 -0
- package/dist/orchestration/gateway-config.d.ts.map +1 -0
- package/dist/orchestration/gateway-config.js +128 -0
- package/dist/orchestration/gateway-config.js.map +1 -0
- package/dist/orchestration/history.d.ts +13 -0
- package/dist/orchestration/history.d.ts.map +1 -0
- package/dist/orchestration/history.js +48 -0
- package/dist/orchestration/history.js.map +1 -0
- package/dist/orchestration/identity.d.ts +6 -0
- package/dist/orchestration/identity.d.ts.map +1 -0
- package/dist/orchestration/identity.js +13 -0
- package/dist/orchestration/identity.js.map +1 -0
- package/dist/orchestration/inference-errors.d.ts +3 -0
- package/dist/orchestration/inference-errors.d.ts.map +1 -0
- package/dist/orchestration/inference-errors.js +16 -0
- package/dist/orchestration/inference-errors.js.map +1 -0
- package/dist/orchestration/input-images.d.ts +12 -0
- package/dist/orchestration/input-images.d.ts.map +1 -0
- package/dist/orchestration/input-images.js +66 -0
- package/dist/orchestration/input-images.js.map +1 -0
- package/dist/orchestration/instance-lock.d.ts +5 -0
- package/dist/orchestration/instance-lock.d.ts.map +1 -0
- package/dist/orchestration/instance-lock.js +33 -0
- package/dist/orchestration/instance-lock.js.map +1 -0
- package/dist/orchestration/line-loading.d.ts +21 -0
- package/dist/orchestration/line-loading.d.ts.map +1 -0
- package/dist/orchestration/line-loading.js +89 -0
- package/dist/orchestration/line-loading.js.map +1 -0
- package/dist/orchestration/media.d.ts +3 -0
- package/dist/orchestration/media.d.ts.map +1 -0
- package/dist/orchestration/media.js +46 -0
- package/dist/orchestration/media.js.map +1 -0
- package/dist/orchestration/migrations/schema.d.ts +3 -0
- package/dist/orchestration/migrations/schema.d.ts.map +1 -0
- package/dist/orchestration/migrations/schema.js +80 -0
- package/dist/orchestration/migrations/schema.js.map +1 -0
- package/dist/orchestration/notification-mailbox.d.ts +5 -0
- package/dist/orchestration/notification-mailbox.d.ts.map +1 -0
- package/dist/orchestration/notification-mailbox.js +29 -0
- package/dist/orchestration/notification-mailbox.js.map +1 -0
- package/dist/orchestration/process-activity.d.ts +23 -0
- package/dist/orchestration/process-activity.d.ts.map +1 -0
- package/dist/orchestration/process-activity.js +95 -0
- package/dist/orchestration/process-activity.js.map +1 -0
- package/dist/orchestration/process-supervisor.d.ts +15 -0
- package/dist/orchestration/process-supervisor.d.ts.map +1 -0
- package/dist/orchestration/process-supervisor.js +92 -0
- package/dist/orchestration/process-supervisor.js.map +1 -0
- package/dist/orchestration/process-turn.d.ts +35 -0
- package/dist/orchestration/process-turn.d.ts.map +1 -0
- package/dist/orchestration/process-turn.js +246 -0
- package/dist/orchestration/process-turn.js.map +1 -0
- package/dist/orchestration/progress-review.d.ts +28 -0
- package/dist/orchestration/progress-review.d.ts.map +1 -0
- package/dist/orchestration/progress-review.js +48 -0
- package/dist/orchestration/progress-review.js.map +1 -0
- package/dist/orchestration/recovery.d.ts +8 -0
- package/dist/orchestration/recovery.d.ts.map +1 -0
- package/dist/orchestration/recovery.js +35 -0
- package/dist/orchestration/recovery.js.map +1 -0
- package/dist/orchestration/reply-context.d.ts +7 -0
- package/dist/orchestration/reply-context.d.ts.map +1 -0
- package/dist/orchestration/reply-context.js +54 -0
- package/dist/orchestration/reply-context.js.map +1 -0
- package/dist/orchestration/runtime.d.ts +232 -0
- package/dist/orchestration/runtime.d.ts.map +1 -0
- package/dist/orchestration/runtime.js +962 -0
- package/dist/orchestration/runtime.js.map +1 -0
- package/dist/orchestration/skills.d.ts +17 -0
- package/dist/orchestration/skills.d.ts.map +1 -0
- package/dist/orchestration/skills.js +32 -0
- package/dist/orchestration/skills.js.map +1 -0
- package/dist/orchestration/source-policy.d.ts +6 -0
- package/dist/orchestration/source-policy.d.ts.map +1 -0
- package/dist/orchestration/source-policy.js +16 -0
- package/dist/orchestration/source-policy.js.map +1 -0
- package/dist/orchestration/speech.d.ts +24 -0
- package/dist/orchestration/speech.d.ts.map +1 -0
- package/dist/orchestration/speech.js +61 -0
- package/dist/orchestration/speech.js.map +1 -0
- package/dist/orchestration/stop-controls.d.ts +30 -0
- package/dist/orchestration/stop-controls.d.ts.map +1 -0
- package/dist/orchestration/stop-controls.js +79 -0
- package/dist/orchestration/stop-controls.js.map +1 -0
- package/dist/orchestration/store.d.ts +86 -0
- package/dist/orchestration/store.d.ts.map +1 -0
- package/dist/orchestration/store.js +275 -0
- package/dist/orchestration/store.js.map +1 -0
- package/dist/orchestration/task-controls.d.ts +130 -0
- package/dist/orchestration/task-controls.d.ts.map +1 -0
- package/dist/orchestration/task-controls.js +55 -0
- package/dist/orchestration/task-controls.js.map +1 -0
- package/dist/orchestration/task-files.d.ts +29 -0
- package/dist/orchestration/task-files.d.ts.map +1 -0
- package/dist/orchestration/task-files.js +200 -0
- package/dist/orchestration/task-files.js.map +1 -0
- package/dist/orchestration/task-report.d.ts +7 -0
- package/dist/orchestration/task-report.d.ts.map +1 -0
- package/dist/orchestration/task-report.js +33 -0
- package/dist/orchestration/task-report.js.map +1 -0
- package/dist/orchestration/tasks/checkpoint-hook.d.ts +19 -0
- package/dist/orchestration/tasks/checkpoint-hook.d.ts.map +1 -0
- package/dist/orchestration/tasks/checkpoint-hook.js +49 -0
- package/dist/orchestration/tasks/checkpoint-hook.js.map +1 -0
- package/dist/orchestration/tasks/cleanup.d.ts +18 -0
- package/dist/orchestration/tasks/cleanup.d.ts.map +1 -0
- package/dist/orchestration/tasks/cleanup.js +113 -0
- package/dist/orchestration/tasks/cleanup.js.map +1 -0
- package/dist/orchestration/tasks/driver.d.ts +23 -0
- package/dist/orchestration/tasks/driver.d.ts.map +1 -0
- package/dist/orchestration/tasks/driver.js +209 -0
- package/dist/orchestration/tasks/driver.js.map +1 -0
- package/dist/orchestration/tasks/failure.d.ts +5 -0
- package/dist/orchestration/tasks/failure.d.ts.map +1 -0
- package/dist/orchestration/tasks/failure.js +17 -0
- package/dist/orchestration/tasks/failure.js.map +1 -0
- package/dist/orchestration/tasks/pool.d.ts +18 -0
- package/dist/orchestration/tasks/pool.d.ts.map +1 -0
- package/dist/orchestration/tasks/pool.js +73 -0
- package/dist/orchestration/tasks/pool.js.map +1 -0
- package/dist/orchestration/tasks/scheduler.d.ts +38 -0
- package/dist/orchestration/tasks/scheduler.d.ts.map +1 -0
- package/dist/orchestration/tasks/scheduler.js +160 -0
- package/dist/orchestration/tasks/scheduler.js.map +1 -0
- package/dist/orchestration/tasks/service.d.ts +109 -0
- package/dist/orchestration/tasks/service.d.ts.map +1 -0
- package/dist/orchestration/tasks/service.js +697 -0
- package/dist/orchestration/tasks/service.js.map +1 -0
- package/dist/orchestration/tasks/shared-workspace.d.ts +25 -0
- package/dist/orchestration/tasks/shared-workspace.d.ts.map +1 -0
- package/dist/orchestration/tasks/shared-workspace.js +162 -0
- package/dist/orchestration/tasks/shared-workspace.js.map +1 -0
- package/dist/orchestration/tasks/task-directive.d.ts +6 -0
- package/dist/orchestration/tasks/task-directive.d.ts.map +1 -0
- package/dist/orchestration/tasks/task-directive.js +41 -0
- package/dist/orchestration/tasks/task-directive.js.map +1 -0
- package/dist/orchestration/tasks/timing.d.ts +15 -0
- package/dist/orchestration/tasks/timing.d.ts.map +1 -0
- package/dist/orchestration/tasks/timing.js +48 -0
- package/dist/orchestration/tasks/timing.js.map +1 -0
- package/dist/orchestration/tasks/tool-repetition.d.ts +3 -0
- package/dist/orchestration/tasks/tool-repetition.d.ts.map +1 -0
- package/dist/orchestration/tasks/tool-repetition.js +30 -0
- package/dist/orchestration/tasks/tool-repetition.js.map +1 -0
- package/dist/orchestration/tasks/workspace.d.ts +24 -0
- package/dist/orchestration/tasks/workspace.d.ts.map +1 -0
- package/dist/orchestration/tasks/workspace.js +147 -0
- package/dist/orchestration/tasks/workspace.js.map +1 -0
- package/dist/orchestration/telegram-speech.d.ts +17 -0
- package/dist/orchestration/telegram-speech.d.ts.map +1 -0
- package/dist/orchestration/telegram-speech.js +55 -0
- package/dist/orchestration/telegram-speech.js.map +1 -0
- package/dist/orchestration/telegram-tool-status.d.ts +23 -0
- package/dist/orchestration/telegram-tool-status.d.ts.map +1 -0
- package/dist/orchestration/telegram-tool-status.js +207 -0
- package/dist/orchestration/telegram-tool-status.js.map +1 -0
- package/dist/orchestration/telegram-voices.d.ts +42 -0
- package/dist/orchestration/telegram-voices.d.ts.map +1 -0
- package/dist/orchestration/telegram-voices.js +70 -0
- package/dist/orchestration/telegram-voices.js.map +1 -0
- package/dist/orchestration/tool-activity.d.ts +10 -0
- package/dist/orchestration/tool-activity.d.ts.map +1 -0
- package/dist/orchestration/tool-activity.js +38 -0
- package/dist/orchestration/tool-activity.js.map +1 -0
- package/dist/orchestration/types.d.ts +177 -0
- package/dist/orchestration/types.d.ts.map +1 -0
- package/dist/orchestration/types.js +13 -0
- package/dist/orchestration/types.js.map +1 -0
- package/dist/orchestration/voice-reply-policy.d.ts +8 -0
- package/dist/orchestration/voice-reply-policy.d.ts.map +1 -0
- package/dist/orchestration/voice-reply-policy.js +46 -0
- package/dist/orchestration/voice-reply-policy.js.map +1 -0
- package/dist/orchestration/worker-shares.d.ts +8 -0
- package/dist/orchestration/worker-shares.d.ts.map +1 -0
- package/dist/orchestration/worker-shares.js +59 -0
- package/dist/orchestration/worker-shares.js.map +1 -0
- package/dist/orchestration/workflow.d.ts +121 -0
- package/dist/orchestration/workflow.d.ts.map +1 -0
- package/dist/orchestration/workflow.js +69 -0
- package/dist/orchestration/workflow.js.map +1 -0
- package/dist/session/input-image.d.ts +10 -0
- package/dist/session/input-image.d.ts.map +1 -0
- package/dist/session/input-image.js +3 -0
- package/dist/session/input-image.js.map +1 -0
- package/dist/session/process.d.ts +15 -3
- package/dist/session/process.d.ts.map +1 -1
- package/dist/session/process.js +144 -35
- package/dist/session/process.js.map +1 -1
- package/dist/session/runtime-profile.d.ts +36 -0
- package/dist/session/runtime-profile.d.ts.map +1 -0
- package/dist/session/runtime-profile.js +63 -0
- package/dist/session/runtime-profile.js.map +1 -0
- package/dist/session/store.d.ts.map +1 -1
- package/dist/session/store.js +23 -1
- package/dist/session/store.js.map +1 -1
- package/dist/share/share-store.d.ts +3 -1
- package/dist/share/share-store.d.ts.map +1 -1
- package/dist/share/share-store.js +13 -2
- package/dist/share/share-store.js.map +1 -1
- package/dist/shared/line-request-order.d.ts +2 -0
- package/dist/shared/line-request-order.d.ts.map +1 -0
- package/dist/shared/line-request-order.js +16 -0
- package/dist/shared/line-request-order.js.map +1 -0
- package/dist/shared/task-elapsed.d.ts +3 -0
- package/dist/shared/task-elapsed.d.ts.map +1 -0
- package/dist/shared/task-elapsed.js +12 -0
- package/dist/shared/task-elapsed.js.map +1 -0
- package/dist/shared/task-updated-time.d.ts +3 -0
- package/dist/shared/task-updated-time.d.ts.map +1 -0
- package/dist/shared/task-updated-time.js +15 -0
- package/dist/shared/task-updated-time.js.map +1 -0
- package/dist/skills/loader.d.ts +2 -0
- package/dist/skills/loader.d.ts.map +1 -1
- package/dist/skills/loader.js.map +1 -1
- package/dist/telegram/chunks.d.ts +19 -0
- package/dist/telegram/chunks.d.ts.map +1 -0
- package/dist/telegram/chunks.js +129 -0
- package/dist/telegram/chunks.js.map +1 -0
- package/dist/telegram/markdown.d.ts.map +1 -1
- package/dist/telegram/markdown.js +18 -3
- package/dist/telegram/markdown.js.map +1 -1
- package/dist/telegram/receiver.d.ts +2 -1
- package/dist/telegram/receiver.d.ts.map +1 -1
- package/dist/telegram/receiver.js +6 -1
- package/dist/telegram/receiver.js.map +1 -1
- package/dist/types.d.ts +54 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/web-ui.d.ts.map +1 -1
- package/dist/ui/web-ui.js +31 -5
- package/dist/ui/web-ui.js.map +1 -1
- package/dist/voice/diagnostics.d.ts +29 -0
- package/dist/voice/diagnostics.d.ts.map +1 -0
- package/dist/voice/diagnostics.js +37 -0
- package/dist/voice/diagnostics.js.map +1 -0
- package/dist/voice/errors.d.ts +19 -0
- package/dist/voice/errors.d.ts.map +1 -0
- package/dist/voice/errors.js +133 -0
- package/dist/voice/errors.js.map +1 -0
- package/dist/voice/line-audio.d.ts +4 -0
- package/dist/voice/line-audio.d.ts.map +1 -0
- package/dist/voice/line-audio.js +27 -0
- package/dist/voice/line-audio.js.map +1 -0
- package/dist/voice/managed-quota.d.ts +5 -0
- package/dist/voice/managed-quota.d.ts.map +1 -0
- package/dist/voice/managed-quota.js +35 -0
- package/dist/voice/managed-quota.js.map +1 -0
- package/dist/voice/mp3.d.ts +3 -0
- package/dist/voice/mp3.d.ts.map +1 -0
- package/dist/voice/mp3.js +30 -0
- package/dist/voice/mp3.js.map +1 -0
- package/dist/voice/notes.d.ts +9 -0
- package/dist/voice/notes.d.ts.map +1 -0
- package/dist/voice/notes.js +68 -0
- package/dist/voice/notes.js.map +1 -0
- package/dist/voice/playback.d.ts +22 -0
- package/dist/voice/playback.d.ts.map +1 -0
- package/dist/voice/playback.js +52 -0
- package/dist/voice/playback.js.map +1 -0
- package/dist/voice/preview.d.ts +6 -0
- package/dist/voice/preview.d.ts.map +1 -0
- package/dist/voice/preview.js +44 -0
- package/dist/voice/preview.js.map +1 -0
- package/dist/voice/protocol.d.ts +10 -0
- package/dist/voice/protocol.d.ts.map +1 -0
- package/dist/voice/protocol.js +30 -0
- package/dist/voice/protocol.js.map +1 -0
- package/dist/voice/providers/cartesia-tts.d.ts +26 -0
- package/dist/voice/providers/cartesia-tts.d.ts.map +1 -0
- package/dist/voice/providers/cartesia-tts.js +95 -0
- package/dist/voice/providers/cartesia-tts.js.map +1 -0
- package/dist/voice/providers/deepgram-stt.d.ts +20 -0
- package/dist/voice/providers/deepgram-stt.d.ts.map +1 -0
- package/dist/voice/providers/deepgram-stt.js +66 -0
- package/dist/voice/providers/deepgram-stt.js.map +1 -0
- package/dist/voice/providers/elevenlabs-stt.d.ts +20 -0
- package/dist/voice/providers/elevenlabs-stt.d.ts.map +1 -0
- package/dist/voice/providers/elevenlabs-stt.js +92 -0
- package/dist/voice/providers/elevenlabs-stt.js.map +1 -0
- package/dist/voice/providers/elevenlabs-tts.d.ts +26 -0
- package/dist/voice/providers/elevenlabs-tts.d.ts.map +1 -0
- package/dist/voice/providers/elevenlabs-tts.js +82 -0
- package/dist/voice/providers/elevenlabs-tts.js.map +1 -0
- package/dist/voice/providers/encoded-audio-tts.d.ts +21 -0
- package/dist/voice/providers/encoded-audio-tts.d.ts.map +1 -0
- package/dist/voice/providers/encoded-audio-tts.js +175 -0
- package/dist/voice/providers/encoded-audio-tts.js.map +1 -0
- package/dist/voice/providers/fake.d.ts +39 -0
- package/dist/voice/providers/fake.d.ts.map +1 -0
- package/dist/voice/providers/fake.js +41 -0
- package/dist/voice/providers/fake.js.map +1 -0
- package/dist/voice/providers/gemini-live-stt.d.ts +21 -0
- package/dist/voice/providers/gemini-live-stt.d.ts.map +1 -0
- package/dist/voice/providers/gemini-live-stt.js +158 -0
- package/dist/voice/providers/gemini-live-stt.js.map +1 -0
- package/dist/voice/providers/gemini.d.ts +60 -0
- package/dist/voice/providers/gemini.d.ts.map +1 -0
- package/dist/voice/providers/gemini.js +124 -0
- package/dist/voice/providers/gemini.js.map +1 -0
- package/dist/voice/providers/model-ref.d.ts +9 -0
- package/dist/voice/providers/model-ref.d.ts.map +1 -0
- package/dist/voice/providers/model-ref.js +31 -0
- package/dist/voice/providers/model-ref.js.map +1 -0
- package/dist/voice/providers/openrouter.d.ts +39 -0
- package/dist/voice/providers/openrouter.d.ts.map +1 -0
- package/dist/voice/providers/openrouter.js +154 -0
- package/dist/voice/providers/openrouter.js.map +1 -0
- package/dist/voice/providers/paxalabs-stt.d.ts +12 -0
- package/dist/voice/providers/paxalabs-stt.d.ts.map +1 -0
- package/dist/voice/providers/paxalabs-stt.js +41 -0
- package/dist/voice/providers/paxalabs-stt.js.map +1 -0
- package/dist/voice/providers/paxalabs-tts.d.ts +23 -0
- package/dist/voice/providers/paxalabs-tts.d.ts.map +1 -0
- package/dist/voice/providers/paxalabs-tts.js +80 -0
- package/dist/voice/providers/paxalabs-tts.js.map +1 -0
- package/dist/voice/providers/recorded-stt.d.ts +34 -0
- package/dist/voice/providers/recorded-stt.d.ts.map +1 -0
- package/dist/voice/providers/recorded-stt.js +59 -0
- package/dist/voice/providers/recorded-stt.js.map +1 -0
- package/dist/voice/providers/registry.d.ts +10 -0
- package/dist/voice/providers/registry.d.ts.map +1 -0
- package/dist/voice/providers/registry.js +77 -0
- package/dist/voice/providers/registry.js.map +1 -0
- package/dist/voice/providers/socket.d.ts +10 -0
- package/dist/voice/providers/socket.d.ts.map +1 -0
- package/dist/voice/providers/socket.js +91 -0
- package/dist/voice/providers/socket.js.map +1 -0
- package/dist/voice/providers/upstream.d.ts +9 -0
- package/dist/voice/providers/upstream.d.ts.map +1 -0
- package/dist/voice/providers/upstream.js +51 -0
- package/dist/voice/providers/upstream.js.map +1 -0
- package/dist/voice/providers/voice-catalog.d.ts +17 -0
- package/dist/voice/providers/voice-catalog.d.ts.map +1 -0
- package/dist/voice/providers/voice-catalog.js +167 -0
- package/dist/voice/providers/voice-catalog.js.map +1 -0
- package/dist/voice/queue.d.ts +2 -0
- package/dist/voice/queue.d.ts.map +1 -0
- package/dist/voice/queue.js +6 -0
- package/dist/voice/queue.js.map +1 -0
- package/dist/voice/session.d.ts +86 -0
- package/dist/voice/session.d.ts.map +1 -0
- package/dist/voice/session.js +464 -0
- package/dist/voice/session.js.map +1 -0
- package/dist/voice/turn-manager.d.ts +27 -0
- package/dist/voice/turn-manager.d.ts.map +1 -0
- package/dist/voice/turn-manager.js +75 -0
- package/dist/voice/turn-manager.js.map +1 -0
- package/dist/voice/types.d.ts +78 -0
- package/dist/voice/types.d.ts.map +1 -0
- package/dist/voice/types.js +18 -0
- package/dist/voice/types.js.map +1 -0
- package/dist/voice/wav.d.ts +2 -0
- package/dist/voice/wav.d.ts.map +1 -0
- package/dist/voice/wav.js +21 -0
- package/dist/voice/wav.js.map +1 -0
- package/dist/wechat/ilink-client.d.ts +207 -0
- package/dist/wechat/ilink-client.d.ts.map +1 -0
- package/dist/wechat/ilink-client.js +660 -0
- package/dist/wechat/ilink-client.js.map +1 -0
- package/dist/wechat/manager.d.ts +93 -0
- package/dist/wechat/manager.d.ts.map +1 -0
- package/dist/wechat/manager.js +409 -0
- package/dist/wechat/manager.js.map +1 -0
- package/dist/whatsapp/manager.d.ts.map +1 -1
- package/dist/whatsapp/manager.js +51 -1
- package/dist/whatsapp/manager.js.map +1 -1
- package/mcp/capability-catalog.ts +206 -0
- package/mcp/modules.ts +56 -0
- package/mcp/server.ts +18 -35
- package/mcp/tools/browser/module.ts +1 -1
- package/mcp/tools/browser/skills/open-browser/SKILL.md +5 -3
- package/mcp/tools/discord/commands.ts +17 -1
- package/mcp/tools/discord/inbound.ts +11 -0
- package/mcp/tools/discord/module.ts +42 -2
- package/mcp/tools/discord/receiver-server.ts +10 -0
- package/mcp/tools/discord/types.ts +4 -1
- package/mcp/tools/image/module.ts +3 -1
- package/mcp/tools/receiver-spool.test.ts +28 -0
- package/mcp/tools/receiver-spool.ts +56 -0
- package/mcp/tools/share-file/module.ts +9 -1
- package/mcp/tools/shared/share-client.ts +19 -0
- package/mcp/tools/tasks/module.ts +35 -0
- package/mcp/tools/telegram/media-group.ts +21 -0
- package/mcp/tools/telegram/receiver-server.ts +232 -11
- package/mcp/tools/telegram/selection-confirmation.ts +20 -0
- package/mcp/tools/telegram/task-browser.ts +117 -0
- package/mcp/tools/telegram/task-detail.ts +36 -0
- package/mcp/tools/telegram/task-elapsed.ts +1 -0
- package/mcp/tools/telegram/typing.ts +6 -116
- package/mcp/tools/video/module.ts +1 -1
- package/mcp/tools/wechat/client.ts +49 -0
- package/mcp/tools/wechat/module.ts +88 -0
- package/mcp/types.ts +5 -0
- package/package.json +2 -1
- package/resource/claude_gateway.jpeg +0 -0
- package/scripts/orchestration/bench-store.cjs +30 -0
- package/scripts/orchestration/inspect.cjs +16 -0
- package/scripts/orchestration/probe-profile.cjs +67 -0
- package/scripts/orchestration/reconcile.cjs +21 -0
- package/scripts/orchestration/smoke-elevenlabs.cjs +90 -0
- package/scripts/orchestration/smoke-media.cjs +70 -0
- package/scripts/orchestration/smoke-text.cjs +101 -0
- package/scripts/orchestration/smoke-vision.cjs +49 -0
|
@@ -190,6 +190,10 @@ export class DiscordModule implements ChannelModule {
|
|
|
190
190
|
const { createDiscordClient } = await import('./client');
|
|
191
191
|
this.client = await createDiscordClient(token);
|
|
192
192
|
this.running = true;
|
|
193
|
+
if(process.env.CLAUDE_CHANNEL_CALLBACK){
|
|
194
|
+
const {registerCommands}=await import('./commands');
|
|
195
|
+
await registerCommands(this.client,token,process.env.GATEWAY_ORCHESTRATION_ENABLED==='true',process.env.GATEWAY_INTERACTIVE_CLI_ENABLED==='true').catch(err=>process.stderr.write(`discord: command registration failed: ${err}\n`));
|
|
196
|
+
}
|
|
193
197
|
}
|
|
194
198
|
|
|
195
199
|
async start(handler: InboundMessageHandler, signal: AbortSignal): Promise<void> {
|
|
@@ -296,7 +300,12 @@ export class DiscordModule implements ChannelModule {
|
|
|
296
300
|
// button) instead of forwarding the text to the agent. Only reached after
|
|
297
301
|
// gate() authorized this user, so it inherits the channel's access control.
|
|
298
302
|
const cliText = (msg.content ?? '').replace(/<@!?\d+>/g, '').trim().toLowerCase();
|
|
303
|
+
if(/^\/(voice|voices|tasks|stop|help|orch)(?:\s|$)/.test(cliText)){
|
|
304
|
+
await handler({channel:'discord',accountId:this.client.user?.id??'discord',senderId:context.userId,chatId:context.channelId,chatType:isDM?'direct':'group',text:(msg.content??'').replace(/<@!?\d+>/g,'').trim(),messageId:msg.id,ts:Date.now()});
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
299
307
|
if (cliText === '/cli') {
|
|
308
|
+
if(process.env.GATEWAY_INTERACTIVE_CLI_ENABLED!=='true'){await msg.channel.send('The terminal viewer requires interactive mode.');return;}
|
|
300
309
|
const base = cliCallbackBase();
|
|
301
310
|
try {
|
|
302
311
|
const res = await fetch(base + '/command', {
|
|
@@ -336,7 +345,7 @@ export class DiscordModule implements ChannelModule {
|
|
|
336
345
|
const typingFileDir = path.join(this.stateDir, 'typing');
|
|
337
346
|
try {
|
|
338
347
|
fs.mkdirSync(typingFileDir, { recursive: true });
|
|
339
|
-
fs.writeFileSync(path.join(typingFileDir, channelId), '');
|
|
348
|
+
if (process.env.GATEWAY_ORCHESTRATION_ENABLED !== 'true') fs.writeFileSync(path.join(typingFileDir, channelId), '');
|
|
340
349
|
await fetch(`https://discord.com/api/v10/channels/${channelId}/typing`, {
|
|
341
350
|
method: 'POST',
|
|
342
351
|
headers: { Authorization: `Bot ${this.getToken()!}`, 'Content-Length': '0' },
|
|
@@ -388,7 +397,14 @@ export class DiscordModule implements ChannelModule {
|
|
|
388
397
|
// Security mirrors the message path: the access gate must return 'deliver'.
|
|
389
398
|
// discord.js client is typed as `any` (dynamic import) so we narrow locally.
|
|
390
399
|
interface ButtonInteraction {
|
|
400
|
+
id?: string;
|
|
391
401
|
isButton?: () => boolean;
|
|
402
|
+
isChatInputCommand?: () => boolean;
|
|
403
|
+
commandName?: string;
|
|
404
|
+
options?: {getString(name:string):string|null};
|
|
405
|
+
deferUpdate?: () => Promise<unknown>;
|
|
406
|
+
deferReply?: (options: {ephemeral:boolean}) => Promise<unknown>;
|
|
407
|
+
deleteReply?: () => Promise<unknown>;
|
|
392
408
|
customId?: string;
|
|
393
409
|
guildId?: string | null;
|
|
394
410
|
channelId: string;
|
|
@@ -401,6 +417,28 @@ export class DiscordModule implements ChannelModule {
|
|
|
401
417
|
}
|
|
402
418
|
this.client.on('interactionCreate', async (interaction: ButtonInteraction) => {
|
|
403
419
|
try {
|
|
420
|
+
const orchButton=interaction.isButton?.()&&/^orch:[a-f0-9-]{36}$/.test(interaction.customId??'');
|
|
421
|
+
const slash=interaction.isChatInputCommand?.();
|
|
422
|
+
if(orchButton||slash){
|
|
423
|
+
const isDM=!interaction.guildId,isThread=interaction.channel?.isThread?.()??false;
|
|
424
|
+
const context:DiscordMessageContext={guildId:interaction.guildId??null,channelId:interaction.channelId,threadId:isThread?interaction.channelId:null,userId:interaction.user.id,username:interaction.user.username,messageId:interaction.message?.id??'',isDM,isThread,mentionsBot:true};
|
|
425
|
+
const access=gate(loadAccessFn(),context,saveAccessFn,()=>randomBytes(3).toString('hex'));
|
|
426
|
+
if(access.action!=='deliver'){await interaction.reply({content:'Not authorized.',ephemeral:true});return;}
|
|
427
|
+
if(orchButton)await interaction.deferUpdate?.();else await interaction.deferReply?.({ephemeral:true});
|
|
428
|
+
let text=orchButton?`/orch ${interaction.customId!.slice(5)}`:`/${interaction.commandName}`;
|
|
429
|
+
if(slash){
|
|
430
|
+
const name=interaction.commandName;
|
|
431
|
+
const arg=interaction.options?.getString(name==='voice'?'mode':name==='ask'?'question':'name');
|
|
432
|
+
if(name==='ask')text=arg??'';else if(arg)text+=' '+arg;
|
|
433
|
+
if(name==='cli'){
|
|
434
|
+
const channel=await this.client.channels.fetch(interaction.channelId);
|
|
435
|
+
await handleDiscordMessage({id:randomBytes(12).toString('hex'),content:'/cli',author:{id:interaction.user.id,username:interaction.user.username,bot:false},guild:interaction.guildId?{id:interaction.guildId}:null,guildId:interaction.guildId,channelId:interaction.channelId,channel,mentions:{has:()=>true}} as any);
|
|
436
|
+
await interaction.deleteReply?.();return;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
await handler({channel:'discord',accountId:interaction.client.user?.id??'discord',senderId:interaction.user.id,chatId:interaction.channelId,chatType:isDM?'direct':'group',text,messageId:interaction.id??randomBytes(12).toString('hex'),controlMessageId:orchButton?interaction.message?.id:undefined,ts:Date.now()});
|
|
440
|
+
if(slash)await interaction.deleteReply?.();return;
|
|
441
|
+
}
|
|
404
442
|
if (!interaction.isButton?.()) return;
|
|
405
443
|
|
|
406
444
|
// `/cli` approve/deny — unlock (or reject) a pending terminal-viewer
|
|
@@ -518,7 +556,7 @@ export class DiscordModule implements ChannelModule {
|
|
|
518
556
|
const typingFileDir = path.join(this.stateDir, 'typing');
|
|
519
557
|
try {
|
|
520
558
|
fs.mkdirSync(typingFileDir, { recursive: true });
|
|
521
|
-
fs.writeFileSync(path.join(typingFileDir, channelId), '');
|
|
559
|
+
if (process.env.GATEWAY_ORCHESTRATION_ENABLED !== 'true') fs.writeFileSync(path.join(typingFileDir, channelId), '');
|
|
522
560
|
} catch {}
|
|
523
561
|
|
|
524
562
|
const inbound: InboundMessage = {
|
|
@@ -621,6 +659,8 @@ export class DiscordModule implements ChannelModule {
|
|
|
621
659
|
}
|
|
622
660
|
|
|
623
661
|
private async processTypingSignals(typingDir: string, token: string): Promise<void> {
|
|
662
|
+
// Managed activity is derived from durable Agent/Worker state; stale legacy files are not work.
|
|
663
|
+
if (process.env.GATEWAY_ORCHESTRATION_ENABLED === 'true') return;
|
|
624
664
|
let files: string[];
|
|
625
665
|
try { files = fs.readdirSync(typingDir); } catch { return; }
|
|
626
666
|
|
|
@@ -7,8 +7,10 @@
|
|
|
7
7
|
|
|
8
8
|
import { DiscordModule } from './module';
|
|
9
9
|
import type { InboundMessage } from '../../types';
|
|
10
|
+
import { ReceiverSpool } from '../receiver-spool';
|
|
10
11
|
|
|
11
12
|
const CALLBACK_URL = process.env.CLAUDE_CHANNEL_CALLBACK;
|
|
13
|
+
const spool = process.env.GATEWAY_ORCHESTRATION_INGRESS_DIR && CALLBACK_URL ? new ReceiverSpool(process.env.GATEWAY_ORCHESTRATION_INGRESS_DIR, CALLBACK_URL) : undefined;
|
|
12
14
|
if (!CALLBACK_URL) {
|
|
13
15
|
process.stderr.write('discord receiver: CLAUDE_CHANNEL_CALLBACK required\n');
|
|
14
16
|
process.exit(1);
|
|
@@ -30,6 +32,14 @@ async function postCallback(inbound: InboundMessage): Promise<void> {
|
|
|
30
32
|
if (inbound.attachmentFileId) {
|
|
31
33
|
meta['attachment_file_id'] = inbound.attachmentFileId;
|
|
32
34
|
}
|
|
35
|
+
if(inbound.attachments?.length)meta.attachments_json=JSON.stringify(inbound.attachments.map(a=>({ref:a.url,name:a.name,kind:a.kind,quoted:a.quoted})));
|
|
36
|
+
if(inbound.replyToMessageId)meta.replied_message_id=inbound.replyToMessageId;
|
|
37
|
+
if(inbound.repliedText)meta.replied_text=inbound.repliedText;
|
|
38
|
+
if(inbound.repliedSender)meta.replied_user=inbound.repliedSender;
|
|
39
|
+
if(inbound.threadId)meta.thread_ts=inbound.threadId;
|
|
40
|
+
if(inbound.attachmentKind)meta.attachment_kind=inbound.attachmentKind;
|
|
41
|
+
if(inbound.controlMessageId)meta.control_message_id=inbound.controlMessageId;
|
|
42
|
+
if (spool && !/^\/(voice|voices|tasks|stop|orch)(?:\s|$)/.test(inbound.text??'')) { spool.enqueue({ content: inbound.text ?? '', meta }); return; }
|
|
33
43
|
|
|
34
44
|
try {
|
|
35
45
|
await fetch(CALLBACK_URL!, {
|
|
@@ -108,7 +108,10 @@ export interface DiscordMessage {
|
|
|
108
108
|
parentId?: string | null;
|
|
109
109
|
};
|
|
110
110
|
createdTimestamp: number;
|
|
111
|
-
|
|
111
|
+
reference?: {messageId?:string;channelId?:string};
|
|
112
|
+
fetchReference?(): Promise<DiscordMessage>;
|
|
113
|
+
flags?: number | {has(bit:number):boolean};
|
|
114
|
+
attachments: { first(): { url: string; contentType?: string | null; name?: string } | undefined; values?(): IterableIterator<{url:string;contentType?:string|null;name?:string}> };
|
|
112
115
|
client: { user: { id: string } | null };
|
|
113
116
|
startThread(options: { name: string; autoArchiveDuration: number }): Promise<{ id: string }>;
|
|
114
117
|
}
|
|
@@ -735,7 +735,9 @@ export class ImageModule implements ToolModule {
|
|
|
735
735
|
files,
|
|
736
736
|
...(artifacts ? { artifacts } : {}),
|
|
737
737
|
...(droppedImages > 0 ? { dropped_images: droppedImages } : {}),
|
|
738
|
-
note:
|
|
738
|
+
note: (process.env.GATEWAY_ORCHESTRATION_ROLE === 'worker'
|
|
739
|
+
? 'Image saved. Call task_stage_file for each output path, then finish this task. The agent orchestration engine owns user-facing delivery.'
|
|
740
|
+
: 'Image saved. Deliver it to the user with your channel delivery tool — api_reply/reply (files: [...]), or line_image on LINE. Do NOT open/Read the file to inspect it first; attach it and answer briefly.')
|
|
739
741
|
+ (model ? ` Mention which model made it (${model}).` : '')
|
|
740
742
|
+ (artifacts ? ' To edit this image later, reference it via its artifact_ref (e.g. image: "artifact:...").' : '')
|
|
741
743
|
+ (droppedImages > 0 ? ` (${droppedImages} extra image(s) beyond the cap were not saved)` : ''),
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { test, expect } from 'bun:test';
|
|
2
|
+
import { mkdtempSync, readdirSync, rmSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { ReceiverSpool } from './receiver-spool';
|
|
6
|
+
|
|
7
|
+
test('receiver restart retains unacknowledged input and removes it only after gateway acceptance', async () => {
|
|
8
|
+
const root = mkdtempSync(join(tmpdir(), 'receiver-spool-'));
|
|
9
|
+
let fail = true;
|
|
10
|
+
const delivered: unknown[] = [];
|
|
11
|
+
const request = (async (_url: string | URL | Request, options?: RequestInit) => {
|
|
12
|
+
delivered.push(JSON.parse(String(options?.body)));
|
|
13
|
+
return new Response('', { status: fail ? 503 : 200 });
|
|
14
|
+
}) as typeof fetch;
|
|
15
|
+
let spool = new ReceiverSpool(root, 'http://fixture.invalid/channel', request);
|
|
16
|
+
try {
|
|
17
|
+
const input = { content: 'hello', meta: { chat_id: 'original', message_id: '1' } };
|
|
18
|
+
spool.enqueue(input);
|
|
19
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
20
|
+
const file = readdirSync(root).find(file => file.endsWith('.json'))!;
|
|
21
|
+
expect(JSON.parse(readFileSync(join(root, file), 'utf8'))).toEqual(input);
|
|
22
|
+
spool.close(); fail = false;
|
|
23
|
+
spool = new ReceiverSpool(root, 'http://fixture.invalid/channel', request);
|
|
24
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
25
|
+
expect(readdirSync(root)).toEqual([]);
|
|
26
|
+
expect(delivered.at(-1)).toEqual(input);
|
|
27
|
+
} finally { spool.close(); rmSync(root, { recursive: true, force: true }); }
|
|
28
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { mediaGroupKey, mergeMediaGroup, type ChannelInput } from './telegram/media-group';
|
|
2
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
3
|
+
import { mkdirSync, readdirSync, openSync, closeSync, writeFileSync, fsyncSync, renameSync, readFileSync, unlinkSync, statSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
|
|
6
|
+
/** Receiver-local handoff journal. Persist before returning to the platform
|
|
7
|
+
* client; only remove after the gateway confirms its SQLite admission. */
|
|
8
|
+
export class ReceiverSpool {
|
|
9
|
+
private active = false;
|
|
10
|
+
private readonly timer: ReturnType<typeof setInterval>;
|
|
11
|
+
constructor(private readonly directory: string, private readonly callback: string, private readonly request: typeof fetch = fetch, private readonly mediaGroupWaitMs = 2000) {
|
|
12
|
+
mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
13
|
+
this.timer = setInterval(() => { void this.flush(); }, 1000); this.timer.unref();
|
|
14
|
+
void this.flush();
|
|
15
|
+
}
|
|
16
|
+
enqueue(input: unknown): void {
|
|
17
|
+
const group=mediaGroupKey(input as ChannelInput);
|
|
18
|
+
if(group){
|
|
19
|
+
let prior:ChannelInput|undefined;
|
|
20
|
+
try{prior=JSON.parse(readFileSync(join(this.directory,`${group}.json`),'utf8'));}catch{}
|
|
21
|
+
input=mergeMediaGroup(prior,input as ChannelInput);
|
|
22
|
+
}
|
|
23
|
+
const payload = JSON.stringify(input);
|
|
24
|
+
if (Buffer.byteLength(payload) > 131072) throw new Error('Ingress payload too large');
|
|
25
|
+
if (readdirSync(this.directory).filter(file => file.endsWith('.json')).length >= 1000) throw new Error('Ingress spool full');
|
|
26
|
+
const key = group ?? createHash('sha256').update(payload).digest('hex');
|
|
27
|
+
const temporary = join(this.directory, `${key}.${randomUUID()}.tmp`);
|
|
28
|
+
const descriptor = openSync(temporary, 'wx', 0o600);
|
|
29
|
+
try { writeFileSync(descriptor, payload); fsyncSync(descriptor); } finally { closeSync(descriptor); }
|
|
30
|
+
renameSync(temporary, join(this.directory, `${key}.json`));
|
|
31
|
+
this.syncDirectory();
|
|
32
|
+
void this.flush();
|
|
33
|
+
}
|
|
34
|
+
private syncDirectory(): void {
|
|
35
|
+
const descriptor = openSync(this.directory, 'r');
|
|
36
|
+
try { fsyncSync(descriptor); } finally { closeSync(descriptor); }
|
|
37
|
+
}
|
|
38
|
+
async flush(): Promise<void> {
|
|
39
|
+
if (this.active) return;
|
|
40
|
+
this.active = true;
|
|
41
|
+
try {
|
|
42
|
+
const files = readdirSync(this.directory).filter(file => /^[a-f0-9]{64}\.json$/.test(file)).map(file => ({ file, created: statSync(join(this.directory, file)).mtimeMs })).sort((a, b) => a.created - b.created);
|
|
43
|
+
for (const { file } of files.slice(0, 100)) {
|
|
44
|
+
const location = join(this.directory, file);
|
|
45
|
+
const payload=readFileSync(location,'utf8');
|
|
46
|
+
const input=JSON.parse(payload) as ChannelInput;
|
|
47
|
+
if(mediaGroupKey(input)&&Date.now()-statSync(location).mtimeMs<this.mediaGroupWaitMs)continue;
|
|
48
|
+
const response = await this.request(this.callback, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: payload, signal: AbortSignal.timeout(10000) });
|
|
49
|
+
if (!response.ok) break;
|
|
50
|
+
if(readFileSync(location,'utf8')===payload){unlinkSync(location); this.syncDirectory();}
|
|
51
|
+
}
|
|
52
|
+
} catch { /* persisted message is retried on next tick or process restart */ }
|
|
53
|
+
finally { this.active = false; }
|
|
54
|
+
}
|
|
55
|
+
close(): void { clearInterval(this.timer); }
|
|
56
|
+
}
|
|
@@ -28,7 +28,15 @@ export class ShareFileModule implements ToolModule {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
getTools(): McpToolDefinition[] {
|
|
31
|
-
return shareFileToolDefs;
|
|
31
|
+
if (process.env.GATEWAY_ORCHESTRATION_ROLE !== 'worker') return shareFileToolDefs;
|
|
32
|
+
return shareFileToolDefs.map(tool => ({
|
|
33
|
+
...tool,
|
|
34
|
+
description: tool.description + ' In a task, use the original absolute file path in the active task workspace, a supplied input attachment or this session’s media directory. The gateway stages it automatically; do not copy it to the agent-wide media root. Describe this as creating a link (Thai: สร้างลิงก์).',
|
|
35
|
+
inputSchema: { ...shareFileInputSchema, properties: { ...shareFileInputSchema.properties,
|
|
36
|
+
path: { type: 'string', description: 'Original absolute file path in the active task workspace or session media, or artifact:<id>.' },
|
|
37
|
+
paths: { type: 'array', items: { type: 'string' }, description: 'Up to 5 authorized absolute file paths or artifact refs.' },
|
|
38
|
+
} },
|
|
39
|
+
}));
|
|
32
40
|
}
|
|
33
41
|
|
|
34
42
|
async handleTool(name: string, args: Record<string, unknown>): Promise<McpToolResult> {
|
|
@@ -71,6 +71,7 @@ export class ShareClientError extends Error {
|
|
|
71
71
|
* is absent the private mint endpoint is not mounted and calls fail closed.
|
|
72
72
|
*/
|
|
73
73
|
export function shareBridgeEnabled(): boolean {
|
|
74
|
+
if (process.env.GATEWAY_ORCHESTRATION_ROLE === 'worker' && process.env.GATEWAY_ORCHESTRATION_MEDIA === 'true' && process.env.GATEWAY_ORCHESTRATION_TICKET_FILE) return true;
|
|
74
75
|
return (
|
|
75
76
|
!!process.env.GATEWAY_API_URL &&
|
|
76
77
|
!!process.env.GATEWAY_API_KEY &&
|
|
@@ -88,6 +89,24 @@ async function callGateway(
|
|
|
88
89
|
pathname: string,
|
|
89
90
|
body?: Record<string, unknown>,
|
|
90
91
|
): Promise<{ status: number; json: Record<string, unknown> }> {
|
|
92
|
+
if (process.env.GATEWAY_ORCHESTRATION_ROLE === 'worker' && process.env.GATEWAY_ORCHESTRATION_TICKET_FILE) {
|
|
93
|
+
const { readFile } = await import('node:fs/promises');
|
|
94
|
+
const ticket = JSON.parse(await readFile(process.env.GATEWAY_ORCHESTRATION_TICKET_FILE, 'utf8'));
|
|
95
|
+
const response = await fetch(ticket.url, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${ticket.token}` },
|
|
96
|
+
body: JSON.stringify({ tool: 'task_share_call', action_id: crypto.randomUUID(), args: { method, pathname, body } }), signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS) });
|
|
97
|
+
if (!response.ok) {
|
|
98
|
+
const failure = await response.json().catch(() => ({})) as Record<string, unknown> | null;
|
|
99
|
+
// The bridge uses {error: CODE}; retain that cause instead of treating
|
|
100
|
+
// path validation, stale attempts and unavailable configuration alike.
|
|
101
|
+
const code = typeof failure?.error === 'string' && /^[A-Z][A-Z0-9_]{0,79}$/.test(failure.error)
|
|
102
|
+
? failure.error : 'share_scope_denied';
|
|
103
|
+
const error = code === 'ARTIFACT_PATH_DENIED'
|
|
104
|
+
? 'File is outside this task scope. Use the original file’s absolute path in the active task workspace, a supplied input attachment, or this session’s media directory. Do not copy it to the agent-wide media root. The gateway stages authorized files automatically.'
|
|
105
|
+
: code === 'share_scope_denied' ? 'Scoped share request denied' : code;
|
|
106
|
+
return { status: response.status, json: { error, code } };
|
|
107
|
+
}
|
|
108
|
+
return await response.json() as { status: number; json: Record<string, unknown> };
|
|
109
|
+
}
|
|
91
110
|
const res = await fetch(`${apiBase()}${pathname}`, {
|
|
92
111
|
method,
|
|
93
112
|
headers: {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// MCP sources are published, src/ is not. Share the compiled schema so an
|
|
2
|
+
// installed package has the same inventory as a development checkout.
|
|
3
|
+
import { WORKFLOW_SCHEMA } from '../../../dist/orchestration/workflow.js';
|
|
4
|
+
import type { McpToolDefinition, McpToolResult } from '../../types';
|
|
5
|
+
|
|
6
|
+
const schema = (properties: Record<string, unknown>, required: string[]) => ({ type: 'object', properties, required, additionalProperties: false });
|
|
7
|
+
const text = { type: 'string' };
|
|
8
|
+
export const AGENT_TASK_TOOLS: McpToolDefinition[] = [
|
|
9
|
+
{ name: 'capabilities_list', description: 'Discover all capabilities this agent can offer: installed/shared/native skills, gateway MCP tools and enabled connector/plugin MCP tools, including tools executed only by workers. Read metadata only; never executes a tool or grants permissions. Use query to find relevant tools before assigning work. Follow next_offset until null when the user asks for the complete list, passing catalog_version from the first page. On CAPABILITY_CATALOG_CHANGED restart from offset 0. Report unavailable discovery honestly; do not confuse your own restricted callable tools with the capabilities of the agent as a whole.', inputSchema: schema({query:text,catalog_version:text,offset:{type:'integer',minimum:0}},[]) },
|
|
10
|
+
{ name: 'conversation_intake', description: 'Prepare executable work, incomplete materials, or an amendment to an existing task. Do not call this for greetings, introductions, casual conversation or questions you can answer directly; answer those normally once. When semantic intake is enabled, acknowledge before work mutations. Incomplete material is inspected now; the gateway asks the supplied clarification after the configured silence interval, not on every item.',
|
|
11
|
+
inputSchema: schema({mode:{type:'string',enum:['ready','wait','update']},acknowledgement:{type:'string',description:'A brief contextual message addressed directly to the user about the work you will do. Immediately displayed and spoken aloud. Never include private classification, reasoning, or instructions to yourself.'},preparation:text,clarification:text,task_id:text},['mode']) },
|
|
12
|
+
{ name: 'task_spawn', description: 'Durably queue a task for an independent worker. Returns after commit without waiting for worker startup or completion.',
|
|
13
|
+
inputSchema: schema({ title: text, instructions: text, target_profile: text, spoken_acknowledgement: { type: 'string', description: 'Required for live voice: a short natural response in the user language explaining the specific work you are about to do. Describe the specific user request as your own task, in the voice of your existing persona; do not announce handing it to a worker or use a generic acknowledgement. Speak as the person doing the work; avoid Thai delegation phrases such as สั่งเช็คแล้ว, สั่งไปแล้ว or ส่งให้ตรวจแล้ว. Describe queued work as accepted/to do next, and only say it is running when that state is confirmed. Do not claim completion. The gateway manages playback and channel text-before-voice ordering.' }, skill_name: { type: 'string', description: 'Exact installed gateway or discovered Claude Code runtime skill name for skill-worker. Native skills are invoked directly by the CLI; shared/workspace skills are supplied with their resources. Never supply a file path.' }, skill_args: { type: 'string', description: 'Arguments for the installed skill; required with skill_name.' }, continue_task_id: { type: 'string', description: 'Prior task ID in this conversation for related follow-up work. Reuses its worker session when compatible; waits for success by default. Queue every authorized dependent step now, using each returned task ID for the next step. Omit for independent work.' }, continuation_policy: { type: 'string', enum: ['after_success', 'after_terminal'], description: 'With continue_task_id: after_success (default) starts only after the predecessor succeeds; otherwise fails without executing. Use after_terminal only for explicitly authorized recovery/inspection that must run after failure or cancellation.' }, context_refs: { type: 'array', items: text, description: 'Only orchestration input IDs, authorized attachment refs or task artifact IDs. Put project filenames in instructions instead.' } }, ['title', 'instructions', 'target_profile']) },
|
|
14
|
+
{ name: 'task_status', description: 'Read the task index in this conversation without waiting. Pass task_id to retrieve the complete stored result and evidence before discussing an earlier task. An index entry is not a partial worker report.', inputSchema: schema({ task_id: text }, []) },
|
|
15
|
+
{ name: 'task_cancel', description: 'Request cancellation, including needs_reconciliation cleanup. cancel_requested is not proof of termination. Existing files are retained. Set replaced_by_task_id only for a known replacement task, never infer from similar titles.', inputSchema: schema({ task_id: text, replaced_by_task_id: text }, ['task_id']) },
|
|
16
|
+
{ name: 'task_update', description: 'Accept a revised task instruction. applied_revision changes only when the worker accepts it.', inputSchema: schema({ task_id: text, expected_revision: { type: 'integer', minimum: 1 }, instruction: text, mode: { type: 'string', enum: ['when_ready', 'interrupt_and_resume'] } }, ['task_id', 'expected_revision', 'instruction', 'mode']) },
|
|
17
|
+
{ name: 'task_answer', description: 'Answer the matching pending question on a task.', inputSchema: schema({ task_id: text, question_id: text, answer: text }, ['task_id', 'question_id', 'answer']) },
|
|
18
|
+
];
|
|
19
|
+
export const WORKER_REPORT_TOOLS: McpToolDefinition[] = [
|
|
20
|
+
{ name: 'task_memory_append', description: 'Append an explicitly requested memory note for a channel task. API tasks cannot write memory. Files are restricted to MEMORY.md, USER.md, or memory/<name>.md. Retains existing content and deduplicates retries.', inputSchema: schema({ note: text, path: text }, ['note']) },
|
|
21
|
+
{ name: 'task_stage_file', description: 'Stage a finished image or document for the user. The orchestration attaches it to the next completed agent response after this task succeeds, using the original destination. This tool does not send to a channel. Call once per output file. For an image returned by an MCP tool (such as a remote browser screenshot), omit path to use the latest captured image in this attempt, or pass source_tool_call_id to select its tool call. The gateway saves the actual image bytes; never invent a screenshot filename. For an existing local file supply path.', inputSchema: schema({ path: text, source_tool_call_id: text, caption: text }, []) },
|
|
22
|
+
{ name: 'task_report_progress', description: 'Report factual progress internally. At phase changes include a checkpoint with phase, evidenceVersion, checks, findings and nextAction. This does not send a user message.', inputSchema: schema({ text, checkpoint: WORKFLOW_SCHEMA }, ['text']) },
|
|
23
|
+
{ name: 'task_request_input', description: 'Ask the user for information required by your task, then end this turn immediately.', inputSchema: schema({ question: text }, ['question']) },
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
export async function callTaskBridge(tool: string, args: Record<string, unknown>, requestId: string, signal: AbortSignal): Promise<McpToolResult> {
|
|
27
|
+
// Rotated by the gateway at each decision/attempt boundary. A loaded token is
|
|
28
|
+
// immutable for this request; late requests cannot borrow the next decision.
|
|
29
|
+
const { readFile } = await import('node:fs/promises');
|
|
30
|
+
const scope = JSON.parse(await readFile(process.env.GATEWAY_ORCHESTRATION_TICKET_FILE!, 'utf8')) as { url: string; token: string };
|
|
31
|
+
const response = await fetch(scope.url, { method: 'POST', signal, headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${scope.token}` },
|
|
32
|
+
body: JSON.stringify({ tool, args, action_id: requestId }) });
|
|
33
|
+
const body = await response.text();
|
|
34
|
+
return { content: [{ type: 'text', text: body }], ...(response.ok ? {} : { isError: true }) };
|
|
35
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
export type ChannelInput = {content:string;meta:Record<string,string>};
|
|
3
|
+
export function mediaGroupKey(input: ChannelInput): string | undefined {
|
|
4
|
+
const m=input?.meta;
|
|
5
|
+
return m?.media_group_id ? createHash('sha256').update(JSON.stringify([m.chat_id,m.user_id,m.message_thread_id??'',m.media_group_id])).digest('hex') : undefined;
|
|
6
|
+
}
|
|
7
|
+
/** Telegram albums arrive as separate updates. Keep the native group intact. */
|
|
8
|
+
export function mergeMediaGroup(prior:ChannelInput|undefined,input:ChannelInput):ChannelInput {
|
|
9
|
+
const ids:string[]=prior?JSON.parse(prior.meta.message_ids_json):[];
|
|
10
|
+
if(ids.includes(input.meta.message_id))return prior!;
|
|
11
|
+
if(ids.length>=10)throw Error('Telegram media group exceeds 10 items');
|
|
12
|
+
const parts:Array<{id:string;caption:string;ref?:string;path?:string;name?:string}> = prior?JSON.parse(prior.meta.media_group_parts_json):[];
|
|
13
|
+
parts.push({id:input.meta.message_id,caption:input.meta.media_caption??'',ref:input.meta.attachment_file_id,path:input.meta.image_path,name:input.meta.attachment_name});
|
|
14
|
+
parts.sort((a,b)=>Number(a.id)-Number(b.id));
|
|
15
|
+
const meta:Record<string,string>={...(prior?.meta??input.meta),media_group_id:input.meta.media_group_id,message_id:parts[0]!.id,
|
|
16
|
+
message_ids_json:JSON.stringify(parts.map(p=>p.id)),media_group_parts_json:JSON.stringify(parts),
|
|
17
|
+
attachments_json:JSON.stringify(parts.map(({ref,path,name})=>({ref,path,name})))};
|
|
18
|
+
// Album files must not turn a mixed album into a single-file voice-note turn.
|
|
19
|
+
delete meta.attachment_file_id;delete meta.image_path;delete meta.attachment_kind;
|
|
20
|
+
return {content:parts.map(p=>p.caption).filter(Boolean).join('\n\n')||'[Media album attached]',meta};
|
|
21
|
+
}
|