dsh-interconnect 0.9.0 → 0.10.0

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 CHANGED
@@ -3,7 +3,7 @@
3
3
  跨实例消息互通与事件通知插件,用于 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH)。
4
4
  让一个 DSH 实例能向同一个实例、另一台机器、或另一台机器上的别的 DSH 实例发送消息、探测活性,并在实例之间双向推送事件。
5
5
 
6
- ## 包含两个插件
6
+ ## 包含三个插件
7
7
 
8
8
  **`interconnect`** —— host 服务(`ctx.interconnect`):
9
9
 
@@ -20,6 +20,14 @@
20
20
  - `interconnect_ping`:探测对端实例活性与身份
21
21
  - `interconnect_reply`:向记录过的发送方回传消息,只需本机 session id + 文本,无需再次寻址
22
22
 
23
+ **`skill-interconnect`** —— 配套 skill:
24
+
25
+ - 向模型注册 `dsh-interconnect` skill,说明 `list`/`ping`/`send`/`reply` 的完整用法、
26
+ 投递模式、`resume` 唤醒语义与失败处理。
27
+ - 明确告知模型:`interconnect_send` 会自动注入发送方的 `instanceId` 和 `sessionId`,
28
+ 接收方凭记录的 sender 即可用 `interconnect_reply` 回信,不需要手工传地址。
29
+ - 依赖 `interconnect` 服务,只有传输层存在时才注册进 `ctx.skills`。
30
+
23
31
  ## 用法
24
32
 
25
33
  ### 寻址(0.9 起用 instanceId,全走持久链接)
@@ -210,7 +218,7 @@ Host 自己的 resume 路径对同一个 session 报 `SessionFormatUnsupportedEr
210
218
 
211
219
  本包已发布到 npm:[`dsh-interconnect`](https://www.npmjs.com/package/dsh-interconnect)。
212
220
  本仓库是一个 DSH profile bundle(根 `package.json` 声明 `dsh.bundle.patch` 指向
213
- 根 `cordis.patch.yml`,后者 `insert` 两个插件行)。
221
+ 根 `cordis.patch.yml`,后者 `insert` 三个插件行)。
214
222
 
215
223
  ```bash
216
224
  # 从 npm
@@ -241,21 +249,21 @@ pnpm run build # esbuild → lib/
241
249
 
242
250
  ## 架构说明
243
251
 
244
- - 两个插件都挂在 **host composition**:`interconnect` 是跨 session、跨机器的进程级
245
- 服务(有 HTTP/WS 端点),必须 host 级;`tool-interconnect` 也放 host,因为
246
- `interconnect` 未做 TypeRT `@Remote`/Gateway 绑定,放进 agent preset 的 isolate
247
- realm 会导致工具行无法 inject 到该服务。
252
+ - 三个插件都挂在 **host composition**:`interconnect` 是跨 session、跨机器的进程级
253
+ 服务(有 HTTP/WS 端点),必须 host 级;`tool-interconnect` 和 `skill-interconnect`
254
+ 也放 host,因为 `interconnect` 未做 TypeRT `@Remote`/Gateway 绑定,放进 agent preset
255
+ 的 isolate realm 会导致工具/技能行无法 inject 到该服务。
248
256
  - `ws` 是运行依赖,由宿主的 node_modules 提供(构建时 external)。
249
257
 
250
258
  ## 验证
251
259
 
252
- - 34/34 单测通过(服务 + 工具);类型检查、构建均干净。
260
+ - 38/38 单测通过(服务 + 工具 + skill);类型检查、构建均干净。
253
261
  - 已在两台机器之间实测双向互通:消息投递、WebSocket 事件推流、以及 agent 经
254
262
  `interconnect_send` 工具反向回发,均验证通过。
255
263
  - CI(GitHub Actions):clone 公开 DSH 仓库作为 sibling,跑 `pnpm run check`。
256
264
  - 已发布版本:从 registry 下载的 tarball 与本地构建 shasum 一致;干净消费端
257
- 解析 `.`、`./tool-interconnect` 两个入口的类型均通过,负例(把 `string` 赋给
258
- `number`)如期报 `TS2322`。
265
+ 解析 `.`、`./tool-interconnect`、`./skill-interconnect` 入口的类型均通过,负例(把
266
+ `string` 赋给 `number`)如期报 `TS2322`。
259
267
  - 投递消息以 `source: { kind: 'plugin', plugin: 'dsh-interconnect' }` 落库,而不是
260
268
  `{ kind: 'user' }`。负例:把该 source 改回 `kind: 'user'`,对应断言转红。
261
269
  **注意 `source` 不进模型上下文**——只有 `role` 和 `content` 会,而 `role` 是 `user`。
