dominds 1.20.1 → 1.20.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.
@@ -102,13 +102,13 @@ providers:
102
102
  models:
103
103
  gpt-5.5:
104
104
  name: GPT-5.5
105
- optimal_max_tokens: 350000
105
+ optimal_max_tokens: 200000
106
106
  # Caution remediation reinjection cadence in generation turns (default: 10).
107
107
  caution_remediation_cadence_generations: 10
108
- context_length: 400000
108
+ context_length: 272000
109
109
  input_length: 272000
110
- output_length: 128000
111
- context_window: '400K'
110
+ output_length: 32768
111
+ context_window: '272K'
112
112
  gpt-5.4:
113
113
  name: GPT-5.4
114
114
  optimal_max_tokens: 200000
@@ -871,13 +871,13 @@ providers:
871
871
  models:
872
872
  gpt-5.5:
873
873
  name: GPT-5.5
874
- optimal_max_tokens: 350000
874
+ optimal_max_tokens: 200000
875
875
  # Caution remediation reinjection cadence in generation turns (default: 10).
876
876
  caution_remediation_cadence_generations: 10
877
- context_length: 1000000
878
- input_length: 1000000
879
- output_length: 128000
880
- context_window: '1M'
877
+ context_length: 272000
878
+ input_length: 272000
879
+ output_length: 32768
880
+ context_window: '272K'
881
881
  gpt-5.5-pro:
882
882
  name: GPT-5.5 Pro
883
883
  optimal_max_tokens: 600000
@@ -234,6 +234,25 @@ function isOpenAiLikeRejectedFailure(error) {
234
234
  const status = readErrorStatus(error);
235
235
  return isHighConfidenceRejectedStatus(status);
236
236
  }
