dominds 1.26.0 → 1.26.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/README.zh.md +3 -3
- package/dist/bootstrap/rtws-cli.d.ts +1 -0
- package/dist/bootstrap/rtws-cli.js +8 -8
- package/dist/cli/cert.d.ts +3 -1
- package/dist/cli/cert.js +69 -20
- package/dist/cli/create.d.ts +1 -1
- package/dist/cli/create.js +1 -1
- package/dist/cli/read.js +1 -1
- package/dist/cli/tui.js +1 -1
- package/dist/cli/webui.js +15 -5
- package/dist/cli-runner.d.ts +31 -0
- package/dist/cli-runner.js +349 -0
- package/dist/cli.d.ts +0 -31
- package/dist/cli.js +540 -304
- package/dist/docs/cli-usage.md +11 -10
- package/dist/docs/cli-usage.zh.md +11 -10
- package/dist/docs/dialog-persistence.md +1 -1
- package/dist/docs/dominds-terminology.md +2 -2
- package/dist/llm/kernel-driver/drive.js +19 -14
- package/dist/runtime/driver-messages.d.ts +2 -0
- package/dist/runtime/driver-messages.js +24 -4
- package/dist/server/certificates.js +1 -1
- package/dist/server/dominds-self-update.js +33 -121
- package/dist/server/network-hosts.js +140 -38
- package/dist/server-debug.d.ts +2 -0
- package/dist/server-debug.js +79 -0
- package/dist/server.js +4 -123
- package/dist/supervisor-protocol.d.ts +15 -0
- package/dist/supervisor-protocol.js +4 -0
- package/package.json +6 -5
- package/dist/server/dominds-self-update-restart-helper.d.ts +0 -15
- package/dist/server/dominds-self-update-restart-helper.js +0 -305
package/dist/docs/cli-usage.md
CHANGED
|
@@ -4,7 +4,9 @@ Chinese version: [中文版](./cli-usage.zh.md)
|
|
|
4
4
|
|
|
5
5
|
The `dominds` CLI provides a unified entry point, but the **primary interaction experience is the Web UI** (the default `dominds` command). This guide focuses on the Web UI workflow.
|
|
6
6
|
|
|
7
|
-
> Note: In this document, **rtws (runtime workspace)** refers to the runtime root directory Dominds uses (by default `
|
|
7
|
+
> Note: In this document, **rtws (runtime workspace)** refers to the runtime root directory Dominds uses (by default the directory where `dominds` is launched, switchable via `-C <dir>`). Relative `-C` paths are resolved against the original launch directory by the `dominds` supervisor before the runner starts.
|
|
8
|
+
|
|
9
|
+
> Process model: in production, `dominds` is a lightweight supervisor. It parses global options such as `-C`, starts `dominds-runner` in the resolved rtws, keeps the terminal stdio attached to the runner, and restarts long-running WebUI runners after crashes with exponential backoff starting at 1 second and capped at 30 minutes. Self-update restarts are coordinated by this supervisor, so the old runner can fully exit and release server resources before the new runner starts; if the old runner does not exit after a restart request, the supervisor terminates it before starting the next runner. Development WebUI runs (`NODE_ENV=dev` or `--mode dev`, including `dev-server.sh`) bypass the supervisor and are managed by the development launcher instead.
|
|
8
10
|
|
|
9
11
|
> Note: `dominds tui` / `dominds run` are currently reserved subcommand names and do not have a stable implementation yet. As a result, this guide does not document TUI options or detailed usage.
|
|
10
12
|
|
|
@@ -58,8 +60,7 @@ dominds read [options] [member-id]
|
|
|
58
60
|
|
|
59
61
|
# Certificate tools: create/inspect local HTTPS certificates
|
|
60
62
|
dominds cert create [--host <host>] [--days <days>] [--force]
|
|
61
|
-
dominds cert
|
|
62
|
-
dominds cert status --host <host> [--port <port>] [--origin]
|
|
63
|
+
dominds cert status [--host <host>] [--port <port>] [--origin]
|
|
63
64
|
|
|
64
65
|
# rtws creation: scaffold a new runtime workspace
|
|
65
66
|
dominds create <template> [directory]
|
|
@@ -90,7 +91,7 @@ Start the web-based user interface for the current rtws. This provides a graphic
|
|
|
90
91
|
|
|
91
92
|
- `-p, --port <port>` - Port to listen on; a bare port binds strictly, suffix `+` tries higher ports, and suffix `-` tries lower ports (omitting `--port` is equivalent to `5666-`)
|
|
92
93
|
- `-h, --host <host>` - Host to bind to (default: localhost)
|
|
93
|
-
- `-C, --cwd <
|
|
94
|
+
- `-C, --cwd <dir>` - Change to rtws directory before starting; relative paths are resolved against the original launch directory
|
|
94
95
|
- `--help` - Show help message
|
|
95
96
|
|
|
96
97
|
**Examples:**
|
|
@@ -100,6 +101,7 @@ dominds
|
|
|
100
101
|
dominds webui -p 8080
|
|
101
102
|
dominds webui -p 8080+
|
|
102
103
|
dominds webui -C /path/to/my-rtws
|
|
104
|
+
dominds -C ux-rtws webui
|
|
103
105
|
```
|
|
104
106
|
|
|
105
107
|
**Common use cases:**
|
|
@@ -129,7 +131,7 @@ Read and inspect agent prompts/configuration for the rtws. This is commonly used
|
|
|
129
131
|
|
|
130
132
|
**Options:**
|
|
131
133
|
|
|
132
|
-
- `-C, --cwd <
|
|
134
|
+
- `-C, --cwd <dir>` - Change to rtws directory before reading; relative paths are resolved against the original launch directory
|
|
133
135
|
- `--only-prompt` - Show only system prompts
|
|
134
136
|
- `--only-mem` - Show only memory
|
|
135
137
|
- `--help` - Show help message
|
|
@@ -148,8 +150,7 @@ dominds read --only-mem
|
|
|
148
150
|
|
|
149
151
|
```bash
|
|
150
152
|
dominds cert create [--host <host>] [--days <days>] [--force]
|
|
151
|
-
dominds cert
|
|
152
|
-
dominds cert status --host <host> [--port <port>] [--origin]
|
|
153
|
+
dominds cert status [--host <host>] [--port <port>] [--origin]
|
|
153
154
|
```
|
|
154
155
|
|
|
155
156
|
Create or inspect local HTTPS certificates for the Dominds WebUI. Certificates live in `~/.dominds/certs/` and match DNS/IP hostnames, not ports; one certificate covers every WebUI port on that host.
|
|
@@ -167,11 +168,11 @@ Create or inspect local HTTPS certificates for the Dominds WebUI. Certificates l
|
|
|
167
168
|
```bash
|
|
168
169
|
dominds cert create
|
|
169
170
|
dominds cert create --host 192.168.1.10 --host my-host.local
|
|
170
|
-
dominds cert status
|
|
171
|
-
dominds cert status --
|
|
171
|
+
dominds cert status
|
|
172
|
+
dominds cert status --port 5666 --origin
|
|
172
173
|
```
|
|
173
174
|
|
|
174
|
-
`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.
|
|
175
|
+
`localhost`, `loopback`, `127.0.0.0/8`, `169.254.0.0/16`, `::1`, `fe80::/10`, `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.
|
|
175
176
|
|
|
176
177
|
### rtws Creation
|
|
177
178
|
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
`dominds` 提供统一的命令行入口,但**主要交互界面是 Web UI**(默认命令 `dominds`)。本文档以 Web UI 工作流为主。
|
|
6
6
|
|
|
7
|
-
> 注:本文统一使用 **rtws(运行时工作区)** 表示 Dominds
|
|
7
|
+
> 注:本文统一使用 **rtws(运行时工作区)** 表示 Dominds 运行时使用的根目录(默认是启动 `dominds` 时所在目录,可通过 `-C <dir>` 切换)。相对路径形式的 `-C` 由 `dominds` supervisor 按原始启动目录解析为绝对路径,再启动 runner。
|
|
8
|
+
|
|
9
|
+
> 进程模型:生产模式下,`dominds` 是轻量 supervisor,负责解析 `-C` 等全局选项、在解析后的 rtws 中启动 `dominds-runner`、让 runner 继承当前终端 stdio,并在长期运行的 WebUI runner 崩溃后用指数退避保活重启(初始 1 秒,最长 30 分钟)。self-update 重启也由 supervisor 协调,因此旧 runner 可以完整退出并释放 server 资源,再启动新版 runner;如果旧 runner 在发出重启请求后仍不退出,supervisor 会终止它再启动下一轮 runner。开发模式 WebUI(`NODE_ENV=dev` 或 `--mode dev`,包括 `dev-server.sh`)不走 supervisor,由开发启动器自行管理。
|
|
8
10
|
|
|
9
11
|
> 说明:`dominds tui` / `dominds run` 相关功能目前尚未提供稳定实现(子命令名保留用于未来规划),因此本指南不再展开 TUI 的命令选项与用法细节。
|
|
10
12
|
|
|
@@ -58,8 +60,7 @@ dominds read [options] [member-id]
|
|
|
58
60
|
|
|
59
61
|
# 证书工具:创建/检查本机 HTTPS 证书
|
|
60
62
|
dominds cert create [--host <host>] [--days <days>] [--force]
|
|
61
|
-
dominds cert
|
|
62
|
-
dominds cert status --host <host> [--port <port>] [--origin]
|
|
63
|
+
dominds cert status [--host <host>] [--port <port>] [--origin]
|
|
63
64
|
|
|
64
65
|
# rtws 创建:搭建新项目/运行时工作区
|
|
65
66
|
dominds create <template> [directory]
|
|
@@ -90,7 +91,7 @@ dominds webui [options]
|
|
|
90
91
|
|
|
91
92
|
- `-p, --port <port>` - 监听端口;裸端口严格绑定,后缀 `+` 向更大端口自动尝试,后缀 `-` 向更小端口自动尝试(未指定时等价于 `5666-`)
|
|
92
93
|
- `-h, --host <host>` - 绑定的主机(默认:localhost)
|
|
93
|
-
- `-C, --cwd <
|
|
94
|
+
- `-C, --cwd <dir>` - 启动前更改 rtws 目录;相对路径按原始启动目录解析
|
|
94
95
|
- `--help` - 显示帮助消息
|
|
95
96
|
|
|
96
97
|
**示例:**
|
|
@@ -107,6 +108,7 @@ dominds webui -p 8080+
|
|
|
107
108
|
|
|
108
109
|
# 在特定 rtws 启动 Web UI
|
|
109
110
|
dominds webui -C /path/to/my-rtws
|
|
111
|
+
dominds -C ux-rtws webui
|
|
110
112
|
```
|
|
111
113
|
|
|
112
114
|
**常见用途:**
|
|
@@ -136,7 +138,7 @@ dominds read [options] [member-id]
|
|
|
136
138
|
|
|
137
139
|
**选项:**
|
|
138
140
|
|
|
139
|
-
- `-C, --cwd <
|
|
141
|
+
- `-C, --cwd <dir>` - 读取前更改 rtws 目录;相对路径按原始启动目录解析
|
|
140
142
|
- `--only-prompt` - 仅显示系统提示词
|
|
141
143
|
- `--only-mem` - 仅显示内存
|
|
142
144
|
- `--help` - 显示帮助消息
|
|
@@ -155,8 +157,7 @@ dominds read --only-mem
|
|
|
155
157
|
|
|
156
158
|
```bash
|
|
157
159
|
dominds cert create [--host <host>] [--days <days>] [--force]
|
|
158
|
-
dominds cert
|
|
159
|
-
dominds cert status --host <host> [--port <port>] [--origin]
|
|
160
|
+
dominds cert status [--host <host>] [--port <port>] [--origin]
|
|
160
161
|
```
|
|
161
162
|
|
|
162
163
|
创建或检查 Dominds WebUI 的本机 HTTPS 证书。证书保存在 `~/.dominds/certs/`,按 DNS/IP 主机名匹配,不绑定端口;同一张证书可覆盖该主机上的所有 WebUI 端口。
|
|
@@ -174,11 +175,11 @@ dominds cert status --host <host> [--port <port>] [--origin]
|
|
|
174
175
|
```bash
|
|
175
176
|
dominds cert create
|
|
176
177
|
dominds cert create --host 192.168.1.10 --host my-host.local
|
|
177
|
-
dominds cert status
|
|
178
|
-
dominds cert status --
|
|
178
|
+
dominds cert status
|
|
179
|
+
dominds cert status --port 5666 --origin
|
|
179
180
|
```
|
|
180
181
|
|
|
181
|
-
`localhost`、`loopback`、`127.0.0.0/8`、`::1`、`0.0.0.0`、`::` 不会作为 HTTPS 证书主机。`0.0.0.0` / `::` 只表示绑定所有地址,匹配证书时会使用检测到的非 loopback LAN 主机。
|
|
182
|
+
`localhost`、`loopback`、`127.0.0.0/8`、`169.254.0.0/16`、`::1`、`fe80::/10`、`0.0.0.0`、`::` 不会作为 HTTPS 证书主机。`0.0.0.0` / `::` 只表示绑定所有地址,匹配证书时会使用检测到的非 loopback LAN 主机。
|
|
182
183
|
|
|
183
184
|
### rtws 创建
|
|
184
185
|
|
|
@@ -4,7 +4,7 @@ Chinese version: [中文版](./dialog-persistence.zh.md)
|
|
|
4
4
|
|
|
5
5
|
This document describes the persistence layer and storage mechanisms for the Dominds dialog system, including file system conventions, data structures, and storage patterns.
|
|
6
6
|
|
|
7
|
-
> Note: In this document, **rtws (runtime workspace)** refers to Dominds' runtime root directory (by default `
|
|
7
|
+
> Note: In this document, **rtws (runtime workspace)** refers to Dominds' runtime root directory (by default the directory where `dominds` is launched, switchable via `-C <dir>`; relative `-C` paths are resolved against the original launch directory).
|
|
8
8
|
|
|
9
9
|
## Current Implementation Status
|
|
10
10
|
|
|
@@ -264,8 +264,8 @@ Example / 示例(概念):
|
|
|
264
264
|
|
|
265
265
|
### rtws(运行时工作区)
|
|
266
266
|
|
|
267
|
-
- EN: **rtws** (runtime workspace) is the directory Dominds treats as its runtime root (by default it is `
|
|
268
|
-
- ZH: **rtws(运行时工作区)**是 Dominds
|
|
267
|
+
- EN: **rtws** (runtime workspace) is the directory Dominds treats as its runtime root (by default it is the directory where `dominds` is launched, and can be changed via `-C <dir>`; relative `-C` paths are resolved against the original launch directory). Files like `.minds/` and `.dialogs/` live under the rtws.
|
|
268
|
+
- ZH: **rtws(运行时工作区)**是 Dominds 运行时使用的根目录(默认是启动 `dominds` 时所在目录,可通过 `-C <dir>` 切换;相对路径形式的 `-C` 按原始启动目录解析)。诸如 `.minds/`、`.dialogs/` 等运行态目录均位于 rtws 下。
|
|
269
269
|
|
|
270
270
|
- EN: Wording rule: when the meaning is **rtws**, prefer writing “rtws (runtime workspace)” (or just “rtws” after the first mention) rather than the ambiguous generic “workspace”.
|
|
271
271
|
- ZH: 用词规则:当语义指向 **rtws** 时,优先写“rtws(运行时工作区)”(或在已定义后只写“rtws”),避免在对外提示/文档中只写“工作区”从而与其他语境的 workspace/workdir 混淆。
|
|
@@ -259,6 +259,10 @@ function resolveReminderContextFollowingDialogState(prompt, currentTurnDialogMsg
|
|
|
259
259
|
return 'none';
|
|
260
260
|
return prompt.origin === 'user' ? 'user_message' : 'runtime_notice';
|
|
261
261
|
}
|
|
262
|
+
function resolveReminderContextHealthState(snapshot) {
|
|
263
|
+
const remediationLevel = getContextHealthRemediationLevel(snapshot);
|
|
264
|
+
return remediationLevel === undefined ? 'normal' : remediationLevel;
|
|
265
|
+
}
|
|
262
266
|
async function resolveReminderContextFooterState(args) {
|
|
263
267
|
const latest = await persistence_1.DialogPersistence.loadDialogLatest(args.dlg.id, args.dlg.status);
|
|
264
268
|
const deferredReplyReassertion = latest?.deferredReplyReassertion;
|
|
@@ -273,6 +277,7 @@ async function resolveReminderContextFooterState(args) {
|
|
|
273
277
|
followingDialogState: resolveReminderContextFollowingDialogState(args.prompt, args.currentTurnDialogMsgsForContext),
|
|
274
278
|
pendingUserInterjectionReply,
|
|
275
279
|
interDialogReplyObligation,
|
|
280
|
+
contextHealthState: resolveReminderContextHealthState(args.dlg.getLastContextHealth()),
|
|
276
281
|
};
|
|
277
282
|
}
|
|
278
283
|
function splitDialogMsgsForReminderInsertion(args) {
|
|
@@ -715,8 +720,8 @@ const TELLASK_SPECIAL_VIRTUAL_TOOLS = [
|
|
|
715
720
|
},
|
|
716
721
|
];
|
|
717
722
|
const CONTEXT_HEALTH_TOOL_RESULT_VISIBLE_BYTE_LIMIT = 2000;
|
|
718
|
-
const CONTEXT_HEALTH_LARGE_TOOL_RETURN_UNAVAILABLE_ZH = '
|
|
719
|
-
const CONTEXT_HEALTH_LARGE_TOOL_RETURN_UNAVAILABLE_EN = 'This function returned too much content
|
|
723
|
+
const CONTEXT_HEALTH_LARGE_TOOL_RETURN_UNAVAILABLE_ZH = '这次函数返回内容太大,清理头脑之前不会显示给你。';
|
|
724
|
+
const CONTEXT_HEALTH_LARGE_TOOL_RETURN_UNAVAILABLE_EN = 'This function returned too much content. It will not be shown to you before you clear your mind.';
|
|
720
725
|
function getContextHealthRemediationLevel(snapshot) {
|
|
721
726
|
if (snapshot?.kind !== 'available') {
|
|
722
727
|
return undefined;
|
|
@@ -736,9 +741,9 @@ function formatContextHealthLargeToolReturnUnavailable(args) {
|
|
|
736
741
|
return [
|
|
737
742
|
CONTEXT_HEALTH_LARGE_TOOL_RETURN_UNAVAILABLE_ZH,
|
|
738
743
|
'',
|
|
739
|
-
'
|
|
744
|
+
'不要再尝试获取各种大段的输出,都不会显示给你。现在先做两件事:',
|
|
740
745
|
'1. 把需要回传给主线对话的结论、证据定位和风险整理清楚。',
|
|
741
|
-
'2.
|
|
746
|
+
'2. 对于下一程恢复工作需要的信息,写入提醒项。',
|
|
742
747
|
'',
|
|
743
748
|
'然后尽快完成当前支线回复;如果你有 clear_mind({}),再调用它开启新一程。',
|
|
744
749
|
'',
|
|
@@ -748,9 +753,9 @@ function formatContextHealthLargeToolReturnUnavailable(args) {
|
|
|
748
753
|
return [
|
|
749
754
|
CONTEXT_HEALTH_LARGE_TOOL_RETURN_UNAVAILABLE_ZH,
|
|
750
755
|
'',
|
|
751
|
-
'
|
|
752
|
-
'1.
|
|
753
|
-
'2.
|
|
756
|
+
'不要再尝试获取各种大段的输出,都不会显示给你。现在先做两件事:',
|
|
757
|
+
'1. 把下一程对话需要知道的此程细节信息写入差遣牒合适章节。',
|
|
758
|
+
'2. 对于不适合差遣牒章节覆盖、但下一程恢复工作需要的信息写入提醒项。',
|
|
754
759
|
'',
|
|
755
760
|
'然后调用 clear_mind({}) 开启新一程。',
|
|
756
761
|
'',
|
|
@@ -761,11 +766,11 @@ function formatContextHealthLargeToolReturnUnavailable(args) {
|
|
|
761
766
|
return [
|
|
762
767
|
CONTEXT_HEALTH_LARGE_TOOL_RETURN_UNAVAILABLE_EN,
|
|
763
768
|
'',
|
|
764
|
-
'Do not
|
|
765
|
-
'1. Organize the
|
|
766
|
-
'2.
|
|
769
|
+
'Do not try again to fetch any kind of large output; it still will not be shown. Do two things now:',
|
|
770
|
+
'1. Organize the conclusions, evidence pointers, and risks that need to go back to the Mainline dialog.',
|
|
771
|
+
'2. Write any details needed to resume the next course into reminders.',
|
|
767
772
|
'',
|
|
768
|
-
'Then finish the current
|
|
773
|
+
'Then finish the current Sideline dialog reply as soon as possible; if you have clear_mind({}), call it to start a new course.',
|
|
769
774
|
'',
|
|
770
775
|
`Detail: this return was about ${approxBytes} bytes.`,
|
|
771
776
|
].join('\n');
|
|
@@ -773,9 +778,9 @@ function formatContextHealthLargeToolReturnUnavailable(args) {
|
|
|
773
778
|
return [
|
|
774
779
|
CONTEXT_HEALTH_LARGE_TOOL_RETURN_UNAVAILABLE_EN,
|
|
775
780
|
'',
|
|
776
|
-
'Do not
|
|
777
|
-
'1. Write the
|
|
778
|
-
'2. Write
|
|
781
|
+
'Do not try again to fetch any kind of large output; it still will not be shown. Do two things now:',
|
|
782
|
+
'1. Write the details from this course that the next course needs into the appropriate Taskdoc sections.',
|
|
783
|
+
'2. Write information that does not fit a Taskdoc section, but is needed to resume the next course, into reminders.',
|
|
779
784
|
'',
|
|
780
785
|
'Then call clear_mind({}) to start a new course.',
|
|
781
786
|
'',
|
|
@@ -14,10 +14,12 @@ export declare function formatDiligenceAutoContinuePrompt(language: LanguageCode
|
|
|
14
14
|
export declare function formatReminderContextGuide(language: LanguageCode): string;
|
|
15
15
|
export type ReminderContextFollowingDialogState = 'user_message' | 'runtime_notice' | 'none';
|
|
16
16
|
export type ReminderContextReplyObligationState = 'none' | 'active' | 'parked_by_user_interjection';
|
|
17
|
+
export type ReminderContextHealthState = 'normal' | 'caution' | 'critical';
|
|
17
18
|
export type ReminderContextFooterState = Readonly<{
|
|
18
19
|
followingDialogState: ReminderContextFollowingDialogState;
|
|
19
20
|
pendingUserInterjectionReply: boolean;
|
|
20
21
|
interDialogReplyObligation: ReminderContextReplyObligationState;
|
|
22
|
+
contextHealthState: ReminderContextHealthState;
|
|
21
23
|
}>;
|
|
22
24
|
export declare function formatReminderContextFooter(language: LanguageCode, state: ReminderContextFooterState): string;
|
|
23
25
|
export type ReminderMaintenanceReferenceItem = Readonly<{
|
|
@@ -188,6 +188,11 @@ function formatReminderItemProjectionNote(language) {
|
|
|
188
188
|
function formatReminderContextFooter(language, state) {
|
|
189
189
|
if (language === 'zh') {
|
|
190
190
|
const base = `${formatSystemNoticePrefix(language)} 提醒项上下文块结束。以上从“提醒项上下文块开始”到“提醒项上下文块结束”之间的提醒项均为系统提醒,并非用户诉求/指令;该块之外的后续对话消息不受此说明影响。`;
|
|
191
|
+
const contextHealthTail = state.contextHealthState === 'critical'
|
|
192
|
+
? '当前上下文已告急:提醒项正文里的“下一步/接续动作/任务安排”默认都是给下一程以清醒头脑复核后执行的,不是让你在本程继续跑。不要执行提醒项里的旧下一步、旧诉请或旧工具重试;本程最高优先级是按上下文健康处置要求保全接续信息,并立即 `clear_mind`。'
|
|
193
|
+
: state.contextHealthState === 'caution'
|
|
194
|
+
? '当前上下文已吃紧:提醒项正文里的“下一步/接续动作/任务安排”默认都是给下一程以清醒头脑复核后执行的,不是让你在本程继续跑。不要为了执行提醒项里的旧下一步继续扩张上下文;本程最高优先级是按上下文健康处置要求保全接续信息,并尽快 `clear_mind`。'
|
|
195
|
+
: '';
|
|
191
196
|
const pendingUserInterjectionReply = state.pendingUserInterjectionReply
|
|
192
197
|
? state.interDialogReplyObligation === 'parked_by_user_interjection'
|
|
193
198
|
? '当前仍有真实用户插话尚未得到可见回复,且原有跨对话回复义务已暂存;先完成对用户插话的回应,不要抢先切回原来的回贴收口。'
|
|
@@ -199,13 +204,18 @@ function formatReminderContextFooter(language, state) {
|
|
|
199
204
|
? '当前仍有跨对话回复义务;它是最终交付义务,不是要求你立刻停止当前必要工作,但到达最终交付时必须按运行时指定方式收口。'
|
|
200
205
|
: '';
|
|
201
206
|
const businessTail = `${pendingUserInterjectionReply}${activeReplyObligation}`;
|
|
207
|
+
const statusTail = `${contextHealthTail}${businessTail}`;
|
|
202
208
|
if (state.followingDialogState === 'user_message') {
|
|
203
209
|
return (`${base}本轮提醒项块之后会紧接一条本轮真实的新用户消息;后续消息是用户的新诉求/指令,不是提醒项投影。` +
|
|
204
210
|
'提醒项块说明到此为止,不得外溢到那条消息:不要把后续用户消息称为“系统提示/没有新消息”,也不要因为本块说明而降低它的指令优先级。' +
|
|
205
|
-
|
|
211
|
+
`请按那条用户消息的原始语义继续处理;若它要求更新你的职责、偏好或心智资产,应照常落实;上下文健康处置要求仍按系统提示优先于普通任务动作。${statusTail}`);
|
|
206
212
|
}
|
|
207
213
|
if (state.followingDialogState === 'runtime_notice') {
|
|
208
|
-
return `${base}本轮提醒项块之后会接着出现一条运行时提示;它不是用户的新诉求/指令,请按其中的运行时要求继续推进。${
|
|
214
|
+
return `${base}本轮提醒项块之后会接着出现一条运行时提示;它不是用户的新诉求/指令,请按其中的运行时要求继续推进。${statusTail}`;
|
|
215
|
+
}
|
|
216
|
+
if (state.contextHealthState !== 'normal') {
|
|
217
|
+
return (`${base}本轮没有新的用户消息或运行时提示;这是工具调用后的自动续推。` +
|
|
218
|
+
`不要把“没有新消息”理解为空系统提示。${statusTail}`);
|
|
209
219
|
}
|
|
210
220
|
return (`${base}本轮没有新的用户消息或运行时提示;这是工具调用后的自动续推。` +
|
|
211
221
|
'请基于已有任务状态判断下一步:若已有明确、相关且有价值的动作,就继续执行;若当前确实只能等待外部结果或用户输入,不要为了避免“等待”而寻找无关小事。' +
|
|
@@ -214,6 +224,11 @@ function formatReminderContextFooter(language, state) {
|
|
|
214
224
|
const base = `${formatSystemNoticePrefix(language)} Reminder context block ends. The reminder items between ` +
|
|
215
225
|
'"Reminder context block begins" and "Reminder context block ends" are system reminders, ' +
|
|
216
226
|
'not user requests/instructions; this reminder-block guidance does not apply to subsequent dialog messages outside this block. ';
|
|
227
|
+
const contextHealthTail = state.contextHealthState === 'critical'
|
|
228
|
+
? 'Context health is critical: any "next step", continuation action, or task plan inside reminders is meant for the next course to review and run with a clear head, not for this course to keep executing. Do not perform old next steps, old inter-dialog requests, or old tool retries from reminders; this course must first preserve the continuation details required by the context-health guidance, then call `clear_mind` immediately. '
|
|
229
|
+
: state.contextHealthState === 'caution'
|
|
230
|
+
? 'Context health is tight: any "next step", continuation action, or task plan inside reminders is meant for the next course to review and run with a clear head, not for this course to keep executing. Do not expand context by performing old next steps from reminders; this course must first preserve the continuation details required by the context-health guidance, then call `clear_mind` soon. '
|
|
231
|
+
: '';
|
|
217
232
|
const pendingUserInterjectionReply = state.pendingUserInterjectionReply
|
|
218
233
|
? state.interDialogReplyObligation === 'parked_by_user_interjection'
|
|
219
234
|
? "There is still a real user interjection without a visible reply, and the earlier inter-dialog reply obligation is parked; finish answering the user's interjection first, and do not switch back to closing the earlier reply yet. "
|
|
@@ -225,13 +240,18 @@ function formatReminderContextFooter(language, state) {
|
|
|
225
240
|
? 'An inter-dialog reply obligation is still active; it is a final delivery obligation, not a demand to stop necessary current work immediately, but final delivery must close through the runtime-specified path. '
|
|
226
241
|
: '';
|
|
227
242
|
const businessTail = `${pendingUserInterjectionReply}${activeReplyObligation}`;
|
|
243
|
+
const statusTail = `${contextHealthTail}${businessTail}`;
|
|
228
244
|
if (state.followingDialogState === 'user_message') {
|
|
229
245
|
return (`${base}A real new user message for this round immediately follows this reminder block; the following message is a new user request/instruction, not a reminder projection. ` +
|
|
230
246
|
'The reminder-block guidance ends here and must not spill over onto that message: do not label the following user message as a "system notice" or "no new message", and do not lower its instruction priority because of this block. ' +
|
|
231
|
-
`Handle that user message according to its original meaning; if it asks you to update your responsibilities, preferences, or mind assets, carry that out normally. ${
|
|
247
|
+
`Handle that user message according to its original meaning; if it asks you to update your responsibilities, preferences, or mind assets, carry that out normally. Context-health remediation still takes system-guided priority over ordinary task actions. ${statusTail}`);
|
|
232
248
|
}
|
|
233
249
|
if (state.followingDialogState === 'runtime_notice') {
|
|
234
|
-
return `${base}A runtime notice follows this reminder block in this round; it is not a new user request/instruction, so follow that runtime guidance and continue the work. ${
|
|
250
|
+
return `${base}A runtime notice follows this reminder block in this round; it is not a new user request/instruction, so follow that runtime guidance and continue the work. ${statusTail}`;
|
|
251
|
+
}
|
|
252
|
+
if (state.contextHealthState !== 'normal') {
|
|
253
|
+
return (`${base}There is no new user message or runtime notice in this round; this is an automatic continuation after a tool call. ` +
|
|
254
|
+
`Do not interpret the absence of a new message as an empty system notice. ${statusTail}`);
|
|
235
255
|
}
|
|
236
256
|
return (`${base}There is no new user message or runtime notice in this round; this is an automatic continuation after a tool call. ` +
|
|
237
257
|
'Judge the next step from the existing task state: if there is a clear, relevant, valuable action, continue with it; if the work genuinely can only wait for an external result or user input, do not invent unrelated work just to avoid "waiting". ' +
|
|
@@ -224,7 +224,7 @@ function validateCertificateHost(host) {
|
|
|
224
224
|
if (!(0, network_hosts_1.isLanHttpsHost)(host)) {
|
|
225
225
|
return {
|
|
226
226
|
kind: 'invalid',
|
|
227
|
-
message: '--host must not be localhost, loopback, 127.0.0.0/8, ::1, 0.0.0.0, or ::',
|
|
227
|
+
message: '--host must not be localhost, loopback, 127.0.0.0/8, 169.254.0.0/16, ::1, fe80::/10, 0.0.0.0, or ::',
|
|
228
228
|
};
|
|
229
229
|
}
|
|
230
230
|
if (net.isIP(host) !== 0)
|
|
@@ -15,14 +15,11 @@ const promises_1 = __importDefault(require("fs/promises"));
|
|
|
15
15
|
const path_1 = __importDefault(require("path"));
|
|
16
16
|
const time_1 = require("@longrun-ai/kernel/utils/time");
|
|
17
17
|
const log_1 = require("../log");
|
|
18
|
+
const supervisor_protocol_1 = require("../supervisor-protocol");
|
|
18
19
|
const dominds_running_version_1 = require("./dominds-running-version");
|
|
19
20
|
const log = (0, log_1.createLogger)('dominds-self-update');
|
|
20
21
|
const BACKGROUND_CHECK_INTERVAL_MS = 30 * 60 * 1000;
|
|
21
22
|
const LATEST_VERSION_CHECK_TIMEOUT_MS = 60000;
|
|
22
|
-
const RESTART_PORT_RELEASE_TIMEOUT_MS = 15000;
|
|
23
|
-
const RESTART_PORT_PROBE_INTERVAL_MS = 150;
|
|
24
|
-
const RESTART_EXIT_GRACE_MS = 1000;
|
|
25
|
-
const RESTART_FORCE_KILL_AFTER_MS = 30000;
|
|
26
23
|
const COMMAND_OUTPUT_LOG_LIMIT = 2000;
|
|
27
24
|
const PROXY_URL_ENV_KEYS = new Set([
|
|
28
25
|
'HTTP_PROXY',
|
|
@@ -34,7 +31,6 @@ const PROXY_URL_ENV_KEYS = new Set([
|
|
|
34
31
|
]);
|
|
35
32
|
const IDLE_RESTART_STATE = { kind: 'idle' };
|
|
36
33
|
const PROCESS_START_ARGV = [...process.argv];
|
|
37
|
-
const PROCESS_START_EXEC_ARGV = [...process.execArgv];
|
|
38
34
|
const PROCESS_START_CWD = process.cwd();
|
|
39
35
|
let runtimeConfig = null;
|
|
40
36
|
let latestObservation = { kind: 'unknown' };
|
|
@@ -86,19 +82,6 @@ function detectRunKind(mode) {
|
|
|
86
82
|
}
|
|
87
83
|
return 'global';
|
|
88
84
|
}
|
|
89
|
-
function hasInteractiveConsole() {
|
|
90
|
-
return Boolean(process.stdin.isTTY || process.stdout.isTTY || process.stderr.isTTY);
|
|
91
|
-
}
|
|
92
|
-
function getRestartHelperStdio() {
|
|
93
|
-
return hasInteractiveConsole() ? 'inherit' : 'ignore';
|
|
94
|
-
}
|
|
95
|
-
function getRestartPortProbeHost(host) {
|
|
96
|
-
if (host === '0.0.0.0')
|
|
97
|
-
return '127.0.0.1';
|
|
98
|
-
if (host === '::')
|
|
99
|
-
return '::1';
|
|
100
|
-
return host;
|
|
101
|
-
}
|
|
102
85
|
function normalizeComparablePath(value) {
|
|
103
86
|
const normalized = path_1.default.normalize(value);
|
|
104
87
|
return process.platform === 'win32' ? normalized.toLowerCase() : normalized;
|
|
@@ -118,9 +101,6 @@ function buildRestartTraceContext() {
|
|
|
118
101
|
].join('-'));
|
|
119
102
|
return { debugDir, traceFile };
|
|
120
103
|
}
|
|
121
|
-
function getRestartHelperEntrypoint() {
|
|
122
|
-
return path_1.default.resolve(__dirname, 'dominds-self-update-restart-helper.js');
|
|
123
|
-
}
|
|
124
104
|
async function appendRestartTrace(trace, event, details = {}) {
|
|
125
105
|
const payload = {
|
|
126
106
|
...details,
|
|
@@ -170,13 +150,6 @@ function getCurrentProcessEntrypoint() {
|
|
|
170
150
|
}
|
|
171
151
|
return entrypoint;
|
|
172
152
|
}
|
|
173
|
-
function buildCurrentProcessRestartArgs() {
|
|
174
|
-
getCurrentProcessEntrypoint();
|
|
175
|
-
return [...PROCESS_START_EXEC_ARGV, ...PROCESS_START_ARGV.slice(1)];
|
|
176
|
-
}
|
|
177
|
-
function buildCurrentDomindsCliArgs() {
|
|
178
|
-
return PROCESS_START_ARGV.slice(2);
|
|
179
|
-
}
|
|
180
153
|
function getNpxWorkspaceDirAbs() {
|
|
181
154
|
const entrypoint = getCurrentProcessEntrypoint().replace(/\\/g, '/');
|
|
182
155
|
const marker = '/node_modules/dominds/';
|
|
@@ -223,28 +196,12 @@ async function readNpxDomindsSpec() {
|
|
|
223
196
|
}
|
|
224
197
|
return null;
|
|
225
198
|
}
|
|
226
|
-
async function buildNpxLatestRestartLaunchSpec() {
|
|
227
|
-
const npm = await resolveNpmCommandSpec();
|
|
228
|
-
return {
|
|
229
|
-
command: npm.command,
|
|
230
|
-
args: [...npm.args, 'exec', '-y', '--', 'dominds@latest', ...buildCurrentDomindsCliArgs()],
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
function buildCurrentProcessRestartLaunchSpec() {
|
|
234
|
-
return {
|
|
235
|
-
command: process.execPath,
|
|
236
|
-
args: buildCurrentProcessRestartArgs(),
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
199
|
function truncateCommandOutput(value) {
|
|
240
200
|
const raw = typeof value === 'string' ? value.trim() : '';
|
|
241
201
|
if (raw.length <= COMMAND_OUTPUT_LOG_LIMIT)
|
|
242
202
|
return raw;
|
|
243
203
|
return `${raw.slice(0, COMMAND_OUTPUT_LOG_LIMIT)}...[truncated ${raw.length - COMMAND_OUTPUT_LOG_LIMIT} chars]`;
|
|
244
204
|
}
|
|
245
|
-
function delayMs(ms) {
|
|
246
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
247
|
-
}
|
|
248
205
|
function formatPathEnvExcerpt(pathEnv) {
|
|
249
206
|
if (pathEnv === null || pathEnv.trim() === '')
|
|
250
207
|
return null;
|
|
@@ -1382,57 +1339,31 @@ async function installLatestDominds() {
|
|
|
1382
1339
|
publishStatusUpdateSoon();
|
|
1383
1340
|
return await getDomindsSelfUpdateStatus();
|
|
1384
1341
|
}
|
|
1385
|
-
async function
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
const
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
cwd:
|
|
1393
|
-
host:
|
|
1394
|
-
port:
|
|
1395
|
-
retiringPid: process.pid,
|
|
1396
|
-
forceKillAfterMs: RESTART_FORCE_KILL_AFTER_MS,
|
|
1397
|
-
probeIntervalMs: RESTART_PORT_PROBE_INTERVAL_MS,
|
|
1398
|
-
portReleaseTimeoutMs: RESTART_PORT_RELEASE_TIMEOUT_MS,
|
|
1399
|
-
stdioMode,
|
|
1342
|
+
async function requestSupervisorRestart(params) {
|
|
1343
|
+
if (typeof process.send !== 'function') {
|
|
1344
|
+
throw new Error('Dominds restart requires the dominds supervisor process; this runner has no supervisor IPC channel');
|
|
1345
|
+
}
|
|
1346
|
+
const cfg = assertRuntimeConfig();
|
|
1347
|
+
const message = {
|
|
1348
|
+
type: supervisor_protocol_1.DOMINDS_SUPERVISOR_RESTART_WEBUI,
|
|
1349
|
+
cwd: process.cwd(),
|
|
1350
|
+
host: cfg.host,
|
|
1351
|
+
port: cfg.port,
|
|
1400
1352
|
traceFile: params.trace.traceFile,
|
|
1401
1353
|
debugDir: params.trace.debugDir,
|
|
1354
|
+
currentVersion: params.currentVersion,
|
|
1355
|
+
targetVersion: params.targetVersion,
|
|
1356
|
+
runKind: params.runKind,
|
|
1402
1357
|
};
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
const helperPid = typeof helper.pid === 'number' ? helper.pid : null;
|
|
1411
|
-
const helperSpawned = new Promise((resolve, reject) => {
|
|
1412
|
-
helper.once('spawn', () => {
|
|
1413
|
-
appendRestartTraceSoon(params.trace, 'parent.helper_spawn_event', {
|
|
1414
|
-
helperPid,
|
|
1415
|
-
});
|
|
1416
|
-
resolve(helperPid);
|
|
1417
|
-
});
|
|
1418
|
-
helper.once('error', (error) => {
|
|
1419
|
-
appendRestartTraceSoon(params.trace, 'parent.helper_error_event', {
|
|
1420
|
-
message: error.message,
|
|
1421
|
-
stack: error.stack ?? null,
|
|
1422
|
-
});
|
|
1423
|
-
reject(error);
|
|
1424
|
-
});
|
|
1425
|
-
});
|
|
1426
|
-
helper.once('exit', (code, signal) => {
|
|
1427
|
-
appendRestartTraceSoon(params.trace, 'parent.helper_exit_event', {
|
|
1428
|
-
code,
|
|
1429
|
-
signal,
|
|
1358
|
+
await new Promise((resolve, reject) => {
|
|
1359
|
+
process.send?.(message, (error) => {
|
|
1360
|
+
if (error !== null) {
|
|
1361
|
+
reject(error);
|
|
1362
|
+
return;
|
|
1363
|
+
}
|
|
1364
|
+
resolve();
|
|
1430
1365
|
});
|
|
1431
1366
|
});
|
|
1432
|
-
if (stdioMode !== 'inherit') {
|
|
1433
|
-
helper.unref();
|
|
1434
|
-
}
|
|
1435
|
-
return await helperSpawned;
|
|
1436
1367
|
}
|
|
1437
1368
|
async function stopAndExitForRestart() {
|
|
1438
1369
|
const cfg = assertRuntimeConfig();
|
|
@@ -1444,7 +1375,6 @@ async function stopAndExitForRestart() {
|
|
|
1444
1375
|
await appendRestartTraceBestEffort(trace, 'parent.stop_and_exit.start', {
|
|
1445
1376
|
host: cfg.host,
|
|
1446
1377
|
port: cfg.port,
|
|
1447
|
-
exitGraceMs: RESTART_EXIT_GRACE_MS,
|
|
1448
1378
|
});
|
|
1449
1379
|
}
|
|
1450
1380
|
const stopPromise = cfg
|
|
@@ -1481,18 +1411,8 @@ async function stopAndExitForRestart() {
|
|
|
1481
1411
|
return undefined;
|
|
1482
1412
|
});
|
|
1483
1413
|
cfg.closeWebSocketClients();
|
|
1484
|
-
await
|
|
1485
|
-
if (!stopSettled) {
|
|
1486
|
-
log.warn('Exiting Dominds process before graceful HTTP server stop completed during restart', undefined, {
|
|
1487
|
-
host: cfg.host,
|
|
1488
|
-
port: cfg.port,
|
|
1489
|
-
graceMs: RESTART_EXIT_GRACE_MS,
|
|
1490
|
-
});
|
|
1491
|
-
}
|
|
1414
|
+
await stopPromise;
|
|
1492
1415
|
if (trace !== null) {
|
|
1493
|
-
if (stopSettled) {
|
|
1494
|
-
await stopPromise;
|
|
1495
|
-
}
|
|
1496
1416
|
await appendRestartTraceBestEffort(trace, 'parent.process_exit', {
|
|
1497
1417
|
host: cfg.host,
|
|
1498
1418
|
port: cfg.port,
|
|
@@ -1519,19 +1439,17 @@ async function restartDomindsIntoLatest() {
|
|
|
1519
1439
|
throw new Error('No restartable Dominds update is currently available');
|
|
1520
1440
|
}
|
|
1521
1441
|
const runKind = detectRunKind(cfg.mode);
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
if (previousRestartRequiredState !== null) {
|
|
1525
|
-
launchSpec = buildCurrentProcessRestartLaunchSpec();
|
|
1442
|
+
if (runKind === 'disabled') {
|
|
1443
|
+
throw new Error('Dominds restart requires a production run kind');
|
|
1526
1444
|
}
|
|
1527
|
-
|
|
1445
|
+
const previousRestartRequiredState = restartState.kind === 'restart_required' ? restartState : null;
|
|
1446
|
+
if (previousRestartRequiredState === null && runKind === 'npx') {
|
|
1528
1447
|
const npxSpec = await readNpxDomindsSpec();
|
|
1529
1448
|
if (npxSpec?.kind !== 'latest') {
|
|
1530
1449
|
throw new Error('Dominds npx restart requires launching Dominds with dominds@latest');
|
|
1531
1450
|
}
|
|
1532
|
-
launchSpec = await buildNpxLatestRestartLaunchSpec();
|
|
1533
1451
|
}
|
|
1534
|
-
else {
|
|
1452
|
+
else if (previousRestartRequiredState === null) {
|
|
1535
1453
|
throw new Error('Dominds restart requires a completed install or a restartable session');
|
|
1536
1454
|
}
|
|
1537
1455
|
restartState = { kind: 'restarting', targetVersion: status.targetVersion };
|
|
@@ -1544,29 +1462,23 @@ async function restartDomindsIntoLatest() {
|
|
|
1544
1462
|
runKind,
|
|
1545
1463
|
currentVersion: status.currentVersion,
|
|
1546
1464
|
targetVersion: status.targetVersion,
|
|
1547
|
-
launchCommand: launchSpec.command,
|
|
1548
|
-
launchArgs: launchSpec.args,
|
|
1549
1465
|
restartCwd,
|
|
1550
1466
|
host: cfg.host,
|
|
1551
1467
|
port: cfg.port,
|
|
1552
1468
|
traceFile: trace.traceFile,
|
|
1553
1469
|
});
|
|
1554
|
-
|
|
1555
|
-
command: launchSpec.command,
|
|
1556
|
-
args: launchSpec.args,
|
|
1557
|
-
cwd: restartCwd,
|
|
1558
|
-
host: cfg.host,
|
|
1559
|
-
port: cfg.port,
|
|
1470
|
+
await requestSupervisorRestart({
|
|
1560
1471
|
trace,
|
|
1472
|
+
runKind,
|
|
1473
|
+
currentVersion: status.currentVersion,
|
|
1474
|
+
targetVersion: status.targetVersion,
|
|
1561
1475
|
});
|
|
1562
|
-
await appendRestartTraceBestEffort(trace, 'parent.
|
|
1563
|
-
helperPid,
|
|
1476
|
+
await appendRestartTraceBestEffort(trace, 'parent.supervisor_restart_requested', {
|
|
1564
1477
|
retiringPid: process.pid,
|
|
1565
1478
|
host: cfg.host,
|
|
1566
1479
|
port: cfg.port,
|
|
1567
1480
|
});
|
|
1568
|
-
log.info('Dominds restart
|
|
1569
|
-
helperPid,
|
|
1481
|
+
log.info('Dominds supervisor restart requested', undefined, {
|
|
1570
1482
|
traceFile: trace.traceFile,
|
|
1571
1483
|
});
|
|
1572
1484
|
setImmediate(() => {
|