lark-remote 0.1.1 → 0.1.3
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 +2 -5
- package/README.md +1 -4
- package/dist/bridge/index.d.ts +1 -3
- package/dist/bridge/index.js +11 -12
- package/dist/card/card-budget.js +1 -2
- package/dist/card/card-shared.d.ts +8 -0
- package/dist/card/card-shared.js +14 -0
- package/dist/card/run-renderer.js +1 -0
- package/dist/card/run-state.d.ts +4 -0
- package/dist/config/codex-config.d.ts +3 -5
- package/dist/config/codex-config.js +7 -7
- package/dist/config/dir.d.ts +1 -0
- package/dist/config/dir.js +4 -0
- package/dist/config/index.d.ts +0 -10
- package/dist/config/index.js +0 -11
- package/dist/connector/index.js +28 -0
- package/dist/index.js +89 -41
- package/dist/router/config/codex.js +8 -12
- package/dist/router/index.d.ts +15 -2
- package/dist/router/index.js +314 -44
- package/dist/router/utils.d.ts +3 -0
- package/dist/router/utils.js +15 -3
- package/dist/runner/claude/runner.d.ts +0 -1
- package/dist/runner/claude/runner.js +1 -1
- package/dist/runner/codex/runner.d.ts +0 -2
- package/dist/runner/codex/runner.js +1 -1
- package/dist/runner/common/spawning-runner.d.ts +0 -1
- package/dist/runner/common/spawning-runner.js +2 -4
- package/dist/runner/kimi/runner.d.ts +0 -1
- package/dist/runner/kimi/runner.js +1 -1
- package/dist/runner/opencode/runner.d.ts +0 -2
- package/dist/runner/opencode/runner.js +1 -1
- package/dist/runner/pi/runner.d.ts +0 -1
- package/dist/runner/pi/runner.js +1 -1
- package/dist/runner/probe.d.ts +45 -0
- package/dist/runner/probe.js +87 -0
- package/dist/runner/types.d.ts +3 -0
- package/dist/session/claude/sessions.d.ts +8 -6
- package/dist/session/claude/sessions.js +178 -26
- package/dist/session/codex/rollout-reader.d.ts +1 -0
- package/dist/session/codex/rollout-reader.js +15 -0
- package/dist/session/codex/sessions.d.ts +1 -1
- package/dist/session/codex/sessions.js +2 -1
- package/dist/session/kimi/sessions.d.ts +3 -1
- package/dist/session/kimi/sessions.js +42 -6
- package/dist/session/opencode/sessions.d.ts +0 -2
- package/dist/session/opencode/sessions.js +1 -1
- package/dist/startup-contact.d.ts +4 -2
- package/dist/startup-contact.js +7 -4
- package/package.json +39 -4
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { parseCliArgs, resolveConfigDir, setConfigDir, printHelp, printVersion,
|
|
|
5
5
|
import { FeishuConnector } from './connector/index.js';
|
|
6
6
|
import { ClaudeRunner, CodexExecRunner, OpencodeExecRunner, PiRunner, KimiRunner, } from './runner/index.js';
|
|
7
7
|
import { AgentRegistry } from './runner/registry.js';
|
|
8
|
+
import { probeAllAgents } from './runner/probe.js';
|
|
8
9
|
import { SessionReaderRegistry, SessionStore } from './session/index.js';
|
|
9
10
|
import { ClaudeSessionReader, CodexSessionReader, OpencodeSessionReader, PiSessionReader, KimiSessionReader, } from './session/index.js';
|
|
10
11
|
import { CommandRouter, isImmediateAction, formatUsageStats, } from './router/index.js';
|
|
@@ -21,6 +22,7 @@ import { markdownDiv } from './card/collapsible.js';
|
|
|
21
22
|
import { sessionEventPanel } from './router/card-helpers.js';
|
|
22
23
|
import { newSessionButton, agentDisplayName } from './card/card-shared.js';
|
|
23
24
|
import path from 'node:path';
|
|
25
|
+
import fs from 'node:fs';
|
|
24
26
|
/** Send auto-resume card for a restored session */
|
|
25
27
|
async function sendAutoResumeCard(connector, contact, cwd, session, state) {
|
|
26
28
|
if (!contact.userId)
|
|
@@ -143,27 +145,23 @@ function setupInstanceLockAndHandlers(instanceLock, logger, configDir) {
|
|
|
143
145
|
}
|
|
144
146
|
/** Initialize per-workspace runner factory + agent registry. */
|
|
145
147
|
function initializeRunner(config, configDir, cliArgs) {
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
148
|
+
const agentRegistry = new AgentRegistry();
|
|
149
|
+
// P1-15: Claude factory reads from configContainer (not closure) so runtime
|
|
150
|
+
// config changes (model, effort, stopGraceMs) take effect after
|
|
151
|
+
// bridge.setConfig() + clearRunners(). Same pattern as codex/pi/kimi.
|
|
152
|
+
agentRegistry.register('claude', (ws) => {
|
|
153
|
+
const container = agentRegistry.getConfigContainer();
|
|
154
|
+
const latestConfig = container?.current ?? config;
|
|
155
|
+
const claudeConfig = latestConfig.claude;
|
|
156
|
+
return new ClaudeRunner({
|
|
157
|
+
model: claudeConfig.model,
|
|
158
|
+
effort: claudeConfig.effort,
|
|
159
|
+
stopGraceMs: claudeConfig.stopGraceMs,
|
|
152
160
|
settings: cliArgs.settings,
|
|
153
161
|
pidDir: configDir,
|
|
154
|
-
workspace,
|
|
162
|
+
workspace: ws,
|
|
155
163
|
});
|
|
156
|
-
|
|
157
|
-
};
|
|
158
|
-
const runner = createRunner('default');
|
|
159
|
-
runner.killOrphan();
|
|
160
|
-
runner.registerExitHandlers();
|
|
161
|
-
// Wire multi-agent registries. All five agents (claude/codex/opencode/pi/kimi)
|
|
162
|
-
// are already registered. Bridge and Router depend on these registries instead of
|
|
163
|
-
// importing session readers directly, so adding a new agent is "register factory + reader"
|
|
164
|
-
// with zero upstream changes.
|
|
165
|
-
const agentRegistry = new AgentRegistry();
|
|
166
|
-
agentRegistry.register('claude', (ws) => createRunner(ws));
|
|
164
|
+
});
|
|
167
165
|
// Register CodexExecRunner (codex exec --json, approval_policy=never).
|
|
168
166
|
// Factory reads latest config from container.current so runtime config changes
|
|
169
167
|
// (reasoningEffort, model, etc.) take effect after bridge.setConfig() + clearRunners().
|
|
@@ -173,7 +171,6 @@ function initializeRunner(config, configDir, cliArgs) {
|
|
|
173
171
|
const latestConfig = container?.current ?? config;
|
|
174
172
|
const codexConfig = getAgentConfig(latestConfig, 'codex');
|
|
175
173
|
return new CodexExecRunner({
|
|
176
|
-
binary: codexConfig?.binary ?? 'codex',
|
|
177
174
|
model: codexConfig?.model,
|
|
178
175
|
modelProvider: codexConfig?.modelProvider,
|
|
179
176
|
reasoningEffort: codexConfig?.reasoningEffort,
|
|
@@ -185,20 +182,17 @@ function initializeRunner(config, configDir, cliArgs) {
|
|
|
185
182
|
});
|
|
186
183
|
// Register OpencodeExecRunner (run mode)
|
|
187
184
|
// Using `opencode run --format json --auto` instead of HTTP+SSE server mode
|
|
188
|
-
const opencodeConfig = getAgentConfig(config, 'opencode');
|
|
189
185
|
// Register session reader (same instance as used by runner)
|
|
190
186
|
const sessionReaderRegistry = new SessionReaderRegistry();
|
|
191
187
|
sessionReaderRegistry.register('claude', new ClaudeSessionReader());
|
|
192
188
|
sessionReaderRegistry.register('codex', codexSessionReader);
|
|
193
189
|
// Register OpencodeSessionReader (CLI version)
|
|
194
190
|
// Using `opencode session list` and `opencode export` instead of HTTP API
|
|
195
|
-
const opencodeSessionReader = new OpencodeSessionReader(
|
|
196
|
-
binary: opencodeConfig?.binary ?? 'opencode',
|
|
197
|
-
});
|
|
191
|
+
const opencodeSessionReader = new OpencodeSessionReader();
|
|
198
192
|
agentRegistry.register('opencode', (ws) => {
|
|
199
193
|
// Get latest config from container (set below for pi)
|
|
200
194
|
const container = agentRegistry.getConfigContainer();
|
|
201
|
-
const latestConfig = container?.current;
|
|
195
|
+
const latestConfig = container?.current ?? config;
|
|
202
196
|
const ocConfig = getAgentConfig(latestConfig, 'opencode');
|
|
203
197
|
// Build model string with validation: provider/model format
|
|
204
198
|
let model;
|
|
@@ -213,9 +207,9 @@ function initializeRunner(config, configDir, cliArgs) {
|
|
|
213
207
|
}
|
|
214
208
|
}
|
|
215
209
|
return new OpencodeExecRunner({
|
|
216
|
-
binary: ocConfig?.binary ?? 'opencode',
|
|
217
210
|
model,
|
|
218
|
-
|
|
211
|
+
// P1-15: read stopGraceMs from latestConfig (not startup closure)
|
|
212
|
+
stopGraceMs: latestConfig.claude?.stopGraceMs ?? DEFAULT_STOP_GRACE_MS,
|
|
219
213
|
pidDir: configDir,
|
|
220
214
|
workspace: ws,
|
|
221
215
|
sessionReader: opencodeSessionReader,
|
|
@@ -232,10 +226,9 @@ function initializeRunner(config, configDir, cliArgs) {
|
|
|
232
226
|
agentRegistry.register('pi', (ws) => {
|
|
233
227
|
// 每次 factory 调用时从 registry 获取最新 config
|
|
234
228
|
const container = agentRegistry.getConfigContainer();
|
|
235
|
-
const latestConfig = container?.current;
|
|
229
|
+
const latestConfig = container?.current ?? config;
|
|
236
230
|
const piConf = getAgentConfig(latestConfig, 'pi');
|
|
237
231
|
return new PiRunner({
|
|
238
|
-
binary: piConf?.binary ?? 'pi',
|
|
239
232
|
provider: piConf?.provider ?? 'Volcano',
|
|
240
233
|
model: piConf?.model ?? 'glm-5.2',
|
|
241
234
|
thinking: piConf?.thinking ?? 'medium',
|
|
@@ -254,13 +247,13 @@ function initializeRunner(config, configDir, cliArgs) {
|
|
|
254
247
|
agentRegistry.register('kimi', (ws) => {
|
|
255
248
|
// 每次 factory 调用时从 registry 获取最新 config
|
|
256
249
|
const container = agentRegistry.getConfigContainer();
|
|
257
|
-
const latestConfig = container?.current;
|
|
250
|
+
const latestConfig = container?.current ?? config;
|
|
258
251
|
const kimiConf = getAgentConfig(latestConfig, 'kimi');
|
|
259
252
|
return new KimiRunner({
|
|
260
|
-
binary: kimiConf?.binary ?? 'kimi',
|
|
261
253
|
model: kimiConf?.model ?? 'kimi-code/k3',
|
|
262
254
|
thinkingEffort: kimiConf?.thinkingEffort ?? 'max',
|
|
263
|
-
|
|
255
|
+
// P1-15: read stopGraceMs from latestConfig (not startup closure)
|
|
256
|
+
stopGraceMs: latestConfig.claude?.stopGraceMs ?? DEFAULT_STOP_GRACE_MS,
|
|
264
257
|
pidDir: configDir,
|
|
265
258
|
workspace: ws,
|
|
266
259
|
sessionReader: kimiSessionReader,
|
|
@@ -275,10 +268,25 @@ function initializeRunner(config, configDir, cliArgs) {
|
|
|
275
268
|
agentRegistry.registerDisplayName('kimi', 'Kimi');
|
|
276
269
|
// 设置全局 registry,供 agentDisplayName 等全局函数使用
|
|
277
270
|
AgentRegistry.setGlobalInstance(agentRegistry);
|
|
278
|
-
|
|
271
|
+
// Probe agent CLI availability (fire-and-forget, populates cache for /config card).
|
|
272
|
+
// Don't block startup — log unavailable agents as warnings.
|
|
273
|
+
probeAllAgents()
|
|
274
|
+
.then((availability) => {
|
|
275
|
+
const unavailable = [...availability.entries()].filter(([, ok]) => !ok).map(([kind]) => kind);
|
|
276
|
+
if (unavailable.length > 0) {
|
|
277
|
+
getLogger().warn(`[probe] agent CLI not found or not functional: ${unavailable.join(', ')}`);
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
getLogger().info('[probe] all agent CLIs available');
|
|
281
|
+
}
|
|
282
|
+
})
|
|
283
|
+
.catch(() => {
|
|
284
|
+
// Probe failure is non-fatal; /config card will retry on open.
|
|
285
|
+
});
|
|
286
|
+
return { agentRegistry, sessionReaderRegistry };
|
|
279
287
|
}
|
|
280
288
|
/** Setup message and card action handlers. */
|
|
281
|
-
function setupMessageHandlers(connector, router, bridge, sessionStore, workspaceStore, binder, logger) {
|
|
289
|
+
function setupMessageHandlers(connector, router, bridge, sessionStore, workspaceStore, binder, logger, config) {
|
|
282
290
|
connector.setMessageHandler((msg) => {
|
|
283
291
|
// 绑定/授权闸门:仅 owner 放行;非 owner 静默丢弃;未绑定时要求 PIN 认领
|
|
284
292
|
const decision = binder.classify(msg.userId, msg.content, msg.chatId);
|
|
@@ -288,9 +296,50 @@ function setupMessageHandlers(connector, router, bridge, sessionStore, workspace
|
|
|
288
296
|
if (decision.kind === 'pin_wrong')
|
|
289
297
|
return;
|
|
290
298
|
if (decision.kind === 'bind_success') {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
299
|
+
// First-run onboarding: set default cwd + send welcome + Help card.
|
|
300
|
+
// setCwd is synchronous (outside the async closure) so that the user's
|
|
301
|
+
// next message — which will hit the `owner` branch now that
|
|
302
|
+
// startup-contact.json has been written — finds cwd already set.
|
|
303
|
+
// process.cwd() is the only sensible default: the user started
|
|
304
|
+
// lark-remote in the directory they want to work in.
|
|
305
|
+
// setCwd only when no cwd is set yet (e.g. fresh start after bind).
|
|
306
|
+
// Don't overwrite an existing cwd — the user may have already set one
|
|
307
|
+
// via /cd or a previous bind. Use realpath for canonical form (matching
|
|
308
|
+
// Claude JSONL cwd, e.g. /tmp → /private/tmp on macOS).
|
|
309
|
+
let resolvedCwd;
|
|
310
|
+
try {
|
|
311
|
+
resolvedCwd = fs.realpathSync(process.cwd());
|
|
312
|
+
}
|
|
313
|
+
catch {
|
|
314
|
+
resolvedCwd = process.cwd();
|
|
315
|
+
}
|
|
316
|
+
if (!sessionStore.getCwd(msg.userId)) {
|
|
317
|
+
sessionStore.setCwd(msg.userId, resolvedCwd);
|
|
318
|
+
}
|
|
319
|
+
void (async () => {
|
|
320
|
+
try {
|
|
321
|
+
// Message 1: bind confirmation + status (combined to avoid
|
|
322
|
+
// Feishu out-of-order delivery across three separate messages).
|
|
323
|
+
await connector.sendWithRetry(msg.chatId, {
|
|
324
|
+
text: `✅ 已绑定到本账号,此后仅你可使用本应用\n` +
|
|
325
|
+
`📂 当前工作目录: \`${resolvedCwd}\`\n` +
|
|
326
|
+
`🤖 默认 Agent: ${agentDisplayName(config.defaultAgent)}\n` +
|
|
327
|
+
`💡 直接输入消息即可开始对话,或 /cd 切换目录`,
|
|
328
|
+
});
|
|
329
|
+
// Message 2: Help card.
|
|
330
|
+
// Use router.cmdHelp() + manual send (without replyTo) so the Help
|
|
331
|
+
// card appears as an independent message, not a reply to the PIN
|
|
332
|
+
// message. router.handle('/help') would set replyTo=msg.messageId
|
|
333
|
+
// (the PIN), causing the card to nest under the PIN in Feishu UI.
|
|
334
|
+
const helpResult = router.cmdHelp();
|
|
335
|
+
if (helpResult.card) {
|
|
336
|
+
await connector.sendWithRetry(msg.chatId, { card: helpResult.card });
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
catch (err) {
|
|
340
|
+
logger.error('[binder] onboarding send failed:', err);
|
|
341
|
+
}
|
|
342
|
+
})();
|
|
294
343
|
return;
|
|
295
344
|
}
|
|
296
345
|
// decision.kind === 'owner':正常处理(不再每条覆盖 startup-contact)
|
|
@@ -488,11 +537,11 @@ async function main() {
|
|
|
488
537
|
logger.info('config loaded');
|
|
489
538
|
logger.info(`configDir = ${configDir}`);
|
|
490
539
|
logger.info(`feishu.appId = ${config.feishu.appId}`);
|
|
491
|
-
logger.info(`claude.
|
|
540
|
+
logger.info(`claude.model = ${config.claude.model}`);
|
|
492
541
|
if (cliArgs.settings) {
|
|
493
542
|
logger.info(`claude.settings = ${cliArgs.settings}`);
|
|
494
543
|
}
|
|
495
|
-
const {
|
|
544
|
+
const { agentRegistry, sessionReaderRegistry } = initializeRunner(config, configDir, cliArgs);
|
|
496
545
|
const connector = new FeishuConnector(config);
|
|
497
546
|
const startupContactStore = new StartupContactStore(path.join(configDir, 'startup-contact.json'));
|
|
498
547
|
const binder = new OwnerBinder(startupContactStore);
|
|
@@ -507,7 +556,6 @@ async function main() {
|
|
|
507
556
|
const sessionStore = new SessionStore(path.join(configDir, 'last-session.json'), config.defaultAgent);
|
|
508
557
|
const workspaceStore = new WorkspaceStore(path.join(configDir, 'workspace.json'));
|
|
509
558
|
const bridge = new Bridge({
|
|
510
|
-
runner,
|
|
511
559
|
connector,
|
|
512
560
|
sessionStore,
|
|
513
561
|
config,
|
|
@@ -525,7 +573,7 @@ async function main() {
|
|
|
525
573
|
restartSpawner: () => spawnReplacementBridge(path.join(configDir, 'logs')),
|
|
526
574
|
sessionReaderRegistry,
|
|
527
575
|
});
|
|
528
|
-
setupMessageHandlers(connector, router, bridge, sessionStore, workspaceStore, binder, logger);
|
|
576
|
+
setupMessageHandlers(connector, router, bridge, sessionStore, workspaceStore, binder, logger, config);
|
|
529
577
|
try {
|
|
530
578
|
await connector.connect();
|
|
531
579
|
}
|
|
@@ -535,7 +583,7 @@ async function main() {
|
|
|
535
583
|
}
|
|
536
584
|
if (binder.isBound()) {
|
|
537
585
|
// 仅已绑定时发送启动通知;未绑定时不打扰(PIN 引导已在控制台输出)
|
|
538
|
-
await sendStartupHello(connector, startupContactStore);
|
|
586
|
+
await sendStartupHello(connector, startupContactStore, { dev: cliArgs.dev });
|
|
539
587
|
}
|
|
540
588
|
// Auto-restore: resume the persisted sessionId if available
|
|
541
589
|
const restoredContact = startupContactStore.getContact();
|
|
@@ -6,14 +6,12 @@ export class CodexConfigBuilder {
|
|
|
6
6
|
buildFields(displayConfig) {
|
|
7
7
|
const fields = [];
|
|
8
8
|
// 从 codex config.toml 动态读取 provider 和 model
|
|
9
|
-
const
|
|
10
|
-
const codexCfg = loadCodexConfig({ binary: codexBinary });
|
|
9
|
+
const codexCfg = loadCodexConfig();
|
|
11
10
|
const codexProviderNames = codexCfg.providerNames;
|
|
12
11
|
const currentModelProvider = displayConfig.agents?.codex?.modelProvider ?? codexCfg.currentProvider;
|
|
13
12
|
const currentCodexModel = displayConfig.agents?.codex?.model ?? codexCfg.currentModel;
|
|
14
|
-
const currentReasoningEffort = displayConfig.agents?.codex?.reasoningEffort ??
|
|
15
|
-
|
|
16
|
-
// 传入当前 provider 过滤模型列���
|
|
13
|
+
const currentReasoningEffort = displayConfig.agents?.codex?.reasoningEffort ?? getDefaultReasoningEffort(currentCodexModel);
|
|
14
|
+
// 传入当前 provider 过滤模型列表
|
|
17
15
|
const codexModelOptions = codexCfg.modelOptions(currentModelProvider);
|
|
18
16
|
fields.push({
|
|
19
17
|
key: 'agents.codex.modelProvider',
|
|
@@ -42,7 +40,7 @@ export class CodexConfigBuilder {
|
|
|
42
40
|
label: '推理强度',
|
|
43
41
|
type: 'select',
|
|
44
42
|
// 档位按目录实际声明透传(P2-5):codex 支持 none/Custom,不再按标准枚举过滤
|
|
45
|
-
options: getReasoningEffortOptions(currentCodexModel
|
|
43
|
+
options: getReasoningEffortOptions(currentCodexModel),
|
|
46
44
|
currentValue: currentReasoningEffort,
|
|
47
45
|
});
|
|
48
46
|
return fields;
|
|
@@ -50,10 +48,9 @@ export class CodexConfigBuilder {
|
|
|
50
48
|
handleFieldChange(key, value, config) {
|
|
51
49
|
const patches = [];
|
|
52
50
|
patches.push({ key, value });
|
|
53
|
-
// provider 变更时,重置 model
|
|
51
|
+
// provider 变更时,重置 model 为新 provider 的首个模型
|
|
54
52
|
if (key === 'agents.codex.modelProvider' && typeof value === 'string') {
|
|
55
|
-
const
|
|
56
|
-
const codexCfg = loadCodexConfig({ binary: codexBinary });
|
|
53
|
+
const codexCfg = loadCodexConfig();
|
|
57
54
|
const newModelOptions = codexCfg.modelOptions(value);
|
|
58
55
|
const currentModel = config.agents?.codex?.model;
|
|
59
56
|
const currentModelIsValid = newModelOptions.some((m) => m === currentModel);
|
|
@@ -86,14 +83,13 @@ export class CodexConfigBuilder {
|
|
|
86
83
|
* 对 undefined 做键删除,P1)。
|
|
87
84
|
*/
|
|
88
85
|
effortPatchForModel(config, newModel) {
|
|
89
|
-
const codexBinary = config.agents?.codex?.binary ?? 'codex';
|
|
90
86
|
const currentReasoningEffort = config.agents?.codex?.reasoningEffort;
|
|
91
|
-
const newModelSupportedEfforts = getReasoningEffortOptions(newModel
|
|
87
|
+
const newModelSupportedEfforts = getReasoningEffortOptions(newModel);
|
|
92
88
|
const isCurrentEffortValid = currentReasoningEffort && newModelSupportedEfforts.includes(currentReasoningEffort);
|
|
93
89
|
if (isCurrentEffortValid)
|
|
94
90
|
return null;
|
|
95
91
|
const middle = newModelSupportedEfforts[Math.floor((newModelSupportedEfforts.length - 1) / 2)];
|
|
96
|
-
const newEffort = middle ?? getDefaultReasoningEffort(newModel
|
|
92
|
+
const newEffort = middle ?? getDefaultReasoningEffort(newModel);
|
|
97
93
|
return { key: 'agents.codex.reasoningEffort', value: newEffort };
|
|
98
94
|
}
|
|
99
95
|
}
|
package/dist/router/index.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ interface CommandResult {
|
|
|
26
26
|
* stop — interrupt current run
|
|
27
27
|
* ls.file — send file only
|
|
28
28
|
* ws.remove — delete workspace alias only
|
|
29
|
-
* resume.use — set sessionId
|
|
29
|
+
* resume.use — set sessionId + agent for correct reader routing
|
|
30
30
|
* help.* — read-only help commands
|
|
31
31
|
* order.delete — delete order only
|
|
32
32
|
* order.exec is intercepted by index.ts at the enqueue boundary
|
|
@@ -73,6 +73,8 @@ interface CardActionResponse {
|
|
|
73
73
|
[key: string]: unknown;
|
|
74
74
|
}
|
|
75
75
|
export declare class CommandRouter {
|
|
76
|
+
/** Valid agent kinds — single source of truth for resume.use / resume.page / cmdResume. */
|
|
77
|
+
static readonly VALID_AGENTS: readonly ["claude", "codex", "opencode", "pi", "kimi"];
|
|
76
78
|
private sessionStore;
|
|
77
79
|
private bridge;
|
|
78
80
|
private config;
|
|
@@ -187,6 +189,11 @@ export declare class CommandRouter {
|
|
|
187
189
|
* Mirrors handleLsPage — updates the same card, never sends a new one.
|
|
188
190
|
*/
|
|
189
191
|
private handleResumePage;
|
|
192
|
+
/**
|
|
193
|
+
* Handle active.page: paginate the /active run list in place.
|
|
194
|
+
* Mirrors handleResumePage — updates the same card, never sends a new one.
|
|
195
|
+
*/
|
|
196
|
+
private handleActivePage;
|
|
190
197
|
/**
|
|
191
198
|
* Handle ls.browse: browse directory without switching cwd.
|
|
192
199
|
*/
|
|
@@ -223,6 +230,11 @@ export declare class CommandRouter {
|
|
|
223
230
|
* Handle order.delete: remove the order and update card in place.
|
|
224
231
|
*/
|
|
225
232
|
private handleOrderDelete;
|
|
233
|
+
/**
|
|
234
|
+
* Handle order.page: paginate the /order list in place.
|
|
235
|
+
* Mirrors handleLsPage — updates the same card, never sends a new one.
|
|
236
|
+
*/
|
|
237
|
+
private handleOrderPage;
|
|
226
238
|
/**
|
|
227
239
|
* Handle ws.remove: remove the workspace alias and refresh the /ws list card
|
|
228
240
|
* in place (mirrors handleOrderDelete). Without this the stale alias would
|
|
@@ -273,7 +285,7 @@ export declare class CommandRouter {
|
|
|
273
285
|
*/
|
|
274
286
|
private propagateConfigSave;
|
|
275
287
|
private executeCommand;
|
|
276
|
-
|
|
288
|
+
cmdHelp(): CommandResult;
|
|
277
289
|
private cmdStatus;
|
|
278
290
|
private cmdPs;
|
|
279
291
|
private cmdStop;
|
|
@@ -307,6 +319,7 @@ export declare class CommandRouter {
|
|
|
307
319
|
/**
|
|
308
320
|
* Build CardKit 2.0 /active card from bridge memory (not file system).
|
|
309
321
|
* Shows only runs that were started by THIS bridge process.
|
|
322
|
+
* Paginates with ACTIVE_PAGE_SIZE (default 20) items per page.
|
|
310
323
|
*/
|
|
311
324
|
private buildActiveCardFromMemory;
|
|
312
325
|
private cmdReconnect;
|