lark-remote 0.4.1 → 0.4.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/CHANGELOG.md +39 -0
- package/README.en.md +2 -2
- package/README.md +2 -2
- package/dist/bridge/approval-coordinator.d.ts +2 -0
- package/dist/bridge/approval-coordinator.js +16 -7
- package/dist/bridge/index.d.ts +22 -0
- package/dist/bridge/index.js +138 -56
- package/dist/card/approval-render.js +9 -8
- package/dist/card/card-budget.js +39 -26
- package/dist/card/run-renderer.js +9 -2
- package/dist/card/text-truncate.d.ts +9 -10
- package/dist/card/text-truncate.js +48 -43
- package/dist/cli.js +17 -0
- package/dist/config/codex-config.d.ts +3 -0
- package/dist/config/codex-config.js +4 -1
- package/dist/config/dir.js +6 -6
- package/dist/config/index.d.ts +7 -5
- package/dist/config/index.js +52 -13
- package/dist/config/kimi-config.d.ts +4 -1
- package/dist/config/kimi-config.js +5 -2
- package/dist/config/pi-config.d.ts +2 -7
- package/dist/config/pi-config.js +6 -6
- package/dist/config/wizard.js +8 -4
- package/dist/connector/index.d.ts +19 -0
- package/dist/connector/index.js +134 -23
- package/dist/inbound/placeholder.d.ts +3 -2
- package/dist/inbound/placeholder.js +17 -7
- package/dist/index.js +28 -6
- package/dist/instance-lock.d.ts +31 -15
- package/dist/instance-lock.js +64 -62
- package/dist/platform/agent-stopper.d.ts +29 -7
- package/dist/platform/agent-stopper.js +40 -8
- package/dist/platform/identity.d.ts +59 -3
- package/dist/platform/identity.js +105 -30
- package/dist/platform/path.d.ts +0 -7
- package/dist/platform/path.js +1 -51
- package/dist/platform/shell.d.ts +14 -0
- package/dist/platform/shell.js +35 -2
- package/dist/platform/sleep-blocker.d.ts +6 -0
- package/dist/platform/sleep-blocker.js +31 -5
- package/dist/platform/spawn.d.ts +1 -1
- package/dist/platform/spawn.js +1 -1
- package/dist/platform/terminator-posix.d.ts +1 -29
- package/dist/platform/terminator-posix.js +32 -30
- package/dist/platform/terminator-win32.js +4 -2
- package/dist/platform/terminator.d.ts +2 -2
- package/dist/platform/terminator.js +17 -2
- package/dist/platform/types.d.ts +3 -0
- package/dist/router/card-action-feedback.d.ts +17 -0
- package/dist/router/card-action-feedback.js +31 -0
- package/dist/router/card-helpers.d.ts +38 -2
- package/dist/router/card-helpers.js +79 -2
- package/dist/router/config/claude.js +8 -5
- package/dist/router/index.d.ts +41 -6
- package/dist/router/index.js +254 -84
- package/dist/runner/claude/runner.js +1 -1
- package/dist/runner/claude/session.d.ts +2 -6
- package/dist/runner/claude/session.js +7 -8
- package/dist/runner/codex/app-server/protocol-types.d.ts +4 -0
- package/dist/runner/codex/app-server/protocol-types.js +4 -0
- package/dist/runner/codex/app-server/runner.js +3 -0
- package/dist/runner/common/acp/base-acp-runner.js +7 -0
- package/dist/runner/common/connection-based-runner.d.ts +18 -0
- package/dist/runner/common/connection-based-runner.js +31 -0
- package/dist/runner/common/jsonrpc/client.js +6 -1
- package/dist/runner/common/jsonrpc/connection-manager.d.ts +20 -0
- package/dist/runner/common/jsonrpc/connection-manager.js +27 -1
- package/dist/runner/common/jsonrpc/transport.d.ts +29 -1
- package/dist/runner/common/jsonrpc/transport.js +79 -10
- package/dist/runner/common/spawning-runner.d.ts +49 -19
- package/dist/runner/common/spawning-runner.js +94 -54
- package/dist/runner/dsh/client.d.ts +1 -3
- package/dist/runner/dsh/client.js +0 -4
- package/dist/runner/dsh/types.d.ts +0 -36
- package/dist/runner/kimi/acp/runner.d.ts +18 -1
- package/dist/runner/kimi/acp/runner.js +100 -42
- package/dist/runner/kimi/acp/translator.d.ts +0 -1
- package/dist/runner/opencode/acp/translator.d.ts +0 -1
- package/dist/runner/pi/rpc/protocol-types.d.ts +4 -0
- package/dist/runner/pi/rpc/runner.js +3 -0
- package/dist/runner/resolve-agent-choices.js +0 -5
- package/package.json +2 -2
- package/dist/runner/common/process-stopper.d.ts +0 -7
- package/dist/runner/common/process-stopper.js +0 -8
- package/dist/runner/dsh/fake-dsh-server.d.ts +0 -60
- package/dist/runner/dsh/fake-dsh-server.js +0 -156
package/dist/router/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import { diffConfig, setNestedValue } from './config-diff.js';
|
|
|
11
11
|
import { getLogger } from '../logger/index.js';
|
|
12
12
|
import { stripPlaceholders } from '../inbound/placeholder.js';
|
|
13
13
|
import { activeRunUsage, clampInt } from './utils.js';
|
|
14
|
-
import { markdownDiv, buildSessionHistoryCard, paginationBar, parseJumpOffset, PAGE_JUMP_INVALID_HINT, } from './card-helpers.js';
|
|
14
|
+
import { markdownDiv, buildSessionHistoryCard, paginationBar, searchBar, parseJumpOffset, SEARCH_INPUT_NAME, PAGE_JUMP_INVALID_HINT, } from './card-helpers.js';
|
|
15
15
|
import { MAX_FILE_UPLOAD_SIZE } from '../connector/file-limits.js';
|
|
16
16
|
import { atomicWrite } from '../persistence/atomic-write.js';
|
|
17
17
|
import { checkLatestVersion as defaultCheckLatestVersion, isNewer as defaultIsNewer, runInstallLatest as defaultRunInstallLatest, } from '../update/index.js';
|
|
@@ -290,9 +290,11 @@ const IMMEDIATE_ACTION_CMDS = new Set([
|
|
|
290
290
|
'ls.browse',
|
|
291
291
|
'ls.switch',
|
|
292
292
|
'ls.page', // control operation: paginate only, never spawns claude
|
|
293
|
+
'ls.filter', // control operation: refilter the /ls list only
|
|
293
294
|
'resume.page', // control operation: paginate only, never spawns claude
|
|
294
295
|
'active.page', // control operation: paginate active card
|
|
295
296
|
'ws.page', // control operation: paginate /ws list only
|
|
297
|
+
'ws.filter', // control operation: refilter the /ws list only
|
|
296
298
|
'ws.remove',
|
|
297
299
|
'ws.sort', // control operation: toggle sort mode only
|
|
298
300
|
'resume.use',
|
|
@@ -322,6 +324,19 @@ const IMMEDIATE_ACTION_CMDS = new Set([
|
|
|
322
324
|
function payloadOffset(value) {
|
|
323
325
|
return Math.max(0, Math.trunc(Number(value.offset) || 0));
|
|
324
326
|
}
|
|
327
|
+
/**
|
|
328
|
+
* 搜索框提交值单源读取:`inputValue` 主路(CardKit 2.0 input 提交(键盘回车/
|
|
329
|
+
* 完成键)经 raw `action.input_value` 回传,SDK normalizer 会丢弃
|
|
330
|
+
* `action.input_value`,依赖 connector 的 includeRawEvent)+
|
|
331
|
+
* `formValue[searchInput]` 回退。空串/纯空白一律归一为 undefined = 清除筛选,
|
|
332
|
+
* 不是报错也不是无操作。「清除筛选」按钮带 `clearQuery`,直接短路为 undefined。
|
|
333
|
+
*/
|
|
334
|
+
function searchQueryFrom(value) {
|
|
335
|
+
if (value.clearQuery)
|
|
336
|
+
return undefined;
|
|
337
|
+
const raw = value.inputValue ?? value.formValue?.[SEARCH_INPUT_NAME];
|
|
338
|
+
return raw?.trim() || undefined;
|
|
339
|
+
}
|
|
325
340
|
/** 卡片 cardAction payload 缺字段的统一报错文案(原先 12 处手写且已漂移出两种前缀)。 */
|
|
326
341
|
const CARD_PAYLOAD_MISSING = '⚠️ 卡片 payload 缺少必要信息';
|
|
327
342
|
export class CommandRouter {
|
|
@@ -524,8 +539,12 @@ export class CommandRouter {
|
|
|
524
539
|
return;
|
|
525
540
|
case 'ls.page':
|
|
526
541
|
return this.handleLsPage(value, ctx);
|
|
542
|
+
case 'ls.filter':
|
|
543
|
+
return this.handleLsFilter(value, ctx);
|
|
527
544
|
case 'ws.page':
|
|
528
545
|
return this.handleWsPage(value, ctx);
|
|
546
|
+
case 'ws.filter':
|
|
547
|
+
return this.handleWsFilter(value, ctx);
|
|
529
548
|
case 'ws.use':
|
|
530
549
|
return await this.handleWsUse(value, ctx);
|
|
531
550
|
case 'ws.sort':
|
|
@@ -932,7 +951,7 @@ export class CommandRouter {
|
|
|
932
951
|
return;
|
|
933
952
|
}
|
|
934
953
|
// Build edit card
|
|
935
|
-
// CardKit 2.0 input
|
|
954
|
+
// CardKit 2.0 input 提交(回车/完成键)时输入值走 raw.action.input_value
|
|
936
955
|
// (SDK normalizer 丢弃,需 connector includeRawEvent: true + index.ts 从 raw 提取)。
|
|
937
956
|
// 用 column_set + input + behaviors,不用 form 容器(form 触发 300123 无 submit button /
|
|
938
957
|
// 200621 嵌套 column,submit-typed button 也被 CardKit 2.0 拒绝 HTTP 400)。
|
|
@@ -952,7 +971,7 @@ export class CommandRouter {
|
|
|
952
971
|
{ tag: 'hr' },
|
|
953
972
|
{
|
|
954
973
|
tag: 'div',
|
|
955
|
-
text: { tag: 'lark_md', content: '💡
|
|
974
|
+
text: { tag: 'lark_md', content: '💡 输入新内容后按回车提交' },
|
|
956
975
|
},
|
|
957
976
|
{
|
|
958
977
|
tag: 'column_set',
|
|
@@ -1126,11 +1145,11 @@ export class CommandRouter {
|
|
|
1126
1145
|
try {
|
|
1127
1146
|
card =
|
|
1128
1147
|
targetPath && fs.existsSync(targetPath) && fs.statSync(targetPath).isDirectory()
|
|
1129
|
-
? this.cmdLs([targetPath], ctx, offset, value.root)
|
|
1130
|
-
: this.cmdLs([], ctx, offset, value.root);
|
|
1148
|
+
? this.cmdLs([targetPath], ctx, offset, value.root, value.q)
|
|
1149
|
+
: this.cmdLs([], ctx, offset, value.root, value.q);
|
|
1131
1150
|
}
|
|
1132
1151
|
catch {
|
|
1133
|
-
card = this.cmdLs([], ctx, offset, value.root);
|
|
1152
|
+
card = this.cmdLs([], ctx, offset, value.root, value.q);
|
|
1134
1153
|
}
|
|
1135
1154
|
await this.bridge.updateCardInPlace(card.card, ctx);
|
|
1136
1155
|
}
|
|
@@ -1160,11 +1179,39 @@ export class CommandRouter {
|
|
|
1160
1179
|
if (!isDir) {
|
|
1161
1180
|
return { toast: { type: 'error', content: `路径无效: ${resolvedTarget}` } };
|
|
1162
1181
|
}
|
|
1163
|
-
const card = this.cmdLs([resolvedTarget], ctx, paging.offset, value.root);
|
|
1182
|
+
const card = this.cmdLs([resolvedTarget], ctx, paging.offset, value.root, value.q);
|
|
1164
1183
|
// 直接更新卡片,与 ls.browse/ls.refresh 行为一致
|
|
1165
1184
|
await this.bridge.updateCardInPlace(card.card, ctx);
|
|
1166
1185
|
return { toast: { type: 'success', content: '' } };
|
|
1167
1186
|
}
|
|
1187
|
+
/**
|
|
1188
|
+
* Handle ls.filter: 按搜索框提交的关键词重新渲染当前目录卡。
|
|
1189
|
+
*
|
|
1190
|
+
* offset 恒重置为 0(新筛选从第 1 页开始)。路径校验与 TOCTOU 兜底照
|
|
1191
|
+
* handleLsPage——校验失败只回错误 toast,绝不动卡片(否则用户看到一张空卡)。
|
|
1192
|
+
* ls.browse / ls.switch 的 value 里刻意不带 q,换目录即清除筛选(设计文档 §2.3)。
|
|
1193
|
+
*/
|
|
1194
|
+
async handleLsFilter(value, ctx) {
|
|
1195
|
+
const targetPath = value.path;
|
|
1196
|
+
if (!targetPath) {
|
|
1197
|
+
return { toast: { type: 'error', content: '卡片 payload 缺少 path' } };
|
|
1198
|
+
}
|
|
1199
|
+
const q = searchQueryFrom(value);
|
|
1200
|
+
const resolvedTarget = path.resolve(targetPath);
|
|
1201
|
+
let isDir;
|
|
1202
|
+
try {
|
|
1203
|
+
isDir = fs.existsSync(resolvedTarget) && fs.statSync(resolvedTarget).isDirectory();
|
|
1204
|
+
}
|
|
1205
|
+
catch {
|
|
1206
|
+
isDir = false;
|
|
1207
|
+
}
|
|
1208
|
+
if (!isDir) {
|
|
1209
|
+
return { toast: { type: 'error', content: `路径无效: ${resolvedTarget}` } };
|
|
1210
|
+
}
|
|
1211
|
+
const card = this.cmdLs([resolvedTarget], ctx, 0, value.root, q);
|
|
1212
|
+
await this.bridge.updateCardInPlace(card.card, ctx);
|
|
1213
|
+
return { toast: { type: 'success', content: q ? `筛选:"${q}"` : '已清除筛选' } };
|
|
1214
|
+
}
|
|
1168
1215
|
/**
|
|
1169
1216
|
* Handle resume.page: paginate the /resume session list in place.
|
|
1170
1217
|
* Mirrors handleLsPage — updates the same card, never sends a new one.
|
|
@@ -1287,18 +1334,19 @@ export class CommandRouter {
|
|
|
1287
1334
|
}
|
|
1288
1335
|
/**
|
|
1289
1336
|
* W2.8 单源:重建 order/ws 列表卡(不投递,card 进 callback 响应体用)。
|
|
1337
|
+
* `q` 只服务 ws 卡的关键词筛选;order 卡无此功能,不透传。
|
|
1290
1338
|
*/
|
|
1291
|
-
rebuildListCard(kind, offset, ctx) {
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1339
|
+
rebuildListCard(kind, offset, ctx, q) {
|
|
1340
|
+
if (kind === 'order')
|
|
1341
|
+
return this.cmdOrder([], ctx, offset).card;
|
|
1342
|
+
return this.cmdWs([], ctx, offset, q).card;
|
|
1295
1343
|
}
|
|
1296
1344
|
/**
|
|
1297
1345
|
* W2.8 单源:「重建列表卡 → updateCardInPlace」原地刷新骨架(列表卡删除/
|
|
1298
|
-
*
|
|
1346
|
+
* 翻页/移除/排序/筛选动作共用)。返回重建后的卡片;无卡时返回 undefined 且跳过更新。
|
|
1299
1347
|
*/
|
|
1300
1348
|
async refreshListCard(kind, value, ctx) {
|
|
1301
|
-
const card = this.rebuildListCard(kind, payloadOffset(value), ctx);
|
|
1349
|
+
const card = this.rebuildListCard(kind, payloadOffset(value), ctx, value.q);
|
|
1302
1350
|
if (!card)
|
|
1303
1351
|
return undefined;
|
|
1304
1352
|
await this.bridge.updateCardInPlace(card, ctx);
|
|
@@ -1361,7 +1409,7 @@ export class CommandRouter {
|
|
|
1361
1409
|
return { toast: { type: 'success', content: '' } };
|
|
1362
1410
|
}
|
|
1363
1411
|
/**
|
|
1364
|
-
* Handle order.aliasEdit: 展示别名编辑卡(input
|
|
1412
|
+
* Handle order.aliasEdit: 展示别名编辑卡(input,回车/完成键提交)。
|
|
1365
1413
|
* 有别名时预填;提交 `order.aliasInput` 处理(含校验与唯一性)。
|
|
1366
1414
|
*/
|
|
1367
1415
|
/**
|
|
@@ -1381,7 +1429,7 @@ export class CommandRouter {
|
|
|
1381
1429
|
}
|
|
1382
1430
|
// 列表卡显示的是截断版(≤100 字符 + ...),编辑卡预览保持一致
|
|
1383
1431
|
const displayText = order.text.length > 100 ? order.text.slice(0, 97) + '...' : order.text;
|
|
1384
|
-
// CardKit 2.0 input
|
|
1432
|
+
// CardKit 2.0 input 提交(回车/完成键;input_value 经 raw 回传,红线)。
|
|
1385
1433
|
// 不用 form 容器(触发 300123 无 submit button / 200621 嵌套 column)。
|
|
1386
1434
|
const editCard = {
|
|
1387
1435
|
schema: '2.0',
|
|
@@ -1436,7 +1484,7 @@ export class CommandRouter {
|
|
|
1436
1484
|
const order = this.orderStore.get().find((o) => o.id === value.orderId);
|
|
1437
1485
|
return this.showOrderEditCard(value, ctx, {
|
|
1438
1486
|
title: '✏️ 给指令起别名',
|
|
1439
|
-
hint: '💡
|
|
1487
|
+
hint: '💡 输入别名名后按回车提交;删除别名请点列表卡别名旁的 ✕',
|
|
1440
1488
|
inputName: 'aliasName',
|
|
1441
1489
|
placeholder: '输入 $别名名(如 all)...',
|
|
1442
1490
|
defaultValue: order?.alias ?? '',
|
|
@@ -1480,7 +1528,7 @@ export class CommandRouter {
|
|
|
1480
1528
|
});
|
|
1481
1529
|
}
|
|
1482
1530
|
/**
|
|
1483
|
-
* Handle order.textEdit: 展示指令文本编辑卡(input
|
|
1531
|
+
* Handle order.textEdit: 展示指令文本编辑卡(input,回车/完成键提交)。
|
|
1484
1532
|
* 预填当前 text(完整内容,不截断——input 组件有自有滚动条);
|
|
1485
1533
|
* 提交 `order.textInput` 处理(trim + 长度校验 + OrderStore.updateText)。
|
|
1486
1534
|
* 完全镜像 handleOrderAliasEdit 的 4 段结构(reload → find → 构造 editCard →
|
|
@@ -1492,7 +1540,7 @@ export class CommandRouter {
|
|
|
1492
1540
|
// input 组件 default_value 预填完整 text(不受截断影响),提交后生效完整文本
|
|
1493
1541
|
return this.showOrderEditCard(value, ctx, {
|
|
1494
1542
|
title: '✏️ 编辑指令',
|
|
1495
|
-
hint: '💡
|
|
1543
|
+
hint: '💡 修改后按回车提交;空白提交 = 报错;最多 200 字符',
|
|
1496
1544
|
inputName: 'text',
|
|
1497
1545
|
placeholder: '输入新的指令文本...',
|
|
1498
1546
|
defaultValue: order?.text ?? '',
|
|
@@ -1576,13 +1624,15 @@ export class CommandRouter {
|
|
|
1576
1624
|
if (!name) {
|
|
1577
1625
|
return { toast: { type: 'error', content: CARD_PAYLOAD_MISSING } };
|
|
1578
1626
|
}
|
|
1579
|
-
// Execute the removal
|
|
1580
|
-
//
|
|
1581
|
-
|
|
1627
|
+
// Execute the removal and let its result decide the toast: the card can be
|
|
1628
|
+
// a stale list (alias already deleted elsewhere), and an unconditional
|
|
1629
|
+
// "已删除" would then contradict what the refreshed card shows.
|
|
1630
|
+
const result = this.cmdWs(['remove', name], ctx);
|
|
1631
|
+
const text = result.text ?? `删除 workspace "${name}" 失败`;
|
|
1582
1632
|
// Rebuild the /ws list card and update it in place, preserving the page
|
|
1583
1633
|
// the user was on when they clicked 删除.
|
|
1584
1634
|
await this.refreshListCard('ws', value, ctx);
|
|
1585
|
-
return { toast: { type: 'success', content:
|
|
1635
|
+
return { toast: { type: text.startsWith('已删除') ? 'success' : 'error', content: text } };
|
|
1586
1636
|
}
|
|
1587
1637
|
/**
|
|
1588
1638
|
* Handle ws.page: paginate the /ws list in place.
|
|
@@ -1594,9 +1644,18 @@ export class CommandRouter {
|
|
|
1594
1644
|
return { toast: { type: 'error', content: paging.error } };
|
|
1595
1645
|
}
|
|
1596
1646
|
// cmdWs internally clamps stale/out-of-range offsets
|
|
1597
|
-
await this.refreshListCard('ws', { offset: paging.offset }, ctx);
|
|
1647
|
+
await this.refreshListCard('ws', { offset: paging.offset, q: value.q }, ctx);
|
|
1598
1648
|
return { toast: { type: 'success', content: '' } };
|
|
1599
1649
|
}
|
|
1650
|
+
/**
|
|
1651
|
+
* Handle ws.filter: 按搜索框提交的关键词重新渲染列表卡。
|
|
1652
|
+
* offset 恒重置为 0(新筛选从第 1 页开始);提交空串 = 清除筛选。
|
|
1653
|
+
*/
|
|
1654
|
+
async handleWsFilter(value, ctx) {
|
|
1655
|
+
const q = searchQueryFrom(value);
|
|
1656
|
+
await this.refreshListCard('ws', { offset: 0, q }, ctx);
|
|
1657
|
+
return { toast: { type: 'success', content: q ? `筛选:"${q}"` : '已清除筛选' } };
|
|
1658
|
+
}
|
|
1600
1659
|
/**
|
|
1601
1660
|
* Handle ws.sort: toggle sort preference and refresh the /ws list card.
|
|
1602
1661
|
* Sort preference is memory-only (not persisted); restart resets to 'recent'.
|
|
@@ -1606,7 +1665,7 @@ export class CommandRouter {
|
|
|
1606
1665
|
const current = this.wsSortPreference.get(userId) ?? 'recent';
|
|
1607
1666
|
const next = current === 'recent' ? 'alpha' : 'recent';
|
|
1608
1667
|
this.wsSortPreference.set(userId, next);
|
|
1609
|
-
await this.refreshListCard('ws', { offset: 0 }, ctx);
|
|
1668
|
+
await this.refreshListCard('ws', { offset: 0, q: value.q }, ctx);
|
|
1610
1669
|
const nextLabel = next === 'recent' ? '🕐 最近使用' : '🔤 字母顺序';
|
|
1611
1670
|
return {
|
|
1612
1671
|
toast: { type: 'success', content: `已切换为 ${nextLabel}` },
|
|
@@ -1741,7 +1800,7 @@ export class CommandRouter {
|
|
|
1741
1800
|
}
|
|
1742
1801
|
case 'config.input': {
|
|
1743
1802
|
// Handle input field: value.key is the field key.
|
|
1744
|
-
// 2026-07-04: CardKit 2.0 input
|
|
1803
|
+
// 2026-07-04: CardKit 2.0 input 提交(回车/完成键)触发 callback,回传 input_value。
|
|
1745
1804
|
// Fall back to formValue[key]: the SDK currently reports input values
|
|
1746
1805
|
// via action.formValue for form-wrapped inputs.
|
|
1747
1806
|
const key = value.key;
|
|
@@ -2609,12 +2668,15 @@ ${sessionCwdLine}${agentLines.map((l) => `- ${l}`).join('\n')}
|
|
|
2609
2668
|
* @param rootDir 浏览起点:卡片「返回」按钮回到这里。省略时默认 = 本次列出的
|
|
2610
2669
|
* 目录(`/ls <dir>` 的起点即该目录),因此「返回」不会把用户
|
|
2611
2670
|
* 丢回 workspace cwd(用户明确反馈过)。
|
|
2671
|
+
* @param q 关键词筛选:只匹配**当前层**条目名(不递归),大小写不敏感。
|
|
2672
|
+
* 省略/空 = 无筛选。
|
|
2612
2673
|
*/
|
|
2613
|
-
cmdLs(args, ctx, offset = 0, rootDir) {
|
|
2674
|
+
cmdLs(args, ctx, offset = 0, rootDir, q) {
|
|
2614
2675
|
const cwd = this.sessionStore.getCwd(ctx.userId);
|
|
2615
2676
|
if (!cwd) {
|
|
2616
2677
|
return { text: '请先使用 /cd <path> 设置工作目录' };
|
|
2617
2678
|
}
|
|
2679
|
+
const filter = q?.trim() || undefined;
|
|
2618
2680
|
// args can be:
|
|
2619
2681
|
// - [] : list current cwd
|
|
2620
2682
|
// - [dirName] : list subdirectory if it exists
|
|
@@ -2651,22 +2713,48 @@ ${sessionCwdLine}${agentLines.map((l) => `- ${l}`).join('\n')}
|
|
|
2651
2713
|
const browseRoot = rootDir ? path.resolve(cwd, rootDir) : targetDir;
|
|
2652
2714
|
try {
|
|
2653
2715
|
const entries = fs.readdirSync(targetDir, { withFileTypes: true });
|
|
2654
|
-
//
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
const
|
|
2716
|
+
// 逐条目分类。`Dirent.isFile()/isDirectory()` 对符号链接恒 false(旧实现
|
|
2717
|
+
// 因此完全不列链接);必须 stat 解析目标。单条目 stat 失败(悬空链接、
|
|
2718
|
+
// readdir 与 stat 之间被删、无权限)只让该条目降级为「大小未知」,不能
|
|
2719
|
+
// 让整次列目录失败——一个坏邻居毁掉整张卡是旧实现的第二宗罪。
|
|
2720
|
+
const dirs = [];
|
|
2721
|
+
const files = [];
|
|
2722
|
+
for (const entry of entries) {
|
|
2723
|
+
let isDir = entry.isDirectory();
|
|
2724
|
+
let size;
|
|
2725
|
+
if (!isDir) {
|
|
2726
|
+
try {
|
|
2727
|
+
const st = fs.statSync(path.join(targetDir, entry.name));
|
|
2728
|
+
isDir = st.isDirectory();
|
|
2729
|
+
if (!isDir)
|
|
2730
|
+
size = st.size;
|
|
2731
|
+
}
|
|
2732
|
+
catch {
|
|
2733
|
+
// 目标拿不到:按文件列出,size 留空
|
|
2734
|
+
}
|
|
2735
|
+
}
|
|
2736
|
+
if (isDir)
|
|
2737
|
+
dirs.push(entry.name);
|
|
2738
|
+
else
|
|
2739
|
+
files.push({ name: entry.name, size });
|
|
2740
|
+
}
|
|
2741
|
+
dirs.sort((a, b) => a.localeCompare(b));
|
|
2742
|
+
files.sort((a, b) => a.name.localeCompare(b.name));
|
|
2659
2743
|
// Merge dirs and files for pagination, preserving type info
|
|
2660
2744
|
const allItems = [
|
|
2661
|
-
...dirs.map((
|
|
2662
|
-
...files.map((f) => ({
|
|
2663
|
-
name: f.name,
|
|
2664
|
-
isDir: false,
|
|
2665
|
-
size: fs.statSync(path.join(targetDir, f.name)).size,
|
|
2666
|
-
})),
|
|
2745
|
+
...dirs.map((name) => ({ name, isDir: true })),
|
|
2746
|
+
...files.map((f) => ({ name: f.name, isDir: false, size: f.size })),
|
|
2667
2747
|
];
|
|
2748
|
+
// 关键词筛选:只匹配当前层条目名(不递归子目录)。大小写不敏感的子串包含
|
|
2749
|
+
// ——禁止 new RegExp(q)(用户搜 `foo(` 会直接抛)。插在排序之后、分页之前。
|
|
2750
|
+
const ql = filter?.toLowerCase();
|
|
2751
|
+
const visibleItems = ql
|
|
2752
|
+
? allItems.filter((i) => i.name.toLowerCase().includes(ql))
|
|
2753
|
+
: allItems;
|
|
2754
|
+
const visibleDirCount = visibleItems.reduce((n, i) => n + (i.isDir ? 1 : 0), 0);
|
|
2755
|
+
const visibleFileCount = visibleItems.length - visibleDirCount;
|
|
2668
2756
|
// Pagination calculations(clamp 到最后一页边界,原先不 clamp 会显示空页)
|
|
2669
|
-
const { totalCount, totalPages, safeOffset, currentPage, pageItems, hasPagination } = pageSlice(
|
|
2757
|
+
const { totalCount, totalPages, safeOffset, currentPage, pageItems, hasPagination } = pageSlice(visibleItems, offset, CommandRouter.LS_PAGE_SIZE);
|
|
2670
2758
|
// Check if we need to show parent directory button
|
|
2671
2759
|
const parentDir = path.dirname(targetDir);
|
|
2672
2760
|
const hasParent = parentDir !== targetDir;
|
|
@@ -2712,6 +2800,7 @@ ${sessionCwdLine}${agentLines.map((l) => `- ${l}`).join('\n')}
|
|
|
2712
2800
|
path: targetDir,
|
|
2713
2801
|
offset: safeOffset,
|
|
2714
2802
|
root: browseRoot,
|
|
2803
|
+
...(filter ? { q: filter } : {}),
|
|
2715
2804
|
},
|
|
2716
2805
|
},
|
|
2717
2806
|
],
|
|
@@ -2763,8 +2852,9 @@ ${sessionCwdLine}${agentLines.map((l) => `- ${l}`).join('\n')}
|
|
|
2763
2852
|
// Note: div+elements is not supported in CardKit 2.0, use column_set instead
|
|
2764
2853
|
const elements = [];
|
|
2765
2854
|
// Status line:只报条目构成;页码/总数交给分页栏文案行(同一信息不重复
|
|
2766
|
-
// 渲染两遍——2026-09-10
|
|
2767
|
-
|
|
2855
|
+
// 渲染两遍——2026-09-10 分页栏改成整行文案后重复会很明显)。筛选态一律用
|
|
2856
|
+
// 过滤后的计数,否则标题说 12 项、列表只有 3 项,卡片自相矛盾。
|
|
2857
|
+
const status = `\n共 ${visibleDirCount} 目录, ${visibleFileCount} 文件`;
|
|
2768
2858
|
// Header info + navigation buttons - show targetDir in header
|
|
2769
2859
|
elements.push({ tag: 'div', text: { tag: 'lark_md', content: `\`${targetDir}\`${status}` } });
|
|
2770
2860
|
elements.push({
|
|
@@ -2772,54 +2862,81 @@ ${sessionCwdLine}${agentLines.map((l) => `- ${l}`).join('\n')}
|
|
|
2772
2862
|
columns: headerElements.map((e) => ({ tag: 'column', width: 'auto', elements: [e] })),
|
|
2773
2863
|
});
|
|
2774
2864
|
elements.push({ tag: 'hr' });
|
|
2775
|
-
//
|
|
2865
|
+
// 搜索行:头部导航按钮之下、内容区之上(主导航在上、过滤紧随其后、内容区
|
|
2866
|
+
// 在下)。path/root 必须进 callback value,否则提交后 handler 不知道刷哪。
|
|
2867
|
+
elements.push(searchBar({
|
|
2868
|
+
cmd: 'ls.filter',
|
|
2869
|
+
placeholder: '搜索本层目录/文件名,输完回车',
|
|
2870
|
+
currentQuery: filter,
|
|
2871
|
+
extra: { path: targetDir, root: browseRoot },
|
|
2872
|
+
}));
|
|
2873
|
+
if (filter) {
|
|
2874
|
+
elements.push({
|
|
2875
|
+
tag: 'div',
|
|
2876
|
+
text: {
|
|
2877
|
+
tag: 'lark_md',
|
|
2878
|
+
content: `🔍 筛选:"${filter}" · 命中 ${totalCount} 项(点「清除筛选」取消)`,
|
|
2879
|
+
},
|
|
2880
|
+
});
|
|
2881
|
+
}
|
|
2882
|
+
// Section 1 + 2: Directories / Files (show only items on current page)
|
|
2776
2883
|
const pageDirs = pageItems.filter((i) => i.isDir);
|
|
2777
2884
|
const pageFiles = pageItems.filter((i) => !i.isDir);
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
tag: 'column_set',
|
|
2786
|
-
flex_mode: 'none',
|
|
2787
|
-
columns: [{ tag: 'column', width: 'auto', elements: [dirButton(d.name)] }],
|
|
2788
|
-
});
|
|
2789
|
-
}
|
|
2790
|
-
}
|
|
2791
|
-
else if (dirs.length === 0) {
|
|
2792
|
-
elements.push({ tag: 'div', text: { tag: 'lark_md', content: '无子目录' } });
|
|
2885
|
+
if (filter && visibleItems.length === 0) {
|
|
2886
|
+
// 筛选零命中:两个区标题都不渲染(两行空区标题只是噪音),搜索行仍在,
|
|
2887
|
+
// 用户可直接改词再回车,或点「清除筛选」。
|
|
2888
|
+
elements.push({
|
|
2889
|
+
tag: 'div',
|
|
2890
|
+
text: { tag: 'lark_md', content: `🔍 无匹配条目(关键词:"${filter}")` },
|
|
2891
|
+
});
|
|
2793
2892
|
}
|
|
2794
2893
|
else {
|
|
2795
2894
|
elements.push({
|
|
2796
2895
|
tag: 'div',
|
|
2797
|
-
text: { tag: 'lark_md', content:
|
|
2896
|
+
text: { tag: 'lark_md', content: `**📂 目录 (${visibleDirCount})**` },
|
|
2798
2897
|
});
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2898
|
+
if (pageDirs.length > 0) {
|
|
2899
|
+
for (const d of pageDirs) {
|
|
2900
|
+
elements.push({
|
|
2901
|
+
tag: 'column_set',
|
|
2902
|
+
flex_mode: 'none',
|
|
2903
|
+
columns: [{ tag: 'column', width: 'auto', elements: [dirButton(d.name)] }],
|
|
2904
|
+
});
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
else if (visibleDirCount === 0) {
|
|
2908
|
+
elements.push({ tag: 'div', text: { tag: 'lark_md', content: '无子目录' } });
|
|
2909
|
+
}
|
|
2910
|
+
else {
|
|
2808
2911
|
elements.push({
|
|
2809
|
-
tag: '
|
|
2810
|
-
|
|
2811
|
-
columns: [{ tag: 'column', width: 'auto', elements: [fileButton(f.name, f.size)] }],
|
|
2912
|
+
tag: 'div',
|
|
2913
|
+
text: { tag: 'lark_md', content: `(第 ${currentPage} 页无目录)` },
|
|
2812
2914
|
});
|
|
2813
2915
|
}
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
elements.push({ tag: 'div', text: { tag: 'lark_md', content: '无文件' } });
|
|
2817
|
-
}
|
|
2818
|
-
else {
|
|
2916
|
+
elements.push({ tag: 'hr' });
|
|
2917
|
+
// Section 2: Files
|
|
2819
2918
|
elements.push({
|
|
2820
2919
|
tag: 'div',
|
|
2821
|
-
text: { tag: 'lark_md', content:
|
|
2920
|
+
text: { tag: 'lark_md', content: `**📄 文件 (${visibleFileCount})**` },
|
|
2822
2921
|
});
|
|
2922
|
+
if (pageFiles.length > 0) {
|
|
2923
|
+
for (const f of pageFiles) {
|
|
2924
|
+
elements.push({
|
|
2925
|
+
tag: 'column_set',
|
|
2926
|
+
flex_mode: 'none',
|
|
2927
|
+
columns: [{ tag: 'column', width: 'auto', elements: [fileButton(f.name, f.size)] }],
|
|
2928
|
+
});
|
|
2929
|
+
}
|
|
2930
|
+
}
|
|
2931
|
+
else if (visibleFileCount === 0) {
|
|
2932
|
+
elements.push({ tag: 'div', text: { tag: 'lark_md', content: '无文件' } });
|
|
2933
|
+
}
|
|
2934
|
+
else {
|
|
2935
|
+
elements.push({
|
|
2936
|
+
tag: 'div',
|
|
2937
|
+
text: { tag: 'lark_md', content: `(第 ${currentPage} 页无文件)` },
|
|
2938
|
+
});
|
|
2939
|
+
}
|
|
2823
2940
|
}
|
|
2824
2941
|
// Pagination bar (only shown when there are more items than PAGE_SIZE)
|
|
2825
2942
|
if (hasPagination) {
|
|
@@ -2828,7 +2945,7 @@ ${sessionCwdLine}${agentLines.map((l) => `- ${l}`).join('\n')}
|
|
|
2828
2945
|
offset: safeOffset,
|
|
2829
2946
|
pageSize: CommandRouter.LS_PAGE_SIZE,
|
|
2830
2947
|
total: totalCount,
|
|
2831
|
-
extra: { path: targetDir, root: browseRoot },
|
|
2948
|
+
extra: { path: targetDir, root: browseRoot, ...(filter ? { q: filter } : {}) },
|
|
2832
2949
|
label: `**第 ${currentPage}/${totalPages} 页**(共 ${totalCount} 项)`,
|
|
2833
2950
|
});
|
|
2834
2951
|
elements.push({ tag: 'hr' });
|
|
@@ -2945,7 +3062,14 @@ ${sessionCwdLine}${agentLines.map((l) => `- ${l}`).join('\n')}
|
|
|
2945
3062
|
},
|
|
2946
3063
|
};
|
|
2947
3064
|
}
|
|
2948
|
-
|
|
3065
|
+
/**
|
|
3066
|
+
* `/ws` 实现(public:测试直接调用,替代 as unknown as,与 cmdLs 同款)。
|
|
3067
|
+
*
|
|
3068
|
+
* @param offset list 分支的分页起点(条目数)
|
|
3069
|
+
* @param q list 分支的关键词筛选:name 或完整 path 命中即保留,大小写
|
|
3070
|
+
* 不敏感。省略/空 = 无筛选。
|
|
3071
|
+
*/
|
|
3072
|
+
cmdWs(args, ctx, offset = 0, q) {
|
|
2949
3073
|
const sub = args[0]?.toLowerCase();
|
|
2950
3074
|
switch (sub) {
|
|
2951
3075
|
case 'save': {
|
|
@@ -2994,6 +3118,7 @@ ${sessionCwdLine}${agentLines.map((l) => `- ${l}`).join('\n')}
|
|
|
2994
3118
|
}
|
|
2995
3119
|
case 'list':
|
|
2996
3120
|
default: {
|
|
3121
|
+
const filter = q?.trim() || undefined;
|
|
2997
3122
|
const entries = this.workspaceStore.list();
|
|
2998
3123
|
const currentCwd = this.sessionStore.getCwd(ctx.userId);
|
|
2999
3124
|
const sortMode = this.wsSortPreference.get(ctx.userId) ?? 'recent';
|
|
@@ -3010,9 +3135,16 @@ ${sessionCwdLine}${agentLines.map((l) => `- ${l}`).join('\n')}
|
|
|
3010
3135
|
// Alphabetical by alias name
|
|
3011
3136
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
3012
3137
|
}
|
|
3138
|
+
// 关键词筛选:alias name 或完整 path 命中即保留,大小写不敏感的子串包含
|
|
3139
|
+
// (禁止 new RegExp(q)——用户搜 `foo(` 会直接抛)。插在排序之后、分页
|
|
3140
|
+
// 之前:先分页再过滤会出现某页只剩 1 条的残页,且翻页时筛选像是丢了。
|
|
3141
|
+
const ql = filter?.toLowerCase();
|
|
3142
|
+
const visible = ql
|
|
3143
|
+
? entries.filter((e) => e.name.toLowerCase().includes(ql) || e.path.toLowerCase().includes(ql))
|
|
3144
|
+
: entries;
|
|
3013
3145
|
// Pagination calculations (mirror cmdOrder): clamp stale/out-of-range
|
|
3014
3146
|
// offsets so prev/next always step by WS_PAGE_SIZE.
|
|
3015
|
-
const { totalCount, totalPages, safeOffset, currentPage, pageItems: pageEntries, hasPagination, } = pageSlice(
|
|
3147
|
+
const { totalCount, totalPages, safeOffset, currentPage, pageItems: pageEntries, hasPagination, } = pageSlice(visible, offset, WS_PAGE_SIZE);
|
|
3016
3148
|
// Build body elements: current cwd + workspace list with dividers
|
|
3017
3149
|
const bodyElements = [];
|
|
3018
3150
|
// Current working directory section
|
|
@@ -3020,13 +3152,35 @@ ${sessionCwdLine}${agentLines.map((l) => `- ${l}`).join('\n')}
|
|
|
3020
3152
|
tag: 'div',
|
|
3021
3153
|
text: { tag: 'lark_md', content: `📂 当前工作目录:\`${currentCwd ?? '(未设置)'}\`` },
|
|
3022
3154
|
});
|
|
3023
|
-
|
|
3024
|
-
|
|
3155
|
+
bodyElements.push({ tag: 'hr' });
|
|
3156
|
+
// 搜索行:「当前工作目录」之下、排序行之上(与 /ls 同一视觉动线:主信息
|
|
3157
|
+
// 在上、过滤紧随其后、列表在下)
|
|
3158
|
+
bodyElements.push(searchBar({
|
|
3159
|
+
cmd: 'ws.filter',
|
|
3160
|
+
placeholder: '搜索名称或路径,输完回车',
|
|
3161
|
+
currentQuery: filter,
|
|
3162
|
+
}));
|
|
3163
|
+
if (filter) {
|
|
3164
|
+
bodyElements.push({
|
|
3165
|
+
tag: 'div',
|
|
3166
|
+
text: {
|
|
3167
|
+
tag: 'lark_md',
|
|
3168
|
+
content: `🔍 筛选:"${filter}" · 命中 ${totalCount} 个 workspace(点「清除筛选」取消)`,
|
|
3169
|
+
},
|
|
3170
|
+
});
|
|
3171
|
+
}
|
|
3172
|
+
if (entries.length === 0 && !filter) {
|
|
3025
3173
|
bodyElements.push({
|
|
3026
3174
|
tag: 'div',
|
|
3027
3175
|
text: { tag: 'lark_md', content: '没有保存的 workspace' },
|
|
3028
3176
|
});
|
|
3029
3177
|
}
|
|
3178
|
+
else if (filter && visible.length === 0) {
|
|
3179
|
+
bodyElements.push({
|
|
3180
|
+
tag: 'div',
|
|
3181
|
+
text: { tag: 'lark_md', content: `🔍 无匹配条目(关键词:"${filter}")` },
|
|
3182
|
+
});
|
|
3183
|
+
}
|
|
3030
3184
|
else {
|
|
3031
3185
|
// Sort mode indicator + toggle button: placed above the list so the user
|
|
3032
3186
|
// sees "current mode" and "switch to X" before scanning entries.
|
|
@@ -3059,7 +3213,12 @@ ${sessionCwdLine}${agentLines.map((l) => `- ${l}`).join('\n')}
|
|
|
3059
3213
|
text: { tag: 'plain_text', content: `切换为 ${switchLabel}` },
|
|
3060
3214
|
type: 'default',
|
|
3061
3215
|
size: 'small',
|
|
3062
|
-
behaviors: [
|
|
3216
|
+
behaviors: [
|
|
3217
|
+
{
|
|
3218
|
+
type: 'callback',
|
|
3219
|
+
value: { cmd: 'ws.sort', ...(filter ? { q: filter } : {}) },
|
|
3220
|
+
},
|
|
3221
|
+
],
|
|
3063
3222
|
},
|
|
3064
3223
|
],
|
|
3065
3224
|
},
|
|
@@ -3087,7 +3246,12 @@ ${sessionCwdLine}${agentLines.map((l) => `- ${l}`).join('\n')}
|
|
|
3087
3246
|
behaviors: [
|
|
3088
3247
|
{
|
|
3089
3248
|
type: 'callback',
|
|
3090
|
-
value: {
|
|
3249
|
+
value: {
|
|
3250
|
+
cmd: 'ws.use',
|
|
3251
|
+
name: entry.name,
|
|
3252
|
+
offset: safeOffset,
|
|
3253
|
+
...(filter ? { q: filter } : {}),
|
|
3254
|
+
},
|
|
3091
3255
|
},
|
|
3092
3256
|
],
|
|
3093
3257
|
},
|
|
@@ -3105,7 +3269,12 @@ ${sessionCwdLine}${agentLines.map((l) => `- ${l}`).join('\n')}
|
|
|
3105
3269
|
behaviors: [
|
|
3106
3270
|
{
|
|
3107
3271
|
type: 'callback',
|
|
3108
|
-
value: {
|
|
3272
|
+
value: {
|
|
3273
|
+
cmd: 'ws.remove',
|
|
3274
|
+
name: entry.name,
|
|
3275
|
+
offset: safeOffset,
|
|
3276
|
+
...(filter ? { q: filter } : {}),
|
|
3277
|
+
},
|
|
3109
3278
|
},
|
|
3110
3279
|
],
|
|
3111
3280
|
},
|
|
@@ -3124,6 +3293,7 @@ ${sessionCwdLine}${agentLines.map((l) => `- ${l}`).join('\n')}
|
|
|
3124
3293
|
offset: safeOffset,
|
|
3125
3294
|
pageSize: WS_PAGE_SIZE,
|
|
3126
3295
|
total: totalCount,
|
|
3296
|
+
extra: filter ? { q: filter } : {},
|
|
3127
3297
|
label: `**${currentPage}/${totalPages}**(${totalCount})`,
|
|
3128
3298
|
prevText: '⬅',
|
|
3129
3299
|
nextText: '➡',
|
|
@@ -3836,7 +4006,7 @@ ${sessionCwdLine}${agentLines.map((l) => `- ${l}`).join('\n')}
|
|
|
3836
4006
|
],
|
|
3837
4007
|
},
|
|
3838
4008
|
{
|
|
3839
|
-
// 编辑:弹蓝色 header 输入卡(CardKit 2.0 input
|
|
4009
|
+
// 编辑:弹蓝色 header 输入卡(CardKit 2.0 input,回车提交),
|
|
3840
4010
|
// 镜像 order.aliasEdit 流程。order.textEdit 是 control-only action
|
|
3841
4011
|
// (isImmediateAction 注册),不 spawn agent。
|
|
3842
4012
|
tag: 'column',
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* 架构:ClaudeRunner 是 workspace-lifetime 的薄包装,进程与协议细节在
|
|
9
9
|
* ClaudeSession(src/runner/claude/session.ts,extends SpawningRunner 复用
|
|
10
|
-
* pid 文件/killOrphan/
|
|
10
|
+
* pid 文件/killOrphan/Terminator/心跳/退出分发器机制)。每次 run() 委托
|
|
11
11
|
* session:确保进程(可 --resume)→ 写 user 消息 → 消费事件直到本 turn result。
|
|
12
12
|
*/
|
|
13
13
|
import { ClaudeSessionReader } from '../../session/claude/index.js';
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* 生命周期:一个 workspace 一个长驻进程(lifetime='workspace')。每次
|
|
26
26
|
* run(message) = 写一条 user 消息 + 消费 stdout 事件直到本 turn 的 result;
|
|
27
27
|
* 进程在 turn 之间保持存活(stdin 不关闭),/stop / /new / /cd / 看门狗超时
|
|
28
|
-
* 时经
|
|
28
|
+
* 时经 Terminator 组杀,下条消息按 SessionStore 的 sessionId --resume。
|
|
29
29
|
*/
|
|
30
30
|
import { SpawningRunner } from '../common/spawning-runner.js';
|
|
31
31
|
import type { AgentEvent, SpawnOptions } from '../types.js';
|
|
@@ -54,7 +54,7 @@ export interface PermissionResult {
|
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
56
|
* ClaudeSession extends SpawningRunner 复用其 spawn/pid 文件/killOrphan/
|
|
57
|
-
*
|
|
57
|
+
* Terminator/SpawnHeartbeat/退出分发器机制(P1-1/P1-10/P1-11 契约保持),
|
|
58
58
|
* 但 run() 覆盖为「长驻 + 按 turn 消费」:进程跨 turn 存活,turn 结束以
|
|
59
59
|
* stream-json result 事件(非 compact)为界,而不是进程退出。
|
|
60
60
|
*/
|
|
@@ -107,10 +107,6 @@ export declare class ClaudeSession extends SpawningRunner {
|
|
|
107
107
|
* 直到本 turn 的 result。进程在 turn 结束后保持存活,供下一条消息复用。
|
|
108
108
|
*/
|
|
109
109
|
run(message: string, opts: SpawnOptions): AsyncGenerator<AgentEvent>;
|
|
110
|
-
/**
|
|
111
|
-
* 写一条用户消息到 stdin(--input-format stream-json 的 user 事件)。
|
|
112
|
-
*/
|
|
113
|
-
sendUserMessage(message: string): Promise<void>;
|
|
114
110
|
/**
|
|
115
111
|
* 回写审批响应(允许/拒绝)。
|
|
116
112
|
*/
|