lark-remote 0.1.4 → 0.1.6
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/CHANGELOG.md +38 -0
- package/README.en.md +0 -1
- package/README.md +0 -1
- package/dist/bridge/approval-coordinator.d.ts +108 -0
- package/dist/bridge/approval-coordinator.js +258 -0
- package/dist/bridge/index.d.ts +62 -0
- package/dist/bridge/index.js +423 -20
- package/dist/bridge/queue-manager.d.ts +9 -0
- package/dist/bridge/queue-manager.js +19 -11
- package/dist/card/approval-render.d.ts +16 -0
- package/dist/card/approval-render.js +247 -0
- package/dist/card/card-shared.d.ts +14 -0
- package/dist/card/card-shared.js +28 -0
- package/dist/card/run-renderer.js +78 -7
- package/dist/card/run-state.d.ts +25 -3
- package/dist/card/run-state.js +210 -2
- package/dist/config/dir.d.ts +1 -0
- package/dist/config/dir.js +4 -0
- package/dist/config/index.d.ts +43 -0
- package/dist/config/index.js +25 -1
- package/dist/connector/index.d.ts +5 -0
- package/dist/connector/index.js +32 -0
- package/dist/index.js +95 -23
- package/dist/router/config/codex.d.ts +1 -1
- package/dist/router/config/codex.js +49 -0
- package/dist/router/config/common/render.js +4 -0
- package/dist/router/config/index.d.ts +0 -10
- package/dist/router/config/index.js +0 -17
- package/dist/router/config/types.d.ts +1 -1
- package/dist/router/index.d.ts +61 -1
- package/dist/router/index.js +323 -48
- package/dist/router/utils.d.ts +2 -0
- package/dist/router/utils.js +5 -2
- package/dist/runner/codex/app-server/client.d.ts +82 -0
- package/dist/runner/codex/app-server/client.js +234 -0
- package/dist/runner/codex/app-server/connection-manager.d.ts +56 -0
- package/dist/runner/codex/app-server/connection-manager.js +170 -0
- package/dist/runner/codex/app-server/protocol-types.d.ts +527 -0
- package/dist/runner/codex/app-server/protocol-types.js +67 -0
- package/dist/runner/codex/app-server/runner.d.ts +121 -0
- package/dist/runner/codex/app-server/runner.js +554 -0
- package/dist/runner/codex/app-server/translator.d.ts +109 -0
- package/dist/runner/codex/app-server/translator.js +734 -0
- package/dist/runner/codex/app-server/transport.d.ts +49 -0
- package/dist/runner/codex/app-server/transport.js +231 -0
- package/dist/runner/codex/argv.d.ts +1 -1
- package/dist/runner/codex/argv.js +1 -1
- package/dist/runner/codex/factory.d.ts +29 -0
- package/dist/runner/codex/factory.js +39 -0
- package/dist/runner/codex/index.d.ts +2 -0
- package/dist/runner/codex/index.js +2 -0
- package/dist/runner/codex/runner.d.ts +3 -0
- package/dist/runner/codex/runner.js +5 -0
- package/dist/runner/common/runner-utils.d.ts +12 -0
- package/dist/runner/common/runner-utils.js +21 -0
- package/dist/runner/common/spawning-runner.js +9 -1
- package/dist/runner/common/usage.d.ts +2 -0
- package/dist/runner/common/usage.js +2 -0
- package/dist/runner/index.d.ts +2 -2
- package/dist/runner/index.js +1 -1
- package/dist/runner/types.d.ts +123 -2
- package/dist/session/claude/session-index.d.ts +93 -0
- package/dist/session/claude/session-index.js +374 -0
- package/dist/session/claude/sessions.d.ts +0 -18
- package/dist/session/claude/sessions.js +102 -319
- package/dist/session/codex/rollout-reader.js +46 -3
- package/dist/update/index.d.ts +10 -0
- package/dist/update/index.js +11 -0
- package/dist/update/install.d.ts +29 -0
- package/dist/update/install.js +93 -0
- package/dist/update/startup-hint.d.ts +5 -0
- package/dist/update/startup-hint.js +11 -0
- package/dist/update/version-check.d.ts +31 -0
- package/dist/update/version-check.js +149 -0
- package/package.json +1 -14
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { resolveAgentChoices, } from './runner/index.js';
|
|
|
3
3
|
import { ensureConfig } from './config/wizard.js';
|
|
4
4
|
import { parseCliArgs, resolveConfigDir, setConfigDir, printHelp, printVersion, } from './config/dir.js';
|
|
5
5
|
import { FeishuConnector } from './connector/index.js';
|
|
6
|
-
import { ClaudeRunner,
|
|
6
|
+
import { ClaudeRunner, createCodexRunner, OpencodeExecRunner, PiRunner, KimiRunner, } from './runner/index.js';
|
|
7
7
|
import { AgentRegistry } from './runner/registry.js';
|
|
8
8
|
import { probeAllAgents } from './runner/probe.js';
|
|
9
9
|
import { SessionReaderRegistry, SessionStore } from './session/index.js';
|
|
@@ -16,15 +16,16 @@ import { StartupContactStore, sendStartupHello } from './startup-contact.js';
|
|
|
16
16
|
import { OwnerBinder, formatPinGuidance } from './binder.js';
|
|
17
17
|
import { InstanceAlreadyRunningError, InstanceLock } from './instance-lock.js';
|
|
18
18
|
import { spawnReplacementBridge, waitForPreviousInstance } from './restart.js';
|
|
19
|
+
import { checkLatestVersion, isNewer, runInstallLatest, formatUpdateHint } from './update/index.js';
|
|
19
20
|
import { classifyRejection } from './error-classification.js';
|
|
20
21
|
import { WorkspaceStore } from './workspace/index.js';
|
|
21
22
|
import { markdownDiv } from './card/collapsible.js';
|
|
22
23
|
import { sessionEventPanel } from './router/card-helpers.js';
|
|
23
|
-
import { newSessionButton, agentDisplayName } from './card/card-shared.js';
|
|
24
|
+
import { newSessionButton, resumeCompactButton, agentDisplayName } from './card/card-shared.js';
|
|
24
25
|
import path from 'node:path';
|
|
25
26
|
import fs from 'node:fs';
|
|
26
27
|
/** Send auto-resume card for a restored session */
|
|
27
|
-
async function sendAutoResumeCard(connector, contact, cwd, session, state) {
|
|
28
|
+
async function sendAutoResumeCard(connector, contact, cwd, session, state, compactSupported = false) {
|
|
28
29
|
if (!contact.userId)
|
|
29
30
|
return;
|
|
30
31
|
const recipient = contact.chatId ?? contact.userId;
|
|
@@ -63,17 +64,21 @@ async function sendAutoResumeCard(connector, contact, cwd, session, state) {
|
|
|
63
64
|
const usageStr = formatUsageStats(state.usage);
|
|
64
65
|
elements.push(markdownDiv(usageStr));
|
|
65
66
|
}
|
|
66
|
-
// Add
|
|
67
|
-
const
|
|
67
|
+
// Add action buttons - use column_set+column (div+elements not supported in 2.0)
|
|
68
|
+
const actionButtons = [];
|
|
69
|
+
// Compact 按钮:仅 codex app-server 模式(runner 有 runCompact)且未在跑。
|
|
70
|
+
// 启动自动恢复时不会存在该会话的 activeRun,直接渲染。
|
|
71
|
+
if (compactSupported) {
|
|
72
|
+
actionButtons.push(resumeCompactButton(session.sessionId, state.agentKind ?? 'codex'));
|
|
73
|
+
}
|
|
74
|
+
actionButtons.push(newSessionButton());
|
|
68
75
|
elements.push({
|
|
69
76
|
tag: 'column_set',
|
|
70
|
-
columns:
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
},
|
|
76
|
-
],
|
|
77
|
+
columns: actionButtons.map((btn) => ({
|
|
78
|
+
tag: 'column',
|
|
79
|
+
width: 'auto',
|
|
80
|
+
elements: [btn],
|
|
81
|
+
})),
|
|
77
82
|
});
|
|
78
83
|
const card = {
|
|
79
84
|
schema: '2.0',
|
|
@@ -162,15 +167,17 @@ function initializeRunner(config, configDir, cliArgs) {
|
|
|
162
167
|
workspace: ws,
|
|
163
168
|
});
|
|
164
169
|
});
|
|
165
|
-
// Register
|
|
166
|
-
//
|
|
167
|
-
//
|
|
170
|
+
// Register Codex runner. Factory reads latest config from container.current
|
|
171
|
+
// so runtime config changes (serviceMode, model, sandbox, approvalPolicy,
|
|
172
|
+
// reasoningEffort, etc.) take effect after bridge.setConfig() + clearRunners().
|
|
173
|
+
// serviceMode=app-server → CodexAppServerRunner (persistent connection with
|
|
174
|
+
// approval + sandbox); otherwise CodexExecRunner (codex exec --json).
|
|
168
175
|
const codexSessionReader = new CodexSessionReader({ codexHome: process.env.CODEX_HOME });
|
|
169
176
|
agentRegistry.register('codex', (ws) => {
|
|
170
177
|
const container = agentRegistry.getConfigContainer();
|
|
171
178
|
const latestConfig = container?.current ?? config;
|
|
172
179
|
const codexConfig = getAgentConfig(latestConfig, 'codex');
|
|
173
|
-
return
|
|
180
|
+
return createCodexRunner({
|
|
174
181
|
model: codexConfig?.model,
|
|
175
182
|
modelProvider: codexConfig?.modelProvider,
|
|
176
183
|
reasoningEffort: codexConfig?.reasoningEffort,
|
|
@@ -178,6 +185,13 @@ function initializeRunner(config, configDir, cliArgs) {
|
|
|
178
185
|
pidDir: configDir,
|
|
179
186
|
workspace: ws,
|
|
180
187
|
sessionReader: codexSessionReader,
|
|
188
|
+
serviceMode: codexConfig?.serviceMode,
|
|
189
|
+
sandbox: codexConfig?.sandbox,
|
|
190
|
+
approvalPolicy: codexConfig?.approvalPolicy,
|
|
191
|
+
appServerBinary: codexConfig?.appServer?.binary,
|
|
192
|
+
appServerRequestTimeoutMs: codexConfig?.appServer?.requestTimeoutMs,
|
|
193
|
+
appServerIdleTtlMs: codexConfig?.appServer?.idleTtlMs,
|
|
194
|
+
appServerTurnIdleTimeoutMinutes: codexConfig?.appServer?.turnIdleTimeoutMinutes,
|
|
181
195
|
});
|
|
182
196
|
});
|
|
183
197
|
// Register OpencodeExecRunner (run mode)
|
|
@@ -444,7 +458,7 @@ function setupMessageHandlers(connector, router, bridge, sessionStore, workspace
|
|
|
444
458
|
if (actionValue.cmd === 'stop') {
|
|
445
459
|
if (!actionValue.runId) {
|
|
446
460
|
logger.warn('[control] ignored stop card action without runId');
|
|
447
|
-
// Card button clicks must have visible feedback (
|
|
461
|
+
// Card button clicks must have visible feedback (design constraint: card button
|
|
448
462
|
// 点击必须有可见反馈,见 design.md §6.2)。
|
|
449
463
|
void bridge
|
|
450
464
|
.sendResult({ text: '⚠️ 无效的停止请求,缺少必要信息' }, { userId, chatId, messageId })
|
|
@@ -478,11 +492,15 @@ function setupMessageHandlers(connector, router, bridge, sessionStore, workspace
|
|
|
478
492
|
inputValue: action.raw?.action?.input_value ??
|
|
479
493
|
action.action.input_value,
|
|
480
494
|
};
|
|
481
|
-
// queue.input
|
|
482
|
-
//
|
|
483
|
-
//
|
|
484
|
-
//
|
|
485
|
-
|
|
495
|
+
// queue.input / config.save / approval.respond / approval.toggle 返回
|
|
496
|
+
// CardActionResponse toast 给点击用户即时反馈。必须直接返回值 --
|
|
497
|
+
// enqueueImmediate / enqueueConfigAction 是 fire-and-forget,会吞掉返回值。
|
|
498
|
+
// 审批响应尤其不能落串行队列:run 任务占用队列头直到 turn 结束,审批响应
|
|
499
|
+
// 排在后面会形成死锁(run 不结束不执行、run 结束 coordinator 已删响应空转)。
|
|
500
|
+
if (actionValue.cmd === 'queue.input' ||
|
|
501
|
+
actionValue.cmd === 'config.save' ||
|
|
502
|
+
actionValue.cmd === 'approval.respond' ||
|
|
503
|
+
actionValue.cmd === 'approval.toggle') {
|
|
486
504
|
return router.handleCardAction(fullValue, { userId, chatId, messageId });
|
|
487
505
|
}
|
|
488
506
|
// order.exec → equivalent queued message (Plan A): resolve the order text
|
|
@@ -513,6 +531,8 @@ function setupMessageHandlers(connector, router, bridge, sessionStore, workspace
|
|
|
513
531
|
chatId,
|
|
514
532
|
messageId,
|
|
515
533
|
messagePreview: `card action: ${actionValue.cmd}`,
|
|
534
|
+
// Compact 是单向操作,排队卡不允许编辑(编辑预览无意义)。
|
|
535
|
+
editable: actionValue.cmd !== 'codex.compact' && actionValue.cmd !== 'resume.compact',
|
|
516
536
|
},
|
|
517
537
|
});
|
|
518
538
|
}
|
|
@@ -531,6 +551,32 @@ async function main() {
|
|
|
531
551
|
printVersion();
|
|
532
552
|
process.exit(0);
|
|
533
553
|
}
|
|
554
|
+
// --update: upgrade to latest version and exit (for cron/script automation)
|
|
555
|
+
if (cliArgs.update) {
|
|
556
|
+
// --update 在 acquireLock 之前执行;先解析 configDir 并初始化 logger,
|
|
557
|
+
// 让版本检查的日志落到正确目录(默认 ~/.lark-remote 或 --config-dir 指定)。
|
|
558
|
+
const updateConfigDir = resolveConfigDir(cliArgs.configDir);
|
|
559
|
+
initLogger({ dir: path.join(updateConfigDir, 'logs') });
|
|
560
|
+
try {
|
|
561
|
+
const { current, latest } = await checkLatestVersion();
|
|
562
|
+
if (!isNewer(current, latest)) {
|
|
563
|
+
console.log(`Already up to date: ${current}`);
|
|
564
|
+
process.exit(0);
|
|
565
|
+
}
|
|
566
|
+
console.log(`Updating ${current} → ${latest} ...`);
|
|
567
|
+
const result = await runInstallLatest();
|
|
568
|
+
if (!result.success) {
|
|
569
|
+
console.error(`Update failed: ${result.error}`);
|
|
570
|
+
process.exit(1);
|
|
571
|
+
}
|
|
572
|
+
console.log(`✅ Updated to ${latest}. Restart lark-remote to use the new version.`);
|
|
573
|
+
process.exit(0);
|
|
574
|
+
}
|
|
575
|
+
catch (err) {
|
|
576
|
+
console.error(`Update failed: ${err.message}`);
|
|
577
|
+
process.exit(1);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
534
580
|
const { config, configDir, logger, instanceLock } = await initializeCliAndConfig();
|
|
535
581
|
// Restart handoff: if spawned as a /restart replacement, wait for the old
|
|
536
582
|
// bridge to die (and release the instance lock) before acquiring it.
|
|
@@ -574,6 +620,8 @@ async function main() {
|
|
|
574
620
|
ordersPath: path.join(configDir, 'orders.json'),
|
|
575
621
|
restartSpawner: () => spawnReplacementBridge(path.join(configDir, 'logs')),
|
|
576
622
|
sessionReaderRegistry,
|
|
623
|
+
devMode: cliArgs.dev,
|
|
624
|
+
updateCachePath: path.join(configDir, 'update-cache.json'),
|
|
577
625
|
});
|
|
578
626
|
setupMessageHandlers(connector, router, bridge, sessionStore, workspaceStore, binder, logger, config);
|
|
579
627
|
try {
|
|
@@ -586,6 +634,27 @@ async function main() {
|
|
|
586
634
|
if (binder.isBound()) {
|
|
587
635
|
// 仅已绑定时发送启动通知;未绑定时不打扰(PIN 引导已在控制台输出)
|
|
588
636
|
await sendStartupHello(connector, startupContactStore, { dev: cliArgs.dev });
|
|
637
|
+
// 启动时静默检查版本(由 checkUpdateOnStartup 控制,默认关闭)
|
|
638
|
+
if (config.checkUpdateOnStartup) {
|
|
639
|
+
void (async () => {
|
|
640
|
+
try {
|
|
641
|
+
const cachePath = path.join(configDir, 'update-cache.json');
|
|
642
|
+
const { current, latest } = await checkLatestVersion({ cachePath });
|
|
643
|
+
const hint = formatUpdateHint(current, latest);
|
|
644
|
+
if (hint) {
|
|
645
|
+
const contact = startupContactStore.getContact();
|
|
646
|
+
const recipient = contact?.chatId ?? contact?.userId;
|
|
647
|
+
if (recipient) {
|
|
648
|
+
await connector.sendWithRetry(recipient, { text: hint });
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
catch (err) {
|
|
653
|
+
// Non-fatal: startup check failure must not crash the bridge
|
|
654
|
+
logger.warn(`[startup] update check failed: ${err.message}`);
|
|
655
|
+
}
|
|
656
|
+
})();
|
|
657
|
+
}
|
|
589
658
|
}
|
|
590
659
|
// Auto-restore: resume the persisted sessionId if available
|
|
591
660
|
const restoredContact = startupContactStore.getContact();
|
|
@@ -613,7 +682,10 @@ async function main() {
|
|
|
613
682
|
recap: content.recap,
|
|
614
683
|
displayTitle: content.displayTitle,
|
|
615
684
|
agentKind: config.defaultAgent,
|
|
616
|
-
}
|
|
685
|
+
},
|
|
686
|
+
// Compact 仅 codex app-server 模式有实现(runner.runCompact)。
|
|
687
|
+
config.defaultAgent === 'codex' &&
|
|
688
|
+
getAgentConfig(config, 'codex')?.serviceMode === 'app-server');
|
|
617
689
|
}
|
|
618
690
|
catch (err) {
|
|
619
691
|
getLogger().warn('[startup] sendAutoResumeCard failed:', err);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Codex config builder — builds fields and handles field changes for Codex agent.
|
|
3
3
|
*/
|
|
4
4
|
import type { AgentConfigCardBuilder, ConfigField } from './types.js';
|
|
5
|
-
import type
|
|
5
|
+
import { type AppConfig } from '../../config/index.js';
|
|
6
6
|
export declare class CodexConfigBuilder implements AgentConfigCardBuilder {
|
|
7
7
|
buildFields(displayConfig: AppConfig): ConfigField[];
|
|
8
8
|
handleFieldChange(key: string, value: unknown, config: AppConfig): Array<{
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Codex config builder — builds fields and handles field changes for Codex agent.
|
|
3
3
|
*/
|
|
4
4
|
import { loadCodexConfig, getReasoningEffortOptions, getDefaultReasoningEffort, } from '../../config/codex-config.js';
|
|
5
|
+
import { DEFAULT_TURN_IDLE_TIMEOUT_MINUTES } from '../../config/index.js';
|
|
5
6
|
export class CodexConfigBuilder {
|
|
6
7
|
buildFields(displayConfig) {
|
|
7
8
|
const fields = [];
|
|
@@ -43,6 +44,54 @@ export class CodexConfigBuilder {
|
|
|
43
44
|
options: getReasoningEffortOptions(currentCodexModel),
|
|
44
45
|
currentValue: currentReasoningEffort,
|
|
45
46
|
});
|
|
47
|
+
// Service mode (exec vs app-server)
|
|
48
|
+
const currentServiceMode = displayConfig.agents?.codex?.serviceMode ?? 'exec';
|
|
49
|
+
fields.push({
|
|
50
|
+
key: 'agents.codex.serviceMode',
|
|
51
|
+
label: '运行模式',
|
|
52
|
+
type: 'select',
|
|
53
|
+
options: ['exec', 'app-server'],
|
|
54
|
+
currentValue: currentServiceMode,
|
|
55
|
+
});
|
|
56
|
+
// 审批策略与沙箱模式仅 app-server 模式可配置(CodexAppServerRunner 读取);
|
|
57
|
+
// exec 模式在 runner 层固定 `--sandbox danger-full-access` +
|
|
58
|
+
// `approval_policy="never"`(src/runner/codex/argv.ts),卡片不暴露选项,
|
|
59
|
+
// 只用说明行把默认语义呈现给用户。
|
|
60
|
+
if (currentServiceMode === 'app-server') {
|
|
61
|
+
// Approval policy (Codex 官方 AskForApproval 标准值;on-request 为 codex 默认)
|
|
62
|
+
const currentApprovalPolicy = displayConfig.agents?.codex?.approvalPolicy ?? 'on-request';
|
|
63
|
+
fields.push({
|
|
64
|
+
key: 'agents.codex.approvalPolicy',
|
|
65
|
+
label: '审批策略',
|
|
66
|
+
type: 'select',
|
|
67
|
+
options: ['untrusted', 'on-request', 'never'],
|
|
68
|
+
currentValue: currentApprovalPolicy,
|
|
69
|
+
});
|
|
70
|
+
// Sandbox mode (Codex 官方 SandboxMode 标准值)
|
|
71
|
+
const currentSandbox = displayConfig.agents?.codex?.sandbox ?? 'danger-full-access';
|
|
72
|
+
fields.push({
|
|
73
|
+
key: 'agents.codex.sandbox',
|
|
74
|
+
label: '沙箱模式',
|
|
75
|
+
type: 'select',
|
|
76
|
+
options: ['read-only', 'workspace-write', 'danger-full-access'],
|
|
77
|
+
currentValue: currentSandbox,
|
|
78
|
+
});
|
|
79
|
+
const currentTurnIdleTimeoutMinutes = displayConfig.agents?.codex?.appServer?.turnIdleTimeoutMinutes ??
|
|
80
|
+
DEFAULT_TURN_IDLE_TIMEOUT_MINUTES;
|
|
81
|
+
fields.push({
|
|
82
|
+
key: 'agents.codex.appServer.turnIdleTimeoutMinutes',
|
|
83
|
+
label: 'Turn 空闲超时(分钟, 0关闭)',
|
|
84
|
+
type: 'input',
|
|
85
|
+
currentValue: String(currentTurnIdleTimeoutMinutes),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
fields.push({
|
|
90
|
+
key: 'agents.codex.modeNote',
|
|
91
|
+
label: '命令行模式固定为完全访问(danger-full-access)且无需审批(approval never),不提供审批策略/沙箱配置',
|
|
92
|
+
type: 'note',
|
|
93
|
+
});
|
|
94
|
+
}
|
|
46
95
|
return fields;
|
|
47
96
|
}
|
|
48
97
|
handleFieldChange(key, value, config) {
|
|
@@ -19,6 +19,10 @@ function buildFieldElements(fields, displayConfig) {
|
|
|
19
19
|
else if (field.type === 'select' && field.options) {
|
|
20
20
|
elements.push(buildSelectElement(field, currentValue));
|
|
21
21
|
}
|
|
22
|
+
else if (field.type === 'note') {
|
|
23
|
+
// 纯说明行:无 config.* 回调,只渲染 label 为 markdown 文本。
|
|
24
|
+
elements.push({ tag: 'div', text: { tag: 'lark_md', content: field.label } });
|
|
25
|
+
}
|
|
22
26
|
else {
|
|
23
27
|
elements.push(buildInputElement(field, currentValue));
|
|
24
28
|
}
|
|
@@ -16,13 +16,3 @@ import type { AgentConfigCardBuilder } from './types.js';
|
|
|
16
16
|
export declare function getConfigBuilder(agent: AgentKind): AgentConfigCardBuilder;
|
|
17
17
|
/** List all registered agent kinds. */
|
|
18
18
|
export declare function listRegisteredAgents(): AgentKind[];
|
|
19
|
-
/**
|
|
20
|
-
* Sort agent kinds for UI lists: agents that are definitively unavailable
|
|
21
|
-
* (availability === false) sink to the bottom; everything else keeps its
|
|
22
|
-
* input order. The sort is stable, so relative order within both groups is
|
|
23
|
-
* preserved (e.g. registration order in the config card selector).
|
|
24
|
-
*
|
|
25
|
-
* `undefined` (probe cache missing/expired) is treated as "keep in place",
|
|
26
|
-
* so a stale cache cannot misplace installed agents.
|
|
27
|
-
*/
|
|
28
|
-
export declare function sortAgentsByAvailability(kinds: AgentKind[], isAvailable: (kind: AgentKind) => boolean | undefined): AgentKind[];
|
|
@@ -35,21 +35,4 @@ export function getConfigBuilder(agent) {
|
|
|
35
35
|
export function listRegisteredAgents() {
|
|
36
36
|
return Object.keys(builders);
|
|
37
37
|
}
|
|
38
|
-
/**
|
|
39
|
-
* Sort agent kinds for UI lists: agents that are definitively unavailable
|
|
40
|
-
* (availability === false) sink to the bottom; everything else keeps its
|
|
41
|
-
* input order. The sort is stable, so relative order within both groups is
|
|
42
|
-
* preserved (e.g. registration order in the config card selector).
|
|
43
|
-
*
|
|
44
|
-
* `undefined` (probe cache missing/expired) is treated as "keep in place",
|
|
45
|
-
* so a stale cache cannot misplace installed agents.
|
|
46
|
-
*/
|
|
47
|
-
export function sortAgentsByAvailability(kinds, isAvailable) {
|
|
48
|
-
const unavailable = new Set(kinds.filter((kind) => isAvailable(kind) === false));
|
|
49
|
-
return [...kinds].sort((a, b) => {
|
|
50
|
-
const rankA = unavailable.has(a) ? 1 : 0;
|
|
51
|
-
const rankB = unavailable.has(b) ? 1 : 0;
|
|
52
|
-
return rankA - rankB;
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
38
|
//# sourceMappingURL=index.js.map
|
|
@@ -9,7 +9,7 @@ import type { AppConfig } from '../../config/index.js';
|
|
|
9
9
|
export interface ConfigField {
|
|
10
10
|
key: string;
|
|
11
11
|
label: string;
|
|
12
|
-
type: 'boolean' | 'select' | 'input';
|
|
12
|
+
type: 'boolean' | 'select' | 'input' | 'note';
|
|
13
13
|
/** For select type: the list of options shown in the dropdown. */
|
|
14
14
|
options?: readonly string[];
|
|
15
15
|
/** Override the currentValue shown in the card (takes priority over getConfigValue). */
|
package/dist/router/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { SessionStore, SessionReaderRegistry } from '../session/index.js';
|
|
|
2
2
|
import type { AppConfig } from '../config/index.js';
|
|
3
3
|
import type { Bridge } from '../bridge/index.js';
|
|
4
4
|
import type { AgentBinding } from '../bridge/queue-manager.js';
|
|
5
|
+
import { type VersionCheckResult, type InstallResult } from '../update/index.js';
|
|
5
6
|
interface CommandContext {
|
|
6
7
|
userId: string;
|
|
7
8
|
chatId: string;
|
|
@@ -59,6 +60,18 @@ export interface CardActionPayload {
|
|
|
59
60
|
/** CardKit 2.0 input 组件自带提交图标触发回调时回传的输入值 */
|
|
60
61
|
inputValue?: string;
|
|
61
62
|
orderId?: string;
|
|
63
|
+
/** Approval request ID for approval card actions. */
|
|
64
|
+
requestId?: number | string;
|
|
65
|
+
/** Decision for approval.respond (e.g. 'accept', 'decline', 'cancel'). */
|
|
66
|
+
decision?: string;
|
|
67
|
+
/** Scope for acceptForSession: 'turn' | 'session'. */
|
|
68
|
+
scope?: 'turn' | 'session';
|
|
69
|
+
/** Unique nonce to prevent duplicate processing. */
|
|
70
|
+
nonce?: string;
|
|
71
|
+
/** Permission item ID for approval.toggle. */
|
|
72
|
+
permId?: string;
|
|
73
|
+
/** Desired selection state for approval.toggle (card renders !current). */
|
|
74
|
+
selected?: boolean;
|
|
62
75
|
}
|
|
63
76
|
/**
|
|
64
77
|
* Response a cardAction handler may return to give the clicking user native
|
|
@@ -91,6 +104,12 @@ export declare class CommandRouter {
|
|
|
91
104
|
*/
|
|
92
105
|
private restartSpawner?;
|
|
93
106
|
private idleTimeoutMs;
|
|
107
|
+
/** Dev mode flag: --dev means the bridge was started from source (bun src/index.ts). */
|
|
108
|
+
private devMode;
|
|
109
|
+
/** Cache file for version checks (<configDir>/update-cache.json). */
|
|
110
|
+
private updateCachePath?;
|
|
111
|
+
/** Injected update functions (for testability; defaults to real implementation). */
|
|
112
|
+
private updateFns;
|
|
94
113
|
private pendingConfig;
|
|
95
114
|
/**
|
|
96
115
|
* Monotonic counter minting unique internal keys for order.exec enqueue
|
|
@@ -135,6 +154,19 @@ export declare class CommandRouter {
|
|
|
135
154
|
idleTimeoutMs?: number;
|
|
136
155
|
/** Session reader registry (required). */
|
|
137
156
|
sessionReaderRegistry: SessionReaderRegistry;
|
|
157
|
+
/** Dev mode: bridge was started from source (--dev flag). */
|
|
158
|
+
devMode?: boolean;
|
|
159
|
+
/** Version check cache path (<configDir>/update-cache.json). */
|
|
160
|
+
updateCachePath?: string;
|
|
161
|
+
/** Override update functions for testability. */
|
|
162
|
+
updateFns?: {
|
|
163
|
+
checkLatestVersion?: (opts?: {
|
|
164
|
+
cachePath?: string;
|
|
165
|
+
bypassCache?: boolean;
|
|
166
|
+
}) => Promise<VersionCheckResult>;
|
|
167
|
+
isNewer?: (current: string, latest: string) => boolean | null;
|
|
168
|
+
runInstallLatest?: () => Promise<InstallResult>;
|
|
169
|
+
};
|
|
138
170
|
});
|
|
139
171
|
/**
|
|
140
172
|
* Resolve the active session reader for the current defaultAgent.
|
|
@@ -153,6 +185,12 @@ export declare class CommandRouter {
|
|
|
153
185
|
* Validates payload and dispatches to the corresponding command.
|
|
154
186
|
*/
|
|
155
187
|
handleCardAction(value: CardActionPayload, ctx: CommandContext): Promise<CardActionResponse | void>;
|
|
188
|
+
/**
|
|
189
|
+
* Handle approval-related card actions.
|
|
190
|
+
* Routes to the appropriate bridge method based on value.cmd.
|
|
191
|
+
* Returns a toast response for immediate user feedback.
|
|
192
|
+
*/
|
|
193
|
+
private handleApprovalAction;
|
|
156
194
|
/**
|
|
157
195
|
* Handle queue.cancel: remove this message from the queue.
|
|
158
196
|
*/
|
|
@@ -307,7 +345,7 @@ export declare class CommandRouter {
|
|
|
307
345
|
*
|
|
308
346
|
* @param updates 以 config 路径形式给出的变更 key(卡片路径来自 diffConfig;
|
|
309
347
|
* 直写路径传 mapAgentKey(key),保证 pi./codex./opencode./kimi. 命中 agents.*)。
|
|
310
|
-
* @returns
|
|
348
|
+
* @returns 结构化切换结果(含 notice 文案 + 新 agent/sessionId 信息)
|
|
311
349
|
*/
|
|
312
350
|
private propagateConfigSave;
|
|
313
351
|
private executeCommand;
|
|
@@ -317,6 +355,13 @@ export declare class CommandRouter {
|
|
|
317
355
|
private cmdStop;
|
|
318
356
|
private cmdExit;
|
|
319
357
|
private cmdRestart;
|
|
358
|
+
/**
|
|
359
|
+
* /update: check for newer version and upgrade if available.
|
|
360
|
+
* /update check: only check, don't upgrade.
|
|
361
|
+
*
|
|
362
|
+
* Flow: check version → if newer, install → report success (no auto-restart).
|
|
363
|
+
*/
|
|
364
|
+
private cmdUpdate;
|
|
320
365
|
private cmdNew;
|
|
321
366
|
private cmdCd;
|
|
322
367
|
private readSessionDisplayState;
|
|
@@ -330,6 +375,21 @@ export declare class CommandRouter {
|
|
|
330
375
|
private switchCwdAndNotify;
|
|
331
376
|
/** Build card for auto-resumed session with new session button */
|
|
332
377
|
private buildAutoResumeCard;
|
|
378
|
+
/**
|
|
379
|
+
* Build card for config.save agent switch.
|
|
380
|
+
* When the new agent has a restored session, renders a Resume card (mirrors
|
|
381
|
+
* buildAutoResumeCard) with session history + stop/new buttons.
|
|
382
|
+
* When the session was cleared, renders a compact notice card instead.
|
|
383
|
+
*/
|
|
384
|
+
private buildConfigSwitchCard;
|
|
385
|
+
/**
|
|
386
|
+
* Whether a session of the given agent kind can be compacted from a resume
|
|
387
|
+
* card. Compact (thread/compact/start) is only implemented by the codex
|
|
388
|
+
* app-server runner (`runCompact`), so the button is gated on
|
|
389
|
+
* `serviceMode === 'app-server'` — exec mode spawns a fresh CLI per message
|
|
390
|
+
* and has no persistent session to compact.
|
|
391
|
+
*/
|
|
392
|
+
private canCompactSession;
|
|
333
393
|
private static readonly LS_PAGE_SIZE;
|
|
334
394
|
private cmdLs;
|
|
335
395
|
private cmdWs;
|