botmux 2.94.0 → 2.96.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 +4 -4
- package/README.md +3 -3
- package/dist/adapters/backend/tmux-backend.d.ts +18 -2
- package/dist/adapters/backend/tmux-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-backend.js +44 -11
- package/dist/adapters/backend/tmux-backend.js.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.js +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.js.map +1 -1
- package/dist/adapters/backend/types.d.ts +8 -0
- package/dist/adapters/backend/types.d.ts.map +1 -1
- package/dist/adapters/backend/types.js.map +1 -1
- package/dist/adapters/backend/zellij-backend.js +1 -1
- package/dist/adapters/backend/zellij-backend.js.map +1 -1
- package/dist/adapters/cli/kimi.d.ts +4 -0
- package/dist/adapters/cli/kimi.d.ts.map +1 -0
- package/dist/adapters/cli/kimi.js +54 -0
- package/dist/adapters/cli/kimi.js.map +1 -0
- package/dist/adapters/cli/registry.d.ts +2 -1
- package/dist/adapters/cli/registry.d.ts.map +1 -1
- package/dist/adapters/cli/registry.js +6 -20
- package/dist/adapters/cli/registry.js.map +1 -1
- package/dist/adapters/cli/types.d.ts +1 -1
- package/dist/adapters/cli/types.d.ts.map +1 -1
- package/dist/adapters/hook-installer.d.ts.map +1 -1
- package/dist/adapters/hook-installer.js +138 -28
- package/dist/adapters/hook-installer.js.map +1 -1
- package/dist/bot-registry.d.ts +101 -4
- package/dist/bot-registry.d.ts.map +1 -1
- package/dist/bot-registry.js +192 -3
- package/dist/bot-registry.js.map +1 -1
- package/dist/cli/stdin-encoding.d.ts +21 -0
- package/dist/cli/stdin-encoding.d.ts.map +1 -1
- package/dist/cli/stdin-encoding.js +37 -0
- package/dist/cli/stdin-encoding.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +27 -4
- package/dist/cli.js.map +1 -1
- package/dist/core/ask-hook/opencode.d.ts +15 -17
- package/dist/core/ask-hook/opencode.d.ts.map +1 -1
- package/dist/core/ask-hook/opencode.js +17 -19
- package/dist/core/ask-hook/opencode.js.map +1 -1
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +29 -3
- 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 +282 -5
- package/dist/core/dashboard-ipc-server.js.map +1 -1
- package/dist/core/dashboard-rows.d.ts +2 -0
- package/dist/core/dashboard-rows.d.ts.map +1 -1
- package/dist/core/dashboard-rows.js +2 -0
- package/dist/core/dashboard-rows.js.map +1 -1
- package/dist/core/session-discovery.d.ts +9 -0
- package/dist/core/session-discovery.d.ts.map +1 -1
- package/dist/core/session-discovery.js +24 -0
- 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 +7 -6
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/terminal-url.d.ts.map +1 -1
- package/dist/core/terminal-url.js +15 -0
- package/dist/core/terminal-url.js.map +1 -1
- package/dist/core/trigger-session.d.ts.map +1 -1
- package/dist/core/trigger-session.js +101 -9
- package/dist/core/trigger-session.js.map +1 -1
- package/dist/core/types.d.ts +16 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/core/worker-pool.d.ts +1 -1
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +69 -11
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +14 -11
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/aggregator.d.ts +5 -0
- package/dist/dashboard/aggregator.d.ts.map +1 -1
- package/dist/dashboard/aggregator.js +7 -0
- package/dist/dashboard/aggregator.js.map +1 -1
- package/dist/dashboard/bot-payload.d.ts +8 -0
- package/dist/dashboard/bot-payload.d.ts.map +1 -1
- package/dist/dashboard/bot-payload.js +8 -1
- package/dist/dashboard/bot-payload.js.map +1 -1
- package/dist/dashboard/connector-api.d.ts.map +1 -1
- package/dist/dashboard/connector-api.js +14 -3
- package/dist/dashboard/connector-api.js.map +1 -1
- package/dist/dashboard/session-cleanup.d.ts +1 -0
- package/dist/dashboard/session-cleanup.d.ts.map +1 -1
- package/dist/dashboard/session-cleanup.js +2 -0
- package/dist/dashboard/session-cleanup.js.map +1 -1
- package/dist/dashboard/settings-write-applier.d.ts +2 -1
- package/dist/dashboard/settings-write-applier.d.ts.map +1 -1
- package/dist/dashboard/settings-write-applier.js +7 -0
- package/dist/dashboard/settings-write-applier.js.map +1 -1
- package/dist/dashboard/trigger-api.d.ts +4 -0
- package/dist/dashboard/trigger-api.d.ts.map +1 -1
- package/dist/dashboard/trigger-api.js +20 -0
- package/dist/dashboard/trigger-api.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 +352 -37
- package/dist/dashboard/web/bot-defaults.js.map +1 -1
- package/dist/dashboard/web/connectors.d.ts +11 -0
- package/dist/dashboard/web/connectors.d.ts.map +1 -1
- package/dist/dashboard/web/connectors.js +45 -1
- package/dist/dashboard/web/connectors.js.map +1 -1
- package/dist/dashboard/web/groups.d.ts +7 -0
- package/dist/dashboard/web/groups.d.ts.map +1 -1
- package/dist/dashboard/web/groups.js +62 -15
- package/dist/dashboard/web/groups.js.map +1 -1
- package/dist/dashboard/web/i18n.d.ts.map +1 -1
- package/dist/dashboard/web/i18n.js +82 -4
- 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 +149 -5
- package/dist/dashboard/web/sessions.js.map +1 -1
- package/dist/dashboard/web/settings.d.ts.map +1 -1
- package/dist/dashboard/web/settings.js +11 -0
- package/dist/dashboard/web/settings.js.map +1 -1
- package/dist/dashboard/web/whiteboards.d.ts.map +1 -1
- package/dist/dashboard/web/whiteboards.js +14 -5
- package/dist/dashboard/web/whiteboards.js.map +1 -1
- package/dist/dashboard/webhook-routes.d.ts.map +1 -1
- package/dist/dashboard/webhook-routes.js +126 -6
- package/dist/dashboard/webhook-routes.js.map +1 -1
- package/dist/dashboard-web/app.js +814 -725
- package/dist/dashboard-web/apple-touch-icon.png +0 -0
- package/dist/dashboard-web/favicon.png +0 -0
- package/dist/dashboard-web/index.html +2 -0
- package/dist/dashboard-web/style.css +47 -0
- package/dist/dashboard.js +247 -16
- package/dist/dashboard.js.map +1 -1
- package/dist/global-config.d.ts +10 -0
- package/dist/global-config.d.ts.map +1 -1
- package/dist/global-config.js +8 -0
- package/dist/global-config.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +21 -0
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +21 -0
- package/dist/i18n/zh.js.map +1 -1
- package/dist/im/lark/card-builder.d.ts.map +1 -1
- package/dist/im/lark/card-builder.js +1 -0
- package/dist/im/lark/card-builder.js.map +1 -1
- package/dist/im/lark/client.d.ts +12 -0
- package/dist/im/lark/client.d.ts.map +1 -1
- package/dist/im/lark/client.js +48 -21
- package/dist/im/lark/client.js.map +1 -1
- package/dist/im/lark/event-dispatcher.d.ts +15 -1
- package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
- package/dist/im/lark/event-dispatcher.js +199 -16
- package/dist/im/lark/event-dispatcher.js.map +1 -1
- package/dist/im/lark/grant-command.js +4 -4
- package/dist/im/lark/grant-command.js.map +1 -1
- package/dist/im/lark/message-parser.d.ts +40 -1
- package/dist/im/lark/message-parser.d.ts.map +1 -1
- package/dist/im/lark/message-parser.js +37 -2
- package/dist/im/lark/message-parser.js.map +1 -1
- package/dist/im/lark/summary-command.d.ts +19 -0
- package/dist/im/lark/summary-command.d.ts.map +1 -0
- package/dist/im/lark/summary-command.js +276 -0
- package/dist/im/lark/summary-command.js.map +1 -0
- package/dist/mir-local-runtime.d.ts +40 -0
- package/dist/mir-local-runtime.d.ts.map +1 -1
- package/dist/mir-local-runtime.js +246 -52
- package/dist/mir-local-runtime.js.map +1 -1
- package/dist/mir-runner.js +26 -1
- package/dist/mir-runner.js.map +1 -1
- package/dist/platform/binding.d.ts +6 -0
- package/dist/platform/binding.d.ts.map +1 -1
- package/dist/platform/binding.js +17 -0
- package/dist/platform/binding.js.map +1 -1
- package/dist/platform/tunnel-client.d.ts +2 -0
- package/dist/platform/tunnel-client.d.ts.map +1 -1
- package/dist/platform/tunnel-client.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 +2 -2
- package/dist/services/card-prefs-store.d.ts.map +1 -1
- package/dist/services/card-prefs-store.js +5 -5
- package/dist/services/card-prefs-store.js.map +1 -1
- package/dist/services/chat-reply-mode-store.d.ts +6 -4
- package/dist/services/chat-reply-mode-store.d.ts.map +1 -1
- package/dist/services/chat-reply-mode-store.js +6 -4
- package/dist/services/chat-reply-mode-store.js.map +1 -1
- package/dist/services/oncall-store.d.ts +25 -0
- package/dist/services/oncall-store.d.ts.map +1 -1
- package/dist/services/oncall-store.js +56 -0
- package/dist/services/oncall-store.js.map +1 -1
- package/dist/services/pi-transcript.d.ts +19 -0
- package/dist/services/pi-transcript.d.ts.map +1 -0
- package/dist/services/pi-transcript.js +222 -0
- package/dist/services/pi-transcript.js.map +1 -0
- package/dist/services/summary-range-store.d.ts +21 -0
- package/dist/services/summary-range-store.d.ts.map +1 -0
- package/dist/services/summary-range-store.js +89 -0
- package/dist/services/summary-range-store.js.map +1 -0
- package/dist/services/transcript-resolver.d.ts.map +1 -1
- package/dist/services/transcript-resolver.js +21 -4
- package/dist/services/transcript-resolver.js.map +1 -1
- package/dist/services/trigger-types.d.ts +14 -2
- package/dist/services/trigger-types.d.ts.map +1 -1
- package/dist/services/trigger-types.js +15 -1
- package/dist/services/trigger-types.js.map +1 -1
- package/dist/setup/bot-config-editor.d.ts +7 -0
- package/dist/setup/bot-config-editor.d.ts.map +1 -1
- package/dist/setup/bot-config-editor.js +35 -0
- package/dist/setup/bot-config-editor.js.map +1 -1
- package/dist/types.d.ts +21 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/executable.d.ts +3 -0
- package/dist/utils/executable.d.ts.map +1 -0
- package/dist/utils/executable.js +24 -0
- package/dist/utils/executable.js.map +1 -0
- package/dist/utils/terminal-favicon.d.ts +2 -0
- package/dist/utils/terminal-favicon.d.ts.map +1 -0
- package/dist/utils/terminal-favicon.js +5 -0
- package/dist/utils/terminal-favicon.js.map +1 -0
- package/dist/worker.js +211 -12
- package/dist/worker.js.map +1 -1
- package/dist/workflows/definition.d.ts +8 -8
- package/dist/workflows/events/payloads.d.ts +10 -10
- package/dist/workflows/events/schema.d.ts +28 -28
- package/dist/workflows/v3/bot-resolve.d.ts +1 -1
- package/dist/workflows/v3/bot-resolve.d.ts.map +1 -1
- package/dist/workflows/v3/bot-resolve.js +2 -1
- package/dist/workflows/v3/bot-resolve.js.map +1 -1
- package/dist/workflows/v3/cli-run.js +2 -2
- package/dist/workflows/v3/cli-run.js.map +1 -1
- package/package.json +2 -2
|
@@ -18,10 +18,11 @@ import * as observedBotsStore from '../services/observed-bots-store.js';
|
|
|
18
18
|
import { getDeploymentIdentity } from '../services/deployment-identity.js';
|
|
19
19
|
import * as grantPrefsStore from '../services/grant-prefs-store.js';
|
|
20
20
|
import { findConfigField, applyConfigField, coerceConfigValue } from '../services/bot-config-store.js';
|
|
21
|
+
import { summaryRangeFromBotConfig, updateDashboardSummaryRange } from '../services/summary-range-store.js';
|
|
21
22
|
import { config } from '../config.js';
|
|
22
23
|
import { computeSandboxDiff, applySandboxDiff } from '../services/sandbox-land.js';
|
|
23
24
|
import { buildSafeInsightConversation, buildSafeInsightOverview, buildSafeInsightReport, buildSafeInsightTurnDetail } from '../services/insight/report.js';
|
|
24
|
-
import { readRawConfig, findEntryIndex, requireConfigPath } from '../services/config-store.js';
|
|
25
|
+
import { readRawConfig, findEntryIndex, requireConfigPath, rmwBotEntry } from '../services/config-store.js';
|
|
25
26
|
import { setDefaultLocale, localeForBot, t } from '../i18n/index.js';
|
|
26
27
|
import { isLocale } from '../i18n/types.js';
|
|
27
28
|
import { readGlobalConfig } from '../global-config.js';
|
|
@@ -44,6 +45,7 @@ import { deleteRoleProfileEntry, deleteRoleProfileIfEmpty, isValidRoleProfileId,
|
|
|
44
45
|
import { triggerSessionTurn } from './trigger-session.js';
|
|
45
46
|
import { triggerWorkflowFromEnvelope } from '../workflows/trigger-from-envelope.js';
|
|
46
47
|
import { validateTriggerRequest } from '../services/trigger-types.js';
|
|
48
|
+
import { resolveCliSelection, selectionKeyForBot } from '../setup/cli-selection.js';
|
|
47
49
|
// Workflow runner is wired by the daemon (it owns the heavy triggerWorkflowRun
|
|
48
50
|
// deps). Until set, workflow-targeted triggers report not-implemented.
|
|
49
51
|
let workflowRunner = null;
|
|
@@ -209,6 +211,46 @@ ipcRoute('POST', '/api/sessions/:sessionId/restart', (_req, res, params) => {
|
|
|
209
211
|
function findSessionRecord(sessionId) {
|
|
210
212
|
return findActiveBySessionId(sessionId)?.session ?? sessionStore.getSession(sessionId);
|
|
211
213
|
}
|
|
214
|
+
function buildAsyncTriggerLookupResponse(sessionId, triggerId) {
|
|
215
|
+
const ds = findActiveBySessionId(sessionId);
|
|
216
|
+
if (!ds) {
|
|
217
|
+
return { ok: false, errorCode: 'session_not_found', error: `active session not found: ${sessionId}` };
|
|
218
|
+
}
|
|
219
|
+
const resolvedTriggerId = triggerId || ds.latestAsyncTriggerId;
|
|
220
|
+
if (!resolvedTriggerId) {
|
|
221
|
+
return { ok: false, errorCode: 'bad_request', error: 'no async trigger recorded for this session' };
|
|
222
|
+
}
|
|
223
|
+
const state = ds.asyncTriggerResults?.get(resolvedTriggerId);
|
|
224
|
+
if (!state) {
|
|
225
|
+
return { ok: false, errorCode: 'bad_request', error: `async trigger not found for session: ${resolvedTriggerId}` };
|
|
226
|
+
}
|
|
227
|
+
if (state.status === 'completed') {
|
|
228
|
+
return {
|
|
229
|
+
ok: true,
|
|
230
|
+
triggerId: resolvedTriggerId,
|
|
231
|
+
action: 'completed',
|
|
232
|
+
target: { kind: 'turn', sessionId, chatId: ds.chatId },
|
|
233
|
+
output: state.content ? { content: state.content } : undefined,
|
|
234
|
+
async: {
|
|
235
|
+
status: 'completed',
|
|
236
|
+
sessionId,
|
|
237
|
+
completedAt: state.completedAt ? new Date(state.completedAt).toISOString() : undefined,
|
|
238
|
+
},
|
|
239
|
+
message: 'async trigger completed',
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
return {
|
|
243
|
+
ok: true,
|
|
244
|
+
triggerId: resolvedTriggerId,
|
|
245
|
+
action: 'queued',
|
|
246
|
+
target: { kind: 'turn', sessionId, chatId: ds.chatId },
|
|
247
|
+
async: {
|
|
248
|
+
status: 'pending',
|
|
249
|
+
sessionId,
|
|
250
|
+
},
|
|
251
|
+
message: 'async trigger pending',
|
|
252
|
+
};
|
|
253
|
+
}
|
|
212
254
|
// 看板放置:dashboard 看板视图拖拽卡片后持久化列 + 列内排序位置。
|
|
213
255
|
// 改完广播 session.update,所有打开的 dashboard 实时同步。
|
|
214
256
|
ipcRoute('POST', '/api/sessions/:sessionId/board', async (req, res, params) => {
|
|
@@ -352,6 +394,17 @@ ipcRoute('GET', '/api/sessions/:sessionId/history', async (req, res, params) =>
|
|
|
352
394
|
jsonRes(res, 502, { ok: false, error: String(err?.message ?? err) });
|
|
353
395
|
}
|
|
354
396
|
});
|
|
397
|
+
ipcRoute('GET', '/api/sessions/:sessionId/trigger-result', (req, res, params) => {
|
|
398
|
+
const url = new URL(req.url ?? '/', 'http://localhost');
|
|
399
|
+
const triggerId = url.searchParams.get('triggerId') ?? undefined;
|
|
400
|
+
const result = buildAsyncTriggerLookupResponse(params.sessionId, triggerId);
|
|
401
|
+
const status = result.ok
|
|
402
|
+
? 200
|
|
403
|
+
: result.errorCode === 'session_not_found'
|
|
404
|
+
? 404
|
|
405
|
+
: 400;
|
|
406
|
+
jsonRes(res, status, result);
|
|
407
|
+
});
|
|
355
408
|
// 会话 insight:只读解析本会话的 transcript,产出动作 span / 失败聚合 / 规则建议
|
|
356
409
|
// (SafeInsightReport)。底层 services/insight 已做 fail-closed 脱敏投影——raw 命令
|
|
357
410
|
// 与输出永不进结构。detail=summary 只返聚合+建议(/insight 卡片、抽屉概览用);
|
|
@@ -487,6 +540,33 @@ ipcRoute('POST', '/api/sessions/:sessionId/rename', async (req, res, params) =>
|
|
|
487
540
|
});
|
|
488
541
|
jsonRes(res, 200, { ok: true, title });
|
|
489
542
|
});
|
|
543
|
+
// 会话锁定:保护被锁定会话不被 dashboard「清理空闲」批量关闭。锁定是会话元数据,
|
|
544
|
+
// 不影响用户显式点击关闭/批量关闭,避免把会话变成不可管理状态。
|
|
545
|
+
ipcRoute('POST', '/api/sessions/:sessionId/lock', async (req, res, params) => {
|
|
546
|
+
let body;
|
|
547
|
+
try {
|
|
548
|
+
body = await readJsonBody(req);
|
|
549
|
+
}
|
|
550
|
+
catch {
|
|
551
|
+
return jsonRes(res, 400, { ok: false, error: 'bad_json' });
|
|
552
|
+
}
|
|
553
|
+
if (typeof body.locked !== 'boolean')
|
|
554
|
+
return jsonRes(res, 400, { ok: false, error: 'bad_locked' });
|
|
555
|
+
const session = findSessionRecord(params.sessionId);
|
|
556
|
+
if (!session)
|
|
557
|
+
return jsonRes(res, 404, { ok: false, error: 'session_not_found' });
|
|
558
|
+
if (body.locked)
|
|
559
|
+
session.locked = true;
|
|
560
|
+
else
|
|
561
|
+
delete session.locked;
|
|
562
|
+
sessionStore.updateSession(session);
|
|
563
|
+
const locked = !!session.locked;
|
|
564
|
+
dashboardEventBus.publish({
|
|
565
|
+
type: 'session.update',
|
|
566
|
+
body: { sessionId: params.sessionId, patch: { locked } },
|
|
567
|
+
});
|
|
568
|
+
jsonRes(res, 200, { ok: true, locked });
|
|
569
|
+
});
|
|
490
570
|
/**
|
|
491
571
|
* Mint the WRITABLE web-terminal link for a live session — the dashboard
|
|
492
572
|
* counterpart to the Lark card's "🔑 获取操作链接" button. Returns the URL with
|
|
@@ -863,9 +943,11 @@ ipcRoute('POST', '/api/trigger', async (req, res) => {
|
|
|
863
943
|
? 403
|
|
864
944
|
: result.errorCode === 'session_not_found'
|
|
865
945
|
? 404
|
|
866
|
-
: result.errorCode === '
|
|
867
|
-
?
|
|
868
|
-
:
|
|
946
|
+
: result.errorCode === 'wait_timeout'
|
|
947
|
+
? 504
|
|
948
|
+
: result.errorCode === 'target_required' || result.errorCode === 'bad_request'
|
|
949
|
+
? 400
|
|
950
|
+
: 500;
|
|
869
951
|
return jsonRes(res, status, result);
|
|
870
952
|
}
|
|
871
953
|
catch (e) {
|
|
@@ -1180,6 +1262,18 @@ ipcRoute('GET', '/api/bot-default-oncall', async (_req, res) => {
|
|
|
1180
1262
|
p2pMode = 'chat';
|
|
1181
1263
|
}
|
|
1182
1264
|
catch { /* default thread */ }
|
|
1265
|
+
let cliId = '';
|
|
1266
|
+
let wrapperCli = null;
|
|
1267
|
+
let model = null;
|
|
1268
|
+
let agentSelectionKey = '';
|
|
1269
|
+
try {
|
|
1270
|
+
const cfg = getBot(cachedLarkAppId).config;
|
|
1271
|
+
cliId = cfg.cliId;
|
|
1272
|
+
wrapperCli = typeof cfg.wrapperCli === 'string' && cfg.wrapperCli.trim() ? cfg.wrapperCli : null;
|
|
1273
|
+
model = typeof cfg.model === 'string' && cfg.model.trim() ? cfg.model : null;
|
|
1274
|
+
agentSelectionKey = selectionKeyForBot(cliId, wrapperCli ?? undefined);
|
|
1275
|
+
}
|
|
1276
|
+
catch { /* no registered bot */ }
|
|
1183
1277
|
let maxLiveWorkers = null;
|
|
1184
1278
|
try {
|
|
1185
1279
|
const m = getBot(cachedLarkAppId).config.maxLiveWorkers;
|
|
@@ -1205,10 +1299,25 @@ ipcRoute('GET', '/api/bot-default-oncall', async (_req, res) => {
|
|
|
1205
1299
|
env = JSON.stringify(e, null, 2);
|
|
1206
1300
|
}
|
|
1207
1301
|
catch { /* none */ }
|
|
1302
|
+
// defaultWorkingDir — the "仅默认目录" mode source. Mutually exclusive with
|
|
1303
|
+
// defaultOncall in the dashboard 3-way selector; the frontend derives the
|
|
1304
|
+
// current mode from (defaultOncall.enabled ? oncall : defaultWorkingDir ? default : off).
|
|
1305
|
+
let defaultWorkingDir = null;
|
|
1306
|
+
try {
|
|
1307
|
+
const d = getBot(cachedLarkAppId).config.defaultWorkingDir;
|
|
1308
|
+
if (typeof d === 'string' && d.trim())
|
|
1309
|
+
defaultWorkingDir = d;
|
|
1310
|
+
}
|
|
1311
|
+
catch { /* none */ }
|
|
1208
1312
|
jsonRes(res, 200, {
|
|
1209
1313
|
larkAppId: cachedLarkAppId,
|
|
1210
1314
|
botName: getBotName(),
|
|
1315
|
+
cliId,
|
|
1316
|
+
wrapperCli,
|
|
1317
|
+
model,
|
|
1318
|
+
agentSelectionKey,
|
|
1211
1319
|
defaultOncall: defaultOncall ?? { enabled: false, workingDir: '', since: 0 },
|
|
1320
|
+
defaultWorkingDir,
|
|
1212
1321
|
autoboundChatCount: autoboundChats.length,
|
|
1213
1322
|
brandLabel: brandStore.getBotBrandLabel(cachedLarkAppId) ?? null,
|
|
1214
1323
|
sandbox: sandboxStore.getBotSandbox(cachedLarkAppId),
|
|
@@ -1229,7 +1338,9 @@ ipcRoute('GET', '/api/bot-default-oncall', async (_req, res) => {
|
|
|
1229
1338
|
p2pMode,
|
|
1230
1339
|
maxLiveWorkers,
|
|
1231
1340
|
startupCommands,
|
|
1341
|
+
launchShell: getBot(cachedLarkAppId).config.launchShell ?? '',
|
|
1232
1342
|
env,
|
|
1343
|
+
summaryRange: summaryRangeFromBotConfig(getBot(cachedLarkAppId).config),
|
|
1233
1344
|
skills: getBot(cachedLarkAppId).config.skills ?? null,
|
|
1234
1345
|
});
|
|
1235
1346
|
});
|
|
@@ -1267,7 +1378,7 @@ ipcRoute('PUT', '/api/bot-card-prefs', async (req, res) => {
|
|
|
1267
1378
|
if (m)
|
|
1268
1379
|
patch.regularGroupReplyMode = m;
|
|
1269
1380
|
}
|
|
1270
|
-
if (body.regularGroupMentionMode === 'always' || body.regularGroupMentionMode === 'topic' || body.regularGroupMentionMode === 'never') {
|
|
1381
|
+
if (body.regularGroupMentionMode === 'always' || body.regularGroupMentionMode === 'topic' || body.regularGroupMentionMode === 'never' || body.regularGroupMentionMode === 'ambient') {
|
|
1271
1382
|
patch.regularGroupMentionMode = body.regularGroupMentionMode;
|
|
1272
1383
|
}
|
|
1273
1384
|
if (body.docSubscribeDefaultMode === 'mention-only' || body.docSubscribeDefaultMode === 'all') {
|
|
@@ -1280,6 +1391,41 @@ ipcRoute('PUT', '/api/bot-card-prefs', async (req, res) => {
|
|
|
1280
1391
|
return jsonRes(res, 400, { ok: false, error: r.reason });
|
|
1281
1392
|
jsonRes(res, 200, { ok: true, ...r.prefs });
|
|
1282
1393
|
});
|
|
1394
|
+
// Per-bot explicit `/summary` history range. Body `{ limit, sinceHours }`.
|
|
1395
|
+
ipcRoute('PUT', '/api/bot-summary-range', async (req, res) => {
|
|
1396
|
+
if (!cachedLarkAppId)
|
|
1397
|
+
return jsonRes(res, 503, { error: 'larkAppId_not_set' });
|
|
1398
|
+
let raw;
|
|
1399
|
+
try {
|
|
1400
|
+
raw = await readJsonBody(req);
|
|
1401
|
+
}
|
|
1402
|
+
catch {
|
|
1403
|
+
return jsonRes(res, 400, { ok: false, error: 'bad_json' });
|
|
1404
|
+
}
|
|
1405
|
+
const r = await updateDashboardSummaryRange(cachedLarkAppId, raw);
|
|
1406
|
+
if (!r.ok)
|
|
1407
|
+
return jsonRes(res, 400, { ok: false, error: r.reason });
|
|
1408
|
+
jsonRes(res, 200, { ok: true, summaryRange: r.summaryRange });
|
|
1409
|
+
});
|
|
1410
|
+
// Backward-compatible dashboard endpoint from the short-lived keyword-trigger UI.
|
|
1411
|
+
ipcRoute('PUT', '/api/bot-summary-trigger', async (req, res) => {
|
|
1412
|
+
if (!cachedLarkAppId)
|
|
1413
|
+
return jsonRes(res, 503, { error: 'larkAppId_not_set' });
|
|
1414
|
+
let raw;
|
|
1415
|
+
try {
|
|
1416
|
+
raw = await readJsonBody(req);
|
|
1417
|
+
}
|
|
1418
|
+
catch {
|
|
1419
|
+
return jsonRes(res, 400, { ok: false, error: 'bad_json' });
|
|
1420
|
+
}
|
|
1421
|
+
const body = raw && typeof raw === 'object' && !Array.isArray(raw)
|
|
1422
|
+
? { limit: raw.limit, sinceHours: raw.sinceHours }
|
|
1423
|
+
: raw;
|
|
1424
|
+
const r = await updateDashboardSummaryRange(cachedLarkAppId, body);
|
|
1425
|
+
if (!r.ok)
|
|
1426
|
+
return jsonRes(res, 400, { ok: false, error: r.reason });
|
|
1427
|
+
jsonRes(res, 200, { ok: true, summaryRange: r.summaryRange });
|
|
1428
|
+
});
|
|
1283
1429
|
// Per-bot 授权偏好。Body 任意子集:
|
|
1284
1430
|
// • restrictGrantCommands: boolean — 限制被授权人只能纯对话
|
|
1285
1431
|
// • autoGrantRequestCards: boolean — 未授权 @ 被挡住时是否发 grant 申请卡
|
|
@@ -1335,6 +1481,60 @@ ipcRoute('PUT', '/api/bot-brand-label', async (req, res) => {
|
|
|
1335
1481
|
return jsonRes(res, 400, { ok: false, error: r.reason });
|
|
1336
1482
|
jsonRes(res, 200, { ok: true, brandLabel: r.brandLabel });
|
|
1337
1483
|
});
|
|
1484
|
+
// Per-bot agent launch settings. Body `{ cliId, model }` where `cliId` is the
|
|
1485
|
+
// dashboard selection key (plain adapter id or a wrapper option such as
|
|
1486
|
+
// `ttadk-x-codex`). Changes affect the next spawned CLI session.
|
|
1487
|
+
ipcRoute('PUT', '/api/bot-agent', async (req, res) => {
|
|
1488
|
+
if (!cachedLarkAppId)
|
|
1489
|
+
return jsonRes(res, 503, { error: 'larkAppId_not_set' });
|
|
1490
|
+
let body;
|
|
1491
|
+
try {
|
|
1492
|
+
body = await readJsonBody(req);
|
|
1493
|
+
}
|
|
1494
|
+
catch {
|
|
1495
|
+
return jsonRes(res, 400, { ok: false, error: 'bad_json' });
|
|
1496
|
+
}
|
|
1497
|
+
const key = typeof body.cliId === 'string' && body.cliId.trim() ? body.cliId.trim() : '';
|
|
1498
|
+
if (!key)
|
|
1499
|
+
return jsonRes(res, 400, { ok: false, error: 'cli_required' });
|
|
1500
|
+
let selected;
|
|
1501
|
+
try {
|
|
1502
|
+
selected = resolveCliSelection(key);
|
|
1503
|
+
}
|
|
1504
|
+
catch (err) {
|
|
1505
|
+
return jsonRes(res, 400, { ok: false, error: 'invalid_cli', message: err?.message ?? String(err) });
|
|
1506
|
+
}
|
|
1507
|
+
const model = typeof body.model === 'string' ? body.model.trim() : '';
|
|
1508
|
+
const r = await rmwBotEntry(cachedLarkAppId, (entry) => {
|
|
1509
|
+
entry.cliId = selected.cliId;
|
|
1510
|
+
if (selected.wrapperCli)
|
|
1511
|
+
entry.wrapperCli = selected.wrapperCli;
|
|
1512
|
+
else
|
|
1513
|
+
delete entry.wrapperCli;
|
|
1514
|
+
if (model)
|
|
1515
|
+
entry.model = model;
|
|
1516
|
+
else
|
|
1517
|
+
delete entry.model;
|
|
1518
|
+
return { write: true, result: null };
|
|
1519
|
+
});
|
|
1520
|
+
if (!r.ok)
|
|
1521
|
+
return jsonRes(res, 400, { ok: false, error: r.reason });
|
|
1522
|
+
const bot = getBot(cachedLarkAppId);
|
|
1523
|
+
bot.config.cliId = selected.cliId;
|
|
1524
|
+
if (selected.wrapperCli)
|
|
1525
|
+
bot.config.wrapperCli = selected.wrapperCli;
|
|
1526
|
+
else
|
|
1527
|
+
bot.config.wrapperCli = undefined;
|
|
1528
|
+
bot.config.model = model || undefined;
|
|
1529
|
+
const selectionKey = selectionKeyForBot(selected.cliId, selected.wrapperCli);
|
|
1530
|
+
jsonRes(res, 200, {
|
|
1531
|
+
ok: true,
|
|
1532
|
+
cliId: selected.cliId,
|
|
1533
|
+
wrapperCli: selected.wrapperCli ?? null,
|
|
1534
|
+
model: model || null,
|
|
1535
|
+
selectionKey,
|
|
1536
|
+
});
|
|
1537
|
+
});
|
|
1338
1538
|
// Per-bot 私聊单聊模式 p2pMode。Body `{ p2pMode: 'chat' | 'thread' }`:
|
|
1339
1539
|
// • 'chat' → 私聊走扁平连续 chat-scope 会话
|
|
1340
1540
|
// • 'thread'(默认) → 清回每条 DM 独立 thread-scope 会话
|
|
@@ -1392,6 +1592,38 @@ ipcRoute('PUT', '/api/bot-startup-commands', async (req, res) => {
|
|
|
1392
1592
|
return jsonRes(res, 400, { ok: false, error: r.reason });
|
|
1393
1593
|
jsonRes(res, 200, { ok: true, startupCommands: (value ?? []).join('\n') });
|
|
1394
1594
|
});
|
|
1595
|
+
// Per-bot launch-shell override launchShell。Body `{ launchShell: string }`:
|
|
1596
|
+
// 空字符串=清除(回 $SHELL)。走 applyConfigField(与 /config launchShell 同一写盘
|
|
1597
|
+
// + 内存热更新路径),next-session 生效(下个会话起用新 shell 启动 CLI)。
|
|
1598
|
+
ipcRoute('PUT', '/api/bot-launch-shell', async (req, res) => {
|
|
1599
|
+
if (!cachedLarkAppId)
|
|
1600
|
+
return jsonRes(res, 503, { error: 'larkAppId_not_set' });
|
|
1601
|
+
let body;
|
|
1602
|
+
try {
|
|
1603
|
+
body = await readJsonBody(req);
|
|
1604
|
+
}
|
|
1605
|
+
catch {
|
|
1606
|
+
return jsonRes(res, 400, { ok: false, error: 'bad_json' });
|
|
1607
|
+
}
|
|
1608
|
+
const spec = findConfigField('launchShell');
|
|
1609
|
+
if (!spec)
|
|
1610
|
+
return jsonRes(res, 500, { ok: false, error: 'spec_missing' });
|
|
1611
|
+
const raw = typeof body.launchShell === 'string' ? body.launchShell : '';
|
|
1612
|
+
let value;
|
|
1613
|
+
if (!raw.trim()) {
|
|
1614
|
+
value = null; // 清除 → 回 $SHELL
|
|
1615
|
+
}
|
|
1616
|
+
else {
|
|
1617
|
+
const coerced = coerceConfigValue(spec, raw);
|
|
1618
|
+
if (!coerced.ok)
|
|
1619
|
+
return jsonRes(res, 400, { ok: false, error: coerced.reason });
|
|
1620
|
+
value = coerced.value;
|
|
1621
|
+
}
|
|
1622
|
+
const r = await applyConfigField(cachedLarkAppId, spec, value);
|
|
1623
|
+
if (!r.ok)
|
|
1624
|
+
return jsonRes(res, 400, { ok: false, error: r.reason });
|
|
1625
|
+
jsonRes(res, 200, { ok: true, launchShell: value ?? '' });
|
|
1626
|
+
});
|
|
1395
1627
|
// Per-bot 环境变量 env。Body `{ env: string }`(原始 JSON 文本,如
|
|
1396
1628
|
// `{"ANTHROPIC_BASE_URL":"…","ANTHROPIC_AUTH_TOKEN":"…"}` 让本 bot 走 GLM/第三方
|
|
1397
1629
|
// 服务商):空白 → 清除;否则按 json kind 解析 + sanitizePerBotEnv 过滤后落盘。
|
|
@@ -1605,6 +1837,51 @@ ipcRoute('PUT', '/api/bot-default-oncall', async (req, res) => {
|
|
|
1605
1837
|
return jsonRes(res, 400, r);
|
|
1606
1838
|
jsonRes(res, 200, { ok: true, defaultOncall: r.defaultOncall, resolvedPath: resolvedPath || undefined });
|
|
1607
1839
|
});
|
|
1840
|
+
// Per-bot「默认工作目录模式」三选一(dashboard 单选;两个底层字段互斥):
|
|
1841
|
+
// • off → 清 defaultWorkingDir + 关 defaultOncall(新会话弹「选仓库」卡)
|
|
1842
|
+
// • default → 写 defaultWorkingDir + 关 defaultOncall(钉目录、跳过选仓库、不改权限)
|
|
1843
|
+
// • oncall → 开 defaultOncall(+dir) + 清 defaultWorkingDir(新群自动绑+开放对话;
|
|
1844
|
+
// 该目录经 resolveBotDefaultWorkingDir 的 layer-4 兜底覆盖该 bot 所有会话)
|
|
1845
|
+
// 两字段在 oncallStore.setWorkingDirMode 的**同一个 rmwBotEntry 锁内**一次性原子写盘 +
|
|
1846
|
+
// 同步内存:否则两个并发请求分别加锁写各自字段会交错,最终留下 defaultOncall.enabled 与
|
|
1847
|
+
// defaultWorkingDir 同时存在的不一致态(GET/前端按 enabled 显示 oncall,但 runtime 的
|
|
1848
|
+
// effectiveDefaultWorkingDir 优先用 defaultWorkingDir → UI 与实际目录背离;PR #311 Codex 评审)。
|
|
1849
|
+
// next-session 生效(运行中会话需 /restart)。
|
|
1850
|
+
ipcRoute('PUT', '/api/bot-working-dir-mode', async (req, res) => {
|
|
1851
|
+
if (!cachedLarkAppId)
|
|
1852
|
+
return jsonRes(res, 503, { error: 'larkAppId_not_set' });
|
|
1853
|
+
let body;
|
|
1854
|
+
try {
|
|
1855
|
+
body = await readJsonBody(req);
|
|
1856
|
+
}
|
|
1857
|
+
catch {
|
|
1858
|
+
return jsonRes(res, 400, { ok: false, error: 'bad_json' });
|
|
1859
|
+
}
|
|
1860
|
+
const mode = body.mode;
|
|
1861
|
+
if (mode !== 'off' && mode !== 'default' && mode !== 'oncall') {
|
|
1862
|
+
return jsonRes(res, 400, { ok: false, error: 'invalid_mode' });
|
|
1863
|
+
}
|
|
1864
|
+
const workingDir = typeof body.workingDir === 'string' ? body.workingDir.trim() : '';
|
|
1865
|
+
// 非「关闭」模式必须给一个真实存在的目录。
|
|
1866
|
+
let resolvedPath = '';
|
|
1867
|
+
if (mode !== 'off') {
|
|
1868
|
+
if (!workingDir)
|
|
1869
|
+
return jsonRes(res, 400, { ok: false, error: 'workingDir_required' });
|
|
1870
|
+
const v = validateWorkingDir(workingDir);
|
|
1871
|
+
if (!v.ok)
|
|
1872
|
+
return jsonRes(res, 400, { ok: false, error: v.error });
|
|
1873
|
+
resolvedPath = v.resolvedPath;
|
|
1874
|
+
}
|
|
1875
|
+
const r = await oncallStore.setWorkingDirMode(cachedLarkAppId, mode, workingDir);
|
|
1876
|
+
if (!r.ok)
|
|
1877
|
+
return jsonRes(res, 400, r);
|
|
1878
|
+
return jsonRes(res, 200, {
|
|
1879
|
+
ok: true, mode,
|
|
1880
|
+
defaultWorkingDir: r.defaultWorkingDir,
|
|
1881
|
+
defaultOncall: r.defaultOncall,
|
|
1882
|
+
resolvedPath: resolvedPath || undefined,
|
|
1883
|
+
});
|
|
1884
|
+
});
|
|
1608
1885
|
// Create a brand-new chat with this bot as creator/owner and `larkAppIds` as
|
|
1609
1886
|
// initial bot members. The dashboard's public route picks any online daemon
|
|
1610
1887
|
// to act as creator, then forwards here.
|