@xmanrui/dsh-im 3.0.7 → 3.0.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xmanrui/dsh-im",
3
- "version": "3.0.7",
3
+ "version": "3.0.8",
4
4
  "description": "把九种 IM 机器人和公网 AI Office 接入本机 DeepSeek Harness。 Connect nine IM channels and a public AI Office to a local DeepSeek Harness.",
5
5
  "keywords": [
6
6
  "deepseek-harness",
@@ -2,7 +2,7 @@ import { createProductionController } from './production.mjs';
2
2
  import { installDingtalkRpc } from './rpc.mjs';
3
3
 
4
4
  export const name = 'dsh-dingtalk-host';
5
- export const inject = ['connection', 'credentials', 'webServer', 'typertGateway'];
5
+ export const inject = ['connection', 'credentials', 'apiProxy', 'typertGateway'];
6
6
 
7
7
  export async function apply(ctx, config = {}) {
8
8
  if (config?.controller) {
@@ -17,17 +17,9 @@ import {
17
17
  import { listAgentPresetCatalog } from '../../../../src/channels/shared/agent-preset.mjs';
18
18
  import { createConnectionSupervisor } from './connection-supervisor.mjs';
19
19
  import { createHarnessCommandExecutor } from '../../harness-command-executor.mjs';
20
+ import { harnessConnection } from '../../harness-connection.mjs';
20
21
  import { createHarnessSessionExecutors } from '../../harness-session-coordinator.mjs';
21
22
 
22
- function harnessOrigin(webServer, configured) {
23
- if (configured !== undefined) return new URL(configured);
24
- const port = webServer?.port;
25
- if (!Number.isInteger(port) || port < 1 || port > 65_535) {
26
- throw new Error('dsh-dingtalk requires an initialized DSH webServer port');
27
- }
28
- return new URL(`http://127.0.0.1:${port}`);
29
- }
30
-
31
23
  function pluginPaths(config) {
32
24
  const dshHome = resolve(config.dshHome ?? process.env.DSH_HOME ?? join(homedir(), '.dsh'));
33
25
  const root = resolve(config.dataDir ?? join(dshHome, 'integrations', 'dsh-dingtalk'));
@@ -41,7 +33,7 @@ function pluginPaths(config) {
41
33
 
42
34
  export async function createProductionController(ctx, config = {}, internals = {}) {
43
35
  if (!ctx?.credentials) throw new TypeError('dsh-dingtalk requires ctx.credentials');
44
- if (!ctx?.webServer) throw new TypeError('dsh-dingtalk requires ctx.webServer');
36
+ const connection = harnessConnection(ctx, config);
45
37
 
46
38
  const ConfigStore = internals.ConfigStore ?? DingtalkConfigStore;
47
39
  const DeviceAuth = internals.DeviceAuth ?? DingtalkDeviceAuth;
@@ -92,7 +84,7 @@ export async function createProductionController(ctx, config = {}, internals = {
92
84
  fileIngressExecutor: internals.fileIngressExecutor,
93
85
  });
94
86
  const harness = new Harness({
95
- baseUrl: harnessOrigin(ctx.webServer, config.harnessBaseUrl),
87
+ ...connection,
96
88
  workspace: defaultWorkspace,
97
89
  autostart: false,
98
90
  dshBin: config.dshBin ?? 'dsh',
@@ -2,7 +2,7 @@ import { createProductionController } from './production.mjs';
2
2
  import { installDiscordRpc } from './rpc.mjs';
3
3
 
4
4
  export const name = 'dsh-im-discord-host';
5
- export const inject = ['connection', 'credentials', 'webServer', 'typertGateway'];
5
+ export const inject = ['connection', 'credentials', 'apiProxy', 'typertGateway'];
6
6
 
7
7
  export async function apply(ctx, config = {}) {
8
8
  if (config?.controller) {
@@ -3,7 +3,7 @@ import { createProductionController } from './production.mjs';
3
3
  import { installFeishuRpc } from './rpc.mjs';
4
4
 
5
5
  export const name = 'dsh-feishu-host';
6
- export const inject = ['connection', 'credentials', 'webServer', 'typertGateway'];
6
+ export const inject = ['connection', 'credentials', 'apiProxy', 'typertGateway'];
7
7
 
8
8
  function controllerFrom(ctx, config) {
9
9
  if (config?.controller) return config.controller;
@@ -5,6 +5,7 @@ import * as Lark from '@larksuiteoapi/node-sdk';
5
5
  import HttpsProxyAgent from 'https-proxy-agent';
6
6
  import { createConnectionSupervisor } from './connection-supervisor.mjs';
7
7
  import { createHarnessCommandExecutor } from '../../harness-command-executor.mjs';
8
+ import { harnessConnection } from '../../harness-connection.mjs';
8
9
  import { createHarnessSessionExecutors } from '../../harness-session-coordinator.mjs';
9
10
  import { verifyFeishuApp } from '../../../../src/channels/feishu/feishu-app.mjs';
10
11
  import { FeishuRuntime } from '../../../../src/channels/feishu/feishu-runtime.mjs';
@@ -39,17 +40,6 @@ export function createFeishuWebSocketAgent(
39
40
  return proxyUrl ? createAgent(proxyUrl) : undefined;
40
41
  }
41
42
 
42
- function harnessOrigin(webServer, configured) {
43
- if (configured !== undefined) return new URL(configured);
44
- const port = webServer?.port;
45
- if (!Number.isInteger(port) || port < 1 || port > 65_535) {
46
- throw new Error('dsh-feishu requires an initialized DSH webServer port');
47
- }
48
- // Even when DSH listens on all interfaces, its own plugin talks through the
49
- // loopback authority accepted by Connection's request-trust fence.
50
- return new URL(`http://127.0.0.1:${port}`);
51
- }
52
-
53
43
  function pluginPaths(config) {
54
44
  const dshHome = resolve(config.dshHome
55
45
  ?? process.env.DSH_HOME
@@ -70,7 +60,7 @@ function pluginPaths(config) {
70
60
  */
71
61
  export async function createProductionController(ctx, config = {}, internals = {}) {
72
62
  if (!ctx?.credentials) throw new TypeError('dsh-feishu requires ctx.credentials');
73
- if (!ctx?.webServer) throw new TypeError('dsh-feishu requires ctx.webServer');
63
+ const connection = harnessConnection(ctx, config);
74
64
 
75
65
  const lark = internals.lark ?? Lark;
76
66
  const Controller = internals.Controller ?? MultiBotDshFeishuController;
@@ -139,7 +129,7 @@ export async function createProductionController(ctx, config = {}, internals = {
139
129
  fileIngressExecutor: internals.fileIngressExecutor,
140
130
  });
141
131
  const harness = new Harness({
142
- baseUrl: harnessOrigin(ctx.webServer, config.harnessBaseUrl),
132
+ ...connection,
143
133
  workspace: defaultWorkspace,
144
134
  // This plugin is already hosted by a running DSH process. Starting a
145
135
  // second DSH would create a competing server and lifecycle.
@@ -5,7 +5,7 @@ import { OfficeConfigStore } from '../../../../src/channels/office/config-store.
5
5
  import { OfficeController } from '../../../../src/channels/office/office-controller.mjs';
6
6
  import { OfficeRuntime } from '../../../../src/channels/office/office-runtime.mjs';
7
7
  import { HarnessClient } from '../../../../src/channels/shared/harness-client.mjs';
8
- import { harnessOrigin } from '../shared/production.mjs';
8
+ import { harnessConnection } from '../../harness-connection.mjs';
9
9
 
10
10
  export function officePaths(config = {}) {
11
11
  const dshHome = resolve(config.dshHome ?? process.env.DSH_HOME ?? join(homedir(), '.dsh'));
@@ -14,6 +14,7 @@ export function officePaths(config = {}) {
14
14
  }
15
15
 
16
16
  export async function createProductionController(ctx, config = {}, internals = {}) {
17
+ const connection = harnessConnection(ctx, config);
17
18
  const Store = internals.ConfigStore ?? OfficeConfigStore;
18
19
  const Controller = internals.Controller ?? OfficeController;
19
20
  const Runtime = internals.Runtime ?? OfficeRuntime;
@@ -21,9 +22,8 @@ export async function createProductionController(ctx, config = {}, internals = {
21
22
  const paths = officePaths(config);
22
23
  const configStore = await new Store(paths.config).load();
23
24
  const logger = typeof ctx.logger === 'function' ? ctx.logger('dsh-im:office') : (ctx.logger ?? console);
24
- const harnessBaseUrl = harnessOrigin(ctx.webServer, config.harnessBaseUrl);
25
25
  const createHarness = internals.createHarness ?? (({ workspace }) => new ResolvedHarness({
26
- baseUrl: harnessBaseUrl,
26
+ ...connection,
27
27
  workspace,
28
28
  autostart: false,
29
29
  dshBin: config.dshBin ?? 'dsh',
@@ -2,7 +2,7 @@ import { createProductionController } from './production.mjs';
2
2
  import { installQqRpc } from './rpc.mjs';
3
3
 
4
4
  export const name = 'dsh-im-qq-host';
5
- export const inject = ['connection', 'credentials', 'webServer', 'typertGateway'];
5
+ export const inject = ['connection', 'credentials', 'apiProxy', 'typertGateway'];
6
6
 
7
7
  export async function apply(ctx, config = {}) {
8
8
  if (config?.controller) {
@@ -17,17 +17,9 @@ import {
17
17
  import { listAgentPresetCatalog } from '../../../../src/channels/shared/agent-preset.mjs';
18
18
  import { createConnectionSupervisor } from './connection-supervisor.mjs';
19
19
  import { createHarnessCommandExecutor } from '../../harness-command-executor.mjs';
20
+ import { harnessConnection } from '../../harness-connection.mjs';
20
21
  import { createHarnessSessionExecutors } from '../../harness-session-coordinator.mjs';
21
22
 
22
- function harnessOrigin(webServer, configured) {
23
- if (configured !== undefined) return new URL(configured);
24
- const port = webServer?.port;
25
- if (!Number.isInteger(port) || port < 1 || port > 65_535) {
26
- throw new Error('dsh-im QQ requires an initialized DSH webServer port');
27
- }
28
- return new URL(`http://127.0.0.1:${port}`);
29
- }
30
-
31
23
  function pluginPaths(config) {
32
24
  const dshHome = resolve(config.dshHome ?? process.env.DSH_HOME ?? join(homedir(), '.dsh'));
33
25
  const root = resolve(config.dataDir ?? join(dshHome, 'integrations', 'dsh-qq'));
@@ -40,7 +32,7 @@ function pluginPaths(config) {
40
32
 
41
33
  export async function createProductionController(ctx, config = {}, internals = {}) {
42
34
  if (!ctx?.credentials) throw new TypeError('dsh-im QQ requires ctx.credentials');
43
- if (!ctx?.webServer) throw new TypeError('dsh-im QQ requires ctx.webServer');
35
+ const connection = harnessConnection(ctx, config);
44
36
 
45
37
  const ConfigStore = internals.ConfigStore ?? QqConfigStore;
46
38
  const StateStore = internals.StateStore ?? QqStateStore;
@@ -83,7 +75,7 @@ export async function createProductionController(ctx, config = {}, internals = {
83
75
  fileIngressExecutor: internals.fileIngressExecutor,
84
76
  });
85
77
  const harness = new Harness({
86
- baseUrl: harnessOrigin(ctx.webServer, config.harnessBaseUrl),
78
+ ...connection,
87
79
  workspace: defaultWorkspace,
88
80
  autostart: false,
89
81
  dshBin: config.dshBin ?? 'dsh',
@@ -4,6 +4,7 @@ import { join, resolve } from 'node:path';
4
4
 
5
5
  import { createTokenConnectionSupervisor } from './connection-supervisor.mjs';
6
6
  import { createHarnessCommandExecutor } from '../../harness-command-executor.mjs';
7
+ import { harnessConnection } from '../../harness-connection.mjs';
7
8
  import { createHarnessSessionExecutors } from '../../harness-session-coordinator.mjs';
8
9
  import {
9
10
  BotWorkspaceStore,
@@ -13,15 +14,6 @@ import {
13
14
  } from '../../../../src/channels/shared/bot-workspace-store.mjs';
14
15
  import { listAgentPresetCatalog } from '../../../../src/channels/shared/agent-preset.mjs';
15
16
 
16
- export function harnessOrigin(webServer, configured) {
17
- if (configured !== undefined) return new URL(configured);
18
- const port = webServer?.port;
19
- if (!Number.isInteger(port) || port < 1 || port > 65_535) {
20
- throw new Error('dsh-im token channel requires an initialized DSH webServer port');
21
- }
22
- return new URL(`http://127.0.0.1:${port}`);
23
- }
24
-
25
17
  export function pluginPaths(config, channel) {
26
18
  const dshHome = resolve(config.dshHome ?? process.env.DSH_HOME ?? join(homedir(), '.dsh'));
27
19
  const root = resolve(config.dataDir ?? join(dshHome, 'integrations', `dsh-${channel}`));
@@ -37,7 +29,7 @@ export async function createTokenProductionController(ctx, config, internals, de
37
29
  channel, ConfigStore, StateStore, HarnessClient, Controller, Runtime, runtimeOptions,
38
30
  } = definitions;
39
31
  if (!ctx?.credentials) throw new TypeError(`dsh-im ${channel} requires ctx.credentials`);
40
- if (!ctx?.webServer) throw new TypeError(`dsh-im ${channel} requires ctx.webServer`);
32
+ const connection = harnessConnection(ctx, config);
41
33
 
42
34
  const ResolvedConfigStore = internals.ConfigStore ?? ConfigStore;
43
35
  const ResolvedStateStore = internals.StateStore ?? StateStore;
@@ -84,7 +76,7 @@ export async function createTokenProductionController(ctx, config, internals, de
84
76
  fileIngressExecutor: internals.fileIngressExecutor,
85
77
  });
86
78
  const harness = new ResolvedHarness({
87
- baseUrl: harnessOrigin(ctx.webServer, config.harnessBaseUrl),
79
+ ...connection,
88
80
  workspace: defaultWorkspace,
89
81
  autostart: false,
90
82
  dshBin: config.dshBin ?? 'dsh',
@@ -2,7 +2,7 @@ import { createProductionController } from './production.mjs';
2
2
  import { installSlackRpc } from './rpc.mjs';
3
3
 
4
4
  export const name = 'dsh-im-slack-host';
5
- export const inject = ['connection', 'credentials', 'webServer', 'typertGateway'];
5
+ export const inject = ['connection', 'credentials', 'apiProxy', 'typertGateway'];
6
6
 
7
7
  export async function apply(ctx, config = {}) {
8
8
  if (config?.controller) return installSlackRpc(ctx, config.controller, config.rpcAuthority);
@@ -14,13 +14,14 @@ import {
14
14
  } from '../../../../src/channels/shared/bot-workspace-store.mjs';
15
15
  import { listAgentPresetCatalog } from '../../../../src/channels/shared/agent-preset.mjs';
16
16
  import { createTokenConnectionSupervisor } from '../shared/connection-supervisor.mjs';
17
- import { harnessOrigin, pluginPaths } from '../shared/production.mjs';
17
+ import { pluginPaths } from '../shared/production.mjs';
18
18
  import { createHarnessCommandExecutor } from '../../harness-command-executor.mjs';
19
+ import { harnessConnection } from '../../harness-connection.mjs';
19
20
  import { createHarnessSessionExecutors } from '../../harness-session-coordinator.mjs';
20
21
 
21
22
  export async function createProductionController(ctx, config = {}, internals = {}) {
22
23
  if (!ctx?.credentials) throw new TypeError('dsh-im slack requires ctx.credentials');
23
- if (!ctx?.webServer) throw new TypeError('dsh-im slack requires ctx.webServer');
24
+ const connection = harnessConnection(ctx, config);
24
25
 
25
26
  const ResolvedConfigStore = internals.ConfigStore ?? SlackConfigStore;
26
27
  const ResolvedStateStore = internals.StateStore ?? SlackStateStore;
@@ -62,7 +63,7 @@ export async function createProductionController(ctx, config = {}, internals = {
62
63
  fileIngressExecutor: internals.fileIngressExecutor,
63
64
  });
64
65
  const harness = new ResolvedHarness({
65
- baseUrl: harnessOrigin(ctx.webServer, config.harnessBaseUrl),
66
+ ...connection,
66
67
  workspace: defaultWorkspace,
67
68
  autostart: false,
68
69
  dshBin: config.dshBin ?? 'dsh',
@@ -2,7 +2,7 @@ import { createProductionController } from './production.mjs';
2
2
  import { installTelegramRpc } from './rpc.mjs';
3
3
 
4
4
  export const name = 'dsh-im-telegram-host';
5
- export const inject = ['connection', 'credentials', 'webServer', 'typertGateway'];
5
+ export const inject = ['connection', 'credentials', 'apiProxy', 'typertGateway'];
6
6
 
7
7
  export async function apply(ctx, config = {}) {
8
8
  if (config?.controller) {
@@ -2,7 +2,7 @@ import { createProductionController } from './production.mjs';
2
2
  import { installWecomRpc } from './rpc.mjs';
3
3
 
4
4
  export const name = 'dsh-im-wecom-host';
5
- export const inject = ['connection', 'credentials', 'webServer', 'typertGateway'];
5
+ export const inject = ['connection', 'credentials', 'apiProxy', 'typertGateway'];
6
6
 
7
7
  export async function apply(ctx, config = {}) {
8
8
  if (config?.controller) {
@@ -17,17 +17,9 @@ import {
17
17
  import { listAgentPresetCatalog } from '../../../../src/channels/shared/agent-preset.mjs';
18
18
  import { createConnectionSupervisor } from './connection-supervisor.mjs';
19
19
  import { createHarnessCommandExecutor } from '../../harness-command-executor.mjs';
20
+ import { harnessConnection } from '../../harness-connection.mjs';
20
21
  import { createHarnessSessionExecutors } from '../../harness-session-coordinator.mjs';
21
22
 
22
- function harnessOrigin(webServer, configured) {
23
- if (configured !== undefined) return new URL(configured);
24
- const port = webServer?.port;
25
- if (!Number.isInteger(port) || port < 1 || port > 65_535) {
26
- throw new Error('dsh-im Enterprise WeChat requires an initialized DSH webServer port');
27
- }
28
- return new URL(`http://127.0.0.1:${port}`);
29
- }
30
-
31
23
  function pluginPaths(config) {
32
24
  const dshHome = resolve(config.dshHome ?? process.env.DSH_HOME ?? join(homedir(), '.dsh'));
33
25
  const root = resolve(config.dataDir ?? join(dshHome, 'integrations', 'dsh-wecom'));
@@ -40,7 +32,7 @@ function pluginPaths(config) {
40
32
 
41
33
  export async function createProductionController(ctx, config = {}, internals = {}) {
42
34
  if (!ctx?.credentials) throw new TypeError('dsh-im Enterprise WeChat requires ctx.credentials');
43
- if (!ctx?.webServer) throw new TypeError('dsh-im Enterprise WeChat requires ctx.webServer');
35
+ const connection = harnessConnection(ctx, config);
44
36
 
45
37
  const ConfigStore = internals.ConfigStore ?? WecomConfigStore;
46
38
  const StateStore = internals.StateStore ?? WecomStateStore;
@@ -86,7 +78,7 @@ export async function createProductionController(ctx, config = {}, internals = {
86
78
  fileIngressExecutor: internals.fileIngressExecutor,
87
79
  });
88
80
  const harness = new Harness({
89
- baseUrl: harnessOrigin(ctx.webServer, config.harnessBaseUrl),
81
+ ...connection,
90
82
  workspace: defaultWorkspace,
91
83
  autostart: false,
92
84
  dshBin: config.dshBin ?? 'dsh',
@@ -2,7 +2,7 @@ import { createProductionController } from './production.mjs';
2
2
  import { installWeixinRpc } from './rpc.mjs';
3
3
 
4
4
  export const name = 'dsh-weixin-host';
5
- export const inject = ['connection', 'credentials', 'webServer', 'typertGateway'];
5
+ export const inject = ['connection', 'credentials', 'apiProxy', 'typertGateway'];
6
6
 
7
7
  export async function apply(ctx, config = {}) {
8
8
  if (config?.controller) {
@@ -20,17 +20,9 @@ import {
20
20
  import { listAgentPresetCatalog } from '../../../../src/channels/shared/agent-preset.mjs';
21
21
  import { createConnectionSupervisor } from './connection-supervisor.mjs';
22
22
  import { createHarnessCommandExecutor } from '../../harness-command-executor.mjs';
23
+ import { harnessConnection } from '../../harness-connection.mjs';
23
24
  import { createHarnessSessionExecutors } from '../../harness-session-coordinator.mjs';
24
25
 
25
- function harnessOrigin(webServer, configured) {
26
- if (configured !== undefined) return new URL(configured);
27
- const port = webServer?.port;
28
- if (!Number.isInteger(port) || port < 1 || port > 65_535) {
29
- throw new Error('dsh-weixin requires an initialized DSH webServer port');
30
- }
31
- return new URL(`http://127.0.0.1:${port}`);
32
- }
33
-
34
26
  function pluginPaths(config) {
35
27
  const dshHome = resolve(config.dshHome ?? process.env.DSH_HOME ?? join(homedir(), '.dsh'));
36
28
  const root = resolve(config.dataDir ?? join(dshHome, 'integrations', 'dsh-weixin'));
@@ -44,7 +36,7 @@ function pluginPaths(config) {
44
36
 
45
37
  export async function createProductionController(ctx, config = {}, internals = {}) {
46
38
  if (!ctx?.credentials) throw new TypeError('dsh-weixin requires ctx.credentials');
47
- if (!ctx?.webServer) throw new TypeError('dsh-weixin requires ctx.webServer');
39
+ const connection = harnessConnection(ctx, config);
48
40
 
49
41
  const ConfigStore = internals.ConfigStore ?? WeixinConfigStore;
50
42
  const StateStore = internals.StateStore ?? WeixinStateStore;
@@ -89,7 +81,7 @@ export async function createProductionController(ctx, config = {}, internals = {
89
81
  fileIngressExecutor: internals.fileIngressExecutor,
90
82
  });
91
83
  const harness = new Harness({
92
- baseUrl: harnessOrigin(ctx.webServer, config.harnessBaseUrl),
84
+ ...connection,
93
85
  workspace: defaultWorkspace,
94
86
  autostart: false,
95
87
  dshBin: config.dshBin ?? 'dsh',
@@ -2,7 +2,7 @@ import { createProductionController } from './production.mjs';
2
2
  import { installWhatsappRpc } from './rpc.mjs';
3
3
 
4
4
  export const name = 'dsh-im-whatsapp-host';
5
- export const inject = ['connection', 'webServer', 'typertGateway'];
5
+ export const inject = ['connection', 'apiProxy', 'typertGateway'];
6
6
 
7
7
  export async function apply(ctx, config = {}) {
8
8
  if (config?.controller) {
@@ -17,19 +17,11 @@ import {
17
17
  import { listAgentPresetCatalog } from '../../../../src/channels/shared/agent-preset.mjs';
18
18
  import { createTokenConnectionSupervisor } from '../shared/connection-supervisor.mjs';
19
19
  import { createHarnessCommandExecutor } from '../../harness-command-executor.mjs';
20
+ import { harnessConnection } from '../../harness-connection.mjs';
20
21
  import { createHarnessSessionExecutors } from '../../harness-session-coordinator.mjs';
21
22
 
22
23
  const AUTH_DIRECTORY_PATTERN = /^[a-f0-9-]{36}$/;
23
24
 
24
- function harnessOrigin(webServer, configured) {
25
- if (configured !== undefined) return new URL(configured);
26
- const port = webServer?.port;
27
- if (!Number.isInteger(port) || port < 1 || port > 65_535) {
28
- throw new Error('dsh-im WhatsApp requires an initialized DSH webServer port');
29
- }
30
- return new URL(`http://127.0.0.1:${port}`);
31
- }
32
-
33
25
  function pluginPaths(config) {
34
26
  const dshHome = resolve(config.dshHome ?? process.env.DSH_HOME ?? join(homedir(), '.dsh'));
35
27
  const root = resolve(config.dataDir ?? join(dshHome, 'integrations', 'dsh-whatsapp'));
@@ -47,7 +39,7 @@ function pluginPaths(config) {
47
39
  }
48
40
 
49
41
  export async function createProductionController(ctx, config = {}, internals = {}) {
50
- if (!ctx?.webServer) throw new TypeError('dsh-im WhatsApp requires ctx.webServer');
42
+ const connection = harnessConnection(ctx, config);
51
43
  const logger = typeof ctx.logger === 'function'
52
44
  ? ctx.logger('dsh-im:whatsapp') : (ctx.logger ?? console);
53
45
  const agentPresetCatalog = () => listAgentPresetCatalog(ctx);
@@ -89,7 +81,7 @@ export async function createProductionController(ctx, config = {}, internals = {
89
81
  fileIngressExecutor: internals.fileIngressExecutor,
90
82
  });
91
83
  const harness = new Harness({
92
- baseUrl: harnessOrigin(ctx.webServer, config.harnessBaseUrl),
84
+ ...connection,
93
85
  workspace: defaultWorkspace,
94
86
  autostart: false,
95
87
  dshBin: config.dshBin ?? 'dsh',
@@ -0,0 +1,15 @@
1
+ /** Connect to this Host directly unless an external Harness URL was configured. */
2
+ export function harnessConnection(ctx, config = {}) {
3
+ if (config.harnessBaseUrl !== undefined) {
4
+ return { baseUrl: new URL(config.harnessBaseUrl) };
5
+ }
6
+ if (!ctx?.apiProxy) {
7
+ throw new TypeError('dsh-im requires the Host apiProxy service; check that DSH has finished loading its Host services');
8
+ }
9
+ return {
10
+ apiProxy: ctx.apiProxy,
11
+ // Cordis child contexts share one root; different Hosts must not share
12
+ // ownership of pending questions and approvals.
13
+ interactionScope: ctx.root ?? ctx,
14
+ };
15
+ }
@@ -15,7 +15,7 @@ export const name = 'dsh-im-host';
15
15
  export const inject = [
16
16
  'connection',
17
17
  'credentials',
18
- 'webServer',
18
+ 'apiProxy',
19
19
  'typertGateway',
20
20
  ];
21
21