@xmanrui/dsh-im 0.8.0 → 0.9.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 (36) hide show
  1. package/README.en.md +3 -1
  2. package/README.md +3 -1
  3. package/lib/client.js +15 -14
  4. package/lib/index.js +122 -122
  5. package/package.json +1 -1
  6. package/plugin-src/client/styles.js +15 -14
  7. package/plugin-src/host/channels/dingtalk/index.mjs +1 -1
  8. package/plugin-src/host/channels/dingtalk/production.mjs +3 -0
  9. package/plugin-src/host/channels/discord/index.mjs +1 -1
  10. package/plugin-src/host/channels/feishu/index.mjs +1 -1
  11. package/plugin-src/host/channels/feishu/production.mjs +3 -0
  12. package/plugin-src/host/channels/qq/index.mjs +1 -1
  13. package/plugin-src/host/channels/qq/production.mjs +3 -0
  14. package/plugin-src/host/channels/shared/production.mjs +3 -0
  15. package/plugin-src/host/channels/slack/index.mjs +1 -1
  16. package/plugin-src/host/channels/slack/production.mjs +3 -0
  17. package/plugin-src/host/channels/telegram/index.mjs +1 -1
  18. package/plugin-src/host/channels/wecom/index.mjs +1 -1
  19. package/plugin-src/host/channels/wecom/production.mjs +3 -0
  20. package/plugin-src/host/channels/weixin/index.mjs +1 -1
  21. package/plugin-src/host/channels/weixin/production.mjs +3 -0
  22. package/plugin-src/host/channels/whatsapp/index.mjs +1 -1
  23. package/plugin-src/host/channels/whatsapp/production.mjs +3 -0
  24. package/plugin-src/host/harness-command-executor.mjs +21 -0
  25. package/plugin-src/host/index.mjs +1 -1
  26. package/src/channels/dingtalk/dingtalk-bridge.mjs +13 -0
  27. package/src/channels/discord/discord-api.mjs +1 -1
  28. package/src/channels/feishu/bridge.mjs +13 -0
  29. package/src/channels/qq/qq-bridge.mjs +14 -0
  30. package/src/channels/shared/bot-workspace-store.mjs +13 -0
  31. package/src/channels/shared/compact-command.mjs +95 -0
  32. package/src/channels/shared/harness-client.mjs +24 -0
  33. package/src/channels/shared/text-harness-bridge.mjs +13 -0
  34. package/src/channels/wecom/wecom-bridge.mjs +14 -0
  35. package/src/channels/weixin/weixin-api.mjs +1 -1
  36. package/src/channels/weixin/weixin-bridge.mjs +14 -0
