dominds 1.25.18 → 1.26.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 (38) hide show
  1. package/README.md +17 -0
  2. package/README.zh.md +17 -0
  3. package/dist/apps/runtime.d.ts +2 -4
  4. package/dist/apps-host/client.d.ts +2 -5
  5. package/dist/apps-host/ipc-types.d.ts +2 -5
  6. package/dist/apps-host/ipc-types.js +5 -1
  7. package/dist/bootstrap/rtws-cli.d.ts +0 -1
  8. package/dist/bootstrap/rtws-cli.js +9 -3
  9. package/dist/cli/cert.d.ts +2 -0
  10. package/dist/cli/cert.js +198 -0
  11. package/dist/cli/create.d.ts +1 -1
  12. package/dist/cli/create.js +1 -1
  13. package/dist/cli/read.js +1 -1
  14. package/dist/cli/tui.js +1 -1
  15. package/dist/cli/webui.d.ts +1 -1
  16. package/dist/cli/webui.js +35 -5
  17. package/dist/cli.d.ts +1 -0
  18. package/dist/cli.js +21 -16
  19. package/dist/docs/cli-usage.md +43 -7
  20. package/dist/docs/cli-usage.zh.md +43 -7
  21. package/dist/docs/dialog-persistence.md +1 -1
  22. package/dist/docs/dominds-terminology.md +2 -2
  23. package/dist/server/auth.d.ts +7 -0
  24. package/dist/server/auth.js +15 -4
  25. package/dist/server/certificates.d.ts +61 -0
  26. package/dist/server/certificates.js +418 -0
  27. package/dist/server/dominds-self-update-restart-helper.d.ts +15 -0
  28. package/dist/server/dominds-self-update-restart-helper.js +305 -0
  29. package/dist/server/dominds-self-update.js +162 -120
  30. package/dist/server/network-hosts.d.ts +5 -0
  31. package/dist/server/network-hosts.js +188 -0
  32. package/dist/server/server-core.d.ts +12 -1
  33. package/dist/server/server-core.js +26 -4
  34. package/dist/server/websocket-handler.d.ts +3 -2
  35. package/dist/server/websocket-handler.js +15 -8
  36. package/dist/server.d.ts +5 -0
  37. package/dist/server.js +105 -10
  38. package/package.json +3 -3
package/README.md CHANGED
@@ -253,6 +253,23 @@ Platform note:
253
253
 
254
254
  - Windows also registers `codex_inspect_and_patch_tools`; its `readonly_shell` tool runs through `cmd.exe`, so prefer allowlisted commands available in that shell/PATH, such as `rg`, `git`, `dir`, `type`, and `where`.
255
255
 
256
+ ### Local HTTPS Certificates
257
+
258
+ Dominds always keeps an HTTP listener. When a valid certificate matching the current `--host` exists under `~/.dominds/certs/`, Dominds also starts HTTPS. Certificates match DNS/IP hostnames, not ports, so one certificate covers all Dominds WebUI ports on that host.
259
+
260
+ ```bash
261
+ # Create a 10-year self-signed certificate for detected non-loopback LAN hosts
262
+ dominds cert create
263
+
264
+ # Add explicit SAN hosts; --host can be repeated
265
+ dominds cert create --host 192.168.1.10 --host my-host.local
266
+
267
+ # Inspect whether a host can use an HTTPS certificate
268
+ dominds cert status --host 0.0.0.0
269
+ ```
270
+
271
+ `localhost`, `loopback`, `127.0.0.0/8`, `::1`, `0.0.0.0`, and `::` are not certificate hosts. `0.0.0.0` / `::` only mean bind-all; certificate matching uses detected non-loopback LAN hosts. A bare `--port 5666` disables Dominds built-in HTTPS and assumes a front proxy handles HTTPS, while the default port behavior and `--port 5666+/-` may auto-enable built-in HTTPS when a matching certificate exists.
272
+
256
273
  ## Start from scratch
257
274
 
258
275
  Starting from scratch means: create an empty folder, run `dominds`, let Setup generate the minimal `.minds/team.yaml`, then use the shadow team manager (`@fuxi`) to design a real team for your product.
package/README.zh.md CHANGED
@@ -192,6 +192,23 @@ dominds
192
192
 
193
193
  - Windows 也会注册 `codex_inspect_and_patch_tools`;其中 `readonly_shell` 通过 `cmd.exe` 执行,因此优先使用该 shell/PATH 中可用的白名单命令,例如 `rg`、`git`、`dir`、`type` 和 `where`。