237
+ function isOpenAiLikeContextWindowRejectedFailure(args) {
238
+ if (args.lowerCode === 'context_length_exceeded') {
239
+ return true;
240
+ }
241
+ if (args.lowerMessage.includes('context window') &&
242
+ (args.lowerMessage.includes('exceeds') || args.lowerMessage.includes('exceeded'))) {
243
+ return true;
244
+ }
245
+ if (args.lowerMessage.includes('context limit exceeded')) {
246
+ return true;
247
+ }
248
+ if (args.lowerMessage.includes('maximum context length')) {
249
+ return true;
250
+ }
251
+ if (args.lowerMessage.includes('context_length_exceeded')) {
252
+ return true;
253
+ }
254
+ return args.lowerMessage.includes('too many tokens') && args.lowerMessage.includes('context');
255
+ }
237
256
  function isOpenAiLikeRateLimitFailure(error) {
238
257
  const lowerMessage = buildFailureMessage(error).toLowerCase();
239
258
  const status = readErrorStatus(error);
@@ -267,7 +286,9 @@ function classifyOpenAiLikeFailure(error) {
267
286
  const lowerMessage = message.toLowerCase();
268
287
  const status = readErrorStatus(error);
269
288
  const code = readErrorCode(error);
270
- if (isOpenAiLikeRejectedFailure(error)) {
289
+ const lowerCode = typeof code === 'string' ? code.trim().toLowerCase() : undefined;
290
+ if (isOpenAiLikeRejectedFailure(error) ||
291
+ isOpenAiLikeContextWindowRejectedFailure({ lowerMessage, lowerCode })) {
271
292
  return {
272
293
  kind: 'rejected',
273
294
  message,
@@ -4709,7 +4709,7 @@ class DialogPersistence {
4709
4709
  genseq,
4710
4710
  content,
4711
4711
  };
4712
- await this.appendEvent(dialog.id, course, ev, dialog.status);
4712
+ await this.appendEvent(dialog.id, course, attachRootGenerationRef(dialog, ev), dialog.status);
4713
4713
  }
4714
4714
  /**
4715
4715
  * Capture the current byte offset of a course JSONL file.
@@ -371,7 +371,7 @@ function getCtrlMessages(language) {
371
371
  tooManyArgsChangeMind: '参数格式不对。用法:change_mind({ selector: string, category?: string, content: string })',
372
372
  invalidFormatMindMore: '参数格式不对。用法:mind_more({ items: string[], sep?: string, selector?: string, category?: string })(selector 默认 progress)',
373
373
  mindMoreItemsRequired: '需要提供要追加的条目(items),且每一项都必须是非空字符串。\n' +
374
- '示例:mind_more({"items":["- 下一步:复核验证结果","- 阻塞:无"]})',
374
+ '示例:mind_more({"items":["- 下一步:复核验证结果(详见 <文档路径>#<章节>)","- 阻塞:等待 API 验收口径确认"]})',
375
375
  invalidFormatRecallTaskdoc: '参数格式不对。用法:recall_taskdoc({ category: string, selector: string })',
376
376
  taskDocContentRequired: '需要提供差遣牒内容(content)。\n' +
377
377
  '示例:\n' +
@@ -408,7 +408,7 @@ function getCtrlMessages(language) {
408
408
  tooManyArgsChangeMind: 'Error: Invalid args. Use: change_mind({ selector: string, category?: string, content: string })',
409
409
  invalidFormatMindMore: 'Error: Invalid args. Use: mind_more({ items: string[], sep?: string, selector?: string, category?: string }) (selector defaults to progress).',
410
410
  mindMoreItemsRequired: 'Error: items are required, and every item must be a non-empty string.\n' +
411
- 'Example: mind_more({"items":["- Next: review verification results","- Blocker: none"]})',
411
+ 'Example: mind_more({"items":["- Next: review verification results (details: <doc-path>#<section>)","- Blocker: API acceptance criteria pending"]})',
412
412
  invalidFormatRecallTaskdoc: 'Error: Invalid args. Use: recall_taskdoc({ category: string, selector: string })',
413
413
  taskDocContentRequired: 'Error: Taskdoc content is required (content).\n' +
414
414
  'Copy/paste example:\n' +
@@ -1016,6 +1016,7 @@ exports.recallTaskdocTool = {
1016
1016
  ? `\n\n⚠️ 已截断:内容过大(${bytes} bytes),仅回显前 ${maxSize} bytes。`
1017
1017
  : `\n\n⚠️ Truncated: content is too large (${bytes} bytes); showing first ${maxSize} bytes.`
1018
1018
  : '';
1019
- return (0, tool_1.toolSuccess)(`**recall_taskdoc:** \`${relPath}\`\n\n---\n${clipped}\n---${note}`);
1019
+ const closingSeparatorPrefix = clipped.endsWith('\n') ? '' : '\n';
1020
+ return (0, tool_1.toolSuccess)(`**recall_taskdoc:** \`${relPath}\`\n\n---\n${clipped}${closingSeparatorPrefix}---${note}`);
1020
1021
  },
1021
1022
  };
@@ -77,6 +77,8 @@ Taskdoc is a **task contract** and the task's **team-shared source of current tr
77
77
  - Does not reset dialog rounds
78
78
  - Changes visible to all teammates
79
79
  - When writing `progress`, assume teammates will skim it to synchronize on the current task truth rather than read your private process log
80
+ - Do not keep blindly calling `mind_more` until `progress` becomes a chronology; when the bulletin board starts accumulating duplicates, stale entries, or noisy history, use `change_mind` to condense it around facts that are still effective now
81
+ - Detailed investigations, long logs, full plans, acceptance records, and expanded rationale belong in formal rtws documentation; Taskdoc should keep only the key point, current conclusion, next step, and a location pointer such as path/section/command
80
82
 
81
83
  ## Tool Overview
82
84
 
@@ -129,8 +131,10 @@ Taskdoc is a **task contract** and the task's **team-shared source of current tr
129
131
  - Keep concise: reminders are often 1-3 items; prefer `update_reminder` to compress/merge
130
132
  - Separate carriers: information that must synchronize the team's current effective state, key decisions, next steps, or still-active blockers belongs in `progress`, the quasi-real-time task bulletin board; reminders keep local resume details
131
133
  - Team-facing: keep `progress` scannable and centered on what is still effective now; do not let it degrade into a personal log, raw chronology, scratchpad, or stale history pile. Use `mind_more` for small additions and `change_mind` when cleanup/reordering/compression is needed
134
+ - Condense when needed: `mind_more` is not the default bookkeeping move. If one topic already has several phase notes, prefer `change_mind` to merge them into the current summary; put the detailed expansion in formal rtws documentation and keep a document pointer in Taskdoc
132
135
  - Collapse before clearing: the Main Dialog first records undocumented discussion details the next course needs to know into the appropriate Taskdoc sections, then creates a structured continuation-package reminder; a Side Dialog must not maintain Taskdoc or draft Taskdoc update proposals, and should directly maintain sufficiently detailed continuation-package reminders. If the current course is already under system remediation, rough multi-reminder carry-over is acceptable but must be reconciled first in the new course
133
136
  - Avoid raw-material dumps: do not paste long logs or large tool outputs into reminders
137
+ - Documentation layering: Taskdoc says “what the team should sync on / do next now”; formal rtws documentation carries “why, how, detailed evidence, and the full process”. When Taskdoc references formal rtws documentation, use a stable path/section name/relevant command instead of copying the full content
134
138
 
135
139
  ### 4. What Belongs in `progress`
136
140
 
@@ -139,16 +143,18 @@ Taskdoc is a **task contract** and the task's **team-shared source of current tr
139
143
  - blockers that are confirmed and still active
140
144
  - the next step the team should currently align on
141
145
  - completed stage closures and remaining gaps
146
+ - a short summary of content already written to formal rtws documentation, plus a pointer to that document
142
147
  - Poor fits for `progress`:
143
148
  - “I just read file X”
144
149
  - “I might try a small idea next”
145
150
  - scratch notes only useful to the current speaker
146
151
  - historical traces whose current validity is unclear
152
+ - detailed expansions, long logs, full plans, or acceptance-record text that belongs in formal rtws documentation
147
153
 
148
154
  ## Limitations and Notes
149
155
 
150
156
  1. `dialog` reminders end with the dialog; `personal` reminders stay visible in all later dialogs you lead
151
- 2. Use `mind_more` for small Taskdoc additions; use `change_mind` for full-section replacement and merge existing content first
157
+ 2. Use `mind_more` for small Taskdoc additions; use `change_mind` for full-section replacement and merge existing content first. Do not treat `mind_more` as a chronology tool; when cleanup, stale-entry removal, or same-topic consolidation is needed, use `change_mind`
152
158
  3. `mind_more` / `change_mind` do not reset dialog rounds
153
159
  4. A continuation-package reminder should keep only details still not covered by Taskdoc but easy to lose during resume; in the Main Dialog, undocumented discussion details from current dialog history that the next course needs to know should be written to the appropriate Taskdoc sections first; in a Side Dialog under caution/critical remediation, maintain sufficiently detailed continuation-package reminders only
154
160
  5. Do not turn `personal` reminders into a long-term fact dump; move durable knowledge into `personal_memory`
@@ -117,21 +117,23 @@ replyTellaskBack({
117
117
 
118
118
  ### Scenario Description
119
119
 
120
- Announce the current effective state, key decisions, next step, and still-active blockers to the whole team rather than writing a private chronology.
120
+ Announce the current effective state, key decisions, next step, and still-active blockers to the whole team rather than writing a private chronology. If details have been organized into formal rtws documentation, `progress` should keep only the summary and document pointer.
121
121
 
122
122
  ### Example
123
123
 
124
124
  ```typescript
125
125
  // Small additions that are still effective now
126
126
  mind_more({
127
- items: ['- Next: verify control / team_mgmt manuals and tests are aligned'],
127
+ items: [
128
+ '- Next: verify control / team_mgmt manuals and tests are aligned (details: <doc-path>#<section>)',
129
+ ],
128
130
  });
129
131
 
130
- // Full-section replacement when cleanup, reordering, or compression is needed
132
+ // Full-section replacement when cleanup, reordering, same-topic consolidation, or chronology compression is needed
131
133
  change_mind({
132
134
  selector: 'progress',
133
135
  content:
134
- '## Progress\n\n### Current Effective State\n- The memory-carrier boundary cleanup is complete; next we strengthen the Taskdoc bulletin-board semantics\n\n### Decisions In Effect\n- `personal_memory` is no longer treated as a short-term junk drawer\n- `team_memory` now carries only long-lived team conventions and invariants\n\n### Next Step\n- Add stronger `progress` bulletin-board guidance in control / team_mgmt manuals\n\n### Still-Active Blockers\n- None',
136
+ '## Progress\n\n### Current Effective State\n- The memory-carrier boundary cleanup is complete; next we strengthen the Taskdoc bulletin-board semantics; details: <doc-path>#<section>\n\n### Decisions In Effect\n- `personal_memory` is no longer treated as a short-term junk drawer\n- `team_memory` now carries only long-lived team conventions and invariants\n\n### Next Step\n- Add stronger `progress` bulletin-board guidance in control / team_mgmt manuals\n\n### Still-Active Blockers\n- None',
135
137
  });
136
138
  ```
137
139
 
@@ -193,7 +195,7 @@ recall_taskdoc({
193
195
 
194
196
  ### Scenario Description
195
197
 
196
- Maintain taskdoc integrity and consistency, and keep `progress` as a team-scannable current-truth snapshot.
198
+ Maintain taskdoc integrity and consistency, and keep `progress` as a team-scannable current-truth snapshot; put detailed expansion in formal rtws documentation and keep only the summary plus location pointer in Taskdoc.
197
199
 
198
200
  ### Example
199
201
 
@@ -202,6 +204,6 @@ Maintain taskdoc integrity and consistency, and keep `progress` as a team-scanna
202
204
  change_mind({
203
205
  selector: 'progress',
204
206
  content:
205
- '## Progress\n\n### Current Effective State\n- The boundary wording has been propagated into handbook sources and tests\n\n### Decisions In Effect\n- role assets / personal_memory / team_memory / Taskdoc-progress / reminders now have separated responsibilities\n\n### Next Step\n- Re-verify control manual wording, Taskdoc display text, and boundary tests\n\n### Still-Active Blockers\n- None',
207
+ '## Progress\n\n### Current Effective State\n- The boundary wording has been propagated into handbook sources and tests; details: <doc-path>#<section>\n\n### Decisions In Effect\n- role assets / personal_memory / team_memory / Taskdoc-progress / reminders now have separated responsibilities\n\n### Next Step\n- Re-verify control manual wording, Taskdoc display text, and boundary tests\n\n### Still-Active Blockers\n- None',
206
208
  });
207
209
  ```
@@ -175,7 +175,10 @@ Append entries to a Taskdoc section; defaults to `progress`, reducing full-secti
175
175
 
176
176
  ```typescript
177
177
  mind_more({
178
- items: ['- Next: review verification results', '- Blocker: none'],
178
+ items: [
179
+ '- Next: review verification results (details: <doc-path>#<section>)',
180
+ '- Blocker: API acceptance criteria pending',
181
+ ],
179
182
  });
180
183
  ```
181
184
 
@@ -183,7 +186,9 @@ mind_more({
183
186
 
184
187
  - Append-only: it does not deduplicate, rewrite, or compress old content
185
188
  - Good for adding one or two still-effective states, decisions, next steps, or blockers to `progress`
189
+ - Not for appending every investigation step, long log, full plan, or acceptance record as a chronology; those details belong in formal rtws documentation, while Taskdoc keeps the summary and document pointer
186
190
  - If stale entries must be removed, reordered, or compressed, use `change_mind` for a full-section replacement
191
+ - When one topic already has several phase notes, prefer `change_mind` to merge them into a concise current announcement instead of continuing to call `mind_more`
187
192
 
188
193
  ### 7. recall_taskdoc
189
194
 
@@ -257,7 +262,9 @@ update_reminder({
257
262
 
258
263
  ```typescript
259
264
  mind_more({
260
- items: ['- Next: strengthen the bulletin-board semantics of Taskdoc `progress`'],
265
+ items: [
266
+ '- Next: strengthen the bulletin-board semantics of Taskdoc `progress` (details: <doc-path>#<section>)',
267
+ ],
261
268
  });
262
269
  ```
263
270
 
@@ -267,7 +274,7 @@ mind_more({
267
274
  change_mind({
268
275
  selector: 'progress',
269
276
  content:
270
- '## Progress\n\n### Current Effective State\n- The handbook boundary split is now agreed: role assets / personal long-lived experience / Taskdoc-progress / reminders\n\n### Decisions In Effect\n- `persona / knowhow / pitfalls` no longer absorb daily member experience\n- `personal_memory` is reserved for one member\\'s reusable long-lived experience\n\n### Next Step\n- Strengthen the bulletin-board semantics of Taskdoc `progress`\n\n### Still-Active Blockers\n- None',
277
+ '## Progress\n\n### Current Effective State\n- The handbook boundary split is now agreed: role assets / personal long-lived experience / Taskdoc-progress / reminders; details: <doc-path>#<section>\n\n### Decisions In Effect\n- `persona / knowhow / pitfalls` no longer absorb daily member experience\n- `personal_memory` is reserved for one member\\'s reusable long-lived experience\n\n### Next Step\n- Strengthen the bulletin-board semantics of Taskdoc `progress`\n\n### Still-Active Blockers\n- None',
271
278
  });
272
279
  ```
273
280
 
@@ -77,6 +77,8 @@
77
77
  - 不重置对话轮次
78
78
  - 变更对所有队友可见
79
79
  - 写入 `progress` 时,应默认假设全队成员会用它快速同步“当前任务真相”,而不是阅读你的个人过程记录
80
+ - 不要无脑连续使用 `mind_more` 把 `progress` 写成流水账;当公告牌开始堆积、重复或含过期信息时,用 `change_mind` 按当前仍有效的事实压缩整理
81
+ - 细节展开、调查过程、长日志、方案全文和验收记录应落进 rtws 正式文档;差遣牒只保留要点、当前结论、下一步,以及指向正式文档的路径/章节/命令等定位 pointer
80
82
 
81
83
  ## 工具概览
82
84
 
@@ -129,8 +131,10 @@
129
131
  - 保持简洁:默认提醒项常见 1–3 条,优先 `update_reminder` 压缩/合并
130
132
  - 区分载体:需要向全队同步的当前有效状态、关键决策、下一步与仍成立阻塞,写入 `progress` 这一准实时任务公告牌;提醒项只留个人/当前对话恢复所需细节
131
133
  - 面向全队:`progress` 应保持可扫读、以“当前仍有效”为准,不要退化成个人日志、流水账、临时便签或历史残影堆积;少量新增用 `mind_more`,需要清旧/重排/压缩时用 `change_mind`
134
+ - 按需整理:`mind_more` 不是默认记账动作。若同一主题已有多条阶段性记录,优先用 `change_mind` 合并成当前摘要;把细节放进 rtws 正式文档,并在差遣牒里保留文档定位 pointer
132
135
  - 换程前收束:主线对话先把尚未落实到文档、且下一程需要知会的讨论细节写入差遣牒合适章节,再整理结构化接续包提醒项;支线对话不要维护差遣牒,也不要整理差遣牒更新提案,直接维护足够详尽的接续包提醒项。若系统已把当前程切到吃紧/告急处置态,则先保留多条粗略提醒项过桥也可以;当前程只做落文档/保信息 + `clear_mind`(支线只做保信息 + `clear_mind`),系统真正开启新一程后第一步再收敛
133
136
  - 拒绝原料堆积:不要把长日志/大段 tool output 直接塞进提醒项
137
+ - 文档分层:差遣牒写“现在应如何同步/推进”,正式文档写“为什么、怎么做、详细证据和完整过程”。差遣牒需要引用正式文档时,写稳定路径/章节名/相关命令,而不是复制整段内容
134
138
 
135
139
  ### 4. `progress` 内容取舍
136
140
 
@@ -139,16 +143,18 @@
139
143
  - 当前已确认、仍成立的 blocker
140
144
  - 当前全队应共识的下一步
141
145
  - 当前阶段性闭环与尚未闭环的 gap
146
+ - 已落正式文档的关键内容摘要,以及定位该文档的 pointer
142
147
  - 不适合写进 `progress`:
143
148
  - “我刚刚看了什么文件”
144
149
  - “我准备先试一个小想法”
145
150
  - 只对当前说话者自己有用的临时便签
146
151
  - 无法判断是否仍然有效的历史痕迹
152
+ - 可在 rtws 正式文档中承载的细节展开、长日志、完整方案或验收记录全文
147
153
 
148
154
  ## 限制与注意事项
149
155
 
150
156
  1. `dialog` 提醒会随对话结束而结束;`personal` 提醒会在所有由你主理的后续对话里继续可见
151
- 2. 差遣牒少量新增可用 `mind_more` 追加;整段替换用 `change_mind`,请确保合并已有内容
157
+ 2. 差遣牒少量新增可用 `mind_more` 追加;整段替换用 `change_mind`,请确保合并已有内容。不要把 `mind_more` 当流水账工具;需要整理、去旧、合并同主题记录时直接 `change_mind`
152
158
  3. `mind_more` / `change_mind` 不重置对话轮次
153
159
  4. 接续包提醒项只保留差遣牒仍未覆盖、但恢复工作容易丢的细节;主线对话应先把当前对话历史中应由下一程知会的未落文档讨论细节写入差遣牒合适章节;支线对话在吃紧/告急时只维护足够详尽的接续包提醒项
154
160
  5. 不要把 `personal` 提醒堆成长期事实仓库;耐久知识应迁到 `personal_memory`
@@ -116,21 +116,21 @@ replyTellaskBack({
116
116
 
117
117
  ### 场景描述
118
118
 
119
- 把当前有效状态、关键决策、下一步与仍成立阻塞公告给全队,而不是写个人流水账。
119
+ 把当前有效状态、关键决策、下一步与仍成立阻塞公告给全队,而不是写个人流水账。若细节已整理到 rtws 正式文档,`progress` 只写摘要和文档定位 pointer。
120
120
 
121
121
  ### 示例
122
122
 
123
123
  ```typescript
124
124
  // 少量新增当前仍有效的公告条目
125
125
  mind_more({
126
- items: ['- 下一步:复核 control / team_mgmt 手册与测试是否对齐'],
126
+ items: ['- 下一步:复核 control / team_mgmt 手册与测试是否对齐(详见 <文档路径>#<章节>)'],
127
127
  });
128
128
 
129
- // 需要清理旧项、重排或压缩时,整章替换
129
+ // 需要清理旧项、重排、同主题合并或压缩流水账时,整章替换
130
130
  change_mind({
131
131
  selector: 'progress',
132
132
  content:
133
- '## Progress\n\n### 当前有效状态\n- 已完成三类记忆载体边界收口,准备补 Taskdoc 公告牌属性\n\n### 已生效决策\n- `personal_memory` 不再作为短期杂物柜\n- `team_memory` 只承接团队长期共识与不变量\n\n### 下一步\n- 在 control / team_mgmt 手册中补强 `progress` 的公告牌语义\n\n### 仍成立阻塞\n- 无',
133
+ '## Progress\n\n### 当前有效状态\n- 已完成三类记忆载体边界收口,准备补 Taskdoc 公告牌属性;细节见 <文档路径>#<章节>\n\n### 已生效决策\n- `personal_memory` 不再作为短期杂物柜\n- `team_memory` 只承接团队长期共识与不变量\n\n### 下一步\n- 在 control / team_mgmt 手册中补强 `progress` 的公告牌语义\n\n### 仍成立阻塞\n- 无',
134
134
  });
135
135
  ```
136
136
 
@@ -192,7 +192,7 @@ recall_taskdoc({
192
192
 
193
193
  ### 场景描述
194
194
 
195
- 维护差遣牒的完整性和一致性,并确保 `progress` 始终是可供全队扫读的当前真相快照。
195
+ 维护差遣牒的完整性和一致性,并确保 `progress` 始终是可供全队扫读的当前真相快照;细节展开放入 rtws 正式文档,差遣牒只保留摘要和定位 pointer。
196
196
 
197
197
  ### 示例
198
198
 
@@ -201,6 +201,6 @@ recall_taskdoc({
201
201
  change_mind({
202
202
  selector: 'progress',
203
203
  content:
204
- '## Progress\n\n### 当前有效状态\n- 边界口径已统一到手册源头与测试\n\n### 已生效决策\n- 角色级资产 / personal_memory / team_memory / Taskdoc-progress / reminders 的职责已经切开\n\n### 下一步\n- 复验 control 手册、Taskdoc 展示文案与边界测试\n\n### 仍成立阻塞\n- 无',
204
+ '## Progress\n\n### 当前有效状态\n- 边界口径已统一到手册源头与测试;细节见 <文档路径>#<章节>\n\n### 已生效决策\n- 角色级资产 / personal_memory / team_memory / Taskdoc-progress / reminders 的职责已经切开\n\n### 下一步\n- 复验 control 手册、Taskdoc 展示文案与边界测试\n\n### 仍成立阻塞\n- 无',
205
205
  });
206
206
  ```
@@ -175,7 +175,7 @@ updated_at: <更新时间戳>
175
175
 
176
176
  ```typescript
177
177
  mind_more({
178
- items: ['- 下一步:复核验证结果', '- 阻塞:无'],
178
+ items: ['- 下一步:复核验证结果(详见 <文档路径>#<章节>)', '- 阻塞:等待 API 验收口径确认'],
179
179
  });
180
180
  ```
181
181
 
@@ -183,7 +183,9 @@ mind_more({
183
183
 
184
184
  - 只追加,不会自动去重、改写或压缩旧内容
185
185
  - 适合给 `progress` 补一两条当前仍有效的状态、决策、下一步或阻塞
186
+ - 不适合把每一步调查过程、长日志、完整方案或验收记录当流水账追加进去;这些细节应写入 rtws 正式文档,差遣牒只写摘要和文档定位 pointer
186
187
  - 若需要删除陈旧项、重排结构或压缩公告牌,仍使用 `change_mind` 做整章替换
188
+ - 当同一主题已经有多条阶段记录时,优先 `change_mind` 合并成当前仍有效的简明公告,而不是继续 `mind_more`
187
189
 
188
190
  ### 7. recall_taskdoc
189
191
 
@@ -255,7 +257,7 @@ update_reminder({
255
257
 
256
258
  ```typescript
257
259
  mind_more({
258
- items: ['- 下一步:补齐 Taskdoc `progress` 的公告牌属性说明'],
260
+ items: ['- 下一步:补齐 Taskdoc `progress` 的公告牌属性说明(详见 <文档路径>#<章节>)'],
259
261
  });
260
262
  ```
261
263
 
@@ -265,7 +267,7 @@ mind_more({
265
267
  change_mind({
266
268
  selector: 'progress',
267
269
  content:
268
- '## Progress\n\n### 当前有效状态\n- 手册边界方案已确定:角色级资产 / 个人长期经验 / Taskdoc-progress / reminders 分流\n\n### 已生效决策\n- `persona / knowhow / pitfalls` 不承接成员日常经验\n- `personal_memory` 只承接成员自己的长期可复用经验\n\n### 下一步\n- 补齐 Taskdoc `progress` 的公告牌属性说明\n\n### 仍成立阻塞\n- 无',
270
+ '## Progress\n\n### 当前有效状态\n- 手册边界方案已确定:角色级资产 / 个人长期经验 / Taskdoc-progress / reminders 分流;细节见 <文档路径>#<章节>\n\n### 已生效决策\n- `persona / knowhow / pitfalls` 不承接成员日常经验\n- `personal_memory` 只承接成员自己的长期可复用经验\n\n### 下一步\n- 补齐 Taskdoc `progress` 的公告牌属性说明\n\n### 仍成立阻塞\n- 无',
269
271
  });
270
272
  ```
271
273
 
@@ -189,7 +189,7 @@ async function updateTaskPackageByChangeMindTarget(params) {
189
189
  await ensureTaskPackage(taskPackageDirFullPath, updatedBy);
190
190
  const filePath = taskPackageFilePathForChangeMindTarget(taskPackageDirFullPath, target);
191
191
  await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
192
- await fs.promises.writeFile(filePath, content, 'utf8');
192
+ await writeMarkdownFileWithCanonicalEnding(filePath, content);
193
193
  }
194
194
  async function appendTaskPackageByChangeMindTarget(params) {
195
195
  const { taskPackageDirFullPath, target, content, sep, updatedBy } = params;
@@ -198,7 +198,16 @@ async function appendTaskPackageByChangeMindTarget(params) {
198
198
  await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
199
199
  const current = await readTextFileIfPresent(filePath);
200
200
  const next = current === null || current.trim() === '' ? content : joinForAppend(current, content, sep);
201
- await fs.promises.writeFile(filePath, next, 'utf8');
201
+ await writeMarkdownFileWithCanonicalEnding(filePath, next);
202
+ }
203
+ async function writeMarkdownFileWithCanonicalEnding(filePath, content) {
204
+ await fs.promises.writeFile(filePath, withCanonicalMarkdownFileEnding(content), 'utf8');
205
+ }
206
+ function withCanonicalMarkdownFileEnding(content) {
207
+ const stripped = stripTrailingMarkdownFileNewlines(content);
208
+ if (stripped === '')
209
+ return '';
210
+ return `${stripped}\n`;
202
211
  }
203
212
  function taskPackageFilePathForChangeMindTarget(taskPackageDirFullPath, target) {
204
213
  switch (target.kind) {
@@ -271,18 +280,23 @@ async function readTaskPackageSections(taskPackageDirFullPath) {
271
280
  return { goals, constraints, progress };
272
281
  }
273
282
  function formatSectionBodyI18n(state) {
274
- // Injection must be deterministic and treat section bodies as opaque markdown.
283
+ // Injection must be deterministic and treat section bodies as opaque markdown,
284
+ // except for file-final newlines that only encode on-disk formatting.
275
285
  // If a required file is missing, inject an empty body (status should be shown elsewhere).
276
286
  if (state.kind === 'present')
277
- return state.content;
287
+ return stripTrailingMarkdownFileNewlines(state.content);
278
288
  return '';
279
289
  }
280
290
  function formatBearInMindBody(state) {
281
291
  if (state.kind !== 'present')
282
292
  return null;
283
- if (state.content.trim() === '')
293
+ const content = stripTrailingMarkdownFileNewlines(state.content);
294
+ if (content.trim() === '')
284
295
  return null;
285
- return state.content;
296
+ return content;
297
+ }
298
+ function stripTrailingMarkdownFileNewlines(content) {
299
+ return content.replace(/(?:\r\n?|\n)+$/u, '');
286
300
  }
287
301
  function formatEffectiveTaskDocFromSections(language, sections, bearInMind) {
288
302
  // Deterministic framing only; section bodies are treated as opaque markdown.
@@ -470,7 +484,7 @@ async function updateTaskPackageSection(params) {
470
484
  const { taskPackageDirFullPath, section, content, updatedBy } = params;
471
485
  await ensureTaskPackage(taskPackageDirFullPath, updatedBy);
472
486
  const filePath = path.join(taskPackageDirFullPath, taskPackageFilenameForSection(section));
473
- await fs.promises.writeFile(filePath, content, 'utf8');
487
+ await writeMarkdownFileWithCanonicalEnding(filePath, content);
474
488
  }
475
489
  async function readTaskPackageExtraSectionsIndex(taskPackageDirFullPath) {
476
490
  const maxEntries = 64;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dominds",
3
- "version": "1.20.1",
3
+ "version": "1.20.2",
4
4
  "description": "Dominds CLI and aggregation shell for the LongRun AI kernel/runtime packages.",
5
5
  "type": "commonjs",
6
6
  "publishConfig": {