@@ -318,6 +318,7 @@ export class HarnessClient {
318
318
  #interactionReconnectDelayMs;
319
319
  #rpcIdPrefix;
320
320
  #logPrefix;
321
+ #commandExecutor;
321
322
  #managedProcess = null;
322
323
  #interactionRegistry;
323
324
  #interactionOwnerships;
@@ -334,6 +335,7 @@ export class HarnessClient {
334
335
  interactionReconnectDelayMs = 500,
335
336
  rpcIdPrefix = 'im',
336
337
  logPrefix = 'dsh-im',
338
+ commandExecutor,
337
339
  }) {
338
340
  if (typeof createWebSocket !== 'function') {
339
341
  throw new TypeError('createWebSocket must be a function');
@@ -347,6 +349,9 @@ export class HarnessClient {
347
349
  if (typeof logPrefix !== 'string' || !logPrefix.trim()) {
348
350
  throw new TypeError('logPrefix must be a non-empty string');
349
351
  }
352
+ if (commandExecutor !== undefined && typeof commandExecutor !== 'function') {
353
+ throw new TypeError('commandExecutor must be a function');
354
+ }
350
355
  this.#baseUrl = new URL(baseUrl);
351
356
  this.#workspace = workspace;
352
357
  this.#agentPreset = agentPreset;
@@ -357,6 +362,7 @@ export class HarnessClient {
357
362
  this.#interactionReconnectDelayMs = interactionReconnectDelayMs;
358
363
  this.#rpcIdPrefix = rpcIdPrefix.trim();
359
364
  this.#logPrefix = logPrefix.trim();
365
+ this.#commandExecutor = commandExecutor;
360
366
  this.#interactionRegistry = interactionRegistry(this.#baseUrl.origin);
361
367
  this.#interactionOwnerships = this.#interactionRegistry.ownerships;
362
368
  this.#interactionClaims = this.#interactionRegistry.claims;
@@ -459,6 +465,24 @@ export class HarnessClient {
459
465
  return created.sessionId;
460
466
  }
461
467
 
468
+ async executeCommand(sessionId, line, options = {}) {
469
+ if (typeof sessionId !== 'string' || !sessionId) throw new TypeError('sessionId is required');
470
+ if (typeof line !== 'string' || !line) throw new TypeError('command line is required');
471
+ if (!this.#commandExecutor) {
472
+ const error = new Error('Harness command execution is unavailable');
473
+ error.code = 'commands-unavailable';
474
+ throw error;
475
+ }
476
+ try {
477
+ return await this.#commandExecutor(sessionId, line, options);
478
+ } catch (error) {
479
+ if (error?.failure && typeof error.failure === 'object') {
480
+ throw new HarnessRpcError('commands.execute', error.failure);
481
+ }
482
+ throw error;
483
+ }
484
+ }
485
+
462
486
  async sessionExists(sessionId, options = {}) {
463
487
  try {
464
488
  await this.rpc('session.history', { sessionId, maxMessages: 1 }, 30_000, options);
@@ -1,4 +1,5 @@
1
1
  import { runWorkspaceCommand } from './workspace-command.mjs';
2
+ import { runCompactCommand } from './compact-command.mjs';
2
3
  import { askInWorkspaceSession } from './workspace-session.mjs';
3
4
  import { HarnessApprovalQueue } from './harness-approval.mjs';
4
5
  import {
@@ -218,6 +219,7 @@ export class TextHarnessBridge {
218
219
  '',
219
220
  '直接发送文字即可继续当前会话。',
220
221
  '/new 开启一个全新会话',
222
+ '/compact 压缩当前会话的较早上下文',
221
223
  '/workspace 工作区绝对路径 切换工作区',
222
224
  '/workspacelist 列出工作区绝对路径',
223
225
  '/sessionlist [工作区序号或绝对路径] 列出会话 ID 和标题',
@@ -244,6 +246,17 @@ export class TextHarnessBridge {
244
246
  await this.#bot.sendText(target, '已开启新会话。请发送你的问题。');
245
247
  return;
246
248
  }
249
+ const compactCommand = await runCompactCommand(
250
+ text,
251
+ this.#harness,
252
+ this.#state,
253
+ conversationKey,
254
+ { signal: this.#signal },
255
+ );
256
+ if (compactCommand) {
257
+ await this.#bot.sendText(target, compactCommand.message);
258
+ return;
259
+ }
247
260
 
248
261
  await this.#bot.sendTyping?.(target).catch((error) => {
249
262
  this.#logger.warn?.(`[dsh-im:${this.#descriptor.key}] typing indicator failed:`, error);
@@ -5,6 +5,7 @@ import {
5
5
  validHarnessQuestion,
6
6
  } from '../shared/harness-question.mjs';
7
7
  import { HarnessApprovalQueue } from '../shared/harness-approval.mjs';
8
+ import { runCompactCommand } from '../shared/compact-command.mjs';
8
9
  import { runWorkspaceCommand } from '../shared/workspace-command.mjs';
9
10
  import { askInWorkspaceSession } from '../shared/workspace-session.mjs';
10
11
 
@@ -13,6 +14,7 @@ const HELP_TEXT = [
13
14
  '',
14
15
  '直接发送文字即可继续当前会话。',
15
16
  '/new 开启一个全新会话',
17
+ '/compact 压缩当前会话的较早上下文',
16
18
  '/workspace 工作区绝对路径 切换工作区',
17
19
  '/workspacelist 列出工作区绝对路径',
18
20
  '/sessionlist [工作区序号或绝对路径] 列出会话 ID 和标题',
@@ -321,6 +323,18 @@ export class WecomHarnessBridge {
321
323
  await this.#state.markSeen(messageId);
322
324
  return;
323
325
  }
326
+ const compactCommand = await runCompactCommand(
327
+ text,
328
+ this.#harness,
329
+ this.#state,
330
+ key,
331
+ { signal: this.#signal },
332
+ );
333
+ if (compactCommand) {
334
+ await this.#sendImmediate(frame, chatId, compactCommand.message);
335
+ await this.#state.markSeen(messageId);
336
+ return;
337
+ }
324
338
 
325
339
  streamId = this.#generateReqId('stream');
326
340
  try {
@@ -92,7 +92,7 @@ function authenticatedHeaders(token) {
92
92
  function baseInfo() {
93
93
  return {
94
94
  channel_version: WEIXIN_PROTOCOL_VERSION,
95
- bot_agent: 'DeepSeekHarness/0.8.0',
95
+ bot_agent: 'DeepSeekHarness/0.9.0',
96
96
  };
97
97
  }
98
98
 
@@ -9,6 +9,7 @@ import {
9
9
  validHarnessQuestion,
10
10
  } from '../shared/harness-question.mjs';
11
11
  import { HarnessApprovalQueue } from '../shared/harness-approval.mjs';
12
+ import { runCompactCommand } from '../shared/compact-command.mjs';
12
13
  import { runWorkspaceCommand } from '../shared/workspace-command.mjs';
13
14
  import { askInWorkspaceSession } from '../shared/workspace-session.mjs';
14
15
 
@@ -19,6 +20,7 @@ const HELP_TEXT = [
19
20
  '',
20
21
  '直接发送文字或带文字识别结果的语音即可继续当前会话。',
21
22
  '/new 开启一个全新会话',
23
+ '/compact 压缩当前会话的较早上下文',
22
24
  '/workspace 工作区绝对路径 切换工作区',
23
25
  '/workspacelist 列出工作区绝对路径',
24
26
  '/sessionlist [工作区序号或绝对路径] 列出会话 ID 和标题',
@@ -248,6 +250,18 @@ export class WeixinHarnessBridge {
248
250
  await this.#state.markSeen(messageId);
249
251
  return;
250
252
  }
253
+ const compactCommand = await runCompactCommand(
254
+ text,
255
+ this.#harness,
256
+ this.#state,
257
+ key,
258
+ { signal: this.#signal },
259
+ );
260
+ if (compactCommand) {
261
+ await this.#send(sender, compactCommand.message, contextToken, runId);
262
+ await this.#state.markSeen(messageId);
263
+ return;
264
+ }
251
265
 
252
266
  let answer;
253
267
  try {