dsh-lark-bot 0.17.0 → 0.17.2
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.md +7 -5
- package/README_EN.md +4 -4
- package/dist/cli.js +72 -38
- package/dist/cli.js.map +1 -1
- package/dist/plugin.d.ts +10 -0
- package/dist/plugin.js +72 -38
- package/dist/plugin.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -165,7 +165,7 @@ transcript 卡并持久绑定。私聊允许已授权用户;member scope 仅
|
|
|
165
165
|
|
|
166
166
|
**`/newg <群名>`**:自动新建私密群、拉发送者入群并回复群链接——新群即新 scope / 新会话,当前会话不受影响。需应用具备 `im:chat` 与 `im:chat.members:write_only` 权限。
|
|
167
167
|
|
|
168
|
-
同一 scope(私聊 / 群聊 / 话题)默认 **2 个任务并行**(`DSH_LARK_SCOPE_CONCURRENCY` 或 `/concurrency` 调整):多条消息以独立 run 并行推进,每个 run 使用独立 dsh session 与 runId
|
|
168
|
+
同一 scope(私聊 / 群聊 / 话题)默认 **2 个任务并行**(`DSH_LARK_SCOPE_CONCURRENCY` 或 `/concurrency` 调整):多条消息以独立 run 并行推进,每个 run 使用独立 dsh session 与 runId;SDK runtime 以 `scope + workspace` 为取消域,同一 scope 的并发 session 也会切到独立 runtime,因此卡片停止只影响该 run,`/stop` 只终止当前 scope 的全部运行,不会误停其他群。`/status` 查看当前 workspace 的 run,`/new` 只停止当前 workspace。
|
|
169
169
|
|
|
170
170
|
**会话状态卡**:`/status` 展示工作区、有效模型、session、显式投影绑定/cursor、active runs、版本、上下文占用、
|
|
171
171
|
累计 input / output / cache token,以及待审批 / 待提问 / 待批准计划;点击“刷新”会原位更新同一张卡。
|
|
@@ -395,7 +395,7 @@ dsh plugin --profile dsh-lark remove dsh-lark-bot
|
|
|
395
395
|
|
|
396
396
|
## 兼容性
|
|
397
397
|
|
|
398
|
-
- **DeepSeek Harness(`dsh`)**:已验证 **dsh 0.1.0-rc.8**(最后验证 2026-08-
|
|
398
|
+
- **DeepSeek Harness(`dsh`)**:已验证 **dsh 0.1.0-rc.8**(最后验证 2026-08-22:临时安装 + SDK JSON-RPC / ACP runtime initialize、工具/审批、live session 续接与 restart collision 探针),通过官方 `@deepseek-ai/dsh-sdk-client` / `@deepseek-ai/dsh-acp` 接入;
|
|
399
399
|
具体锁定版本、升级政策与自动化探测见 [`docs/COMPATIBILITY.md`](docs/COMPATIBILITY.md),
|
|
400
400
|
adapter 接入细节见 [`docs/adapter-notes.md`](docs/adapter-notes.md),rc.8 差异、已知风险和
|
|
401
401
|
自动/人工验证边界见 [`docs/DSH_RC8_AUDIT.md`](docs/DSH_RC8_AUDIT.md)。
|
|
@@ -409,10 +409,12 @@ dsh plugin --profile dsh-lark remove dsh-lark-bot
|
|
|
409
409
|
|
|
410
410
|
## 已知限制
|
|
411
411
|
|
|
412
|
-
- ACP 模式会话每次全新(上游限制,无续跑);SDK 协议暂无 mid-turn cancel
|
|
413
|
-
|
|
412
|
+
- ACP 模式会话每次全新(上游限制,无续跑);SDK 协议暂无 mid-turn cancel,停止操作会关闭
|
|
413
|
+
该 run 所属的隔离 runtime 并自动重建,不会关闭其他 scope 或并发 run 的 runtime。SDK 只在当前
|
|
414
|
+
bridge 进程仍持有同一个 live runtime 时原生续接 session;进程重启、停止或模型切换后会主动
|
|
415
|
+
新建 session 并回放 bridge transcript,避免把旧 ID 交给 rc.8 新 runtime 触发 `id collision`。
|
|
414
416
|
- 桥接引擎作为 dsh 插件在 dsh 进程内运行,agent 执行使用官方 dsh SDK runtime 子进程
|
|
415
|
-
(嵌套 runtime
|
|
417
|
+
(嵌套 runtime 是有意取舍,用于按 scope + workspace 隔离取消域与并行 run)。
|
|
416
418
|
唯一的进程级例外是默认安装的「安全网守护」——它独立于 dsh / Cordis 常驻,仅在 dsh
|
|
417
419
|
下线后接管飞书通道,正常运行时保持静默。
|
|
418
420
|
- 飞书文档评论、富文本回复为规划中能力,尚未实现。
|
package/README_EN.md
CHANGED
|
@@ -165,7 +165,7 @@ message mappings, plus only the unfinished card body needed to resume that card
|
|
|
165
165
|
|
|
166
166
|
**`/newg <group name>`**: auto-creates a private group, invites the sender and replies with a group link — chatting in the new group starts a fresh scope/session while the current session is untouched. Requires the `im:chat` and `im:chat.members:write_only` scopes.
|
|
167
167
|
|
|
168
|
-
Each scope (DM / group / topic) runs up to **2 tasks in parallel** by default (adjust with `DSH_LARK_SCOPE_CONCURRENCY` or `/concurrency`): successive messages become independent runs, each with its own dsh session and run id. `/status` lists runs for the current workspace; `/new` stops only that workspace
|
|
168
|
+
Each scope (DM / group / topic) runs up to **2 tasks in parallel** by default (adjust with `DSH_LARK_SCOPE_CONCURRENCY` or `/concurrency`): successive messages become independent runs, each with its own dsh session and run id. SDK runtimes use `scope + workspace` as their cancellation domain, and concurrent sessions in one scope are split into separate runtimes, so a card stop affects only that run and `/stop` affects only the current scope—never another group. `/status` lists runs for the current workspace; `/new` stops only that workspace.
|
|
169
169
|
|
|
170
170
|
**Session status card**: `/status` shows the workspace, effective model, session, explicit projection binding/cursor, active runs, version,
|
|
171
171
|
context occupancy, cumulative input/output/cache tokens, and pending approvals/questions/plans. **Refresh**
|
|
@@ -391,15 +391,15 @@ See [`docs/QUICK_START.md`](docs/QUICK_START.md) for installation details, state
|
|
|
391
391
|
|
|
392
392
|
## Compatibility
|
|
393
393
|
|
|
394
|
-
- **DeepSeek Harness (`dsh`)**: verified against **dsh 0.1.0-rc.8** (last verified 2026-08-
|
|
394
|
+
- **DeepSeek Harness (`dsh`)**: verified against **dsh 0.1.0-rc.8** (last verified 2026-08-22: clean temporary install, SDK JSON-RPC / ACP initialize, tool/approval, live-session resume, and restart-collision probes), connected through the official `@deepseek-ai/dsh-sdk-client` / `@deepseek-ai/dsh-acp`; see [`docs/COMPATIBILITY.md`](docs/COMPATIBILITY.md) for exact pins and probing, [`docs/adapter-notes.md`](docs/adapter-notes.md) for adapter details, and [`docs/DSH_RC8_AUDIT.md`](docs/DSH_RC8_AUDIT.md) for rc.8 risks and verification boundaries.
|
|
395
395
|
- **Runtime**: Node.js ≥ 22.19 (see `engines` in `package.json`).
|
|
396
396
|
- **Platform**: Linux / macOS / Windows (Feishu outbound WebSocket long connection; no public server, domain or tunneling required).
|
|
397
397
|
- The default adapter is the official **`@deepseek-ai/dsh-sdk-client`** (SDK JSON-RPC runtime with native continuation, streaming events, and the rc.8 approval answerer); `DSH_LARK_ADAPTER=acp` switches to the official **ACP server** with protocol-native approval; `headless` keeps the legacy subprocess fallback; `DSH_LARK_ADAPTER=web` drives the **local dsh web agent** (`session.prompt` + `/api/events.mux` — the web agent becomes the single writer, eliminating multi-writer session-log corruption at the root). On first start the bot creates the runtime profile at `~/.dsh/profiles/dsh-lark-sdk` (or `dsh-lark-acp`).
|
|
398
398
|
|
|
399
399
|
## Known limitations
|
|
400
400
|
|
|
401
|
-
- ACP sessions are always fresh (an upstream limit); the SDK protocol has no mid-turn cancel, so
|
|
402
|
-
- The engine runs in-process as a dsh plugin; agent execution uses the official dsh SDK runtime subprocess — a deliberate nested-runtime design for
|
|
401
|
+
- ACP sessions are always fresh (an upstream limit); the SDK protocol has no mid-turn cancel, so stopping a run closes and recreates only that run's isolated runtime. Other scopes and concurrent runs keep their own runtimes. Native SDK continuation is used only while this bridge process still owns the same live runtime; after restart, stop, or model switch the bridge creates a fresh session and replays its transcript instead of handing rc.8 a stale ID that would trigger `id collision`.
|
|
402
|
+
- The engine runs in-process as a dsh plugin; agent execution uses the official dsh SDK runtime subprocess — a deliberate nested-runtime design for scope/workspace cancellation domains and parallel runs. The one process-level exception is the safety-net guardian installed by default — a minimal resident process independent of dsh / Cordis that only takes over the Feishu channel after dsh goes down and stays silent otherwise.
|
|
403
403
|
- Feishu doc comments and rich-text replies are planned, not yet implemented.
|
|
404
404
|
- pnpm ≥ 10 build policy is handled by `setup`; when installing manually and `ERR_PNPM_IGNORED_BUILDS` appears, add `allowBuilds: { protobufjs: true }` to the profile's `pnpm-workspace.yaml` and retry.
|
|
405
405
|
|
package/dist/cli.js
CHANGED
|
@@ -64,7 +64,7 @@ var init_dsh_compat = __esm({
|
|
|
64
64
|
sdkServer: "0.1.0-rc.8",
|
|
65
65
|
acp: "0.1.0-rc.8",
|
|
66
66
|
node: ">=22.19.0",
|
|
67
|
-
verifiedAt: "2026-08-
|
|
67
|
+
verifiedAt: "2026-08-22"
|
|
68
68
|
};
|
|
69
69
|
}
|
|
70
70
|
});
|
|
@@ -1498,12 +1498,17 @@ var SdkDshAdapter = class {
|
|
|
1498
1498
|
}
|
|
1499
1499
|
run(options) {
|
|
1500
1500
|
const cwd = options.cwd ?? process.cwd();
|
|
1501
|
+
const runtimeKey = options.runtimeKey ?? cwd;
|
|
1501
1502
|
const route = {
|
|
1502
1503
|
provider: options.provider ?? this.provider,
|
|
1503
1504
|
model: options.model ?? this.model
|
|
1504
1505
|
};
|
|
1505
|
-
|
|
1506
|
-
const
|
|
1506
|
+
let sessionId = options.sessionId ?? `session-${randomUUID().replaceAll("-", "")}`;
|
|
1507
|
+
const current = this.runtimes.get(runtimeKey);
|
|
1508
|
+
if (current?.active) {
|
|
1509
|
+
sessionId = `session-${randomUUID().replaceAll("-", "")}`;
|
|
1510
|
+
}
|
|
1511
|
+
const entry = this.runtimeFor(runtimeKey, cwd, route, sessionId);
|
|
1507
1512
|
const stopRequested = { value: false };
|
|
1508
1513
|
entry.active += 1;
|
|
1509
1514
|
const handle = createSdkRun(entry.harness, options.prompt, {
|
|
@@ -1519,11 +1524,17 @@ var SdkDshAdapter = class {
|
|
|
1519
1524
|
events: handle.events,
|
|
1520
1525
|
stop: async () => {
|
|
1521
1526
|
stopRequested.value = true;
|
|
1522
|
-
await this.
|
|
1527
|
+
await this.closeEntry(entry);
|
|
1523
1528
|
},
|
|
1524
1529
|
waitForExit: (timeoutMs) => waitWithTimeout(handle.settled, timeoutMs)
|
|
1525
1530
|
};
|
|
1526
1531
|
}
|
|
1532
|
+
canResume(options) {
|
|
1533
|
+
const cwd = options.cwd ?? process.cwd();
|
|
1534
|
+
const runtimeKey = options.runtimeKey ?? cwd;
|
|
1535
|
+
const entry = this.runtimes.get(runtimeKey);
|
|
1536
|
+
return entry !== void 0 && entry.cwd === cwd && entry.sessionId === options.sessionId && entry.provider === (options.provider ?? this.provider) && entry.model === (options.model ?? this.model) && entry.active === 0 && !entry.retired;
|
|
1537
|
+
}
|
|
1527
1538
|
/** Close every runtime subprocess (used on bridge shutdown). */
|
|
1528
1539
|
async dispose() {
|
|
1529
1540
|
this.disposed = true;
|
|
@@ -1532,7 +1543,7 @@ var SdkDshAdapter = class {
|
|
|
1532
1543
|
const draining = [...this.draining];
|
|
1533
1544
|
this.draining.clear();
|
|
1534
1545
|
await Promise.allSettled(
|
|
1535
|
-
[...entries, ...draining].map((entry) =>
|
|
1546
|
+
[...entries, ...draining].map((entry) => this.closeHarness(entry))
|
|
1536
1547
|
);
|
|
1537
1548
|
}
|
|
1538
1549
|
createHarness(cwd, route) {
|
|
@@ -1549,57 +1560,59 @@ var SdkDshAdapter = class {
|
|
|
1549
1560
|
});
|
|
1550
1561
|
}
|
|
1551
1562
|
/**
|
|
1552
|
-
* Return the runtime
|
|
1553
|
-
*
|
|
1554
|
-
*
|
|
1555
|
-
*
|
|
1556
|
-
* runtime. An in-use harness is NOT killed: it is retired and closed once
|
|
1557
|
-
* its last in-flight run settles, so parallel tasks are never interrupted
|
|
1558
|
-
* by a model switch.
|
|
1563
|
+
* Return the runtime for one scope/workspace + native-session identity.
|
|
1564
|
+
* A concurrent fresh session or route change retires the previous entry,
|
|
1565
|
+
* which drains without being killed. This is required because rc.8 has no
|
|
1566
|
+
* per-session cancel: each stop handle must own the process it closes.
|
|
1559
1567
|
*/
|
|
1560
|
-
runtimeFor(cwd, route) {
|
|
1568
|
+
runtimeFor(runtimeKey, cwd, route, sessionId) {
|
|
1561
1569
|
if (this.disposed) {
|
|
1562
1570
|
throw new Error("SdkDshAdapter is disposed");
|
|
1563
1571
|
}
|
|
1564
|
-
const existing = this.runtimes.get(
|
|
1565
|
-
if (existing && existing.provider === route.provider && existing.model === route.model) {
|
|
1572
|
+
const existing = this.runtimes.get(runtimeKey);
|
|
1573
|
+
if (existing && existing.active === 0 && existing.cwd === cwd && existing.sessionId === sessionId && existing.provider === route.provider && existing.model === route.model) {
|
|
1566
1574
|
return existing;
|
|
1567
1575
|
}
|
|
1568
1576
|
if (existing) {
|
|
1569
|
-
this.runtimes.delete(
|
|
1577
|
+
this.runtimes.delete(runtimeKey);
|
|
1570
1578
|
if (existing.active > 0) {
|
|
1571
1579
|
existing.retired = true;
|
|
1572
1580
|
this.draining.add(existing);
|
|
1573
1581
|
} else {
|
|
1574
|
-
void
|
|
1582
|
+
void this.closeHarness(existing);
|
|
1575
1583
|
}
|
|
1576
1584
|
}
|
|
1577
1585
|
const entry = {
|
|
1578
1586
|
harness: withRetryableStart(this.harnessFactory(cwd, route)),
|
|
1587
|
+
runtimeKey,
|
|
1588
|
+
cwd,
|
|
1589
|
+
sessionId,
|
|
1579
1590
|
provider: route.provider,
|
|
1580
1591
|
model: route.model,
|
|
1581
1592
|
active: 0,
|
|
1582
1593
|
retired: false
|
|
1583
1594
|
};
|
|
1584
|
-
this.runtimes.set(
|
|
1595
|
+
this.runtimes.set(runtimeKey, entry);
|
|
1585
1596
|
return entry;
|
|
1586
1597
|
}
|
|
1587
1598
|
releaseEntry(entry) {
|
|
1588
1599
|
entry.active = Math.max(0, entry.active - 1);
|
|
1589
1600
|
if (entry.retired && entry.active === 0) {
|
|
1590
1601
|
this.draining.delete(entry);
|
|
1591
|
-
void
|
|
1602
|
+
void this.closeHarness(entry);
|
|
1592
1603
|
}
|
|
1593
1604
|
}
|
|
1594
|
-
async
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
this.runtimes.delete(cwd);
|
|
1598
|
-
try {
|
|
1599
|
-
await entry.harness.close();
|
|
1600
|
-
} catch (error) {
|
|
1601
|
-
void error;
|
|
1605
|
+
async closeEntry(entry) {
|
|
1606
|
+
if (this.runtimes.get(entry.runtimeKey) === entry) {
|
|
1607
|
+
this.runtimes.delete(entry.runtimeKey);
|
|
1602
1608
|
}
|
|
1609
|
+
entry.retired = true;
|
|
1610
|
+
this.draining.delete(entry);
|
|
1611
|
+
await this.closeHarness(entry);
|
|
1612
|
+
}
|
|
1613
|
+
closeHarness(entry) {
|
|
1614
|
+
entry.closing ??= entry.harness.close().catch(() => void 0);
|
|
1615
|
+
return entry.closing;
|
|
1603
1616
|
}
|
|
1604
1617
|
};
|
|
1605
1618
|
|
|
@@ -6522,6 +6535,7 @@ var initialState = {
|
|
|
6522
6535
|
idleTimeoutMinutes: void 0,
|
|
6523
6536
|
scopeOwner: void 0,
|
|
6524
6537
|
actionScope: void 0,
|
|
6538
|
+
actionRunId: void 0,
|
|
6525
6539
|
startedAtMs: void 0,
|
|
6526
6540
|
lastActivityMs: void 0
|
|
6527
6541
|
};
|
|
@@ -6688,6 +6702,7 @@ var MAX_VISIBLE_TOOL_CALLS = 40;
|
|
|
6688
6702
|
var MAX_TOOL_NAME_LENGTH = 160;
|
|
6689
6703
|
var MAX_OWNER_LENGTH = 160;
|
|
6690
6704
|
var MAX_ACTION_SCOPE_LENGTH = 512;
|
|
6705
|
+
var MAX_ACTION_RUN_ID_LENGTH = 160;
|
|
6691
6706
|
var MAX_FINAL_FALLBACK_LENGTH = 8e3;
|
|
6692
6707
|
function boundedText(value, limit) {
|
|
6693
6708
|
return value.length <= limit ? value : `${value.slice(0, Math.max(0, limit - 1))}\u2026`;
|
|
@@ -6734,12 +6749,16 @@ function fallbackSummaryText(state, locale, maxTools) {
|
|
|
6734
6749
|
if (state.finalDeliveryError) parts.push(zh ? "\u6700\u7EC8\u56DE\u7B54\u53D1\u9001\u5931\u8D25" : "Final answer delivery failed");
|
|
6735
6750
|
return parts.join(" \xB7 ").slice(0, 500);
|
|
6736
6751
|
}
|
|
6737
|
-
function stopButton(scope, locale) {
|
|
6752
|
+
function stopButton(scope, runId, locale) {
|
|
6738
6753
|
return {
|
|
6739
6754
|
tag: "button",
|
|
6740
6755
|
text: { tag: "plain_text", content: locale === "zh_cn" ? "\u23F9 \u7EC8\u6B62" : "\u23F9 Stop" },
|
|
6741
6756
|
type: "danger",
|
|
6742
|
-
value: {
|
|
6757
|
+
value: {
|
|
6758
|
+
cmd: "stop",
|
|
6759
|
+
...scope ? { scope: boundedText(scope, MAX_ACTION_SCOPE_LENGTH) } : {},
|
|
6760
|
+
...runId ? { runId: boundedText(runId, MAX_ACTION_RUN_ID_LENGTH) } : {}
|
|
6761
|
+
}
|
|
6743
6762
|
};
|
|
6744
6763
|
}
|
|
6745
6764
|
function toolBlock(tool) {
|
|
@@ -6851,7 +6870,7 @@ function renderStandard(state, now, locale, maxTools) {
|
|
|
6851
6870
|
if (fallback) elements.push(fallback);
|
|
6852
6871
|
if (state.terminal === "running") {
|
|
6853
6872
|
if (state.footer) elements.push(footerStatus(state.footer, state, now, locale));
|
|
6854
|
-
elements.push(stopButton(state.actionScope, locale));
|
|
6873
|
+
elements.push(stopButton(state.actionScope, state.actionRunId, locale));
|
|
6855
6874
|
}
|
|
6856
6875
|
return {
|
|
6857
6876
|
schema: "2.0",
|
|
@@ -6883,7 +6902,7 @@ function renderCompact(state, now, locale, maxTools) {
|
|
|
6883
6902
|
elements.push(footerStatus(state.footer, state, now, locale));
|
|
6884
6903
|
}
|
|
6885
6904
|
if (state.terminal === "running") {
|
|
6886
|
-
elements.push(stopButton(state.actionScope, locale));
|
|
6905
|
+
elements.push(stopButton(state.actionScope, state.actionRunId, locale));
|
|
6887
6906
|
}
|
|
6888
6907
|
return {
|
|
6889
6908
|
schema: "2.0",
|
|
@@ -6919,7 +6938,7 @@ function renderDetailed(state, now, locale, maxTools) {
|
|
|
6919
6938
|
if (fallback) elements.push(fallback);
|
|
6920
6939
|
if (state.terminal === "running") {
|
|
6921
6940
|
if (state.footer) elements.push(footerStatus(state.footer, state, now, locale));
|
|
6922
|
-
elements.push(stopButton(state.actionScope, locale));
|
|
6941
|
+
elements.push(stopButton(state.actionScope, state.actionRunId, locale));
|
|
6923
6942
|
}
|
|
6924
6943
|
return {
|
|
6925
6944
|
schema: "2.0",
|
|
@@ -6957,7 +6976,7 @@ function renderLegacyVariant(state, now, locale, maxTools) {
|
|
|
6957
6976
|
elements.push(compatibilityProcessSnapshot(state, locale, maxTools));
|
|
6958
6977
|
if (state.terminal === "running") {
|
|
6959
6978
|
if (state.footer) elements.push(footerStatus(state.footer, state, now, locale));
|
|
6960
|
-
elements.push(stopButton(state.actionScope, locale));
|
|
6979
|
+
elements.push(stopButton(state.actionScope, state.actionRunId, locale));
|
|
6961
6980
|
} else if (state.terminal === "interrupted") {
|
|
6962
6981
|
elements.push(noteMd(zh ? "_\u23F9 \u5DF2\u88AB\u4E2D\u65AD_" : "_\u23F9 Interrupted_"));
|
|
6963
6982
|
} else if (state.terminal === "idle_timeout") {
|
|
@@ -7008,7 +7027,7 @@ function minimalRunCard(state, bilingualFallback) {
|
|
|
7008
7027
|
body: {
|
|
7009
7028
|
elements: [
|
|
7010
7029
|
noteMd(locale === "zh_cn" ? "\u6267\u884C\u8BB0\u5F55\u8FC7\u957F\uFF0C\u8F83\u65E9\u7684\u8BE6\u60C5\u5DF2\u9690\u85CF\u3002" : "The execution history is too long; older details are hidden."),
|
|
7011
|
-
...state.terminal === "running" ? [stopButton(
|
|
7030
|
+
...state.terminal === "running" ? [stopButton(state.actionScope, state.actionRunId, locale)] : []
|
|
7012
7031
|
]
|
|
7013
7032
|
}
|
|
7014
7033
|
});
|
|
@@ -7283,8 +7302,16 @@ async function runAgentBatch(input) {
|
|
|
7283
7302
|
const activeInWorkspace = input.activeRuns.countWorkspace(input.scope, requestedCwd);
|
|
7284
7303
|
const workspace = input.workspaceManager ? await input.workspaceManager.ensure(input.scope, requestedCwd) : { cwd: requestedCwd };
|
|
7285
7304
|
const cwd = workspace.cwd;
|
|
7286
|
-
const
|
|
7287
|
-
const
|
|
7305
|
+
const runtimeKey = `${input.scope}\0${requestedCwd ?? ""}`;
|
|
7306
|
+
const storedSessionId = activeInWorkspace === 0 ? input.sessions.resumeFor(input.scope, requestedCwd) : void 0;
|
|
7307
|
+
const resuming = storedSessionId !== void 0 && input.adapter.resumeCapable === true && (input.adapter.canResume?.({
|
|
7308
|
+
runtimeKey,
|
|
7309
|
+
cwd,
|
|
7310
|
+
sessionId: storedSessionId,
|
|
7311
|
+
...input.provider === void 0 ? {} : { provider: input.provider },
|
|
7312
|
+
model: input.model
|
|
7313
|
+
}) ?? true);
|
|
7314
|
+
const sessionId = resuming ? storedSessionId : void 0;
|
|
7288
7315
|
try {
|
|
7289
7316
|
return terminalOutcome(await runAttempt(input, cwd, requestedCwd, sessionId, resuming, replyOptions));
|
|
7290
7317
|
} catch (error) {
|
|
@@ -7341,6 +7368,7 @@ async function runAttempt(input, cwd, workspaceCwd, sessionId, resuming, replyOp
|
|
|
7341
7368
|
const runId = randomUUID7();
|
|
7342
7369
|
const run = input.adapter.run({
|
|
7343
7370
|
runId,
|
|
7371
|
+
runtimeKey: `${input.scope}\0${workspaceCwd ?? ""}`,
|
|
7344
7372
|
prompt,
|
|
7345
7373
|
cwd,
|
|
7346
7374
|
sessionId,
|
|
@@ -7376,7 +7404,8 @@ async function runAttempt(input, cwd, workspaceCwd, sessionId, resuming, replyOp
|
|
|
7376
7404
|
startedAtMs: now,
|
|
7377
7405
|
lastActivityMs: now,
|
|
7378
7406
|
scopeOwner: input.scopeOwner,
|
|
7379
|
-
actionScope: input.scope
|
|
7407
|
+
actionScope: input.scope,
|
|
7408
|
+
actionRunId: runId
|
|
7380
7409
|
};
|
|
7381
7410
|
const stopRequested = { value: false };
|
|
7382
7411
|
const timeoutMs = input.runPolicies?.get(input.scope) ?? input.runTimeoutMs ?? 0;
|
|
@@ -12835,7 +12864,12 @@ ${msg.content}`,
|
|
|
12835
12864
|
}
|
|
12836
12865
|
}
|
|
12837
12866
|
if (value?.cmd === "stop") {
|
|
12838
|
-
|
|
12867
|
+
const runId = typeof value.runId === "string" ? value.runId : void 0;
|
|
12868
|
+
if (runId) {
|
|
12869
|
+
await deps.activeRuns.interruptRun(scope, runId);
|
|
12870
|
+
} else {
|
|
12871
|
+
await deps.activeRuns.interrupt(scope);
|
|
12872
|
+
}
|
|
12839
12873
|
return;
|
|
12840
12874
|
}
|
|
12841
12875
|
if (value?.cmd === "execution-mode" && deps.executionModes) {
|