botmux 2.9.1 → 2.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +140 -76
- package/README.md +134 -75
- package/dist/adapters/backend/pty-backend.d.ts +6 -0
- package/dist/adapters/backend/pty-backend.d.ts.map +1 -1
- package/dist/adapters/backend/pty-backend.js +10 -0
- package/dist/adapters/backend/pty-backend.js.map +1 -1
- package/dist/adapters/backend/session-backend-selector.d.ts +11 -0
- package/dist/adapters/backend/session-backend-selector.d.ts.map +1 -0
- package/dist/adapters/backend/session-backend-selector.js +26 -0
- package/dist/adapters/backend/session-backend-selector.js.map +1 -0
- package/dist/adapters/backend/tmux-backend.d.ts +80 -3
- package/dist/adapters/backend/tmux-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-backend.js +301 -49
- package/dist/adapters/backend/tmux-backend.js.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.d.ts +100 -0
- package/dist/adapters/backend/tmux-pipe-backend.d.ts.map +1 -0
- package/dist/adapters/backend/tmux-pipe-backend.js +473 -0
- package/dist/adapters/backend/tmux-pipe-backend.js.map +1 -0
- package/dist/adapters/cli/aiden.d.ts.map +1 -1
- package/dist/adapters/cli/aiden.js +5 -0
- package/dist/adapters/cli/aiden.js.map +1 -1
- package/dist/adapters/cli/claude-code.d.ts +40 -1
- package/dist/adapters/cli/claude-code.d.ts.map +1 -1
- package/dist/adapters/cli/claude-code.js +470 -49
- 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 +191 -9
- 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 +94 -17
- package/dist/adapters/cli/codex.js.map +1 -1
- package/dist/adapters/cli/shared-hints.d.ts +2 -2
- package/dist/adapters/cli/shared-hints.d.ts.map +1 -1
- package/dist/adapters/cli/shared-hints.js +7 -5
- package/dist/adapters/cli/shared-hints.js.map +1 -1
- package/dist/adapters/cli/types.d.ts +38 -1
- package/dist/adapters/cli/types.d.ts.map +1 -1
- package/dist/autostart.d.ts +14 -0
- package/dist/autostart.d.ts.map +1 -0
- package/dist/autostart.js +357 -0
- package/dist/autostart.js.map +1 -0
- package/dist/bot-registry.d.ts +29 -3
- package/dist/bot-registry.d.ts.map +1 -1
- package/dist/bot-registry.js +91 -12
- package/dist/bot-registry.js.map +1 -1
- package/dist/cli/arg-utils.d.ts +11 -0
- package/dist/cli/arg-utils.d.ts.map +1 -0
- package/dist/cli/arg-utils.js +25 -0
- package/dist/cli/arg-utils.js.map +1 -0
- package/dist/cli/create-group-resolver.d.ts +32 -0
- package/dist/cli/create-group-resolver.d.ts.map +1 -0
- package/dist/cli/create-group-resolver.js +70 -0
- package/dist/cli/create-group-resolver.js.map +1 -0
- package/dist/cli/quoted-render.d.ts +30 -0
- package/dist/cli/quoted-render.d.ts.map +1 -0
- package/dist/cli/quoted-render.js +29 -0
- package/dist/cli/quoted-render.js.map +1 -0
- package/dist/cli.js +916 -272
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +6 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +18 -8
- package/dist/config.js.map +1 -1
- package/dist/core/command-handler.d.ts +43 -0
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +167 -64
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/dashboard-events.d.ts +57 -0
- package/dist/core/dashboard-events.d.ts.map +1 -0
- package/dist/core/dashboard-events.js +23 -0
- package/dist/core/dashboard-events.js.map +1 -0
- package/dist/core/dashboard-ipc-server.d.ts +43 -0
- package/dist/core/dashboard-ipc-server.d.ts.map +1 -0
- package/dist/core/dashboard-ipc-server.js +481 -0
- package/dist/core/dashboard-ipc-server.js.map +1 -0
- package/dist/core/dashboard-locate.d.ts +20 -0
- package/dist/core/dashboard-locate.d.ts.map +1 -0
- package/dist/core/dashboard-locate.js +26 -0
- package/dist/core/dashboard-locate.js.map +1 -0
- package/dist/core/dashboard-rows.d.ts +31 -0
- package/dist/core/dashboard-rows.d.ts.map +1 -0
- package/dist/core/dashboard-rows.js +65 -0
- package/dist/core/dashboard-rows.js.map +1 -0
- package/dist/core/inherit-peer.d.ts +14 -0
- package/dist/core/inherit-peer.d.ts.map +1 -0
- package/dist/core/inherit-peer.js +32 -0
- package/dist/core/inherit-peer.js.map +1 -0
- package/dist/core/scheduler.d.ts +24 -0
- package/dist/core/scheduler.d.ts.map +1 -1
- package/dist/core/scheduler.js +93 -2
- package/dist/core/scheduler.js.map +1 -1
- package/dist/core/session-activity.d.ts +3 -0
- package/dist/core/session-activity.d.ts.map +1 -0
- package/dist/core/session-activity.js +20 -0
- package/dist/core/session-activity.js.map +1 -0
- package/dist/core/session-discovery.d.ts +39 -0
- package/dist/core/session-discovery.d.ts.map +1 -1
- package/dist/core/session-discovery.js +114 -21
- package/dist/core/session-discovery.js.map +1 -1
- package/dist/core/session-manager.d.ts +72 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +396 -106
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/types.d.ts +27 -2
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +14 -3
- package/dist/core/types.js.map +1 -1
- package/dist/core/worker-pool.d.ts +72 -3
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +459 -38
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +601 -309
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/aggregator.d.ts +41 -0
- package/dist/dashboard/aggregator.d.ts.map +1 -0
- package/dist/dashboard/aggregator.js +125 -0
- package/dist/dashboard/aggregator.js.map +1 -0
- package/dist/dashboard/auth.d.ts +23 -0
- package/dist/dashboard/auth.d.ts.map +1 -0
- package/dist/dashboard/auth.js +66 -0
- package/dist/dashboard/auth.js.map +1 -0
- package/dist/dashboard/operator-selector.d.ts +20 -0
- package/dist/dashboard/operator-selector.d.ts.map +1 -0
- package/dist/dashboard/operator-selector.js +39 -0
- package/dist/dashboard/operator-selector.js.map +1 -0
- package/dist/dashboard/registry.d.ts +35 -0
- package/dist/dashboard/registry.d.ts.map +1 -0
- package/dist/dashboard/registry.js +74 -0
- package/dist/dashboard/registry.js.map +1 -0
- package/dist/dashboard/web/app.d.ts +2 -0
- package/dist/dashboard/web/app.d.ts.map +1 -0
- package/dist/dashboard/web/app.js +45 -0
- package/dist/dashboard/web/app.js.map +1 -0
- package/dist/dashboard/web/bot-defaults.d.ts +2 -0
- package/dist/dashboard/web/bot-defaults.d.ts.map +1 -0
- package/dist/dashboard/web/bot-defaults.js +201 -0
- package/dist/dashboard/web/bot-defaults.js.map +1 -0
- package/dist/dashboard/web/groups.d.ts +16 -0
- package/dist/dashboard/web/groups.d.ts.map +1 -0
- package/dist/dashboard/web/groups.js +584 -0
- package/dist/dashboard/web/groups.js.map +1 -0
- package/dist/dashboard/web/schedules.d.ts +2 -0
- package/dist/dashboard/web/schedules.d.ts.map +1 -0
- package/dist/dashboard/web/schedules.js +105 -0
- package/dist/dashboard/web/schedules.js.map +1 -0
- package/dist/dashboard/web/sessions.d.ts +2 -0
- package/dist/dashboard/web/sessions.d.ts.map +1 -0
- package/dist/dashboard/web/sessions.js +374 -0
- package/dist/dashboard/web/sessions.js.map +1 -0
- package/dist/dashboard/web/store.d.ts +23 -0
- package/dist/dashboard/web/store.d.ts.map +1 -0
- package/dist/dashboard/web/store.js +82 -0
- package/dist/dashboard/web/store.js.map +1 -0
- package/dist/dashboard-web/app.js +263 -0
- package/dist/dashboard-web/index.html +23 -0
- package/dist/dashboard-web/style.css +93 -0
- package/dist/dashboard.d.ts +2 -0
- package/dist/dashboard.d.ts.map +1 -0
- package/dist/dashboard.js +639 -0
- package/dist/dashboard.js.map +1 -0
- package/dist/im/lark/card-builder.d.ts +18 -1
- package/dist/im/lark/card-builder.d.ts.map +1 -1
- package/dist/im/lark/card-builder.js +70 -9
- 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 +123 -109
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/im/lark/client.d.ts +35 -0
- package/dist/im/lark/client.d.ts.map +1 -1
- package/dist/im/lark/client.js +114 -11
- package/dist/im/lark/client.js.map +1 -1
- package/dist/im/lark/event-dispatcher.d.ts +88 -6
- package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
- package/dist/im/lark/event-dispatcher.js +398 -62
- package/dist/im/lark/event-dispatcher.js.map +1 -1
- package/dist/im/lark/forwarded-renderer.d.ts +23 -0
- package/dist/im/lark/forwarded-renderer.d.ts.map +1 -0
- package/dist/im/lark/forwarded-renderer.js +105 -0
- package/dist/im/lark/forwarded-renderer.js.map +1 -0
- package/dist/im/lark/md-card.d.ts +73 -0
- package/dist/im/lark/md-card.d.ts.map +1 -0
- package/dist/im/lark/md-card.js +332 -0
- package/dist/im/lark/md-card.js.map +1 -0
- package/dist/im/lark/merge-forward.d.ts +32 -0
- package/dist/im/lark/merge-forward.d.ts.map +1 -0
- package/dist/im/lark/merge-forward.js +110 -0
- package/dist/im/lark/merge-forward.js.map +1 -0
- package/dist/im/lark/message-parser.d.ts +9 -3
- package/dist/im/lark/message-parser.d.ts.map +1 -1
- package/dist/im/lark/message-parser.js +48 -13
- package/dist/im/lark/message-parser.js.map +1 -1
- package/dist/im/lark/quote-hint.d.ts +18 -0
- package/dist/im/lark/quote-hint.d.ts.map +1 -0
- package/dist/im/lark/quote-hint.js +23 -0
- package/dist/im/lark/quote-hint.js.map +1 -0
- package/dist/services/bridge-fallback-gate.d.ts +42 -0
- package/dist/services/bridge-fallback-gate.d.ts.map +1 -0
- package/dist/services/bridge-fallback-gate.js +12 -0
- package/dist/services/bridge-fallback-gate.js.map +1 -0
- package/dist/services/bridge-rotation-policy.d.ts +139 -0
- package/dist/services/bridge-rotation-policy.d.ts.map +1 -0
- package/dist/services/bridge-rotation-policy.js +125 -0
- package/dist/services/bridge-rotation-policy.js.map +1 -0
- package/dist/services/bridge-turn-queue.d.ts +154 -0
- package/dist/services/bridge-turn-queue.d.ts.map +1 -0
- package/dist/services/bridge-turn-queue.js +316 -0
- package/dist/services/bridge-turn-queue.js.map +1 -0
- package/dist/services/chat-first-seen-store.d.ts +27 -0
- package/dist/services/chat-first-seen-store.d.ts.map +1 -0
- package/dist/services/chat-first-seen-store.js +114 -0
- package/dist/services/chat-first-seen-store.js.map +1 -0
- package/dist/services/claude-transcript.d.ts +268 -0
- package/dist/services/claude-transcript.d.ts.map +1 -0
- package/dist/services/claude-transcript.js +798 -0
- package/dist/services/claude-transcript.js.map +1 -0
- package/dist/services/coco-transcript.d.ts +35 -0
- package/dist/services/coco-transcript.d.ts.map +1 -0
- package/dist/services/coco-transcript.js +192 -0
- package/dist/services/coco-transcript.js.map +1 -0
- package/dist/services/codex-bridge-queue.d.ts +56 -0
- package/dist/services/codex-bridge-queue.d.ts.map +1 -0
- package/dist/services/codex-bridge-queue.js +150 -0
- package/dist/services/codex-bridge-queue.js.map +1 -0
- package/dist/services/codex-transcript.d.ts +84 -0
- package/dist/services/codex-transcript.d.ts.map +1 -0
- package/dist/services/codex-transcript.js +298 -0
- package/dist/services/codex-transcript.js.map +1 -0
- package/dist/services/group-creator.d.ts +23 -0
- package/dist/services/group-creator.d.ts.map +1 -0
- package/dist/services/group-creator.js +75 -0
- package/dist/services/group-creator.js.map +1 -0
- package/dist/services/groups-store.d.ts +98 -0
- package/dist/services/groups-store.d.ts.map +1 -0
- package/dist/services/groups-store.js +213 -0
- package/dist/services/groups-store.js.map +1 -0
- package/dist/services/oncall-store.d.ts +80 -8
- package/dist/services/oncall-store.d.ts.map +1 -1
- package/dist/services/oncall-store.js +265 -55
- package/dist/services/oncall-store.js.map +1 -1
- package/dist/services/project-scanner.d.ts +1 -2
- package/dist/services/project-scanner.d.ts.map +1 -1
- package/dist/services/project-scanner.js +118 -68
- package/dist/services/project-scanner.js.map +1 -1
- package/dist/services/schedule-store.d.ts +5 -0
- package/dist/services/schedule-store.d.ts.map +1 -1
- package/dist/services/schedule-store.js +77 -1
- package/dist/services/schedule-store.js.map +1 -1
- package/dist/services/session-store.d.ts +22 -0
- package/dist/services/session-store.d.ts.map +1 -1
- package/dist/services/session-store.js +62 -4
- package/dist/services/session-store.js.map +1 -1
- package/dist/setup/bots-store.d.ts +3 -0
- package/dist/setup/bots-store.d.ts.map +1 -0
- package/dist/setup/bots-store.js +24 -0
- package/dist/setup/bots-store.js.map +1 -0
- package/dist/setup/detect-platform.d.ts +14 -0
- package/dist/setup/detect-platform.d.ts.map +1 -0
- package/dist/setup/detect-platform.js +139 -0
- package/dist/setup/detect-platform.js.map +1 -0
- package/dist/setup/ensure-fonts.d.ts +13 -0
- package/dist/setup/ensure-fonts.d.ts.map +1 -0
- package/dist/setup/ensure-fonts.js +225 -0
- package/dist/setup/ensure-fonts.js.map +1 -0
- package/dist/setup/ensure-tmux.d.ts +60 -0
- package/dist/setup/ensure-tmux.d.ts.map +1 -0
- package/dist/setup/ensure-tmux.js +236 -0
- package/dist/setup/ensure-tmux.js.map +1 -0
- package/dist/setup/index.d.ts +9 -0
- package/dist/setup/index.d.ts.map +1 -0
- package/dist/setup/index.js +46 -0
- package/dist/setup/index.js.map +1 -0
- package/dist/setup/lark-scopes.json +301 -0
- package/dist/setup/register-app.d.ts +52 -0
- package/dist/setup/register-app.d.ts.map +1 -0
- package/dist/setup/register-app.js +91 -0
- package/dist/setup/register-app.js.map +1 -0
- package/dist/setup/verify-permissions.d.ts +115 -0
- package/dist/setup/verify-permissions.d.ts.map +1 -0
- package/dist/setup/verify-permissions.js +207 -0
- package/dist/setup/verify-permissions.js.map +1 -0
- package/dist/skills/definitions.d.ts +4 -0
- package/dist/skills/definitions.d.ts.map +1 -1
- package/dist/skills/definitions.js +133 -19
- package/dist/skills/definitions.js.map +1 -1
- package/dist/skills/installer.d.ts +3 -1
- package/dist/skills/installer.d.ts.map +1 -1
- package/dist/skills/installer.js +18 -3
- package/dist/skills/installer.js.map +1 -1
- package/dist/types.d.ts +44 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/bot-routing.d.ts +6 -0
- package/dist/utils/bot-routing.d.ts.map +1 -0
- package/dist/utils/bot-routing.js +50 -0
- package/dist/utils/bot-routing.js.map +1 -0
- package/dist/utils/file-lock.d.ts +2 -0
- package/dist/utils/file-lock.d.ts.map +1 -0
- package/dist/utils/file-lock.js +114 -0
- package/dist/utils/file-lock.js.map +1 -0
- package/dist/utils/font-installer.js +1 -1
- package/dist/utils/font-installer.js.map +1 -1
- package/dist/utils/idle-detector.d.ts +6 -0
- package/dist/utils/idle-detector.d.ts.map +1 -1
- package/dist/utils/idle-detector.js +25 -4
- package/dist/utils/idle-detector.js.map +1 -1
- package/dist/utils/logger.d.ts +10 -0
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +60 -8
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/render-dimensions.d.ts +48 -0
- package/dist/utils/render-dimensions.d.ts.map +1 -0
- package/dist/utils/render-dimensions.js +55 -0
- package/dist/utils/render-dimensions.js.map +1 -0
- package/dist/utils/screen-analyzer.d.ts.map +1 -1
- package/dist/utils/screen-analyzer.js +24 -0
- package/dist/utils/screen-analyzer.js.map +1 -1
- package/dist/utils/screenshot-renderer.d.ts.map +1 -1
- package/dist/utils/screenshot-renderer.js +67 -23
- package/dist/utils/screenshot-renderer.js.map +1 -1
- package/dist/utils/terminal-renderer.d.ts +16 -0
- package/dist/utils/terminal-renderer.d.ts.map +1 -1
- package/dist/utils/terminal-renderer.js +40 -23
- package/dist/utils/terminal-renderer.js.map +1 -1
- package/dist/utils/transient-snapshot.d.ts +28 -0
- package/dist/utils/transient-snapshot.d.ts.map +1 -0
- package/dist/utils/transient-snapshot.js +96 -0
- package/dist/utils/transient-snapshot.js.map +1 -0
- package/dist/worker.js +2220 -83
- package/dist/worker.js.map +1 -1
- package/package.json +12 -5
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reader for Codex's per-session rollout JSONL.
|
|
3
|
+
*
|
|
4
|
+
* Codex stores each session's full transcript at
|
|
5
|
+
* ~/.codex/sessions/<YYYY>/<MM>/<DD>/rollout-<ts>-<cliSessionId>.jsonl
|
|
6
|
+
* and creates the file lazily on the first user submit. Inside, the bridge
|
|
7
|
+
* fallback only cares about two `response_item.payload.type === 'message'`
|
|
8
|
+
* shapes:
|
|
9
|
+
*
|
|
10
|
+
* - role=user → the user's prompt text (input_text content)
|
|
11
|
+
* - role=assistant +
|
|
12
|
+
* phase=final_answer → the model's final reply (output_text content)
|
|
13
|
+
*
|
|
14
|
+
* Why these and not `event_msg`:
|
|
15
|
+
* - `response_item` is the canonical transcript record; `event_msg` is a
|
|
16
|
+
* UI-event stream that can carry the same final text via two channels
|
|
17
|
+
* (`agent_message phase=final_answer` AND `task_complete.last_agent_message`).
|
|
18
|
+
* Picking `response_item` keeps the reader to a single source of truth
|
|
19
|
+
* and avoids any chance of double-emit if both paths are present.
|
|
20
|
+
* - Skipping role=developer (system instructions), phase=commentary
|
|
21
|
+
* (mid-turn status), reasoning, and function_call* keeps the bridge
|
|
22
|
+
* focused on what the user actually said and what the model finally
|
|
23
|
+
* answered — same scope as the Claude bridge.
|
|
24
|
+
*
|
|
25
|
+
* Pure I/O. Attribution belongs in CodexBridgeQueue.
|
|
26
|
+
*/
|
|
27
|
+
import { existsSync, statSync, openSync, readSync, closeSync, readdirSync, readlinkSync } from 'node:fs';
|
|
28
|
+
import { execSync } from 'node:child_process';
|
|
29
|
+
import { homedir, platform } from 'node:os';
|
|
30
|
+
import { join } from 'node:path';
|
|
31
|
+
const CODEX_SESSIONS_ROOT = join(homedir(), '.codex', 'sessions');
|
|
32
|
+
const IS_LINUX = platform() === 'linux';
|
|
33
|
+
/** Extract the cliSessionId encoded in a rollout filename. Codex's session
|
|
34
|
+
* id is UUID-shaped (8-4-4-4-12 hex), which lets us anchor the regex on
|
|
35
|
+
* the UUID alone — the `<ts>` segment between "rollout-" and the sid
|
|
36
|
+
* contains its own dashes that would otherwise let a greedy match swallow
|
|
37
|
+
* parts of the sid. Returns undefined for paths that don't match. */
|
|
38
|
+
export function codexSessionIdFromRolloutPath(path) {
|
|
39
|
+
const m = /rollout-.*-([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i.exec(path);
|
|
40
|
+
return m ? m[1] : undefined;
|
|
41
|
+
}
|
|
42
|
+
/** Find the rollout file an externally-running Codex process has open. The
|
|
43
|
+
* Codex process keeps fd open on its current rollout for the entire
|
|
44
|
+
* lifetime of the session, so this is the authoritative way to bind a
|
|
45
|
+
* Codex pid to its sessionId — far more reliable than scanning
|
|
46
|
+
* `~/.codex/sessions` by mtime (which would race with sibling Codex panes
|
|
47
|
+
* in the same project).
|
|
48
|
+
*
|
|
49
|
+
* Linux: `/proc/<pid>/fd/*` fast path.
|
|
50
|
+
* macOS / BSD: `lsof -p <pid> -Fn` 兜底(同 session-discovery 里的 readCwd)。
|
|
51
|
+
* 两种平台都用 `codexSessionIdFromRolloutPath` 提取 sid。 */
|
|
52
|
+
export function findCodexRolloutByPid(pid) {
|
|
53
|
+
if (!Number.isInteger(pid) || pid <= 0)
|
|
54
|
+
return undefined;
|
|
55
|
+
if (IS_LINUX) {
|
|
56
|
+
const fdDir = `/proc/${pid}/fd`;
|
|
57
|
+
if (existsSync(fdDir)) {
|
|
58
|
+
let entries;
|
|
59
|
+
try {
|
|
60
|
+
entries = readdirSync(fdDir);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
for (const fd of entries) {
|
|
66
|
+
let target;
|
|
67
|
+
try {
|
|
68
|
+
target = readlinkSync(join(fdDir, fd));
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const hit = matchCodexRolloutPath(target);
|
|
74
|
+
if (hit)
|
|
75
|
+
return hit;
|
|
76
|
+
}
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
// /proc 不可读时落到下面的 lsof 兜底(极少见,但兜一下)
|
|
80
|
+
}
|
|
81
|
+
// BSD ps 的 lsof:每个 fd 输出一行 `f<n>` 加一行 `n<path>`,socket / pipe
|
|
82
|
+
// 之类的内部条目以 `n->0x...` 或 `n<garbage>` 开头,所以只接受 `n/` 开头。
|
|
83
|
+
let out;
|
|
84
|
+
try {
|
|
85
|
+
out = execSync(`lsof -p ${pid} -Fn`, {
|
|
86
|
+
encoding: 'utf-8',
|
|
87
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
for (const line of out.split('\n')) {
|
|
94
|
+
if (!line.startsWith('n/'))
|
|
95
|
+
continue;
|
|
96
|
+
const target = line.slice(1);
|
|
97
|
+
const hit = matchCodexRolloutPath(target);
|
|
98
|
+
if (hit)
|
|
99
|
+
return hit;
|
|
100
|
+
}
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
function matchCodexRolloutPath(target) {
|
|
104
|
+
if (!target.endsWith('.jsonl'))
|
|
105
|
+
return undefined;
|
|
106
|
+
if (!target.includes('/.codex/sessions/'))
|
|
107
|
+
return undefined;
|
|
108
|
+
const sid = codexSessionIdFromRolloutPath(target);
|
|
109
|
+
if (!sid)
|
|
110
|
+
return undefined;
|
|
111
|
+
return { path: target, cliSessionId: sid };
|
|
112
|
+
}
|
|
113
|
+
/** Extract the last completed user/assistant turn from a Codex / CoCo bridge
|
|
114
|
+
* event sequence. Used by /adopt to surface the previous turn as a
|
|
115
|
+
* preamble card in the Lark thread — gives the user context to continue
|
|
116
|
+
* from. CoCo events share the same shape (uuid/timestampMs/kind/text),
|
|
117
|
+
* so this works for both bridges.
|
|
118
|
+
*
|
|
119
|
+
* Algorithm: scan tail-first for the most recent `assistant_final`, then
|
|
120
|
+
* pair it with the most recent `user` event that precedes it. Returns
|
|
121
|
+
* undefined when either side is missing — typically a fresh session whose
|
|
122
|
+
* user typed something but the model hasn't replied yet. */
|
|
123
|
+
export function extractLastCodexTurn(events) {
|
|
124
|
+
let assistantIdx = -1;
|
|
125
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
126
|
+
if (events[i].kind === 'assistant_final') {
|
|
127
|
+
assistantIdx = i;
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (assistantIdx < 0)
|
|
132
|
+
return undefined;
|
|
133
|
+
let userIdx = -1;
|
|
134
|
+
for (let i = assistantIdx - 1; i >= 0; i--) {
|
|
135
|
+
if (events[i].kind === 'user') {
|
|
136
|
+
userIdx = i;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (userIdx < 0)
|
|
141
|
+
return undefined;
|
|
142
|
+
return {
|
|
143
|
+
userText: events[userIdx].text,
|
|
144
|
+
assistantText: events[assistantIdx].text,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
/** Split a drained event list into "history" (older than the live cutoff)
|
|
148
|
+
* and "live" (cutoff or newer). The Codex adopt bridge uses this when
|
|
149
|
+
* it discovers the rollout file LATE (after the user already typed in
|
|
150
|
+
* iTerm or sent a Lark message): drain-from-0 produces a mix of pre-
|
|
151
|
+
* adopt history and post-adopt live events. The worker then `absorb()`s
|
|
152
|
+
* the history (so it isn't replayed) and `ingest()`s the live partition
|
|
153
|
+
* (so the local-turn synthesis / fingerprint match still works). Pure
|
|
154
|
+
* function — no I/O, easy to test against fixed timestamps. */
|
|
155
|
+
export function splitCodexEventsByCutoff(events, liveSinceMs) {
|
|
156
|
+
const history = [];
|
|
157
|
+
const live = [];
|
|
158
|
+
for (const ev of events) {
|
|
159
|
+
if (ev.timestampMs < liveSinceMs)
|
|
160
|
+
history.push(ev);
|
|
161
|
+
else
|
|
162
|
+
live.push(ev);
|
|
163
|
+
}
|
|
164
|
+
return { history, live };
|
|
165
|
+
}
|
|
166
|
+
/** Locate the rollout file for a given Codex sessionId. Codex names files
|
|
167
|
+
* `rollout-<ts>-<sid>.jsonl`, so a suffix match is unambiguous. The
|
|
168
|
+
* directory tree is small (year/month/day) — a one-shot recursive scan
|
|
169
|
+
* is cheap enough that we don't bother caching. */
|
|
170
|
+
export function findCodexRolloutBySessionId(cliSessionId) {
|
|
171
|
+
if (!cliSessionId || !existsSync(CODEX_SESSIONS_ROOT))
|
|
172
|
+
return undefined;
|
|
173
|
+
const suffix = `-${cliSessionId}.jsonl`;
|
|
174
|
+
const stack = [CODEX_SESSIONS_ROOT];
|
|
175
|
+
while (stack.length > 0) {
|
|
176
|
+
const dir = stack.pop();
|
|
177
|
+
let entries;
|
|
178
|
+
try {
|
|
179
|
+
entries = readdirSync(dir);
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
for (const name of entries) {
|
|
185
|
+
const full = join(dir, name);
|
|
186
|
+
let st;
|
|
187
|
+
try {
|
|
188
|
+
st = statSync(full);
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
if (st.isDirectory()) {
|
|
194
|
+
stack.push(full);
|
|
195
|
+
}
|
|
196
|
+
else if (st.isFile() && name.endsWith(suffix)) {
|
|
197
|
+
return full;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return undefined;
|
|
202
|
+
}
|
|
203
|
+
/** Concatenate all text blocks of a content array. Codex rollout content
|
|
204
|
+
* is always an array of `{type, text}`; the kinds we care about are
|
|
205
|
+
* `input_text` (user) and `output_text` (assistant). Other block types
|
|
206
|
+
* (image_url, audio, etc.) are ignored — the bridge only forwards text. */
|
|
207
|
+
function joinTextBlocks(content, kind) {
|
|
208
|
+
if (!Array.isArray(content))
|
|
209
|
+
return '';
|
|
210
|
+
const parts = [];
|
|
211
|
+
for (const block of content) {
|
|
212
|
+
if (block && typeof block === 'object' && block.type === kind) {
|
|
213
|
+
const text = block.text;
|
|
214
|
+
if (typeof text === 'string')
|
|
215
|
+
parts.push(text);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return parts.join('');
|
|
219
|
+
}
|
|
220
|
+
/** Increment-read the rollout from `fromOffset`. Mirrors the byte-offset
|
|
221
|
+
* contract of claude-transcript.drainTranscript so callers can swap them
|
|
222
|
+
* out and reuse the existing fs.watch / poll wakeup machinery. */
|
|
223
|
+
export function drainCodexRollout(path, fromOffset) {
|
|
224
|
+
if (!existsSync(path))
|
|
225
|
+
return { events: [], newOffset: 0, pendingTail: '' };
|
|
226
|
+
let size;
|
|
227
|
+
try {
|
|
228
|
+
size = statSync(path).size;
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
return { events: [], newOffset: fromOffset, pendingTail: '' };
|
|
232
|
+
}
|
|
233
|
+
let start = fromOffset;
|
|
234
|
+
// Truncated/rotated jsonl — re-read from the top. Codex doesn't normally
|
|
235
|
+
// rewrite rollouts, but mirror Claude's defensive handling.
|
|
236
|
+
if (size < start)
|
|
237
|
+
start = 0;
|
|
238
|
+
if (size === start)
|
|
239
|
+
return { events: [], newOffset: start, pendingTail: '' };
|
|
240
|
+
const len = size - start;
|
|
241
|
+
const buf = Buffer.alloc(len);
|
|
242
|
+
const fd = openSync(path, 'r');
|
|
243
|
+
try {
|
|
244
|
+
readSync(fd, buf, 0, len, start);
|
|
245
|
+
}
|
|
246
|
+
finally {
|
|
247
|
+
closeSync(fd);
|
|
248
|
+
}
|
|
249
|
+
const text = buf.toString('utf8');
|
|
250
|
+
const lastNl = text.lastIndexOf('\n');
|
|
251
|
+
const completeText = lastNl >= 0 ? text.slice(0, lastNl + 1) : '';
|
|
252
|
+
const pendingTail = lastNl >= 0 ? text.slice(lastNl + 1) : text;
|
|
253
|
+
const newOffset = start + Buffer.byteLength(completeText, 'utf8');
|
|
254
|
+
const events = [];
|
|
255
|
+
// Track byte offset within the file as we walk lines so synthetic uuids
|
|
256
|
+
// are stable across re-drains.
|
|
257
|
+
let cursor = start;
|
|
258
|
+
for (const line of completeText.split('\n')) {
|
|
259
|
+
if (line.length === 0) {
|
|
260
|
+
cursor += 1; // the \n after an empty line
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
const lineByteLen = Buffer.byteLength(line, 'utf8') + 1; // include \n
|
|
264
|
+
const lineStart = cursor;
|
|
265
|
+
cursor += lineByteLen;
|
|
266
|
+
let obj;
|
|
267
|
+
try {
|
|
268
|
+
obj = JSON.parse(line);
|
|
269
|
+
}
|
|
270
|
+
catch {
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
if (obj?.type !== 'response_item')
|
|
274
|
+
continue;
|
|
275
|
+
const p = obj.payload;
|
|
276
|
+
if (!p || typeof p !== 'object' || p.type !== 'message')
|
|
277
|
+
continue;
|
|
278
|
+
const ts = typeof obj.timestamp === 'string' ? Date.parse(obj.timestamp) : NaN;
|
|
279
|
+
const timestampMs = Number.isFinite(ts) ? ts : Date.now();
|
|
280
|
+
if (p.role === 'user') {
|
|
281
|
+
const text = joinTextBlocks(p.content, 'input_text');
|
|
282
|
+
if (!text)
|
|
283
|
+
continue;
|
|
284
|
+
events.push({ uuid: `${path}:${lineStart}`, timestampMs, kind: 'user', text });
|
|
285
|
+
}
|
|
286
|
+
else if (p.role === 'assistant' && p.phase === 'final_answer') {
|
|
287
|
+
const text = joinTextBlocks(p.content, 'output_text');
|
|
288
|
+
if (!text)
|
|
289
|
+
continue;
|
|
290
|
+
events.push({ uuid: `${path}:${lineStart}`, timestampMs, kind: 'assistant_final', text });
|
|
291
|
+
}
|
|
292
|
+
// Skip role=developer (instructions), phase=commentary (mid-turn
|
|
293
|
+
// status), and any reasoning / function_call* events — see file
|
|
294
|
+
// header for rationale.
|
|
295
|
+
}
|
|
296
|
+
return { events, newOffset, pendingTail };
|
|
297
|
+
}
|
|
298
|
+
//# sourceMappingURL=codex-transcript.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-transcript.js","sourceRoot":"","sources":["../../src/services/codex-transcript.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface CreateGroupOpts {
|
|
2
|
+
creatorLarkAppId: string;
|
|
3
|
+
/** Bots expected to join the new chat. Creator is filtered out internally
|
|
4
|
+
* (Lark rejects self-invite). May be empty (creator-only chat). */
|
|
5
|
+
larkAppIds: string[];
|
|
6
|
+
name?: string;
|
|
7
|
+
userOpenIds?: string[];
|
|
8
|
+
transferOwnerTo?: string;
|
|
9
|
+
notifyOwnerOpenId?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface CreateGroupResult {
|
|
12
|
+
ok: true;
|
|
13
|
+
chatId: string;
|
|
14
|
+
creator: string;
|
|
15
|
+
invalidBotIds: string[];
|
|
16
|
+
invalidUserIds: string[];
|
|
17
|
+
ownerTransferredTo: string | null;
|
|
18
|
+
transferError: string | null;
|
|
19
|
+
notifyMessageId: string | null;
|
|
20
|
+
notifyError: string | null;
|
|
21
|
+
}
|
|
22
|
+
export declare function createGroupWithBots(opts: CreateGroupOpts): Promise<CreateGroupResult>;
|
|
23
|
+
//# sourceMappingURL=group-creator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"group-creator.d.ts","sourceRoot":"","sources":["../../src/services/group-creator.ts"],"names":[],"mappings":"AAsBA,MAAM,WAAW,eAAe;IAC9B,gBAAgB,EAAE,MAAM,CAAC;IACzB;wEACoE;IACpE,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,IAAI,CAAC;IACT,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAuD3F"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Group creation service — execution layer shared by dashboard and CLI.
|
|
3
|
+
*
|
|
4
|
+
* Decision layers (dashboard handler / CLI subcommand) are responsible for
|
|
5
|
+
* choosing `creatorLarkAppId`, resolving bot refs, deriving user_open_ids, etc.
|
|
6
|
+
* This service only orchestrates the Lark API sequence:
|
|
7
|
+
*
|
|
8
|
+
* 1. createChat (bots + invited users)
|
|
9
|
+
* 2. transferChatOwner (best-effort, skipped if invitee was rejected)
|
|
10
|
+
* 3. send @-mention notify (best-effort, skipped if invitee was rejected)
|
|
11
|
+
*
|
|
12
|
+
* Partial failures (transfer/notify) are returned as `*Error` fields without
|
|
13
|
+
* throwing — the chat already exists at that point and retrying would create
|
|
14
|
+
* duplicate groups. Only createChat throwing surfaces as an exception.
|
|
15
|
+
*
|
|
16
|
+
* Lark open_id is app-scoped: `userOpenIds`, `transferOwnerTo`, and
|
|
17
|
+
* `notifyOwnerOpenId` MUST be in `creatorLarkAppId`'s app scope. Enforcing
|
|
18
|
+
* this is the decision layer's job — the service trusts its inputs.
|
|
19
|
+
*/
|
|
20
|
+
import { createChat, transferChatOwner } from './groups-store.js';
|
|
21
|
+
import { sendMessage } from '../im/lark/client.js';
|
|
22
|
+
export async function createGroupWithBots(opts) {
|
|
23
|
+
// Filter creator out of the bot invite list. createChat does this defensively
|
|
24
|
+
// too, but doing it here makes the service contract explicit and keeps
|
|
25
|
+
// invalidBotIds reporting stable across underlying API changes.
|
|
26
|
+
const otherBots = opts.larkAppIds.filter(id => id !== opts.creatorLarkAppId);
|
|
27
|
+
const r = await createChat(opts.creatorLarkAppId, {
|
|
28
|
+
name: opts.name,
|
|
29
|
+
botIds: otherBots,
|
|
30
|
+
userIds: opts.userOpenIds ?? [],
|
|
31
|
+
});
|
|
32
|
+
let ownerTransferredTo = null;
|
|
33
|
+
let transferError = null;
|
|
34
|
+
if (opts.transferOwnerTo) {
|
|
35
|
+
// Skip transfer if Feishu rejected the invite — transferring to a
|
|
36
|
+
// non-member returns "user not in chat" anyway.
|
|
37
|
+
if (r.invalidUserIds.includes(opts.transferOwnerTo)) {
|
|
38
|
+
transferError = 'invitee_rejected';
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
const tr = await transferChatOwner(opts.creatorLarkAppId, r.chatId, opts.transferOwnerTo);
|
|
42
|
+
if (tr.ok)
|
|
43
|
+
ownerTransferredTo = opts.transferOwnerTo;
|
|
44
|
+
else
|
|
45
|
+
transferError = tr.error;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
let notifyMessageId = null;
|
|
49
|
+
let notifyError = null;
|
|
50
|
+
if (opts.notifyOwnerOpenId) {
|
|
51
|
+
if (r.invalidUserIds.includes(opts.notifyOwnerOpenId)) {
|
|
52
|
+
notifyError = 'invitee_rejected';
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
try {
|
|
56
|
+
notifyMessageId = await sendMessage(opts.creatorLarkAppId, r.chatId, `<at user_id="${opts.notifyOwnerOpenId}"></at>`, 'text');
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
notifyError = e?.message ?? String(e);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
ok: true,
|
|
65
|
+
chatId: r.chatId,
|
|
66
|
+
creator: opts.creatorLarkAppId,
|
|
67
|
+
invalidBotIds: r.invalidBotIds,
|
|
68
|
+
invalidUserIds: r.invalidUserIds,
|
|
69
|
+
ownerTransferredTo,
|
|
70
|
+
transferError,
|
|
71
|
+
notifyMessageId,
|
|
72
|
+
notifyError,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=group-creator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"group-creator.js","sourceRoot":"","sources":["../../src/services/group-creator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAyBnD,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,IAAqB;IAC7D,8EAA8E;IAC9E,uEAAuE;IACvE,gEAAgE;IAChE,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC7E,MAAM,CAAC,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,gBAAgB,EAAE;QAChD,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,MAAM,EAAE,SAAS;QACjB,OAAO,EAAE,IAAI,CAAC,WAAW,IAAI,EAAE;KAChC,CAAC,CAAC;IAEH,IAAI,kBAAkB,GAAkB,IAAI,CAAC;IAC7C,IAAI,aAAa,GAAkB,IAAI,CAAC;IACxC,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;QACzB,kEAAkE;QAClE,gDAAgD;QAChD,IAAI,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC;YACpD,aAAa,GAAG,kBAAkB,CAAC;QACrC,CAAC;aAAM,CAAC;YACN,MAAM,EAAE,GAAG,MAAM,iBAAiB,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;YAC1F,IAAI,EAAE,CAAC,EAAE;gBAAE,kBAAkB,GAAG,IAAI,CAAC,eAAe,CAAC;;gBAChD,aAAa,GAAG,EAAE,CAAC,KAAK,CAAC;QAChC,CAAC;IACH,CAAC;IAED,IAAI,eAAe,GAAkB,IAAI,CAAC;IAC1C,IAAI,WAAW,GAAkB,IAAI,CAAC;IACtC,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC3B,IAAI,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC;YACtD,WAAW,GAAG,kBAAkB,CAAC;QACnC,CAAC;aAAM,CAAC;YACN,IAAI,CAAC;gBACH,eAAe,GAAG,MAAM,WAAW,CACjC,IAAI,CAAC,gBAAgB,EACrB,CAAC,CAAC,MAAM,EACR,gBAAgB,IAAI,CAAC,iBAAiB,SAAS,EAC/C,MAAM,CACP,CAAC;YACJ,CAAC;YAAC,OAAO,CAAM,EAAE,CAAC;gBAChB,WAAW,GAAG,CAAC,EAAE,OAAO,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,EAAE,EAAE,IAAI;QACR,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,OAAO,EAAE,IAAI,CAAC,gBAAgB;QAC9B,aAAa,EAAE,CAAC,CAAC,aAAa;QAC9B,cAAc,EAAE,CAAC,CAAC,cAAc;QAChC,kBAAkB;QAClB,aAAa;QACb,eAAe;QACf,WAAW;KACZ,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
export interface ChatBrief {
|
|
2
|
+
chatId: string;
|
|
3
|
+
name?: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
chatMode?: string;
|
|
6
|
+
ownerId?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* List chats the given bot is a member of, draining pagination internally.
|
|
10
|
+
* Uses /open-apis/im/v1/chats.
|
|
11
|
+
*/
|
|
12
|
+
export declare function listChats(larkAppId: string): Promise<ChatBrief[]>;
|
|
13
|
+
/**
|
|
14
|
+
* Check whether the given bot is a member of the given chat.
|
|
15
|
+
* Uses /open-apis/im/v1/chats/:chat_id/members/is_in_chat — the bot's own
|
|
16
|
+
* access token implicitly identifies the bot being checked.
|
|
17
|
+
*
|
|
18
|
+
* Errors (chat not found, no permission, etc.) are swallowed and treated as
|
|
19
|
+
* "not in chat" so callers can use this as a simple boolean predicate.
|
|
20
|
+
*/
|
|
21
|
+
export declare function isInChat(larkAppId: string, chatId: string): Promise<boolean>;
|
|
22
|
+
/**
|
|
23
|
+
* Create a brand-new chat with `bot_id_list` as initial bot members. The
|
|
24
|
+
* `creatorLarkAppId` bot becomes the chat's owner and an implicit member; the
|
|
25
|
+
* other bots in `botIds` are added in the same call. Used by the dashboard's
|
|
26
|
+
* "Create new group" flow.
|
|
27
|
+
*
|
|
28
|
+
* Returns the new chatId on success. Throws on any non-zero Lark response so
|
|
29
|
+
* the route can surface a real error. We deliberately don't soften failures
|
|
30
|
+
* here (unlike `isInChat`) because the caller wants to know whether the chat
|
|
31
|
+
* actually got created.
|
|
32
|
+
*/
|
|
33
|
+
export declare function createChat(creatorLarkAppId: string, opts: {
|
|
34
|
+
name?: string;
|
|
35
|
+
botIds: string[];
|
|
36
|
+
userIds?: string[];
|
|
37
|
+
}): Promise<{
|
|
38
|
+
chatId: string;
|
|
39
|
+
invalidBotIds: string[];
|
|
40
|
+
invalidUserIds: string[];
|
|
41
|
+
}>;
|
|
42
|
+
/**
|
|
43
|
+
* Transfer ownership of a chat from the calling bot to a Feishu user. Used
|
|
44
|
+
* after `createChat` so the dashboard operator (who's been invited as a
|
|
45
|
+
* member) ends up as the actual owner — otherwise the bot stays group owner
|
|
46
|
+
* and the user can't manage the chat.
|
|
47
|
+
*
|
|
48
|
+
* Calls /open-apis/im/v1/chats/:chat_id with `owner_id` in the body and
|
|
49
|
+
* `user_id_type=open_id`. The caller's bot must currently be the owner; this
|
|
50
|
+
* is the case right after createChat since the creator bot is the implicit
|
|
51
|
+
* owner.
|
|
52
|
+
*
|
|
53
|
+
* `newOwnerOpenId` must be in the calling bot's app scope — Lark open_ids are
|
|
54
|
+
* app-scoped, see operator-selector.ts for why.
|
|
55
|
+
*/
|
|
56
|
+
export declare function transferChatOwner(ownerLarkAppId: string, chatId: string, newOwnerOpenId: string): Promise<{
|
|
57
|
+
ok: true;
|
|
58
|
+
} | {
|
|
59
|
+
ok: false;
|
|
60
|
+
error: string;
|
|
61
|
+
}>;
|
|
62
|
+
/**
|
|
63
|
+
* Disband (delete) a chat. The Lark API only succeeds when the calling bot is
|
|
64
|
+
* the chat's current owner, OR is the creator AND the app holds
|
|
65
|
+
* `im:chat:operate_as_owner`. Routes that fan-out to multiple bots can use
|
|
66
|
+
* this best-effort: try each in-chat bot until one succeeds.
|
|
67
|
+
*/
|
|
68
|
+
export declare function disbandChat(larkAppId: string, chatId: string): Promise<{
|
|
69
|
+
ok: true;
|
|
70
|
+
} | {
|
|
71
|
+
ok: false;
|
|
72
|
+
error: string;
|
|
73
|
+
}>;
|
|
74
|
+
/**
|
|
75
|
+
* Make the calling bot leave a chat. Per Lark docs, self-removal succeeds
|
|
76
|
+
* regardless of role (owner/manager/member). Useful when the bot can't disband
|
|
77
|
+
* (not owner, no operate_as_owner scope) but still wants to detach.
|
|
78
|
+
*/
|
|
79
|
+
export declare function leaveChat(larkAppId: string, chatId: string): Promise<{
|
|
80
|
+
ok: true;
|
|
81
|
+
} | {
|
|
82
|
+
ok: false;
|
|
83
|
+
error: string;
|
|
84
|
+
}>;
|
|
85
|
+
/**
|
|
86
|
+
* Add bot apps to a chat using a "proxy" bot that's already a member.
|
|
87
|
+
* Uses /open-apis/im/v1/chats/:chat_id/members with member_id_type=app_id.
|
|
88
|
+
* Returns per-id result derived from the API's invalid_id_list.
|
|
89
|
+
*
|
|
90
|
+
* On total failure (network error, non-zero code) every id reports the same
|
|
91
|
+
* error so the caller can present a uniform per-id status.
|
|
92
|
+
*/
|
|
93
|
+
export declare function addBotToChat(proxyLarkAppId: string, chatId: string, targetLarkAppIds: string[]): Promise<{
|
|
94
|
+
id: string;
|
|
95
|
+
ok: boolean;
|
|
96
|
+
error?: string;
|
|
97
|
+
}[]>;
|
|
98
|
+
//# sourceMappingURL=groups-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"groups-store.d.ts","sourceRoot":"","sources":["../../src/services/groups-store.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CA2BvE;AAED;;;;;;;GAOG;AACH,wBAAsB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAWlF;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,UAAU,CAC9B,gBAAgB,EAAE,MAAM,EACxB,IAAI,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAC5D,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,EAAE,CAAC;IAAC,cAAc,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAqBhF;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,iBAAiB,CACrC,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAetD;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAChC,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAWtD;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAC7B,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAChC,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAetD;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAChC,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,MAAM,EAAE,GACzB,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAwBxD"}
|