botmux 3.13.0 → 3.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +1 -1
- package/README.md +25 -1
- package/dist/.runtime-build-id +1 -1
- package/dist/adapters/adopt-route.d.ts +58 -0
- package/dist/adapters/adopt-route.d.ts.map +1 -1
- package/dist/adapters/adopt-route.js +136 -0
- package/dist/adapters/adopt-route.js.map +1 -1
- package/dist/adapters/backend/capabilities.js +1 -1
- package/dist/adapters/backend/capabilities.js.map +1 -1
- package/dist/adapters/backend/herdr-backend.d.ts +1 -1
- package/dist/adapters/backend/herdr-backend.d.ts.map +1 -1
- package/dist/adapters/backend/herdr-backend.js +2 -1
- package/dist/adapters/backend/herdr-backend.js.map +1 -1
- package/dist/adapters/backend/riff-backend.d.ts +97 -0
- package/dist/adapters/backend/riff-backend.d.ts.map +1 -1
- package/dist/adapters/backend/riff-backend.js +380 -66
- package/dist/adapters/backend/riff-backend.js.map +1 -1
- package/dist/adapters/backend/sandbox.d.ts +8 -0
- package/dist/adapters/backend/sandbox.d.ts.map +1 -1
- package/dist/adapters/backend/sandbox.js +16 -2
- package/dist/adapters/backend/sandbox.js.map +1 -1
- package/dist/adapters/backend/tmux-backend.d.ts +12 -13
- package/dist/adapters/backend/tmux-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-backend.js +113 -53
- package/dist/adapters/backend/tmux-backend.js.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.d.ts +4 -3
- package/dist/adapters/backend/tmux-pipe-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.js +12 -9
- package/dist/adapters/backend/tmux-pipe-backend.js.map +1 -1
- package/dist/adapters/backend/zellij-backend.d.ts +2 -3
- package/dist/adapters/backend/zellij-backend.d.ts.map +1 -1
- package/dist/adapters/backend/zellij-backend.js +6 -13
- package/dist/adapters/backend/zellij-backend.js.map +1 -1
- package/dist/adapters/backend/zellij-observe-backend.d.ts +2 -1
- package/dist/adapters/backend/zellij-observe-backend.d.ts.map +1 -1
- package/dist/adapters/backend/zellij-observe-backend.js +6 -3
- package/dist/adapters/backend/zellij-observe-backend.js.map +1 -1
- package/dist/adapters/backend/zmx-backend.d.ts.map +1 -1
- package/dist/adapters/backend/zmx-backend.js +40 -18
- package/dist/adapters/backend/zmx-backend.js.map +1 -1
- package/dist/adapters/cli/claude-code.d.ts.map +1 -1
- package/dist/adapters/cli/claude-code.js +12 -1
- package/dist/adapters/cli/claude-code.js.map +1 -1
- package/dist/adapters/cli/codex.d.ts.map +1 -1
- package/dist/adapters/cli/codex.js +3 -2
- package/dist/adapters/cli/codex.js.map +1 -1
- package/dist/adapters/cli/dsh.d.ts +4 -0
- package/dist/adapters/cli/dsh.d.ts.map +1 -0
- package/dist/adapters/cli/dsh.js +96 -0
- package/dist/adapters/cli/dsh.js.map +1 -0
- package/dist/adapters/cli/fs-policy.d.ts.map +1 -1
- package/dist/adapters/cli/fs-policy.js +5 -0
- package/dist/adapters/cli/fs-policy.js.map +1 -1
- package/dist/adapters/cli/opencode.d.ts +52 -1
- package/dist/adapters/cli/opencode.d.ts.map +1 -1
- package/dist/adapters/cli/opencode.js +117 -76
- package/dist/adapters/cli/opencode.js.map +1 -1
- package/dist/adapters/cli/opencode2.d.ts +4 -0
- package/dist/adapters/cli/opencode2.d.ts.map +1 -0
- package/dist/adapters/cli/opencode2.js +137 -0
- package/dist/adapters/cli/opencode2.js.map +1 -0
- package/dist/adapters/cli/read-isolation.d.ts +1 -1
- package/dist/adapters/cli/read-isolation.d.ts.map +1 -1
- package/dist/adapters/cli/read-isolation.js +5 -2
- package/dist/adapters/cli/read-isolation.js.map +1 -1
- package/dist/adapters/cli/registry.d.ts +7 -1
- package/dist/adapters/cli/registry.d.ts.map +1 -1
- package/dist/adapters/cli/registry.js +19 -6
- package/dist/adapters/cli/registry.js.map +1 -1
- package/dist/adapters/cli/shared-hints.d.ts.map +1 -1
- package/dist/adapters/cli/shared-hints.js +13 -0
- package/dist/adapters/cli/shared-hints.js.map +1 -1
- package/dist/adapters/cli/types.d.ts +24 -3
- package/dist/adapters/cli/types.d.ts.map +1 -1
- package/dist/adapters/hook-command.d.ts +8 -0
- package/dist/adapters/hook-command.d.ts.map +1 -1
- package/dist/adapters/hook-command.js +11 -0
- package/dist/adapters/hook-command.js.map +1 -1
- package/dist/adapters/hook-installer.d.ts +16 -1
- package/dist/adapters/hook-installer.d.ts.map +1 -1
- package/dist/adapters/hook-installer.js +232 -2
- package/dist/adapters/hook-installer.js.map +1 -1
- package/dist/bot-registry.d.ts +116 -8
- package/dist/bot-registry.d.ts.map +1 -1
- package/dist/bot-registry.js +52 -4
- package/dist/bot-registry.js.map +1 -1
- package/dist/cli/pm2-start-transaction.d.ts +14 -0
- package/dist/cli/pm2-start-transaction.d.ts.map +1 -1
- package/dist/cli/pm2-start-transaction.js +25 -9
- package/dist/cli/pm2-start-transaction.js.map +1 -1
- package/dist/cli/restart-failure-notification.d.ts +54 -0
- package/dist/cli/restart-failure-notification.d.ts.map +1 -0
- package/dist/cli/restart-failure-notification.js +142 -0
- package/dist/cli/restart-failure-notification.js.map +1 -0
- package/dist/cli/restart-failure-owner.d.ts +20 -0
- package/dist/cli/restart-failure-owner.d.ts.map +1 -0
- package/dist/cli/restart-failure-owner.js +27 -0
- package/dist/cli/restart-failure-owner.js.map +1 -0
- package/dist/cli/restart-shutdown-preflight.d.ts +24 -0
- package/dist/cli/restart-shutdown-preflight.d.ts.map +1 -0
- package/dist/cli/restart-shutdown-preflight.js +105 -0
- package/dist/cli/restart-shutdown-preflight.js.map +1 -0
- package/dist/cli/send-dispatch.d.ts +26 -0
- package/dist/cli/send-dispatch.d.ts.map +1 -1
- package/dist/cli/send-dispatch.js +30 -0
- package/dist/cli/send-dispatch.js.map +1 -1
- package/dist/cli.d.ts +4 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +665 -399
- package/dist/cli.js.map +1 -1
- package/dist/codex-app-runner.js +38 -15
- package/dist/codex-app-runner.js.map +1 -1
- package/dist/codex-rpc-lifecycle.d.ts +14 -2
- package/dist/codex-rpc-lifecycle.d.ts.map +1 -1
- package/dist/codex-rpc-lifecycle.js +13 -3
- package/dist/codex-rpc-lifecycle.js.map +1 -1
- package/dist/core/ask-broker.d.ts +3 -0
- package/dist/core/ask-broker.d.ts.map +1 -1
- package/dist/core/ask-broker.js +29 -7
- package/dist/core/ask-broker.js.map +1 -1
- package/dist/core/ask-hook/registry.d.ts.map +1 -1
- package/dist/core/ask-hook/registry.js +4 -0
- package/dist/core/ask-hook/registry.js.map +1 -1
- package/dist/core/ask-types.d.ts +5 -1
- package/dist/core/ask-types.d.ts.map +1 -1
- package/dist/core/ask-types.js.map +1 -1
- package/dist/core/browser-restart.d.ts +112 -0
- package/dist/core/browser-restart.d.ts.map +1 -0
- package/dist/core/browser-restart.js +233 -0
- package/dist/core/browser-restart.js.map +1 -0
- package/dist/core/command-handler.d.ts +19 -11
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +237 -43
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/current-turn-provenance.d.ts.map +1 -1
- package/dist/core/current-turn-provenance.js +7 -27
- package/dist/core/current-turn-provenance.js.map +1 -1
- package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
- package/dist/core/dashboard-ipc-server.js +317 -10
- package/dist/core/dashboard-ipc-server.js.map +1 -1
- package/dist/core/dispatch-registry.d.ts.map +1 -1
- package/dist/core/dispatch-registry.js +6 -0
- package/dist/core/dispatch-registry.js.map +1 -1
- package/dist/core/dispatch-report-binding.d.ts +31 -0
- package/dist/core/dispatch-report-binding.d.ts.map +1 -0
- package/dist/core/dispatch-report-binding.js +88 -0
- package/dist/core/dispatch-report-binding.js.map +1 -0
- package/dist/core/doc-comment-prompt.d.ts +2 -0
- package/dist/core/doc-comment-prompt.d.ts.map +1 -1
- package/dist/core/doc-comment-prompt.js +6 -0
- package/dist/core/doc-comment-prompt.js.map +1 -1
- package/dist/core/host-overload-alert.d.ts +25 -1
- package/dist/core/host-overload-alert.d.ts.map +1 -1
- package/dist/core/host-overload-alert.js +69 -8
- package/dist/core/host-overload-alert.js.map +1 -1
- package/dist/core/local-terminal-opener.js +1 -1
- package/dist/core/local-terminal-opener.js.map +1 -1
- package/dist/core/managed-origin-capability.d.ts +7 -6
- package/dist/core/managed-origin-capability.d.ts.map +1 -1
- package/dist/core/managed-origin-capability.js +32 -1
- package/dist/core/managed-origin-capability.js.map +1 -1
- package/dist/core/passthrough-commands.d.ts.map +1 -1
- package/dist/core/passthrough-commands.js +3 -2
- package/dist/core/passthrough-commands.js.map +1 -1
- package/dist/core/plugins/materializer.d.ts.map +1 -1
- package/dist/core/plugins/materializer.js +1 -0
- package/dist/core/plugins/materializer.js.map +1 -1
- package/dist/core/producer-quiescence.d.ts +70 -0
- package/dist/core/producer-quiescence.d.ts.map +1 -0
- package/dist/core/producer-quiescence.js +90 -0
- package/dist/core/producer-quiescence.js.map +1 -0
- package/dist/core/raw-command-write-options.d.ts +10 -0
- package/dist/core/raw-command-write-options.d.ts.map +1 -0
- package/dist/core/raw-command-write-options.js +23 -0
- package/dist/core/raw-command-write-options.js.map +1 -0
- package/dist/core/raw-command-writer.d.ts +4 -0
- package/dist/core/raw-command-writer.d.ts.map +1 -1
- package/dist/core/raw-command-writer.js +15 -6
- package/dist/core/raw-command-writer.js.map +1 -1
- package/dist/core/reply-target.d.ts +11 -0
- package/dist/core/reply-target.d.ts.map +1 -1
- package/dist/core/reply-target.js +22 -7
- package/dist/core/reply-target.js.map +1 -1
- package/dist/core/report-session-relay.d.ts +53 -0
- package/dist/core/report-session-relay.d.ts.map +1 -0
- package/dist/core/report-session-relay.js +116 -0
- package/dist/core/report-session-relay.js.map +1 -0
- package/dist/core/session-discovery.d.ts +5 -0
- package/dist/core/session-discovery.d.ts.map +1 -1
- package/dist/core/session-discovery.js +13 -0
- package/dist/core/session-discovery.js.map +1 -1
- package/dist/core/session-group-birth.d.ts +7 -0
- package/dist/core/session-group-birth.d.ts.map +1 -0
- package/dist/core/session-group-birth.js +145 -0
- package/dist/core/session-group-birth.js.map +1 -0
- package/dist/core/session-manager.d.ts +16 -21
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +140 -21
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/trigger-session.d.ts.map +1 -1
- package/dist/core/trigger-session.js +18 -3
- package/dist/core/trigger-session.js.map +1 -1
- package/dist/core/types.d.ts +18 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/core/worker-pool.d.ts +63 -11
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +241 -13
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.d.ts +33 -0
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +900 -137
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/auth.d.ts +20 -0
- package/dist/dashboard/auth.d.ts.map +1 -1
- package/dist/dashboard/auth.js +86 -1
- package/dist/dashboard/auth.js.map +1 -1
- package/dist/dashboard/bot-payload.d.ts +5 -0
- package/dist/dashboard/bot-payload.d.ts.map +1 -1
- package/dist/dashboard/bot-payload.js +4 -1
- package/dist/dashboard/bot-payload.js.map +1 -1
- package/dist/dashboard/federation-spoke-api.d.ts.map +1 -1
- package/dist/dashboard/federation-spoke-api.js +27 -3
- package/dist/dashboard/federation-spoke-api.js.map +1 -1
- package/dist/dashboard/feedback-analytics-api.d.ts +6 -0
- package/dist/dashboard/feedback-analytics-api.d.ts.map +1 -0
- package/dist/dashboard/feedback-analytics-api.js +39 -0
- package/dist/dashboard/feedback-analytics-api.js.map +1 -0
- package/dist/dashboard/session-action-timeout.d.ts +3 -0
- package/dist/dashboard/session-action-timeout.d.ts.map +1 -0
- package/dist/dashboard/session-action-timeout.js +12 -0
- package/dist/dashboard/session-action-timeout.js.map +1 -0
- package/dist/dashboard/vc-consumer-profiles-api.d.ts +9 -3
- package/dist/dashboard/vc-consumer-profiles-api.d.ts.map +1 -1
- package/dist/dashboard/vc-consumer-profiles-api.js +2 -1
- package/dist/dashboard/vc-consumer-profiles-api.js.map +1 -1
- package/dist/dashboard/web/app.d.ts.map +1 -1
- package/dist/dashboard/web/app.js +48 -5
- package/dist/dashboard/web/app.js.map +1 -1
- package/dist/dashboard/web/bot-defaults-page.d.ts +4 -0
- package/dist/dashboard/web/bot-defaults-page.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults-page.js +273 -36
- package/dist/dashboard/web/bot-defaults-page.js.map +1 -1
- package/dist/dashboard/web/bot-defaults.d.ts +6 -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/dashboard-routes.d.ts.map +1 -1
- package/dist/dashboard/web/dashboard-routes.js +1 -0
- package/dist/dashboard/web/dashboard-routes.js.map +1 -1
- package/dist/dashboard/web/feedback-page.d.ts +3 -0
- package/dist/dashboard/web/feedback-page.d.ts.map +1 -0
- package/dist/dashboard/web/feedback-page.js +34 -0
- package/dist/dashboard/web/feedback-page.js.map +1 -0
- package/dist/dashboard/web/groups-page.d.ts.map +1 -1
- package/dist/dashboard/web/groups-page.js +7 -2
- 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 +114 -22
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard/web/team-federation-page.d.ts.map +1 -1
- package/dist/dashboard/web/team-federation-page.js +26 -2
- package/dist/dashboard/web/team-federation-page.js.map +1 -1
- package/dist/dashboard/web/team-federation.d.ts +19 -0
- package/dist/dashboard/web/team-federation.d.ts.map +1 -1
- package/dist/dashboard/web/team-federation.js +3 -0
- package/dist/dashboard/web/team-federation.js.map +1 -1
- package/dist/dashboard/web/update-action.d.ts +8 -0
- package/dist/dashboard/web/update-action.d.ts.map +1 -1
- package/dist/dashboard/web/update-action.js +10 -0
- package/dist/dashboard/web/update-action.js.map +1 -1
- package/dist/dashboard/web/vc-consumer-profiles-section.d.ts.map +1 -1
- package/dist/dashboard/web/vc-consumer-profiles-section.js +58 -9
- package/dist/dashboard/web/vc-consumer-profiles-section.js.map +1 -1
- package/dist/dashboard-web/app.js +1 -1
- package/dist/dashboard-web/chunks/bot-defaults-page-4RENHE7J.js +10 -0
- package/dist/dashboard-web/chunks/chunk-2WQDS65D.js +1 -0
- package/dist/dashboard-web/chunks/{chunk-CU4SUKK3.js → chunk-6O7KXFD2.js} +1 -1
- package/dist/dashboard-web/chunks/chunk-G5XGBCM6.js +1 -0
- package/dist/dashboard-web/chunks/{chunk-6JTZJRQJ.js → chunk-Q2MT4VWH.js} +15 -15
- package/dist/dashboard-web/chunks/{chunk-5QJB24I2.js → chunk-U3ZFSO7E.js} +1 -1
- package/dist/dashboard-web/chunks/connectors-page-2KZO5KSJ.js +1 -0
- package/dist/dashboard-web/chunks/feedback-page-CLVTOLLO.js +1 -0
- package/dist/dashboard-web/chunks/groups-page-HLASRTSY.js +8 -0
- package/dist/dashboard-web/chunks/{insights-page-EVGGJI5L.js → insights-page-4RPU2CRU.js} +1 -1
- package/dist/dashboard-web/chunks/{monitor-room-HRGR2ENP.js → monitor-room-OTKQ2CXK.js} +1 -1
- package/dist/dashboard-web/chunks/monitoring-page-IJPUB6JT.js +2 -0
- package/dist/dashboard-web/chunks/office-page-QSR3J44Y.js +1 -0
- package/dist/dashboard-web/chunks/overview-page-6OK63V4V.js +1 -0
- package/dist/dashboard-web/chunks/roles-page-6NWJMOB5.js +1 -0
- package/dist/dashboard-web/chunks/schedules-page-6I3LNXD4.js +1 -0
- package/dist/dashboard-web/chunks/{sessions-page-DXBCDWCS.js → sessions-page-B2TXGJDO.js} +1 -1
- package/dist/dashboard-web/chunks/settings-page-6KJADSC6.js +2 -0
- package/dist/dashboard-web/chunks/{skills-page-2QAVB2SA.js → skills-page-M2Q6L5CB.js} +1 -1
- package/dist/dashboard-web/chunks/team-federation-page-7I7FDE3B.js +1 -0
- package/dist/dashboard-web/chunks/{v3-page-AY35LKCX.js → v3-page-HQXRL65L.js} +1 -1
- package/dist/dashboard-web/chunks/whiteboards-page-LQKC4TAZ.js +1 -0
- package/dist/dashboard-web/style.css +35 -0
- package/dist/dashboard.js +199 -12
- package/dist/dashboard.js.map +1 -1
- package/dist/desktop/shared/shell-path-probes.d.ts +1 -1
- package/dist/desktop/shared/shell-path-probes.js +2 -2
- package/dist/desktop/shared/shell-path-probes.js.map +1 -1
- package/dist/dsh-runner.d.ts +3 -0
- package/dist/dsh-runner.d.ts.map +1 -0
- package/dist/dsh-runner.js +666 -0
- package/dist/dsh-runner.js.map +1 -0
- package/dist/global-config.d.ts +24 -0
- package/dist/global-config.d.ts.map +1 -1
- package/dist/global-config.js +35 -0
- package/dist/global-config.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +25 -6
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +25 -6
- package/dist/i18n/zh.js.map +1 -1
- package/dist/im/lark/ask-card.d.ts +3 -1
- package/dist/im/lark/ask-card.d.ts.map +1 -1
- package/dist/im/lark/ask-card.js +61 -5
- package/dist/im/lark/ask-card.js.map +1 -1
- package/dist/im/lark/card-builder.d.ts.map +1 -1
- package/dist/im/lark/card-builder.js +13 -6
- package/dist/im/lark/card-builder.js.map +1 -1
- package/dist/im/lark/card-handler.d.ts +2 -1
- package/dist/im/lark/card-handler.d.ts.map +1 -1
- package/dist/im/lark/card-handler.js +145 -5
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/im/lark/event-dispatcher.d.ts +18 -0
- package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
- package/dist/im/lark/event-dispatcher.js +36 -9
- package/dist/im/lark/event-dispatcher.js.map +1 -1
- package/dist/im/lark/md-card.d.ts +18 -0
- package/dist/im/lark/md-card.d.ts.map +1 -1
- package/dist/im/lark/md-card.js +21 -0
- package/dist/im/lark/md-card.js.map +1 -1
- package/dist/im/lark/relay-target-routing.d.ts.map +1 -1
- package/dist/im/lark/relay-target-routing.js +3 -2
- package/dist/im/lark/relay-target-routing.js.map +1 -1
- package/dist/im/lark/reply-mode-command.d.ts.map +1 -1
- package/dist/im/lark/reply-mode-command.js +19 -8
- package/dist/im/lark/reply-mode-command.js.map +1 -1
- package/dist/im/lark/skill-feedback-card.d.ts +15 -0
- package/dist/im/lark/skill-feedback-card.d.ts.map +1 -0
- package/dist/im/lark/skill-feedback-card.js +149 -0
- package/dist/im/lark/skill-feedback-card.js.map +1 -0
- package/dist/services/bot-config-store.d.ts +10 -1
- package/dist/services/bot-config-store.d.ts.map +1 -1
- package/dist/services/bot-config-store.js +103 -3
- package/dist/services/bot-config-store.js.map +1 -1
- package/dist/services/bridge-fallback-gate.d.ts +14 -0
- package/dist/services/bridge-fallback-gate.d.ts.map +1 -1
- package/dist/services/bridge-fallback-gate.js +15 -0
- package/dist/services/bridge-fallback-gate.js.map +1 -1
- package/dist/services/codex-reasoning-effort.d.ts +9 -0
- package/dist/services/codex-reasoning-effort.d.ts.map +1 -0
- package/dist/services/codex-reasoning-effort.js +23 -0
- package/dist/services/codex-reasoning-effort.js.map +1 -0
- package/dist/services/codex-service-tier.d.ts +1 -1
- package/dist/services/codex-service-tier.d.ts.map +1 -1
- package/dist/services/codex-transcript.d.ts +9 -0
- package/dist/services/codex-transcript.d.ts.map +1 -1
- package/dist/services/codex-transcript.js +13 -6
- package/dist/services/codex-transcript.js.map +1 -1
- package/dist/services/feed-group-tagger.d.ts +15 -0
- package/dist/services/feed-group-tagger.d.ts.map +1 -0
- package/dist/services/feed-group-tagger.js +348 -0
- package/dist/services/feed-group-tagger.js.map +1 -0
- package/dist/services/feedback-analytics.d.ts +82 -0
- package/dist/services/feedback-analytics.d.ts.map +1 -0
- package/dist/services/feedback-analytics.js +95 -0
- package/dist/services/feedback-analytics.js.map +1 -0
- package/dist/services/feedback-outbox.d.ts +24 -0
- package/dist/services/feedback-outbox.d.ts.map +1 -0
- package/dist/services/feedback-outbox.js +12 -0
- package/dist/services/feedback-outbox.js.map +1 -0
- package/dist/services/feedback-policy-resolver.d.ts +56 -0
- package/dist/services/feedback-policy-resolver.d.ts.map +1 -0
- package/dist/services/feedback-policy-resolver.js +156 -0
- package/dist/services/feedback-policy-resolver.js.map +1 -0
- package/dist/services/feedback-policy.d.ts +41 -0
- package/dist/services/feedback-policy.d.ts.map +1 -0
- package/dist/services/feedback-policy.js +102 -0
- package/dist/services/feedback-policy.js.map +1 -0
- package/dist/services/feedback-webhook-dispatcher.d.ts +76 -0
- package/dist/services/feedback-webhook-dispatcher.d.ts.map +1 -0
- package/dist/services/feedback-webhook-dispatcher.js +237 -0
- package/dist/services/feedback-webhook-dispatcher.js.map +1 -0
- package/dist/services/grant-prefs-store.d.ts +3 -0
- package/dist/services/grant-prefs-store.d.ts.map +1 -1
- package/dist/services/grant-prefs-store.js +30 -1
- package/dist/services/grant-prefs-store.js.map +1 -1
- package/dist/services/groups-store.d.ts +14 -0
- package/dist/services/groups-store.d.ts.map +1 -1
- package/dist/services/groups-store.js +23 -0
- package/dist/services/groups-store.js.map +1 -1
- package/dist/services/local-cli-opener.d.ts +1 -1
- package/dist/services/local-cli-opener.d.ts.map +1 -1
- package/dist/services/local-cli-opener.js +2 -0
- package/dist/services/local-cli-opener.js.map +1 -1
- package/dist/services/prompt-context-store.d.ts +29 -0
- package/dist/services/prompt-context-store.d.ts.map +1 -0
- package/dist/services/prompt-context-store.js +205 -0
- package/dist/services/prompt-context-store.js.map +1 -0
- package/dist/services/session-group-avatar.d.ts +6 -0
- package/dist/services/session-group-avatar.d.ts.map +1 -0
- package/dist/services/session-group-avatar.js +96 -0
- package/dist/services/session-group-avatar.js.map +1 -0
- package/dist/services/session-group-title.d.ts +47 -0
- package/dist/services/session-group-title.d.ts.map +1 -0
- package/dist/services/session-group-title.js +226 -0
- package/dist/services/session-group-title.js.map +1 -0
- package/dist/services/session-groups-store.d.ts +30 -0
- package/dist/services/session-groups-store.d.ts.map +1 -0
- package/dist/services/session-groups-store.js +132 -0
- package/dist/services/session-groups-store.js.map +1 -0
- package/dist/services/session-store.d.ts +58 -0
- package/dist/services/session-store.d.ts.map +1 -1
- package/dist/services/session-store.js +174 -0
- package/dist/services/session-store.js.map +1 -1
- package/dist/services/skill-feedback-store.d.ts +252 -0
- package/dist/services/skill-feedback-store.d.ts.map +1 -0
- package/dist/services/skill-feedback-store.js +795 -0
- package/dist/services/skill-feedback-store.js.map +1 -0
- package/dist/services/skill-registry-store.d.ts +23 -0
- package/dist/services/skill-registry-store.d.ts.map +1 -1
- package/dist/services/skill-registry-store.js +93 -7
- package/dist/services/skill-registry-store.js.map +1 -1
- package/dist/services/team-store.d.ts +4 -0
- package/dist/services/team-store.d.ts.map +1 -1
- package/dist/services/team-store.js +16 -0
- package/dist/services/team-store.js.map +1 -1
- package/dist/services/traex-transcript.d.ts +32 -4
- package/dist/services/traex-transcript.d.ts.map +1 -1
- package/dist/services/traex-transcript.js +116 -8
- package/dist/services/traex-transcript.js.map +1 -1
- package/dist/services/trigger-types.d.ts +1 -1
- package/dist/services/trigger-types.d.ts.map +1 -1
- package/dist/services/trigger-types.js +2 -2
- package/dist/services/trigger-types.js.map +1 -1
- package/dist/services/turn-completion-events.d.ts +57 -0
- package/dist/services/turn-completion-events.d.ts.map +1 -0
- package/dist/services/turn-completion-events.js +179 -0
- package/dist/services/turn-completion-events.js.map +1 -0
- package/dist/services/vc-meeting-consumer-isolation.d.ts +21 -12
- package/dist/services/vc-meeting-consumer-isolation.d.ts.map +1 -1
- package/dist/services/vc-meeting-consumer-isolation.js +25 -19
- package/dist/services/vc-meeting-consumer-isolation.js.map +1 -1
- package/dist/services/vc-meeting-consumer-profile-bootstrap.d.ts +8 -2
- package/dist/services/vc-meeting-consumer-profile-bootstrap.d.ts.map +1 -1
- package/dist/services/vc-meeting-consumer-profile-bootstrap.js +18 -10
- package/dist/services/vc-meeting-consumer-profile-bootstrap.js.map +1 -1
- package/dist/setup/bot-config-editor.d.ts.map +1 -1
- package/dist/setup/bot-config-editor.js +6 -0
- package/dist/setup/bot-config-editor.js.map +1 -1
- package/dist/setup/cli-availability.d.ts +2 -1
- package/dist/setup/cli-availability.d.ts.map +1 -1
- package/dist/setup/cli-availability.js +2 -1
- package/dist/setup/cli-availability.js.map +1 -1
- package/dist/setup/cli-selection.d.ts +8 -0
- package/dist/setup/cli-selection.d.ts.map +1 -1
- package/dist/setup/cli-selection.js +31 -0
- package/dist/setup/cli-selection.js.map +1 -1
- package/dist/setup/ensure-fonts.d.ts +5 -0
- package/dist/setup/ensure-fonts.d.ts.map +1 -1
- package/dist/setup/ensure-fonts.js +26 -1
- package/dist/setup/ensure-fonts.js.map +1 -1
- package/dist/setup/lark-scopes.json +3 -1
- package/dist/setup/open-platform-automation.d.ts +1 -1
- package/dist/setup/open-platform-automation.d.ts.map +1 -1
- package/dist/setup/open-platform-automation.js +15 -3
- package/dist/setup/open-platform-automation.js.map +1 -1
- package/dist/skills/definitions.d.ts +1 -1
- package/dist/skills/definitions.d.ts.map +1 -1
- package/dist/skills/definitions.js +9 -2
- package/dist/skills/definitions.js.map +1 -1
- package/dist/types.d.ts +10 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/user-token.d.ts +38 -0
- package/dist/utils/user-token.d.ts.map +1 -1
- package/dist/utils/user-token.js +76 -1
- package/dist/utils/user-token.js.map +1 -1
- package/dist/utils/web-terminal-scroll.d.ts +27 -0
- package/dist/utils/web-terminal-scroll.d.ts.map +1 -0
- package/dist/utils/web-terminal-scroll.js +60 -0
- package/dist/utils/web-terminal-scroll.js.map +1 -0
- package/dist/vc-agent/polling-source.d.ts +70 -0
- package/dist/vc-agent/polling-source.d.ts.map +1 -1
- package/dist/vc-agent/polling-source.js +115 -0
- package/dist/vc-agent/polling-source.js.map +1 -1
- package/dist/worker.js +237 -76
- package/dist/worker.js.map +1 -1
- package/dist/workflows/definition.d.ts +22 -22
- package/dist/workflows/events/payloads.d.ts +8 -8
- package/dist/workflows/events/schema.d.ts +20 -20
- package/dist/workflows/migration/v2-run-archive-schema.d.ts +20 -20
- package/package.json +1 -1
- package/dist/dashboard-web/chunks/bot-defaults-page-NQJFJ45Z.js +0 -10
- package/dist/dashboard-web/chunks/chunk-KEEYQ3WF.js +0 -1
- package/dist/dashboard-web/chunks/connectors-page-HADHZXXZ.js +0 -1
- package/dist/dashboard-web/chunks/groups-page-5TYF46RS.js +0 -8
- package/dist/dashboard-web/chunks/monitoring-page-LBU7TTTW.js +0 -2
- package/dist/dashboard-web/chunks/office-page-DF6RRBMN.js +0 -1
- package/dist/dashboard-web/chunks/overview-page-ZB6QH2EX.js +0 -1
- package/dist/dashboard-web/chunks/roles-page-ZBZGHIIF.js +0 -1
- package/dist/dashboard-web/chunks/schedules-page-NQVQC3QY.js +0 -1
- package/dist/dashboard-web/chunks/settings-page-E7NN4NVQ.js +0 -2
- package/dist/dashboard-web/chunks/team-federation-page-VGWL53AE.js +0 -1
- package/dist/dashboard-web/chunks/whiteboards-page-BNWUU4KG.js +0 -1
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
2
4
|
import { execFileSync } from 'node:child_process';
|
|
3
5
|
import { createHash } from 'node:crypto';
|
|
4
6
|
import { logger } from '../../utils/logger.js';
|
|
@@ -193,6 +195,237 @@ export async function cancelRiffTaskById(cfg, taskId) {
|
|
|
193
195
|
export function hashUrlForLog(u) {
|
|
194
196
|
return createHash('sha256').update(u).digest('hex').slice(0, 8);
|
|
195
197
|
}
|
|
198
|
+
/** The keychain leaf under a ByteCloud tool's storage root:
|
|
199
|
+
* `<root>/bytecloud-auth/keychain/auth/cn/default`, whose JSON holds the
|
|
200
|
+
* `bytecloud_jwt` field. `cn` is ByteCloud CN (riff is an internal CN
|
|
201
|
+
* service). NOTE the sibling `bytecloud-auth/auth/cn/credentials.json` (no
|
|
202
|
+
* `keychain/` segment) carries only metadata (app_id / expires_at / user) and
|
|
203
|
+
* NO `bytecloud_jwt` — we deliberately never read it. */
|
|
204
|
+
const BYTECLOUD_KEYCHAIN_LEAF = join('bytecloud-auth', 'keychain', 'auth', 'cn', 'default');
|
|
205
|
+
/**
|
|
206
|
+
* Reproduce bytedcli's `sanitizeFilenamePart` + AIME base-dir assembly EXACTLY
|
|
207
|
+
* (from `@bytedance-dev/bytedcli` dist/bytedcli-core.js, verified against
|
|
208
|
+
* 0.124.0): a username path segment keeps only `[a-zA-Z0-9._-]` (every other
|
|
209
|
+
* char → `_`), then a lone `.` → `_` and a lone `..` → `__`. Must match
|
|
210
|
+
* byte-for-byte or the AIME keychain path we build won't line up with where
|
|
211
|
+
* bytedcli actually wrote the token.
|
|
212
|
+
*/
|
|
213
|
+
function sanitizeAimeUser(user) {
|
|
214
|
+
return user.replace(/[^a-zA-Z0-9._-]/g, '_').replace(/^\.$/, '_').replace(/^\.\.$/, '__');
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* bytedcli's data-home base when running inside an AIME workspace. bytedcli
|
|
218
|
+
* uses it (in place of `os.homedir()`) ONLY when both `AIME_WORKSPACE_PATH` and
|
|
219
|
+
* `AIME_CURRENT_USER` are set (trimmed non-empty); it then stores under
|
|
220
|
+
* `<workspace>/<sanitizedUser>/.local/share/bytedcli/data/…`. We return the
|
|
221
|
+
* `<workspace>/<sanitizedUser>/.local/share` prefix (parallel to the plain
|
|
222
|
+
* `~/.local/share` data-home, so the shared `join(base,'bytedcli','data')`
|
|
223
|
+
* below lands on the right leaf), or null when this is not an AIME runtime.
|
|
224
|
+
*/
|
|
225
|
+
function aimeDataHome(env) {
|
|
226
|
+
const workspace = env.AIME_WORKSPACE_PATH?.trim();
|
|
227
|
+
const user = env.AIME_CURRENT_USER?.trim();
|
|
228
|
+
if (!workspace || !user)
|
|
229
|
+
return null;
|
|
230
|
+
return join(workspace, sanitizeAimeUser(user), '.local', 'share');
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* The keychain candidates for a ByteCloud tool's `bytecloud-auth/` store, across
|
|
234
|
+
* the CLIs botmux users log into (kaboo-cli / aiden-cli / cjadk / bytedcli).
|
|
235
|
+
*
|
|
236
|
+
* ⚠️ This is NOT a "cast a wide net" list. The selector in
|
|
237
|
+
* `readBytecloudKeychainJwt` picks the globally-freshest token by `exp`
|
|
238
|
+
* REGARDLESS of order, so an extra candidate is not free: a stale/foreign token
|
|
239
|
+
* at a location the tool never actually writes could WIN and shadow the real
|
|
240
|
+
* one. Every entry must be a location the tool genuinely uses on THIS host:
|
|
241
|
+
* - Config-style CLIs (kaboo-cli / aiden-cli / cjadk) resolve their base via
|
|
242
|
+
* Go's os.UserConfigDir (verified against kaboo 1.3.77): macOS →
|
|
243
|
+
* `~/Library/Application Support`, Windows → `%AppData%` (Go errors, does
|
|
244
|
+
* NOT default to `~/AppData/Roaming`, when it is unset — so we emit no
|
|
245
|
+
* config candidate then), otherwise → `$XDG_CONFIG_HOME` (else `~/.config`).
|
|
246
|
+
* We list ONLY the current platform's root, never several — a
|
|
247
|
+
* foreign-platform root is never live here and would only invite shadowing.
|
|
248
|
+
* - cjadk also uses a home dot-dir `~/.cjadk`; aipaas uses `~/.aipaas`.
|
|
249
|
+
* - bytedcli stores under `~/.local/share/bytedcli/data` on Linux, macOS AND
|
|
250
|
+
* Windows: its `bytedcliBaseDir()` (bytedcli-core.js, 0.125.0) has no
|
|
251
|
+
* platform branch and ignores `$XDG_DATA_HOME`. Inside an AIME workspace it
|
|
252
|
+
* swaps the home base for `$AIME_WORKSPACE_PATH/<sanitized $AIME_CURRENT_USER>`
|
|
253
|
+
* — see the fail-closed early return below.
|
|
254
|
+
* Order is otherwise NOT significant (selection is by `exp`, not position).
|
|
255
|
+
* Non-existent candidates simply fail the read and are skipped.
|
|
256
|
+
*/
|
|
257
|
+
export function bytecloudKeychainCandidates(home = homedir(), env = process.env, platform = process.platform) {
|
|
258
|
+
const dedupe = (xs) => [...new Set(xs.filter(Boolean))];
|
|
259
|
+
const isMac = platform === 'darwin';
|
|
260
|
+
// --- Full AIME runtime: fail-closed to the AIME identity domain ---------
|
|
261
|
+
// When BOTH AIME vars are set, bytedcli swaps its storage root to
|
|
262
|
+
// `$AIME_WORKSPACE_PATH/<sanitized user>/.local/share/bytedcli/data` and,
|
|
263
|
+
// crucially, does NOT fall back to the host HOME (bytedcliBaseDir returns the
|
|
264
|
+
// AIME root and stops). `os.homedir()` here is still the HOST home — that is
|
|
265
|
+
// precisely WHY bytedcli needs the override — so EVERY host-HOME-derived
|
|
266
|
+
// keychain (the config-style CLIs under ~/.config or Application Support,
|
|
267
|
+
// ~/.cjadk, ~/.aipaas) belongs to a DIFFERENT identity. Reading any of them
|
|
268
|
+
// would cross AIME user identities, and the exp-aware selector below would
|
|
269
|
+
// happily prefer a longer-lived host token. The safe boundary is the
|
|
270
|
+
// identity domain, not the tool name: in a full AIME runtime the ONLY
|
|
271
|
+
// in-domain source is the AIME-scoped bytedcli store. If it holds no live
|
|
272
|
+
// token we return nothing here and the caller fails closed (the user logs in
|
|
273
|
+
// inside AIME) rather than silently authenticating as someone else.
|
|
274
|
+
const aimeHome = aimeDataHome(env);
|
|
275
|
+
if (aimeHome) {
|
|
276
|
+
return [join(aimeHome, 'bytedcli', 'data', BYTECLOUD_KEYCHAIN_LEAF)];
|
|
277
|
+
}
|
|
278
|
+
// --- Ordinary (non-AIME) runtime ---------------------------------------
|
|
279
|
+
// Config-style CLIs (kaboo-cli / aiden-cli / cjadk) resolve their base via
|
|
280
|
+
// Go's os.UserConfigDir (verified against kaboo 1.3.77's embedded ByteCloud
|
|
281
|
+
// auth). That maps per-platform: macOS → `~/Library/Application Support`;
|
|
282
|
+
// Windows → `%AppData%`; everything else → `$XDG_CONFIG_HOME` (falling back
|
|
283
|
+
// to `~/.config`). A single process only ever uses ONE of these — the current
|
|
284
|
+
// platform's. We must key off the actual platform, NOT list several: the
|
|
285
|
+
// exp-aware selector picks the globally-freshest token regardless of order,
|
|
286
|
+
// so a stale token under another platform's root could otherwise shadow the
|
|
287
|
+
// authoritative one (a foreign-platform root is never a live location on this
|
|
288
|
+
// host anyway). `platform` is injectable so every spelling stays testable.
|
|
289
|
+
//
|
|
290
|
+
// `configHome` is null when we cannot name the platform's real config root:
|
|
291
|
+
// on Windows Go ERRORS if `%AppData%` is unset (it does NOT default to
|
|
292
|
+
// `~/AppData/Roaming`), so with APPDATA absent we emit NO config-style
|
|
293
|
+
// candidate rather than invent a phantom path a stale token could shadow
|
|
294
|
+
// from. The other verified candidates (bytedcli, dot-dirs) are unaffected.
|
|
295
|
+
const xdgConfig = env.XDG_CONFIG_HOME?.trim();
|
|
296
|
+
let configHome;
|
|
297
|
+
if (isMac) {
|
|
298
|
+
configHome = join(home, 'Library', 'Application Support');
|
|
299
|
+
}
|
|
300
|
+
else if (platform === 'win32') {
|
|
301
|
+
configHome = env.APPDATA?.trim() || null;
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
configHome = xdgConfig || join(home, '.config');
|
|
305
|
+
}
|
|
306
|
+
// bytedcli keeps `bytedcli/data/bytecloud-auth/...` under its data home.
|
|
307
|
+
// `bytedcliBaseDir()` in `@bytedance-dev/bytedcli` (dist/bytedcli-core.js,
|
|
308
|
+
// 0.125.0) has NO platform branch: in the ordinary case it unconditionally
|
|
309
|
+
// uses `~/.local/share/bytedcli` on Linux, macOS AND Windows, and it ignores
|
|
310
|
+
// $XDG_DATA_HOME. So the single `~/.local/share` data home is correct on
|
|
311
|
+
// every platform — there is no Application Support / %AppData% spelling to
|
|
312
|
+
// add. (The AIME workspace override is the only base swap, handled above.)
|
|
313
|
+
const bytedcliHome = join(home, '.local', 'share');
|
|
314
|
+
const roots = [];
|
|
315
|
+
// Config-dir CLIs (single platform-correct base, when we can name one).
|
|
316
|
+
if (configHome) {
|
|
317
|
+
for (const cli of ['kaboo-cli', 'aiden-cli', 'cjadk'])
|
|
318
|
+
roots.push(join(configHome, cli));
|
|
319
|
+
}
|
|
320
|
+
// Home dot-dir layouts (Linux-observed; harmless as extra candidates elsewhere).
|
|
321
|
+
roots.push(join(home, '.cjadk'));
|
|
322
|
+
roots.push(join(home, '.aipaas'));
|
|
323
|
+
// Data-dir CLI (bytedcli) — the extra `data/` segment is part of its layout.
|
|
324
|
+
roots.push(join(bytedcliHome, 'bytedcli', 'data'));
|
|
325
|
+
return dedupe(roots).map((root) => join(root, BYTECLOUD_KEYCHAIN_LEAF));
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Decode a JWT's `exp` (seconds since epoch) from its payload without verifying
|
|
329
|
+
* the signature — we only need the expiry to prefer a live token over a stale
|
|
330
|
+
* one. Returns null for anything we cannot confidently parse as an expiry so it
|
|
331
|
+
* ranks below any parseable-live token (opaque/non-JWT strings, malformed
|
|
332
|
+
* base64, missing/non-number `exp`).
|
|
333
|
+
*
|
|
334
|
+
* A JWS compact JWT is EXACTLY three non-empty base64url segments
|
|
335
|
+
* (`header.payload.signature`) whose header and payload are JSON. We require
|
|
336
|
+
* that shape up front: a 2- or 4-segment string, a segment that isn't
|
|
337
|
+
* base64url (incl. the signature), or a header/payload that isn't a JSON
|
|
338
|
+
* object is NOT a JWT and must never be ranked as a live token where its
|
|
339
|
+
* (accidentally decodable) `exp` could shadow a genuine JWT. We do NOT verify
|
|
340
|
+
* the signature (that is riff's job) — only that the structure is a real JWT.
|
|
341
|
+
*/
|
|
342
|
+
const BASE64URL_RE = /^[A-Za-z0-9_-]+$/;
|
|
343
|
+
function decodeJoseJson(seg) {
|
|
344
|
+
try {
|
|
345
|
+
const obj = JSON.parse(Buffer.from(seg, 'base64url').toString('utf-8'));
|
|
346
|
+
// A JOSE header / JWT payload is a JSON object (not an array, not a scalar).
|
|
347
|
+
if (typeof obj !== 'object' || obj === null || Array.isArray(obj))
|
|
348
|
+
return null;
|
|
349
|
+
return obj;
|
|
350
|
+
}
|
|
351
|
+
catch {
|
|
352
|
+
return null;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
export function decodeJwtExp(jwt) {
|
|
356
|
+
const parts = jwt.split('.');
|
|
357
|
+
// Exactly three non-empty, strictly-base64url segments (header.payload.sig).
|
|
358
|
+
if (parts.length !== 3)
|
|
359
|
+
return null;
|
|
360
|
+
if (!parts[0] || !parts[1] || !parts[2])
|
|
361
|
+
return null;
|
|
362
|
+
if (parts.some((p) => !BASE64URL_RE.test(p)))
|
|
363
|
+
return null;
|
|
364
|
+
// Header must decode to a JSON object (confirms it's really JOSE, not just
|
|
365
|
+
// base64url-shaped noise); we don't require a specific `typ`/`alg`.
|
|
366
|
+
if (!decodeJoseJson(parts[0]))
|
|
367
|
+
return null;
|
|
368
|
+
const payload = decodeJoseJson(parts[1]);
|
|
369
|
+
if (!payload)
|
|
370
|
+
return null;
|
|
371
|
+
const exp = payload['exp'];
|
|
372
|
+
return typeof exp === 'number' && Number.isFinite(exp) ? exp : null;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Read the ByteCloud JWT from the keychain candidates, preferring a live token.
|
|
376
|
+
* Pure + injectable (home/env/now) so it is unit-testable without touching the
|
|
377
|
+
* real HOME. Never throws — unreadable/malformed candidates are skipped.
|
|
378
|
+
*
|
|
379
|
+
* Selection (fixes the stale-token-shadows-valid-token hazard: an expired token
|
|
380
|
+
* from an earlier-listed tool must not mask a valid token from a later one):
|
|
381
|
+
* 1. Collect every candidate's non-empty `bytecloud_jwt`, in candidate order.
|
|
382
|
+
* 2. Drop tokens whose decoded `exp` is already past `now`.
|
|
383
|
+
* 3. Among the survivors, pick the one with the greatest `exp` (freshest);
|
|
384
|
+
* candidates whose `exp` we cannot parse (opaque values) rank BELOW any
|
|
385
|
+
* parseable live token and are used only as a last-resort fallback when no
|
|
386
|
+
* parseable-live token exists — so a broken/opaque old value can never
|
|
387
|
+
* shadow a clearly-valid newer token.
|
|
388
|
+
* Returns null when nothing yields a usable token.
|
|
389
|
+
*/
|
|
390
|
+
/**
|
|
391
|
+
* Treat a token that expires within this many seconds as already expired. riff
|
|
392
|
+
* task creation reads the JWT once and does a single fetch; a 401 there throws
|
|
393
|
+
* and fails the whole turn (SSE reconnect only covers an ALREADY-created task),
|
|
394
|
+
* and a fresh sandbox cold-boot costs minutes — so a token about to expire
|
|
395
|
+
* mid-request is worse than skipping to a longer-lived candidate. Also absorbs
|
|
396
|
+
* small client/server clock skew.
|
|
397
|
+
*/
|
|
398
|
+
export const JWT_EXPIRY_SAFETY_WINDOW_SEC = 30;
|
|
399
|
+
export function readBytecloudKeychainJwt(home = homedir(), env = process.env, nowMs = Date.now(), platform = process.platform) {
|
|
400
|
+
const cutoffSec = nowMs / 1000 + JWT_EXPIRY_SAFETY_WINDOW_SEC;
|
|
401
|
+
let bestLive = null; // parseable, unexpired, freshest
|
|
402
|
+
let opaqueFallback = null; // first exp-less, non-expired-unknown token
|
|
403
|
+
for (const path of bytecloudKeychainCandidates(home, env, platform)) {
|
|
404
|
+
let jwt;
|
|
405
|
+
try {
|
|
406
|
+
const data = JSON.parse(readFileSync(path, 'utf-8'));
|
|
407
|
+
const v = data['bytecloud_jwt'];
|
|
408
|
+
if (typeof v !== 'string' || v.length === 0)
|
|
409
|
+
continue;
|
|
410
|
+
jwt = v;
|
|
411
|
+
}
|
|
412
|
+
catch {
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
const exp = decodeJwtExp(jwt);
|
|
416
|
+
if (exp === null) {
|
|
417
|
+
// Cannot parse expiry — keep only the first as a last-resort fallback.
|
|
418
|
+
if (opaqueFallback === null)
|
|
419
|
+
opaqueFallback = jwt;
|
|
420
|
+
continue;
|
|
421
|
+
}
|
|
422
|
+
if (exp <= cutoffSec)
|
|
423
|
+
continue; // expired or about to expire — never select.
|
|
424
|
+
if (!bestLive || exp > bestLive.exp)
|
|
425
|
+
bestLive = { jwt, exp };
|
|
426
|
+
}
|
|
427
|
+
return bestLive?.jwt ?? opaqueFallback;
|
|
428
|
+
}
|
|
196
429
|
function defaultRunGit(cwd) {
|
|
197
430
|
return (args) => {
|
|
198
431
|
try {
|
|
@@ -236,6 +469,11 @@ function isBareCodexNoiseLine(text) {
|
|
|
236
469
|
return false;
|
|
237
470
|
}
|
|
238
471
|
}
|
|
472
|
+
/** Terminal riff task statuses (riff openApiDocs task contract). Once a task
|
|
473
|
+
* reaches one of these it will emit no further progress — an `init` replay or
|
|
474
|
+
* a `done` event carrying one of these IS the task's completion. Non-terminal:
|
|
475
|
+
* pending / creating_session / running. */
|
|
476
|
+
const TERMINAL_RIFF_STATUSES = new Set(['completed', 'failed', 'cancelled', 'timeout']);
|
|
239
477
|
/**
|
|
240
478
|
* RiffBackend — bridges botmux's SessionBackend interface to riff's HTTP API.
|
|
241
479
|
*
|
|
@@ -274,11 +512,41 @@ export class RiffBackend {
|
|
|
274
512
|
* cleared past 64 entries (a session rarely exceeds a few dozen turns). */
|
|
275
513
|
completedTaskIds = new Set();
|
|
276
514
|
reconnectAttempts = 0;
|
|
277
|
-
maxReconnectAttempts =
|
|
515
|
+
maxReconnectAttempts = 6;
|
|
516
|
+
/** Wall-clock ms when the CURRENT SSE connection was established, or `null`
|
|
517
|
+
* when none is open / the last fetch never connected. Typed `number | null`
|
|
518
|
+
* (not a 0 sentinel) on purpose: 0 is both "not connected" AND a valid number
|
|
519
|
+
* you could subtract, so a future edit dropping the guard would compute a
|
|
520
|
+
* bogus multi-decade lifetime from `Date.now() - 0` and refund forever. `null`
|
|
521
|
+
* makes "never connected" un-subtractable and forces the guard at the type
|
|
522
|
+
* level. The reconnect budget is refunded only when a broken connection had
|
|
523
|
+
* LIVED long enough to be a healthy long connection merely severed by the
|
|
524
|
+
* upstream proxy's fixed ~183s lifetime cap — NOT merely because a connection
|
|
525
|
+
* opened. Keying on "connection lived ≥ reconnectHealthyConnMs" (not on
|
|
526
|
+
* receiving init, and not on any data event — both were falsified/
|
|
527
|
+
* insufficient) is what separates the two cases that look identical from the
|
|
528
|
+
* client:
|
|
529
|
+
* • healthy cap: connection lives ~183s, EOFs → refund → task streams on
|
|
530
|
+
* • dead/hot-loop: connection opens then EOFs within ~1s, repeatedly →
|
|
531
|
+
* NO refund → budget exhausts and bails. Covers BOTH a fetch that never
|
|
532
|
+
* connects (stays null) AND a "connect→init→instant-EOF" loop against a
|
|
533
|
+
* stale-running orphan (lives <threshold) — the latter is exactly the
|
|
534
|
+
* infinite-retry hole a naive "reset on connect/init" would reopen. */
|
|
535
|
+
connectionStartedAtMs = null;
|
|
278
536
|
/** 预算层级(单调覆盖,见 destroySession 注释);字段化以便测试注入边界。 */
|
|
279
537
|
cancelTimeoutMs = 4_000;
|
|
280
538
|
createTimeoutMs = 10_000;
|
|
281
539
|
destroyDeadlineMs = 20_000;
|
|
540
|
+
/** SSE 重连退避基数(指数退避的第一档);字段化以便测试把重连间隔压到 0。 */
|
|
541
|
+
reconnectBaseDelayMs = 1_000;
|
|
542
|
+
reconnectMaxDelayMs = 30_000;
|
|
543
|
+
/** A broken SSE connection that lived at least this long is treated as a
|
|
544
|
+
* healthy long connection severed by the ~183s proxy cap → refund the
|
|
545
|
+
* reconnect budget. Shorter-lived breaks (dead endpoint / instant-EOF hot
|
|
546
|
+
* loop) do NOT refund. 30s: the cap is metronomic at ~181-183s (6× margin)
|
|
547
|
+
* while pathological EOFs are sub-second, so the two separate cleanly.
|
|
548
|
+
* Field-ized for test injection. */
|
|
549
|
+
reconnectHealthyConnMs = 30_000;
|
|
282
550
|
/** Exact late/current task whose close cancellation failed. Retained across
|
|
283
551
|
* the prepare-close handshake so the daemon can persist a retry handle. */
|
|
284
552
|
closeFailureTaskId = null;
|
|
@@ -339,7 +607,7 @@ export class RiffBackend {
|
|
|
339
607
|
const fromEnv = process.env[envKey];
|
|
340
608
|
if (fromEnv)
|
|
341
609
|
return fromEnv;
|
|
342
|
-
// Fallback: try ByteCloud Auth SDK keychain (kaboo-cli / aiden-cli / cjadk)
|
|
610
|
+
// Fallback: try ByteCloud Auth SDK keychain (kaboo-cli / aiden-cli / cjadk / bytedcli)
|
|
343
611
|
const fromKeychain = this.readJwtFromBytecloudKeychain();
|
|
344
612
|
if (fromKeychain) {
|
|
345
613
|
logger.info(`[riff] JWT loaded from ByteCloud keychain`);
|
|
@@ -349,23 +617,7 @@ export class RiffBackend {
|
|
|
349
617
|
return null;
|
|
350
618
|
}
|
|
351
619
|
readJwtFromBytecloudKeychain() {
|
|
352
|
-
|
|
353
|
-
const candidates = [
|
|
354
|
-
`${home}/.config/kaboo-cli/bytecloud-auth/keychain/auth/cn/default`,
|
|
355
|
-
`${home}/.config/aiden-cli/bytecloud-auth/keychain/auth/cn/default`,
|
|
356
|
-
`${home}/.cjadk/bytecloud-auth/keychain/auth/cn/default`,
|
|
357
|
-
];
|
|
358
|
-
for (const path of candidates) {
|
|
359
|
-
try {
|
|
360
|
-
const raw = readFileSync(path, 'utf-8');
|
|
361
|
-
const data = JSON.parse(raw);
|
|
362
|
-
const jwt = data['bytecloud_jwt'];
|
|
363
|
-
if (jwt)
|
|
364
|
-
return jwt;
|
|
365
|
-
}
|
|
366
|
-
catch { /* try next */ }
|
|
367
|
-
}
|
|
368
|
-
return null;
|
|
620
|
+
return readBytecloudKeychainJwt();
|
|
369
621
|
}
|
|
370
622
|
spawn(_bin, _args, _opts) {
|
|
371
623
|
logger.info(`[riff] spawn (ignoring bin/args, using config: ${this.config.baseUrl})`);
|
|
@@ -970,11 +1222,14 @@ export class RiffBackend {
|
|
|
970
1222
|
return env;
|
|
971
1223
|
}
|
|
972
1224
|
async uploadAndCreate(url, payload, attachments) {
|
|
1225
|
+
// Assemble the request body FIRST (attachment reads can be slow on large
|
|
1226
|
+
// files / slow disks), THEN resolve the JWT immediately before fetch. The
|
|
1227
|
+
// keychain selector skips tokens expiring within a safety window, but that
|
|
1228
|
+
// guarantee only holds if we read the token close to the request — reading
|
|
1229
|
+
// it before a multi-second upload prep could hand off a token that expires
|
|
1230
|
+
// mid-flight. createTimeout only bounds the fetch, not the prep before it.
|
|
973
1231
|
const headers = {};
|
|
974
|
-
|
|
975
|
-
if (jwt)
|
|
976
|
-
headers['x-jwt-token'] = jwt;
|
|
977
|
-
let resp;
|
|
1232
|
+
let body;
|
|
978
1233
|
if (attachments.length > 0) {
|
|
979
1234
|
const form = new FormData();
|
|
980
1235
|
form.append('payload', JSON.stringify(payload));
|
|
@@ -987,12 +1242,18 @@ export class RiffBackend {
|
|
|
987
1242
|
logger.warn(`[riff] failed to read attachment ${att.path}: ${err}`);
|
|
988
1243
|
}
|
|
989
1244
|
}
|
|
990
|
-
|
|
1245
|
+
body = form;
|
|
991
1246
|
}
|
|
992
1247
|
else {
|
|
993
1248
|
headers['Content-Type'] = 'application/json';
|
|
994
|
-
|
|
1249
|
+
body = JSON.stringify(payload);
|
|
995
1250
|
}
|
|
1251
|
+
// Resolve JWT last — right before the request — so the safety-window
|
|
1252
|
+
// freshness check reflects the token that actually goes on the wire.
|
|
1253
|
+
const jwt = this.getJwt();
|
|
1254
|
+
if (jwt)
|
|
1255
|
+
headers['x-jwt-token'] = jwt;
|
|
1256
|
+
const resp = await fetch(url, { method: 'POST', headers, body, signal: AbortSignal.timeout(this.createTimeoutMs) });
|
|
996
1257
|
if (!resp.ok)
|
|
997
1258
|
throw new Error(`HTTP ${resp.status}: ${await resp.text()}`);
|
|
998
1259
|
const result = (await resp.json());
|
|
@@ -1104,14 +1365,25 @@ export class RiffBackend {
|
|
|
1104
1365
|
if (jwt)
|
|
1105
1366
|
headers['x-jwt-token'] = jwt;
|
|
1106
1367
|
this.abortController = new AbortController();
|
|
1368
|
+
// Per-connection lifetime clock (see field doc): null until this connection
|
|
1369
|
+
// is confirmed established below. Reset PER streamTask invocation so a fetch
|
|
1370
|
+
// that never connects can't inherit the previous connection's start time.
|
|
1371
|
+
this.connectionStartedAtMs = null;
|
|
1107
1372
|
try {
|
|
1108
1373
|
const resp = await fetch(url, { headers, signal: this.abortController.signal });
|
|
1109
1374
|
if (!resp.ok || !resp.body) {
|
|
1110
1375
|
throw new Error(`SSE HTTP ${resp.status}`);
|
|
1111
1376
|
}
|
|
1112
|
-
//
|
|
1113
|
-
//
|
|
1114
|
-
//
|
|
1377
|
+
// Connection established — start its lifetime clock. On break, catch
|
|
1378
|
+
// compares elapsed against reconnectHealthyConnMs to decide whether this
|
|
1379
|
+
// was a healthy ~183s-capped connection (refund budget) or a short-lived
|
|
1380
|
+
// dead/hot-loop break (do not refund).
|
|
1381
|
+
this.connectionStartedAtMs = Date.now();
|
|
1382
|
+
// NOTE: reconnectAttempts is reset per TASK (createTask/followUp) AND
|
|
1383
|
+
// whenever a broken connection had LIVED ≥ reconnectHealthyConnMs (see the
|
|
1384
|
+
// catch) — NOT unconditionally on every 200, which would let a "connect OK
|
|
1385
|
+
// → instant EOF" loop retry forever (the hole the per-task-only reset
|
|
1386
|
+
// originally guarded, which a naive "reset on connect/init" reopens).
|
|
1115
1387
|
const reader = resp.body.getReader();
|
|
1116
1388
|
const decoder = new TextDecoder();
|
|
1117
1389
|
let buffer = '';
|
|
@@ -1154,10 +1426,29 @@ export class RiffBackend {
|
|
|
1154
1426
|
if (taskId !== this.currentTaskId || this.completedTaskIds.has(taskId))
|
|
1155
1427
|
return;
|
|
1156
1428
|
logger.warn(`[riff] SSE stream error: ${err}`);
|
|
1429
|
+
// Core fix: an upstream proxy caps each task-stream connection at a fixed
|
|
1430
|
+
// ~183s lifetime and closes it with a clean EOF (no done event) — verified
|
|
1431
|
+
// against live data: tasks that "重连失败" had actually COMPLETED server-
|
|
1432
|
+
// side; botmux gave up ~22s early on one, 16min early on another. A healthy
|
|
1433
|
+
// long runner task thus breaks every ~183s. If this just-broken connection
|
|
1434
|
+
// had LIVED long enough (≥ reconnectHealthyConnMs), it was such a healthy
|
|
1435
|
+
// capped connection — refund the reconnect budget so those periodic caps
|
|
1436
|
+
// never accumulate into a false failure, letting the task stream until it
|
|
1437
|
+
// truly finishes. A short-lived break (dead endpoint that never connected,
|
|
1438
|
+
// or a connect→instant-EOF hot loop against a stale-running orphan) does
|
|
1439
|
+
// NOT refund, so it still exhausts the budget and bails (no infinite
|
|
1440
|
+
// retry). Keyed on connection LIFETIME — not on connect/init receipt,
|
|
1441
|
+
// which would refund every attempt and reopen the infinite-retry hole.
|
|
1442
|
+
const connLivedMs = this.connectionStartedAtMs !== null ? Date.now() - this.connectionStartedAtMs : 0;
|
|
1443
|
+
if (connLivedMs >= this.reconnectHealthyConnMs)
|
|
1444
|
+
this.reconnectAttempts = 0;
|
|
1157
1445
|
// Attempt reconnect if task is still running
|
|
1158
1446
|
if (!this.killed && !this.taskDone && this.reconnectAttempts < this.maxReconnectAttempts) {
|
|
1159
1447
|
this.reconnectAttempts++;
|
|
1160
|
-
|
|
1448
|
+
// Exponential backoff with a cap: 1s,2s,4s,8s,16s,30s(cap). Linear 1s/2s/3s
|
|
1449
|
+
// was negligible against a ~180s connection lifetime anyway; the cap keeps
|
|
1450
|
+
// a truly-unreachable gateway from stalling teardown for minutes.
|
|
1451
|
+
const delay = Math.min(this.reconnectMaxDelayMs, this.reconnectBaseDelayMs * 2 ** (this.reconnectAttempts - 1));
|
|
1161
1452
|
logger.info(`[riff] SSE reconnect attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts} in ${delay}ms`);
|
|
1162
1453
|
this.emitLine(`[riff] 连接中断,正在重连 (${this.reconnectAttempts}/${this.maxReconnectAttempts})`, 'warn');
|
|
1163
1454
|
await new Promise((r) => setTimeout(r, delay));
|
|
@@ -1172,6 +1463,50 @@ export class RiffBackend {
|
|
|
1172
1463
|
}
|
|
1173
1464
|
}
|
|
1174
1465
|
}
|
|
1466
|
+
/**
|
|
1467
|
+
* Fire a task's completion exactly once — the turn boundary + final-output
|
|
1468
|
+
* fetch. Called from BOTH the `done` SSE event AND an `init` replay carrying a
|
|
1469
|
+
* terminal status (the task finished while a prior connection was dead and its
|
|
1470
|
+
* `done` was lost with the closed stream). Idempotency & staleness — per TASK,
|
|
1471
|
+
* not per backend: streams can deliver done more than once (observed ~500ms
|
|
1472
|
+
* apart live), and by the time a duplicate (or a reconnect's init replay)
|
|
1473
|
+
* arrives, a queued follow-up may already be running as the NEXT task (write()
|
|
1474
|
+
* reset the global taskDone). A plain boolean guard would re-fire the boundary
|
|
1475
|
+
* mid-way through that next task and falsely mark it done, so gate on:
|
|
1476
|
+
* 1) the completion must belong to the CURRENT task (stale streams no-op)
|
|
1477
|
+
* 2) each task fires the boundary at most once (completedTaskIds)
|
|
1478
|
+
*/
|
|
1479
|
+
completeTask(taskId, status, exitCode) {
|
|
1480
|
+
if (taskId !== this.currentTaskId)
|
|
1481
|
+
return;
|
|
1482
|
+
if (this.completedTaskIds.has(taskId))
|
|
1483
|
+
return;
|
|
1484
|
+
this.completedTaskIds.add(taskId);
|
|
1485
|
+
// Bounded FIFO eviction — never a blanket clear(), which would drop the id
|
|
1486
|
+
// just added and let its ~500ms duplicate done re-fire.
|
|
1487
|
+
while (this.completedTaskIds.size > 64) {
|
|
1488
|
+
const oldest = this.completedTaskIds.values().next().value;
|
|
1489
|
+
if (oldest === taskId)
|
|
1490
|
+
break;
|
|
1491
|
+
this.completedTaskIds.delete(oldest);
|
|
1492
|
+
}
|
|
1493
|
+
this.taskDone = true;
|
|
1494
|
+
if (this.config.injectStatusLines !== false) {
|
|
1495
|
+
this.emitLine(`[riff] 任务完成${status ? ` (${status}${exitCode != null ? `, exit=${exitCode}` : ''})` : ''}`, status === 'failed' ? 'warn' : 'ok');
|
|
1496
|
+
}
|
|
1497
|
+
// Fetch final output from task-detail API (SSE has no output events for
|
|
1498
|
+
// runner tasks) BEFORE firing the turn boundary: the boundary flushes queued
|
|
1499
|
+
// follow-ups → currentTaskId flips to the next task → the stale guard would
|
|
1500
|
+
// (correctly) drop THIS task's only report.
|
|
1501
|
+
if (status === 'completed' || status === 'failed') {
|
|
1502
|
+
void this.fetchAndEmitOutput(taskId)
|
|
1503
|
+
.catch(() => { })
|
|
1504
|
+
.finally(() => { this.taskDoneCb?.(); });
|
|
1505
|
+
}
|
|
1506
|
+
else {
|
|
1507
|
+
this.taskDoneCb?.();
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1175
1510
|
handleSseEvent(block, taskId) {
|
|
1176
1511
|
// Task isolation: once a newer task is current, EVERY event from an older
|
|
1177
1512
|
// task's stream (output/log/init/session_info/done alike) is inert — a
|
|
@@ -1232,48 +1567,27 @@ export class RiffBackend {
|
|
|
1232
1567
|
if (changed && !this.accessUrlIsDirect) {
|
|
1233
1568
|
void this.fetchDirectAccessUrl(taskId);
|
|
1234
1569
|
}
|
|
1570
|
+
// init REPLAYS the full accumulated task state, including a terminal
|
|
1571
|
+
// `status` when the task finished while our previous connection was
|
|
1572
|
+
// dead (the ~183s cap closes mid-flight and the `done` event is lost
|
|
1573
|
+
// with it). Consume that replay: a terminal status here IS the missed
|
|
1574
|
+
// completion — route it through the same completion path so the turn
|
|
1575
|
+
// ends cleanly instead of the budget eventually exhausting into a
|
|
1576
|
+
// false "重连失败". Non-terminal (running/pending/…) just means the
|
|
1577
|
+
// reconnect resumed a still-live task — no completion, keep streaming.
|
|
1578
|
+
if (eventType === 'init') {
|
|
1579
|
+
const initStatus = data['status'];
|
|
1580
|
+
if (initStatus && TERMINAL_RIFF_STATUSES.has(initStatus)) {
|
|
1581
|
+
const exitCode = data['exitCode'];
|
|
1582
|
+
this.completeTask(taskId, initStatus, exitCode);
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1235
1585
|
break;
|
|
1236
1586
|
}
|
|
1237
1587
|
case 'done': {
|
|
1238
|
-
// Idempotency & staleness — per TASK, not per backend: streams can
|
|
1239
|
-
// deliver done more than once (observed ~500ms apart live), and by
|
|
1240
|
-
// the time the duplicate arrives a queued follow-up may already be
|
|
1241
|
-
// running as the NEXT task (write() reset the global taskDone). A
|
|
1242
|
-
// plain boolean guard would re-fire the turn-boundary callback mid-
|
|
1243
|
-
// way through that next task and falsely mark it done, so gate on:
|
|
1244
|
-
// 1) the done must belong to the CURRENT task (stale streams no-op)
|
|
1245
|
-
// 2) each task fires the boundary at most once (completedTaskIds)
|
|
1246
|
-
if (taskId !== this.currentTaskId)
|
|
1247
|
-
break;
|
|
1248
|
-
if (this.completedTaskIds.has(taskId))
|
|
1249
|
-
break;
|
|
1250
|
-
this.completedTaskIds.add(taskId);
|
|
1251
|
-
// Bounded FIFO eviction — never a blanket clear(), which would drop
|
|
1252
|
-
// the id just added and let its ~500ms duplicate done re-fire.
|
|
1253
|
-
while (this.completedTaskIds.size > 64) {
|
|
1254
|
-
const oldest = this.completedTaskIds.values().next().value;
|
|
1255
|
-
if (oldest === taskId)
|
|
1256
|
-
break;
|
|
1257
|
-
this.completedTaskIds.delete(oldest);
|
|
1258
|
-
}
|
|
1259
|
-
this.taskDone = true;
|
|
1260
1588
|
const status = data['status'];
|
|
1261
1589
|
const exitCode = data['exitCode'];
|
|
1262
|
-
|
|
1263
|
-
this.emitLine(`[riff] 任务完成${status ? ` (${status}${exitCode != null ? `, exit=${exitCode}` : ''})` : ''}`, status === 'failed' ? 'warn' : 'ok');
|
|
1264
|
-
}
|
|
1265
|
-
// Fetch final output from task-detail API (SSE has no output events
|
|
1266
|
-
// for runner tasks) BEFORE firing the turn boundary: the boundary
|
|
1267
|
-
// flushes queued follow-ups → currentTaskId flips to the next task →
|
|
1268
|
-
// the stale guard would (correctly) drop THIS task's only report.
|
|
1269
|
-
if (status === 'completed' || status === 'failed') {
|
|
1270
|
-
void this.fetchAndEmitOutput(taskId)
|
|
1271
|
-
.catch(() => { })
|
|
1272
|
-
.finally(() => { this.taskDoneCb?.(); });
|
|
1273
|
-
}
|
|
1274
|
-
else {
|
|
1275
|
-
this.taskDoneCb?.();
|
|
1276
|
-
}
|
|
1590
|
+
this.completeTask(taskId, status, exitCode);
|
|
1277
1591
|
// NOTE: task done does NOT trigger onExit — session stays alive
|
|
1278
1592
|
// for follow-up messages. Only /close or unrecoverable errors exit.
|
|
1279
1593
|
break;
|