botmux 3.7.1 → 3.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.runtime-build-id +1 -1
- package/dist/adapters/backend/capabilities.d.ts +17 -0
- package/dist/adapters/backend/capabilities.d.ts.map +1 -0
- package/dist/adapters/backend/capabilities.js +22 -0
- package/dist/adapters/backend/capabilities.js.map +1 -0
- package/dist/adapters/backend/critical-control-key.d.ts +19 -0
- package/dist/adapters/backend/critical-control-key.d.ts.map +1 -0
- package/dist/adapters/backend/critical-control-key.js +34 -0
- package/dist/adapters/backend/critical-control-key.js.map +1 -0
- package/dist/adapters/backend/herdr-backend.d.ts +9 -0
- package/dist/adapters/backend/herdr-backend.d.ts.map +1 -1
- package/dist/adapters/backend/herdr-backend.js +23 -4
- package/dist/adapters/backend/herdr-backend.js.map +1 -1
- package/dist/adapters/backend/riff-backend.d.ts.map +1 -1
- package/dist/adapters/backend/riff-backend.js +3 -2
- package/dist/adapters/backend/riff-backend.js.map +1 -1
- package/dist/adapters/backend/session-backend-selector.d.ts +61 -6
- package/dist/adapters/backend/session-backend-selector.d.ts.map +1 -1
- package/dist/adapters/backend/session-backend-selector.js +173 -9
- package/dist/adapters/backend/session-backend-selector.js.map +1 -1
- package/dist/adapters/backend/tmux-backend.d.ts +10 -3
- package/dist/adapters/backend/tmux-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-backend.js +25 -8
- package/dist/adapters/backend/tmux-backend.js.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.js +3 -2
- package/dist/adapters/backend/tmux-pipe-backend.js.map +1 -1
- package/dist/adapters/backend/types.d.ts +45 -4
- package/dist/adapters/backend/types.d.ts.map +1 -1
- package/dist/adapters/backend/types.js +11 -0
- package/dist/adapters/backend/types.js.map +1 -1
- package/dist/adapters/backend/zellij-backend.d.ts.map +1 -1
- package/dist/adapters/backend/zellij-backend.js +3 -2
- package/dist/adapters/backend/zellij-backend.js.map +1 -1
- package/dist/adapters/backend/zmx-backend.d.ts +286 -0
- package/dist/adapters/backend/zmx-backend.d.ts.map +1 -0
- package/dist/adapters/backend/zmx-backend.js +2396 -0
- package/dist/adapters/backend/zmx-backend.js.map +1 -0
- package/dist/adapters/cli/claude-code.d.ts.map +1 -1
- package/dist/adapters/cli/claude-code.js +3 -0
- package/dist/adapters/cli/claude-code.js.map +1 -1
- package/dist/adapters/cli/codex-app.d.ts.map +1 -1
- package/dist/adapters/cli/codex-app.js +5 -1
- package/dist/adapters/cli/codex-app.js.map +1 -1
- package/dist/adapters/cli/codex.d.ts.map +1 -1
- package/dist/adapters/cli/codex.js +26 -1
- package/dist/adapters/cli/codex.js.map +1 -1
- package/dist/adapters/cli/fs-policy.d.ts +79 -1
- package/dist/adapters/cli/fs-policy.d.ts.map +1 -1
- package/dist/adapters/cli/fs-policy.js +290 -13
- package/dist/adapters/cli/fs-policy.js.map +1 -1
- package/dist/adapters/cli/grok.d.ts.map +1 -1
- package/dist/adapters/cli/grok.js +4 -1
- package/dist/adapters/cli/grok.js.map +1 -1
- package/dist/adapters/cli/oh-my-pi.d.ts.map +1 -1
- package/dist/adapters/cli/oh-my-pi.js +5 -3
- package/dist/adapters/cli/oh-my-pi.js.map +1 -1
- package/dist/adapters/cli/shared-hints.d.ts +7 -4
- package/dist/adapters/cli/shared-hints.d.ts.map +1 -1
- package/dist/adapters/cli/shared-hints.js +52 -35
- package/dist/adapters/cli/shared-hints.js.map +1 -1
- package/dist/adapters/cli/strict-input-handle.d.ts +13 -0
- package/dist/adapters/cli/strict-input-handle.d.ts.map +1 -0
- package/dist/adapters/cli/strict-input-handle.js +39 -0
- package/dist/adapters/cli/strict-input-handle.js.map +1 -0
- package/dist/adapters/cli/traex.d.ts.map +1 -1
- package/dist/adapters/cli/traex.js +6 -4
- package/dist/adapters/cli/traex.js.map +1 -1
- package/dist/adapters/cli/types.d.ts +16 -0
- package/dist/adapters/cli/types.d.ts.map +1 -1
- package/dist/bot-registry.d.ts +137 -8
- package/dist/bot-registry.d.ts.map +1 -1
- package/dist/bot-registry.js +298 -12
- package/dist/bot-registry.js.map +1 -1
- package/dist/cli/session-list-liveness.d.ts +1 -1
- package/dist/cli/session-list-liveness.js +1 -1
- package/dist/cli/zmx-managed-attach.d.ts +41 -0
- package/dist/cli/zmx-managed-attach.d.ts.map +1 -0
- package/dist/cli/zmx-managed-attach.js +72 -0
- package/dist/cli/zmx-managed-attach.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +780 -131
- package/dist/cli.js.map +1 -1
- package/dist/codex-app-runner.js +90 -2
- package/dist/codex-app-runner.js.map +1 -1
- package/dist/codex-rpc-engine.d.ts.map +1 -1
- package/dist/codex-rpc-engine.js +22 -6
- package/dist/codex-rpc-engine.js.map +1 -1
- package/dist/config.d.ts +5 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +29 -1
- package/dist/config.js.map +1 -1
- package/dist/core/ask-broker.d.ts +22 -1
- package/dist/core/ask-broker.d.ts.map +1 -1
- package/dist/core/ask-broker.js +12 -5
- package/dist/core/ask-broker.js.map +1 -1
- package/dist/core/botmux-wrapper.d.ts +18 -0
- package/dist/core/botmux-wrapper.d.ts.map +1 -1
- package/dist/core/botmux-wrapper.js +25 -1
- package/dist/core/botmux-wrapper.js.map +1 -1
- package/dist/core/chat-rename.d.ts +27 -0
- package/dist/core/chat-rename.d.ts.map +1 -0
- package/dist/core/chat-rename.js +53 -0
- package/dist/core/chat-rename.js.map +1 -0
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +160 -12
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/cost-calculator.d.ts +25 -1
- package/dist/core/cost-calculator.d.ts.map +1 -1
- package/dist/core/cost-calculator.js +102 -4
- package/dist/core/cost-calculator.js.map +1 -1
- package/dist/core/dashboard-ipc-server.d.ts +16 -2
- package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
- package/dist/core/dashboard-ipc-server.js +611 -62
- package/dist/core/dashboard-ipc-server.js.map +1 -1
- package/dist/core/dashboard-rows.d.ts +22 -1
- package/dist/core/dashboard-rows.d.ts.map +1 -1
- package/dist/core/dashboard-rows.js +61 -0
- package/dist/core/dashboard-rows.js.map +1 -1
- package/dist/core/dashboard-url.d.ts +6 -0
- package/dist/core/dashboard-url.d.ts.map +1 -1
- package/dist/core/dashboard-url.js +11 -1
- package/dist/core/dashboard-url.js.map +1 -1
- package/dist/core/device-isolation-daemon.d.ts +28 -6
- package/dist/core/device-isolation-daemon.d.ts.map +1 -1
- package/dist/core/device-isolation-daemon.js +96 -13
- package/dist/core/device-isolation-daemon.js.map +1 -1
- package/dist/core/host-overload-alert.d.ts +75 -0
- package/dist/core/host-overload-alert.d.ts.map +1 -1
- package/dist/core/host-overload-alert.js +103 -0
- package/dist/core/host-overload-alert.js.map +1 -1
- package/dist/core/idle-worker-sweeper.js +1 -1
- package/dist/core/idle-worker-sweeper.js.map +1 -1
- package/dist/core/inflight-input-tracker.d.ts +3 -0
- package/dist/core/inflight-input-tracker.d.ts.map +1 -1
- package/dist/core/inflight-input-tracker.js +9 -0
- package/dist/core/inflight-input-tracker.js.map +1 -1
- package/dist/core/passthrough-commands.d.ts.map +1 -1
- package/dist/core/passthrough-commands.js +10 -0
- package/dist/core/passthrough-commands.js.map +1 -1
- package/dist/core/persistent-backend.d.ts +32 -4
- package/dist/core/persistent-backend.d.ts.map +1 -1
- package/dist/core/persistent-backend.js +75 -6
- package/dist/core/persistent-backend.js.map +1 -1
- package/dist/core/plugins/mcp/gateway.js +2 -2
- package/dist/core/plugins/mcp/gateway.js.map +1 -1
- package/dist/core/plugins/runtime.d.ts +3 -0
- package/dist/core/plugins/runtime.d.ts.map +1 -1
- package/dist/core/plugins/runtime.js.map +1 -1
- package/dist/core/plugins/service-manager.d.ts +4 -1
- package/dist/core/plugins/service-manager.d.ts.map +1 -1
- package/dist/core/plugins/service-manager.js +11 -6
- package/dist/core/plugins/service-manager.js.map +1 -1
- package/dist/core/role-library.d.ts +48 -1
- package/dist/core/role-library.d.ts.map +1 -1
- package/dist/core/role-library.js +111 -3
- package/dist/core/role-library.js.map +1 -1
- package/dist/core/role-resolver.d.ts +14 -2
- package/dist/core/role-resolver.d.ts.map +1 -1
- package/dist/core/role-resolver.js +47 -4
- package/dist/core/role-resolver.js.map +1 -1
- package/dist/core/session-activity.d.ts +14 -0
- package/dist/core/session-activity.d.ts.map +1 -1
- package/dist/core/session-activity.js +46 -1
- package/dist/core/session-activity.js.map +1 -1
- package/dist/core/session-board.d.ts +5 -2
- package/dist/core/session-board.d.ts.map +1 -1
- package/dist/core/session-board.js +5 -2
- package/dist/core/session-board.js.map +1 -1
- package/dist/core/session-liveness.d.ts +6 -5
- package/dist/core/session-liveness.d.ts.map +1 -1
- package/dist/core/session-liveness.js +34 -13
- package/dist/core/session-liveness.js.map +1 -1
- package/dist/core/session-manager.d.ts +3 -2
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +397 -103
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-marker.d.ts +11 -2
- package/dist/core/session-marker.d.ts.map +1 -1
- package/dist/core/session-marker.js +50 -11
- package/dist/core/session-marker.js.map +1 -1
- package/dist/core/session-message-preview.d.ts +20 -0
- package/dist/core/session-message-preview.d.ts.map +1 -0
- package/dist/core/session-message-preview.js +188 -0
- package/dist/core/session-message-preview.js.map +1 -0
- package/dist/core/session-title.d.ts +5 -1
- package/dist/core/session-title.d.ts.map +1 -1
- package/dist/core/session-title.js +20 -3
- package/dist/core/session-title.js.map +1 -1
- package/dist/core/startup-commands.d.ts +1 -1
- package/dist/core/startup-commands.js +1 -1
- package/dist/core/terminal-url.d.ts.map +1 -1
- package/dist/core/terminal-url.js +3 -2
- package/dist/core/terminal-url.js.map +1 -1
- package/dist/core/trigger-session.d.ts.map +1 -1
- package/dist/core/trigger-session.js +75 -12
- package/dist/core/trigger-session.js.map +1 -1
- package/dist/core/types.d.ts +35 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +23 -0
- package/dist/core/types.js.map +1 -1
- package/dist/core/worker-ipc.d.ts +11 -0
- package/dist/core/worker-ipc.d.ts.map +1 -0
- package/dist/core/worker-ipc.js +26 -0
- package/dist/core/worker-ipc.js.map +1 -0
- package/dist/core/worker-pool.d.ts +179 -29
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +2118 -331
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.d.ts +132 -3
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +1327 -449
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/auth.d.ts +2 -0
- package/dist/dashboard/auth.d.ts.map +1 -1
- package/dist/dashboard/auth.js +9 -0
- package/dist/dashboard/auth.js.map +1 -1
- package/dist/dashboard/bot-payload.d.ts +4 -0
- package/dist/dashboard/bot-payload.d.ts.map +1 -1
- package/dist/dashboard/bot-payload.js +5 -0
- package/dist/dashboard/bot-payload.js.map +1 -1
- package/dist/dashboard/federation-api.d.ts.map +1 -1
- package/dist/dashboard/federation-api.js +4 -0
- package/dist/dashboard/federation-api.js.map +1 -1
- package/dist/dashboard/federation-spoke-api.d.ts.map +1 -1
- package/dist/dashboard/federation-spoke-api.js +32 -5
- package/dist/dashboard/federation-spoke-api.js.map +1 -1
- package/dist/dashboard/public-redact.d.ts +8 -2
- package/dist/dashboard/public-redact.d.ts.map +1 -1
- package/dist/dashboard/public-redact.js +34 -7
- package/dist/dashboard/public-redact.js.map +1 -1
- package/dist/dashboard/session-card-model.d.ts.map +1 -1
- package/dist/dashboard/session-card-model.js +10 -2
- package/dist/dashboard/session-card-model.js.map +1 -1
- package/dist/dashboard/settings-write-applier.d.ts +35 -1
- package/dist/dashboard/settings-write-applier.d.ts.map +1 -1
- package/dist/dashboard/settings-write-applier.js +88 -1
- package/dist/dashboard/settings-write-applier.js.map +1 -1
- package/dist/dashboard/web/app.d.ts.map +1 -1
- package/dist/dashboard/web/app.js +0 -1
- package/dist/dashboard/web/app.js.map +1 -1
- package/dist/dashboard/web/bot-defaults-page.d.ts +15 -0
- package/dist/dashboard/web/bot-defaults-page.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults-page.js +212 -58
- package/dist/dashboard/web/bot-defaults-page.js.map +1 -1
- package/dist/dashboard/web/bot-defaults.d.ts +3 -0
- package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults.js.map +1 -1
- package/dist/dashboard/web/bot-onboarding.d.ts +2 -1
- package/dist/dashboard/web/bot-onboarding.d.ts.map +1 -1
- package/dist/dashboard/web/bot-onboarding.js.map +1 -1
- package/dist/dashboard/web/clipboard.d.ts +2 -0
- package/dist/dashboard/web/clipboard.d.ts.map +1 -0
- package/dist/dashboard/web/clipboard.js +42 -0
- package/dist/dashboard/web/clipboard.js.map +1 -0
- package/dist/dashboard/web/connectors-page.d.ts.map +1 -1
- package/dist/dashboard/web/connectors-page.js +12 -8
- package/dist/dashboard/web/connectors-page.js.map +1 -1
- package/dist/dashboard/web/dashboard-components.d.ts +17 -16
- package/dist/dashboard/web/dashboard-components.d.ts.map +1 -1
- package/dist/dashboard/web/dashboard-components.js.map +1 -1
- package/dist/dashboard/web/groups-page.d.ts.map +1 -1
- package/dist/dashboard/web/groups-page.js +7 -3
- package/dist/dashboard/web/groups-page.js.map +1 -1
- package/dist/dashboard/web/i18n.d.ts.map +1 -1
- package/dist/dashboard/web/i18n.js +205 -12
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard/web/icon-tooltip.d.ts.map +1 -1
- package/dist/dashboard/web/icon-tooltip.js +16 -1
- package/dist/dashboard/web/icon-tooltip.js.map +1 -1
- package/dist/dashboard/web/listener-filters.d.ts +23 -0
- package/dist/dashboard/web/listener-filters.d.ts.map +1 -0
- package/dist/dashboard/web/listener-filters.js +36 -0
- package/dist/dashboard/web/listener-filters.js.map +1 -0
- package/dist/dashboard/web/overview-page.d.ts.map +1 -1
- package/dist/dashboard/web/overview-page.js.map +1 -1
- package/dist/dashboard/web/plugin-page.d.ts.map +1 -1
- package/dist/dashboard/web/plugin-page.js.map +1 -1
- package/dist/dashboard/web/preview-markdown.d.ts +5 -0
- package/dist/dashboard/web/preview-markdown.d.ts.map +1 -0
- package/dist/dashboard/web/preview-markdown.js +52 -0
- package/dist/dashboard/web/preview-markdown.js.map +1 -0
- package/dist/dashboard/web/roles-page.d.ts.map +1 -1
- package/dist/dashboard/web/roles-page.js +535 -10
- package/dist/dashboard/web/roles-page.js.map +1 -1
- package/dist/dashboard/web/roles.d.ts +77 -0
- package/dist/dashboard/web/roles.d.ts.map +1 -1
- package/dist/dashboard/web/roles.js +98 -0
- package/dist/dashboard/web/roles.js.map +1 -1
- package/dist/dashboard/web/session-terminal.d.ts.map +1 -1
- package/dist/dashboard/web/session-terminal.js +6 -4
- package/dist/dashboard/web/session-terminal.js.map +1 -1
- package/dist/dashboard/web/sessions-kanban.d.ts +4 -1
- package/dist/dashboard/web/sessions-kanban.d.ts.map +1 -1
- package/dist/dashboard/web/sessions-kanban.js +1 -1
- package/dist/dashboard/web/sessions-kanban.js.map +1 -1
- package/dist/dashboard/web/sessions-page.d.ts +3 -2
- package/dist/dashboard/web/sessions-page.d.ts.map +1 -1
- package/dist/dashboard/web/sessions-page.js +163 -28
- package/dist/dashboard/web/sessions-page.js.map +1 -1
- package/dist/dashboard/web/sessions.d.ts +25 -0
- package/dist/dashboard/web/sessions.d.ts.map +1 -1
- package/dist/dashboard/web/sessions.js +58 -7
- package/dist/dashboard/web/sessions.js.map +1 -1
- package/dist/dashboard/web/settings-page.d.ts +28 -3
- package/dist/dashboard/web/settings-page.d.ts.map +1 -1
- package/dist/dashboard/web/settings-page.js +61 -1
- package/dist/dashboard/web/settings-page.js.map +1 -1
- package/dist/dashboard/web/skills-page.d.ts +6 -5
- package/dist/dashboard/web/skills-page.d.ts.map +1 -1
- package/dist/dashboard/web/skills-page.js +2 -0
- package/dist/dashboard/web/skills-page.js.map +1 -1
- package/dist/dashboard/web/v3-components.d.ts +3 -2
- package/dist/dashboard/web/v3-components.d.ts.map +1 -1
- package/dist/dashboard/web/v3-components.js.map +1 -1
- package/dist/dashboard/web/vc-consumer-profiles-section.d.ts +12 -2
- package/dist/dashboard/web/vc-consumer-profiles-section.d.ts.map +1 -1
- package/dist/dashboard/web/vc-consumer-profiles-section.js +0 -9
- package/dist/dashboard/web/vc-consumer-profiles-section.js.map +1 -1
- package/dist/dashboard/web/webhook-logs-page.d.ts +2 -1
- package/dist/dashboard/web/webhook-logs-page.d.ts.map +1 -1
- package/dist/dashboard/web/webhook-logs-page.js +4 -1
- package/dist/dashboard/web/webhook-logs-page.js.map +1 -1
- package/dist/dashboard-web/app.js +1 -1
- package/dist/dashboard-web/chunks/bot-defaults-page-FAPIMQV3.js +10 -0
- package/dist/dashboard-web/chunks/{chunk-QFMH6ITB.js → chunk-5CJMHTT4.js} +1 -1
- package/dist/dashboard-web/chunks/{chunk-KQB42ML5.js → chunk-DLZK52JU.js} +14 -12
- package/dist/dashboard-web/chunks/chunk-FDZ7WOBW.js +16 -0
- package/dist/dashboard-web/chunks/{chunk-3QAUJXAS.js → chunk-GTAJV5YC.js} +1 -1
- package/dist/dashboard-web/chunks/{chunk-FNPGOZMX.js → chunk-IHNG6KE6.js} +1 -1
- package/dist/dashboard-web/chunks/{chunk-FLGXZJTD.js → chunk-VA6QWSGQ.js} +1 -1
- package/dist/dashboard-web/chunks/chunk-XJ7BGPJH.js +1 -0
- package/dist/dashboard-web/chunks/chunk-ZJVTGU5X.js +1 -0
- package/dist/dashboard-web/chunks/connectors-page-LKWRT3GS.js +1 -0
- package/dist/dashboard-web/chunks/groups-page-V6654ICQ.js +8 -0
- package/dist/dashboard-web/chunks/insights-page-237RMFQ5.js +7 -0
- package/dist/dashboard-web/chunks/{monitor-room-7IVIS75W.js → monitor-room-OO5Y4FRQ.js} +1 -1
- package/dist/dashboard-web/chunks/{monitoring-page-5SSJRQZF.js → monitoring-page-OUEITM5P.js} +1 -1
- package/dist/dashboard-web/chunks/{office-page-EOND3L5D.js → office-page-4KNAHQ4Q.js} +1 -1
- package/dist/dashboard-web/chunks/{overview-page-NISBVBBJ.js → overview-page-QDP4YK2S.js} +1 -1
- package/dist/dashboard-web/chunks/{plugin-page-JXC5F5YV.js → plugin-page-VEGTCEAS.js} +1 -1
- package/dist/dashboard-web/chunks/roles-page-PGXNZZNP.js +1 -0
- package/dist/dashboard-web/chunks/{schedules-page-AVOOKLUH.js → schedules-page-BJNC5TID.js} +1 -1
- package/dist/dashboard-web/chunks/sessions-page-M2ZYYCMO.js +6 -0
- package/dist/dashboard-web/chunks/settings-page-IJFZKUUW.js +2 -0
- package/dist/dashboard-web/chunks/{skills-page-5MW54PCC.js → skills-page-YRAIRZOQ.js} +3 -3
- package/dist/dashboard-web/chunks/{team-federation-page-2SNIMVXI.js → team-federation-page-DEU27GRU.js} +1 -1
- package/dist/dashboard-web/chunks/{v3-page-W6SBXXQC.js → v3-page-6KHEW2YL.js} +5 -5
- package/dist/dashboard-web/chunks/{whiteboards-page-STC54KTP.js → whiteboards-page-VDECAALH.js} +1 -1
- package/dist/dashboard-web/style.css +12545 -11432
- package/dist/dashboard.js +215 -36
- package/dist/dashboard.js.map +1 -1
- package/dist/global-config.d.ts +41 -2
- package/dist/global-config.d.ts.map +1 -1
- package/dist/global-config.js +47 -0
- package/dist/global-config.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +71 -19
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +71 -19
- package/dist/i18n/zh.js.map +1 -1
- package/dist/im/lark/callback-button-marker.d.ts +34 -0
- package/dist/im/lark/callback-button-marker.d.ts.map +1 -0
- package/dist/im/lark/callback-button-marker.js +99 -0
- package/dist/im/lark/callback-button-marker.js.map +1 -0
- package/dist/im/lark/card-builder.d.ts +46 -10
- package/dist/im/lark/card-builder.d.ts.map +1 -1
- package/dist/im/lark/card-builder.js +299 -78
- package/dist/im/lark/card-builder.js.map +1 -1
- package/dist/im/lark/card-handler.d.ts +3 -4
- package/dist/im/lark/card-handler.d.ts.map +1 -1
- package/dist/im/lark/card-handler.js +380 -148
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/im/lark/client.d.ts +24 -1
- package/dist/im/lark/client.d.ts.map +1 -1
- package/dist/im/lark/client.js +101 -8
- package/dist/im/lark/client.js.map +1 -1
- package/dist/im/lark/doc-comment.d.ts.map +1 -1
- package/dist/im/lark/doc-comment.js +6 -1
- package/dist/im/lark/doc-comment.js.map +1 -1
- package/dist/im/lark/event-dispatcher.d.ts +115 -3
- package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
- package/dist/im/lark/event-dispatcher.js +534 -147
- package/dist/im/lark/event-dispatcher.js.map +1 -1
- package/dist/im/lark/grant-command.d.ts +16 -12
- package/dist/im/lark/grant-command.d.ts.map +1 -1
- package/dist/im/lark/grant-command.js +48 -151
- package/dist/im/lark/grant-command.js.map +1 -1
- package/dist/im/lark/grant-pending.d.ts +12 -4
- package/dist/im/lark/grant-pending.d.ts.map +1 -1
- package/dist/im/lark/grant-pending.js +31 -8
- package/dist/im/lark/grant-pending.js.map +1 -1
- package/dist/im/lark/invite-command.d.ts +20 -0
- package/dist/im/lark/invite-command.d.ts.map +1 -0
- package/dist/im/lark/invite-command.js +239 -0
- package/dist/im/lark/invite-command.js.map +1 -0
- package/dist/im/lark/md-card.d.ts +66 -4
- package/dist/im/lark/md-card.d.ts.map +1 -1
- package/dist/im/lark/md-card.js +201 -31
- package/dist/im/lark/md-card.js.map +1 -1
- package/dist/im/lark/mention-targets.d.ts +43 -0
- package/dist/im/lark/mention-targets.d.ts.map +1 -0
- package/dist/im/lark/mention-targets.js +190 -0
- package/dist/im/lark/mention-targets.js.map +1 -0
- package/dist/im/lark/message-parser.d.ts +31 -0
- package/dist/im/lark/message-parser.d.ts.map +1 -1
- package/dist/im/lark/message-parser.js +305 -32
- package/dist/im/lark/message-parser.js.map +1 -1
- package/dist/im/lark/reply-card-footer-signature.d.ts +7 -0
- package/dist/im/lark/reply-card-footer-signature.d.ts.map +1 -0
- package/dist/im/lark/reply-card-footer-signature.js +7 -0
- package/dist/im/lark/reply-card-footer-signature.js.map +1 -0
- package/dist/im/lark/sessions-card.d.ts.map +1 -1
- package/dist/im/lark/sessions-card.js +4 -1
- package/dist/im/lark/sessions-card.js.map +1 -1
- package/dist/im/lark/substitute-command.d.ts.map +1 -1
- package/dist/im/lark/substitute-command.js +8 -0
- package/dist/im/lark/substitute-command.js.map +1 -1
- package/dist/im/lark/topic-root-context.d.ts +35 -0
- package/dist/im/lark/topic-root-context.d.ts.map +1 -0
- package/dist/im/lark/topic-root-context.js +37 -0
- package/dist/im/lark/topic-root-context.js.map +1 -0
- package/dist/im/lark/v3-blocked-card.d.ts.map +1 -1
- package/dist/im/lark/v3-blocked-card.js +2 -1
- package/dist/im/lark/v3-blocked-card.js.map +1 -1
- package/dist/im/lark/v3-gate-card.d.ts.map +1 -1
- package/dist/im/lark/v3-gate-card.js +2 -1
- package/dist/im/lark/v3-gate-card.js.map +1 -1
- package/dist/im/lark/v3-loop-grant-card.d.ts.map +1 -1
- package/dist/im/lark/v3-loop-grant-card.js +2 -1
- package/dist/im/lark/v3-loop-grant-card.js.map +1 -1
- package/dist/im/lark/v3-progress-card.d.ts.map +1 -1
- package/dist/im/lark/v3-progress-card.js +2 -1
- package/dist/im/lark/v3-progress-card.js.map +1 -1
- package/dist/im/lark/v3-revisit-grant-card.d.ts.map +1 -1
- package/dist/im/lark/v3-revisit-grant-card.js +2 -1
- package/dist/im/lark/v3-revisit-grant-card.js.map +1 -1
- package/dist/index-core-only.d.ts +3 -0
- package/dist/index-core-only.d.ts.map +1 -0
- package/dist/index-core-only.js +107 -0
- package/dist/index-core-only.js.map +1 -0
- package/dist/services/async-trigger-state.d.ts +8 -0
- package/dist/services/async-trigger-state.d.ts.map +1 -1
- package/dist/services/async-trigger-state.js +3 -2
- package/dist/services/async-trigger-state.js.map +1 -1
- package/dist/services/async-trigger-store.d.ts +10 -2
- package/dist/services/async-trigger-store.d.ts.map +1 -1
- package/dist/services/async-trigger-store.js +3 -2
- package/dist/services/async-trigger-store.js.map +1 -1
- package/dist/services/backend-availability.d.ts +3 -1
- package/dist/services/backend-availability.d.ts.map +1 -1
- package/dist/services/backend-availability.js +14 -1
- package/dist/services/backend-availability.js.map +1 -1
- package/dist/services/backend-type-store.d.ts.map +1 -1
- package/dist/services/backend-type-store.js +1 -1
- package/dist/services/backend-type-store.js.map +1 -1
- package/dist/services/bot-config-store.d.ts.map +1 -1
- package/dist/services/bot-config-store.js +2 -1
- package/dist/services/bot-config-store.js.map +1 -1
- package/dist/services/bridge-fallback-gate.d.ts +14 -1
- package/dist/services/bridge-fallback-gate.d.ts.map +1 -1
- package/dist/services/bridge-fallback-gate.js +65 -1
- package/dist/services/bridge-fallback-gate.js.map +1 -1
- package/dist/services/card-prefs-store.d.ts +7 -2
- package/dist/services/card-prefs-store.d.ts.map +1 -1
- package/dist/services/card-prefs-store.js +30 -4
- package/dist/services/card-prefs-store.js.map +1 -1
- package/dist/services/codex-app-runner-protocol.d.ts +9 -0
- package/dist/services/codex-app-runner-protocol.d.ts.map +1 -1
- package/dist/services/codex-app-runner-protocol.js +17 -0
- package/dist/services/codex-app-runner-protocol.js.map +1 -1
- package/dist/services/codex-app-token-usage.d.ts +93 -0
- package/dist/services/codex-app-token-usage.d.ts.map +1 -0
- package/dist/services/codex-app-token-usage.js +190 -0
- package/dist/services/codex-app-token-usage.js.map +1 -0
- package/dist/services/codex-transcript.d.ts +6 -1
- package/dist/services/codex-transcript.d.ts.map +1 -1
- package/dist/services/codex-transcript.js +103 -32
- package/dist/services/codex-transcript.js.map +1 -1
- package/dist/services/federation-roster.d.ts +4 -0
- package/dist/services/federation-roster.d.ts.map +1 -1
- package/dist/services/federation-roster.js +3 -0
- package/dist/services/federation-roster.js.map +1 -1
- package/dist/services/federation-store.d.ts +6 -0
- package/dist/services/federation-store.d.ts.map +1 -1
- package/dist/services/federation-store.js.map +1 -1
- package/dist/services/grant-policy.d.ts +13 -0
- package/dist/services/grant-policy.d.ts.map +1 -0
- package/dist/services/grant-policy.js +40 -0
- package/dist/services/grant-policy.js.map +1 -0
- package/dist/services/grant-store.d.ts +24 -3
- package/dist/services/grant-store.d.ts.map +1 -1
- package/dist/services/grant-store.js +196 -12
- package/dist/services/grant-store.js.map +1 -1
- package/dist/services/groups-store.d.ts +36 -0
- package/dist/services/groups-store.d.ts.map +1 -1
- package/dist/services/groups-store.js +123 -1
- package/dist/services/groups-store.js.map +1 -1
- package/dist/services/jsonl-cursor.d.ts.map +1 -1
- package/dist/services/jsonl-cursor.js +8 -2
- package/dist/services/jsonl-cursor.js.map +1 -1
- package/dist/services/local-cli-opener.d.ts.map +1 -1
- package/dist/services/local-cli-opener.js +32 -0
- package/dist/services/local-cli-opener.js.map +1 -1
- package/dist/services/message-listener-run-preview-store.d.ts +43 -0
- package/dist/services/message-listener-run-preview-store.d.ts.map +1 -0
- package/dist/services/message-listener-run-preview-store.js +152 -0
- package/dist/services/message-listener-run-preview-store.js.map +1 -0
- package/dist/services/message-listener-store.d.ts +26 -0
- package/dist/services/message-listener-store.d.ts.map +1 -0
- package/dist/services/message-listener-store.js +138 -0
- package/dist/services/message-listener-store.js.map +1 -0
- package/dist/services/message-listener.d.ts +112 -0
- package/dist/services/message-listener.d.ts.map +1 -0
- package/dist/services/message-listener.js +391 -0
- package/dist/services/message-listener.js.map +1 -0
- package/dist/services/overload-alert-migration.d.ts +15 -0
- package/dist/services/overload-alert-migration.d.ts.map +1 -0
- package/dist/services/overload-alert-migration.js +115 -0
- package/dist/services/overload-alert-migration.js.map +1 -0
- package/dist/services/send-policy.d.ts +38 -0
- package/dist/services/send-policy.d.ts.map +1 -1
- package/dist/services/send-policy.js +34 -0
- package/dist/services/send-policy.js.map +1 -1
- package/dist/services/session-store.d.ts +12 -1
- package/dist/services/session-store.d.ts.map +1 -1
- package/dist/services/session-store.js +44 -2
- package/dist/services/session-store.js.map +1 -1
- package/dist/services/skill-registry-store.d.ts.map +1 -1
- package/dist/services/skill-registry-store.js +87 -12
- package/dist/services/skill-registry-store.js.map +1 -1
- package/dist/services/substitute-mode-normalize.d.ts +3 -0
- package/dist/services/substitute-mode-normalize.d.ts.map +1 -1
- package/dist/services/substitute-mode-normalize.js +8 -0
- package/dist/services/substitute-mode-normalize.js.map +1 -1
- package/dist/services/substitute-mode-store.d.ts.map +1 -1
- package/dist/services/substitute-mode-store.js +8 -1
- package/dist/services/substitute-mode-store.js.map +1 -1
- package/dist/services/transcript-resolver.d.ts +6 -1
- package/dist/services/transcript-resolver.d.ts.map +1 -1
- package/dist/services/transcript-resolver.js +145 -29
- package/dist/services/transcript-resolver.js.map +1 -1
- package/dist/services/trigger-types.d.ts +16 -0
- package/dist/services/trigger-types.d.ts.map +1 -1
- package/dist/services/trigger-types.js +6 -0
- package/dist/services/trigger-types.js.map +1 -1
- package/dist/setup/bot-config-editor.js +2 -2
- package/dist/setup/bot-config-editor.js.map +1 -1
- package/dist/setup/ensure-zmx.d.ts +31 -0
- package/dist/setup/ensure-zmx.d.ts.map +1 -0
- package/dist/setup/ensure-zmx.js +161 -0
- package/dist/setup/ensure-zmx.js.map +1 -0
- package/dist/setup/index.d.ts +1 -1
- package/dist/setup/index.js +1 -1
- package/dist/setup/open-platform-automation.d.ts +9 -0
- package/dist/setup/open-platform-automation.d.ts.map +1 -1
- package/dist/setup/open-platform-automation.js +15 -2
- package/dist/setup/open-platform-automation.js.map +1 -1
- package/dist/setup/setup-args.d.ts +1 -1
- package/dist/setup/setup-args.d.ts.map +1 -1
- package/dist/setup/setup-args.js +1 -1
- package/dist/skills/definitions.d.ts.map +1 -1
- package/dist/skills/definitions.js +32 -0
- package/dist/skills/definitions.js.map +1 -1
- package/dist/skills/injection-mode.d.ts +6 -2
- package/dist/skills/injection-mode.d.ts.map +1 -1
- package/dist/skills/injection-mode.js +10 -5
- package/dist/skills/injection-mode.js.map +1 -1
- package/dist/types.d.ts +79 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/child-env.d.ts +1 -1
- package/dist/utils/child-env.d.ts.map +1 -1
- package/dist/utils/child-env.js +4 -0
- package/dist/utils/child-env.js.map +1 -1
- package/dist/utils/effort-confirm-dialog.d.ts +40 -0
- package/dist/utils/effort-confirm-dialog.d.ts.map +1 -0
- package/dist/utils/effort-confirm-dialog.js +74 -0
- package/dist/utils/effort-confirm-dialog.js.map +1 -0
- package/dist/utils/pending-input-queue.d.ts +56 -0
- package/dist/utils/pending-input-queue.d.ts.map +1 -1
- package/dist/utils/pending-input-queue.js +80 -0
- package/dist/utils/pending-input-queue.js.map +1 -1
- package/dist/utils/render-dimensions.d.ts +8 -0
- package/dist/utils/render-dimensions.d.ts.map +1 -1
- package/dist/utils/render-dimensions.js +10 -0
- package/dist/utils/render-dimensions.js.map +1 -1
- package/dist/utils/stuck-key-guard.d.ts +3 -2
- package/dist/utils/stuck-key-guard.d.ts.map +1 -1
- package/dist/utils/stuck-key-guard.js +3 -3
- package/dist/utils/stuck-key-guard.js.map +1 -1
- package/dist/utils/terminal-renderer.d.ts +6 -0
- package/dist/utils/terminal-renderer.d.ts.map +1 -1
- package/dist/utils/terminal-renderer.js +15 -0
- package/dist/utils/terminal-renderer.js.map +1 -1
- package/dist/utils/tui-input-delivery.d.ts +32 -0
- package/dist/utils/tui-input-delivery.d.ts.map +1 -0
- package/dist/utils/tui-input-delivery.js +53 -0
- package/dist/utils/tui-input-delivery.js.map +1 -0
- package/dist/utils/xml.d.ts +19 -0
- package/dist/utils/xml.d.ts.map +1 -0
- package/dist/utils/xml.js +26 -0
- package/dist/utils/xml.js.map +1 -0
- package/dist/worker.js +1852 -374
- package/dist/worker.js.map +1 -1
- package/dist/workflows/definition.d.ts +8 -8
- package/dist/workflows/events/payloads.d.ts +8 -8
- package/dist/workflows/events/schema.d.ts +160 -160
- package/dist/workflows/v3/session-relay-client.js +1 -1
- package/dist/workflows/v3/session-relay-client.js.map +1 -1
- package/dist/workflows/v3/worker-fence.d.ts.map +1 -1
- package/dist/workflows/v3/worker-fence.js +15 -10
- package/dist/workflows/v3/worker-fence.js.map +1 -1
- package/package.json +1 -1
- package/dist/dashboard-web/chunks/bot-defaults-page-UKA7K4JV.js +0 -10
- package/dist/dashboard-web/chunks/chunk-DFLNXQNT.js +0 -1
- package/dist/dashboard-web/chunks/connectors-page-A77YAB5Y.js +0 -1
- package/dist/dashboard-web/chunks/groups-page-RUZNVXQB.js +0 -8
- package/dist/dashboard-web/chunks/insights-page-RF7U7RTA.js +0 -22
- package/dist/dashboard-web/chunks/roles-page-BUMKD7Y4.js +0 -1
- package/dist/dashboard-web/chunks/sessions-page-6HLSEAB7.js +0 -2
- package/dist/dashboard-web/chunks/settings-page-MJDZHQ4X.js +0 -2
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 拉 bot 进群元命令:`@bot /invite @目标bot [@目标bot2 ...]`,也支持
|
|
3
|
+
* `@bot /invite --app cli_xxx(可多个)` 直接按 app_id 拉任意飞书应用。
|
|
4
|
+
*
|
|
5
|
+
* 与 /grant 同款拦截模型(在 dispatcher 路由/spawn 之前处理,见 event-dispatcher):
|
|
6
|
+
* - 必须明确 @ 本 bot 才执行(多 bot 群防重复处理)——执行方(inviter)必须本身
|
|
7
|
+
* 在群内,飞书要求 inviter 是群成员,本 bot 处理这条消息天然满足;
|
|
8
|
+
* - 仅 owner 可用(对齐 /grant 的权限模型);
|
|
9
|
+
* - 命令词之后的 @ 才是目标(共享 mention-targets.ts 的位置解析)。
|
|
10
|
+
*
|
|
11
|
+
* 目标 mention → larkAppId 的解析不走群成员表(目标恰恰不在群里),改查
|
|
12
|
+
* 部署级共享花名册 bots-info.json(每个 daemon 启动时 merge 写入),按显示名
|
|
13
|
+
* 唯一匹配(大小写不敏感,与 /group 的 knownBotNames 判定同款);重名 / 查无
|
|
14
|
+
* 时按目标报错,并提示用 --app 直通。已在群内的目标(live 群 bot 成员表能
|
|
15
|
+
* 对上的)跳过并报「已在群内」,幂等。
|
|
16
|
+
*
|
|
17
|
+
* 拉人走 services/groups-store.ts 的 addBotToChat(proxy=本 bot),与 /group、
|
|
18
|
+
* dashboard groups 面板、vc-agent 共用同一封装;批量失败时回退逐个拉(镜像
|
|
19
|
+
* group-creator 的批处理回退)。
|
|
20
|
+
*/
|
|
21
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
22
|
+
import { join } from 'node:path';
|
|
23
|
+
import { getOwnerOpenId, getBotOpenId } from '../../bot-registry.js';
|
|
24
|
+
import { config } from '../../config.js';
|
|
25
|
+
import { isBotMentioned, extractMessageTextForRouting } from './event-dispatcher.js';
|
|
26
|
+
import { stripLeadingMentions } from './message-parser.js';
|
|
27
|
+
import { addBotToChat } from '../../services/groups-store.js';
|
|
28
|
+
import { listChatBotMembers, replyMessage } from './client.js';
|
|
29
|
+
import { localeForBot, t } from '../../i18n/index.js';
|
|
30
|
+
import { logger } from '../../utils/logger.js';
|
|
31
|
+
import { parseTargetsAfterCommand, isCommandTargetOnly, stripAllMentions } from './mention-targets.js';
|
|
32
|
+
const INVITE_CMD_PATTERN = /\/invite\b/i;
|
|
33
|
+
/** app_id 的合法形状(飞书自建/商店应用均为 cli_ 前缀)。 */
|
|
34
|
+
const APP_ID_PATTERN = /^cli_[A-Za-z0-9]+$/;
|
|
35
|
+
/** 飞书 chatMembers.create 的 id_list 上限很小(实测 >5 即 400,见 group-creator),按 5 一批。 */
|
|
36
|
+
const INVITE_BATCH_SIZE = 5;
|
|
37
|
+
/** 读部署共享花名册 bots-info.json;文件缺失/损坏按空花名册处理(名字解析全部走不通,提示 --app)。 */
|
|
38
|
+
export function readBotsInfoEntries() {
|
|
39
|
+
try {
|
|
40
|
+
const p = join(config.session.dataDir, 'bots-info.json');
|
|
41
|
+
if (!existsSync(p))
|
|
42
|
+
return [];
|
|
43
|
+
const raw = JSON.parse(readFileSync(p, 'utf-8'));
|
|
44
|
+
if (!Array.isArray(raw))
|
|
45
|
+
return [];
|
|
46
|
+
return raw.filter((e) => typeof e?.larkAppId === 'string' && e.larkAppId);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** 从已 stripLeadingMentions 的命令文本解析 --app 参数。 */
|
|
53
|
+
export function parseInviteArgs(text, mentions) {
|
|
54
|
+
// 先剥 mention 显示名(避免 @名字 里的空格干扰 token 切分),再去命令词。
|
|
55
|
+
const body = stripAllMentions(text, mentions).replace(INVITE_CMD_PATTERN, ' ');
|
|
56
|
+
const appIds = [];
|
|
57
|
+
const badAppTokens = [];
|
|
58
|
+
const leftoverTokens = [];
|
|
59
|
+
const tokens = body.split(/\s+/).filter(Boolean);
|
|
60
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
61
|
+
const tok = tokens[i];
|
|
62
|
+
const inline = /^--app=(\S+)$/.exec(tok);
|
|
63
|
+
if (inline) {
|
|
64
|
+
(APP_ID_PATTERN.test(inline[1]) ? appIds : badAppTokens).push(inline[1]);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (tok === '--app') {
|
|
68
|
+
const next = tokens[++i];
|
|
69
|
+
if (next === undefined) {
|
|
70
|
+
badAppTokens.push('');
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
(APP_ID_PATTERN.test(next) ? appIds : badAppTokens).push(next);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
leftoverTokens.push(tok);
|
|
77
|
+
}
|
|
78
|
+
return { appIds: [...new Set(appIds)], badAppTokens, leftover: leftoverTokens.join(' ') };
|
|
79
|
+
}
|
|
80
|
+
/** 批量拉人;整批全失败且 >1 个时回退逐个拉(镜像 group-creator 的批处理回退)。 */
|
|
81
|
+
async function addBotsResilient(larkAppId, chatId, ids) {
|
|
82
|
+
let results = [];
|
|
83
|
+
for (let i = 0; i < ids.length; i += INVITE_BATCH_SIZE) {
|
|
84
|
+
const batch = ids.slice(i, i + INVITE_BATCH_SIZE);
|
|
85
|
+
let r = await addBotToChat(larkAppId, chatId, batch);
|
|
86
|
+
if (batch.length > 1 && r.every(x => !x.ok)) {
|
|
87
|
+
// 整批失败可能是单个坏 id 拖累全批 → 逐个隔离重试,让好 id 落进去。
|
|
88
|
+
const perId = [];
|
|
89
|
+
for (const id of batch)
|
|
90
|
+
perId.push(...await addBotToChat(larkAppId, chatId, [id]));
|
|
91
|
+
r = perId;
|
|
92
|
+
}
|
|
93
|
+
results.push(...r);
|
|
94
|
+
}
|
|
95
|
+
return results;
|
|
96
|
+
}
|
|
97
|
+
/** 返回 true 表示已拦截(不再进入路由/spawn)。 */
|
|
98
|
+
export async function tryHandleInviteCommand(larkAppId, message, senderOpenId) {
|
|
99
|
+
const rawText = extractMessageTextForRouting(message);
|
|
100
|
+
if (!rawText)
|
|
101
|
+
return false;
|
|
102
|
+
// 先 strip 掉开头的 @<mention>(含本 bot),否则 `@bot /invite @x` 匹配不到命令词。
|
|
103
|
+
const text = stripLeadingMentions(rawText.trim(), message?.mentions ?? []);
|
|
104
|
+
if (!/^\/invite(\s|$)/i.test(text))
|
|
105
|
+
return false;
|
|
106
|
+
const myOpenId = getBotOpenId(larkAppId);
|
|
107
|
+
const messageId = message.message_id;
|
|
108
|
+
const chatId = message.chat_id;
|
|
109
|
+
const loc = localeForBot(larkAppId);
|
|
110
|
+
const reply = (key, params) => replyMessage(larkAppId, messageId, t(key, params, loc))
|
|
111
|
+
.catch(err => logger.debug(`invite ${key} reply failed: ${err}`));
|
|
112
|
+
// 本 bot 只是作为 /invite 的【目标】被 @(`@OperatorBot /invite @ThisBot`)→ 命令属于
|
|
113
|
+
// 前导 @ 的操作 bot,本 bot 必须静默放手(同 /grant 的 target-only 守卫)。传 larkAppId
|
|
114
|
+
// 让 guard 也认 app_id 形态的本 bot @(群外/协作 bot 常以 app_id 被 @,只认 open_id 会漏判)。
|
|
115
|
+
if (isCommandTargetOnly(message, myOpenId, INVITE_CMD_PATTERN, larkAppId)) {
|
|
116
|
+
logger.debug(`[invite:${larkAppId}] ignoring /invite where this bot is only a target`);
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
// 私聊拉不了成员。必须在 isBotMentioned 选举门之前:DM 里没有群成员表、用户
|
|
120
|
+
// @ 不出本 bot,放选举门后面这条提示永远不可达,用户只会看到沉默。
|
|
121
|
+
if (message?.chat_type === 'p2p') {
|
|
122
|
+
await reply('cmd.invite.p2p');
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
// 多 bot 群:必须明确 @ 当前 bot 才由本 daemon 处理;否则吞掉(不喂 CLI)。
|
|
126
|
+
if (!isBotMentioned(larkAppId, message, senderOpenId))
|
|
127
|
+
return true;
|
|
128
|
+
// owner 强闸门(对齐 /grant)。
|
|
129
|
+
const owner = getOwnerOpenId(larkAppId);
|
|
130
|
+
if (!senderOpenId || senderOpenId !== owner) {
|
|
131
|
+
await reply('cmd.invite.owner_only');
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
if (!chatId) {
|
|
135
|
+
await reply('cmd.invite.usage');
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
const mentionTargets = parseTargetsAfterCommand(message, myOpenId, INVITE_CMD_PATTERN);
|
|
139
|
+
const args = parseInviteArgs(text, message?.mentions ?? []);
|
|
140
|
+
if (args.badAppTokens.length > 0 || args.leftover) {
|
|
141
|
+
await reply('cmd.invite.usage');
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
if (mentionTargets.length === 0 && args.appIds.length === 0) {
|
|
145
|
+
await reply('cmd.invite.usage');
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
// live 群 bot 成员表:already-in-chat 判定的权威源。拿不到就降级为空表——
|
|
149
|
+
// 飞书 API 自身对重复拉人也是幂等报错,不至于出错事(与 /group 对 listChatBotMembers
|
|
150
|
+
// 的容错一致)。
|
|
151
|
+
let roster = [];
|
|
152
|
+
try {
|
|
153
|
+
roster = await listChatBotMembers(larkAppId, chatId);
|
|
154
|
+
}
|
|
155
|
+
catch (e) {
|
|
156
|
+
logger.warn(`[invite:${larkAppId}] failed to list chat bot members (already-in-chat detection degraded): ${e?.message ?? e}`);
|
|
157
|
+
}
|
|
158
|
+
const rosterOpenIds = new Set(roster.map(m => m.openId));
|
|
159
|
+
const rosterAppIds = new Set(roster.map(m => m.larkAppId).filter(Boolean));
|
|
160
|
+
const rosterNameById = new Map(roster.filter(m => m.larkAppId).map(m => [m.larkAppId, m.displayName || m.name || m.larkAppId]));
|
|
161
|
+
const botsInfo = readBotsInfoEntries();
|
|
162
|
+
const byLowerName = new Map();
|
|
163
|
+
for (const e of botsInfo) {
|
|
164
|
+
const k = e.botName?.toLowerCase();
|
|
165
|
+
if (!k)
|
|
166
|
+
continue;
|
|
167
|
+
(byLowerName.get(k) ?? byLowerName.set(k, []).get(k)).push(e);
|
|
168
|
+
}
|
|
169
|
+
const nameOf = (appId) => botsInfo.find(e => e.larkAppId === appId)?.botName ?? rosterNameById.get(appId) ?? appId;
|
|
170
|
+
const toInvite = [];
|
|
171
|
+
const already = [];
|
|
172
|
+
const unresolved = [];
|
|
173
|
+
const ambiguous = [];
|
|
174
|
+
for (const tgt of mentionTargets) {
|
|
175
|
+
// 已在群内:open_id 命中 live 成员表即跳过(app_id 形态目标无 open_id,靠下方 appId 分支的 rosterAppIds 判定)。
|
|
176
|
+
if (tgt.openId && rosterOpenIds.has(tgt.openId)) {
|
|
177
|
+
already.push(tgt.name);
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
// 目标 mention 自带 app_id(飞书对「群外 bot」的 @ 形态)→ app_id 就是待拉 id,
|
|
181
|
+
// 直接用,跳过名字→花名册解析(更可靠,规避重名/查无)。
|
|
182
|
+
if (tgt.appId) {
|
|
183
|
+
if (tgt.appId === larkAppId || rosterAppIds.has(tgt.appId))
|
|
184
|
+
already.push(tgt.name);
|
|
185
|
+
else if (!toInvite.includes(tgt.appId))
|
|
186
|
+
toInvite.push(tgt.appId);
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
// 仅有 open_id(无 app_id):按显示名查部署花名册解析出 app_id。
|
|
190
|
+
const candidates = tgt.name ? (byLowerName.get(tgt.name.toLowerCase()) ?? []) : [];
|
|
191
|
+
if (candidates.length === 1) {
|
|
192
|
+
const appId = candidates[0].larkAppId;
|
|
193
|
+
if (appId === larkAppId || rosterAppIds.has(appId))
|
|
194
|
+
already.push(tgt.name);
|
|
195
|
+
else if (!toInvite.includes(appId))
|
|
196
|
+
toInvite.push(appId);
|
|
197
|
+
}
|
|
198
|
+
else if (candidates.length > 1) {
|
|
199
|
+
ambiguous.push(t('cmd.invite.ambiguous_item', { name: tgt.name, apps: candidates.map(c => c.larkAppId).join('、') }, loc));
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
unresolved.push(tgt.name || tgt.openId);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
for (const appId of args.appIds) {
|
|
206
|
+
if (appId === larkAppId || rosterAppIds.has(appId))
|
|
207
|
+
already.push(nameOf(appId));
|
|
208
|
+
else if (!toInvite.includes(appId))
|
|
209
|
+
toInvite.push(appId);
|
|
210
|
+
}
|
|
211
|
+
const added = [];
|
|
212
|
+
const failed = [];
|
|
213
|
+
if (toInvite.length > 0) {
|
|
214
|
+
const results = await addBotsResilient(larkAppId, chatId, toInvite);
|
|
215
|
+
for (const r of results) {
|
|
216
|
+
if (r.ok)
|
|
217
|
+
added.push(nameOf(r.id));
|
|
218
|
+
else
|
|
219
|
+
failed.push(t('cmd.invite.failed_item', { name: nameOf(r.id), reason: r.error ?? 'unknown' }, loc));
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
const sections = [];
|
|
223
|
+
if (added.length)
|
|
224
|
+
sections.push(t('cmd.invite.ok', { names: added.join('、') }, loc));
|
|
225
|
+
if (already.length)
|
|
226
|
+
sections.push(t('cmd.invite.already', { names: [...new Set(already)].join('、') }, loc));
|
|
227
|
+
if (unresolved.length)
|
|
228
|
+
sections.push(t('cmd.invite.unresolved', { names: [...new Set(unresolved)].join('、') }, loc));
|
|
229
|
+
if (ambiguous.length)
|
|
230
|
+
sections.push(...ambiguous);
|
|
231
|
+
if (failed.length)
|
|
232
|
+
sections.push(...failed);
|
|
233
|
+
const body = sections.join('\n') || t('cmd.invite.usage', undefined, loc);
|
|
234
|
+
await replyMessage(larkAppId, messageId, toInvite.length > 0 || already.length > 0 ? t('cmd.invite.header', undefined, loc) + '\n' + body : body).catch(err => logger.debug(`invite result reply failed: ${err}`));
|
|
235
|
+
logger.info(`[invite:${larkAppId}] chat=${chatId} added=[${added}] already=[${already}] ` +
|
|
236
|
+
`unresolved=[${unresolved}] ambiguous=${ambiguous.length} failed=[${failed}]`);
|
|
237
|
+
return true;
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=invite-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invite-command.js","sourceRoot":"","sources":["../../../src/im/lark/invite-command.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,7 +19,41 @@
|
|
|
19
19
|
* the outer block (CommonMark spec).
|
|
20
20
|
*/
|
|
21
21
|
import { type Locale } from '../../i18n/index.js';
|
|
22
|
+
import { REPLY_CARD_FOOTER_ELEMENT_ID } from './reply-card-footer-signature.js';
|
|
23
|
+
export { REPLY_CARD_FOOTER_MARKER } from './reply-card-footer-signature.js';
|
|
22
24
|
export type LocalHomeLinkMode = 'filesystem' | 'lexical' | 'disabled';
|
|
25
|
+
/** Native usage facts rendered in a Bot reply-card footer. Context is the
|
|
26
|
+
* latest context-window measurement; tokens are cumulative for the Session.
|
|
27
|
+
* Missing facts are omitted independently and must never be estimated. */
|
|
28
|
+
export interface CardUsageSnapshot {
|
|
29
|
+
context: {
|
|
30
|
+
usedTokens: number;
|
|
31
|
+
windowTokens?: number;
|
|
32
|
+
percentUsed?: number;
|
|
33
|
+
} | null;
|
|
34
|
+
tokens: {
|
|
35
|
+
in: number;
|
|
36
|
+
out: number;
|
|
37
|
+
} | null;
|
|
38
|
+
/** Delta for the latest user turn (small, matches the CLI TUI's per-turn
|
|
39
|
+
* ↑↓). Null for dialects without per-turn tracking. Rendered on the live
|
|
40
|
+
* streaming card; the reply-card footer stays compact and omits it. */
|
|
41
|
+
turnTokens?: {
|
|
42
|
+
in: number;
|
|
43
|
+
out: number;
|
|
44
|
+
} | null;
|
|
45
|
+
}
|
|
46
|
+
export interface ReplyCardFooter {
|
|
47
|
+
/** Fully wrapped markdown content, reusable inside the voice-button row. */
|
|
48
|
+
content: string;
|
|
49
|
+
/** Standalone footer element used by ordinary reply cards. */
|
|
50
|
+
element: {
|
|
51
|
+
tag: 'markdown';
|
|
52
|
+
element_id: typeof REPLY_CARD_FOOTER_ELEMENT_ID;
|
|
53
|
+
text_size: 'notation_small_v2';
|
|
54
|
+
content: string;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
23
57
|
/**
|
|
24
58
|
* Restore the leading slash when a model emits the current user's home path
|
|
25
59
|
* as a relative Markdown link destination. Codex file links are normally
|
|
@@ -41,11 +75,38 @@ export declare const DEFAULT_BRAND_LABEL = "[botmux](https://github.com/deepcold
|
|
|
41
75
|
* `brandLabel` (see {@link resolveBrandLabel}):
|
|
42
76
|
* • `undefined` (unset) → the default botmux link
|
|
43
77
|
* • `''` / whitespace → `null` (brand suppressed)
|
|
44
|
-
* • any other string →
|
|
78
|
+
* • any other string → one trimmed line (markdown allowed)
|
|
45
79
|
* Returning `null` lets callers drop the brand — and, when there's also no
|
|
46
80
|
* recipient, the whole footer (HR included) — so an empty brand reads clean.
|
|
47
81
|
*/
|
|
48
82
|
export declare function brandFooterSegment(brand: string | undefined): string | null;
|
|
83
|
+
/** Format usage as one segment shared by reply-card footers and the live
|
|
84
|
+
* streaming card. The caller supplies native facts; this module only formats
|
|
85
|
+
* them and never infers a context window or token count. Returns null when no
|
|
86
|
+
* valid native metric is available.
|
|
87
|
+
*
|
|
88
|
+
* `variant`:
|
|
89
|
+
* - `'footer'` (default): minimal — context only. Reply-card footers are
|
|
90
|
+
* cramped (brand · usage · 发送给), so the large cumulative token string is
|
|
91
|
+
* dropped here (it lives on the streaming card / usage ledger). 上下文占用
|
|
92
|
+
* is the one glanceable "how full am I" metric worth keeping.
|
|
93
|
+
* - `'streaming'`: rich — context + `本轮 ↑X ↓Y`(per-turn delta, matches the
|
|
94
|
+
* CLI TUI) + `累计 ↑A ↓B`(session total). The live card has room and
|
|
95
|
+
* refreshes during execution. */
|
|
96
|
+
export declare function cardUsageFooterSegment(usage: CardUsageSnapshot, locale?: Locale, variant?: 'footer' | 'streaming'): string | null;
|
|
97
|
+
/** Build the one canonical footer shared by all Bot Session reply cards.
|
|
98
|
+
* Ordering, i18n, the parser marker, grey styling, and recipient rendering live
|
|
99
|
+
* here so direct sends and daemon fallbacks cannot drift apart. */
|
|
100
|
+
export declare function buildReplyCardFooter(opts: {
|
|
101
|
+
brand?: string;
|
|
102
|
+
recipientOpenIds?: readonly string[];
|
|
103
|
+
usage?: CardUsageSnapshot;
|
|
104
|
+
locale?: Locale;
|
|
105
|
+
}): ReplyCardFooter | null;
|
|
106
|
+
/** Clone a caller-supplied schema-2 card and append the canonical reply
|
|
107
|
+
* footer. Returns null for cards without a v2 `body.elements` array or when a
|
|
108
|
+
* caller-owned element already occupies the globally unique footer id. */
|
|
109
|
+
export declare function appendReplyCardFooterToV2Card(card: Record<string, unknown>, opts: Parameters<typeof buildReplyCardFooter>[0]): Record<string, unknown> | null;
|
|
49
110
|
/** Normalize source bytes that must be settled before the card is rendered. */
|
|
50
111
|
export declare function prepareCardMarkdown(input: string, cwd?: string, localHomeLinkMode?: LocalHomeLinkMode): string;
|
|
51
112
|
/**
|
|
@@ -98,10 +159,10 @@ export declare function hasMarkdown(text: string): boolean;
|
|
|
98
159
|
*
|
|
99
160
|
* `brand` is the sending bot's configured `brandLabel` (see
|
|
100
161
|
* {@link brandFooterSegment}): unset → default botmux link, `''` → brand
|
|
101
|
-
* suppressed, else custom. When brand and recipient are
|
|
102
|
-
* footer (HR included) is omitted.
|
|
162
|
+
* suppressed, else custom. When brand, usage, and recipient are all absent the
|
|
163
|
+
* whole footer (HR included) is omitted.
|
|
103
164
|
*/
|
|
104
|
-
export declare function buildMarkdownCard(md: string, recipientOpenId?: string, brand?: string, locale?: Locale, workingDir?: string, localHomeLinkMode?: LocalHomeLinkMode): string;
|
|
165
|
+
export declare function buildMarkdownCard(md: string, recipientOpenId?: string, brand?: string, locale?: Locale, workingDir?: string, localHomeLinkMode?: LocalHomeLinkMode, usage?: CardUsageSnapshot): string;
|
|
105
166
|
/**
|
|
106
167
|
* Build a contextual reply card: a title strip, an optional quoted user
|
|
107
168
|
* prompt, and the assistant body rendered through the same markdown-it
|
|
@@ -126,5 +187,6 @@ export declare function buildContextualReplyCard(opts: {
|
|
|
126
187
|
locale?: Locale;
|
|
127
188
|
workingDir?: string;
|
|
128
189
|
localHomeLinkMode?: LocalHomeLinkMode;
|
|
190
|
+
usage?: CardUsageSnapshot;
|
|
129
191
|
}): string;
|
|
130
192
|
//# sourceMappingURL=md-card.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"md-card.d.ts","sourceRoot":"","sources":["../../../src/im/lark/md-card.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAQH,OAAO,EAAK,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"md-card.d.ts","sourceRoot":"","sources":["../../../src/im/lark/md-card.ts"],"names":[],"mappings":"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"}
|
package/dist/im/lark/md-card.js
CHANGED
|
@@ -24,6 +24,8 @@ import { randomBytes } from 'node:crypto';
|
|
|
24
24
|
import { resolve } from 'node:path';
|
|
25
25
|
import MarkdownIt from 'markdown-it';
|
|
26
26
|
import { t } from '../../i18n/index.js';
|
|
27
|
+
import { REPLY_CARD_FOOTER_ELEMENT_ID, REPLY_CARD_FOOTER_MARKER, } from './reply-card-footer-signature.js';
|
|
28
|
+
export { REPLY_CARD_FOOTER_MARKER } from './reply-card-footer-signature.js';
|
|
27
29
|
const md = new MarkdownIt({ html: false, linkify: false, breaks: false });
|
|
28
30
|
const MAX_LOCAL_HOME_LINK_REPAIRS = 256;
|
|
29
31
|
function escapeRegExp(value) {
|
|
@@ -197,14 +199,190 @@ export const DEFAULT_BRAND_LABEL = '[botmux](https://github.com/deepcoldy/botmux
|
|
|
197
199
|
* `brandLabel` (see {@link resolveBrandLabel}):
|
|
198
200
|
* • `undefined` (unset) → the default botmux link
|
|
199
201
|
* • `''` / whitespace → `null` (brand suppressed)
|
|
200
|
-
* • any other string →
|
|
202
|
+
* • any other string → one trimmed line (markdown allowed)
|
|
201
203
|
* Returning `null` lets callers drop the brand — and, when there's also no
|
|
202
204
|
* recipient, the whole footer (HR included) — so an empty brand reads clean.
|
|
203
205
|
*/
|
|
204
206
|
export function brandFooterSegment(brand) {
|
|
205
207
|
if (brand === undefined)
|
|
206
208
|
return DEFAULT_BRAND_LABEL;
|
|
207
|
-
|
|
209
|
+
const normalized = brand
|
|
210
|
+
.trim()
|
|
211
|
+
.replace(/[ \t]*(?:\r\n?|\n|\u2028|\u2029)+[ \t]*/g, ' ');
|
|
212
|
+
return normalized || null;
|
|
213
|
+
}
|
|
214
|
+
function compactTokenCount(value) {
|
|
215
|
+
const units = [
|
|
216
|
+
{ threshold: 1_000_000_000, suffix: 'B' },
|
|
217
|
+
{ threshold: 1_000_000, suffix: 'M' },
|
|
218
|
+
{ threshold: 1_000, suffix: 'K' },
|
|
219
|
+
];
|
|
220
|
+
let unitIndex = units.findIndex(candidate => value >= candidate.threshold);
|
|
221
|
+
if (unitIndex < 0)
|
|
222
|
+
return Math.round(value).toString();
|
|
223
|
+
let unit = units[unitIndex];
|
|
224
|
+
let scaled = value / unit.threshold;
|
|
225
|
+
// Avoid boundary artifacts such as 1000K/1000M after one-decimal rounding.
|
|
226
|
+
if (unitIndex > 0 && Number(scaled.toFixed(1)) >= 1_000) {
|
|
227
|
+
unit = units[--unitIndex];
|
|
228
|
+
scaled = value / unit.threshold;
|
|
229
|
+
}
|
|
230
|
+
return `${scaled.toFixed(1).replace(/\.0$/, '')}${unit.suffix}`;
|
|
231
|
+
}
|
|
232
|
+
function isNonNegativeFinite(value) {
|
|
233
|
+
return typeof value === 'number' && Number.isFinite(value) && value >= 0;
|
|
234
|
+
}
|
|
235
|
+
/** Format usage as one segment shared by reply-card footers and the live
|
|
236
|
+
* streaming card. The caller supplies native facts; this module only formats
|
|
237
|
+
* them and never infers a context window or token count. Returns null when no
|
|
238
|
+
* valid native metric is available.
|
|
239
|
+
*
|
|
240
|
+
* `variant`:
|
|
241
|
+
* - `'footer'` (default): minimal — context only. Reply-card footers are
|
|
242
|
+
* cramped (brand · usage · 发送给), so the large cumulative token string is
|
|
243
|
+
* dropped here (it lives on the streaming card / usage ledger). 上下文占用
|
|
244
|
+
* is the one glanceable "how full am I" metric worth keeping.
|
|
245
|
+
* - `'streaming'`: rich — context + `本轮 ↑X ↓Y`(per-turn delta, matches the
|
|
246
|
+
* CLI TUI) + `累计 ↑A ↓B`(session total). The live card has room and
|
|
247
|
+
* refreshes during execution. */
|
|
248
|
+
export function cardUsageFooterSegment(usage, locale, variant = 'footer') {
|
|
249
|
+
const parts = [];
|
|
250
|
+
if (usage.context && isNonNegativeFinite(usage.context.usedTokens)) {
|
|
251
|
+
const used = compactTokenCount(usage.context.usedTokens);
|
|
252
|
+
const window = usage.context.windowTokens;
|
|
253
|
+
const windowSuffix = isNonNegativeFinite(window) && window > 0
|
|
254
|
+
? `/${compactTokenCount(window)}`
|
|
255
|
+
: '';
|
|
256
|
+
const percentSuffix = isNonNegativeFinite(usage.context.percentUsed)
|
|
257
|
+
? ` (${Math.min(100, Math.round(usage.context.percentUsed))}%)`
|
|
258
|
+
: '';
|
|
259
|
+
const suffix = `${windowSuffix}${percentSuffix}`;
|
|
260
|
+
parts.push(`${t('card.usage.context', undefined, locale)} ${used}${suffix}`);
|
|
261
|
+
}
|
|
262
|
+
// Footer variant is context-only (keeps the cramped reply-card footer clean);
|
|
263
|
+
// the token breakdown below is streaming-only.
|
|
264
|
+
if (variant !== 'streaming') {
|
|
265
|
+
return parts.length > 0 ? parts.join(' · ') : null;
|
|
266
|
+
}
|
|
267
|
+
// Per-turn delta (streaming only): small ↑↓ for the latest turn, labelled 本轮.
|
|
268
|
+
const turn = usage.turnTokens;
|
|
269
|
+
if (turn
|
|
270
|
+
&& isNonNegativeFinite(turn.in)
|
|
271
|
+
&& isNonNegativeFinite(turn.out)
|
|
272
|
+
&& (turn.in > 0 || turn.out > 0)) {
|
|
273
|
+
parts.push(`${t('card.usage.turn', undefined, locale)} `
|
|
274
|
+
+ `↑${compactTokenCount(turn.in)} ↓${compactTokenCount(turn.out)}`);
|
|
275
|
+
}
|
|
276
|
+
if (usage.tokens
|
|
277
|
+
&& isNonNegativeFinite(usage.tokens.in)
|
|
278
|
+
&& isNonNegativeFinite(usage.tokens.out)
|
|
279
|
+
// Suppress an all-zero token line: a brand-new session (or a synthetic /
|
|
280
|
+
// zero-usage transcript record read before the real turn lands) yields
|
|
281
|
+
// in=out=0, which would render a meaningless "↑0 ↓0". Omit it like any
|
|
282
|
+
// other missing metric until there is real usage to show.
|
|
283
|
+
&& (usage.tokens.in > 0 || usage.tokens.out > 0)) {
|
|
284
|
+
parts.push(`${t('card.usage.total', undefined, locale)} `
|
|
285
|
+
+ `↑${compactTokenCount(usage.tokens.in)} ↓${compactTokenCount(usage.tokens.out)}`);
|
|
286
|
+
}
|
|
287
|
+
return parts.length > 0 ? parts.join(' · ') : null;
|
|
288
|
+
}
|
|
289
|
+
/** Build the one canonical footer shared by all Bot Session reply cards.
|
|
290
|
+
* Ordering, i18n, the parser marker, grey styling, and recipient rendering live
|
|
291
|
+
* here so direct sends and daemon fallbacks cannot drift apart. */
|
|
292
|
+
export function buildReplyCardFooter(opts) {
|
|
293
|
+
const parts = [];
|
|
294
|
+
const brandSeg = brandFooterSegment(opts.brand);
|
|
295
|
+
if (brandSeg)
|
|
296
|
+
parts.push(brandSeg);
|
|
297
|
+
let hasUsage = false;
|
|
298
|
+
if (opts.usage) {
|
|
299
|
+
const usageSeg = cardUsageFooterSegment(opts.usage, opts.locale);
|
|
300
|
+
if (usageSeg) {
|
|
301
|
+
parts.push(usageSeg);
|
|
302
|
+
hasUsage = true;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
const recipientOpenIds = [...new Set((opts.recipientOpenIds ?? []).filter(Boolean))];
|
|
306
|
+
const hasRecipient = recipientOpenIds.length > 0;
|
|
307
|
+
if (hasRecipient) {
|
|
308
|
+
parts.push(`${t('card.sent_to', undefined, opts.locale)}`
|
|
309
|
+
+ recipientOpenIds.map(id => `<at id=${id}></at>`).join(' '));
|
|
310
|
+
}
|
|
311
|
+
if (parts.length === 0)
|
|
312
|
+
return null;
|
|
313
|
+
// The marker is a visible, versioned link that lets the parser identify a
|
|
314
|
+
// card's footer (and strip it before a bot-to-bot relay). It doubles as the
|
|
315
|
+
// first separator. But a BRAND-ONLY footer (no usage, no recipient — the
|
|
316
|
+
// common case now that usageDisplay defaults to the streaming card body and
|
|
317
|
+
// the reply-card footer is context-only) needs no marker: appending it renders
|
|
318
|
+
// a dangling "botmux ·". The default/repository brand is plain link text with
|
|
319
|
+
// no `@`, so it cannot trigger bot-to-bot pollution and does not need the
|
|
320
|
+
// ownership marker (the parser already treats a bare repo link as ordinary
|
|
321
|
+
// content, matching the long-standing "brand-only is undecidable, keep it"
|
|
322
|
+
// contract). Any footer carrying usage or a recipient is still signed.
|
|
323
|
+
const signMarker = hasUsage || hasRecipient;
|
|
324
|
+
let signedContent;
|
|
325
|
+
if (!signMarker) {
|
|
326
|
+
signedContent = parts[0]; // brand-only — no marker
|
|
327
|
+
}
|
|
328
|
+
else if (parts.length > 1) {
|
|
329
|
+
signedContent = `${parts[0]} ${REPLY_CARD_FOOTER_MARKER} ${parts.slice(1).join(' · ')}`;
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
// usage-only / recipient-only (brand disabled) — still marked for parsing.
|
|
333
|
+
signedContent = `${parts[0]} ${REPLY_CARD_FOOTER_MARKER}`;
|
|
334
|
+
}
|
|
335
|
+
const content = `<font color='grey'>${signedContent}</font>`;
|
|
336
|
+
return {
|
|
337
|
+
content,
|
|
338
|
+
element: {
|
|
339
|
+
tag: 'markdown',
|
|
340
|
+
element_id: REPLY_CARD_FOOTER_ELEMENT_ID,
|
|
341
|
+
text_size: 'notation_small_v2',
|
|
342
|
+
content,
|
|
343
|
+
},
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
/** Clone a caller-supplied schema-2 card and append the canonical reply
|
|
347
|
+
* footer. Returns null for cards without a v2 `body.elements` array or when a
|
|
348
|
+
* caller-owned element already occupies the globally unique footer id. */
|
|
349
|
+
export function appendReplyCardFooterToV2Card(card, opts) {
|
|
350
|
+
const cloned = JSON.parse(JSON.stringify(card));
|
|
351
|
+
if (cloned.schema !== '2.0')
|
|
352
|
+
return null;
|
|
353
|
+
const body = cloned.body;
|
|
354
|
+
if (!body || !Array.isArray(body.elements))
|
|
355
|
+
return null;
|
|
356
|
+
const header = cloned.header;
|
|
357
|
+
const i18nHeaderTagLists = header?.i18n_text_tag_list
|
|
358
|
+
&& typeof header.i18n_text_tag_list === 'object'
|
|
359
|
+
? Object.values(header.i18n_text_tag_list)
|
|
360
|
+
: [];
|
|
361
|
+
if (containsReplyCardFooterId(body.elements)
|
|
362
|
+
|| containsReplyCardFooterId(header?.text_tag_list)
|
|
363
|
+
|| containsReplyCardFooterId(i18nHeaderTagLists)) {
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
const footer = buildReplyCardFooter(opts);
|
|
367
|
+
if (footer)
|
|
368
|
+
body.elements.push({ tag: 'hr' }, footer.element);
|
|
369
|
+
return cloned;
|
|
370
|
+
}
|
|
371
|
+
function containsReplyCardFooterId(value) {
|
|
372
|
+
if (Array.isArray(value))
|
|
373
|
+
return value.some(containsReplyCardFooterId);
|
|
374
|
+
if (!value || typeof value !== 'object')
|
|
375
|
+
return false;
|
|
376
|
+
const record = value;
|
|
377
|
+
if (record.element_id === REPLY_CARD_FOOTER_ELEMENT_ID)
|
|
378
|
+
return true;
|
|
379
|
+
// Follow only documented component-child slots. Callback `value`, behavior
|
|
380
|
+
// payloads, and other arbitrary business JSON are deliberately outside the
|
|
381
|
+
// card component tree even when they contain tag/element_id-shaped fields.
|
|
382
|
+
return containsReplyCardFooterId(record.elements)
|
|
383
|
+
|| containsReplyCardFooterId(record.columns)
|
|
384
|
+
|| containsReplyCardFooterId(record.actions)
|
|
385
|
+
|| containsReplyCardFooterId(record.extra);
|
|
208
386
|
}
|
|
209
387
|
/** Build a Feishu native `table` element from a `table_open … table_close` token slice. */
|
|
210
388
|
function buildTableFromTokens(tokens) {
|
|
@@ -605,25 +783,21 @@ export function hasMarkdown(text) {
|
|
|
605
783
|
*
|
|
606
784
|
* `brand` is the sending bot's configured `brandLabel` (see
|
|
607
785
|
* {@link brandFooterSegment}): unset → default botmux link, `''` → brand
|
|
608
|
-
* suppressed, else custom. When brand and recipient are
|
|
609
|
-
* footer (HR included) is omitted.
|
|
786
|
+
* suppressed, else custom. When brand, usage, and recipient are all absent the
|
|
787
|
+
* whole footer (HR included) is omitted.
|
|
610
788
|
*/
|
|
611
|
-
export function buildMarkdownCard(md, recipientOpenId, brand, locale, workingDir, localHomeLinkMode = 'filesystem') {
|
|
789
|
+
export function buildMarkdownCard(md, recipientOpenId, brand, locale, workingDir, localHomeLinkMode = 'filesystem', usage) {
|
|
612
790
|
const elements = md ? buildCardBodyElements(md, workingDir, localHomeLinkMode) : [];
|
|
613
|
-
const
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
//
|
|
620
|
-
if (
|
|
791
|
+
const footer = buildReplyCardFooter({
|
|
792
|
+
brand,
|
|
793
|
+
recipientOpenIds: recipientOpenId ? [recipientOpenId] : [],
|
|
794
|
+
usage,
|
|
795
|
+
locale,
|
|
796
|
+
});
|
|
797
|
+
// No brand, usage, or recipient → no footer at all (skip the orphan HR too).
|
|
798
|
+
if (footer) {
|
|
621
799
|
elements.push({ tag: 'hr' });
|
|
622
|
-
elements.push(
|
|
623
|
-
tag: 'markdown',
|
|
624
|
-
text_size: 'notation_small_v2',
|
|
625
|
-
content: `<font color='grey'>${footerParts.join(' · ')}</font>`,
|
|
626
|
-
});
|
|
800
|
+
elements.push(footer.element);
|
|
627
801
|
}
|
|
628
802
|
return JSON.stringify({
|
|
629
803
|
schema: '2.0',
|
|
@@ -655,7 +829,7 @@ function quoteLines(text) {
|
|
|
655
829
|
* section entirely (headless variant).
|
|
656
830
|
*/
|
|
657
831
|
export function buildContextualReplyCard(opts) {
|
|
658
|
-
const { title, userText, assistantText, assistantLabel, recipientOpenId, brand, locale, workingDir, localHomeLinkMode = 'filesystem', } = opts;
|
|
832
|
+
const { title, userText, assistantText, assistantLabel, recipientOpenId, brand, locale, workingDir, localHomeLinkMode = 'filesystem', usage, } = opts;
|
|
659
833
|
const elements = [];
|
|
660
834
|
elements.push({
|
|
661
835
|
tag: 'markdown',
|
|
@@ -679,19 +853,15 @@ export function buildContextualReplyCard(opts) {
|
|
|
679
853
|
: [{ tag: 'markdown', content: `*${t('common.empty_paren', undefined, locale)}*` }];
|
|
680
854
|
for (const el of bodyElements)
|
|
681
855
|
elements.push(el);
|
|
682
|
-
const
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
if (
|
|
856
|
+
const footer = buildReplyCardFooter({
|
|
857
|
+
brand,
|
|
858
|
+
recipientOpenIds: recipientOpenId ? [recipientOpenId] : [],
|
|
859
|
+
usage,
|
|
860
|
+
locale,
|
|
861
|
+
});
|
|
862
|
+
if (footer) {
|
|
689
863
|
elements.push({ tag: 'hr' });
|
|
690
|
-
elements.push(
|
|
691
|
-
tag: 'markdown',
|
|
692
|
-
text_size: 'notation_small_v2',
|
|
693
|
-
content: `<font color='grey'>${footerParts.join(' · ')}</font>`,
|
|
694
|
-
});
|
|
864
|
+
elements.push(footer.element);
|
|
695
865
|
}
|
|
696
866
|
return JSON.stringify({
|
|
697
867
|
schema: '2.0',
|