dsh-session-bridge 0.3.1 → 0.3.2-alpha.1
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 +18 -1
- package/README.zh.md +16 -0
- package/dsh.plugin.json +2 -2
- package/lib/index.js +251 -49
- package/package.json +21 -20
- package/scripts/build.sh +18 -0
- package/scripts/check-dsh-compat.mjs +173 -0
- package/src/tools.ts +10 -2
package/README.md
CHANGED
|
@@ -119,13 +119,22 @@ time — not just its final reply — and act on it:
|
|
|
119
119
|
# type-check + bundle the host build + pack a tgz (DSH_CHECKOUT points at the dsh source checkout)
|
|
120
120
|
bash scripts/build.sh && npm run build:client
|
|
121
121
|
|
|
122
|
+
# type-check src/ against the dsh that is actually installed (no checkout needed)
|
|
123
|
+
npm run check:compat
|
|
124
|
+
|
|
122
125
|
# via the injector toolchain
|
|
123
126
|
dev_build_plugin dsh-session-bridge
|
|
124
127
|
```
|
|
125
128
|
|
|
126
129
|
`build.sh` type-links against a local DSH checkout and is only for local dev.
|
|
130
|
+
That checkout frequently lags the harness the plugin is loaded into, so a green
|
|
131
|
+
`build.sh` does **not** prove the plugin works on the running DSH — `build.sh`
|
|
132
|
+
warns when the two versions differ. Use `npm run check:compat` for that: it
|
|
133
|
+
type-checks `src/` against the `lib/types/*.d.ts` shipped inside the installed
|
|
134
|
+
DSH package, which is the exact API surface the plugin loads against.
|
|
135
|
+
|
|
127
136
|
The GitHub Actions CI (`ci.yml`) instead resolves the `@deepseek-ai/dsh-*`
|
|
128
|
-
prereleases from the registry — pinned to the `0.1.
|
|
137
|
+
prereleases from the registry — pinned to the `0.1.6-alpha.1` line, which is
|
|
129
138
|
the DSH API surface this code targets — then runs `pnpm typecheck` and
|
|
130
139
|
`pnpm build:client` (the self-contained `tsdown` bundle). Bump that pin
|
|
131
140
|
together with the code when you migrate to a newer DSH API.
|
|
@@ -149,6 +158,14 @@ publishing.
|
|
|
149
158
|
npx -p @deepseek-ai/dsh dsh plugin --profile web add dsh-session-bridge
|
|
150
159
|
```
|
|
151
160
|
|
|
161
|
+
A prerelease tag (`v0.3.2-alpha.1`) is published to its own dist-tag (`alpha`,
|
|
162
|
+
`beta`, `rc`) instead of `latest`, so it cannot displace the stable release for
|
|
163
|
+
other users. Opt in explicitly:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
npx -p @deepseek-ai/dsh dsh plugin --profile web add dsh-session-bridge@alpha
|
|
167
|
+
```
|
|
168
|
+
|
|
152
169
|
pnpm installs the published tarball and runs its `prepare` script (`tsdown`) to
|
|
153
170
|
ensure `lib/` is present, then `dsh` activates the bundle.
|
|
154
171
|
|
package/README.zh.md
CHANGED
|
@@ -87,10 +87,19 @@
|
|
|
87
87
|
# 类型检查 + 打包 host bundle + 生成 tgz(DSH_CHECKOUT 指向 dsh 源码 checkout)
|
|
88
88
|
bash scripts/build.sh && npm run build:client
|
|
89
89
|
|
|
90
|
+
# 针对"实际安装的 dsh"做类型检查(不需要 checkout)
|
|
91
|
+
npm run check:compat
|
|
92
|
+
|
|
90
93
|
# 或经注入器工具链
|
|
91
94
|
dev_build_plugin dsh-session-bridge
|
|
92
95
|
```
|
|
93
96
|
|
|
97
|
+
`build.sh` 按本地 dsh 源码 checkout 做类型链接,仅用于本地开发。该 checkout 常常
|
|
98
|
+
落后于插件实际加载进的 harness,因此 `build.sh` 通过**并不**代表插件在运行中的
|
|
99
|
+
DSH 上可用——两者版本不一致时 `build.sh` 会给出警告。要验证运行版本请用
|
|
100
|
+
`npm run check:compat`:它按已安装 DSH 包内随附的 `lib/types/*.d.ts`(即插件真正
|
|
101
|
+
加载的 API 面)对 `src/` 做类型检查。
|
|
102
|
+
|
|
94
103
|
## 部署
|
|
95
104
|
|
|
96
105
|
DSH web 从活动 profile 加载外部插件。本包是一个 **bundle**:`package.json` 声明了
|
|
@@ -107,6 +116,13 @@ DSH web 从活动 profile 加载外部插件。本包是一个 **bundle**:`pac
|
|
|
107
116
|
npx -p @deepseek-ai/dsh dsh plugin --profile web add dsh-session-bridge
|
|
108
117
|
```
|
|
109
118
|
|
|
119
|
+
预发布标签(`v0.3.2-alpha.1`)会发布到自己的 dist-tag(`alpha`/`beta`/`rc`),
|
|
120
|
+
而不会占用 `latest`,因此不会顶掉其他用户使用的稳定版。需要显式选用:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
npx -p @deepseek-ai/dsh dsh plugin --profile web add dsh-session-bridge@alpha
|
|
124
|
+
```
|
|
125
|
+
|
|
110
126
|
pnpm 会安装发布的 tarball 并运行其 `prepare` 脚本(`tsdown`)以确保 `lib/` 就绪,
|
|
111
127
|
随后 `dsh` 激活该 bundle。
|
|
112
128
|
|
package/dsh.plugin.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-external/dsh-session-bridge",
|
|
3
|
-
"version": "0.3.1",
|
|
3
|
+
"version": "0.3.2-alpha.1",
|
|
4
4
|
"main": "./lib/index.js",
|
|
5
5
|
"description": "会话桥:创建主会话 / 向任意会话发消息 / 等待回复 / 读取消息 / 按名或 id 查找会话(支持跨工作区);另含监控/调度主任务与归档会话。",
|
|
6
6
|
"engines": {
|
|
7
|
-
"dsh": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0"
|
|
7
|
+
"dsh": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0 || ^0.1.6-0"
|
|
8
8
|
},
|
|
9
9
|
"contributes": {
|
|
10
10
|
"tools": [
|
package/lib/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { homedir } from "node:os";
|
|
|
4
4
|
import { dirname, join, resolve } from "node:path";
|
|
5
5
|
import { appendFileSync, mkdirSync } from "node:fs";
|
|
6
6
|
import { randomUUID } from "node:crypto";
|
|
7
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.
|
|
7
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-home-paths/lib/index.js
|
|
8
8
|
/**
|
|
9
9
|
* Shared filesystem path helpers for DeepSeek Harness user data.
|
|
10
10
|
*
|
|
@@ -2200,7 +2200,7 @@ var Service = class Service {
|
|
|
2200
2200
|
}
|
|
2201
2201
|
};
|
|
2202
2202
|
//#endregion
|
|
2203
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.
|
|
2203
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-typert-protocol/lib/index.js
|
|
2204
2204
|
/** The one Remote failure class shared by owners, the Gateway, and consumers. */
|
|
2205
2205
|
/**
|
|
2206
2206
|
* One Remote call failure: a real Error carrying its stable code and typed
|
|
@@ -2345,7 +2345,7 @@ function validateName(subject, value) {
|
|
|
2345
2345
|
if (!isTypertRemoteSegment(value)) throw new TypeError(`typert-protocol: ${subject} must contain only RPC endpoint segment characters`);
|
|
2346
2346
|
}
|
|
2347
2347
|
//#endregion
|
|
2348
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-util-values@0.1.
|
|
2348
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-util-values@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-util-values/lib/index.js
|
|
2349
2349
|
/** Duplicate-install-safe JSON and immutable-value helpers. @module @deepseek-ai/dsh-util-values */
|
|
2350
2350
|
/**
|
|
2351
2351
|
* Mark an unreachable closed-union branch.
|
|
@@ -2557,7 +2557,7 @@ function deepFreeze(value) {
|
|
|
2557
2557
|
return value;
|
|
2558
2558
|
}
|
|
2559
2559
|
//#endregion
|
|
2560
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-util-crypto@0.1.
|
|
2560
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-util-crypto@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-util-crypto/lib/index.js
|
|
2561
2561
|
/**
|
|
2562
2562
|
* Random v4 UUID, minted from `crypto.getRandomValues`.
|
|
2563
2563
|
* @returns the UUID string.
|
|
@@ -2570,7 +2570,7 @@ function randomUUID$1() {
|
|
|
2570
2570
|
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
2571
2571
|
}
|
|
2572
2572
|
//#endregion
|
|
2573
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.
|
|
2573
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-brand/lib/index.js
|
|
2574
2574
|
/**
|
|
2575
2575
|
* Duplicate-install-safe nominal primitive helpers.
|
|
2576
2576
|
*
|
|
@@ -3187,11 +3187,11 @@ defineMethod("transform", [
|
|
|
3187
3187
|
"preserve"
|
|
3188
3188
|
], ({ inner }, isInner) => inner.toString(isInner));
|
|
3189
3189
|
//#endregion
|
|
3190
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.
|
|
3190
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-timeout/lib/index.js
|
|
3191
3191
|
/** Largest delay Node schedules without clamping it to one millisecond. */
|
|
3192
3192
|
const MAX_TIMER_DELAY_MS = 2147483647;
|
|
3193
3193
|
//#endregion
|
|
3194
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.
|
|
3194
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-llm/lib/index.js
|
|
3195
3195
|
/**
|
|
3196
3196
|
* Bound one `notice` summary to {@link CONTEXT_SUMMARY_MAX_CHARS}.
|
|
3197
3197
|
* @param summary - the producer's one-line account, of any length.
|
|
@@ -3441,13 +3441,15 @@ function failureSnapshot(value) {
|
|
|
3441
3441
|
const status = candidate.status;
|
|
3442
3442
|
const providerRetryAfterMs = candidate.providerRetryAfterMs;
|
|
3443
3443
|
const requestId = candidate.requestId;
|
|
3444
|
-
|
|
3444
|
+
const offloadImages = candidate.offloadImages;
|
|
3445
|
+
if (typeof message !== "string" || message.length === 0 || typeof code !== "string" || code.length === 0 || status !== void 0 && (!Number.isInteger(status) || status < 100 || status > 599) || providerRetryAfterMs !== void 0 && (!Number.isFinite(providerRetryAfterMs) || providerRetryAfterMs <= 0) || requestId !== void 0 && (typeof requestId !== "string" || requestId.length === 0) || offloadImages !== void 0 && (!Number.isSafeInteger(offloadImages) || offloadImages <= 0)) return void 0;
|
|
3445
3446
|
return Object.freeze({
|
|
3446
3447
|
message,
|
|
3447
3448
|
code,
|
|
3448
3449
|
...status === void 0 ? {} : { status },
|
|
3449
3450
|
...providerRetryAfterMs === void 0 ? {} : { providerRetryAfterMs },
|
|
3450
|
-
...requestId === void 0 ? {} : { requestId }
|
|
3451
|
+
...requestId === void 0 ? {} : { requestId },
|
|
3452
|
+
...offloadImages === void 0 ? {} : { offloadImages }
|
|
3451
3453
|
});
|
|
3452
3454
|
} catch (_sdkFailureGetter) {
|
|
3453
3455
|
return;
|
|
@@ -3686,7 +3688,8 @@ var LlmError = class extends HarnessError {
|
|
|
3686
3688
|
code,
|
|
3687
3689
|
...options?.status === void 0 ? {} : { status: options.status },
|
|
3688
3690
|
...options?.providerRetryAfterMs === void 0 ? {} : { providerRetryAfterMs: options.providerRetryAfterMs },
|
|
3689
|
-
...options?.requestId === void 0 ? {} : { requestId: options.requestId }
|
|
3691
|
+
...options?.requestId === void 0 ? {} : { requestId: options.requestId },
|
|
3692
|
+
...options?.offloadImages === void 0 ? {} : { offloadImages: options.offloadImages }
|
|
3690
3693
|
});
|
|
3691
3694
|
}
|
|
3692
3695
|
};
|
|
@@ -9077,7 +9080,7 @@ function superRefine(fn, params) {
|
|
|
9077
9080
|
return /* @__PURE__ */ _superRefine(fn, params);
|
|
9078
9081
|
}
|
|
9079
9082
|
//#endregion
|
|
9080
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.
|
|
9083
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-storage/lib/index.js
|
|
9081
9084
|
/**
|
|
9082
9085
|
* Backend-facing vocabulary of the storage hub: a backend owns one medium
|
|
9083
9086
|
* (a file-tree root, a database file) and exposes operation groups over it.
|
|
@@ -9088,7 +9091,7 @@ function superRefine(fn, params) {
|
|
|
9088
9091
|
/** Allowed format for unit and table names: safe as a file name and as a SQL identifier segment without escaping. */
|
|
9089
9092
|
const UNIT_NAME_RE = /^[a-z][a-z0-9_]*$/;
|
|
9090
9093
|
//#endregion
|
|
9091
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.
|
|
9094
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2_@deepseek-ai+ds_404bb44176e435660710548cd6a4e0aa/node_modules/@deepseek-ai/dsh-storage-domain/lib/index.js
|
|
9092
9095
|
/**
|
|
9093
9096
|
* Domain declaration vocabulary. A spec object is the single source of a
|
|
9094
9097
|
* domain's identity, layout, and record schemas: the owning package defines
|
|
@@ -10038,7 +10041,7 @@ var SessionMonitor = class {
|
|
|
10038
10041
|
}
|
|
10039
10042
|
};
|
|
10040
10043
|
//#endregion
|
|
10041
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.
|
|
10044
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2_@deepseek-ai+dsh-invaria_eaf7046112a9b60866fe7f69bc8f6f64/node_modules/@deepseek-ai/dsh-scope/lib/index.js
|
|
10042
10045
|
/**
|
|
10043
10046
|
* Shared insertion-ordered storage and effect ownership for scope-aware registries.
|
|
10044
10047
|
*
|
|
@@ -10317,7 +10320,92 @@ function scopeTarget(base, key) {
|
|
|
10317
10320
|
return carrier;
|
|
10318
10321
|
}
|
|
10319
10322
|
//#endregion
|
|
10320
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-
|
|
10323
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-sandbox@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2_@deepseek-ai+dsh-llm@0_1d3a97f96d2766469566ca2b01247bfa/node_modules/@deepseek-ai/dsh-sandbox/lib/index.js
|
|
10324
|
+
/**
|
|
10325
|
+
* The escalation vocabulary and choreography shared by every sandbox-enforcing
|
|
10326
|
+
* tool family (`@deepseek-ai/dsh-tool-bash`, `@deepseek-ai/dsh-tool-fs`): the
|
|
10327
|
+
* strictly-wider ladder, the argument-pairing validation, the model-facing
|
|
10328
|
+
* denial/hint markers, and {@link approveEscalation} — the ordered fail-closed
|
|
10329
|
+
* sequence that resolves a `sandbox_permissions` request through a
|
|
10330
|
+
* user-approval channel BEFORE anything executes. One home keeps the two
|
|
10331
|
+
* families' approval ordering and verbatim error texts from drifting apart.
|
|
10332
|
+
*
|
|
10333
|
+
* The channel is a minimal STRUCTURAL function shape ({@link EscalationAsk}),
|
|
10334
|
+
* not the approval service type: the tool layer — which owns the agent, the
|
|
10335
|
+
* call id, and the tool name — closes over `ctx.approval.request(...)` and
|
|
10336
|
+
* hands the closure down, so this package never depends on the approval or
|
|
10337
|
+
* agent packages.
|
|
10338
|
+
*
|
|
10339
|
+
* @module dsh-sandbox/escalation
|
|
10340
|
+
*/
|
|
10341
|
+
/**
|
|
10342
|
+
* The strictly-wider table: what a call whose effective mode is the key may
|
|
10343
|
+
* escalate TO. Checked at EXECUTION, never baked into a tool schema — the
|
|
10344
|
+
* schema's enum is {@link ESCALATION_TARGETS}, because schemas are
|
|
10345
|
+
* registry-global while the effective mode is per-call truth.
|
|
10346
|
+
*/
|
|
10347
|
+
const WIDER_MODES = {
|
|
10348
|
+
"read-only": ["workspace-write", "danger-full-access"],
|
|
10349
|
+
"workspace-write": ["danger-full-access"]
|
|
10350
|
+
};
|
|
10351
|
+
/**
|
|
10352
|
+
* The closed escalation-target vocabulary — every mode a call could ever
|
|
10353
|
+
* escalate TO (`read-only` is the floor; nothing escalates to it). Advertised
|
|
10354
|
+
* whenever the mounted capability confines: cutting the enum down to the modes
|
|
10355
|
+
* wider than the composition's DEFAULT would strand a session whose effective
|
|
10356
|
+
* mode sits below it (a `danger-full-access` default would advertise nothing
|
|
10357
|
+
* while a narrower-switched session stays confined with no lever).
|
|
10358
|
+
*/
|
|
10359
|
+
const ESCALATION_TARGETS = ["workspace-write", "danger-full-access"];
|
|
10360
|
+
/**
|
|
10361
|
+
* Validate the escalation argument pairing a tool schema cannot express:
|
|
10362
|
+
* `sandbox_permissions` and `justification` travel together — an approval
|
|
10363
|
+
* prompt without a reason, or a reason driving nothing, is a malformed ask —
|
|
10364
|
+
* and the justification must be a non-empty sentence.
|
|
10365
|
+
* @param sandboxPermissions - the raw `sandbox_permissions` argument, if given.
|
|
10366
|
+
* @param justification - the raw `justification` argument, if given.
|
|
10367
|
+
*/
|
|
10368
|
+
function validateEscalationArgs(sandboxPermissions, justification) {
|
|
10369
|
+
if (sandboxPermissions !== void 0 && justification === void 0) throw new Error("invalid escalation: sandbox_permissions requires a justification");
|
|
10370
|
+
if (justification !== void 0 && sandboxPermissions === void 0) throw new Error("invalid escalation: justification is only valid together with sandbox_permissions");
|
|
10371
|
+
if (justification !== void 0 && justification.trim().length === 0) throw new Error("invalid justification: expected a non-empty sentence");
|
|
10372
|
+
}
|
|
10373
|
+
/**
|
|
10374
|
+
* Resolve a sandbox-escalation request BEFORE anything executes: check strict
|
|
10375
|
+
* widening against the call's effective mode, then resolve the approval
|
|
10376
|
+
* channel, then map every outcome — the ordered fail-closed sequence both
|
|
10377
|
+
* enforcing families share. Returns the granted mode to stamp onto exactly
|
|
10378
|
+
* this call; throws the distinct verbatim text for every other path (a
|
|
10379
|
+
* non-widening request, a missing approval service, an agent-less execution,
|
|
10380
|
+
* a rejection, a cancellation, an unanswerable ask) — the tool registry turns
|
|
10381
|
+
* the throw into the call's isError result, and nothing has run. A
|
|
10382
|
+
* non-widening request never prompts a human.
|
|
10383
|
+
* @param request - the escalation to judge (see {@link EscalationRequest}).
|
|
10384
|
+
* @param approval - the approval ingredients the tool holds (see {@link EscalationApproval}).
|
|
10385
|
+
* @returns the granted mode, consumed by the one call that asked.
|
|
10386
|
+
*/
|
|
10387
|
+
async function approveEscalation(request, approval) {
|
|
10388
|
+
const { requestedMode: mode, effectiveMode, justification, subject } = request;
|
|
10389
|
+
if (!(WIDER_MODES[effectiveMode] ?? []).includes(mode)) throw new Error(`sandbox escalation to "${mode}" is not strictly wider than this call's current "${effectiveMode}" mode`);
|
|
10390
|
+
if (approval.approver === void 0) throw new Error(`sandbox escalation to "${mode}" requires approval, but no approval service is composed`);
|
|
10391
|
+
if (approval.agent === void 0) throw new Error(`sandbox escalation to "${mode}" requires approval, but the call has no agent to route it through`);
|
|
10392
|
+
const outcome = await approval.approver.request({
|
|
10393
|
+
agent: approval.agent,
|
|
10394
|
+
toolName: approval.toolName,
|
|
10395
|
+
callId: approval.callId,
|
|
10396
|
+
reason: `escalate sandbox to ${mode}: ${justification}`,
|
|
10397
|
+
...approval.signal ? { signal: approval.signal } : {}
|
|
10398
|
+
});
|
|
10399
|
+
switch (outcome) {
|
|
10400
|
+
case "allowed-once": return mode;
|
|
10401
|
+
case "rejected": throw new Error(`the user rejected escalating this ${subject} to "${mode}"`);
|
|
10402
|
+
case "cancelled": throw new Error(`approval for escalating to "${mode}" was cancelled`);
|
|
10403
|
+
case "unavailable": throw new Error(`sandbox escalation to "${mode}" requires approval, but no approval channel is available`);
|
|
10404
|
+
default: return assertNever(outcome, "EscalationOutcome");
|
|
10405
|
+
}
|
|
10406
|
+
}
|
|
10407
|
+
//#endregion
|
|
10408
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.6-alpha.1_e89197212305e1b19bd6df05221bc44b/node_modules/@deepseek-ai/dsh-tools/lib/index.js
|
|
10321
10409
|
/**
|
|
10322
10410
|
* Enforced JSON Schema subset shared by tool outputs, generated PTC mode
|
|
10323
10411
|
* types, subagents, and workflows. The subset accepts any JSON root, an
|
|
@@ -11188,7 +11276,7 @@ const TYPESCRIPT_FLAVOR = {
|
|
|
11188
11276
|
description: "Execute a TypeScript program against the available tools. Takes two required arguments: `code`, the BODY of an async function (erasable syntax only; top-level `await` and `return` work), and `description`, a short summary of what the program does. Call tools as `await tools.name(args)` per the declarations in the system prompt. Only what you print or return is program output — curate it. Image-bearing subtool results are attached after the run.",
|
|
11189
11277
|
codeDescription: "The program: the body of an async TypeScript function."
|
|
11190
11278
|
};
|
|
11191
|
-
/** Per-language `run_code` schema flavors (see {@link RunCodeFlavor}); one entry per {@link
|
|
11279
|
+
/** Per-language `run_code` schema flavors (see {@link RunCodeFlavor}); one entry per {@link PtcSdkLanguage}. */
|
|
11192
11280
|
const RUN_CODE_FLAVORS = {
|
|
11193
11281
|
typescript: TYPESCRIPT_FLAVOR,
|
|
11194
11282
|
python: {
|
|
@@ -11203,17 +11291,48 @@ const RUN_CODE_FLAVORS = {
|
|
|
11203
11291
|
* can never drift.
|
|
11204
11292
|
*/
|
|
11205
11293
|
const RUN_CODE_DESCRIPTION_PARAM_DESCRIPTION = "Clear, concise description of what this program does in active voice, 5-10 words (shown in the UI). Examples: \"Count TODO markers across packages\"; \"Read failing test and its fixture\"; \"Rename config key in every cordis.yml\".";
|
|
11294
|
+
const RUN_CODE_CONTROLS = {
|
|
11295
|
+
timeoutMs: {
|
|
11296
|
+
type: "number",
|
|
11297
|
+
description: "Positive elapsed-time budget in milliseconds, capped by the deployment maximum."
|
|
11298
|
+
},
|
|
11299
|
+
sandbox_permissions: {
|
|
11300
|
+
type: "string",
|
|
11301
|
+
enum: [...ESCALATION_TARGETS],
|
|
11302
|
+
description: "Wider sandbox mode for this complete program execution; requires justification and approval."
|
|
11303
|
+
},
|
|
11304
|
+
justification: {
|
|
11305
|
+
type: "string",
|
|
11306
|
+
description: "Reason this complete program needs wider access, shown to the user for approval."
|
|
11307
|
+
}
|
|
11308
|
+
};
|
|
11309
|
+
function controlParameters(runtime) {
|
|
11310
|
+
if (runtime === void 0) return RUN_CODE_CONTROLS;
|
|
11311
|
+
return {
|
|
11312
|
+
...runtime.timeout === void 0 ? {} : { timeoutMs: {
|
|
11313
|
+
...RUN_CODE_CONTROLS.timeoutMs,
|
|
11314
|
+
description: `Positive elapsed-time budget in milliseconds, including nested tool and approval waits. Default ${runtime.timeout.defaultMs}; capped at ${runtime.timeout.maxMs}. Zero does not disable the deadline.`
|
|
11315
|
+
} },
|
|
11316
|
+
...runtime.sandboxMode === void 0 ? {} : {
|
|
11317
|
+
sandbox_permissions: RUN_CODE_CONTROLS.sandbox_permissions,
|
|
11318
|
+
justification: RUN_CODE_CONTROLS.justification
|
|
11319
|
+
}
|
|
11320
|
+
};
|
|
11321
|
+
}
|
|
11322
|
+
function escalationGuidance(runtime) {
|
|
11323
|
+
return runtime?.sandboxMode === void 0 ? "" : " A sandbox escalation approves this complete program for one execution only. Nested tools retain their own policies and approvals. Request wider access only after evidence of a denial. Earlier effects may already have completed: inspect them before explicitly retrying. Programs are never replayed automatically.";
|
|
11324
|
+
}
|
|
11206
11325
|
/**
|
|
11207
11326
|
* Resolve the {@link RunCodeFlavor} for the loaded runtime's language, read at
|
|
11208
11327
|
* schema-emission time so the model-visible `run_code` schema always matches
|
|
11209
11328
|
* the SDK section's language. `peekRuntime` returns `undefined` only when no
|
|
11210
11329
|
* runtime is mounted, which reaches this function through definition readers
|
|
11211
11330
|
* and `schemas()` — the doc-catalog harvest is the only shipped one, and none
|
|
11212
|
-
* of them feeds a model, because `wireSchemas` calls `
|
|
11331
|
+
* of them feeds a model, because `wireSchemas` calls `requirePtcRuntime`
|
|
11213
11332
|
* before projecting — so that path degrades to {@link TYPESCRIPT_FLAVOR}. A
|
|
11214
11333
|
* mounted runtime whose language has no flavor entry fails loud, exactly as
|
|
11215
|
-
* `
|
|
11216
|
-
* `SDK_RENDERERS` is the compiler's job ({@link
|
|
11334
|
+
* `requirePtcRuntime` rejects it at assembly. Keeping this table in step with
|
|
11335
|
+
* `SDK_RENDERERS` is the compiler's job ({@link PtcSdkLanguage}); what this
|
|
11217
11336
|
* guard owns is the runtime-supplied language neither table knows, which never
|
|
11218
11337
|
* yields a wrong-language schema for a real runtime.
|
|
11219
11338
|
*/
|
|
@@ -11382,7 +11501,8 @@ function createRunCodeTool(registry, options) {
|
|
|
11382
11501
|
type: "string",
|
|
11383
11502
|
required: true,
|
|
11384
11503
|
description: RUN_CODE_DESCRIPTION_PARAM_DESCRIPTION
|
|
11385
|
-
}
|
|
11504
|
+
},
|
|
11505
|
+
...RUN_CODE_CONTROLS
|
|
11386
11506
|
},
|
|
11387
11507
|
output: {
|
|
11388
11508
|
schema: {
|
|
@@ -11394,12 +11514,37 @@ function createRunCodeTool(registry, options) {
|
|
|
11394
11514
|
required: true,
|
|
11395
11515
|
items: { type: "string" }
|
|
11396
11516
|
},
|
|
11397
|
-
result: { type: "json" }
|
|
11517
|
+
result: { type: "json" },
|
|
11518
|
+
sandbox: {
|
|
11519
|
+
type: "object",
|
|
11520
|
+
additionalProperties: false,
|
|
11521
|
+
properties: {
|
|
11522
|
+
mode: {
|
|
11523
|
+
type: "string",
|
|
11524
|
+
required: true,
|
|
11525
|
+
enum: [
|
|
11526
|
+
"read-only",
|
|
11527
|
+
"workspace-write",
|
|
11528
|
+
"danger-full-access"
|
|
11529
|
+
]
|
|
11530
|
+
},
|
|
11531
|
+
denied: {
|
|
11532
|
+
type: "boolean",
|
|
11533
|
+
required: true
|
|
11534
|
+
},
|
|
11535
|
+
enforcement: {
|
|
11536
|
+
type: "string",
|
|
11537
|
+
enum: ["full", "partial"]
|
|
11538
|
+
}
|
|
11539
|
+
}
|
|
11540
|
+
}
|
|
11398
11541
|
}
|
|
11399
11542
|
},
|
|
11400
11543
|
render: (_args, value) => {
|
|
11401
11544
|
const rendered = value.result === void 0 ? "" : renderValue(value.result);
|
|
11402
11545
|
const parts = [value.logs.join("\n"), rendered].filter((part) => part.length > 0);
|
|
11546
|
+
if (value.sandbox?.enforcement === "partial") parts.push("File sandbox enforcement is partial on this host.");
|
|
11547
|
+
if (value.sandbox?.denied) parts.push(`The ${value.sandbox.mode} file sandbox denied an operation.${escalationGuidance(peekRuntime())}`);
|
|
11403
11548
|
return [{
|
|
11404
11549
|
type: "text",
|
|
11405
11550
|
text: parts.length > 0 ? parts.join("\n") : "(run_code completed with no output)"
|
|
@@ -11409,6 +11554,31 @@ function createRunCodeTool(registry, options) {
|
|
|
11409
11554
|
async execute(args, exec) {
|
|
11410
11555
|
if (args.description.trim().length === 0) throw new Error("invalid description: expected a non-empty string");
|
|
11411
11556
|
const runtime = requireRuntime();
|
|
11557
|
+
validateEscalationArgs(args.sandbox_permissions, args.justification);
|
|
11558
|
+
if (args.timeoutMs !== void 0 && runtime.timeout === void 0) throw new Error("timeoutMs is not available for this PTC runtime");
|
|
11559
|
+
if (args.timeoutMs !== void 0 && (!Number.isFinite(args.timeoutMs) || args.timeoutMs <= 0)) throw new Error("invalid timeoutMs: expected a positive finite number");
|
|
11560
|
+
const standingPolicy = runtime.sandboxMode === void 0 ? void 0 : options.resolveSandboxPolicy(exec);
|
|
11561
|
+
let policy = standingPolicy;
|
|
11562
|
+
if (args.sandbox_permissions !== void 0 && args.justification !== void 0) {
|
|
11563
|
+
if (standingPolicy === void 0) throw new Error("sandbox_permissions is not available for this PTC runtime");
|
|
11564
|
+
const approvedMode = await approveEscalation({
|
|
11565
|
+
requestedMode: args.sandbox_permissions,
|
|
11566
|
+
justification: args.justification,
|
|
11567
|
+
effectiveMode: standingPolicy.mode,
|
|
11568
|
+
subject: "program"
|
|
11569
|
+
}, {
|
|
11570
|
+
approver: options.peekApprover(),
|
|
11571
|
+
agent: exec.agent,
|
|
11572
|
+
callId: exec.callId,
|
|
11573
|
+
toolName: RUN_CODE_NAME,
|
|
11574
|
+
signal: exec.signal
|
|
11575
|
+
});
|
|
11576
|
+
policy = {
|
|
11577
|
+
...standingPolicy,
|
|
11578
|
+
mode: approvedMode
|
|
11579
|
+
};
|
|
11580
|
+
}
|
|
11581
|
+
exec.signal.throwIfAborted();
|
|
11412
11582
|
const runController = new AbortController();
|
|
11413
11583
|
const onOuterAbort = () => {
|
|
11414
11584
|
runController.abort(exec.signal.reason);
|
|
@@ -11490,7 +11660,8 @@ function createRunCodeTool(registry, options) {
|
|
|
11490
11660
|
while (logWork.size > 0) await Promise.allSettled([...logWork]);
|
|
11491
11661
|
};
|
|
11492
11662
|
const runOver = () => runController.signal.aborted;
|
|
11493
|
-
const binding = (
|
|
11663
|
+
const binding = (schema) => async (rawArgs) => {
|
|
11664
|
+
const { name } = schema;
|
|
11494
11665
|
if (runOver()) throw new Error(`run_code run is over (${String(runController.signal.reason)}); ${name} not dispatched`);
|
|
11495
11666
|
const normalized = jsonNormalizeArgs(rawArgs);
|
|
11496
11667
|
const n = ++dispatches;
|
|
@@ -11499,6 +11670,7 @@ function createRunCodeTool(registry, options) {
|
|
|
11499
11670
|
callId: subCallId,
|
|
11500
11671
|
rootCallId: exec.rootCallId,
|
|
11501
11672
|
name,
|
|
11673
|
+
schema,
|
|
11502
11674
|
arguments: normalized.dispatched,
|
|
11503
11675
|
...exec.agent ? { agent: exec.agent } : {},
|
|
11504
11676
|
parent: exec.token,
|
|
@@ -11533,6 +11705,7 @@ function createRunCodeTool(registry, options) {
|
|
|
11533
11705
|
name,
|
|
11534
11706
|
arguments: normalized.logged,
|
|
11535
11707
|
isError: result.isError,
|
|
11708
|
+
...result.error?.info === void 0 ? {} : { error: result.error.info },
|
|
11536
11709
|
content: logged
|
|
11537
11710
|
});
|
|
11538
11711
|
})().finally(() => {
|
|
@@ -11603,13 +11776,13 @@ function createRunCodeTool(registry, options) {
|
|
|
11603
11776
|
if (schema.name === "run_code") continue;
|
|
11604
11777
|
Object.defineProperty(functions, schema.name, {
|
|
11605
11778
|
enumerable: true,
|
|
11606
|
-
value: binding(schema
|
|
11779
|
+
value: binding(deepFreeze(schema))
|
|
11607
11780
|
});
|
|
11608
11781
|
}
|
|
11609
11782
|
try {
|
|
11610
11783
|
let result;
|
|
11611
11784
|
try {
|
|
11612
|
-
result = await runtime.run({
|
|
11785
|
+
result = await runtime.run(runtime.resolve({
|
|
11613
11786
|
program: args.code,
|
|
11614
11787
|
bindings: [{
|
|
11615
11788
|
global: "tools",
|
|
@@ -11619,18 +11792,23 @@ function createRunCodeTool(registry, options) {
|
|
|
11619
11792
|
memberNameProperty: "toolName"
|
|
11620
11793
|
}
|
|
11621
11794
|
}],
|
|
11622
|
-
signal: runController.signal
|
|
11623
|
-
|
|
11795
|
+
signal: runController.signal,
|
|
11796
|
+
...exec.agent?.session.header.cwd !== void 0 ? { cwd: exec.agent.session.header.cwd } : {},
|
|
11797
|
+
...policy !== void 0 ? { sandboxPolicy: policy } : {},
|
|
11798
|
+
...args.timeoutMs !== void 0 ? { timeoutMs: args.timeoutMs } : {}
|
|
11799
|
+
}));
|
|
11624
11800
|
} finally {
|
|
11625
11801
|
runController.abort("run_code settled");
|
|
11626
11802
|
await drainDispatches();
|
|
11627
11803
|
}
|
|
11628
11804
|
if (result.error) {
|
|
11629
11805
|
const logsText = result.logs.length > 0 ? `\nCaptured output:\n${result.logs.join("\n")}` : "";
|
|
11630
|
-
|
|
11806
|
+
const sandboxText = result.sandbox === void 0 ? "" : `\nFile sandbox: ${result.sandbox.mode}${result.sandbox.enforcement === void 0 ? "" : `; enforcement: ${result.sandbox.enforcement}`}${result.sandbox.denied ? "; operation denied" : ""}.`;
|
|
11807
|
+
throw new CodeRunFailedError(`code run failed (${result.error.kind}): ${result.error.message}${logsText}${sandboxText}${result.sandbox?.denied ? escalationGuidance(runtime) : ""}`);
|
|
11631
11808
|
}
|
|
11632
11809
|
return {
|
|
11633
11810
|
logs: result.logs,
|
|
11811
|
+
...result.sandbox === void 0 ? {} : { sandbox: result.sandbox },
|
|
11634
11812
|
...result.value !== void 0 ? { result: result.value } : {}
|
|
11635
11813
|
};
|
|
11636
11814
|
} finally {
|
|
@@ -11646,7 +11824,11 @@ function createRunCodeTool(registry, options) {
|
|
|
11646
11824
|
});
|
|
11647
11825
|
Object.defineProperty(definition, "description", {
|
|
11648
11826
|
enumerable: true,
|
|
11649
|
-
get: () =>
|
|
11827
|
+
get: () => {
|
|
11828
|
+
const runtime = peekRuntime();
|
|
11829
|
+
const instructions = runtime?.executionInstructions;
|
|
11830
|
+
return resolveFlavor(peekRuntime).description + (instructions ? ` ${instructions}` : "") + (runtime === void 0 ? "" : " The working directory is the Session's current directory.") + escalationGuidance(runtime);
|
|
11831
|
+
}
|
|
11650
11832
|
});
|
|
11651
11833
|
Object.defineProperty(definition, "parameters", {
|
|
11652
11834
|
enumerable: true,
|
|
@@ -11660,7 +11842,8 @@ function createRunCodeTool(registry, options) {
|
|
|
11660
11842
|
type: "string",
|
|
11661
11843
|
required: true,
|
|
11662
11844
|
description: RUN_CODE_DESCRIPTION_PARAM_DESCRIPTION
|
|
11663
|
-
}
|
|
11845
|
+
},
|
|
11846
|
+
...controlParameters(peekRuntime())
|
|
11664
11847
|
})
|
|
11665
11848
|
});
|
|
11666
11849
|
return definition;
|
|
@@ -11945,7 +12128,7 @@ function renderToolsSdk(schemas) {
|
|
|
11945
12128
|
* PTC mode codegen — Python flavor. The pure projection from registered tool schemas to the
|
|
11946
12129
|
* Python SDK text the model programs against under `runtime.language === 'python'`. Sibling of
|
|
11947
12130
|
* {@link ./ts-types.ts | ts-types.ts}; the two files are two projections of the same registry
|
|
11948
|
-
* store, keyed by the loaded {@link @deepseek-ai/dsh-
|
|
12131
|
+
* store, keyed by the loaded {@link @deepseek-ai/dsh-ptc-runtime#PtcRuntime.language | PTC
|
|
11949
12132
|
* runtime's language}.
|
|
11950
12133
|
*
|
|
11951
12134
|
* Under `mode: 'ptc'` the native tool schemas are omitted from the request, so this generated
|
|
@@ -12632,17 +12815,17 @@ function renderToolsSdkPy(schemas) {
|
|
|
12632
12815
|
*/
|
|
12633
12816
|
/**
|
|
12634
12817
|
* Language → SDK-section renderer. The registry looks up the loaded
|
|
12635
|
-
* `ctx.
|
|
12818
|
+
* `ctx.ptcRuntime.language` in this table when assembling the `tools:sdk`
|
|
12636
12819
|
* section under a non-native mode; a runtime whose language is not a key
|
|
12637
12820
|
* fails the assembly loudly (same idiom as `toolOrder` violations). Adding a
|
|
12638
|
-
* new backend language is three parallel edits — a {@link
|
|
12821
|
+
* new backend language is three parallel edits — a {@link PtcSdkLanguage}
|
|
12639
12822
|
* member, an entry here, and a `RUN_CODE_FLAVORS` entry in `ptc.ts` for
|
|
12640
12823
|
* its `run_code` schema strings — plus the renderer function this table points
|
|
12641
12824
|
* at. The `satisfies` clause pins this table's key set to that union, which
|
|
12642
12825
|
* the flavor table is checked against too, so any of the three left out is a
|
|
12643
12826
|
* typecheck failure. What no check reaches is the prose that names the values
|
|
12644
|
-
* instead of deriving them: the seam's `dsh-
|
|
12645
|
-
* `
|
|
12827
|
+
* instead of deriving them: the seam's `dsh-ptc-runtime` README pair, its
|
|
12828
|
+
* `PtcRuntime.language` JSDoc, and `docs/subsystems/ptc-runtime.md`
|
|
12646
12829
|
* with its zh pair, plus this package's own README pair and the
|
|
12647
12830
|
* {@link Config.mode} JSDoc.
|
|
12648
12831
|
*/
|
|
@@ -12881,12 +13064,13 @@ var ToolRuntime = class extends Service {
|
|
|
12881
13064
|
return {
|
|
12882
13065
|
name: "tools:sdk",
|
|
12883
13066
|
order: this.ctx.systemPrompt.getSectionOrder("TOOLS_SDK"),
|
|
13067
|
+
interpolate: false,
|
|
12884
13068
|
text: (context) => {
|
|
12885
13069
|
const mode = this.modeFor(context.scope);
|
|
12886
13070
|
if (mode === "native") return "";
|
|
12887
|
-
const runtime = this.
|
|
13071
|
+
const runtime = this.requirePtcRuntime(mode);
|
|
12888
13072
|
const render = SDK_RENDERERS[runtime.language];
|
|
12889
|
-
/* v8 ignore next --
|
|
13073
|
+
/* v8 ignore next -- requirePtcRuntime rejects an unknown language before this runs. */
|
|
12890
13074
|
if (render === void 0) throw new Error(`dsh-tools: no SDK renderer for ${runtime.language}`);
|
|
12891
13075
|
return render(this.sdkSchemas(context.scope));
|
|
12892
13076
|
}
|
|
@@ -12915,10 +13099,16 @@ var ToolRuntime = class extends Service {
|
|
|
12915
13099
|
* and only for scopes whose mode actually presents it.
|
|
12916
13100
|
* @returns the shared transport definition.
|
|
12917
13101
|
*/
|
|
12918
|
-
|
|
13102
|
+
requirePtcTransport() {
|
|
12919
13103
|
this.ptcTransport ??= createRunCodeTool(this, {
|
|
12920
|
-
requireRuntime: () => this.
|
|
12921
|
-
|
|
13104
|
+
requireRuntime: () => this.requirePtcRuntime(this.defaultMode),
|
|
13105
|
+
peekApprover: () => this.ctx.get("approval"),
|
|
13106
|
+
resolveSandboxPolicy: (exec) => {
|
|
13107
|
+
const policy = this.ctx.get("sandboxPolicy");
|
|
13108
|
+
if (policy === void 0) throw new Error("dsh-tools: confined PTC runtime requires sandboxPolicy");
|
|
13109
|
+
return policy.resolve(exec.agent === void 0 ? {} : { session: exec.agent.session });
|
|
13110
|
+
},
|
|
13111
|
+
peekRuntime: () => this.ctx.get("ptcRuntime"),
|
|
12922
13112
|
maxParallel: this.maxParallelSubCalls,
|
|
12923
13113
|
shapeDispatchLog: (dispatch) => this.shapeDispatchLog(dispatch)
|
|
12924
13114
|
});
|
|
@@ -12963,7 +13153,7 @@ var ToolRuntime = class extends Service {
|
|
|
12963
13153
|
schemas: [...view.visible.values()].map((definition) => this.schemaOf(definition, false)),
|
|
12964
13154
|
knownNames: [...view.knownNames]
|
|
12965
13155
|
};
|
|
12966
|
-
this.
|
|
13156
|
+
this.requirePtcRuntime(mode);
|
|
12967
13157
|
const schemas = [...view.visible.values()].map((definition) => this.schemaOf(definition, false));
|
|
12968
13158
|
if (mode === "ptc") return {
|
|
12969
13159
|
schemas: schemas.filter((schema) => schema.name === RUN_CODE_NAME),
|
|
@@ -12975,10 +13165,10 @@ var ToolRuntime = class extends Service {
|
|
|
12975
13165
|
};
|
|
12976
13166
|
}
|
|
12977
13167
|
/**
|
|
12978
|
-
* Resolve the
|
|
13168
|
+
* Resolve the PTC runtime or throw the actionable misconfiguration error.
|
|
12979
13169
|
* Read at use time (assembly / run_code execution), NOT via static
|
|
12980
13170
|
* `inject`: an inject entry would hold `ctx.tools` — and every tool plugin
|
|
12981
|
-
* behind it — hostage to a
|
|
13171
|
+
* behind it — hostage to a PTC runtime existing even under `mode:
|
|
12982
13172
|
* 'native'`.
|
|
12983
13173
|
*
|
|
12984
13174
|
* Assembly and `run_code` execution read separately, so the language is not
|
|
@@ -12988,9 +13178,9 @@ var ToolRuntime = class extends Service {
|
|
|
12988
13178
|
* other. Binding it is deferred until a second backend ships (the first
|
|
12989
13179
|
* point it is testable).
|
|
12990
13180
|
*/
|
|
12991
|
-
|
|
12992
|
-
const runtime = this.ctx.get("
|
|
12993
|
-
if (!runtime) throw new Error(`dsh-tools: mode "${mode}" requires a
|
|
13181
|
+
requirePtcRuntime(mode) {
|
|
13182
|
+
const runtime = this.ctx.get("ptcRuntime");
|
|
13183
|
+
if (!runtime) throw new Error(`dsh-tools: mode "${mode}" requires a PTC runtime — load a ctx.ptcRuntime implementation (e.g. @deepseek-ai/dsh-ptc-runtime-node) or set tools mode to "native"`);
|
|
12994
13184
|
if (!Object.hasOwn(SDK_RENDERERS, runtime.language)) {
|
|
12995
13185
|
const known = Object.keys(SDK_RENDERERS).map((name) => JSON.stringify(name)).join(", ");
|
|
12996
13186
|
throw new Error(`dsh-tools: no SDK renderer registered for runtime language ${JSON.stringify(runtime.language)} (known: ${known})`);
|
|
@@ -13104,7 +13294,7 @@ var ToolRuntime = class extends Service {
|
|
|
13104
13294
|
knownNames.add(name);
|
|
13105
13295
|
visible.set(name, definition);
|
|
13106
13296
|
}
|
|
13107
|
-
if (this.modeFor(scope) !== "native") visible.set(RUN_CODE_NAME, this.
|
|
13297
|
+
if (this.modeFor(scope) !== "native") visible.set(RUN_CODE_NAME, this.requirePtcTransport());
|
|
13108
13298
|
return {
|
|
13109
13299
|
visible,
|
|
13110
13300
|
knownNames,
|
|
@@ -13275,6 +13465,7 @@ var ToolRuntime = class extends Service {
|
|
|
13275
13465
|
signal,
|
|
13276
13466
|
...agent !== void 0 ? { agent } : {},
|
|
13277
13467
|
...parent !== void 0 ? { parent } : {},
|
|
13468
|
+
...exec.schema !== void 0 ? { schema: exec.schema } : {},
|
|
13278
13469
|
deferContext(context) {
|
|
13279
13470
|
deferredContexts.push(context);
|
|
13280
13471
|
},
|
|
@@ -13357,7 +13548,13 @@ var ToolRuntime = class extends Service {
|
|
|
13357
13548
|
exec,
|
|
13358
13549
|
result: toolAbortedBeforeDispatchResult()
|
|
13359
13550
|
});
|
|
13551
|
+
if (decision.kind === "cancel") return await next({
|
|
13552
|
+
kind: "post-result",
|
|
13553
|
+
exec,
|
|
13554
|
+
result: toolAbortedBeforeDispatchResult()
|
|
13555
|
+
});
|
|
13360
13556
|
const denialReason = decision.kind === "allow" ? this.guardReason(exec) : decision.reason;
|
|
13557
|
+
const denialInfo = decision.kind === "deny" ? decision.info : void 0;
|
|
13361
13558
|
if (denialReason !== void 0) return await next({
|
|
13362
13559
|
kind: "post-result",
|
|
13363
13560
|
exec,
|
|
@@ -13367,7 +13564,10 @@ var ToolRuntime = class extends Service {
|
|
|
13367
13564
|
text: `Error: ${denialReason}`
|
|
13368
13565
|
}],
|
|
13369
13566
|
isError: true,
|
|
13370
|
-
error: {
|
|
13567
|
+
error: {
|
|
13568
|
+
message: denialReason,
|
|
13569
|
+
...denialInfo === void 0 ? {} : { info: denialInfo }
|
|
13570
|
+
}
|
|
13371
13571
|
})
|
|
13372
13572
|
});
|
|
13373
13573
|
if (this.callerCancelled(exec)) return await next({
|
|
@@ -13818,7 +14018,7 @@ function toolAbortedBeforeDispatchResult(prior) {
|
|
|
13818
14018
|
};
|
|
13819
14019
|
}
|
|
13820
14020
|
//#endregion
|
|
13821
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.
|
|
14021
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.6-alpha.1_ce40d13c69e7e1ce48818baba37665e1/node_modules/@deepseek-ai/dsh-agent/lib/index.js
|
|
13822
14022
|
/**
|
|
13823
14023
|
* Agent-scoped model selection shared by runtime entry points.
|
|
13824
14024
|
* @module @deepseek-ai/dsh-agent/model-selection
|
|
@@ -14057,8 +14257,10 @@ function registerCreate(env) {
|
|
|
14057
14257
|
...model !== "" ? { model } : {},
|
|
14058
14258
|
...reasoningEffort === void 0 ? {} : { reasoningEffort }
|
|
14059
14259
|
},
|
|
14060
|
-
setup: (agentCtx) => {
|
|
14061
|
-
|
|
14260
|
+
setup: async (agentCtx) => {
|
|
14261
|
+
const requestedPreset = typeof args.agentPreset === "string" && args.agentPreset.trim() !== "" ? args.agentPreset.trim() : void 0;
|
|
14262
|
+
if (requestedPreset !== void 0) await env.ctx.agentPresets.mount(agentCtx, requestedPreset);
|
|
14263
|
+
else if (caller !== void 0) env.ctx.agentPresets.composeFrom(agentCtx, caller.ctx);
|
|
14062
14264
|
if (installModelSelection$1 !== void 0) {
|
|
14063
14265
|
installModelSelection$1(agentCtx, selection);
|
|
14064
14266
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-session-bridge",
|
|
3
|
-
"version": "0.3.1",
|
|
3
|
+
"version": "0.3.2-alpha.1",
|
|
4
4
|
"description": "会话桥(dsh-session-bridge):通过提示词创建新的主会话(顶层 UI 会话)、向任意会话发送消息、等待会话的下一条回复、读取会话消息,并按会话名或 id 跨工作区查找会话;此外支持监控/调度主任务与归档会话。",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -52,28 +52,28 @@
|
|
|
52
52
|
},
|
|
53
53
|
"license": "MIT",
|
|
54
54
|
"peerDependencies": {
|
|
55
|
-
"@deepseek-ai/dsh-agent": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0",
|
|
56
|
-
"@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0",
|
|
57
|
-
"@deepseek-ai/dsh-home-paths": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0",
|
|
58
|
-
"@deepseek-ai/dsh-llm": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0",
|
|
59
|
-
"@deepseek-ai/dsh-session": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0",
|
|
60
|
-
"@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0",
|
|
61
|
-
"@deepseek-ai/dsh-tools": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0",
|
|
62
|
-
"@deepseek-ai/dsh-workspace": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0",
|
|
55
|
+
"@deepseek-ai/dsh-agent": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0 || ^0.1.6-0",
|
|
56
|
+
"@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0 || ^0.1.6-0",
|
|
57
|
+
"@deepseek-ai/dsh-home-paths": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0 || ^0.1.6-0",
|
|
58
|
+
"@deepseek-ai/dsh-llm": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0 || ^0.1.6-0",
|
|
59
|
+
"@deepseek-ai/dsh-session": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0 || ^0.1.6-0",
|
|
60
|
+
"@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0 || ^0.1.6-0",
|
|
61
|
+
"@deepseek-ai/dsh-tools": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0 || ^0.1.6-0",
|
|
62
|
+
"@deepseek-ai/dsh-workspace": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0 || ^0.1.6-0",
|
|
63
63
|
"cordis": "^4.0.0-rc.7"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
|
-
"@deepseek-ai/dsh-agent": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0",
|
|
67
|
-
"@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0",
|
|
68
|
-
"@deepseek-ai/dsh-brand": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0",
|
|
69
|
-
"@deepseek-ai/dsh-home-paths": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0",
|
|
70
|
-
"@deepseek-ai/dsh-llm": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0",
|
|
71
|
-
"@deepseek-ai/dsh-scope": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0",
|
|
72
|
-
"@deepseek-ai/dsh-session": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0",
|
|
73
|
-
"@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0",
|
|
74
|
-
"@deepseek-ai/dsh-tools": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0",
|
|
75
|
-
"@deepseek-ai/dsh-util-values": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0",
|
|
76
|
-
"@deepseek-ai/dsh-workspace": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0",
|
|
66
|
+
"@deepseek-ai/dsh-agent": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0 || ^0.1.6-0",
|
|
67
|
+
"@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0 || ^0.1.6-0",
|
|
68
|
+
"@deepseek-ai/dsh-brand": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0 || ^0.1.6-0",
|
|
69
|
+
"@deepseek-ai/dsh-home-paths": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0 || ^0.1.6-0",
|
|
70
|
+
"@deepseek-ai/dsh-llm": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0 || ^0.1.6-0",
|
|
71
|
+
"@deepseek-ai/dsh-scope": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0 || ^0.1.6-0",
|
|
72
|
+
"@deepseek-ai/dsh-session": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0 || ^0.1.6-0",
|
|
73
|
+
"@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0 || ^0.1.6-0",
|
|
74
|
+
"@deepseek-ai/dsh-tools": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0 || ^0.1.6-0",
|
|
75
|
+
"@deepseek-ai/dsh-util-values": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0 || ^0.1.6-0",
|
|
76
|
+
"@deepseek-ai/dsh-workspace": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0 || ^0.1.6-0",
|
|
77
77
|
"@types/node": "^24.0.0",
|
|
78
78
|
"cordis": "^4.0.0-rc.7",
|
|
79
79
|
"tsdown": "^0.22.14",
|
|
@@ -82,6 +82,7 @@
|
|
|
82
82
|
"scripts": {
|
|
83
83
|
"build": "bash scripts/build.sh",
|
|
84
84
|
"build:client": "tsdown",
|
|
85
|
+
"check:compat": "node scripts/check-dsh-compat.mjs",
|
|
85
86
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
86
87
|
}
|
|
87
88
|
}
|
package/scripts/build.sh
CHANGED
|
@@ -14,6 +14,24 @@ if [ -z "$CHECKOUT" ] || [ ! -d "$CHECKOUT/packages" ]; then
|
|
|
14
14
|
exit 1
|
|
15
15
|
fi
|
|
16
16
|
|
|
17
|
+
# The type-check below runs against $DSH_CHECKOUT, which commonly lags the dsh
|
|
18
|
+
# that actually loads this plugin — a stale checkout type-checks green while the
|
|
19
|
+
# running harness has already moved on. Warn loudly rather than implying support.
|
|
20
|
+
read_pkg_version() {
|
|
21
|
+
node -e "try{process.stdout.write(String(require(process.argv[1]).version))}catch(e){process.stdout.write('unknown')}" "$1" 2>/dev/null || echo unknown
|
|
22
|
+
}
|
|
23
|
+
CHECKOUT_VERSION="$(read_pkg_version "$CHECKOUT/package.json")"
|
|
24
|
+
INSTALLED_VERSION="unknown"
|
|
25
|
+
GLOBAL_ROOT="$(npm root -g 2>/dev/null | head -n1 || true)"
|
|
26
|
+
if [ -n "$GLOBAL_ROOT" ] && [ -f "$GLOBAL_ROOT/@deepseek-ai/dsh/package.json" ]; then
|
|
27
|
+
INSTALLED_VERSION="$(read_pkg_version "$GLOBAL_ROOT/@deepseek-ai/dsh/package.json")"
|
|
28
|
+
fi
|
|
29
|
+
if [ "$INSTALLED_VERSION" != "unknown" ] && [ "$CHECKOUT_VERSION" != "$INSTALLED_VERSION" ]; then
|
|
30
|
+
echo "build: WARNING — checkout is $CHECKOUT_VERSION but the installed dsh is $INSTALLED_VERSION." >&2
|
|
31
|
+
echo "build: the type-check below therefore does NOT cover the running harness;" >&2
|
|
32
|
+
echo "build: run 'npm run check:compat' to type-check against the installed dsh." >&2
|
|
33
|
+
fi
|
|
34
|
+
|
|
17
35
|
TSC="$CHECKOUT/node_modules/.bin/tsc"
|
|
18
36
|
if [ ! -x "$TSC" ]; then
|
|
19
37
|
echo "build: tsc not found at $TSC" >&2
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Type-check src/ against the DSH packages that are ACTUALLY INSTALLED,
|
|
4
|
+
* rather than against $DSH_CHECKOUT.
|
|
5
|
+
*
|
|
6
|
+
* Why this exists: scripts/build.sh type-checks against a DSH *source* checkout.
|
|
7
|
+
* That checkout routinely lags the harness the plugin is loaded into (e.g. the
|
|
8
|
+
* checkout sat at 0.1.5-alpha.2 while the running harness was 0.1.6-alpha.1), so
|
|
9
|
+
* a green `build.sh` silently proves nothing about the running version. This
|
|
10
|
+
* script reads the `lib/types/*.d.ts` that ship inside the installed DSH npm
|
|
11
|
+
* package, i.e. the exact API surface the plugin loads against — so an upstream
|
|
12
|
+
* break shows up here even when the checkout is stale.
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* node scripts/check-dsh-compat.mjs [--dsh <path>]
|
|
16
|
+
*
|
|
17
|
+
* <path> may be either the DSH package directory or the `@deepseek-ai` scope
|
|
18
|
+
* directory that holds dsh-session, dsh-agent, ... . When omitted, the installed
|
|
19
|
+
* location is probed (DSH_INSTALLED_MODULES, then `npm root -g`).
|
|
20
|
+
*
|
|
21
|
+
* Exits 0 when the plugin's src/ type-checks against those types, 1 otherwise.
|
|
22
|
+
*/
|
|
23
|
+
import { execFileSync, execSync } from 'node:child_process'
|
|
24
|
+
import { existsSync, readFileSync, realpathSync, rmSync, writeFileSync } from 'node:fs'
|
|
25
|
+
import { dirname, join, resolve } from 'node:path'
|
|
26
|
+
import { fileURLToPath } from 'node:url'
|
|
27
|
+
|
|
28
|
+
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..')
|
|
29
|
+
|
|
30
|
+
/** Read a JSON file, or return undefined when it is absent/unreadable. */
|
|
31
|
+
function readJson(file) {
|
|
32
|
+
try { return JSON.parse(readFileSync(file, 'utf8')) } catch { return undefined }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** True when `dir` looks like the `@deepseek-ai` scope directory. */
|
|
36
|
+
function isScopeDir(dir) {
|
|
37
|
+
return dir !== undefined && existsSync(join(dir, 'dsh-session', 'package.json'))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Resolve the `@deepseek-ai` scope directory holding the installed DSH packages.
|
|
42
|
+
* Accepts an explicit path (package dir or scope dir) and otherwise probes.
|
|
43
|
+
*/
|
|
44
|
+
function resolveScopeDir(argv) {
|
|
45
|
+
const flagAt = argv.indexOf('--dsh')
|
|
46
|
+
const explicit = flagAt !== -1 ? argv[flagAt + 1] : (process.env.DSH_INSTALLED_MODULES ?? undefined)
|
|
47
|
+
const candidates = []
|
|
48
|
+
if (explicit !== undefined && explicit !== '') {
|
|
49
|
+
const base = resolve(explicit)
|
|
50
|
+
// Accept the scope dir itself, the dsh package dir, or a node_modules tree.
|
|
51
|
+
candidates.push(base, join(base, 'node_modules', '@deepseek-ai'), join(base, '@deepseek-ai'))
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Anchor 1: the global install root. execSync (string command) rather than
|
|
55
|
+
// execFileSync, because npm is a .cmd shim on Windows that cannot be spawned
|
|
56
|
+
// without a shell.
|
|
57
|
+
let globalRoot
|
|
58
|
+
try {
|
|
59
|
+
globalRoot = execSync('npm root -g', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim()
|
|
60
|
+
} catch { globalRoot = undefined }
|
|
61
|
+
if (globalRoot !== undefined && globalRoot !== '') {
|
|
62
|
+
// npm layout, then the common "dsh nests its own deps" layout.
|
|
63
|
+
candidates.push(join(globalRoot, '@deepseek-ai'), join(globalRoot, '@deepseek-ai', 'dsh', 'node_modules', '@deepseek-ai'))
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Anchor 2: walk up from the `dsh` executable itself. Its path is usually a
|
|
67
|
+
// symlink (scoop/volta), so resolve it first or the walk misses the real tree.
|
|
68
|
+
try {
|
|
69
|
+
const found = execSync(process.platform === 'win32' ? 'where dsh' : 'which dsh', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] })
|
|
70
|
+
.split(/\r?\n/).map((line) => line.trim()).filter((line) => line !== '')
|
|
71
|
+
for (const line of found) {
|
|
72
|
+
let dir
|
|
73
|
+
try { dir = dirname(realpathSync(line)) } catch { dir = dirname(line) }
|
|
74
|
+
for (let hop = 0; hop < 4 && dir !== dirname(dir); hop++) {
|
|
75
|
+
candidates.push(join(dir, 'node_modules', '@deepseek-ai', 'dsh', 'node_modules', '@deepseek-ai'))
|
|
76
|
+
candidates.push(join(dir, 'node_modules', '@deepseek-ai'))
|
|
77
|
+
dir = dirname(dir)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
} catch { /* dsh not on PATH; the other anchors decide */ }
|
|
81
|
+
|
|
82
|
+
for (const candidate of candidates) if (isScopeDir(candidate)) return candidate
|
|
83
|
+
return undefined
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Resolve a package's types entry point inside the scope directory. */
|
|
87
|
+
function typesEntry(scope, pkg) {
|
|
88
|
+
const dir = join(scope, pkg)
|
|
89
|
+
const manifest = readJson(join(dir, 'package.json'))
|
|
90
|
+
if (manifest === undefined) return undefined
|
|
91
|
+
const declared = typeof manifest.types === 'string' ? manifest.types : undefined
|
|
92
|
+
const candidates = [
|
|
93
|
+
...(declared !== undefined ? [join(dir, declared)] : []),
|
|
94
|
+
join(dir, 'lib', 'types', 'index.d.ts'),
|
|
95
|
+
join(dir, 'index.d.ts'),
|
|
96
|
+
]
|
|
97
|
+
return candidates.find((c) => existsSync(c))
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function fail(message) {
|
|
101
|
+
console.error('check-dsh-compat: ' + message)
|
|
102
|
+
process.exit(1)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const scope = resolveScopeDir(process.argv.slice(2))
|
|
106
|
+
if (scope === undefined) {
|
|
107
|
+
fail('could not locate the installed DSH packages. Pass --dsh <path> (the DSH package dir or its @deepseek-ai scope dir) or set DSH_INSTALLED_MODULES.')
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Read the version of the `dsh` package that owns this scope directory. */
|
|
111
|
+
function dshVersionOf(scopeDir) {
|
|
112
|
+
// Nested layout puts dsh two levels above its own scope dir; a flat global
|
|
113
|
+
// install puts it beside the other packages.
|
|
114
|
+
for (const candidate of [join(scopeDir, 'dsh', 'package.json'), join(scopeDir, '..', '..', 'package.json')]) {
|
|
115
|
+
const manifest = readJson(candidate)
|
|
116
|
+
if (manifest?.name === '@deepseek-ai/dsh' && typeof manifest.version === 'string') return manifest.version
|
|
117
|
+
}
|
|
118
|
+
return undefined
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const dshVersion = dshVersionOf(scope) ?? '(unknown)'
|
|
122
|
+
|
|
123
|
+
// Every DSH package src/ imports, plus the plain `cordis` specifier that
|
|
124
|
+
// package.json declares as a peer.
|
|
125
|
+
const manifest = readJson(join(ROOT, 'package.json')) ?? {}
|
|
126
|
+
const declared = [...Object.keys(manifest.peerDependencies ?? {}), ...Object.keys(manifest.devDependencies ?? {})]
|
|
127
|
+
const wanted = new Set(declared.filter((name) => name.startsWith('@deepseek-ai/')))
|
|
128
|
+
wanted.add('@deepseek-ai/cordis')
|
|
129
|
+
wanted.add('@deepseek-ai/schemastery')
|
|
130
|
+
|
|
131
|
+
const paths = {}
|
|
132
|
+
const missing = []
|
|
133
|
+
for (const name of [...wanted].sort()) {
|
|
134
|
+
const entry = typesEntry(scope, name.slice('@deepseek-ai/'.length))
|
|
135
|
+
if (entry === undefined) { missing.push(name); continue }
|
|
136
|
+
paths[name] = [entry]
|
|
137
|
+
}
|
|
138
|
+
// tsconfig.json maps the bare `cordis` specifier; keep that working under the
|
|
139
|
+
// installed layout too, where cordis is published scoped.
|
|
140
|
+
if (paths['@deepseek-ai/cordis'] !== undefined) paths['cordis'] = paths['@deepseek-ai/cordis']
|
|
141
|
+
|
|
142
|
+
if (missing.length > 0) {
|
|
143
|
+
fail('installed DSH is missing the packages this plugin imports: ' + missing.join(', ') + '\n (looked in ' + scope + ')')
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// The generated config must live in the repo root: tsconfig.json's `include`
|
|
147
|
+
// is relative to the config that declares it, so a config placed elsewhere
|
|
148
|
+
// would look for src/ in the wrong directory. Every mapped path is absolute,
|
|
149
|
+
// so only `include`/`extends` depend on the location. Removed again below.
|
|
150
|
+
const configPath = join(ROOT, '.dsh-compat.tsconfig.json')
|
|
151
|
+
writeFileSync(configPath, JSON.stringify({ extends: './tsconfig.json', compilerOptions: { paths } }, null, 2))
|
|
152
|
+
|
|
153
|
+
// Run tsc's JS entry through the current node binary. Spawning the .bin shell
|
|
154
|
+
// shim instead would need a shell on Windows (npm .cmd/.bat shims cannot be
|
|
155
|
+
// spawned directly), and this way the exit code and output stay unambiguous.
|
|
156
|
+
const tsc = join(ROOT, 'node_modules', 'typescript', 'bin', 'tsc')
|
|
157
|
+
if (!existsSync(tsc)) { rmSync(configPath, { force: true }); fail('local typescript not found at ' + tsc + ' (run the package manager install first)') }
|
|
158
|
+
|
|
159
|
+
console.log('check-dsh-compat: type-checking src/ against installed dsh ' + dshVersion)
|
|
160
|
+
console.log('check-dsh-compat: scope ' + scope)
|
|
161
|
+
let failure
|
|
162
|
+
try {
|
|
163
|
+
execFileSync(process.execPath, [tsc, '-p', configPath, '--noEmit'], { cwd: ROOT, stdio: 'inherit' })
|
|
164
|
+
} catch (error) {
|
|
165
|
+
failure = error
|
|
166
|
+
} finally {
|
|
167
|
+
rmSync(configPath, { force: true })
|
|
168
|
+
}
|
|
169
|
+
if (failure !== undefined) {
|
|
170
|
+
const status = typeof failure.status === 'number' ? ' (tsc exit ' + failure.status + ')' : ''
|
|
171
|
+
fail('src/ does NOT type-check against installed dsh ' + dshVersion + status + ' — this is a real incompatibility with the running harness.')
|
|
172
|
+
}
|
|
173
|
+
console.log('check-dsh-compat: OK — src/ type-checks against installed dsh ' + dshVersion)
|
package/src/tools.ts
CHANGED
|
@@ -194,8 +194,16 @@ function registerCreate(env: BridgeEnv): void {
|
|
|
194
194
|
...(model !== '' ? { model } : {}),
|
|
195
195
|
...(reasoningEffort === undefined ? {} : { reasoningEffort }),
|
|
196
196
|
},
|
|
197
|
-
setup: (agentCtx: Context) => {
|
|
198
|
-
|
|
197
|
+
setup: async (agentCtx: Context) => {
|
|
198
|
+
const requestedPreset = typeof args.agentPreset === 'string' && args.agentPreset.trim() !== '' ? args.agentPreset.trim() : undefined
|
|
199
|
+
if (requestedPreset !== undefined) {
|
|
200
|
+
// An explicit agentPreset composes THAT preset. Falling through to the
|
|
201
|
+
// caller-join below would silently ignore the request: the id would
|
|
202
|
+
// still reach the session header, while the agent kept running on the
|
|
203
|
+
// caller's standing composition and its tools.
|
|
204
|
+
const presets = env.ctx.agentPresets as unknown as { mount(agentCtx: Context, id: string): Promise<unknown> }
|
|
205
|
+
await presets.mount(agentCtx, requestedPreset)
|
|
206
|
+
} else if (caller !== undefined) {
|
|
199
207
|
const presets = env.ctx.agentPresets as unknown as { composeFrom(agentCtx: Context, parentCtx: Context): string | undefined }
|
|
200
208
|
presets.composeFrom(agentCtx, caller.ctx)
|
|
201
209
|
}
|