@xopcai/xopc 0.0.105 → 0.0.107
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/dashscope/xopc.extension.json +7 -2
- package/dist/extensions/fal/xopc.extension.json +7 -2
- package/dist/extensions/feishu/src/adapters/gateway-setup.js +22 -26
- package/dist/extensions/feishu/src/adapters/gateway-setup.js.map +1 -1
- package/dist/extensions/feishu/src/directory/directory-adapter.js +1 -1
- package/dist/extensions/feishu/src/directory/directory-adapter.js.map +1 -1
- package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
- package/dist/extensions/feishu/src/outbound/outbound-adapter.js +4 -3
- package/dist/extensions/feishu/src/outbound/outbound-adapter.js.map +1 -1
- package/dist/extensions/feishu/src/plugin.d.ts +6 -3
- package/dist/extensions/feishu/src/plugin.js +59 -40
- package/dist/extensions/feishu/src/plugin.js.map +1 -1
- package/dist/extensions/feishu/src/streaming/streaming-adapter.js +20 -16
- package/dist/extensions/feishu/src/streaming/streaming-adapter.js.map +1 -1
- package/dist/extensions/feishu/src/transport/socket-mode/monitor.js +1 -1
- package/dist/extensions/feishu/src/transport/webhook/monitor.js +1 -1
- package/dist/extensions/feishu/src/workflow-progress.d.ts +1 -1
- package/dist/extensions/feishu/src/workflow-progress.js +3 -3
- package/dist/extensions/feishu/src/workflow-progress.js.map +1 -1
- package/dist/extensions/feishu/xopc.extension.json +458 -26
- package/dist/extensions/google/xopc.extension.json +7 -2
- package/dist/extensions/minimax/xopc.extension.json +8 -2
- package/dist/extensions/openai/xopc.extension.json +7 -2
- package/dist/extensions/telegram/src/adapters/gateway-setup.js +8 -6
- package/dist/extensions/telegram/src/adapters/gateway-setup.js.map +1 -1
- package/dist/extensions/telegram/src/adapters/streaming-adapter.js +1 -1
- package/dist/extensions/telegram/src/command-handler.d.ts +1 -1
- package/dist/extensions/telegram/src/command-handler.js +11 -9
- package/dist/extensions/telegram/src/command-handler.js.map +1 -1
- package/dist/extensions/telegram/src/inbound-processor.js +2 -3
- package/dist/extensions/telegram/src/inbound-processor.js.map +1 -1
- package/dist/extensions/telegram/src/plugin.d.ts +1 -0
- package/dist/extensions/telegram/src/plugin.js +7 -7
- package/dist/extensions/telegram/src/plugin.js.map +1 -1
- package/dist/extensions/telegram/src/routing-integration.js +2 -2
- package/dist/extensions/telegram/src/update-offset-store.js +1 -1
- package/dist/extensions/telegram/src/workflow-progress.d.ts +1 -1
- package/dist/extensions/telegram/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/src/workflow-progress.js.map +1 -1
- package/dist/extensions/telegram/xopc.extension.json +10 -2
- package/dist/extensions/weixin/src/api/api.js +2 -2
- package/dist/extensions/weixin/src/auth/accounts.js +1 -1
- package/dist/extensions/weixin/src/cdn/upload.js +1 -1
- package/dist/extensions/weixin/src/cli/gateway-qr-login.d.ts +4 -0
- package/dist/extensions/weixin/src/cli/gateway-qr-login.js +34 -5
- package/dist/extensions/weixin/src/cli/gateway-qr-login.js.map +1 -1
- package/dist/extensions/weixin/src/cli/qr-login.js +4 -3
- package/dist/extensions/weixin/src/cli/qr-login.js.map +1 -1
- package/dist/extensions/weixin/src/media/data-url.js +1 -1
- package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
- package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
- package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
- package/dist/extensions/weixin/src/plugin.d.ts +1 -0
- package/dist/extensions/weixin/src/plugin.js +8 -7
- package/dist/extensions/weixin/src/plugin.js.map +1 -1
- package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
- package/dist/extensions/weixin/src/workflow-progress.d.ts +1 -1
- package/dist/extensions/weixin/src/workflow-progress.js +1 -1
- package/dist/extensions/weixin/src/workflow-progress.js.map +1 -1
- package/dist/extensions/weixin/xopc.extension.json +57 -14
- package/dist/gateway/static/root/apple-touch-icon.png +0 -0
- package/dist/gateway/static/root/assets/agents-BXg2_mE4.js +78 -0
- package/dist/gateway/static/root/assets/apps-page-CJqQ-7Ss.js +1 -0
- package/dist/gateway/static/root/assets/channels-settings-DvMZ6NAd.js +1 -0
- package/dist/gateway/static/root/assets/cron-page-BPBlvSl5.js +1 -0
- package/dist/gateway/static/root/assets/{dist-DJDkNhu5.js → dist-CZh0c-s8.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-DI1XJTJi.js → extension-debug-page-DyJQR0SR.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-SuafGTT_.js → extension-page-CDTuUr9B.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-cKmGax9v.js → extension-settings-page-DszZ8zHD.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-CkvRO30i.js → fetch-CFdKBnE6.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-BkKyRDrF.js → gateway-startup-retry-DdngdObI.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-CRiDcxtt.js → heartbeat-config-api-U10wnPdc.js} +1 -1
- package/dist/gateway/static/root/assets/index-DBc-bVOQ.js +4845 -0
- package/dist/gateway/static/root/assets/index-DI5_GsZt.css +1 -0
- package/dist/gateway/static/root/assets/{logs-page-DM8o5-Bm.js → logs-page-B6js8Bfi.js} +2 -2
- package/dist/gateway/static/root/assets/{note-detail-page-j53jtvq9.js → note-detail-page-DFzAXR35.js} +4 -4
- package/dist/gateway/static/root/assets/{note-time-Ck2H2Qpw.js → note-time-DOiSU-10.js} +1 -1
- package/dist/gateway/static/root/assets/notes-page-DAuZJMT8.js +1 -0
- package/dist/gateway/static/root/assets/{schema-form-BvmGNxiJ.js → schema-form-zM36dvbY.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-CAsV03BY.js +1 -0
- package/dist/gateway/static/root/assets/{settings-advanced-gate-DRdayl8P.js → settings-advanced-gate-BCvObK1y.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-BlIYg2gZ.js → settings-form-section-Bvl-RInc.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-DuCJDd74.js +3 -0
- package/dist/gateway/static/root/assets/{share-preview-page-BlT6Akvk.js → share-preview-page-rpL4DDTO.js} +1 -1
- package/dist/gateway/static/root/assets/skills-page--BioR9J4.js +2 -0
- package/dist/gateway/static/root/assets/{theme-store-DYgVdRB4.js → theme-store-BZozwAeK.js} +1 -1
- package/dist/gateway/static/root/assets/url-DQRqHuL-.js +3 -0
- package/dist/gateway/static/root/assets/voice-api-key-field-D2RJaoj_.js +1 -0
- package/dist/gateway/static/root/assets/{workflow-page.utils-_sjXCMvi.js → workflow-page.utils-BxacHYen.js} +1 -1
- package/dist/gateway/static/root/assets/workflows-page-B1B-est-.js +18 -0
- package/dist/gateway/static/root/favicon-16.png +0 -0
- package/dist/gateway/static/root/favicon-32.png +0 -0
- package/dist/gateway/static/root/favicon.ico +0 -0
- package/dist/gateway/static/root/favicon.svg +18 -0
- package/dist/gateway/static/root/index.html +11 -10
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.js +7 -7
- package/dist/src/agent/agent-scope.js +1 -1
- package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
- package/dist/src/agent/context/workspace-seed.js +2 -2
- package/dist/src/agent/context/workspace-state.js +1 -1
- package/dist/src/agent/goals/goal-run-store.js +4 -4
- package/dist/src/agent/goals/persistent-goal-service.js +1 -1
- package/dist/src/agent/goals/post-turn.js +2 -2
- package/dist/src/agent/image/load-image-media.js +2 -2
- package/dist/src/agent/ipc/bus.js +1 -1
- package/dist/src/agent/ipc/inbox.js +2 -2
- package/dist/src/agent/ipc/socket.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-config.js +16 -8
- package/dist/src/agent/mcp/bundle-mcp-config.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-materialize.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-policy.js +2 -2
- package/dist/src/agent/mcp/bundle-mcp-policy.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-runtime.js +2 -2
- package/dist/src/agent/mcp/mcp-http.js +1 -1
- package/dist/src/agent/mcp/mcp-http.js.map +1 -1
- package/dist/src/agent/mcp/mcp-transport-config.js +3 -7
- package/dist/src/agent/mcp/mcp-transport-config.js.map +1 -1
- package/dist/src/agent/mcp/mcp-transport.js +1 -1
- package/dist/src/agent/memory/builtin-memory-store.js +1 -1
- package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
- package/dist/src/agent/memory/dreaming/events.js +1 -1
- package/dist/src/agent/memory/dreaming/last-run.js +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
- package/dist/src/agent/memory/dreaming/preview.js +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
- package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
- package/dist/src/agent/memory/dreaming/utils.js +1 -1
- package/dist/src/agent/memory/memory-flush.js +1 -1
- package/dist/src/agent/memory/plugin-discovery.js +1 -1
- package/dist/src/agent/models/manager.js +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
- package/dist/src/agent/reply/post-compaction-context.js +1 -1
- package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
- package/dist/src/agent/sandbox/path-policy.js +2 -2
- package/dist/src/agent/service.js +4 -4
- package/dist/src/agent/session/session-inspector.js +1 -1
- package/dist/src/agent/skills/config.js +1 -1
- package/dist/src/agent/skills/hub-hash.js +2 -2
- package/dist/src/agent/skills/hub-lock.js +1 -1
- package/dist/src/agent/skills/hub-pull.js +2 -2
- package/dist/src/agent/skills/index.js +1 -1
- package/dist/src/agent/skills/managed-store.js +1 -1
- package/dist/src/agent/skills/marketplace/adapters/store/store-api-client.d.ts +4 -0
- package/dist/src/agent/skills/marketplace/adapters/store/store-api-client.js +4 -2
- package/dist/src/agent/skills/marketplace/adapters/store/store-api-client.js.map +1 -1
- package/dist/src/agent/skills/scanner.js +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js +1 -1
- package/dist/src/agent/skills/skill-manager.js +1 -1
- package/dist/src/agent/starter-agents.d.ts +19 -0
- package/dist/src/agent/starter-agents.js +190 -0
- package/dist/src/agent/starter-agents.js.map +1 -0
- package/dist/src/agent/tools/dreaming-tool.js +1 -1
- package/dist/src/agent/tools/factory.js +1 -1
- package/dist/src/agent/tools/image-generate-tool.js +1 -1
- package/dist/src/agent/tools/send-media.js +1 -1
- package/dist/src/agent/tools/skill-manage-tool.js +1 -1
- package/dist/src/agent/tools/workflow-tool.js +1 -1
- package/dist/src/agent/tools/write.js +1 -1
- package/dist/src/agent/workflow/catalog.js +1 -1
- package/dist/src/agent/workflow/index.js +2 -1
- package/dist/src/agent/workflow/runtime.d.ts +2 -2
- package/dist/src/agent/workflow/runtime.js +50 -29
- package/dist/src/agent/workflow/runtime.js.map +1 -1
- package/dist/src/agent/workflow/snapshot-empty.d.ts +2 -0
- package/dist/src/agent/workflow/snapshot-empty.js +19 -0
- package/dist/src/agent/workflow/snapshot-empty.js.map +1 -0
- package/dist/src/agent/workflow/snapshot.js +1 -1
- package/dist/src/agent/workflow/snapshot.js.map +1 -1
- package/dist/src/agent/workflow/types.d.ts +11 -0
- package/dist/src/auth/credentials.js +3 -3
- package/dist/src/auth/profiles/store.js +2 -2
- package/dist/src/auth/sync-provider-auth.js +1 -1
- package/dist/src/browser/cache-dir-policy.js +1 -1
- package/dist/src/browser/cdp-local-launcher.js +2 -2
- package/dist/src/browser/providers/browser-ext-install.js +3 -3
- package/dist/src/browser/providers/cloakbrowser.js +4 -4
- package/dist/src/browser/providers/playwright-doctor.js +1 -1
- package/dist/src/browser/stealth.js +1 -1
- package/dist/src/channels/catalog/channel-catalog-service.js +13 -0
- package/dist/src/channels/catalog/channel-catalog-service.js.map +1 -1
- package/dist/src/channels/outbound/persist-store.js +1 -1
- package/dist/src/channels/pairing/allow-from-file.js +1 -1
- package/dist/src/channels/pairing/pairing-store.js +2 -2
- package/dist/src/channels/plugins/types.adapters.d.ts +2 -0
- package/dist/src/chat-commands/agent-edit.js +2 -2
- package/dist/src/chat-commands/builtins/config.js +2 -2
- package/dist/src/chat-commands/context.js +1 -1
- package/dist/src/cli/commands/config.js +1 -1
- package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
- package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
- package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
- package/dist/src/cli/commands/extension-create.d.ts +2 -0
- package/dist/src/cli/commands/extension-create.js +165 -0
- package/dist/src/cli/commands/extension-create.js.map +1 -0
- package/dist/src/cli/commands/extension-dev.js +1 -3
- package/dist/src/cli/commands/extension-dev.js.map +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +105 -81
- package/dist/src/cli/commands/extension-marketplace.js.map +1 -1
- package/dist/src/cli/commands/extension-pack.d.ts +13 -0
- package/dist/src/cli/commands/extension-pack.js +159 -91
- package/dist/src/cli/commands/extension-pack.js.map +1 -1
- package/dist/src/cli/commands/extension.d.ts +2 -0
- package/dist/src/cli/commands/extension.js +375 -3
- package/dist/src/cli/commands/extension.js.map +1 -1
- package/dist/src/cli/commands/gateway/logs.js +1 -1
- package/dist/src/cli/commands/gateway/run-foreground.js +1 -2
- package/dist/src/cli/commands/gateway/run-foreground.js.map +1 -1
- package/dist/src/cli/commands/image.js +1 -1
- package/dist/src/cli/commands/init.js +3 -3
- package/dist/src/cli/commands/models.js +1 -1
- package/dist/src/cli/commands/onboard/model.js +2 -2
- package/dist/src/cli/commands/onboard.js +0 -2
- package/dist/src/cli/commands/onboard.js.map +1 -1
- package/dist/src/cli/commands/setup.js +0 -2
- package/dist/src/cli/commands/setup.js.map +1 -1
- package/dist/src/cli/utils/init-workspace-core.js +10 -7
- package/dist/src/cli/utils/init-workspace-core.js.map +1 -1
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/config/agent-typed-models.js +1 -1
- package/dist/src/config/gateway-bind.js +1 -1
- package/dist/src/config/index.js +5 -5
- package/dist/src/config/loader.js +2 -2
- package/dist/src/config/models-json.js +2 -2
- package/dist/src/config/paths-state.js +1 -1
- package/dist/src/config/paths.d.ts +2 -2
- package/dist/src/config/paths.js +6 -5
- package/dist/src/config/paths.js.map +1 -1
- package/dist/src/config/profile.js +2 -2
- package/dist/src/config/schema.d.ts +2 -0
- package/dist/src/config/schema.js +3 -1
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/config/workspace-path.js +1 -1
- package/dist/src/connectors/health.js +1 -1
- package/dist/src/connectors/install.js +1 -1
- package/dist/src/cron/executor.js +2 -2
- package/dist/src/cron/persistence.js +1 -1
- package/dist/src/daemon/constants.js +1 -1
- package/dist/src/daemon/install-plan.js +2 -2
- package/dist/src/daemon/launchd.js +2 -2
- package/dist/src/daemon/schtasks.js +2 -2
- package/dist/src/daemon/systemd.js +2 -2
- package/dist/src/extensions/api.d.ts +4 -2
- package/dist/src/extensions/api.js +31 -12
- package/dist/src/extensions/api.js.map +1 -1
- package/dist/src/extensions/bundle-mcp.js +1 -1
- package/dist/src/extensions/discover-extensions.js +2 -1
- package/dist/src/extensions/discover-extensions.js.map +1 -1
- package/dist/src/extensions/health.js +1 -1
- package/dist/src/extensions/install.d.ts +1 -0
- package/dist/src/extensions/install.js +51 -8
- package/dist/src/extensions/install.js.map +1 -1
- package/dist/src/extensions/loader.d.ts +0 -4
- package/dist/src/extensions/loader.js +55 -88
- package/dist/src/extensions/loader.js.map +1 -1
- package/dist/src/extensions/lockfile.d.ts +9 -1
- package/dist/src/extensions/lockfile.js +2 -2
- package/dist/src/extensions/lockfile.js.map +1 -1
- package/dist/src/extensions/normalize-manifest.js +20 -4
- package/dist/src/extensions/normalize-manifest.js.map +1 -1
- package/dist/src/extensions/package-contract.d.ts +12 -0
- package/dist/src/extensions/package-contract.js +59 -0
- package/dist/src/extensions/package-contract.js.map +1 -0
- package/dist/src/extensions/sdk/core.d.ts +1 -1
- package/dist/src/extensions/sdk/index.d.ts +1 -1
- package/dist/src/extensions/sdk/index.js.map +1 -1
- package/dist/src/extensions/types/manifest.d.ts +15 -0
- package/dist/src/extensions/update.js +1 -1
- package/dist/src/gateway/agents-admin.d.ts +0 -8
- package/dist/src/gateway/agents-admin.js +3 -28
- package/dist/src/gateway/agents-admin.js.map +1 -1
- package/dist/src/gateway/file-path-classifier.js +2 -2
- package/dist/src/gateway/heartbeat/service.js +1 -1
- package/dist/src/gateway/hono/lib/config-payload.js +1 -1
- package/dist/src/gateway/hono/lib/extension-store.js +2 -2
- package/dist/src/gateway/hono/lib/static-ui.js +2 -2
- package/dist/src/gateway/hono/oauth-async.js +1 -1
- package/dist/src/gateway/hono/oauth.js +1 -1
- package/dist/src/gateway/hono/routes/agents.js +2 -56
- package/dist/src/gateway/hono/routes/agents.js.map +1 -1
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
- package/dist/src/gateway/hono/routes/channels.js +10 -1
- package/dist/src/gateway/hono/routes/channels.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
- package/dist/src/gateway/hono/routes/dreaming.js +1 -1
- package/dist/src/gateway/hono/routes/host-fs.js +2 -2
- package/dist/src/gateway/hono/routes/mcp.js +1 -1
- package/dist/src/gateway/hono/routes/models.js +1 -1
- package/dist/src/gateway/hono/routes/shares.js +1 -1
- package/dist/src/gateway/hono/routes/workflows.js +130 -0
- package/dist/src/gateway/hono/routes/workflows.js.map +1 -1
- package/dist/src/gateway/hono/routes/workspace.js +2 -2
- package/dist/src/gateway/lock.js +3 -3
- package/dist/src/gateway/ports.js +1 -1
- package/dist/src/gateway/service/agent-runner.js +2 -2
- package/dist/src/gateway/service/marketplace-service.js +2 -2
- package/dist/src/gateway/service.d.ts +2 -0
- package/dist/src/gateway/service.js +45 -1
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/workspace-fs-file-list.js +1 -1
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/infra/brew.js +1 -1
- package/dist/src/infra/package-json.js +1 -1
- package/dist/src/infra/package-update-steps.js +1 -1
- package/dist/src/infra/path-env.js +2 -2
- package/dist/src/infra/restart.js +2 -2
- package/dist/src/infra/stable-node-path.js +1 -1
- package/dist/src/infra/update-check.js +1 -1
- package/dist/src/infra/update-global.js +1 -1
- package/dist/src/infra/update-lock.js +3 -3
- package/dist/src/infra/update-runner.js +1 -1
- package/dist/src/infra/update-startup.js +2 -2
- package/dist/src/infra/write-file-atomic.js +2 -2
- package/dist/src/media/store.js +1 -1
- package/dist/src/notes/agent-context.d.ts +12 -4
- package/dist/src/notes/agent-context.js +1 -1
- package/dist/src/notes/agent-context.js.map +1 -1
- package/dist/src/notes/store.js +2 -2
- package/dist/src/project-trust/trust-store.js +2 -2
- package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
- package/dist/src/providers/index.js +2 -2
- package/dist/src/providers/model-registry.js +1 -1
- package/dist/src/session/init-session-turn.js +2 -2
- package/dist/src/session/resolve-session.js +3 -3
- package/dist/src/session/session-title.js +2 -2
- package/dist/src/session/store.js +2 -2
- package/dist/src/share/share-auto.js +2 -2
- package/dist/src/share/share-store.js +3 -3
- package/dist/src/share/share-thumbnail.js +2 -2
- package/dist/src/share/share-zip.js +1 -1
- package/dist/src/share/site-share-store.js +3 -3
- package/dist/src/share/site-static-serve.js +1 -1
- package/dist/src/storage/sqlite/connection.js +2 -2
- package/dist/src/storage/sqlite/memory-index-repository.js +2 -2
- package/dist/src/storage/sqlite/migrations/discover.js +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/tui/backends/embedded-backend.js +1 -8
- package/dist/src/tui/backends/embedded-backend.js.map +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.js +0 -7
- package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
- package/dist/src/tui/clipboard-image.js +3 -3
- package/dist/src/tui/theme-manager.js +1 -1
- package/dist/src/tui/tui-backend.d.ts +0 -1
- package/dist/src/tui/tui-command-formatters.js +3 -3
- package/dist/src/tui/tui-commands.js +3 -3
- package/dist/src/tui/tui-commands.js.map +1 -1
- package/dist/src/tui/tui-keybindings-file.js +1 -1
- package/dist/src/tui/tui-picker-overlay.js +1 -1
- package/dist/src/tui/tui-picker-overlay.js.map +1 -1
- package/dist/src/tui/tui-scoped-models.js +2 -2
- package/dist/src/tui/tui-settings.js +1 -1
- package/dist/src/tui/tui-startup-resources.js +2 -2
- package/dist/src/tui/tui.js +5 -5
- package/dist/src/tunnel/frpc-binary.js +3 -3
- package/dist/src/tunnel/frpc-config.js +1 -1
- package/dist/src/tunnel/frpc-extract.js +1 -1
- package/dist/src/tunnel/tunnel-state.js +1 -1
- package/dist/src/utils/logger/audit.js +1 -1
- package/dist/src/utils/logger/log-store.js +1 -1
- package/dist/src/utils/logger/rotation.js +1 -1
- package/dist/src/voice/stt/availability.d.ts +6 -0
- package/dist/src/voice/stt/availability.js +14 -6
- package/dist/src/voice/stt/availability.js.map +1 -1
- package/dist/src/voice/stt/index.js +2 -1
- package/dist/src/voice/stt/index.js.map +1 -1
- package/dist/src/voice/stt/mention.d.ts +2 -0
- package/dist/src/voice/stt/mention.js +20 -0
- package/dist/src/voice/stt/mention.js.map +1 -0
- package/dist/src/voice/stt/preflight.d.ts +1 -4
- package/dist/src/voice/stt/preflight.js +1 -18
- package/dist/src/voice/stt/preflight.js.map +1 -1
- package/dist/src/voice/tts/audio.js +1 -1
- package/dist/src/voice/tts/providers/edge-speech.js +2 -2
- package/dist/src/workflows/domain/definition-utils.d.ts +1 -0
- package/dist/src/workflows/domain/definition-utils.js +32 -2
- package/dist/src/workflows/domain/definition-utils.js.map +1 -1
- package/dist/src/workflows/domain/definition.d.ts +2 -0
- package/dist/src/workflows/domain/event.d.ts +2 -1
- package/dist/src/workflows/domain/index.d.ts +1 -0
- package/dist/src/workflows/domain/index.js +3 -2
- package/dist/src/workflows/domain/run.d.ts +27 -1
- package/dist/src/workflows/domain/run.js.map +1 -1
- package/dist/src/workflows/domain/schema-validation.d.ts +8 -0
- package/dist/src/workflows/domain/schema-validation.js +28 -0
- package/dist/src/workflows/domain/schema-validation.js.map +1 -0
- package/dist/src/workflows/draft/index.d.ts +3 -0
- package/dist/src/workflows/draft/index.js +3 -0
- package/dist/src/workflows/draft/workflow-draft-prompt.d.ts +23 -0
- package/dist/src/workflows/draft/workflow-draft-prompt.js +98 -0
- package/dist/src/workflows/draft/workflow-draft-prompt.js.map +1 -0
- package/dist/src/workflows/draft/workflow-draft-service.d.ts +12 -0
- package/dist/src/workflows/draft/workflow-draft-service.js +131 -0
- package/dist/src/workflows/draft/workflow-draft-service.js.map +1 -0
- package/dist/src/workflows/draft/workflow-draft-validator.d.ts +4 -0
- package/dist/src/workflows/draft/workflow-draft-validator.js +133 -0
- package/dist/src/workflows/draft/workflow-draft-validator.js.map +1 -0
- package/dist/src/workflows/draft/workflow-draft.types.d.ts +44 -0
- package/dist/src/workflows/draft/workflow-draft.types.js +1 -0
- package/dist/src/workflows/engine/projector.js +1 -0
- package/dist/src/workflows/engine/projector.js.map +1 -1
- package/dist/src/workflows/engine/workflow-engine.d.ts +18 -0
- package/dist/src/workflows/engine/workflow-engine.js +320 -11
- package/dist/src/workflows/engine/workflow-engine.js.map +1 -1
- package/dist/src/workflows/index.js +4 -3
- package/dist/src/workflows/service/workflow-run-service.d.ts +14 -3
- package/dist/src/workflows/service/workflow-run-service.js +227 -6
- package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
- package/dist/src/workflows/service/workflow-run-service.types.d.ts +7 -2
- package/dist/src/workflows/store/event-store.js +1 -1
- package/dist/src/workflows/store/run-store.js +1 -1
- package/package.json +5 -3
- package/dist/gateway/static/root/assets/agents-XzgIVKcI.js +0 -396
- package/dist/gateway/static/root/assets/apps-page-B7Us3RMl.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-BgeV6fzw.js +0 -1
- package/dist/gateway/static/root/assets/cron-page-DKGHEeAU.js +0 -1
- package/dist/gateway/static/root/assets/index-50FVtgXU.js +0 -4845
- package/dist/gateway/static/root/assets/index-BPYKW7FB.css +0 -1
- package/dist/gateway/static/root/assets/notes-page-CsWIw35Q.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-CLPsbyOW.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-CRGHT_bm.js +0 -3
- package/dist/gateway/static/root/assets/skills-page-Ce-RIH2y.js +0 -2
- package/dist/gateway/static/root/assets/url-DPEStU4M.js +0 -3
- package/dist/gateway/static/root/assets/voice-api-key-field-CJGTidqc.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-o63aaARK.js +0 -27
- package/dist/src/agent/builtin-agent-ids.d.ts +0 -2
- package/dist/src/agent/builtin-agent-ids.js +0 -17
- package/dist/src/agent/builtin-agent-ids.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","names":[],"sources":["../../../../extensions/feishu/src/plugin.ts"],"sourcesContent":["/**\n * Feishu/Lark channel plugin (Socket Mode first).\n *\n * This is intentionally decomposed into small modules so we can grow toward\n * openclaw `extensions/feishu` parity without turning `plugin.ts` into a monolith.\n */\n\nimport { isDeepStrictEqual } from 'node:util';\n\nimport type { Config } from '@xopcai/xopc/config/schema.js';\nimport type { MessageBus } from '@xopcai/xopc/infra/bus/index.js';\nimport type {\n ChannelCapabilities,\n ChannelDoctorAdapter,\n ChannelMessageActionAdapter,\n ChannelOutboundAdapter,\n ChannelPlugin,\n ChannelPluginDefaults,\n ChannelPluginInitOptions,\n ChannelPluginReloadMeta,\n ChannelPluginStartOptions,\n ChannelSecurityAdapter,\n ChannelSecurityContext,\n ChannelStatusAdapter,\n ChatType,\n} from '@xopcai/xopc/channels/plugin-types.js';\nimport type {\n ChannelCliLoginAdapter,\n ChannelRuntimeActionAdapter,\n} from '@xopcai/xopc/channels/plugins/types.adapters.js';\nimport { createLogger } from '@xopcai/xopc/utils/logger.js';\nimport { evaluateAccess, resolveDmPolicy, resolveGroupPolicy } from '@xopcai/xopc/channels/security.js';\nimport { createStandardPairingAdapter } from '@xopcai/xopc/channels/pairing/pairing-store-adapter.js';\n\nimport { FeishuConfigSchema, type FeishuConfig } from './schema/config-schema.js';\nimport { listFeishuAccountIds, resolveFeishuAccount, type ResolvedFeishuAccount } from './state/accounts.js';\nimport { createFeishuSocketModeMonitor } from './transport/socket-mode/monitor.js';\nimport { createFeishuWebhookMonitor } from './transport/webhook/monitor.js';\nimport { createFeishuOutboundAdapter } from './outbound/outbound-adapter.js';\nimport { createFeishuStatusAdapter } from './status/status-adapter.js';\nimport { createFeishuDoctorAdapter } from './status/doctor.js';\nimport { feishuConfigSurface } from './ui/config-surface.js';\nimport { createFeishuStreamingAdapter } from './streaming/streaming-adapter.js';\nimport { readFrameworkAllowFromList } from './auth/pairing.js';\nimport {\n addReactionFeishu,\n editMessageFeishu,\n getMessageFeishu,\n listPinsFeishu,\n listReactionsFeishu,\n pinMessageFeishu,\n removeReactionFeishu,\n unpinMessageFeishu,\n} from './outbound/actions.js';\nimport { createFeishuDirectoryAdapter } from './directory/directory-adapter.js';\nimport { feishuWhoAmI } from './tools/tools.js';\nimport { feishuCliLoginAdapter } from './adapters/cli-login.js';\nimport { feishuOnboardAdapter } from './adapters/onboard-cli.js';\nimport { feishuGatewaySetupActions } from './adapters/gateway-setup.js';\nimport { handleFeishuChannelMessageAction } from './actions/message-action-handler.js';\nimport { createFeishuInboundPipeline, type FeishuInboundWork } from './transport/reliability/inbound-pipeline.js';\nimport { getWorkflowProgressBroker } from '@xopcai/xopc/agent/workflow/index.js';\nimport { createFeishuWorkflowProgressCapability } from './workflow-progress.js';\n\nconst log = createLogger('FeishuPlugin');\n\nexport class FeishuChannelPlugin implements ChannelPlugin<ResolvedFeishuAccount> {\n readonly id = 'feishu' as const;\n\n readonly reload: ChannelPluginReloadMeta = {\n configPrefixes: ['channels.feishu'],\n };\n\n readonly meta = {\n id: 'feishu',\n label: 'Feishu',\n selectionLabel: 'Feishu/Lark (飞书)',\n docsPath: '/channels/feishu',\n blurb: 'Feishu/Lark enterprise messaging (Socket Mode).',\n order: 4,\n deferConnectUntilAfterListen: true,\n } as const;\n\n readonly capabilities: ChannelCapabilities = {\n chatTypes: ['direct', 'channel'] as ChatType[],\n reactions: true,\n threads: true,\n media: true,\n polls: false,\n nativeCommands: false,\n blockStreaming: false,\n edit: true,\n reply: true,\n } as any;\n\n readonly defaults: ChannelPluginDefaults = {\n queue: { debounceMs: 350 },\n outbound: { textChunkLimit: 4000 },\n streaming: {\n blockStreamingCoalesce: {\n minChars: 200,\n idleMs: 2500,\n },\n },\n };\n\n readonly configSchema = {\n schema: {},\n validate: (raw: unknown) => {\n const r = FeishuConfigSchema.safeParse(raw);\n return r.success ? { ok: true as const } : { ok: false as const, errors: [r.error.message] };\n },\n };\n\n readonly configSurface = feishuConfigSurface;\n\n readonly pairing = createStandardPairingAdapter('feishu');\n\n onboard = feishuOnboardAdapter;\n\n readonly cliLogin: ChannelCliLoginAdapter = feishuCliLoginAdapter;\n\n readonly runtimeActions: ChannelRuntimeActionAdapter = feishuGatewaySetupActions;\n\n private bus!: MessageBus;\n private cfg!: Config;\n private abortControllers = new Map<string, AbortController>();\n private inboundPipeline?: ReturnType<typeof createFeishuInboundPipeline>;\n /** Unregister fn for the workflow-progress capability registered against the global broker. */\n private workflowProgressUnregister: (() => void) | null = null;\n\n config = {\n listAccountIds: (cfg: Config) => listFeishuAccountIds(cfg),\n resolveAccount: (cfg: Config, accountId?: string | null) => resolveFeishuAccount(cfg, accountId),\n isConfigured: async (account: ResolvedFeishuAccount) => account.configured,\n describeAccount: (account: ResolvedFeishuAccount) => ({\n accountId: account.accountId,\n channelId: 'feishu',\n enabled: account.enabled,\n configured: account.configured,\n status: account.configured ? undefined : 'unconfigured',\n }),\n };\n\n security: ChannelSecurityAdapter<ResolvedFeishuAccount> = {\n resolveDmPolicy: ({ account }: { account: ResolvedFeishuAccount }) =>\n resolveDmPolicy(account.dmPolicy, 'open'),\n resolveGroupPolicy: ({ account }: { account: ResolvedFeishuAccount }) =>\n resolveGroupPolicy(account.groupPolicy, 'allowlist'),\n checkAccess: (ctx: ChannelSecurityContext, account: ResolvedFeishuAccount, _cfg: Config) => {\n const isDm = !ctx.isGroup;\n const frameworkAllowFrom = readFrameworkAllowFromList(account.accountId);\n const baseAllowFrom = isDm ? account.allowFrom : account.groupAllowFrom ?? account.allowFrom;\n const allowFrom = [...(baseAllowFrom ?? []), ...frameworkAllowFrom];\n if (isDm) {\n return evaluateAccess({\n context: {\n channel: 'feishu',\n accountId: account.accountId,\n chatId: ctx.chatId,\n senderId: ctx.senderId,\n senderName: ctx.senderName,\n isGroup: false,\n isDm: true,\n },\n dmPolicy: account.dmPolicy,\n allowFrom,\n });\n }\n return evaluateAccess({\n context: {\n channel: 'feishu',\n accountId: account.accountId,\n chatId: ctx.chatId,\n senderId: ctx.senderId,\n senderName: ctx.senderName,\n isGroup: true,\n isDm: false,\n },\n groupPolicy: account.groupPolicy,\n allowFrom,\n });\n },\n };\n\n outbound: ChannelOutboundAdapter = createFeishuOutboundAdapter();\n\n streaming = createFeishuStreamingAdapter(() => this.cfg);\n\n status: ChannelStatusAdapter<ResolvedFeishuAccount> = createFeishuStatusAdapter();\n\n doctor: ChannelDoctorAdapter = createFeishuDoctorAdapter();\n\n directory = createFeishuDirectoryAdapter();\n\n actions: ChannelMessageActionAdapter = {\n handleAction: handleFeishuChannelMessageAction,\n };\n\n agentTools = [\n {\n name: 'feishu_read',\n description: 'Read a Feishu message by messageId (debug/utility).',\n execute: async (toolCtx, args) => {\n const messageId = typeof (args as any)?.messageId === 'string' ? (args as any).messageId : toolCtx.messageId;\n if (!messageId) throw new Error('feishu_read requires messageId');\n return await getMessageFeishu({ cfg: this.cfg, accountId: toolCtx.accountId, messageId });\n },\n },\n {\n name: 'feishu_edit',\n description: 'Edit a Feishu message by messageId.',\n execute: async (toolCtx, args) => {\n const messageId = typeof (args as any)?.messageId === 'string' ? (args as any).messageId : toolCtx.messageId;\n const text = typeof (args as any)?.text === 'string' ? (args as any).text : '';\n if (!messageId) throw new Error('feishu_edit requires messageId');\n if (!text.trim()) throw new Error('feishu_edit requires text');\n return await editMessageFeishu({ cfg: this.cfg, accountId: toolCtx.accountId, messageId, text });\n },\n },\n {\n name: 'feishu_scopes_probe',\n description: 'Probe Feishu credentials/scopes (placeholder for full docs/wiki/drive tools).',\n execute: async (toolCtx) => {\n return await feishuWhoAmI({ cfg: this.cfg, accountId: toolCtx.accountId });\n },\n },\n {\n name: 'feishu_react',\n description: 'Add/remove/list reactions for a message.',\n execute: async (toolCtx, args) => {\n const a = args as any;\n const messageId = typeof a?.messageId === 'string' ? a.messageId : toolCtx.messageId;\n if (!messageId) throw new Error('feishu_react requires messageId');\n\n const account = resolveFeishuAccount(this.cfg, toolCtx.accountId ?? 'default');\n const enabled = (account.actions as any)?.reactions !== false;\n if (!enabled) {\n throw new Error('Feishu reactions are disabled via channels.feishu.actions.reactions');\n }\n\n if (a?.list === true) {\n return await listReactionsFeishu({\n cfg: this.cfg,\n accountId: toolCtx.accountId,\n messageId,\n emojiType: typeof a?.emojiType === 'string' ? a.emojiType : undefined,\n });\n }\n\n if (a?.remove === true) {\n const reactionId = typeof a?.reactionId === 'string' ? a.reactionId : '';\n if (!reactionId) throw new Error('feishu_react remove requires reactionId');\n return await removeReactionFeishu({ cfg: this.cfg, accountId: toolCtx.accountId, messageId, reactionId });\n }\n\n const emojiType = typeof a?.emojiType === 'string' ? a.emojiType : '';\n if (!emojiType) throw new Error('feishu_react requires emojiType');\n return await addReactionFeishu({ cfg: this.cfg, accountId: toolCtx.accountId, messageId, emojiType });\n },\n },\n {\n name: 'feishu_pins',\n description: 'Pin/unpin/list pins for a chat.',\n execute: async (toolCtx, args) => {\n const a = args as any;\n const action = typeof a?.action === 'string' ? a.action : '';\n if (action === 'list') {\n const chatId = typeof a?.chatId === 'string' ? a.chatId : toolCtx.chatId;\n if (!chatId) throw new Error('feishu_pins list requires chatId');\n return await listPinsFeishu({\n cfg: this.cfg,\n accountId: toolCtx.accountId,\n chatId,\n startTime: typeof a?.startTime === 'string' ? a.startTime : undefined,\n endTime: typeof a?.endTime === 'string' ? a.endTime : undefined,\n pageSize: typeof a?.pageSize === 'number' ? a.pageSize : undefined,\n pageToken: typeof a?.pageToken === 'string' ? a.pageToken : undefined,\n });\n }\n const messageId = typeof a?.messageId === 'string' ? a.messageId : toolCtx.messageId;\n if (!messageId) throw new Error('feishu_pins requires messageId');\n if (action === 'pin') {\n return await pinMessageFeishu({ cfg: this.cfg, accountId: toolCtx.accountId, messageId });\n }\n if (action === 'unpin') {\n return await unpinMessageFeishu({ cfg: this.cfg, accountId: toolCtx.accountId, messageId });\n }\n throw new Error('feishu_pins requires action: pin | unpin | list');\n },\n },\n ];\n\n async init(options: ChannelPluginInitOptions): Promise<void> {\n this.bus = options.bus;\n this.cfg = options.config;\n const defaultDebounce = this.defaults.queue?.debounceMs ?? 350;\n this.inboundPipeline = createFeishuInboundPipeline({\n bus: this.bus,\n defaultDebounceMs: defaultDebounce,\n onError: (err, items) => {\n log.error({ err, count: items.length }, 'Feishu inbound pipeline flush failed');\n },\n });\n\n // Workflow progress broker capability — turns mid-run snapshots into\n // edit-in-place Feishu messages. Broker is the agent-side subscriber for\n // `tool_execution_update` on the `workflow` tool. Registration is\n // idempotent (replaces a prior cap with the same channelId).\n this.workflowProgressUnregister = getWorkflowProgressBroker().registerChannel(\n createFeishuWorkflowProgressCapability({ getConfig: () => this.cfg }),\n );\n\n log.debug('Feishu plugin initialized');\n }\n\n async start(options?: ChannelPluginStartOptions): Promise<void> {\n const section = this.cfg.channels?.feishu as FeishuConfig | undefined;\n if (!section || section.enabled !== true) {\n return;\n }\n\n const ids = options?.accountId ? [options.accountId] : listFeishuAccountIds(this.cfg);\n for (const accountId of ids) {\n const account = resolveFeishuAccount(this.cfg, accountId);\n if (!account.enabled || !account.configured) continue;\n if (this.abortControllers.has(accountId)) continue;\n\n const ac = new AbortController();\n this.abortControllers.set(accountId, ac);\n\n const defaultDebounce = this.defaults.queue?.debounceMs ?? 350;\n const enqueueInbound = (work: FeishuInboundWork) => {\n const p = this.inboundPipeline;\n if (!p) {\n return this.bus.publishInbound(work.inbound);\n }\n return p.enqueue(work);\n };\n\n const monitor = createFeishuSocketModeMonitor({\n account,\n config: this.cfg,\n enqueueInbound,\n inboundDebounceDefaultMs: defaultDebounce,\n abortSignal: ac.signal,\n security: {\n checkAccess: (ctx: ChannelSecurityContext) => this.security.checkAccess?.(ctx, account, this.cfg),\n },\n });\n\n const runner =\n account.connectionMode === 'webhook'\n ? createFeishuWebhookMonitor({\n account,\n config: this.cfg,\n enqueueInbound,\n inboundDebounceDefaultMs: defaultDebounce,\n abortSignal: ac.signal,\n security: {\n checkAccess: (ctx: ChannelSecurityContext) =>\n this.security.checkAccess?.(ctx, account, this.cfg),\n },\n })\n : monitor;\n\n void runner.run().catch((err) => {\n if ((err as { name?: string } | undefined)?.name === 'AbortError') {\n log.debug({ accountId }, 'Feishu monitor stopped');\n return;\n }\n log.error({ err, accountId }, 'Feishu monitor exited with error');\n });\n\n log.info({ accountId, mode: account.connectionMode }, 'Feishu monitor started');\n }\n }\n\n async stop(accountId?: string): Promise<void> {\n try {\n await this.inboundPipeline?.flushAll();\n } catch (err) {\n log.warn({ err }, 'Feishu inbound pipeline flushAll failed');\n }\n const ids = accountId ? [accountId] : [...this.abortControllers.keys()];\n for (const id of ids) {\n const ac = this.abortControllers.get(id);\n if (ac) {\n ac.abort();\n this.abortControllers.delete(id);\n }\n }\n // Only unregister the broker capability on a full stop. Per-account stops\n // still leave other accounts capable of delivering progress through the\n // same registered cap.\n if (!accountId) {\n this.workflowProgressUnregister?.();\n this.workflowProgressUnregister = null;\n }\n }\n\n channelIsRunning(cfg: Config): boolean {\n const ids = listFeishuAccountIds(cfg);\n return ids.some((id) => {\n const a = resolveFeishuAccount(cfg, id);\n return a.enabled !== false && a.configured && this.abortControllers.has(id);\n });\n }\n\n async onConfigUpdated(cfg: Config): Promise<void> {\n const prev = this.cfg.channels?.feishu as unknown;\n const next = cfg.channels?.feishu as { enabled?: boolean } | undefined;\n const channelOff = !next || next.enabled !== true;\n\n if (channelOff) {\n this.cfg = cfg;\n await this.stop();\n return;\n }\n\n this.cfg = cfg;\n\n if (isDeepStrictEqual(prev, next) && this.channelIsRunning(cfg)) {\n return;\n }\n\n await this.stop();\n await this.start();\n }\n}\n\nexport const feishuPlugin = new FeishuChannelPlugin();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"plugin.js","names":[],"sources":["../../../../extensions/feishu/src/plugin.ts"],"sourcesContent":["/**\n * Feishu/Lark channel plugin (Socket Mode first).\n *\n * This is intentionally decomposed into small modules so we can grow toward\n * openclaw `extensions/feishu` parity without turning `plugin.ts` into a monolith.\n */\n\nimport { isDeepStrictEqual } from 'node:util';\n\nimport type { Config } from '@xopcai/xopc/config/schema.js';\nimport type { MessageBus } from '@xopcai/xopc/infra/bus/index.js';\nimport type {\n ChannelCapabilities,\n ChannelDoctorAdapter,\n ChannelMessageActionAdapter,\n ChannelOutboundAdapter,\n ChannelPlugin,\n ChannelPluginDefaults,\n ChannelPluginInitOptions,\n ChannelPluginReloadMeta,\n ChannelPluginStartOptions,\n ChannelSecurityAdapter,\n ChannelSecurityContext,\n ChannelStatusAdapter,\n ChatType,\n} from '@xopcai/xopc/channels/plugin-types.js';\nimport type {\n ChannelCliLoginAdapter,\n ChannelRuntimeActionAdapter,\n ChannelOnboardAdapter,\n} from '@xopcai/xopc/channels/plugins/types.adapters.js';\nimport { createLogger } from '@xopcai/xopc/utils/logger.js';\nimport { evaluateAccess, resolveDmPolicy, resolveGroupPolicy } from '@xopcai/xopc/channels/security.js';\nimport { createStandardPairingAdapter } from '@xopcai/xopc/channels/pairing/pairing-store-adapter.js';\n\nimport { FeishuConfigSchema, type FeishuConfig } from './schema/config-schema.js';\nimport { listFeishuAccountIds, resolveFeishuAccount, type ResolvedFeishuAccount } from './state/accounts.js';\nimport { createFeishuOutboundAdapter } from './outbound/outbound-adapter.js';\nimport { createFeishuStatusAdapter } from './status/status-adapter.js';\nimport { createFeishuDoctorAdapter } from './status/doctor.js';\nimport { feishuConfigSurface } from './ui/config-surface.js';\nimport { createFeishuStreamingAdapter } from './streaming/streaming-adapter.js';\nimport { readFrameworkAllowFromList } from './auth/pairing.js';\nimport { feishuGatewaySetupActions } from './adapters/gateway-setup.js';\nimport { handleFeishuChannelMessageAction } from './actions/message-action-handler.js';\nimport { createFeishuInboundPipeline, type FeishuInboundWork } from './transport/reliability/inbound-pipeline.js';\n\nconst log = createLogger('FeishuPlugin');\n\nexport class FeishuChannelPlugin implements ChannelPlugin<ResolvedFeishuAccount> {\n readonly id = 'feishu' as const;\n\n readonly reload: ChannelPluginReloadMeta = {\n configPrefixes: ['channels.feishu'],\n };\n\n readonly meta = {\n id: 'feishu',\n label: 'Feishu',\n selectionLabel: 'Feishu/Lark (飞书)',\n docsPath: '/channels/feishu',\n blurb: 'Feishu/Lark enterprise messaging (Socket Mode).',\n order: 4,\n deferConnectUntilAfterListen: true,\n } as const;\n\n readonly capabilities: ChannelCapabilities = {\n chatTypes: ['direct', 'channel'] as ChatType[],\n reactions: true,\n threads: true,\n media: true,\n polls: false,\n nativeCommands: false,\n blockStreaming: false,\n edit: true,\n reply: true,\n } as any;\n\n readonly defaults: ChannelPluginDefaults = {\n queue: { debounceMs: 350 },\n outbound: { textChunkLimit: 4000 },\n streaming: {\n blockStreamingCoalesce: {\n minChars: 200,\n idleMs: 2500,\n },\n },\n };\n\n readonly configSchema = {\n schema: {},\n validate: (raw: unknown) => {\n const r = FeishuConfigSchema.safeParse(raw);\n return r.success ? { ok: true as const } : { ok: false as const, errors: [r.error.message] };\n },\n };\n\n readonly configSurface = feishuConfigSurface;\n\n readonly pairing = createStandardPairingAdapter('feishu');\n\n onboard: ChannelOnboardAdapter = {\n isConfigured: (config) => {\n const feishu = config.channels?.feishu as Record<string, unknown> | undefined;\n const appId = typeof feishu?.appId === 'string' ? feishu.appId.trim() : '';\n const appSecret = typeof feishu?.appSecret === 'string' ? feishu.appSecret.trim() : '';\n return feishu?.enabled === true && Boolean(appId && appSecret);\n },\n configure: async (config) => {\n const { feishuOnboardAdapter } = await import('./adapters/onboard-cli.js');\n return feishuOnboardAdapter.configure(config);\n },\n };\n\n readonly cliLogin: ChannelCliLoginAdapter = {\n runLogin: async (params) => {\n const { feishuCliLoginAdapter } = await import('./adapters/cli-login.js');\n return feishuCliLoginAdapter.runLogin(params);\n },\n };\n\n readonly runtimeActions: ChannelRuntimeActionAdapter = feishuGatewaySetupActions;\n\n private bus!: MessageBus;\n private cfg!: Config;\n private abortControllers = new Map<string, AbortController>();\n private inboundPipeline?: ReturnType<typeof createFeishuInboundPipeline>;\n /** Unregister fn for the workflow-progress capability registered against the global broker. */\n private workflowProgressUnregister: (() => void) | null = null;\n\n config = {\n listAccountIds: (cfg: Config) => listFeishuAccountIds(cfg),\n resolveAccount: (cfg: Config, accountId?: string | null) => resolveFeishuAccount(cfg, accountId),\n isConfigured: async (account: ResolvedFeishuAccount) => account.configured,\n describeAccount: (account: ResolvedFeishuAccount) => ({\n accountId: account.accountId,\n channelId: 'feishu',\n enabled: account.enabled,\n configured: account.configured,\n status: account.configured ? undefined : 'unconfigured',\n }),\n };\n\n security: ChannelSecurityAdapter<ResolvedFeishuAccount> = {\n resolveDmPolicy: ({ account }: { account: ResolvedFeishuAccount }) =>\n resolveDmPolicy(account.dmPolicy, 'open'),\n resolveGroupPolicy: ({ account }: { account: ResolvedFeishuAccount }) =>\n resolveGroupPolicy(account.groupPolicy, 'allowlist'),\n checkAccess: (ctx: ChannelSecurityContext, account: ResolvedFeishuAccount, _cfg: Config) => {\n const isDm = !ctx.isGroup;\n const frameworkAllowFrom = readFrameworkAllowFromList(account.accountId);\n const baseAllowFrom = isDm ? account.allowFrom : account.groupAllowFrom ?? account.allowFrom;\n const allowFrom = [...(baseAllowFrom ?? []), ...frameworkAllowFrom];\n if (isDm) {\n return evaluateAccess({\n context: {\n channel: 'feishu',\n accountId: account.accountId,\n chatId: ctx.chatId,\n senderId: ctx.senderId,\n senderName: ctx.senderName,\n isGroup: false,\n isDm: true,\n },\n dmPolicy: account.dmPolicy,\n allowFrom,\n });\n }\n return evaluateAccess({\n context: {\n channel: 'feishu',\n accountId: account.accountId,\n chatId: ctx.chatId,\n senderId: ctx.senderId,\n senderName: ctx.senderName,\n isGroup: true,\n isDm: false,\n },\n groupPolicy: account.groupPolicy,\n allowFrom,\n });\n },\n };\n\n outbound: ChannelOutboundAdapter = createFeishuOutboundAdapter();\n\n streaming = createFeishuStreamingAdapter(() => this.cfg);\n\n status: ChannelStatusAdapter<ResolvedFeishuAccount> = createFeishuStatusAdapter();\n\n doctor: ChannelDoctorAdapter = createFeishuDoctorAdapter();\n\n directory = {\n resolveDisplayName: async (params) => {\n const { createFeishuDirectoryAdapter } = await import('./directory/directory-adapter.js');\n return createFeishuDirectoryAdapter().resolveDisplayName?.(params);\n },\n };\n\n actions: ChannelMessageActionAdapter = {\n handleAction: handleFeishuChannelMessageAction,\n };\n\n agentTools = [\n {\n name: 'feishu_read',\n description: 'Read a Feishu message by messageId (debug/utility).',\n execute: async (toolCtx, args) => {\n const messageId = typeof (args as any)?.messageId === 'string' ? (args as any).messageId : toolCtx.messageId;\n if (!messageId) throw new Error('feishu_read requires messageId');\n const { getMessageFeishu } = await import('./outbound/actions.js');\n return await getMessageFeishu({ cfg: this.cfg, accountId: toolCtx.accountId, messageId });\n },\n },\n {\n name: 'feishu_edit',\n description: 'Edit a Feishu message by messageId.',\n execute: async (toolCtx, args) => {\n const messageId = typeof (args as any)?.messageId === 'string' ? (args as any).messageId : toolCtx.messageId;\n const text = typeof (args as any)?.text === 'string' ? (args as any).text : '';\n if (!messageId) throw new Error('feishu_edit requires messageId');\n if (!text.trim()) throw new Error('feishu_edit requires text');\n const { editMessageFeishu } = await import('./outbound/actions.js');\n return await editMessageFeishu({ cfg: this.cfg, accountId: toolCtx.accountId, messageId, text });\n },\n },\n {\n name: 'feishu_scopes_probe',\n description: 'Probe Feishu credentials/scopes (placeholder for full docs/wiki/drive tools).',\n execute: async (toolCtx) => {\n const { feishuWhoAmI } = await import('./tools/tools.js');\n return await feishuWhoAmI({ cfg: this.cfg, accountId: toolCtx.accountId });\n },\n },\n {\n name: 'feishu_react',\n description: 'Add/remove/list reactions for a message.',\n execute: async (toolCtx, args) => {\n const a = args as any;\n const messageId = typeof a?.messageId === 'string' ? a.messageId : toolCtx.messageId;\n if (!messageId) throw new Error('feishu_react requires messageId');\n\n const account = resolveFeishuAccount(this.cfg, toolCtx.accountId ?? 'default');\n const enabled = (account.actions as any)?.reactions !== false;\n if (!enabled) {\n throw new Error('Feishu reactions are disabled via channels.feishu.actions.reactions');\n }\n\n if (a?.list === true) {\n const { listReactionsFeishu } = await import('./outbound/actions.js');\n return await listReactionsFeishu({\n cfg: this.cfg,\n accountId: toolCtx.accountId,\n messageId,\n emojiType: typeof a?.emojiType === 'string' ? a.emojiType : undefined,\n });\n }\n\n if (a?.remove === true) {\n const reactionId = typeof a?.reactionId === 'string' ? a.reactionId : '';\n if (!reactionId) throw new Error('feishu_react remove requires reactionId');\n const { removeReactionFeishu } = await import('./outbound/actions.js');\n return await removeReactionFeishu({ cfg: this.cfg, accountId: toolCtx.accountId, messageId, reactionId });\n }\n\n const emojiType = typeof a?.emojiType === 'string' ? a.emojiType : '';\n if (!emojiType) throw new Error('feishu_react requires emojiType');\n const { addReactionFeishu } = await import('./outbound/actions.js');\n return await addReactionFeishu({ cfg: this.cfg, accountId: toolCtx.accountId, messageId, emojiType });\n },\n },\n {\n name: 'feishu_pins',\n description: 'Pin/unpin/list pins for a chat.',\n execute: async (toolCtx, args) => {\n const a = args as any;\n const action = typeof a?.action === 'string' ? a.action : '';\n if (action === 'list') {\n const chatId = typeof a?.chatId === 'string' ? a.chatId : toolCtx.chatId;\n if (!chatId) throw new Error('feishu_pins list requires chatId');\n const { listPinsFeishu } = await import('./outbound/actions.js');\n return await listPinsFeishu({\n cfg: this.cfg,\n accountId: toolCtx.accountId,\n chatId,\n startTime: typeof a?.startTime === 'string' ? a.startTime : undefined,\n endTime: typeof a?.endTime === 'string' ? a.endTime : undefined,\n pageSize: typeof a?.pageSize === 'number' ? a.pageSize : undefined,\n pageToken: typeof a?.pageToken === 'string' ? a.pageToken : undefined,\n });\n }\n const messageId = typeof a?.messageId === 'string' ? a.messageId : toolCtx.messageId;\n if (!messageId) throw new Error('feishu_pins requires messageId');\n if (action === 'pin') {\n const { pinMessageFeishu } = await import('./outbound/actions.js');\n return await pinMessageFeishu({ cfg: this.cfg, accountId: toolCtx.accountId, messageId });\n }\n if (action === 'unpin') {\n const { unpinMessageFeishu } = await import('./outbound/actions.js');\n return await unpinMessageFeishu({ cfg: this.cfg, accountId: toolCtx.accountId, messageId });\n }\n throw new Error('feishu_pins requires action: pin | unpin | list');\n },\n },\n ];\n\n async init(options: ChannelPluginInitOptions): Promise<void> {\n this.bus = options.bus;\n this.cfg = options.config;\n const defaultDebounce = this.defaults.queue?.debounceMs ?? 350;\n this.inboundPipeline = createFeishuInboundPipeline({\n bus: this.bus,\n defaultDebounceMs: defaultDebounce,\n onError: (err, items) => {\n log.error({ err, count: items.length }, 'Feishu inbound pipeline flush failed');\n },\n });\n\n await this.registerWorkflowProgressCapability();\n\n log.debug('Feishu plugin initialized');\n }\n\n private async registerWorkflowProgressCapability(): Promise<void> {\n // Lazy-load workflow progress so Feishu runtime startup does not pull the\n // agent/workflow/provider graph into Electron's dynamic extension path.\n const [{ getWorkflowProgressBroker }, { createFeishuWorkflowProgressCapability }] = await Promise.all([\n import('@xopcai/xopc/agent/workflow/progress-broker.js'),\n import('./workflow-progress.js'),\n ]);\n this.workflowProgressUnregister = getWorkflowProgressBroker().registerChannel(\n createFeishuWorkflowProgressCapability({ getConfig: () => this.cfg }),\n );\n }\n\n async start(options?: ChannelPluginStartOptions): Promise<void> {\n const section = this.cfg.channels?.feishu as FeishuConfig | undefined;\n if (!section || section.enabled !== true) {\n return;\n }\n\n const ids = options?.accountId ? [options.accountId] : listFeishuAccountIds(this.cfg);\n for (const accountId of ids) {\n const account = resolveFeishuAccount(this.cfg, accountId);\n if (!account.enabled || !account.configured) continue;\n if (this.abortControllers.has(accountId)) continue;\n\n const ac = new AbortController();\n this.abortControllers.set(accountId, ac);\n\n const defaultDebounce = this.defaults.queue?.debounceMs ?? 350;\n const enqueueInbound = (work: FeishuInboundWork) => {\n const p = this.inboundPipeline;\n if (!p) {\n return this.bus.publishInbound(work.inbound);\n }\n return p.enqueue(work);\n };\n\n const monitorDeps = {\n account,\n config: this.cfg,\n enqueueInbound,\n inboundDebounceDefaultMs: defaultDebounce,\n abortSignal: ac.signal,\n security: {\n checkAccess: (ctx: ChannelSecurityContext) => this.security.checkAccess?.(ctx, account, this.cfg),\n },\n };\n const runner =\n account.connectionMode === 'webhook'\n ? (await import('./transport/webhook/monitor.js')).createFeishuWebhookMonitor(monitorDeps)\n : (await import('./transport/socket-mode/monitor.js')).createFeishuSocketModeMonitor(monitorDeps);\n\n void runner.run().catch((err) => {\n if ((err as { name?: string } | undefined)?.name === 'AbortError') {\n log.debug({ accountId }, 'Feishu monitor stopped');\n return;\n }\n log.error({ err, accountId }, 'Feishu monitor exited with error');\n });\n\n log.info({ accountId, mode: account.connectionMode }, 'Feishu monitor started');\n }\n }\n\n async stop(accountId?: string): Promise<void> {\n try {\n await this.inboundPipeline?.flushAll();\n } catch (err) {\n log.warn({ err }, 'Feishu inbound pipeline flushAll failed');\n }\n const ids = accountId ? [accountId] : [...this.abortControllers.keys()];\n for (const id of ids) {\n const ac = this.abortControllers.get(id);\n if (ac) {\n ac.abort();\n this.abortControllers.delete(id);\n }\n }\n // Only unregister the broker capability on a full stop. Per-account stops\n // still leave other accounts capable of delivering progress through the\n // same registered cap.\n if (!accountId) {\n this.workflowProgressUnregister?.();\n this.workflowProgressUnregister = null;\n }\n }\n\n channelIsRunning(cfg: Config): boolean {\n const ids = listFeishuAccountIds(cfg);\n return ids.some((id) => {\n const a = resolveFeishuAccount(cfg, id);\n return a.enabled !== false && a.configured && this.abortControllers.has(id);\n });\n }\n\n async onConfigUpdated(cfg: Config): Promise<void> {\n const prev = this.cfg.channels?.feishu as unknown;\n const next = cfg.channels?.feishu as { enabled?: boolean } | undefined;\n const channelOff = !next || next.enabled !== true;\n\n if (channelOff) {\n this.cfg = cfg;\n await this.stop();\n return;\n }\n\n this.cfg = cfg;\n\n if (isDeepStrictEqual(prev, next) && this.channelIsRunning(cfg)) {\n return;\n }\n\n await this.stop();\n await this.start();\n }\n}\n\nexport const feishuPlugin = new FeishuChannelPlugin();\n"],"mappings":"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"}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { createLogger } from "../../../../src/utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../../../src/utils/logger.js";
|
|
3
|
-
import { formatFeishuOutboundText } from "../format.js";
|
|
4
3
|
import { resolveFeishuAccount } from "../state/accounts.js";
|
|
5
|
-
import { createFeishuClient } from "../transport/client/client.js";
|
|
6
4
|
import { getFeishuBindingByMessageId, recordFeishuMessageBinding } from "../state/message-bindings.js";
|
|
7
5
|
import { randomUUID } from "node:crypto";
|
|
8
6
|
//#region extensions/feishu/src/streaming/streaming-adapter.ts
|
|
@@ -36,7 +34,11 @@ function createFeishuStreamingAdapter(getConfig) {
|
|
|
36
34
|
const account = resolveFeishuAccount(getConfig(), options.accountId ?? "default");
|
|
37
35
|
if (!account.configured) return null;
|
|
38
36
|
if (account.streaming !== true) return null;
|
|
39
|
-
|
|
37
|
+
let apiPromise = null;
|
|
38
|
+
const getApi = async () => {
|
|
39
|
+
apiPromise ??= import("../transport/client/client.js").then(({ createFeishuClient }) => createFeishuClient(account).api);
|
|
40
|
+
return apiPromise;
|
|
41
|
+
};
|
|
40
42
|
let messageId;
|
|
41
43
|
let lastText = "";
|
|
42
44
|
let timer = null;
|
|
@@ -49,13 +51,15 @@ function createFeishuStreamingAdapter(getConfig) {
|
|
|
49
51
|
let fallbackSent = false;
|
|
50
52
|
const renderMode = account.renderMode ?? "auto";
|
|
51
53
|
const preferCard = renderMode === "card" || renderMode === "auto";
|
|
52
|
-
const formatStreamText = (text) => {
|
|
54
|
+
const formatStreamText = async (text) => {
|
|
53
55
|
if (!text.trim()) return text;
|
|
54
56
|
if (text.trim() === "Thinking…") return text;
|
|
57
|
+
const forCardMarkdown = Boolean(preferCard && cardId);
|
|
58
|
+
const { formatFeishuOutboundText } = await import("../format.js");
|
|
55
59
|
return formatFeishuOutboundText({
|
|
56
60
|
text,
|
|
57
61
|
renderMode,
|
|
58
|
-
forCardMarkdown
|
|
62
|
+
forCardMarkdown
|
|
59
63
|
});
|
|
60
64
|
};
|
|
61
65
|
const recordBindingIfReply = (childMessageId) => {
|
|
@@ -72,10 +76,10 @@ function createFeishuStreamingAdapter(getConfig) {
|
|
|
72
76
|
const edit = async (text) => {
|
|
73
77
|
if (ready) await ready;
|
|
74
78
|
if (!messageId) return;
|
|
75
|
-
const outbound = formatStreamText(text);
|
|
79
|
+
const outbound = await formatStreamText(text);
|
|
76
80
|
if (cardId && preferCard) {
|
|
77
81
|
cardSeq += 1;
|
|
78
|
-
await
|
|
82
|
+
await (await getApi()).cardkit.v1.cardElement.content({
|
|
79
83
|
path: {
|
|
80
84
|
card_id: cardId,
|
|
81
85
|
element_id: cardElementId
|
|
@@ -86,7 +90,7 @@ function createFeishuStreamingAdapter(getConfig) {
|
|
|
86
90
|
uuid: `${cardId}:${cardSeq}`
|
|
87
91
|
}
|
|
88
92
|
});
|
|
89
|
-
} else await
|
|
93
|
+
} else await (await getApi()).im.v1.message.update({
|
|
90
94
|
path: { message_id: messageId },
|
|
91
95
|
data: {
|
|
92
96
|
msg_type: "text",
|
|
@@ -100,15 +104,15 @@ function createFeishuStreamingAdapter(getConfig) {
|
|
|
100
104
|
fallbackSent = true;
|
|
101
105
|
const receive_id_type = options.chatId.startsWith("ou_") || options.chatId.startsWith("on_") ? "open_id" : "chat_id";
|
|
102
106
|
try {
|
|
103
|
-
const outbound = formatStreamText(text);
|
|
104
|
-
const res = options.replyToMessageId ? await
|
|
107
|
+
const outbound = await formatStreamText(text);
|
|
108
|
+
const res = options.replyToMessageId ? await (await getApi()).im.message.reply({
|
|
105
109
|
path: { message_id: options.replyToMessageId },
|
|
106
110
|
data: {
|
|
107
111
|
msg_type: "text",
|
|
108
112
|
content: JSON.stringify({ text: outbound }),
|
|
109
113
|
...options.threadId ? { reply_in_thread: true } : {}
|
|
110
114
|
}
|
|
111
|
-
}) : await
|
|
115
|
+
}) : await (await getApi()).im.message.create({
|
|
112
116
|
params: { receive_id_type },
|
|
113
117
|
data: {
|
|
114
118
|
receive_id: options.chatId,
|
|
@@ -165,7 +169,7 @@ function createFeishuStreamingAdapter(getConfig) {
|
|
|
165
169
|
};
|
|
166
170
|
let created;
|
|
167
171
|
try {
|
|
168
|
-
created = await
|
|
172
|
+
created = await (await getApi()).cardkit.v1.card.create({ data: {
|
|
169
173
|
type: "card_json",
|
|
170
174
|
data: JSON.stringify(cardSpec)
|
|
171
175
|
} });
|
|
@@ -188,7 +192,7 @@ function createFeishuStreamingAdapter(getConfig) {
|
|
|
188
192
|
responsePreview: JSON.stringify(created).slice(0, 400)
|
|
189
193
|
}, "Feishu cardkit.card.create returned no card_id; falling back to text stream");
|
|
190
194
|
if (cardId) {
|
|
191
|
-
const res = options.replyToMessageId ? await
|
|
195
|
+
const res = options.replyToMessageId ? await (await getApi()).im.message.reply({
|
|
192
196
|
path: { message_id: options.replyToMessageId },
|
|
193
197
|
data: {
|
|
194
198
|
msg_type: "interactive",
|
|
@@ -198,7 +202,7 @@ function createFeishuStreamingAdapter(getConfig) {
|
|
|
198
202
|
}),
|
|
199
203
|
...options.threadId ? { reply_in_thread: true } : {}
|
|
200
204
|
}
|
|
201
|
-
}) : await
|
|
205
|
+
}) : await (await getApi()).im.message.create({
|
|
202
206
|
params: { receive_id_type },
|
|
203
207
|
data: {
|
|
204
208
|
receive_id: options.chatId,
|
|
@@ -221,14 +225,14 @@ function createFeishuStreamingAdapter(getConfig) {
|
|
|
221
225
|
}
|
|
222
226
|
cardId = void 0;
|
|
223
227
|
}
|
|
224
|
-
const res = options.replyToMessageId ? await
|
|
228
|
+
const res = options.replyToMessageId ? await (await getApi()).im.message.reply({
|
|
225
229
|
path: { message_id: options.replyToMessageId },
|
|
226
230
|
data: {
|
|
227
231
|
msg_type: "text",
|
|
228
232
|
content: JSON.stringify({ text: thinking }),
|
|
229
233
|
...options.threadId ? { reply_in_thread: true } : {}
|
|
230
234
|
}
|
|
231
|
-
}) : await
|
|
235
|
+
}) : await (await getApi()).im.message.create({
|
|
232
236
|
params: { receive_id_type },
|
|
233
237
|
data: {
|
|
234
238
|
receive_id: options.chatId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streaming-adapter.js","names":[],"sources":["../../../../../extensions/feishu/src/streaming/streaming-adapter.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport type {\n ChannelStreamHandle,\n ChannelStreamingAdapter,\n} from '@xopcai/xopc/channels/plugin-types.js';\nimport type { Config } from '@xopcai/xopc/config/schema.js';\nimport { createLogger } from '@xopcai/xopc/utils/logger.js';\n\nimport { resolveFeishuAccount } from '../state/accounts.js';\nimport { formatFeishuOutboundText } from '../format.js';\nimport { getFeishuBindingByMessageId, recordFeishuMessageBinding } from '../state/message-bindings.js';\nimport { createFeishuClient } from '../transport/client/client.js';\n\nconst log = createLogger('FeishuStreaming');\n\n/** Normalize CardKit `card.create` responses (SDK / OpenAPI envelope shapes differ). */\nfunction extractFeishuCardKitCreateCardId(raw: unknown): string | undefined {\n if (!raw || typeof raw !== 'object') return undefined;\n const o = raw as Record<string, unknown>;\n const tryId = (v: unknown): string | undefined => {\n if (typeof v !== 'string') return undefined;\n const t = v.trim();\n return t.length > 0 ? t : undefined;\n };\n\n const fromData = (data: unknown): string | undefined => {\n if (!data || typeof data !== 'object') return undefined;\n const d = data as Record<string, unknown>;\n return tryId(d.card_id) ?? tryId(d.cardId);\n };\n\n return (\n fromData(o.data) ??\n (o.data && typeof o.data === 'object' ? fromData((o.data as Record<string, unknown>).data) : undefined) ??\n tryId(o.card_id)\n );\n}\n\nfunction feishuOpenApiOk(res: unknown): boolean {\n if (res === null || res === undefined) return false;\n if (typeof res !== 'object') return true;\n const code = (res as Record<string, unknown>).code;\n if (code === undefined || code === null) return true;\n return Number(code) === 0;\n}\n\nexport function createFeishuStreamingAdapter(getConfig: () => Config): ChannelStreamingAdapter {\n return {\n startStream(options: {\n chatId: string;\n accountId?: string;\n threadId?: string;\n replyToMessageId?: string;\n parseMode?: 'Markdown' | 'HTML';\n }): ChannelStreamHandle | null {\n const cfg = getConfig();\n const account = resolveFeishuAccount(cfg, options.accountId ?? 'default');\n if (!account.configured) {\n return null;\n }\n // Feishu streaming is opt-in. When omitted/false, fall back to normal final outbound.\n if (account.streaming !== true) {\n return null;\n }\n const { api } = createFeishuClient(account);\n\n let messageId: string | undefined;\n let lastText = '';\n let timer: NodeJS.Timeout | null = null;\n let aborted = false;\n let editedAtLeastOnce = false;\n let ready: Promise<void> | null = null;\n let cardId: string | undefined;\n let cardSeq = 0;\n const cardElementId = `md_${randomUUID().replace(/-/g, '')}`;\n let fallbackSent = false;\n\n const renderMode = account.renderMode ?? 'auto';\n const preferCard = renderMode === 'card' || renderMode === 'auto';\n\n const formatStreamText = (text: string) => {\n if (!text.trim()) return text;\n if (text.trim() === 'Thinking…') return text;\n const forCardMarkdown = Boolean(preferCard && cardId);\n return formatFeishuOutboundText({\n text,\n renderMode,\n forCardMarkdown,\n });\n };\n\n const recordBindingIfReply = (childMessageId: string) => {\n if (!childMessageId) return;\n const parentId = options.replyToMessageId;\n if (!parentId) return;\n const parent = getFeishuBindingByMessageId(parentId);\n if (!parent) return;\n recordFeishuMessageBinding({ ...parent, messageId: childMessageId });\n };\n\n const edit = async (text: string) => {\n if (ready) await ready;\n if (!messageId) return;\n const outbound = formatStreamText(text);\n if (cardId && preferCard) {\n cardSeq += 1;\n await (api as any).cardkit.v1.cardElement.content({\n path: { card_id: cardId, element_id: cardElementId },\n data: {\n content: outbound,\n sequence: cardSeq,\n uuid: `${cardId}:${cardSeq}`,\n },\n });\n } else {\n await (api as any).im.v1.message.update({\n path: { message_id: messageId },\n data: { msg_type: 'text', content: JSON.stringify({ text: outbound }) },\n });\n }\n editedAtLeastOnce = true;\n };\n\n const sendFallbackText = async (text: string) => {\n if (fallbackSent) return;\n fallbackSent = true;\n const receive_id_type =\n options.chatId.startsWith('ou_') || options.chatId.startsWith('on_') ? 'open_id' : 'chat_id';\n try {\n const outbound = formatStreamText(text);\n const res = options.replyToMessageId\n ? await (api as any).im.message.reply({\n path: { message_id: options.replyToMessageId },\n data: {\n msg_type: 'text',\n content: JSON.stringify({ text: outbound }),\n ...(options.threadId ? { reply_in_thread: true } : {}),\n },\n })\n : await (api as any).im.message.create({\n params: { receive_id_type },\n data: {\n receive_id: options.chatId,\n msg_type: 'text',\n content: JSON.stringify({ text: outbound }),\n },\n });\n const mid = res?.data?.message_id ?? res?.message_id ?? undefined;\n if (mid) recordBindingIfReply(mid);\n // Mark as delivered through the channel so the final outbound is skipped.\n editedAtLeastOnce = true;\n messageId = mid ?? messageId;\n // If we were in card mode, stop trying to update the card.\n cardId = undefined;\n } catch (err) {\n log.warn({ err, accountId: account.accountId }, 'Feishu streaming fallback send failed');\n }\n };\n\n const flush = async () => {\n if (aborted) return;\n if (ready) await ready;\n if (!messageId) return;\n const text = lastText;\n if (!text.trim()) return;\n try {\n await edit(text);\n } catch (err) {\n // Don't crash the agent loop. CardKit updates can fail (scopes, element conflicts); plain\n // `im.message.update` can also fail for some message states — always fall back to a text\n // reply so the user is not stuck on \"Thinking…\".\n log.warn({ err, accountId: account.accountId, messageId, mode: preferCard ? 'card' : 'text' }, 'Feishu streaming edit failed');\n await sendFallbackText(text);\n }\n };\n\n const start = async () => {\n const receive_id_type =\n options.chatId.startsWith('ou_') || options.chatId.startsWith('on_') ? 'open_id' : 'chat_id';\n const thinking = 'Thinking…';\n\n if (preferCard) {\n const cardSpec = {\n schema: '2.0',\n config: { update_multi: true },\n header: {\n title: { tag: 'plain_text', content: 'xopc' },\n },\n body: {\n elements: [\n {\n tag: 'markdown',\n element_id: cardElementId,\n content: thinking,\n },\n ],\n },\n };\n\n let created: unknown;\n try {\n created = await (api as any).cardkit.v1.card.create({\n data: { type: 'card_json', data: JSON.stringify(cardSpec) },\n });\n } catch (err) {\n log.warn({ err, accountId: account.accountId }, 'Feishu cardkit.card.create threw; falling back to text stream');\n created = null;\n }\n\n const apiOk = feishuOpenApiOk(created);\n cardId = apiOk ? extractFeishuCardKitCreateCardId(created) : undefined;\n\n if (!apiOk) {\n log.warn(\n {\n accountId: account.accountId,\n code: (created as Record<string, unknown> | null)?.code,\n msg: (created as Record<string, unknown> | null)?.msg,\n },\n 'Feishu cardkit.card.create returned non-zero code; falling back to text stream',\n );\n } else if (!cardId) {\n log.warn(\n { accountId: account.accountId, responsePreview: JSON.stringify(created).slice(0, 400) },\n 'Feishu cardkit.card.create returned no card_id; falling back to text stream',\n );\n }\n\n if (cardId) {\n const res = options.replyToMessageId\n ? await (api as any).im.message.reply({\n path: { message_id: options.replyToMessageId },\n data: {\n msg_type: 'interactive',\n content: JSON.stringify({ type: 'card', data: { card_id: cardId } }),\n ...(options.threadId ? { reply_in_thread: true } : {}),\n },\n })\n : await (api as any).im.message.create({\n params: { receive_id_type },\n data: {\n receive_id: options.chatId,\n msg_type: 'interactive',\n content: JSON.stringify({ type: 'card', data: { card_id: cardId } }),\n },\n });\n messageId = res?.data?.message_id ?? res?.message_id ?? undefined;\n if (messageId) recordBindingIfReply(messageId);\n log.info(\n { accountId: account.accountId, chatId: options.chatId, messageId, mode: 'card' },\n 'Feishu streaming started',\n );\n return;\n }\n\n // Clear so downstream edits use im.message.update (text), not CardKit.\n cardId = undefined;\n }\n\n const res = options.replyToMessageId\n ? await (api as any).im.message.reply({\n path: { message_id: options.replyToMessageId },\n data: {\n msg_type: 'text',\n content: JSON.stringify({ text: thinking }),\n ...(options.threadId ? { reply_in_thread: true } : {}),\n },\n })\n : await (api as any).im.message.create({\n params: { receive_id_type },\n data: {\n receive_id: options.chatId,\n msg_type: 'text',\n content: JSON.stringify({ text: thinking }),\n },\n });\n messageId = res?.data?.message_id ?? res?.message_id ?? undefined;\n if (messageId) recordBindingIfReply(messageId);\n log.info(\n { accountId: account.accountId, chatId: options.chatId, messageId, mode: 'text' },\n 'Feishu streaming started',\n );\n };\n\n ready = start().catch((err) => {\n log.warn({ err, accountId: account.accountId }, 'Feishu streaming start failed');\n });\n\n return {\n update: (text: string) => {\n lastText = text;\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n void flush().catch((err) => log.warn({ err }, 'Feishu streaming flush failed'));\n }, 800);\n },\n end: async () => {\n if (timer) clearTimeout(timer);\n await flush();\n log.debug(\n {\n accountId: account.accountId,\n chatId: options.chatId,\n messageId,\n editedAtLeastOnce,\n lastTextLen: lastText.length,\n mode: preferCard ? 'card' : 'text',\n },\n 'Feishu streaming ended',\n );\n },\n abort: async () => {\n aborted = true;\n if (timer) clearTimeout(timer);\n },\n messageId: () => undefined,\n skipFinalOutbound: () => Boolean(messageId) && editedAtLeastOnce,\n updateProgress: undefined,\n setProgress: undefined,\n };\n },\n };\n}\n\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"streaming-adapter.js","names":[],"sources":["../../../../../extensions/feishu/src/streaming/streaming-adapter.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport type {\n ChannelStreamHandle,\n ChannelStreamingAdapter,\n} from '@xopcai/xopc/channels/plugin-types.js';\nimport type { Config } from '@xopcai/xopc/config/schema.js';\nimport { createLogger } from '@xopcai/xopc/utils/logger.js';\n\nimport { resolveFeishuAccount } from '../state/accounts.js';\nimport { getFeishuBindingByMessageId, recordFeishuMessageBinding } from '../state/message-bindings.js';\n\nconst log = createLogger('FeishuStreaming');\n\n/** Normalize CardKit `card.create` responses (SDK / OpenAPI envelope shapes differ). */\nfunction extractFeishuCardKitCreateCardId(raw: unknown): string | undefined {\n if (!raw || typeof raw !== 'object') return undefined;\n const o = raw as Record<string, unknown>;\n const tryId = (v: unknown): string | undefined => {\n if (typeof v !== 'string') return undefined;\n const t = v.trim();\n return t.length > 0 ? t : undefined;\n };\n\n const fromData = (data: unknown): string | undefined => {\n if (!data || typeof data !== 'object') return undefined;\n const d = data as Record<string, unknown>;\n return tryId(d.card_id) ?? tryId(d.cardId);\n };\n\n return (\n fromData(o.data) ??\n (o.data && typeof o.data === 'object' ? fromData((o.data as Record<string, unknown>).data) : undefined) ??\n tryId(o.card_id)\n );\n}\n\nfunction feishuOpenApiOk(res: unknown): boolean {\n if (res === null || res === undefined) return false;\n if (typeof res !== 'object') return true;\n const code = (res as Record<string, unknown>).code;\n if (code === undefined || code === null) return true;\n return Number(code) === 0;\n}\n\nexport function createFeishuStreamingAdapter(getConfig: () => Config): ChannelStreamingAdapter {\n return {\n startStream(options: {\n chatId: string;\n accountId?: string;\n threadId?: string;\n replyToMessageId?: string;\n parseMode?: 'Markdown' | 'HTML';\n }): ChannelStreamHandle | null {\n const cfg = getConfig();\n const account = resolveFeishuAccount(cfg, options.accountId ?? 'default');\n if (!account.configured) {\n return null;\n }\n // Feishu streaming is opt-in. When omitted/false, fall back to normal final outbound.\n if (account.streaming !== true) {\n return null;\n }\n let apiPromise: Promise<unknown> | null = null;\n const getApi = async () => {\n apiPromise ??= import('../transport/client/client.js').then(({ createFeishuClient }) => createFeishuClient(account).api);\n return apiPromise;\n };\n\n let messageId: string | undefined;\n let lastText = '';\n let timer: NodeJS.Timeout | null = null;\n let aborted = false;\n let editedAtLeastOnce = false;\n let ready: Promise<void> | null = null;\n let cardId: string | undefined;\n let cardSeq = 0;\n const cardElementId = `md_${randomUUID().replace(/-/g, '')}`;\n let fallbackSent = false;\n\n const renderMode = account.renderMode ?? 'auto';\n const preferCard = renderMode === 'card' || renderMode === 'auto';\n\n const formatStreamText = async (text: string) => {\n if (!text.trim()) return text;\n if (text.trim() === 'Thinking…') return text;\n const forCardMarkdown = Boolean(preferCard && cardId);\n const { formatFeishuOutboundText } = await import('../format.js');\n return formatFeishuOutboundText({\n text,\n renderMode,\n forCardMarkdown,\n });\n };\n\n const recordBindingIfReply = (childMessageId: string) => {\n if (!childMessageId) return;\n const parentId = options.replyToMessageId;\n if (!parentId) return;\n const parent = getFeishuBindingByMessageId(parentId);\n if (!parent) return;\n recordFeishuMessageBinding({ ...parent, messageId: childMessageId });\n };\n\n const edit = async (text: string) => {\n if (ready) await ready;\n if (!messageId) return;\n const outbound = await formatStreamText(text);\n if (cardId && preferCard) {\n cardSeq += 1;\n await ((await getApi()) as any).cardkit.v1.cardElement.content({\n path: { card_id: cardId, element_id: cardElementId },\n data: {\n content: outbound,\n sequence: cardSeq,\n uuid: `${cardId}:${cardSeq}`,\n },\n });\n } else {\n await ((await getApi()) as any).im.v1.message.update({\n path: { message_id: messageId },\n data: { msg_type: 'text', content: JSON.stringify({ text: outbound }) },\n });\n }\n editedAtLeastOnce = true;\n };\n\n const sendFallbackText = async (text: string) => {\n if (fallbackSent) return;\n fallbackSent = true;\n const receive_id_type =\n options.chatId.startsWith('ou_') || options.chatId.startsWith('on_') ? 'open_id' : 'chat_id';\n try {\n const outbound = await formatStreamText(text);\n const res = options.replyToMessageId\n ? await ((await getApi()) as any).im.message.reply({\n path: { message_id: options.replyToMessageId },\n data: {\n msg_type: 'text',\n content: JSON.stringify({ text: outbound }),\n ...(options.threadId ? { reply_in_thread: true } : {}),\n },\n })\n : await ((await getApi()) as any).im.message.create({\n params: { receive_id_type },\n data: {\n receive_id: options.chatId,\n msg_type: 'text',\n content: JSON.stringify({ text: outbound }),\n },\n });\n const mid = res?.data?.message_id ?? res?.message_id ?? undefined;\n if (mid) recordBindingIfReply(mid);\n // Mark as delivered through the channel so the final outbound is skipped.\n editedAtLeastOnce = true;\n messageId = mid ?? messageId;\n // If we were in card mode, stop trying to update the card.\n cardId = undefined;\n } catch (err) {\n log.warn({ err, accountId: account.accountId }, 'Feishu streaming fallback send failed');\n }\n };\n\n const flush = async () => {\n if (aborted) return;\n if (ready) await ready;\n if (!messageId) return;\n const text = lastText;\n if (!text.trim()) return;\n try {\n await edit(text);\n } catch (err) {\n // Don't crash the agent loop. CardKit updates can fail (scopes, element conflicts); plain\n // `im.message.update` can also fail for some message states — always fall back to a text\n // reply so the user is not stuck on \"Thinking…\".\n log.warn({ err, accountId: account.accountId, messageId, mode: preferCard ? 'card' : 'text' }, 'Feishu streaming edit failed');\n await sendFallbackText(text);\n }\n };\n\n const start = async () => {\n const receive_id_type =\n options.chatId.startsWith('ou_') || options.chatId.startsWith('on_') ? 'open_id' : 'chat_id';\n const thinking = 'Thinking…';\n\n if (preferCard) {\n const cardSpec = {\n schema: '2.0',\n config: { update_multi: true },\n header: {\n title: { tag: 'plain_text', content: 'xopc' },\n },\n body: {\n elements: [\n {\n tag: 'markdown',\n element_id: cardElementId,\n content: thinking,\n },\n ],\n },\n };\n\n let created: unknown;\n try {\n created = await ((await getApi()) as any).cardkit.v1.card.create({\n data: { type: 'card_json', data: JSON.stringify(cardSpec) },\n });\n } catch (err) {\n log.warn({ err, accountId: account.accountId }, 'Feishu cardkit.card.create threw; falling back to text stream');\n created = null;\n }\n\n const apiOk = feishuOpenApiOk(created);\n cardId = apiOk ? extractFeishuCardKitCreateCardId(created) : undefined;\n\n if (!apiOk) {\n log.warn(\n {\n accountId: account.accountId,\n code: (created as Record<string, unknown> | null)?.code,\n msg: (created as Record<string, unknown> | null)?.msg,\n },\n 'Feishu cardkit.card.create returned non-zero code; falling back to text stream',\n );\n } else if (!cardId) {\n log.warn(\n { accountId: account.accountId, responsePreview: JSON.stringify(created).slice(0, 400) },\n 'Feishu cardkit.card.create returned no card_id; falling back to text stream',\n );\n }\n\n if (cardId) {\n const res = options.replyToMessageId\n ? await ((await getApi()) as any).im.message.reply({\n path: { message_id: options.replyToMessageId },\n data: {\n msg_type: 'interactive',\n content: JSON.stringify({ type: 'card', data: { card_id: cardId } }),\n ...(options.threadId ? { reply_in_thread: true } : {}),\n },\n })\n : await ((await getApi()) as any).im.message.create({\n params: { receive_id_type },\n data: {\n receive_id: options.chatId,\n msg_type: 'interactive',\n content: JSON.stringify({ type: 'card', data: { card_id: cardId } }),\n },\n });\n messageId = res?.data?.message_id ?? res?.message_id ?? undefined;\n if (messageId) recordBindingIfReply(messageId);\n log.info(\n { accountId: account.accountId, chatId: options.chatId, messageId, mode: 'card' },\n 'Feishu streaming started',\n );\n return;\n }\n\n // Clear so downstream edits use im.message.update (text), not CardKit.\n cardId = undefined;\n }\n\n const res = options.replyToMessageId\n ? await ((await getApi()) as any).im.message.reply({\n path: { message_id: options.replyToMessageId },\n data: {\n msg_type: 'text',\n content: JSON.stringify({ text: thinking }),\n ...(options.threadId ? { reply_in_thread: true } : {}),\n },\n })\n : await ((await getApi()) as any).im.message.create({\n params: { receive_id_type },\n data: {\n receive_id: options.chatId,\n msg_type: 'text',\n content: JSON.stringify({ text: thinking }),\n },\n });\n messageId = res?.data?.message_id ?? res?.message_id ?? undefined;\n if (messageId) recordBindingIfReply(messageId);\n log.info(\n { accountId: account.accountId, chatId: options.chatId, messageId, mode: 'text' },\n 'Feishu streaming started',\n );\n };\n\n ready = start().catch((err) => {\n log.warn({ err, accountId: account.accountId }, 'Feishu streaming start failed');\n });\n\n return {\n update: (text: string) => {\n lastText = text;\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n void flush().catch((err) => log.warn({ err }, 'Feishu streaming flush failed'));\n }, 800);\n },\n end: async () => {\n if (timer) clearTimeout(timer);\n await flush();\n log.debug(\n {\n accountId: account.accountId,\n chatId: options.chatId,\n messageId,\n editedAtLeastOnce,\n lastTextLen: lastText.length,\n mode: preferCard ? 'card' : 'text',\n },\n 'Feishu streaming ended',\n );\n },\n abort: async () => {\n aborted = true;\n if (timer) clearTimeout(timer);\n },\n messageId: () => undefined,\n skipFinalOutbound: () => Boolean(messageId) && editedAtLeastOnce,\n updateProgress: undefined,\n setProgress: undefined,\n };\n },\n };\n}\n\n"],"mappings":"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"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { createLogger } from "../../../../../src/utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../../../../src/utils/logger.js";
|
|
3
3
|
import { generateSessionKey } from "../../../../../src/chat-commands/session-key.js";
|
|
4
|
+
import { getFeishuBindingByMessageId, recordFeishuMessageBinding } from "../../state/message-bindings.js";
|
|
4
5
|
import { createFeishuClient } from "../client/client.js";
|
|
5
6
|
import { sendFeishuPairingPromptIfNeeded } from "../../pairing/feishu-pairing-prompt.js";
|
|
6
7
|
import { createFeishuDedupe } from "../reliability/dedupe.js";
|
|
7
8
|
import { stripFeishuMentions } from "../text/mentions.js";
|
|
8
9
|
import { computeBackoffMs } from "./retry.js";
|
|
9
|
-
import { getFeishuBindingByMessageId, recordFeishuMessageBinding } from "../../state/message-bindings.js";
|
|
10
10
|
//#region extensions/feishu/src/transport/socket-mode/monitor.ts
|
|
11
11
|
init_logger();
|
|
12
12
|
const log = createLogger("FeishuSocketMode");
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { createLogger } from "../../../../../src/utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../../../../src/utils/logger.js";
|
|
3
3
|
import { generateSessionKey } from "../../../../../src/chat-commands/session-key.js";
|
|
4
|
+
import { recordFeishuMessageBinding } from "../../state/message-bindings.js";
|
|
4
5
|
import { createFeishuLarkSdkPinoLogger } from "../client/lark-sdk-logger.js";
|
|
5
6
|
import { sendFeishuPairingPromptIfNeeded } from "../../pairing/feishu-pairing-prompt.js";
|
|
6
7
|
import { createFeishuDedupe } from "../reliability/dedupe.js";
|
|
7
8
|
import { stripFeishuMentions } from "../text/mentions.js";
|
|
8
|
-
import { recordFeishuMessageBinding } from "../../state/message-bindings.js";
|
|
9
9
|
import crypto from "node:crypto";
|
|
10
10
|
import * as http$1 from "node:http";
|
|
11
11
|
import * as lark from "@larksuiteoapi/node-sdk";
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* - Other errors → rethrow so the broker logs and drops the update; the next
|
|
21
21
|
* key event (or the next throttle tick) retries.
|
|
22
22
|
*/
|
|
23
|
-
import type { ChannelProgressCapability } from '@xopcai/xopc/agent/workflow/
|
|
23
|
+
import type { ChannelProgressCapability } from '@xopcai/xopc/agent/workflow/channel-capability.js';
|
|
24
24
|
import type { Config } from '@xopcai/xopc/config/schema.js';
|
|
25
25
|
export declare function createFeishuWorkflowProgressCapability(opts: {
|
|
26
26
|
getConfig: () => Config | undefined;
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
+
import { init_session_key, parseSessionKey } from "../../../src/routing/session-key.js";
|
|
1
2
|
import { createLogger } from "../../../src/utils/logger/index.js";
|
|
2
3
|
import { init_logger } from "../../../src/utils/logger.js";
|
|
3
|
-
import { init_session_key, parseSessionKey } from "../../../src/routing/session-key.js";
|
|
4
4
|
import { resolveFeishuAccount } from "./state/accounts.js";
|
|
5
|
-
import { createFeishuClient } from "./transport/client/client.js";
|
|
6
|
-
import { editMessageFeishu } from "./outbound/actions.js";
|
|
7
5
|
//#region extensions/feishu/src/workflow-progress.ts
|
|
8
6
|
init_session_key();
|
|
9
7
|
init_logger();
|
|
@@ -25,6 +23,7 @@ function createFeishuWorkflowProgressCapability(opts) {
|
|
|
25
23
|
if (!account.configured) throw new Error(`feishu workflow progress: account "${target.accountId}" not configured (sessionKey "${input.sessionKey}")`);
|
|
26
24
|
const text = clampForFeishu(input.text);
|
|
27
25
|
if (input.previousMessageId && !input.isFinal) try {
|
|
26
|
+
const { editMessageFeishu } = await import("./outbound/actions.js");
|
|
28
27
|
await editMessageFeishu({
|
|
29
28
|
cfg,
|
|
30
29
|
accountId: target.accountId,
|
|
@@ -40,6 +39,7 @@ function createFeishuWorkflowProgressCapability(opts) {
|
|
|
40
39
|
}, "edit target gone; falling back to fresh send");
|
|
41
40
|
else throw err;
|
|
42
41
|
}
|
|
42
|
+
const { createFeishuClient } = await import("./transport/client/client.js");
|
|
43
43
|
const { api } = createFeishuClient(account);
|
|
44
44
|
const receiveIdType = isOpenId(target.peerId) ? "open_id" : "chat_id";
|
|
45
45
|
const messageId = extractMessageId(await api.im.message.create({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow-progress.js","names":[],"sources":["../../../../extensions/feishu/src/workflow-progress.ts"],"sourcesContent":["/**\n * Feishu/Lark capability for the workflow progress broker.\n *\n * Feishu exposes `im.v1.message.update`, so we get the same edit-in-place UX\n * as Telegram: send the first snapshot, then update the same message on\n * every subsequent throttled tick. Key events (phase change / new error /\n * tool_end) bypass the throttle so milestones land promptly.\n *\n * Per-bot send rate ~5 msg/sec/account (Feishu open API limit); a 5-second\n * default throttle leaves comfortable headroom even when several workflows\n * run concurrently.\n *\n * Routing: sessionKey `main:feishu:<accountId>:<dm|group|channel>:<peerId>`.\n * - DM peerId is an `open_id` (starts with `ou_`) → use `receive_id_type=open_id`.\n * - Group / channel peerId is a `chat_id` → use `receive_id_type=chat_id`.\n *\n * Failure handling:\n * - \"edit must not modify same content\" / \"message_not_modified\" → swallow, keep id.\n * - Edit target gone (deleted / 410-class errors) → fall back to a fresh send.\n * - Other errors → rethrow so the broker logs and drops the update; the next\n * key event (or the next throttle tick) retries.\n */\n\nimport type {\n ChannelProgressCapability,\n WorkflowProgressPostInput,\n} from '@xopcai/xopc/agent/workflow/
|
|
1
|
+
{"version":3,"file":"workflow-progress.js","names":[],"sources":["../../../../extensions/feishu/src/workflow-progress.ts"],"sourcesContent":["/**\n * Feishu/Lark capability for the workflow progress broker.\n *\n * Feishu exposes `im.v1.message.update`, so we get the same edit-in-place UX\n * as Telegram: send the first snapshot, then update the same message on\n * every subsequent throttled tick. Key events (phase change / new error /\n * tool_end) bypass the throttle so milestones land promptly.\n *\n * Per-bot send rate ~5 msg/sec/account (Feishu open API limit); a 5-second\n * default throttle leaves comfortable headroom even when several workflows\n * run concurrently.\n *\n * Routing: sessionKey `main:feishu:<accountId>:<dm|group|channel>:<peerId>`.\n * - DM peerId is an `open_id` (starts with `ou_`) → use `receive_id_type=open_id`.\n * - Group / channel peerId is a `chat_id` → use `receive_id_type=chat_id`.\n *\n * Failure handling:\n * - \"edit must not modify same content\" / \"message_not_modified\" → swallow, keep id.\n * - Edit target gone (deleted / 410-class errors) → fall back to a fresh send.\n * - Other errors → rethrow so the broker logs and drops the update; the next\n * key event (or the next throttle tick) retries.\n */\n\nimport type {\n ChannelProgressCapability,\n WorkflowProgressPostInput,\n} from '@xopcai/xopc/agent/workflow/channel-capability.js';\nimport type { Config } from '@xopcai/xopc/config/schema.js';\nimport { parseSessionKey } from '@xopcai/xopc/routing/session-key.js';\nimport { createLogger } from '@xopcai/xopc/utils/logger.js';\n\nimport { resolveFeishuAccount } from './state/accounts.js';\n\nconst log = createLogger('FeishuWorkflowProgress');\n\nconst FEISHU_TEXT_MAX = 4_000;\nconst DEFAULT_THROTTLE_MS = 5_000;\n\nexport function createFeishuWorkflowProgressCapability(opts: {\n getConfig: () => Config | undefined;\n}): ChannelProgressCapability {\n return {\n channelId: 'feishu',\n supportsEdit: true,\n defaultThrottleMs: DEFAULT_THROTTLE_MS,\n defaultMode: 'edit',\n\n async postProgress(input: WorkflowProgressPostInput) {\n const cfg = opts.getConfig();\n if (!cfg) {\n throw new Error('feishu workflow progress: no config loaded');\n }\n const target = resolveTarget(input.sessionKey);\n if (!target) {\n throw new Error(`feishu workflow progress: cannot route sessionKey \"${input.sessionKey}\"`);\n }\n\n const account = resolveFeishuAccount(cfg, target.accountId);\n if (!account.configured) {\n throw new Error(\n `feishu workflow progress: account \"${target.accountId}\" not configured (sessionKey \"${input.sessionKey}\")`,\n );\n }\n\n const text = clampForFeishu(input.text);\n\n // Edit-in-place when we have a previous message id and we're not on the\n // final send. The final tick is always a fresh send so users scrolled\n // past the running bubble can still see the conclusion.\n if (input.previousMessageId && !input.isFinal) {\n try {\n const { editMessageFeishu } = await import('./outbound/actions.js');\n await editMessageFeishu({\n cfg,\n accountId: target.accountId,\n messageId: input.previousMessageId,\n text,\n });\n return { messageId: input.previousMessageId };\n } catch (err) {\n if (isMessageNotModified(err)) {\n return { messageId: input.previousMessageId };\n }\n if (isEditTargetGone(err)) {\n log.debug(\n { sessionKey: input.sessionKey, previousMessageId: input.previousMessageId },\n 'edit target gone; falling back to fresh send',\n );\n // fall through to fresh send below\n } else {\n throw err;\n }\n }\n }\n\n const { createFeishuClient } = await import('./transport/client/client.js');\n const { api } = createFeishuClient(account);\n const receiveIdType = isOpenId(target.peerId) ? 'open_id' : 'chat_id';\n const res: unknown = await (api as { im: { message: { create(arg: unknown): Promise<unknown> } } }).im.message.create({\n params: { receive_id_type: receiveIdType },\n data: {\n receive_id: target.peerId,\n msg_type: 'text',\n content: JSON.stringify({ text }),\n },\n });\n const messageId = extractMessageId(res);\n if (!messageId) {\n throw new Error('feishu workflow progress: send succeeded but no message_id returned');\n }\n return { messageId };\n },\n };\n}\n\ninterface ResolvedTarget {\n accountId: string;\n peerId: string;\n}\n\nfunction resolveTarget(sessionKey: string): ResolvedTarget | null {\n const parsed = parseSessionKey(sessionKey);\n if (!parsed) return null;\n if (parsed.source !== 'feishu') return null;\n if (!parsed.peerId) return null;\n return {\n accountId: parsed.accountId || 'default',\n peerId: parsed.peerId,\n };\n}\n\nfunction clampForFeishu(text: string): string {\n if (text.length <= FEISHU_TEXT_MAX) return text;\n return `${text.slice(0, FEISHU_TEXT_MAX - 1)}…`;\n}\n\nfunction isOpenId(peerId: string): boolean {\n // Feishu open_id is prefixed `ou_`; chat_id is prefixed `oc_`. Anything\n // else (custom test fixtures, edge cases) defaults to chat_id which is the\n // safer guess for non-DM contexts.\n return peerId.toLowerCase().startsWith('ou_');\n}\n\nfunction extractMessageId(res: unknown): string | undefined {\n if (!res || typeof res !== 'object') return undefined;\n const rec = res as Record<string, unknown>;\n const data = rec.data as Record<string, unknown> | undefined;\n const fromData = typeof data?.message_id === 'string' ? data.message_id : undefined;\n if (fromData) return fromData;\n const direct = typeof rec.message_id === 'string' ? rec.message_id : undefined;\n return direct;\n}\n\nfunction isMessageNotModified(err: unknown): boolean {\n const msg = errorMessage(err).toLowerCase();\n return msg.includes('not_modified') || msg.includes('not modified');\n}\n\nfunction isEditTargetGone(err: unknown): boolean {\n const msg = errorMessage(err).toLowerCase();\n return (\n msg.includes('message_not_found') ||\n msg.includes('message not found') ||\n msg.includes('not exist')\n );\n}\n\nfunction errorMessage(err: unknown): string {\n if (!err) return '';\n if (err instanceof Error) return err.message;\n return String(err);\n}\n"],"mappings":"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"}
|