@barryfan2045/dsh-matrix 0.1.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.
Files changed (206) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +286 -0
  3. package/THIRD_PARTY_NOTICES.md +53 -0
  4. package/assets/avatars/instance-01.png +0 -0
  5. package/assets/avatars/instance-02.png +0 -0
  6. package/assets/avatars/instance-03.png +0 -0
  7. package/assets/avatars/instance-04.png +0 -0
  8. package/assets/avatars/instance-05.png +0 -0
  9. package/assets/avatars/instance-06.png +0 -0
  10. package/assets/avatars/instance-07.png +0 -0
  11. package/assets/avatars/instance-08.png +0 -0
  12. package/assets/avatars/instance-09.png +0 -0
  13. package/assets/avatars/instance-10.png +0 -0
  14. package/assets/avatars/instance-11.png +0 -0
  15. package/assets/avatars/instance-12.png +0 -0
  16. package/assets/avatars/management.png +0 -0
  17. package/cordis.patch.yml +13 -0
  18. package/dist/auth/admin-commands.d.ts +47 -0
  19. package/dist/auth/admin-commands.d.ts.map +1 -0
  20. package/dist/auth/admin-commands.js +112 -0
  21. package/dist/auth/admin-commands.js.map +1 -0
  22. package/dist/auth/challenge.d.ts +93 -0
  23. package/dist/auth/challenge.d.ts.map +1 -0
  24. package/dist/auth/challenge.js +104 -0
  25. package/dist/auth/challenge.js.map +1 -0
  26. package/dist/auth/store.d.ts +55 -0
  27. package/dist/auth/store.d.ts.map +1 -0
  28. package/dist/auth/store.js +124 -0
  29. package/dist/auth/store.js.map +1 -0
  30. package/dist/bridge/agent-commands.d.ts +39 -0
  31. package/dist/bridge/agent-commands.d.ts.map +1 -0
  32. package/dist/bridge/agent-commands.js +243 -0
  33. package/dist/bridge/agent-commands.js.map +1 -0
  34. package/dist/bridge/attachments-ledger.d.ts +54 -0
  35. package/dist/bridge/attachments-ledger.d.ts.map +1 -0
  36. package/dist/bridge/attachments-ledger.js +68 -0
  37. package/dist/bridge/attachments-ledger.js.map +1 -0
  38. package/dist/bridge/commands.d.ts +28 -0
  39. package/dist/bridge/commands.d.ts.map +1 -0
  40. package/dist/bridge/commands.js +18 -0
  41. package/dist/bridge/commands.js.map +1 -0
  42. package/dist/bridge/crypto-health.d.ts +37 -0
  43. package/dist/bridge/crypto-health.d.ts.map +1 -0
  44. package/dist/bridge/crypto-health.js +38 -0
  45. package/dist/bridge/crypto-health.js.map +1 -0
  46. package/dist/bridge/group-gate.d.ts +38 -0
  47. package/dist/bridge/group-gate.d.ts.map +1 -0
  48. package/dist/bridge/group-gate.js +49 -0
  49. package/dist/bridge/group-gate.js.map +1 -0
  50. package/dist/bridge/instance-lock.d.ts +10 -0
  51. package/dist/bridge/instance-lock.d.ts.map +1 -0
  52. package/dist/bridge/instance-lock.js +82 -0
  53. package/dist/bridge/instance-lock.js.map +1 -0
  54. package/dist/bridge/interactions.d.ts +62 -0
  55. package/dist/bridge/interactions.d.ts.map +1 -0
  56. package/dist/bridge/interactions.js +237 -0
  57. package/dist/bridge/interactions.js.map +1 -0
  58. package/dist/bridge/management-room.d.ts +13 -0
  59. package/dist/bridge/management-room.d.ts.map +1 -0
  60. package/dist/bridge/management-room.js +27 -0
  61. package/dist/bridge/management-room.js.map +1 -0
  62. package/dist/bridge/multi-project.d.ts +34 -0
  63. package/dist/bridge/multi-project.d.ts.map +1 -0
  64. package/dist/bridge/multi-project.js +44 -0
  65. package/dist/bridge/multi-project.js.map +1 -0
  66. package/dist/bridge/pipeline.d.ts +151 -0
  67. package/dist/bridge/pipeline.d.ts.map +1 -0
  68. package/dist/bridge/pipeline.js +502 -0
  69. package/dist/bridge/pipeline.js.map +1 -0
  70. package/dist/bridge/pmctl.d.ts +50 -0
  71. package/dist/bridge/pmctl.d.ts.map +1 -0
  72. package/dist/bridge/pmctl.js +272 -0
  73. package/dist/bridge/pmctl.js.map +1 -0
  74. package/dist/bridge/power-levels.d.ts +57 -0
  75. package/dist/bridge/power-levels.d.ts.map +1 -0
  76. package/dist/bridge/power-levels.js +92 -0
  77. package/dist/bridge/power-levels.js.map +1 -0
  78. package/dist/bridge/power-sync.d.ts +64 -0
  79. package/dist/bridge/power-sync.d.ts.map +1 -0
  80. package/dist/bridge/power-sync.js +121 -0
  81. package/dist/bridge/power-sync.js.map +1 -0
  82. package/dist/bridge/projects.d.ts +97 -0
  83. package/dist/bridge/projects.d.ts.map +1 -0
  84. package/dist/bridge/projects.js +288 -0
  85. package/dist/bridge/projects.js.map +1 -0
  86. package/dist/bridge/quote-cache.d.ts +38 -0
  87. package/dist/bridge/quote-cache.d.ts.map +1 -0
  88. package/dist/bridge/quote-cache.js +56 -0
  89. package/dist/bridge/quote-cache.js.map +1 -0
  90. package/dist/bridge/reply.d.ts +31 -0
  91. package/dist/bridge/reply.d.ts.map +1 -0
  92. package/dist/bridge/reply.js +122 -0
  93. package/dist/bridge/reply.js.map +1 -0
  94. package/dist/bridge/space-identity.d.ts +43 -0
  95. package/dist/bridge/space-identity.d.ts.map +1 -0
  96. package/dist/bridge/space-identity.js +92 -0
  97. package/dist/bridge/space-identity.js.map +1 -0
  98. package/dist/bridge/space-sync.d.ts +94 -0
  99. package/dist/bridge/space-sync.d.ts.map +1 -0
  100. package/dist/bridge/space-sync.js +137 -0
  101. package/dist/bridge/space-sync.js.map +1 -0
  102. package/dist/bridge/turn-commands.d.ts +28 -0
  103. package/dist/bridge/turn-commands.d.ts.map +1 -0
  104. package/dist/bridge/turn-commands.js +97 -0
  105. package/dist/bridge/turn-commands.js.map +1 -0
  106. package/dist/cli/config-store.d.ts +32 -0
  107. package/dist/cli/config-store.d.ts.map +1 -0
  108. package/dist/cli/config-store.js +118 -0
  109. package/dist/cli/config-store.js.map +1 -0
  110. package/dist/cli/crypto-store.d.ts +42 -0
  111. package/dist/cli/crypto-store.d.ts.map +1 -0
  112. package/dist/cli/crypto-store.js +70 -0
  113. package/dist/cli/crypto-store.js.map +1 -0
  114. package/dist/cli/device-prune.d.ts +105 -0
  115. package/dist/cli/device-prune.d.ts.map +1 -0
  116. package/dist/cli/device-prune.js +163 -0
  117. package/dist/cli/device-prune.js.map +1 -0
  118. package/dist/cli/index.d.ts +4 -0
  119. package/dist/cli/index.d.ts.map +1 -0
  120. package/dist/cli/index.js +584 -0
  121. package/dist/cli/index.js.map +1 -0
  122. package/dist/cli/log-filter.d.ts +32 -0
  123. package/dist/cli/log-filter.d.ts.map +1 -0
  124. package/dist/cli/log-filter.js +40 -0
  125. package/dist/cli/log-filter.js.map +1 -0
  126. package/dist/cli/pnpm-builds.d.ts +32 -0
  127. package/dist/cli/pnpm-builds.d.ts.map +1 -0
  128. package/dist/cli/pnpm-builds.js +73 -0
  129. package/dist/cli/pnpm-builds.js.map +1 -0
  130. package/dist/cli/profile-patch.d.ts +26 -0
  131. package/dist/cli/profile-patch.d.ts.map +1 -0
  132. package/dist/cli/profile-patch.js +56 -0
  133. package/dist/cli/profile-patch.js.map +1 -0
  134. package/dist/cli/setup.d.ts +39 -0
  135. package/dist/cli/setup.d.ts.map +1 -0
  136. package/dist/cli/setup.js +234 -0
  137. package/dist/cli/setup.js.map +1 -0
  138. package/dist/cli/systemd-hint.d.ts +11 -0
  139. package/dist/cli/systemd-hint.d.ts.map +1 -0
  140. package/dist/cli/systemd-hint.js +46 -0
  141. package/dist/cli/systemd-hint.js.map +1 -0
  142. package/dist/cli/systemd.d.ts +32 -0
  143. package/dist/cli/systemd.d.ts.map +1 -0
  144. package/dist/cli/systemd.js +58 -0
  145. package/dist/cli/systemd.js.map +1 -0
  146. package/dist/config.d.ts +54 -0
  147. package/dist/config.d.ts.map +1 -0
  148. package/dist/config.js +107 -0
  149. package/dist/config.js.map +1 -0
  150. package/dist/dsh/backend.d.ts +110 -0
  151. package/dist/dsh/backend.d.ts.map +1 -0
  152. package/dist/dsh/backend.js +481 -0
  153. package/dist/dsh/backend.js.map +1 -0
  154. package/dist/dsh/interactions.d.ts +50 -0
  155. package/dist/dsh/interactions.d.ts.map +1 -0
  156. package/dist/dsh/interactions.js +141 -0
  157. package/dist/dsh/interactions.js.map +1 -0
  158. package/dist/dsh/stream.d.ts +32 -0
  159. package/dist/dsh/stream.d.ts.map +1 -0
  160. package/dist/dsh/stream.js +109 -0
  161. package/dist/dsh/stream.js.map +1 -0
  162. package/dist/formatting.d.ts +14 -0
  163. package/dist/formatting.d.ts.map +1 -0
  164. package/dist/formatting.js +63 -0
  165. package/dist/formatting.js.map +1 -0
  166. package/dist/index.d.ts +8 -0
  167. package/dist/index.d.ts.map +1 -0
  168. package/dist/index.js +232 -0
  169. package/dist/index.js.map +1 -0
  170. package/dist/logger.d.ts +9 -0
  171. package/dist/logger.d.ts.map +1 -0
  172. package/dist/logger.js +28 -0
  173. package/dist/logger.js.map +1 -0
  174. package/dist/matrix/matrix-events.d.ts +49 -0
  175. package/dist/matrix/matrix-events.d.ts.map +1 -0
  176. package/dist/matrix/matrix-events.js +89 -0
  177. package/dist/matrix/matrix-events.js.map +1 -0
  178. package/dist/matrix/transport.d.ts +192 -0
  179. package/dist/matrix/transport.d.ts.map +1 -0
  180. package/dist/matrix/transport.js +510 -0
  181. package/dist/matrix/transport.js.map +1 -0
  182. package/dist/ports/attachments.d.ts +51 -0
  183. package/dist/ports/attachments.d.ts.map +1 -0
  184. package/dist/ports/attachments.js +27 -0
  185. package/dist/ports/attachments.js.map +1 -0
  186. package/dist/ports/backend.d.ts +159 -0
  187. package/dist/ports/backend.d.ts.map +1 -0
  188. package/dist/ports/backend.js +25 -0
  189. package/dist/ports/backend.js.map +1 -0
  190. package/dist/ports/interactions.d.ts +65 -0
  191. package/dist/ports/interactions.d.ts.map +1 -0
  192. package/dist/ports/interactions.js +15 -0
  193. package/dist/ports/interactions.js.map +1 -0
  194. package/dist/ports/streaming.d.ts +45 -0
  195. package/dist/ports/streaming.d.ts.map +1 -0
  196. package/dist/ports/streaming.js +23 -0
  197. package/dist/ports/streaming.js.map +1 -0
  198. package/dist/ports/transport.d.ts +68 -0
  199. package/dist/ports/transport.d.ts.map +1 -0
  200. package/dist/ports/transport.js +2 -0
  201. package/dist/ports/transport.js.map +1 -0
  202. package/dist/types.d.ts +53 -0
  203. package/dist/types.d.ts.map +1 -0
  204. package/dist/types.js +2 -0
  205. package/dist/types.js.map +1 -0
  206. package/package.json +80 -0
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Backend port: everything the bridge knows about the agent runtime.
3
+ * The DSH implementation lives in src/dsh/; tests use a scripted fake.
4
+ */
5
+ import type { PreparedAttachment } from './attachments.ts';
6
+ export interface SessionInfo {
7
+ readonly id: string;
8
+ readonly title?: string;
9
+ readonly cwd: string;
10
+ }
11
+ /** One open room↔session binding, as `/sessions` renders it (T11). */
12
+ export interface SessionListEntry {
13
+ readonly roomId: string;
14
+ readonly sessionId: string;
15
+ /** True while that room's turn is executing. */
16
+ readonly running: boolean;
17
+ }
18
+ /** One pending inbox item as the bridge displays it (T3 turn commands). */
19
+ export interface QueuedItem {
20
+ /** 'steer' = next-step injection, 'queue' = next-turn follow-up. */
21
+ readonly kind: 'steer' | 'queue';
22
+ readonly text: string;
23
+ }
24
+ export interface SessionHandle {
25
+ readonly id: string;
26
+ /** True while a turn is executing (drives steer vs prompt choice). */
27
+ isRunning(): boolean;
28
+ /** Queue an ordinary next-turn prompt (idle: runs immediately).
29
+ * T6: `files` are the sender's pending ledger attachments - the backend
30
+ * admits images into the model natively and files as path-bearing
31
+ * attachments. Consumption (ledger clear) happens only after this call
32
+ * returned without throwing. */
33
+ prompt(text: string, files?: PreparedAttachment[]): void;
34
+ /** Inject into the running turn (TUI Enter while busy). */
35
+ steer(text: string): void;
36
+ /** Resolve once the whole agent reaches quiescence. */
37
+ whenIdle(): Promise<void>;
38
+ /** Text of the last assistant reply, or undefined when none. */
39
+ lastReply(): string | undefined;
40
+ /**
41
+ * T11(US42):最近一个回合若以失败收尾,返回可读原因;正常结束(或还没有
42
+ * 回合结束事件)返回 undefined。
43
+ *
44
+ * DSH 的回合可能以 `turn/end{ reason.kind: 'error' }` 收尾而**不抛错** ——
45
+ * 此时 prompt()/whenIdle() 照常 resolve,单靠 try/catch 兜不住,房间会静默。
46
+ * `aborted`(用户自己 /stop)不算失败,不返回原因。
47
+ */
48
+ lastTurnFailure(): string | undefined;
49
+ /**
50
+ * Abort the active turn. With `keepInbox` the pending queue survives for a
51
+ * later turn (pi-courier abort semantics, used by /stop and /interrupt);
52
+ * by default pending work is discarded too. No-op when nothing runs.
53
+ */
54
+ cancel(options?: {
55
+ keepInbox?: boolean;
56
+ }): void;
57
+ /** Pending inbox items for /queue views and /stop warnings. */
58
+ queuedItems(): QueuedItem[];
59
+ /** Model-facing context for the next admitted step, without waking. */
60
+ injectContext(text: string): void;
61
+ }
62
+ /**
63
+ * The room's durable session is already bound to another live write handle —
64
+ * in practice the DSH GUI (or a second bridge instance) has that session open.
65
+ * DSH allows exactly ONE writer per session, so the bridge cannot resume it
66
+ * until the other holder lets go.
67
+ *
68
+ * Transient by nature: the condition clears the moment the other holder
69
+ * closes the session, so the pipeline retries instead of failing the turn.
70
+ * Kept as a port-level type so any Backend implementation can report it and
71
+ * the pipeline never has to string-match a DSH-internal message.
72
+ */
73
+ export declare class SessionBusyError extends Error {
74
+ /** Durable session id whose write ownership is taken. */
75
+ readonly sessionId: string;
76
+ constructor(sessionId: string, options?: {
77
+ cause?: unknown;
78
+ });
79
+ }
80
+ /** Narrow an unknown catch value to the transient session-busy condition. */
81
+ export declare function isSessionBusyError(error: unknown): error is SessionBusyError;
82
+ /** One DSH registry command as advertised to the room (for /help). */
83
+ export interface PassthroughCommandInfo {
84
+ readonly name: string;
85
+ readonly description: string;
86
+ readonly hint?: string;
87
+ }
88
+ /** One catalog entry: a model id served by one registered provider route. */
89
+ export interface ModelInfo {
90
+ readonly provider: string;
91
+ readonly model: string;
92
+ readonly name?: string;
93
+ }
94
+ /** The effective model route of one live session (mirror of AgentOptions). */
95
+ export interface ModelSelection {
96
+ readonly provider?: string;
97
+ readonly model?: string;
98
+ readonly reasoningEffort?: string;
99
+ }
100
+ /** One selectable reasoning level advertised by the model catalog. */
101
+ export interface ThinkingEffort {
102
+ readonly id: string;
103
+ readonly name: string;
104
+ readonly description?: string;
105
+ }
106
+ export interface Backend {
107
+ /**
108
+ * Run one DSH slash command against the room's agent through the
109
+ * `commands` service. Returns the settled result text (success or error
110
+ * kind) verbatim — an empty string for a textless success — or `undefined`
111
+ * when the registry rejected the line (invalid syntax / unknown name);
112
+ * a rejected line never becomes a model prompt.
113
+ * Requires the room session to be open; throws a clear error otherwise.
114
+ */
115
+ executeCommand(roomId: string, line: string): Promise<string | undefined>;
116
+ /** Commands the DSH registry would accept for this room (bridge-local names excluded). */
117
+ listPassthroughCommands(roomId: string): Promise<PassthroughCommandInfo[]>;
118
+ /** Model catalog across every registered provider route (ctx.llm). */
119
+ listModels(): Promise<ModelInfo[]>;
120
+ /** The room session's live model route; undefined when no session is open. */
121
+ currentModel(roomId: string): Promise<ModelSelection | undefined>;
122
+ /**
123
+ * Re-point the room's session at another route. Without a sessionController
124
+ * in the base profile this disposes the live agent and resumes the SAME
125
+ * persisted session under new options (history survives; the switch must not
126
+ * happen mid-turn). Throws a clear error on unknown routes / running turns.
127
+ */
128
+ selectModel(roomId: string, provider: string, model: string, reasoningEffort?: string): Promise<ModelSelection>;
129
+ /** Reasoning levels one exact route supports (empty = no thinking control). */
130
+ listThinkingEfforts(provider: string, model: string): Promise<ThinkingEffort[]>;
131
+ /** Persist a user-chosen title for the room's live session. */
132
+ renameSession(roomId: string, title: string): Promise<void>;
133
+ /**
134
+ * Resolve (lazily create / resume) the session bound to a room.
135
+ * `cwd` selects the working directory for a fresh session.
136
+ */
137
+ getSession(roomId: string, cwd: string): Promise<SessionHandle>;
138
+ /**
139
+ * Non-creating lookup: the room's session ONLY if one is already open.
140
+ * The pipeline uses it for the running→steer fast path, which must not
141
+ * wait behind the per-room queue (otherwise steering could never fire).
142
+ */
143
+ peekSession(roomId: string): SessionHandle | undefined;
144
+ /**
145
+ * T11(/sessions):本进程已知的房间↔会话绑定,只读。
146
+ * 架构上房间与会话是确定性一对一(`sessionIdFor(roomId)`),所以这里没有
147
+ * pi-courier 那种"可切换的会话池"——列出来的是"哪些房间已经有会话"以及
148
+ * 各自是否在跑回合。懒恢复,重启后要等那个房间再来消息才重新出现。
149
+ */
150
+ listSessions(): Promise<SessionListEntry[]>;
151
+ /**
152
+ * T9(/pmctl rm|mv):放掉该房间的会话句柄(dispose + 清映射)。持久会话数据
153
+ * 不动 —— 同房间再来消息会按新 cwd 重开/resume(US35 换目录语义)。幂等。
154
+ */
155
+ dropRoomSession(roomId: string): Promise<void>;
156
+ /** Tear down everything the backend opened. Idempotent. */
157
+ dispose(): Promise<void>;
158
+ }
159
+ //# sourceMappingURL=backend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/ports/backend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The room's durable session is already bound to another live write handle —
3
+ * in practice the DSH GUI (or a second bridge instance) has that session open.
4
+ * DSH allows exactly ONE writer per session, so the bridge cannot resume it
5
+ * until the other holder lets go.
6
+ *
7
+ * Transient by nature: the condition clears the moment the other holder
8
+ * closes the session, so the pipeline retries instead of failing the turn.
9
+ * Kept as a port-level type so any Backend implementation can report it and
10
+ * the pipeline never has to string-match a DSH-internal message.
11
+ */
12
+ export class SessionBusyError extends Error {
13
+ /** Durable session id whose write ownership is taken. */
14
+ sessionId;
15
+ constructor(sessionId, options) {
16
+ super(`session "${sessionId}" is already owned by an active write handle`, options);
17
+ this.name = 'SessionBusyError';
18
+ this.sessionId = sessionId;
19
+ }
20
+ }
21
+ /** Narrow an unknown catch value to the transient session-busy condition. */
22
+ export function isSessionBusyError(error) {
23
+ return error instanceof SessionBusyError;
24
+ }
25
+ //# sourceMappingURL=backend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backend.js","sourceRoot":"","sources":["../../src/ports/backend.ts"],"names":[],"mappings":"AAgEA;;;;;;;;;;GAUG;AACH,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IACzC,yDAAyD;IAChD,SAAS,CAAQ;IAC1B,YAAY,SAAiB,EAAE,OAA6B;QAC1D,KAAK,CAAC,YAAY,SAAS,8CAA8C,EAAE,OAAO,CAAC,CAAA;QACnF,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAA;QAC9B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;IAC5B,CAAC;CACF;AAED,6EAA6E;AAC7E,MAAM,UAAU,kBAAkB,CAAC,KAAc;IAC/C,OAAO,KAAK,YAAY,gBAAgB,CAAA;AAC1C,CAAC"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Interactions port: agent 侧的提问(user-questions)与沙箱审批(approval)
3
+ * 如何进入桥的房间。dsh/interactions.ts 用 Cordis 根 waterfall 监听器实现
4
+ * 本端口;bridge/interactions.ts 只依赖本端口,用假实现做 seam 测试。
5
+ *
6
+ * 字段形状来自对部署包源码的实证读取(spike + lib/index.js):
7
+ * - user-questions/request 监听器收到 `{ questions, agent?, signal? }`,
8
+ * 答案对象 `{ answers: [{ id, selected, custom? }] }`,或 next() 交还。
9
+ * - approval/request 监听器收到 `{ agent, toolName, callId?, reason?, signal? }`,
10
+ * 返回 'allowed-once' | 'rejected' | 'cancelled',或 next() 交还。
11
+ * 归属判定用 `agent.session.id`(桥会话 id 形如 matrix-<room>):非桥会话
12
+ * 必须 next(),与 Web 回答器共存。
13
+ */
14
+ /** 提问的单个选项(label 即回答值)。 */
15
+ export interface QuestionOption {
16
+ label: string;
17
+ description?: string;
18
+ }
19
+ /** 一道问题(与 dsh-user-questions 的 AskUserQuestionRequest.questions 项同构)。 */
20
+ export interface QuestionItem {
21
+ id: string;
22
+ question: string;
23
+ detail?: string;
24
+ header?: string;
25
+ options?: QuestionOption[];
26
+ multiSelect?: boolean;
27
+ }
28
+ /** 一道题的答案:selected 为选中标签;custom 自由文本(单选时覆盖 selected)。 */
29
+ export interface QuestionAnswerItem {
30
+ id: string;
31
+ selected: string[];
32
+ custom?: string;
33
+ }
34
+ /** 一次审批的结果。'cancelled' = 用户取消或超时(服务侧同样视为不放行)。 */
35
+ export type ApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled';
36
+ /** 只读切片:监听器收到的 signal 我们只关心 abort。 */
37
+ export interface AbortSignalLike {
38
+ readonly aborted: boolean;
39
+ addEventListener(type: 'abort', listener: () => void): void;
40
+ }
41
+ /** 归一化后的提问事件(sessionId 为提问 agent 的会话 id,归属判定的钥匙)。 */
42
+ export interface QuestionRequestEvent {
43
+ sessionId: string;
44
+ questions: QuestionItem[];
45
+ signal?: AbortSignalLike;
46
+ }
47
+ /** 归一化后的审批事件。 */
48
+ export interface ApprovalRequestEvent {
49
+ sessionId: string;
50
+ toolName: string;
51
+ reason?: string;
52
+ callId?: string;
53
+ signal?: AbortSignalLike;
54
+ }
55
+ /** respond 在答案/结果确定时被调用一次(桥侧编排器持有其时机)。 */
56
+ export type QuestionResponder = (answers: QuestionAnswerItem[]) => void;
57
+ export type ApprovalResponder = (outcome: ApprovalOutcome) => void;
58
+ /** 事件来源:dsh 侧注册根监听器,只把桥自己会话的请求回调进桥。 */
59
+ export interface InteractionSource {
60
+ /** 订阅桥会话的提问。返回 disposer(ctx.on 随 fiber 自动回收,这里通常 no-op)。 */
61
+ onRequestQuestion(cb: (event: QuestionRequestEvent, respond: QuestionResponder) => void): () => void;
62
+ /** 订阅桥会话的沙箱审批。 */
63
+ onRequestApproval(cb: (event: ApprovalRequestEvent, respond: ApprovalResponder) => void): () => void;
64
+ }
65
+ //# sourceMappingURL=interactions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactions.d.ts","sourceRoot":"","sources":["../../src/ports/interactions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,2BAA2B;AAC3B,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,yEAAyE;AACzE,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,cAAc,EAAE,CAAA;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB;AAED,yDAAyD;AACzD,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,iDAAiD;AACjD,MAAM,MAAM,eAAe,GAAG,cAAc,GAAG,UAAU,GAAG,WAAW,CAAA;AAEvE,sCAAsC;AACtC,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAA;CAC5D;AAED,qDAAqD;AACrD,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,YAAY,EAAE,CAAA;IACzB,MAAM,CAAC,EAAE,eAAe,CAAA;CACzB;AAED,iBAAiB;AACjB,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,eAAe,CAAA;CACzB;AAED,0CAA0C;AAC1C,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,EAAE,kBAAkB,EAAE,KAAK,IAAI,CAAA;AACvE,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAA;AAElE,uCAAuC;AACvC,MAAM,WAAW,iBAAiB;IAChC,4DAA4D;IAC5D,iBAAiB,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,oBAAoB,EAAE,OAAO,EAAE,iBAAiB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAA;IACpG,kBAAkB;IAClB,iBAAiB,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,oBAAoB,EAAE,OAAO,EAAE,iBAAiB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAA;CACrG"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Interactions port: agent 侧的提问(user-questions)与沙箱审批(approval)
3
+ * 如何进入桥的房间。dsh/interactions.ts 用 Cordis 根 waterfall 监听器实现
4
+ * 本端口;bridge/interactions.ts 只依赖本端口,用假实现做 seam 测试。
5
+ *
6
+ * 字段形状来自对部署包源码的实证读取(spike + lib/index.js):
7
+ * - user-questions/request 监听器收到 `{ questions, agent?, signal? }`,
8
+ * 答案对象 `{ answers: [{ id, selected, custom? }] }`,或 next() 交还。
9
+ * - approval/request 监听器收到 `{ agent, toolName, callId?, reason?, signal? }`,
10
+ * 返回 'allowed-once' | 'rejected' | 'cancelled',或 next() 交还。
11
+ * 归属判定用 `agent.session.id`(桥会话 id 形如 matrix-<room>):非桥会话
12
+ * 必须 next(),与 Web 回答器共存。
13
+ */
14
+ export {};
15
+ //# sourceMappingURL=interactions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactions.js","sourceRoot":"","sources":["../../src/ports/interactions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * T7 streaming port: the bridge-side view of DSH live assistant output.
3
+ *
4
+ * Ground truth (dsh-agent@0.1.5 `lib/types/runtime-types.d.ts` +
5
+ * dsh-llm `lib/types/types.d.ts`, spike-measured 15-73 frames/turn):
6
+ * - root event `agent/assistant-stream`, payload `{ agent, frame }`;
7
+ * - `frame` is one ordered publication of ONE MODEL ATTEMPT:
8
+ * `{type:'start', attemptId, revision, turn, step}` |
9
+ * `{type:'chunk', attemptId, revision, index, time, chunk: StreamChunk}`
10
+ * (`index` dense from 0) |
11
+ * `{type:'end', attemptId, revision, index, outcome:
12
+ * {kind:'committed', eventType, seq} | {kind:'abandoned'}}`.
13
+ * - visible text arrives as `frame.chunk.type === 'text-delta'` with a
14
+ * `text: string` field. `reasoning-delta` ALSO carries `text` - never
15
+ * forward anything but 'text-delta'.
16
+ *
17
+ * One turn contains many attempts (tool loops, retries), so an `end` frame is
18
+ * NOT the turn end: turn completion stays the pipeline's `whenIdle()`. The
19
+ * committed/abandoned outcome only decides whether the current attempt's
20
+ * buffered text survives (abandoned retries must not reach the room).
21
+ */
22
+ /** Callbacks a TurnStreamSource drives for one session. */
23
+ export interface TurnStreamHandlers {
24
+ /** One streamed visible-text delta. */
25
+ onTextDelta(text: string): void;
26
+ /**
27
+ * Stream-side "turn is over" hint. Optional in practice: DSH implementations
28
+ * never fire it (end frame ≠ turn end); fakes may script it to flush edits.
29
+ */
30
+ onTurnEnd(): void;
31
+ /** A new model attempt began: per-attempt buffering restarts. */
32
+ onAttemptStart?(): void;
33
+ /**
34
+ * The current attempt was ABANDONED (model-request retry): everything the
35
+ * stream forwarded since its start must be dropped - retry content never
36
+ * belongs in the room.
37
+ */
38
+ onAttemptAbandoned?(): void;
39
+ }
40
+ /** Anything the bridge can read streamed assistant text from, per session. */
41
+ export interface TurnStreamSource {
42
+ /** Subscribe to one DSH session's stream. Returns an unsubscribe disposer. */
43
+ subscribe(sessionId: string, handlers: TurnStreamHandlers): () => void;
44
+ }
45
+ //# sourceMappingURL=streaming.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streaming.d.ts","sourceRoot":"","sources":["../../src/ports/streaming.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,2DAA2D;AAC3D,MAAM,WAAW,kBAAkB;IACjC,uCAAuC;IACvC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B;;;OAGG;IACH,SAAS,IAAI,IAAI,CAAA;IACjB,iEAAiE;IACjE,cAAc,CAAC,IAAI,IAAI,CAAA;IACvB;;;;OAIG;IACH,kBAAkB,CAAC,IAAI,IAAI,CAAA;CAC5B;AAED,8EAA8E;AAC9E,MAAM,WAAW,gBAAgB;IAC/B,8EAA8E;IAC9E,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,kBAAkB,GAAG,MAAM,IAAI,CAAA;CACvE"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * T7 streaming port: the bridge-side view of DSH live assistant output.
3
+ *
4
+ * Ground truth (dsh-agent@0.1.5 `lib/types/runtime-types.d.ts` +
5
+ * dsh-llm `lib/types/types.d.ts`, spike-measured 15-73 frames/turn):
6
+ * - root event `agent/assistant-stream`, payload `{ agent, frame }`;
7
+ * - `frame` is one ordered publication of ONE MODEL ATTEMPT:
8
+ * `{type:'start', attemptId, revision, turn, step}` |
9
+ * `{type:'chunk', attemptId, revision, index, time, chunk: StreamChunk}`
10
+ * (`index` dense from 0) |
11
+ * `{type:'end', attemptId, revision, index, outcome:
12
+ * {kind:'committed', eventType, seq} | {kind:'abandoned'}}`.
13
+ * - visible text arrives as `frame.chunk.type === 'text-delta'` with a
14
+ * `text: string` field. `reasoning-delta` ALSO carries `text` - never
15
+ * forward anything but 'text-delta'.
16
+ *
17
+ * One turn contains many attempts (tool loops, retries), so an `end` frame is
18
+ * NOT the turn end: turn completion stays the pipeline's `whenIdle()`. The
19
+ * committed/abandoned outcome only decides whether the current attempt's
20
+ * buffered text survives (abandoned retries must not reach the room).
21
+ */
22
+ export {};
23
+ //# sourceMappingURL=streaming.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streaming.js","sourceRoot":"","sources":["../../src/ports/streaming.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG"}
@@ -0,0 +1,68 @@
1
+ import type { IncomingMessage, Logger } from '../types.ts';
2
+ import type { MediaDownload } from './attachments.ts';
3
+ /**
4
+ * Transport port: everything the bridge knows about the chat side.
5
+ * The bridge core is tested against a fake of exactly this interface -
6
+ * the single pre-agreed seam (spec: Testing Decisions).
7
+ */
8
+ export interface Transport {
9
+ /** Subscribe to normalized inbound messages. Returns an unsubscribe fn. */
10
+ onIncoming(handler: (msg: IncomingMessage) => void | Promise<void>): () => void;
11
+ /**
12
+ * T8 (optional): subscribe to room joins with the group verdict, used for
13
+ * the one-time group join hint. Fake transports may omit it.
14
+ */
15
+ onRoomJoin?(handler: (roomId: string, isGroup: boolean) => void): () => void;
16
+ /** Send an m.text message. Returns the Matrix event id (for later edits). */
17
+ send(roomId: string, text: string): Promise<string>;
18
+ /** Send an m.notice (bot-to-human meta chatter; other bots should ignore). */
19
+ notify(roomId: string, text: string): Promise<string>;
20
+ /** Edit a previously sent event in place. Best-effort; ignore failures. */
21
+ edit(roomId: string, editId: string, text: string): Promise<void>;
22
+ /**
23
+ * T6: fetch one media payload by mxc:// address (E2EE-decrypted when the
24
+ * transport runs with crypto). Rejects with a room-ready message when the
25
+ * real bytes exceed `maxSizeBytes` or the download/decrypt fails.
26
+ */
27
+ downloadMedia(mxc: string, maxSizeBytes: number): Promise<MediaDownload>;
28
+ /** Connect and start receiving. */
29
+ start(logger: Logger): Promise<void>;
30
+ /** Stop and release all resources. Idempotent. */
31
+ stop(): Promise<void>;
32
+ /** 建私有房间,名字 `name`,邀请 `inviteUserId`(邀请者+被邀者都进)。返回房间 ID。 */
33
+ createRoom?(opts: {
34
+ name: string;
35
+ inviteUserId: string;
36
+ }): Promise<string>;
37
+ /** 设置房间显示名(m.room.name 状态)。 */
38
+ setRoomName?(roomId: string, name: string): Promise<void>;
39
+ /** 设置用户在房间的权限等级(trusted → PL100)。尽力而为。 */
40
+ setUserPowerLevel?(roomId: string, userId: string, level: number): Promise<void>;
41
+ /**
42
+ * T12(US37):读某人在某房间的权限等级(`m.room.power_levels` 的 `users[userId]`,
43
+ * 回落 `users_default`,再回落 0)。
44
+ *
45
+ * 提权前**必须**先读:只有真正发生的"低 → 100"才记账本,否则 `/revoke` 会把
46
+ * 管理员手工提上去的人一起降掉(误伤人工授权)。
47
+ */
48
+ getUserPowerLevel?(roomId: string, userId: string): Promise<number>;
49
+ /** T12(US38):建 space(`creation_content: {type:'m.space'}` 的私有房)。 */
50
+ createSpace?(opts: {
51
+ name: string;
52
+ inviteUserId?: string;
53
+ }): Promise<string>;
54
+ /** T12(US38):读房间头像;没设过 → undefined(自愈据此判断"要不要补挂")。 */
55
+ getRoomAvatar?(roomId: string): Promise<{
56
+ url?: string;
57
+ info?: Record<string, unknown>;
58
+ } | undefined>;
59
+ /** T12(US38):上传 PNG 并设为房间头像(先 uploadContent 拿 mxc,再发 m.room.avatar)。 */
60
+ setRoomAvatar?(roomId: string, png: Buffer, info?: Record<string, unknown>): Promise<void>;
61
+ /** T12(US38):把房间挂进 space(在 space 里发 `m.space.child`,state_key = 房间 ID)。 */
62
+ addRoomToSpace?(spaceId: string, roomId: string, via?: string): Promise<void>;
63
+ /** 邀请用户进房(createRoom 之外的独立邀请;Matrix 建房已带 invite 时可不调)。 */
64
+ inviteUser?(roomId: string, userId: string): Promise<void>;
65
+ /** 桥自身账号的 MXID(管理房指南文案用;未连接/未知 → undefined)。 */
66
+ getBotUserId?(): string | undefined;
67
+ }
68
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/ports/transport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/ports/transport.ts"],"names":[],"mappings":""}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Shared bridge vocabulary - transport-independent, DSH-independent.
3
+ * Ported shapes stay close to pi-courier's `ExternalMessage` so the router
4
+ *移植 keeps a familiar body.
5
+ */
6
+ import type { MediaIncoming } from './ports/attachments.ts';
7
+ /** One inbound chat text message, already normalized by a Transport. */
8
+ export interface IncomingMessage {
9
+ readonly roomId: string;
10
+ readonly sender: string;
11
+ readonly text: string;
12
+ /** True for 1:1 rooms (DM). T8: real judgment (was hardcoded in T1). */
13
+ readonly isDm: boolean;
14
+ /**
15
+ * T8: true for rooms with more than two joined members. Optional so
16
+ * pre-T8 fakes stay valid; when absent, pipelines derive `!isDm`.
17
+ */
18
+ readonly isGroup?: boolean;
19
+ /** T8: the message @-mentions the bot (m.mentions list or body fallback). */
20
+ readonly mentionsBot?: boolean;
21
+ /** T8: reply-to relation target; cache-hit resolution lives in the bridge. */
22
+ readonly replyTo?: {
23
+ eventId: string;
24
+ };
25
+ readonly eventId: string;
26
+ readonly timestamp: number;
27
+ /**
28
+ * T6: media payloads referenced by this message (m.image/m.file/… and
29
+ * m.sticker events). Media messages are receipted by the attachment stage
30
+ * and never reach the prompt path; `text` carries no caption for them.
31
+ */
32
+ readonly media?: MediaIncoming[];
33
+ /**
34
+ * T6: set when the event is neither text nor media (m.location, …). The
35
+ * bridge answers politely instead of silently swallowing (US/蓝本票3).
36
+ */
37
+ readonly unsupportedMsgtype?: string;
38
+ }
39
+ /** Outbound plain message (m.text). */
40
+ export interface OutboundMessage {
41
+ roomId: string;
42
+ text: string;
43
+ /** Replace an earlier message (streaming edit). Transport assigns the id when absent on first send. */
44
+ editId?: string;
45
+ }
46
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
47
+ export interface Logger {
48
+ debug(...args: unknown[]): void;
49
+ info(...args: unknown[]): void;
50
+ warn(...args: unknown[]): void;
51
+ error(...args: unknown[]): void;
52
+ }
53
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAE3D,wEAAwE;AACxE,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;IAC1B,6EAA6E;IAC7E,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAA;IAC9B,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,EAAE,CAAA;IAChC;;;OAGG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;CACrC;AAED,uCAAuC;AACvC,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,uGAAuG;IACvG,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;AAE1D,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;IAC/B,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;IAC9B,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;IAC9B,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;CAChC"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "@barryfan2045/dsh-matrix",
3
+ "version": "0.1.0",
4
+ "description": "Matrix bridge plugin for DeepSeek Harness: drive in-process agent sessions from chat rooms, with questions and approvals in the room",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/Hi-Barry/dsh-matrix.git"
8
+ },
9
+ "homepage": "https://github.com/Hi-Barry/dsh-matrix#readme",
10
+ "bugs": {
11
+ "url": "https://github.com/Hi-Barry/dsh-matrix/issues"
12
+ },
13
+ "type": "module",
14
+ "main": "dist/index.js",
15
+ "types": "dist/index.d.ts",
16
+ "license": "MIT",
17
+ "engines": {
18
+ "node": ">=20.0.0"
19
+ },
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "default": "./dist/index.js"
24
+ },
25
+ "./cordis.patch.yml": "./cordis.patch.yml",
26
+ "./package.json": "./package.json"
27
+ },
28
+ "files": [
29
+ "dist",
30
+ "cordis.patch.yml",
31
+ "LICENSE",
32
+ "THIRD_PARTY_NOTICES.md",
33
+ "assets"
34
+ ],
35
+ "dsh": {
36
+ "bundle": {
37
+ "patch": "./cordis.patch.yml"
38
+ }
39
+ },
40
+ "scripts": {
41
+ "build": "rm -rf dist && tsc",
42
+ "clean": "rm -rf dist",
43
+ "lint": "tsc --noEmit",
44
+ "test": "vitest run",
45
+ "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json",
46
+ "prepack": "npm run typecheck && npm test && npm run build"
47
+ },
48
+ "keywords": [
49
+ "dsh",
50
+ "deepseek-harness",
51
+ "matrix",
52
+ "bridge",
53
+ "cordis",
54
+ "plugin",
55
+ "chat",
56
+ "bot"
57
+ ],
58
+ "dependencies": {
59
+ "@deepseek-ai/dsh-llm": "^0.1.5-rc.2",
60
+ "matrix-bot-sdk": "^0.8.0",
61
+ "@deepseek-ai/dsh-tool-ask-user": "^0.1.5-rc.2",
62
+ "@deepseek-ai/dsh-user-questions": "^0.1.5-rc.2"
63
+ },
64
+ "devDependencies": {
65
+ "@deepseek-ai/cordis": "^4.0.2",
66
+ "@types/node": "^24.0.0",
67
+ "typescript": "^5.9.0",
68
+ "vitest": "^3.2.0"
69
+ },
70
+ "allowScripts": {
71
+ "esbuild@0.28.2": true,
72
+ "@matrix-org/matrix-sdk-crypto-nodejs@0.4.0": true
73
+ },
74
+ "optionalDependencies": {
75
+ "@matrix-org/matrix-sdk-crypto-nodejs": "^0.4.0"
76
+ },
77
+ "bin": {
78
+ "dsh-matrix": "dist/cli/index.js"
79
+ }
80
+ }