botmux 2.46.1 → 2.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +5 -10
- package/README.md +5 -10
- package/dist/adapters/backend/tmux-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-backend.js +0 -11
- package/dist/adapters/backend/tmux-backend.js.map +1 -1
- package/dist/adapters/cli/claude-code.d.ts.map +1 -1
- package/dist/adapters/cli/claude-code.js +9 -36
- 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 +1 -26
- package/dist/adapters/cli/coco.js.map +1 -1
- package/dist/adapters/cli/codex.d.ts.map +1 -1
- package/dist/adapters/cli/codex.js +1 -6
- 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 +12 -58
- 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 +1 -5
- package/dist/adapters/cli/gemini.js.map +1 -1
- package/dist/adapters/cli/opencode.d.ts.map +1 -1
- package/dist/adapters/cli/opencode.js +1 -19
- package/dist/adapters/cli/opencode.js.map +1 -1
- package/dist/adapters/cli/registry.d.ts +1 -5
- package/dist/adapters/cli/registry.d.ts.map +1 -1
- package/dist/adapters/cli/registry.js +2 -22
- 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 +1 -2
- package/dist/adapters/cli/shared-hints.js.map +1 -1
- package/dist/adapters/cli/types.d.ts +2 -35
- package/dist/adapters/cli/types.d.ts.map +1 -1
- package/dist/bot-registry.d.ts +0 -59
- package/dist/bot-registry.d.ts.map +1 -1
- package/dist/bot-registry.js +0 -67
- package/dist/bot-registry.js.map +1 -1
- package/dist/cli/bots-list-output.d.ts +0 -8
- package/dist/cli/bots-list-output.d.ts.map +1 -1
- package/dist/cli/bots-list-output.js +0 -9
- package/dist/cli/bots-list-output.js.map +1 -1
- package/dist/cli.d.ts +1 -15
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +106 -603
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +2 -11
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -17
- package/dist/config.js.map +1 -1
- package/dist/core/command-handler.d.ts +0 -20
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +313 -762
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/dashboard-ipc-server.d.ts +0 -2
- package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
- package/dist/core/dashboard-ipc-server.js +2 -222
- package/dist/core/dashboard-ipc-server.js.map +1 -1
- package/dist/core/role-resolver.d.ts +1 -17
- package/dist/core/role-resolver.d.ts.map +1 -1
- package/dist/core/role-resolver.js +10 -64
- 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 +5 -19
- 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 +20 -37
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/types.d.ts +0 -5
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/core/worker-pool.d.ts +0 -141
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +24 -543
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +58 -213
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/auth.d.ts +1 -6
- package/dist/dashboard/auth.d.ts.map +1 -1
- package/dist/dashboard/auth.js +1 -9
- package/dist/dashboard/auth.js.map +1 -1
- package/dist/dashboard/web/app.js +0 -8
- 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 +21 -205
- package/dist/dashboard/web/bot-defaults.js.map +1 -1
- package/dist/dashboard/web/i18n.d.ts.map +1 -1
- package/dist/dashboard/web/i18n.js +5 -43
- 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 +0 -4
- package/dist/dashboard/web/sessions.js.map +1 -1
- package/dist/dashboard/web/workflows.js +3 -3
- package/dist/dashboard/web/workflows.js.map +1 -1
- package/dist/dashboard/workflow-api.d.ts +1 -8
- package/dist/dashboard/workflow-api.d.ts.map +1 -1
- package/dist/dashboard/workflow-api.js +4 -19
- package/dist/dashboard/workflow-api.js.map +1 -1
- package/dist/dashboard-web/app.js +375 -539
- package/dist/dashboard-web/index.html +1 -3
- package/dist/dashboard-web/style.css +0 -22
- package/dist/dashboard.js +2 -199
- package/dist/dashboard.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +11 -104
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +11 -104
- package/dist/i18n/zh.js.map +1 -1
- package/dist/im/lark/card-builder.d.ts +3 -108
- package/dist/im/lark/card-builder.d.ts.map +1 -1
- package/dist/im/lark/card-builder.js +50 -480
- 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 +18 -241
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/im/lark/client.d.ts +0 -83
- package/dist/im/lark/client.d.ts.map +1 -1
- package/dist/im/lark/client.js +70 -286
- 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 +4 -29
- package/dist/im/lark/event-dispatcher.js.map +1 -1
- package/dist/im/lark/grant-command.d.ts +1 -2
- package/dist/im/lark/grant-command.d.ts.map +1 -1
- package/dist/im/lark/grant-command.js +2 -3
- 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 +2 -20
- package/dist/im/lark/md-card.d.ts.map +1 -1
- package/dist/im/lark/md-card.js +17 -49
- 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 +31 -87
- 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 +1 -12
- 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 +0 -53
- package/dist/im/lark/workflow-progress-card.js.map +1 -1
- package/dist/services/codex-bridge-queue.d.ts +0 -1
- package/dist/services/codex-bridge-queue.d.ts.map +1 -1
- package/dist/services/codex-bridge-queue.js +0 -23
- package/dist/services/codex-bridge-queue.js.map +1 -1
- package/dist/services/codex-transcript.d.ts +0 -1
- package/dist/services/codex-transcript.d.ts.map +1 -1
- package/dist/services/codex-transcript.js.map +1 -1
- package/dist/services/feishu-task-client.d.ts +28 -0
- package/dist/services/feishu-task-client.d.ts.map +1 -0
- package/dist/services/feishu-task-client.js +123 -0
- package/dist/services/feishu-task-client.js.map +1 -0
- package/dist/services/grant-store.d.ts +2 -12
- package/dist/services/grant-store.d.ts.map +1 -1
- package/dist/services/grant-store.js +4 -51
- package/dist/services/grant-store.js.map +1 -1
- package/dist/services/group-creator.d.ts +0 -10
- package/dist/services/group-creator.d.ts.map +1 -1
- package/dist/services/group-creator.js +1 -26
- package/dist/services/group-creator.js.map +1 -1
- package/dist/services/groups-store.d.ts +0 -30
- package/dist/services/groups-store.d.ts.map +1 -1
- package/dist/services/groups-store.js +12 -85
- package/dist/services/groups-store.js.map +1 -1
- package/dist/services/project-scanner.d.ts +0 -10
- package/dist/services/project-scanner.d.ts.map +1 -1
- package/dist/services/project-scanner.js +0 -11
- package/dist/services/project-scanner.js.map +1 -1
- package/dist/services/session-store.js +1 -1
- package/dist/services/session-store.js.map +1 -1
- package/dist/services/task-store.d.ts +37 -0
- package/dist/services/task-store.d.ts.map +1 -0
- package/dist/services/task-store.js +115 -0
- package/dist/services/task-store.js.map +1 -0
- package/dist/setup/bot-config-editor.d.ts +1 -8
- package/dist/setup/bot-config-editor.d.ts.map +1 -1
- package/dist/setup/bot-config-editor.js +2 -20
- package/dist/setup/bot-config-editor.js.map +1 -1
- package/dist/setup/ensure-tmux.d.ts +22 -0
- package/dist/setup/ensure-tmux.d.ts.map +1 -1
- package/dist/setup/ensure-tmux.js +1 -25
- 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 +1 -15
- package/dist/setup/verify-permissions.js.map +1 -1
- package/dist/skills/definitions.d.ts +0 -2
- package/dist/skills/definitions.d.ts.map +1 -1
- package/dist/skills/definitions.js +12 -178
- package/dist/skills/definitions.js.map +1 -1
- package/dist/skills/installer.d.ts +0 -34
- package/dist/skills/installer.d.ts.map +1 -1
- package/dist/skills/installer.js +2 -119
- package/dist/skills/installer.js.map +1 -1
- package/dist/types.d.ts +0 -25
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/bot-routing.d.ts +0 -50
- package/dist/utils/bot-routing.d.ts.map +1 -1
- package/dist/utils/bot-routing.js +0 -83
- package/dist/utils/bot-routing.js.map +1 -1
- package/dist/utils/user-token.d.ts.map +1 -1
- package/dist/utils/user-token.js +2 -0
- package/dist/utils/user-token.js.map +1 -1
- package/dist/worker.js +27 -198
- 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 +9 -412
- package/dist/workflows/definition.d.ts.map +1 -1
- package/dist/workflows/definition.js +3 -238
- package/dist/workflows/definition.js.map +1 -1
- package/dist/workflows/events/payloads.d.ts +11 -114
- package/dist/workflows/events/payloads.d.ts.map +1 -1
- package/dist/workflows/events/payloads.js +0 -46
- package/dist/workflows/events/payloads.js.map +1 -1
- package/dist/workflows/events/replay.d.ts +0 -21
- package/dist/workflows/events/replay.d.ts.map +1 -1
- package/dist/workflows/events/replay.js +0 -103
- package/dist/workflows/events/replay.js.map +1 -1
- package/dist/workflows/events/schema.d.ts +1017 -1712
- package/dist/workflows/events/schema.d.ts.map +1 -1
- package/dist/workflows/events/schema.js +1 -37
- package/dist/workflows/events/schema.js.map +1 -1
- package/dist/workflows/events/types.d.ts +1 -5
- package/dist/workflows/events/types.d.ts.map +1 -1
- package/dist/workflows/loader.d.ts +0 -14
- package/dist/workflows/loader.d.ts.map +1 -1
- package/dist/workflows/loader.js +0 -27
- package/dist/workflows/loader.js.map +1 -1
- package/dist/workflows/loop.js +0 -58
- package/dist/workflows/loop.js.map +1 -1
- package/dist/workflows/ops-projection.d.ts +0 -58
- package/dist/workflows/ops-projection.d.ts.map +1 -1
- package/dist/workflows/ops-projection.js +0 -74
- package/dist/workflows/ops-projection.js.map +1 -1
- package/dist/workflows/orchestrator.d.ts +1 -65
- package/dist/workflows/orchestrator.d.ts.map +1 -1
- package/dist/workflows/orchestrator.js +74 -486
- package/dist/workflows/orchestrator.js.map +1 -1
- package/dist/workflows/output-binding.d.ts +1 -8
- package/dist/workflows/output-binding.d.ts.map +1 -1
- package/dist/workflows/output-binding.js +11 -75
- 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 +4 -39
- package/dist/workflows/runtime.js.map +1 -1
- package/dist/workflows/wait.d.ts +2 -23
- package/dist/workflows/wait.d.ts.map +1 -1
- package/dist/workflows/wait.js +17 -39
- package/dist/workflows/wait.js.map +1 -1
- package/package.json +1 -1
- package/dist/adapters/adopt-route.d.ts +0 -63
- package/dist/adapters/adopt-route.d.ts.map +0 -1
- package/dist/adapters/adopt-route.js +0 -195
- package/dist/adapters/adopt-route.js.map +0 -1
- package/dist/adapters/cli/codex-app.d.ts +0 -4
- package/dist/adapters/cli/codex-app.d.ts.map +0 -1
- package/dist/adapters/cli/codex-app.js +0 -72
- package/dist/adapters/cli/codex-app.js.map +0 -1
- package/dist/adapters/cli/hermes.d.ts +0 -4
- package/dist/adapters/cli/hermes.d.ts.map +0 -1
- package/dist/adapters/cli/hermes.js +0 -40
- package/dist/adapters/cli/hermes.js.map +0 -1
- package/dist/adapters/cli/mira.d.ts +0 -4
- package/dist/adapters/cli/mira.d.ts.map +0 -1
- package/dist/adapters/cli/mira.js +0 -67
- package/dist/adapters/cli/mira.js.map +0 -1
- package/dist/adapters/cli/mtr.d.ts +0 -5
- package/dist/adapters/cli/mtr.d.ts.map +0 -1
- package/dist/adapters/cli/mtr.js +0 -62
- package/dist/adapters/cli/mtr.js.map +0 -1
- package/dist/adapters/hook-command.d.ts +0 -18
- package/dist/adapters/hook-command.d.ts.map +0 -1
- package/dist/adapters/hook-command.js +0 -38
- package/dist/adapters/hook-command.js.map +0 -1
- package/dist/adapters/hook-installer.d.ts +0 -14
- package/dist/adapters/hook-installer.d.ts.map +0 -1
- package/dist/adapters/hook-installer.js +0 -192
- package/dist/adapters/hook-installer.js.map +0 -1
- package/dist/codex-app-runner.d.ts +0 -3
- package/dist/codex-app-runner.d.ts.map +0 -1
- package/dist/codex-app-runner.js +0 -512
- package/dist/codex-app-runner.js.map +0 -1
- package/dist/core/ask-api.d.ts +0 -47
- package/dist/core/ask-api.d.ts.map +0 -1
- package/dist/core/ask-api.js +0 -139
- package/dist/core/ask-api.js.map +0 -1
- package/dist/core/ask-args.d.ts +0 -53
- package/dist/core/ask-args.d.ts.map +0 -1
- package/dist/core/ask-args.js +0 -122
- package/dist/core/ask-args.js.map +0 -1
- package/dist/core/ask-broker.d.ts +0 -98
- package/dist/core/ask-broker.d.ts.map +0 -1
- package/dist/core/ask-broker.js +0 -329
- package/dist/core/ask-broker.js.map +0 -1
- package/dist/core/ask-hook/claude-code.d.ts +0 -50
- package/dist/core/ask-hook/claude-code.d.ts.map +0 -1
- package/dist/core/ask-hook/claude-code.js +0 -145
- package/dist/core/ask-hook/claude-code.js.map +0 -1
- package/dist/core/ask-hook/codex.d.ts +0 -43
- package/dist/core/ask-hook/codex.d.ts.map +0 -1
- package/dist/core/ask-hook/codex.js +0 -69
- package/dist/core/ask-hook/codex.js.map +0 -1
- package/dist/core/ask-hook/opencode.d.ts +0 -41
- package/dist/core/ask-hook/opencode.d.ts.map +0 -1
- package/dist/core/ask-hook/opencode.js +0 -108
- package/dist/core/ask-hook/opencode.js.map +0 -1
- package/dist/core/ask-hook/registry.d.ts +0 -3
- package/dist/core/ask-hook/registry.d.ts.map +0 -1
- package/dist/core/ask-hook/registry.js +0 -12
- package/dist/core/ask-hook/registry.js.map +0 -1
- package/dist/core/ask-hook/types.d.ts +0 -26
- package/dist/core/ask-hook/types.d.ts.map +0 -1
- package/dist/core/ask-hook/types.js +0 -2
- package/dist/core/ask-hook/types.js.map +0 -1
- package/dist/core/ask-types.d.ts +0 -146
- package/dist/core/ask-types.d.ts.map +0 -1
- package/dist/core/ask-types.js +0 -18
- package/dist/core/ask-types.js.map +0 -1
- package/dist/core/trigger-session.d.ts +0 -9
- package/dist/core/trigger-session.d.ts.map +0 -1
- package/dist/core/trigger-session.js +0 -158
- package/dist/core/trigger-session.js.map +0 -1
- package/dist/dashboard/connector-api.d.ts +0 -3
- package/dist/dashboard/connector-api.d.ts.map +0 -1
- package/dist/dashboard/connector-api.js +0 -351
- package/dist/dashboard/connector-api.js.map +0 -1
- package/dist/dashboard/federated-group-core.d.ts +0 -54
- package/dist/dashboard/federated-group-core.d.ts.map +0 -1
- package/dist/dashboard/federated-group-core.js +0 -165
- package/dist/dashboard/federated-group-core.js.map +0 -1
- package/dist/dashboard/federation-api.d.ts +0 -42
- package/dist/dashboard/federation-api.d.ts.map +0 -1
- package/dist/dashboard/federation-api.js +0 -408
- package/dist/dashboard/federation-api.js.map +0 -1
- package/dist/dashboard/federation-spoke-api.d.ts +0 -76
- package/dist/dashboard/federation-spoke-api.d.ts.map +0 -1
- package/dist/dashboard/federation-spoke-api.js +0 -618
- package/dist/dashboard/federation-spoke-api.js.map +0 -1
- package/dist/dashboard/team-group.d.ts +0 -18
- package/dist/dashboard/team-group.d.ts.map +0 -1
- package/dist/dashboard/team-group.js +0 -7
- package/dist/dashboard/team-group.js.map +0 -1
- package/dist/dashboard/trigger-api.d.ts +0 -13
- package/dist/dashboard/trigger-api.d.ts.map +0 -1
- package/dist/dashboard/trigger-api.js +0 -77
- package/dist/dashboard/trigger-api.js.map +0 -1
- package/dist/dashboard/web/connectors.d.ts +0 -2
- package/dist/dashboard/web/connectors.d.ts.map +0 -1
- package/dist/dashboard/web/connectors.js +0 -187
- package/dist/dashboard/web/connectors.js.map +0 -1
- package/dist/dashboard/web/team-federation.d.ts +0 -3
- package/dist/dashboard/web/team-federation.d.ts.map +0 -1
- package/dist/dashboard/web/team-federation.js +0 -487
- package/dist/dashboard/web/team-federation.js.map +0 -1
- package/dist/dashboard/webhook-routes.d.ts +0 -19
- package/dist/dashboard/webhook-routes.d.ts.map +0 -1
- package/dist/dashboard/webhook-routes.js +0 -321
- package/dist/dashboard/webhook-routes.js.map +0 -1
- package/dist/im/lark/ask-card.d.ts +0 -55
- package/dist/im/lark/ask-card.d.ts.map +0 -1
- package/dist/im/lark/ask-card.js +0 -328
- package/dist/im/lark/ask-card.js.map +0 -1
- package/dist/mira-output.d.ts +0 -3
- package/dist/mira-output.d.ts.map +0 -1
- package/dist/mira-output.js +0 -136
- package/dist/mira-output.js.map +0 -1
- package/dist/mira-runner.d.ts +0 -3
- package/dist/mira-runner.d.ts.map +0 -1
- package/dist/mira-runner.js +0 -534
- package/dist/mira-runner.js.map +0 -1
- package/dist/services/bot-owner-store.d.ts +0 -28
- package/dist/services/bot-owner-store.d.ts.map +0 -1
- package/dist/services/bot-owner-store.js +0 -82
- package/dist/services/bot-owner-store.js.map +0 -1
- package/dist/services/bot-profile-store.d.ts +0 -16
- package/dist/services/bot-profile-store.d.ts.map +0 -1
- package/dist/services/bot-profile-store.js +0 -98
- package/dist/services/bot-profile-store.js.map +0 -1
- package/dist/services/brand-store.d.ts +0 -15
- package/dist/services/brand-store.d.ts.map +0 -1
- package/dist/services/brand-store.js +0 -47
- package/dist/services/brand-store.js.map +0 -1
- package/dist/services/card-prefs-store.d.ts +0 -20
- package/dist/services/card-prefs-store.d.ts.map +0 -1
- package/dist/services/card-prefs-store.js +0 -82
- package/dist/services/card-prefs-store.js.map +0 -1
- package/dist/services/connector-store.d.ts +0 -58
- package/dist/services/connector-store.d.ts.map +0 -1
- package/dist/services/connector-store.js +0 -79
- package/dist/services/connector-store.js.map +0 -1
- package/dist/services/deployment-identity.d.ts +0 -22
- package/dist/services/deployment-identity.d.ts.map +0 -1
- package/dist/services/deployment-identity.js +0 -67
- package/dist/services/deployment-identity.js.map +0 -1
- package/dist/services/federation-membership-store.d.ts +0 -23
- package/dist/services/federation-membership-store.d.ts.map +0 -1
- package/dist/services/federation-membership-store.js +0 -66
- package/dist/services/federation-membership-store.js.map +0 -1
- package/dist/services/federation-roster.d.ts +0 -54
- package/dist/services/federation-roster.d.ts.map +0 -1
- package/dist/services/federation-roster.js +0 -51
- package/dist/services/federation-roster.js.map +0 -1
- package/dist/services/federation-store.d.ts +0 -76
- package/dist/services/federation-store.d.ts.map +0 -1
- package/dist/services/federation-store.js +0 -133
- package/dist/services/federation-store.js.map +0 -1
- package/dist/services/hermes-transcript.d.ts +0 -7
- package/dist/services/hermes-transcript.d.ts.map +0 -1
- package/dist/services/hermes-transcript.js +0 -117
- package/dist/services/hermes-transcript.js.map +0 -1
- package/dist/services/invite-store.d.ts +0 -28
- package/dist/services/invite-store.d.ts.map +0 -1
- package/dist/services/invite-store.js +0 -85
- package/dist/services/invite-store.js.map +0 -1
- package/dist/services/pairing-store.d.ts +0 -47
- package/dist/services/pairing-store.d.ts.map +0 -1
- package/dist/services/pairing-store.js +0 -132
- package/dist/services/pairing-store.js.map +0 -1
- package/dist/services/relay-picker.d.ts +0 -22
- package/dist/services/relay-picker.d.ts.map +0 -1
- package/dist/services/relay-picker.js +0 -62
- package/dist/services/relay-picker.js.map +0 -1
- package/dist/services/send-policy.d.ts +0 -55
- package/dist/services/send-policy.d.ts.map +0 -1
- package/dist/services/send-policy.js +0 -47
- package/dist/services/send-policy.js.map +0 -1
- package/dist/services/team-roster.d.ts +0 -38
- package/dist/services/team-roster.d.ts.map +0 -1
- package/dist/services/team-roster.js +0 -82
- package/dist/services/team-roster.js.map +0 -1
- package/dist/services/team-store.d.ts +0 -54
- package/dist/services/team-store.d.ts.map +0 -1
- package/dist/services/team-store.js +0 -156
- package/dist/services/team-store.js.map +0 -1
- package/dist/services/trigger-log-store.d.ts +0 -46
- package/dist/services/trigger-log-store.d.ts.map +0 -1
- package/dist/services/trigger-log-store.js +0 -132
- package/dist/services/trigger-log-store.js.map +0 -1
- package/dist/services/trigger-types.d.ts +0 -57
- package/dist/services/trigger-types.d.ts.map +0 -1
- package/dist/services/trigger-types.js +0 -28
- package/dist/services/trigger-types.js.map +0 -1
- package/dist/services/webhook-key.d.ts +0 -16
- package/dist/services/webhook-key.d.ts.map +0 -1
- package/dist/services/webhook-key.js +0 -123
- package/dist/services/webhook-key.js.map +0 -1
- package/dist/services/webhook-lifecycle-extractors.d.ts +0 -15
- package/dist/services/webhook-lifecycle-extractors.d.ts.map +0 -1
- package/dist/services/webhook-lifecycle-extractors.js +0 -59
- package/dist/services/webhook-lifecycle-extractors.js.map +0 -1
- package/dist/services/webhook-lifecycle-store.d.ts +0 -45
- package/dist/services/webhook-lifecycle-store.d.ts.map +0 -1
- package/dist/services/webhook-lifecycle-store.js +0 -159
- package/dist/services/webhook-lifecycle-store.js.map +0 -1
- package/dist/utils/daemon-discovery.d.ts +0 -11
- package/dist/utils/daemon-discovery.d.ts.map +0 -1
- package/dist/utils/daemon-discovery.js +0 -59
- package/dist/utils/daemon-discovery.js.map +0 -1
- package/dist/workflows/trigger-from-envelope.d.ts +0 -13
- package/dist/workflows/trigger-from-envelope.d.ts.map +0 -1
- package/dist/workflows/trigger-from-envelope.js +0 -67
- package/dist/workflows/trigger-from-envelope.js.map +0 -1
|
@@ -1,33 +1,33 @@
|
|
|
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
|
|
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
|
|
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"},Pt={"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 Default Oncall","botDefaults.subtitle":"Configure each bot's default oncall behavior in new chats.","botDefaults.search":"Search bot name / app id","botDefaults.refresh":"Refresh","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","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"},Ge={zh:Bt,en:Pt};function ze(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 Nt(e=[]){for(let t of e){let o=ze(t);if(o)return o}return"zh"}function he(e){return(t,o)=>{let r=Ge[e][t]??Ge.zh[t]??t;return o?r.replace(/\{(\w+)\}/g,(s,a)=>{let d=o[a];return d==null?`{${a}}`:String(d)}):r}}function Ke(e,t){return(e?ze(e.getItem(Me)):null)??Nt(t)}var Ae="botmux.dashboard.theme";function jt(e){return e==="system"||e==="light"||e==="dark"?e:null}function Ve(e,t){return e==="system"?t?"dark":"light":e}function Ye(e){return jt(e?.getItem(Ae))??"system"}var He=class{locale="zh";themeMode="system";resolvedTheme="light";listeners=new Set;translate=he(this.locale);mediaQuery=null;init(){let t=typeof window<"u"?window:void 0;this.locale=Ke(t?.localStorage,Ut()),this.translate=he(this.locale),this.themeMode=Ye(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,o){return this.translate(t,o)}setLocale(t){this.locale!==t&&(this.locale=t,this.translate=he(t),window.localStorage.setItem(Me,t),this.applyLocale(),this.emit())}setThemeMode(t){this.themeMode!==t&&(this.themeMode=t,window.localStorage.setItem(Ae,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=Ve(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 Ut(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var K=new He;function n(e,t){return K.t(e,t)}function m(e){return e.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function re(e){if(!e)return"-";let t=Date.now()-e;return t<6e4?n("common.now"):t<36e5?Math.floor(t/6e4)+"m":t<864e5?Math.floor(t/36e5)+"h":Math.floor(t/864e5)+"d"}var Re={chats:[],bots:[]};async function Ft(){try{let e=await fetch("/api/groups");if(!e.ok)return;Re=await e.json()}catch{}}function Wt(e){return`status status-${m(e||"unknown")}`}function _t(e){return`<li class="overview-list-row">
|
|
14
14
|
<div>
|
|
15
|
-
<strong>${
|
|
16
|
-
<span>${
|
|
15
|
+
<strong>${m(e.title??e.sessionId)}</strong>
|
|
16
|
+
<span>${m(e.botName??"")} \xB7 ${m(e.cliId??"unknown")}</span>
|
|
17
17
|
</div>
|
|
18
|
-
<span class="${
|
|
19
|
-
</li>`}function
|
|
18
|
+
<span class="${Wt(e.status)}">${m(e.status??"unknown")}</span>
|
|
19
|
+
</li>`}function Jt(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>${m(e.name??e.id)}</strong>
|
|
22
|
+
<span>${m(e.botName??e.larkAppId??"")} \xB7 ${m(e.parsed?.display??"")}</span>
|
|
23
23
|
</div>
|
|
24
|
-
<span>${
|
|
25
|
-
</li>`}async function
|
|
24
|
+
<span>${m(t)}</span>
|
|
25
|
+
</li>`}async function Qe(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">${n("app.subtitle")}</p>
|
|
29
|
+
<h1>${n("overview.title")}</h1>
|
|
30
|
+
<p>${n("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>${n("overview.recentSessions")}</h2>
|
|
39
|
+
<p>${n("sessions.subtitle")}</p>
|
|
40
40
|
</div>
|
|
41
|
-
<a class="btn-link" href="#/sessions">${
|
|
41
|
+
<a class="btn-link" href="#/sessions">${n("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>${n("overview.nextSchedules")}</h2>
|
|
49
|
+
<p>${n("schedules.subtitle")}</p>
|
|
50
50
|
</div>
|
|
51
|
-
<a class="btn-link" href="#/schedules">${
|
|
51
|
+
<a class="btn-link" href="#/schedules">${n("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"),o=e.querySelector("#recent-sessions"),r=e.querySelector("#next-schedules");function s(){let a=[...O.sessions.values()],d=[...O.schedules.values()],f=a.filter(L=>L.status!=="closed"),y=a.filter(L=>L.status==="working"||L.status==="analyzing"||L.status==="starting"),S=d.filter(L=>L.enabled),b=Re.bots?.length||new Set(a.map(L=>L.larkAppId).filter(Boolean)).size,k=[{label:n("overview.openSessions"),value:f.length,meta:`${a.length} ${n("overview.total")}`},{label:n("overview.workingSessions"),value:y.length,meta:`${f.length} ${n("overview.active")}`},{label:n("overview.onlineBots"),value:b,meta:n("overview.daemonRegistry")},{label:n("overview.schedules"),value:d.length,meta:`${S.length} ${n("overview.enabledSchedules")}`},{label:n("overview.groups"),value:Re.chats?.length??0,meta:n("overview.chatMatrix")}];t.innerHTML=k.map(L=>`<article class="metric-card">
|
|
57
|
+
<span>${m(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>${m(L.meta)}</small>
|
|
60
|
+
</article>`).join("");let l=a.sort((L,g)=>Number(g.lastMessageAt??0)-Number(L.lastMessageAt??0)).slice(0,6);o.innerHTML=l.length?l.map(L=>_t({...L,title:L.title??`${re(L.lastMessageAt)} \xB7 ${L.sessionId}`})).join(""):`<li class="empty">${n("overview.noSessions")}</li>`;let T=d.filter(L=>L.nextRunAt).sort((L,g)=>Date.parse(L.nextRunAt)-Date.parse(g.nextRunAt)).slice(0,6);r.innerHTML=T.length?T.map(Jt).join(""):`<li class="empty">${n("overview.noSchedules")}</li>`}O.on(s),s(),Ft().then(s)}function V(e,t){return`<th data-sort="${e}" data-label="${m(t)}">${m(t)}</th>`}var Xe=["claude-code","codex","cursor","gemini","opencode","aiden","coco","unknown"];function Gt(){return`<div class="filter-check-group" role="group" aria-label="${n("sessions.cli")}">
|
|
61
|
+
<span class="filter-check-label">${n("sessions.cli")}</span>
|
|
62
|
+
${Xe.map(e=>`
|
|
63
63
|
<label class="filter-check">
|
|
64
|
-
<input type="checkbox" name="cli" value="${
|
|
65
|
-
<span>${
|
|
64
|
+
<input type="checkbox" name="cli" value="${m(e)}" checked>
|
|
65
|
+
<span>${m(e)}</span>
|
|
66
66
|
</label>
|
|
67
67
|
`).join("")}
|
|
68
|
-
</div>`}function
|
|
68
|
+
</div>`}function zt(){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">${n("nav.sessions")}</p>
|
|
72
|
+
<h1>${n("sessions.title")}</h1>
|
|
73
|
+
<p>${n("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="${n("sessions.search")}" />
|
|
78
78
|
<select name="status">
|
|
79
|
-
<option value="">${
|
|
79
|
+
<option value="">${n("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="">${n("sessions.adoptAny")}</option>
|
|
85
|
+
<option value="yes">${n("sessions.adoptYes")}</option>
|
|
86
|
+
<option value="no">${n("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> ${n("sessions.activeOnly")}</label>
|
|
89
|
+
${Gt()}
|
|
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">${n("sessions.closeSelected")}</button>
|
|
94
|
+
<button type="button" id="bulk-clear">${n("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="${n("sessions.activeOnly")}"></th>
|
|
99
|
+
${V("botName",n("sessions.bot"))}
|
|
100
|
+
${V("cliId",n("sessions.cli"))}
|
|
101
|
+
${V("status",n("sessions.status"))}
|
|
102
|
+
${V("title",n("sessions.titleCol"))}
|
|
103
|
+
${V("workingDir",n("sessions.workingDir"))}
|
|
104
|
+
${V("spawnedAt",n("sessions.created"))}
|
|
105
|
+
${V("lastMessageAt",n("sessions.last"))}
|
|
106
|
+
${V("adopt",n("sessions.adopt"))}
|
|
107
|
+
<th>${n("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 Ze(e){e.innerHTML=zt();let t=e.querySelector("#sessions-table tbody"),o=e.querySelector("#filters"),r=e.querySelector("#drawer"),s=e.querySelector("#select-all"),a=e.querySelector("#bulk-bar"),d=e.querySelector("#bulk-count"),f=e.querySelector("#bulk-close"),y=e.querySelector("#bulk-clear"),S=e.querySelector("#sessions-table"),b=new Set,k="lastMessageAt",l="desc";function T(c){let p=c.status==="closed",h=b.has(c.sessionId)?"checked":"";return`<tr data-id="${m(c.sessionId)}">
|
|
113
|
+
<td><input type="checkbox" class="row-select" ${h} ${p?"disabled":""}></td>
|
|
114
|
+
<td>${m(c.botName??"")}</td>
|
|
115
|
+
<td><span class="badge cli-${m(c.cliId??"unknown")}">${m(c.cliId??"unknown")}</span></td>
|
|
116
|
+
<td><span class="status status-${m(c.status??"unknown")}">${m(c.status??"unknown")}</span></td>
|
|
117
|
+
<td>${m((c.title??"").slice(0,48))}</td>
|
|
118
|
+
<td title="${m(c.workingDir??"")}">${m((c.workingDir??"").slice(-34))}</td>
|
|
119
|
+
<td>${re(c.spawnedAt)}</td>
|
|
120
|
+
<td>${re(c.lastMessageAt)}</td>
|
|
121
|
+
<td>${c.adopt?'<span class="badge">adopt</span>':""}</td>
|
|
122
|
+
<td><button class="open" type="button">${n("sessions.details")}</button></td>
|
|
123
|
+
</tr>`}function L(){let c=new FormData(o),p=(c.get("q")??"").toLowerCase(),h=c.getAll("cli"),E=h.length>0&&h.length<Xe.length,A=c.get("status"),R=c.get("adopt"),q=!!c.get("active"),B=[...O.sessions.values()].filter(D=>!E||h.includes(D.cliId??"unknown")).filter(D=>!A||D.status===A).filter(D=>!R||R==="yes"==!!D.adopt).filter(D=>!q||D.status!=="closed").filter(D=>!p||JSON.stringify(D).toLowerCase().includes(p));return B.sort(u),B}function g(c,p){return p==="spawnedAt"||p==="lastMessageAt"?Number(c[p]??0):p==="adopt"?!!c.adopt:String(c[p]??"").toLowerCase()}function u(c,p){let h=g(c,k),E=g(p,k),A=0;return typeof h=="number"&&typeof E=="number"?A=h-E:typeof h=="boolean"&&typeof E=="boolean"?A=Number(h)-Number(E):A=String(h).localeCompare(String(E)),A===0&&(A=Number(c.lastMessageAt??0)-Number(p.lastMessageAt??0)),l==="asc"?A:-A}function I(){S.querySelectorAll("th[data-sort]").forEach(c=>{let p=c.dataset.sort===k;c.classList.toggle("sorted",p),c.setAttribute("aria-sort",p?l==="asc"?"ascending":"descending":"none");let h=c.dataset.label??c.textContent?.trim()??"";c.textContent=p?`${h} ${l==="asc"?"\u25B2":"\u25BC"}`:h})}function $(c){a.hidden=b.size===0,d.textContent=n("sessions.selectedCount",{count:b.size});let p=c.filter(E=>E.status!=="closed");if(p.length===0){s.checked=!1,s.indeterminate=!1,s.disabled=!0;return}s.disabled=!1;let h=p.filter(E=>b.has(E.sessionId)).length;s.checked=h===p.length,s.indeterminate=h>0&&h<p.length}function v(){let c=L();for(let p of[...b]){let h=O.sessions.get(p);(!h||h.status==="closed")&&b.delete(p)}t.innerHTML=c.length?c.map(T).join(""):`<tr><td colspan="10" class="empty">${n("sessions.empty")}</td></tr>`,I(),$(c)}function M(c){let p=c.status==="closed";r.innerHTML=`<article>
|
|
124
124
|
<header>
|
|
125
|
-
<h3>${
|
|
126
|
-
<span class="status status-${
|
|
127
|
-
<p><code>${
|
|
125
|
+
<h3>${m(c.title??c.sessionId)}</h3>
|
|
126
|
+
<span class="status status-${m(c.status??"unknown")}">${m(c.status??"unknown")}</span>
|
|
127
|
+
<p><code>${m(c.sessionId)}</code> <button data-copy="${m(c.sessionId)}">${n("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>${n("sessions.bot")}:</b> ${m(c.botName??"-")} \xB7 <b>${n("sessions.cli")}:</b> ${m(c.cliId??"?")}</p>
|
|
130
|
+
<p><b>chatId:</b> <code>${m(c.chatId??"")}</code> <button data-copy="${m(c.chatId??"")}">${n("sessions.copy")}</button></p>
|
|
131
|
+
<p><b>rootMessageId:</b> <code>${m(c.rootMessageId??"")}</code> <button data-copy="${m(c.rootMessageId??"")}">${n("sessions.copy")}</button></p>
|
|
132
|
+
${c.threadId?`<p><b>threadId:</b> <code>${m(c.threadId)}</code></p>`:""}
|
|
133
|
+
<p><b>${n("sessions.workingDir")}:</b> ${m(c.workingDir??"-")}</p>
|
|
134
134
|
<div class="actions">
|
|
135
|
-
<button id="locate-btn" type="button">${
|
|
136
|
-
${
|
|
137
|
-
${
|
|
138
|
-
${
|
|
135
|
+
<button id="locate-btn" type="button">${n("sessions.locate")}</button>
|
|
136
|
+
${c.webPort?`<a class="btn-link primary" href="http://${m(location.hostname)}:${c.webPort}" target="_blank" rel="noopener">${n("sessions.openTerminal")}</a>`:""}
|
|
137
|
+
${p?`<button id="resume-btn" type="button" class="primary">${n("sessions.resume")}</button>`:""}
|
|
138
|
+
${p?"":`<button id="close-btn" type="button" class="contrast">${n("sessions.close")}</button>`}
|
|
139
139
|
</div>
|
|
140
|
-
<form method="dialog"><button>${
|
|
141
|
-
</article>`,
|
|
140
|
+
<form method="dialog"><button>${n("sessions.dismiss")}</button></form>
|
|
141
|
+
</article>`,r.querySelectorAll("[data-copy]").forEach(R=>{R.onclick=()=>{navigator.clipboard.writeText(R.dataset.copy??""),R.textContent=n("sessions.copied"),setTimeout(()=>{R.textContent=n("sessions.copy")},800)}});let h=r.querySelector("#locate-btn");h&&(h.onclick=async()=>{h.disabled=!0,h.textContent=n("sessions.locating");try{let R=await fetch(`/api/sessions/${encodeURIComponent(c.sessionId)}/locate`,{method:"POST"}),q=await R.json();if(q.ok){let B=30;h.textContent=n("sessions.cooldown",{seconds:B});let D=setInterval(()=>{B-=1,B<=0?(clearInterval(D),h.disabled=!1,h.textContent=n("sessions.locate")):h.textContent=n("sessions.cooldown",{seconds:B})},1e3)}else alert(`Locate failed: ${q.error??R.status}`),h.disabled=!1,h.textContent=n("sessions.locate")}catch(R){alert(`Locate error: ${R}`),h.disabled=!1,h.textContent=n("sessions.locate")}});let E=r.querySelector("#resume-btn");E&&(E.onclick=async()=>{E.disabled=!0;try{let R=await fetch(`/api/sessions/${encodeURIComponent(c.sessionId)}/resume`,{method:"POST"}),q=await R.json().catch(()=>({}));if(!R.ok||q.ok===!1){alert(`${n("sessions.resumeFailed")}: ${q?.error??R.status}`),E.disabled=!1;return}r.close()}catch(R){alert(`${n("sessions.resumeFailed")}: ${R}`),E.disabled=!1}});let A=r.querySelector("#close-btn");A&&(A.onclick=async()=>{if(confirm(n("sessions.closeConfirm"))){A.disabled=!0;try{await fetch(`/api/sessions/${encodeURIComponent(c.sessionId)}/close`,{method:"POST"})}finally{r.close()}}}),r.showModal()}t.addEventListener("click",c=>{let p=c.target;if(p.classList.contains("row-select")){let R=p.closest("tr[data-id]");if(!R)return;p.checked?b.add(R.dataset.id):b.delete(R.dataset.id),$(L());return}let h=p.closest("td");if(h&&h.querySelector(".row-select"))return;let E=p.closest("tr[data-id]");if(!E)return;let A=O.sessions.get(E.dataset.id);A&&M(A)}),s.addEventListener("change",()=>{let c=L().filter(p=>p.status!=="closed");for(let p of c)s.checked?b.add(p.sessionId):b.delete(p.sessionId);v()}),y.addEventListener("click",()=>{b.clear(),v()}),f.addEventListener("click",async()=>{let c=[...b];if(c.length===0||!confirm(n("sessions.closeBulkConfirm",{count:c.length})))return;f.disabled=!0,y.disabled=!0;let p=f.textContent,h=0,E=0,A=[...c];f.textContent=`0/${c.length}`;async function R(){for(;A.length;){let q=A.shift();try{let B=await fetch(`/api/sessions/${encodeURIComponent(q)}/close`,{method:"POST"}),D=await B.json().catch(()=>({}));(!B.ok||D?.ok===!1)&&(E+=1)}catch{E+=1}finally{h+=1,f.textContent=`${h}/${c.length}`}}}await Promise.all(Array.from({length:Math.min(6,c.length)},()=>R())),f.textContent=p,f.disabled=!1,y.disabled=!1,b.clear(),v(),E>0&&alert(`Failed: ${E}/${c.length}`)}),S.querySelectorAll("th[data-sort]").forEach(c=>{c.addEventListener("click",()=>{let p=c.dataset.sort;k===p?l=l==="asc"?"desc":"asc":(k=p,l=p==="spawnedAt"||p==="lastMessageAt"?"desc":"asc"),v()})}),o.addEventListener("input",v),O.on(v),v()}function Kt(){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">${n("nav.schedules")}</p>
|
|
145
|
+
<h1>${n("schedules.title")}</h1>
|
|
146
|
+
<p>${n("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="${n("schedules.search")}" />
|
|
151
151
|
<select name="kind">
|
|
152
|
-
<option value="">${
|
|
152
|
+
<option value="">${n("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"> ${n("schedules.enabledOnly")}</label>
|
|
158
158
|
</form>
|
|
159
159
|
<table>
|
|
160
160
|
<thead><tr>
|
|
161
|
-
<th>${
|
|
162
|
-
<th>${
|
|
161
|
+
<th>${n("schedules.name")}</th><th>${n("schedules.bot")}</th><th>${n("schedules.schedule")}</th><th>${n("schedules.next")}</th><th>${n("schedules.last")}</th>
|
|
162
|
+
<th>${n("schedules.repeat")}</th><th>${n("schedules.enabled")}</th><th>${n("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 et(e){if(!e)return"\u2014";try{return new Date(e).toLocaleString()}catch{return e}}function tt(e){e.innerHTML=Kt();let t=e.querySelector("#schedules-tbody"),o=e.querySelector("#sched-filters");function r(){let a=new FormData(o),d=(a.get("q")??"").toLowerCase(),f=a.get("kind"),y=!!a.get("enabled");return[...O.schedules.values()].filter(S=>!f||S.parsed?.kind===f).filter(S=>!y||S.enabled).filter(S=>!d||JSON.stringify(S).toLowerCase().includes(d)).sort((S,b)=>{if(S.enabled!==b.enabled)return S.enabled?-1:1;let k=S.nextRunAt?Date.parse(S.nextRunAt):1/0,l=b.nextRunAt?Date.parse(b.nextRunAt):1/0;return k-l})}function s(){t.innerHTML=r().map(a=>`<tr data-id="${m(a.id)}">
|
|
167
|
+
<td>${m(a.name??a.id)}</td>
|
|
168
|
+
<td>${m(a.botName??a.larkAppId??"-")}</td>
|
|
169
|
+
<td><code>${m(a.parsed?.display??"?")}</code></td>
|
|
170
|
+
<td>${et(a.nextRunAt)}</td>
|
|
171
|
+
<td>${et(a.lastRunAt)} ${a.lastStatus==="error"?"\u26A0\uFE0F":""}</td>
|
|
172
|
+
<td>${a.repeat?`${a.repeat.completed}/${a.repeat.times??"\u221E"}`:"\u2014"}</td>
|
|
173
|
+
<td>${a.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">${n("schedules.runNow")}</button>
|
|
176
|
+
${a.enabled?`<button data-op="pause" type="button">${n("schedules.pause")}</button>`:`<button data-op="resume" type="button">${n("schedules.resume")}</button>`}
|
|
177
177
|
</td>
|
|
178
|
-
</tr>`).join("")||`<tr><td colspan="8" class="empty">${
|
|
178
|
+
</tr>`).join("")||`<tr><td colspan="8" class="empty">${n("schedules.empty")}</td></tr>`}t.addEventListener("click",async a=>{let d=a.target.closest("button[data-op]");if(!d)return;let f=d.closest("tr[data-id]");if(!f)return;let y=f.dataset.id,S=d.dataset.op;d.disabled=!0;let b=d.textContent;d.textContent="...";try{let k=await fetch(`/api/schedules/${encodeURIComponent(y)}/${S}`,{method:"POST"}),l=await k.json().catch(()=>({}));(!k.ok||l.ok===!1)&&alert(`Failed: ${k.status} ${l?.error??""}`.trim())}catch(k){alert("Network error: "+k)}finally{d.disabled=!1,d.textContent=b}}),o.addEventListener("input",s),O.on(s),s()}var N={chats:[],bots:[]};function Vt(){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">${n("nav.groups")}</p>
|
|
182
|
+
<h1>${n("groups.title")}</h1>
|
|
183
|
+
<p>${n("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="${n("groups.search")}" />
|
|
188
|
+
<label><input type="checkbox" name="missing"> ${n("groups.missingOnly")}</label>
|
|
189
|
+
<button type="button" id="g-refresh">${n("groups.refresh")}</button>
|
|
190
|
+
<button type="button" id="g-create" class="primary">${n("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 te(){N=await(await fetch("/api/groups")).json()}async function Yt(){return(await fetch("/api/groups")).json()}function Qt(e,t){if(t.size===0)return!0;let o=e?.memberBots??[];for(let r of t)if(!o.some(s=>s.larkAppId===r&&s.inChat))return!1;return!0}function nt(e,t){return e.filter(o=>!t||!t.has(o.larkAppId)).map(o=>`
|
|
198
198
|
<label class="checkbox-row">
|
|
199
|
-
<input type="checkbox" name="bot" value="${
|
|
200
|
-
${
|
|
199
|
+
<input type="checkbox" name="bot" value="${m(o.larkAppId)}">
|
|
200
|
+
${m(o.botName??o.larkAppId)} <small>(${m(o.larkAppId)})</small>
|
|
201
201
|
</label>
|
|
202
|
-
`).join("")}async function
|
|
202
|
+
`).join("")}async function ot(e){e.innerHTML=Vt();let t=e.querySelector("#g-head"),o=e.querySelector("#g-body"),r=e.querySelector("#g-filters"),s=e.querySelector("#g-refresh"),a=e.querySelector("#g-drawer");s.onclick=async()=>{s.disabled=!0;try{await te(),b()}finally{s.disabled=!1}};let d=e.querySelector("#g-create");d.onclick=()=>f(),await te();function f(){let l=N.bots;if(l.length===0){alert(n("groups.noBotsOnline"));return}a.innerHTML=`
|
|
203
203
|
<article>
|
|
204
|
-
<header><h3>${
|
|
205
|
-
<p>${
|
|
204
|
+
<header><h3>${n("groups.createTitle")}</h3></header>
|
|
205
|
+
<p>${n("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>${n("groups.name")}</span>
|
|
209
|
+
<input type="text" name="name" placeholder="${n("groups.namePlaceholder")}" maxlength="60">
|
|
210
210
|
</label>
|
|
211
211
|
<label class="form-row">
|
|
212
|
-
<span>${
|
|
212
|
+
<span>${n("groups.bindDir")}</span>
|
|
213
213
|
<input type="text" name="bindWorkingDir" placeholder="e.g. ~/projects/botmux">
|
|
214
|
-
<small>${
|
|
214
|
+
<small>${n("groups.bindDirHelp")}</small>
|
|
215
215
|
</label>
|
|
216
216
|
<fieldset>
|
|
217
|
-
<legend>${
|
|
218
|
-
${
|
|
217
|
+
<legend>${n("groups.botPicker")}</legend>
|
|
218
|
+
${nt(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">${n("groups.createSubmit")}</button>
|
|
222
|
+
<button type="button" id="g-create-cancel">${n("groups.cancel")}</button>
|
|
223
223
|
</div>
|
|
224
224
|
</form>
|
|
225
|
-
</article>`,
|
|
225
|
+
</article>`,a.showModal(),a.querySelector("#g-create-cancel").onclick=()=>a.close(),a.querySelector("#g-createform").onsubmit=async g=>{g.preventDefault();let u=new FormData(g.target),I=(u.get("name")??"").trim(),$=(u.get("bindWorkingDir")??"").trim(),v=u.getAll("bot");if(v.length===0){alert("Pick at least one bot.");return}let M=g.target.querySelector("button[type=submit]");M&&(M.disabled=!0,M.textContent="Creating...");try{let c=await fetch("/api/groups/create",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:I||void 0,larkAppIds:v,bindWorkingDir:$||void 0})}),p=await c.json();if(p.ok&&p.chatId){y(p);let h=Array.isArray(p.invalidBotIds)?p.invalidBotIds:[],E=v.filter(R=>!h.includes(R)),A=new Set(E);typeof p.creator=="string"&&p.creator&&A.add(p.creator),T(p.chatId,I||p.chatId,E,p.creator),b(),L(p.chatId,A).catch(()=>{})}else alert(`Failed: ${p.error??c.status}`),a.close()}catch(c){alert("Network error: "+c),a.close()}};function T(g,u,I,$){let v=new Set(I);$&&v.add($);let M=N.bots.map(p=>({larkAppId:p.larkAppId,botName:p.botName,inChat:v.has(p.larkAppId),oncallChat:null})),c={chatId:g,name:u,ownerId:$??null,memberBots:M};N.chats=[c,...N.chats.filter(p=>p.chatId!==g)]}async function L(g,u){let I=[600,1200,1200,1200,1200,1200];for(let $ of I){await new Promise(c=>setTimeout(c,$));let v;try{v=await Yt()}catch{continue}let M=(v.chats??[]).find(c=>c.chatId===g);if(M&&Qt(M,u)){N=v,b();return}}}}function y(l){let T=String(l.chatId),L=`https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent(T)}`,g=l.invalidBotIds??[],u=l.invalidUserIds??[],I=l.autoInvitedOpenId,$=!!l.autoInviteRejected,v=l.ownerTransferredTo,M=l.transferError,c=l.notifyMessageId,p=l.notifyError,h=Array.isArray(l.oncallBindings)?l.oncallBindings:[],E=h.filter(D=>D?.ok).length,A=h.filter(D=>!D?.ok),R=h.length>0?A.length===0?`<p class="hint-ok">\u5DF2\u7ED1\u5B9A\u76EE\u5F55\uFF1A<code>${m(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${A.map(D=>`<br><code>${m(D.larkAppId??"?")}</code>: ${m(D.error??"unknown")}`).join("")}</p>`:"",q;if(I){let D=v?"<br><small>\u7FA4\u4E3B\u5DF2\u4ECE\u673A\u5668\u4EBA\u8F6C\u8BA9\u7ED9\u4F60\u3002</small>":M?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8\u8F6C\u8BA9\u7FA4\u4E3B\u5931\u8D25\uFF08${m(M)}\uFF09\uFF0C\u4F60\u73B0\u5728\u662F\u6210\u5458\u4F46\u7FA4\u4E3B\u4ECD\u662F\u673A\u5668\u4EBA\u3002</small>`:"",Te=c?`<br><small>\u673A\u5668\u4EBA\u5DF2\u5728\u7FA4\u91CC @ \u4E86\u4F60\uFF08\u6D88\u606F id <code>${m(c)}</code>\uFF09\uFF0C\u770B\u98DE\u4E66\u901A\u77E5\u5C31\u80FD\u8FDB\u7FA4\u3002</small>`:p?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8 @ \u901A\u77E5\u5931\u8D25\uFF08${m(p)}\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>`:"";q=`<p class="hint-ok">\u5DF2\u81EA\u52A8\u9080\u8BF7\u4F60\uFF08<code>${m(I)}</code>\uFF09\u4F5C\u4E3A\u6210\u5458\u3002${D}${Te}</p>`}else $?q='<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>':q='<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 B=[g.length?`<li>\u65E0\u6548 bot id: <code>${g.map(m).join(", ")}</code></li>`:"",u.length?`<li>\u65E0\u6548\u7528\u6237 open_id: <code>${u.map(m).join(", ")}</code></li>`:""].filter(Boolean).join("");a.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>${n("groups.successTitle")}</h3></header>
|
|
228
|
+
<p><b>chatId:</b> <code>${m(T)}</code> <button type="button" data-copy="${m(T)}">${n("sessions.copy")}</button></p>
|
|
229
|
+
<p><b>\u521B\u5EFA\u8005:</b> <code>${m(l.creator??"?")}</code></p>
|
|
230
|
+
${q}
|
|
231
|
+
${R}
|
|
232
|
+
${B?`<ul>${B}</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">${n("groups.openGroup")}</a>
|
|
235
|
+
<button type="button" id="g-create-close">${n("sessions.dismiss")}</button>
|
|
236
236
|
</div>
|
|
237
|
-
</article>`,
|
|
238
|
-
<th>${
|
|
239
|
-
${
|
|
240
|
-
<th>${
|
|
241
|
-
</tr>`}function
|
|
237
|
+
</article>`,a.querySelectorAll("[data-copy]").forEach(D=>{D.onclick=()=>{navigator.clipboard.writeText(D.dataset.copy??""),D.textContent=n("sessions.copied"),setTimeout(()=>{D.textContent=n("sessions.copy")},800)}}),a.querySelector("#g-create-close").onclick=()=>a.close()}function S(){t.innerHTML=`<tr>
|
|
238
|
+
<th>${n("groups.chat")}</th>
|
|
239
|
+
${N.bots.map(l=>`<th>${m(l.botName??l.larkAppId)}</th>`).join("")}
|
|
240
|
+
<th>${n("groups.actions")}</th>
|
|
241
|
+
</tr>`}function b(){S();let l=new FormData(r),T=(l.get("q")??"").toLowerCase(),L=!!l.get("missing"),g=N.chats.filter(u=>!T||(u.name??"").toLowerCase().includes(T)||u.chatId.toLowerCase().includes(T)||(u.ownerId??"").toLowerCase().includes(T)).filter(u=>!L||u.memberBots.some(I=>!I.inChat));if(g.length===0){o.innerHTML=`<tr><td colspan="${N.bots.length+2}" class="empty">${n("groups.empty")}</td></tr>`;return}o.innerHTML=g.map(u=>`<tr data-chat="${m(u.chatId)}">
|
|
242
242
|
<td>
|
|
243
|
-
<strong>${
|
|
244
|
-
<small><code>${
|
|
243
|
+
<strong>${m(u.name??u.chatId)}</strong><br>
|
|
244
|
+
<small><code>${m(u.chatId)}</code></small>
|
|
245
245
|
</td>
|
|
246
|
-
${
|
|
246
|
+
${N.bots.map(I=>{let $=u.memberBots.find(c=>c.larkAppId===I.larkAppId),v=$?$.error?"!":$.inChat?"\u2713":"\u2717":"?";return`<td class="${$?$.error?"cell-error":$.inChat?"cell-in":"cell-out":"cell-unknown"}" title="${m($?.error??"")}">${v}</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">${n("groups.addBots")}</button>
|
|
249
|
+
<button class="manage-chat" type="button">${n("groups.manage")}</button>
|
|
250
250
|
</td>
|
|
251
|
-
</tr>`).join("")}
|
|
251
|
+
</tr>`).join("")}b(),o.addEventListener("click",async l=>{let T=l.target.closest("button.add-bots");if(!T)return;let g=T.closest("tr[data-chat]").dataset.chat,u=N.chats.find(v=>v.chatId===g);if(!u)return;let I=new Set(u.memberBots.filter(v=>v.inChat).map(v=>v.larkAppId));if(!N.bots.filter(v=>!I.has(v.larkAppId)).length){alert("All configured bots are already in this chat.");return}a.innerHTML=`
|
|
252
252
|
<article>
|
|
253
|
-
<header><h3>${
|
|
254
|
-
<p>${
|
|
253
|
+
<header><h3>${n("groups.addBots")} \xB7 ${m(u.name??u.chatId)}</h3></header>
|
|
254
|
+
<p>${n("groups.createHelp")}</p>
|
|
255
255
|
<form id="g-addform">
|
|
256
|
-
${
|
|
256
|
+
${nt(N.bots,I)}
|
|
257
257
|
<div class="actions">
|
|
258
|
-
<button type="submit" class="primary">${
|
|
259
|
-
<button type="button" id="g-cancel">${
|
|
258
|
+
<button type="submit" class="primary">${n("groups.addBots")}</button>
|
|
259
|
+
<button type="button" id="g-cancel">${n("groups.cancel")}</button>
|
|
260
260
|
</div>
|
|
261
261
|
</form>
|
|
262
|
-
</article>`,
|
|
263
|
-
`);alert(E),await
|
|
262
|
+
</article>`,a.showModal(),a.querySelector("#g-cancel").onclick=()=>a.close(),a.querySelector("#g-addform").onsubmit=async v=>{v.preventDefault();let c=new FormData(v.target).getAll("bot");if(c.length===0){alert("Pick at least one bot.");return}try{let h=await(await fetch(`/api/groups/${encodeURIComponent(g)}/add-bots`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:c})})).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(A=>`${A.id}: ${A.ok?"OK":`failed (${A.error??"unknown"})`}`).join(`
|
|
263
|
+
`);alert(E),await te(),b()}else alert(`Unexpected response: ${JSON.stringify(h)}`)}catch(p){alert("Network error: "+p)}finally{a.close()}}}),o.addEventListener("click",async l=>{let T=l.target.closest("button.manage-chat");if(!T)return;let g=T.closest("tr[data-chat]").dataset.chat,u=N.chats.find(I=>I.chatId===g);u&&k(u)});function k(l){let T=l.memberBots.filter(g=>g.inChat),L=typeof l.ownerId=="string"?l.ownerId:"";a.innerHTML=`
|
|
264
264
|
<article>
|
|
265
|
-
<header><h3>${
|
|
266
|
-
<p><b>chatId:</b> <code>${
|
|
267
|
-
<p><b>${
|
|
265
|
+
<header><h3>${n("groups.manageTitle",{name:l.name??l.chatId})}</h3></header>
|
|
266
|
+
<p><b>chatId:</b> <code>${m(l.chatId)}</code></p>
|
|
267
|
+
<p><b>${n("groups.owner")}:</b> <code>${m(l.ownerId??n("common.unknown"))}</code></p>
|
|
268
268
|
|
|
269
269
|
<fieldset>
|
|
270
|
-
<legend>${
|
|
271
|
-
<p><small>${
|
|
272
|
-
${
|
|
273
|
-
<div class="oncall-row" data-bot="${
|
|
270
|
+
<legend>${n("groups.oncall")}</legend>
|
|
271
|
+
<p><small>${n("groups.oncallHelp")}</small></p>
|
|
272
|
+
${T.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':T.map(g=>{let u=!!g.oncallChat,I=g.oncallChat?.workingDir??"";return`
|
|
273
|
+
<div class="oncall-row" data-bot="${m(g.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" ${u?"checked":""}>
|
|
276
|
+
<strong>${m(g.botName??g.larkAppId)}</strong>
|
|
277
|
+
<small>(${m(g.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="${m(I)}" ${u?"":"disabled"}>
|
|
282
|
+
<button type="button" data-action="save">${n("groups.save")}</button>
|
|
283
283
|
<span class="oncall-status" data-status></span>
|
|
284
284
|
</div>
|
|
285
285
|
</div>
|
|
@@ -287,135 +287,94 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
287
287
|
</fieldset>
|
|
288
288
|
|
|
289
289
|
<fieldset>
|
|
290
|
-
<legend>${
|
|
291
|
-
${
|
|
290
|
+
<legend>${n("groups.leaveTitle")}</legend>
|
|
291
|
+
${T.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':T.map(g=>`
|
|
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="${m(g.larkAppId)}">
|
|
294
|
+
${m(g.botName??g.larkAppId)}
|
|
295
|
+
<small>${g.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" ${T.length===0?"disabled":""}>${n("groups.leaveSelected")}</button>
|
|
302
|
+
<button id="g-disband-btn" type="button" class="contrast" ${T.length===0?"disabled":""}>${n("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>${n("groups.dangerHint")}</small></p>
|
|
305
|
+
<form method="dialog"><button>${n("sessions.dismiss")}</button></form>
|
|
306
|
+
</article>`,a.showModal(),a.querySelectorAll(".oncall-row").forEach(g=>{let u=g.dataset.bot,I=g.querySelector("input[data-action=toggle]"),$=g.querySelector("input[data-input=workingDir]"),v=g.querySelector("button[data-action=save]"),M=g.querySelector("[data-status]");I.addEventListener("change",()=>{$.disabled=!I.checked,I.checked&&$.focus()}),v.addEventListener("click",async()=>{M.textContent="",M.className="oncall-status";let c=I.checked,p=$.value.trim();if(c&&!p){M.textContent=n("groups.needWorkingDir"),M.classList.add("hint-warn-inline");return}v.disabled=!0;try{let h=`/api/groups/${encodeURIComponent(l.chatId)}/oncall/${encodeURIComponent(u)}`,E=c?await fetch(h,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({workingDir:p})}):await fetch(h,{method:"DELETE"}),A=await E.json().catch(()=>({}));if(E.ok&&A.ok){M.textContent=c?`\u2713 \u5DF2\u7ED1\u5B9A \u2192 ${A.resolvedPath??p}`:"\u2713 \u5DF2\u89E3\u7ED1",M.classList.add("hint-ok");try{await te(),b()}catch{}}else M.textContent=`\u2717 ${A.error??E.status}`,M.classList.add("hint-warn-inline")}catch(h){M.textContent=`\u2717 ${h?.message??h}`,M.classList.add("hint-warn-inline")}finally{v.disabled=!1}})}),a.querySelector("#g-leave-btn").onclick=async()=>{let g=[...a.querySelectorAll("input[name=leave-bot]:checked")].map(u=>u.value);if(g.length===0){alert("\u81F3\u5C11\u9009\u4E00\u4E2A\u673A\u5668\u4EBA");return}if(confirm(`\u786E\u5B9A\u8BA9 ${g.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 I=await(await fetch(`/api/groups/${encodeURIComponent(l.chatId)}/leave`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:g})})).json(),$=(I.result??[]).map(v=>{if(!v.ok)return`${v.larkAppId}: \u5931\u8D25 (${v.error??"unknown"})`;let M=v.closedSessions??[],c=M.filter(E=>!E.ok).length,p=M.length-c,h=M.length===0?"":c===0?`\uFF08\u5173\u95ED ${p} \u4E2A\u4F1A\u8BDD\uFF09`:`\uFF08\u5173\u95ED ${p} \u4E2A\uFF0C${c} \u4E2A\u5931\u8D25\uFF09`;return`${v.larkAppId}: OK${h}`}).join(`
|
|
307
|
+
`);alert($||`Unexpected: ${JSON.stringify(I)}`),await te(),b()}catch(u){alert("Network error: "+u)}finally{a.close()}},a.querySelector("#g-disband-btn").onclick=async()=>{if(T.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 g=[...T].sort((I,$)=>($.larkAppId===L?1:0)-(I.larkAppId===L?1:0)),u=[];for(let I of g)try{let $=await fetch(`/api/groups/${encodeURIComponent(l.chatId)}/disband`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppId:I.larkAppId})}),v=await $.json();if(v.ok){let M=v.closedSessions??[],c=M.filter(E=>!E.ok).length,p=M.length-c,h=M.length===0?"":c===0?`
|
|
308
|
+
\u5173\u95ED\u4E86 ${p} \u4E2A\u4F1A\u8BDD\u3002`:`
|
|
309
|
+
\u5173\u95ED\u4E86 ${p} \u4E2A\u4F1A\u8BDD\uFF0C${c} \u4E2A\u4F1A\u8BDD\u5173\u95ED\u5931\u8D25\u3002`;alert(`\u5DF2\u89E3\u6563\uFF08\u7531 ${I.botName??I.larkAppId} \u6267\u884C\uFF09${h}`),await te(),b(),a.close();return}u.push(`${I.botName??I.larkAppId}: ${v.error??$.status}`)}catch($){u.push(`${I.botName??I.larkAppId}: ${$}`)}alert(`\u6240\u6709\u5728\u7FA4\u673A\u5668\u4EBA\u5747\u65E0\u6CD5\u89E3\u6563\uFF1A
|
|
310
|
+
${u.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`)}}r.addEventListener("input",b)}var ne={bots:[]},oe=null;function Xt(){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">${n("nav.botDefaults")}</p>
|
|
317
|
+
<h1>${n("botDefaults.title")}</h1>
|
|
318
|
+
<p>${n("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="${n("botDefaults.search")}" />
|
|
323
|
+
<button type="button" id="bd-refresh">${n("botDefaults.refresh")}</button>
|
|
324
324
|
</form>
|
|
325
|
+
<p class="hint-warn" style="max-width:760px">
|
|
326
|
+
${n("botDefaults.warning")}
|
|
327
|
+
</p>
|
|
325
328
|
<div id="bd-list"></div>
|
|
326
|
-
</section>`}async function
|
|
327
|
-
<header><strong>${
|
|
328
|
-
<small>${
|
|
329
|
-
<p class="hint-warn-inline">\u67E5\u8BE2\u5931\u8D25\uFF1A${
|
|
330
|
-
</article>`;let
|
|
329
|
+
</section>`}async function st(){try{let e=await fetch("/api/bots"),t=await e.json().catch(()=>({}));if(!e.ok){oe=t?.error?`HTTP ${e.status}: ${t.error}${t.path?` (${t.path})`:""}`:`HTTP ${e.status}`,ne={bots:[]};return}if(!t||!Array.isArray(t.bots)){oe="unexpected response shape (no `bots` array)",ne={bots:[]};return}oe=null,ne=t}catch(e){oe=e?.message??String(e),ne={bots:[]}}}function at(e){if(!e)return"\u2014";let t=new Date(e);return Number.isNaN(t.getTime())?"\u2014":t.toLocaleString()}async function rt(e){e.innerHTML=Xt();let t=e.querySelector("#bd-list"),o=e.querySelector("#bd-filters"),r=e.querySelector("#bd-refresh");r.onclick=async()=>{r.disabled=!0;try{await st(),s()}finally{r.disabled=!1}},await st();function s(){let y=(new FormData(o).get("q")??"").toLowerCase(),S=ne.bots.filter(b=>!y||(b.botName??"").toLowerCase().includes(y)||(b.larkAppId??"").toLowerCase().includes(y));if(oe){t.innerHTML=`<p class="hint-warn">\u65E0\u6CD5\u52A0\u8F7D bot \u5217\u8868\uFF1A${m(oe)}<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(S.length===0){t.innerHTML=`<p class="empty">${n("botDefaults.empty")}</p>`;return}t.innerHTML=S.map(a).join(""),d()}function a(f){if(f.error)return`<article class="bd-card" data-appid="${m(f.larkAppId)}">
|
|
330
|
+
<header><strong>${m(f.botName??f.larkAppId)}</strong>
|
|
331
|
+
<small>${m(f.larkAppId)}</small></header>
|
|
332
|
+
<p class="hint-warn-inline">\u67E5\u8BE2\u5931\u8D25\uFF1A${m(f.error)}</p>
|
|
333
|
+
</article>`;let y=f.defaultOncall??{enabled:!1,workingDir:"",since:0},S=!!y.enabled;return`<article class="bd-card" data-appid="${m(f.larkAppId)}">
|
|
331
334
|
<header>
|
|
332
|
-
<strong>${
|
|
333
|
-
<small>${
|
|
335
|
+
<strong>${m(f.botName??f.larkAppId)}</strong>
|
|
336
|
+
<small>${m(f.larkAppId)}</small>
|
|
334
337
|
</header>
|
|
335
338
|
<div class="bd-body">
|
|
336
|
-
<
|
|
337
|
-
<
|
|
338
|
-
<
|
|
339
|
-
|
|
340
|
-
<strong>${o("botDefaults.defaultOncall")}</strong>
|
|
341
|
-
<small>${o("botDefaults.defaultOncallHelp")}</small>
|
|
342
|
-
</label>
|
|
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??"")}">
|
|
339
|
+
<label class="checkbox-row">
|
|
340
|
+
<input type="checkbox" data-action="toggle" ${S?"checked":""}>
|
|
341
|
+
<strong>${n("botDefaults.defaultOncall")}</strong>
|
|
342
|
+
<small>${n("botDefaults.defaultOncallHelp")}</small>
|
|
371
343
|
</label>
|
|
372
|
-
<
|
|
373
|
-
|
|
344
|
+
<div class="bd-row">
|
|
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"}>
|
|
349
|
+
</label>
|
|
350
|
+
</div>
|
|
351
|
+
<div class="bd-meta">
|
|
352
|
+
<small>${n("botDefaults.lastEnabled")}: ${m(at(y.since??0))}</small>
|
|
353
|
+
<small>${n("botDefaults.autobound",{count:f.autoboundChatCount??0})}</small>
|
|
354
|
+
</div>
|
|
374
355
|
<div class="actions">
|
|
375
|
-
<button type="button" data-action="save
|
|
376
|
-
<
|
|
377
|
-
<span class="oncall-status" data-brand-status></span>
|
|
356
|
+
<button type="button" data-action="save">${n("botDefaults.save")}</button>
|
|
357
|
+
<span class="oncall-status" data-status></span>
|
|
378
358
|
</div>
|
|
379
359
|
</div>
|
|
380
|
-
</
|
|
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">
|
|
360
|
+
</article>`}function d(){t.querySelectorAll(".bd-card").forEach(f=>{let y=f.dataset.appid,S=f.querySelector("input[data-action=toggle]"),b=f.querySelector("input[data-input=workingDir]"),k=f.querySelector("button[data-action=save]"),l=f.querySelector("[data-status]");!S||!b||!k||!l||(S.addEventListener("change",()=>{b.disabled=!S.checked,S.checked&&b.focus()}),k.addEventListener("click",async()=>{l.textContent="",l.className="oncall-status";let T=S.checked,L=b.value.trim();if(T&&!L){l.textContent=n("botDefaults.required"),l.classList.add("hint-warn-inline");return}k.disabled=!0;try{let g=await fetch(`/api/bots/${encodeURIComponent(y)}/default-oncall`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:T,workingDir:L})}),u=await g.json().catch(()=>({}));if(g.ok&&u.ok){let I=u.resolvedPath?` \u2192 ${u.resolvedPath}`:"";l.textContent=T?`\u2713 \u5DF2\u5F00\u542F${I}\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",l.classList.add("hint-ok");let $=ne.bots.find(M=>M.larkAppId===y);$&&u.defaultOncall&&($.defaultOncall=u.defaultOncall);let v=f.querySelector(".bd-meta small:first-child");v&&u.defaultOncall?.since!=null&&(v.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${at(u.defaultOncall.since)}`)}else l.textContent=`\u2717 ${u.error??g.status}`,l.classList.add("hint-warn-inline")}catch(g){l.textContent=`\u2717 ${g?.message??g}`,l.classList.add("hint-warn-inline")}finally{k.disabled=!1}}))})}s(),o.addEventListener("input",s)}var xe=4096,ve=[],W=null,_=null,j="",se=new Set;function Zt(){return`<section class="page roles-page">
|
|
402
361
|
<div class="page-heading">
|
|
403
362
|
<div>
|
|
404
|
-
<p class="eyebrow">${
|
|
405
|
-
<h1>${
|
|
406
|
-
<p>${
|
|
363
|
+
<p class="eyebrow">${n("nav.roles")}</p>
|
|
364
|
+
<h1>${n("roles.title")}</h1>
|
|
365
|
+
<p>${n("roles.subtitle")}</p>
|
|
407
366
|
</div>
|
|
408
367
|
</div>
|
|
409
368
|
<div class="roles-layout">
|
|
410
369
|
<div class="roles-tree-panel">
|
|
411
370
|
<div class="roles-tree-header">
|
|
412
|
-
<input type="search" id="roles-search" placeholder="${
|
|
413
|
-
<button type="button" id="roles-refresh">${
|
|
371
|
+
<input type="search" id="roles-search" placeholder="${n("roles.search")}" />
|
|
372
|
+
<button type="button" id="roles-refresh">${n("roles.refresh")}</button>
|
|
414
373
|
</div>
|
|
415
374
|
<div id="roles-tree" class="roles-tree"></div>
|
|
416
375
|
</div>
|
|
417
376
|
<div class="roles-editor-panel">
|
|
418
|
-
<div id="roles-editor-empty" class="roles-editor-empty">${
|
|
377
|
+
<div id="roles-editor-empty" class="roles-editor-empty">${n("roles.selectHint")}</div>
|
|
419
378
|
<div id="roles-editor-form" class="roles-editor-form" style="display:none">
|
|
420
379
|
<div class="roles-editor-breadcrumb">
|
|
421
380
|
<span id="roles-editor-group-name"></span>
|
|
@@ -425,205 +384,82 @@ ${f.join(`
|
|
|
425
384
|
<div class="roles-editor-meta">
|
|
426
385
|
<span id="roles-editor-chat-id" class="roles-editor-meta-line"></span>
|
|
427
386
|
</div>
|
|
428
|
-
<textarea id="roles-editor-textarea" placeholder="${
|
|
387
|
+
<textarea id="roles-editor-textarea" placeholder="${n("roles.editorPlaceholder")}" rows="14"></textarea>
|
|
429
388
|
<div class="roles-editor-footer">
|
|
430
389
|
<span id="roles-editor-bytecount" class="roles-bytecount"></span>
|
|
431
390
|
<div class="roles-editor-actions">
|
|
432
|
-
<button type="button" id="roles-delete" class="danger">${
|
|
433
|
-
<button type="button" id="roles-save" class="primary">${
|
|
391
|
+
<button type="button" id="roles-delete" class="danger">${n("roles.delete")}</button>
|
|
392
|
+
<button type="button" id="roles-save" class="primary">${n("roles.save")}</button>
|
|
434
393
|
</div>
|
|
435
394
|
</div>
|
|
436
395
|
<div id="roles-preview" class="roles-preview"></div>
|
|
437
396
|
</div>
|
|
438
397
|
</div>
|
|
439
398
|
</div>
|
|
440
|
-
</section>`}async function
|
|
441
|
-
<div class="roles-bot-row ${
|
|
442
|
-
data-group-id="${
|
|
443
|
-
data-bot-id="${
|
|
399
|
+
</section>`}async function be(){ve=((await(await fetch("/api/groups")).json()).chats??[]).map(o=>({chatId:o.chatId,name:o.name??o.chatId,memberBots:(o.memberBots??[]).map(r=>({larkAppId:r.larkAppId,botName:r.botName??r.larkAppId,inChat:r.inChat??!1,hasRole:r.hasRole??!1,oncallChat:r.oncallChat??null}))}))}async function lt(e,t){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)).json()}async function en(e,t,o){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({content:o})})).ok}async function tn(e,t){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{method:"DELETE"})).ok}function dt(e){return e.memberBots.filter(t=>t.inChat&&t.hasRole).length}function nn(e){return e.memberBots.filter(t=>t.inChat).length}function Z(e=""){let t=document.getElementById("roles-tree");if(!t)return;let o=e.toLowerCase(),r=ve.filter(s=>{if(!o)return!0;let a=s.chatId.toLowerCase().includes(o)||(s.name??"").toLowerCase().includes(o),d=s.memberBots.some(f=>f.larkAppId.toLowerCase().includes(o)||(f.botName??"").toLowerCase().includes(o));return a||d});if(r.length===0){t.innerHTML=`<div class="roles-empty">${n("roles.noChats")}</div>`;return}t.innerHTML=r.map(s=>{let a=se.has(s.chatId),d=s.memberBots.filter(k=>k.inChat),f=a?"\u25BE":"\u25B8",y=dt(s),S=nn(s),b=a?d.map(k=>`
|
|
400
|
+
<div class="roles-bot-row ${W===s.chatId&&_===k.larkAppId?"selected":""}"
|
|
401
|
+
data-group-id="${m(s.chatId)}"
|
|
402
|
+
data-bot-id="${m(k.larkAppId)}">
|
|
444
403
|
<span class="roles-bot-indent"></span>
|
|
445
404
|
<span class="roles-bot-icon">\u{1F916}</span>
|
|
446
405
|
<div class="roles-bot-info">
|
|
447
|
-
<div class="roles-bot-name">${
|
|
448
|
-
<div class="roles-bot-id">${
|
|
406
|
+
<div class="roles-bot-name">${m(k.botName)}</div>
|
|
407
|
+
<div class="roles-bot-id">${m(k.larkAppId)}</div>
|
|
449
408
|
</div>
|
|
450
|
-
<span class="roles-badge ${
|
|
451
|
-
${
|
|
409
|
+
<span class="roles-badge ${k.hasRole?"has-role":"no-role"}">
|
|
410
|
+
${k.hasRole?n("roles.configured"):n("roles.unconfigured")}
|
|
452
411
|
</span>
|
|
453
412
|
</div>`).join(""):"";return`
|
|
454
413
|
<div class="roles-group-section">
|
|
455
|
-
<div class="roles-group-row ${
|
|
456
|
-
data-group-id="${
|
|
457
|
-
<span class="roles-group-arrow">${
|
|
414
|
+
<div class="roles-group-row ${a?"expanded":""} ${W===s.chatId&&!_?"selected":""}"
|
|
415
|
+
data-group-id="${m(s.chatId)}">
|
|
416
|
+
<span class="roles-group-arrow">${f}</span>
|
|
458
417
|
<span class="roles-group-icon">\u{1F4C1}</span>
|
|
459
418
|
<div class="roles-group-info">
|
|
460
|
-
<div class="roles-group-name">${
|
|
419
|
+
<div class="roles-group-name">${m(s.name??s.chatId)}</div>
|
|
461
420
|
<div class="roles-group-meta">
|
|
462
|
-
${
|
|
421
|
+
${y}/${S} ${n("roles.botsWithRoles")}
|
|
463
422
|
</div>
|
|
464
423
|
</div>
|
|
465
424
|
<span class="roles-group-chevron"></span>
|
|
466
425
|
</div>
|
|
467
|
-
<div class="roles-bot-list">${
|
|
468
|
-
</div>`}).join(""),t.querySelectorAll(".roles-group-row").forEach(
|
|
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`
|
|
426
|
+
<div class="roles-bot-list">${b}</div>
|
|
427
|
+
</div>`}).join(""),t.querySelectorAll(".roles-group-row").forEach(s=>{s.addEventListener("click",()=>{let a=s.dataset.groupId;a&&(se.has(a)?se.delete(a):se.add(a),Z(document.getElementById("roles-search")?.value??""))})}),t.querySelectorAll(".roles-bot-row").forEach(s=>{s.addEventListener("click",a=>{a.stopPropagation();let d=s.dataset.groupId,f=s.dataset.botId;d&&f&&on(d,f)})})}async function on(e,t){W=e,_=t;let o=await lt(t,e),r=document.getElementById("roles-editor-empty"),s=document.getElementById("roles-editor-form"),a=document.getElementById("roles-editor-textarea"),d=document.getElementById("roles-editor-group-name"),f=document.getElementById("roles-editor-bot-name"),y=document.getElementById("roles-editor-chat-id");r&&(r.style.display="none"),s&&(s.style.display="");let S=ve.find(l=>l.chatId===e),b=S?.memberBots.find(l=>l.larkAppId===t);d&&(d.textContent=S?.name??e),f&&(f.textContent=b?.botName??t),y&&(y.textContent=`${e} \xB7 ${t}`),j=o.content??"",a&&(a.value=j,a.focus()),De(),Oe(),Z(document.getElementById("roles-search")?.value??"");let k=document.getElementById("roles-delete");k&&(k.style.display=o.hasRole?"":"none")}function De(){let e=document.getElementById("roles-editor-bytecount");if(!e)return;let t=new TextEncoder().encode(j).length;e.textContent=`${t} / ${xe} bytes`,e.className=`roles-bytecount ${t>3800?"warn":""} ${t>xe?"over":""}`,sn(t)}function sn(e){let t=document.getElementById("roles-save");if(!t)return;let o=e??new TextEncoder().encode(j).length;t.disabled=o>xe||j.trim().length===0}function Oe(){let e=document.getElementById("roles-preview");e&&(j.trim()?e.innerHTML=`<strong>${n("roles.preview")}</strong><pre>${m(j)}</pre>`:e.innerHTML=`<small>${n("roles.previewEmpty")}</small>`)}function it(){W=null,_=null,j="";let e=document.getElementById("roles-editor-empty"),t=document.getElementById("roles-editor-form"),o=document.getElementById("roles-editor-textarea"),r=document.getElementById("roles-delete");e&&(e.style.display=""),t&&(t.style.display="none"),o&&(o.value=""),r&&(r.style.display="none")}async function ct(e){e.innerHTML=Zt(),se.clear(),it(),await be();for(let t of ve)dt(t)>0&&se.add(t.chatId);Z(),document.getElementById("roles-search")?.addEventListener("input",t=>{Z(t.target.value)}),document.getElementById("roles-refresh")?.addEventListener("click",async()=>{if(await be(),Z(document.getElementById("roles-search")?.value??""),W&&_){let t=await lt(_,W),o=document.getElementById("roles-editor-textarea");o&&(o.value=t.content??""),j=t.content??"",De(),Oe();let r=document.getElementById("roles-delete");r&&(r.style.display=t.hasRole?"":"none")}}),document.getElementById("roles-save")?.addEventListener("click",async function(){if(!(!W||!_)){this.disabled=!0,this.textContent="...";try{if(await en(_,W,j)){await be(),Z(document.getElementById("roles-search")?.value??"");let o=document.getElementById("roles-delete");o&&(o.style.display="");let r=document.createElement("span");r.className="roles-saved-flash",r.textContent=` ${n("roles.saved")}`,document.querySelector(".roles-editor-footer")?.appendChild(r),setTimeout(()=>r.remove(),2e3)}else{let o=document.createElement("span");o.className="roles-saved-flash roles-save-error",o.textContent=j.trim().length===0?` ${n("roles.emptyError")}`:` ${n("roles.saveFailed")}`,document.querySelector(".roles-editor-footer")?.appendChild(o),setTimeout(()=>o.remove(),3e3)}}finally{this.disabled=!1,this.textContent=n("roles.save")}}}),document.getElementById("roles-delete")?.addEventListener("click",async function(){if(!(!W||!_)&&confirm(n("roles.confirmDelete"))){this.disabled=!0,this.textContent="...";try{await tn(_,W)&&(await be(),it(),Z(document.getElementById("roles-search")?.value??""))}finally{this.disabled=!1,this.textContent=n("roles.delete")}}}),document.getElementById("roles-editor-textarea")?.addEventListener("input",t=>{j=t.target.value,De(),Oe()})}function an(){let e=[["",n("workflow.filter.nonTerminal")],["all",n("workflow.filter.all")],["pending",Y("pending")],["running",Y("running")],["waiting",Y("waiting")],["succeeded",Y("succeeded")],["failed",Y("failed")],["cancelled",Y("cancelled")]];return`
|
|
592
428
|
<nav class="wf-subnav">
|
|
593
|
-
<a href="#/workflows" class="active" data-i18n="workflow.subnav.runs">${
|
|
594
|
-
<a href="#/workflows/catalog" data-i18n="workflow.subnav.catalog">${
|
|
429
|
+
<a href="#/workflows" class="active" data-i18n="workflow.subnav.runs">${i(n("workflow.subnav.runs"))}</a>
|
|
430
|
+
<a href="#/workflows/catalog" data-i18n="workflow.subnav.catalog">${i(n("workflow.subnav.catalog"))}</a>
|
|
595
431
|
</nav>
|
|
596
432
|
<form id="wf-filters" class="filters">
|
|
597
|
-
<input type="search" name="q" placeholder="${
|
|
433
|
+
<input type="search" name="q" placeholder="${i(n("workflow.searchPlaceholder"))}" />
|
|
598
434
|
<select name="status">
|
|
599
|
-
${e.map(([t,
|
|
435
|
+
${e.map(([t,o])=>`<option value="${i(t)}">${i(o)}</option>`).join("")}
|
|
600
436
|
</select>
|
|
601
437
|
<span id="wf-last-load" class="muted"></span>
|
|
602
438
|
</form>
|
|
603
439
|
<table>
|
|
604
440
|
<thead><tr>
|
|
605
|
-
<th>${
|
|
606
|
-
<th>${
|
|
607
|
-
<th>${
|
|
441
|
+
<th>${i(n("workflow.table.run"))}</th><th>${i(n("workflow.table.workflow"))}</th><th>${i(n("workflow.table.status"))}</th>
|
|
442
|
+
<th>${i(n("workflow.table.lastSeq"))}</th><th>${i(n("workflow.table.dangling"))}</th><th>${i(n("workflow.table.updated"))}</th>
|
|
443
|
+
<th>${i(n("workflow.table.chatApp"))}</th>
|
|
608
444
|
</tr></thead>
|
|
609
445
|
<tbody id="wf-tbody"></tbody>
|
|
610
446
|
</table>
|
|
611
|
-
`}var
|
|
612
|
-
<td><a href="#/workflows/${encodeURIComponent(
|
|
613
|
-
<td>${
|
|
614
|
-
<td>${
|
|
615
|
-
<td>${
|
|
616
|
-
<td class="${
|
|
617
|
-
<td title="${
|
|
618
|
-
<td>${
|
|
619
|
-
</tr>`}).join("")}function
|
|
447
|
+
`}var rn=5e3,ln=2e3,ie=new Set(["succeeded","failed","cancelled"]);function i(e){return e.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function dn(e){let t=new Date(e),r=Date.now()-e;return r<6e4?n("time.secondsAgo",{value:Math.max(1,Math.floor(r/1e3))}):r<36e5?n("time.minutesAgo",{value:Math.floor(r/6e4)}):r<864e5?n("time.hoursAgo",{value:Math.floor(r/36e5)}):t.toISOString().slice(0,19).replace("T"," ")}function G(e){return`<span class="${ie.has(e)?"wf-status terminal":"wf-status live"} wf-status-${i(e)}">${i(Y(e))}</span>`}function Y(e){let t=`workflow.status.${e}`,o=n(t);return o===t?e:o}function mt(e){let t=location.hash.match(/^#\/workflows\/([^?#]+)(?:\?([^#]*))?$/);if(t){let o=new URLSearchParams(t[2]??"");return un(e,decodeURIComponent(t[1]),{focusAttemptId:o.get("attempt")??void 0})}return cn(e)}function cn(e){e.innerHTML=an();let t=e.querySelector("#wf-tbody"),o=e.querySelector("#wf-filters"),r=e.querySelector("#wf-last-load"),s=[],a=null,d=!1,f=null,y=!1;function S(g){let I=(new FormData(o).get("q")??"").trim().toLowerCase();return I?g.filter($=>$.runId.toLowerCase().includes(I)||$.workflowId.toLowerCase().includes(I)||($.chatId??"").toLowerCase().includes(I)):g}function b(){let g=S(s);if(g.length===0){t.innerHTML=`<tr><td colspan="7" class="empty">${f?i(n("workflow.list.failedLoad",{error:f})):s.length===0?i(n("workflow.list.noRuns")):i(n("workflow.list.noFilterMatch"))}</td></tr>`;return}t.innerHTML=g.map(u=>{let I=`${u.dEf}/${u.dAct}/${u.dWait}`,$=u.dEf+u.dAct+u.dWait>0?"wf-dangling has":"wf-dangling none",v=[];u.chatId&&v.push(i(u.chatId)),u.larkAppId&&v.push(`<span class="muted">${i(u.larkAppId)}</span>`);let M=v.length>0?v.join("<br/>"):"\u2014",c=pn(u);return`<tr data-runid="${i(u.runId)}">
|
|
448
|
+
<td><a href="#/workflows/${encodeURIComponent(u.runId)}"><code>${i(u.runId)}</code></a></td>
|
|
449
|
+
<td>${i(u.workflowId)}</td>
|
|
450
|
+
<td>${G(u.status)}${u.failedNodeId?` <span class="muted">(${i(u.failedNodeId)})</span>`:""}${c}</td>
|
|
451
|
+
<td>${u.lastSeq}</td>
|
|
452
|
+
<td class="${$}">${I}</td>
|
|
453
|
+
<td title="${i(new Date(u.updatedAt).toISOString())}">${dn(u.updatedAt)}</td>
|
|
454
|
+
<td>${M}</td>
|
|
455
|
+
</tr>`}).join("")}function k(){f?(r.textContent=n("workflow.list.error",{error:f}),r.classList.add("error")):(r.textContent=n("workflow.list.loaded",{count:s.length,time:new Date().toLocaleTimeString()}),r.classList.remove("error"))}async function l(){if(!(y||d)&&!document.hidden){d=!0;try{let g=o.elements.namedItem("status")?.value??"",u=new URLSearchParams;g==="all"?u.set("all","1"):g&&u.set("status",g);let I="/api/workflows/runs"+(u.toString()?`?${u}`:""),$=await fetch(I);$.ok?(s=(await $.json()).runs??[],f=null):(f=`HTTP ${$.status}`,s=[])}catch(g){f=g?.message??String(g),s=[]}finally{d=!1,y||(b(),k())}}}function T(){a!==null&&window.clearTimeout(a),a=window.setTimeout(async()=>{await l(),y||T()},rn)}function L(){document.hidden||l()}return o.addEventListener("input",()=>{b()}),o.addEventListener("change",g=>{g.target.getAttribute("name")==="status"&&l()}),document.addEventListener("visibilitychange",L),l().then(()=>{y||T()}),()=>{y=!0,a!==null&&window.clearTimeout(a),document.removeEventListener("visibilitychange",L)}}function un(e,t,o={}){e.innerHTML=`
|
|
620
456
|
<div class="wf-detail-head">
|
|
621
|
-
<a class="btn-link" href="#/workflows">${
|
|
457
|
+
<a class="btn-link" href="#/workflows">${i(n("workflow.detail.back"))}</a>
|
|
622
458
|
<div>
|
|
623
|
-
<h2><code>${
|
|
624
|
-
<div id="wf-detail-subtitle" class="muted">${
|
|
459
|
+
<h2><code>${i(t)}</code></h2>
|
|
460
|
+
<div id="wf-detail-subtitle" class="muted">${i(n("workflow.detail.loading"))}</div>
|
|
625
461
|
</div>
|
|
626
|
-
<button id="wf-cancel-run" type="button" class="contrast" hidden>${
|
|
462
|
+
<button id="wf-cancel-run" type="button" class="contrast" hidden>${i(n("workflow.detail.cancel"))}</button>
|
|
627
463
|
<span id="wf-detail-refresh" class="muted"></span>
|
|
628
464
|
</div>
|
|
629
465
|
<section id="wf-detail-error" class="hint-warn" hidden></section>
|
|
@@ -632,20 +468,20 @@ ${Bt("manage")}
|
|
|
632
468
|
<section id="wf-dangling-panel"></section>
|
|
633
469
|
<section class="wf-panel">
|
|
634
470
|
<div class="wf-panel-title">
|
|
635
|
-
<h3>${
|
|
471
|
+
<h3>${i(n("workflow.detail.parallel"))}</h3>
|
|
636
472
|
<span id="wf-parallel-meta" class="muted"></span>
|
|
637
473
|
</div>
|
|
638
474
|
<div id="wf-parallel-view"></div>
|
|
639
475
|
</section>
|
|
640
476
|
<section class="wf-panel">
|
|
641
477
|
<div class="wf-panel-title">
|
|
642
|
-
<h3>${
|
|
478
|
+
<h3>${i(n("workflow.detail.nodes"))}</h3>
|
|
643
479
|
</div>
|
|
644
480
|
<div class="wf-table-scroll">
|
|
645
481
|
<table>
|
|
646
482
|
<thead><tr>
|
|
647
|
-
<th>${
|
|
648
|
-
<th>${
|
|
483
|
+
<th>${i(n("workflow.detail.node"))}</th><th>${i(n("workflow.detail.nodeStatus"))}</th><th>${i(n("workflow.detail.activity"))}</th><th>${i(n("workflow.detail.activityStatus"))}</th>
|
|
484
|
+
<th>${i(n("workflow.detail.attempts"))}</th><th>${i(n("workflow.detail.current"))}</th><th>${i(n("workflow.detail.detail"))}</th>
|
|
649
485
|
</tr></thead>
|
|
650
486
|
<tbody id="wf-node-tbody"></tbody>
|
|
651
487
|
</table>
|
|
@@ -653,237 +489,237 @@ ${Bt("manage")}
|
|
|
653
489
|
</section>
|
|
654
490
|
<section class="wf-panel">
|
|
655
491
|
<div class="wf-panel-title">
|
|
656
|
-
<h3>${
|
|
492
|
+
<h3>${i(n("workflow.detail.nodeIO"))}</h3>
|
|
657
493
|
</div>
|
|
658
494
|
<div id="wf-io-list" class="wf-io-list"></div>
|
|
659
495
|
</section>
|
|
660
496
|
<section class="wf-panel">
|
|
661
497
|
<div class="wf-panel-title">
|
|
662
|
-
<h3>${
|
|
663
|
-
<button id="wf-load-older" type="button" hidden>${
|
|
498
|
+
<h3>${i(n("workflow.detail.timeline"))}</h3>
|
|
499
|
+
<button id="wf-load-older" type="button" hidden>${i(n("workflow.detail.loadOlder"))}</button>
|
|
664
500
|
</div>
|
|
665
501
|
<div class="wf-table-scroll wf-timeline-scroll">
|
|
666
502
|
<table>
|
|
667
503
|
<thead><tr>
|
|
668
|
-
<th>${
|
|
504
|
+
<th>${i(n("workflow.detail.seq"))}</th><th>${i(n("workflow.detail.event"))}</th><th>${i(n("workflow.detail.actor"))}</th><th>${i(n("workflow.detail.node"))}</th><th>${i(n("workflow.detail.activity"))}</th><th>${i(n("workflow.detail.error"))}</th><th>${i(n("workflow.detail.time"))}</th>
|
|
669
505
|
</tr></thead>
|
|
670
506
|
<tbody id="wf-event-tbody"></tbody>
|
|
671
507
|
</table>
|
|
672
508
|
</div>
|
|
673
509
|
<div id="wf-event-meta" class="muted"></div>
|
|
674
510
|
</section>
|
|
675
|
-
`;let
|
|
676
|
-
<span class="muted error">${
|
|
677
|
-
</div>`}function
|
|
511
|
+
`;let r=e.querySelector("#wf-detail-subtitle"),s=e.querySelector("#wf-detail-refresh"),a=e.querySelector("#wf-detail-error"),d=e.querySelector("#wf-cancel-status"),f=e.querySelector("#wf-summary"),y=e.querySelector("#wf-dangling-panel"),S=e.querySelector("#wf-parallel-view"),b=e.querySelector("#wf-parallel-meta"),k=e.querySelector("#wf-node-tbody"),l=e.querySelector("#wf-io-list"),T=e.querySelector(".wf-timeline-scroll"),L=e.querySelector("#wf-event-tbody"),g=e.querySelector("#wf-event-meta"),u=e.querySelector("#wf-cancel-run"),I=e.querySelector("#wf-load-older"),$=null,v=[],M=new Set,c=null,p=null,h=!1,E=0,A=null,R=!1,q=!1,B=!1,D=new Set,Te=new Map,Ne=new Map,ue=new Map,fe=new Set,pe=new Map,X=new Set,ae=new Map,At=new Map,je=0,Ue=o.focusAttemptId;function U(w){if(!w){a.hidden=!0,a.textContent="";return}a.hidden=!1,a.textContent=w}function Fe(w){if(!w){d.hidden=!0,d.textContent="";return}d.hidden=!1,d.textContent=w}async function We(){let w=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/snapshot`);if(w.status===404)throw new Error(n("workflow.detail.unknownRun"));if(!w.ok)throw new Error(n("workflow.detail.snapshotHttp",{status:w.status}));$=await w.json()}async function me(w){let P=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/events?${w}`);if(P.status===404)throw new Error(n("workflow.detail.unknownRun"));if(!P.ok)throw new Error(n("workflow.detail.eventsHttp",{status:P.status}));return await P.json()}function we(w,P){let x=w.filter(H=>M.has(H.eventId)?!1:(M.add(H.eventId),!0));x.length!==0&&(v=P==="prepend"?[...x,...v]:[...v,...x],v.sort((H,z)=>le(H.eventId)-le(z.eventId)))}async function Ht(){await We();let w=await me(new URLSearchParams({tail:"100"}));v=[],M=new Set,we(w.events,"append"),c=w.oldestSeq,p=w.newestSeq,h=w.hasOlder,E=w.totalCount,F()}async function ge(){if(!(R||q||document.hidden)){q=!0;try{if(await We(),p!==null){let w=await me(new URLSearchParams({afterSeq:String(p),limit:"200"}));we(w.events,"append"),w.newestSeq!==null&&(p=w.newestSeq),c===null&&w.oldestSeq!==null&&(c=w.oldestSeq),E=w.totalCount}else{let w=await me(new URLSearchParams({tail:"1"}));we(w.events,"append"),c=w.oldestSeq,p=w.newestSeq,h=w.hasOlder,E=w.totalCount}U(null),F()}catch(w){U(w?.message??String(w))}finally{q=!1}}}async function Rt(){if(!(c===null||!h)){I.disabled=!0;try{let w=await me(new URLSearchParams({beforeSeq:String(c),limit:"100"}));we(w.events,"prepend"),w.oldestSeq!==null&&(c=w.oldestSeq),h=w.hasOlder,E=w.totalCount,U(null),F()}catch(w){U(w?.message??String(w))}finally{I.disabled=!1}}}async function xt(){if(!$||ie.has($.run.status)||B)return;if(!$.chatBinding?.larkAppId){U(n("workflow.detail.cancelUnavailable",{runId:t}));return}let w=mn($),P=n("workflow.detail.cancelConfirm",{runId:t,...w});if(window.confirm(P)){B=!0,u.disabled=!0;try{let x=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/cancel`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"cancelled via dashboard"})});if(x.status===401)throw new Error(n("workflow.detail.writeAccessCancel"));let H=await x.json().catch(()=>({}));if(!x.ok||!H.ok)throw new Error(H.hint??H.error??n("workflow.detail.cancelHttp",{status:x.status}));Fe(H.pending?n("workflow.detail.cancelPending"):null),U(null),await ge()}catch(x){U(x?.message??String(x))}finally{B=!1,u.disabled=!1,F()}}}async function Dt(w,P){if(!X.has(w)){X.add(w),ae.delete(w),F();try{let x=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/attempts/${encodeURIComponent(P)}/${encodeURIComponent(w)}/resume`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({})});if(x.status===401)throw new Error(n("workflow.detail.writeAccessResume"));let H=await x.json().catch(()=>({}));if(!x.ok||!H.ok||!H.resumeId||!H.url)throw new Error(H.hint??H.message??H.error??n("workflow.detail.resumeStartFailed",{status:x.status}));pe.set(w,{resumeId:H.resumeId,url:H.url})}catch(x){let H=x?.message??String(x);ae.set(w,H)}finally{X.delete(w),F()}}}async function Ot(w,P){if(!X.has(w)){X.add(w),ae.delete(w),F();try{let x=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/attempts/${encodeURIComponent(P)}/${encodeURIComponent(w)}/resume/end`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"ended_by_dashboard"})});if(x.status===401)throw new Error(n("workflow.detail.writeAccessResume"));let H=await x.json().catch(()=>({}));if(!x.ok||!H.ok)if(H.error==="resume_not_running")pe.delete(w);else throw new Error(H.hint??H.message??H.error??n("workflow.detail.resumeEndFailed",{status:x.status}));else pe.delete(w)}catch(x){let H=x?.message??String(x);ae.set(w,H)}finally{X.delete(w),F()}}}async function qt(w,P){if(!fe.has(w)){fe.add(w),ue.delete(w),F();try{let x=Ne.get(w)?.trim()||void 0,H=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/${P}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({comment:x})});if(H.status===401)throw new Error(n("workflow.detail.writeAccessApproval"));let z=await H.json().catch(()=>({}));if(!H.ok||!z.ok)throw new Error(z.hint??z.message??z.error??n("workflow.detail.actionHttp",{action:P,status:H.status}));let Ee=P==="approve"?n("workflow.detail.approved"):n("workflow.detail.rejected");ue.set(w,{kind:"ok",text:z.alreadyTerminal?n("workflow.detail.alreadyTerminal",{label:Ee}):z.pending?n("workflow.detail.workflowContinue",{label:Ee}):n("workflow.detail.workflowRefreshing",{label:Ee})}),U(null),await ge()}catch(x){let H=x?.message??String(x);ue.set(w,{kind:"error",text:H}),U(H)}finally{fe.delete(w),F()}}}function F(){if(!$)return;je=T.scrollTop;let w=$.run;ie.has(w.status)&&Fe(null),r.innerHTML=`${i(w.workflowId??"?")} \xB7 ${G(w.status)} \xB7 lastSeq ${$.lastSeq}`,s.textContent=n("workflow.detail.refreshed",{time:new Date().toLocaleTimeString()}),u.hidden=ie.has(w.status),u.disabled=B||!$.chatBinding?.larkAppId,u.textContent=$.chatBinding?.larkAppId?n("workflow.detail.cancel"):n("workflow.detail.cliCancelOnly"),u.title=$.chatBinding?.larkAppId?n("workflow.detail.cancelTitle"):n("workflow.detail.cliCancelTitle",{runId:t}),fn(f,$),wn(y,$),gn(S,b,$,v),$n(k,$),Sn(l,$,D,Te,{comments:Ne,statuses:ue,resolving:fe,onResolve:qt},{sessions:pe,pending:X,errors:ae,onStart:Dt,onEnd:Ot},Ue,At)&&(Ue=void 0),Vn(L,v),T.scrollTop=je,I.hidden=!h,g.textContent=n("workflow.detail.eventsLoaded",{loaded:v.length,total:E})}function Le(){if(A!==null&&window.clearTimeout(A),$&&ie.has($.run.status)){A=null;return}A=window.setTimeout(async()=>{await ge(),R||Le()},ln)}function _e(){document.hidden||ge().then(()=>{!R&&A===null&&Le()})}return I.addEventListener("click",()=>{Rt()}),u.addEventListener("click",()=>{xt()}),document.addEventListener("visibilitychange",_e),Ht().then(()=>{U(null),R||Le()}).catch(w=>{U(w?.message??String(w)),r.textContent=n("workflow.detail.loadFailed")}),()=>{R=!0,A!==null&&window.clearTimeout(A),document.removeEventListener("visibilitychange",_e)}}function fn(e,t){let o=t.run,r=[[n("workflow.summary.workflow"),i(o.workflowId??"?")],[n("workflow.summary.status"),G(o.status)],[n("workflow.summary.lastSeq"),String(t.lastSeq)],[n("workflow.summary.updated"),i(new Date(t.updatedAt).toLocaleString())],[n("workflow.summary.revision"),i($e(o.revisionId))],[n("workflow.summary.initiator"),i(o.initiator??"-")]];o.failedNodeId&&r.push([n("workflow.summary.failedNode"),i(o.failedNodeId)]),o.cancelOriginEventId&&r.push([n("workflow.summary.cancelOrigin"),i(o.cancelOriginEventId)]),t.chatBinding&&(r.push([n("workflow.summary.chat"),`<code>${i(t.chatBinding.chatId)}</code>`]),r.push([n("workflow.summary.app"),`<code>${i(t.chatBinding.larkAppId)}</code>`])),e.innerHTML=r.map(([s,a])=>`<div class="wf-summary-item"><span>${s}</span><strong>${a}</strong></div>`).join("")}function pn(e){if(!e.errorCode)return"";let t=e.errorMessage?` \u2014 ${Zn(e.errorMessage,96)}`:"";return`<div class="wf-run-error">
|
|
512
|
+
<span class="muted error">${i(e.errorCode)}</span>${i(t)}
|
|
513
|
+
</div>`}function mn(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 wn(e,t){let o=t.dangling,r=[[n("workflow.dangling.activities"),o.activities],[n("workflow.dangling.effects"),o.effectAttempted],[n("workflow.dangling.waits"),o.waits],[n("workflow.dangling.cancels"),o.cancels]],s=new Set(r.flatMap(([,a])=>a)).size;if(e.className=s>0?"wf-panel wf-dangling-panel has":"wf-panel wf-dangling-panel",s===0){e.innerHTML=`<div class="wf-panel-title"><h3>${i(n("workflow.detail.dangling"))}</h3></div><div class="muted">${i(n("workflow.detail.noDangling"))}</div>`;return}e.innerHTML=`<div class="wf-panel-title"><h3>${i(n("workflow.detail.dangling"))}</h3><span class="wf-dangling has">${s}</span></div>
|
|
678
514
|
<div class="wf-dangling-grid">
|
|
679
|
-
${
|
|
680
|
-
</div>`}function
|
|
681
|
-
<span title="${
|
|
682
|
-
<span title="${
|
|
515
|
+
${r.map(([a,d])=>`<div><strong>${a}</strong>${d.length===0?`<div class="muted">${i(n("workflow.detail.none"))}</div>`:`<ul>${d.map(f=>`<li><code>${i(f)}</code></li>`).join("")}</ul>`}</div>`).join("")}
|
|
516
|
+
</div>`}function gn(e,t,o,r){let s=hn(r,o);if(s.length===0){t.textContent="",e.innerHTML=`<div class="empty">${i(n("workflow.detail.noParallelData"))}</div>`;return}let a=Date.now(),d=Math.min(...s.map(l=>l.startedAt)),f=Math.max(...s.map(l=>l.endedAt??a),d+1e3),y=Math.max(1,f-d),S=vn(s,a),b=s.filter(l=>!l.endedAt&&(l.status==="running"||l.status==="effectAttempting")).length;t.textContent=n("workflow.detail.parallelMeta",{count:s.length,max:S,running:b});let k=s.sort((l,T)=>l.startedAt-T.startedAt||l.activityId.localeCompare(T.activityId)).map(l=>bn(l,d,y,a)).join("");e.innerHTML=`<div class="wf-parallel-axis">
|
|
517
|
+
<span title="${i(new Date(d).toISOString())}">${i(ke(d))}</span>
|
|
518
|
+
<span title="${i(new Date(f).toISOString())}">${i(ke(f))}</span>
|
|
683
519
|
</div>
|
|
684
|
-
<div class="wf-parallel-list">${
|
|
520
|
+
<div class="wf-parallel-list">${k}</div>`}function hn(e,t){let o=new Map,r=new Map(t.activities.map(s=>[s.activityId,s.ownerNodeId]));for(let s of[...e].sort((a,d)=>le(a.eventId)-le(d.eventId))){let a=Xn(s);if(!a)continue;let d=typeof a.activityId=="string"?a.activityId:void 0,f=typeof a.attemptId=="string"?a.attemptId:void 0;if(!d||!f)continue;let y=o.get(f);if(s.type==="attemptCreated"){let S=typeof a.attemptNumber=="number"?a.attemptNumber:void 0;y={nodeId:typeof a.nodeId=="string"?a.nodeId:r.get(d),activityId:d,attemptId:f,attemptNumber:S,status:"pending",startedAt:s.timestamp},o.set(f,y);continue}y||(y={nodeId:r.get(d),activityId:d,attemptId:f,status:"pending",startedAt:s.timestamp},o.set(f,y)),s.type==="activityRunning"?(y.status="running",y.runningAt=s.timestamp):s.type==="effectAttempted"?y.status="effectAttempting":s.type==="activityWaiting"||s.type==="waitCreated"?y.status="waiting":yn(s.type)&&(y.status=kn(s.type),y.endedAt=s.timestamp,y.endType=s.type)}return[...o.values()]}function bn(e,t,o,r){let s=e.endedAt??r,a=pt((e.startedAt-t)/o*100,0,100),d=pt((Math.max(s,e.startedAt+1)-e.startedAt)/o*100,.7,100-a),f=e.nodeId??e.activityId,y=e.attemptNumber!==void 0?`#${e.attemptNumber}`:$e(e.attemptId),S=[`${f} ${e.status}`,`${new Date(e.startedAt).toISOString()} \u2192 ${e.endedAt?new Date(e.endedAt).toISOString():n("workflow.detail.parallelNow")}`,e.endType?`end: ${e.endType}`:void 0].filter(Boolean).join(`
|
|
685
521
|
`);return`<div class="wf-parallel-row">
|
|
686
522
|
<div class="wf-parallel-label">
|
|
687
|
-
<code>${
|
|
688
|
-
<span class="muted">${
|
|
523
|
+
<code>${i(f)}</code>
|
|
524
|
+
<span class="muted">${i(e.activityId)} \xB7 ${i(y)}</span>
|
|
689
525
|
</div>
|
|
690
526
|
<div class="wf-parallel-track">
|
|
691
|
-
<div class="wf-parallel-bar wf-parallel-${
|
|
692
|
-
<span>${
|
|
527
|
+
<div class="wf-parallel-bar wf-parallel-${i(e.status)}" style="left:${a.toFixed(3)}%;width:${d.toFixed(3)}%;" title="${i(S)}">
|
|
528
|
+
<span>${i(Y(e.status))}</span>
|
|
693
529
|
</div>
|
|
694
530
|
</div>
|
|
695
|
-
</div>`}function
|
|
696
|
-
<td>${e?`<code>${
|
|
697
|
-
<td>${e?
|
|
698
|
-
<td>${t?`<code>${
|
|
699
|
-
<td>${t?
|
|
531
|
+
</div>`}function vn(e,t){let o=[];for(let a of e)o.push({time:a.startedAt,delta:1}),o.push({time:a.endedAt??t,delta:-1});o.sort((a,d)=>a.time-d.time||d.delta-a.delta);let r=0,s=0;for(let a of o)r+=a.delta,s=Math.max(s,r);return s}function yn(e){return e==="activitySucceeded"||e==="activityFailed"||e==="activityTimedOut"||e==="activityCanceled"}function kn(e){return e==="activitySucceeded"?"succeeded":e==="activityCanceled"?"cancelled":e==="activityTimedOut"?"timedOut":"failed"}function $n(e,t){let o=new Map(t.activities.map(a=>[a.activityId,a])),r=new Set,s=[];for(let a of t.nodes){let d=(a.activityId?o.get(a.activityId):void 0)??t.activities.find(f=>f.ownerNodeId===a.nodeId);d&&r.add(d.activityId),s.push(ut(a,d))}for(let a of t.activities)r.has(a.activityId)||s.push(ut(void 0,a));e.innerHTML=s.length>0?s.join(""):`<tr><td colspan="7" class="empty">${i(n("workflow.detail.noNodes"))}</td></tr>`}function ut(e,t){let o=t?.attempts[t.attempts.length-1];return`<tr>
|
|
532
|
+
<td>${e?`<code>${i(e.nodeId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
533
|
+
<td>${e?G(e.status):'<span class="muted">-</span>'}</td>
|
|
534
|
+
<td>${t?`<code>${i(t.activityId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
535
|
+
<td>${t?G(t.status):'<span class="muted">-</span>'}</td>
|
|
700
536
|
<td>${t?.attempts.length??0}</td>
|
|
701
|
-
<td>${
|
|
702
|
-
<td>${
|
|
703
|
-
</tr>`}function
|
|
537
|
+
<td>${o?`<code>${i(o.attemptId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
538
|
+
<td>${o?Kn(o):`<span class="muted">${i(n("workflow.detail.idle"))}</span>`}</td>
|
|
539
|
+
</tr>`}function Sn(e,t,o,r,s,a,d,f){Fn(e,o,r),Pn(e,s.comments);let y=!!(d&&t.attemptIO?.[d]?.terminal);y&&d&&o.add(qe(d,n("workflow.detail.liveTerminal")));let S=In(t),b=new Set;if(f){for(let l of S){b.add(l.key);let T=f.get(l.key);T||(T=Tn(l.key),f.set(l.key,T),e.appendChild(T.article)),Ln(T,l,o,s,a,d)}for(let[l,T]of Array.from(f))b.has(l)||(T.article.remove(),f.delete(l));if(S.length===0){if(!e.querySelector(".wf-io-empty-placeholder")){let l=document.createElement("div");l.className="empty wf-io-empty-placeholder",l.textContent=n("workflow.detail.noNodeIO"),e.appendChild(l)}}else e.querySelector(".wf-io-empty-placeholder")?.remove()}else{let l=[];for(let T of S)l.push(Hn(T,o,s,a,d));e.innerHTML=l.length>0?l.join(""):`<div class="empty">${i(n("workflow.detail.noNodeIO"))}</div>`}_n(e,r);let k=Un(e,d);return Wn(e,o),Jn(e,r),jn(e,s),St(e,a),k&&y}function In(e){let t=new Map(e.activities.map(s=>[s.activityId,s])),o=new Set,r=[];for(let s of e.nodes){let a=(s.activityId?t.get(s.activityId):void 0)??e.activities.find(d=>d.ownerNodeId===s.nodeId);if(!a){r.push({key:`node:${s.nodeId}`,node:s});continue}o.add(a.activityId),r.push({key:`activity:${a.activityId}`,node:s,activity:a,io:e.attemptIO?.[ye(a)?.attemptId??""]})}for(let s of e.activities)o.has(s.activityId)||r.push({key:`activity:${s.activityId}`,activity:s,io:e.attemptIO?.[ye(s)?.attemptId??""]});return r}function Tn(e){let t=document.createElement("article");t.className="wf-io-card",t.dataset.wfCardKey=e;let o=document.createElement("div");o.className="wf-io-card-head";let r=document.createElement("div");r.className="wf-io-terminal-slot";let s=document.createElement("div");return s.className="wf-io-grid",t.appendChild(o),t.appendChild(r),t.appendChild(s),{article:t,head:o,terminalSlot:r,grid:s,currentTerminalUrl:null}}function Ln(e,t,o,r,s,a){let d=ye(t.activity),f=t.node?.nodeId??t.activity?.ownerNodeId??t.activity?.activityId??"unknown",y=!!(d&&d.attemptId===a);e.article.classList.toggle("is-focused",y),d?e.article.dataset.wfAttemptCard=d.attemptId:delete e.article.dataset.wfAttemptCard;let S=$t(d,r);e.head.innerHTML=`
|
|
704
540
|
<header>
|
|
705
541
|
<div>
|
|
706
|
-
<strong><code>${
|
|
707
|
-
<span class="muted">${t.activity?
|
|
542
|
+
<strong><code>${i(f)}</code></strong>
|
|
543
|
+
<span class="muted">${t.activity?i(t.activity.activityId):i(n("workflow.detail.notDispatched"))}</span>
|
|
708
544
|
</div>
|
|
709
|
-
<div>${t.node?
|
|
545
|
+
<div>${t.node?G(t.node.status):""} ${t.activity?G(t.activity.status):""}</div>
|
|
710
546
|
</header>
|
|
711
547
|
<div class="wf-io-meta">
|
|
712
|
-
${
|
|
548
|
+
${d?`${i(n("workflow.detail.attempt"))} <code>${i(d.attemptId)}</code>`:i(n("workflow.detail.noAttempt"))}
|
|
713
549
|
</div>
|
|
714
|
-
${
|
|
715
|
-
`;let
|
|
716
|
-
${
|
|
717
|
-
${
|
|
718
|
-
${
|
|
719
|
-
${
|
|
720
|
-
${t.io?.waitPrompt?
|
|
721
|
-
`}function
|
|
722
|
-
<summary>${
|
|
550
|
+
${S}
|
|
551
|
+
`;let b=wt(d,t.activity,t.io?.terminal,s),k=b?.url??null;if(k!==e.currentTerminalUrl)b===null?e.terminalSlot.innerHTML="":e.terminalSlot.innerHTML=gt(t.key,d,t.activity,t.io?.terminal,b,o,s),e.currentTerminalUrl=k;else if(b!==null&&t.io?.terminal){let T=e.terminalSlot.querySelector("details.wf-terminal-block > summary");if(T){let L=ht(b.kind);T.innerHTML=`${i(L)} ${kt(d,t.io.terminal)}`}d&&Nn(e.terminalSlot,d,t.activity,t.io.terminal,b,s)}let l=d?.attemptId??t.activity?.activityId??t.node?.nodeId??"unknown";e.grid.innerHTML=`
|
|
552
|
+
${J(l,n("workflow.detail.authoredInput"),t.io?.input,o)}
|
|
553
|
+
${J(l,n("workflow.detail.resolvedInput"),t.io?.resolvedInput,o)}
|
|
554
|
+
${J(l,n("workflow.detail.output"),t.io?.output,o)}
|
|
555
|
+
${J(l,n("workflow.detail.executionLog"),t.io?.log,o)}
|
|
556
|
+
${t.io?.waitPrompt?J(l,n("workflow.detail.waitPrompt"),t.io.waitPrompt,o):""}
|
|
557
|
+
`}function wt(e,t,o,r){if(!o||o.error)return null;if(Rn(e,o))return{kind:"live",url:Dn(o)};if(!e||!t||!xn(e,o))return null;let s=qn();if(!s)return null;let a=r?.sessions.get(e.attemptId);return a?{kind:"resume",url:a.url,resumeId:a.resumeId,downloadUrl:ft(s,t.activityId,e.attemptId)}:{kind:"replay",url:On(s,t.activityId,e.attemptId,!!o.hasPtyLog),downloadUrl:ft(s,t.activityId,e.attemptId)}}function gt(e,t,o,r,s,a,d){if(!r)return"";let f=ht(s.kind),y=qe(e,f),S=kt(t,r),b=En(s.kind),k=s.kind==="replay"||s.kind==="resume"?`<a class="btn-link" href="${i(s.downloadUrl)}" download>${i(n("workflow.detail.downloadFullLog"))}</a>`:"",l=t?vt(t,o,r,s,d):"",T=t?yt(t.attemptId,d):"";return`<details class="wf-io-block wf-terminal-block" data-io-key="${i(y)}"${a.has(y)?" open":""}>
|
|
558
|
+
<summary>${i(f)} ${S}</summary>
|
|
723
559
|
<div class="wf-terminal-actions">
|
|
724
|
-
<a class="btn-link" href="${
|
|
725
|
-
${
|
|
560
|
+
<a class="btn-link" href="${i(s.url)}" target="_blank" rel="noreferrer">${i(b)}</a>
|
|
561
|
+
${k}
|
|
726
562
|
${l}
|
|
727
563
|
</div>
|
|
728
|
-
${
|
|
729
|
-
<iframe class="wf-terminal-frame" src="${
|
|
730
|
-
</details>`}function
|
|
564
|
+
${T}
|
|
565
|
+
<iframe class="wf-terminal-frame" src="${i(s.url)}" title="${i(f)}" loading="lazy"></iframe>
|
|
566
|
+
</details>`}function ht(e){return e==="live"?n("workflow.detail.liveTerminal"):e==="resume"?n("workflow.detail.terminalResume"):n("workflow.detail.terminalReplay")}function En(e){return e==="live"?n("workflow.detail.openTerminalNewTab"):e==="resume"?n("workflow.detail.openResumeNewTab"):n("workflow.detail.openReplayNewTab")}var bt=new Set(["antigravity","cursor"]),Cn=new Set(["aiden","coco","claude-code","codex"]);function Mn(e){return!!e&&(Cn.has(e)||bt.has(e))}function An(e){return!!e&&bt.has(e)}function vt(e,t,o,r,s){if(!s||r.kind==="live"||!t)return"";let a=r.kind==="resume",d=s.pending.has(e.attemptId),f=`data-wf-resume-attempt="${i(e.attemptId)}" data-wf-resume-activity="${i(t.activityId)}"`;return a?`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="end" ${f}${d?" disabled":""}>${i(d?n("workflow.detail.resumeEnding"):n("workflow.detail.endResumeSession"))}</button>`:Mn(o.cliId)?An(o.cliId)&&!o.cliSessionId?`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${i(n("workflow.detail.resumeMissingCliSession"))}">${i(n("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="start" ${f}${d?" disabled":""}>${i(d?n("workflow.detail.resumeStarting"):n("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${i(n("workflow.detail.resumeUnsupportedCli",{cliId:o.cliId??"?"}))}">${i(n("workflow.detail.resumeSession"))}</button>`}function yt(e,t){if(!t)return"";let o=t.errors.get(e);return o?`<div class="hint-warn wf-resume-status" data-wf-resume-status="${i(e)}">${i(o)}</div>`:""}function Hn(e,t,o,r,s){let a=ye(e.activity),d=e.node?.nodeId??e.activity?.ownerNodeId??e.activity?.activityId??"unknown",f=a?.attemptId??e.activity?.activityId??e.node?.nodeId??"unknown",y=$t(a,o),S=a?.attemptId===s?" is-focused":"",b=a?` data-wf-attempt-card="${i(a.attemptId)}"`:"",k=wt(a,e.activity,e.io?.terminal,r),l=k?gt(f,a,e.activity,e.io?.terminal,k,t,r):"";return`<article class="wf-io-card${S}" data-wf-card-key="${i(e.key)}"${b}>
|
|
731
567
|
<div class="wf-io-card-head">
|
|
732
568
|
<header>
|
|
733
569
|
<div>
|
|
734
|
-
<strong><code>${
|
|
735
|
-
<span class="muted">${e.activity?
|
|
570
|
+
<strong><code>${i(d)}</code></strong>
|
|
571
|
+
<span class="muted">${e.activity?i(e.activity.activityId):i(n("workflow.detail.notDispatched"))}</span>
|
|
736
572
|
</div>
|
|
737
|
-
<div>${e.node?
|
|
573
|
+
<div>${e.node?G(e.node.status):""} ${e.activity?G(e.activity.status):""}</div>
|
|
738
574
|
</header>
|
|
739
575
|
<div class="wf-io-meta">
|
|
740
|
-
${
|
|
576
|
+
${a?`${i(n("workflow.detail.attempt"))} <code>${i(a.attemptId)}</code>`:i(n("workflow.detail.noAttempt"))}
|
|
741
577
|
</div>
|
|
742
|
-
${
|
|
578
|
+
${y}
|
|
743
579
|
</div>
|
|
744
580
|
<div class="wf-io-terminal-slot">${l}</div>
|
|
745
581
|
<div class="wf-io-grid">
|
|
746
|
-
${
|
|
747
|
-
${
|
|
748
|
-
${
|
|
749
|
-
${
|
|
750
|
-
${e.io?.waitPrompt?
|
|
582
|
+
${J(f,n("workflow.detail.authoredInput"),e.io?.input,t)}
|
|
583
|
+
${J(f,n("workflow.detail.resolvedInput"),e.io?.resolvedInput,t)}
|
|
584
|
+
${J(f,n("workflow.detail.output"),e.io?.output,t)}
|
|
585
|
+
${J(f,n("workflow.detail.executionLog"),e.io?.log,t)}
|
|
586
|
+
${e.io?.waitPrompt?J(f,n("workflow.detail.waitPrompt"),e.io.waitPrompt,t):""}
|
|
751
587
|
</div>
|
|
752
|
-
</article>`}function
|
|
588
|
+
</article>`}function ye(e){return e?.attempts[e.attempts.length-1]}function kt(e,t){let o=[];return t.error?o.push(n("workflow.detail.error")):o.push(t.status==="live"?n("workflow.detail.terminalLive"):n("workflow.detail.terminalClosedShort")),e?.status&&o.push(e.status),t.webPort>0&&o.push(`:${t.webPort}`),`<span class="muted">${i(o.join(" \xB7 "))}</span>`}function Rn(e,t){return t.status==="live"&&t.webPort>0&&(e?.status==="pending"||e?.status==="running"||e?.status==="effectAttempting")}function xn(e,t){return e.status==="succeeded"||e.status==="failed"||e.status==="cancelled"||e.status==="timedOut"?!!(t.sessionId||t.startedAt):!1}function Dn(e){return`http://${window.location.hostname||"127.0.0.1"}:${e.webPort}`}function On(e,t,o,r){let s=new URLSearchParams({runId:e,activityId:t,attemptId:o});return r&&s.set("hasPtyLog","1"),`/assets/terminal-replay.html?${s.toString()}`}function ft(e,t,o){return`/api/workflows/runs/${encodeURIComponent(e)}/attempts/${encodeURIComponent(t)}/${encodeURIComponent(o)}/terminal-log/raw?download=1`}function qn(){let e=window.location.hash.match(/^#\/workflows\/([^/?#]+)/);if(!e)return null;try{return decodeURIComponent(e[1])}catch{return null}}function $t(e,t){if(!Bn(e))return"";let o=e.attemptId,r=t.comments.get(o)??"",s=t.resolving.has(o),a=t.statuses.get(o),d=a?.kind==="error"?"hint-warn":"hint-ok";return`<div class="wf-approval-box" data-wf-approval="${i(o)}">
|
|
753
589
|
<label>
|
|
754
|
-
<span>${
|
|
755
|
-
<textarea class="wf-approval-comment" data-wf-approval-comment="${
|
|
590
|
+
<span>${i(n("workflow.detail.approvalComment"))}</span>
|
|
591
|
+
<textarea class="wf-approval-comment" data-wf-approval-comment="${i(o)}" rows="2" placeholder="${i(n("workflow.detail.optionalComment"))}"${s?" disabled":""}>${i(r)}</textarea>
|
|
756
592
|
</label>
|
|
757
593
|
<div class="wf-approval-actions">
|
|
758
|
-
<button type="button" class="primary" data-wf-approval-action="approve" data-wf-attempt-id="${
|
|
759
|
-
<button type="button" data-wf-approval-action="reject" data-wf-attempt-id="${
|
|
760
|
-
${
|
|
594
|
+
<button type="button" class="primary" data-wf-approval-action="approve" data-wf-attempt-id="${i(o)}"${s?" disabled":""}>${i(n("workflow.detail.approve"))}</button>
|
|
595
|
+
<button type="button" data-wf-approval-action="reject" data-wf-attempt-id="${i(o)}"${s?" disabled":""}>${i(n("workflow.detail.reject"))}</button>
|
|
596
|
+
${s?`<span class="muted">${i(n("workflow.detail.submitting"))}</span>`:""}
|
|
761
597
|
</div>
|
|
762
|
-
${
|
|
763
|
-
</div>`}function
|
|
764
|
-
<summary>${
|
|
765
|
-
${
|
|
766
|
-
</details>`}function
|
|
767
|
-
<td>${
|
|
768
|
-
<td><code>${
|
|
769
|
-
<td>${
|
|
770
|
-
<td>${t.nodeId?`<code>${
|
|
771
|
-
<td>${t.activityId?`<code>${
|
|
772
|
-
<td>${t.errorCode?`<span class="muted error">${
|
|
773
|
-
<td title="${
|
|
774
|
-
</tr>`}function
|
|
598
|
+
${a?`<div class="${d} wf-approval-status">${i(a.text)}</div>`:""}
|
|
599
|
+
</div>`}function Bn(e){return!!e&&e.status==="waiting"&&e.wait?.waitKind==="human-gate"&&!e.wait.resolution}function Pn(e,t){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(o=>{let r=o.dataset.wfApprovalComment;r&&t.set(r,o.value)})}function St(e,t){e.querySelectorAll("button[data-wf-resume-action][data-wf-resume-attempt][data-wf-resume-activity]").forEach(o=>{o.dataset.wfResumeBound!=="1"&&(o.dataset.wfResumeBound="1",o.addEventListener("click",()=>{let r=o.dataset.wfResumeAttempt,s=o.dataset.wfResumeActivity,a=o.dataset.wfResumeAction;!r||!s||(a==="start"?t.onStart(r,s):a==="end"&&t.onEnd(r,s))}))})}function Nn(e,t,o,r,s,a){let d=e.querySelector(".wf-terminal-actions");if(!d)return;let f=d.querySelector('button[data-wf-resume-button="1"]'),y=vt(t,o,r,s,a);f?f.outerHTML=y:y&&d.insertAdjacentHTML("beforeend",y);let S=e.querySelector("details.wf-terminal-block");if(S){let b=S.querySelector(".wf-resume-status"),k=yt(t.attemptId,a);b?b.outerHTML=k:k&&d.insertAdjacentHTML("afterend",k)}St(e,a)}function jn(e,t){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(o=>{let r=o.dataset.wfApprovalComment;r&&o.addEventListener("input",()=>{t.comments.set(r,o.value)})}),e.querySelectorAll("button[data-wf-approval-action][data-wf-attempt-id]").forEach(o=>{o.addEventListener("click",()=>{let r=o.dataset.wfAttemptId,s=o.dataset.wfApprovalAction;!r||s!=="approve"&&s!=="reject"||t.onResolve(r,s)})})}function J(e,t,o,r){let s=qe(e,t);return`<details class="wf-io-block" data-io-key="${i(s)}"${r.has(s)?" open":""}>
|
|
600
|
+
<summary>${i(t)} ${Gn(o)}</summary>
|
|
601
|
+
${zn(o)}
|
|
602
|
+
</details>`}function qe(e,t){return`${e}:${t}`}function Un(e,t){if(!t)return!1;for(let o of e.querySelectorAll("[data-wf-attempt-card]"))if(o.dataset.wfAttemptCard===t)return o.scrollIntoView({block:"center"}),!0;return!1}function Fn(e,t,o){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(r=>{let s=r.dataset.ioKey;if(!s)return;r.open?t.add(s):t.delete(s);let a=r.querySelector(".wf-io-pre");a&&o.set(s,a.scrollTop)})}function Wn(e,t){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(o=>{o.dataset.ioToggleBound!=="1"&&(o.dataset.ioToggleBound="1",o.addEventListener("toggle",()=>{let r=o.dataset.ioKey;r&&(o.open?t.add(r):t.delete(r))}))})}function _n(e,t){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(o=>{let r=o.dataset.ioKey;if(!r)return;let s=t.get(r);if(s===void 0)return;let a=o.querySelector(".wf-io-pre");a&&(a.scrollTop=s)})}function Jn(e,t){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(o=>{let r=o.dataset.ioKey;if(!r)return;let s=o.querySelector(".wf-io-pre");s&&s.dataset.ioScrollBound!=="1"&&(s.dataset.ioScrollBound="1",s.addEventListener("scroll",()=>{t.set(r,s.scrollTop)}))})}function Gn(e){if(!e)return`<span class="muted">${i(n("workflow.detail.empty"))}</span>`;let t=[];return e.outputBytes!==void 0&&t.push(`${e.outputBytes}B`),e.truncated&&t.push(n("workflow.detail.truncated")),e.error&&t.push(n("workflow.detail.error")),e.outputHash&&t.push($e(e.outputHash)),t.length?`<span class="muted">${i(t.join(" \xB7 "))}</span>`:""}function zn(e){if(!e)return`<div class="muted wf-io-empty">${i(n("workflow.detail.noData"))}</div>`;let t=e.value!==void 0?JSON.stringify(e.value,null,2):e.text??"",o=e.error?`<div class="muted error">${i(e.error)}</div>`:"";return t?`${o}<pre class="wf-io-pre">${i(t)}</pre>`:`${o}<div class="muted wf-io-empty">${i(n("workflow.detail.noPreview"))}</div>`}function Kn(e){let t=[];if(e.effectAttempted&&t.push(`${i(n("workflow.detail.effect"))} ${i(e.effectAttempted.provider)}`),e.wait){let o=e.wait.resolution?`${e.wait.resolution.kind}${e.wait.resolution.resolution?":"+e.wait.resolution.resolution:""}`:n("workflow.detail.open");t.push(`${i(n("workflow.detail.wait"))} ${i(e.wait.waitKind)} ${i(o)}`),e.wait.deadlineAt!==void 0&&t.push(`${i(n("workflow.detail.deadline"))} ${i(ke(e.wait.deadlineAt))}`)}if(e.error){let o=`${e.error.errorCode}${e.error.errorClass?` \xB7 ${e.error.errorClass}`:""}`;t.push(`<span class="muted error">${i(o)}</span>`),e.error.errorMessage&&t.push(`<span class="error wf-error-msg">${i(e.error.errorMessage)}</span>`)}return e.output&&t.push(`${i(n("workflow.detail.output"))} ${i($e(e.output.outputHash))}`),e.runningMs!==void 0&&t.push(`${e.runningMs}ms`),t.length>0?t.join("<br/>"):'<span class="muted">-</span>'}function Vn(e,t){e.innerHTML=t.length>0?t.map(Yn).join(""):`<tr><td colspan="7" class="empty">${i(n("workflow.detail.noEvents"))}</td></tr>`}function Yn(e){let t=Qn(e.payload);return`<tr>
|
|
603
|
+
<td>${le(e.eventId)}</td>
|
|
604
|
+
<td><code>${i(e.type)}</code></td>
|
|
605
|
+
<td>${i(e.actor)}</td>
|
|
606
|
+
<td>${t.nodeId?`<code>${i(t.nodeId)}</code>`:"-"}</td>
|
|
607
|
+
<td>${t.activityId?`<code>${i(t.activityId)}</code>`:"-"}</td>
|
|
608
|
+
<td>${t.errorCode?`<span class="muted error">${i(t.errorCode)}</span>`:"-"}</td>
|
|
609
|
+
<td title="${i(new Date(e.timestamp).toISOString())}">${i(ke(e.timestamp))}</td>
|
|
610
|
+
</tr>`}function le(e){let t=e.lastIndexOf("-");if(t<0)return 0;let o=Number(e.slice(t+1));return Number.isFinite(o)?o:0}function Qn(e){if(!e||typeof e!="object"||"ref"in e)return{};let t=e,o={};typeof t.nodeId=="string"&&(o.nodeId=t.nodeId),typeof t.activityId=="string"&&(o.activityId=t.activityId),typeof t.failedNodeId=="string"&&(o.nodeId=t.failedNodeId);let r=t.error;return r&&typeof r=="object"&&"errorCode"in r&&(o.errorCode=String(r.errorCode)),o}function Xn(e){return!e.payload||typeof e.payload!="object"||"ref"in e.payload?null:e.payload}function pt(e,t,o){return Math.min(o,Math.max(t,e))}function $e(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function Zn(e,t){return e.length>t?e.slice(0,t-1)+"\u2026":e}function ke(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 It(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function Tt(e){let t=location.hash.match(/^#\/(?:workflows\/catalog|workflows-catalog)\/([^/?#]+)$/);return t?to(e,decodeURIComponent(t[1])):eo(e)}function eo(e){e.innerHTML=`
|
|
775
611
|
<nav class="wf-subnav">
|
|
776
|
-
<a href="#/workflows" data-i18n="workflow.subnav.runs">${C(
|
|
777
|
-
<a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${C(
|
|
612
|
+
<a href="#/workflows" data-i18n="workflow.subnav.runs">${C(n("workflow.subnav.runs"))}</a>
|
|
613
|
+
<a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${C(n("workflow.subnav.catalog"))}</a>
|
|
778
614
|
</nav>
|
|
779
615
|
<section class="catalog-head">
|
|
780
616
|
<div>
|
|
781
|
-
<h2>${C(
|
|
782
|
-
<p class="muted">${C(
|
|
617
|
+
<h2>${C(n("catalog.title"))}</h2>
|
|
618
|
+
<p class="muted">${C(n("catalog.subtitle"))}</p>
|
|
783
619
|
</div>
|
|
784
|
-
<button id="catalog-refresh" type="button">${C(
|
|
620
|
+
<button id="catalog-refresh" type="button">${C(n("catalog.refresh"))}</button>
|
|
785
621
|
</section>
|
|
786
622
|
<form id="catalog-filters" class="filters">
|
|
787
|
-
<input type="search" name="q" placeholder="${C(
|
|
623
|
+
<input type="search" name="q" placeholder="${C(n("catalog.searchPlaceholder"))}" />
|
|
788
624
|
<span id="catalog-status" class="muted"></span>
|
|
789
625
|
</form>
|
|
790
626
|
<div class="wf-table-scroll">
|
|
791
627
|
<table>
|
|
792
628
|
<thead><tr>
|
|
793
|
-
<th>${C(
|
|
794
|
-
<th>${C(
|
|
795
|
-
<th>${C(
|
|
796
|
-
<th>${C(
|
|
797
|
-
<th>${C(
|
|
798
|
-
<th>${C(
|
|
629
|
+
<th>${C(n("catalog.table.workflow"))}</th>
|
|
630
|
+
<th>${C(n("catalog.table.version"))}</th>
|
|
631
|
+
<th>${C(n("catalog.table.params"))}</th>
|
|
632
|
+
<th>${C(n("catalog.table.nodes"))}</th>
|
|
633
|
+
<th>${C(n("catalog.table.revision"))}</th>
|
|
634
|
+
<th>${C(n("catalog.table.path"))}</th>
|
|
799
635
|
</tr></thead>
|
|
800
636
|
<tbody id="catalog-tbody"></tbody>
|
|
801
637
|
</table>
|
|
802
638
|
</div>
|
|
803
|
-
`;let t=e.querySelector("#catalog-tbody"),
|
|
639
|
+
`;let t=e.querySelector("#catalog-tbody"),o=e.querySelector("#catalog-status"),r=e.querySelector("#catalog-filters"),s=e.querySelector("#catalog-refresh"),a=[],d=null,f=!1;function y(){let k=(new FormData(r).get("q")??"").trim().toLowerCase();return k?a.filter(l=>l.workflowId.toLowerCase().includes(k)||l.path.toLowerCase().includes(k)):a}function S(){d?(o.textContent=n("catalog.loadFailed",{error:d}),o.classList.add("error")):(o.textContent=`${a.length}`,o.classList.remove("error"));let k=y();if(k.length===0){t.innerHTML=`<tr><td colspan="6" class="empty">${a.length===0?C(n("catalog.noDefinitions")):C(n("catalog.noFilterMatch"))}</td></tr>`;return}t.innerHTML=k.map(l=>`
|
|
804
640
|
<tr>
|
|
805
641
|
<td><a href="#/workflows/catalog/${encodeURIComponent(l.workflowId)}"><code>${C(l.workflowId)}</code></a></td>
|
|
806
642
|
<td>${l.version}</td>
|
|
807
|
-
<td>${C(
|
|
643
|
+
<td>${C(n("catalog.paramSummary",{required:l.requiredParamCount,total:l.paramCount}))}</td>
|
|
808
644
|
<td>${l.nodeCount}</td>
|
|
809
|
-
<td><code>${C(
|
|
645
|
+
<td><code>${C(It(l.revisionId))}</code></td>
|
|
810
646
|
<td><code>${C(l.path)}</code></td>
|
|
811
647
|
</tr>
|
|
812
|
-
`).join("")}async function
|
|
648
|
+
`).join("")}async function b(){s.disabled=!0,o.textContent=n("catalog.loading");try{let k=await fetch("/api/workflows/definitions");if(!k.ok)throw new Error(`HTTP ${k.status}`);a=(await k.json()).definitions??[],d=null}catch(k){d=k?.message??String(k),a=[]}finally{s.disabled=!1,f||S()}}return r.addEventListener("input",S),s.addEventListener("click",()=>{b()}),b(),()=>{f=!0}}function to(e,t){e.innerHTML=`
|
|
813
649
|
<div class="catalog-detail-head">
|
|
814
|
-
<a class="btn-link" href="#/workflows/catalog">${C(
|
|
650
|
+
<a class="btn-link" href="#/workflows/catalog">${C(n("catalog.back"))}</a>
|
|
815
651
|
<div>
|
|
816
652
|
<h2><code>${C(t)}</code></h2>
|
|
817
|
-
<div id="catalog-detail-subtitle" class="muted">${C(
|
|
653
|
+
<div id="catalog-detail-subtitle" class="muted">${C(n("workflow.detail.loading"))}</div>
|
|
818
654
|
</div>
|
|
819
655
|
</div>
|
|
820
656
|
<section id="catalog-error" class="hint-warn" hidden></section>
|
|
821
657
|
<section id="catalog-run-status" class="hint-ok" hidden></section>
|
|
822
658
|
<div id="catalog-detail-body"></div>
|
|
823
|
-
`;let
|
|
659
|
+
`;let o=e.querySelector("#catalog-detail-subtitle"),r=e.querySelector("#catalog-error"),s=e.querySelector("#catalog-run-status"),a=e.querySelector("#catalog-detail-body"),d=null,f=!1,y=!1;function S(u){r.hidden=!u,r.textContent=u??""}function b(u){s.hidden=!u,s.textContent=u??""}function k(u){let I={};for(let[$,v]of Object.entries(u??{}))"default"in v&&(I[$]=v.default);return I}function l(){if(!d)return;let u=d.definition;o.textContent=`${n("catalog.revision")} ${It(d.revisionId)} \xB7 ${d.path}`;let I=JSON.stringify(k(u.params),null,2);a.innerHTML=`
|
|
824
660
|
<section class="wf-panel">
|
|
825
|
-
<div class="wf-panel-title"><h3>${C(
|
|
661
|
+
<div class="wf-panel-title"><h3>${C(n("catalog.summary"))}</h3></div>
|
|
826
662
|
<div class="wf-summary-grid">
|
|
827
|
-
<div class="wf-summary-item"><span>${C(
|
|
828
|
-
<div class="wf-summary-item"><span>${C(
|
|
829
|
-
<div class="wf-summary-item"><span>${C(
|
|
830
|
-
<div class="wf-summary-item"><span>${C(
|
|
663
|
+
<div class="wf-summary-item"><span>${C(n("catalog.table.workflow"))}</span><strong><code>${C(u.workflowId)}</code></strong></div>
|
|
664
|
+
<div class="wf-summary-item"><span>${C(n("catalog.table.version"))}</span><strong>${u.version}</strong></div>
|
|
665
|
+
<div class="wf-summary-item"><span>${C(n("catalog.nodeCount"))}</span><strong>${Object.keys(u.nodes).length}</strong></div>
|
|
666
|
+
<div class="wf-summary-item"><span>${C(n("catalog.path"))}</span><strong><code>${C(d.path)}</code></strong></div>
|
|
831
667
|
</div>
|
|
832
668
|
</section>
|
|
833
669
|
|
|
834
670
|
<section class="wf-panel">
|
|
835
|
-
<div class="wf-panel-title"><h3>${C(
|
|
671
|
+
<div class="wf-panel-title"><h3>${C(n("catalog.runPanel"))}</h3></div>
|
|
836
672
|
<form id="catalog-run-form" class="catalog-run-form">
|
|
837
673
|
<label>
|
|
838
|
-
<span>${C(
|
|
839
|
-
<textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${C(
|
|
674
|
+
<span>${C(n("catalog.paramsJson"))}</span>
|
|
675
|
+
<textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${C(n("catalog.paramsPlaceholder"))}">${C(I)}</textarea>
|
|
840
676
|
</label>
|
|
841
677
|
<div class="catalog-chat-grid">
|
|
842
678
|
<label>
|
|
843
|
-
<span>${C(
|
|
679
|
+
<span>${C(n("catalog.chatId"))}</span>
|
|
844
680
|
<input id="catalog-chat-id" type="text" autocomplete="off" />
|
|
845
681
|
</label>
|
|
846
682
|
<label>
|
|
847
|
-
<span>${C(
|
|
683
|
+
<span>${C(n("catalog.larkAppId"))}</span>
|
|
848
684
|
<input id="catalog-lark-app-id" type="text" autocomplete="off" />
|
|
849
685
|
</label>
|
|
850
686
|
</div>
|
|
851
|
-
<div class="muted">${C(
|
|
687
|
+
<div class="muted">${C(n("catalog.chatBindingHint"))}</div>
|
|
852
688
|
<div id="catalog-param-errors" class="catalog-param-errors" hidden></div>
|
|
853
|
-
<button id="catalog-run-btn" type="submit" class="primary">${C(
|
|
689
|
+
<button id="catalog-run-btn" type="submit" class="primary">${C(n("catalog.run"))}</button>
|
|
854
690
|
</form>
|
|
855
691
|
</section>
|
|
856
692
|
|
|
857
693
|
<section class="wf-panel">
|
|
858
|
-
<div class="wf-panel-title"><h3>${C(
|
|
859
|
-
${
|
|
694
|
+
<div class="wf-panel-title"><h3>${C(n("catalog.paramsSchema"))}</h3></div>
|
|
695
|
+
${no(u.params)}
|
|
860
696
|
</section>
|
|
861
697
|
|
|
862
698
|
<section class="wf-panel">
|
|
863
|
-
<div class="wf-panel-title"><h3>${C(
|
|
864
|
-
<pre class="wf-io-pre">${C(JSON.stringify(
|
|
699
|
+
<div class="wf-panel-title"><h3>${C(n("catalog.definitionJson"))}</h3></div>
|
|
700
|
+
<pre class="wf-io-pre">${C(JSON.stringify(u,null,2))}</pre>
|
|
865
701
|
</section>
|
|
866
|
-
`,L()}async function
|
|
702
|
+
`,L()}async function T(){if(!d||y)return;let u=a.querySelector("#catalog-params"),I=a.querySelector("#catalog-chat-id"),$=a.querySelector("#catalog-lark-app-id"),v=a.querySelector("#catalog-run-btn"),M=a.querySelector("#catalog-param-errors"),c;try{if(c=JSON.parse(u.value||"{}"),!c||typeof c!="object"||Array.isArray(c))throw new Error(n("catalog.badParamsJson"))}catch(p){M.hidden=!1,M.innerHTML=`<div class="muted error">${C(p?.message??String(p))}</div>`;return}y=!0,v.disabled=!0,v.textContent=n("catalog.running"),M.hidden=!0,S(null),b(null);try{let p=await fetch(`/api/workflows/definitions/${encodeURIComponent(d.definition.workflowId)}/run`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({params:c,chatBinding:{chatId:I.value.trim(),larkAppId:$.value.trim()}})});if(p.status===401)throw new Error(n("catalog.writeAccess"));let h=await p.json().catch(()=>({}));if(!p.ok||!h.ok)throw h.issues?.length&&(M.hidden=!1,M.innerHTML=`<strong>${C(n("catalog.invalidParams"))}</strong><ul>${h.issues.map(E=>`<li>${C(n("catalog.issue",{path:E.path.length?E.path.join("."):"(root)",message:E.message}))}</li>`).join("")}</ul>`),new Error(h.hint??h.message??h.error??n("catalog.runHttp",{status:p.status}));b(n("catalog.runStarted")),h.runId&&(location.hash=`#/workflows/${encodeURIComponent(h.runId)}`)}catch(p){S(p?.message??String(p))}finally{y=!1,v.disabled=!1,v.textContent=n("catalog.run")}}function L(){a.querySelector("#catalog-run-form")?.addEventListener("submit",I=>{I.preventDefault(),T()})}async function g(){try{let u=await fetch(`/api/workflows/definitions/${encodeURIComponent(t)}`);if(u.status===404)throw new Error("unknown_workflow");if(!u.ok)throw new Error(`HTTP ${u.status}`);d=await u.json(),S(null),l()}catch(u){S(n("catalog.definitionLoadFailed",{error:u?.message??String(u)})),o.textContent=n("workflow.detail.loadFailed")}}return g().then(()=>{}),()=>{f=!0}}function no(e){let t=Object.entries(e??{});return t.length===0?`<div class="muted">${C(n("catalog.noParams"))}</div>`:`<div class="catalog-param-list">${t.map(([o,r])=>`
|
|
867
703
|
<article class="catalog-param">
|
|
868
704
|
<header>
|
|
869
|
-
<code>${C(
|
|
870
|
-
<span class="wf-status">${C(
|
|
871
|
-
<span class="muted">${C(
|
|
705
|
+
<code>${C(o)}</code>
|
|
706
|
+
<span class="wf-status">${C(r.required?n("catalog.required"):n("catalog.optional"))}</span>
|
|
707
|
+
<span class="muted">${C(r.type)}${r.format?` \xB7 ${C(r.format)}`:""}</span>
|
|
872
708
|
</header>
|
|
873
|
-
${
|
|
874
|
-
${"default"in
|
|
709
|
+
${r.description?`<div class="muted">${C(n("catalog.description"))}: ${C(r.description)}</div>`:""}
|
|
710
|
+
${"default"in r?`<pre class="wf-io-pre">${C(`${n("catalog.default")}: ${JSON.stringify(r.default,null,2)}`)}</pre>`:""}
|
|
875
711
|
</article>
|
|
876
|
-
`).join("")}</div>`}var
|
|
877
|
-
<img class="qr-image" src="${e.qrDataUrl}" alt="${
|
|
878
|
-
${e.qrUrl?`<a class="onboarding-link" href="${e.qrUrl}" target="_blank" rel="noopener">${
|
|
879
|
-
</div>`:"",
|
|
712
|
+
`).join("")}</div>`}var ee=null,Se=null;function Ie(){Se!==null&&(window.clearInterval(Se),Se=null)}function Lt(){return ee||(ee=document.createElement("dialog"),ee.className="onboarding-dialog",document.body.appendChild(ee),ee.addEventListener("close",Ie),ee)}function oo(e){return e.status==="waiting_for_scan"?n("botOnboarding.waiting"):e.status==="verifying"?n("botOnboarding.verifying"):e.status==="completed"?n("botOnboarding.completed"):e.status==="failed"?`${n("botOnboarding.failed")}: ${e.message??e.error??"unknown"}`:n("botOnboarding.starting")}function de(e){let t=Lt(),o=e.qrDataUrl?`<div class="qr-card">
|
|
713
|
+
<img class="qr-image" src="${e.qrDataUrl}" alt="${n("botOnboarding.qrAlt")}">
|
|
714
|
+
${e.qrUrl?`<a class="onboarding-link" href="${e.qrUrl}" target="_blank" rel="noopener">${n("botOnboarding.openLink")}</a>`:""}
|
|
715
|
+
</div>`:"",r=e.appId?`<p><b>App ID:</b> <code>${e.appId}</code></p>`:"",s=e.status==="completed"?`<p class="hint-ok">${n("botOnboarding.restartHint")}</p>`:"";t.innerHTML=`<article>
|
|
880
716
|
<header>
|
|
881
|
-
<h3>${
|
|
882
|
-
<p>${
|
|
717
|
+
<h3>${n("botOnboarding.title")}</h3>
|
|
718
|
+
<p>${n("botOnboarding.intro")}</p>
|
|
883
719
|
</header>
|
|
884
|
-
<p class="onboarding-status status-${e.status}">${
|
|
885
|
-
${
|
|
720
|
+
<p class="onboarding-status status-${e.status}">${oo(e)}</p>
|
|
721
|
+
${o}
|
|
722
|
+
${r}
|
|
886
723
|
${s}
|
|
887
|
-
|
|
888
|
-
|
|
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()})();})();
|
|
724
|
+
<form method="dialog"><button>${n("botOnboarding.close")}</button></form>
|
|
725
|
+
</article>`}async function so(e){let t=await fetch(`/api/bot-onboarding/${encodeURIComponent(e)}`),o=await t.json();if(!t.ok||!o?.job)throw new Error(o?.error??`http_${t.status}`);de(o.job),(o.job.status==="completed"||o.job.status==="failed")&&Ie()}async function ao(){Ie(),de({id:"",status:"starting"});let e=Lt();e.open||e.showModal();try{let t=await fetch("/api/bot-onboarding/start",{method:"POST"}),o=await t.json();if(!t.ok||!o?.job?.id)throw new Error(o?.error??`http_${t.status}`);de(o.job),Se=window.setInterval(()=>{so(o.job.id).catch(r=>{Ie(),de({id:o.job.id,status:"failed",message:r instanceof Error?r.message:String(r)})})},1200)}catch(t){de({id:"",status:"failed",message:t instanceof Error?t.message:String(t)})}}function Et(){let e=document.getElementById("add-bot-btn");e&&(e.onclick=()=>{ao()})}var Q=document.getElementById("root"),ce=null;function Be(){ce&&(ce(),ce=null);let e=location.hash||"#/";e.startsWith("#/workflows/catalog")||e.startsWith("#/workflows-catalog")?ce=Tt(Q):e.startsWith("#/workflows")?ce=mt(Q):e.startsWith("#/groups")?ot(Q):e.startsWith("#/bot-defaults")?rt(Q):e.startsWith("#/roles")?ct(Q):e.startsWith("#/schedules")?tt(Q):e.startsWith("#/sessions")?Ze(Q):Qe(Q);for(let t of document.querySelectorAll(".sidebar-nav a")){let o=t.getAttribute("href")??"#/";t.classList.toggle("active",o===(e||"#/"))}}var Pe=document.getElementById("status");function Mt(){Pe&&(Pe.textContent=O.online?n("status.live"):n("status.disconnected"),Pe.className="connection-status "+(O.online?"online":"offline"))}O.on(Mt);function Ct(){document.querySelectorAll("[data-i18n]").forEach(e=>{e.textContent=n(e.dataset.i18n??"")}),document.querySelectorAll("[data-locale]").forEach(e=>{e.classList.toggle("active",e.dataset.locale===K.locale)}),document.querySelectorAll("[data-theme-mode]").forEach(e=>{e.classList.toggle("active",e.dataset.themeMode===K.themeMode)}),Mt()}function ro(){document.querySelectorAll("[data-locale]").forEach(e=>{e.onclick=()=>K.setLocale(e.dataset.locale)}),document.querySelectorAll("[data-theme-mode]").forEach(e=>{e.onclick=()=>K.setThemeMode(e.dataset.themeMode)})}(async()=>{K.init(),ro(),Et(),K.on(()=>{Ct(),Be()}),Ct();try{await Je()}catch(e){console.error("botmux dashboard bootstrap failed",e),O.setOnline(!1)}window.addEventListener("hashchange",Be),Be()})();})();
|