botmux 2.47.0 → 2.47.2
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 +10 -5
- package/README.md +10 -5
- package/dist/adapters/adopt-route.d.ts +63 -0
- package/dist/adapters/adopt-route.d.ts.map +1 -0
- package/dist/adapters/adopt-route.js +195 -0
- package/dist/adapters/adopt-route.js.map +1 -0
- package/dist/adapters/backend/tmux-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-backend.js +11 -0
- package/dist/adapters/backend/tmux-backend.js.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.d.ts +11 -0
- package/dist/adapters/backend/tmux-pipe-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.js +17 -1
- package/dist/adapters/backend/tmux-pipe-backend.js.map +1 -1
- package/dist/adapters/cli/claude-code.d.ts.map +1 -1
- package/dist/adapters/cli/claude-code.js +36 -9
- package/dist/adapters/cli/claude-code.js.map +1 -1
- package/dist/adapters/cli/coco.d.ts.map +1 -1
- package/dist/adapters/cli/coco.js +26 -1
- package/dist/adapters/cli/coco.js.map +1 -1
- package/dist/adapters/cli/codex-app.d.ts +4 -0
- package/dist/adapters/cli/codex-app.d.ts.map +1 -0
- package/dist/adapters/cli/codex-app.js +72 -0
- package/dist/adapters/cli/codex-app.js.map +1 -0
- package/dist/adapters/cli/codex.d.ts.map +1 -1
- package/dist/adapters/cli/codex.js +34 -17
- package/dist/adapters/cli/codex.js.map +1 -1
- package/dist/adapters/cli/cursor.d.ts.map +1 -1
- package/dist/adapters/cli/cursor.js +58 -12
- package/dist/adapters/cli/cursor.js.map +1 -1
- package/dist/adapters/cli/gemini.d.ts.map +1 -1
- package/dist/adapters/cli/gemini.js +5 -1
- package/dist/adapters/cli/gemini.js.map +1 -1
- package/dist/adapters/cli/hermes.d.ts +4 -0
- package/dist/adapters/cli/hermes.d.ts.map +1 -0
- package/dist/adapters/cli/hermes.js +40 -0
- package/dist/adapters/cli/hermes.js.map +1 -0
- package/dist/adapters/cli/mira.d.ts +4 -0
- package/dist/adapters/cli/mira.d.ts.map +1 -0
- package/dist/adapters/cli/mira.js +67 -0
- package/dist/adapters/cli/mira.js.map +1 -0
- package/dist/adapters/cli/mtr.d.ts +5 -0
- package/dist/adapters/cli/mtr.d.ts.map +1 -0
- package/dist/adapters/cli/mtr.js +62 -0
- package/dist/adapters/cli/mtr.js.map +1 -0
- package/dist/adapters/cli/opencode.d.ts.map +1 -1
- package/dist/adapters/cli/opencode.js +19 -1
- package/dist/adapters/cli/opencode.js.map +1 -1
- package/dist/adapters/cli/registry.d.ts +5 -1
- package/dist/adapters/cli/registry.d.ts.map +1 -1
- package/dist/adapters/cli/registry.js +22 -2
- package/dist/adapters/cli/registry.js.map +1 -1
- package/dist/adapters/cli/shared-hints.d.ts +1 -1
- package/dist/adapters/cli/shared-hints.d.ts.map +1 -1
- package/dist/adapters/cli/shared-hints.js +2 -1
- package/dist/adapters/cli/shared-hints.js.map +1 -1
- package/dist/adapters/cli/types.d.ts +35 -2
- package/dist/adapters/cli/types.d.ts.map +1 -1
- package/dist/adapters/hook-command.d.ts +18 -0
- package/dist/adapters/hook-command.d.ts.map +1 -0
- package/dist/adapters/hook-command.js +38 -0
- package/dist/adapters/hook-command.js.map +1 -0
- package/dist/adapters/hook-installer.d.ts +14 -0
- package/dist/adapters/hook-installer.d.ts.map +1 -0
- package/dist/adapters/hook-installer.js +192 -0
- package/dist/adapters/hook-installer.js.map +1 -0
- package/dist/bot-registry.d.ts +59 -0
- package/dist/bot-registry.d.ts.map +1 -1
- package/dist/bot-registry.js +67 -0
- package/dist/bot-registry.js.map +1 -1
- package/dist/cli/bots-list-output.d.ts +8 -0
- package/dist/cli/bots-list-output.d.ts.map +1 -1
- package/dist/cli/bots-list-output.js +9 -0
- package/dist/cli/bots-list-output.js.map +1 -1
- package/dist/cli.d.ts +15 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +603 -106
- package/dist/cli.js.map +1 -1
- package/dist/codex-app-runner.d.ts +3 -0
- package/dist/codex-app-runner.d.ts.map +1 -0
- package/dist/codex-app-runner.js +512 -0
- package/dist/codex-app-runner.js.map +1 -0
- package/dist/config.d.ts +11 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +17 -4
- package/dist/config.js.map +1 -1
- package/dist/core/ask-api.d.ts +47 -0
- package/dist/core/ask-api.d.ts.map +1 -0
- package/dist/core/ask-api.js +139 -0
- package/dist/core/ask-api.js.map +1 -0
- package/dist/core/ask-args.d.ts +53 -0
- package/dist/core/ask-args.d.ts.map +1 -0
- package/dist/core/ask-args.js +122 -0
- package/dist/core/ask-args.js.map +1 -0
- package/dist/core/ask-broker.d.ts +98 -0
- package/dist/core/ask-broker.d.ts.map +1 -0
- package/dist/core/ask-broker.js +329 -0
- package/dist/core/ask-broker.js.map +1 -0
- package/dist/core/ask-hook/claude-code.d.ts +50 -0
- package/dist/core/ask-hook/claude-code.d.ts.map +1 -0
- package/dist/core/ask-hook/claude-code.js +145 -0
- package/dist/core/ask-hook/claude-code.js.map +1 -0
- package/dist/core/ask-hook/codex.d.ts +43 -0
- package/dist/core/ask-hook/codex.d.ts.map +1 -0
- package/dist/core/ask-hook/codex.js +69 -0
- package/dist/core/ask-hook/codex.js.map +1 -0
- package/dist/core/ask-hook/opencode.d.ts +41 -0
- package/dist/core/ask-hook/opencode.d.ts.map +1 -0
- package/dist/core/ask-hook/opencode.js +108 -0
- package/dist/core/ask-hook/opencode.js.map +1 -0
- package/dist/core/ask-hook/registry.d.ts +3 -0
- package/dist/core/ask-hook/registry.d.ts.map +1 -0
- package/dist/core/ask-hook/registry.js +12 -0
- package/dist/core/ask-hook/registry.js.map +1 -0
- package/dist/core/ask-hook/types.d.ts +26 -0
- package/dist/core/ask-hook/types.d.ts.map +1 -0
- package/dist/core/ask-hook/types.js +2 -0
- package/dist/core/ask-hook/types.js.map +1 -0
- package/dist/core/ask-types.d.ts +146 -0
- package/dist/core/ask-types.d.ts.map +1 -0
- package/dist/core/ask-types.js +18 -0
- package/dist/core/ask-types.js.map +1 -0
- package/dist/core/command-handler.d.ts +29 -0
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +787 -312
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/dashboard-ipc-server.d.ts +2 -0
- package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
- package/dist/core/dashboard-ipc-server.js +222 -2
- package/dist/core/dashboard-ipc-server.js.map +1 -1
- package/dist/core/role-resolver.d.ts +17 -1
- package/dist/core/role-resolver.d.ts.map +1 -1
- package/dist/core/role-resolver.js +64 -10
- package/dist/core/role-resolver.js.map +1 -1
- package/dist/core/session-discovery.d.ts.map +1 -1
- package/dist/core/session-discovery.js +19 -5
- package/dist/core/session-discovery.js.map +1 -1
- package/dist/core/session-manager.d.ts +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +37 -20
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/trigger-session.d.ts +9 -0
- package/dist/core/trigger-session.d.ts.map +1 -0
- package/dist/core/trigger-session.js +158 -0
- package/dist/core/trigger-session.js.map +1 -0
- package/dist/core/types.d.ts +5 -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 +141 -0
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +543 -24
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +224 -60
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/auth.d.ts +6 -1
- package/dist/dashboard/auth.d.ts.map +1 -1
- package/dist/dashboard/auth.js +9 -1
- package/dist/dashboard/auth.js.map +1 -1
- package/dist/dashboard/connector-api.d.ts +3 -0
- package/dist/dashboard/connector-api.d.ts.map +1 -0
- package/dist/dashboard/connector-api.js +351 -0
- package/dist/dashboard/connector-api.js.map +1 -0
- package/dist/dashboard/federated-group-core.d.ts +54 -0
- package/dist/dashboard/federated-group-core.d.ts.map +1 -0
- package/dist/dashboard/federated-group-core.js +165 -0
- package/dist/dashboard/federated-group-core.js.map +1 -0
- package/dist/dashboard/federation-api.d.ts +42 -0
- package/dist/dashboard/federation-api.d.ts.map +1 -0
- package/dist/dashboard/federation-api.js +408 -0
- package/dist/dashboard/federation-api.js.map +1 -0
- package/dist/dashboard/federation-spoke-api.d.ts +76 -0
- package/dist/dashboard/federation-spoke-api.d.ts.map +1 -0
- package/dist/dashboard/federation-spoke-api.js +618 -0
- package/dist/dashboard/federation-spoke-api.js.map +1 -0
- package/dist/dashboard/team-group.d.ts +18 -0
- package/dist/dashboard/team-group.d.ts.map +1 -0
- package/dist/dashboard/team-group.js +7 -0
- package/dist/dashboard/team-group.js.map +1 -0
- package/dist/dashboard/trigger-api.d.ts +13 -0
- package/dist/dashboard/trigger-api.d.ts.map +1 -0
- package/dist/dashboard/trigger-api.js +77 -0
- package/dist/dashboard/trigger-api.js.map +1 -0
- package/dist/dashboard/web/app.js +8 -0
- package/dist/dashboard/web/app.js.map +1 -1
- package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults.js +205 -21
- package/dist/dashboard/web/bot-defaults.js.map +1 -1
- package/dist/dashboard/web/connectors.d.ts +2 -0
- package/dist/dashboard/web/connectors.d.ts.map +1 -0
- package/dist/dashboard/web/connectors.js +187 -0
- package/dist/dashboard/web/connectors.js.map +1 -0
- package/dist/dashboard/web/i18n.d.ts.map +1 -1
- package/dist/dashboard/web/i18n.js +43 -5
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard/web/sessions.d.ts.map +1 -1
- package/dist/dashboard/web/sessions.js +4 -0
- package/dist/dashboard/web/sessions.js.map +1 -1
- package/dist/dashboard/web/team-federation.d.ts +3 -0
- package/dist/dashboard/web/team-federation.d.ts.map +1 -0
- package/dist/dashboard/web/team-federation.js +487 -0
- package/dist/dashboard/web/team-federation.js.map +1 -0
- package/dist/dashboard/web/workflows.js +3 -3
- package/dist/dashboard/web/workflows.js.map +1 -1
- package/dist/dashboard/webhook-routes.d.ts +19 -0
- package/dist/dashboard/webhook-routes.d.ts.map +1 -0
- package/dist/dashboard/webhook-routes.js +321 -0
- package/dist/dashboard/webhook-routes.js.map +1 -0
- package/dist/dashboard/workflow-api.d.ts +8 -1
- package/dist/dashboard/workflow-api.d.ts.map +1 -1
- package/dist/dashboard/workflow-api.js +19 -4
- package/dist/dashboard/workflow-api.js.map +1 -1
- package/dist/dashboard-web/app.js +539 -375
- package/dist/dashboard-web/index.html +3 -1
- package/dist/dashboard-web/style.css +22 -0
- package/dist/dashboard.js +199 -2
- package/dist/dashboard.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +104 -11
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +104 -11
- package/dist/i18n/zh.js.map +1 -1
- package/dist/im/lark/ask-card.d.ts +55 -0
- package/dist/im/lark/ask-card.d.ts.map +1 -0
- package/dist/im/lark/ask-card.js +328 -0
- package/dist/im/lark/ask-card.js.map +1 -0
- package/dist/im/lark/card-builder.d.ts +108 -3
- package/dist/im/lark/card-builder.d.ts.map +1 -1
- package/dist/im/lark/card-builder.js +480 -50
- package/dist/im/lark/card-builder.js.map +1 -1
- package/dist/im/lark/card-handler.d.ts.map +1 -1
- package/dist/im/lark/card-handler.js +241 -18
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/im/lark/client.d.ts +83 -0
- package/dist/im/lark/client.d.ts.map +1 -1
- package/dist/im/lark/client.js +286 -70
- package/dist/im/lark/client.js.map +1 -1
- package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
- package/dist/im/lark/event-dispatcher.js +29 -4
- package/dist/im/lark/event-dispatcher.js.map +1 -1
- package/dist/im/lark/grant-command.d.ts +2 -1
- package/dist/im/lark/grant-command.d.ts.map +1 -1
- package/dist/im/lark/grant-command.js +3 -2
- package/dist/im/lark/grant-command.js.map +1 -1
- package/dist/im/lark/identity-cache.d.ts.map +1 -1
- package/dist/im/lark/identity-cache.js +3 -3
- package/dist/im/lark/identity-cache.js.map +1 -1
- package/dist/im/lark/md-card.d.ts +20 -2
- package/dist/im/lark/md-card.d.ts.map +1 -1
- package/dist/im/lark/md-card.js +49 -17
- package/dist/im/lark/md-card.js.map +1 -1
- package/dist/im/lark/message-parser.d.ts.map +1 -1
- package/dist/im/lark/message-parser.js +87 -31
- package/dist/im/lark/message-parser.js.map +1 -1
- package/dist/im/lark/workflow-card-handler.d.ts +2 -2
- package/dist/im/lark/workflow-card-handler.d.ts.map +1 -1
- package/dist/im/lark/workflow-card-handler.js +12 -1
- package/dist/im/lark/workflow-card-handler.js.map +1 -1
- package/dist/im/lark/workflow-progress-card.d.ts.map +1 -1
- package/dist/im/lark/workflow-progress-card.js +53 -0
- package/dist/im/lark/workflow-progress-card.js.map +1 -1
- package/dist/mira-output.d.ts +3 -0
- package/dist/mira-output.d.ts.map +1 -0
- package/dist/mira-output.js +136 -0
- package/dist/mira-output.js.map +1 -0
- package/dist/mira-runner.d.ts +3 -0
- package/dist/mira-runner.d.ts.map +1 -0
- package/dist/mira-runner.js +534 -0
- package/dist/mira-runner.js.map +1 -0
- package/dist/services/bot-owner-store.d.ts +28 -0
- package/dist/services/bot-owner-store.d.ts.map +1 -0
- package/dist/services/bot-owner-store.js +82 -0
- package/dist/services/bot-owner-store.js.map +1 -0
- package/dist/services/bot-profile-store.d.ts +16 -0
- package/dist/services/bot-profile-store.d.ts.map +1 -0
- package/dist/services/bot-profile-store.js +98 -0
- package/dist/services/bot-profile-store.js.map +1 -0
- package/dist/services/brand-store.d.ts +15 -0
- package/dist/services/brand-store.d.ts.map +1 -0
- package/dist/services/brand-store.js +47 -0
- package/dist/services/brand-store.js.map +1 -0
- package/dist/services/card-prefs-store.d.ts +20 -0
- package/dist/services/card-prefs-store.d.ts.map +1 -0
- package/dist/services/card-prefs-store.js +82 -0
- package/dist/services/card-prefs-store.js.map +1 -0
- package/dist/services/codex-bridge-queue.d.ts +1 -0
- package/dist/services/codex-bridge-queue.d.ts.map +1 -1
- package/dist/services/codex-bridge-queue.js +23 -0
- package/dist/services/codex-bridge-queue.js.map +1 -1
- package/dist/services/codex-transcript.d.ts +1 -0
- package/dist/services/codex-transcript.d.ts.map +1 -1
- package/dist/services/codex-transcript.js.map +1 -1
- package/dist/services/connector-store.d.ts +58 -0
- package/dist/services/connector-store.d.ts.map +1 -0
- package/dist/services/connector-store.js +79 -0
- package/dist/services/connector-store.js.map +1 -0
- package/dist/services/deployment-identity.d.ts +22 -0
- package/dist/services/deployment-identity.d.ts.map +1 -0
- package/dist/services/deployment-identity.js +67 -0
- package/dist/services/deployment-identity.js.map +1 -0
- package/dist/services/federation-membership-store.d.ts +23 -0
- package/dist/services/federation-membership-store.d.ts.map +1 -0
- package/dist/services/federation-membership-store.js +66 -0
- package/dist/services/federation-membership-store.js.map +1 -0
- package/dist/services/federation-roster.d.ts +54 -0
- package/dist/services/federation-roster.d.ts.map +1 -0
- package/dist/services/federation-roster.js +51 -0
- package/dist/services/federation-roster.js.map +1 -0
- package/dist/services/federation-store.d.ts +76 -0
- package/dist/services/federation-store.d.ts.map +1 -0
- package/dist/services/federation-store.js +133 -0
- package/dist/services/federation-store.js.map +1 -0
- package/dist/services/grant-store.d.ts +12 -2
- package/dist/services/grant-store.d.ts.map +1 -1
- package/dist/services/grant-store.js +51 -4
- package/dist/services/grant-store.js.map +1 -1
- package/dist/services/group-creator.d.ts +10 -0
- package/dist/services/group-creator.d.ts.map +1 -1
- package/dist/services/group-creator.js +26 -1
- package/dist/services/group-creator.js.map +1 -1
- package/dist/services/groups-store.d.ts +30 -0
- package/dist/services/groups-store.d.ts.map +1 -1
- package/dist/services/groups-store.js +85 -12
- package/dist/services/groups-store.js.map +1 -1
- package/dist/services/hermes-transcript.d.ts +7 -0
- package/dist/services/hermes-transcript.d.ts.map +1 -0
- package/dist/services/hermes-transcript.js +117 -0
- package/dist/services/hermes-transcript.js.map +1 -0
- package/dist/services/invite-store.d.ts +28 -0
- package/dist/services/invite-store.d.ts.map +1 -0
- package/dist/services/invite-store.js +85 -0
- package/dist/services/invite-store.js.map +1 -0
- package/dist/services/pairing-store.d.ts +47 -0
- package/dist/services/pairing-store.d.ts.map +1 -0
- package/dist/services/pairing-store.js +132 -0
- package/dist/services/pairing-store.js.map +1 -0
- package/dist/services/project-scanner.d.ts +10 -0
- package/dist/services/project-scanner.d.ts.map +1 -1
- package/dist/services/project-scanner.js +11 -0
- package/dist/services/project-scanner.js.map +1 -1
- package/dist/services/relay-picker.d.ts +22 -0
- package/dist/services/relay-picker.d.ts.map +1 -0
- package/dist/services/relay-picker.js +62 -0
- package/dist/services/relay-picker.js.map +1 -0
- package/dist/services/send-policy.d.ts +55 -0
- package/dist/services/send-policy.d.ts.map +1 -0
- package/dist/services/send-policy.js +47 -0
- package/dist/services/send-policy.js.map +1 -0
- package/dist/services/session-store.js +1 -1
- package/dist/services/session-store.js.map +1 -1
- package/dist/services/team-roster.d.ts +38 -0
- package/dist/services/team-roster.d.ts.map +1 -0
- package/dist/services/team-roster.js +82 -0
- package/dist/services/team-roster.js.map +1 -0
- package/dist/services/team-store.d.ts +54 -0
- package/dist/services/team-store.d.ts.map +1 -0
- package/dist/services/team-store.js +156 -0
- package/dist/services/team-store.js.map +1 -0
- package/dist/services/trigger-log-store.d.ts +46 -0
- package/dist/services/trigger-log-store.d.ts.map +1 -0
- package/dist/services/trigger-log-store.js +132 -0
- package/dist/services/trigger-log-store.js.map +1 -0
- package/dist/services/trigger-types.d.ts +57 -0
- package/dist/services/trigger-types.d.ts.map +1 -0
- package/dist/services/trigger-types.js +28 -0
- package/dist/services/trigger-types.js.map +1 -0
- package/dist/services/webhook-key.d.ts +16 -0
- package/dist/services/webhook-key.d.ts.map +1 -0
- package/dist/services/webhook-key.js +123 -0
- package/dist/services/webhook-key.js.map +1 -0
- package/dist/services/webhook-lifecycle-extractors.d.ts +15 -0
- package/dist/services/webhook-lifecycle-extractors.d.ts.map +1 -0
- package/dist/services/webhook-lifecycle-extractors.js +59 -0
- package/dist/services/webhook-lifecycle-extractors.js.map +1 -0
- package/dist/services/webhook-lifecycle-store.d.ts +45 -0
- package/dist/services/webhook-lifecycle-store.d.ts.map +1 -0
- package/dist/services/webhook-lifecycle-store.js +159 -0
- package/dist/services/webhook-lifecycle-store.js.map +1 -0
- package/dist/setup/bot-config-editor.d.ts +8 -1
- package/dist/setup/bot-config-editor.d.ts.map +1 -1
- package/dist/setup/bot-config-editor.js +20 -2
- package/dist/setup/bot-config-editor.js.map +1 -1
- package/dist/setup/ensure-tmux.d.ts +0 -22
- package/dist/setup/ensure-tmux.d.ts.map +1 -1
- package/dist/setup/ensure-tmux.js +25 -1
- package/dist/setup/ensure-tmux.js.map +1 -1
- package/dist/setup/verify-permissions.d.ts.map +1 -1
- package/dist/setup/verify-permissions.js +15 -1
- package/dist/setup/verify-permissions.js.map +1 -1
- package/dist/skills/definitions.d.ts +2 -0
- package/dist/skills/definitions.d.ts.map +1 -1
- package/dist/skills/definitions.js +178 -12
- package/dist/skills/definitions.js.map +1 -1
- package/dist/skills/installer.d.ts +34 -0
- package/dist/skills/installer.d.ts.map +1 -1
- package/dist/skills/installer.js +119 -2
- package/dist/skills/installer.js.map +1 -1
- package/dist/types.d.ts +29 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/bot-routing.d.ts +50 -0
- package/dist/utils/bot-routing.d.ts.map +1 -1
- package/dist/utils/bot-routing.js +83 -0
- package/dist/utils/bot-routing.js.map +1 -1
- package/dist/utils/daemon-discovery.d.ts +11 -0
- package/dist/utils/daemon-discovery.d.ts.map +1 -0
- package/dist/utils/daemon-discovery.js +59 -0
- package/dist/utils/daemon-discovery.js.map +1 -0
- package/dist/utils/user-token.d.ts.map +1 -1
- package/dist/utils/user-token.js +0 -2
- package/dist/utils/user-token.js.map +1 -1
- package/dist/worker.js +233 -51
- package/dist/worker.js.map +1 -1
- package/dist/workflows/attempt-resume.d.ts.map +1 -1
- package/dist/workflows/attempt-resume.js +2 -2
- package/dist/workflows/attempt-resume.js.map +1 -1
- package/dist/workflows/definition.d.ts +412 -9
- package/dist/workflows/definition.d.ts.map +1 -1
- package/dist/workflows/definition.js +238 -3
- package/dist/workflows/definition.js.map +1 -1
- package/dist/workflows/events/payloads.d.ts +114 -11
- package/dist/workflows/events/payloads.d.ts.map +1 -1
- package/dist/workflows/events/payloads.js +46 -0
- package/dist/workflows/events/payloads.js.map +1 -1
- package/dist/workflows/events/replay.d.ts +21 -0
- package/dist/workflows/events/replay.d.ts.map +1 -1
- package/dist/workflows/events/replay.js +103 -0
- package/dist/workflows/events/replay.js.map +1 -1
- package/dist/workflows/events/schema.d.ts +1301 -606
- package/dist/workflows/events/schema.d.ts.map +1 -1
- package/dist/workflows/events/schema.js +37 -1
- package/dist/workflows/events/schema.js.map +1 -1
- package/dist/workflows/events/types.d.ts +5 -1
- package/dist/workflows/events/types.d.ts.map +1 -1
- package/dist/workflows/loader.d.ts +14 -0
- package/dist/workflows/loader.d.ts.map +1 -1
- package/dist/workflows/loader.js +27 -0
- package/dist/workflows/loader.js.map +1 -1
- package/dist/workflows/loop.js +58 -0
- package/dist/workflows/loop.js.map +1 -1
- package/dist/workflows/ops-projection.d.ts +58 -0
- package/dist/workflows/ops-projection.d.ts.map +1 -1
- package/dist/workflows/ops-projection.js +74 -0
- package/dist/workflows/ops-projection.js.map +1 -1
- package/dist/workflows/orchestrator.d.ts +65 -1
- package/dist/workflows/orchestrator.d.ts.map +1 -1
- package/dist/workflows/orchestrator.js +486 -74
- package/dist/workflows/orchestrator.js.map +1 -1
- package/dist/workflows/output-binding.d.ts +8 -1
- package/dist/workflows/output-binding.d.ts.map +1 -1
- package/dist/workflows/output-binding.js +75 -11
- package/dist/workflows/output-binding.js.map +1 -1
- package/dist/workflows/runtime.d.ts +1 -1
- package/dist/workflows/runtime.d.ts.map +1 -1
- package/dist/workflows/runtime.js +39 -4
- package/dist/workflows/runtime.js.map +1 -1
- package/dist/workflows/trigger-from-envelope.d.ts +13 -0
- package/dist/workflows/trigger-from-envelope.d.ts.map +1 -0
- package/dist/workflows/trigger-from-envelope.js +67 -0
- package/dist/workflows/trigger-from-envelope.js.map +1 -0
- package/dist/workflows/wait.d.ts +23 -2
- package/dist/workflows/wait.d.ts.map +1 -1
- package/dist/workflows/wait.js +39 -17
- package/dist/workflows/wait.js.map +1 -1
- package/package.json +1 -1
- package/dist/services/feishu-task-client.d.ts +0 -28
- package/dist/services/feishu-task-client.d.ts.map +0 -1
- package/dist/services/feishu-task-client.js +0 -123
- package/dist/services/feishu-task-client.js.map +0 -1
- package/dist/services/task-store.d.ts +0 -37
- package/dist/services/task-store.d.ts.map +0 -1
- package/dist/services/task-store.js +0 -115
- package/dist/services/task-store.js.map +0 -1
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
"use strict";(()=>{var Ce=class{sessions=new Map;schedules=new Map;online=!0;listeners=new Set;upsertSessions(t){for(let o of t)this.sessions.set(o.sessionId,o);this.emit()}upsertSchedules(t){for(let o of t)this.schedules.set(o.id,o);this.emit()}applySse(t,o){if(t==="session.spawned")this.sessions.set(o.session.sessionId,o.session);else if(t==="session.update"){let r=this.sessions.get(o.sessionId);r&&this.sessions.set(o.sessionId,{...r,...o.patch})}else if(t==="session.exited"){let r=this.sessions.get(o.sessionId);r&&this.sessions.set(o.sessionId,{...r,status:"closed"})}else if(t==="schedule.created")this.schedules.set(o.schedule.id,o.schedule);else if(t==="schedule.updated"){let r=this.schedules.get(o.id);r&&this.schedules.set(o.id,{...r,...o.patch})}else if(t==="schedule.deleted")this.schedules.delete(o.id);else return;this.emit()}setOnline(t){this.online!==t&&(this.online=t,this.emit())}on(t){return this.listeners.add(t),()=>this.listeners.delete(t)}emit(){for(let t of this.listeners)t()}},O=new Ce;async function Je(){let[e,t]=await Promise.all([fetch("/api/sessions").then(s=>s.json()),fetch("/api/schedules").then(s=>s.json())]);O.upsertSessions(e.sessions??[]),O.upsertSchedules(t.schedules??[]);let o=new EventSource("/events"),r=["session.spawned","session.update","session.exited","schedule.created","schedule.updated","schedule.deleted","schedule.fired","heartbeat"];for(let s of r)o.addEventListener(s,a=>{try{let d=JSON.parse(a.data);O.applySse(s,d.body??d)}catch{}});o.onerror=()=>O.setOnline(!1),o.onopen=()=>O.setOnline(!0)}var Me="botmux.dashboard.locale",Bt={"app.name":"botmux","app.subtitle":"\u98DE\u4E66 AI CLI \u63A7\u5236\u53F0","time.secondsAgo":"{value} \u79D2\u524D","time.minutesAgo":"{value} \u5206\u949F\u524D","time.hoursAgo":"{value} \u5C0F\u65F6\u524D","nav.overview":"\u603B\u89C8","nav.sessions":"\u4F1A\u8BDD","nav.groups":"\u7FA4\u7EC4","nav.schedules":"\u5B9A\u65F6","nav.botDefaults":"\u9ED8\u8BA4 Bot","status.live":"\u5B9E\u65F6\u8FDE\u63A5","status.disconnected":"\u8FDE\u63A5\u65AD\u5F00","status.system":"\u7CFB\u7EDF","status.light":"\u6D45\u8272","status.dark":"\u6697\u9ED1","status.language":"\u8BED\u8A00","status.theme":"\u4E3B\u9898","botOnboarding.add":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.title":"\u626B\u7801\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.intro":"\u7528\u98DE\u4E66 App \u626B\u7801\u521B\u5EFA PersonalAgent \u5E94\u7528\uFF0C\u6210\u529F\u540E\u4F1A\u5199\u5165\u672C\u673A bots.json\u3002","botOnboarding.starting":"\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801...","botOnboarding.waiting":"\u8BF7\u7528\u98DE\u4E66 App \u626B\u7801\u786E\u8BA4\u3002","botOnboarding.verifying":"\u626B\u7801\u6210\u529F\uFF0C\u6B63\u5728\u6821\u9A8C\u51ED\u8BC1...","botOnboarding.completed":"\u673A\u5668\u4EBA\u5DF2\u6DFB\u52A0\u3002","botOnboarding.failed":"\u6DFB\u52A0\u5931\u8D25","botOnboarding.openLink":"\u6253\u4E0D\u5F00\u626B\u7801\uFF1F\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00","botOnboarding.close":"\u5173\u95ED","botOnboarding.restartHint":"\u5DF2\u5199\u5165 bots.json\u3002\u6267\u884C pnpm daemon:restart \u540E\u65B0\u673A\u5668\u4EBA\u751F\u6548\u3002","botOnboarding.qrAlt":"\u98DE\u4E66\u626B\u7801\u6DFB\u52A0\u673A\u5668\u4EBA\u4E8C\u7EF4\u7801","overview.title":"\u63A7\u5236\u53F0\u603B\u89C8","overview.subtitle":"\u8DE8 bot\u3001\u7FA4\u804A\u3001\u4F1A\u8BDD\u548C\u5B9A\u65F6\u4EFB\u52A1\u7684\u5B9E\u65F6\u7BA1\u63A7\u9762\u3002","overview.openSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.workingSessions":"\u5DE5\u4F5C\u4E2D","overview.onlineBots":"\u5728\u7EBF Bot","overview.schedules":"\u5B9A\u65F6\u4EFB\u52A1","overview.groups":"\u7FA4\u804A\u8986\u76D6","overview.enabledSchedules":"\u5DF2\u542F\u7528","overview.total":"\u603B\u8BA1","overview.active":"\u6D3B\u8DC3","overview.daemonRegistry":"daemon \u6CE8\u518C\u8868","overview.chatMatrix":"\u7FA4\u804A\u77E9\u9635","overview.recentSessions":"\u6700\u8FD1\u4F1A\u8BDD","overview.nextSchedules":"\u5373\u5C06\u6267\u884C","overview.noSessions":"\u6682\u65E0\u4F1A\u8BDD\u3002","overview.noSchedules":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","sessions.title":"\u4F1A\u8BDD\u63A7\u5236","sessions.subtitle":"\u5B9A\u4F4D\u98DE\u4E66\u8BDD\u9898\u3001\u6253\u5F00 Web Terminal\u3001\u5173\u95ED\u6216\u6062\u590D CLI \u4F1A\u8BDD\u3002","sessions.search":"\u641C\u7D22\u5DE5\u4F5C\u76EE\u5F55 / \u6807\u9898 / ID","sessions.anyStatus":"\u5168\u90E8\u72B6\u6001","sessions.adoptAny":"adopt: \u5168\u90E8","sessions.adoptYes":"adopt: \u662F","sessions.adoptNo":"adopt: \u5426","sessions.activeOnly":"\u4EC5\u6D3B\u8DC3","sessions.closeSelected":"\u5173\u95ED\u9009\u4E2D","sessions.clearSelection":"\u53D6\u6D88\u9009\u62E9","sessions.selectedCount":"\u5DF2\u9009 {count} \u4E2A\u4F1A\u8BDD","sessions.bot":"bot","sessions.cli":"CLI","sessions.status":"\u72B6\u6001","sessions.titleCol":"\u6807\u9898","sessions.workingDir":"\u5DE5\u4F5C\u76EE\u5F55","sessions.created":"\u521B\u5EFA","sessions.last":"\u6700\u8FD1","sessions.adopt":"\u63A5\u5165","sessions.actions":"\u64CD\u4F5C","sessions.details":"\u8BE6\u60C5","sessions.copy":"\u590D\u5236","sessions.copied":"\u5DF2\u590D\u5236","sessions.locate":"\u5B9A\u4F4D\u8BDD\u9898","sessions.locating":"\u53D1\u9001\u4E2D...","sessions.cooldown":"\u51B7\u5374 {seconds}s","sessions.openTerminal":"\u7EC8\u7AEF","sessions.close":"\u5173\u95ED\u4F1A\u8BDD","sessions.resume":"\u6062\u590D\u4F1A\u8BDD","sessions.dismiss":"\u5173\u95ED","sessions.closeConfirm":"\u5173\u95ED\u8FD9\u4E2A\u4F1A\u8BDD\uFF1F","sessions.resumeFailed":"\u6062\u590D\u5931\u8D25","sessions.closeBulkConfirm":"\u5173\u95ED\u9009\u4E2D\u7684 {count} \u4E2A\u4F1A\u8BDD\uFF1F","sessions.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u4F1A\u8BDD\u3002","groups.title":"\u7FA4\u7EC4\u4E0E Bot","groups.subtitle":"\u67E5\u770B chat x bot \u8986\u76D6\u77E9\u9635\uFF0C\u7BA1\u7406\u62C9\u7FA4\u3001oncall\u3001\u9000\u7FA4\u548C\u89E3\u6563\u3002","groups.search":"\u641C\u7D22\u7FA4\u540D / ID / owner","groups.missingOnly":"\u4EC5\u7F3A bot","groups.refresh":"\u5237\u65B0","groups.create":"\u65B0\u5EFA\u7FA4","groups.chat":"\u7FA4\u804A","groups.actions":"\u64CD\u4F5C","groups.addBots":"\u6DFB\u52A0 bot","groups.manage":"\u7BA1\u7406","groups.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u7FA4\u804A\u3002","groups.createTitle":"\u65B0\u5EFA\u7FA4\u804A","groups.createHelp":"\u9009\u62E9\u8981\u9080\u8BF7\u7684 bot\u3002dashboard \u4F1A\u81EA\u52A8\u9009\u62E9\u5728\u7EBF daemon \u4F5C\u4E3A\u521B\u5EFA\u8005\u3002","groups.name":"\u7FA4\u540D","groups.namePlaceholder":"\u4F8B\u5982 AI ChangeLog","groups.bindDir":"\u7ED1\u5B9A\u76EE\u5F55","groups.bindDirHelp":"\u65B0\u8BDD\u9898\u76F4\u63A5\u7528\u8BE5\u76EE\u5F55\u542F\u52A8 CLI\uFF0C\u8DF3\u8FC7 repo \u9009\u62E9\u3002","groups.botPicker":"Bot","groups.createSubmit":"\u521B\u5EFA","groups.cancel":"\u53D6\u6D88","groups.successTitle":"\u7FA4\u521B\u5EFA\u6210\u529F","groups.openGroup":"\u6253\u5F00\u65B0\u7FA4","groups.manageTitle":"\u7BA1\u7406 {name}","groups.owner":"\u7FA4\u4E3B","groups.oncall":"Oncall \u6A21\u5F0F","groups.oncallHelp":"\u5F00\u542F\u540E\uFF0C\u7FA4\u5185\u6210\u5458\u53EF @ \u673A\u5668\u4EBA\uFF1B\u65B0\u8BDD\u9898\u76F4\u63A5\u4F7F\u7528\u7ED1\u5B9A\u76EE\u5F55\u3002","groups.leaveTitle":"\u9009\u62E9\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.leaveSelected":"\u9009\u4E2D\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.disband":"\u89E3\u6563\u7FA4\u804A","groups.dangerHint":"\u89E3\u6563\u4EC5\u5F53\u5728\u7FA4\u673A\u5668\u4EBA\u662F\u7FA4\u4E3B\u65F6\u624D\u4F1A\u6210\u529F\uFF0C\u5426\u5219\u5EFA\u8BAE\u4F7F\u7528\u9000\u51FA\u7FA4\u804A\u3002","groups.save":"\u4FDD\u5B58","groups.needWorkingDir":"\u8BF7\u586B\u5DE5\u4F5C\u76EE\u5F55","groups.noBotsOnline":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u8BF7\u5148\u91CD\u542F daemon\u3002","schedules.title":"\u5B9A\u65F6\u4EFB\u52A1","schedules.subtitle":"\u8DE8 daemon \u67E5\u770B\u3001\u6682\u505C\u3001\u6062\u590D\u548C\u7ACB\u5373\u89E6\u53D1\u5B9A\u65F6\u4EFB\u52A1\u3002","schedules.search":"\u641C\u7D22\u540D\u79F0 / prompt / \u5DE5\u4F5C\u76EE\u5F55","schedules.anyKind":"\u5168\u90E8\u7C7B\u578B","schedules.enabledOnly":"\u4EC5\u542F\u7528","schedules.name":"\u540D\u79F0","schedules.bot":"bot","schedules.schedule":"\u89C4\u5219","schedules.next":"\u4E0B\u6B21","schedules.last":"\u4E0A\u6B21","schedules.repeat":"\u91CD\u590D","schedules.enabled":"\u542F\u7528","schedules.actions":"\u64CD\u4F5C","schedules.runNow":"\u7ACB\u5373\u8FD0\u884C","schedules.pause":"\u6682\u505C","schedules.resume":"\u6062\u590D","schedules.empty":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","botDefaults.title":"Bot \u9ED8\u8BA4 Oncall","botDefaults.subtitle":"\u914D\u7F6E\u6BCF\u4E2A bot \u5728\u65B0\u7FA4\u91CC\u7684\u9ED8\u8BA4 oncall \u884C\u4E3A\u3002","botDefaults.search":"\u641C\u7D22 bot \u540D / app id","botDefaults.refresh":"\u5237\u65B0","botDefaults.warning":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 oncall binding \u7684\u7FA4\u4F1A\u5728\u4E0B\u6B21\u5F00\u65B0\u8BDD\u9898\u65F6\u81EA\u52A8\u7ED1\u5B9A\u5230\u8BE5\u76EE\u5F55\uFF1B\u624B\u52A8\u7ED1\u5B9A\u6216\u624B\u52A8\u89E3\u7ED1\u8FC7\u7684\u7FA4\u4E0D\u4F1A\u88AB\u8986\u76D6\u3002","botDefaults.empty":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u5148 botmux restart \u8BA9 daemon \u4E0A\u7EBF\u3002","botDefaults.defaultOncall":"\u9ED8\u8BA4\u8FDB\u5165 oncall \u6A21\u5F0F","botDefaults.defaultOncallHelp":"\u6240\u6709\u672A\u7ED1\u5B9A\u7684\u7FA4\u4E0B\u6B21\u5F00\u8BDD\u9898\u81EA\u52A8\u7ED1\u5B9A","botDefaults.workingDir":"\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55","botDefaults.lastEnabled":"\u4E0A\u6B21\u542F\u7528\u65F6\u95F4","botDefaults.autobound":"\u5DF2\u81EA\u52A8\u7ED1\u5B9A {count} \u4E2A\u7FA4","botDefaults.save":"\u4FDD\u5B58","botDefaults.required":"\u5F00\u542F\u65F6\u5FC5\u987B\u586B\u5DE5\u4F5C\u76EE\u5F55","nav.roles":"\u89D2\u8272\u7BA1\u7406","roles.title":"\u89D2\u8272\u7BA1\u7406","roles.subtitle":"\u4E3A\u6BCF\u4E2A\u7FA4\u7EC4\u7684\u6BCF\u4E2A Bot \u5355\u72EC\u8BBE\u7F6E\u89D2\u8272\u63D0\u793A\u8BCD\uFF0CBot \u5728\u8BE5\u7FA4\u4E2D\u4F1A\u4EE5\u6B64\u89D2\u8272\u884C\u4E8B\u3002","roles.search":"\u641C\u7D22\u7FA4\u540D/Bot/ID","roles.refresh":"\u5237\u65B0","roles.selectHint":"\u2190 \u5C55\u5F00\u7FA4\u7EC4\uFF0C\u9009\u62E9\u4E00\u4E2A Bot \u6765\u7F16\u8F91\u89D2\u8272","roles.editorPlaceholder":`\u8F93\u5165\u89D2\u8272\u63CF\u8FF0\uFF0C\u4F8B\u5982\uFF1A
|
|
1
|
+
"use strict";(()=>{var We=class{sessions=new Map;schedules=new Map;online=!0;listeners=new Set;upsertSessions(t){for(let n of t)this.sessions.set(n.sessionId,n);this.emit()}upsertSchedules(t){for(let n of t)this.schedules.set(n.id,n);this.emit()}applySse(t,n){if(t==="session.spawned")this.sessions.set(n.session.sessionId,n.session);else if(t==="session.update"){let s=this.sessions.get(n.sessionId);s&&this.sessions.set(n.sessionId,{...s,...n.patch})}else if(t==="session.exited"){let s=this.sessions.get(n.sessionId);s&&this.sessions.set(n.sessionId,{...s,status:"closed"})}else if(t==="schedule.created")this.schedules.set(n.schedule.id,n.schedule);else if(t==="schedule.updated"){let s=this.schedules.get(n.id);s&&this.schedules.set(n.id,{...s,...n.patch})}else if(t==="schedule.deleted")this.schedules.delete(n.id);else return;this.emit()}setOnline(t){this.online!==t&&(this.online=t,this.emit())}on(t){return this.listeners.add(t),()=>this.listeners.delete(t)}emit(){for(let t of this.listeners)t()}},N=new We;async function pt(){let[e,t]=await Promise.all([fetch("/api/sessions").then(a=>a.json()),fetch("/api/schedules").then(a=>a.json())]);N.upsertSessions(e.sessions??[]),N.upsertSchedules(t.schedules??[]);let n=new EventSource("/events"),s=["session.spawned","session.update","session.exited","schedule.created","schedule.updated","schedule.deleted","schedule.fired","heartbeat"];for(let a of s)n.addEventListener(a,r=>{try{let i=JSON.parse(r.data);N.applySse(a,i.body??i)}catch{}});n.onerror=()=>N.setOnline(!1),n.onopen=()=>N.setOnline(!0)}var ze="botmux.dashboard.locale",wn={"app.name":"botmux","app.subtitle":"\u98DE\u4E66 AI CLI \u63A7\u5236\u53F0","time.secondsAgo":"{value} \u79D2\u524D","time.minutesAgo":"{value} \u5206\u949F\u524D","time.hoursAgo":"{value} \u5C0F\u65F6\u524D","nav.overview":"\u603B\u89C8","nav.sessions":"\u4F1A\u8BDD","nav.groups":"\u7FA4\u7EC4","nav.schedules":"\u5B9A\u65F6","nav.botDefaults":"Bot \u914D\u7F6E","status.live":"\u5B9E\u65F6\u8FDE\u63A5","status.disconnected":"\u8FDE\u63A5\u65AD\u5F00","status.system":"\u7CFB\u7EDF","status.light":"\u6D45\u8272","status.dark":"\u6697\u9ED1","status.language":"\u8BED\u8A00","status.theme":"\u4E3B\u9898","botOnboarding.add":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.title":"\u626B\u7801\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.intro":"\u7528\u98DE\u4E66 App \u626B\u7801\u521B\u5EFA PersonalAgent \u5E94\u7528\uFF0C\u6210\u529F\u540E\u4F1A\u5199\u5165\u672C\u673A bots.json\u3002","botOnboarding.starting":"\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801...","botOnboarding.waiting":"\u8BF7\u7528\u98DE\u4E66 App \u626B\u7801\u786E\u8BA4\u3002","botOnboarding.verifying":"\u626B\u7801\u6210\u529F\uFF0C\u6B63\u5728\u6821\u9A8C\u51ED\u8BC1...","botOnboarding.completed":"\u673A\u5668\u4EBA\u5DF2\u6DFB\u52A0\u3002","botOnboarding.failed":"\u6DFB\u52A0\u5931\u8D25","botOnboarding.openLink":"\u6253\u4E0D\u5F00\u626B\u7801\uFF1F\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00","botOnboarding.close":"\u5173\u95ED","botOnboarding.restartHint":"\u5DF2\u5199\u5165 bots.json\u3002\u6267\u884C pnpm daemon:restart \u540E\u65B0\u673A\u5668\u4EBA\u751F\u6548\u3002","botOnboarding.qrAlt":"\u98DE\u4E66\u626B\u7801\u6DFB\u52A0\u673A\u5668\u4EBA\u4E8C\u7EF4\u7801","overview.title":"\u63A7\u5236\u53F0\u603B\u89C8","overview.subtitle":"\u8DE8 bot\u3001\u7FA4\u804A\u3001\u4F1A\u8BDD\u548C\u5B9A\u65F6\u4EFB\u52A1\u7684\u5B9E\u65F6\u7BA1\u63A7\u9762\u3002","overview.openSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.workingSessions":"\u5DE5\u4F5C\u4E2D","overview.onlineBots":"\u5728\u7EBF Bot","overview.schedules":"\u5B9A\u65F6\u4EFB\u52A1","overview.groups":"\u7FA4\u804A\u8986\u76D6","overview.enabledSchedules":"\u5DF2\u542F\u7528","overview.total":"\u603B\u8BA1","overview.active":"\u6D3B\u8DC3","overview.daemonRegistry":"daemon \u6CE8\u518C\u8868","overview.chatMatrix":"\u7FA4\u804A\u77E9\u9635","overview.recentSessions":"\u6700\u8FD1\u4F1A\u8BDD","overview.nextSchedules":"\u5373\u5C06\u6267\u884C","overview.noSessions":"\u6682\u65E0\u4F1A\u8BDD\u3002","overview.noSchedules":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","sessions.title":"\u4F1A\u8BDD\u63A7\u5236","sessions.subtitle":"\u5B9A\u4F4D\u98DE\u4E66\u8BDD\u9898\u3001\u6253\u5F00 Web Terminal\u3001\u5173\u95ED\u6216\u6062\u590D CLI \u4F1A\u8BDD\u3002","sessions.search":"\u641C\u7D22\u5DE5\u4F5C\u76EE\u5F55 / \u6807\u9898 / ID","sessions.anyStatus":"\u5168\u90E8\u72B6\u6001","sessions.adoptAny":"adopt: \u5168\u90E8","sessions.adoptYes":"adopt: \u662F","sessions.adoptNo":"adopt: \u5426","sessions.activeOnly":"\u4EC5\u6D3B\u8DC3","sessions.closeSelected":"\u5173\u95ED\u9009\u4E2D","sessions.clearSelection":"\u53D6\u6D88\u9009\u62E9","sessions.selectedCount":"\u5DF2\u9009 {count} \u4E2A\u4F1A\u8BDD","sessions.bot":"bot","sessions.cli":"CLI","sessions.status":"\u72B6\u6001","sessions.titleCol":"\u6807\u9898","sessions.workingDir":"\u5DE5\u4F5C\u76EE\u5F55","sessions.created":"\u521B\u5EFA","sessions.last":"\u6700\u8FD1","sessions.adopt":"\u63A5\u5165","sessions.actions":"\u64CD\u4F5C","sessions.details":"\u8BE6\u60C5","sessions.copy":"\u590D\u5236","sessions.copied":"\u5DF2\u590D\u5236","sessions.locate":"\u5B9A\u4F4D\u8BDD\u9898","sessions.locating":"\u53D1\u9001\u4E2D...","sessions.cooldown":"\u51B7\u5374 {seconds}s","sessions.openTerminal":"\u7EC8\u7AEF","sessions.close":"\u5173\u95ED\u4F1A\u8BDD","sessions.resume":"\u6062\u590D\u4F1A\u8BDD","sessions.dismiss":"\u5173\u95ED","sessions.closeConfirm":"\u5173\u95ED\u8FD9\u4E2A\u4F1A\u8BDD\uFF1F","sessions.resumeFailed":"\u6062\u590D\u5931\u8D25","sessions.closeBulkConfirm":"\u5173\u95ED\u9009\u4E2D\u7684 {count} \u4E2A\u4F1A\u8BDD\uFF1F","sessions.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u4F1A\u8BDD\u3002","groups.title":"\u7FA4\u7EC4\u4E0E Bot","groups.subtitle":"\u67E5\u770B chat x bot \u8986\u76D6\u77E9\u9635\uFF0C\u7BA1\u7406\u62C9\u7FA4\u3001oncall\u3001\u9000\u7FA4\u548C\u89E3\u6563\u3002","groups.search":"\u641C\u7D22\u7FA4\u540D / ID / owner","groups.missingOnly":"\u4EC5\u7F3A bot","groups.refresh":"\u5237\u65B0","groups.create":"\u65B0\u5EFA\u7FA4","groups.chat":"\u7FA4\u804A","groups.actions":"\u64CD\u4F5C","groups.addBots":"\u6DFB\u52A0 bot","groups.manage":"\u7BA1\u7406","groups.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u7FA4\u804A\u3002","groups.createTitle":"\u65B0\u5EFA\u7FA4\u804A","groups.createHelp":"\u9009\u62E9\u8981\u9080\u8BF7\u7684 bot\u3002dashboard \u4F1A\u81EA\u52A8\u9009\u62E9\u5728\u7EBF daemon \u4F5C\u4E3A\u521B\u5EFA\u8005\u3002","groups.name":"\u7FA4\u540D","groups.namePlaceholder":"\u4F8B\u5982 AI ChangeLog","groups.bindDir":"\u7ED1\u5B9A\u76EE\u5F55","groups.bindDirHelp":"\u65B0\u8BDD\u9898\u76F4\u63A5\u7528\u8BE5\u76EE\u5F55\u542F\u52A8 CLI\uFF0C\u8DF3\u8FC7 repo \u9009\u62E9\u3002","groups.botPicker":"Bot","groups.createSubmit":"\u521B\u5EFA","groups.cancel":"\u53D6\u6D88","groups.successTitle":"\u7FA4\u521B\u5EFA\u6210\u529F","groups.openGroup":"\u6253\u5F00\u65B0\u7FA4","groups.manageTitle":"\u7BA1\u7406 {name}","groups.owner":"\u7FA4\u4E3B","groups.oncall":"Oncall \u6A21\u5F0F","groups.oncallHelp":"\u5F00\u542F\u540E\uFF0C\u7FA4\u5185\u6210\u5458\u53EF @ \u673A\u5668\u4EBA\uFF1B\u65B0\u8BDD\u9898\u76F4\u63A5\u4F7F\u7528\u7ED1\u5B9A\u76EE\u5F55\u3002","groups.leaveTitle":"\u9009\u62E9\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.leaveSelected":"\u9009\u4E2D\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.disband":"\u89E3\u6563\u7FA4\u804A","groups.dangerHint":"\u89E3\u6563\u4EC5\u5F53\u5728\u7FA4\u673A\u5668\u4EBA\u662F\u7FA4\u4E3B\u65F6\u624D\u4F1A\u6210\u529F\uFF0C\u5426\u5219\u5EFA\u8BAE\u4F7F\u7528\u9000\u51FA\u7FA4\u804A\u3002","groups.save":"\u4FDD\u5B58","groups.needWorkingDir":"\u8BF7\u586B\u5DE5\u4F5C\u76EE\u5F55","groups.noBotsOnline":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u8BF7\u5148\u91CD\u542F daemon\u3002","schedules.title":"\u5B9A\u65F6\u4EFB\u52A1","schedules.subtitle":"\u8DE8 daemon \u67E5\u770B\u3001\u6682\u505C\u3001\u6062\u590D\u548C\u7ACB\u5373\u89E6\u53D1\u5B9A\u65F6\u4EFB\u52A1\u3002","schedules.search":"\u641C\u7D22\u540D\u79F0 / prompt / \u5DE5\u4F5C\u76EE\u5F55","schedules.anyKind":"\u5168\u90E8\u7C7B\u578B","schedules.enabledOnly":"\u4EC5\u542F\u7528","schedules.name":"\u540D\u79F0","schedules.bot":"bot","schedules.schedule":"\u89C4\u5219","schedules.next":"\u4E0B\u6B21","schedules.last":"\u4E0A\u6B21","schedules.repeat":"\u91CD\u590D","schedules.enabled":"\u542F\u7528","schedules.actions":"\u64CD\u4F5C","schedules.runNow":"\u7ACB\u5373\u8FD0\u884C","schedules.pause":"\u6682\u505C","schedules.resume":"\u6062\u590D","schedules.empty":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","botDefaults.title":"Bot \u9ED8\u8BA4\u914D\u7F6E","botDefaults.subtitle":"\u7BA1\u7406\u6BCF\u4E2A bot \u7684\u9ED8\u8BA4\u884C\u4E3A\uFF1A\u65B0\u7FA4 oncall \u81EA\u52A8\u7ED1\u5B9A\u3001\u5361\u7247\u7B7E\u540D\u7B49\u3002","botDefaults.search":"\u641C\u7D22 bot \u540D / app id","botDefaults.refresh":"\u5237\u65B0","botDefaults.sectionOncall":"\u65B0\u7FA4 Oncall","botDefaults.sectionBrand":"\u5361\u7247\u7B7E\u540D","botDefaults.warning":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 oncall binding \u7684\u7FA4\u4F1A\u5728\u4E0B\u6B21\u5F00\u65B0\u8BDD\u9898\u65F6\u81EA\u52A8\u7ED1\u5B9A\u5230\u8BE5\u76EE\u5F55\uFF1B\u624B\u52A8\u7ED1\u5B9A\u6216\u624B\u52A8\u89E3\u7ED1\u8FC7\u7684\u7FA4\u4E0D\u4F1A\u88AB\u8986\u76D6\u3002","botDefaults.empty":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u5148 botmux restart \u8BA9 daemon \u4E0A\u7EBF\u3002","botDefaults.defaultOncall":"\u9ED8\u8BA4\u8FDB\u5165 oncall \u6A21\u5F0F","botDefaults.defaultOncallHelp":"\u6240\u6709\u672A\u7ED1\u5B9A\u7684\u7FA4\u4E0B\u6B21\u5F00\u8BDD\u9898\u81EA\u52A8\u7ED1\u5B9A","botDefaults.workingDir":"\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55","botDefaults.lastEnabled":"\u4E0A\u6B21\u542F\u7528\u65F6\u95F4","botDefaults.autobound":"\u5DF2\u81EA\u52A8\u7ED1\u5B9A {count} \u4E2A\u7FA4","botDefaults.save":"\u4FDD\u5B58","botDefaults.required":"\u5F00\u542F\u65F6\u5FC5\u987B\u586B\u5DE5\u4F5C\u76EE\u5F55","botDefaults.brandLabel":"\u4E2A\u6027\u7B7E\u540D\uFF08\u5361\u7247\u9875\u811A\uFF09","botDefaults.brandLabelHelp":"\u8BE5 bot \u53D1\u51FA\u7684\u5361\u7247\u9875\u811A\u7B7E\u540D\u3002\u7559\u7A7A\u4FDD\u5B58\uFF1D\u4E0D\u663E\u793A\uFF1B\u586B\u5199\uFF1D\u81EA\u5B9A\u4E49\uFF08\u652F\u6301 markdown\uFF0C\u5982 [Acme](https://\u2026)\uFF09\uFF1B\u6062\u590D\u9ED8\u8BA4\uFF1D\u663E\u793A botmux\u3002","botDefaults.brandLabelPlaceholder":"\u9ED8\u8BA4\uFF1Abotmux\uFF08\u7559\u7A7A\u5219\u4E0D\u663E\u793A\uFF09","botDefaults.brandSave":"\u4FDD\u5B58\u7B7E\u540D","botDefaults.brandReset":"\u6062\u590D\u9ED8\u8BA4","botDefaults.brandStateDefault":"\u5F53\u524D\uFF1A\u9ED8\u8BA4 botmux","botDefaults.brandStateOff":"\u5F53\u524D\uFF1A\u5DF2\u5173\u95ED","botDefaults.brandStateCustom":"\u5F53\u524D\uFF1A\u81EA\u5B9A\u4E49","botDefaults.sectionCard":"\u5361\u7247\u884C\u4E3A","botDefaults.disableStreaming":"\u5173\u95ED\u98DE\u4E66\u6D41\u5F0F\u5361\u7247","botDefaults.disableStreamingHelp":"\u4E0D\u518D\u53D1\u5B9E\u65F6\u5237\u65B0\u7684\u4F1A\u8BDD\u72B6\u6001\u5361\uFF08\u542B\u300C\u6253\u5F00\u7EC8\u7AEF\u300D\u5165\u53E3\uFF09\uFF1B\u4EFB\u52A1\u6700\u7EC8\u7ED3\u679C\u4ECD\u901A\u8FC7\u6D88\u606F\u9001\u8FBE\u3002\u9002\u5408\u5ACC\u6D41\u5F0F\u5361\u7247\u70E6\u7684\u573A\u666F\u3002","botDefaults.writableLink":"\u5361\u7247\u4E0A\u76F4\u63A5\u7ED9\u53EF\u64CD\u4F5C\uFF08\u53EF\u5199\uFF09\u7EC8\u7AEF\u94FE\u63A5","botDefaults.writableLinkHelp":"\u26A0\uFE0F \u5728\u6D41\u5F0F\u5361\u7247\u6B63\u6587\u76F4\u63A5\u8D34\u51FA\u53EF\u5199\u7EC8\u7AEF\u94FE\u63A5\uFF0C\u7FA4\u5185\u4EFB\u4F55\u4EBA\u90FD\u80FD\u70B9\u5F00\u5E76\u64CD\u63A7\u7EC8\u7AEF\u3002\u4E0D\u52FE\uFF1D\u4FDD\u6301\u73B0\u72B6\uFF08\u8D70\u300C\u83B7\u53D6\u64CD\u4F5C\u94FE\u63A5\u300D\u6309\u94AE\u79C1\u804A\u53D1\u7ED9\u70B9\u51FB\u8005\uFF09\u3002","botDefaults.writableLinkMoot":"\u5DF2\u5173\u95ED\u6D41\u5F0F\u5361\u7247\uFF0C\u672C\u9879\u4E0D\u751F\u6548","botDefaults.privateCard":"/card \u53D1\u79C1\u5BC6\u5361\u7247\uFF08\u4EC5\u6388\u6743\u4EBA\u53EF\u89C1\uFF09","botDefaults.privateCardHelp":"\u5F00\u542F\u540E /card \u6539\u7528\u300C\u4EC5\u7279\u5B9A\u4EBA\u53EF\u89C1\u300D\u7684\u4E34\u65F6\u5361\u7247\uFF1A\u53EA\u53D1\u7ED9 owner\uFF08allowedUsers\uFF09\uFF0C/grant \u6388\u6743\u5BF9\u8BDD\u7684\u4EBA\u548C\u7FA4\u91CC\u5176\u4ED6\u4EBA\u90FD\u770B\u4E0D\u5230\u3002\u4EE3\u4EF7\uFF1A\u662F\u9759\u6001\u5FEB\u7167\u3001\u4E0D\u4F1A\u5B9E\u65F6\u5237\u65B0\uFF1B\u4E14\u4EC5\u666E\u901A\u7FA4\u53EF\u7528\uFF08\u8BDD\u9898\u7FA4 / \u5355\u804A\u4F1A\u5931\u8D25\uFF0C\u4E0D\u964D\u7EA7\uFF09\u3002\u53EA\u5F71\u54CD /card \u547D\u4EE4\uFF0C\u81EA\u52A8\u6D41\u5F0F\u5361\u4E0D\u53D8\u3002","botDefaults.cardPrefSaved":"\u5DF2\u4FDD\u5B58","nav.roles":"\u89D2\u8272\u7BA1\u7406","roles.title":"\u89D2\u8272\u7BA1\u7406","roles.subtitle":"\u4E3A\u6BCF\u4E2A\u7FA4\u7EC4\u7684\u6BCF\u4E2A Bot \u5355\u72EC\u8BBE\u7F6E\u89D2\u8272\u63D0\u793A\u8BCD\uFF0CBot \u5728\u8BE5\u7FA4\u4E2D\u4F1A\u4EE5\u6B64\u89D2\u8272\u884C\u4E8B\u3002","roles.search":"\u641C\u7D22\u7FA4\u540D/Bot/ID","roles.refresh":"\u5237\u65B0","roles.selectHint":"\u2190 \u5C55\u5F00\u7FA4\u7EC4\uFF0C\u9009\u62E9\u4E00\u4E2A Bot \u6765\u7F16\u8F91\u89D2\u8272","roles.editorPlaceholder":`\u8F93\u5165\u89D2\u8272\u63CF\u8FF0\uFF0C\u4F8B\u5982\uFF1A
|
|
2
2
|
\u4F60\u662F\u672C\u7FA4\u7684\u6280\u672F\u987E\u95EE\uFF0C\u8D1F\u8D23\u56DE\u7B54\u6240\u6709\u6280\u672F\u95EE\u9898...`,"roles.configured":"\u5DF2\u914D\u7F6E","roles.unconfigured":"\u672A\u914D\u7F6E","roles.noChats":"\u6682\u65E0\u7FA4\u7EC4","roles.preview":"\u9884\u89C8","roles.previewEmpty":"\uFF08\u7A7A\u5185\u5BB9\uFF09","roles.saved":"\u5DF2\u4FDD\u5B58","roles.delete":"\u5220\u9664","roles.save":"\u4FDD\u5B58","roles.confirmDelete":"\u786E\u8BA4\u5220\u9664\u8BE5 Bot \u5728\u6B64\u7FA4\u7684\u89D2\u8272\u914D\u7F6E\uFF1F","roles.botsWithRoles":"\u4E2A Bot \u5DF2\u914D\u7F6E\u89D2\u8272","roles.emptyError":"\u89D2\u8272\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u8BF7\u5148\u8F93\u5165\u5185\u5BB9","roles.saveFailed":"\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5","common.none":"\u65E0","common.unknown":"\u672A\u77E5","common.now":"\u521A\u521A","common.never":"\u4ECE\u672A","nav.workflows":"\u5DE5\u4F5C\u6D41(beta)","nav.workflowCatalog":"\u76EE\u5F55","workflow.subnav.runs":"\u8FD0\u884C","workflow.subnav.catalog":"\u76EE\u5F55","workflow.searchPlaceholder":"\u641C\u7D22 runId / workflowId / chatId","workflow.filter.nonTerminal":"\u975E\u7EC8\u6001","workflow.filter.all":"\u5168\u90E8","workflow.status.pending":"\u5F85\u5F00\u59CB","workflow.status.running":"\u8FD0\u884C\u4E2D","workflow.status.waiting":"\u7B49\u5F85\u4E2D","workflow.status.effectAttempting":"\u526F\u4F5C\u7528\u4E2D","workflow.status.timedOut":"\u5DF2\u8D85\u65F6","workflow.status.succeeded":"\u6210\u529F","workflow.status.failed":"\u5931\u8D25","workflow.status.cancelled":"\u5DF2\u53D6\u6D88","workflow.table.run":"\u8FD0\u884C","workflow.table.workflow":"\u5DE5\u4F5C\u6D41","workflow.table.status":"\u72B6\u6001","workflow.table.lastSeq":"\u6700\u540E\u5E8F\u53F7","workflow.table.dangling":"\u60AC\u6302 dEf/dAct/dWait","workflow.table.updated":"\u66F4\u65B0\u65F6\u95F4","workflow.table.chatApp":"\u7FA4\u804A / \u5E94\u7528","workflow.list.failedLoad":"\u52A0\u8F7D\u5931\u8D25\uFF1A{error}","workflow.list.noRuns":"\u6CA1\u6709\u5339\u914D\u7684\u8FD0\u884C\u3002","workflow.list.noFilterMatch":"\u6CA1\u6709\u7B26\u5408\u7B5B\u9009\u6761\u4EF6\u7684\u8FD0\u884C\u3002","workflow.list.loaded":"{count} \u4E2A\u8FD0\u884C \xB7 \u5237\u65B0\u4E8E {time}","workflow.list.error":"\u9519\u8BEF\uFF1A{error}","workflow.detail.back":"\u8FD4\u56DE","workflow.detail.loading":"\u52A0\u8F7D\u4E2D...","workflow.detail.loadFailed":"\u52A0\u8F7D\u5931\u8D25","workflow.detail.cancel":"\u53D6\u6D88","workflow.detail.cliCancelOnly":"\u4EC5 CLI \u53EF\u53D6\u6D88","workflow.detail.cancelTitle":"\u53D6\u6D88\u8FD9\u4E2A\u5DE5\u4F5C\u6D41\u8FD0\u884C","workflow.detail.cliCancelTitle":"\u65E0\u6CD5\u5728\u9875\u9762\u53D6\u6D88\uFF1A\u8BF7\u4F7F\u7528 botmux workflow cancel {runId}","workflow.detail.nodes":"\u8282\u70B9 / Activity","workflow.detail.parallel":"\u5E76\u53D1\u6267\u884C","workflow.detail.parallelMeta":"{count} \u6B21\u5C1D\u8BD5 \xB7 \u6700\u9AD8\u5E76\u53D1 {max} \xB7 \u8FD0\u884C\u4E2D {running}","workflow.detail.noParallelData":"\u8FD8\u6CA1\u6709 attempt \u65F6\u95F4\u6570\u636E\u3002","workflow.detail.parallelNow":"\u73B0\u5728","workflow.detail.node":"\u8282\u70B9","workflow.detail.nodeStatus":"\u8282\u70B9\u72B6\u6001","workflow.detail.activity":"Activity","workflow.detail.activityStatus":"Activity \u72B6\u6001","workflow.detail.attempts":"\u5C1D\u8BD5\u6B21\u6570","workflow.detail.current":"\u5F53\u524D\u5C1D\u8BD5","workflow.detail.detail":"\u8BE6\u60C5","workflow.detail.nodeIO":"\u8282\u70B9\u8F93\u5165\u8F93\u51FA","workflow.detail.timeline":"\u65F6\u95F4\u7EBF","workflow.detail.loadOlder":"\u52A0\u8F7D\u66F4\u65E9\u4E8B\u4EF6","workflow.detail.seq":"\u5E8F\u53F7","workflow.detail.actor":"\u6267\u884C\u8005","workflow.detail.error":"\u9519\u8BEF","workflow.detail.event":"\u4E8B\u4EF6","workflow.detail.time":"\u65F6\u95F4","workflow.detail.refreshed":"\u5237\u65B0\u4E8E {time}","workflow.detail.unknownRun":"\u672A\u77E5\u8FD0\u884C","workflow.detail.snapshotHttp":"snapshot HTTP {status}","workflow.detail.eventsHttp":"events HTTP {status}","workflow.detail.cancelUnavailable":"\u65E0\u6CD5\u53D6\u6D88\uFF1A\u8BF7\u4F7F\u7528 botmux workflow cancel {runId}","workflow.detail.cancelConfirm":`\u786E\u8BA4\u53D6\u6D88\u5DE5\u4F5C\u6D41\u8FD0\u884C {runId}\uFF1F
|
|
3
3
|
|
|
4
4
|
{total} \u4E2A\u60AC\u6302\u9879\u4F1A\u7531 cancel recovery \u5904\u7406\u3002
|
|
5
5
|
effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"workflow.detail.writeAccessCancel":"\u9700\u8981\u5199\u6743\u9650\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C `botmux dashboard` \u83B7\u53D6\u4E00\u6B21\u6027 URL\uFF0C\u6253\u5F00\u540E\u5199\u5165 cookie\uFF0C\u518D\u56DE\u6765\u70B9\u51FB\u53D6\u6D88\u3002","workflow.detail.cancelHttp":"cancel HTTP {status}","workflow.detail.cancelPending":"\u53D6\u6D88\u5DF2\u63D0\u4EA4\uFF1B\u7B49\u5F85\u8FD0\u884C\u4E2D\u7684 activity \u6536\u655B","workflow.detail.writeAccessApproval":"\u9700\u8981\u5199\u6743\u9650\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C `botmux dashboard` \u83B7\u53D6\u4E00\u6B21\u6027 URL\uFF0C\u6253\u5F00\u540E\u5199\u5165 cookie\uFF0C\u518D\u56DE\u6765\u5BA1\u6279\u3002","workflow.detail.actionHttp":"{action} HTTP {status}","workflow.detail.approved":"\u5DF2\u901A\u8FC7","workflow.detail.rejected":"\u5DF2\u62D2\u7EDD","workflow.detail.alreadyTerminal":"\u8FD0\u884C\u5DF2\u7EC8\u6001\uFF1B\u672A\u5E94\u7528\u201C{label}\u201D\u3002","workflow.detail.workflowContinue":"{label}\uFF1B\u7B49\u5F85\u5DE5\u4F5C\u6D41\u7EE7\u7EED\u6267\u884C\u3002","workflow.detail.workflowRefreshing":"{label}\uFF1B\u6B63\u5728\u5237\u65B0\u5DE5\u4F5C\u6D41\u72B6\u6001\u3002","workflow.detail.eventsLoaded":"\u5DF2\u52A0\u8F7D {loaded}/{total} \u4E2A\u4E8B\u4EF6","workflow.detail.dangling":"\u60AC\u6302\u9879","workflow.detail.noDangling":"\u6CA1\u6709\u60AC\u6302\u5DE5\u4F5C\u3002","workflow.detail.none":"\u65E0","workflow.detail.noNodes":"\u8FD8\u6CA1\u6709\u8282\u70B9\u3002","workflow.detail.idle":"\u7A7A\u95F2","workflow.detail.noNodeIO":"\u8FD8\u6CA1\u6709\u8282\u70B9\u8F93\u5165\u8F93\u51FA\u3002","workflow.detail.notDispatched":"\u5C1A\u672A\u6D3E\u53D1","workflow.detail.noAttempt":"\u8FD8\u6CA1\u6709\u5C1D\u8BD5","workflow.detail.attempt":"\u5C1D\u8BD5","workflow.detail.authoredInput":"\u539F\u59CB\u8F93\u5165","workflow.detail.resolvedInput":"\u89E3\u6790\u540E\u8F93\u5165","workflow.detail.output":"\u8F93\u51FA","workflow.detail.executionLog":"\u6267\u884C\u65E5\u5FD7","workflow.detail.liveTerminal":"\u5B9E\u65F6\u7EC8\u7AEF","workflow.detail.terminalLive":"\u5728\u7EBF","workflow.detail.terminalClosedShort":"\u5DF2\u5173\u95ED","workflow.detail.terminalClosed":"\u7EC8\u7AEF\u5DF2\u5173\u95ED\u3002\u8BF7\u67E5\u770B\u4E0B\u65B9\u6267\u884C\u65E5\u5FD7\u83B7\u53D6\u6700\u7EC8\u8BB0\u5F55\u3002","workflow.detail.openTerminalNewTab":"\u5728\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u7EC8\u7AEF","workflow.detail.terminalReplay":"\u7EC8\u7AEF\u56DE\u653E","workflow.detail.openReplayNewTab":"\u5728\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u56DE\u653E","workflow.detail.downloadFullLog":"\u4E0B\u8F7D\u5B8C\u6574\u65E5\u5FD7","workflow.detail.terminalResume":"\u8C03\u8BD5\u4F1A\u8BDD","workflow.detail.openResumeNewTab":"\u5728\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u8C03\u8BD5\u4F1A\u8BDD","workflow.detail.resumeSession":"\u7EE7\u7EED\u4F1A\u8BDD","workflow.detail.resumeStarting":"\u6B63\u5728\u542F\u52A8\u2026","workflow.detail.endResumeSession":"\u7ED3\u675F\u8C03\u8BD5\u4F1A\u8BDD","workflow.detail.resumeEnding":"\u7ED3\u675F\u4E2D\u2026","workflow.detail.resumeUnsupportedCli":"{cliId} CLI \u4E0D\u652F\u6301 resume","workflow.detail.resumeMissingCliSession":"\u7F3A\u5C11 cliSessionId\uFF0C\u65E0\u6CD5 resume","workflow.detail.resumeStartFailed":"\u542F\u52A8\u8C03\u8BD5\u4F1A\u8BDD\u5931\u8D25 (HTTP {status})","workflow.detail.resumeEndFailed":"\u7ED3\u675F\u8C03\u8BD5\u4F1A\u8BDD\u5931\u8D25 (HTTP {status})","workflow.detail.writeAccessResume":"\u9700\u8981\u5199\u5165\u6743\u9650\u624D\u80FD resume \u4F1A\u8BDD\u3002","workflow.detail.waitPrompt":"\u7B49\u5F85\u63D0\u793A","workflow.detail.approvalComment":"\u5BA1\u6279\u5907\u6CE8","workflow.detail.optionalComment":"\u53EF\u9009\u5907\u6CE8","workflow.detail.approve":"\u901A\u8FC7","workflow.detail.reject":"\u62D2\u7EDD","workflow.detail.submitting":"\u63D0\u4EA4\u4E2D...","workflow.detail.empty":"\u7A7A","workflow.detail.truncated":"\u5DF2\u622A\u65AD","workflow.detail.noData":"\u6CA1\u6709\u6570\u636E\u3002","workflow.detail.noPreview":"\u6CA1\u6709\u9884\u89C8\u3002","workflow.detail.open":"\u6253\u5F00","workflow.detail.deadline":"\u622A\u6B62","workflow.detail.effect":"\u526F\u4F5C\u7528","workflow.detail.wait":"\u7B49\u5F85","workflow.detail.noEvents":"\u8FD8\u6CA1\u6709\u4E8B\u4EF6\u3002","workflow.summary.workflow":"\u5DE5\u4F5C\u6D41","workflow.summary.status":"\u72B6\u6001","workflow.summary.lastSeq":"\u6700\u540E\u5E8F\u53F7","workflow.summary.updated":"\u66F4\u65B0\u65F6\u95F4","workflow.summary.revision":"\u4FEE\u8BA2","workflow.summary.initiator":"\u53D1\u8D77\u4EBA","workflow.summary.failedNode":"\u5931\u8D25\u8282\u70B9","workflow.summary.cancelOrigin":"\u53D6\u6D88\u6765\u6E90","workflow.summary.chat":"\u7FA4\u804A","workflow.summary.app":"\u5E94\u7528","workflow.dangling.activities":"Activities","workflow.dangling.effects":"Effects","workflow.dangling.waits":"Waits","workflow.dangling.cancels":"Cancels","catalog.title":"\u5DE5\u4F5C\u6D41\u76EE\u5F55","catalog.subtitle":"\u4ECE\u5DF2\u4FDD\u5B58\u7684 workflow \u5B9A\u4E49\u521B\u5EFA\u4E00\u6B21\u8FD0\u884C\u3002","catalog.searchPlaceholder":"\u641C\u7D22 workflowId / \u8DEF\u5F84","catalog.refresh":"\u5237\u65B0","catalog.loading":"\u6B63\u5728\u52A0\u8F7D\u76EE\u5F55...","catalog.loadFailed":"\u76EE\u5F55\u52A0\u8F7D\u5931\u8D25\uFF1A{error}","catalog.noDefinitions":"\u6CA1\u6709\u627E\u5230 workflow \u5B9A\u4E49\u3002","catalog.noFilterMatch":"\u6CA1\u6709\u7B26\u5408\u7B5B\u9009\u6761\u4EF6\u7684\u5B9A\u4E49\u3002","catalog.table.workflow":"\u5DE5\u4F5C\u6D41","catalog.table.version":"\u7248\u672C","catalog.table.params":"\u53C2\u6570","catalog.table.nodes":"\u8282\u70B9","catalog.table.revision":"\u4FEE\u8BA2","catalog.table.path":"\u8DEF\u5F84","catalog.paramSummary":"{required}/{total} \u5FC5\u586B","catalog.back":"\u8FD4\u56DE\u76EE\u5F55","catalog.detailTitle":"\u5DE5\u4F5C\u6D41\u5B9A\u4E49","catalog.definitionLoadFailed":"\u5B9A\u4E49\u52A0\u8F7D\u5931\u8D25\uFF1A{error}","catalog.summary":"\u6458\u8981","catalog.paramsSchema":"\u53C2\u6570 Schema","catalog.definitionJson":"\u5B9A\u4E49 JSON","catalog.runPanel":"\u8FD0\u884C\u5DE5\u4F5C\u6D41","catalog.paramsJson":"\u53C2\u6570 JSON","catalog.paramsPlaceholder":`{
|
|
6
6
|
"city": "\u5317\u4EAC"
|
|
7
|
-
}`,"catalog.chatId":"\u7FA4\u804A ID","catalog.larkAppId":"\u98DE\u4E66\u5E94\u7528 ID","catalog.chatBindingHint":"\u5FC5\u586B\uFF0C\u7528\u4E8E\u786E\u5B9A humanGate \u5361\u7247\u53D1\u9001\u5230\u54EA\u4E2A\u98DE\u4E66\u7FA4\uFF0C\u4EE5\u53CA\u53D6\u6D88\u8DEF\u7531\u5F52\u5C5E\u3002","catalog.run":"\u8FD0\u884C","catalog.running":"\u542F\u52A8\u4E2D...","catalog.badParamsJson":"\u53C2\u6570\u5FC5\u987B\u662F JSON object\u3002","catalog.writeAccess":"\u9700\u8981\u5199\u6743\u9650\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C `botmux dashboard` \u83B7\u53D6\u4E00\u6B21\u6027 URL\uFF0C\u6253\u5F00\u540E\u5199\u5165 cookie\uFF0C\u518D\u56DE\u6765\u8FD0\u884C\u3002","catalog.runHttp":"run HTTP {status}","catalog.runStarted":"\u8FD0\u884C\u5DF2\u542F\u52A8\uFF1B\u6B63\u5728\u6253\u5F00\u8BE6\u60C5\u9875...","catalog.invalidParams":"\u53C2\u6570\u65E0\u6548","catalog.issue":"{path}: {message}","catalog.noParams":"\u6CA1\u6709\u58F0\u660E\u53C2\u6570\u3002","catalog.required":"\u5FC5\u586B","catalog.optional":"\u53EF\u9009","catalog.default":"\u9ED8\u8BA4\u503C","catalog.description":"\u8BF4\u660E","catalog.path":"\u8DEF\u5F84","catalog.revision":"\u4FEE\u8BA2","catalog.nodeCount":"\u8282\u70B9\u6570"},
|
|
7
|
+
}`,"catalog.chatId":"\u7FA4\u804A ID","catalog.larkAppId":"\u98DE\u4E66\u5E94\u7528 ID","catalog.chatBindingHint":"\u5FC5\u586B\uFF0C\u7528\u4E8E\u786E\u5B9A humanGate \u5361\u7247\u53D1\u9001\u5230\u54EA\u4E2A\u98DE\u4E66\u7FA4\uFF0C\u4EE5\u53CA\u53D6\u6D88\u8DEF\u7531\u5F52\u5C5E\u3002","catalog.run":"\u8FD0\u884C","catalog.running":"\u542F\u52A8\u4E2D...","catalog.badParamsJson":"\u53C2\u6570\u5FC5\u987B\u662F JSON object\u3002","catalog.writeAccess":"\u9700\u8981\u5199\u6743\u9650\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C `botmux dashboard` \u83B7\u53D6\u4E00\u6B21\u6027 URL\uFF0C\u6253\u5F00\u540E\u5199\u5165 cookie\uFF0C\u518D\u56DE\u6765\u8FD0\u884C\u3002","catalog.runHttp":"run HTTP {status}","catalog.runStarted":"\u8FD0\u884C\u5DF2\u542F\u52A8\uFF1B\u6B63\u5728\u6253\u5F00\u8BE6\u60C5\u9875...","catalog.invalidParams":"\u53C2\u6570\u65E0\u6548","catalog.issue":"{path}: {message}","catalog.noParams":"\u6CA1\u6709\u58F0\u660E\u53C2\u6570\u3002","catalog.required":"\u5FC5\u586B","catalog.optional":"\u53EF\u9009","catalog.default":"\u9ED8\u8BA4\u503C","catalog.description":"\u8BF4\u660E","catalog.path":"\u8DEF\u5F84","catalog.revision":"\u4FEE\u8BA2","catalog.nodeCount":"\u8282\u70B9\u6570"},gn={"app.name":"botmux","app.subtitle":"Feishu AI CLI Control","time.secondsAgo":"{value}s ago","time.minutesAgo":"{value}m ago","time.hoursAgo":"{value}h ago","nav.overview":"Overview","nav.sessions":"Sessions","nav.groups":"Groups","nav.schedules":"Schedules","nav.botDefaults":"Bot Defaults","status.live":"Live","status.disconnected":"Disconnected","status.system":"System","status.light":"Light","status.dark":"Dark","status.language":"Language","status.theme":"Theme","botOnboarding.add":"Add Bot","botOnboarding.title":"Scan to Add Bot","botOnboarding.intro":"Scan with the Feishu app to create a PersonalAgent app. The dashboard writes it to local bots.json after success.","botOnboarding.starting":"Generating QR code...","botOnboarding.waiting":"Scan with the Feishu app to continue.","botOnboarding.verifying":"Scan accepted. Verifying credentials...","botOnboarding.completed":"Bot added.","botOnboarding.failed":"Add failed","botOnboarding.openLink":"Open scan link in browser","botOnboarding.close":"Close","botOnboarding.restartHint":"bots.json has been updated. Run pnpm daemon:restart for the new bot to take effect.","botOnboarding.qrAlt":"Feishu bot onboarding QR code","overview.title":"Control Overview","overview.subtitle":"A realtime control plane across bots, chats, CLI sessions, and schedules.","overview.openSessions":"Active Sessions","overview.workingSessions":"Working","overview.onlineBots":"Online Bots","overview.schedules":"Schedules","overview.groups":"Groups Seen","overview.enabledSchedules":"Enabled","overview.total":"total","overview.active":"active","overview.daemonRegistry":"daemon registry","overview.chatMatrix":"chat matrix","overview.recentSessions":"Recent Sessions","overview.nextSchedules":"Next Runs","overview.noSessions":"No sessions yet.","overview.noSchedules":"No schedules yet.","sessions.title":"Session Control","sessions.subtitle":"Locate Feishu topics, open Web Terminal, close or resume CLI sessions.","sessions.search":"Search working dir / title / IDs","sessions.anyStatus":"Any status","sessions.adoptAny":"adopt: any","sessions.adoptYes":"adopt: yes","sessions.adoptNo":"adopt: no","sessions.activeOnly":"Active only","sessions.closeSelected":"Close selected","sessions.clearSelection":"Clear","sessions.selectedCount":"{count} sessions selected","sessions.bot":"Bot","sessions.cli":"CLI","sessions.status":"Status","sessions.titleCol":"Title","sessions.workingDir":"Working Dir","sessions.created":"Created","sessions.last":"Last","sessions.adopt":"Adopt","sessions.actions":"Actions","sessions.details":"Details","sessions.copy":"Copy","sessions.copied":"Copied","sessions.locate":"Locate Topic","sessions.locating":"Sending...","sessions.cooldown":"Cooldown {seconds}s","sessions.openTerminal":"Terminal","sessions.close":"Close Session","sessions.resume":"Resume Session","sessions.dismiss":"Close","sessions.closeConfirm":"Close this session?","sessions.resumeFailed":"Resume failed","sessions.closeBulkConfirm":"Close {count} selected sessions?","sessions.empty":"No sessions match the filters.","groups.title":"Groups & Bots","groups.subtitle":"Inspect the chat x bot matrix and manage group creation, oncall, leave, and disband flows.","groups.search":"Search chat name / ID / owner","groups.missingOnly":"Missing bot only","groups.refresh":"Refresh","groups.create":"New Group","groups.chat":"Chat","groups.actions":"Actions","groups.addBots":"Add Bots","groups.manage":"Manage","groups.empty":"No chats match the filters.","groups.createTitle":"Create New Group","groups.createHelp":"Pick bots to invite. The dashboard chooses an online daemon as creator.","groups.name":"Group Name","groups.namePlaceholder":"e.g. AI ChangeLog","groups.bindDir":"Bind Directory","groups.bindDirHelp":"New topics start the CLI here and skip repo selection.","groups.botPicker":"Bots","groups.createSubmit":"Create","groups.cancel":"Cancel","groups.successTitle":"Group Created","groups.openGroup":"Open Group","groups.manageTitle":"Manage {name}","groups.owner":"Owner","groups.oncall":"Oncall Mode","groups.oncallHelp":"When enabled, group members can @ the bot; new topics use the bound directory.","groups.leaveTitle":"Select Bots to Leave","groups.leaveSelected":"Selected Bots Leave","groups.disband":"Disband Group","groups.dangerHint":"Disband only works when an in-chat bot is the owner. Otherwise prefer leaving the chat.","groups.save":"Save","groups.needWorkingDir":"Working directory is required","groups.noBotsOnline":"No bots online. Restart the daemon first.","schedules.title":"Schedules","schedules.subtitle":"View, pause, resume, and run scheduled tasks across daemons.","schedules.search":"Search name / prompt / working dir","schedules.anyKind":"Any kind","schedules.enabledOnly":"Enabled only","schedules.name":"Name","schedules.bot":"Bot","schedules.schedule":"Schedule","schedules.next":"Next","schedules.last":"Last","schedules.repeat":"Repeat","schedules.enabled":"Enabled","schedules.actions":"Actions","schedules.runNow":"Run Now","schedules.pause":"Pause","schedules.resume":"Resume","schedules.empty":"No schedules.","botDefaults.title":"Bot Defaults","botDefaults.subtitle":"Manage each bot's defaults: new-chat oncall auto-binding, card signature, and more.","botDefaults.search":"Search bot name / app id","botDefaults.refresh":"Refresh","botDefaults.sectionOncall":"New-chat Oncall","botDefaults.sectionBrand":"Card Signature","botDefaults.warning":"When enabled, chats without an oncall binding auto-bind to this directory on their next new topic. Manually bound or unbound chats are preserved.","botDefaults.empty":"No bots online. Run botmux restart first.","botDefaults.defaultOncall":"Default to oncall mode","botDefaults.defaultOncallHelp":"Unbound chats auto-bind on the next new topic","botDefaults.workingDir":"Default Working Directory","botDefaults.lastEnabled":"Last Enabled","botDefaults.autobound":"{count} chats auto-bound","botDefaults.save":"Save","botDefaults.required":"Working directory is required when enabled","botDefaults.brandLabel":"Signature (card footer)","botDefaults.brandLabelHelp":"Footer signature on cards this bot sends. Save empty = hide; fill in = custom (markdown ok, e.g. [Acme](https://\u2026)); Reset = show botmux.","botDefaults.brandLabelPlaceholder":"Default: botmux (empty = hidden)","botDefaults.brandSave":"Save Signature","botDefaults.brandReset":"Reset to default","botDefaults.brandStateDefault":"Current: default botmux","botDefaults.brandStateOff":"Current: off","botDefaults.brandStateCustom":"Current: custom","botDefaults.sectionCard":"Card Behavior","botDefaults.disableStreaming":"Disable streaming card","botDefaults.disableStreamingHelp":"Stop posting the live session status card (and its Open Terminal entry). The task's final result still arrives as a message. For those who find the live card noisy.","botDefaults.writableLink":"Put a writable terminal link on the card","botDefaults.writableLinkHelp":'\u26A0\uFE0F Embeds a writable terminal link in the streaming card body \u2014 anyone in the chat can open and drive the terminal. Off = current behavior (private DM via the "Get Write Link" button).',"botDefaults.writableLinkMoot":"Streaming card disabled \u2014 this has no effect","botDefaults.privateCard":"/card sends a private card (authorized users only)","botDefaults.privateCardHelp":'Makes /card send an ephemeral "visible-to-specific-people" card: delivered only to the owner (allowedUsers); /grant-authorized talk users and everyone else in the chat cannot see it. Trade-off: it is a static snapshot (no live updates) and only works in regular group chats (topic groups / DMs fail, with no fallback). Affects only the /card command; the auto streaming card is unchanged.',"botDefaults.cardPrefSaved":"Saved","nav.roles":"Roles","roles.title":"Role Management","roles.subtitle":"Set per-bot role prompts for each group. Each bot adopts its own persona in the selected group.","roles.search":"Search group / bot / ID","roles.refresh":"Refresh","roles.selectHint":"\u2190 Expand a group and select a bot to edit its role","roles.editorPlaceholder":`Enter role description, e.g.:
|
|
8
8
|
You are a code reviewer for this group...`,"roles.configured":"Configured","roles.unconfigured":"None","roles.noChats":"No groups","roles.preview":"Preview","roles.previewEmpty":"(empty)","roles.saved":"Saved","roles.delete":"Delete","roles.save":"Save","roles.confirmDelete":"Delete this bot's role config for this group?","roles.botsWithRoles":"bots configured","roles.emptyError":"Role content cannot be empty","roles.saveFailed":"Save failed, please retry","common.none":"None","common.unknown":"Unknown","common.now":"now","common.never":"never","nav.workflows":"Workflows (beta)","nav.workflowCatalog":"Catalog","workflow.subnav.runs":"Runs","workflow.subnav.catalog":"Catalog","workflow.searchPlaceholder":"search runId / workflowId / chatId","workflow.filter.nonTerminal":"non-terminal","workflow.filter.all":"all","workflow.status.pending":"pending","workflow.status.running":"running","workflow.status.waiting":"waiting","workflow.status.effectAttempting":"effect","workflow.status.timedOut":"timed out","workflow.status.succeeded":"succeeded","workflow.status.failed":"failed","workflow.status.cancelled":"cancelled","workflow.table.run":"run","workflow.table.workflow":"workflow","workflow.table.status":"status","workflow.table.lastSeq":"lastSeq","workflow.table.dangling":"dEf/dAct/dWait","workflow.table.updated":"updated","workflow.table.chatApp":"chat / app","workflow.list.failedLoad":"Failed to load: {error}","workflow.list.noRuns":"No runs match.","workflow.list.noFilterMatch":"No runs match this filter.","workflow.list.loaded":"{count} runs \xB7 refreshed {time}","workflow.list.error":"error: {error}","workflow.detail.back":"Back","workflow.detail.loading":"Loading...","workflow.detail.loadFailed":"Load failed","workflow.detail.cancel":"Cancel","workflow.detail.cliCancelOnly":"CLI cancel only","workflow.detail.cancelTitle":"Cancel this workflow run","workflow.detail.cliCancelTitle":"Cancel unavailable: use botmux workflow cancel {runId}","workflow.detail.nodes":"Nodes / Activities","workflow.detail.parallel":"Parallel execution","workflow.detail.parallelMeta":"{count} attempt(s) \xB7 max parallel {max} \xB7 running {running}","workflow.detail.noParallelData":"No attempt timing data yet.","workflow.detail.parallelNow":"now","workflow.detail.node":"node","workflow.detail.nodeStatus":"node status","workflow.detail.activity":"activity","workflow.detail.activityStatus":"activity status","workflow.detail.attempts":"attempts","workflow.detail.current":"current","workflow.detail.detail":"detail","workflow.detail.nodeIO":"Node I/O","workflow.detail.timeline":"Timeline","workflow.detail.loadOlder":"Load older","workflow.detail.seq":"seq","workflow.detail.actor":"actor","workflow.detail.error":"error","workflow.detail.event":"event","workflow.detail.time":"time","workflow.detail.refreshed":"refreshed {time}","workflow.detail.unknownRun":"unknown run","workflow.detail.snapshotHttp":"snapshot HTTP {status}","workflow.detail.eventsHttp":"events HTTP {status}","workflow.detail.cancelUnavailable":"cancel unavailable: use botmux workflow cancel {runId}","workflow.detail.cancelConfirm":`Cancel workflow run {runId}?
|
|
9
9
|
|
|
10
10
|
{total} dangling item(s) will be handled by cancel-driven recovery.
|
|
11
11
|
effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"workflow.detail.writeAccessCancel":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and click cancel again.","workflow.detail.cancelHttp":"cancel HTTP {status}","workflow.detail.cancelPending":"cancel pending; waiting for running activity to drain","workflow.detail.writeAccessApproval":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and approve/reject again.","workflow.detail.actionHttp":"{action} HTTP {status}","workflow.detail.approved":"approved","workflow.detail.rejected":"rejected","workflow.detail.alreadyTerminal":"Run already terminal; {label} was not applied.","workflow.detail.workflowContinue":"{label}; waiting for workflow to continue.","workflow.detail.workflowRefreshing":"{label}; refreshing workflow state.","workflow.detail.eventsLoaded":"{loaded}/{total} events loaded","workflow.detail.dangling":"Dangling","workflow.detail.noDangling":"No dangling work.","workflow.detail.none":"none","workflow.detail.noNodes":"No nodes yet.","workflow.detail.idle":"idle","workflow.detail.noNodeIO":"No node I/O yet.","workflow.detail.notDispatched":"not dispatched","workflow.detail.noAttempt":"No attempt yet","workflow.detail.attempt":"attempt","workflow.detail.authoredInput":"Authored input","workflow.detail.resolvedInput":"Resolved input","workflow.detail.output":"Output","workflow.detail.executionLog":"Execution log","workflow.detail.liveTerminal":"Live terminal","workflow.detail.terminalLive":"live","workflow.detail.terminalClosedShort":"closed","workflow.detail.terminalClosed":"Terminal is closed. Use the execution log below for the final transcript.","workflow.detail.openTerminalNewTab":"Open terminal in new tab","workflow.detail.terminalReplay":"Terminal replay","workflow.detail.openReplayNewTab":"Open replay in new tab","workflow.detail.downloadFullLog":"Download full log","workflow.detail.terminalResume":"Debug session","workflow.detail.openResumeNewTab":"Open debug session in new tab","workflow.detail.resumeSession":"Resume session","workflow.detail.resumeStarting":"Starting\u2026","workflow.detail.endResumeSession":"End debug session","workflow.detail.resumeEnding":"Ending\u2026","workflow.detail.resumeUnsupportedCli":'CLI "{cliId}" does not support resume',"workflow.detail.resumeMissingCliSession":"Missing cliSessionId \u2014 cannot resume","workflow.detail.resumeStartFailed":"Failed to start debug session (HTTP {status})","workflow.detail.resumeEndFailed":"Failed to end debug session (HTTP {status})","workflow.detail.writeAccessResume":"Resume requires dashboard write access.","workflow.detail.waitPrompt":"Wait prompt","workflow.detail.approvalComment":"Approval comment","workflow.detail.optionalComment":"Optional comment","workflow.detail.approve":"Approve","workflow.detail.reject":"Reject","workflow.detail.submitting":"Submitting...","workflow.detail.empty":"empty","workflow.detail.truncated":"truncated","workflow.detail.noData":"No data.","workflow.detail.noPreview":"No preview.","workflow.detail.open":"open","workflow.detail.deadline":"deadline","workflow.detail.effect":"effect","workflow.detail.wait":"wait","workflow.detail.noEvents":"No events.","workflow.summary.workflow":"workflow","workflow.summary.status":"status","workflow.summary.lastSeq":"lastSeq","workflow.summary.updated":"updated","workflow.summary.revision":"revision","workflow.summary.initiator":"initiator","workflow.summary.failedNode":"failedNode","workflow.summary.cancelOrigin":"cancelOrigin","workflow.summary.chat":"chat","workflow.summary.app":"app","workflow.dangling.activities":"activities","workflow.dangling.effects":"effects","workflow.dangling.waits":"waits","workflow.dangling.cancels":"cancels","catalog.title":"Workflow catalog","catalog.subtitle":"Create a workflow run from a saved workflow definition.","catalog.searchPlaceholder":"search workflowId / path","catalog.refresh":"Refresh","catalog.loading":"Loading catalog...","catalog.loadFailed":"Failed to load catalog: {error}","catalog.noDefinitions":"No workflow definitions found.","catalog.noFilterMatch":"No definitions match this filter.","catalog.table.workflow":"workflow","catalog.table.version":"version","catalog.table.params":"params","catalog.table.nodes":"nodes","catalog.table.revision":"revision","catalog.table.path":"path","catalog.paramSummary":"{required}/{total} required","catalog.back":"Back to catalog","catalog.detailTitle":"Workflow definition","catalog.definitionLoadFailed":"Failed to load definition: {error}","catalog.summary":"Summary","catalog.paramsSchema":"Params schema","catalog.definitionJson":"Definition JSON","catalog.runPanel":"Run workflow","catalog.paramsJson":"Params JSON","catalog.paramsPlaceholder":`{
|
|
12
12
|
"city": "\u5317\u4EAC"
|
|
13
|
-
}`,"catalog.chatId":"Chat ID","catalog.larkAppId":"Lark app ID","catalog.chatBindingHint":"Required so humanGate cards and cancel routing know which Lark chat owns the run.","catalog.run":"Run","catalog.running":"Starting...","catalog.badParamsJson":"Params must be a JSON object.","catalog.writeAccess":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and run again.","catalog.runHttp":"run HTTP {status}","catalog.runStarted":"Run started; opening detail page...","catalog.invalidParams":"Invalid params","catalog.issue":"{path}: {message}","catalog.noParams":"No params declared.","catalog.required":"required","catalog.optional":"optional","catalog.default":"default","catalog.description":"description","catalog.path":"path","catalog.revision":"revision","catalog.nodeCount":"nodes"},
|
|
13
|
+
}`,"catalog.chatId":"Chat ID","catalog.larkAppId":"Lark app ID","catalog.chatBindingHint":"Required so humanGate cards and cancel routing know which Lark chat owns the run.","catalog.run":"Run","catalog.running":"Starting...","catalog.badParamsJson":"Params must be a JSON object.","catalog.writeAccess":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and run again.","catalog.runHttp":"run HTTP {status}","catalog.runStarted":"Run started; opening detail page...","catalog.invalidParams":"Invalid params","catalog.issue":"{path}: {message}","catalog.noParams":"No params declared.","catalog.required":"required","catalog.optional":"optional","catalog.default":"default","catalog.description":"description","catalog.path":"path","catalog.revision":"revision","catalog.nodeCount":"nodes"},ft={zh:wn,en:gn};function mt(e){if(typeof e!="string")return null;let t=e.trim().toLowerCase();return t==="zh"||t.startsWith("zh-")?"zh":t==="en"||t.startsWith("en-")?"en":null}function hn(e=[]){for(let t of e){let n=mt(t);if(n)return n}return"zh"}function Me(e){return(t,n)=>{let s=ft[e][t]??ft.zh[t]??t;return n?s.replace(/\{(\w+)\}/g,(a,r)=>{let i=n[r];return i==null?`{${r}}`:String(i)}):s}}function wt(e,t){return(e?mt(e.getItem(ze)):null)??hn(t)}var Je="botmux.dashboard.theme";function bn(e){return e==="system"||e==="light"||e==="dark"?e:null}function gt(e,t){return e==="system"?t?"dark":"light":e}function ht(e){return bn(e?.getItem(Je))??"system"}var Ge=class{locale="zh";themeMode="system";resolvedTheme="light";listeners=new Set;translate=Me(this.locale);mediaQuery=null;init(){let t=typeof window<"u"?window:void 0;this.locale=wt(t?.localStorage,yn()),this.translate=Me(this.locale),this.themeMode=ht(t?.localStorage),this.mediaQuery=t?.matchMedia?.("(prefers-color-scheme: dark)")??null,this.mediaQuery?.addEventListener("change",()=>{this.applyTheme(),this.emit()}),this.applyTheme(),this.applyLocale()}t(t,n){return this.translate(t,n)}setLocale(t){this.locale!==t&&(this.locale=t,this.translate=Me(t),window.localStorage.setItem(ze,t),this.applyLocale(),this.emit())}setThemeMode(t){this.themeMode!==t&&(this.themeMode=t,window.localStorage.setItem(Je,t),this.applyTheme(),this.emit())}on(t){return this.listeners.add(t),()=>this.listeners.delete(t)}emit(){for(let t of this.listeners)t()}applyTheme(){this.resolvedTheme=gt(this.themeMode,!!this.mediaQuery?.matches),document.documentElement.dataset.theme=this.resolvedTheme,document.documentElement.dataset.themeMode=this.themeMode}applyLocale(){document.documentElement.lang=this.locale==="zh"?"zh-CN":"en"}};function yn(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var ae=new Ge;function o(e,t){return ae.t(e,t)}function d(e){return e.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function be(e){if(!e)return"-";let t=Date.now()-e;return t<6e4?o("common.now"):t<36e5?Math.floor(t/6e4)+"m":t<864e5?Math.floor(t/36e5)+"h":Math.floor(t/864e5)+"d"}var Ke={chats:[],bots:[]};async function vn(){try{let e=await fetch("/api/groups");if(!e.ok)return;Ke=await e.json()}catch{}}function kn(e){return`status status-${d(e||"unknown")}`}function $n(e){return`<li class="overview-list-row">
|
|
14
14
|
<div>
|
|
15
|
-
<strong>${
|
|
16
|
-
<span>${
|
|
15
|
+
<strong>${d(e.title??e.sessionId)}</strong>
|
|
16
|
+
<span>${d(e.botName??"")} \xB7 ${d(e.cliId??"unknown")}</span>
|
|
17
17
|
</div>
|
|
18
|
-
<span class="${
|
|
19
|
-
</li>`}function
|
|
18
|
+
<span class="${kn(e.status)}">${d(e.status??"unknown")}</span>
|
|
19
|
+
</li>`}function Sn(e){let t=e.nextRunAt?new Date(e.nextRunAt).toLocaleString():"-";return`<li class="overview-list-row">
|
|
20
20
|
<div>
|
|
21
|
-
<strong>${
|
|
22
|
-
<span>${
|
|
21
|
+
<strong>${d(e.name??e.id)}</strong>
|
|
22
|
+
<span>${d(e.botName??e.larkAppId??"")} \xB7 ${d(e.parsed?.display??"")}</span>
|
|
23
23
|
</div>
|
|
24
|
-
<span>${
|
|
25
|
-
</li>`}async function
|
|
24
|
+
<span>${d(t)}</span>
|
|
25
|
+
</li>`}async function bt(e){e.innerHTML=`<section class="page hero-page">
|
|
26
26
|
<div class="page-heading">
|
|
27
27
|
<div>
|
|
28
|
-
<p class="eyebrow">${
|
|
29
|
-
<h1>${
|
|
30
|
-
<p>${
|
|
28
|
+
<p class="eyebrow">${o("app.subtitle")}</p>
|
|
29
|
+
<h1>${o("overview.title")}</h1>
|
|
30
|
+
<p>${o("overview.subtitle")}</p>
|
|
31
31
|
</div>
|
|
32
32
|
</div>
|
|
33
33
|
<div class="metric-grid" id="overview-metrics"></div>
|
|
@@ -35,251 +35,251 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
35
35
|
<section class="panel">
|
|
36
36
|
<header class="panel-header">
|
|
37
37
|
<div>
|
|
38
|
-
<h2>${
|
|
39
|
-
<p>${
|
|
38
|
+
<h2>${o("overview.recentSessions")}</h2>
|
|
39
|
+
<p>${o("sessions.subtitle")}</p>
|
|
40
40
|
</div>
|
|
41
|
-
<a class="btn-link" href="#/sessions">${
|
|
41
|
+
<a class="btn-link" href="#/sessions">${o("nav.sessions")}</a>
|
|
42
42
|
</header>
|
|
43
43
|
<ul class="overview-list" id="recent-sessions"></ul>
|
|
44
44
|
</section>
|
|
45
45
|
<section class="panel">
|
|
46
46
|
<header class="panel-header">
|
|
47
47
|
<div>
|
|
48
|
-
<h2>${
|
|
49
|
-
<p>${
|
|
48
|
+
<h2>${o("overview.nextSchedules")}</h2>
|
|
49
|
+
<p>${o("schedules.subtitle")}</p>
|
|
50
50
|
</div>
|
|
51
|
-
<a class="btn-link" href="#/schedules">${
|
|
51
|
+
<a class="btn-link" href="#/schedules">${o("nav.schedules")}</a>
|
|
52
52
|
</header>
|
|
53
53
|
<ul class="overview-list" id="next-schedules"></ul>
|
|
54
54
|
</section>
|
|
55
55
|
</div>
|
|
56
|
-
</section>`;let t=e.querySelector("#overview-metrics"),
|
|
57
|
-
<span>${
|
|
56
|
+
</section>`;let t=e.querySelector("#overview-metrics"),n=e.querySelector("#recent-sessions"),s=e.querySelector("#next-schedules");function a(){let r=[...N.sessions.values()],i=[...N.schedules.values()],m=r.filter(L=>L.status!=="closed"),k=r.filter(L=>L.status==="working"||L.status==="analyzing"||L.status==="starting"),$=i.filter(L=>L.enabled),p=Ke.bots?.length||new Set(r.map(L=>L.larkAppId).filter(Boolean)).size,g=[{label:o("overview.openSessions"),value:m.length,meta:`${r.length} ${o("overview.total")}`},{label:o("overview.workingSessions"),value:k.length,meta:`${m.length} ${o("overview.active")}`},{label:o("overview.onlineBots"),value:p,meta:o("overview.daemonRegistry")},{label:o("overview.schedules"),value:i.length,meta:`${$.length} ${o("overview.enabledSchedules")}`},{label:o("overview.groups"),value:Ke.chats?.length??0,meta:o("overview.chatMatrix")}];t.innerHTML=g.map(L=>`<article class="metric-card">
|
|
57
|
+
<span>${d(L.label)}</span>
|
|
58
58
|
<strong>${L.value}</strong>
|
|
59
|
-
<small>${
|
|
60
|
-
</article>`).join("");let l=
|
|
61
|
-
<span class="filter-check-label">${
|
|
62
|
-
${
|
|
59
|
+
<small>${d(L.meta)}</small>
|
|
60
|
+
</article>`).join("");let l=r.sort((L,b)=>Number(b.lastMessageAt??0)-Number(L.lastMessageAt??0)).slice(0,6);n.innerHTML=l.length?l.map(L=>$n({...L,title:L.title??`${be(L.lastMessageAt)} \xB7 ${L.sessionId}`})).join(""):`<li class="empty">${o("overview.noSessions")}</li>`;let I=i.filter(L=>L.nextRunAt).sort((L,b)=>Date.parse(L.nextRunAt)-Date.parse(b.nextRunAt)).slice(0,6);s.innerHTML=I.length?I.map(Sn).join(""):`<li class="empty">${o("overview.noSchedules")}</li>`}N.on(a),a(),vn().then(a)}function se(e,t){return`<th data-sort="${e}" data-label="${d(t)}">${d(t)}</th>`}var yt=["claude-code","codex","codex-app","cursor","gemini","opencode","mtr","hermes","mira","aiden","coco","unknown"];function In(){return`<div class="filter-check-group" role="group" aria-label="${o("sessions.cli")}">
|
|
61
|
+
<span class="filter-check-label">${o("sessions.cli")}</span>
|
|
62
|
+
${yt.map(e=>`
|
|
63
63
|
<label class="filter-check">
|
|
64
|
-
<input type="checkbox" name="cli" value="${
|
|
65
|
-
<span>${
|
|
64
|
+
<input type="checkbox" name="cli" value="${d(e)}" checked>
|
|
65
|
+
<span>${d(e)}</span>
|
|
66
66
|
</label>
|
|
67
67
|
`).join("")}
|
|
68
|
-
</div>`}function
|
|
68
|
+
</div>`}function Tn(){return`<section class="page">
|
|
69
69
|
<div class="page-heading">
|
|
70
70
|
<div>
|
|
71
|
-
<p class="eyebrow">${
|
|
72
|
-
<h1>${
|
|
73
|
-
<p>${
|
|
71
|
+
<p class="eyebrow">${o("nav.sessions")}</p>
|
|
72
|
+
<h1>${o("sessions.title")}</h1>
|
|
73
|
+
<p>${o("sessions.subtitle")}</p>
|
|
74
74
|
</div>
|
|
75
75
|
</div>
|
|
76
76
|
<form id="filters" class="filters sessions-filters">
|
|
77
|
-
<input type="search" name="q" placeholder="${
|
|
77
|
+
<input type="search" name="q" placeholder="${o("sessions.search")}" />
|
|
78
78
|
<select name="status">
|
|
79
|
-
<option value="">${
|
|
79
|
+
<option value="">${o("sessions.anyStatus")}</option>
|
|
80
80
|
<option>starting</option><option>working</option><option>idle</option>
|
|
81
81
|
<option>analyzing</option><option>active</option><option>closed</option>
|
|
82
82
|
</select>
|
|
83
83
|
<select name="adopt">
|
|
84
|
-
<option value="">${
|
|
85
|
-
<option value="yes">${
|
|
86
|
-
<option value="no">${
|
|
84
|
+
<option value="">${o("sessions.adoptAny")}</option>
|
|
85
|
+
<option value="yes">${o("sessions.adoptYes")}</option>
|
|
86
|
+
<option value="no">${o("sessions.adoptNo")}</option>
|
|
87
87
|
</select>
|
|
88
|
-
<label class="filter-toggle"><input type="checkbox" name="active" checked> ${
|
|
89
|
-
${
|
|
88
|
+
<label class="filter-toggle"><input type="checkbox" name="active" checked> ${o("sessions.activeOnly")}</label>
|
|
89
|
+
${In()}
|
|
90
90
|
</form>
|
|
91
91
|
<div id="bulk-bar" class="bulk-bar" hidden>
|
|
92
92
|
<span id="bulk-count"></span>
|
|
93
|
-
<button type="button" id="bulk-close" class="contrast">${
|
|
94
|
-
<button type="button" id="bulk-clear">${
|
|
93
|
+
<button type="button" id="bulk-close" class="contrast">${o("sessions.closeSelected")}</button>
|
|
94
|
+
<button type="button" id="bulk-clear">${o("sessions.clearSelection")}</button>
|
|
95
95
|
</div>
|
|
96
96
|
<table id="sessions-table">
|
|
97
97
|
<thead><tr>
|
|
98
|
-
<th><input type="checkbox" id="select-all" title="${
|
|
99
|
-
${
|
|
100
|
-
${
|
|
101
|
-
${
|
|
102
|
-
${
|
|
103
|
-
${
|
|
104
|
-
${
|
|
105
|
-
${
|
|
106
|
-
${
|
|
107
|
-
<th>${
|
|
98
|
+
<th><input type="checkbox" id="select-all" title="${o("sessions.activeOnly")}"></th>
|
|
99
|
+
${se("botName",o("sessions.bot"))}
|
|
100
|
+
${se("cliId",o("sessions.cli"))}
|
|
101
|
+
${se("status",o("sessions.status"))}
|
|
102
|
+
${se("title",o("sessions.titleCol"))}
|
|
103
|
+
${se("workingDir",o("sessions.workingDir"))}
|
|
104
|
+
${se("spawnedAt",o("sessions.created"))}
|
|
105
|
+
${se("lastMessageAt",o("sessions.last"))}
|
|
106
|
+
${se("adopt",o("sessions.adopt"))}
|
|
107
|
+
<th>${o("sessions.actions")}</th>
|
|
108
108
|
</tr></thead>
|
|
109
109
|
<tbody></tbody>
|
|
110
110
|
</table>
|
|
111
111
|
<dialog id="drawer"></dialog>
|
|
112
|
-
</section>`}function
|
|
113
|
-
<td><input type="checkbox" class="row-select" ${h} ${
|
|
114
|
-
<td>${
|
|
115
|
-
<td><span class="badge cli-${
|
|
116
|
-
<td><span class="status status-${
|
|
117
|
-
<td>${
|
|
118
|
-
<td title="${
|
|
119
|
-
<td>${
|
|
120
|
-
<td>${
|
|
121
|
-
<td>${
|
|
122
|
-
<td><button class="open" type="button">${
|
|
123
|
-
</tr>`}function L(){let
|
|
112
|
+
</section>`}function vt(e){e.innerHTML=Tn();let t=e.querySelector("#sessions-table tbody"),n=e.querySelector("#filters"),s=e.querySelector("#drawer"),a=e.querySelector("#select-all"),r=e.querySelector("#bulk-bar"),i=e.querySelector("#bulk-count"),m=e.querySelector("#bulk-close"),k=e.querySelector("#bulk-clear"),$=e.querySelector("#sessions-table"),p=new Set,g="lastMessageAt",l="desc";function I(u){let w=u.status==="closed",h=p.has(u.sessionId)?"checked":"";return`<tr data-id="${d(u.sessionId)}">
|
|
113
|
+
<td><input type="checkbox" class="row-select" ${h} ${w?"disabled":""}></td>
|
|
114
|
+
<td>${d(u.botName??"")}</td>
|
|
115
|
+
<td><span class="badge cli-${d(u.cliId??"unknown")}">${d(u.cliId??"unknown")}</span></td>
|
|
116
|
+
<td><span class="status status-${d(u.status??"unknown")}">${d(u.status??"unknown")}</span></td>
|
|
117
|
+
<td>${d((u.title??"").slice(0,48))}</td>
|
|
118
|
+
<td title="${d(u.workingDir??"")}">${d((u.workingDir??"").slice(-34))}</td>
|
|
119
|
+
<td>${be(u.spawnedAt)}</td>
|
|
120
|
+
<td>${be(u.lastMessageAt)}</td>
|
|
121
|
+
<td>${u.adopt?'<span class="badge">adopt</span>':""}</td>
|
|
122
|
+
<td><button class="open" type="button">${o("sessions.details")}</button></td>
|
|
123
|
+
</tr>`}function L(){let u=new FormData(n),w=(u.get("q")??"").toLowerCase(),h=u.getAll("cli"),E=h.length>0&&h.length<yt.length,M=u.get("status"),A=u.get("adopt"),P=!!u.get("active"),O=[...N.sessions.values()].filter(x=>!E||h.includes(x.cliId??"unknown")).filter(x=>!M||x.status===M).filter(x=>!A||A==="yes"==!!x.adopt).filter(x=>!P||x.status!=="closed").filter(x=>!w||JSON.stringify(x).toLowerCase().includes(w));return O.sort(f),O}function b(u,w){return w==="spawnedAt"||w==="lastMessageAt"?Number(u[w]??0):w==="adopt"?!!u.adopt:String(u[w]??"").toLowerCase()}function f(u,w){let h=b(u,g),E=b(w,g),M=0;return typeof h=="number"&&typeof E=="number"?M=h-E:typeof h=="boolean"&&typeof E=="boolean"?M=Number(h)-Number(E):M=String(h).localeCompare(String(E)),M===0&&(M=Number(u.lastMessageAt??0)-Number(w.lastMessageAt??0)),l==="asc"?M:-M}function T(){$.querySelectorAll("th[data-sort]").forEach(u=>{let w=u.dataset.sort===g;u.classList.toggle("sorted",w),u.setAttribute("aria-sort",w?l==="asc"?"ascending":"descending":"none");let h=u.dataset.label??u.textContent?.trim()??"";u.textContent=w?`${h} ${l==="asc"?"\u25B2":"\u25BC"}`:h})}function S(u){r.hidden=p.size===0,i.textContent=o("sessions.selectedCount",{count:p.size});let w=u.filter(E=>E.status!=="closed");if(w.length===0){a.checked=!1,a.indeterminate=!1,a.disabled=!0;return}a.disabled=!1;let h=w.filter(E=>p.has(E.sessionId)).length;a.checked=h===w.length,a.indeterminate=h>0&&h<w.length}function y(){let u=L();for(let w of[...p]){let h=N.sessions.get(w);(!h||h.status==="closed")&&p.delete(w)}t.innerHTML=u.length?u.map(I).join(""):`<tr><td colspan="10" class="empty">${o("sessions.empty")}</td></tr>`,T(),S(u)}function H(u){let w=u.status==="closed";s.innerHTML=`<article>
|
|
124
124
|
<header>
|
|
125
|
-
<h3>${
|
|
126
|
-
<span class="status status-${
|
|
127
|
-
<p><code>${
|
|
125
|
+
<h3>${d(u.title??u.sessionId)}</h3>
|
|
126
|
+
<span class="status status-${d(u.status??"unknown")}">${d(u.status??"unknown")}</span>
|
|
127
|
+
<p><code>${d(u.sessionId)}</code> <button data-copy="${d(u.sessionId)}">${o("sessions.copy")}</button></p>
|
|
128
128
|
</header>
|
|
129
|
-
<p><b>${
|
|
130
|
-
<p><b>chatId:</b> <code>${
|
|
131
|
-
<p><b>rootMessageId:</b> <code>${
|
|
132
|
-
${
|
|
133
|
-
<p><b>${
|
|
129
|
+
<p><b>${o("sessions.bot")}:</b> ${d(u.botName??"-")} \xB7 <b>${o("sessions.cli")}:</b> ${d(u.cliId??"?")}</p>
|
|
130
|
+
<p><b>chatId:</b> <code>${d(u.chatId??"")}</code> <button data-copy="${d(u.chatId??"")}">${o("sessions.copy")}</button></p>
|
|
131
|
+
<p><b>rootMessageId:</b> <code>${d(u.rootMessageId??"")}</code> <button data-copy="${d(u.rootMessageId??"")}">${o("sessions.copy")}</button></p>
|
|
132
|
+
${u.threadId?`<p><b>threadId:</b> <code>${d(u.threadId)}</code></p>`:""}
|
|
133
|
+
<p><b>${o("sessions.workingDir")}:</b> ${d(u.workingDir??"-")}</p>
|
|
134
134
|
<div class="actions">
|
|
135
|
-
<button id="locate-btn" type="button">${
|
|
136
|
-
${
|
|
137
|
-
${
|
|
138
|
-
${
|
|
135
|
+
<button id="locate-btn" type="button">${o("sessions.locate")}</button>
|
|
136
|
+
${u.webPort?`<a class="btn-link primary" href="http://${d(location.hostname)}:${u.webPort}" target="_blank" rel="noopener">${o("sessions.openTerminal")}</a>`:""}
|
|
137
|
+
${w?`<button id="resume-btn" type="button" class="primary">${o("sessions.resume")}</button>`:""}
|
|
138
|
+
${w?"":`<button id="close-btn" type="button" class="contrast">${o("sessions.close")}</button>`}
|
|
139
139
|
</div>
|
|
140
|
-
<form method="dialog"><button>${
|
|
141
|
-
</article>`,
|
|
140
|
+
<form method="dialog"><button>${o("sessions.dismiss")}</button></form>
|
|
141
|
+
</article>`,s.querySelectorAll("[data-copy]").forEach(A=>{A.onclick=()=>{navigator.clipboard.writeText(A.dataset.copy??""),A.textContent=o("sessions.copied"),setTimeout(()=>{A.textContent=o("sessions.copy")},800)}});let h=s.querySelector("#locate-btn");h&&(h.onclick=async()=>{h.disabled=!0,h.textContent=o("sessions.locating");try{let A=await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/locate`,{method:"POST"}),P=await A.json();if(P.ok){let O=30;h.textContent=o("sessions.cooldown",{seconds:O});let x=setInterval(()=>{O-=1,O<=0?(clearInterval(x),h.disabled=!1,h.textContent=o("sessions.locate")):h.textContent=o("sessions.cooldown",{seconds:O})},1e3)}else alert(`Locate failed: ${P.error??A.status}`),h.disabled=!1,h.textContent=o("sessions.locate")}catch(A){alert(`Locate error: ${A}`),h.disabled=!1,h.textContent=o("sessions.locate")}});let E=s.querySelector("#resume-btn");E&&(E.onclick=async()=>{E.disabled=!0;try{let A=await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/resume`,{method:"POST"}),P=await A.json().catch(()=>({}));if(!A.ok||P.ok===!1){alert(`${o("sessions.resumeFailed")}: ${P?.error??A.status}`),E.disabled=!1;return}s.close()}catch(A){alert(`${o("sessions.resumeFailed")}: ${A}`),E.disabled=!1}});let M=s.querySelector("#close-btn");M&&(M.onclick=async()=>{if(confirm(o("sessions.closeConfirm"))){M.disabled=!0;try{await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/close`,{method:"POST"})}finally{s.close()}}}),s.showModal()}t.addEventListener("click",u=>{let w=u.target;if(w.classList.contains("row-select")){let A=w.closest("tr[data-id]");if(!A)return;w.checked?p.add(A.dataset.id):p.delete(A.dataset.id),S(L());return}let h=w.closest("td");if(h&&h.querySelector(".row-select"))return;let E=w.closest("tr[data-id]");if(!E)return;let M=N.sessions.get(E.dataset.id);M&&H(M)}),a.addEventListener("change",()=>{let u=L().filter(w=>w.status!=="closed");for(let w of u)a.checked?p.add(w.sessionId):p.delete(w.sessionId);y()}),k.addEventListener("click",()=>{p.clear(),y()}),m.addEventListener("click",async()=>{let u=[...p];if(u.length===0||!confirm(o("sessions.closeBulkConfirm",{count:u.length})))return;m.disabled=!0,k.disabled=!0;let w=m.textContent,h=0,E=0,M=[...u];m.textContent=`0/${u.length}`;async function A(){for(;M.length;){let P=M.shift();try{let O=await fetch(`/api/sessions/${encodeURIComponent(P)}/close`,{method:"POST"}),x=await O.json().catch(()=>({}));(!O.ok||x?.ok===!1)&&(E+=1)}catch{E+=1}finally{h+=1,m.textContent=`${h}/${u.length}`}}}await Promise.all(Array.from({length:Math.min(6,u.length)},()=>A())),m.textContent=w,m.disabled=!1,k.disabled=!1,p.clear(),y(),E>0&&alert(`Failed: ${E}/${u.length}`)}),$.querySelectorAll("th[data-sort]").forEach(u=>{u.addEventListener("click",()=>{let w=u.dataset.sort;g===w?l=l==="asc"?"desc":"asc":(g=w,l=w==="spawnedAt"||w==="lastMessageAt"?"desc":"asc"),y()})}),n.addEventListener("input",y),N.on(y),y()}function Ln(){return`<section class="page">
|
|
142
142
|
<div class="page-heading">
|
|
143
143
|
<div>
|
|
144
|
-
<p class="eyebrow">${
|
|
145
|
-
<h1>${
|
|
146
|
-
<p>${
|
|
144
|
+
<p class="eyebrow">${o("nav.schedules")}</p>
|
|
145
|
+
<h1>${o("schedules.title")}</h1>
|
|
146
|
+
<p>${o("schedules.subtitle")}</p>
|
|
147
147
|
</div>
|
|
148
148
|
</div>
|
|
149
149
|
<form id="sched-filters" class="filters">
|
|
150
|
-
<input type="search" name="q" placeholder="${
|
|
150
|
+
<input type="search" name="q" placeholder="${o("schedules.search")}" />
|
|
151
151
|
<select name="kind">
|
|
152
|
-
<option value="">${
|
|
152
|
+
<option value="">${o("schedules.anyKind")}</option>
|
|
153
153
|
<option>cron</option>
|
|
154
154
|
<option>interval</option>
|
|
155
155
|
<option>once</option>
|
|
156
156
|
</select>
|
|
157
|
-
<label><input type="checkbox" name="enabled"> ${
|
|
157
|
+
<label><input type="checkbox" name="enabled"> ${o("schedules.enabledOnly")}</label>
|
|
158
158
|
</form>
|
|
159
159
|
<table>
|
|
160
160
|
<thead><tr>
|
|
161
|
-
<th>${
|
|
162
|
-
<th>${
|
|
161
|
+
<th>${o("schedules.name")}</th><th>${o("schedules.bot")}</th><th>${o("schedules.schedule")}</th><th>${o("schedules.next")}</th><th>${o("schedules.last")}</th>
|
|
162
|
+
<th>${o("schedules.repeat")}</th><th>${o("schedules.enabled")}</th><th>${o("schedules.actions")}</th>
|
|
163
163
|
</tr></thead>
|
|
164
164
|
<tbody id="schedules-tbody"></tbody>
|
|
165
165
|
</table>
|
|
166
|
-
</section>`}function
|
|
167
|
-
<td>${
|
|
168
|
-
<td>${
|
|
169
|
-
<td><code>${
|
|
170
|
-
<td>${
|
|
171
|
-
<td>${
|
|
172
|
-
<td>${
|
|
173
|
-
<td>${
|
|
166
|
+
</section>`}function kt(e){if(!e)return"\u2014";try{return new Date(e).toLocaleString()}catch{return e}}function $t(e){e.innerHTML=Ln();let t=e.querySelector("#schedules-tbody"),n=e.querySelector("#sched-filters");function s(){let r=new FormData(n),i=(r.get("q")??"").toLowerCase(),m=r.get("kind"),k=!!r.get("enabled");return[...N.schedules.values()].filter($=>!m||$.parsed?.kind===m).filter($=>!k||$.enabled).filter($=>!i||JSON.stringify($).toLowerCase().includes(i)).sort(($,p)=>{if($.enabled!==p.enabled)return $.enabled?-1:1;let g=$.nextRunAt?Date.parse($.nextRunAt):1/0,l=p.nextRunAt?Date.parse(p.nextRunAt):1/0;return g-l})}function a(){t.innerHTML=s().map(r=>`<tr data-id="${d(r.id)}">
|
|
167
|
+
<td>${d(r.name??r.id)}</td>
|
|
168
|
+
<td>${d(r.botName??r.larkAppId??"-")}</td>
|
|
169
|
+
<td><code>${d(r.parsed?.display??"?")}</code></td>
|
|
170
|
+
<td>${kt(r.nextRunAt)}</td>
|
|
171
|
+
<td>${kt(r.lastRunAt)} ${r.lastStatus==="error"?"\u26A0\uFE0F":""}</td>
|
|
172
|
+
<td>${r.repeat?`${r.repeat.completed}/${r.repeat.times??"\u221E"}`:"\u2014"}</td>
|
|
173
|
+
<td>${r.enabled?"\u2713":"\u2717"}</td>
|
|
174
174
|
<td class="actions-cell">
|
|
175
|
-
<button data-op="run" type="button">${
|
|
176
|
-
${
|
|
175
|
+
<button data-op="run" type="button">${o("schedules.runNow")}</button>
|
|
176
|
+
${r.enabled?`<button data-op="pause" type="button">${o("schedules.pause")}</button>`:`<button data-op="resume" type="button">${o("schedules.resume")}</button>`}
|
|
177
177
|
</td>
|
|
178
|
-
</tr>`).join("")||`<tr><td colspan="8" class="empty">${
|
|
178
|
+
</tr>`).join("")||`<tr><td colspan="8" class="empty">${o("schedules.empty")}</td></tr>`}t.addEventListener("click",async r=>{let i=r.target.closest("button[data-op]");if(!i)return;let m=i.closest("tr[data-id]");if(!m)return;let k=m.dataset.id,$=i.dataset.op;i.disabled=!0;let p=i.textContent;i.textContent="...";try{let g=await fetch(`/api/schedules/${encodeURIComponent(k)}/${$}`,{method:"POST"}),l=await g.json().catch(()=>({}));(!g.ok||l.ok===!1)&&alert(`Failed: ${g.status} ${l?.error??""}`.trim())}catch(g){alert("Network error: "+g)}finally{i.disabled=!1,i.textContent=p}}),n.addEventListener("input",a),N.on(a),a()}var W={chats:[],bots:[]};function En(){return`<section class="page">
|
|
179
179
|
<div class="page-heading">
|
|
180
180
|
<div>
|
|
181
|
-
<p class="eyebrow">${
|
|
182
|
-
<h1>${
|
|
183
|
-
<p>${
|
|
181
|
+
<p class="eyebrow">${o("nav.groups")}</p>
|
|
182
|
+
<h1>${o("groups.title")}</h1>
|
|
183
|
+
<p>${o("groups.subtitle")}</p>
|
|
184
184
|
</div>
|
|
185
185
|
</div>
|
|
186
186
|
<form id="g-filters" class="filters">
|
|
187
|
-
<input type="search" name="q" placeholder="${
|
|
188
|
-
<label><input type="checkbox" name="missing"> ${
|
|
189
|
-
<button type="button" id="g-refresh">${
|
|
190
|
-
<button type="button" id="g-create" class="primary">${
|
|
187
|
+
<input type="search" name="q" placeholder="${o("groups.search")}" />
|
|
188
|
+
<label><input type="checkbox" name="missing"> ${o("groups.missingOnly")}</label>
|
|
189
|
+
<button type="button" id="g-refresh">${o("groups.refresh")}</button>
|
|
190
|
+
<button type="button" id="g-create" class="primary">${o("groups.create")}</button>
|
|
191
191
|
</form>
|
|
192
192
|
<table>
|
|
193
193
|
<thead id="g-head"></thead>
|
|
194
194
|
<tbody id="g-body"></tbody>
|
|
195
195
|
</table>
|
|
196
196
|
<dialog id="g-drawer"></dialog>
|
|
197
|
-
</section>`}async function
|
|
197
|
+
</section>`}async function fe(){W=await(await fetch("/api/groups")).json()}async function Mn(){return(await fetch("/api/groups")).json()}function Cn(e,t){if(t.size===0)return!0;let n=e?.memberBots??[];for(let s of t)if(!n.some(a=>a.larkAppId===s&&a.inChat))return!1;return!0}function St(e,t){return e.filter(n=>!t||!t.has(n.larkAppId)).map(n=>`
|
|
198
198
|
<label class="checkbox-row">
|
|
199
|
-
<input type="checkbox" name="bot" value="${
|
|
200
|
-
${
|
|
199
|
+
<input type="checkbox" name="bot" value="${d(n.larkAppId)}">
|
|
200
|
+
${d(n.botName??n.larkAppId)} <small>(${d(n.larkAppId)})</small>
|
|
201
201
|
</label>
|
|
202
|
-
`).join("")}async function
|
|
202
|
+
`).join("")}async function It(e){e.innerHTML=En();let t=e.querySelector("#g-head"),n=e.querySelector("#g-body"),s=e.querySelector("#g-filters"),a=e.querySelector("#g-refresh"),r=e.querySelector("#g-drawer");a.onclick=async()=>{a.disabled=!0;try{await fe(),p()}finally{a.disabled=!1}};let i=e.querySelector("#g-create");i.onclick=()=>m(),await fe();function m(){let l=W.bots;if(l.length===0){alert(o("groups.noBotsOnline"));return}r.innerHTML=`
|
|
203
203
|
<article>
|
|
204
|
-
<header><h3>${
|
|
205
|
-
<p>${
|
|
204
|
+
<header><h3>${o("groups.createTitle")}</h3></header>
|
|
205
|
+
<p>${o("groups.createHelp")}</p>
|
|
206
206
|
<form id="g-createform">
|
|
207
207
|
<label class="form-row">
|
|
208
|
-
<span>${
|
|
209
|
-
<input type="text" name="name" placeholder="${
|
|
208
|
+
<span>${o("groups.name")}</span>
|
|
209
|
+
<input type="text" name="name" placeholder="${o("groups.namePlaceholder")}" maxlength="60">
|
|
210
210
|
</label>
|
|
211
211
|
<label class="form-row">
|
|
212
|
-
<span>${
|
|
212
|
+
<span>${o("groups.bindDir")}</span>
|
|
213
213
|
<input type="text" name="bindWorkingDir" placeholder="e.g. ~/projects/botmux">
|
|
214
|
-
<small>${
|
|
214
|
+
<small>${o("groups.bindDirHelp")}</small>
|
|
215
215
|
</label>
|
|
216
216
|
<fieldset>
|
|
217
|
-
<legend>${
|
|
218
|
-
${
|
|
217
|
+
<legend>${o("groups.botPicker")}</legend>
|
|
218
|
+
${St(l)}
|
|
219
219
|
</fieldset>
|
|
220
220
|
<div class="actions">
|
|
221
|
-
<button type="submit" class="primary">${
|
|
222
|
-
<button type="button" id="g-create-cancel">${
|
|
221
|
+
<button type="submit" class="primary">${o("groups.createSubmit")}</button>
|
|
222
|
+
<button type="button" id="g-create-cancel">${o("groups.cancel")}</button>
|
|
223
223
|
</div>
|
|
224
224
|
</form>
|
|
225
|
-
</article>`,
|
|
225
|
+
</article>`,r.showModal(),r.querySelector("#g-create-cancel").onclick=()=>r.close(),r.querySelector("#g-createform").onsubmit=async b=>{b.preventDefault();let f=new FormData(b.target),T=(f.get("name")??"").trim(),S=(f.get("bindWorkingDir")??"").trim(),y=f.getAll("bot");if(y.length===0){alert("Pick at least one bot.");return}let H=b.target.querySelector("button[type=submit]");H&&(H.disabled=!0,H.textContent="Creating...");try{let u=await fetch("/api/groups/create",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:T||void 0,larkAppIds:y,bindWorkingDir:S||void 0})}),w=await u.json();if(w.ok&&w.chatId){k(w);let h=Array.isArray(w.invalidBotIds)?w.invalidBotIds:[],E=y.filter(A=>!h.includes(A)),M=new Set(E);typeof w.creator=="string"&&w.creator&&M.add(w.creator),I(w.chatId,T||w.chatId,E,w.creator),p(),L(w.chatId,M).catch(()=>{})}else alert(`Failed: ${w.error??u.status}`),r.close()}catch(u){alert("Network error: "+u),r.close()}};function I(b,f,T,S){let y=new Set(T);S&&y.add(S);let H=W.bots.map(w=>({larkAppId:w.larkAppId,botName:w.botName,inChat:y.has(w.larkAppId),oncallChat:null})),u={chatId:b,name:f,ownerId:S??null,memberBots:H};W.chats=[u,...W.chats.filter(w=>w.chatId!==b)]}async function L(b,f){let T=[600,1200,1200,1200,1200,1200];for(let S of T){await new Promise(u=>setTimeout(u,S));let y;try{y=await Mn()}catch{continue}let H=(y.chats??[]).find(u=>u.chatId===b);if(H&&Cn(H,f)){W=y,p();return}}}}function k(l){let I=String(l.chatId),L=`https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent(I)}`,b=l.invalidBotIds??[],f=l.invalidUserIds??[],T=l.autoInvitedOpenId,S=!!l.autoInviteRejected,y=l.ownerTransferredTo,H=l.transferError,u=l.notifyMessageId,w=l.notifyError,h=Array.isArray(l.oncallBindings)?l.oncallBindings:[],E=h.filter(x=>x?.ok).length,M=h.filter(x=>!x?.ok),A=h.length>0?M.length===0?`<p class="hint-ok">\u5DF2\u7ED1\u5B9A\u76EE\u5F55\uFF1A<code>${d(l.bindResolvedPath??"")}</code>\uFF08${E}/${h.length} bots\uFF09</p>`:`<p class="hint-warn">\u76EE\u5F55\u7ED1\u5B9A\u90E8\u5206\u5931\u8D25\uFF1A\u6210\u529F ${E}/${h.length}\u3002${M.map(x=>`<br><code>${d(x.larkAppId??"?")}</code>: ${d(x.error??"unknown")}`).join("")}</p>`:"",P;if(T){let x=y?"<br><small>\u7FA4\u4E3B\u5DF2\u4ECE\u673A\u5668\u4EBA\u8F6C\u8BA9\u7ED9\u4F60\u3002</small>":H?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8\u8F6C\u8BA9\u7FA4\u4E3B\u5931\u8D25\uFF08${d(H)}\uFF09\uFF0C\u4F60\u73B0\u5728\u662F\u6210\u5458\u4F46\u7FA4\u4E3B\u4ECD\u662F\u673A\u5668\u4EBA\u3002</small>`:"",q=u?`<br><small>\u673A\u5668\u4EBA\u5DF2\u5728\u7FA4\u91CC @ \u4E86\u4F60\uFF08\u6D88\u606F id <code>${d(u)}</code>\uFF09\uFF0C\u770B\u98DE\u4E66\u901A\u77E5\u5C31\u80FD\u8FDB\u7FA4\u3002</small>`:w?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8 @ \u901A\u77E5\u5931\u8D25\uFF08${d(w)}\uFF09\uFF0C\u65B0\u7FA4\u53EF\u80FD\u4E0D\u4F1A\u4E3B\u52A8\u51FA\u73B0\u5728\u4F60\u4FA7\u8FB9\u680F\uFF0C\u5EFA\u8BAE\u4ECE\u4E0B\u9762\u6309\u94AE\u8DF3\u8FDB\u53BB\u3002</small>`:"";P=`<p class="hint-ok">\u5DF2\u81EA\u52A8\u9080\u8BF7\u4F60\uFF08<code>${d(T)}</code>\uFF09\u4F5C\u4E3A\u6210\u5458\u3002${x}${q}</p>`}else S?P='<p class="hint-warn">\u98DE\u4E66\u62D2\u7EDD\u4E86\u81EA\u52A8\u9080\u8BF7\uFF08\u4F60\u7684 open_id \u5728\u521B\u5EFA\u8005 bot \u7684 scope \u4E0B\u4E0D\u53EF\u7528\uFF09\u3002<strong>\u4F60\u76EE\u524D\u4E0D\u662F\u65B0\u7FA4\u6210\u5458</strong>\uFF0C\u9700\u8981\u8BA9\u7FA4\u91CC\u7684\u67D0\u4E2A\u673A\u5668\u4EBA\u624B\u52A8\u628A\u4F60\u52A0\u8FDB\u6765\u3002</p>':P='<p class="hint-warn">\u6CA1\u5728 dashboard \u7F13\u5B58\u91CC\u627E\u5230 ownerOpenId\uFF0C<strong>\u6CA1\u6709\u81EA\u52A8\u9080\u8BF7\u4F60</strong>\u3002\u70B9\u5F00\u4E0B\u9762\u94FE\u63A5\u524D\uFF0C\u5148\u8BA9\u7FA4\u91CC\u4EFB\u4E00\u673A\u5668\u4EBA\u624B\u52A8\u628A\u4F60\u52A0\u8FDB\u53BB\u3002</p>';let O=[b.length?`<li>\u65E0\u6548 bot id: <code>${b.map(d).join(", ")}</code></li>`:"",f.length?`<li>\u65E0\u6548\u7528\u6237 open_id: <code>${f.map(d).join(", ")}</code></li>`:""].filter(Boolean).join("");r.innerHTML=`
|
|
226
226
|
<article>
|
|
227
|
-
<header><h3>${
|
|
228
|
-
<p><b>chatId:</b> <code>${
|
|
229
|
-
<p><b>\u521B\u5EFA\u8005:</b> <code>${
|
|
230
|
-
${
|
|
231
|
-
${
|
|
232
|
-
${
|
|
227
|
+
<header><h3>${o("groups.successTitle")}</h3></header>
|
|
228
|
+
<p><b>chatId:</b> <code>${d(I)}</code> <button type="button" data-copy="${d(I)}">${o("sessions.copy")}</button></p>
|
|
229
|
+
<p><b>\u521B\u5EFA\u8005:</b> <code>${d(l.creator??"?")}</code></p>
|
|
230
|
+
${P}
|
|
231
|
+
${A}
|
|
232
|
+
${O?`<ul>${O}</ul>`:""}
|
|
233
233
|
<div class="actions">
|
|
234
|
-
<a class="btn-link primary" href="${L}" target="_blank" rel="noopener">${
|
|
235
|
-
<button type="button" id="g-create-close">${
|
|
234
|
+
<a class="btn-link primary" href="${L}" target="_blank" rel="noopener">${o("groups.openGroup")}</a>
|
|
235
|
+
<button type="button" id="g-create-close">${o("sessions.dismiss")}</button>
|
|
236
236
|
</div>
|
|
237
|
-
</article>`,
|
|
238
|
-
<th>${
|
|
239
|
-
${
|
|
240
|
-
<th>${
|
|
241
|
-
</tr>`}function
|
|
237
|
+
</article>`,r.querySelectorAll("[data-copy]").forEach(x=>{x.onclick=()=>{navigator.clipboard.writeText(x.dataset.copy??""),x.textContent=o("sessions.copied"),setTimeout(()=>{x.textContent=o("sessions.copy")},800)}}),r.querySelector("#g-create-close").onclick=()=>r.close()}function $(){t.innerHTML=`<tr>
|
|
238
|
+
<th>${o("groups.chat")}</th>
|
|
239
|
+
${W.bots.map(l=>`<th>${d(l.botName??l.larkAppId)}</th>`).join("")}
|
|
240
|
+
<th>${o("groups.actions")}</th>
|
|
241
|
+
</tr>`}function p(){$();let l=new FormData(s),I=(l.get("q")??"").toLowerCase(),L=!!l.get("missing"),b=W.chats.filter(f=>!I||(f.name??"").toLowerCase().includes(I)||f.chatId.toLowerCase().includes(I)||(f.ownerId??"").toLowerCase().includes(I)).filter(f=>!L||f.memberBots.some(T=>!T.inChat));if(b.length===0){n.innerHTML=`<tr><td colspan="${W.bots.length+2}" class="empty">${o("groups.empty")}</td></tr>`;return}n.innerHTML=b.map(f=>`<tr data-chat="${d(f.chatId)}">
|
|
242
242
|
<td>
|
|
243
|
-
<strong>${
|
|
244
|
-
<small><code>${
|
|
243
|
+
<strong>${d(f.name??f.chatId)}</strong><br>
|
|
244
|
+
<small><code>${d(f.chatId)}</code></small>
|
|
245
245
|
</td>
|
|
246
|
-
${
|
|
246
|
+
${W.bots.map(T=>{let S=f.memberBots.find(u=>u.larkAppId===T.larkAppId),y=S?S.error?"!":S.inChat?"\u2713":"\u2717":"?";return`<td class="${S?S.error?"cell-error":S.inChat?"cell-in":"cell-out":"cell-unknown"}" title="${d(S?.error??"")}">${y}</td>`}).join("")}
|
|
247
247
|
<td>
|
|
248
|
-
<button class="add-bots" type="button">${
|
|
249
|
-
<button class="manage-chat" type="button">${
|
|
248
|
+
<button class="add-bots" type="button">${o("groups.addBots")}</button>
|
|
249
|
+
<button class="manage-chat" type="button">${o("groups.manage")}</button>
|
|
250
250
|
</td>
|
|
251
|
-
</tr>`).join("")}
|
|
251
|
+
</tr>`).join("")}p(),n.addEventListener("click",async l=>{let I=l.target.closest("button.add-bots");if(!I)return;let b=I.closest("tr[data-chat]").dataset.chat,f=W.chats.find(y=>y.chatId===b);if(!f)return;let T=new Set(f.memberBots.filter(y=>y.inChat).map(y=>y.larkAppId));if(!W.bots.filter(y=>!T.has(y.larkAppId)).length){alert("All configured bots are already in this chat.");return}r.innerHTML=`
|
|
252
252
|
<article>
|
|
253
|
-
<header><h3>${
|
|
254
|
-
<p>${
|
|
253
|
+
<header><h3>${o("groups.addBots")} \xB7 ${d(f.name??f.chatId)}</h3></header>
|
|
254
|
+
<p>${o("groups.createHelp")}</p>
|
|
255
255
|
<form id="g-addform">
|
|
256
|
-
${
|
|
256
|
+
${St(W.bots,T)}
|
|
257
257
|
<div class="actions">
|
|
258
|
-
<button type="submit" class="primary">${
|
|
259
|
-
<button type="button" id="g-cancel">${
|
|
258
|
+
<button type="submit" class="primary">${o("groups.addBots")}</button>
|
|
259
|
+
<button type="button" id="g-cancel">${o("groups.cancel")}</button>
|
|
260
260
|
</div>
|
|
261
261
|
</form>
|
|
262
|
-
</article>`,
|
|
263
|
-
`);alert(E),await
|
|
262
|
+
</article>`,r.showModal(),r.querySelector("#g-cancel").onclick=()=>r.close(),r.querySelector("#g-addform").onsubmit=async y=>{y.preventDefault();let u=new FormData(y.target).getAll("bot");if(u.length===0){alert("Pick at least one bot.");return}try{let h=await(await fetch(`/api/groups/${encodeURIComponent(b)}/add-bots`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:u})})).json();if(h.error==="no_proxy_bot")alert("No bot is currently in this chat \u2014 add one manually in Feishu first, then retry.");else if(h.result){let E=h.result.map(M=>`${M.id}: ${M.ok?"OK":`failed (${M.error??"unknown"})`}`).join(`
|
|
263
|
+
`);alert(E),await fe(),p()}else alert(`Unexpected response: ${JSON.stringify(h)}`)}catch(w){alert("Network error: "+w)}finally{r.close()}}}),n.addEventListener("click",async l=>{let I=l.target.closest("button.manage-chat");if(!I)return;let b=I.closest("tr[data-chat]").dataset.chat,f=W.chats.find(T=>T.chatId===b);f&&g(f)});function g(l){let I=l.memberBots.filter(b=>b.inChat),L=typeof l.ownerId=="string"?l.ownerId:"";r.innerHTML=`
|
|
264
264
|
<article>
|
|
265
|
-
<header><h3>${
|
|
266
|
-
<p><b>chatId:</b> <code>${
|
|
267
|
-
<p><b>${
|
|
265
|
+
<header><h3>${o("groups.manageTitle",{name:l.name??l.chatId})}</h3></header>
|
|
266
|
+
<p><b>chatId:</b> <code>${d(l.chatId)}</code></p>
|
|
267
|
+
<p><b>${o("groups.owner")}:</b> <code>${d(l.ownerId??o("common.unknown"))}</code></p>
|
|
268
268
|
|
|
269
269
|
<fieldset>
|
|
270
|
-
<legend>${
|
|
271
|
-
<p><small>${
|
|
272
|
-
${
|
|
273
|
-
<div class="oncall-row" data-bot="${
|
|
270
|
+
<legend>${o("groups.oncall")}</legend>
|
|
271
|
+
<p><small>${o("groups.oncallHelp")}</small></p>
|
|
272
|
+
${I.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':I.map(b=>{let f=!!b.oncallChat,T=b.oncallChat?.workingDir??"";return`
|
|
273
|
+
<div class="oncall-row" data-bot="${d(b.larkAppId)}">
|
|
274
274
|
<label class="checkbox-row">
|
|
275
|
-
<input type="checkbox" data-action="toggle" ${
|
|
276
|
-
<strong>${
|
|
277
|
-
<small>(${
|
|
275
|
+
<input type="checkbox" data-action="toggle" ${f?"checked":""}>
|
|
276
|
+
<strong>${d(b.botName??b.larkAppId)}</strong>
|
|
277
|
+
<small>(${d(b.larkAppId)})</small>
|
|
278
278
|
</label>
|
|
279
279
|
<div class="oncall-row-body">
|
|
280
280
|
<input type="text" data-input="workingDir" placeholder="e.g. /root/iserver/botmux"
|
|
281
|
-
value="${
|
|
282
|
-
<button type="button" data-action="save">${
|
|
281
|
+
value="${d(T)}" ${f?"":"disabled"}>
|
|
282
|
+
<button type="button" data-action="save">${o("groups.save")}</button>
|
|
283
283
|
<span class="oncall-status" data-status></span>
|
|
284
284
|
</div>
|
|
285
285
|
</div>
|
|
@@ -287,94 +287,135 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
287
287
|
</fieldset>
|
|
288
288
|
|
|
289
289
|
<fieldset>
|
|
290
|
-
<legend>${
|
|
291
|
-
${
|
|
290
|
+
<legend>${o("groups.leaveTitle")}</legend>
|
|
291
|
+
${I.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':I.map(b=>`
|
|
292
292
|
<label class="checkbox-row">
|
|
293
|
-
<input type="checkbox" name="leave-bot" value="${
|
|
294
|
-
${
|
|
295
|
-
<small>${
|
|
293
|
+
<input type="checkbox" name="leave-bot" value="${d(b.larkAppId)}">
|
|
294
|
+
${d(b.botName??b.larkAppId)}
|
|
295
|
+
<small>${b.larkAppId===L?"\xB7 \u7FA4\u4E3B":""}</small>
|
|
296
296
|
</label>
|
|
297
297
|
`).join("")}
|
|
298
298
|
</fieldset>
|
|
299
299
|
|
|
300
300
|
<div class="actions">
|
|
301
|
-
<button id="g-leave-btn" type="button" ${
|
|
302
|
-
<button id="g-disband-btn" type="button" class="contrast" ${
|
|
301
|
+
<button id="g-leave-btn" type="button" ${I.length===0?"disabled":""}>${o("groups.leaveSelected")}</button>
|
|
302
|
+
<button id="g-disband-btn" type="button" class="contrast" ${I.length===0?"disabled":""}>${o("groups.disband")}</button>
|
|
303
303
|
</div>
|
|
304
|
-
<p class="hint-warn"><small>${
|
|
305
|
-
<form method="dialog"><button>${
|
|
306
|
-
</article>`,
|
|
307
|
-
`);alert(
|
|
308
|
-
\u5173\u95ED\u4E86 ${
|
|
309
|
-
\u5173\u95ED\u4E86 ${
|
|
310
|
-
${
|
|
304
|
+
<p class="hint-warn"><small>${o("groups.dangerHint")}</small></p>
|
|
305
|
+
<form method="dialog"><button>${o("sessions.dismiss")}</button></form>
|
|
306
|
+
</article>`,r.showModal(),r.querySelectorAll(".oncall-row").forEach(b=>{let f=b.dataset.bot,T=b.querySelector("input[data-action=toggle]"),S=b.querySelector("input[data-input=workingDir]"),y=b.querySelector("button[data-action=save]"),H=b.querySelector("[data-status]");T.addEventListener("change",()=>{S.disabled=!T.checked,T.checked&&S.focus()}),y.addEventListener("click",async()=>{H.textContent="",H.className="oncall-status";let u=T.checked,w=S.value.trim();if(u&&!w){H.textContent=o("groups.needWorkingDir"),H.classList.add("hint-warn-inline");return}y.disabled=!0;try{let h=`/api/groups/${encodeURIComponent(l.chatId)}/oncall/${encodeURIComponent(f)}`,E=u?await fetch(h,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({workingDir:w})}):await fetch(h,{method:"DELETE"}),M=await E.json().catch(()=>({}));if(E.ok&&M.ok){H.textContent=u?`\u2713 \u5DF2\u7ED1\u5B9A \u2192 ${M.resolvedPath??w}`:"\u2713 \u5DF2\u89E3\u7ED1",H.classList.add("hint-ok");try{await fe(),p()}catch{}}else H.textContent=`\u2717 ${M.error??E.status}`,H.classList.add("hint-warn-inline")}catch(h){H.textContent=`\u2717 ${h?.message??h}`,H.classList.add("hint-warn-inline")}finally{y.disabled=!1}})}),r.querySelector("#g-leave-btn").onclick=async()=>{let b=[...r.querySelectorAll("input[name=leave-bot]:checked")].map(f=>f.value);if(b.length===0){alert("\u81F3\u5C11\u9009\u4E00\u4E2A\u673A\u5668\u4EBA");return}if(confirm(`\u786E\u5B9A\u8BA9 ${b.length} \u4E2A\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A\uFF1F\u8BE5 bot \u5728\u6B64\u7FA4\u7684\u4F1A\u8BDD\u4F1A\u4E00\u5E76\u5173\u95ED\u3002`))try{let T=await(await fetch(`/api/groups/${encodeURIComponent(l.chatId)}/leave`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:b})})).json(),S=(T.result??[]).map(y=>{if(!y.ok)return`${y.larkAppId}: \u5931\u8D25 (${y.error??"unknown"})`;let H=y.closedSessions??[],u=H.filter(E=>!E.ok).length,w=H.length-u,h=H.length===0?"":u===0?`\uFF08\u5173\u95ED ${w} \u4E2A\u4F1A\u8BDD\uFF09`:`\uFF08\u5173\u95ED ${w} \u4E2A\uFF0C${u} \u4E2A\u5931\u8D25\uFF09`;return`${y.larkAppId}: OK${h}`}).join(`
|
|
307
|
+
`);alert(S||`Unexpected: ${JSON.stringify(T)}`),await fe(),p()}catch(f){alert("Network error: "+f)}finally{r.close()}},r.querySelector("#g-disband-btn").onclick=async()=>{if(I.length===0||!confirm(`\u786E\u5B9A\u89E3\u6563\u7FA4\u804A\u300C${l.name??l.chatId}\u300D\uFF1F\u6B64\u64CD\u4F5C\u4E0D\u53EF\u6062\u590D\uFF0C\u672C\u7FA4\u6240\u6709\u673A\u5668\u4EBA\u4F1A\u8BDD\u4E5F\u4F1A\u4E00\u5E76\u5173\u95ED\u3002`))return;let b=[...I].sort((T,S)=>(S.larkAppId===L?1:0)-(T.larkAppId===L?1:0)),f=[];for(let T of b)try{let S=await fetch(`/api/groups/${encodeURIComponent(l.chatId)}/disband`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppId:T.larkAppId})}),y=await S.json();if(y.ok){let H=y.closedSessions??[],u=H.filter(E=>!E.ok).length,w=H.length-u,h=H.length===0?"":u===0?`
|
|
308
|
+
\u5173\u95ED\u4E86 ${w} \u4E2A\u4F1A\u8BDD\u3002`:`
|
|
309
|
+
\u5173\u95ED\u4E86 ${w} \u4E2A\u4F1A\u8BDD\uFF0C${u} \u4E2A\u4F1A\u8BDD\u5173\u95ED\u5931\u8D25\u3002`;alert(`\u5DF2\u89E3\u6563\uFF08\u7531 ${T.botName??T.larkAppId} \u6267\u884C\uFF09${h}`),await fe(),p(),r.close();return}f.push(`${T.botName??T.larkAppId}: ${y.error??S.status}`)}catch(S){f.push(`${T.botName??T.larkAppId}: ${S}`)}alert(`\u6240\u6709\u5728\u7FA4\u673A\u5668\u4EBA\u5747\u65E0\u6CD5\u89E3\u6563\uFF1A
|
|
310
|
+
${f.join(`
|
|
311
311
|
`)}
|
|
312
312
|
|
|
313
|
-
\u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}
|
|
313
|
+
\u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}s.addEventListener("input",p)}var re={bots:[]},me=null;function Hn(){return`<section class="page">
|
|
314
314
|
<div class="page-heading">
|
|
315
315
|
<div>
|
|
316
|
-
<p class="eyebrow">${
|
|
317
|
-
<h1>${
|
|
318
|
-
<p>${
|
|
316
|
+
<p class="eyebrow">${o("nav.botDefaults")}</p>
|
|
317
|
+
<h1>${o("botDefaults.title")}</h1>
|
|
318
|
+
<p>${o("botDefaults.subtitle")}</p>
|
|
319
319
|
</div>
|
|
320
320
|
</div>
|
|
321
321
|
<form id="bd-filters" class="filters">
|
|
322
|
-
<input type="search" name="q" placeholder="${
|
|
323
|
-
<button type="button" id="bd-refresh">${
|
|
322
|
+
<input type="search" name="q" placeholder="${o("botDefaults.search")}" />
|
|
323
|
+
<button type="button" id="bd-refresh">${o("botDefaults.refresh")}</button>
|
|
324
324
|
</form>
|
|
325
|
-
<p class="hint-warn" style="max-width:760px">
|
|
326
|
-
${n("botDefaults.warning")}
|
|
327
|
-
</p>
|
|
328
325
|
<div id="bd-list"></div>
|
|
329
|
-
</section>`}async function
|
|
330
|
-
<header><strong>${
|
|
331
|
-
<small>${
|
|
332
|
-
<p class="hint-warn-inline">\u67E5\u8BE2\u5931\u8D25\uFF1A${
|
|
333
|
-
</article>`;let
|
|
326
|
+
</section>`}async function Tt(){try{let e=await fetch("/api/bots"),t=await e.json().catch(()=>({}));if(!e.ok){me=t?.error?`HTTP ${e.status}: ${t.error}${t.path?` (${t.path})`:""}`:`HTTP ${e.status}`,re={bots:[]};return}if(!t||!Array.isArray(t.bots)){me="unexpected response shape (no `bots` array)",re={bots:[]};return}me=null,re=t}catch(e){me=e?.message??String(e),re={bots:[]}}}function Lt(e){if(!e)return"\u2014";let t=new Date(e);return Number.isNaN(t.getTime())?"\u2014":t.toLocaleString()}async function Et(e){e.innerHTML=Hn();let t=e.querySelector("#bd-list"),n=e.querySelector("#bd-filters"),s=e.querySelector("#bd-refresh");s.onclick=async()=>{s.disabled=!0;try{await Tt(),a()}finally{s.disabled=!1}},await Tt();function a(){let g=(new FormData(n).get("q")??"").toLowerCase(),l=re.bots.filter(I=>!g||(I.botName??"").toLowerCase().includes(g)||(I.larkAppId??"").toLowerCase().includes(g));if(me){t.innerHTML=`<p class="hint-warn">\u65E0\u6CD5\u52A0\u8F7D bot \u5217\u8868\uFF1A${d(me)}<br>\u5E38\u89C1\u539F\u56E0\uFF1Adashboard / daemon \u8FDB\u7A0B\u8FD8\u5728\u8DD1\u65E7\u4EE3\u7801\uFF0C\u6267\u884C <code>botmux restart</code> \u540E\u5237\u65B0\u3002</p>`;return}if(l.length===0){t.innerHTML=`<p class="empty">${o("botDefaults.empty")}</p>`;return}t.innerHTML=l.map(r).join(""),$()}function r(p){if(p.error)return`<article class="bd-card" data-appid="${d(p.larkAppId)}">
|
|
327
|
+
<header><strong>${d(p.botName??p.larkAppId)}</strong>
|
|
328
|
+
<small>${d(p.larkAppId)}</small></header>
|
|
329
|
+
<p class="hint-warn-inline">\u67E5\u8BE2\u5931\u8D25\uFF1A${d(p.error)}</p>
|
|
330
|
+
</article>`;let g=p.defaultOncall??{enabled:!1,workingDir:"",since:0},l=!!g.enabled;return`<article class="bd-card" data-appid="${d(p.larkAppId)}">
|
|
334
331
|
<header>
|
|
335
|
-
<strong>${
|
|
336
|
-
<small>${
|
|
332
|
+
<strong>${d(p.botName??p.larkAppId)}</strong>
|
|
333
|
+
<small>${d(p.larkAppId)}</small>
|
|
337
334
|
</header>
|
|
338
335
|
<div class="bd-body">
|
|
339
|
-
<
|
|
340
|
-
<
|
|
341
|
-
<
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
<label>
|
|
346
|
-
<span>${n("botDefaults.workingDir")}</span>
|
|
347
|
-
<input type="text" data-input="workingDir" placeholder="e.g. /root/iserver/botmux"
|
|
348
|
-
value="${m(y.workingDir??"")}" ${S?"":"disabled"}>
|
|
336
|
+
<section class="bd-section">
|
|
337
|
+
<h3 class="bd-section-title">${o("botDefaults.sectionOncall")}</h3>
|
|
338
|
+
<label class="checkbox-row">
|
|
339
|
+
<input type="checkbox" data-action="toggle" ${l?"checked":""}>
|
|
340
|
+
<strong>${o("botDefaults.defaultOncall")}</strong>
|
|
341
|
+
<small>${o("botDefaults.defaultOncallHelp")}</small>
|
|
349
342
|
</label>
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
343
|
+
<div class="bd-row">
|
|
344
|
+
<label>
|
|
345
|
+
<span>${o("botDefaults.workingDir")}</span>
|
|
346
|
+
<input type="text" data-input="workingDir" placeholder="e.g. /root/iserver/botmux"
|
|
347
|
+
value="${d(g.workingDir??"")}" ${l?"":"disabled"}>
|
|
348
|
+
</label>
|
|
349
|
+
</div>
|
|
350
|
+
<p class="bd-section-note">${o("botDefaults.warning")}</p>
|
|
351
|
+
<div class="bd-meta">
|
|
352
|
+
<small>${o("botDefaults.lastEnabled")}: ${d(Lt(g.since??0))}</small>
|
|
353
|
+
<small>${o("botDefaults.autobound",{count:p.autoboundChatCount??0})}</small>
|
|
354
|
+
</div>
|
|
355
|
+
<div class="actions">
|
|
356
|
+
<button type="button" data-action="save">${o("botDefaults.save")}</button>
|
|
357
|
+
<span class="oncall-status" data-status></span>
|
|
358
|
+
</div>
|
|
359
|
+
</section>
|
|
360
|
+
${m(p)}
|
|
361
|
+
${k(p)}
|
|
362
|
+
</div>
|
|
363
|
+
</article>`}function i(p){return p==null?o("botDefaults.brandStateDefault"):p.trim()===""?o("botDefaults.brandStateOff"):o("botDefaults.brandStateCustom")}function m(p){let g=p.brandLabel??null;return`<section class="bd-section">
|
|
364
|
+
<h3 class="bd-section-title">${o("botDefaults.sectionBrand")}</h3>
|
|
365
|
+
<div class="bd-row bd-brand">
|
|
366
|
+
<label>
|
|
367
|
+
<span>${o("botDefaults.brandLabel")}</span>
|
|
368
|
+
<input type="text" data-input="brandLabel"
|
|
369
|
+
placeholder="${d(o("botDefaults.brandLabelPlaceholder"))}"
|
|
370
|
+
value="${d(g??"")}">
|
|
371
|
+
</label>
|
|
372
|
+
<small data-brand-state>${d(i(g))}</small>
|
|
373
|
+
<small>${o("botDefaults.brandLabelHelp")}</small>
|
|
355
374
|
<div class="actions">
|
|
356
|
-
<button type="button" data-action="save">${
|
|
357
|
-
<
|
|
375
|
+
<button type="button" data-action="save-brand">${o("botDefaults.brandSave")}</button>
|
|
376
|
+
<button type="button" data-action="reset-brand">${o("botDefaults.brandReset")}</button>
|
|
377
|
+
<span class="oncall-status" data-brand-status></span>
|
|
358
378
|
</div>
|
|
359
379
|
</div>
|
|
360
|
-
</
|
|
380
|
+
</section>`}function k(p){let g=p.disableStreamingCard===!0,l=p.writableTerminalLinkInCard===!0,I=p.privateCard===!0;return`<section class="bd-section">
|
|
381
|
+
<h3 class="bd-section-title">${o("botDefaults.sectionCard")}</h3>
|
|
382
|
+
<label class="checkbox-row">
|
|
383
|
+
<input type="checkbox" data-action="toggle-disable-streaming" ${g?"checked":""}>
|
|
384
|
+
<strong>${o("botDefaults.disableStreaming")}</strong>
|
|
385
|
+
<small>${o("botDefaults.disableStreamingHelp")}</small>
|
|
386
|
+
</label>
|
|
387
|
+
<label class="checkbox-row">
|
|
388
|
+
<input type="checkbox" data-action="toggle-writable-link" ${l?"checked":""} ${g?"disabled":""}>
|
|
389
|
+
<strong>${o("botDefaults.writableLink")}</strong>
|
|
390
|
+
<small>${o("botDefaults.writableLinkHelp")}</small>
|
|
391
|
+
</label>
|
|
392
|
+
<label class="checkbox-row">
|
|
393
|
+
<input type="checkbox" data-action="toggle-private-card" ${I?"checked":""}>
|
|
394
|
+
<strong>${o("botDefaults.privateCard")}</strong>
|
|
395
|
+
<small>${o("botDefaults.privateCardHelp")}</small>
|
|
396
|
+
</label>
|
|
397
|
+
<div class="actions">
|
|
398
|
+
<small data-card-pref-moot class="hint-warn-inline" ${g?"":"hidden"}>${o("botDefaults.writableLinkMoot")}</small>
|
|
399
|
+
<span class="oncall-status" data-card-pref-status></span>
|
|
400
|
+
</div>
|
|
401
|
+
</section>`}function $(){t.querySelectorAll(".bd-card").forEach(p=>{let g=p.dataset.appid,l=p.querySelector("input[data-action=toggle]"),I=p.querySelector("input[data-input=workingDir]"),L=p.querySelector("button[data-action=save]"),b=p.querySelector("[data-status]");if(!l||!I||!L||!b)return;l.addEventListener("change",()=>{I.disabled=!l.checked,l.checked&&I.focus()}),L.addEventListener("click",async()=>{b.textContent="",b.className="oncall-status";let O=l.checked,x=I.value.trim();if(O&&!x){b.textContent=o("botDefaults.required"),b.classList.add("hint-warn-inline");return}L.disabled=!0;try{let q=await fetch(`/api/bots/${encodeURIComponent(g)}/default-oncall`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:O,workingDir:x})}),j=await q.json().catch(()=>({}));if(q.ok&&j.ok){let F=j.resolvedPath?` \u2192 ${j.resolvedPath}`:"";b.textContent=O?`\u2713 \u5DF2\u5F00\u542F${F}\uFF08\u672A\u7ED1\u5B9A\u7684\u7FA4\u4E0B\u6B21\u5F00\u8BDD\u9898\u81EA\u52A8 oncall\uFF09`:"\u2713 \u5DF2\u5173\u95ED\uFF08\u5DF2\u7ED1\u5B9A\u7684\u7FA4\u4E0D\u52A8\uFF09",b.classList.add("hint-ok");let z=re.bots.find(te=>te.larkAppId===g);z&&j.defaultOncall&&(z.defaultOncall=j.defaultOncall);let ee=p.querySelector(".bd-meta small:first-child");ee&&j.defaultOncall?.since!=null&&(ee.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${Lt(j.defaultOncall.since)}`)}else b.textContent=`\u2717 ${j.error??q.status}`,b.classList.add("hint-warn-inline")}catch(q){b.textContent=`\u2717 ${q?.message??q}`,b.classList.add("hint-warn-inline")}finally{L.disabled=!1}});let f=p.querySelector("input[data-input=brandLabel]"),T=p.querySelector("button[data-action=save-brand]"),S=p.querySelector("button[data-action=reset-brand]"),y=p.querySelector("[data-brand-status]"),H=p.querySelector("[data-brand-state]");async function u(O,x){if(y){y.textContent="",y.className="oncall-status",x.disabled=!0;try{let q=await fetch(`/api/bots/${encodeURIComponent(g)}/brand-label`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({brandLabel:O})}),j=await q.json().catch(()=>({}));if(q.ok&&j.ok){let F=j.brandLabel??null;y.textContent="\u2713",y.classList.add("hint-ok"),f&&(f.value=F??""),H&&(H.textContent=i(F));let z=re.bots.find(ee=>ee.larkAppId===g);z&&(z.brandLabel=F)}else y.textContent=`\u2717 ${j.error??q.status}`,y.classList.add("hint-warn-inline")}catch(q){y.textContent=`\u2717 ${q?.message??q}`,y.classList.add("hint-warn-inline")}finally{x.disabled=!1}}}f&&T&&T.addEventListener("click",()=>u(f.value,T)),S&&S.addEventListener("click",()=>u(null,S));let w=p.querySelector("input[data-action=toggle-disable-streaming]"),h=p.querySelector("input[data-action=toggle-writable-link]"),E=p.querySelector("input[data-action=toggle-private-card]"),M=p.querySelector("[data-card-pref-status]"),A=p.querySelector("[data-card-pref-moot]");async function P(O,x){if(M){M.textContent="",M.className="oncall-status",x.disabled=!0;try{let q=await fetch(`/api/bots/${encodeURIComponent(g)}/card-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(O)}),j=await q.json().catch(()=>({}));if(q.ok&&j.ok){M.textContent=`\u2713 ${o("botDefaults.cardPrefSaved")}`,M.classList.add("hint-ok");let F=re.bots.find(z=>z.larkAppId===g);F&&(F.disableStreamingCard=j.disableStreamingCard,F.writableTerminalLinkInCard=j.writableTerminalLinkInCard,F.privateCard=j.privateCard)}else M.textContent=`\u2717 ${j.error??q.status}`,M.classList.add("hint-warn-inline")}catch(q){M.textContent=`\u2717 ${q?.message??q}`,M.classList.add("hint-warn-inline")}finally{x===h?x.disabled=!!w?.checked:x.disabled=!1}}}w&&w.addEventListener("change",()=>{let O=w.checked;h&&(h.disabled=O),A&&(A.hidden=!O),P({disableStreamingCard:O},w)}),h&&h.addEventListener("change",()=>{P({writableTerminalLinkInCard:h.checked},h)}),E&&E.addEventListener("change",()=>{P({privateCard:E.checked},E)})})}a(),n.addEventListener("input",a)}var Ve=4096,He=[],Q=null,X=null,J="",we=new Set;function xn(){return`<section class="page roles-page">
|
|
361
402
|
<div class="page-heading">
|
|
362
403
|
<div>
|
|
363
|
-
<p class="eyebrow">${
|
|
364
|
-
<h1>${
|
|
365
|
-
<p>${
|
|
404
|
+
<p class="eyebrow">${o("nav.roles")}</p>
|
|
405
|
+
<h1>${o("roles.title")}</h1>
|
|
406
|
+
<p>${o("roles.subtitle")}</p>
|
|
366
407
|
</div>
|
|
367
408
|
</div>
|
|
368
409
|
<div class="roles-layout">
|
|
369
410
|
<div class="roles-tree-panel">
|
|
370
411
|
<div class="roles-tree-header">
|
|
371
|
-
<input type="search" id="roles-search" placeholder="${
|
|
372
|
-
<button type="button" id="roles-refresh">${
|
|
412
|
+
<input type="search" id="roles-search" placeholder="${o("roles.search")}" />
|
|
413
|
+
<button type="button" id="roles-refresh">${o("roles.refresh")}</button>
|
|
373
414
|
</div>
|
|
374
415
|
<div id="roles-tree" class="roles-tree"></div>
|
|
375
416
|
</div>
|
|
376
417
|
<div class="roles-editor-panel">
|
|
377
|
-
<div id="roles-editor-empty" class="roles-editor-empty">${
|
|
418
|
+
<div id="roles-editor-empty" class="roles-editor-empty">${o("roles.selectHint")}</div>
|
|
378
419
|
<div id="roles-editor-form" class="roles-editor-form" style="display:none">
|
|
379
420
|
<div class="roles-editor-breadcrumb">
|
|
380
421
|
<span id="roles-editor-group-name"></span>
|
|
@@ -384,82 +425,205 @@ ${u.join(`
|
|
|
384
425
|
<div class="roles-editor-meta">
|
|
385
426
|
<span id="roles-editor-chat-id" class="roles-editor-meta-line"></span>
|
|
386
427
|
</div>
|
|
387
|
-
<textarea id="roles-editor-textarea" placeholder="${
|
|
428
|
+
<textarea id="roles-editor-textarea" placeholder="${o("roles.editorPlaceholder")}" rows="14"></textarea>
|
|
388
429
|
<div class="roles-editor-footer">
|
|
389
430
|
<span id="roles-editor-bytecount" class="roles-bytecount"></span>
|
|
390
431
|
<div class="roles-editor-actions">
|
|
391
|
-
<button type="button" id="roles-delete" class="danger">${
|
|
392
|
-
<button type="button" id="roles-save" class="primary">${
|
|
432
|
+
<button type="button" id="roles-delete" class="danger">${o("roles.delete")}</button>
|
|
433
|
+
<button type="button" id="roles-save" class="primary">${o("roles.save")}</button>
|
|
393
434
|
</div>
|
|
394
435
|
</div>
|
|
395
436
|
<div id="roles-preview" class="roles-preview"></div>
|
|
396
437
|
</div>
|
|
397
438
|
</div>
|
|
398
439
|
</div>
|
|
399
|
-
</section>`}async function
|
|
400
|
-
<div class="roles-bot-row ${
|
|
401
|
-
data-group-id="${
|
|
402
|
-
data-bot-id="${
|
|
440
|
+
</section>`}async function Ce(){He=((await(await fetch("/api/groups")).json()).chats??[]).map(n=>({chatId:n.chatId,name:n.name??n.chatId,memberBots:(n.memberBots??[]).map(s=>({larkAppId:s.larkAppId,botName:s.botName??s.larkAppId,inChat:s.inChat??!1,hasRole:s.hasRole??!1,oncallChat:s.oncallChat??null}))}))}async function Ct(e,t){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)).json()}async function An(e,t,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({content:n})})).ok}async function Rn(e,t){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{method:"DELETE"})).ok}function Ht(e){return e.memberBots.filter(t=>t.inChat&&t.hasRole).length}function Dn(e){return e.memberBots.filter(t=>t.inChat).length}function de(e=""){let t=document.getElementById("roles-tree");if(!t)return;let n=e.toLowerCase(),s=He.filter(a=>{if(!n)return!0;let r=a.chatId.toLowerCase().includes(n)||(a.name??"").toLowerCase().includes(n),i=a.memberBots.some(m=>m.larkAppId.toLowerCase().includes(n)||(m.botName??"").toLowerCase().includes(n));return r||i});if(s.length===0){t.innerHTML=`<div class="roles-empty">${o("roles.noChats")}</div>`;return}t.innerHTML=s.map(a=>{let r=we.has(a.chatId),i=a.memberBots.filter(g=>g.inChat),m=r?"\u25BE":"\u25B8",k=Ht(a),$=Dn(a),p=r?i.map(g=>`
|
|
441
|
+
<div class="roles-bot-row ${Q===a.chatId&&X===g.larkAppId?"selected":""}"
|
|
442
|
+
data-group-id="${d(a.chatId)}"
|
|
443
|
+
data-bot-id="${d(g.larkAppId)}">
|
|
403
444
|
<span class="roles-bot-indent"></span>
|
|
404
445
|
<span class="roles-bot-icon">\u{1F916}</span>
|
|
405
446
|
<div class="roles-bot-info">
|
|
406
|
-
<div class="roles-bot-name">${
|
|
407
|
-
<div class="roles-bot-id">${
|
|
447
|
+
<div class="roles-bot-name">${d(g.botName)}</div>
|
|
448
|
+
<div class="roles-bot-id">${d(g.larkAppId)}</div>
|
|
408
449
|
</div>
|
|
409
|
-
<span class="roles-badge ${
|
|
410
|
-
${
|
|
450
|
+
<span class="roles-badge ${g.hasRole?"has-role":"no-role"}">
|
|
451
|
+
${g.hasRole?o("roles.configured"):o("roles.unconfigured")}
|
|
411
452
|
</span>
|
|
412
453
|
</div>`).join(""):"";return`
|
|
413
454
|
<div class="roles-group-section">
|
|
414
|
-
<div class="roles-group-row ${
|
|
415
|
-
data-group-id="${
|
|
416
|
-
<span class="roles-group-arrow">${
|
|
455
|
+
<div class="roles-group-row ${r?"expanded":""} ${Q===a.chatId&&!X?"selected":""}"
|
|
456
|
+
data-group-id="${d(a.chatId)}">
|
|
457
|
+
<span class="roles-group-arrow">${m}</span>
|
|
417
458
|
<span class="roles-group-icon">\u{1F4C1}</span>
|
|
418
459
|
<div class="roles-group-info">
|
|
419
|
-
<div class="roles-group-name">${
|
|
460
|
+
<div class="roles-group-name">${d(a.name??a.chatId)}</div>
|
|
420
461
|
<div class="roles-group-meta">
|
|
421
|
-
${
|
|
462
|
+
${k}/${$} ${o("roles.botsWithRoles")}
|
|
422
463
|
</div>
|
|
423
464
|
</div>
|
|
424
465
|
<span class="roles-group-chevron"></span>
|
|
425
466
|
</div>
|
|
426
|
-
<div class="roles-bot-list">${
|
|
427
|
-
</div>`}).join(""),t.querySelectorAll(".roles-group-row").forEach(
|
|
467
|
+
<div class="roles-bot-list">${p}</div>
|
|
468
|
+
</div>`}).join(""),t.querySelectorAll(".roles-group-row").forEach(a=>{a.addEventListener("click",()=>{let r=a.dataset.groupId;r&&(we.has(r)?we.delete(r):we.add(r),de(document.getElementById("roles-search")?.value??""))})}),t.querySelectorAll(".roles-bot-row").forEach(a=>{a.addEventListener("click",r=>{r.stopPropagation();let i=a.dataset.groupId,m=a.dataset.botId;i&&m&&Bn(i,m)})})}async function Bn(e,t){Q=e,X=t;let n=await Ct(t,e),s=document.getElementById("roles-editor-empty"),a=document.getElementById("roles-editor-form"),r=document.getElementById("roles-editor-textarea"),i=document.getElementById("roles-editor-group-name"),m=document.getElementById("roles-editor-bot-name"),k=document.getElementById("roles-editor-chat-id");s&&(s.style.display="none"),a&&(a.style.display="");let $=He.find(l=>l.chatId===e),p=$?.memberBots.find(l=>l.larkAppId===t);i&&(i.textContent=$?.name??e),m&&(m.textContent=p?.botName??t),k&&(k.textContent=`${e} \xB7 ${t}`),J=n.content??"",r&&(r.value=J,r.focus()),Ye(),Qe(),de(document.getElementById("roles-search")?.value??"");let g=document.getElementById("roles-delete");g&&(g.style.display=n.hasRole?"":"none")}function Ye(){let e=document.getElementById("roles-editor-bytecount");if(!e)return;let t=new TextEncoder().encode(J).length;e.textContent=`${t} / ${Ve} bytes`,e.className=`roles-bytecount ${t>3800?"warn":""} ${t>Ve?"over":""}`,On(t)}function On(e){let t=document.getElementById("roles-save");if(!t)return;let n=e??new TextEncoder().encode(J).length;t.disabled=n>Ve||J.trim().length===0}function Qe(){let e=document.getElementById("roles-preview");e&&(J.trim()?e.innerHTML=`<strong>${o("roles.preview")}</strong><pre>${d(J)}</pre>`:e.innerHTML=`<small>${o("roles.previewEmpty")}</small>`)}function Mt(){Q=null,X=null,J="";let e=document.getElementById("roles-editor-empty"),t=document.getElementById("roles-editor-form"),n=document.getElementById("roles-editor-textarea"),s=document.getElementById("roles-delete");e&&(e.style.display=""),t&&(t.style.display="none"),n&&(n.value=""),s&&(s.style.display="none")}async function xt(e){e.innerHTML=xn(),we.clear(),Mt(),await Ce();for(let t of He)Ht(t)>0&&we.add(t.chatId);de(),document.getElementById("roles-search")?.addEventListener("input",t=>{de(t.target.value)}),document.getElementById("roles-refresh")?.addEventListener("click",async()=>{if(await Ce(),de(document.getElementById("roles-search")?.value??""),Q&&X){let t=await Ct(X,Q),n=document.getElementById("roles-editor-textarea");n&&(n.value=t.content??""),J=t.content??"",Ye(),Qe();let s=document.getElementById("roles-delete");s&&(s.style.display=t.hasRole?"":"none")}}),document.getElementById("roles-save")?.addEventListener("click",async function(){if(!(!Q||!X)){this.disabled=!0,this.textContent="...";try{if(await An(X,Q,J)){await Ce(),de(document.getElementById("roles-search")?.value??"");let n=document.getElementById("roles-delete");n&&(n.style.display="");let s=document.createElement("span");s.className="roles-saved-flash",s.textContent=` ${o("roles.saved")}`,document.querySelector(".roles-editor-footer")?.appendChild(s),setTimeout(()=>s.remove(),2e3)}else{let n=document.createElement("span");n.className="roles-saved-flash roles-save-error",n.textContent=J.trim().length===0?` ${o("roles.emptyError")}`:` ${o("roles.saveFailed")}`,document.querySelector(".roles-editor-footer")?.appendChild(n),setTimeout(()=>n.remove(),3e3)}}finally{this.disabled=!1,this.textContent=o("roles.save")}}}),document.getElementById("roles-delete")?.addEventListener("click",async function(){if(!(!Q||!X)&&confirm(o("roles.confirmDelete"))){this.disabled=!0,this.textContent="...";try{await Rn(X,Q)&&(await Ce(),Mt(),de(document.getElementById("roles-search")?.value??""))}finally{this.disabled=!1,this.textContent=o("roles.delete")}}}),document.getElementById("roles-editor-textarea")?.addEventListener("input",t=>{J=t.target.value,Ye(),Qe()})}async function Re(e){let t=await fetch(e);return{status:t.status,body:await t.json().catch(()=>({}))}}async function De(e,t,n){let s=await fetch(t,{method:e,headers:{"content-type":"application/json"},body:n?JSON.stringify(n):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}var ue=(e,t)=>De("POST",e,t),At=(e,t)=>De("PUT",e,t),Xe=[],Rt=[],Dt="",xe="",Ze=new Map,Ae=new Map,ye=new Set,ve=new Set;function B(e){return document.getElementById(e)}function Be(){return[...Xe,...Rt]}function ce(e){let t=Ze.get(e);return t||(t=new Set,Ze.set(e,t)),t}function qn(e){return Be().find(t=>t.key===e)}function Bt(e){let t=(n,s,a)=>`<a href="${n}" style="padding:6px 14px;border-radius:8px;text-decoration:none;font-size:14px;${a?"background:var(--accent,#3370ff);color:#fff":"color:var(--text,#1f2329)"}">${s}</a>`;return`<div style="display:flex;gap:8px;margin-bottom:14px">${t("#/team","\u6211\u7684\u56E2\u961F",e==="home")}${t("#/team/manage","\u56E2\u961F\u7BA1\u7406",e==="manage")}</div>`}function Pn(){return`<section class="page">
|
|
469
|
+
<div class="page-heading"><div>
|
|
470
|
+
<p class="eyebrow">\u56E2\u961F</p><h1>\u56E2\u961F\u534F\u4F5C\uFF08\u8DE8\u90E8\u7F72\uFF09</h1>
|
|
471
|
+
<p>\u628A\u522B\u7684\u90E8\u7F72\uFF08\u540C\u4E8B\u81EA\u5DF1\u8DD1\u7684 botmux\uFF09\u9080\u8BF7\u8FDB\u540C\u4E00\u4E2A\u56E2\u961F\uFF0C\u4E92\u76F8\u53D1\u73B0\u673A\u5668\u4EBA\u3001\u534F\u4F5C\u62C9\u7FA4\u3002</p>
|
|
472
|
+
</div></div>
|
|
473
|
+
${Bt("home")}
|
|
474
|
+
<div class="card" style="margin-bottom:16px">
|
|
475
|
+
<h2 style="margin-top:0">\u672C\u90E8\u7F72</h2>
|
|
476
|
+
<p>\u6211\u7684\u98DE\u4E66\u8EAB\u4EFD\uFF1A<b id="tf-owner">\u672A\u7ED1\u5B9A</b>
|
|
477
|
+
<button id="tf-autobind" class="primary" style="margin-left:8px">\u7ED1\u5B9A</button>
|
|
478
|
+
<span class="muted" style="font-size:13px">\uFF08\u7528\u673A\u5668\u4EBA\u51ED\u8BC1\u81EA\u52A8\u8BC6\u522B\u4F60\uFF1B\u7ED1\u5B9A\u540E\u62C9\u7FA4\u4F1A\u628A\u4F60\u62C9\u8FDB\u7FA4\u3001\u673A\u5668\u4EBA\u4E5F\u5F52\u5230\u4F60\u540D\u4E0B\uFF09</span></p>
|
|
479
|
+
<div id="tf-bind-out" style="display:none;margin-top:6px"></div>
|
|
480
|
+
</div>
|
|
481
|
+
<div class="card">
|
|
482
|
+
<h2 style="margin-top:0">\u6211\u7684\u56E2\u961F <span class="muted" id="tf-count" style="font-size:13px"></span></h2>
|
|
483
|
+
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:8px;font-size:13px">
|
|
484
|
+
<input id="tf-search" placeholder="\u641C\u7D22 \u540D\u79F0/\u80FD\u529B/CLI\u2026" style="padding:5px 9px;min-width:180px">
|
|
485
|
+
<select id="tf-cli" style="padding:5px"><option value="">\u5168\u90E8 CLI</option></select>
|
|
486
|
+
<label><input type="checkbox" id="tf-fcap"> \u6709\u80FD\u529B\u6807\u7B7E</label>
|
|
487
|
+
<label><input type="checkbox" id="tf-frole"> \u6709\u56E2\u961F\u89D2\u8272</label>
|
|
488
|
+
</div>
|
|
489
|
+
<p class="muted" style="font-size:13px;margin:0 0 4px">\u6BCF\u4E2A\u56E2\u961F\u91CC\u52FE\u9009\u673A\u5668\u4EBA\u5373\u53EF\u5355\u72EC\u62C9\u7FA4\uFF08\u81EA\u52A8\u5E26\u4E0A\u5404\u81EA\u8D1F\u8D23\u4EBA\uFF09\u3002\u8981\u65B0\u5EFA\u56E2\u961F / \u751F\u6210\u9080\u8BF7\u7801 / \u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\uFF0C\u53BB\u300C\u56E2\u961F\u7BA1\u7406\u300D\u3002</p>
|
|
490
|
+
<div id="tf-teams">\u52A0\u8F7D\u4E2D\u2026</div>
|
|
491
|
+
</div>
|
|
492
|
+
<div id="tf-modal" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);align-items:center;justify-content:center;z-index:50">
|
|
493
|
+
<div style="background:var(--card,#fff);color:var(--text,#1f2329);border-radius:10px;padding:18px 20px;width:min(560px,92vw)">
|
|
494
|
+
<h2 id="tf-modal-title" style="margin-top:0">\u56E2\u961F\u89D2\u8272</h2>
|
|
495
|
+
<p class="muted" style="font-size:13px">\u56E2\u961F\u7EA7\u89D2\u8272\uFF08\u8BE5\u673A\u5668\u4EBA\u8DE8\u7FA4\u7684\u9ED8\u8BA4\u4EBA\u8BBE\uFF09\u3002\u7559\u7A7A\u4FDD\u5B58\u5373\u5220\u9664\u3002\u4EC5\u672C\u90E8\u7F72\u7684\u673A\u5668\u4EBA\u53EF\u7F16\u8F91\u3002</p>
|
|
496
|
+
<textarea id="tf-modal-text" style="width:100%;min-height:200px;font:13px/1.5 ui-monospace,Menlo,monospace;padding:10px;box-sizing:border-box"></textarea>
|
|
497
|
+
<div style="display:flex;justify-content:flex-end;gap:8px;margin-top:12px">
|
|
498
|
+
<button id="tf-modal-cancel">\u53D6\u6D88</button><button id="tf-modal-save" class="primary">\u4FDD\u5B58</button>
|
|
499
|
+
</div>
|
|
500
|
+
</div>
|
|
501
|
+
</div>
|
|
502
|
+
</section>`}function Nn(e){let t=(B("tf-search").value||"").trim().toLowerCase();if(t&&!((e.name||"")+" "+(e.cliId||"")+" "+(e.capability||"")).toLowerCase().includes(t))return!1;let n=B("tf-cli").value;return!(n&&e.cliId!==n||B("tf-fcap").checked&&!e.capability||B("tf-frole").checked&&!e.hasTeamRole)}function jn(e,t){let n=[...e.deployments].sort((a,r)=>a.local===r.local?0:a.local?-1:1),s="";for(let a of n){let r=t.filter(l=>l.deployment.id===a.id);if(!r.length)continue;let i=a.id===Dt,m=i?"\u672C\u90E8\u7F72":a.stale?"\u8FDC\u7AEF\xB7\u79BB\u7EBF\uFF1F":"\u8FDC\u7AEF",k=e.kind==="local"&&!i?` <button class="tf-rmmember ghost" data-team="${d(e.teamId)}" data-dep="${d(a.id)}" data-name="${d(a.name)}" style="font-size:12px">\u79FB\u9664</button>`:"",$=`${e.key}::${a.id}`,p=ve.has($),g=r.filter(l=>ce(e.key).has(l.larkAppId)).length;if(s+=`<div class="tf-dep-h" data-dk="${d($)}" style="cursor:pointer;margin:10px 0 2px"><b>${p?"\u25BE":"\u25B8"} ${d(a.name)}</b> <span class="muted" style="font-size:12px">\uFF08${m}\uFF09\xB7 ${r.length} \u4E2A${g?`\uFF0C\u5DF2\u9009 ${g}`:""}</span>${k}</div>`,!!p){s+='<table style="width:100%;border-collapse:collapse;font-size:14px"><tbody>';for(let l of r){let I=d(l.larkAppId),L=ce(e.key).has(l.larkAppId)?" checked":"",b=l.deployment.stale?"opacity:.55":"",f=i?`<input class="tf-cap" data-app="${I}" value="${d(l.capability||"")}" placeholder="\u80FD\u529B\u6807\u7B7E\u2026" style="width:92%;padding:3px 6px">`:l.capability?d(l.capability):'<span class="muted">\u2014</span>',T=i?`<button class="tf-role" data-app="${I}" data-name="${d(l.name)}">${l.hasTeamRole?"\u5DF2\u8BBE\xB7\u6539":"\u8BBE\u7F6E"}</button>`:l.hasTeamRole?"\u6709\u89D2\u8272":'<span class="muted">\u2014</span>';s+=`<tr style="${b}"><td style="padding:4px 8px"><input type="checkbox" class="tf-pick" data-tk="${d(e.key)}" data-app="${I}"${L}></td><td style="padding:4px 8px">${d(l.name)}</td><td style="padding:4px 8px" class="muted">${d(l.cliId)}</td><td style="padding:4px 8px">${f}</td><td style="padding:4px 8px">${T}</td></tr>`}s+="</tbody></table>"}}return s||(s='<p class="muted" style="margin:8px 0 0">\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u673A\u5668\u4EBA\u3002</p>'),s+=`<div style="margin-top:12px;display:flex;gap:8px;flex-wrap:wrap;align-items:center"><input class="tf-gname" data-tk="${d(e.key)}" value="${d(Ae.get(e.key)||"")}" placeholder="\u7FA4\u540D\uFF08\u5982\uFF1A\u8DE8\u56E2\u961F\u6392\u969C\uFF09" style="min-width:200px"><button class="tf-grp primary" data-tk="${d(e.key)}">\u628A\u52FE\u9009\u7684\u673A\u5668\u4EBA\u62C9\u4E00\u4E2A\u7FA4</button><span class="muted" style="font-size:13px">\u52FE\u9009\u673A\u5668\u4EBA \u2192 \u62C9\u5230\u4E00\u4E2A\u98DE\u4E66\u7FA4\uFF08\u81EA\u52A8\u542B owner\uFF09</span><span class="tf-gout" data-tk="${d(e.key)}" style="font-size:13px;display:block;flex-basis:100%"></span></div>`,s}function ie(){let e=B("tf-teams"),t=Be();if(!t.length){e.innerHTML='<p class="muted">\u8FD8\u6CA1\u6709\u56E2\u961F\u3002\u53BB\u300C\u56E2\u961F\u7BA1\u7406\u300D\u751F\u6210\u9080\u8BF7\u7801\u8BA9\u522B\u4EBA\u52A0\u5165\u4F60\uFF0C\u6216\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\u3002</p>',B("tf-count").textContent="";return}let n="",s=new Set,a=new Set;for(let i of t){let m=i.bots.filter(Nn);m.forEach(g=>s.add(g.larkAppId)),i.bots.forEach(g=>a.add(g.larkAppId));let k=new Set(m.map(g=>g.larkAppId));[...ce(i.key)].forEach(g=>{k.has(g)||ce(i.key).delete(g)});let $=!ye.has(i.key),p=i.kind==="remote"?i.ok?' <span class="ok" style="font-size:12px">\u5DF2\u8FDE\u63A5</span>':` <span class="err" style="font-size:12px">\u8FDE\u63A5\u5931\u8D25\uFF1A${d(i.error||"")}</span>`:' <span class="muted" style="font-size:12px">\u6211\u6258\u7BA1</span>';n+=`<div class="card" style="margin:0 0 12px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)"><div class="tf-team-h" data-tk="${d(i.key)}" style="cursor:pointer;display:flex;align-items:center;gap:8px;flex-wrap:wrap"><b style="font-size:15px">${$?"\u25B8":"\u25BE"} ${d(i.label)}</b>`+(i.sub?` <span class="muted" style="font-size:12px">${d(i.sub)}</span>`:"")+p+` <span class="muted" style="font-size:12px">\xB7 ${i.deployments.length} \u4E2A\u90E8\u7F72 \xB7 ${i.bots.length} \u4E2A\u673A\u5668\u4EBA</span></div>`,$||(n+=i.kind==="remote"&&!i.ok?'<p class="muted" style="margin:8px 0 0">\u65E0\u6CD5\u83B7\u53D6\u8BE5\u56E2\u961F\u82B1\u540D\u518C\u3002</p>':jn(i,m)),n+="</div>"}e.innerHTML=n;let r=t.length>1?`\uFF08\u8DE8 ${t.length} \u4E2A\u56E2\u961F\uFF0C\u53BB\u91CD\uFF09`:"";B("tf-count").textContent=`\xB7 ${s.size===a.size?`${a.size}`:`${s.size} / ${a.size}`} \u4E2A\u673A\u5668\u4EBA${r}`,Un()}function Un(){let e=B("tf-teams");e.querySelectorAll(".tf-team-h").forEach(t=>{t.onclick=()=>{let n=t.dataset.tk;ye.has(n)?ye.delete(n):ye.add(n),ie()}}),e.querySelectorAll(".tf-dep-h").forEach(t=>{t.onclick=()=>{let n=t.dataset.dk;ve.has(n)?ve.delete(n):ve.add(n),ie()}}),e.querySelectorAll(".tf-pick").forEach(t=>{t.onchange=()=>{let n=ce(t.dataset.tk);t.checked?n.add(t.dataset.app):n.delete(t.dataset.app)}}),e.querySelectorAll(".tf-gname").forEach(t=>{t.oninput=()=>{Ae.set(t.dataset.tk,t.value)}}),e.querySelectorAll(".tf-cap").forEach(t=>{t.onchange=async()=>{let n=t.dataset.app,s=t.value;await At("/api/team/local-bots/"+encodeURIComponent(n)+"/capability",{capability:s}),Be().forEach(a=>{let r=a.bots.find(i=>i.larkAppId===n);r&&(r.capability=s.trim()||null)})}}),e.querySelectorAll(".tf-role").forEach(t=>{t.onclick=()=>_n(t.dataset.app,t.dataset.name||"")}),e.querySelectorAll(".tf-rmmember").forEach(t=>{t.onclick=async n=>{n.stopPropagation(),confirm(`\u628A\u300C${t.dataset.name}\u300D\u79FB\u51FA\u8FD9\u4E2A\u56E2\u961F\uFF1F\u5B83\u7684\u673A\u5668\u4EBA\u5C06\u4ECE\u672C\u56E2\u961F\u82B1\u540D\u518C\u6D88\u5931\uFF08\u4E0D\u5F71\u54CD\u5BF9\u65B9\u81EA\u5DF1\u7684\u90E8\u7F72\uFF09\u3002`)&&(await De("DELETE",`/api/team/hosted/${encodeURIComponent(t.dataset.team)}/members/${encodeURIComponent(t.dataset.dep)}`),ge())}}),e.querySelectorAll(".tf-grp").forEach(t=>{t.onclick=async()=>{let n=t.dataset.tk,s=qn(n);if(!s)return;let a=[...ce(n)],r=e.querySelector(`.tf-gout[data-tk="${CSS.escape(n)}"]`);if(!a.length){r.innerHTML='<span class="err">\u8BF7\u5148\u52FE\u9009\u81F3\u5C11\u4E00\u4E2A\u673A\u5668\u4EBA</span>';return}let i=(e.querySelector(`.tf-gname[data-tk="${CSS.escape(n)}"]`)?.value||"").trim()||"\u534F\u4F5C\u7FA4";r.innerHTML='<span class="muted">\u5EFA\u7FA4\u4E2D\u2026</span>';let m=s.kind==="local"?await ue("/api/team/federated-group",{name:i,larkAppIds:a,teamId:s.teamId}):await ue("/api/team/remote-group",{hubUrl:s.hubUrl,teamId:s.teamId,name:i,larkAppIds:a});if(Fn(r,m.body,m.status),m.body?.ok){ce(n).clear(),Ae.delete(n);let k=r.innerHTML,$=()=>{let p=e.querySelector(`.tf-gout[data-tk="${CSS.escape(n)}"]`);p&&(p.innerHTML=k)};s.kind==="local"?ge().then($):(ie(),$())}}})}function Fn(e,t,n){if(t?.ok&&t.chatId){let s=t.shareLink||"https://applink.feishu.cn/client/chat/open?openChatId="+encodeURIComponent(t.chatId),a=(t.invalidBotIds||[]).length?`<span class="err"> \xB7 \u672A\u52A0\u5165\u7684\u673A\u5668\u4EBA\uFF1A${d((t.invalidBotIds||[]).join(", "))}</span>`:"",r=(t.invalidOwnerUnionIds||[]).length?`<span class="err"> \xB7 ${(t.invalidOwnerUnionIds||[]).length} \u4E2A owner \u672A\u80FD\u62C9\u8FDB</span>`:"",i=t.missingOperatorIdentity?'<span class="err"> \xB7 \u4F60\u672A\u7ED1\u5B9A\u98DE\u4E66\u8EAB\u4EFD\uFF0C\u6CA1\u628A\u4F60\u81EA\u5DF1\u62C9\u8FDB\u7FA4\uFF08\u53BB\u300C\u6211\u7684\u56E2\u961F\u300D\u7ED1\u5B9A\uFF09</span>':"",m=(t.skippedNoOwner||[]).length?`<span class="err"> \xB7 ${(t.skippedNoOwner||[]).length} \u4E2A\u673A\u5668\u4EBA\u56E0\u8D1F\u8D23\u4EBA\u672A\u7ED1\u5B9A\u8EAB\u4EFD\u88AB\u8DF3\u8FC7\uFF08\u672A\u52A0\u5165\u7FA4\uFF09</span>`:"",k=t.delegatedTo?`\uFF08\u7531\u300C${d(t.delegatedTo)}\u300D\u5EFA\u7FA4\uFF09`:"";e.innerHTML=`<span class="ok">\u7FA4\u5DF2\u521B\u5EFA</span>${k} \xB7 <a href="${d(s)}" target="_blank">\u5728\u98DE\u4E66\u6253\u5F00</a>${a}${r}${i}${m}`}else{let s=t?.error||n,a=s==="no_local_online_bot"?"\u8BF7\u81F3\u5C11\u52FE\u9009\u4E00\u4E2A\u4F60\u81EA\u5DF1\uFF08\u672C\u90E8\u7F72\uFF09\u7684\u5728\u7EBF\u673A\u5668\u4EBA\u2014\u2014\u7FA4\u8981\u7531\u5B83\u521B\u5EFA\u5E76\u628A\u4F60\uFF08\u53D1\u8D77\u4EBA\uFF09\u62C9\u8FDB\u7FA4\u3002":s==="all_bots_skipped_no_owner"?"\u6240\u9009\u673A\u5668\u4EBA\u7684\u8D1F\u8D23\u4EBA\u90FD\u6CA1\u7ED1\u5B9A\u8EAB\u4EFD\uFF0C\u65E0\u6CD5\u62C9\u7FA4\uFF08\u673A\u5668\u4EBA\u4E0D\u80FD\u8FDB\u4E00\u4E2A owner \u4E0D\u5728\u7684\u7FA4\uFF09\u3002\u8BF7\u8BA9\u5BF9\u5E94\u90E8\u7F72\u5148\u7ED1\u5B9A\u8EAB\u4EFD\u3002":s==="no_creator_available"?"\u6CA1\u6709\u53EF\u7528\u7684\u5EFA\u7FA4\u53D1\u8D77\u65B9\uFF08\u76F8\u5173\u90E8\u7F72\u90FD\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF0C\u6216\u4E0D\u53EF\u8FBE\uFF09":s==="delegation_timeout"?"\u59D4\u6258\u5BF9\u65B9\u90E8\u7F72\u5EFA\u7FA4\u8D85\u65F6\uFF08\u53EF\u80FD\u5DF2\u5EFA\uFF0C\u53BB\u98DE\u4E66\u786E\u8BA4\uFF0C\u52FF\u91CD\u590D\u70B9\uFF09":`\u5EFA\u7FA4\u5931\u8D25\uFF1A${s}`;e.innerHTML=`<span class="err">${d(String(a))}</span>`}}async function _n(e,t){let n=await Re("/api/team/local-bots/"+encodeURIComponent(e)+"/role");B("tf-modal-title").textContent="\u56E2\u961F\u89D2\u8272 \xB7 "+t,B("tf-modal-text").value=n.body?.role||"",B("tf-modal").dataset.app=e,B("tf-modal").style.display="flex"}function Ot(){let e=Array.from(new Set(Be().flatMap(s=>s.bots.map(a=>a.cliId)).filter(Boolean))).sort(),t=B("tf-cli"),n=t.value;t.innerHTML='<option value="">\u5168\u90E8 CLI</option>'+e.map(s=>`<option value="${d(s)}">${d(s)}</option>`).join(""),t.value=n}async function ge(){let t=(await Re("/api/team/hosted")).body;if(!t?.ok){Xe=[],ie();return}Dt=t.deployment.deploymentId,xe=t.suggestedHubUrl||"",B("tf-owner").textContent=t.deployment.ownerName||(t.deployment.ownerUnionId?"\u5DF2\u7ED1\u5B9A":"\u672A\u7ED1\u5B9A"),Xe=(t.teams||[]).map(n=>({kind:"local",key:`local:${n.teamId}`,teamId:n.teamId,label:n.isDefault?"\u6211\u6258\u7BA1\u7684\u56E2\u961F":n.name,sub:"",ok:!0,deployments:n.deployments||[],bots:n.bots||[]})),Ot(),ie()}async function Wn(){Rt=((await Re("/api/team/remote-roster")).body?.memberships||[]).map(n=>{let s=n.roster?.deployments||[],a=s.find(i=>i.local),r=a?.name?`${a.name} \u7684\u56E2\u961F`:n.teamName||n.teamId;return{kind:"remote",key:`${n.hubUrl}::${n.teamId}`,teamId:n.teamId,label:r,sub:n.hubUrl,ok:!!n.ok,error:n.error,hubUrl:n.hubUrl,deployments:s,bots:n.roster?.bots||[]}}),Ot(),ie()}function qt(e){e.innerHTML=Pn(),Ze.clear(),Ae.clear(),ye.clear(),ve.clear(),["tf-search","tf-cli","tf-fcap","tf-frole"].forEach(t=>{let n=B(t);n.oninput=ie,n.onchange=ie}),B("tf-modal-cancel").onclick=()=>{B("tf-modal").style.display="none"},B("tf-modal-save").onclick=async()=>{let t=B("tf-modal").dataset.app;await At("/api/team/local-bots/"+encodeURIComponent(t)+"/role",{role:B("tf-modal-text").value}),B("tf-modal").style.display="none",ge()},Jn(),ge(),Wn()}function zn(){return`<section class="page">
|
|
503
|
+
<div class="page-heading"><div>
|
|
504
|
+
<p class="eyebrow">\u56E2\u961F</p><h1>\u56E2\u961F\u7BA1\u7406</h1>
|
|
505
|
+
<p>\u521B\u5EFA\u591A\u4E2A\u56E2\u961F\u3001\u7ED9\u6BCF\u4E2A\u56E2\u961F\u751F\u6210\u9080\u8BF7\u7801\u3001\u6216\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\u3002\u4E00\u4E2A\u56E2\u961F = \u4F60\u672C\u90E8\u7F72\u7684\u673A\u5668\u4EBA + \u52A0\u5165\u8BE5\u56E2\u961F\u7684\u5176\u5B83\u90E8\u7F72\u3002</p>
|
|
506
|
+
</div></div>
|
|
507
|
+
${Bt("manage")}
|
|
508
|
+
<div class="card" style="margin-bottom:16px">
|
|
509
|
+
<h2 style="margin-top:0">\u6211\u6258\u7BA1\u7684\u56E2\u961F</h2>
|
|
510
|
+
<p style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:6px">
|
|
511
|
+
<input id="tm-newname" placeholder="\u65B0\u56E2\u961F\u540D\u79F0" style="min-width:200px">
|
|
512
|
+
<button id="tm-create" class="primary">\u521B\u5EFA\u56E2\u961F</button>
|
|
513
|
+
<span class="muted tm-cout" style="font-size:13px"></span>
|
|
514
|
+
</p>
|
|
515
|
+
<div id="tm-list">\u52A0\u8F7D\u4E2D\u2026</div>
|
|
516
|
+
</div>
|
|
517
|
+
<div class="card">
|
|
518
|
+
<h2 style="margin-top:0">\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F</h2>
|
|
519
|
+
<p style="display:flex;gap:8px;flex-wrap:wrap;align-items:center">
|
|
520
|
+
<input id="tm-hub" placeholder="Hub \u5730\u5740\uFF0C\u5982 http://10.0.0.5:7891" style="flex:1;min-width:240px">
|
|
521
|
+
<input id="tm-code" placeholder="\u9080\u8BF7\u7801" style="min-width:160px">
|
|
522
|
+
<button id="tm-join" class="primary">\u52A0\u5165</button>
|
|
523
|
+
</p>
|
|
524
|
+
<div id="tm-join-out" style="display:none;margin-top:6px"></div>
|
|
525
|
+
</div>
|
|
526
|
+
</section>`}async function et(){let t=(await Re("/api/team/hosted")).body,n=B("tm-list");xe=t?.suggestedHubUrl||xe;let s=t?.teams||[];if(!s.length){n.innerHTML='<p class="muted">\u8FD8\u6CA1\u6709\u56E2\u961F\u3002</p>';return}n.innerHTML=s.map(a=>{let r=(a.deployments||[]).filter(i=>!i.local).length;return`<div class="card" style="margin:0 0 8px;padding:10px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
527
|
+
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
528
|
+
<b>${d(a.name)}</b>${a.isDefault?' <span class="muted" style="font-size:12px">\u9ED8\u8BA4</span>':""}
|
|
529
|
+
<span class="muted" style="font-size:12px">\xB7 ${(a.deployments||[]).length} \u4E2A\u90E8\u7F72${r?`\uFF08\u542B ${r} \u8FDC\u7AEF\uFF09`:""} \xB7 ${(a.bots||[]).length} \u4E2A\u673A\u5668\u4EBA</span>
|
|
530
|
+
<span style="margin-left:auto;display:flex;gap:6px">
|
|
531
|
+
<button class="tm-invite ghost" data-team="${d(a.teamId)}" style="font-size:12px">\u751F\u6210\u9080\u8BF7\u7801</button>
|
|
532
|
+
${a.isDefault?"":`<button class="tm-del ghost" data-team="${d(a.teamId)}" data-name="${d(a.name)}" style="font-size:12px">\u5220\u9664</button>`}
|
|
533
|
+
</span>
|
|
534
|
+
</div>
|
|
535
|
+
<div class="tm-inv-out" data-team="${d(a.teamId)}" style="display:none;margin-top:6px;font-size:13px"></div></div>`}).join(""),n.querySelectorAll(".tm-invite").forEach(a=>{a.onclick=async()=>{let r=a.dataset.team,i=n.querySelector(`.tm-inv-out[data-team="${CSS.escape(r)}"]`);i.style.display="",i.innerHTML='<span class="muted">\u751F\u6210\u4E2D\u2026</span>';let m=await ue("/api/team/local-invite",{teamId:r});m.body?.code?i.innerHTML=`\u628A\u4E0B\u9762\u4E24\u9879\u53D1\u7ED9<b>\u522B\u7684\u90E8\u7F72</b>\u7684\u4EBA\uFF0824 \u5C0F\u65F6\u5185\u3001\u5355\u6B21\u6709\u6548\uFF09\uFF1A<br>Hub \u5730\u5740\uFF1A<code>${d(xe)}</code><br>\u9080\u8BF7\u7801\uFF1A<code style="font-size:15px">${d(m.body.code)}</code>`:i.innerHTML='<span class="err">\u751F\u6210\u5931\u8D25\u3002</span>'}}),n.querySelectorAll(".tm-del").forEach(a=>{a.onclick=async()=>{confirm(`\u5220\u9664\u56E2\u961F\u300C${a.dataset.name}\u300D\uFF1F\u5DF2\u52A0\u5165\u5B83\u7684\u90E8\u7F72\u4F1A\u88AB\u79FB\u9664\uFF08\u4E0D\u5F71\u54CD\u4ED6\u4EEC\u81EA\u5DF1\u7684\u90E8\u7F72\uFF09\u3002`)&&(await De("DELETE","/api/team/hosted/"+encodeURIComponent(a.dataset.team)),et())}})}function Pt(e){e.innerHTML=zn(),B("tm-create").onclick=async()=>{let t=B("tm-newname").value.trim(),n=e.querySelector(".tm-cout");if(!t){n.innerHTML='<span class="err">\u8BF7\u586B\u56E2\u961F\u540D\u79F0</span>';return}n.innerHTML='<span class="muted">\u521B\u5EFA\u4E2D\u2026</span>';let s=await ue("/api/team/hosted",{name:t});s.body?.ok?(n.innerHTML='<span class="ok">\u5DF2\u521B\u5EFA</span>',B("tm-newname").value="",et()):n.innerHTML=`<span class="err">\u521B\u5EFA\u5931\u8D25\uFF1A${d(String(s.body?.error||s.status))}</span>`},B("tm-join").onclick=async()=>{let t=B("tm-hub").value.trim(),n=B("tm-code").value.trim(),s=B("tm-join-out");if(s.style.display="",!t||!n){s.innerHTML='<span class="err">\u8BF7\u586B Hub \u5730\u5740\u548C\u9080\u8BF7\u7801\u3002</span>';return}s.innerHTML='<span class="muted">\u52A0\u5165\u4E2D\u2026</span>';let a=await ue("/api/team/join-remote",{hubUrl:t,inviteCode:n});if(a.body?.ok)s.innerHTML=`<span class="ok">\u5DF2\u52A0\u5165\u300C${d(a.body.teamName||"")}\u300D\uFF0C\u53BB\u300C\u6211\u7684\u56E2\u961F\u300D\u67E5\u770B\u3002</span>`,B("tm-code").value="";else{let r=a.body?.error||a.status,i=r==="cannot_join_self"?"\u8FD9\u662F\u4F60\u81EA\u5DF1\u7684\u90E8\u7F72\uFF0C\u4E0D\u80FD\u52A0\u5165\u81EA\u5DF1\uFF08\u9080\u8BF7\u7801\u8981\u53D1\u7ED9\u522B\u7684\u90E8\u7F72\u7684\u4EBA\u7528\uFF09":r==="deployment_already_joined"?"\u4F60\u7684\u90E8\u7F72\u5DF2\u7ECF\u52A0\u5165\u8FC7\u8FD9\u4E2A\u56E2\u961F\u4E86":r==="hub_unreachable"?"\u8FDE\u4E0D\u4E0A\u5BF9\u65B9 Hub\uFF08\u68C0\u67E5\u5730\u5740/\u7F51\u7EDC\uFF09":r==="hub_timeout"?"\u5BF9\u65B9 Hub \u54CD\u5E94\u8D85\u65F6":`\u52A0\u5165\u5931\u8D25\uFF1A${r}`;s.innerHTML=`<span class="err">${d(String(i))}</span>`}},et()}function Jn(){B("tf-autobind").onclick=async()=>{let e=B("tf-bind-out");e.style.display="",e.innerHTML='<span class="muted">\u8BC6\u522B\u4E2D\u2026</span>';let n=(await ue("/api/team/identity/auto-bind")).body;if(n?.ok&&n.owner){e.innerHTML=`<span class="ok">\u5DF2\u7ED1\u5B9A\uFF1A${d(n.owner.name||n.owner.unionId)}</span>`,ge();return}if(n?.ok&&n.needChoice&&Array.isArray(n.candidates)){let s=n.candidates.map(a=>`<button class="tf-pickowner ghost" data-union="${d(a.unionId)}" style="margin:2px">${d(a.name||a.unionId)}</button>`).join(" ");e.innerHTML=`\u8BC6\u522B\u5230\u591A\u4E2A\u5019\u9009\uFF0C\u70B9\u4F60\u81EA\u5DF1\uFF1A<br>${s}`,e.querySelectorAll(".tf-pickowner").forEach(a=>{a.onclick=async()=>{e.innerHTML='<span class="muted">\u7ED1\u5B9A\u4E2D\u2026</span>';let i=(await ue("/api/team/identity/auto-bind",{unionId:a.dataset.union})).body;i?.ok&&i.owner?(e.innerHTML=`<span class="ok">\u5DF2\u7ED1\u5B9A\uFF1A${d(i.owner.name||i.owner.unionId)}</span>`,ge()):e.innerHTML=`<span class="err">\u7ED1\u5B9A\u5931\u8D25\uFF1A${d(String(i?.error||"unknown"))}</span>`}});return}if(n?.error==="no_candidates"){e.innerHTML='<span class="err">\u6CA1\u8BC6\u522B\u5230\u8EAB\u4EFD\uFF1A\u8BF7\u786E\u8BA4\u673A\u5668\u4EBA\u914D\u7F6E\u4E86 allowedUsers\uFF08\u5141\u8BB8\u4F7F\u7528\u8005\uFF09\uFF0C\u4E14\u673A\u5668\u4EBA\u6709\u901A\u8BAF\u5F55\u6743\u9650\u3002</span>';return}e.innerHTML=`<span class="err">\u7ED1\u5B9A\u5931\u8D25\uFF1A${d(String(n?.error||"unknown"))}</span>`}}async function Nt(e){let t=await fetch(e);return{status:t.status,body:await t.json().catch(()=>({}))}}async function nt(e,t,n){let s=await fetch(t,{method:e,headers:{"content-type":"application/json"},body:n?JSON.stringify(n):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}function _(e){return document.getElementById(e)}function K(e){return(_(e).value||"").trim()}var ot=[];function Gn(){return`<section class="page">
|
|
536
|
+
<div class="page-heading">
|
|
537
|
+
<div>
|
|
538
|
+
<p class="eyebrow">\u63A5\u5165\u70B9 \xB7 beta</p>
|
|
539
|
+
<h1>\u63A5\u5165\u70B9\uFF08Webhook\uFF09<span class="muted" style="font-size:14px;font-weight:400">beta</span></h1>
|
|
540
|
+
<p>\u8BA9\u5916\u90E8\u7CFB\u7EDF\uFF08\u76D1\u63A7\u544A\u8B66\u3001CI\u3001\u5DE5\u5355\u2026\uFF09\u901A\u8FC7\u4E00\u4E2A webhook \u89E6\u53D1\u673A\u5668\u4EBA\u5728\u7FA4\u91CC\u8BF4\u8BDD\u6216\u8DD1\u5DE5\u4F5C\u6D41\u3002<span class="muted">\uFF08beta\uFF1A\u5C1A\u672A\u5145\u5206\u6D4B\u8BD5\uFF0C\u6B22\u8FCE\u53CD\u9988\uFF09</span></p>
|
|
541
|
+
</div>
|
|
542
|
+
</div>
|
|
543
|
+
|
|
544
|
+
<div class="card" style="margin-bottom:16px">
|
|
545
|
+
<h2 style="margin-top:0">\u65B0\u5EFA\u63A5\u5165\u70B9</h2>
|
|
546
|
+
<div class="cn-form" style="display:grid;grid-template-columns:140px 1fr;gap:10px 14px;align-items:center;max-width:680px">
|
|
547
|
+
<label>\u540D\u79F0</label><input id="cn-name" placeholder="\u5982\uFF1A\u7EBF\u4E0A\u544A\u8B66">
|
|
548
|
+
<label>\u89E6\u53D1\u7684\u673A\u5668\u4EBA</label><select id="cn-bot"></select>
|
|
549
|
+
<label>\u89E6\u53D1\u65B9\u5F0F</label>
|
|
550
|
+
<select id="cn-kind"><option value="turn">\u5355\u8F6E\u5BF9\u8BDD\uFF08\u8BA9\u673A\u5668\u4EBA\u56DE\u5E94\u4E00\u6B21\uFF09</option><option value="workflow">\u5DE5\u4F5C\u6D41</option></select>
|
|
551
|
+
<label class="cn-wf" style="display:none">\u5DE5\u4F5C\u6D41 ID</label><input class="cn-wf" id="cn-wf" style="display:none" placeholder="workflowId">
|
|
552
|
+
<label>\u6295\u9012\u5230\u54EA\u4E2A\u7FA4</label>
|
|
553
|
+
<select id="cn-mode">
|
|
554
|
+
<option value="dynamic">\u7531\u8BF7\u6C42\u6307\u5B9A\uFF08\u7FA4 ID \u968F\u8BF7\u6C42\u4F20\u5165\uFF09</option>
|
|
555
|
+
<option value="fixed">\u56FA\u5B9A\u7FA4</option>
|
|
556
|
+
<option value="new-group">\u6BCF\u6B21\u65B0\u5EFA\u7FA4</option>
|
|
557
|
+
</select>
|
|
558
|
+
<label class="cn-fixed" style="display:none">\u7FA4 ID</label><input class="cn-fixed" id="cn-chat" style="display:none" placeholder="oc_\u2026">
|
|
559
|
+
<label class="cn-allow">\u5141\u8BB8\u7684\u7FA4<span class="muted" style="font-weight:400">\uFF08\u53EF\u9009\uFF09</span></label>
|
|
560
|
+
<input class="cn-allow" id="cn-allow" placeholder="oc_xxx,oc_yyy\uFF08\u9017\u53F7\u5206\u9694\uFF0C\u7559\u7A7A=\u4E0D\u9650\uFF09">
|
|
561
|
+
<label class="cn-life" style="display:none">\u53BB\u91CD\u5B57\u6BB5</label><input class="cn-life" id="cn-dedup" style="display:none" placeholder="\u5982 payload.alert.id">
|
|
562
|
+
<label class="cn-life" style="display:none">\u72B6\u6001\u5B57\u6BB5</label><input class="cn-life" id="cn-status" style="display:none" placeholder="\u5982 payload.status">
|
|
563
|
+
<label>\u7B7E\u540D\u5BC6\u94A5</label><input id="cn-secret" placeholder="\u7559\u7A7A\u81EA\u52A8\u751F\u6210\uFF08\u53EA\u663E\u793A\u4E00\u6B21\uFF09">
|
|
564
|
+
</div>
|
|
565
|
+
<div style="margin-top:14px"><button id="cn-create" class="primary">\u521B\u5EFA</button>
|
|
566
|
+
<span class="muted" id="cn-create-out" style="margin-left:10px;font-size:13px"></span></div>
|
|
567
|
+
<div id="cn-created" style="display:none;margin-top:12px"></div>
|
|
568
|
+
</div>
|
|
569
|
+
|
|
570
|
+
<div class="card">
|
|
571
|
+
<h2 style="margin-top:0">\u5DF2\u6709\u63A5\u5165\u70B9 <span class="muted" id="cn-count" style="font-size:13px"></span></h2>
|
|
572
|
+
<div id="cn-list">\u52A0\u8F7D\u4E2D\u2026</div>
|
|
573
|
+
</div>
|
|
574
|
+
</section>`}function tt(){let e=_("cn-kind").value,t=_("cn-mode").value;document.querySelectorAll(".cn-wf").forEach(n=>{n.style.display=e==="workflow"?"":"none"}),document.querySelectorAll(".cn-fixed").forEach(n=>{n.style.display=t==="fixed"?"":"none"}),document.querySelectorAll(".cn-allow").forEach(n=>{n.style.display=t==="fixed"?"none":""}),document.querySelectorAll(".cn-life").forEach(n=>{n.style.display=t==="new-group"?"":"none"})}function jt(e){return`${location.origin}/webhook/${encodeURIComponent(e)}`}function Kn(e){return e==="fixed"?"\u56FA\u5B9A\u7FA4":e==="new-group"?"\u6BCF\u6B21\u65B0\u5EFA\u7FA4":"\u8BF7\u6C42\u6307\u5B9A\u7FA4"}function Vn(e){return e==="workflow"?"\u5DE5\u4F5C\u6D41":"\u5355\u8F6E"}function Yn(e){let t=_("cn-list");if(_("cn-count").textContent=e.length?`\xB7 ${e.length} \u4E2A`:"",!e.length){t.innerHTML='<p class="muted">\u8FD8\u6CA1\u6709\u63A5\u5165\u70B9\u3002\u7528\u4E0A\u9762\u7684\u8868\u5355\u521B\u5EFA\u4E00\u4E2A\u3002</p>';return}t.innerHTML=e.map(n=>{let s=ot.find(r=>r.larkAppId===n.target.botId),a=jt(n.id);return`<div class="card" style="margin:0 0 10px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
575
|
+
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
576
|
+
<b style="font-size:15px">${d(n.name)}</b>
|
|
577
|
+
<span class="${n.enabled?"ok":"muted"}" style="font-size:12px">${n.enabled?"\u5DF2\u542F\u7528":"\u5DF2\u505C\u7528"}</span>
|
|
578
|
+
<span class="muted" style="font-size:12px">\xB7 ${d(s?.botName||n.target.botId)} \xB7 ${Vn(n.target.kind)} \xB7 ${Kn(n.target.mode)}</span>
|
|
579
|
+
<span style="margin-left:auto;display:flex;gap:6px">
|
|
580
|
+
<button class="cn-toggle ghost" data-id="${d(n.id)}" data-on="${n.enabled}" style="font-size:12px">${n.enabled?"\u505C\u7528":"\u542F\u7528"}</button>
|
|
581
|
+
<button class="cn-del ghost" data-id="${d(n.id)}" style="font-size:12px">\u5220\u9664</button>
|
|
582
|
+
</span>
|
|
583
|
+
</div>
|
|
584
|
+
<div style="margin-top:6px;font-size:13px;display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
585
|
+
<span class="muted">Webhook URL\uFF1A</span><code style="font-size:12px;word-break:break-all">${d(a)}</code>
|
|
586
|
+
<button class="cn-copy ghost" data-url="${d(a)}" style="font-size:12px">\u590D\u5236</button>
|
|
587
|
+
</div></div>`}).join(""),t.querySelectorAll(".cn-copy").forEach(n=>{n.onclick=()=>{navigator.clipboard?.writeText(n.dataset.url),n.textContent="\u5DF2\u590D\u5236",setTimeout(()=>n.textContent="\u590D\u5236",1200)}}),t.querySelectorAll(".cn-toggle").forEach(n=>{n.onclick=async()=>{await nt("PATCH","/api/connectors/"+encodeURIComponent(n.dataset.id),{enabled:n.dataset.on!=="true"}),Oe()}}),t.querySelectorAll(".cn-del").forEach(n=>{n.onclick=async()=>{confirm("\u5220\u9664\u8FD9\u4E2A\u63A5\u5165\u70B9\uFF1F\u5B83\u7684 webhook URL \u4F1A\u7ACB\u5373\u5931\u6548\u3002")&&(await nt("DELETE","/api/connectors/"+encodeURIComponent(n.dataset.id)),Oe())}})}async function Oe(){let[e,t]=await Promise.all([Nt("/api/bots"),Nt("/api/connectors")]);ot=(e.body?.bots||[]).map(a=>({larkAppId:a.larkAppId,botName:a.botName||a.larkAppId}));let n=_("cn-bot"),s=n.value;n.innerHTML=ot.map(a=>`<option value="${d(a.larkAppId)}">${d(a.botName)}</option>`).join("")||'<option value="">\uFF08\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF09</option>',s&&(n.value=s),Yn(t.body?.connectors||[])}function Ut(e){e.innerHTML=Gn(),_("cn-kind").onchange=tt,_("cn-mode").onchange=tt,tt(),_("cn-create").onclick=async()=>{let t=_("cn-create-out"),n=K("cn-name"),s=_("cn-bot").value;if(!n){t.innerHTML='<span class="err">\u8BF7\u586B\u540D\u79F0</span>';return}if(!s){t.innerHTML='<span class="err">\u8BF7\u9009\u673A\u5668\u4EBA</span>';return}let a=_("cn-kind").value,r=_("cn-mode").value,i={name:n,enabled:!0,target:{kind:a,mode:r,botId:s},promptEnvelope:{sourceName:n}};if(a==="workflow"){if(!K("cn-wf")){t.innerHTML='<span class="err">\u8BF7\u586B\u5DE5\u4F5C\u6D41 ID</span>';return}i.target.workflowId=K("cn-wf")}if(r==="fixed"){if(!K("cn-chat")){t.innerHTML='<span class="err">\u56FA\u5B9A\u7FA4\u9700\u8981\u586B\u7FA4 ID</span>';return}i.target.chatId=K("cn-chat")}else{let $=K("cn-allow");$&&(i.target.allowChats=$.split(",").map(p=>p.trim()).filter(Boolean))}if(r==="new-group"){if(!K("cn-dedup")||!K("cn-status")){t.innerHTML='<span class="err">\u300C\u6BCF\u6B21\u65B0\u5EFA\u7FA4\u300D\u9700\u8981\u586B\u53BB\u91CD\u5B57\u6BB5\u548C\u72B6\u6001\u5B57\u6BB5</span>';return}i.lifecycleExtractors={dedupKey:K("cn-dedup"),status:K("cn-status")}}let m=K("cn-secret");m&&(i.secret=m),t.innerHTML='<span class="muted">\u521B\u5EFA\u4E2D\u2026</span>';let k=await nt("POST","/api/connectors",i);if(k.status===201&&k.body?.ok){t.innerHTML="";let $=_("cn-created");$.style.display="";let p=k.body.webhookUrl||jt(k.body.connector.id),g=k.body.secret;$.innerHTML=`<div class="card" style="padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
588
|
+
<p class="ok" style="margin:0 0 6px">\u5DF2\u521B\u5EFA\u300C${d(n)}\u300D</p>
|
|
589
|
+
<p style="margin:4px 0;font-size:13px"><span class="muted">Webhook URL\uFF1A</span><code style="word-break:break-all">${d(p)}</code></p>
|
|
590
|
+
${g?`<p style="margin:4px 0;font-size:13px"><span class="muted">\u7B7E\u540D\u5BC6\u94A5\uFF08\u53EA\u663E\u793A\u8FD9\u4E00\u6B21\uFF0C\u8BF7\u4FDD\u5B58\uFF09\uFF1A</span><code>${d(g)}</code></p>`:""}
|
|
591
|
+
<p class="muted" style="font-size:12px;margin:6px 0 0">\u5916\u90E8\u7CFB\u7EDF\u7528\u6B64 URL + \u5BC6\u94A5\uFF08HMAC-SHA256 \u7B7E\u540D\uFF09\u8C03\u7528\u5373\u53EF\u89E6\u53D1\u3002</p></div>`,["cn-name","cn-wf","cn-chat","cn-allow","cn-dedup","cn-status","cn-secret"].forEach(l=>{_(l).value=""}),Oe()}else{let $=k.body?.error||k.status;t.innerHTML=`<span class="err">\u521B\u5EFA\u5931\u8D25\uFF1A${d(String($))}</span>`}},Oe()}function Qn(){let e=[["",o("workflow.filter.nonTerminal")],["all",o("workflow.filter.all")],["pending",le("pending")],["running",le("running")],["waiting",le("waiting")],["succeeded",le("succeeded")],["failed",le("failed")],["cancelled",le("cancelled")]];return`
|
|
428
592
|
<nav class="wf-subnav">
|
|
429
|
-
<a href="#/workflows" class="active" data-i18n="workflow.subnav.runs">${
|
|
430
|
-
<a href="#/workflows/catalog" data-i18n="workflow.subnav.catalog">${
|
|
593
|
+
<a href="#/workflows" class="active" data-i18n="workflow.subnav.runs">${c(o("workflow.subnav.runs"))}</a>
|
|
594
|
+
<a href="#/workflows/catalog" data-i18n="workflow.subnav.catalog">${c(o("workflow.subnav.catalog"))}</a>
|
|
431
595
|
</nav>
|
|
432
596
|
<form id="wf-filters" class="filters">
|
|
433
|
-
<input type="search" name="q" placeholder="${
|
|
597
|
+
<input type="search" name="q" placeholder="${c(o("workflow.searchPlaceholder"))}" />
|
|
434
598
|
<select name="status">
|
|
435
|
-
${e.map(([t,
|
|
599
|
+
${e.map(([t,n])=>`<option value="${c(t)}">${c(n)}</option>`).join("")}
|
|
436
600
|
</select>
|
|
437
601
|
<span id="wf-last-load" class="muted"></span>
|
|
438
602
|
</form>
|
|
439
603
|
<table>
|
|
440
604
|
<thead><tr>
|
|
441
|
-
<th>${
|
|
442
|
-
<th>${
|
|
443
|
-
<th>${
|
|
605
|
+
<th>${c(o("workflow.table.run"))}</th><th>${c(o("workflow.table.workflow"))}</th><th>${c(o("workflow.table.status"))}</th>
|
|
606
|
+
<th>${c(o("workflow.table.lastSeq"))}</th><th>${c(o("workflow.table.dangling"))}</th><th>${c(o("workflow.table.updated"))}</th>
|
|
607
|
+
<th>${c(o("workflow.table.chatApp"))}</th>
|
|
444
608
|
</tr></thead>
|
|
445
609
|
<tbody id="wf-tbody"></tbody>
|
|
446
610
|
</table>
|
|
447
|
-
`}var
|
|
448
|
-
<td><a href="#/workflows/${encodeURIComponent(
|
|
449
|
-
<td>${
|
|
450
|
-
<td>${
|
|
451
|
-
<td>${
|
|
452
|
-
<td class="${
|
|
453
|
-
<td title="${
|
|
454
|
-
<td>${
|
|
455
|
-
</tr>`}).join("")}function
|
|
611
|
+
`}var Xn=5e3,Zn=2e3,ke=new Set(["succeeded","failed","cancelled"]);function c(e){return e.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function eo(e){let t=new Date(e),s=Date.now()-e;return s<6e4?o("time.secondsAgo",{value:Math.max(1,Math.floor(s/1e3))}):s<36e5?o("time.minutesAgo",{value:Math.floor(s/6e4)}):s<864e5?o("time.hoursAgo",{value:Math.floor(s/36e5)}):t.toISOString().slice(0,19).replace("T"," ")}function ne(e){return`<span class="${ke.has(e)?"wf-status terminal":"wf-status live"} wf-status-${c(e)}">${c(le(e))}</span>`}function le(e){let t=`workflow.status.${e}`,n=o(t);return n===t?e:n}function zt(e){let t=location.hash.match(/^#\/workflows\/([^?#]+)(?:\?([^#]*))?$/);if(t){let n=new URLSearchParams(t[2]??"");return no(e,decodeURIComponent(t[1]),{focusAttemptId:n.get("attempt")??void 0})}return to(e)}function to(e){e.innerHTML=Qn();let t=e.querySelector("#wf-tbody"),n=e.querySelector("#wf-filters"),s=e.querySelector("#wf-last-load"),a=[],r=null,i=!1,m=null,k=!1;function $(b){let T=(new FormData(n).get("q")??"").trim().toLowerCase();return T?b.filter(S=>S.runId.toLowerCase().includes(T)||S.workflowId.toLowerCase().includes(T)||(S.chatId??"").toLowerCase().includes(T)):b}function p(){let b=$(a);if(b.length===0){t.innerHTML=`<tr><td colspan="7" class="empty">${m?c(o("workflow.list.failedLoad",{error:m})):a.length===0?c(o("workflow.list.noRuns")):c(o("workflow.list.noFilterMatch"))}</td></tr>`;return}t.innerHTML=b.map(f=>{let T=`${f.dEf}/${f.dAct}/${f.dWait}`,S=f.dEf+f.dAct+f.dWait>0?"wf-dangling has":"wf-dangling none",y=[];f.chatId&&y.push(c(f.chatId)),f.larkAppId&&y.push(`<span class="muted">${c(f.larkAppId)}</span>`);let H=y.length>0?y.join("<br/>"):"\u2014",u=ao(f);return`<tr data-runid="${c(f.runId)}">
|
|
612
|
+
<td><a href="#/workflows/${encodeURIComponent(f.runId)}"><code>${c(f.runId)}</code></a></td>
|
|
613
|
+
<td>${c(f.workflowId)}</td>
|
|
614
|
+
<td>${ne(f.status)}${f.failedNodeId?` <span class="muted">(${c(f.failedNodeId)})</span>`:""}${u}</td>
|
|
615
|
+
<td>${f.lastSeq}</td>
|
|
616
|
+
<td class="${S}">${T}</td>
|
|
617
|
+
<td title="${c(new Date(f.updatedAt).toISOString())}">${eo(f.updatedAt)}</td>
|
|
618
|
+
<td>${H}</td>
|
|
619
|
+
</tr>`}).join("")}function g(){m?(s.textContent=o("workflow.list.error",{error:m}),s.classList.add("error")):(s.textContent=o("workflow.list.loaded",{count:a.length,time:new Date().toLocaleTimeString()}),s.classList.remove("error"))}async function l(){if(!(k||i)&&!document.hidden){i=!0;try{let b=n.elements.namedItem("status")?.value??"",f=new URLSearchParams;b==="all"?f.set("all","1"):b&&f.set("status",b);let T="/api/workflows/runs"+(f.toString()?`?${f}`:""),S=await fetch(T);S.ok?(a=(await S.json()).runs??[],m=null):(m=`HTTP ${S.status}`,a=[])}catch(b){m=b?.message??String(b),a=[]}finally{i=!1,k||(p(),g())}}}function I(){r!==null&&window.clearTimeout(r),r=window.setTimeout(async()=>{await l(),k||I()},Xn)}function L(){document.hidden||l()}return n.addEventListener("input",()=>{p()}),n.addEventListener("change",b=>{b.target.getAttribute("name")==="status"&&l()}),document.addEventListener("visibilitychange",L),l().then(()=>{k||I()}),()=>{k=!0,r!==null&&window.clearTimeout(r),document.removeEventListener("visibilitychange",L)}}function no(e,t,n={}){e.innerHTML=`
|
|
456
620
|
<div class="wf-detail-head">
|
|
457
|
-
<a class="btn-link" href="#/workflows">${
|
|
621
|
+
<a class="btn-link" href="#/workflows">${c(o("workflow.detail.back"))}</a>
|
|
458
622
|
<div>
|
|
459
|
-
<h2><code>${
|
|
460
|
-
<div id="wf-detail-subtitle" class="muted">${
|
|
623
|
+
<h2><code>${c(t)}</code></h2>
|
|
624
|
+
<div id="wf-detail-subtitle" class="muted">${c(o("workflow.detail.loading"))}</div>
|
|
461
625
|
</div>
|
|
462
|
-
<button id="wf-cancel-run" type="button" class="contrast" hidden>${
|
|
626
|
+
<button id="wf-cancel-run" type="button" class="contrast" hidden>${c(o("workflow.detail.cancel"))}</button>
|
|
463
627
|
<span id="wf-detail-refresh" class="muted"></span>
|
|
464
628
|
</div>
|
|
465
629
|
<section id="wf-detail-error" class="hint-warn" hidden></section>
|
|
@@ -468,20 +632,20 @@ ${u.join(`
|
|
|
468
632
|
<section id="wf-dangling-panel"></section>
|
|
469
633
|
<section class="wf-panel">
|
|
470
634
|
<div class="wf-panel-title">
|
|
471
|
-
<h3>${
|
|
635
|
+
<h3>${c(o("workflow.detail.parallel"))}</h3>
|
|
472
636
|
<span id="wf-parallel-meta" class="muted"></span>
|
|
473
637
|
</div>
|
|
474
638
|
<div id="wf-parallel-view"></div>
|
|
475
639
|
</section>
|
|
476
640
|
<section class="wf-panel">
|
|
477
641
|
<div class="wf-panel-title">
|
|
478
|
-
<h3>${
|
|
642
|
+
<h3>${c(o("workflow.detail.nodes"))}</h3>
|
|
479
643
|
</div>
|
|
480
644
|
<div class="wf-table-scroll">
|
|
481
645
|
<table>
|
|
482
646
|
<thead><tr>
|
|
483
|
-
<th>${
|
|
484
|
-
<th>${
|
|
647
|
+
<th>${c(o("workflow.detail.node"))}</th><th>${c(o("workflow.detail.nodeStatus"))}</th><th>${c(o("workflow.detail.activity"))}</th><th>${c(o("workflow.detail.activityStatus"))}</th>
|
|
648
|
+
<th>${c(o("workflow.detail.attempts"))}</th><th>${c(o("workflow.detail.current"))}</th><th>${c(o("workflow.detail.detail"))}</th>
|
|
485
649
|
</tr></thead>
|
|
486
650
|
<tbody id="wf-node-tbody"></tbody>
|
|
487
651
|
</table>
|
|
@@ -489,237 +653,237 @@ ${u.join(`
|
|
|
489
653
|
</section>
|
|
490
654
|
<section class="wf-panel">
|
|
491
655
|
<div class="wf-panel-title">
|
|
492
|
-
<h3>${
|
|
656
|
+
<h3>${c(o("workflow.detail.nodeIO"))}</h3>
|
|
493
657
|
</div>
|
|
494
658
|
<div id="wf-io-list" class="wf-io-list"></div>
|
|
495
659
|
</section>
|
|
496
660
|
<section class="wf-panel">
|
|
497
661
|
<div class="wf-panel-title">
|
|
498
|
-
<h3>${
|
|
499
|
-
<button id="wf-load-older" type="button" hidden>${
|
|
662
|
+
<h3>${c(o("workflow.detail.timeline"))}</h3>
|
|
663
|
+
<button id="wf-load-older" type="button" hidden>${c(o("workflow.detail.loadOlder"))}</button>
|
|
500
664
|
</div>
|
|
501
665
|
<div class="wf-table-scroll wf-timeline-scroll">
|
|
502
666
|
<table>
|
|
503
667
|
<thead><tr>
|
|
504
|
-
<th>${
|
|
668
|
+
<th>${c(o("workflow.detail.seq"))}</th><th>${c(o("workflow.detail.event"))}</th><th>${c(o("workflow.detail.actor"))}</th><th>${c(o("workflow.detail.node"))}</th><th>${c(o("workflow.detail.activity"))}</th><th>${c(o("workflow.detail.error"))}</th><th>${c(o("workflow.detail.time"))}</th>
|
|
505
669
|
</tr></thead>
|
|
506
670
|
<tbody id="wf-event-tbody"></tbody>
|
|
507
671
|
</table>
|
|
508
672
|
</div>
|
|
509
673
|
<div id="wf-event-meta" class="muted"></div>
|
|
510
674
|
</section>
|
|
511
|
-
`;let
|
|
512
|
-
<span class="muted error">${
|
|
513
|
-
</div>`}function
|
|
675
|
+
`;let s=e.querySelector("#wf-detail-subtitle"),a=e.querySelector("#wf-detail-refresh"),r=e.querySelector("#wf-detail-error"),i=e.querySelector("#wf-cancel-status"),m=e.querySelector("#wf-summary"),k=e.querySelector("#wf-dangling-panel"),$=e.querySelector("#wf-parallel-view"),p=e.querySelector("#wf-parallel-meta"),g=e.querySelector("#wf-node-tbody"),l=e.querySelector("#wf-io-list"),I=e.querySelector(".wf-timeline-scroll"),L=e.querySelector("#wf-event-tbody"),b=e.querySelector("#wf-event-meta"),f=e.querySelector("#wf-cancel-run"),T=e.querySelector("#wf-load-older"),S=null,y=[],H=new Set,u=null,w=null,h=!1,E=0,M=null,A=!1,P=!1,O=!1,x=new Set,q=new Map,j=new Map,F=new Map,z=new Set,ee=new Map,te=new Set,he=new Map,ln=new Map,it=0,lt=n.focusAttemptId;function G(v){if(!v){r.hidden=!0,r.textContent="";return}r.hidden=!1,r.textContent=v}function dt(v){if(!v){i.hidden=!0,i.textContent="";return}i.hidden=!1,i.textContent=v}async function ct(){let v=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/snapshot`);if(v.status===404)throw new Error(o("workflow.detail.unknownRun"));if(!v.ok)throw new Error(o("workflow.detail.snapshotHttp",{status:v.status}));S=await v.json()}async function Te(v){let U=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/events?${v}`);if(U.status===404)throw new Error(o("workflow.detail.unknownRun"));if(!U.ok)throw new Error(o("workflow.detail.eventsHttp",{status:U.status}));return await U.json()}function Le(v,U){let D=v.filter(R=>H.has(R.eventId)?!1:(H.add(R.eventId),!0));D.length!==0&&(y=U==="prepend"?[...D,...y]:[...y,...D],y.sort((R,oe)=>$e(R.eventId)-$e(oe.eventId)))}async function dn(){await ct();let v=await Te(new URLSearchParams({tail:"100"}));y=[],H=new Set,Le(v.events,"append"),u=v.oldestSeq,w=v.newestSeq,h=v.hasOlder,E=v.totalCount,Y()}async function Ee(){if(!(A||P||document.hidden)){P=!0;try{if(await ct(),w!==null){let v=await Te(new URLSearchParams({afterSeq:String(w),limit:"200"}));Le(v.events,"append"),v.newestSeq!==null&&(w=v.newestSeq),u===null&&v.oldestSeq!==null&&(u=v.oldestSeq),E=v.totalCount}else{let v=await Te(new URLSearchParams({tail:"1"}));Le(v.events,"append"),u=v.oldestSeq,w=v.newestSeq,h=v.hasOlder,E=v.totalCount}G(null),Y()}catch(v){G(v?.message??String(v))}finally{P=!1}}}async function cn(){if(!(u===null||!h)){T.disabled=!0;try{let v=await Te(new URLSearchParams({beforeSeq:String(u),limit:"100"}));Le(v.events,"prepend"),v.oldestSeq!==null&&(u=v.oldestSeq),h=v.hasOlder,E=v.totalCount,G(null),Y()}catch(v){G(v?.message??String(v))}finally{T.disabled=!1}}}async function un(){if(!S||ke.has(S.run.status)||O)return;if(!S.chatBinding?.larkAppId){G(o("workflow.detail.cancelUnavailable",{runId:t}));return}let v=so(S),U=o("workflow.detail.cancelConfirm",{runId:t,...v});if(window.confirm(U)){O=!0,f.disabled=!0;try{let D=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/cancel`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"cancelled via dashboard"})});if(D.status===401)throw new Error(o("workflow.detail.writeAccessCancel"));let R=await D.json().catch(()=>({}));if(!D.ok||!R.ok)throw new Error(R.hint??R.error??o("workflow.detail.cancelHttp",{status:D.status}));dt(R.pending?o("workflow.detail.cancelPending"):null),G(null),await Ee()}catch(D){G(D?.message??String(D))}finally{O=!1,f.disabled=!1,Y()}}}async function pn(v,U){if(!te.has(v)){te.add(v),he.delete(v),Y();try{let D=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/attempts/${encodeURIComponent(U)}/${encodeURIComponent(v)}/resume`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({})});if(D.status===401)throw new Error(o("workflow.detail.writeAccessResume"));let R=await D.json().catch(()=>({}));if(!D.ok||!R.ok||!R.resumeId||!R.url)throw new Error(R.hint??R.message??R.error??o("workflow.detail.resumeStartFailed",{status:D.status}));ee.set(v,{resumeId:R.resumeId,url:R.url})}catch(D){let R=D?.message??String(D);he.set(v,R)}finally{te.delete(v),Y()}}}async function fn(v,U){if(!te.has(v)){te.add(v),he.delete(v),Y();try{let D=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/attempts/${encodeURIComponent(U)}/${encodeURIComponent(v)}/resume/end`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"ended_by_dashboard"})});if(D.status===401)throw new Error(o("workflow.detail.writeAccessResume"));let R=await D.json().catch(()=>({}));if(!D.ok||!R.ok)if(R.error==="resume_not_running")ee.delete(v);else throw new Error(R.hint??R.message??R.error??o("workflow.detail.resumeEndFailed",{status:D.status}));else ee.delete(v)}catch(D){let R=D?.message??String(D);he.set(v,R)}finally{te.delete(v),Y()}}}async function mn(v,U){if(!z.has(v)){z.add(v),F.delete(v),Y();try{let D=j.get(v)?.trim()||void 0,R=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/${U}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({comment:D})});if(R.status===401)throw new Error(o("workflow.detail.writeAccessApproval"));let oe=await R.json().catch(()=>({}));if(!R.ok||!oe.ok)throw new Error(oe.hint??oe.message??oe.error??o("workflow.detail.actionHttp",{action:U,status:R.status}));let _e=U==="approve"?o("workflow.detail.approved"):o("workflow.detail.rejected");F.set(v,{kind:"ok",text:oe.alreadyTerminal?o("workflow.detail.alreadyTerminal",{label:_e}):oe.pending?o("workflow.detail.workflowContinue",{label:_e}):o("workflow.detail.workflowRefreshing",{label:_e})}),G(null),await Ee()}catch(D){let R=D?.message??String(D);F.set(v,{kind:"error",text:R}),G(R)}finally{z.delete(v),Y()}}}function Y(){if(!S)return;it=I.scrollTop;let v=S.run;ke.has(v.status)&&dt(null),s.innerHTML=`${c(v.workflowId??"?")} \xB7 ${ne(v.status)} \xB7 lastSeq ${S.lastSeq}`,a.textContent=o("workflow.detail.refreshed",{time:new Date().toLocaleTimeString()}),f.hidden=ke.has(v.status),f.disabled=O||!S.chatBinding?.larkAppId,f.textContent=S.chatBinding?.larkAppId?o("workflow.detail.cancel"):o("workflow.detail.cliCancelOnly"),f.title=S.chatBinding?.larkAppId?o("workflow.detail.cancelTitle"):o("workflow.detail.cliCancelTitle",{runId:t}),oo(m,S),ro(k,S),io($,p,S,y),mo(g,S),wo(l,S,x,q,{comments:j,statuses:F,resolving:z,onResolve:mn},{sessions:ee,pending:te,errors:he,onStart:pn,onEnd:fn},lt,ln)&&(lt=void 0),Uo(L,y),I.scrollTop=it,T.hidden=!h,b.textContent=o("workflow.detail.eventsLoaded",{loaded:y.length,total:E})}function Fe(){if(M!==null&&window.clearTimeout(M),S&&ke.has(S.run.status)){M=null;return}M=window.setTimeout(async()=>{await Ee(),A||Fe()},Zn)}function ut(){document.hidden||Ee().then(()=>{!A&&M===null&&Fe()})}return T.addEventListener("click",()=>{cn()}),f.addEventListener("click",()=>{un()}),document.addEventListener("visibilitychange",ut),dn().then(()=>{G(null),A||Fe()}).catch(v=>{G(v?.message??String(v)),s.textContent=o("workflow.detail.loadFailed")}),()=>{A=!0,M!==null&&window.clearTimeout(M),document.removeEventListener("visibilitychange",ut)}}function oo(e,t){let n=t.run,s=[[o("workflow.summary.workflow"),c(n.workflowId??"?")],[o("workflow.summary.status"),ne(n.status)],[o("workflow.summary.lastSeq"),String(t.lastSeq)],[o("workflow.summary.updated"),c(new Date(t.updatedAt).toLocaleString())],[o("workflow.summary.revision"),c(Ne(n.revisionId))],[o("workflow.summary.initiator"),c(n.initiator??"-")]];n.failedNodeId&&s.push([o("workflow.summary.failedNode"),c(n.failedNodeId)]),n.cancelOriginEventId&&s.push([o("workflow.summary.cancelOrigin"),c(n.cancelOriginEventId)]),t.chatBinding&&(s.push([o("workflow.summary.chat"),`<code>${c(t.chatBinding.chatId)}</code>`]),s.push([o("workflow.summary.app"),`<code>${c(t.chatBinding.larkAppId)}</code>`])),e.innerHTML=s.map(([a,r])=>`<div class="wf-summary-item"><span>${a}</span><strong>${r}</strong></div>`).join("")}function ao(e){if(!e.errorCode)return"";let t=e.errorMessage?` \u2014 ${zo(e.errorMessage,96)}`:"";return`<div class="wf-run-error">
|
|
676
|
+
<span class="muted error">${c(e.errorCode)}</span>${c(t)}
|
|
677
|
+
</div>`}function so(e){let t=e.dangling;return{total:new Set([...t.activities,...t.effectAttempted,...t.waits,...t.cancels]).size,effects:t.effectAttempted.length,activities:t.activities.length,waits:t.waits.length,cancels:t.cancels.length}}function ro(e,t){let n=t.dangling,s=[[o("workflow.dangling.activities"),n.activities],[o("workflow.dangling.effects"),n.effectAttempted],[o("workflow.dangling.waits"),n.waits],[o("workflow.dangling.cancels"),n.cancels]],a=new Set(s.flatMap(([,r])=>r)).size;if(e.className=a>0?"wf-panel wf-dangling-panel has":"wf-panel wf-dangling-panel",a===0){e.innerHTML=`<div class="wf-panel-title"><h3>${c(o("workflow.detail.dangling"))}</h3></div><div class="muted">${c(o("workflow.detail.noDangling"))}</div>`;return}e.innerHTML=`<div class="wf-panel-title"><h3>${c(o("workflow.detail.dangling"))}</h3><span class="wf-dangling has">${a}</span></div>
|
|
514
678
|
<div class="wf-dangling-grid">
|
|
515
|
-
${
|
|
516
|
-
</div>`}function
|
|
517
|
-
<span title="${
|
|
518
|
-
<span title="${
|
|
679
|
+
${s.map(([r,i])=>`<div><strong>${r}</strong>${i.length===0?`<div class="muted">${c(o("workflow.detail.none"))}</div>`:`<ul>${i.map(m=>`<li><code>${c(m)}</code></li>`).join("")}</ul>`}</div>`).join("")}
|
|
680
|
+
</div>`}function io(e,t,n,s){let a=lo(s,n);if(a.length===0){t.textContent="",e.innerHTML=`<div class="empty">${c(o("workflow.detail.noParallelData"))}</div>`;return}let r=Date.now(),i=Math.min(...a.map(l=>l.startedAt)),m=Math.max(...a.map(l=>l.endedAt??r),i+1e3),k=Math.max(1,m-i),$=uo(a,r),p=a.filter(l=>!l.endedAt&&(l.status==="running"||l.status==="effectAttempting")).length;t.textContent=o("workflow.detail.parallelMeta",{count:a.length,max:$,running:p});let g=a.sort((l,I)=>l.startedAt-I.startedAt||l.activityId.localeCompare(I.activityId)).map(l=>co(l,i,k,r)).join("");e.innerHTML=`<div class="wf-parallel-axis">
|
|
681
|
+
<span title="${c(new Date(i).toISOString())}">${c(Pe(i))}</span>
|
|
682
|
+
<span title="${c(new Date(m).toISOString())}">${c(Pe(m))}</span>
|
|
519
683
|
</div>
|
|
520
|
-
<div class="wf-parallel-list">${
|
|
684
|
+
<div class="wf-parallel-list">${g}</div>`}function lo(e,t){let n=new Map,s=new Map(t.activities.map(a=>[a.activityId,a.ownerNodeId]));for(let a of[...e].sort((r,i)=>$e(r.eventId)-$e(i.eventId))){let r=Wo(a);if(!r)continue;let i=typeof r.activityId=="string"?r.activityId:void 0,m=typeof r.attemptId=="string"?r.attemptId:void 0;if(!i||!m)continue;let k=n.get(m);if(a.type==="attemptCreated"){let $=typeof r.attemptNumber=="number"?r.attemptNumber:void 0;k={nodeId:typeof r.nodeId=="string"?r.nodeId:s.get(i),activityId:i,attemptId:m,attemptNumber:$,status:"pending",startedAt:a.timestamp},n.set(m,k);continue}k||(k={nodeId:s.get(i),activityId:i,attemptId:m,status:"pending",startedAt:a.timestamp},n.set(m,k)),a.type==="activityRunning"?(k.status="running",k.runningAt=a.timestamp):a.type==="effectAttempted"?k.status="effectAttempting":a.type==="activityWaiting"||a.type==="waitCreated"?k.status="waiting":po(a.type)&&(k.status=fo(a.type),k.endedAt=a.timestamp,k.endType=a.type)}return[...n.values()]}function co(e,t,n,s){let a=e.endedAt??s,r=Wt((e.startedAt-t)/n*100,0,100),i=Wt((Math.max(a,e.startedAt+1)-e.startedAt)/n*100,.7,100-r),m=e.nodeId??e.activityId,k=e.attemptNumber!==void 0?`#${e.attemptNumber}`:Ne(e.attemptId),$=[`${m} ${e.status}`,`${new Date(e.startedAt).toISOString()} \u2192 ${e.endedAt?new Date(e.endedAt).toISOString():o("workflow.detail.parallelNow")}`,e.endType?`end: ${e.endType}`:void 0].filter(Boolean).join(`
|
|
521
685
|
`);return`<div class="wf-parallel-row">
|
|
522
686
|
<div class="wf-parallel-label">
|
|
523
|
-
<code>${
|
|
524
|
-
<span class="muted">${
|
|
687
|
+
<code>${c(m)}</code>
|
|
688
|
+
<span class="muted">${c(e.activityId)} \xB7 ${c(k)}</span>
|
|
525
689
|
</div>
|
|
526
690
|
<div class="wf-parallel-track">
|
|
527
|
-
<div class="wf-parallel-bar wf-parallel-${
|
|
528
|
-
<span>${
|
|
691
|
+
<div class="wf-parallel-bar wf-parallel-${c(e.status)}" style="left:${r.toFixed(3)}%;width:${i.toFixed(3)}%;" title="${c($)}">
|
|
692
|
+
<span>${c(le(e.status))}</span>
|
|
529
693
|
</div>
|
|
530
694
|
</div>
|
|
531
|
-
</div>`}function
|
|
532
|
-
<td>${e?`<code>${
|
|
533
|
-
<td>${e?
|
|
534
|
-
<td>${t?`<code>${
|
|
535
|
-
<td>${t?
|
|
695
|
+
</div>`}function uo(e,t){let n=[];for(let r of e)n.push({time:r.startedAt,delta:1}),n.push({time:r.endedAt??t,delta:-1});n.sort((r,i)=>r.time-i.time||i.delta-r.delta);let s=0,a=0;for(let r of n)s+=r.delta,a=Math.max(a,s);return a}function po(e){return e==="activitySucceeded"||e==="activityFailed"||e==="activityTimedOut"||e==="activityCanceled"}function fo(e){return e==="activitySucceeded"?"succeeded":e==="activityCanceled"?"cancelled":e==="activityTimedOut"?"timedOut":"failed"}function mo(e,t){let n=new Map(t.activities.map(r=>[r.activityId,r])),s=new Set,a=[];for(let r of t.nodes){let i=(r.activityId?n.get(r.activityId):void 0)??t.activities.find(m=>m.ownerNodeId===r.nodeId);i&&s.add(i.activityId),a.push(Ft(r,i))}for(let r of t.activities)s.has(r.activityId)||a.push(Ft(void 0,r));e.innerHTML=a.length>0?a.join(""):`<tr><td colspan="7" class="empty">${c(o("workflow.detail.noNodes"))}</td></tr>`}function Ft(e,t){let n=t?.attempts[t.attempts.length-1];return`<tr>
|
|
696
|
+
<td>${e?`<code>${c(e.nodeId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
697
|
+
<td>${e?ne(e.status):'<span class="muted">-</span>'}</td>
|
|
698
|
+
<td>${t?`<code>${c(t.activityId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
699
|
+
<td>${t?ne(t.status):'<span class="muted">-</span>'}</td>
|
|
536
700
|
<td>${t?.attempts.length??0}</td>
|
|
537
|
-
<td>${
|
|
538
|
-
<td>${
|
|
539
|
-
</tr>`}function
|
|
701
|
+
<td>${n?`<code>${c(n.attemptId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
702
|
+
<td>${n?jo(n):`<span class="muted">${c(o("workflow.detail.idle"))}</span>`}</td>
|
|
703
|
+
</tr>`}function wo(e,t,n,s,a,r,i,m){Do(e,n,s),Ho(e,a.comments);let k=!!(i&&t.attemptIO?.[i]?.terminal);k&&i&&n.add(at(i,o("workflow.detail.liveTerminal")));let $=go(t),p=new Set;if(m){for(let l of $){p.add(l.key);let I=m.get(l.key);I||(I=ho(l.key),m.set(l.key,I),e.appendChild(I.article)),bo(I,l,n,a,r,i)}for(let[l,I]of Array.from(m))p.has(l)||(I.article.remove(),m.delete(l));if($.length===0){if(!e.querySelector(".wf-io-empty-placeholder")){let l=document.createElement("div");l.className="empty wf-io-empty-placeholder",l.textContent=o("workflow.detail.noNodeIO"),e.appendChild(l)}}else e.querySelector(".wf-io-empty-placeholder")?.remove()}else{let l=[];for(let I of $)l.push(So(I,n,a,r,i));e.innerHTML=l.length>0?l.join(""):`<div class="empty">${c(o("workflow.detail.noNodeIO"))}</div>`}Oo(e,s);let g=Ro(e,i);return Bo(e,n),qo(e,s),Ao(e,a),en(e,r),g&&k}function go(e){let t=new Map(e.activities.map(a=>[a.activityId,a])),n=new Set,s=[];for(let a of e.nodes){let r=(a.activityId?t.get(a.activityId):void 0)??e.activities.find(i=>i.ownerNodeId===a.nodeId);if(!r){s.push({key:`node:${a.nodeId}`,node:a});continue}n.add(r.activityId),s.push({key:`activity:${r.activityId}`,node:a,activity:r,io:e.attemptIO?.[qe(r)?.attemptId??""]})}for(let a of e.activities)n.has(a.activityId)||s.push({key:`activity:${a.activityId}`,activity:a,io:e.attemptIO?.[qe(a)?.attemptId??""]});return s}function ho(e){let t=document.createElement("article");t.className="wf-io-card",t.dataset.wfCardKey=e;let n=document.createElement("div");n.className="wf-io-card-head";let s=document.createElement("div");s.className="wf-io-terminal-slot";let a=document.createElement("div");return a.className="wf-io-grid",t.appendChild(n),t.appendChild(s),t.appendChild(a),{article:t,head:n,terminalSlot:s,grid:a,currentTerminalUrl:null}}function bo(e,t,n,s,a,r){let i=qe(t.activity),m=t.node?.nodeId??t.activity?.ownerNodeId??t.activity?.activityId??"unknown",k=!!(i&&i.attemptId===r);e.article.classList.toggle("is-focused",k),i?e.article.dataset.wfAttemptCard=i.attemptId:delete e.article.dataset.wfAttemptCard;let $=Zt(i,s);e.head.innerHTML=`
|
|
540
704
|
<header>
|
|
541
705
|
<div>
|
|
542
|
-
<strong><code>${
|
|
543
|
-
<span class="muted">${t.activity?
|
|
706
|
+
<strong><code>${c(m)}</code></strong>
|
|
707
|
+
<span class="muted">${t.activity?c(t.activity.activityId):c(o("workflow.detail.notDispatched"))}</span>
|
|
544
708
|
</div>
|
|
545
|
-
<div>${t.node?
|
|
709
|
+
<div>${t.node?ne(t.node.status):""} ${t.activity?ne(t.activity.status):""}</div>
|
|
546
710
|
</header>
|
|
547
711
|
<div class="wf-io-meta">
|
|
548
|
-
${
|
|
712
|
+
${i?`${c(o("workflow.detail.attempt"))} <code>${c(i.attemptId)}</code>`:c(o("workflow.detail.noAttempt"))}
|
|
549
713
|
</div>
|
|
550
|
-
${
|
|
551
|
-
`;let
|
|
552
|
-
${
|
|
553
|
-
${
|
|
554
|
-
${
|
|
555
|
-
${
|
|
556
|
-
${t.io?.waitPrompt?
|
|
557
|
-
`}function
|
|
558
|
-
<summary>${
|
|
714
|
+
${$}
|
|
715
|
+
`;let p=Jt(i,t.activity,t.io?.terminal,a),g=p?.url??null;if(g!==e.currentTerminalUrl)p===null?e.terminalSlot.innerHTML="":e.terminalSlot.innerHTML=Gt(t.key,i,t.activity,t.io?.terminal,p,n,a),e.currentTerminalUrl=g;else if(p!==null&&t.io?.terminal){let I=e.terminalSlot.querySelector("details.wf-terminal-block > summary");if(I){let L=Kt(p.kind);I.innerHTML=`${c(L)} ${Xt(i,t.io.terminal)}`}i&&xo(e.terminalSlot,i,t.activity,t.io.terminal,p,a)}let l=i?.attemptId??t.activity?.activityId??t.node?.nodeId??"unknown";e.grid.innerHTML=`
|
|
716
|
+
${Z(l,o("workflow.detail.authoredInput"),t.io?.input,n)}
|
|
717
|
+
${Z(l,o("workflow.detail.resolvedInput"),t.io?.resolvedInput,n)}
|
|
718
|
+
${Z(l,o("workflow.detail.output"),t.io?.output,n)}
|
|
719
|
+
${Z(l,o("workflow.detail.executionLog"),t.io?.log,n)}
|
|
720
|
+
${t.io?.waitPrompt?Z(l,o("workflow.detail.waitPrompt"),t.io.waitPrompt,n):""}
|
|
721
|
+
`}function Jt(e,t,n,s){if(!n||n.error)return null;if(Io(e,n))return{kind:"live",url:Lo(n)};if(!e||!t||!To(e,n))return null;let a=Mo();if(!a)return null;let r=s?.sessions.get(e.attemptId);return r?{kind:"resume",url:r.url,resumeId:r.resumeId,downloadUrl:_t(a,t.activityId,e.attemptId)}:{kind:"replay",url:Eo(a,t.activityId,e.attemptId,!!n.hasPtyLog),downloadUrl:_t(a,t.activityId,e.attemptId)}}function Gt(e,t,n,s,a,r,i){if(!s)return"";let m=Kt(a.kind),k=at(e,m),$=Xt(t,s),p=yo(a.kind),g=a.kind==="replay"||a.kind==="resume"?`<a class="btn-link" href="${c(a.downloadUrl)}" download>${c(o("workflow.detail.downloadFullLog"))}</a>`:"",l=t?Yt(t,n,s,a,i):"",I=t?Qt(t.attemptId,i):"";return`<details class="wf-io-block wf-terminal-block" data-io-key="${c(k)}"${r.has(k)?" open":""}>
|
|
722
|
+
<summary>${c(m)} ${$}</summary>
|
|
559
723
|
<div class="wf-terminal-actions">
|
|
560
|
-
<a class="btn-link" href="${
|
|
561
|
-
${
|
|
724
|
+
<a class="btn-link" href="${c(a.url)}" target="_blank" rel="noreferrer">${c(p)}</a>
|
|
725
|
+
${g}
|
|
562
726
|
${l}
|
|
563
727
|
</div>
|
|
564
|
-
${
|
|
565
|
-
<iframe class="wf-terminal-frame" src="${
|
|
566
|
-
</details>`}function
|
|
728
|
+
${I}
|
|
729
|
+
<iframe class="wf-terminal-frame" src="${c(a.url)}" title="${c(m)}" loading="lazy"></iframe>
|
|
730
|
+
</details>`}function Kt(e){return e==="live"?o("workflow.detail.liveTerminal"):e==="resume"?o("workflow.detail.terminalResume"):o("workflow.detail.terminalReplay")}function yo(e){return e==="live"?o("workflow.detail.openTerminalNewTab"):e==="resume"?o("workflow.detail.openResumeNewTab"):o("workflow.detail.openReplayNewTab")}var Vt=new Set(["antigravity","codex-app","cursor","mira"]),vo=new Set(["aiden","coco","claude-code","codex","mtr","hermes"]);function ko(e){return!!e&&(vo.has(e)||Vt.has(e))}function $o(e){return!!e&&Vt.has(e)}function Yt(e,t,n,s,a){if(!a||s.kind==="live"||!t)return"";let r=s.kind==="resume",i=a.pending.has(e.attemptId),m=`data-wf-resume-attempt="${c(e.attemptId)}" data-wf-resume-activity="${c(t.activityId)}"`;return r?`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="end" ${m}${i?" disabled":""}>${c(i?o("workflow.detail.resumeEnding"):o("workflow.detail.endResumeSession"))}</button>`:ko(n.cliId)?$o(n.cliId)&&!n.cliSessionId?`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${c(o("workflow.detail.resumeMissingCliSession"))}">${c(o("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="start" ${m}${i?" disabled":""}>${c(i?o("workflow.detail.resumeStarting"):o("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${c(o("workflow.detail.resumeUnsupportedCli",{cliId:n.cliId??"?"}))}">${c(o("workflow.detail.resumeSession"))}</button>`}function Qt(e,t){if(!t)return"";let n=t.errors.get(e);return n?`<div class="hint-warn wf-resume-status" data-wf-resume-status="${c(e)}">${c(n)}</div>`:""}function So(e,t,n,s,a){let r=qe(e.activity),i=e.node?.nodeId??e.activity?.ownerNodeId??e.activity?.activityId??"unknown",m=r?.attemptId??e.activity?.activityId??e.node?.nodeId??"unknown",k=Zt(r,n),$=r?.attemptId===a?" is-focused":"",p=r?` data-wf-attempt-card="${c(r.attemptId)}"`:"",g=Jt(r,e.activity,e.io?.terminal,s),l=g?Gt(m,r,e.activity,e.io?.terminal,g,t,s):"";return`<article class="wf-io-card${$}" data-wf-card-key="${c(e.key)}"${p}>
|
|
567
731
|
<div class="wf-io-card-head">
|
|
568
732
|
<header>
|
|
569
733
|
<div>
|
|
570
|
-
<strong><code>${i
|
|
571
|
-
<span class="muted">${e.activity?
|
|
734
|
+
<strong><code>${c(i)}</code></strong>
|
|
735
|
+
<span class="muted">${e.activity?c(e.activity.activityId):c(o("workflow.detail.notDispatched"))}</span>
|
|
572
736
|
</div>
|
|
573
|
-
<div>${e.node?
|
|
737
|
+
<div>${e.node?ne(e.node.status):""} ${e.activity?ne(e.activity.status):""}</div>
|
|
574
738
|
</header>
|
|
575
739
|
<div class="wf-io-meta">
|
|
576
|
-
${
|
|
740
|
+
${r?`${c(o("workflow.detail.attempt"))} <code>${c(r.attemptId)}</code>`:c(o("workflow.detail.noAttempt"))}
|
|
577
741
|
</div>
|
|
578
|
-
${
|
|
742
|
+
${k}
|
|
579
743
|
</div>
|
|
580
744
|
<div class="wf-io-terminal-slot">${l}</div>
|
|
581
745
|
<div class="wf-io-grid">
|
|
582
|
-
${
|
|
583
|
-
${
|
|
584
|
-
${
|
|
585
|
-
${
|
|
586
|
-
${e.io?.waitPrompt?
|
|
746
|
+
${Z(m,o("workflow.detail.authoredInput"),e.io?.input,t)}
|
|
747
|
+
${Z(m,o("workflow.detail.resolvedInput"),e.io?.resolvedInput,t)}
|
|
748
|
+
${Z(m,o("workflow.detail.output"),e.io?.output,t)}
|
|
749
|
+
${Z(m,o("workflow.detail.executionLog"),e.io?.log,t)}
|
|
750
|
+
${e.io?.waitPrompt?Z(m,o("workflow.detail.waitPrompt"),e.io.waitPrompt,t):""}
|
|
587
751
|
</div>
|
|
588
|
-
</article>`}function
|
|
752
|
+
</article>`}function qe(e){return e?.attempts[e.attempts.length-1]}function Xt(e,t){let n=[];return t.error?n.push(o("workflow.detail.error")):n.push(t.status==="live"?o("workflow.detail.terminalLive"):o("workflow.detail.terminalClosedShort")),e?.status&&n.push(e.status),t.webPort>0&&n.push(`:${t.webPort}`),`<span class="muted">${c(n.join(" \xB7 "))}</span>`}function Io(e,t){return t.status==="live"&&t.webPort>0&&(e?.status==="pending"||e?.status==="running"||e?.status==="effectAttempting")}function To(e,t){return e.status==="succeeded"||e.status==="failed"||e.status==="cancelled"||e.status==="timedOut"?!!(t.sessionId||t.startedAt):!1}function Lo(e){return`http://${window.location.hostname||"127.0.0.1"}:${e.webPort}`}function Eo(e,t,n,s){let a=new URLSearchParams({runId:e,activityId:t,attemptId:n});return s&&a.set("hasPtyLog","1"),`/assets/terminal-replay.html?${a.toString()}`}function _t(e,t,n){return`/api/workflows/runs/${encodeURIComponent(e)}/attempts/${encodeURIComponent(t)}/${encodeURIComponent(n)}/terminal-log/raw?download=1`}function Mo(){let e=window.location.hash.match(/^#\/workflows\/([^/?#]+)/);if(!e)return null;try{return decodeURIComponent(e[1])}catch{return null}}function Zt(e,t){if(!Co(e))return"";let n=e.attemptId,s=t.comments.get(n)??"",a=t.resolving.has(n),r=t.statuses.get(n),i=r?.kind==="error"?"hint-warn":"hint-ok";return`<div class="wf-approval-box" data-wf-approval="${c(n)}">
|
|
589
753
|
<label>
|
|
590
|
-
<span>${
|
|
591
|
-
<textarea class="wf-approval-comment" data-wf-approval-comment="${
|
|
754
|
+
<span>${c(o("workflow.detail.approvalComment"))}</span>
|
|
755
|
+
<textarea class="wf-approval-comment" data-wf-approval-comment="${c(n)}" rows="2" placeholder="${c(o("workflow.detail.optionalComment"))}"${a?" disabled":""}>${c(s)}</textarea>
|
|
592
756
|
</label>
|
|
593
757
|
<div class="wf-approval-actions">
|
|
594
|
-
<button type="button" class="primary" data-wf-approval-action="approve" data-wf-attempt-id="${
|
|
595
|
-
<button type="button" data-wf-approval-action="reject" data-wf-attempt-id="${
|
|
596
|
-
${
|
|
758
|
+
<button type="button" class="primary" data-wf-approval-action="approve" data-wf-attempt-id="${c(n)}"${a?" disabled":""}>${c(o("workflow.detail.approve"))}</button>
|
|
759
|
+
<button type="button" data-wf-approval-action="reject" data-wf-attempt-id="${c(n)}"${a?" disabled":""}>${c(o("workflow.detail.reject"))}</button>
|
|
760
|
+
${a?`<span class="muted">${c(o("workflow.detail.submitting"))}</span>`:""}
|
|
597
761
|
</div>
|
|
598
|
-
${
|
|
599
|
-
</div>`}function
|
|
600
|
-
<summary>${
|
|
601
|
-
${
|
|
602
|
-
</details>`}function
|
|
603
|
-
<td>${
|
|
604
|
-
<td><code>${
|
|
605
|
-
<td>${
|
|
606
|
-
<td>${t.nodeId?`<code>${
|
|
607
|
-
<td>${t.activityId?`<code>${
|
|
608
|
-
<td>${t.errorCode?`<span class="muted error">${
|
|
609
|
-
<td title="${
|
|
610
|
-
</tr>`}function
|
|
762
|
+
${r?`<div class="${i} wf-approval-status">${c(r.text)}</div>`:""}
|
|
763
|
+
</div>`}function Co(e){return!!e&&e.status==="waiting"&&e.wait?.waitKind==="human-gate"&&!e.wait.resolution}function Ho(e,t){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(n=>{let s=n.dataset.wfApprovalComment;s&&t.set(s,n.value)})}function en(e,t){e.querySelectorAll("button[data-wf-resume-action][data-wf-resume-attempt][data-wf-resume-activity]").forEach(n=>{n.dataset.wfResumeBound!=="1"&&(n.dataset.wfResumeBound="1",n.addEventListener("click",()=>{let s=n.dataset.wfResumeAttempt,a=n.dataset.wfResumeActivity,r=n.dataset.wfResumeAction;!s||!a||(r==="start"?t.onStart(s,a):r==="end"&&t.onEnd(s,a))}))})}function xo(e,t,n,s,a,r){let i=e.querySelector(".wf-terminal-actions");if(!i)return;let m=i.querySelector('button[data-wf-resume-button="1"]'),k=Yt(t,n,s,a,r);m?m.outerHTML=k:k&&i.insertAdjacentHTML("beforeend",k);let $=e.querySelector("details.wf-terminal-block");if($){let p=$.querySelector(".wf-resume-status"),g=Qt(t.attemptId,r);p?p.outerHTML=g:g&&i.insertAdjacentHTML("afterend",g)}en(e,r)}function Ao(e,t){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(n=>{let s=n.dataset.wfApprovalComment;s&&n.addEventListener("input",()=>{t.comments.set(s,n.value)})}),e.querySelectorAll("button[data-wf-approval-action][data-wf-attempt-id]").forEach(n=>{n.addEventListener("click",()=>{let s=n.dataset.wfAttemptId,a=n.dataset.wfApprovalAction;!s||a!=="approve"&&a!=="reject"||t.onResolve(s,a)})})}function Z(e,t,n,s){let a=at(e,t);return`<details class="wf-io-block" data-io-key="${c(a)}"${s.has(a)?" open":""}>
|
|
764
|
+
<summary>${c(t)} ${Po(n)}</summary>
|
|
765
|
+
${No(n)}
|
|
766
|
+
</details>`}function at(e,t){return`${e}:${t}`}function Ro(e,t){if(!t)return!1;for(let n of e.querySelectorAll("[data-wf-attempt-card]"))if(n.dataset.wfAttemptCard===t)return n.scrollIntoView({block:"center"}),!0;return!1}function Do(e,t,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(s=>{let a=s.dataset.ioKey;if(!a)return;s.open?t.add(a):t.delete(a);let r=s.querySelector(".wf-io-pre");r&&n.set(a,r.scrollTop)})}function Bo(e,t){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(n=>{n.dataset.ioToggleBound!=="1"&&(n.dataset.ioToggleBound="1",n.addEventListener("toggle",()=>{let s=n.dataset.ioKey;s&&(n.open?t.add(s):t.delete(s))}))})}function Oo(e,t){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(n=>{let s=n.dataset.ioKey;if(!s)return;let a=t.get(s);if(a===void 0)return;let r=n.querySelector(".wf-io-pre");r&&(r.scrollTop=a)})}function qo(e,t){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(n=>{let s=n.dataset.ioKey;if(!s)return;let a=n.querySelector(".wf-io-pre");a&&a.dataset.ioScrollBound!=="1"&&(a.dataset.ioScrollBound="1",a.addEventListener("scroll",()=>{t.set(s,a.scrollTop)}))})}function Po(e){if(!e)return`<span class="muted">${c(o("workflow.detail.empty"))}</span>`;let t=[];return e.outputBytes!==void 0&&t.push(`${e.outputBytes}B`),e.truncated&&t.push(o("workflow.detail.truncated")),e.error&&t.push(o("workflow.detail.error")),e.outputHash&&t.push(Ne(e.outputHash)),t.length?`<span class="muted">${c(t.join(" \xB7 "))}</span>`:""}function No(e){if(!e)return`<div class="muted wf-io-empty">${c(o("workflow.detail.noData"))}</div>`;let t=e.value!==void 0?JSON.stringify(e.value,null,2):e.text??"",n=e.error?`<div class="muted error">${c(e.error)}</div>`:"";return t?`${n}<pre class="wf-io-pre">${c(t)}</pre>`:`${n}<div class="muted wf-io-empty">${c(o("workflow.detail.noPreview"))}</div>`}function jo(e){let t=[];if(e.effectAttempted&&t.push(`${c(o("workflow.detail.effect"))} ${c(e.effectAttempted.provider)}`),e.wait){let n=e.wait.resolution?`${e.wait.resolution.kind}${e.wait.resolution.resolution?":"+e.wait.resolution.resolution:""}`:o("workflow.detail.open");t.push(`${c(o("workflow.detail.wait"))} ${c(e.wait.waitKind)} ${c(n)}`),e.wait.deadlineAt!==void 0&&t.push(`${c(o("workflow.detail.deadline"))} ${c(Pe(e.wait.deadlineAt))}`)}if(e.error){let n=`${e.error.errorCode}${e.error.errorClass?` \xB7 ${e.error.errorClass}`:""}`;t.push(`<span class="muted error">${c(n)}</span>`),e.error.errorMessage&&t.push(`<span class="error wf-error-msg">${c(e.error.errorMessage)}</span>`)}return e.output&&t.push(`${c(o("workflow.detail.output"))} ${c(Ne(e.output.outputHash))}`),e.runningMs!==void 0&&t.push(`${e.runningMs}ms`),t.length>0?t.join("<br/>"):'<span class="muted">-</span>'}function Uo(e,t){e.innerHTML=t.length>0?t.map(Fo).join(""):`<tr><td colspan="7" class="empty">${c(o("workflow.detail.noEvents"))}</td></tr>`}function Fo(e){let t=_o(e.payload);return`<tr>
|
|
767
|
+
<td>${$e(e.eventId)}</td>
|
|
768
|
+
<td><code>${c(e.type)}</code></td>
|
|
769
|
+
<td>${c(e.actor)}</td>
|
|
770
|
+
<td>${t.nodeId?`<code>${c(t.nodeId)}</code>`:"-"}</td>
|
|
771
|
+
<td>${t.activityId?`<code>${c(t.activityId)}</code>`:"-"}</td>
|
|
772
|
+
<td>${t.errorCode?`<span class="muted error">${c(t.errorCode)}</span>`:"-"}</td>
|
|
773
|
+
<td title="${c(new Date(e.timestamp).toISOString())}">${c(Pe(e.timestamp))}</td>
|
|
774
|
+
</tr>`}function $e(e){let t=e.lastIndexOf("-");if(t<0)return 0;let n=Number(e.slice(t+1));return Number.isFinite(n)?n:0}function _o(e){if(!e||typeof e!="object"||"ref"in e)return{};let t=e,n={};typeof t.nodeId=="string"&&(n.nodeId=t.nodeId),typeof t.activityId=="string"&&(n.activityId=t.activityId),typeof t.failedNodeId=="string"&&(n.nodeId=t.failedNodeId);let s=t.error;return s&&typeof s=="object"&&"errorCode"in s&&(n.errorCode=String(s.errorCode)),n}function Wo(e){return!e.payload||typeof e.payload!="object"||"ref"in e.payload?null:e.payload}function Wt(e,t,n){return Math.min(n,Math.max(t,e))}function Ne(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function zo(e,t){return e.length>t?e.slice(0,t-1)+"\u2026":e}function Pe(e){return new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"})}function C(e){return e.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function tn(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function nn(e){let t=location.hash.match(/^#\/(?:workflows\/catalog|workflows-catalog)\/([^/?#]+)$/);return t?Go(e,decodeURIComponent(t[1])):Jo(e)}function Jo(e){e.innerHTML=`
|
|
611
775
|
<nav class="wf-subnav">
|
|
612
|
-
<a href="#/workflows" data-i18n="workflow.subnav.runs">${C(
|
|
613
|
-
<a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${C(
|
|
776
|
+
<a href="#/workflows" data-i18n="workflow.subnav.runs">${C(o("workflow.subnav.runs"))}</a>
|
|
777
|
+
<a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${C(o("workflow.subnav.catalog"))}</a>
|
|
614
778
|
</nav>
|
|
615
779
|
<section class="catalog-head">
|
|
616
780
|
<div>
|
|
617
|
-
<h2>${C(
|
|
618
|
-
<p class="muted">${C(
|
|
781
|
+
<h2>${C(o("catalog.title"))}</h2>
|
|
782
|
+
<p class="muted">${C(o("catalog.subtitle"))}</p>
|
|
619
783
|
</div>
|
|
620
|
-
<button id="catalog-refresh" type="button">${C(
|
|
784
|
+
<button id="catalog-refresh" type="button">${C(o("catalog.refresh"))}</button>
|
|
621
785
|
</section>
|
|
622
786
|
<form id="catalog-filters" class="filters">
|
|
623
|
-
<input type="search" name="q" placeholder="${C(
|
|
787
|
+
<input type="search" name="q" placeholder="${C(o("catalog.searchPlaceholder"))}" />
|
|
624
788
|
<span id="catalog-status" class="muted"></span>
|
|
625
789
|
</form>
|
|
626
790
|
<div class="wf-table-scroll">
|
|
627
791
|
<table>
|
|
628
792
|
<thead><tr>
|
|
629
|
-
<th>${C(
|
|
630
|
-
<th>${C(
|
|
631
|
-
<th>${C(
|
|
632
|
-
<th>${C(
|
|
633
|
-
<th>${C(
|
|
634
|
-
<th>${C(
|
|
793
|
+
<th>${C(o("catalog.table.workflow"))}</th>
|
|
794
|
+
<th>${C(o("catalog.table.version"))}</th>
|
|
795
|
+
<th>${C(o("catalog.table.params"))}</th>
|
|
796
|
+
<th>${C(o("catalog.table.nodes"))}</th>
|
|
797
|
+
<th>${C(o("catalog.table.revision"))}</th>
|
|
798
|
+
<th>${C(o("catalog.table.path"))}</th>
|
|
635
799
|
</tr></thead>
|
|
636
800
|
<tbody id="catalog-tbody"></tbody>
|
|
637
801
|
</table>
|
|
638
802
|
</div>
|
|
639
|
-
`;let t=e.querySelector("#catalog-tbody"),
|
|
803
|
+
`;let t=e.querySelector("#catalog-tbody"),n=e.querySelector("#catalog-status"),s=e.querySelector("#catalog-filters"),a=e.querySelector("#catalog-refresh"),r=[],i=null,m=!1;function k(){let g=(new FormData(s).get("q")??"").trim().toLowerCase();return g?r.filter(l=>l.workflowId.toLowerCase().includes(g)||l.path.toLowerCase().includes(g)):r}function $(){i?(n.textContent=o("catalog.loadFailed",{error:i}),n.classList.add("error")):(n.textContent=`${r.length}`,n.classList.remove("error"));let g=k();if(g.length===0){t.innerHTML=`<tr><td colspan="6" class="empty">${r.length===0?C(o("catalog.noDefinitions")):C(o("catalog.noFilterMatch"))}</td></tr>`;return}t.innerHTML=g.map(l=>`
|
|
640
804
|
<tr>
|
|
641
805
|
<td><a href="#/workflows/catalog/${encodeURIComponent(l.workflowId)}"><code>${C(l.workflowId)}</code></a></td>
|
|
642
806
|
<td>${l.version}</td>
|
|
643
|
-
<td>${C(
|
|
807
|
+
<td>${C(o("catalog.paramSummary",{required:l.requiredParamCount,total:l.paramCount}))}</td>
|
|
644
808
|
<td>${l.nodeCount}</td>
|
|
645
|
-
<td><code>${C(
|
|
809
|
+
<td><code>${C(tn(l.revisionId))}</code></td>
|
|
646
810
|
<td><code>${C(l.path)}</code></td>
|
|
647
811
|
</tr>
|
|
648
|
-
`).join("")}async function
|
|
812
|
+
`).join("")}async function p(){a.disabled=!0,n.textContent=o("catalog.loading");try{let g=await fetch("/api/workflows/definitions");if(!g.ok)throw new Error(`HTTP ${g.status}`);r=(await g.json()).definitions??[],i=null}catch(g){i=g?.message??String(g),r=[]}finally{a.disabled=!1,m||$()}}return s.addEventListener("input",$),a.addEventListener("click",()=>{p()}),p(),()=>{m=!0}}function Go(e,t){e.innerHTML=`
|
|
649
813
|
<div class="catalog-detail-head">
|
|
650
|
-
<a class="btn-link" href="#/workflows/catalog">${C(
|
|
814
|
+
<a class="btn-link" href="#/workflows/catalog">${C(o("catalog.back"))}</a>
|
|
651
815
|
<div>
|
|
652
816
|
<h2><code>${C(t)}</code></h2>
|
|
653
|
-
<div id="catalog-detail-subtitle" class="muted">${C(
|
|
817
|
+
<div id="catalog-detail-subtitle" class="muted">${C(o("workflow.detail.loading"))}</div>
|
|
654
818
|
</div>
|
|
655
819
|
</div>
|
|
656
820
|
<section id="catalog-error" class="hint-warn" hidden></section>
|
|
657
821
|
<section id="catalog-run-status" class="hint-ok" hidden></section>
|
|
658
822
|
<div id="catalog-detail-body"></div>
|
|
659
|
-
`;let
|
|
823
|
+
`;let n=e.querySelector("#catalog-detail-subtitle"),s=e.querySelector("#catalog-error"),a=e.querySelector("#catalog-run-status"),r=e.querySelector("#catalog-detail-body"),i=null,m=!1,k=!1;function $(f){s.hidden=!f,s.textContent=f??""}function p(f){a.hidden=!f,a.textContent=f??""}function g(f){let T={};for(let[S,y]of Object.entries(f??{}))"default"in y&&(T[S]=y.default);return T}function l(){if(!i)return;let f=i.definition;n.textContent=`${o("catalog.revision")} ${tn(i.revisionId)} \xB7 ${i.path}`;let T=JSON.stringify(g(f.params),null,2);r.innerHTML=`
|
|
660
824
|
<section class="wf-panel">
|
|
661
|
-
<div class="wf-panel-title"><h3>${C(
|
|
825
|
+
<div class="wf-panel-title"><h3>${C(o("catalog.summary"))}</h3></div>
|
|
662
826
|
<div class="wf-summary-grid">
|
|
663
|
-
<div class="wf-summary-item"><span>${C(
|
|
664
|
-
<div class="wf-summary-item"><span>${C(
|
|
665
|
-
<div class="wf-summary-item"><span>${C(
|
|
666
|
-
<div class="wf-summary-item"><span>${C(
|
|
827
|
+
<div class="wf-summary-item"><span>${C(o("catalog.table.workflow"))}</span><strong><code>${C(f.workflowId)}</code></strong></div>
|
|
828
|
+
<div class="wf-summary-item"><span>${C(o("catalog.table.version"))}</span><strong>${f.version}</strong></div>
|
|
829
|
+
<div class="wf-summary-item"><span>${C(o("catalog.nodeCount"))}</span><strong>${Object.keys(f.nodes).length}</strong></div>
|
|
830
|
+
<div class="wf-summary-item"><span>${C(o("catalog.path"))}</span><strong><code>${C(i.path)}</code></strong></div>
|
|
667
831
|
</div>
|
|
668
832
|
</section>
|
|
669
833
|
|
|
670
834
|
<section class="wf-panel">
|
|
671
|
-
<div class="wf-panel-title"><h3>${C(
|
|
835
|
+
<div class="wf-panel-title"><h3>${C(o("catalog.runPanel"))}</h3></div>
|
|
672
836
|
<form id="catalog-run-form" class="catalog-run-form">
|
|
673
837
|
<label>
|
|
674
|
-
<span>${C(
|
|
675
|
-
<textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${C(
|
|
838
|
+
<span>${C(o("catalog.paramsJson"))}</span>
|
|
839
|
+
<textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${C(o("catalog.paramsPlaceholder"))}">${C(T)}</textarea>
|
|
676
840
|
</label>
|
|
677
841
|
<div class="catalog-chat-grid">
|
|
678
842
|
<label>
|
|
679
|
-
<span>${C(
|
|
843
|
+
<span>${C(o("catalog.chatId"))}</span>
|
|
680
844
|
<input id="catalog-chat-id" type="text" autocomplete="off" />
|
|
681
845
|
</label>
|
|
682
846
|
<label>
|
|
683
|
-
<span>${C(
|
|
847
|
+
<span>${C(o("catalog.larkAppId"))}</span>
|
|
684
848
|
<input id="catalog-lark-app-id" type="text" autocomplete="off" />
|
|
685
849
|
</label>
|
|
686
850
|
</div>
|
|
687
|
-
<div class="muted">${C(
|
|
851
|
+
<div class="muted">${C(o("catalog.chatBindingHint"))}</div>
|
|
688
852
|
<div id="catalog-param-errors" class="catalog-param-errors" hidden></div>
|
|
689
|
-
<button id="catalog-run-btn" type="submit" class="primary">${C(
|
|
853
|
+
<button id="catalog-run-btn" type="submit" class="primary">${C(o("catalog.run"))}</button>
|
|
690
854
|
</form>
|
|
691
855
|
</section>
|
|
692
856
|
|
|
693
857
|
<section class="wf-panel">
|
|
694
|
-
<div class="wf-panel-title"><h3>${C(
|
|
695
|
-
${
|
|
858
|
+
<div class="wf-panel-title"><h3>${C(o("catalog.paramsSchema"))}</h3></div>
|
|
859
|
+
${Ko(f.params)}
|
|
696
860
|
</section>
|
|
697
861
|
|
|
698
862
|
<section class="wf-panel">
|
|
699
|
-
<div class="wf-panel-title"><h3>${C(
|
|
700
|
-
<pre class="wf-io-pre">${C(JSON.stringify(
|
|
863
|
+
<div class="wf-panel-title"><h3>${C(o("catalog.definitionJson"))}</h3></div>
|
|
864
|
+
<pre class="wf-io-pre">${C(JSON.stringify(f,null,2))}</pre>
|
|
701
865
|
</section>
|
|
702
|
-
`,L()}async function
|
|
866
|
+
`,L()}async function I(){if(!i||k)return;let f=r.querySelector("#catalog-params"),T=r.querySelector("#catalog-chat-id"),S=r.querySelector("#catalog-lark-app-id"),y=r.querySelector("#catalog-run-btn"),H=r.querySelector("#catalog-param-errors"),u;try{if(u=JSON.parse(f.value||"{}"),!u||typeof u!="object"||Array.isArray(u))throw new Error(o("catalog.badParamsJson"))}catch(w){H.hidden=!1,H.innerHTML=`<div class="muted error">${C(w?.message??String(w))}</div>`;return}k=!0,y.disabled=!0,y.textContent=o("catalog.running"),H.hidden=!0,$(null),p(null);try{let w=await fetch(`/api/workflows/definitions/${encodeURIComponent(i.definition.workflowId)}/run`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({params:u,chatBinding:{chatId:T.value.trim(),larkAppId:S.value.trim()}})});if(w.status===401)throw new Error(o("catalog.writeAccess"));let h=await w.json().catch(()=>({}));if(!w.ok||!h.ok)throw h.issues?.length&&(H.hidden=!1,H.innerHTML=`<strong>${C(o("catalog.invalidParams"))}</strong><ul>${h.issues.map(E=>`<li>${C(o("catalog.issue",{path:E.path.length?E.path.join("."):"(root)",message:E.message}))}</li>`).join("")}</ul>`),new Error(h.hint??h.message??h.error??o("catalog.runHttp",{status:w.status}));p(o("catalog.runStarted")),h.runId&&(location.hash=`#/workflows/${encodeURIComponent(h.runId)}`)}catch(w){$(w?.message??String(w))}finally{k=!1,y.disabled=!1,y.textContent=o("catalog.run")}}function L(){r.querySelector("#catalog-run-form")?.addEventListener("submit",T=>{T.preventDefault(),I()})}async function b(){try{let f=await fetch(`/api/workflows/definitions/${encodeURIComponent(t)}`);if(f.status===404)throw new Error("unknown_workflow");if(!f.ok)throw new Error(`HTTP ${f.status}`);i=await f.json(),$(null),l()}catch(f){$(o("catalog.definitionLoadFailed",{error:f?.message??String(f)})),n.textContent=o("workflow.detail.loadFailed")}}return b().then(()=>{}),()=>{m=!0}}function Ko(e){let t=Object.entries(e??{});return t.length===0?`<div class="muted">${C(o("catalog.noParams"))}</div>`:`<div class="catalog-param-list">${t.map(([n,s])=>`
|
|
703
867
|
<article class="catalog-param">
|
|
704
868
|
<header>
|
|
705
|
-
<code>${C(
|
|
706
|
-
<span class="wf-status">${C(
|
|
707
|
-
<span class="muted">${C(
|
|
869
|
+
<code>${C(n)}</code>
|
|
870
|
+
<span class="wf-status">${C(s.required?o("catalog.required"):o("catalog.optional"))}</span>
|
|
871
|
+
<span class="muted">${C(s.type)}${s.format?` \xB7 ${C(s.format)}`:""}</span>
|
|
708
872
|
</header>
|
|
709
|
-
${
|
|
710
|
-
${"default"in
|
|
873
|
+
${s.description?`<div class="muted">${C(o("catalog.description"))}: ${C(s.description)}</div>`:""}
|
|
874
|
+
${"default"in s?`<pre class="wf-io-pre">${C(`${o("catalog.default")}: ${JSON.stringify(s.default,null,2)}`)}</pre>`:""}
|
|
711
875
|
</article>
|
|
712
|
-
`).join("")}</div>`}var
|
|
713
|
-
<img class="qr-image" src="${e.qrDataUrl}" alt="${
|
|
714
|
-
${e.qrUrl?`<a class="onboarding-link" href="${e.qrUrl}" target="_blank" rel="noopener">${
|
|
715
|
-
</div>`:"",
|
|
876
|
+
`).join("")}</div>`}var pe=null,je=null;function Ue(){je!==null&&(window.clearInterval(je),je=null)}function on(){return pe||(pe=document.createElement("dialog"),pe.className="onboarding-dialog",document.body.appendChild(pe),pe.addEventListener("close",Ue),pe)}function Vo(e){return e.status==="waiting_for_scan"?o("botOnboarding.waiting"):e.status==="verifying"?o("botOnboarding.verifying"):e.status==="completed"?o("botOnboarding.completed"):e.status==="failed"?`${o("botOnboarding.failed")}: ${e.message??e.error??"unknown"}`:o("botOnboarding.starting")}function Se(e){let t=on(),n=e.qrDataUrl?`<div class="qr-card">
|
|
877
|
+
<img class="qr-image" src="${e.qrDataUrl}" alt="${o("botOnboarding.qrAlt")}">
|
|
878
|
+
${e.qrUrl?`<a class="onboarding-link" href="${e.qrUrl}" target="_blank" rel="noopener">${o("botOnboarding.openLink")}</a>`:""}
|
|
879
|
+
</div>`:"",s=e.appId?`<p><b>App ID:</b> <code>${e.appId}</code></p>`:"",a=e.status==="completed"?`<p class="hint-ok">${o("botOnboarding.restartHint")}</p>`:"";t.innerHTML=`<article>
|
|
716
880
|
<header>
|
|
717
|
-
<h3>${
|
|
718
|
-
<p>${
|
|
881
|
+
<h3>${o("botOnboarding.title")}</h3>
|
|
882
|
+
<p>${o("botOnboarding.intro")}</p>
|
|
719
883
|
</header>
|
|
720
|
-
<p class="onboarding-status status-${e.status}">${
|
|
721
|
-
${
|
|
722
|
-
${r}
|
|
884
|
+
<p class="onboarding-status status-${e.status}">${Vo(e)}</p>
|
|
885
|
+
${n}
|
|
723
886
|
${s}
|
|
724
|
-
|
|
725
|
-
|
|
887
|
+
${a}
|
|
888
|
+
<form method="dialog"><button>${o("botOnboarding.close")}</button></form>
|
|
889
|
+
</article>`}async function Yo(e){let t=await fetch(`/api/bot-onboarding/${encodeURIComponent(e)}`),n=await t.json();if(!t.ok||!n?.job)throw new Error(n?.error??`http_${t.status}`);Se(n.job),(n.job.status==="completed"||n.job.status==="failed")&&Ue()}async function Qo(){Ue(),Se({id:"",status:"starting"});let e=on();e.open||e.showModal();try{let t=await fetch("/api/bot-onboarding/start",{method:"POST"}),n=await t.json();if(!t.ok||!n?.job?.id)throw new Error(n?.error??`http_${t.status}`);Se(n.job),je=window.setInterval(()=>{Yo(n.job.id).catch(s=>{Ue(),Se({id:n.job.id,status:"failed",message:s instanceof Error?s.message:String(s)})})},1200)}catch(t){Se({id:"",status:"failed",message:t instanceof Error?t.message:String(t)})}}function an(){let e=document.getElementById("add-bot-btn");e&&(e.onclick=()=>{Qo()})}var V=document.getElementById("root"),Ie=null;function st(){Ie&&(Ie(),Ie=null);let e=location.hash||"#/";e.startsWith("#/workflows/catalog")||e.startsWith("#/workflows-catalog")?Ie=nn(V):e.startsWith("#/workflows")?Ie=zt(V):e.startsWith("#/groups")?It(V):e.startsWith("#/bot-defaults")?Et(V):e.startsWith("#/connectors")?Ut(V):e.startsWith("#/team/manage")?Pt(V):e.startsWith("#/team")?qt(V):e.startsWith("#/roles")?xt(V):e.startsWith("#/schedules")?$t(V):e.startsWith("#/sessions")?vt(V):bt(V);for(let t of document.querySelectorAll(".sidebar-nav a")){let n=t.getAttribute("href")??"#/";t.classList.toggle("active",n===(e||"#/"))}}var rt=document.getElementById("status");function rn(){rt&&(rt.textContent=N.online?o("status.live"):o("status.disconnected"),rt.className="connection-status "+(N.online?"online":"offline"))}N.on(rn);function sn(){document.querySelectorAll("[data-i18n]").forEach(e=>{e.textContent=o(e.dataset.i18n??"")}),document.querySelectorAll("[data-locale]").forEach(e=>{e.classList.toggle("active",e.dataset.locale===ae.locale)}),document.querySelectorAll("[data-theme-mode]").forEach(e=>{e.classList.toggle("active",e.dataset.themeMode===ae.themeMode)}),rn()}function Xo(){document.querySelectorAll("[data-locale]").forEach(e=>{e.onclick=()=>ae.setLocale(e.dataset.locale)}),document.querySelectorAll("[data-theme-mode]").forEach(e=>{e.onclick=()=>ae.setThemeMode(e.dataset.themeMode)})}(async()=>{ae.init(),Xo(),an(),ae.on(()=>{sn(),st()}),sn();try{await pt()}catch(e){console.error("botmux dashboard bootstrap failed",e),N.setOnline(!1)}window.addEventListener("hashchange",st),st()})();})();
|