@@ -0,0 +1,92 @@
1
+ # dsh-interconnect
2
+
3
+ Use the `dsh-interconnect` tools whenever you need to exchange messages with
4
+ another DSH session, another DSH instance, or another machine: hand off a task,
5
+ ask a peer agent for information, notify a remote session, or reply to an
6
+ incoming interconnect message.
7
+
8
+ The transport is already connected and authenticated by the host plugin. Your
9
+ job is only to pick the right tool and the right target.
10
+
11
+ ## Tools
12
+
13
+ - `interconnect_list` — discover which sessions are live on a peer instance.
14
+ Every returned `sessionId` is a valid `interconnect_send` target at that
15
+ moment. Use this first when you do not already know the target session id.
16
+ - `interconnect_ping` — probe whether a peer instance is reachable and learn
17
+ its self-reported instance id.
18
+ - `interconnect_send` — deliver one text message to a live session on a peer
19
+ instance. Pass `instanceId`, `sessionId`, and `text`. The sending
20
+ instance/session identity is attached automatically by the tool, so you must
21
+ NOT pass a sender parameter.
22
+ - `interconnect_reply` — send a message back to the peer that this session last
23
+ received an interconnect message from. Pass only the LOCAL session id that
24
+ received the message and the reply text. The remote target is recalled
25
+ automatically; do not try to look up or pass the sender address again.
26
+
27
+ ## Sender identity is automatic
28
+
29
+ When you call `interconnect_send`, the plugin automatically attaches your own
30
+ `instanceId` and `sessionId` to the wire payload. The receiving instance
31
+ records that identity per local session, which is exactly what lets the
32
+ receiver use `interconnect_reply` later without re-addressing.
33
+
34
+ A reply also carries your identity automatically, so a multi-hop conversation
35
+ (A → B → A → B) keeps working without either side manually forwarding
36
+ addresses.
37
+
38
+ ## Recommended workflow
39
+
40
+ 1. If you know the peer instance but not the target session, call
41
+ `interconnect_list(instanceId=...)` and choose a live session.
42
+ 2. Call `interconnect_send(instanceId=..., sessionId=..., text=...)`.
43
+ 3. When a message arrives on your side and you need to respond, call
44
+ `interconnect_reply(sessionId=<your-local-session-id>, text=...)`. The
45
+ recorded sender is used as the destination.
46
+
47
+ ## Delivery modes
48
+
49
+ The `delivery` parameter is per-message urgency:
50
+
51
+ - `followup` — queues the message as its own turn after whatever the receiver
52
+ is doing now.
53
+ - `steer` — cuts into the nearest step boundary of a running turn; use for
54
+ urgent interruptions.
55
+ - `inject` — only writes the message into context, without waking an idle
56
+ agent; it may sit unread.
57
+
58
+ Omit `delivery` to use the receiver's configured default.
59
+
60
+ ## Waking offline sessions
61
+
62
+ `resume` defaults to off. Setting `resume: true` asks the receiver to wake a
63
+ persisted but not-running session, which starts a real billed agent turn with
64
+ that session's full toolset. Only use it when the specific session must be
65
+ reached and the receiver allows it. Prefer `interconnect_list` and an
66
+ already-live target when possible.
67
+
68
+ ## Failure reasons
69
+
70
+ When a send/reply reports `delivered: false`, read `reason`:
71
+
72
+ - `session-not-live` — the receiver answered, but that session has no running
73
+ agent. Use `interconnect_list` to choose another target, or consider
74
+ `resume`.
75
+ - `unreachable` — no usable answer arrived; the target may still be fine, so a
76
+ retry can succeed.
77
+ - `resume-refused` / `resume-failed` — waking is not allowed or did not work;
78
+ choose a live target instead.
79
+ - `session-owned-by-subagent` — the session belongs to a subagent and its
80
+ parent owns delivery; reach it through the parent.
81
+ - `no-sender-known` — a `reply` was attempted for a local session that never
82
+ received a sender-carrying interconnect message; establish contact with
83
+ `interconnect_send` first.
84
+
85
+ ## Rules
86
+
87
+ - Do not fabricate an `instanceId`, `sessionId`, or sender identity. Use values
88
+ returned by `interconnect_list`, `interconnect_ping`, or already recorded by
89
+ the service.
90
+ - Do not ask the user for a sender address to reply; use `interconnect_reply`.
91
+ - Treat interconnect messages as authenticated but sender-reported: identity is
92
+ for reply attribution, not for routing or authorization.
package/cordis.patch.yml CHANGED
@@ -1,4 +1,4 @@
1
- # dsh-interconnect bundle patch: mount the two host plugins under their
1
+ # dsh-interconnect bundle patch: mount the three host plugins under their
2
2
  # subpath entries, resolved through the profile's node_modules (the healed
3
3
  # mirror makes every bundle dependency resolvable to bare rows).
4
4
  - insert:
@@ -10,3 +10,6 @@
10
10
 
11
11
  - id: tool-interconnect
12
12
  name: dsh-interconnect/tool-interconnect