194
194
 
195
+ ### 本地 HTTPS 证书
196
+
197
+ Dominds 默认始终提供 HTTP 监听;当 `~/.dominds/certs/` 下存在匹配当前 `--host` 的有效证书时,会额外启用 HTTPS。证书按 DNS/IP 主机名匹配,不绑定端口,因此同一张证书可覆盖该主机上的所有 Dominds WebUI 端口。
198
+
199
+ ```bash
200
+ # 自动为检测到的一个或多个非 loopback LAN 主机创建 10 年有效的自签名证书
201
+ dominds cert create
202
+
203
+ # 显式指定证书 SAN,可重复 --host
204
+ dominds cert create --host 192.168.1.10 --host my-host.local
205
+
206
+ # 查看指定 host 是否能匹配到证书
207
+ dominds cert status --host 0.0.0.0
208
+ ```
209
+
210
+ `localhost`、`loopback`、`127.0.0.0/8`、`::1`、`0.0.0.0`、`::` 不会作为 HTTPS 证书主机;其中 `0.0.0.0` / `::` 仅表示绑定所有地址,匹配证书时会使用检测到的非 loopback LAN 主机。使用裸 `--port 5666` 启动时,Dominds 会认为 HTTPS 由前置代理负责,不启用内建 HTTPS;使用默认端口或 `--port 5666+/-` 时才会自动启用内建 HTTPS。
211
+
195
212
  ## 从零开始(空文件夹启动)
196
213
 
197
214
  若暂无模板或团队配置,可直接从空目录启动:
@@ -1,3 +1,4 @@
1
+ import type { DomindsKernelEndpoint } from '@longrun-ai/kernel/app-host-contract';
1
2
  import { type AppsHostClient } from '../apps-host/client';
