botmux 2.110.0 → 2.111.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/dist/adapters/backend/tmux-backend.d.ts +25 -5
- package/dist/adapters/backend/tmux-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-backend.js +59 -93
- package/dist/adapters/backend/tmux-backend.js.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.js +5 -0
- package/dist/adapters/backend/tmux-pipe-backend.js.map +1 -1
- package/dist/adapters/backend/zellij-backend.d.ts +30 -0
- package/dist/adapters/backend/zellij-backend.d.ts.map +1 -1
- package/dist/adapters/backend/zellij-backend.js +80 -13
- package/dist/adapters/backend/zellij-backend.js.map +1 -1
- package/dist/adapters/backend/zellij-socket-probe.d.ts +18 -0
- package/dist/adapters/backend/zellij-socket-probe.d.ts.map +1 -0
- package/dist/adapters/backend/zellij-socket-probe.js +146 -0
- package/dist/adapters/backend/zellij-socket-probe.js.map +1 -0
- package/dist/adapters/cli/claude-code.d.ts.map +1 -1
- package/dist/adapters/cli/claude-code.js +5 -0
- package/dist/adapters/cli/claude-code.js.map +1 -1
- package/dist/adapters/cli/codex-app-turn.d.ts +43 -0
- package/dist/adapters/cli/codex-app-turn.d.ts.map +1 -0
- package/dist/adapters/cli/codex-app-turn.js +110 -0
- package/dist/adapters/cli/codex-app-turn.js.map +1 -0
- package/dist/adapters/cli/codex-app.d.ts.map +1 -1
- package/dist/adapters/cli/codex-app.js +6 -0
- package/dist/adapters/cli/codex-app.js.map +1 -1
- package/dist/adapters/cli/codex.d.ts.map +1 -1
- package/dist/adapters/cli/codex.js +1 -0
- package/dist/adapters/cli/codex.js.map +1 -1
- package/dist/adapters/cli/runner-input.d.ts +3 -2
- package/dist/adapters/cli/runner-input.d.ts.map +1 -1
- package/dist/adapters/cli/runner-input.js +7 -4
- package/dist/adapters/cli/runner-input.js.map +1 -1
- package/dist/adapters/cli/types.d.ts +16 -0
- package/dist/adapters/cli/types.d.ts.map +1 -1
- package/dist/bot-registry.d.ts +5 -0
- package/dist/bot-registry.d.ts.map +1 -1
- package/dist/bot-registry.js +1 -0
- package/dist/bot-registry.js.map +1 -1
- package/dist/codex-app-runner.js +75 -12
- package/dist/codex-app-runner.js.map +1 -1
- package/dist/core/command-handler.d.ts +11 -0
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +101 -7
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
- package/dist/core/dashboard-ipc-server.js +69 -11
- package/dist/core/dashboard-ipc-server.js.map +1 -1
- package/dist/core/doc-comment-prompt.d.ts +57 -0
- package/dist/core/doc-comment-prompt.d.ts.map +1 -1
- package/dist/core/doc-comment-prompt.js +147 -2
- package/dist/core/doc-comment-prompt.js.map +1 -1
- package/dist/core/inflight-input-tracker.d.ts +2 -0
- package/dist/core/inflight-input-tracker.d.ts.map +1 -1
- package/dist/core/inflight-input-tracker.js.map +1 -1
- package/dist/core/passthrough-commands.d.ts.map +1 -1
- package/dist/core/passthrough-commands.js +1 -1
- package/dist/core/passthrough-commands.js.map +1 -1
- package/dist/core/persistent-backend.d.ts +4 -0
- package/dist/core/persistent-backend.d.ts.map +1 -1
- package/dist/core/persistent-backend.js +6 -0
- package/dist/core/persistent-backend.js.map +1 -1
- package/dist/core/plugins/cli-generation.d.ts +3 -0
- package/dist/core/plugins/cli-generation.d.ts.map +1 -1
- package/dist/core/plugins/cli-generation.js +1 -0
- package/dist/core/plugins/cli-generation.js.map +1 -1
- package/dist/core/session-board.d.ts +2 -1
- package/dist/core/session-board.d.ts.map +1 -1
- package/dist/core/session-board.js +3 -2
- package/dist/core/session-board.js.map +1 -1
- package/dist/core/session-create.d.ts +38 -0
- package/dist/core/session-create.d.ts.map +1 -1
- package/dist/core/session-create.js +43 -9
- package/dist/core/session-create.js.map +1 -1
- package/dist/core/session-manager.d.ts +65 -2
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +285 -68
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-rename.d.ts +25 -0
- package/dist/core/session-rename.d.ts.map +1 -0
- package/dist/core/session-rename.js +43 -0
- package/dist/core/session-rename.js.map +1 -0
- package/dist/core/session-title.d.ts +11 -0
- package/dist/core/session-title.d.ts.map +1 -0
- package/dist/core/session-title.js +17 -0
- package/dist/core/session-title.js.map +1 -0
- package/dist/core/trigger-session.d.ts +11 -0
- package/dist/core/trigger-session.d.ts.map +1 -1
- package/dist/core/trigger-session.js +61 -20
- package/dist/core/trigger-session.js.map +1 -1
- package/dist/core/types.d.ts +16 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/core/worker-pool.d.ts +6 -2
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +48 -15
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/core/zellij-adopt-discovery.d.ts +17 -0
- package/dist/core/zellij-adopt-discovery.d.ts.map +1 -1
- package/dist/core/zellij-adopt-discovery.js +24 -4
- package/dist/core/zellij-adopt-discovery.js.map +1 -1
- package/dist/core/zellij-session-discovery.d.ts +3 -0
- package/dist/core/zellij-session-discovery.d.ts.map +1 -1
- package/dist/core/zellij-session-discovery.js +1 -0
- package/dist/core/zellij-session-discovery.js.map +1 -1
- package/dist/daemon.d.ts +3 -0
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +181 -81
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/bot-payload.d.ts +1 -0
- package/dist/dashboard/bot-payload.d.ts.map +1 -1
- package/dist/dashboard/bot-payload.js +1 -0
- package/dist/dashboard/bot-payload.js.map +1 -1
- package/dist/dashboard/federated-group-core.d.ts +29 -8
- package/dist/dashboard/federated-group-core.d.ts.map +1 -1
- package/dist/dashboard/federated-group-core.js +68 -6
- package/dist/dashboard/federated-group-core.js.map +1 -1
- package/dist/dashboard/federation-api.d.ts +10 -9
- package/dist/dashboard/federation-api.d.ts.map +1 -1
- package/dist/dashboard/federation-api.js +82 -3
- package/dist/dashboard/federation-api.js.map +1 -1
- package/dist/dashboard/federation-spoke-api.d.ts +8 -9
- package/dist/dashboard/federation-spoke-api.d.ts.map +1 -1
- package/dist/dashboard/federation-spoke-api.js +7 -2
- package/dist/dashboard/federation-spoke-api.js.map +1 -1
- package/dist/dashboard/team-group.d.ts +21 -0
- package/dist/dashboard/team-group.d.ts.map +1 -1
- package/dist/dashboard/team-group.js +16 -0
- package/dist/dashboard/team-group.js.map +1 -1
- package/dist/dashboard/web/bot-defaults-page.d.ts +10 -0
- package/dist/dashboard/web/bot-defaults-page.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults-page.js +33 -1
- package/dist/dashboard/web/bot-defaults-page.js.map +1 -1
- package/dist/dashboard/web/bot-defaults.d.ts +1 -0
- package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults.js.map +1 -1
- package/dist/dashboard/web/i18n.d.ts.map +1 -1
- package/dist/dashboard/web/i18n.js +8 -0
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard/web/sessions.d.ts.map +1 -1
- package/dist/dashboard/web/sessions.js +5 -1
- package/dist/dashboard/web/sessions.js.map +1 -1
- package/dist/dashboard/web/ui.d.ts.map +1 -1
- package/dist/dashboard/web/ui.js +2 -4
- package/dist/dashboard/web/ui.js.map +1 -1
- package/dist/dashboard-web/app.js +1 -1
- package/dist/dashboard-web/chunks/bot-defaults-page-7T7DPOV6.js +4 -0
- package/dist/dashboard-web/chunks/{chunk-SHZ5PUYF.js → chunk-IGXYYRYJ.js} +1 -1
- package/dist/dashboard-web/chunks/{chunk-GF7DU2B5.js → chunk-ISOD7VDX.js} +1 -1
- package/dist/dashboard-web/chunks/{chunk-TORH53FI.js → chunk-OEJIT66L.js} +1 -1
- package/dist/dashboard-web/chunks/{chunk-7UY333A5.js → chunk-PNK3HQBI.js} +2 -2
- package/dist/dashboard-web/chunks/{chunk-IAES47WV.js → chunk-YQFXGRSD.js} +1 -1
- package/dist/dashboard-web/chunks/{connectors-page-N6GKR6JL.js → connectors-page-UQ4QBE45.js} +1 -1
- package/dist/dashboard-web/chunks/{groups-page-IK3GXSQU.js → groups-page-5AJPPJH2.js} +1 -1
- package/dist/dashboard-web/chunks/{insights-page-T2PDFPGO.js → insights-page-R3DFECX4.js} +1 -1
- package/dist/dashboard-web/chunks/{legacy-workflow-page-YQPLKH74.js → legacy-workflow-page-QMC7OZXH.js} +1 -1
- package/dist/dashboard-web/chunks/{monitor-room-7EL3LVJS.js → monitor-room-NLMKJLDY.js} +1 -1
- package/dist/dashboard-web/chunks/{monitoring-page-BCADF56L.js → monitoring-page-EHSOX4GV.js} +1 -1
- package/dist/dashboard-web/chunks/{office-page-KP7BDLAE.js → office-page-OXJKFJ4R.js} +1 -1
- package/dist/dashboard-web/chunks/{overview-page-6GWDHDTI.js → overview-page-GJHIVXJF.js} +1 -1
- package/dist/dashboard-web/chunks/{roles-page-2OFR2IBG.js → roles-page-6ZODQISW.js} +1 -1
- package/dist/dashboard-web/chunks/{schedules-page-TAWMTSNL.js → schedules-page-DAGMHVCH.js} +1 -1
- package/dist/dashboard-web/chunks/{sessions-page-42QZHPPP.js → sessions-page-NNZIDHZM.js} +1 -1
- package/dist/dashboard-web/chunks/{settings-page-OVKXUXSV.js → settings-page-LJIXX5LQ.js} +1 -1
- package/dist/dashboard-web/chunks/{skills-page-Y2EC3NBI.js → skills-page-J7EVUHXP.js} +1 -1
- package/dist/dashboard-web/chunks/{team-federation-page-QYMJUH5F.js → team-federation-page-YM5JBIII.js} +1 -1
- package/dist/dashboard-web/chunks/{v3-page-FZJCW5QG.js → v3-page-YLYVHGKD.js} +1 -1
- package/dist/dashboard-web/chunks/{whiteboards-page-FBHBBCAL.js → whiteboards-page-75N2U6W4.js} +1 -1
- package/dist/dashboard.js +46 -7
- package/dist/dashboard.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +8 -0
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +8 -0
- package/dist/i18n/zh.js.map +1 -1
- package/dist/im/lark/card-handler.d.ts.map +1 -1
- package/dist/im/lark/card-handler.js +96 -32
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
- package/dist/im/lark/event-dispatcher.js +16 -5
- package/dist/im/lark/event-dispatcher.js.map +1 -1
- package/dist/services/bot-config-store.d.ts.map +1 -1
- package/dist/services/bot-config-store.js +1 -0
- package/dist/services/bot-config-store.js.map +1 -1
- package/dist/services/card-prefs-store.d.ts +4 -0
- package/dist/services/card-prefs-store.d.ts.map +1 -1
- package/dist/services/card-prefs-store.js +8 -0
- package/dist/services/card-prefs-store.js.map +1 -1
- package/dist/services/default-worktree.d.ts.map +1 -1
- package/dist/services/default-worktree.js +4 -1
- package/dist/services/default-worktree.js.map +1 -1
- package/dist/services/group-creator.d.ts +19 -0
- package/dist/services/group-creator.d.ts.map +1 -1
- package/dist/services/group-creator.js +62 -28
- package/dist/services/group-creator.js.map +1 -1
- package/dist/services/groups-store.d.ts +7 -5
- package/dist/services/groups-store.d.ts.map +1 -1
- package/dist/services/groups-store.js +10 -8
- package/dist/services/groups-store.js.map +1 -1
- package/dist/setup/ensure-tmux.d.ts +17 -0
- package/dist/setup/ensure-tmux.d.ts.map +1 -1
- package/dist/setup/ensure-tmux.js +72 -1
- package/dist/setup/ensure-tmux.js.map +1 -1
- package/dist/types.d.ts +56 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/child-env.d.ts +27 -0
- package/dist/utils/child-env.d.ts.map +1 -1
- package/dist/utils/child-env.js +59 -0
- package/dist/utils/child-env.js.map +1 -1
- package/dist/utils/codex-app-context.d.ts +9 -0
- package/dist/utils/codex-app-context.d.ts.map +1 -0
- package/dist/utils/codex-app-context.js +47 -0
- package/dist/utils/codex-app-context.js.map +1 -0
- package/dist/utils/pending-input-queue.d.ts +2 -0
- package/dist/utils/pending-input-queue.d.ts.map +1 -1
- package/dist/utils/pending-input-queue.js +6 -0
- package/dist/utils/pending-input-queue.js.map +1 -1
- package/dist/worker.js +197 -38
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
- package/dist/dashboard-web/chunks/bot-defaults-page-QXZ2VFJJ.js +0 -4
package/dist/daemon.js
CHANGED
|
@@ -36,6 +36,7 @@ import { delay } from './utils/timing.js';
|
|
|
36
36
|
import { BoundedMap } from './utils/bounded-map.js';
|
|
37
37
|
import { checkAllowedChatGroupsConfig } from './services/allowed-chat-groups.js';
|
|
38
38
|
import { ensureCjkFontsInstalled } from './utils/font-installer.js';
|
|
39
|
+
import { scrubTmuxServerGlobalEnv } from './setup/ensure-tmux.js';
|
|
39
40
|
import { invalidWorkingDirs } from './utils/working-dir.js';
|
|
40
41
|
import { validateWorkingDir } from './core/working-dir.js';
|
|
41
42
|
import { sessionKey, sessionAnchorId } from './core/types.js';
|
|
@@ -48,18 +49,19 @@ import { isLocalCliOpenReady } from './services/local-cli-opener.js';
|
|
|
48
49
|
import { RECEIVED_REACTION_EMOJI_TYPE, SUBSTITUTE_RECEIVED_REACTION_EMOJI_TYPE } from './core/pending-response.js';
|
|
49
50
|
import { t as tr, botLocale, localeForBot } from './i18n/index.js';
|
|
50
51
|
import { createCliAdapterSync } from './adapters/cli/registry.js';
|
|
51
|
-
import { initWorkerPool, setActiveSessionsRegistry, forkWorker, killWorker, reapOrphanWorkers, scheduleCardPatch, setCurrentCliVersion, getCurrentCliVersion, CARD_POSTING_SENTINEL, parkStreamCard, closeSession as closeSessionHelper, ensureCliEnv, sweepGlobalBotmuxSkills, writableTerminalLinkFor, } from './core/worker-pool.js';
|
|
52
|
+
import { initWorkerPool, setActiveSessionsRegistry, forkWorker, sendWorkerInput, killWorker, reapOrphanWorkers, scheduleCardPatch, setCurrentCliVersion, getCurrentCliVersion, CARD_POSTING_SENTINEL, parkStreamCard, closeSession as closeSessionHelper, ensureCliEnv, sweepGlobalBotmuxSkills, writableTerminalLinkFor, } from './core/worker-pool.js';
|
|
52
53
|
import { ipcRoute, jsonRes, readJsonBody, setBotName, setLarkAppId, startIpcServer, setWorkflowRunner, setBotRenamer } from './core/dashboard-ipc-server.js';
|
|
53
54
|
import { saveFrozenCards } from './services/frozen-card-store.js';
|
|
54
|
-
import { DAEMON_COMMANDS, SESSIONLESS_DAEMON_COMMANDS, resolvePassthroughCommands, resolveAdapterDefaultPassthroughCommands, handleCommand, handleCardCommand, handleTermLinkCommand, parseSlashCommandInvocation, parseForceTopicInvocation } from './core/command-handler.js';
|
|
55
|
+
import { DAEMON_COMMANDS, SESSIONLESS_DAEMON_COMMANDS, EXISTING_SESSION_ONLY_DAEMON_COMMANDS, resolvePassthroughCommands, resolveAdapterDefaultPassthroughCommands, handleCommand, handleCardCommand, handleTermLinkCommand, parseSlashCommandInvocation, parseForceTopicInvocation } from './core/command-handler.js';
|
|
55
56
|
import { docWatchCommandNeedsSession } from './core/doc-watch-command.js';
|
|
56
57
|
import { SLASH_COMMAND_SHAPE } from './core/passthrough-commands.js';
|
|
57
58
|
import { findInheritablePeer } from './core/inherit-peer.js';
|
|
58
59
|
import { isCallbackUrl, handleCallbackUrl } from './utils/user-token.js';
|
|
59
60
|
import { consumeQuota, removeChatGrant, removeGlobalGrant } from './services/grant-store.js';
|
|
60
61
|
import { abortCharge, commitCharge, beginCharge } from './services/quota-dedup.js';
|
|
61
|
-
import { getSessionWorkingDir, getProjectScanDirs, expandHome, downloadResources, formatAttachmentsHint,
|
|
62
|
+
import { getSessionWorkingDir, getProjectScanDirs, expandHome, downloadResources, formatAttachmentsHint, buildNewTopicCliInput, buildFollowUpCliInput, buildBridgeInputContent, buildReforkCliInput, getAvailableBots, restoreActiveSessions, executeScheduledTask, persistStreamCardState, rememberLastCliInput, ensureTerminalWorkerPort, ensureSessionWhiteboard, } from './core/session-manager.js';
|
|
62
63
|
import { triggerSessionTurn } from './core/trigger-session.js';
|
|
64
|
+
import { applyQueuedCodexAppLegacyFallback, mergeQueuedCodexAppTurn } from './core/session-create.js';
|
|
63
65
|
import { findOnlineDaemon, listOnlineDaemons } from './utils/daemon-discovery.js';
|
|
64
66
|
import { beginReplyTargetTurn, fallbackTurnId, resolveSessionReplyTarget, syncReplyTargetState } from './core/reply-target.js';
|
|
65
67
|
import { sweepOrphanSandboxes } from './adapters/backend/sandbox.js';
|
|
@@ -85,7 +87,7 @@ import { getDocSubscription, listAllDocSubscriptions, removeDocSubscription, set
|
|
|
85
87
|
import { BOT_REPLY_SENTINEL, subscribeDocFile, unsubscribeDocFile, addCommentReaction, hasBotSentinel, isBotAuthoredReply, listDocComments } from './im/lark/doc-comment.js';
|
|
86
88
|
import { learnFromMentions, resolveSender, flushIdentityCacheSync } from './im/lark/identity-cache.js';
|
|
87
89
|
import { normalizeBrand } from './im/lark/lark-hosts.js';
|
|
88
|
-
import {
|
|
90
|
+
import { buildDocCommentTurnInput, buildDocWatchWarmupTurnInput } from './core/doc-comment-prompt.js';
|
|
89
91
|
import { advanceDocCommentCursor, docCommentRepliesAfterCursor, latestDocCommentPollCursor } from './core/doc-comment-poller.js';
|
|
90
92
|
import { renderBufferedSenderBlock } from './core/session-manager.js';
|
|
91
93
|
import { shutdownBackendDisposition } from './core/persistent-backend.js';
|
|
@@ -1764,12 +1766,12 @@ async function prewarmDocCommentSession(ds, sub) {
|
|
|
1764
1766
|
const bot = getBot(ds.larkAppId);
|
|
1765
1767
|
const botCfg = bot.config;
|
|
1766
1768
|
const loc = localeForBot(ds.larkAppId);
|
|
1767
|
-
const
|
|
1769
|
+
const warmupInput = {
|
|
1768
1770
|
fileToken: sub.fileToken,
|
|
1769
1771
|
fileType: sub.fileType,
|
|
1770
1772
|
brand: normalizeBrand(botCfg.brand),
|
|
1771
1773
|
locale: loc,
|
|
1772
|
-
}
|
|
1774
|
+
};
|
|
1773
1775
|
const title = `[Doc Watch] ${sub.fileToken.slice(0, 12)}`;
|
|
1774
1776
|
const turnId = `doc-watch-${Date.now()}-${sub.fileToken.slice(0, 8)}`;
|
|
1775
1777
|
const sender = sub.ownerOpenId ? await resolveSender(ds.larkAppId, sub.ownerOpenId, 'user') : undefined;
|
|
@@ -1779,34 +1781,39 @@ async function prewarmDocCommentSession(ds, sub) {
|
|
|
1779
1781
|
if (sub.workingDir && (!ds.worker || ds.worker.killed)) {
|
|
1780
1782
|
ds.workingDir = sub.workingDir;
|
|
1781
1783
|
ds.session.workingDir = sub.workingDir;
|
|
1784
|
+
// An explicit doc-watch cwd replaces the previous repo selection. Keeping
|
|
1785
|
+
// a multi-Riff stamp would make the cold refork ignore this new directory.
|
|
1786
|
+
ds.session.riffRepoDirs = undefined;
|
|
1782
1787
|
}
|
|
1783
1788
|
if (ds.worker && !ds.worker.killed) {
|
|
1784
1789
|
ensureSessionWhiteboard(ds);
|
|
1785
|
-
const
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1790
|
+
const { promptContent, cliInput } = buildDocWatchWarmupTurnInput({
|
|
1791
|
+
ds,
|
|
1792
|
+
promptInput: warmupInput,
|
|
1793
|
+
botCliId: botCfg.cliId,
|
|
1794
|
+
botCliPathOverride: botCfg.cliPathOverride,
|
|
1789
1795
|
sender,
|
|
1790
|
-
|
|
1791
|
-
chatId: ds.session.chatId,
|
|
1792
|
-
whiteboardId: ds.session.whiteboardId,
|
|
1796
|
+
mode: 'live',
|
|
1793
1797
|
});
|
|
1794
|
-
rememberLastCliInput(ds, promptContent,
|
|
1798
|
+
rememberLastCliInput(ds, promptContent, cliInput);
|
|
1795
1799
|
sessionStore.updateSession(ds.session);
|
|
1796
|
-
ds
|
|
1800
|
+
sendWorkerInput(ds, cliInput, turnId);
|
|
1797
1801
|
markSessionActivity(ds);
|
|
1798
1802
|
}
|
|
1799
1803
|
else {
|
|
1800
1804
|
ensureSessionWhiteboard(ds);
|
|
1801
|
-
const
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
+
const { promptContent, cliInput: wrappedInput } = buildDocWatchWarmupTurnInput({
|
|
1806
|
+
ds,
|
|
1807
|
+
promptInput: warmupInput,
|
|
1808
|
+
botCliId: botCfg.cliId,
|
|
1809
|
+
botCliPathOverride: botCfg.cliPathOverride,
|
|
1810
|
+
botIdentity: { name: bot.botName, openId: bot.botOpenId },
|
|
1805
1811
|
sender,
|
|
1812
|
+
mode: 'refork',
|
|
1806
1813
|
});
|
|
1807
|
-
rememberLastCliInput(ds, promptContent,
|
|
1814
|
+
rememberLastCliInput(ds, promptContent, wrappedInput);
|
|
1808
1815
|
sessionStore.updateSession(ds.session);
|
|
1809
|
-
forkWorker(ds,
|
|
1816
|
+
forkWorker(ds, wrappedInput, ds.hasHistory);
|
|
1810
1817
|
}
|
|
1811
1818
|
logger.info(`[${tag(ds)}] doc-comment watch prewarm injected file=${sub.fileToken.slice(0, 12)}`);
|
|
1812
1819
|
}
|
|
@@ -5342,6 +5349,12 @@ async function resolvePinnedWorkingDir(ctx) {
|
|
|
5342
5349
|
return { pinnedWorkingDir, oncallEntry, inheritedFrom, pinnedFromBotDefault };
|
|
5343
5350
|
}
|
|
5344
5351
|
export const __testOnly_resolvePinnedWorkingDir = resolvePinnedWorkingDir;
|
|
5352
|
+
// Production message routes (function declarations hoist, so the references
|
|
5353
|
+
// are valid here). Exposed for route-level regression tests — e.g. asserting
|
|
5354
|
+
// that `/rename` in a fresh topic/thread does NOT pre-create a phantom session,
|
|
5355
|
+
// which unit tests calling handleCommand directly can never catch.
|
|
5356
|
+
export const __testOnly_handleNewTopic = (data, ctx) => handleNewTopic(data, ctx);
|
|
5357
|
+
export const __testOnly_handleThreadReply = (data, ctx) => handleThreadReply(data, ctx);
|
|
5345
5358
|
/**
|
|
5346
5359
|
* 该新会话是否要走「仅默认目录 + 自动建 worktree」:pinned dir 来自本 bot 自己的
|
|
5347
5360
|
* defaultWorkingDir (layer 3) 且开关打开。为真时,spawn 路径不再同步 fork,而是把会话登记
|
|
@@ -5663,6 +5676,17 @@ async function handleNewTopic(data, ctx) {
|
|
|
5663
5676
|
fireSessionlessCommandDetached(cmd, anchor, { ...parsed, content: commandContent, chatId }, larkAppId);
|
|
5664
5677
|
return;
|
|
5665
5678
|
}
|
|
5679
|
+
// `/rename` renames an EXISTING session; a brand-new topic has none. Route
|
|
5680
|
+
// straight to handleCommand (its `!ds` branch replies no_active_session)
|
|
5681
|
+
// so the pre-create block below doesn't spawn a worker:null phantom
|
|
5682
|
+
// session just to rename it. Same phantom-session concern as the /card
|
|
5683
|
+
// and /term special cases, but UNLIKE those (which carry their own
|
|
5684
|
+
// permission gates inside their handlers) this branch MUST stay after
|
|
5685
|
+
// the canOperate gate above — the /rename handler itself has no gate.
|
|
5686
|
+
if (EXISTING_SESSION_ONLY_DAEMON_COMMANDS.has(cmd)) {
|
|
5687
|
+
await handleCommand(cmd, anchor, { ...parsed, content: commandContent }, commandDeps, larkAppId);
|
|
5688
|
+
return;
|
|
5689
|
+
}
|
|
5666
5690
|
// Same rootMessageId reasoning as below in the main spawn path:
|
|
5667
5691
|
// thread-scope MUST anchor on the thread root or sessionAnchorId() will
|
|
5668
5692
|
// disagree with activeSessions's key and downstream card buttons silently
|
|
@@ -5735,7 +5759,8 @@ async function handleNewTopic(data, ctx) {
|
|
|
5735
5759
|
// weight on first turns. `content` (post force-topic-strip) is what the
|
|
5736
5760
|
// worker will see; promptContent wraps it for prompt-building paths but
|
|
5737
5761
|
// leaves `content` untouched for title / log substring uses.
|
|
5738
|
-
const
|
|
5762
|
+
const codexAppMessageContext = buildQuoteHint(parsed, scope, anchor, localeForBot(larkAppId));
|
|
5763
|
+
const promptContent = codexAppMessageContext + content;
|
|
5739
5764
|
// Resolve sender identity for <sender> tag injection. The first call to
|
|
5740
5765
|
// resolveSender for an unseen open_id may await contact.v3.user.get with a
|
|
5741
5766
|
// short budget; subsequent calls hit the cache and are sync-fast.
|
|
@@ -5792,6 +5817,8 @@ async function handleNewTopic(data, ctx) {
|
|
|
5792
5817
|
hasHistory: false,
|
|
5793
5818
|
pendingRepo: !pinnedWorkingDir || autoWt,
|
|
5794
5819
|
pendingPrompt: promptContent,
|
|
5820
|
+
pendingCodexAppText: content,
|
|
5821
|
+
pendingCodexAppMessageContext: codexAppMessageContext,
|
|
5795
5822
|
pendingAttachments: attachments.length > 0 ? attachments : undefined,
|
|
5796
5823
|
pendingMentions: parsed.mentions,
|
|
5797
5824
|
pendingSubstituteTrigger: substituteTrigger,
|
|
@@ -5822,9 +5849,9 @@ async function handleNewTopic(data, ctx) {
|
|
|
5822
5849
|
return;
|
|
5823
5850
|
const selfBot = getBot(larkAppId);
|
|
5824
5851
|
ensureSessionWhiteboard(ds);
|
|
5825
|
-
const prompt =
|
|
5826
|
-
rememberLastCliInput(ds, promptContent, prompt);
|
|
5852
|
+
const prompt = buildNewTopicCliInput(promptContent, session.sessionId, botCfg.cliId, botCfg.cliPathOverride, attachments, parsed.mentions, await getAvailableBots(larkAppId, chatId), undefined, { name: selfBot.botName, openId: selfBot.botOpenId }, localeForBot(larkAppId), newTopicSender, { larkAppId, chatId, whiteboardId: ds.session.whiteboardId, substituteTrigger, codexAppText: content, codexAppMessageContext });
|
|
5827
5853
|
await noteTurnReceived(ds, messageId, content, newTopicSender, messageId, substituteTrigger ? SUBSTITUTE_RECEIVED_REACTION_EMOJI_TYPE : undefined);
|
|
5854
|
+
rememberLastCliInput(ds, promptContent, prompt);
|
|
5828
5855
|
forkWorker(ds, prompt);
|
|
5829
5856
|
const reason = oncallEntry
|
|
5830
5857
|
? `oncall-bound chat ${chatId}`
|
|
@@ -5855,9 +5882,9 @@ async function handleNewTopic(data, ctx) {
|
|
|
5855
5882
|
ds.pendingRepo = false;
|
|
5856
5883
|
const selfBot = getBot(larkAppId);
|
|
5857
5884
|
ensureSessionWhiteboard(ds);
|
|
5858
|
-
const prompt =
|
|
5859
|
-
rememberLastCliInput(ds, promptContent, prompt);
|
|
5885
|
+
const prompt = buildNewTopicCliInput(promptContent, session.sessionId, botCfg.cliId, botCfg.cliPathOverride, attachments, parsed.mentions, await getAvailableBots(larkAppId, chatId), undefined, { name: selfBot.botName, openId: selfBot.botOpenId }, localeForBot(larkAppId), newTopicSender, { larkAppId, chatId, whiteboardId: ds.session.whiteboardId, substituteTrigger, codexAppText: content, codexAppMessageContext });
|
|
5860
5886
|
await noteTurnReceived(ds, messageId, content, newTopicSender, messageId, substituteTrigger ? SUBSTITUTE_RECEIVED_REACTION_EMOJI_TYPE : undefined);
|
|
5887
|
+
rememberLastCliInput(ds, promptContent, prompt);
|
|
5861
5888
|
forkWorker(ds, prompt);
|
|
5862
5889
|
logger.info(`Session ${session.sessionId} ready (no projects to select), total active: ${getActiveCount()}`);
|
|
5863
5890
|
}
|
|
@@ -5963,6 +5990,11 @@ async function handleBotAdded(chatId, operatorOpenId, larkAppId) {
|
|
|
5963
5990
|
const mode = await getChatMode(larkAppId, chatId, { forceRefresh: true });
|
|
5964
5991
|
const promptBody = resolveGroupJoinPrompt(botCfg.autoStartOnGroupJoinPrompt);
|
|
5965
5992
|
const title = (promptBody || tr('daemon.auto_start_join_title', undefined, localeForBot(larkAppId))).substring(0, 50);
|
|
5993
|
+
// D8 deliberately keeps the legacy prompt empty when no join prompt is
|
|
5994
|
+
// configured, so the agent can inspect group context without receiving a
|
|
5995
|
+
// synthetic instruction. Codex App still needs a non-blank visible
|
|
5996
|
+
// UserMessage; reuse the localized session title only in its clean sidecar.
|
|
5997
|
+
const codexAppText = promptBody || title;
|
|
5966
5998
|
// Pick scope + anchor. 话题群 → seed a topic and anchor thread-scope there;
|
|
5967
5999
|
// 普通群 → chat-scope anchored at chatId.
|
|
5968
6000
|
let scope;
|
|
@@ -6010,6 +6042,7 @@ async function handleBotAdded(chatId, operatorOpenId, larkAppId) {
|
|
|
6010
6042
|
hasHistory: false,
|
|
6011
6043
|
pendingRepo: !pinnedWorkingDir || autoWt,
|
|
6012
6044
|
pendingPrompt: promptBody,
|
|
6045
|
+
pendingCodexAppText: botCfg.cliId === 'codex-app' ? codexAppText : undefined,
|
|
6013
6046
|
ownerOpenId: operatorOpenId,
|
|
6014
6047
|
currentTurnTitle: title,
|
|
6015
6048
|
workingDir: pinnedWorkingDir,
|
|
@@ -6019,7 +6052,7 @@ async function handleBotAdded(chatId, operatorOpenId, larkAppId) {
|
|
|
6019
6052
|
// even in 话题群 (where dsKey is the seed id, not chatId).
|
|
6020
6053
|
groupJoinAnchorByChat.set(chatLiveKey, dsKey);
|
|
6021
6054
|
const selfBot = getBot(larkAppId);
|
|
6022
|
-
const buildPrompt = async () =>
|
|
6055
|
+
const buildPrompt = async () => buildNewTopicCliInput(promptBody, session.sessionId, botCfg.cliId, botCfg.cliPathOverride, undefined, undefined, await getAvailableBots(larkAppId, chatId), undefined, { name: selfBot.botName, openId: selfBot.botOpenId }, localeForBot(larkAppId), undefined, { larkAppId, chatId, whiteboardId: ds.session.whiteboardId, codexAppText });
|
|
6023
6056
|
// Auto-worktree: register PENDING, build worktree off-path, commit+fork later.
|
|
6024
6057
|
if (pinnedWorkingDir && autoWt) {
|
|
6025
6058
|
if (await replyInvalidWorkingDirs(anchor, larkAppId, ds))
|
|
@@ -6033,8 +6066,8 @@ async function handleBotAdded(chatId, operatorOpenId, larkAppId) {
|
|
|
6033
6066
|
return;
|
|
6034
6067
|
ensureSessionWhiteboard(ds);
|
|
6035
6068
|
const prompt = await buildPrompt();
|
|
6036
|
-
rememberLastCliInput(ds, promptBody, prompt);
|
|
6037
6069
|
await noteTurnReceived(ds, anchor, promptBody);
|
|
6070
|
+
rememberLastCliInput(ds, promptBody, prompt);
|
|
6038
6071
|
forkWorker(ds, prompt);
|
|
6039
6072
|
logger.info(`[auto-start:入群] ${chatId.substring(0, 12)} 自动开工(${mode}/${scope}),workingDir=${pinnedWorkingDir}`);
|
|
6040
6073
|
return;
|
|
@@ -6055,8 +6088,8 @@ async function handleBotAdded(chatId, operatorOpenId, larkAppId) {
|
|
|
6055
6088
|
ds.pendingRepo = false;
|
|
6056
6089
|
ensureSessionWhiteboard(ds);
|
|
6057
6090
|
const prompt = await buildPrompt();
|
|
6058
|
-
rememberLastCliInput(ds, promptBody, prompt);
|
|
6059
6091
|
await noteTurnReceived(ds, anchor, promptBody);
|
|
6092
|
+
rememberLastCliInput(ds, promptBody, prompt);
|
|
6060
6093
|
forkWorker(ds, prompt);
|
|
6061
6094
|
logger.info(`[auto-start:入群] ${chatId.substring(0, 12)} 无默认目录且无可选项目,直接开工`);
|
|
6062
6095
|
}
|
|
@@ -6136,7 +6169,9 @@ async function handleThreadReply(data, ctx) {
|
|
|
6136
6169
|
: '';
|
|
6137
6170
|
// `let` (not const): the v3 grill gate below may replace this with a
|
|
6138
6171
|
// skill-trigger prompt when the user sends `/workflow [new] <目标>` mid-thread.
|
|
6139
|
-
|
|
6172
|
+
const initialCodexAppMessageContext = buildQuoteHint(parsed, scope, anchor, localeForBot(larkAppId)) + botSenderPrefix;
|
|
6173
|
+
const initialPromptContent = initialCodexAppMessageContext + parsed.content;
|
|
6174
|
+
let promptContent = initialPromptContent;
|
|
6140
6175
|
const existingHookSession = activeSessions.get(sessionKey(anchor, larkAppId));
|
|
6141
6176
|
emitHookEvent('thread.reply', {
|
|
6142
6177
|
larkAppId,
|
|
@@ -6340,8 +6375,12 @@ async function handleThreadReply(data, ctx) {
|
|
|
6340
6375
|
// Without a session, handleCommand gets ds=undefined and `/repo` (and other
|
|
6341
6376
|
// session commands) fall through to the repo-select card. Create the session
|
|
6342
6377
|
// first, mirroring handleNewTopic's first-message `/repo` pendingRepo setup.
|
|
6343
|
-
// Session-less commands (/group /g) don't need one
|
|
6344
|
-
|
|
6378
|
+
// Session-less commands (/group /g) don't need one; existing-session-only
|
|
6379
|
+
// commands (/rename) must NOT get one — a pre-created worker:null session
|
|
6380
|
+
// would be a phantom conversation that only exists to be renamed. Let
|
|
6381
|
+
// handleCommand's `!ds` branch reply no_active_session instead.
|
|
6382
|
+
if (!existingDs && threadChatId && !isSessionlessCommandInvocation(cmd, commandContent)
|
|
6383
|
+
&& !EXISTING_SESSION_ONLY_DAEMON_COMMANDS.has(cmd)) {
|
|
6345
6384
|
const session = sessionStore.createSession(threadChatId, anchor, cmdContent.substring(0, 50), ctxChatType);
|
|
6346
6385
|
const now = Date.now();
|
|
6347
6386
|
if (ctxChatType === 'p2p') {
|
|
@@ -6442,6 +6481,13 @@ async function handleThreadReply(data, ctx) {
|
|
|
6442
6481
|
if (!await enforceMessageQuotaForCliInput(larkAppId, ctxChatId ?? data?.message?.chat_id, quotaSenderOpenId, parsed.messageId, anchor, threadTeamTrustUnionId, threadSenderUnionId)) {
|
|
6443
6482
|
return;
|
|
6444
6483
|
}
|
|
6484
|
+
// When a command path rewrites the model prompt (for example /workflow),
|
|
6485
|
+
// keep the Lark-authored bytes visible and move the rewritten instruction
|
|
6486
|
+
// into hidden untrusted context. Simple quote/bot prefixes use only the
|
|
6487
|
+
// prefix as context, avoiding a duplicate copy of the user text.
|
|
6488
|
+
const codexAppMessageContext = promptContent === initialPromptContent
|
|
6489
|
+
? initialCodexAppMessageContext
|
|
6490
|
+
: promptContent;
|
|
6445
6491
|
// Download attachments
|
|
6446
6492
|
const effectiveAppId = ds?.larkAppId ?? larkAppId;
|
|
6447
6493
|
const { attachments, needLogin } = await downloadResources(effectiveAppId, parsed.messageId, resources);
|
|
@@ -6472,15 +6518,23 @@ async function handleThreadReply(data, ctx) {
|
|
|
6472
6518
|
// If waiting for repo selection, buffer the message and remind user
|
|
6473
6519
|
if (ds?.pendingRepo) {
|
|
6474
6520
|
// Enrich content with attachment hints and mention metadata (same as normal send)
|
|
6475
|
-
|
|
6476
|
-
|
|
6521
|
+
const codexAppFollowUpContextParts = [];
|
|
6522
|
+
if (codexAppMessageContext)
|
|
6523
|
+
codexAppFollowUpContextParts.push(codexAppMessageContext);
|
|
6524
|
+
const attachmentHint = attachments.length > 0 ? formatAttachmentsHint(attachments) : '';
|
|
6525
|
+
let enriched = attachmentHint
|
|
6526
|
+
? `${promptContent}${attachmentHint}`
|
|
6477
6527
|
: promptContent;
|
|
6528
|
+
if (attachmentHint)
|
|
6529
|
+
codexAppFollowUpContextParts.push(attachmentHint);
|
|
6478
6530
|
if (parsed.mentions && parsed.mentions.length > 0) {
|
|
6479
6531
|
const mentionLines = parsed.mentions.map(m => {
|
|
6480
6532
|
const idPart = m.openId ? ` → open_id: ${m.openId}` : '';
|
|
6481
6533
|
return `- @${m.name}${idPart}`;
|
|
6482
6534
|
});
|
|
6483
|
-
|
|
6535
|
+
const mentionContext = `${tr('daemon.enriched_mentions_label', undefined, localeForBot(larkAppId))}\n${mentionLines.join('\n')}`;
|
|
6536
|
+
enriched += `\n\n${mentionContext}`;
|
|
6537
|
+
codexAppFollowUpContextParts.push(mentionContext);
|
|
6484
6538
|
}
|
|
6485
6539
|
// Stamp a buffered follow-up with its own <sender> tag ONLY when it comes
|
|
6486
6540
|
// from a different user than the first message (ds.pendingSender) — the
|
|
@@ -6496,12 +6550,20 @@ async function handleThreadReply(data, ctx) {
|
|
|
6496
6550
|
// guard (the builder's own note only covers ds.pendingSender's top-level
|
|
6497
6551
|
// tag, and is absent entirely when pendingSender is undefined).
|
|
6498
6552
|
const followUpSenderBlock = renderBufferedSenderBlock(followUpSender, getBot(larkAppId).config.cliId, localeForBot(larkAppId));
|
|
6499
|
-
if (followUpSenderBlock)
|
|
6553
|
+
if (followUpSenderBlock) {
|
|
6500
6554
|
enriched = `${followUpSenderBlock}\n${enriched}`;
|
|
6555
|
+
codexAppFollowUpContextParts.unshift(followUpSenderBlock);
|
|
6556
|
+
}
|
|
6501
6557
|
}
|
|
6502
6558
|
if (!ds.pendingFollowUps)
|
|
6503
6559
|
ds.pendingFollowUps = [];
|
|
6504
6560
|
ds.pendingFollowUps.push(enriched);
|
|
6561
|
+
if (!ds.pendingCodexAppFollowUps)
|
|
6562
|
+
ds.pendingCodexAppFollowUps = [];
|
|
6563
|
+
ds.pendingCodexAppFollowUps.push(parsed.content);
|
|
6564
|
+
if (!ds.pendingCodexAppFollowUpContexts)
|
|
6565
|
+
ds.pendingCodexAppFollowUpContexts = [];
|
|
6566
|
+
ds.pendingCodexAppFollowUpContexts.push(codexAppFollowUpContextParts.join('\n\n'));
|
|
6505
6567
|
// Auto-worktree pending (worktreeCreating) has no repo card to point at — the
|
|
6506
6568
|
// message IS buffered (folded on commit), so just say "hold on, building worktree"
|
|
6507
6569
|
// instead of the misleading "pick a repo from the card above".
|
|
@@ -6583,6 +6645,8 @@ async function handleThreadReply(data, ctx) {
|
|
|
6583
6645
|
hasHistory: false,
|
|
6584
6646
|
pendingRepo: !pinnedWorkingDir || autoWt,
|
|
6585
6647
|
pendingPrompt: promptContent,
|
|
6648
|
+
pendingCodexAppText: parsed.content,
|
|
6649
|
+
pendingCodexAppMessageContext: codexAppMessageContext,
|
|
6586
6650
|
pendingAttachments: attachments.length > 0 ? attachments : undefined,
|
|
6587
6651
|
pendingMentions: parsed.mentions,
|
|
6588
6652
|
pendingSubstituteTrigger: substituteTrigger,
|
|
@@ -6612,9 +6676,9 @@ async function handleThreadReply(data, ctx) {
|
|
|
6612
6676
|
return;
|
|
6613
6677
|
const selfBot = getBot(larkAppId);
|
|
6614
6678
|
ensureSessionWhiteboard(newDs);
|
|
6615
|
-
const prompt =
|
|
6616
|
-
rememberLastCliInput(newDs, promptContent, prompt);
|
|
6679
|
+
const prompt = buildNewTopicCliInput(promptContent, session.sessionId, botCfg.cliId, botCfg.cliPathOverride, attachments, parsed.mentions, await getAvailableBots(larkAppId, autoCreateChatId), undefined, { name: selfBot.botName, openId: selfBot.botOpenId }, localeForBot(larkAppId), autoCreateSender, { larkAppId, chatId: autoCreateChatId, whiteboardId: newDs.session.whiteboardId, substituteTrigger, codexAppText: parsed.content, codexAppMessageContext });
|
|
6617
6680
|
await noteTurnReceived(newDs, parsed.messageId, parsed.content, autoCreateSender, parsed.messageId, substituteTrigger ? SUBSTITUTE_RECEIVED_REACTION_EMOJI_TYPE : undefined);
|
|
6681
|
+
rememberLastCliInput(newDs, promptContent, prompt);
|
|
6618
6682
|
forkWorker(newDs, prompt);
|
|
6619
6683
|
const reason = oncallEntry
|
|
6620
6684
|
? `oncall-bound chat ${autoCreateChatId}`
|
|
@@ -6645,9 +6709,9 @@ async function handleThreadReply(data, ctx) {
|
|
|
6645
6709
|
newDs.pendingRepo = false;
|
|
6646
6710
|
const selfBot = getBot(larkAppId);
|
|
6647
6711
|
ensureSessionWhiteboard(newDs);
|
|
6648
|
-
const prompt =
|
|
6649
|
-
rememberLastCliInput(newDs, promptContent, prompt);
|
|
6712
|
+
const prompt = buildNewTopicCliInput(promptContent, session.sessionId, botCfg.cliId, botCfg.cliPathOverride, attachments, parsed.mentions, await getAvailableBots(larkAppId, autoCreateChatId), undefined, { name: selfBot.botName, openId: selfBot.botOpenId }, localeForBot(larkAppId), autoCreateSender, { larkAppId, chatId: autoCreateChatId, whiteboardId: newDs.session.whiteboardId, substituteTrigger, codexAppText: parsed.content, codexAppMessageContext });
|
|
6650
6713
|
await noteTurnReceived(newDs, parsed.messageId, parsed.content, autoCreateSender, parsed.messageId, substituteTrigger ? SUBSTITUTE_RECEIVED_REACTION_EMOJI_TYPE : undefined);
|
|
6714
|
+
rememberLastCliInput(newDs, promptContent, prompt);
|
|
6651
6715
|
forkWorker(newDs, prompt);
|
|
6652
6716
|
}
|
|
6653
6717
|
return;
|
|
@@ -6667,28 +6731,31 @@ async function handleThreadReply(data, ctx) {
|
|
|
6667
6731
|
const selfBot = getBot(ds.larkAppId);
|
|
6668
6732
|
if (!isBridge)
|
|
6669
6733
|
ensureSessionWhiteboard(ds);
|
|
6670
|
-
const
|
|
6671
|
-
|
|
6672
|
-
|
|
6673
|
-
|
|
6674
|
-
|
|
6675
|
-
|
|
6676
|
-
|
|
6734
|
+
const effectiveCliId = ds.session.cliId ?? dsBotCfgForMsg.cliId;
|
|
6735
|
+
const cliInput = isBridge
|
|
6736
|
+
? { content: buildBridgeInputContent(promptContent, {
|
|
6737
|
+
attachments,
|
|
6738
|
+
mentions: parsed.mentions,
|
|
6739
|
+
selfMention: { name: selfBot.botName, openId: selfBot.botOpenId },
|
|
6740
|
+
}) }
|
|
6741
|
+
: buildFollowUpCliInput(promptContent, ds.session.sessionId, {
|
|
6677
6742
|
attachments,
|
|
6678
6743
|
mentions: parsed.mentions,
|
|
6679
6744
|
isAdoptMode: false,
|
|
6680
|
-
cliId:
|
|
6681
|
-
cliPathOverride: dsBotCfgForMsg.cliPathOverride,
|
|
6745
|
+
cliId: effectiveCliId,
|
|
6746
|
+
cliPathOverride: ds.session.cliPathOverride ?? dsBotCfgForMsg.cliPathOverride,
|
|
6682
6747
|
sender: await getThreadSender(),
|
|
6683
6748
|
larkAppId,
|
|
6684
6749
|
chatId: ds.session.chatId,
|
|
6685
6750
|
whiteboardId: ds.session.whiteboardId,
|
|
6686
6751
|
substituteTrigger,
|
|
6752
|
+
codexAppText: parsed.content,
|
|
6753
|
+
codexAppMessageContext,
|
|
6687
6754
|
});
|
|
6688
6755
|
beginNewTurn(ds, parsed.content);
|
|
6689
|
-
rememberLastCliInput(ds, promptContent, msgContent);
|
|
6690
6756
|
await noteTurnReceived(ds, parsed.messageId, parsed.content, await getThreadSender(), parsed.messageId, substituteTrigger ? SUBSTITUTE_RECEIVED_REACTION_EMOJI_TYPE : undefined);
|
|
6691
|
-
ds
|
|
6757
|
+
rememberLastCliInput(ds, promptContent, cliInput);
|
|
6758
|
+
sendWorkerInput(ds, cliInput, parsed.messageId);
|
|
6692
6759
|
}
|
|
6693
6760
|
else {
|
|
6694
6761
|
// Worker not running — re-fork with resume. This is a NEW turn, so drop
|
|
@@ -6739,21 +6806,44 @@ async function handleThreadReply(data, ctx) {
|
|
|
6739
6806
|
// 待办池(queued)会话:CLI 从没起过,暂存的任务内容(queuedPrompt,已按角色包装好)
|
|
6740
6807
|
// 必须当首轮发出去——否则群里来的这第一条消息会顶替掉它、把用户分配的任务丢掉。
|
|
6741
6808
|
// 把暂存任务前置、用户这条消息拼在后面,一并作为首轮。forkWorker 随后清 queued。
|
|
6742
|
-
const
|
|
6809
|
+
const queuedDashboardTurn = !!(ds.session.queued && ds.session.queuedPrompt);
|
|
6810
|
+
const reforkContent = queuedDashboardTurn
|
|
6743
6811
|
? `${ds.session.queuedPrompt}\n\n${promptContent}`
|
|
6744
6812
|
: promptContent;
|
|
6745
|
-
const
|
|
6813
|
+
const queuedCodexAppText = ds.session.queuedCodexAppText ?? ds.pendingCodexAppText;
|
|
6814
|
+
const reforkCodexApp = mergeQueuedCodexAppTurn({
|
|
6815
|
+
queued: queuedDashboardTurn,
|
|
6816
|
+
queuedText: queuedCodexAppText,
|
|
6817
|
+
queuedMessageContext: ds.session.queuedCodexAppMessageContext ?? ds.pendingCodexAppMessageContext,
|
|
6818
|
+
currentText: parsed.content,
|
|
6819
|
+
currentMessageContext: codexAppMessageContext,
|
|
6820
|
+
});
|
|
6821
|
+
const builtReforkInput = buildReforkCliInput(ds, reforkContent, {
|
|
6746
6822
|
attachments,
|
|
6747
6823
|
mentions: parsed.mentions,
|
|
6748
|
-
cliId: dsBotCfgForFork.cliId,
|
|
6749
|
-
cliPathOverride: dsBotCfgForFork.cliPathOverride,
|
|
6824
|
+
cliId: ds.session.cliId ?? dsBotCfgForFork.cliId,
|
|
6825
|
+
cliPathOverride: ds.session.cliPathOverride ?? dsBotCfgForFork.cliPathOverride,
|
|
6750
6826
|
selfMention: { name: selfBot.botName, openId: selfBot.botOpenId },
|
|
6751
6827
|
sender: await getThreadSender(),
|
|
6828
|
+
substituteTrigger,
|
|
6829
|
+
codexAppText: reforkCodexApp.text,
|
|
6830
|
+
codexAppMessageContext: reforkCodexApp.messageContext,
|
|
6752
6831
|
});
|
|
6753
|
-
|
|
6754
|
-
|
|
6832
|
+
const wrappedInput = applyQueuedCodexAppLegacyFallback(builtReforkInput, {
|
|
6833
|
+
queued: queuedDashboardTurn,
|
|
6834
|
+
queuedText: queuedCodexAppText,
|
|
6835
|
+
});
|
|
6836
|
+
if (wrappedInput !== builtReforkInput && dsBotCfgForFork.codexAppCleanInput === true) {
|
|
6837
|
+
// Backlog sessions persisted before clean-input have no raw queued text.
|
|
6838
|
+
// Keep this activation entirely legacy: reforkContent already contains
|
|
6839
|
+
// queuedPrompt + the current reply, whereas a structured turn could only
|
|
6840
|
+
// contain the reply and would silently discard the original task.
|
|
6841
|
+
logger.warn(`[${tag(ds)}] Legacy queued dashboard task has no clean-input text; using the full legacy activation prompt`);
|
|
6842
|
+
}
|
|
6843
|
+
await noteTurnReceived(ds, parsed.messageId, parsed.content, await getThreadSender(), parsed.messageId, substituteTrigger ? SUBSTITUTE_RECEIVED_REACTION_EMOJI_TYPE : undefined);
|
|
6844
|
+
rememberLastCliInput(ds, promptContent, wrappedInput);
|
|
6755
6845
|
sessionStore.updateSession(ds.session);
|
|
6756
|
-
forkWorker(ds,
|
|
6846
|
+
forkWorker(ds, wrappedInput, ds.hasHistory);
|
|
6757
6847
|
}
|
|
6758
6848
|
}
|
|
6759
6849
|
/**
|
|
@@ -6878,7 +6968,7 @@ async function handleDocComment(ctx) {
|
|
|
6878
6968
|
const sender = ctx.authorOpenId ? await resolveSender(larkAppId, ctx.authorOpenId, 'user') : undefined;
|
|
6879
6969
|
const authorName = sender?.name || ctx.authorOpenId?.slice(0, 8) || '?';
|
|
6880
6970
|
const dsBotCfg = getBot(ds.larkAppId).config;
|
|
6881
|
-
const
|
|
6971
|
+
const promptInput = {
|
|
6882
6972
|
fileToken: sub.fileToken,
|
|
6883
6973
|
fileType: sub.fileType,
|
|
6884
6974
|
question: text,
|
|
@@ -6890,7 +6980,7 @@ async function handleDocComment(ctx) {
|
|
|
6890
6980
|
})),
|
|
6891
6981
|
brand: normalizeBrand(dsBotCfg.brand),
|
|
6892
6982
|
locale: loc,
|
|
6893
|
-
}
|
|
6983
|
+
};
|
|
6894
6984
|
// 记录本轮回评论的落点。两条路都要覆盖:
|
|
6895
6985
|
// • ds.docCommentTurns(内存,按 turnId)→ deliverFinalOutput「兜底」分流用
|
|
6896
6986
|
// • session.docCommentTargets(磁盘,per-turn map)→ `botmux send`「主回复」分流用
|
|
@@ -6910,25 +7000,21 @@ async function handleDocComment(ctx) {
|
|
|
6910
7000
|
const isBridge = !!ds.adoptedFrom;
|
|
6911
7001
|
if (!isBridge)
|
|
6912
7002
|
ensureSessionWhiteboard(ds);
|
|
6913
|
-
const
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
:
|
|
6918
|
-
|
|
6919
|
-
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
larkAppId,
|
|
6923
|
-
chatId: ds.session.chatId,
|
|
6924
|
-
whiteboardId: ds.session.whiteboardId,
|
|
6925
|
-
});
|
|
7003
|
+
const { promptContent, cliInput } = buildDocCommentTurnInput({
|
|
7004
|
+
ds,
|
|
7005
|
+
promptInput,
|
|
7006
|
+
botCliId: dsBotCfg.cliId,
|
|
7007
|
+
botCliPathOverride: dsBotCfg.cliPathOverride,
|
|
7008
|
+
botIdentity: { name: selfBot.botName, openId: selfBot.botOpenId },
|
|
7009
|
+
sender,
|
|
7010
|
+
mode: 'live',
|
|
7011
|
+
});
|
|
6926
7012
|
beginNewTurn(ds, text);
|
|
6927
7013
|
(ds.session.docCommentTargets ??= {})[turnId] = docTarget; // per-turn map,不覆盖其他并发轮
|
|
6928
|
-
rememberLastCliInput(ds, promptContent, msgContent);
|
|
6929
7014
|
sessionStore.updateSession(ds.session); // 先落盘,botmux send 子进程才读得到落点
|
|
6930
7015
|
await noteTurnReceived(ds, commentId, text, sender, turnId);
|
|
6931
|
-
ds
|
|
7016
|
+
rememberLastCliInput(ds, promptContent, cliInput);
|
|
7017
|
+
sendWorkerInput(ds, cliInput, turnId);
|
|
6932
7018
|
logger.info(`[${tag(ds)}] doc-comment turn injected (turn ${turnId.slice(0, 8)})`);
|
|
6933
7019
|
}
|
|
6934
7020
|
else {
|
|
@@ -6950,17 +7036,20 @@ async function handleDocComment(ctx) {
|
|
|
6950
7036
|
// the live-worker branch above (if (!isBridge) ensure…).
|
|
6951
7037
|
if (!ds.adoptedFrom)
|
|
6952
7038
|
ensureSessionWhiteboard(ds);
|
|
6953
|
-
const
|
|
6954
|
-
|
|
6955
|
-
|
|
6956
|
-
|
|
7039
|
+
const { promptContent, cliInput: wrappedInput } = buildDocCommentTurnInput({
|
|
7040
|
+
ds,
|
|
7041
|
+
promptInput,
|
|
7042
|
+
botCliId: dsBotCfg.cliId,
|
|
7043
|
+
botCliPathOverride: dsBotCfg.cliPathOverride,
|
|
7044
|
+
botIdentity: { name: selfBot.botName, openId: selfBot.botOpenId },
|
|
6957
7045
|
sender,
|
|
7046
|
+
mode: 'refork',
|
|
6958
7047
|
});
|
|
6959
7048
|
(ds.session.docCommentTargets ??= {})[turnId] = docTarget; // per-turn map,不覆盖其他并发轮
|
|
6960
|
-
rememberLastCliInput(ds, promptContent, wrappedPrompt);
|
|
6961
7049
|
await noteTurnReceived(ds, commentId, text, sender, turnId);
|
|
7050
|
+
rememberLastCliInput(ds, promptContent, wrappedInput);
|
|
6962
7051
|
sessionStore.updateSession(ds.session);
|
|
6963
|
-
forkWorker(ds,
|
|
7052
|
+
forkWorker(ds, wrappedInput, { resume: ds.hasHistory, turnId });
|
|
6964
7053
|
}
|
|
6965
7054
|
return true;
|
|
6966
7055
|
}
|
|
@@ -7133,6 +7222,17 @@ function dashboardUrlForReport() {
|
|
|
7133
7222
|
}
|
|
7134
7223
|
}
|
|
7135
7224
|
export async function startDaemon(botIndex) {
|
|
7225
|
+
// Repair a shared tmux server polluted by an older botmux immediately on
|
|
7226
|
+
// daemon startup. This must not depend on restoring/spawning a bmx-* session:
|
|
7227
|
+
// a user-held tmux server can outlive every botmux pane and still leak stale
|
|
7228
|
+
// routing/profile env into newly-created user panes.
|
|
7229
|
+
const tmuxEnvScrub = scrubTmuxServerGlobalEnv();
|
|
7230
|
+
if (tmuxEnvScrub.removed.length > 0) {
|
|
7231
|
+
logger.info(`[tmux] scrubbed ${tmuxEnvScrub.removed.length} server-global env key(s): ${tmuxEnvScrub.removed.join(', ')}`);
|
|
7232
|
+
}
|
|
7233
|
+
if (tmuxEnvScrub.failed.length > 0) {
|
|
7234
|
+
logger.warn(`[tmux] failed to scrub server-global env key(s): ${tmuxEnvScrub.failed.join(', ')}`);
|
|
7235
|
+
}
|
|
7136
7236
|
// 首次启动时后台尝试安装 CJK 字体(Debian/Ubuntu),避免截图中文显示豆腐块。
|
|
7137
7237
|
// 不阻塞:首张截图可能仍是豆腐块,装完重启 daemon 即可正常。
|
|
7138
7238
|
ensureCjkFontsInstalled();
|