botmux 2.104.0 → 2.105.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 +10 -10
- package/README.md +10 -10
- package/dist/adapters/backend/sandbox.d.ts +5 -1
- package/dist/adapters/backend/sandbox.d.ts.map +1 -1
- package/dist/adapters/backend/sandbox.js +54 -5
- package/dist/adapters/backend/sandbox.js.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.d.ts +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.js +1 -1
- package/dist/adapters/backend/zellij-observe-backend.d.ts +1 -1
- package/dist/adapters/backend/zellij-observe-backend.js +1 -1
- package/dist/adapters/cli/claude-code.d.ts +1 -1
- package/dist/adapters/cli/relay.d.ts +2 -2
- package/dist/adapters/cli/relay.js +2 -2
- package/dist/adapters/cli/seed.d.ts +2 -2
- package/dist/adapters/cli/seed.js +2 -2
- package/dist/adapters/cli/shared-hints.d.ts.map +1 -1
- package/dist/adapters/cli/shared-hints.js +1 -0
- package/dist/adapters/cli/shared-hints.js.map +1 -1
- package/dist/bot-registry.d.ts +65 -1
- package/dist/bot-registry.d.ts.map +1 -1
- package/dist/bot-registry.js +145 -0
- package/dist/bot-registry.js.map +1 -1
- package/dist/cli/send-dispatch.d.ts +44 -0
- package/dist/cli/send-dispatch.d.ts.map +1 -1
- package/dist/cli/send-dispatch.js +79 -0
- package/dist/cli/send-dispatch.js.map +1 -1
- package/dist/cli/vc-agent.d.ts +2 -0
- package/dist/cli/vc-agent.d.ts.map +1 -0
- package/dist/cli/vc-agent.js +331 -0
- package/dist/cli/vc-agent.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +106 -24
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +8 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +13 -1
- package/dist/config.js.map +1 -1
- package/dist/core/auto-start.d.ts +2 -2
- package/dist/core/auto-start.js +2 -2
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +2 -1
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/dashboard-events.d.ts +5 -0
- package/dist/core/dashboard-events.d.ts.map +1 -1
- package/dist/core/dashboard-events.js.map +1 -1
- package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
- package/dist/core/dashboard-ipc-server.js +47 -2
- package/dist/core/dashboard-ipc-server.js.map +1 -1
- package/dist/core/idle-worker-sweeper.d.ts +1 -1
- package/dist/core/idle-worker-sweeper.js +1 -1
- package/dist/core/passthrough-commands.d.ts.map +1 -1
- package/dist/core/passthrough-commands.js +1 -0
- package/dist/core/passthrough-commands.js.map +1 -1
- package/dist/core/scheduler.d.ts +12 -0
- package/dist/core/scheduler.d.ts.map +1 -1
- package/dist/core/scheduler.js +67 -7
- package/dist/core/scheduler.js.map +1 -1
- package/dist/core/session-discovery.js +1 -1
- package/dist/core/session-discovery.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +33 -7
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/trigger-session.d.ts.map +1 -1
- package/dist/core/trigger-session.js +78 -23
- package/dist/core/trigger-session.js.map +1 -1
- package/dist/core/worker-pool.d.ts +4 -1
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +4 -0
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/core/zellij-adopt-discovery.js +1 -1
- package/dist/core/zellij-adopt-discovery.js.map +1 -1
- package/dist/daemon.d.ts +121 -0
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +2644 -2
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/federated-group-core.js +1 -1
- package/dist/dashboard/federated-group-core.js.map +1 -1
- package/dist/dashboard/federation-api.js +1 -1
- package/dist/dashboard/schedule-card-model.d.ts +4 -3
- package/dist/dashboard/schedule-card-model.d.ts.map +1 -1
- package/dist/dashboard/schedule-card-model.js +5 -4
- package/dist/dashboard/schedule-card-model.js.map +1 -1
- package/dist/dashboard/settings-write-applier.d.ts +37 -3
- package/dist/dashboard/settings-write-applier.d.ts.map +1 -1
- package/dist/dashboard/settings-write-applier.js +63 -0
- package/dist/dashboard/settings-write-applier.js.map +1 -1
- package/dist/dashboard/web/i18n.d.ts.map +1 -1
- package/dist/dashboard/web/i18n.js +28 -0
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard/web/insights.js +19 -19
- package/dist/dashboard/web/insights.js.map +1 -1
- package/dist/dashboard/web/overview-page.d.ts.map +1 -1
- package/dist/dashboard/web/overview-page.js +7 -4
- package/dist/dashboard/web/overview-page.js.map +1 -1
- package/dist/dashboard/web/schedules-page.d.ts +1 -1
- package/dist/dashboard/web/schedules-page.d.ts.map +1 -1
- package/dist/dashboard/web/schedules-page.js +7 -3
- package/dist/dashboard/web/schedules-page.js.map +1 -1
- package/dist/dashboard/web/sessions.js +2 -2
- package/dist/dashboard/web/settings-page.d.ts +9 -0
- package/dist/dashboard/web/settings-page.d.ts.map +1 -1
- package/dist/dashboard/web/settings-page.js +132 -43
- package/dist/dashboard/web/settings-page.js.map +1 -1
- package/dist/dashboard/web/store.d.ts +6 -0
- package/dist/dashboard/web/store.d.ts.map +1 -1
- package/dist/dashboard/web/store.js +18 -1
- package/dist/dashboard/web/store.js.map +1 -1
- package/dist/dashboard/webhook-routes.d.ts.map +1 -1
- package/dist/dashboard/webhook-routes.js +24 -0
- package/dist/dashboard/webhook-routes.js.map +1 -1
- package/dist/dashboard-web/app.js +3 -3
- package/dist/dashboard-web/chunks/{bot-defaults-page-Z36I5CKM.js → bot-defaults-page-3OIY7N76.js} +1 -1
- package/dist/dashboard-web/chunks/{chunk-2BBCKWNO.js → chunk-BNEXMNQD.js} +3 -3
- package/dist/dashboard-web/chunks/{chunk-QDKIUULH.js → chunk-DKKOGZCG.js} +1 -1
- package/dist/dashboard-web/chunks/chunk-LXIK7OUJ.js +1 -0
- package/dist/dashboard-web/chunks/{chunk-BAMNP73K.js → chunk-VFCACTRF.js} +1 -1
- package/dist/dashboard-web/chunks/{connectors-I3MGERCM.js → connectors-VDOAKUW3.js} +1 -1
- package/dist/dashboard-web/chunks/{groups-page-DTP2L4FQ.js → groups-page-CX5AN4XG.js} +1 -1
- package/dist/dashboard-web/chunks/{insights-page-FNI24WYF.js → insights-page-DOMRL4S6.js} +1 -1
- package/dist/dashboard-web/chunks/overview-page-AZBAXVZ7.js +1 -0
- package/dist/dashboard-web/chunks/{roles-page-A5DZ7Q6U.js → roles-page-3FEAH6S4.js} +1 -1
- package/dist/dashboard-web/chunks/schedules-CTQEA7IE.js +1 -0
- package/dist/dashboard-web/chunks/{sessions-YJ735IH4.js → sessions-LVZCXO2Z.js} +1 -1
- package/dist/dashboard-web/chunks/{sessions-page-2REIJ56C.js → sessions-page-NHBJDSBC.js} +1 -1
- package/dist/dashboard-web/chunks/settings-page-CRDIHRNE.js +2 -0
- package/dist/dashboard-web/chunks/{skills-page-ZCCLHWMJ.js → skills-page-VUG3EPWX.js} +1 -1
- package/dist/dashboard-web/chunks/{team-federation-page-4FCGO3WW.js → team-federation-page-ZKL3YMGN.js} +1 -1
- package/dist/dashboard-web/chunks/{workflows-KFJ7O57L.js → workflows-4BYQQBFP.js} +1 -1
- package/dist/dashboard-web/index.html +1 -1
- package/dist/dashboard-web/style.css +111 -16
- package/dist/dashboard.js +196 -2
- package/dist/dashboard.js.map +1 -1
- package/dist/global-config.d.ts +30 -0
- package/dist/global-config.d.ts.map +1 -1
- package/dist/global-config.js +64 -1
- package/dist/global-config.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +10 -7
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +10 -7
- package/dist/i18n/zh.js.map +1 -1
- package/dist/im/lark/card-builder.d.ts +1 -1
- package/dist/im/lark/card-builder.js +1 -1
- package/dist/im/lark/card-handler.d.ts +3 -0
- package/dist/im/lark/card-handler.d.ts.map +1 -1
- package/dist/im/lark/card-handler.js +8 -0
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/im/lark/client.d.ts +1 -0
- package/dist/im/lark/client.d.ts.map +1 -1
- package/dist/im/lark/client.js +19 -0
- package/dist/im/lark/client.js.map +1 -1
- package/dist/im/lark/event-dispatcher.d.ts +10 -0
- package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
- package/dist/im/lark/event-dispatcher.js +100 -21
- package/dist/im/lark/event-dispatcher.js.map +1 -1
- package/dist/im/lark/grant-command.d.ts +1 -1
- package/dist/im/lark/grant-command.js +1 -1
- package/dist/im/lark/workflow-slash-command.js +4 -0
- package/dist/im/lark/workflow-slash-command.js.map +1 -1
- package/dist/mir-prompt.d.ts +16 -0
- package/dist/mir-prompt.d.ts.map +1 -0
- package/dist/mir-prompt.js +170 -0
- package/dist/mir-prompt.js.map +1 -0
- package/dist/mir-runner.js +1 -149
- package/dist/mir-runner.js.map +1 -1
- package/dist/platform/bind.d.ts.map +1 -1
- package/dist/platform/bind.js +3 -11
- package/dist/platform/bind.js.map +1 -1
- package/dist/platform/binding.d.ts +4 -5
- package/dist/platform/binding.d.ts.map +1 -1
- package/dist/platform/binding.js +0 -11
- package/dist/platform/binding.js.map +1 -1
- package/dist/platform/tunnel-client.d.ts.map +1 -1
- package/dist/platform/tunnel-client.js +37 -28
- package/dist/platform/tunnel-client.js.map +1 -1
- package/dist/services/deployment-identity.d.ts +1 -1
- package/dist/services/deployment-identity.d.ts.map +1 -1
- package/dist/services/deployment-identity.js +1 -1
- package/dist/services/deployment-identity.js.map +1 -1
- package/dist/services/doc-subs-store.js +1 -1
- package/dist/services/team-board-store.js +1 -1
- package/dist/services/team-board-store.js.map +1 -1
- package/dist/services/trigger-types.d.ts +2 -1
- package/dist/services/trigger-types.d.ts.map +1 -1
- package/dist/services/trigger-types.js +11 -2
- package/dist/services/trigger-types.js.map +1 -1
- package/dist/services/vc-meeting-runtime-store.d.ts +55 -0
- package/dist/services/vc-meeting-runtime-store.d.ts.map +1 -0
- package/dist/services/vc-meeting-runtime-store.js +313 -0
- package/dist/services/vc-meeting-runtime-store.js.map +1 -0
- package/dist/services/voice/index.d.ts +6 -1
- package/dist/services/voice/index.d.ts.map +1 -1
- package/dist/services/voice/index.js +12 -5
- package/dist/services/voice/index.js.map +1 -1
- package/dist/services/voice/sami.js +1 -1
- package/dist/setup/lark-scopes.json +5 -0
- package/dist/setup/verify-permissions.d.ts +6 -0
- package/dist/setup/verify-permissions.d.ts.map +1 -1
- package/dist/setup/verify-permissions.js +17 -0
- package/dist/setup/verify-permissions.js.map +1 -1
- package/dist/skills/definitions.d.ts.map +1 -1
- package/dist/skills/definitions.js +10 -0
- package/dist/skills/definitions.js.map +1 -1
- package/dist/utils/daemon-discovery.d.ts +2 -0
- package/dist/utils/daemon-discovery.d.ts.map +1 -1
- package/dist/utils/daemon-discovery.js +2 -0
- package/dist/utils/daemon-discovery.js.map +1 -1
- package/dist/utils/timezone.d.ts +51 -0
- package/dist/utils/timezone.d.ts.map +1 -0
- package/dist/utils/timezone.js +110 -0
- package/dist/utils/timezone.js.map +1 -0
- package/dist/vc-agent/cards.d.ts +47 -0
- package/dist/vc-agent/cards.d.ts.map +1 -0
- package/dist/vc-agent/cards.js +489 -0
- package/dist/vc-agent/cards.js.map +1 -0
- package/dist/vc-agent/meeting-state.d.ts +39 -0
- package/dist/vc-agent/meeting-state.d.ts.map +1 -0
- package/dist/vc-agent/meeting-state.js +186 -0
- package/dist/vc-agent/meeting-state.js.map +1 -0
- package/dist/vc-agent/normalizer.d.ts +13 -0
- package/dist/vc-agent/normalizer.d.ts.map +1 -0
- package/dist/vc-agent/normalizer.js +411 -0
- package/dist/vc-agent/normalizer.js.map +1 -0
- package/dist/vc-agent/polling-source.d.ts +36 -0
- package/dist/vc-agent/polling-source.d.ts.map +1 -0
- package/dist/vc-agent/polling-source.js +129 -0
- package/dist/vc-agent/polling-source.js.map +1 -0
- package/dist/vc-agent/push-source.d.ts +13 -0
- package/dist/vc-agent/push-source.d.ts.map +1 -0
- package/dist/vc-agent/push-source.js +109 -0
- package/dist/vc-agent/push-source.js.map +1 -0
- package/dist/vc-agent/realtime/audio-source.d.ts +6 -0
- package/dist/vc-agent/realtime/audio-source.d.ts.map +1 -0
- package/dist/vc-agent/realtime/audio-source.js +17 -0
- package/dist/vc-agent/realtime/audio-source.js.map +1 -0
- package/dist/vc-agent/realtime/endpoint.d.ts +6 -0
- package/dist/vc-agent/realtime/endpoint.d.ts.map +1 -0
- package/dist/vc-agent/realtime/endpoint.js +25 -0
- package/dist/vc-agent/realtime/endpoint.js.map +1 -0
- package/dist/vc-agent/realtime/errors.d.ts +9 -0
- package/dist/vc-agent/realtime/errors.d.ts.map +1 -0
- package/dist/vc-agent/realtime/errors.js +17 -0
- package/dist/vc-agent/realtime/errors.js.map +1 -0
- package/dist/vc-agent/realtime/events.d.ts +24 -0
- package/dist/vc-agent/realtime/events.d.ts.map +1 -0
- package/dist/vc-agent/realtime/events.js +190 -0
- package/dist/vc-agent/realtime/events.js.map +1 -0
- package/dist/vc-agent/realtime/frontier.d.ts +34 -0
- package/dist/vc-agent/realtime/frontier.d.ts.map +1 -0
- package/dist/vc-agent/realtime/frontier.js +40 -0
- package/dist/vc-agent/realtime/frontier.js.map +1 -0
- package/dist/vc-agent/realtime/index.d.ts +11 -0
- package/dist/vc-agent/realtime/index.d.ts.map +1 -0
- package/dist/vc-agent/realtime/index.js +11 -0
- package/dist/vc-agent/realtime/index.js.map +1 -0
- package/dist/vc-agent/realtime/pacer.d.ts +21 -0
- package/dist/vc-agent/realtime/pacer.d.ts.map +1 -0
- package/dist/vc-agent/realtime/pacer.js +80 -0
- package/dist/vc-agent/realtime/pacer.js.map +1 -0
- package/dist/vc-agent/realtime/protobuf.d.ts +33 -0
- package/dist/vc-agent/realtime/protobuf.d.ts.map +1 -0
- package/dist/vc-agent/realtime/protobuf.js +159 -0
- package/dist/vc-agent/realtime/protobuf.js.map +1 -0
- package/dist/vc-agent/realtime/protocol.d.ts +4 -0
- package/dist/vc-agent/realtime/protocol.d.ts.map +1 -0
- package/dist/vc-agent/realtime/protocol.js +59 -0
- package/dist/vc-agent/realtime/protocol.js.map +1 -0
- package/dist/vc-agent/realtime/session.d.ts +39 -0
- package/dist/vc-agent/realtime/session.d.ts.map +1 -0
- package/dist/vc-agent/realtime/session.js +221 -0
- package/dist/vc-agent/realtime/session.js.map +1 -0
- package/dist/vc-agent/realtime/transport.d.ts +23 -0
- package/dist/vc-agent/realtime/transport.d.ts.map +1 -0
- package/dist/vc-agent/realtime/transport.js +112 -0
- package/dist/vc-agent/realtime/transport.js.map +1 -0
- package/dist/vc-agent/realtime/types.d.ts +84 -0
- package/dist/vc-agent/realtime/types.d.ts.map +1 -0
- package/dist/vc-agent/realtime/types.js +5 -0
- package/dist/vc-agent/realtime/types.js.map +1 -0
- package/dist/vc-agent/types.d.ts +142 -0
- package/dist/vc-agent/types.d.ts.map +1 -0
- package/dist/vc-agent/types.js +2 -0
- package/dist/vc-agent/types.js.map +1 -0
- package/dist/worker.js +3 -3
- package/dist/worker.js.map +1 -1
- package/dist/workflows/attempt-resume.d.ts +4 -0
- package/dist/workflows/attempt-resume.d.ts.map +1 -1
- package/dist/workflows/attempt-resume.js +2 -0
- package/dist/workflows/attempt-resume.js.map +1 -1
- package/dist/workflows/attempt-terminal.d.ts +4 -0
- package/dist/workflows/attempt-terminal.d.ts.map +1 -1
- package/dist/workflows/attempt-terminal.js.map +1 -1
- package/dist/workflows/daemon-spawn.d.ts.map +1 -1
- package/dist/workflows/daemon-spawn.js +7 -0
- package/dist/workflows/daemon-spawn.js.map +1 -1
- package/dist/workflows/events/payloads.d.ts +32 -0
- package/dist/workflows/events/payloads.d.ts.map +1 -1
- package/dist/workflows/events/payloads.js +4 -0
- package/dist/workflows/events/payloads.js.map +1 -1
- package/dist/workflows/events/schema.d.ts +56 -0
- package/dist/workflows/events/schema.d.ts.map +1 -1
- package/dist/workflows/runtime.d.ts +4 -0
- package/dist/workflows/runtime.d.ts.map +1 -1
- package/dist/workflows/runtime.js.map +1 -1
- package/dist/workflows/spawn-policy.d.ts +14 -0
- package/dist/workflows/spawn-policy.d.ts.map +1 -0
- package/dist/workflows/spawn-policy.js +9 -0
- package/dist/workflows/spawn-policy.js.map +1 -0
- package/dist/workflows/v3/bot-resolve.d.ts.map +1 -1
- package/dist/workflows/v3/bot-resolve.js +4 -0
- package/dist/workflows/v3/bot-resolve.js.map +1 -1
- package/dist/workflows/v3/cli-run.d.ts.map +1 -1
- package/dist/workflows/v3/cli-run.js +4 -0
- package/dist/workflows/v3/cli-run.js.map +1 -1
- package/dist/workflows/v3/contract.d.ts +9 -3
- package/dist/workflows/v3/contract.d.ts.map +1 -1
- package/dist/workflows/v3/contract.js +3 -3
- package/dist/workflows/v3/contract.js.map +1 -1
- package/dist/workflows/v3/ephemeral-pool.d.ts.map +1 -1
- package/dist/workflows/v3/ephemeral-pool.js +2 -0
- package/dist/workflows/v3/ephemeral-pool.js.map +1 -1
- package/dist/workflows/v3/runtime.js +1 -1
- package/dist/workflows/v3/runtime.js.map +1 -1
- package/package.json +1 -1
- package/dist/dashboard-web/chunks/chunk-76J7PNZI.js +0 -1
- package/dist/dashboard-web/chunks/overview-page-EHCZJBWY.js +0 -1
- package/dist/dashboard-web/chunks/schedules-RSXALJU4.js +0 -1
- package/dist/dashboard-web/chunks/settings-page-XKFTXTDE.js +0 -2
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import { beginVcPollingPass, buildVcMeetingStatePayload, collectStableTranscriptItems, createVcMeetingSessionState, ingestNormalizedVcMeetingItems, } from '../vc-agent/meeting-state.js';
|
|
2
|
+
import { fetchMeetingEventsAsBot, joinMeetingAsBot } from '../vc-agent/polling-source.js';
|
|
3
|
+
import { DEFAULT_REALTIME_VOICE_CHANNELS, DEFAULT_REALTIME_VOICE_FRAME_MS, DEFAULT_REALTIME_VOICE_SAMPLE_RATE, connectRealtimeVoiceTransport, createProtoRealtimeVoiceProtocol, fetchRealtimeVoiceEndpoint, RealtimeVoiceSession, } from '../vc-agent/realtime/index.js';
|
|
4
|
+
import { loadBotConfigs, registerBot } from '../bot-registry.js';
|
|
5
|
+
import { config } from '../config.js';
|
|
6
|
+
import { listVcMeetingRuntimeSessions } from '../services/vc-meeting-runtime-store.js';
|
|
7
|
+
import { findOnlineDaemon } from '../utils/daemon-discovery.js';
|
|
8
|
+
const VC_AGENT_SPEAK_MAX_TEXT_LENGTH = 200;
|
|
9
|
+
function argValue(args, name) {
|
|
10
|
+
const eq = args.find((a) => a.startsWith(`${name}=`));
|
|
11
|
+
if (eq)
|
|
12
|
+
return eq.slice(name.length + 1);
|
|
13
|
+
const idx = args.indexOf(name);
|
|
14
|
+
if (idx >= 0)
|
|
15
|
+
return args[idx + 1];
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
function hasFlag(args, name) {
|
|
19
|
+
return args.includes(name);
|
|
20
|
+
}
|
|
21
|
+
function intArg(args, name, fallback, min, max) {
|
|
22
|
+
const raw = argValue(args, name);
|
|
23
|
+
const n = raw ? Number(raw) : fallback;
|
|
24
|
+
if (!Number.isFinite(n))
|
|
25
|
+
return fallback;
|
|
26
|
+
return Math.min(max, Math.max(min, Math.floor(n)));
|
|
27
|
+
}
|
|
28
|
+
function usage() {
|
|
29
|
+
console.log(`botmux vc-agent <command>
|
|
30
|
+
|
|
31
|
+
Commands:
|
|
32
|
+
tat-gate Verify bot identity can read real transcript/chat items from a meeting
|
|
33
|
+
poll Run the P0 polling bridge and print stable meeting-state JSON
|
|
34
|
+
request-output
|
|
35
|
+
Ask the daemon to review/send a meeting agent text or voice output
|
|
36
|
+
speak Speak one TTS utterance into an active meeting via realtime voice
|
|
37
|
+
|
|
38
|
+
Examples:
|
|
39
|
+
botmux vc-agent tat-gate --meeting-id <meeting_id>
|
|
40
|
+
botmux vc-agent tat-gate --meeting-number 123456789
|
|
41
|
+
botmux vc-agent poll --meeting-id <meeting_id> --once
|
|
42
|
+
botmux vc-agent poll --meeting-id <meeting_id> --page-token-mode incremental ...
|
|
43
|
+
botmux vc-agent request-output --lark-app-id cli_xxx --meeting-id <meeting_id> --channel text --content "..."
|
|
44
|
+
botmux vc-agent speak --lark-app-id cli_xxx --meeting-id <meeting_id> --text "大家好"
|
|
45
|
+
`);
|
|
46
|
+
}
|
|
47
|
+
let botRegistryLoaded = false;
|
|
48
|
+
function ensureBotRegistryLoaded() {
|
|
49
|
+
if (botRegistryLoaded)
|
|
50
|
+
return;
|
|
51
|
+
for (const cfg of loadBotConfigs())
|
|
52
|
+
registerBot(cfg);
|
|
53
|
+
botRegistryLoaded = true;
|
|
54
|
+
}
|
|
55
|
+
function resolveMeetingId(args, opts = {}) {
|
|
56
|
+
const meetingId = argValue(args, '--meeting-id');
|
|
57
|
+
if (meetingId)
|
|
58
|
+
return { meetingId, joined: false };
|
|
59
|
+
const meetingNumber = argValue(args, '--meeting-number');
|
|
60
|
+
if (!meetingNumber)
|
|
61
|
+
throw new Error('missing --meeting-id or --meeting-number');
|
|
62
|
+
if (opts.allowJoin === false) {
|
|
63
|
+
throw new Error('--meeting-number would make the bot join the meeting; use --meeting-id for dry-run');
|
|
64
|
+
}
|
|
65
|
+
const joined = joinMeetingAsBot({
|
|
66
|
+
meetingNumber,
|
|
67
|
+
password: argValue(args, '--password'),
|
|
68
|
+
profile: argValue(args, '--profile'),
|
|
69
|
+
});
|
|
70
|
+
return { meetingId: joined.meetingId, joined: true };
|
|
71
|
+
}
|
|
72
|
+
async function cmdTatGate(args) {
|
|
73
|
+
const { meetingId, joined } = resolveMeetingId(args);
|
|
74
|
+
const { raw, batch } = fetchMeetingEventsAsBot({
|
|
75
|
+
meetingId,
|
|
76
|
+
pageSize: intArg(args, '--page-size', 100, 20, 100),
|
|
77
|
+
pageAll: true,
|
|
78
|
+
profile: argValue(args, '--profile'),
|
|
79
|
+
});
|
|
80
|
+
const rawProblem = larkCliErrorSummary(raw);
|
|
81
|
+
const contentItems = batch.items.filter((item) => item.type === 'chat_received' || item.type === 'transcript_received');
|
|
82
|
+
const ok = !rawProblem && (contentItems.length > 0 || hasFlag(args, '--allow-empty-content'));
|
|
83
|
+
const summary = {
|
|
84
|
+
ok,
|
|
85
|
+
meetingId,
|
|
86
|
+
joined,
|
|
87
|
+
totalItems: batch.items.length,
|
|
88
|
+
transcriptItems: batch.items.filter((item) => item.type === 'transcript_received').length,
|
|
89
|
+
chatItems: batch.items.filter((item) => item.type === 'chat_received').length,
|
|
90
|
+
pageToken: batch.pageToken,
|
|
91
|
+
...(rawProblem ? { larkCliError: rawProblem } : {}),
|
|
92
|
+
};
|
|
93
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
94
|
+
if (!ok) {
|
|
95
|
+
if (rawProblem) {
|
|
96
|
+
console.error(`TAT read gate failed: lark-cli returned an error payload: ${rawProblem}`);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
console.error('TAT read gate failed: bot identity did not read transcript_received/chat_received items. Make sure someone speaks or sends chat during the gate.');
|
|
100
|
+
}
|
|
101
|
+
console.error(`raw lark-cli payload excerpt: ${rawExcerpt(raw)}`);
|
|
102
|
+
process.exit(2);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function rawExcerpt(raw) {
|
|
106
|
+
try {
|
|
107
|
+
return JSON.stringify(raw).slice(0, 2_000);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return String(raw).slice(0, 2_000);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function larkCliErrorSummary(raw) {
|
|
114
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw))
|
|
115
|
+
return undefined;
|
|
116
|
+
const r = raw;
|
|
117
|
+
const code = r.code ?? r.error?.code ?? r.data?.code;
|
|
118
|
+
const msg = r.msg ?? r.message ?? r.error?.msg ?? r.error?.message ?? r.data?.msg;
|
|
119
|
+
if (code !== undefined && code !== 0 && code !== '0') {
|
|
120
|
+
return [String(code), typeof msg === 'string' ? msg : undefined].filter(Boolean).join(' ');
|
|
121
|
+
}
|
|
122
|
+
if (r.error && (typeof r.error === 'string' || typeof r.error === 'object')) {
|
|
123
|
+
return typeof r.error === 'string' ? r.error : rawExcerpt(r.error);
|
|
124
|
+
}
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
function sleep(ms) {
|
|
128
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
129
|
+
}
|
|
130
|
+
async function cmdPoll(args) {
|
|
131
|
+
const dryRun = hasFlag(args, '--dry-run');
|
|
132
|
+
const { meetingId, joined } = resolveMeetingId(args, { allowJoin: !dryRun });
|
|
133
|
+
const state = createVcMeetingSessionState({
|
|
134
|
+
meeting: { id: meetingId },
|
|
135
|
+
attentionTargetOpenId: argValue(args, '--attention-target'),
|
|
136
|
+
notificationChatId: argValue(args, '--notification-chat-id'),
|
|
137
|
+
});
|
|
138
|
+
const pollMs = intArg(args, '--poll-ms', 10_000, 1_000, 300_000);
|
|
139
|
+
const maxPolls = intArg(args, '--max-polls', hasFlag(args, '--once') ? 1 : Number.MAX_SAFE_INTEGER, 1, Number.MAX_SAFE_INTEGER);
|
|
140
|
+
const pageSize = intArg(args, '--page-size', 100, 20, 100);
|
|
141
|
+
const stabilizePollWindows = intArg(args, '--stabilize-windows', 1, 0, 10);
|
|
142
|
+
const lookbackMs = intArg(args, '--lookback-ms', 30_000, 0, 30 * 60_000);
|
|
143
|
+
const pageTokenMode = parsePageTokenMode(args);
|
|
144
|
+
const idlePollsBeforeSoftClose = intArg(args, '--idle-polls-before-soft-close', 0, 0, 10_000);
|
|
145
|
+
console.error(`vc-agent polling started: meetingId=${meetingId}${joined ? ' joined=true' : ''} output=json`);
|
|
146
|
+
let consecutiveFailures = 0;
|
|
147
|
+
for (let poll = 0; poll < maxPolls; poll += 1) {
|
|
148
|
+
beginVcPollingPass(state);
|
|
149
|
+
const fallbackStart = pageTokenMode === 'incremental' || state.ingestion.lastSeenEventTime === undefined
|
|
150
|
+
? undefined
|
|
151
|
+
: new Date(Math.max(0, state.ingestion.lastSeenEventTime - lookbackMs)).toISOString();
|
|
152
|
+
let batch;
|
|
153
|
+
try {
|
|
154
|
+
({ batch } = fetchMeetingEventsAsBot({
|
|
155
|
+
meetingId,
|
|
156
|
+
pageToken: pageTokenMode === 'incremental' ? state.ingestion.pageToken : undefined,
|
|
157
|
+
start: fallbackStart,
|
|
158
|
+
pageSize,
|
|
159
|
+
pageAll: true,
|
|
160
|
+
profile: argValue(args, '--profile'),
|
|
161
|
+
}));
|
|
162
|
+
consecutiveFailures = 0;
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
if (maxPolls === 1)
|
|
166
|
+
throw err;
|
|
167
|
+
consecutiveFailures += 1;
|
|
168
|
+
const backoffMs = Math.min(60_000, pollMs * Math.min(consecutiveFailures, 6));
|
|
169
|
+
console.error(`vc-agent poll failed poll=${poll + 1} failures=${consecutiveFailures}: ${err instanceof Error ? err.message : String(err)}; retrying in ${backoffMs}ms`);
|
|
170
|
+
if (poll + 1 < maxPolls)
|
|
171
|
+
await sleep(backoffMs);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
state.meeting = { ...state.meeting, ...batch.meeting, id: meetingId };
|
|
175
|
+
state.ingestion.pageToken = batch.pageToken;
|
|
176
|
+
const ingest = ingestNormalizedVcMeetingItems(state, batch.items);
|
|
177
|
+
const stableTranscripts = collectStableTranscriptItems(state, { stabilizePollWindows });
|
|
178
|
+
const outgoing = [...ingest.acceptedItems, ...stableTranscripts];
|
|
179
|
+
if (outgoing.length > 0) {
|
|
180
|
+
const payload = buildVcMeetingStatePayload(state, outgoing, {
|
|
181
|
+
pageToken: batch.pageToken,
|
|
182
|
+
hasMore: batch.hasMore,
|
|
183
|
+
});
|
|
184
|
+
console.log(JSON.stringify(payload));
|
|
185
|
+
console.error(`vc-agent emitted poll=${state.ingestion.pollOrdinal} items=${outgoing.length}`);
|
|
186
|
+
}
|
|
187
|
+
if (idlePollsBeforeSoftClose > 0 && state.ingestion.emptyPollCount >= idlePollsBeforeSoftClose) {
|
|
188
|
+
console.error(`vc-agent soft close: ${state.ingestion.emptyPollCount} empty polls`);
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
if (poll + 1 < maxPolls)
|
|
192
|
+
await sleep(pollMs);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async function cmdSpeak(args) {
|
|
196
|
+
const larkAppId = argValue(args, '--lark-app-id') ?? argValue(args, '--app-id') ?? argValue(args, '--profile');
|
|
197
|
+
const meetingId = argValue(args, '--meeting-id');
|
|
198
|
+
const text = argValue(args, '--text')?.trim();
|
|
199
|
+
if (!larkAppId)
|
|
200
|
+
throw new Error('missing --lark-app-id');
|
|
201
|
+
if (!meetingId)
|
|
202
|
+
throw new Error('missing --meeting-id');
|
|
203
|
+
if (!text)
|
|
204
|
+
throw new Error('missing --text');
|
|
205
|
+
if (text.length > VC_AGENT_SPEAK_MAX_TEXT_LENGTH) {
|
|
206
|
+
throw new Error(`--text is too long; keep meeting speech within ${VC_AGENT_SPEAK_MAX_TEXT_LENGTH} characters`);
|
|
207
|
+
}
|
|
208
|
+
ensureBotRegistryLoaded();
|
|
209
|
+
if (!hasFlag(args, '--operator-override')) {
|
|
210
|
+
const record = listVcMeetingRuntimeSessions(config.session.dataDir, larkAppId)
|
|
211
|
+
.find(item => item.meeting.id === meetingId);
|
|
212
|
+
if (record?.voiceOutputPolicy !== 'allow') {
|
|
213
|
+
throw new Error('direct vc-agent speak is disabled for meeting agents; use vc-agent request-output or pass --operator-override for human dogfood');
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
const endpoint = await fetchRealtimeVoiceEndpoint(larkAppId, meetingId);
|
|
217
|
+
const transport = await connectRealtimeVoiceTransport(endpoint.websocketUrl);
|
|
218
|
+
const session = new RealtimeVoiceSession({
|
|
219
|
+
larkAppId,
|
|
220
|
+
meetingId,
|
|
221
|
+
protocol: createProtoRealtimeVoiceProtocol(),
|
|
222
|
+
transport,
|
|
223
|
+
audioFormat: {
|
|
224
|
+
sampleRate: intArg(args, '--sample-rate', DEFAULT_REALTIME_VOICE_SAMPLE_RATE, 8_000, 48_000),
|
|
225
|
+
channels: intArg(args, '--channels', DEFAULT_REALTIME_VOICE_CHANNELS, 1, 2),
|
|
226
|
+
frameMs: intArg(args, '--frame-ms', DEFAULT_REALTIME_VOICE_FRAME_MS, 20, 1_000),
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
let started = false;
|
|
230
|
+
try {
|
|
231
|
+
await session.start();
|
|
232
|
+
started = true;
|
|
233
|
+
const result = await session.speak(text);
|
|
234
|
+
console.log(JSON.stringify({
|
|
235
|
+
ok: true,
|
|
236
|
+
meetingId,
|
|
237
|
+
larkAppId,
|
|
238
|
+
frames: result.frames,
|
|
239
|
+
durationMs: result.durationMs,
|
|
240
|
+
}, null, 2));
|
|
241
|
+
}
|
|
242
|
+
finally {
|
|
243
|
+
await session.stop(started ? 'cli-speak-finished' : 'cli-speak-failed').catch(() => { });
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
async function cmdRequestOutput(args) {
|
|
247
|
+
const larkAppId = argValue(args, '--lark-app-id') ?? argValue(args, '--app-id') ?? argValue(args, '--profile');
|
|
248
|
+
const meetingId = argValue(args, '--meeting-id');
|
|
249
|
+
const channel = argValue(args, '--channel');
|
|
250
|
+
const content = argValue(args, '--content')?.trim();
|
|
251
|
+
const reason = argValue(args, '--reason')?.trim();
|
|
252
|
+
const fallbackText = argValue(args, '--fallback-text')?.trim();
|
|
253
|
+
if (!larkAppId)
|
|
254
|
+
throw new Error('missing --lark-app-id');
|
|
255
|
+
if (!meetingId)
|
|
256
|
+
throw new Error('missing --meeting-id');
|
|
257
|
+
if (channel !== 'text' && channel !== 'voice')
|
|
258
|
+
throw new Error('--channel must be text or voice');
|
|
259
|
+
if (!content)
|
|
260
|
+
throw new Error('missing --content');
|
|
261
|
+
if (content.length > VC_AGENT_SPEAK_MAX_TEXT_LENGTH) {
|
|
262
|
+
throw new Error(`--content is too long; keep output within ${VC_AGENT_SPEAK_MAX_TEXT_LENGTH} characters`);
|
|
263
|
+
}
|
|
264
|
+
if (fallbackText && fallbackText.length > VC_AGENT_SPEAK_MAX_TEXT_LENGTH) {
|
|
265
|
+
throw new Error(`--fallback-text is too long; keep output within ${VC_AGENT_SPEAK_MAX_TEXT_LENGTH} characters`);
|
|
266
|
+
}
|
|
267
|
+
ensureBotRegistryLoaded();
|
|
268
|
+
const daemon = findOnlineDaemon(larkAppId);
|
|
269
|
+
if (!daemon)
|
|
270
|
+
throw new Error(`daemon offline for ${larkAppId}`);
|
|
271
|
+
const response = await fetch(`http://127.0.0.1:${daemon.ipcPort}/api/vc-meetings/output-request`, {
|
|
272
|
+
method: 'POST',
|
|
273
|
+
headers: { 'content-type': 'application/json' },
|
|
274
|
+
body: JSON.stringify({
|
|
275
|
+
larkAppId,
|
|
276
|
+
meetingId,
|
|
277
|
+
channel,
|
|
278
|
+
content,
|
|
279
|
+
...(reason ? { reason } : {}),
|
|
280
|
+
...(fallbackText ? { fallbackText } : {}),
|
|
281
|
+
}),
|
|
282
|
+
});
|
|
283
|
+
const raw = await response.text();
|
|
284
|
+
let body = raw;
|
|
285
|
+
try {
|
|
286
|
+
body = raw ? JSON.parse(raw) : {};
|
|
287
|
+
}
|
|
288
|
+
catch {
|
|
289
|
+
// Keep the raw body for operator-visible debugging.
|
|
290
|
+
}
|
|
291
|
+
console.log(typeof body === 'string' ? body : JSON.stringify(body, null, 2));
|
|
292
|
+
if (response.status >= 400)
|
|
293
|
+
process.exit(2);
|
|
294
|
+
}
|
|
295
|
+
function parsePageTokenMode(args) {
|
|
296
|
+
const raw = argValue(args, '--page-token-mode') ?? 'time-window';
|
|
297
|
+
if (raw === 'time-window' || raw === 'incremental')
|
|
298
|
+
return raw;
|
|
299
|
+
throw new Error('--page-token-mode must be time-window or incremental');
|
|
300
|
+
}
|
|
301
|
+
export async function cmdVcAgent(command, args) {
|
|
302
|
+
try {
|
|
303
|
+
if (!command || command === 'help' || command === '--help' || command === '-h') {
|
|
304
|
+
usage();
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (command === 'tat-gate') {
|
|
308
|
+
await cmdTatGate(args);
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
if (command === 'poll') {
|
|
312
|
+
await cmdPoll(args);
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
if (command === 'request-output') {
|
|
316
|
+
await cmdRequestOutput(args);
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
if (command === 'speak') {
|
|
320
|
+
await cmdSpeak(args);
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
usage();
|
|
324
|
+
throw new Error(`unknown vc-agent command: ${command}`);
|
|
325
|
+
}
|
|
326
|
+
catch (err) {
|
|
327
|
+
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
328
|
+
process.exit(1);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
//# sourceMappingURL=vc-agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vc-agent.js","sourceRoot":"","sources":["../../src/cli/vc-agent.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAk7DA,MAAM,MAAM,kBAAkB,GAC1B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,SAAS,GAAG,gBAAgB,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACtE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,WAAW,GAAG,YAAY,GAAG,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAk2HrF;;;;;;;;;;;GAWG;AACH,wBAAsB,OAAO,CAC3B,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,EACvC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,qBAAqB,EAAE,SAAS,CAAC,EAC9F,KAAK,EAAE,MAAM,EACb,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,2BAA2B,EAAE,UAAU,GAAG,IAAI,CAAC,GACzF,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA8F7B"}
|
package/dist/cli.js
CHANGED
|
@@ -40,9 +40,10 @@ import { buildBotFromAddFlags, editInputFromFlags, isScriptedSetupInvocation, ma
|
|
|
40
40
|
import { interactiveSelect, pickChoice, pickCliSelection } from './setup/interactive-select.js';
|
|
41
41
|
import { buildPreset, serializePreset, presetFilename } from './setup/agent-preset.js';
|
|
42
42
|
import { logger } from './utils/logger.js';
|
|
43
|
+
import { scheduleTimeZone } from './utils/timezone.js';
|
|
43
44
|
import { expandHomePath, invalidWorkingDirs } from './utils/working-dir.js';
|
|
44
45
|
import { firstPositional } from './cli/arg-utils.js';
|
|
45
|
-
import { dispatchPrimaryMessage, findStdinAliasAttachment, sendFileAttachments } from './cli/send-dispatch.js';
|
|
46
|
+
import { dispatchPrimaryMessage, findStdinAliasAttachment, sendFileAttachments, sendVideoAttachments, shouldSendAsPureVideo, validateVideoAttachments } from './cli/send-dispatch.js';
|
|
46
47
|
import { buildPm2SpawnCommand } from './cli/pm2-command.js';
|
|
47
48
|
import { callDashboard } from './cli/dashboard-endpoint.js';
|
|
48
49
|
import { npmGlobalUpdateCwd } from './core/maintenance.js';
|
|
@@ -3458,6 +3459,8 @@ botmux v${getVersion()} — IM ↔ AI 编程 CLI 桥接
|
|
|
3458
3459
|
voice 配置语音总结(高级功能,独立于 setup)— 交互式填 TTS 引擎+凭证
|
|
3459
3460
|
voice status 查看当前语音配置(凭证打码)
|
|
3460
3461
|
voice disable 关闭语音功能(移除配置)
|
|
3462
|
+
vc-agent tat-gate|poll
|
|
3463
|
+
飞书会议智能体 P0:校验 TAT 会中事件读取、轮询会议事件并触发 workflow
|
|
3461
3464
|
whiteboard status|enable|disable
|
|
3462
3465
|
本地项目白板(默认关闭;enable 只打开能力,不创建白板)
|
|
3463
3466
|
current --create / list / read / update / write --yes
|
|
@@ -3474,6 +3477,8 @@ botmux v${getVersion()} — IM ↔ AI 编程 CLI 桥接
|
|
|
3474
3477
|
send [content] 发消息到当前话题(支持 stdin / --content-file)
|
|
3475
3478
|
--images <path> 内联图片(可重复)
|
|
3476
3479
|
--files <path> 附件(可重复)
|
|
3480
|
+
--videos <path> 视频预览 MP4(可重复,需配套 --video-covers)
|
|
3481
|
+
--video-covers <path> 视频封面图片(可重复,按顺序对应 --videos)
|
|
3477
3482
|
--mention <open_id:name> @提及(可重复)
|
|
3478
3483
|
--mention-back @回本轮触发消息的发送者(open_id 自动取自会话)
|
|
3479
3484
|
--no-mention 明确声明本条不@任何人
|
|
@@ -3898,8 +3903,8 @@ async function cmdSchedule(sub, rest) {
|
|
|
3898
3903
|
console.log(`定时任务 (${filtered.length}${filter ? '/' + tasks.length : ''}):\n`);
|
|
3899
3904
|
for (const t of filtered) {
|
|
3900
3905
|
const status = t.enabled ? '✅' : '⏸️';
|
|
3901
|
-
const next = t.nextRunAt ? new Date(t.nextRunAt).toLocaleString('zh-CN', { timeZone:
|
|
3902
|
-
const last = t.lastRunAt ? new Date(t.lastRunAt).toLocaleString('zh-CN', { timeZone:
|
|
3906
|
+
const next = t.nextRunAt ? new Date(t.nextRunAt).toLocaleString('zh-CN', { timeZone: scheduleTimeZone() }) : '—';
|
|
3907
|
+
const last = t.lastRunAt ? new Date(t.lastRunAt).toLocaleString('zh-CN', { timeZone: scheduleTimeZone() }) : '—';
|
|
3903
3908
|
const display = t.parsed?.display ?? t.schedule;
|
|
3904
3909
|
const prompt = t.prompt ?? '';
|
|
3905
3910
|
const chatId = t.chatId ?? '—';
|
|
@@ -3961,7 +3966,7 @@ async function cmdSchedule(sub, rest) {
|
|
|
3961
3966
|
chatType: cur?.chatType === 'p2p' ? 'p2p' : 'topic_group',
|
|
3962
3967
|
deliver,
|
|
3963
3968
|
});
|
|
3964
|
-
const next = task.nextRunAt ? new Date(task.nextRunAt).toLocaleString('zh-CN', { timeZone:
|
|
3969
|
+
const next = task.nextRunAt ? new Date(task.nextRunAt).toLocaleString('zh-CN', { timeZone: scheduleTimeZone() }) : '—';
|
|
3965
3970
|
console.log(`✅ 已创建定时任务 [${task.id}] ${task.name}`);
|
|
3966
3971
|
console.log(` 规则: ${parsed.display}`);
|
|
3967
3972
|
console.log(` 下次执行: ${next}`);
|
|
@@ -4275,17 +4280,28 @@ async function relaySend(rest, relayDir) {
|
|
|
4275
4280
|
const contentBase = `${id}.content`;
|
|
4276
4281
|
const cfile = join(relayDir, contentBase);
|
|
4277
4282
|
writeFileSync(cfile, content);
|
|
4278
|
-
// Copy
|
|
4279
|
-
const
|
|
4280
|
-
for (const p of argValues(rest, '--image', '--images', '--file', '--files')) {
|
|
4283
|
+
// Copy attachments into the outbox; carry only basenames.
|
|
4284
|
+
const copyOutboxAttachment = (p, out) => {
|
|
4281
4285
|
if (!p || !existsSync(p))
|
|
4282
|
-
|
|
4286
|
+
return;
|
|
4283
4287
|
const base = `${id}-${randomBytes(4).toString('hex')}-${basename(p)}`;
|
|
4284
4288
|
try {
|
|
4285
4289
|
writeFileSync(join(relayDir, base), readFileSync(p));
|
|
4286
|
-
|
|
4290
|
+
out.push(base);
|
|
4287
4291
|
}
|
|
4288
4292
|
catch { /* skip unreadable */ }
|
|
4293
|
+
};
|
|
4294
|
+
const attachments = [];
|
|
4295
|
+
for (const p of argValues(rest, '--image', '--images', '--file', '--files')) {
|
|
4296
|
+
copyOutboxAttachment(p, attachments);
|
|
4297
|
+
}
|
|
4298
|
+
const videos = [];
|
|
4299
|
+
for (const p of argValues(rest, '--video', '--videos')) {
|
|
4300
|
+
copyOutboxAttachment(p, videos);
|
|
4301
|
+
}
|
|
4302
|
+
const videoCovers = [];
|
|
4303
|
+
for (const p of argValues(rest, '--video-cover', '--video-covers')) {
|
|
4304
|
+
copyOutboxAttachment(p, videoCovers);
|
|
4289
4305
|
}
|
|
4290
4306
|
// Forward only presentation flags (must match the watcher's allowlist); path,
|
|
4291
4307
|
// routing (--chat-id/--into/--top-level) and --session-id flags are dropped —
|
|
@@ -4303,7 +4319,7 @@ async function relaySend(rest, relayDir) {
|
|
|
4303
4319
|
}
|
|
4304
4320
|
// 原子写:req.json 是 host watcher 的触发文件,rename 让它「完整出现」,
|
|
4305
4321
|
// watcher 永远不会读到半截 JSON(tmp 后缀不匹配 .req.json 过滤)。
|
|
4306
|
-
atomicWriteFileSync(join(relayDir, `${id}.req.json`), JSON.stringify({ contentFile: contentBase, attachments, flags }));
|
|
4322
|
+
atomicWriteFileSync(join(relayDir, `${id}.req.json`), JSON.stringify({ contentFile: contentBase, attachments, videos, videoCovers, flags }));
|
|
4307
4323
|
const resPath = join(relayDir, `${id}.res.json`);
|
|
4308
4324
|
const deadlineMs = Date.now() + 120_000;
|
|
4309
4325
|
while (Date.now() < deadlineMs) {
|
|
@@ -4388,15 +4404,29 @@ async function cmdSend(rest) {
|
|
|
4388
4404
|
// from its own worker-written cred file instead (see registerSelfFromCredFile).
|
|
4389
4405
|
await registerSelfFromCredFile();
|
|
4390
4406
|
const sessionIdArg = argValue(rest, '--session-id');
|
|
4407
|
+
for (const flag of ['--video', '--videos', '--video-cover', '--video-covers']) {
|
|
4408
|
+
if (flagPresentButValueMissing(rest, flag, true)) {
|
|
4409
|
+
console.error(`botmux send: ${flag} 需要路径参数`);
|
|
4410
|
+
process.exit(2);
|
|
4411
|
+
}
|
|
4412
|
+
}
|
|
4391
4413
|
const images = argValues(rest, '--image', '--images');
|
|
4392
4414
|
const files = argValues(rest, '--file', '--files');
|
|
4415
|
+
const videos = argValues(rest, '--video', '--videos');
|
|
4416
|
+
const videoCovers = argValues(rest, '--video-cover', '--video-covers');
|
|
4417
|
+
const videoValidation = validateVideoAttachments(videos, videoCovers);
|
|
4418
|
+
if (!videoValidation.ok) {
|
|
4419
|
+
console.error(`botmux send: ${videoValidation.error}`);
|
|
4420
|
+
process.exit(2);
|
|
4421
|
+
}
|
|
4422
|
+
const videoAttachments = videoValidation.videos;
|
|
4393
4423
|
// stdin can't be both the message body (which `botmux send` reads from it) and
|
|
4394
|
-
// a `--file`/`--image` attachment — the second read sees EOF and the upload
|
|
4424
|
+
// a `--file`/`--image`/`--video` attachment — the second read sees EOF and the upload
|
|
4395
4425
|
// fails *after* the message is already sent, leaving the caller to resend.
|
|
4396
4426
|
// Reject up front so exit≠0 reliably means "nothing was sent".
|
|
4397
|
-
const stdinAlias = findStdinAliasAttachment([...images, ...files]);
|
|
4427
|
+
const stdinAlias = findStdinAliasAttachment([...images, ...files, ...videos, ...videoCovers]);
|
|
4398
4428
|
if (stdinAlias) {
|
|
4399
|
-
console.error(`不能把 stdin(${stdinAlias})当作 --file/--image 附件:botmux send 已从 stdin 读取消息正文,\n` +
|
|
4429
|
+
console.error(`不能把 stdin(${stdinAlias})当作 --file/--image/--video 附件:botmux send 已从 stdin 读取消息正文,\n` +
|
|
4400
4430
|
`同一个 stdin 没法既当正文又当附件(第二次读到的是 EOF)。\n` +
|
|
4401
4431
|
`要发送管道内容,先落到临时文件: 数据来源 > /tmp/x && botmux send --files /tmp/x …`);
|
|
4402
4432
|
process.exit(1);
|
|
@@ -4467,8 +4497,8 @@ async function cmdSend(rest) {
|
|
|
4467
4497
|
}
|
|
4468
4498
|
if (!contentFile)
|
|
4469
4499
|
rejectLikelyWindowsStdinMojibake(content);
|
|
4470
|
-
if (!content.trim() && images.length === 0 && files.length === 0) {
|
|
4471
|
-
console.error('没有内容可发送。用法:\n echo "消息" | botmux send\n botmux send "消息"\n botmux send --content-file /tmp/msg.md --images /tmp/chart.png');
|
|
4500
|
+
if (!content.trim() && images.length === 0 && files.length === 0 && videoAttachments.length === 0) {
|
|
4501
|
+
console.error('没有内容可发送。用法:\n echo "消息" | botmux send\n botmux send "消息"\n botmux send --content-file /tmp/msg.md --images /tmp/chart.png\n botmux send --videos /tmp/replay.mp4 --video-covers /tmp/cover.png --no-mention "视频预览"');
|
|
4472
4502
|
process.exit(1);
|
|
4473
4503
|
}
|
|
4474
4504
|
// --attention guard: only valid replying into the current session with a text
|
|
@@ -4637,12 +4667,18 @@ async function cmdSend(rest) {
|
|
|
4637
4667
|
mentions.push({ open_id: s.quoteTargetSenderOpenId, name: '' });
|
|
4638
4668
|
}
|
|
4639
4669
|
// Validate file paths
|
|
4640
|
-
for (const p of [...images, ...files]) {
|
|
4670
|
+
for (const p of [...images, ...files, ...videos, ...videoCovers]) {
|
|
4641
4671
|
if (!existsSync(p)) {
|
|
4642
4672
|
console.error(`文件不存在: ${p}`);
|
|
4643
4673
|
process.exit(1);
|
|
4644
4674
|
}
|
|
4645
4675
|
}
|
|
4676
|
+
for (const p of [...videos, ...videoCovers]) {
|
|
4677
|
+
if (!statSync(p).isFile()) {
|
|
4678
|
+
console.error(`不是普通文件: ${p}`);
|
|
4679
|
+
process.exit(1);
|
|
4680
|
+
}
|
|
4681
|
+
}
|
|
4646
4682
|
// Register bots so Lark client works
|
|
4647
4683
|
const { registerBot, loadBotConfigs, findOncallChatForAnyBot } = await import('./bot-registry.js');
|
|
4648
4684
|
try {
|
|
@@ -4895,7 +4931,36 @@ async function cmdSend(rest) {
|
|
|
4895
4931
|
// we committed to sending — that's the boundary the gate cares about.
|
|
4896
4932
|
const sentAtMs = Date.now();
|
|
4897
4933
|
let messageId;
|
|
4898
|
-
|
|
4934
|
+
let failedAttachments = [];
|
|
4935
|
+
let failedVideoAttachments = [];
|
|
4936
|
+
// Pure-video fast path: send the preview as a standalone media message.
|
|
4937
|
+
// A send that also carries mentions is deliberately excluded (media messages
|
|
4938
|
+
// can't embed `<at>`), so it falls through to the card branch which renders
|
|
4939
|
+
// the @ on the footer and sends the video as a follow-up attachment — same
|
|
4940
|
+
// shape as an attachment-only `--files … --mention …` send, whose card body
|
|
4941
|
+
// is likewise empty. See shouldSendAsPureVideo.
|
|
4942
|
+
const pureVideoSend = shouldSendAsPureVideo({
|
|
4943
|
+
hasBodyText: !!text.trim(),
|
|
4944
|
+
imageCount: imageKeys.length,
|
|
4945
|
+
fileCount: files.length,
|
|
4946
|
+
videoCount: videoAttachments.length,
|
|
4947
|
+
mentionCount: mentions.length,
|
|
4948
|
+
});
|
|
4949
|
+
if (pureVideoSend) {
|
|
4950
|
+
// No card/text primary here, so the FIRST media message must carry the
|
|
4951
|
+
// quote chain itself (dispatchPrimary applies the chat-scope quoteTargetId
|
|
4952
|
+
// and updates primaryQuotedId). Otherwise a bare `--videos … --no-mention`
|
|
4953
|
+
// reply in a 普通群 lands as a standalone message that doesn't quote the
|
|
4954
|
+
// trigger — unlike file-only/image-only sends whose primary card quotes.
|
|
4955
|
+
const videoResult = await sendVideoAttachments({ uploadFile, uploadImage, dispatch, primaryDispatch: dispatchPrimary }, appId, videoAttachments);
|
|
4956
|
+
failedVideoAttachments = videoResult.failed;
|
|
4957
|
+
if (videoResult.sent.length === 0) {
|
|
4958
|
+
const first = failedVideoAttachments[0]?.error ?? 'unknown error';
|
|
4959
|
+
throw new Error(`视频发送失败: ${first}`);
|
|
4960
|
+
}
|
|
4961
|
+
messageId = videoResult.sent[0];
|
|
4962
|
+
}
|
|
4963
|
+
else {
|
|
4899
4964
|
// 回复一律卡片(纯文本 post 路径已删)。
|
|
4900
4965
|
// Inline `@Name` → `<at id=…>` at the exact spot it's written (CJK-name
|
|
4901
4966
|
// aware, see applyInlineMentions); any --mention not inlined here is
|
|
@@ -4999,15 +5064,24 @@ async function cmdSend(rest) {
|
|
|
4999
5064
|
// closed a pending response card for this turn.
|
|
5000
5065
|
if (shouldRecordBridgeMarker)
|
|
5001
5066
|
recordBridgeSendMarker(sentAtMs, messageId, text);
|
|
5002
|
-
// Send
|
|
5003
|
-
//
|
|
5004
|
-
//
|
|
5005
|
-
//
|
|
5006
|
-
// the
|
|
5007
|
-
|
|
5067
|
+
// Send attachments as separate messages — best-effort. The primary message
|
|
5068
|
+
// is already delivered above; a failing attachment must not throw out to the
|
|
5069
|
+
// catch below (which would report total failure / exit 1 for an already-sent
|
|
5070
|
+
// message and make the caller resend). Warn instead, and list failures in
|
|
5071
|
+
// the success JSON. Pure-video sends have no text/card primary, so the media
|
|
5072
|
+
// message above is the primary and failures before any media is sent still
|
|
5073
|
+
// surface as command failure.
|
|
5074
|
+
if (!pureVideoSend) {
|
|
5075
|
+
({ failed: failedAttachments } = await sendFileAttachments({ uploadFile, dispatch }, appId, files));
|
|
5076
|
+
const videoResult = await sendVideoAttachments({ uploadFile, uploadImage, dispatch }, appId, videoAttachments);
|
|
5077
|
+
failedVideoAttachments = videoResult.failed;
|
|
5078
|
+
}
|
|
5008
5079
|
for (const f of failedAttachments) {
|
|
5009
5080
|
console.error(`⚠️ 附件未发送(主消息已送达 ${messageId},请勿重发): ${f.path} — ${f.error}`);
|
|
5010
5081
|
}
|
|
5082
|
+
for (const f of failedVideoAttachments) {
|
|
5083
|
+
console.error(`⚠️ 视频未发送(主消息已送达 ${messageId},请勿重发): ${f.path} / cover ${f.coverPath} — ${f.error}`);
|
|
5084
|
+
}
|
|
5011
5085
|
// Bot-to-bot 转发依赖飞书"获取群组中其他机器人和用户@当前机器人的消息"权限:
|
|
5012
5086
|
// 目标 bot 的 daemon 现在能从 WSClient 原生收到 sender_type='app' 的事件,
|
|
5013
5087
|
// 不需要 botmux 自己再写本地 signal 文件做转发。outgoing 消息里 @BotName /
|
|
@@ -5055,6 +5129,9 @@ async function cmdSend(rest) {
|
|
|
5055
5129
|
...(failedAttachments.length > 0
|
|
5056
5130
|
? { failedAttachments: failedAttachments.map(f => f.path) }
|
|
5057
5131
|
: {}),
|
|
5132
|
+
...(failedVideoAttachments.length > 0
|
|
5133
|
+
? { failedVideoAttachments: failedVideoAttachments.map(f => f.path) }
|
|
5134
|
+
: {}),
|
|
5058
5135
|
}));
|
|
5059
5136
|
}
|
|
5060
5137
|
catch (err) {
|
|
@@ -5264,7 +5341,7 @@ async function cmdDispatch(rest) {
|
|
|
5264
5341
|
*
|
|
5265
5342
|
* In 多话题协作模式 the sub-bot lives in its own sub-topic, where the orchestrator
|
|
5266
5343
|
* has no session; @-ing the orchestrator there would spawn a fresh, context-less
|
|
5267
|
-
* one (
|
|
5344
|
+
* one (the reported #1 bug). Instead this routes the report INTO the orchestrator's own
|
|
5268
5345
|
* thread (recorded by `botmux dispatch` in orchestrate-dispatch.json) and @-s the
|
|
5269
5346
|
* orchestrator there, so its existing, context-rich session is the one that wakes.
|
|
5270
5347
|
*
|
|
@@ -6558,6 +6635,11 @@ switch (command) {
|
|
|
6558
6635
|
case 'voice':
|
|
6559
6636
|
await cmdVoiceSetup(process.argv.slice(3));
|
|
6560
6637
|
break;
|
|
6638
|
+
case 'vc-agent': {
|
|
6639
|
+
const { cmdVcAgent } = await import('./cli/vc-agent.js');
|
|
6640
|
+
await cmdVcAgent(process.argv[3] ?? '', process.argv.slice(4));
|
|
6641
|
+
break;
|
|
6642
|
+
}
|
|
6561
6643
|
case 'whiteboard':
|
|
6562
6644
|
case 'wb':
|
|
6563
6645
|
await cmdWhiteboard(process.argv[3] ?? 'status', process.argv.slice(4));
|