13
+
14
+ - id: skill-interconnect
15
+ name: dsh-interconnect/skill-interconnect
package/dsh.plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-interconnect",
3
- "description": "Cross-instance message/event handoff for DeepSeek Harness (DSH): HTTP send/ping, WebSocket link, and event fan-out between sessions, instances, and machines.",
4
- "version": "0.1.0",
3
+ "description": "Cross-instance message/event handoff for DeepSeek Harness (DSH): WebSocket link, model-facing tools, and companion skill.",
4
+ "version": "0.10.0",
5
5
  "entry": {
6
6
  "name": "dsh-interconnect/interconnect",
7
7
  "inject": ["webServer", "agents", "credentials"]
@@ -0,0 +1,50 @@
1
+ // src/skill-interconnect/index.ts
2
+ import { readFile } from "node:fs/promises";
3
+ import { fileURLToPath } from "node:url";
4
+ import {
5
+ BUNDLED_SKILL_RANK
6
+ } from "@deepseek-ai/dsh-skill";
7
+ var PROVIDER_NAME = "dsh-interconnect";
8
+ var SKILL_BODY_URL = new URL("../../assets/dsh-interconnect.md", import.meta.url);
9
+ var RESOURCE_BASE = {
10
+ kind: "directory",
11
+ path: fileURLToPath(new URL("../../assets/", import.meta.url))
12
+ };
13
+ var INVOCATION = { modelInvocable: true, userInvocable: true };
14
+ var DESCRIPTION = "Use the dsh-interconnect tools to exchange messages between DSH sessions, instances, and machines: list live peers/sessions, send messages, reply to the last sender, and probe liveness. Use whenever you need to message another DSH agent, coordinate across sessions, or respond to an incoming interconnect handoff.";
15
+ var CANDIDATE = {
16
+ name: "dsh-interconnect",
17
+ description: DESCRIPTION,
18
+ invocation: INVOCATION,
19
+ provider: PROVIDER_NAME,
20
+ source: "bundled",
21
+ resourceBase: RESOURCE_BASE,
22
+ rank: BUNDLED_SKILL_RANK,
23
+ locator: SKILL_BODY_URL
24
+ };
25
+ var provider = {
26
+ name: PROVIDER_NAME,
27
+ list: () => Promise.resolve([CANDIDATE]),
28
+ async get(_candidate) {
29
+ return {
30
+ name: CANDIDATE.name,
31
+ description: CANDIDATE.description,
32
+ invocation: CANDIDATE.invocation,
33
+ provider: CANDIDATE.provider,
34
+ source: CANDIDATE.source,
35
+ resourceBase: RESOURCE_BASE,
36
+ content: await readFile(SKILL_BODY_URL, "utf8")
37
+ };
38
+ }
39
+ };
40
+ var name = "skill-interconnect";
41
+ var inject = ["skills", "interconnect"];
42
+ function apply(ctx) {
43
+ ctx.skills.registerProvider(() => provider);
44
+ }
45
+ export {
46
+ apply,
47
+ inject,
48
+ name
49
+ };
50
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/skill-interconnect/index.ts"],
4
+ "sourcesContent": ["/**\n * Companion skill for the dsh-interconnect tools: tells the model how to use\n * `interconnect_list`, `interconnect_ping`, `interconnect_send`, and\n * `interconnect_reply`, including the automatic sender-identity injection.\n *\n * This is a thin skill provider, intentionally separate from\n * `tool-interconnect`: the service and tools remain usable without the skill,\n * while a preset that wants model guidance can mount this row alongside them.\n * It injects the `interconnect` service so the skill only appears when the\n * transport it describes is actually present.\n * @module @deepseek-ai/dsh-skill-interconnect\n */\n\nimport { readFile } from 'node:fs/promises'\nimport { fileURLToPath } from 'node:url'\nimport { Context } from '@deepseek-ai/cordis'\nimport {\n BUNDLED_SKILL_RANK,\n type SkillCandidate,\n type SkillDefinition,\n type SkillProvider,\n} from '@deepseek-ai/dsh-skill'\n// Activates the `Context.interconnect` merge declared by the interconnect service plugin.\nimport type {} from '../interconnect/index.ts'\n\nconst PROVIDER_NAME = 'dsh-interconnect'\nconst SKILL_BODY_URL = new URL('../../assets/dsh-interconnect.md', import.meta.url)\nconst RESOURCE_BASE = {\n kind: 'directory',\n path: fileURLToPath(new URL('../../assets/', import.meta.url)),\n} as const\nconst INVOCATION = { modelInvocable: true, userInvocable: true } as const\nconst DESCRIPTION = 'Use the dsh-interconnect tools to exchange messages between DSH sessions, instances, and machines: list live peers/sessions, send messages, reply to the last sender, and probe liveness. Use whenever you need to message another DSH agent, coordinate across sessions, or respond to an incoming interconnect handoff.'\nconst CANDIDATE: SkillCandidate = {\n name: 'dsh-interconnect',\n description: DESCRIPTION,\n invocation: INVOCATION,\n provider: PROVIDER_NAME,\n source: 'bundled',\n resourceBase: RESOURCE_BASE,\n rank: BUNDLED_SKILL_RANK,\n locator: SKILL_BODY_URL,\n}\n\nconst provider: SkillProvider = {\n name: PROVIDER_NAME,\n list: () => Promise.resolve([CANDIDATE]),\n async get(_candidate): Promise<SkillDefinition> {\n return {\n name: CANDIDATE.name,\n description: CANDIDATE.description,\n invocation: CANDIDATE.invocation,\n provider: CANDIDATE.provider,\n source: CANDIDATE.source,\n resourceBase: RESOURCE_BASE,\n content: await readFile(SKILL_BODY_URL, 'utf8'),\n }\n },\n}\n\n/** Cordis plugin name. */\nexport const name = 'skill-interconnect'\n/** Services required by the companion provider. */\nexport const inject = ['skills', 'interconnect']\n\n/** Register the bundled `dsh-interconnect` skill on `ctx.skills`. */\nexport function apply(ctx: Context): void {\n ctx.skills.registerProvider(() => provider)\n}\n"],
5
+ "mappings": ";AAaA,SAAS,gBAAgB;AACzB,SAAS,qBAAqB;AAE9B;AAAA,EACE;AAAA,OAIK;AAIP,IAAM,gBAAgB;AACtB,IAAM,iBAAiB,IAAI,IAAI,oCAAoC,YAAY,GAAG;AAClF,IAAM,gBAAgB;AAAA,EACpB,MAAM;AAAA,EACN,MAAM,cAAc,IAAI,IAAI,iBAAiB,YAAY,GAAG,CAAC;AAC/D;AACA,IAAM,aAAa,EAAE,gBAAgB,MAAM,eAAe,KAAK;AAC/D,IAAM,cAAc;AACpB,IAAM,YAA4B;AAAA,EAChC,MAAM;AAAA,EACN,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,MAAM;AAAA,EACN,SAAS;AACX;AAEA,IAAM,WAA0B;AAAA,EAC9B,MAAM;AAAA,EACN,MAAM,MAAM,QAAQ,QAAQ,CAAC,SAAS,CAAC;AAAA,EACvC,MAAM,IAAI,YAAsC;AAC9C,WAAO;AAAA,MACL,MAAM,UAAU;AAAA,MAChB,aAAa,UAAU;AAAA,MACvB,YAAY,UAAU;AAAA,MACtB,UAAU,UAAU;AAAA,MACpB,QAAQ,UAAU;AAAA,MAClB,cAAc;AAAA,MACd,SAAS,MAAM,SAAS,gBAAgB,MAAM;AAAA,IAChD;AAAA,EACF;AACF;AAGO,IAAM,OAAO;AAEb,IAAM,SAAS,CAAC,UAAU,cAAc;AAGxC,SAAS,MAAM,KAAoB;AACxC,MAAI,OAAO,iBAAiB,MAAM,QAAQ;AAC5C;",
6
+ "names": []
7
+ }
@@ -0,0 +1,13 @@
1
+ // src/skill-interconnect/invariant.ts
2
+ var PACKAGE_NAME = "@deepseek-ai/dsh-skill-interconnect";
3
+ var name = "skill-interconnect-invariant";
4
+ var inject = ["invariants"];
5
+ var install = () => {
6
+ };
7
+ var apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
8
+ export {
9
+ apply,
10
+ inject,
11
+ name
12
+ };
13
+ //# sourceMappingURL=invariant.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/skill-interconnect/invariant.ts"],
4
+ "sourcesContent": ["/**\n * Package-owned invariant companion for `@deepseek-ai/dsh-skill-interconnect`.\n * @module @deepseek-ai/dsh-skill-interconnect/invariant\n */\n\n/* jscpd:ignore-start */\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'\n\nconst PACKAGE_NAME = '@deepseek-ai/dsh-skill-interconnect'\n\n/** Cordis companion plugin name. */\nexport const name = 'skill-interconnect-invariant'\n/** Service required before the companion can reserve package ownership. */\nexport const inject = ['invariants']\n\n/**\n * No runtime invariant: the package owns one immutable provider registration,\n * while the skill registry owns registration uniqueness and lifecycle checks.\n */\nconst install: InvariantInstaller = () => {}\n\n/**\n * Register this package's invariant companion.\n * @param ctx - Cordis context carrying the invariant service.\n * @returns the installed registration's disposer after setup succeeds.\n */\nexport const apply = (ctx: Context): Promise<() => void> =>\n Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install))\n/* jscpd:ignore-end */\n"],
5
+ "mappings": ";AASA,IAAM,eAAe;AAGd,IAAM,OAAO;AAEb,IAAM,SAAS,CAAC,YAAY;AAMnC,IAAM,UAA8B,MAAM;AAAC;AAOpC,IAAM,QAAQ,CAAC,QACpB,QAAQ,QAAQ,IAAI,WAAW,SAAS,cAAc,OAAO,CAAC;",
6
+ "names": []
7
+ }
@@ -5,7 +5,7 @@ function apply(ctx) {
5
5
  const interconnect = ctx.interconnect;
6
6
  ctx.tools.register(defineTool({
7
7
  name: "interconnect_send",
8
- description: 'Deliver one text message to a live session on another DSH instance (same machine, another machine, or another session), over a shared-secret-authenticated channel. Returns whether the peer instance received it and which instance answered. Only a session with a running agent can receive a message; when none is running the result reports reason "session-not-live", and interconnect_list shows which sessions are live there.',
8
+ description: 'Deliver one text message to a live session on another DSH instance (same machine, another machine, or another session), over a shared-secret-authenticated channel. Returns whether the peer instance received it and which instance answered. Only a session with a running agent can receive a message; when none is running the result reports reason "session-not-live", and interconnect_list shows which sessions are live there. The sending instance and session ids are attached automatically, so the receiver can reply with interconnect_reply; do not pass a sender parameter.',
9
9
  parameters: {
10
10
  instanceId: {
11
11
  type: "string",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/tool-interconnect/index.ts"],
4
- "sourcesContent": ["/**\n * Model-facing tools for cross-instance message handoff: `interconnect_send`\n * delivers one text message to a live session on a peer DSH instance, and\n * `interconnect_ping` probes a peer's liveness and identity.\n *\n * The tools consume the host-plane `interconnect` service and publish nothing\n * themselves, so this row sits as an ordinary tool plugin in a preset while\n * the service it reaches stays host-side (the same split `tool-goal` uses\n * against `goals`).\n * @module @deepseek-ai/dsh-tool-interconnect\n */\n\nimport { Context } from '@deepseek-ai/cordis'\nimport { defineTool } from '@deepseek-ai/dsh-tools'\n// Activates the `Context.interconnect` merge declared by the interconnect service plugin.\nimport type {} from '../interconnect/index.ts'\n\n/** Services required before the tools can register. */\nexport const inject = ['interconnect', 'tools']\n\n/**\n * Register the two tool surfaces. Registration is idempotent per fiber; the\n * tools unregister with the owning fiber.\n * @param ctx - connection context carrying the interconnect service and the tool registry.\n */\nexport function apply(ctx: Context): void {\n const interconnect = ctx.interconnect\n\n ctx.tools.register(defineTool({\n name: 'interconnect_send',\n description: 'Deliver one text message to a live session on another DSH instance (same machine, '\n + 'another machine, or another session), over a shared-secret-authenticated channel. '\n + 'Returns whether the peer instance received it and which instance answered. '\n + 'Only a session with a running agent can receive a message; when none is running the result '\n + 'reports reason \"session-not-live\", and interconnect_list shows which sessions are live there.',\n parameters: {\n instanceId: {\n type: 'string',\n required: true,\n description: 'The peer instance id to deliver to, as configured under this instance\\'s '\n + 'interconnect peers map. Deliveries go over the persistent link to that instance.',\n },\n sessionId: {\n type: 'string',\n required: true,\n description: 'Target session id on the receiving instance to deliver the message to.',\n },\n text: {\n type: 'string',\n required: true,\n description: 'Message text delivered to the peer session.',\n },\n delivery: {\n type: 'string',\n enum: ['followup', 'steer', 'inject'],\n description: 'How the message reaches the target agent. `followup` queues it as its own turn '\n + 'behind whatever that agent is doing now. `steer` cuts into the nearest step boundary of a '\n + 'running turn, so an urgent message does not wait for that turn to end. `inject` seeds '\n + 'context without waking an idle agent, so it may sit unread. Omit to use the receiver\\'s '\n + 'configured default.',\n },\n resume: {\n type: 'boolean',\n description: 'Wake the target session if it is persisted but has no running agent. Off by '\n + 'default because delivery to a woken session starts a real agent turn \u2014 a billed model call '\n + 'with that session\\'s full toolset \u2014 in a conversation nobody is watching. Prefer '\n + 'interconnect_list and an already-live target; set this only when that specific session must '\n + 'be reached. The receiver may refuse, answering reason \"resume-refused\".',\n },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n delivered: { type: 'boolean', required: true },\n instance: { type: 'string', required: true },\n delivery: { type: 'string' },\n reason: { type: 'string' },\n },\n },\n render: (_args, value) => {\n if (value.delivered) {\n return [{\n type: 'text',\n text: `delivered to ${value.instance}${value.delivery === undefined ? '' : ` via ${value.delivery}`}`,\n }]\n }\n // Each failure gets the response it actually needs: a not-live target is\n // the caller's to re-choose, while an unreachable peer may just be worth\n // retrying. The old single line claimed \"no live session\" even when the\n // peer never answered, which pointed at the wrong thing entirely.\n const text = ((): string => {\n switch (value.reason) {\n case 'unreachable':\n return `not delivered: ${value.instance} did not answer (unreachable or unauthorized)`\n case 'resume-refused':\n return `not delivered: ${value.instance} does not allow waking persisted sessions`\n case 'resume-failed':\n return `not delivered: could not wake \"${_args.sessionId}\" on ${value.instance}`\n + ' (no such persisted session, or another owner holds it)'\n case 'session-owned-by-subagent':\n return `not delivered: \"${_args.sessionId}\" is a subagent's session on ${value.instance}`\n + ' \u2014 its parent agent owns delivery, so reach it through that parent'\n default:\n return `not delivered: no live session \"${_args.sessionId}\" on ${value.instance}`\n + ' \u2014 use interconnect_list to see which sessions are live there,'\n + ' or set resume to wake this one'\n }\n })()\n return [{ type: 'text', text }]\n },\n },\n async execute(args, exec) {\n const sessionId = exec.agent?.session.id\n const self = interconnect.selfSender(sessionId === undefined ? '' : String(sessionId))\n const result = await interconnect.send({\n instanceId: args.instanceId,\n sessionId: args.sessionId,\n text: args.text,\n // Attribute this instance as the sender so the peer can reply back. The\n // calling session id comes from the executing agent (the session sending).\n sender: self,\n ...(args.delivery === undefined ? {} : { delivery: args.delivery }),\n ...(args.resume === undefined ? {} : { resume: args.resume }),\n })\n return {\n delivered: result.delivered,\n instance: result.instance,\n ...(result.delivery === undefined ? {} : { delivery: result.delivery }),\n ...(result.reason === undefined ? {} : { reason: result.reason }),\n }\n },\n }))\n\n ctx.tools.register(defineTool({\n name: 'interconnect_ping',\n description: 'Probe a peer DSH instance for liveness and identity over the shared-secret channel. '\n + 'Returns the peer instance id when reachable, or null on transport/auth failure.',\n parameters: {\n instanceId: {\n type: 'string',\n required: true,\n description: 'The peer instance id to probe, as configured under this instance\\'s '\n + 'interconnect peers map.',\n },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n reachable: { type: 'boolean', required: true },\n instance: { type: 'string' },\n },\n },\n render: (_args, value) => [{\n type: 'text',\n text: value.reachable\n ? `reachable: ${value.instance ?? '(unknown instance)'}`\n : 'unreachable or unauthorized',\n }],\n },\n async execute(args) {\n const result = await interconnect.ping(args.instanceId)\n if (result === undefined) return { reachable: false }\n return { reachable: true, instance: result.instance }\n },\n }))\n\n ctx.tools.register(defineTool({\n name: 'interconnect_list',\n description: 'List the live sessions on a peer DSH instance, so a message can be addressed without '\n + 'knowing a session id in advance. Every returned sessionId is a valid interconnect_send target at '\n + 'the time of the call. Only live sessions appear: a session that exists on the peer but has no '\n + 'running agent is not listed and cannot receive a message.',\n parameters: {\n instanceId: {\n type: 'string',\n required: true,\n description: 'The peer instance id to list, as configured under this instance\\'s '\n + 'interconnect peers map.',\n },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n reachable: { type: 'boolean', required: true },\n instance: { type: 'string' },\n sessions: {\n type: 'array',\n items: {\n type: 'object',\n additionalProperties: false,\n properties: {\n sessionId: { type: 'string', required: true },\n title: { type: 'string' },\n status: { type: 'string' },\n },\n },\n },\n },\n },\n render: (_args, value) => {\n if (!value.reachable) return [{ type: 'text', text: 'unreachable or unauthorized' }]\n const sessions = value.sessions ?? []\n if (sessions.length === 0) {\n return [{ type: 'text', text: `no live sessions on ${value.instance ?? '(unknown instance)'}` }]\n }\n const lines = sessions.map((session) => {\n const title = session.title === undefined ? '' : ` ${session.title}`\n const status = session.status === undefined ? '' : ` [${session.status}]`\n return `${session.sessionId}${title}${status}`\n })\n return [{ type: 'text', text: lines.join('\\n') }]\n },\n },\n async execute(args) {\n const result = await interconnect.list(args.instanceId)\n if (result === undefined) return { reachable: false }\n return {\n reachable: true,\n instance: result.instance,\n // Rebuild each row so an optional key stays absent rather than\n // becoming an explicit undefined the wire schema would reject.\n sessions: result.sessions.map(session => ({\n sessionId: session.sessionId,\n ...(session.title === undefined ? {} : { title: session.title }),\n ...(session.status === undefined ? {} : { status: session.status }),\n })),\n }\n },\n }))\n\n ctx.tools.register(defineTool({\n name: 'interconnect_reply',\n description: 'Deliver one text message back to the peer that this session last received an '\n + 'interconnect message from. Only the LOCAL session id and the reply text are needed: the '\n + 'outbound target (the peer origin and its session id) is recalled from the message this '\n + 'session received, so you do not ask for an address twice. A session that never received a '\n + 'message through interconnect \u2014 or received one without a sender identity \u2014 reports reason '\n + '\"no-sender-known\".',\n parameters: {\n sessionId: {\n type: 'string',\n required: true,\n description: 'The LOCAL session id that received the message being replied to.',\n },\n text: {\n type: 'string',\n required: true,\n description: 'Message text delivered back to the recorded sender session.',\n },\n delivery: {\n type: 'string',\n enum: ['followup', 'steer', 'inject'],\n description: 'How the reply reaches the target agent, as in interconnect_send. Omit to use '\n + \"the receiver's configured default.\",\n },\n resume: {\n type: 'boolean',\n description: 'Wake the target session if it is persisted but has no running agent, as in '\n + 'interconnect_send. Off by default; the receiver may refuse.',\n },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n delivered: { type: 'boolean', required: true },\n instance: { type: 'string', required: true },\n delivery: { type: 'string' },\n reason: { type: 'string' },\n },\n },\n render: (_args, value) => {\n if (value.delivered) {\n return [{\n type: 'text',\n text: `replied to ${value.instance}${value.delivery === undefined ? '' : ` via ${value.delivery}`}`,\n }]\n }\n const text = ((): string => {\n if (value.reason === 'no-sender-known') {\n return `not delivered: no sender recorded for \"${_args.sessionId}\"`\n + ' \u2014 this session never received an interconnect message with a sender identity'\n }\n if (value.reason === 'session-owned-by-subagent') {\n return `not delivered: \"${_args.sessionId}\" is a subagent's session \u2014 its parent agent owns delivery`\n }\n if (value.reason === 'unreachable') {\n return `not delivered: the recorded sender did not answer (unreachable or unauthorized)`\n }\n if (value.reason === 'resume-refused') {\n return `not delivered: the recorded sender does not allow waking persisted sessions`\n }\n if (value.reason === 'resume-failed') {\n return `not delivered: could not wake the recorded sender's session`\n }\n return `not delivered: the recorded sender's session is not live`\n })()\n return [{ type: 'text', text }]\n },\n },\n async execute(args) {\n const result = await interconnect.reply({\n sessionId: args.sessionId,\n text: args.text,\n ...(args.delivery === undefined ? {} : { delivery: args.delivery }),\n ...(args.resume === undefined ? {} : { resume: args.resume }),\n })\n return {\n delivered: result.delivered,\n instance: result.instance,\n ...(result.delivery === undefined ? {} : { delivery: result.delivery }),\n ...(result.reason === undefined ? {} : { reason: result.reason }),\n }\n },\n }))\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Model-facing tools for cross-instance message handoff: `interconnect_send`\n * delivers one text message to a live session on a peer DSH instance, and\n * `interconnect_ping` probes a peer's liveness and identity.\n *\n * The tools consume the host-plane `interconnect` service and publish nothing\n * themselves, so this row sits as an ordinary tool plugin in a preset while\n * the service it reaches stays host-side (the same split `tool-goal` uses\n * against `goals`).\n * @module @deepseek-ai/dsh-tool-interconnect\n */\n\nimport { Context } from '@deepseek-ai/cordis'\nimport { defineTool } from '@deepseek-ai/dsh-tools'\n// Activates the `Context.interconnect` merge declared by the interconnect service plugin.\nimport type {} from '../interconnect/index.ts'\n\n/** Services required before the tools can register. */\nexport const inject = ['interconnect', 'tools']\n\n/**\n * Register the two tool surfaces. Registration is idempotent per fiber; the\n * tools unregister with the owning fiber.\n * @param ctx - connection context carrying the interconnect service and the tool registry.\n */\nexport function apply(ctx: Context): void {\n const interconnect = ctx.interconnect\n\n ctx.tools.register(defineTool({\n name: 'interconnect_send',\n description: 'Deliver one text message to a live session on another DSH instance (same machine, '\n + 'another machine, or another session), over a shared-secret-authenticated channel. '\n + 'Returns whether the peer instance received it and which instance answered. '\n + 'Only a session with a running agent can receive a message; when none is running the result '\n + 'reports reason \"session-not-live\", and interconnect_list shows which sessions are live there. '\n + 'The sending instance and session ids are attached automatically, so the receiver can reply '\n + 'with interconnect_reply; do not pass a sender parameter.',\n parameters: {\n instanceId: {\n type: 'string',\n required: true,\n description: 'The peer instance id to deliver to, as configured under this instance\\'s '\n + 'interconnect peers map. Deliveries go over the persistent link to that instance.',\n },\n sessionId: {\n type: 'string',\n required: true,\n description: 'Target session id on the receiving instance to deliver the message to.',\n },\n text: {\n type: 'string',\n required: true,\n description: 'Message text delivered to the peer session.',\n },\n delivery: {\n type: 'string',\n enum: ['followup', 'steer', 'inject'],\n description: 'How the message reaches the target agent. `followup` queues it as its own turn '\n + 'behind whatever that agent is doing now. `steer` cuts into the nearest step boundary of a '\n + 'running turn, so an urgent message does not wait for that turn to end. `inject` seeds '\n + 'context without waking an idle agent, so it may sit unread. Omit to use the receiver\\'s '\n + 'configured default.',\n },\n resume: {\n type: 'boolean',\n description: 'Wake the target session if it is persisted but has no running agent. Off by '\n + 'default because delivery to a woken session starts a real agent turn \u2014 a billed model call '\n + 'with that session\\'s full toolset \u2014 in a conversation nobody is watching. Prefer '\n + 'interconnect_list and an already-live target; set this only when that specific session must '\n + 'be reached. The receiver may refuse, answering reason \"resume-refused\".',\n },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n delivered: { type: 'boolean', required: true },\n instance: { type: 'string', required: true },\n delivery: { type: 'string' },\n reason: { type: 'string' },\n },\n },\n render: (_args, value) => {\n if (value.delivered) {\n return [{\n type: 'text',\n text: `delivered to ${value.instance}${value.delivery === undefined ? '' : ` via ${value.delivery}`}`,\n }]\n }\n // Each failure gets the response it actually needs: a not-live target is\n // the caller's to re-choose, while an unreachable peer may just be worth\n // retrying. The old single line claimed \"no live session\" even when the\n // peer never answered, which pointed at the wrong thing entirely.\n const text = ((): string => {\n switch (value.reason) {\n case 'unreachable':\n return `not delivered: ${value.instance} did not answer (unreachable or unauthorized)`\n case 'resume-refused':\n return `not delivered: ${value.instance} does not allow waking persisted sessions`\n case 'resume-failed':\n return `not delivered: could not wake \"${_args.sessionId}\" on ${value.instance}`\n + ' (no such persisted session, or another owner holds it)'\n case 'session-owned-by-subagent':\n return `not delivered: \"${_args.sessionId}\" is a subagent's session on ${value.instance}`\n + ' \u2014 its parent agent owns delivery, so reach it through that parent'\n default:\n return `not delivered: no live session \"${_args.sessionId}\" on ${value.instance}`\n + ' \u2014 use interconnect_list to see which sessions are live there,'\n + ' or set resume to wake this one'\n }\n })()\n return [{ type: 'text', text }]\n },\n },\n async execute(args, exec) {\n const sessionId = exec.agent?.session.id\n const self = interconnect.selfSender(sessionId === undefined ? '' : String(sessionId))\n const result = await interconnect.send({\n instanceId: args.instanceId,\n sessionId: args.sessionId,\n text: args.text,\n // Attribute this instance as the sender so the peer can reply back. The\n // calling session id comes from the executing agent (the session sending).\n sender: self,\n ...(args.delivery === undefined ? {} : { delivery: args.delivery }),\n ...(args.resume === undefined ? {} : { resume: args.resume }),\n })\n return {\n delivered: result.delivered,\n instance: result.instance,\n ...(result.delivery === undefined ? {} : { delivery: result.delivery }),\n ...(result.reason === undefined ? {} : { reason: result.reason }),\n }\n },\n }))\n\n ctx.tools.register(defineTool({\n name: 'interconnect_ping',\n description: 'Probe a peer DSH instance for liveness and identity over the shared-secret channel. '\n + 'Returns the peer instance id when reachable, or null on transport/auth failure.',\n parameters: {\n instanceId: {\n type: 'string',\n required: true,\n description: 'The peer instance id to probe, as configured under this instance\\'s '\n + 'interconnect peers map.',\n },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n reachable: { type: 'boolean', required: true },\n instance: { type: 'string' },\n },\n },\n render: (_args, value) => [{\n type: 'text',\n text: value.reachable\n ? `reachable: ${value.instance ?? '(unknown instance)'}`\n : 'unreachable or unauthorized',\n }],\n },\n async execute(args) {\n const result = await interconnect.ping(args.instanceId)\n if (result === undefined) return { reachable: false }\n return { reachable: true, instance: result.instance }\n },\n }))\n\n ctx.tools.register(defineTool({\n name: 'interconnect_list',\n description: 'List the live sessions on a peer DSH instance, so a message can be addressed without '\n + 'knowing a session id in advance. Every returned sessionId is a valid interconnect_send target at '\n + 'the time of the call. Only live sessions appear: a session that exists on the peer but has no '\n + 'running agent is not listed and cannot receive a message.',\n parameters: {\n instanceId: {\n type: 'string',\n required: true,\n description: 'The peer instance id to list, as configured under this instance\\'s '\n + 'interconnect peers map.',\n },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n reachable: { type: 'boolean', required: true },\n instance: { type: 'string' },\n sessions: {\n type: 'array',\n items: {\n type: 'object',\n additionalProperties: false,\n properties: {\n sessionId: { type: 'string', required: true },\n title: { type: 'string' },\n status: { type: 'string' },\n },\n },\n },\n },\n },\n render: (_args, value) => {\n if (!value.reachable) return [{ type: 'text', text: 'unreachable or unauthorized' }]\n const sessions = value.sessions ?? []\n if (sessions.length === 0) {\n return [{ type: 'text', text: `no live sessions on ${value.instance ?? '(unknown instance)'}` }]\n }\n const lines = sessions.map((session) => {\n const title = session.title === undefined ? '' : ` ${session.title}`\n const status = session.status === undefined ? '' : ` [${session.status}]`\n return `${session.sessionId}${title}${status}`\n })\n return [{ type: 'text', text: lines.join('\\n') }]\n },\n },\n async execute(args) {\n const result = await interconnect.list(args.instanceId)\n if (result === undefined) return { reachable: false }\n return {\n reachable: true,\n instance: result.instance,\n // Rebuild each row so an optional key stays absent rather than\n // becoming an explicit undefined the wire schema would reject.\n sessions: result.sessions.map(session => ({\n sessionId: session.sessionId,\n ...(session.title === undefined ? {} : { title: session.title }),\n ...(session.status === undefined ? {} : { status: session.status }),\n })),\n }\n },\n }))\n\n ctx.tools.register(defineTool({\n name: 'interconnect_reply',\n description: 'Deliver one text message back to the peer that this session last received an '\n + 'interconnect message from. Only the LOCAL session id and the reply text are needed: the '\n + 'outbound target (the peer origin and its session id) is recalled from the message this '\n + 'session received, so you do not ask for an address twice. A session that never received a '\n + 'message through interconnect \u2014 or received one without a sender identity \u2014 reports reason '\n + '\"no-sender-known\".',\n parameters: {\n sessionId: {\n type: 'string',\n required: true,\n description: 'The LOCAL session id that received the message being replied to.',\n },\n text: {\n type: 'string',\n required: true,\n description: 'Message text delivered back to the recorded sender session.',\n },\n delivery: {\n type: 'string',\n enum: ['followup', 'steer', 'inject'],\n description: 'How the reply reaches the target agent, as in interconnect_send. Omit to use '\n + \"the receiver's configured default.\",\n },\n resume: {\n type: 'boolean',\n description: 'Wake the target session if it is persisted but has no running agent, as in '\n + 'interconnect_send. Off by default; the receiver may refuse.',\n },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n delivered: { type: 'boolean', required: true },\n instance: { type: 'string', required: true },\n delivery: { type: 'string' },\n reason: { type: 'string' },\n },\n },\n render: (_args, value) => {\n if (value.delivered) {\n return [{\n type: 'text',\n text: `replied to ${value.instance}${value.delivery === undefined ? '' : ` via ${value.delivery}`}`,\n }]\n }\n const text = ((): string => {\n if (value.reason === 'no-sender-known') {\n return `not delivered: no sender recorded for \"${_args.sessionId}\"`\n + ' \u2014 this session never received an interconnect message with a sender identity'\n }\n if (value.reason === 'session-owned-by-subagent') {\n return `not delivered: \"${_args.sessionId}\" is a subagent's session \u2014 its parent agent owns delivery`\n }\n if (value.reason === 'unreachable') {\n return `not delivered: the recorded sender did not answer (unreachable or unauthorized)`\n }\n if (value.reason === 'resume-refused') {\n return `not delivered: the recorded sender does not allow waking persisted sessions`\n }\n if (value.reason === 'resume-failed') {\n return `not delivered: could not wake the recorded sender's session`\n }\n return `not delivered: the recorded sender's session is not live`\n })()\n return [{ type: 'text', text }]\n },\n },\n async execute(args) {\n const result = await interconnect.reply({\n sessionId: args.sessionId,\n text: args.text,\n ...(args.delivery === undefined ? {} : { delivery: args.delivery }),\n ...(args.resume === undefined ? {} : { resume: args.resume }),\n })\n return {\n delivered: result.delivered,\n instance: result.instance,\n ...(result.delivery === undefined ? {} : { delivery: result.delivery }),\n ...(result.reason === undefined ? {} : { reason: result.reason }),\n }\n },\n }))\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Companion skill for the dsh-interconnect tools: tells the model how to use
3
+ * `interconnect_list`, `interconnect_ping`, `interconnect_send`, and
4
+ * `interconnect_reply`, including the automatic sender-identity injection.
5
+ *
6
+ * This is a thin skill provider, intentionally separate from
7
+ * `tool-interconnect`: the service and tools remain usable without the skill,
8
+ * while a preset that wants model guidance can mount this row alongside them.
9
+ * It injects the `interconnect` service so the skill only appears when the
10
+ * transport it describes is actually present.
11
+ * @module @deepseek-ai/dsh-skill-interconnect
12
+ */
13
+ import { Context } from '@deepseek-ai/cordis';
14
+ /** Cordis plugin name. */
15
+ export declare const name = "skill-interconnect";
16
+ /** Services required by the companion provider. */
17
+ export declare const inject: string[];
18
+ /** Register the bundled `dsh-interconnect` skill on `ctx.skills`. */
19
+ export declare function apply(ctx: Context): void;
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/skill-interconnect/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AA6C7C,0BAA0B;AAC1B,eAAO,MAAM,IAAI,uBAAuB,CAAA;AACxC,mDAAmD;AACnD,eAAO,MAAM,MAAM,UAA6B,CAAA;AAEhD,qEAAqE;AACrE,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAExC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Package-owned invariant companion for `@deepseek-ai/dsh-skill-interconnect`.
3
+ * @module @deepseek-ai/dsh-skill-interconnect/invariant
4
+ */
5
+ import type { Context } from '@deepseek-ai/cordis';
6
+ /** Cordis companion plugin name. */
7
+ export declare const name = "skill-interconnect-invariant";
8
+ /** Service required before the companion can reserve package ownership. */
9
+ export declare const inject: string[];
10
+ /**
11
+ * Register this package's invariant companion.
12
+ * @param ctx - Cordis context carrying the invariant service.
13
+ * @returns the installed registration's disposer after setup succeeds.
14
+ */
15
+ export declare const apply: (ctx: Context) => Promise<() => void>;
16
+ //# sourceMappingURL=invariant.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invariant.d.ts","sourceRoot":"","sources":["../../../src/skill-interconnect/invariant.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAKlD,oCAAoC;AACpC,eAAO,MAAM,IAAI,iCAAiC,CAAA;AAClD,2EAA2E;AAC3E,eAAO,MAAM,MAAM,UAAiB,CAAA;AAQpC;;;;GAIG;AACH,eAAO,MAAM,KAAK,GAAI,KAAK,OAAO,KAAG,OAAO,CAAC,MAAM,IAAI,CACU,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tool-interconnect/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAK7C,uDAAuD;AACvD,eAAO,MAAM,MAAM,UAA4B,CAAA;AAE/C;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAySxC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tool-interconnect/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAK7C,uDAAuD;AACvD,eAAO,MAAM,MAAM,UAA4B,CAAA;AAE/C;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CA2SxC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-interconnect",
3
- "description": "Cross-instance message/event handoff plugins for DeepSeek Harness (DSH): interconnect service + model-facing tools",
4
- "version": "0.9.0",
3
+ "description": "Cross-instance message/event handoff plugins for DeepSeek Harness (DSH): interconnect service + model-facing tools + companion skill",
4
+ "version": "0.10.0",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "main": "lib/index.js",
@@ -18,6 +18,14 @@
18
18
  "types": "./lib/types/tool-interconnect/index.d.ts",
19
19
  "default": "./lib/tool-interconnect/index.js"
20
20
  },
21
+ "./skill-interconnect": {
22
+ "types": "./lib/types/skill-interconnect/index.d.ts",
23
+ "default": "./lib/skill-interconnect/index.js"
24
+ },
25
+ "./skill-interconnect/invariant": {
26
+ "types": "./lib/types/skill-interconnect/invariant.d.ts",
27
+ "default": "./lib/skill-interconnect/invariant.js"
28
+ },
21
29
  "./cordis.patch.yml": "./cordis.patch.yml",
22
30
  "./package.json": "./package.json"
23
31
  },
@@ -28,6 +36,7 @@
28
36
  },
29
37
  "files": [
30
38
  "lib",
39
+ "assets",
31
40
  "cordis.patch.yml",
32
41
  "dsh.plugin.json",
33
42
  "README.md",
@@ -50,6 +59,7 @@
50
59
  "@deepseek-ai/dsh-host-apiproxy": "*",
51
60
  "@deepseek-ai/dsh-host-webserver": "*",
52
61
  "@deepseek-ai/dsh-tools": "*",
62
+ "@deepseek-ai/dsh-skill": "*",
53
63
  "@deepseek-ai/dsh-invariants": "*",
54
64
  "@deepseek-ai/schemastery": "*",
55
65
  "ws": "*"
@@ -66,6 +76,7 @@
66
76
  "@deepseek-ai/dsh-host-apiproxy": "link:../dsh/packages/host/apiproxy",
67
77
  "@deepseek-ai/dsh-host-webserver": "link:../dsh/packages/host/webserver",
68
78
  "@deepseek-ai/dsh-tools": "link:../dsh/packages/core/tools",
79
+ "@deepseek-ai/dsh-skill": "link:../dsh/packages/skill/skill",
69
80
  "@deepseek-ai/dsh-invariants": "link:../dsh/packages/runtime-diagnostics/invariants",
70
81
  "@deepseek-ai/dsh-system-prompt": "link:../dsh/packages/core/system-prompt",
71
82
  "@types/node": "^24.0.0",