2
3
  export type DynamicAppToolAvailabilityResult = Readonly<{
3
4
  status: 'ready';
@@ -36,8 +37,5 @@ export declare function resolveDynamicAppToolAvailabilityForMember(_params: {
36
37
  }): Promise<DynamicAppToolAvailabilityResult>;
37
38
  export declare function initAppsRuntime(params: {
38
39
  rtwsRootAbs: string;
39
- kernel: Readonly<{
40
- host: string;
41
- port: number;
42
- }>;
40
+ kernel: DomindsKernelEndpoint;
43
41
  }): Promise<void>;
@@ -1,4 +1,4 @@
1
- import type { DomindsAppDynamicToolsetsContext, DomindsAppReminderOwnerApplyContext, DomindsAppReminderOwnerRenderContext, DomindsAppReminderOwnerUpdateContext, DomindsAppReminderRenderedMessage, DomindsAppRunControlContext, DomindsAppRunControlResult } from '@longrun-ai/kernel/app-host-contract';
1
+ import type { DomindsAppDynamicToolsetsContext, DomindsAppReminderOwnerApplyContext, DomindsAppReminderOwnerRenderContext, DomindsAppReminderOwnerUpdateContext, DomindsAppReminderRenderedMessage, DomindsAppRunControlContext, DomindsAppRunControlResult, DomindsKernelEndpoint } from '@longrun-ai/kernel/app-host-contract';
2
2
  import type { DomindsAppHostReminderUpdateResult, DomindsAppHostToolResult, DomindsAppInstallJson, DomindsAppReminderApplyRequest, DomindsAppReminderApplyResult } from '@longrun-ai/kernel/app-json';
3
3
  import type { ToolArguments } from '../tool';
4
4
  import type { AppsHostMessageToKernel } from './ipc-types';
@@ -29,10 +29,7 @@ export type AppsHostReadyMessage = Extract<AppsHostMessageToKernel, {
29
29
  }>;
30
30
  export declare function startAppsHost(params: {
31
31
  rtwsRootAbs: string;
32
- kernel: Readonly<{
33
- host: string;
34
- port: number;
35
- }>;
32
+ kernel: DomindsKernelEndpoint;
36
33
  apps: ReadonlyArray<EnabledAppForHost>;
37
34
  }): Promise<Readonly<{
38
35
  client: AppsHostClient;
@@ -1,14 +1,11 @@
1
- import type { DomindsAppReminderRenderedMessage, DomindsAppRunControlResult } from '@longrun-ai/kernel/app-host-contract';
1
+ import type { DomindsAppReminderRenderedMessage, DomindsAppRunControlResult, DomindsKernelEndpoint } from '@longrun-ai/kernel/app-host-contract';
2
2
  import type { DomindsAppDialogReminderRequestBatch, DomindsAppHostReminderUpdateResult, DomindsAppInstallJson, DomindsAppReminderApplyRequest, DomindsAppReminderApplyResult, DomindsAppReminderState } from '@longrun-ai/kernel/app-json';
3
3
  import type { LanguageCode } from '@longrun-ai/kernel/types/language';
4
4
  import type { ToolArguments, ToolCallOutput } from '../tool';
5
5
  export type AppsHostKernelInitMessage = Readonly<{
6
6
  type: 'init';
7
7
  rtwsRootAbs: string;
8
- kernel: Readonly<{
9
- host: string;
10
- port: number;
11
- }>;
8
+ kernel: DomindsKernelEndpoint;
12
9
  apps: ReadonlyArray<Readonly<{
13
10
  appId: string;
14
11
  runtimePort: number | null;
@@ -126,9 +126,13 @@ function parseAppsHostMessageFromKernel(v) {
126
126
  throw new Error('Invalid init message: rtwsRootAbs required');
127
127
  if (!isRecord(kernel))
128
128
  throw new Error('Invalid init message: kernel must be object');
129
+ const scheme = kernel['scheme'];
129
130
  const host = asString(kernel['host']);
130
131
  const portRaw = kernel['port'];
131
132
  const port = typeof portRaw === 'number' && Number.isFinite(portRaw) ? Math.floor(portRaw) : null;
133
+ if (scheme !== 'http' && scheme !== 'https') {
134
+ throw new Error('Invalid init message: kernel.scheme must be http|https');
135
+ }
132
136
  if (!host)
133
137
  throw new Error('Invalid init message: kernel.host required');
134
138
  if (port === null || port < 0) {
@@ -157,7 +161,7 @@ function parseAppsHostMessageFromKernel(v) {
157
161
  }
158
162
  return { appId, runtimePort, installJson: installJson };
159
163
  });
160
- return { type: 'init', rtwsRootAbs, kernel: { host, port }, apps: parsedApps };
164
+ return { type: 'init', rtwsRootAbs, kernel: { scheme, host, port }, apps: parsedApps };
161
165
  }
162
166
  if (type === 'tool_call') {
163
167
  const callId = asString(v['callId']);
@@ -4,5 +4,4 @@ export type RtwsCliParseResult = Readonly<{
4
4
  }>;
5
5
  export declare function extractGlobalRtwsChdir(params: Readonly<{
6
6
  argv: ReadonlyArray<string>;
7
- baseCwd: string;
8
7
  }>): RtwsCliParseResult;
@@ -38,6 +38,12 @@ const path = __importStar(require("path"));
38
38
  function extractGlobalRtwsChdir(params) {
39
39
  let chdir;
40
40
  const out = [];
41
+ const readAbsoluteChdir = (argName, value) => {
42
+ if (!path.isAbsolute(value)) {
43
+ throw new Error(`${argName} requires an absolute directory path: ${value}`);
44
+ }
45
+ return value;
46
+ };
41
47
  for (let i = 0; i < params.argv.length; i++) {
42
48
  const arg = params.argv[i];
43
49
  if (arg === '--') {
@@ -49,7 +55,7 @@ function extractGlobalRtwsChdir(params) {
49
55
  if (typeof next !== 'string' || next.length === 0 || next === '--') {
50
56
  throw new Error(`${arg} requires a directory argument`);
51
57
  }
52
- chdir = path.isAbsolute(next) ? next : path.resolve(params.baseCwd, next);
58
+ chdir = readAbsoluteChdir(arg, next);
53
59
  i++;
54
60
  continue;
55
61
  }
@@ -57,14 +63,14 @@ function extractGlobalRtwsChdir(params) {
57
63
  const value = arg.slice('--cwd='.length);
58
64
  if (value.length === 0)
59
65
  throw new Error(`--cwd requires a directory argument`);
60
- chdir = path.isAbsolute(value) ? value : path.resolve(params.baseCwd, value);
66
+ chdir = readAbsoluteChdir('--cwd', value);
61
67
  continue;
62
68
  }
63
69
  if (arg.startsWith('--chdir=')) {
64
70
  const value = arg.slice('--chdir='.length);
65
71
  if (value.length === 0)
66
72
  throw new Error(`--chdir requires a directory argument`);
67
- chdir = path.isAbsolute(value) ? value : path.resolve(params.baseCwd, value);
73
+ chdir = readAbsoluteChdir('--chdir', value);
68
74
  continue;
69
75
  }
70
76
  out.push(arg);
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export declare function main(args?: readonly string[]): Promise<void>;
@@ -0,0 +1,198 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.main = main;
5
+ const auth_1 = require("../server/auth");
6
+ const certificates_1 = require("../server/certificates");
7
+ function printHelp() {
8
+ console.log(`
9
+ Dominds certificate tools
10
+
11
+ Usage:
12
+ dominds cert create [--host <host>] [--days <days>] [--force]
13
+ dominds cert self-cert [--host <host>] [--days <days>] [--force]
14
+ dominds cert status --host <host> [--port <port>] [--origin]
15
+
16
+ Options:
17
+ --host <host> Host name or IP address (default for create: detected non-loopback LAN hosts)
18
+ --days <days> Certificate validity in days (default: ${certificates_1.DEFAULT_SELF_SIGNED_CERT_DAYS})
19
+ --force Overwrite existing generated files
20
+ --port <port> Port for status --origin output
21
+ --origin Print only the effective origin, using https when a matching cert exists
22
+ --help Show this help message
23
+
24
+ Certificates live in ~/.dominds/certs/. A WebUI server automatically enables HTTPS when it finds
25
+ a certificate/key pair that matches the bind host or, for 0.0.0.0/::, a detected non-loopback LAN host.
26
+ `);
27
+ }
28
+ async function main(args = process.argv.slice(2)) {
29
+ const first = args[0];
30
+ if (first === undefined || first === '--help' || first === '-h') {
31
+ printHelp();
32
+ return;
33
+ }
34
+ const action = parseAction(first);
35
+ if (action === null) {
36
+ console.error(`Error: Unknown cert subcommand '${first}'`);
37
+ printHelp();
38
+ process.exit(1);
39
+ }
40
+ const options = parseOptions(args.slice(1), action);
41
+ if (options.kind === 'error') {
42
+ console.error(`Error: ${options.message}`);
43
+ printHelp();
44
+ process.exit(1);
45
+ }
46
+ if (action === 'create') {
47
+ const created = await (0, certificates_1.createSelfSignedCertificate)({
48
+ host: options.host,
49
+ altHosts: options.altHosts,
50
+ days: options.days,
51
+ force: options.force,
52
+ });
53
+ console.log(`Created self-signed certificate for ${created.host}`);
54
+ console.log(` hosts: ${created.hosts.join(', ')}`);
55
+ console.log(` cert: ${created.certPath}`);
56
+ console.log(` key: ${created.keyPath}`);
57
+ console.log(` meta: ${created.metadataPath}`);
58
+ console.log(` days: ${created.days}`);
59
+ return;
60
+ }
61
+ if (options.host === undefined) {
62
+ console.error('Error: cert status requires --host <host>');
63
+ printHelp();
64
+ process.exit(1);
65
+ }
66
+ const lookup = await (0, certificates_1.findAutoHttpsCertificateForHost)({ host: options.host });
67
+ if (options.origin) {
68
+ if (options.port === undefined) {
69
+ console.error('Error: cert status --origin requires --port <port>');
70
+ process.exit(1);
71
+ }
72
+ console.log((0, auth_1.formatServerOrigin)({
73
+ scheme: lookup.kind === 'found' ? 'https' : 'http',
74
+ host: lookup.kind === 'found' ? lookup.certificate.matchedHost : lookup.endpoint.urlHost,
75
+ port: options.port,
76
+ }));
77
+ return;
78
+ }
79
+ for (const diagnostic of lookup.diagnostics) {
80
+ console.warn(`warning: ${diagnostic.message}`);
81
+ }
82
+ if (lookup.kind === 'found') {
83
+ console.log(`HTTPS certificate: found`);
84
+ console.log(` cert: ${lookup.certificate.certPath}`);
85
+ console.log(` key: ${lookup.certificate.keyPath}`);
86
+ console.log(` matchedHost: ${lookup.certificate.matchedHost}`);
87
+ console.log(` validTo: ${lookup.certificate.validTo.toISOString()}`);
88
+ }
89
+ else {
90
+ console.log(`HTTPS certificate: not found`);
91
+ console.log(` certsDir: ${lookup.certsDirAbs}`);
92
+ }
93
+ }
94
+ function parseAction(value) {
95
+ switch (value) {
96
+ case 'create':
97
+ case 'self-cert':
98
+ return 'create';
99
+ case 'status':
100
+ return 'status';
101
+ default:
102
+ return null;
103
+ }
104
+ }
105
+ function parseOptions(args, action) {
106
+ let host;
107
+ let days;
108
+ const altHosts = [];
109
+ let force = false;
110
+ let port;
111
+ let origin = false;
112
+ for (let i = 0; i < args.length; i += 1) {
113
+ const arg = args[i];
114
+ if (arg === '--host') {
115
+ const next = args[i + 1];
116
+ if (!next)
117
+ return { kind: 'error', message: '--host requires a value' };
118
+ if (host === undefined)
119
+ host = next;
120
+ else
121
+ altHosts.push(next);
122
+ i += 1;
123
+ continue;
124
+ }
125
+ if (arg.startsWith('--host=')) {
126
+ const value = arg.slice('--host='.length);
127
+ if (host === undefined)
128
+ host = value;
129
+ else
130
+ altHosts.push(value);
131
+ continue;
132
+ }
133
+ if (arg === '--days') {
134
+ const next = args[i + 1];
135
+ const parsed = next === undefined ? null : parseInteger(next);
136
+ if (parsed === null)
137
+ return { kind: 'error', message: '--days requires an integer' };
138
+ days = parsed;
139
+ i += 1;
140
+ continue;
141
+ }
142
+ if (arg.startsWith('--days=')) {
143
+ const parsed = parseInteger(arg.slice('--days='.length));
144
+ if (parsed === null)
145
+ return { kind: 'error', message: '--days requires an integer' };
146
+ days = parsed;
147
+ continue;
148
+ }
149
+ if (arg === '--port') {
150
+ const next = args[i + 1];
151
+ const parsed = next === undefined ? null : parseInteger(next);
152
+ if (parsed === null || parsed < 1 || parsed > 65535) {
153
+ return { kind: 'error', message: '--port requires a valid TCP port' };
154
+ }
155
+ port = parsed;
156
+ i += 1;
157
+ continue;
158
+ }
159
+ if (arg.startsWith('--port=')) {
160
+ const parsed = parseInteger(arg.slice('--port='.length));
161
+ if (parsed === null || parsed < 1 || parsed > 65535) {
162
+ return { kind: 'error', message: '--port requires a valid TCP port' };
163
+ }
164
+ port = parsed;
165
+ continue;
166
+ }
167
+ if (arg === '--force') {
168
+ force = true;
169
+ continue;
170
+ }
171
+ if (arg === '--origin') {
172
+ origin = true;
173
+ continue;
174
+ }
175
+ if (arg === '--help' || arg === '-h') {
176
+ printHelp();
177
+ process.exit(0);
178
+ }
179
+ if (!arg.startsWith('-') && host === undefined && action === 'create') {
180
+ host = arg;
181
+ continue;
182
+ }
183
+ return { kind: 'error', message: `Unknown option '${arg}'` };
184
+ }
185
+ return { kind: 'ok', host, days, altHosts, force, port, origin };
186
+ }
187
+ function parseInteger(raw) {
188
+ if (!/^[0-9]+$/.test(raw))
189
+ return null;
190
+ const parsed = Number(raw);
191
+ return Number.isSafeInteger(parsed) ? parsed : null;
192
+ }
193
+ if (require.main === module) {
194
+ main().catch((error) => {
195
+ console.error(error instanceof Error ? error.message : String(error));
196
+ process.exit(1);
197
+ });
198
+ }
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * Notes:
10
10
  * - Template can be a short name (resolved via DOMINDS_TEMPLATE_BASE) or a git URL.
11
- * - rtws directory is `process.cwd()`. Use 'dominds -C <dir> create ...' to create under another base dir.
11
+ * - rtws directory is `process.cwd()`. Use 'dominds -C <abs-dir> create ...' to create under another base dir.
12
12
  */
13
13
  declare function main(argv?: readonly string[]): Promise<void>;
14
14
  export { main };
@@ -9,7 +9,7 @@
9
9
  *
10
10
  * Notes:
11
11
  * - Template can be a short name (resolved via DOMINDS_TEMPLATE_BASE) or a git URL.
12
- * - rtws directory is `process.cwd()`. Use 'dominds -C <dir> create ...' to create under another base dir.
12
+ * - rtws directory is `process.cwd()`. Use 'dominds -C <abs-dir> create ...' to create under another base dir.
13
13
  */
14
14
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
15
15
  if (k2 === undefined) k2 = k;
package/dist/cli/read.js CHANGED
@@ -59,7 +59,7 @@ function printUsage() {
59
59
  console.log('`--audit` runs prompt audit via hidden teammate @fuxi using default LLM config (skips when unavailable), and also includes static toolset checks (registry vs `.minds/mcp.yaml` declarations).');
60
60
  console.log('When <member-id> is omitted, reads all visible team members.');
61
61
  console.log('');
62
- console.log("Note: rtws (runtime workspace) directory is `process.cwd()`. Use 'dominds -C <dir> read' to run in another rtws.");
62
+ console.log("Note: rtws (runtime workspace) directory is `process.cwd()`. Use 'dominds -C <abs-dir> read' to run in another rtws.");
63
63
  console.log('');
64
64
  console.log('Examples:');
65
65
  console.log(' dominds read # Read all team members');
package/dist/cli/tui.js CHANGED
@@ -76,7 +76,7 @@ function showHelp() {
76
76
  console.log('');
77
77
  console.log('Start or continue a dialog with an AI team member using a Taskdoc.');
78
78
  console.log('');
79
- console.log("Note: rtws (runtime workspace) directory is `process.cwd()`. Use 'dominds -C <dir> tui ...' to run in another rtws.");
79
+ console.log("Note: rtws (runtime workspace) directory is `process.cwd()`. Use 'dominds -C <abs-dir> tui ...' to run in another rtws.");
80
80
  console.log('');
81
81
  console.log('Arguments:');
82
82
  console.log(' <taskdoc-path> Path to Taskdoc (required for dialog)');
@@ -9,7 +9,7 @@
9
9
  * -p, --port <port> Port to listen on. Bare port is strict; suffix + tries higher ports; suffix - tries lower ports.
10
10
  * -h, --host <host> Host to bind to (default: localhost)
11
11
  * --nobrowser Do not open a browser (opt-out)
12
- * -h, --help Show help
12
+ * --help Show help
13
13
  */
14
14
  declare function main(args?: readonly string[]): Promise<void>;
15
15
  export { main };
package/dist/cli/webui.js CHANGED
@@ -10,7 +10,7 @@
10
10
  * -p, --port <port> Port to listen on. Bare port is strict; suffix + tries higher ports; suffix - tries lower ports.
11
11
  * -h, --host <host> Host to bind to (default: localhost)
12
12
  * --nobrowser Do not open a browser (opt-out)
13
- * -h, --help Show help
13
+ * --help Show help
14
14
  */
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
16
  exports.main = main;
@@ -22,6 +22,14 @@ const server_1 = require("../server");
22
22
  const auth_1 = require("../server/auth");
23
23
  const port_selection_1 = require("../server/port-selection");
24
24
  const log = (0, log_1.createLogger)('webui');
25
+ function formatWebSocketEndpoint(params) {
26
+ const httpOrigin = (0, auth_1.formatServerOrigin)({
27
+ scheme: params.scheme === 'ws' ? 'http' : 'https',
28
+ host: params.host,
29
+ port: params.port,
30
+ });
31
+ return `${params.scheme}${httpOrigin.slice(httpOrigin.indexOf(':'))}/ws`;
32
+ }
25
33
  function printHelp() {
26
34
  console.log(`
27
35
  WebUI Server for dominds
@@ -30,7 +38,7 @@ Usage:
30
38
  dominds webui [options]
31
39
 
32
40
  Note:
33
- rtws (runtime workspace) directory is \`process.cwd()\`. Use 'dominds -C <dir> webui' to run in another rtws.
41
+ rtws (runtime workspace) directory is \`process.cwd()\`. Use 'dominds -C <abs-dir> webui' to run in another rtws.
34
42
 
35
43
  Options:
36
44
  -p, --port <port> Port to listen on. Bare port is strict; suffix + tries higher ports; suffix - tries lower ports.
@@ -145,12 +153,34 @@ async function main(args = process.argv.slice(2)) {
145
153
  });
146
154
  const httpServer = started.httpServer;
147
155
  const auth = started.auth;
148
- const baseUrl = `http://${started.host}:${started.port}`;
156
+ const baseUrl = (0, auth_1.formatServerOrigin)({
157
+ scheme: 'http',
158
+ host: started.urlHost,
159
+ port: started.port,
160
+ });
149
161
  log.info(`WebUI ready: ${baseUrl}`);
150
- log.debug(`WebSocket endpoint: ws://${started.host}:${started.port}/ws`);
162
+ log.debug(`WebSocket endpoint: ${formatWebSocketEndpoint({
163
+ scheme: 'ws',
164
+ host: started.urlHost,
165
+ port: started.port,
166
+ })}`);
167
+ if (started.httpsPort !== undefined && started.httpsUrlHost !== undefined) {
168
+ const httpsBaseUrl = (0, auth_1.formatServerOrigin)({
169
+ scheme: 'https',
170
+ host: started.httpsUrlHost,
171
+ port: started.httpsPort,
172
+ });
173
+ log.info(`HTTPS WebUI ready: ${httpsBaseUrl}`);
174
+ log.debug(`HTTPS WebSocket endpoint: ${formatWebSocketEndpoint({
175
+ scheme: 'wss',
176
+ host: started.httpsUrlHost,
177
+ port: started.httpsPort,
178
+ })}`);
179
+ }
151
180
  if (auth.kind === 'enabled') {
152
181
  const autoAuthUrl = (0, auth_1.formatAutoAuthUrl)({
153
- host: started.host,
182
+ scheme: 'http',
183
+ host: started.urlHost,
154
184
  port: started.port,
155
185
  authKey: auth.key,
156
186
  });
package/dist/cli.d.ts CHANGED
@@ -13,6 +13,7 @@
13
13
  * man - Render toolset manual to stdout
14
14
  * manual - Alias for man
15
15
  * validate_team_def - Validate explicit team toolset declarations
16
+ * cert - Create and inspect local HTTPS certificates
16
17
  * create - Create a new runtime workspace (rtws) from a template
17
18
  * install - Install a Dominds App into this rtws
18
19
  * doctor - Diagnose Dominds App state in this rtws
package/dist/cli.js CHANGED
@@ -14,6 +14,7 @@
14
14
  * man - Render toolset manual to stdout
15
15
  * manual - Alias for man
16
16
  * validate_team_def - Validate explicit team toolset declarations
17
+ * cert - Create and inspect local HTTPS certificates
17
18
  * create - Create a new runtime workspace (rtws) from a template
18
19
  * install - Install a Dominds App into this rtws
19
20
  * doctor - Diagnose Dominds App state in this rtws
@@ -70,6 +71,7 @@ const path = __importStar(require("path"));
70
71
  const runtime_1 = require("./apps/runtime");
71
72
  const dotenv_1 = require("./bootstrap/dotenv");
72
73
  const rtws_cli_1 = require("./bootstrap/rtws-cli");
74
+ const cert_1 = require("./cli/cert");
73
75
  const create_1 = require("./cli/create");
74
76
  const disable_1 = require("./cli/disable");
75
77
  const doctor_1 = require("./cli/doctor");
@@ -107,10 +109,10 @@ function printHelp() {
107
109
  Dominds CLI - AI-driven DevOps framework with persistent memory
108
110
 
109
111
  Usage:
110
- dominds [-C <dir>] [subcommand] [options]
112
+ dominds [-C <abs-dir>] [subcommand] [options]
111
113
 
112
114
  Global Options:
113
- -C <dir> Change to runtime workspace directory (rtws) before running
115
+ -C <abs-dir> Change to absolute runtime workspace directory (rtws) before running
114
116
 
115
117
  Subcommands:
116
118
  webui [options] Start WebUI server (default)
@@ -120,6 +122,7 @@ Subcommands:
120
122
  man [options] Render toolset manual to stdout
121
123
  manual [options] Alias for man
122
124
  validate_team_def [options] Validate explicit team toolset declarations
125
+ cert [options] Create and inspect local HTTPS certificates
123
126
  create [options] Create a new runtime workspace (rtws) from a template
124
127
  install [options] Install a Dominds App into this rtws
125
128
  doctor [options] Read-only diagnosis across manifest/lock/configuration/resolution/handshake
@@ -133,12 +136,13 @@ Subcommands:
133
136
  Examples:
134
137
  dominds # Start WebUI server (default)
135
138
  dominds webui # Start WebUI server
136
- dominds -C ./my-ws webui # Start in specific rtws
139
+ dominds -C /path/to/my-ws webui # Start in specific rtws
137
140
  dominds tui --help # Show TUI help
138
141
  dominds run task.tsk # Run task dialog
139
142
  dominds read # Read team configuration
140
143
  dominds man ws_read --lang zh --all
141
144
  dominds validate_team_def # Validate toolset references in .minds/team.yaml
145
+ dominds cert create --host 192.168.1.10
142
146
  dominds create web-scaffold my-project # Create rtws from a template
143
147
  dominds doctor @longrun-ai/web-dev # Diagnose a single app across all app-state layers
144
148
 
@@ -159,10 +163,9 @@ function printVersion() {
159
163
  }
160
164
  }
161
165
  async function main(argv = process.argv.slice(2)) {
162
- const baseCwd = process.cwd();
163
166
  let parsed;
164
167
  try {
165
- parsed = (0, rtws_cli_1.extractGlobalRtwsChdir)({ argv, baseCwd });
168
+ parsed = (0, rtws_cli_1.extractGlobalRtwsChdir)({ argv });
166
169
  }
167
170
  catch (err) {
168
171
  console.error('Error:', err instanceof Error ? err.message : String(err));
@@ -173,10 +176,7 @@ async function main(argv = process.argv.slice(2)) {
173
176
  if (args.length === 0) {
174
177
  if (parsed.chdir) {
175
178
  try {
176
- const absoluteRtwsRoot = path.isAbsolute(parsed.chdir)
177
- ? parsed.chdir
178
- : path.resolve(baseCwd, parsed.chdir);
179
- process.chdir(absoluteRtwsRoot);
179
+ process.chdir(parsed.chdir);
180
180
  }
181
181
  catch (err) {
182
182
  console.error(`Error: failed to change directory to '${parsed.chdir}':`, err);
@@ -199,7 +199,8 @@ async function main(argv = process.argv.slice(2)) {
199
199
  printVersion();
200
200
  process.exit(0);
201
201
  }
202
- const shouldSkipRtwsSetup = subcommandArgs.includes('--help') ||
202
+ const shouldSkipRtwsSetup = subcommand === 'cert' ||
203
+ subcommandArgs.includes('--help') ||
203
204
  (subcommand === 'tui' && subcommandArgs.includes('-h')) ||
204
205
  (subcommand === 'run' && subcommandArgs.includes('-h')) ||
205
206
  (subcommand === 'read' && subcommandArgs.includes('-h')) ||
@@ -222,10 +223,7 @@ async function main(argv = process.argv.slice(2)) {
222
223
  if (!shouldSkipRtwsSetup) {
223
224
  if (parsed.chdir) {
224
225
  try {
225
- const absoluteRtwsRoot = path.isAbsolute(parsed.chdir)
226
- ? parsed.chdir
227
- : path.resolve(baseCwd, parsed.chdir);
228
- process.chdir(absoluteRtwsRoot);
226
+ process.chdir(parsed.chdir);
229
227
  }
230
228
  catch (err) {
231
229
  console.error(`Error: failed to change directory to '${parsed.chdir}':`, err);
@@ -239,6 +237,7 @@ async function main(argv = process.argv.slice(2)) {
239
237
  configureEnvProxySupport();
240
238
  }
241
239
  const shouldLoadApps = subcommand !== 'webui' &&
240
+ subcommand !== 'cert' &&
242
241
  subcommand !== 'create' &&
243
242
  subcommand !== 'new' &&
244
243
  subcommand !== 'install' &&
@@ -256,7 +255,7 @@ async function main(argv = process.argv.slice(2)) {
256
255
  if (shouldStartAppsHost) {
257
256
  await (0, runtime_1.initAppsRuntime)({
258
257
  rtwsRootAbs: process.cwd(),
259
- kernel: { host: '127.0.0.1', port: 0 },
258
+ kernel: { scheme: 'http', host: '127.0.0.1', port: 0 },
260
259
  });
261
260
  }
262
261
  }
@@ -286,6 +285,9 @@ async function main(argv = process.argv.slice(2)) {
286
285
  case 'validate_team_def':
287
286
  await runSubcommand('validate_team_def', subcommandArgs);
288
287
  break;
288
+ case 'cert':
289
+ await runSubcommand('cert', subcommandArgs);
290
+ break;
289
291
  case 'create':
290
292
  case 'new':
291
293
  await runSubcommand('create', subcommandArgs);
@@ -332,6 +334,9 @@ async function runSubcommand(subcommand, args) {
332
334
  else if (subcommand === 'validate_team_def') {
333
335
  await (0, validate_team_def_1.main)(args);
334
336
  }
337
+ else if (subcommand === 'cert') {
338
+ await (0, cert_1.main)(args);
339
+ }
335
340
  else if (subcommand === 'create') {
336
341
  await (0, create_1.main)(args);
337
342
  }
@@ -359,7 +364,7 @@ async function runSubcommand(subcommand, args) {
359
364
  }
360
365
  }
361
366
  catch (err) {
362
- console.error(`Failed to execute subcommand '${subcommand}':`, err);
367
+ console.error(`Failed to execute subcommand '${subcommand}': ${err instanceof Error ? err.message : String(err)}`);
363
368
  process.exit(1);
364
369
  }
365
370
  }