dominds 0.6.2 → 0.6.4

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 (149) hide show
  1. package/dist/access-control.js +2 -2
  2. package/dist/agent-priming.js +826 -92
  3. package/dist/cli/read.js +406 -12
  4. package/dist/dialog.js +4 -0
  5. package/dist/docs/design.md +1 -0
  6. package/dist/docs/design.zh.md +1 -0
  7. package/dist/docs/dialog-system.md +12 -7
  8. package/dist/docs/dialog-system.zh.md +7 -3
  9. package/dist/docs/dominds-agent-priming.md +10 -1
  10. package/dist/docs/dominds-agent-priming.zh.md +9 -1
  11. package/dist/docs/dominds-terminology.md +8 -8
  12. package/dist/docs/fbr-implementation.md +77 -0
  13. package/dist/docs/fbr-implementation.zh.md +77 -0
  14. package/dist/docs/fbr.md +142 -141
  15. package/dist/docs/fbr.zh.md +129 -123
  16. package/dist/docs/keep-going.zh.md +162 -0
  17. package/dist/docs/showing-by-doing.md +208 -0
  18. package/dist/docs/showing-by-doing.zh.md +177 -0
  19. package/dist/docs/tellask-collab.md +250 -0
  20. package/dist/docs/tellask-collab.zh.md +254 -0
  21. package/dist/docs/txt-editing-tools.md +2 -2
  22. package/dist/docs/txt-editing-tools.zh.md +2 -2
  23. package/dist/llm/defaults.yaml +82 -4
  24. package/dist/llm/driver.js +280 -104
  25. package/dist/llm/gen/codex.js +49 -2
  26. package/dist/log.js +385 -30
  27. package/dist/mcp/supervisor.js +113 -40
  28. package/dist/minds/builtin/pangu/persona.zh.md +2 -2
  29. package/dist/minds/load.js +49 -284
  30. package/dist/minds/minds-i18n.js +2 -2
  31. package/dist/minds/promptdocs.js +263 -0
  32. package/dist/minds/system-prompt-parts.js +231 -0
  33. package/dist/minds/system-prompt.js +190 -223
  34. package/dist/persistence.js +66 -1
  35. package/dist/server/websocket-handler.js +14 -0
  36. package/dist/shared/diligence.js +40 -6
  37. package/dist/shared/utils/inter-dialog-format.js +3 -5
  38. package/dist/showing-by-doing.js +34 -31
  39. package/dist/snippets/README.en.md +3 -0
  40. package/dist/static/assets/{_baseUniq-C9vbtHF9.js → _baseUniq-C7IpU2Uk.js} +2 -2
  41. package/dist/static/assets/{_baseUniq-C9vbtHF9.js.map → _baseUniq-C7IpU2Uk.js.map} +1 -1
  42. package/dist/static/assets/{arc-hulXG01i.js → arc-1bhQqjON.js} +2 -2
  43. package/dist/static/assets/{arc-hulXG01i.js.map → arc-1bhQqjON.js.map} +1 -1
  44. package/dist/static/assets/{architectureDiagram-VXUJARFQ-DdLIAMT5.js → architectureDiagram-VXUJARFQ-CkEi1QpB.js} +6 -6
  45. package/dist/static/assets/{architectureDiagram-VXUJARFQ-DdLIAMT5.js.map → architectureDiagram-VXUJARFQ-CkEi1QpB.js.map} +1 -1
  46. package/dist/static/assets/{blockDiagram-VD42YOAC-DACsx66C.js → blockDiagram-VD42YOAC-DaBQ5-pY.js} +7 -7
  47. package/dist/static/assets/{blockDiagram-VD42YOAC-DACsx66C.js.map → blockDiagram-VD42YOAC-DaBQ5-pY.js.map} +1 -1
  48. package/dist/static/assets/{c4Diagram-YG6GDRKO-Cd5xZlLy.js → c4Diagram-YG6GDRKO-ChUgpgkP.js} +3 -3
  49. package/dist/static/assets/{c4Diagram-YG6GDRKO-Cd5xZlLy.js.map → c4Diagram-YG6GDRKO-ChUgpgkP.js.map} +1 -1
  50. package/dist/static/assets/{channel-NQehis0Z.js → channel-CxvmwllM.js} +2 -2
  51. package/dist/static/assets/{channel-NQehis0Z.js.map → channel-CxvmwllM.js.map} +1 -1
  52. package/dist/static/assets/{chunk-4BX2VUAB-DZDPl76b.js → chunk-4BX2VUAB-CKsrU2yk.js} +2 -2
  53. package/dist/static/assets/{chunk-4BX2VUAB-DZDPl76b.js.map → chunk-4BX2VUAB-CKsrU2yk.js.map} +1 -1
  54. package/dist/static/assets/{chunk-55IACEB6-CFSRDUbl.js → chunk-55IACEB6-BAau9SFt.js} +2 -2
  55. package/dist/static/assets/{chunk-55IACEB6-CFSRDUbl.js.map → chunk-55IACEB6-BAau9SFt.js.map} +1 -1
  56. package/dist/static/assets/{chunk-B4BG7PRW-BqQQ9M_z.js → chunk-B4BG7PRW--IiJ7W1m.js} +5 -5
  57. package/dist/static/assets/{chunk-B4BG7PRW-BqQQ9M_z.js.map → chunk-B4BG7PRW--IiJ7W1m.js.map} +1 -1
  58. package/dist/static/assets/{chunk-DI55MBZ5-FiFzz1Gh.js → chunk-DI55MBZ5-B83KrPQj.js} +4 -4
  59. package/dist/static/assets/{chunk-DI55MBZ5-FiFzz1Gh.js.map → chunk-DI55MBZ5-B83KrPQj.js.map} +1 -1
  60. package/dist/static/assets/{chunk-FMBD7UC4-DqqtCyWK.js → chunk-FMBD7UC4-BlDXzeza.js} +2 -2
  61. package/dist/static/assets/{chunk-FMBD7UC4-DqqtCyWK.js.map → chunk-FMBD7UC4-BlDXzeza.js.map} +1 -1
  62. package/dist/static/assets/{chunk-QN33PNHL-F0laQQ-J.js → chunk-QN33PNHL-B596W_v7.js} +2 -2
  63. package/dist/static/assets/{chunk-QN33PNHL-F0laQQ-J.js.map → chunk-QN33PNHL-B596W_v7.js.map} +1 -1
  64. package/dist/static/assets/{chunk-QZHKN3VN-CWhEZPaV.js → chunk-QZHKN3VN-UBBCxgBb.js} +2 -2
  65. package/dist/static/assets/{chunk-QZHKN3VN-CWhEZPaV.js.map → chunk-QZHKN3VN-UBBCxgBb.js.map} +1 -1
  66. package/dist/static/assets/{chunk-TZMSLE5B-Dx9cnwUy.js → chunk-TZMSLE5B-D-wCX2wJ.js} +2 -2
  67. package/dist/static/assets/{chunk-TZMSLE5B-Dx9cnwUy.js.map → chunk-TZMSLE5B-D-wCX2wJ.js.map} +1 -1
  68. package/dist/static/assets/{classDiagram-2ON5EDUG-Dp-dyEGy.js → classDiagram-2ON5EDUG-DvtmzPcu.js} +6 -6
  69. package/dist/static/assets/{classDiagram-2ON5EDUG-Dp-dyEGy.js.map → classDiagram-2ON5EDUG-DvtmzPcu.js.map} +1 -1
  70. package/dist/static/assets/{classDiagram-v2-WZHVMYZB-Dp-dyEGy.js → classDiagram-v2-WZHVMYZB-DvtmzPcu.js} +6 -6
  71. package/dist/static/assets/{classDiagram-v2-WZHVMYZB-Dp-dyEGy.js.map → classDiagram-v2-WZHVMYZB-DvtmzPcu.js.map} +1 -1
  72. package/dist/static/assets/{clone-C6mKvxs5.js → clone-DgJ0ZR-k.js} +2 -2
  73. package/dist/static/assets/{clone-C6mKvxs5.js.map → clone-DgJ0ZR-k.js.map} +1 -1
  74. package/dist/static/assets/{cose-bilkent-S5V4N54A-Dbwh3GoX.js → cose-bilkent-S5V4N54A-DXMyFQvy.js} +2 -2
  75. package/dist/static/assets/{cose-bilkent-S5V4N54A-Dbwh3GoX.js.map → cose-bilkent-S5V4N54A-DXMyFQvy.js.map} +1 -1
  76. package/dist/static/assets/{dagre-6UL2VRFP-BD_6e0Uk.js → dagre-6UL2VRFP-BdaUG-j_.js} +7 -7
  77. package/dist/static/assets/{dagre-6UL2VRFP-BD_6e0Uk.js.map → dagre-6UL2VRFP-BdaUG-j_.js.map} +1 -1
  78. package/dist/static/assets/{diagram-PSM6KHXK-BWt7Q59-.js → diagram-PSM6KHXK-NLiqKBzn.js} +7 -7
  79. package/dist/static/assets/{diagram-PSM6KHXK-BWt7Q59-.js.map → diagram-PSM6KHXK-NLiqKBzn.js.map} +1 -1
  80. package/dist/static/assets/{diagram-QEK2KX5R-D0BvBR_a.js → diagram-QEK2KX5R-D-0fyvY_.js} +6 -6
  81. package/dist/static/assets/{diagram-QEK2KX5R-D0BvBR_a.js.map → diagram-QEK2KX5R-D-0fyvY_.js.map} +1 -1
  82. package/dist/static/assets/{diagram-S2PKOQOG-D8uRdKXp.js → diagram-S2PKOQOG-BQ_FU59m.js} +6 -6
  83. package/dist/static/assets/{diagram-S2PKOQOG-D8uRdKXp.js.map → diagram-S2PKOQOG-BQ_FU59m.js.map} +1 -1
  84. package/dist/static/assets/{erDiagram-Q2GNP2WA-CQoifjFq.js → erDiagram-Q2GNP2WA-DyftKeuC.js} +5 -5
  85. package/dist/static/assets/{erDiagram-Q2GNP2WA-CQoifjFq.js.map → erDiagram-Q2GNP2WA-DyftKeuC.js.map} +1 -1
  86. package/dist/static/assets/{flowDiagram-NV44I4VS-CGhdeaG8.js → flowDiagram-NV44I4VS-9SGefONA.js} +6 -6
  87. package/dist/static/assets/{flowDiagram-NV44I4VS-CGhdeaG8.js.map → flowDiagram-NV44I4VS-9SGefONA.js.map} +1 -1
  88. package/dist/static/assets/{ganttDiagram-JELNMOA3-D8W0wb9H.js → ganttDiagram-JELNMOA3-k_WLhf-r.js} +3 -3
  89. package/dist/static/assets/{ganttDiagram-JELNMOA3-D8W0wb9H.js.map → ganttDiagram-JELNMOA3-k_WLhf-r.js.map} +1 -1
  90. package/dist/static/assets/{gitGraphDiagram-NY62KEGX-ChHni_jP.js → gitGraphDiagram-NY62KEGX-3eoLlCOY.js} +7 -7
  91. package/dist/static/assets/{gitGraphDiagram-NY62KEGX-ChHni_jP.js.map → gitGraphDiagram-NY62KEGX-3eoLlCOY.js.map} +1 -1
  92. package/dist/static/assets/{graph-BWoi_FgC.js → graph-vUevIs4s.js} +3 -3
  93. package/dist/static/assets/{graph-BWoi_FgC.js.map → graph-vUevIs4s.js.map} +1 -1
  94. package/dist/static/assets/{index-th_praGg.js → index-BNBG2CE1.js} +399 -68
  95. package/dist/static/assets/index-BNBG2CE1.js.map +1 -0
  96. package/dist/static/assets/{infoDiagram-WHAUD3N6-B_XKKZTV.js → infoDiagram-WHAUD3N6-CwEhVxkU.js} +5 -5
  97. package/dist/static/assets/{infoDiagram-WHAUD3N6-B_XKKZTV.js.map → infoDiagram-WHAUD3N6-CwEhVxkU.js.map} +1 -1
  98. package/dist/static/assets/{journeyDiagram-XKPGCS4Q-ChGuQ6T9.js → journeyDiagram-XKPGCS4Q-Dtdq4G4Q.js} +5 -5
  99. package/dist/static/assets/{journeyDiagram-XKPGCS4Q-ChGuQ6T9.js.map → journeyDiagram-XKPGCS4Q-Dtdq4G4Q.js.map} +1 -1
  100. package/dist/static/assets/{kanban-definition-3W4ZIXB7-BjWe623u.js → kanban-definition-3W4ZIXB7-Bli-AycJ.js} +3 -3
  101. package/dist/static/assets/{kanban-definition-3W4ZIXB7-BjWe623u.js.map → kanban-definition-3W4ZIXB7-Bli-AycJ.js.map} +1 -1
  102. package/dist/static/assets/{layout-BPyT310w.js → layout-CGlA8c09.js} +5 -5
  103. package/dist/static/assets/{layout-BPyT310w.js.map → layout-CGlA8c09.js.map} +1 -1
  104. package/dist/static/assets/{linear-xUsVjXWq.js → linear-Da2jDWL3.js} +2 -2
  105. package/dist/static/assets/{linear-xUsVjXWq.js.map → linear-Da2jDWL3.js.map} +1 -1
  106. package/dist/static/assets/{min-xFt7zeOd.js → min-Co741hTV.js} +3 -3
  107. package/dist/static/assets/{min-xFt7zeOd.js.map → min-Co741hTV.js.map} +1 -1
  108. package/dist/static/assets/{mindmap-definition-VGOIOE7T-DT_dvf2c.js → mindmap-definition-VGOIOE7T-DvkIjoq8.js} +4 -4
  109. package/dist/static/assets/{mindmap-definition-VGOIOE7T-DT_dvf2c.js.map → mindmap-definition-VGOIOE7T-DvkIjoq8.js.map} +1 -1
  110. package/dist/static/assets/{pieDiagram-ADFJNKIX-B1DQ-OaG.js → pieDiagram-ADFJNKIX-BGuGhTu8.js} +7 -7
  111. package/dist/static/assets/{pieDiagram-ADFJNKIX-B1DQ-OaG.js.map → pieDiagram-ADFJNKIX-BGuGhTu8.js.map} +1 -1
  112. package/dist/static/assets/{quadrantDiagram-AYHSOK5B-IHqyr3iT.js → quadrantDiagram-AYHSOK5B-DAZcrJMg.js} +3 -3
  113. package/dist/static/assets/{quadrantDiagram-AYHSOK5B-IHqyr3iT.js.map → quadrantDiagram-AYHSOK5B-DAZcrJMg.js.map} +1 -1
  114. package/dist/static/assets/{requirementDiagram-UZGBJVZJ-CKBpht7B.js → requirementDiagram-UZGBJVZJ-CXN0DxZs.js} +4 -4
  115. package/dist/static/assets/{requirementDiagram-UZGBJVZJ-CKBpht7B.js.map → requirementDiagram-UZGBJVZJ-CXN0DxZs.js.map} +1 -1
  116. package/dist/static/assets/{sankeyDiagram-TZEHDZUN-D2uGjv3i.js → sankeyDiagram-TZEHDZUN-B7-yAePZ.js} +2 -2
  117. package/dist/static/assets/{sankeyDiagram-TZEHDZUN-D2uGjv3i.js.map → sankeyDiagram-TZEHDZUN-B7-yAePZ.js.map} +1 -1
  118. package/dist/static/assets/{sequenceDiagram-WL72ISMW-wLFRhAKd.js → sequenceDiagram-WL72ISMW-DfBNY6h_.js} +4 -4
  119. package/dist/static/assets/{sequenceDiagram-WL72ISMW-wLFRhAKd.js.map → sequenceDiagram-WL72ISMW-DfBNY6h_.js.map} +1 -1
  120. package/dist/static/assets/{stateDiagram-FKZM4ZOC-BFGQTbx5.js → stateDiagram-FKZM4ZOC-BLo1xRVY.js} +9 -9
  121. package/dist/static/assets/{stateDiagram-FKZM4ZOC-BFGQTbx5.js.map → stateDiagram-FKZM4ZOC-BLo1xRVY.js.map} +1 -1
  122. package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-DF7AjJuk.js → stateDiagram-v2-4FDKWEC3-Dq7MAD0I.js} +5 -5
  123. package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-DF7AjJuk.js.map → stateDiagram-v2-4FDKWEC3-Dq7MAD0I.js.map} +1 -1
  124. package/dist/static/assets/{timeline-definition-IT6M3QCI-ChHFOb0o.js → timeline-definition-IT6M3QCI-ySWyBF3b.js} +3 -3
  125. package/dist/static/assets/{timeline-definition-IT6M3QCI-ChHFOb0o.js.map → timeline-definition-IT6M3QCI-ySWyBF3b.js.map} +1 -1
  126. package/dist/static/assets/{treemap-KMMF4GRG-BxaNvQU4.js → treemap-KMMF4GRG-DOp4sqOh.js} +4 -4
  127. package/dist/static/assets/{treemap-KMMF4GRG-BxaNvQU4.js.map → treemap-KMMF4GRG-DOp4sqOh.js.map} +1 -1
  128. package/dist/static/assets/{xychartDiagram-PRI3JC2R-CrNKeY_-.js → xychartDiagram-PRI3JC2R-vkmh67qb.js} +3 -3
  129. package/dist/static/assets/{xychartDiagram-PRI3JC2R-CrNKeY_-.js.map → xychartDiagram-PRI3JC2R-vkmh67qb.js.map} +1 -1
  130. package/dist/static/index.html +1 -1
  131. package/dist/team.js +29 -6
  132. package/dist/tool.js +56 -0
  133. package/dist/tools/builtins.js +4 -2
  134. package/dist/tools/context-health.js +7 -7
  135. package/dist/tools/os.js +267 -30
  136. package/dist/tools/pending-tellask-reminder.js +185 -0
  137. package/dist/tools/plan.js +1 -0
  138. package/dist/tools/ripgrep.js +145 -4
  139. package/dist/tools/shell-tools.js +21 -0
  140. package/dist/tools/team-mgmt.js +4 -4
  141. package/dist/tools/toolset-manual.js +74 -0
  142. package/dist/utils/task-doc.js +16 -16
  143. package/package.json +1 -1
  144. package/dist/minds/builtin/cmdr/persona.md +0 -3
  145. package/dist/minds/builtin/dijiang/knowledge.md +0 -287
  146. package/dist/minds/builtin/dijiang/persona.md +0 -7
  147. package/dist/static/assets/index-th_praGg.js.map +0 -1
  148. package/dist/static/testing/dom-observation-utils.js +0 -425
  149. package/dist/static/testing/e2e-test-helper.js +0 -3119
@@ -36,6 +36,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.getAgentPrimingCacheStatus = getAgentPrimingCacheStatus;
37
37
  exports.resolveInheritedSubdialogAgentPrimingMode = resolveInheritedSubdialogAgentPrimingMode;
38
38
  exports.scheduleAgentPrimingForNewDialog = scheduleAgentPrimingForNewDialog;
39
+ /**
40
+ * Module: agent-priming
41
+ *
42
+ * Best-effort Agent Priming prelude generation for new dialogs.
43
+ */
44
+ const node_child_process_1 = require("node:child_process");
45
+ const fs = __importStar(require("node:fs/promises"));
46
+ const path = __importStar(require("node:path"));
47
+ const dialog_1 = require("./dialog");
39
48
  const dialog_run_state_1 = require("./dialog-run-state");
40
49
  const driver_1 = require("./llm/driver");
41
50
  const log_1 = require("./log");
@@ -45,6 +54,7 @@ const inter_dialog_format_1 = require("./shared/utils/inter-dialog-format");
45
54
  const time_1 = require("./shared/utils/time");
46
55
  const team_1 = require("./team");
47
56
  const BASELINE_ENV_SNAPSHOT_CMD = 'uname -a';
57
+ const PRIMING_VCS_SESSION_SLUG = 'rtws-vcs-inventory';
48
58
  const cacheByAgentId = new Map();
49
59
  const inflightByAgentId = new Map();
50
60
  async function emitSayingEventsAndPersist(dlg, content) {
@@ -220,9 +230,8 @@ function extractLastShellCmdResultText(messages) {
220
230
  return null;
221
231
  }
222
232
  async function runUnameA() {
223
- const { spawn } = await Promise.resolve().then(() => __importStar(require('child_process')));
224
233
  return await new Promise((resolveUname) => {
225
- const child = spawn('uname', ['-a'], { stdio: ['ignore', 'pipe', 'pipe'] });
234
+ const child = (0, node_child_process_1.spawn)('uname', ['-a'], { stdio: ['ignore', 'pipe', 'pipe'] });
226
235
  let out = '';
227
236
  let err = '';
228
237
  child.stdout.on('data', (buf) => {
@@ -246,6 +255,335 @@ async function runUnameA() {
246
255
  });
247
256
  });
248
257
  }
258
+ async function runCommand(command, args, cwd) {
259
+ return await new Promise((resolveExec) => {
260
+ const child = (0, node_child_process_1.spawn)(command, args, {
261
+ cwd,
262
+ stdio: ['ignore', 'pipe', 'pipe'],
263
+ });
264
+ let out = '';
265
+ let err = '';
266
+ child.stdout.on('data', (buf) => {
267
+ out += buf.toString();
268
+ });
269
+ child.stderr.on('data', (buf) => {
270
+ err += buf.toString();
271
+ });
272
+ child.on('close', (code) => {
273
+ resolveExec({
274
+ ok: code === 0,
275
+ stdout: out.trim(),
276
+ stderr: err.trim(),
277
+ exitCode: code,
278
+ });
279
+ });
280
+ child.on('error', (e) => {
281
+ resolveExec({
282
+ ok: false,
283
+ stdout: out.trim(),
284
+ stderr: err.trim(),
285
+ exitCode: null,
286
+ errorText: e instanceof Error ? e.message : String(e),
287
+ });
288
+ });
289
+ });
290
+ }
291
+ async function runGit(args, cwd) {
292
+ return await runCommand('git', args, cwd);
293
+ }
294
+ async function isGitRepo(dir) {
295
+ const res = await runGit(['rev-parse', '--is-inside-work-tree'], dir);
296
+ return res.ok && res.stdout === 'true';
297
+ }
298
+ async function inspectRtwsRootGitPosition(rtws) {
299
+ // Equivalent to comparing:
300
+ // - `git rev-parse --show-toplevel`
301
+ // - `pwd`
302
+ // to determine whether rtws itself is repo root vs a subdirectory of a repo.
303
+ const showTopRes = await runGit(['rev-parse', '--show-toplevel'], rtws);
304
+ if (!showTopRes.ok || !showTopRes.stdout) {
305
+ return { kind: 'not_git' };
306
+ }
307
+ const rtwsAbs = path.resolve(rtws);
308
+ const topLevelAbsPath = path.resolve(showTopRes.stdout);
309
+ if (topLevelAbsPath === rtwsAbs) {
310
+ return { kind: 'repo_root', topLevelAbsPath };
311
+ }
312
+ const relFromTopLevel = path.relative(topLevelAbsPath, rtwsAbs).replace(/\\/g, '/');
313
+ return {
314
+ kind: 'repo_subdir',
315
+ topLevelAbsPath,
316
+ relFromTopLevel: relFromTopLevel || '.',
317
+ };
318
+ }
319
+ async function listSubmoduleRelPaths(rootDir) {
320
+ const out = new Set();
321
+ const res = await runGit(['submodule', 'status', '--recursive'], rootDir);
322
+ if (!res.ok || !res.stdout)
323
+ return out;
324
+ const lines = res.stdout.split('\n');
325
+ for (const line of lines) {
326
+ const trimmed = line.trim();
327
+ if (!trimmed)
328
+ continue;
329
+ const m = trimmed.match(/^[+\-U ]?[0-9a-fA-F]+\s+([^\s]+)/);
330
+ if (!m)
331
+ continue;
332
+ const rel = (m[1] ?? '').trim();
333
+ if (!rel)
334
+ continue;
335
+ out.add(rel.replace(/\\/g, '/'));
336
+ }
337
+ return out;
338
+ }
339
+ async function findGitMarkerDirs(rootDir) {
340
+ const skipDirs = new Set([
341
+ '.git',
342
+ 'node_modules',
343
+ '.pnpm-store',
344
+ '.yarn',
345
+ '.next',
346
+ 'dist',
347
+ 'build',
348
+ 'out',
349
+ 'target',
350
+ '.cache',
351
+ ]);
352
+ const queue = [rootDir];
353
+ const found = new Set();
354
+ const maxVisited = 20000;
355
+ let visited = 0;
356
+ while (queue.length > 0) {
357
+ const current = queue.shift();
358
+ if (!current)
359
+ continue;
360
+ visited += 1;
361
+ if (visited > maxVisited)
362
+ break;
363
+ let entries;
364
+ try {
365
+ entries = await fs.readdir(current, { withFileTypes: true });
366
+ }
367
+ catch {
368
+ continue;
369
+ }
370
+ const hasGitMarker = entries.some((e) => e.name === '.git' && (e.isDirectory() || e.isFile()));
371
+ if (hasGitMarker) {
372
+ found.add(current);
373
+ if (current !== rootDir) {
374
+ // Treat a nested repo as its own boundary to keep traversal bounded.
375
+ continue;
376
+ }
377
+ }
378
+ for (const entry of entries) {
379
+ if (!entry.isDirectory())
380
+ continue;
381
+ if (skipDirs.has(entry.name))
382
+ continue;
383
+ const next = path.join(current, entry.name);
384
+ queue.push(next);
385
+ }
386
+ }
387
+ return Array.from(found);
388
+ }
389
+ async function collectRtwsGitInventory() {
390
+ const rtws = process.cwd();
391
+ const rootGitPosition = await inspectRtwsRootGitPosition(rtws);
392
+ const rootIsRepo = rootGitPosition.kind === 'repo_root';
393
+ const markerDirs = await findGitMarkerDirs(rtws);
394
+ const submoduleSet = rootIsRepo ? await listSubmoduleRelPaths(rtws) : new Set();
395
+ const repoAbsSet = new Set();
396
+ if (rootGitPosition.kind === 'repo_root' || rootGitPosition.kind === 'repo_subdir') {
397
+ repoAbsSet.add(rtws);
398
+ }
399
+ for (const candidate of markerDirs) {
400
+ if (candidate === rtws)
401
+ continue;
402
+ if (await isGitRepo(candidate)) {
403
+ repoAbsSet.add(candidate);
404
+ }
405
+ }
406
+ const allRepoAbs = Array.from(repoAbsSet).sort();
407
+ const allRepoRel = allRepoAbs.map((abs) => {
408
+ const rel = path.relative(rtws, abs).replace(/\\/g, '/');
409
+ return rel === '' ? '.' : rel;
410
+ });
411
+ const submoduleRelPaths = allRepoRel.filter((rel) => submoduleSet.has(rel));
412
+ const nestedRepoRelPaths = allRepoRel.filter((rel) => rel !== '.' && !submoduleSet.has(rel));
413
+ const repoStatuses = [];
414
+ const maxRepos = 40;
415
+ for (let i = 0; i < Math.min(allRepoAbs.length, maxRepos); i++) {
416
+ const repoAbs = allRepoAbs[i];
417
+ const rel = allRepoRel[i] ?? '.';
418
+ const branchRes = await runGit(['branch', '--show-current'], repoAbs);
419
+ const headRes = await runGit(['rev-parse', '--short', 'HEAD'], repoAbs);
420
+ const upstreamRes = await runGit(['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{upstream}'], repoAbs);
421
+ const remoteRes = await runGit(['remote', '-v'], repoAbs);
422
+ const dirtyRes = await runGit(['status', '--porcelain'], repoAbs);
423
+ const remotes = (() => {
424
+ if (!remoteRes.ok || !remoteRes.stdout)
425
+ return [];
426
+ const lines = remoteRes.stdout.split('\n');
427
+ const items = new Set();
428
+ for (const line of lines) {
429
+ const m = line.match(/^([^\s]+)\s+([^\s]+)\s+\((fetch|push)\)$/);
430
+ if (!m)
431
+ continue;
432
+ const name = m[1] ?? '';
433
+ const url = m[2] ?? '';
434
+ const kind = m[3] ?? '';
435
+ if (!name || !url || !kind)
436
+ continue;
437
+ items.add(`${name}:${kind}=${url}`);
438
+ }
439
+ return Array.from(items).sort();
440
+ })();
441
+ const dirtyCount = (() => {
442
+ if (!dirtyRes.ok || !dirtyRes.stdout)
443
+ return 0;
444
+ return dirtyRes.stdout
445
+ .split('\n')
446
+ .map((line) => line.trim())
447
+ .filter((line) => line.length > 0).length;
448
+ })();
449
+ const statusErrorParts = [];
450
+ if (!branchRes.ok)
451
+ statusErrorParts.push(`branch: ${branchRes.errorText ?? branchRes.stderr}`);
452
+ if (!headRes.ok)
453
+ statusErrorParts.push(`head: ${headRes.errorText ?? headRes.stderr}`);
454
+ if (!remoteRes.ok)
455
+ statusErrorParts.push(`remote: ${remoteRes.errorText ?? remoteRes.stderr}`);
456
+ if (!dirtyRes.ok)
457
+ statusErrorParts.push(`status: ${dirtyRes.errorText ?? dirtyRes.stderr}`);
458
+ repoStatuses.push({
459
+ relPath: rel,
460
+ branch: branchRes.ok && branchRes.stdout ? branchRes.stdout : '(detached-or-unknown)',
461
+ upstream: upstreamRes.ok && upstreamRes.stdout ? upstreamRes.stdout : '(no-upstream-or-unavailable)',
462
+ remotes,
463
+ dirtyCount,
464
+ headShort: headRes.ok && headRes.stdout ? headRes.stdout : '(unknown)',
465
+ statusError: statusErrorParts.length > 0 ? statusErrorParts.join('; ') : undefined,
466
+ });
467
+ }
468
+ return {
469
+ rootIsRepo,
470
+ rootGitPosition,
471
+ submoduleRelPaths,
472
+ nestedRepoRelPaths,
473
+ repoStatuses,
474
+ };
475
+ }
476
+ function formatRtwsGitInventoryRound1(language, inventory) {
477
+ const relationLineZh = (() => {
478
+ if (inventory.rootGitPosition.kind === 'repo_root') {
479
+ return '- rtws 与 git 关系:rtws 本身就是 repo 根路径';
480
+ }
481
+ if (inventory.rootGitPosition.kind === 'repo_subdir') {
482
+ return [
483
+ '- rtws 与 git 关系:rtws 是某个 repo 的子目录(rtws 本身不是 repo 根)',
484
+ `- 上级 repo 顶层:${inventory.rootGitPosition.topLevelAbsPath}`,
485
+ `- rtws 相对上级 repo 路径:${inventory.rootGitPosition.relFromTopLevel}`,
486
+ ].join('\n');
487
+ }
488
+ return '- rtws 与 git 关系:不在任何 git worktree 内';
489
+ })();
490
+ const relationLineEn = (() => {
491
+ if (inventory.rootGitPosition.kind === 'repo_root') {
492
+ return '- rtws vs git: rtws itself is the repo root';
493
+ }
494
+ if (inventory.rootGitPosition.kind === 'repo_subdir') {
495
+ return [
496
+ '- rtws vs git: rtws is a subdirectory inside a repo (rtws itself is not the repo root)',
497
+ `- enclosing repo top-level: ${inventory.rootGitPosition.topLevelAbsPath}`,
498
+ `- rtws path relative to repo root: ${inventory.rootGitPosition.relFromTopLevel}`,
499
+ ].join('\n');
500
+ }
501
+ return '- rtws vs git: not inside any git worktree';
502
+ })();
503
+ if (language === 'zh') {
504
+ const submoduleText = inventory.submoduleRelPaths.length < 1
505
+ ? '无'
506
+ : inventory.submoduleRelPaths.map((p) => `- ${p}`).join('\n');
507
+ const nestedText = inventory.nestedRepoRelPaths.length < 1
508
+ ? '无'
509
+ : inventory.nestedRepoRelPaths.map((p) => `- ${p}`).join('\n');
510
+ return [
511
+ 'VCS 长线诉请 Round-1(rtws 仓库拓扑)',
512
+ '',
513
+ `- 根路径是否 git repo:${inventory.rootIsRepo ? '是' : '否'}`,
514
+ relationLineZh,
515
+ `- submodule 数量:${inventory.submoduleRelPaths.length}`,
516
+ `- 子目录独立 repo 数量:${inventory.nestedRepoRelPaths.length}`,
517
+ '',
518
+ 'submodule 列表:',
519
+ submoduleText,
520
+ '',
521
+ '子目录独立 repo 列表:',
522
+ nestedText,
523
+ ].join('\n');
524
+ }
525
+ const submoduleText = inventory.submoduleRelPaths.length < 1
526
+ ? 'none'
527
+ : inventory.submoduleRelPaths.map((p) => `- ${p}`).join('\n');
528
+ const nestedText = inventory.nestedRepoRelPaths.length < 1
529
+ ? 'none'
530
+ : inventory.nestedRepoRelPaths.map((p) => `- ${p}`).join('\n');
531
+ return [
532
+ 'VCS Tellask Session Round-1 (rtws repo topology)',
533
+ '',
534
+ `- Root path is git repo: ${inventory.rootIsRepo ? 'yes' : 'no'}`,
535
+ relationLineEn,
536
+ `- Submodule count: ${inventory.submoduleRelPaths.length}`,
537
+ `- Nested independent repo count: ${inventory.nestedRepoRelPaths.length}`,
538
+ '',
539
+ 'Submodule list:',
540
+ submoduleText,
541
+ '',
542
+ 'Nested independent repo list:',
543
+ nestedText,
544
+ ].join('\n');
545
+ }
546
+ function formatRtwsGitInventoryRound2(language, inventory) {
547
+ const rows = inventory.repoStatuses.map((repo, idx) => {
548
+ const remotes = repo.remotes.length < 1 ? '(none)' : repo.remotes.join(', ');
549
+ if (language === 'zh') {
550
+ return [
551
+ `${idx + 1}. repo: ${repo.relPath}`,
552
+ ` - head: ${repo.headShort}`,
553
+ ` - branch: ${repo.branch}`,
554
+ ` - upstream: ${repo.upstream}`,
555
+ ` - dirty: ${repo.dirtyCount > 0 ? `yes (${repo.dirtyCount})` : 'no'}`,
556
+ ` - remotes: ${remotes}`,
557
+ repo.statusError ? ` - errors: ${repo.statusError}` : '',
558
+ ]
559
+ .filter((line) => line !== '')
560
+ .join('\n');
561
+ }
562
+ return [
563
+ `${idx + 1}. repo: ${repo.relPath}`,
564
+ ` - head: ${repo.headShort}`,
565
+ ` - branch: ${repo.branch}`,
566
+ ` - upstream: ${repo.upstream}`,
567
+ ` - dirty: ${repo.dirtyCount > 0 ? `yes (${repo.dirtyCount})` : 'no'}`,
568
+ ` - remotes: ${remotes}`,
569
+ repo.statusError ? ` - errors: ${repo.statusError}` : '',
570
+ ]
571
+ .filter((line) => line !== '')
572
+ .join('\n');
573
+ });
574
+ if (language === 'zh') {
575
+ return [
576
+ 'VCS 长线诉请 Round-2(每个 repo 的 remote / branch 现状)',
577
+ '',
578
+ rows.length < 1 ? '未发现可报告的 repo。' : rows.join('\n\n'),
579
+ ].join('\n');
580
+ }
581
+ return [
582
+ 'VCS Tellask Session Round-2 (remote / branch status per repo)',
583
+ '',
584
+ rows.length < 1 ? 'No repos available to report.' : rows.join('\n\n'),
585
+ ].join('\n');
586
+ }
249
587
  function formatPreludeIntro(language, reused, shellPolicy, shellSpecialistId) {
250
588
  const shellSpecialistMention = shellSpecialistId && shellSpecialistId.trim()
251
589
  ? `@${shellSpecialistId.trim()}`
@@ -258,13 +596,12 @@ function formatPreludeIntro(language, reused, shellPolicy, shellSpecialistId) {
258
596
  : shellPolicy === 'self_is_specialist'
259
597
  ? [
260
598
  '本次对话主理人属于 `shell_specialists`,将略去 shell 诉请环节。',
261
- '由 Dominds 运行时执行一个基线命令:`uname -a`,随后进入 `!?@self` FBR。',
599
+ '由 Dominds 运行时获取标准环境事实(`uname -a` + rtws git 现状),随后进入 `!?@self` FBR。',
262
600
  ]
263
601
  : [
264
602
  '本团队未配置 shell 专员。',
265
- '规则:此智能体必须**不执行任何 shell 命令**(不能“自己跑一下看看”)。',
266
- '后续只能通过文件读写等非 shell 工具推进;同时要结合环境快照留意系统相关注意事项。',
267
- '由 Dominds 运行时仅执行一个基线命令:`uname -a`,随后进入 `!?@self` FBR。',
603
+ '这是标准支持模式:由 Dominds 运行时主动获取环境事实(`uname -a` + rtws git 现状)并用于后续 FBR。',
604
+ '规则:此智能体仍然不得自行执行任意 shell 命令。',
268
605
  ];
269
606
  const shellPolicyLinesEn = shellPolicy === 'specialist_only'
270
607
  ? [
@@ -274,13 +611,12 @@ function formatPreludeIntro(language, reused, shellPolicy, shellSpecialistId) {
274
611
  : shellPolicy === 'self_is_specialist'
275
612
  ? [
276
613
  'The dialog owner is a member of `shell_specialists`, so we skip the shell Tellask step.',
277
- 'Dominds runtime runs one baseline command: `uname -a`, then we enter `!?@self` FBR.',
614
+ 'Dominds runtime collects standard environment facts (`uname -a` + rtws git state), then we enter `!?@self` FBR.',
278
615
  ]
279
616
  : [
280
617
  'This team has no configured shell specialist.',
281
- 'Rule: this agent must **not run any shell commands** (no “just try it locally”).',
282
- 'We can only proceed with non-shell tools like file read/write; still, we must watch out for environment-specific constraints.',
283
- 'Dominds runtime runs one baseline command only: `uname -a`, then we enter `!?@self` FBR.',
618
+ 'This is a standard support mode: Dominds runtime proactively collects environment facts (`uname -a` + rtws git state) for FBR.',
619
+ 'Rule: this agent still must not run arbitrary shell commands directly.',
284
620
  ];
285
621
  if (language === 'zh') {
286
622
  return reused
@@ -288,6 +624,7 @@ function formatPreludeIntro(language, reused, shellPolicy, shellSpecialistId) {
288
624
  '## Prelude:智能体启动(复用缓存)',
289
625
  '',
290
626
  '这段序幕用于把“诉请 + 回传 + FBR + 综合提炼”变成体感(引导祂做给自己看)。',
627
+ '关键时序:`!?@self` 只表示发起;必须等待 FBR 支线回贴返回后,才在主线做综合决策。',
291
628
  '本次对话复用了本进程内缓存:未重复执行命令。',
292
629
  '',
293
630
  ...shellPolicyLinesZh,
@@ -297,6 +634,7 @@ function formatPreludeIntro(language, reused, shellPolicy, shellSpecialistId) {
297
634
  '## Prelude:智能体启动',
298
635
  '',
299
636
  '这段序幕用于把“诉请 + 回传 + FBR + 综合提炼”变成体感(引导祂做给自己看)。',
637
+ '关键时序:`!?@self` 只表示发起;必须等待 FBR 支线回贴返回后,才在主线做综合决策。',
300
638
  '',
301
639
  ...shellPolicyLinesZh,
302
640
  '',
@@ -307,6 +645,7 @@ function formatPreludeIntro(language, reused, shellPolicy, shellSpecialistId) {
307
645
  '## Prelude: Agent Priming (Reused)',
308
646
  '',
309
647
  'This prelude makes Tellask + return + FBR + distillation feel real (guiding the agent to show it to itself).',
648
+ 'Critical timing: `!?@self` is initiation only; mainline synthesis/decision happens only after FBR sideline feedback returns.',
310
649
  'This dialog reused the in-process cache (no commands were re-run).',
311
650
  '',
312
651
  ...shellPolicyLinesEn,
@@ -316,6 +655,7 @@ function formatPreludeIntro(language, reused, shellPolicy, shellSpecialistId) {
316
655
  '## Prelude: Agent Priming',
317
656
  '',
318
657
  'This prelude makes Tellask + return + FBR + distillation feel real (guiding the agent to show it to itself).',
658
+ 'Critical timing: `!?@self` is initiation only; mainline synthesis/decision happens only after FBR sideline feedback returns.',
319
659
  '',
320
660
  ...shellPolicyLinesEn,
321
661
  '',
@@ -329,7 +669,7 @@ function formatShellTellaskBody(language, shellSpecialistId) {
329
669
  '',
330
670
  '背景规则:对话主理人不得执行任何 shell 命令;所有 shell 命令必须通过你执行并回传。',
331
671
  '请不要建议我“自己在本地跑一下”。',
332
- '收到回传后,我将基于该环境信息做一次 `!?@self` 扪心自问(FBR),并最终形成一条可复用的“智能体启动(Agent Priming)”笔记。',
672
+ '收到回传后,我会基于该环境信息发起一次 `!?@self` 扪心自问(FBR),先等待该次 FBR 的全部支线回贴,再在主线做综合提炼并形成一条可复用的“智能体启动(Agent Priming)”笔记。',
333
673
  '',
334
674
  '要求:',
335
675
  '- 通过 shell 工具执行:uname -a(只执行这一条)',
@@ -344,7 +684,7 @@ function formatShellTellaskBody(language, shellSpecialistId) {
344
684
  '',
345
685
  'Rule: the dialog owner must not run any shell commands; all shell commands must be executed by you and returned.',
346
686
  'Do not suggest that I “just run it locally”.',
347
- 'After I receive your output, I will run `!?@self` Fresh Boots Reasoning (FBR) on this environment, then produce a reusable “Agent Priming” note.',
687
+ 'After I receive your output, I will initiate `!?@self` Fresh Boots Reasoning (FBR) on this environment, wait for all feedback from that FBR run, then distill a reusable “Agent Priming” note in mainline.',
348
688
  '',
349
689
  'Requirements:',
350
690
  '- Use shell tools to run exactly: uname -a (and only this command)',
@@ -354,117 +694,145 @@ function formatShellTellaskBody(language, shellSpecialistId) {
354
694
  'Output format: prefer raw output only; keep any explanation minimal.',
355
695
  ].join('\n');
356
696
  }
357
- function formatFbrSelfTeaser(language) {
697
+ function formatVcsSessionRound1TellaskBody(language) {
358
698
  if (language === 'zh') {
359
- return '(我会在收到全部 FBR 支线反馈后进行综合提炼,并在主线对话中输出一条可复用的“智能体启动(Agent Priming)”笔记。)';
699
+ return [
700
+ `这是同一长线诉请(session: ${PRIMING_VCS_SESSION_SLUG})的 Round-1,请你只做仓库拓扑盘点。`,
701
+ '',
702
+ '在当前 rtws 中确认:',
703
+ '- 根路径是否是 git repo',
704
+ '- 是否存在 submodule(给出路径列表)',
705
+ '- 是否存在子目录独立 repo(给出路径列表)',
706
+ '',
707
+ '要求:',
708
+ '- 只使用 git / find 命令采集事实;不要用 python/node/perl 等脚本探测',
709
+ '- 建议命令:`git rev-parse --is-inside-work-tree`、`git submodule status --recursive`、`find . -name .git`',
710
+ '- 仅做事实盘点,不做下一步建议',
711
+ '- 输出必须短且结构化,便于我在 Round-2 继续诉请',
712
+ ].join('\n');
360
713
  }
361
- return '(After I receive all FBR sideline feedback, I will distill it into a reusable “Agent Priming” note.)';
714
+ return [
715
+ `This is Round-1 of the same Tellask Session (${PRIMING_VCS_SESSION_SLUG}); do topology inventory only.`,
716
+ '',
717
+ 'In the current rtws, confirm:',
718
+ '- whether the root path is a git repo',
719
+ '- whether submodules exist (with path list)',
720
+ '- whether nested independent repos exist (with path list)',
721
+ '',
722
+ 'Requirements:',
723
+ '- use git/find commands only; do not use python/node/perl scripts for discovery',
724
+ '- suggested commands: `git rev-parse --is-inside-work-tree`, `git submodule status --recursive`, `find . -name .git`',
725
+ '- facts only, no next-step suggestions',
726
+ '- keep output short and structured so I can continue in Round-2',
727
+ ].join('\n');
362
728
  }
363
- function formatFbrTellaskBody(language, snapshotCmd, snapshotText, shellPolicy, shellSpecialistId, options) {
364
- const shellSpecialistMention = shellSpecialistId && shellSpecialistId.trim()
365
- ? `@${shellSpecialistId.trim()}`
366
- : '@<shell specialist>';
367
- const shellPolicyTailZh = shellPolicy === 'specialist_only'
368
- ? [
729
+ function formatVcsSessionRound2TellaskBody(language, round1Response) {
730
+ const round1Anchor = takeFirstNonEmptyLine(round1Response) ?? '(empty)';
731
+ if (language === 'zh') {
732
+ return [
733
+ `这是同一长线诉请(session: ${PRIMING_VCS_SESSION_SLUG})的 Round-2。Round-1 已结束,本轮是新的续推诉请。`,
734
+ `Round-1 摘要锚点:${round1Anchor}`,
369
735
  '',
370
- `约束提醒:后续如需任何 shell 命令,必须诉请 shell 专员(${shellSpecialistMention})执行并回传;此智能体不应自行执行。`,
371
- ].join('\n')
372
- : shellPolicy === 'no_specialist'
373
- ? [
374
- '',
375
- '约束提醒:本团队无 shell 专员,因此后续**不能执行任意 shell 命令**;只能通过文件读写等非 shell 工具推进。',
376
- ].join('\n')
377
- : '';
378
- const shellPolicyTailEn = shellPolicy === 'specialist_only'
379
- ? [
736
+ '请继续确认 Round-1 涉及到的每一个 repo:',
737
+ '- remote(fetch/push)现状',
738
+ '- 当前 branch / upstream 现状',
739
+ '- 工作区是否脏(可给简要计数)',
380
740
  '',
381
- `Constraint: if we need any shell command later, we must Tellask the shell specialist (${shellSpecialistMention}) to run it and return; this agent must not run it directly.`,
382
- ].join('\n')
383
- : shellPolicy === 'no_specialist'
384
- ? [
385
- '',
386
- 'Constraint: this team has no shell specialist, so we must **not run arbitrary shell commands**; proceed only with non-shell tools like file read/write.',
387
- ].join('\n')
388
- : '';
741
+ '要求:',
742
+ '- 只使用 git 命令逐 repo 采集,不要用 python/node/perl',
743
+ '- 建议命令:`git -C <repo> remote -v`、`git -C <repo> branch --show-current`、`git -C <repo> rev-parse --abbrev-ref --symbolic-full-name @{upstream}`、`git -C <repo> status --porcelain`',
744
+ '- 覆盖全部 repo;缺失时明确写 unavailable',
745
+ '- 输出保持结构化与简短,不扩展到修复建议',
746
+ ].join('\n');
747
+ }
748
+ return [
749
+ `This is Round-2 of the same Tellask Session (${PRIMING_VCS_SESSION_SLUG}). Round-1 is closed; this is a new continuation Tellask.`,
750
+ `Round-1 anchor: ${round1Anchor}`,
751
+ '',
752
+ 'For every repo covered by Round-1, continue with:',
753
+ '- remote status (fetch/push)',
754
+ '- current branch / upstream status',
755
+ '- whether working tree is dirty (brief count is enough)',
756
+ '',
757
+ 'Requirements:',
758
+ '- use git commands repo-by-repo; do not use python/node/perl scripts',
759
+ '- suggested commands: `git -C <repo> remote -v`, `git -C <repo> branch --show-current`, `git -C <repo> rev-parse --abbrev-ref --symbolic-full-name @{upstream}`, `git -C <repo> status --porcelain`',
760
+ '- cover all repos; mark unavailable when missing',
761
+ '- keep output structured and short; do not expand into fix proposals',
762
+ ].join('\n');
763
+ }
764
+ function formatRuntimeVcsRoundNote(language, round, content) {
765
+ if (language === 'zh') {
766
+ return [
767
+ `由 Dominds 运行时执行 VCS 盘点 Round-${round}(标准模式,非降级):`,
768
+ '',
769
+ content,
770
+ '',
771
+ ].join('\n');
772
+ }
773
+ return [
774
+ `Dominds runtime VCS inventory Round-${round} (standard mode, not degraded):`,
775
+ '',
776
+ content,
777
+ '',
778
+ ].join('\n');
779
+ }
780
+ function formatFbrSelfTeaser(language) {
781
+ if (language === 'zh') {
782
+ return '(我会先等待该次 FBR 的全部支线反馈返回;在收齐前不做最终行动决策。收齐后再综合提炼,并在主线对话中输出一条可复用的“智能体启动(Agent Priming)”笔记。)';
783
+ }
784
+ return '(I will first wait for all feedback from this FBR run and will not finalize next-action decisions before that. After all feedback returns, I will distill it into a reusable “Agent Priming” note in mainline.)';
785
+ }
786
+ function formatFbrTellaskBody(language, snapshotText, options) {
389
787
  const effortLineZh = options.fbrEffort >= 1
390
- ? '运行时提示:运行时会生成多份“初心自我”独立推理草稿,供上游对话综合提炼(这些草稿之间没有稳定映射关系,不要把它们当作固定身份)。请给出你这一份独立分析。'
788
+ ? '运行时提示:运行时会生成多份“初心自我”独立推理草稿,供上游对话综合提炼(这些草稿之间没有稳定映射关系,不要把它们当作固定身份)。上游对话会在收齐全部回贴后才综合决策;请只给出你这一份独立分析,不要替上游下最终行动决策。'
391
789
  : '运行时提示:本成员已禁用 FBR。';
392
790
  const effortLineEn = options.fbrEffort >= 1
393
- ? 'Runtime note: the runtime will generate multiple independent “fresh boots” drafts for the upstream dialog to distill (no stable mapping—do not treat them as fixed identities). Please produce your own independent analysis.'
791
+ ? 'Runtime note: the runtime will generate multiple independent “fresh boots” drafts for the upstream dialog to distill (no stable mapping—do not treat them as fixed identities). The upstream dialog will decide only after all feedback returns; provide your own draft only and do not finalize upstream next-action decisions.'
394
792
  : 'Runtime note: FBR is disabled for this member.';
395
793
  const tellaskBackHintZh = (() => {
396
- if (shellPolicy === 'specialist_only') {
397
- return [
398
- '提示:如果你还想知道更多系统细节(`uname -a` 之外),可在本 FBR 支线对话中用 `!?@tellasker` 回问诉请者(上游对话)——例如“请补充哪些日志/配置/报错、以及你希望我重点评估哪些风险”。',
399
- `诉请者可据此选择不违反安全协议的命令,并交由 shell 专员(${shellSpecialistMention})执行回传。`,
400
- '(当前这次 FBR 请不要真的发起任何诉请;只需说明你会回问什么。)',
401
- ].join('\n');
402
- }
403
- if (shellPolicy === 'no_specialist') {
404
- return [
405
- '提示:如果你还想知道更多系统细节(`uname -a` 之外),可在本 FBR 支线对话中用 `!?@tellasker` 回问诉请者(上游对话)补充信息。',
406
- '注意:本团队无 shell 专员,因此仍然**不得执行任意 shell 命令**;只能请求补充文本材料(文件片段/日志/配置/运行报错等)。',
407
- '(当前这次 FBR 请不要真的发起任何诉请;只需说明你会回问什么。)',
408
- ].join('\n');
409
- }
410
794
  return [
411
- '提示:如果你还想知道更多系统细节(`uname -a` 之外),可在本 FBR 支线对话中用 `!?@tellasker` 回问诉请者(上游对话)。',
795
+ '提示:如果你还想知道更多系统细节,可在本 FBR 支线对话中用 `!?@tellasker` 回问诉请者(上游对话)。',
412
796
  '(当前这次 FBR 请不要真的发起任何诉请;只需说明你会回问什么。)',
413
797
  ].join('\n');
414
798
  })();
415
799
  const tellaskBackHintEn = (() => {
416
- if (shellPolicy === 'specialist_only') {
417
- return [
418
- 'Hint: if you want more system details beyond `uname -a`, ask back in this FBR sideline dialog via `!?@tellasker` (to the upstream tellasker dialog).',
419
- `Then the tellasker can choose safety-compliant follow-up commands and have the shell specialist (${shellSpecialistMention}) run and return them.`,
420
- '(In this FBR run, do not actually emit any tellasks; just state what you would ask back.)',
421
- ].join('\n');
422
- }
423
- if (shellPolicy === 'no_specialist') {
424
- return [
425
- 'Hint: if you want more system details beyond `uname -a`, ask back in this FBR sideline dialog via `!?@tellasker` (to the upstream tellasker dialog).',
426
- 'Note: there is no shell specialist in this team, so do **not** run arbitrary shell commands; request additional text materials only (file snippets/logs/configs/errors).',
427
- '(In this FBR run, do not actually emit any tellasks; just state what you would ask back.)',
428
- ].join('\n');
429
- }
430
800
  return [
431
- 'Hint: if you want more system details beyond `uname -a`, ask back in this FBR sideline dialog via `!?@tellasker` (to the upstream tellasker dialog).',
801
+ 'Hint: if you want more system details, ask back in this FBR sideline dialog via `!?@tellasker` (to the upstream tellasker dialog).',
432
802
  '(In this FBR run, do not actually emit any tellasks; just state what you would ask back.)',
433
803
  ].join('\n');
434
804
  })();
435
805
  if (language === 'zh') {
436
806
  return [
437
- '你正在进行一次“扪心自问”(FBR)。你**没有任何工具**:不能调用工具,只能使用本文本推理。',
438
807
  effortLineZh,
439
808
  '',
440
809
  tellaskBackHintZh,
441
810
  '',
442
811
  '请基于下面环境信息回答:',
443
812
  '- 在这个环境里要注意些什么?',
444
- '- 优先利用哪些命令行工具,为什么?',
813
+ '- 哪些关键上下文仍然缺失?',
814
+ '- 请明确区分:事实依据 / 不确定项 / 建议下一步(供上游收齐草稿后综合)。',
445
815
  '',
446
- `环境信息(当前 Dominds 运行时真实环境快照;来自命令:\`${snapshotCmd}\`):`,
816
+ '环境信息(当前 Dominds 运行时环境快照):',
447
817
  snapshotText,
448
- shellPolicyTailZh,
449
818
  ].join('\n');
450
819
  }
451
820
  return [
452
- 'You are doing Fresh Boots Reasoning (FBR). You have **no tools**: do not call tools; reason with text only.',
453
821
  effortLineEn,
454
822
  '',
455
823
  tellaskBackHintEn,
456
824
  '',
457
825
  'Based on the environment info below, answer:',
458
826
  '- What should we watch out for in this environment?',
459
- '- Which CLI tools should we prioritize, and why?',
827
+ '- What critical context is still missing?',
828
+ '- Clearly separate: factual evidence / uncertainties / suggested next step (for upstream synthesis after all drafts return).',
460
829
  '',
461
- `Environment info (a real snapshot of the current Dominds runtime; from \`${snapshotCmd}\`):`,
830
+ 'Environment info (a snapshot of the current Dominds runtime):',
462
831
  snapshotText,
463
- shellPolicyTailEn,
464
832
  ].join('\n');
465
833
  }
466
834
  async function generatePrimingNoteViaMainlineAgent(options) {
467
- const { dlg, shellSnapshotText, shellResponseText, fbrResponses, fbrTellaskHead, fbrCallId } = options;
835
+ const { dlg, shellSnapshotText, shellResponseText, vcsRound1Text, vcsRound2Text, fbrResponses, fbrTellaskHead, fbrCallId, } = options;
468
836
  // Trigger a normal drive and rely on driver.ts context assembly.
469
837
  // Agent Priming must not trigger Diligence Push (“鞭策”); it should be best-effort
470
838
  // one-shot distillation with no keep-going injection.
@@ -490,6 +858,18 @@ async function generatePrimingNoteViaMainlineAgent(options) {
490
858
  ? ['Shell 反馈(完整回传):', shellReturnTrimmed].join('\n')
491
859
  : ['Shell feedback (full return):', shellReturnTrimmed].join('\n'));
492
860
  }
861
+ const vcsRound1Trimmed = typeof vcsRound1Text === 'string' ? vcsRound1Text.trim() : '';
862
+ if (vcsRound1Trimmed) {
863
+ evidenceParts.push(language === 'zh'
864
+ ? ['VCS Session Round-1 结果:', vcsRound1Trimmed].join('\n')
865
+ : ['VCS session Round-1 result:', vcsRound1Trimmed].join('\n'));
866
+ }
867
+ const vcsRound2Trimmed = typeof vcsRound2Text === 'string' ? vcsRound2Text.trim() : '';
868
+ if (vcsRound2Trimmed) {
869
+ evidenceParts.push(language === 'zh'
870
+ ? ['VCS Session Round-2 结果:', vcsRound2Trimmed].join('\n')
871
+ : ['VCS session Round-2 result:', vcsRound2Trimmed].join('\n'));
872
+ }
493
873
  const maxDrafts = Math.min(6, fbrResponses.length);
494
874
  for (let i = 0; i < maxDrafts; i++) {
495
875
  const r = fbrResponses[i];
@@ -531,6 +911,7 @@ async function generatePrimingNoteViaMainlineAgent(options) {
531
911
  const internalPrompt = language === 'zh'
532
912
  ? [
533
913
  '你正在进行智能体启动(Agent Priming)的“综合提炼”步骤。',
914
+ '你收到本提示时,意味着该次 `!?@self` FBR 的并发回贴已经收齐;本步骤只做综合提炼,不重新发起 FBR。',
534
915
  '请基于下方提供的环境快照(以及可选的 `!?@self` FBR 草稿),综合提炼出一条可复用的“智能体启动(Agent Priming)笔记”。',
535
916
  '',
536
917
  '证据材料(仅供综合提炼;不要逐条复述):',
@@ -544,9 +925,11 @@ async function generatePrimingNoteViaMainlineAgent(options) {
544
925
  '- 去重并消解冲突,只保留最关键的结论',
545
926
  '- 用 6~12 条 bullet points 输出(每条尽量短)',
546
927
  '- 只写结论要点;不要输出推理过程,也不要出现“我在考虑/我将要/让我们检查”等元话语',
928
+ '- 必须明确写出:收到回贴代表该轮诉请结束;继续推进必须显式发起下一轮诉请',
547
929
  ].join('\n')
548
930
  : [
549
931
  'You are in the Agent Priming distillation step.',
932
+ 'Receiving this prompt means feedback from this `!?@self` FBR run has already been collected; this step is synthesis/distillation only, not another FBR initiation.',
550
933
  'Based on the environment snapshot (and optional `!?@self` FBR drafts) below, distill a reusable “Agent Priming note”.',
551
934
  '',
552
935
  'Evidence (for distillation only; do not repeat draft-by-draft):',
@@ -560,6 +943,7 @@ async function generatePrimingNoteViaMainlineAgent(options) {
560
943
  '- Dedupe and reconcile conflicts; keep only the key conclusions',
561
944
  '- Output 6–12 concise bullet points',
562
945
  '- Conclusion bullets only; no reasoning narration or meta talk (e.g. “I think / I will / let’s inspect”)',
946
+ '- Explicitly include this rule: a delivered response closes the current Tellask round; continuation requires a new explicit Tellask',
563
947
  ].join('\n');
564
948
  // IMPORTANT: this is an internal (non-persisted) prompt. driver.ts will inject it into
565
949
  // the LLM context for this drive only, without polluting dialog history.
@@ -589,20 +973,20 @@ function buildCoursePrefixMsgs(entry) {
589
973
  const header = (() => {
590
974
  if (language === 'zh') {
591
975
  if (entry.shellPolicy === 'specialist_only') {
592
- return '智能体启动(Agent Priming)上下文:本进程在对话创建时已真实跑通一次“诉请(shell 专员)+ 回传 + `!?@self` FBR + 综合提炼”。以下为压缩转录,作为每一程对话的开头上下文注入。';
976
+ return '智能体启动(Agent Priming)上下文:本进程在对话创建时已真实跑通一次“诉请(shell 专员)+ 回传 + `!?@self` FBR + 综合提炼”,并遵循“发起 FBR → 等待回贴 → 综合决策”的时序。以下为压缩转录,作为每一程对话的开头上下文注入。';
593
977
  }
594
978
  if (entry.shellPolicy === 'no_specialist') {
595
- return '智能体启动(Agent Priming)上下文:本进程在对话创建时已获取环境快照并完成一次 `!?@self` FBR + 综合提炼(无 shell 专员;不得执行任意 shell 命令)。以下为压缩转录,作为每一程对话的开头上下文注入。';
979
+ return '智能体启动(Agent Priming)上下文:本进程在对话创建时已获取环境快照并完成一次 `!?@self` FBR + 综合提炼(无 shell 专员;不得执行任意 shell 命令),并遵循“发起 FBR → 等待回贴 → 综合决策”的时序。以下为压缩转录,作为每一程对话的开头上下文注入。';
596
980
  }
597
- return '智能体启动(Agent Priming)上下文:本进程在对话创建时已获取环境快照并完成一次 `!?@self` FBR + 综合提炼。以下为压缩转录,作为每一程对话的开头上下文注入。';
981
+ return '智能体启动(Agent Priming)上下文:本进程在对话创建时已获取环境快照并完成一次 `!?@self` FBR + 综合提炼,并遵循“发起 FBR → 等待回贴 → 综合决策”的时序。以下为压缩转录,作为每一程对话的开头上下文注入。';
598
982
  }
599
983
  if (entry.shellPolicy === 'specialist_only') {
600
- return 'Agent Priming context: this process already ran a real Tellask (shell specialist) + return + `!?@self` FBR + distillation at dialog creation. The condensed transcript below is injected at the start of each course.';
984
+ return 'Agent Priming context: this process already ran a real Tellask (shell specialist) + return + `!?@self` FBR + distillation at dialog creation, following the timing contract “initiate FBR -> wait for feedback -> synthesize/decide”. The condensed transcript below is injected at the start of each course.';
601
985
  }
602
986
  if (entry.shellPolicy === 'no_specialist') {
603
- return 'Agent Priming context: this process captured an environment snapshot and ran `!?@self` FBR + distillation at dialog creation (no shell specialist; do not run arbitrary shell commands). The condensed transcript below is injected at the start of each course.';
987
+ return 'Agent Priming context: this process captured an environment snapshot and ran `!?@self` FBR + distillation at dialog creation (no shell specialist; do not run arbitrary shell commands), following the timing contract “initiate FBR -> wait for feedback -> synthesize/decide”. The condensed transcript below is injected at the start of each course.';
604
988
  }
605
- return 'Agent Priming context: this process captured an environment snapshot and ran `!?@self` FBR + distillation at dialog creation. The condensed transcript below is injected at the start of each course.';
989
+ return 'Agent Priming context: this process captured an environment snapshot and ran `!?@self` FBR + distillation at dialog creation, following the timing contract “initiate FBR -> wait for feedback -> synthesize/decide”. The condensed transcript below is injected at the start of each course.';
606
990
  })();
607
991
  const shellSnapshotLabel = language === 'zh'
608
992
  ? 'Shell 环境快照(当前 Dominds 运行时;来自 `uname -a`)'
@@ -612,8 +996,16 @@ function buildCoursePrefixMsgs(entry) {
612
996
  : language === 'zh'
613
997
  ? '(无)'
614
998
  : '(empty)';
999
+ const vcsInventoryLabel = language === 'zh' ? 'VCS 现状盘点(rtws)' : 'VCS inventory (rtws)';
1000
+ const vcsInventory = entry.vcs.inventoryText.trim()
1001
+ ? entry.vcs.inventoryText.trim()
1002
+ : language === 'zh'
1003
+ ? '(无)'
1004
+ : '(empty)';
615
1005
  const effort = Math.max(0, Math.floor(entry.fbr.effort));
616
- const fbrLabel = language === 'zh' ? 'FBR 输出(摘要)' : 'FBR outputs (summary)';
1006
+ const fbrLabel = language === 'zh'
1007
+ ? 'FBR 输出(摘要;主线在收齐回贴后综合)'
1008
+ : 'FBR outputs (summary; synthesized after all feedback is collected)';
617
1009
  const previewCap = Math.min(entry.fbr.responses.length, Math.max(0, Math.min(6, effort)));
618
1010
  const previewResponses = previewCap > 0 ? entry.fbr.responses.slice(0, previewCap) : [];
619
1011
  const blocks = [];
@@ -647,6 +1039,11 @@ function buildCoursePrefixMsgs(entry) {
647
1039
  role: 'user',
648
1040
  content: `${shellSnapshotLabel}:\n\n${shellSnapshot}`,
649
1041
  },
1042
+ {
1043
+ type: 'environment_msg',
1044
+ role: 'user',
1045
+ content: `${vcsInventoryLabel}:\n\n${vcsInventory}`,
1046
+ },
650
1047
  {
651
1048
  type: 'environment_msg',
652
1049
  role: 'user',
@@ -723,6 +1120,99 @@ async function replayAgentPriming(dlg, entry) {
723
1120
  originMemberId: dlg.agentId,
724
1121
  });
725
1122
  }
1123
+ // Phase 2.5: VCS long-session drill (two rounds)
1124
+ if (entry.vcs.kind === 'specialist_session') {
1125
+ let round1CallId = null;
1126
+ let round1TellaskHead = null;
1127
+ let round2CallId = null;
1128
+ let round2TellaskHead = null;
1129
+ try {
1130
+ await dlg.notifyGeneratingStart();
1131
+ const round1Content = [
1132
+ `!?@${entry.vcs.specialistId} !tellaskSession ${entry.vcs.sessionSlug}`,
1133
+ ...prefixTellaskBodyLines(entry.vcs.round1.tellaskBody).split('\n'),
1134
+ '',
1135
+ ].join('\n');
1136
+ const round1Calls = await emitSayingEventsAndPersist(dlg, round1Content);
1137
+ const round1 = round1Calls.find((c) => c.validation.kind === 'valid');
1138
+ if (round1) {
1139
+ round1CallId = round1.callId;
1140
+ round1TellaskHead = round1.tellaskHead;
1141
+ }
1142
+ }
1143
+ finally {
1144
+ try {
1145
+ await dlg.notifyGeneratingFinish();
1146
+ }
1147
+ catch (_finishErr) {
1148
+ // best-effort
1149
+ }
1150
+ }
1151
+ if (round1CallId && round1TellaskHead) {
1152
+ await dlg.receiveTeammateResponse(entry.vcs.specialistId, round1TellaskHead, 'completed', dlg.id, {
1153
+ response: entry.vcs.round1.responseText,
1154
+ agentId: entry.vcs.specialistId,
1155
+ callId: round1CallId,
1156
+ originMemberId: dlg.agentId,
1157
+ });
1158
+ }
1159
+ try {
1160
+ await dlg.notifyGeneratingStart();
1161
+ const round2Content = [
1162
+ `!?@${entry.vcs.specialistId} !tellaskSession ${entry.vcs.sessionSlug}`,
1163
+ ...prefixTellaskBodyLines(entry.vcs.round2.tellaskBody).split('\n'),
1164
+ '',
1165
+ ].join('\n');
1166
+ const round2Calls = await emitSayingEventsAndPersist(dlg, round2Content);
1167
+ const round2 = round2Calls.find((c) => c.validation.kind === 'valid');
1168
+ if (round2) {
1169
+ round2CallId = round2.callId;
1170
+ round2TellaskHead = round2.tellaskHead;
1171
+ }
1172
+ }
1173
+ finally {
1174
+ try {
1175
+ await dlg.notifyGeneratingFinish();
1176
+ }
1177
+ catch (_finishErr) {
1178
+ // best-effort
1179
+ }
1180
+ }
1181
+ if (round2CallId && round2TellaskHead) {
1182
+ await dlg.receiveTeammateResponse(entry.vcs.specialistId, round2TellaskHead, 'completed', dlg.id, {
1183
+ response: entry.vcs.round2.responseText,
1184
+ agentId: entry.vcs.specialistId,
1185
+ callId: round2CallId,
1186
+ originMemberId: dlg.agentId,
1187
+ });
1188
+ }
1189
+ }
1190
+ else {
1191
+ try {
1192
+ await dlg.notifyGeneratingStart();
1193
+ await emitSayingEventsAndPersist(dlg, entry.vcs.round1NoteMarkdown);
1194
+ }
1195
+ finally {
1196
+ try {
1197
+ await dlg.notifyGeneratingFinish();
1198
+ }
1199
+ catch (_finishErr) {
1200
+ // best-effort
1201
+ }
1202
+ }
1203
+ try {
1204
+ await dlg.notifyGeneratingStart();
1205
+ await emitSayingEventsAndPersist(dlg, entry.vcs.round2NoteMarkdown);
1206
+ }
1207
+ finally {
1208
+ try {
1209
+ await dlg.notifyGeneratingFinish();
1210
+ }
1211
+ catch (_finishErr) {
1212
+ // best-effort
1213
+ }
1214
+ }
1215
+ }
726
1216
  // Phase 3: FBR ask (call bubble)
727
1217
  let fbrCallId = null;
728
1218
  let fbrTellaskHead = null;
@@ -800,6 +1290,10 @@ async function replayAgentPriming(dlg, entry) {
800
1290
  async function runAgentPrimingLive(dlg) {
801
1291
  const createdAt = (0, time_1.formatUnifiedTimestamp)(new Date());
802
1292
  const language = (0, runtime_language_1.getWorkLanguage)();
1293
+ const prevDisableDiligencePush = dlg.disableDiligencePush;
1294
+ // Agent Priming is a bounded bootstrap routine; no keep-going injection should appear
1295
+ // during the priming lifecycle (including any auto-revive drives triggered by subdialog replies).
1296
+ dlg.disableDiligencePush = true;
803
1297
  let fatalRunState = null;
804
1298
  let shellPolicy = 'no_specialist';
805
1299
  let specialistId = null;
@@ -807,6 +1301,15 @@ async function runAgentPrimingLive(dlg) {
807
1301
  let shellResponseText = '';
808
1302
  let snapshotText = '';
809
1303
  let directNoteMarkdown = '';
1304
+ let vcsRound1Body = '';
1305
+ let vcsRound2Body = '';
1306
+ let vcsRound1ResponseText = '';
1307
+ let vcsRound2ResponseText = '';
1308
+ let vcsEvidenceRound1Text = '';
1309
+ let vcsEvidenceRound2Text = '';
1310
+ let vcsRound1NoteMarkdown = '';
1311
+ let vcsRound2NoteMarkdown = '';
1312
+ let vcsInventoryText = '';
810
1313
  let fbrCallBody = '';
811
1314
  let selfTeaser = '';
812
1315
  let fbrEffort = 0;
@@ -946,7 +1449,7 @@ async function runAgentPrimingLive(dlg) {
946
1449
  language,
947
1450
  collectiveTargets: [ensuredSpecialistId],
948
1451
  });
949
- await (0, driver_1.driveDialogStream)(sub, { content: initPrompt, msgId: (0, id_1.generateShortId)(), grammar: 'markdown' }, true);
1452
+ await (0, driver_1.driveDialogStream)(sub, { content: initPrompt, msgId: (0, id_1.generateShortId)(), grammar: 'markdown', skipTaskdoc: true }, true);
950
1453
  shellResponseText = extractLastAssistantSaying(sub.msgs);
951
1454
  const toolResult = extractLastShellCmdResultText(sub.msgs);
952
1455
  snapshotText = toolResult ? toolResult : shellResponseText;
@@ -964,6 +1467,202 @@ async function runAgentPrimingLive(dlg) {
964
1467
  });
965
1468
  });
966
1469
  }
1470
+ // Phase 2.5: VCS tellask-session drill (two rounds) or runtime inventory.
1471
+ if (shellPolicy === 'specialist_only' && specialistId !== null) {
1472
+ const ensuredSpecialistId = specialistId;
1473
+ try {
1474
+ vcsRound1Body = formatVcsSessionRound1TellaskBody(language);
1475
+ let round1CallId = '';
1476
+ let round1TellaskHead = '';
1477
+ let round1TellaskBodyForSubdialog = '';
1478
+ await dlg.withLock(async () => {
1479
+ try {
1480
+ await dlg.notifyGeneratingStart();
1481
+ const round1CallSaying = [
1482
+ `!?@${ensuredSpecialistId} !tellaskSession ${PRIMING_VCS_SESSION_SLUG}`,
1483
+ ...prefixTellaskBodyLines(vcsRound1Body).split('\n'),
1484
+ '',
1485
+ ].join('\n');
1486
+ const calls = await emitSayingEventsAndPersist(dlg, round1CallSaying);
1487
+ const call = calls.find((c) => c.validation.kind === 'valid');
1488
+ if (!call) {
1489
+ throw new Error('Failed to emit VCS session round-1 tellask call');
1490
+ }
1491
+ round1CallId = call.callId;
1492
+ round1TellaskHead = call.tellaskHead;
1493
+ round1TellaskBodyForSubdialog = call.body;
1494
+ }
1495
+ finally {
1496
+ try {
1497
+ await dlg.notifyGeneratingFinish();
1498
+ }
1499
+ catch (_finishErr) {
1500
+ // best-effort
1501
+ }
1502
+ }
1503
+ });
1504
+ const round1Sub = await dlg.withLock(async () => {
1505
+ return await dlg.createSubDialog(ensuredSpecialistId, round1TellaskHead, round1TellaskBodyForSubdialog || vcsRound1Body, {
1506
+ originMemberId: dlg.agentId,
1507
+ callerDialogId: dlg.id.selfId,
1508
+ callId: round1CallId,
1509
+ tellaskSession: PRIMING_VCS_SESSION_SLUG,
1510
+ collectiveTargets: [ensuredSpecialistId],
1511
+ });
1512
+ });
1513
+ const rootDialog = dlg instanceof dialog_1.RootDialog ? dlg : dlg instanceof dialog_1.SubDialog ? dlg.rootDialog : undefined;
1514
+ if (rootDialog) {
1515
+ rootDialog.registerSubdialog(round1Sub);
1516
+ await rootDialog.saveSubdialogRegistry();
1517
+ }
1518
+ const round1Prompt = (0, inter_dialog_format_1.formatAssignmentFromSupdialog)({
1519
+ fromAgentId: dlg.agentId,
1520
+ toAgentId: round1Sub.agentId,
1521
+ tellaskHead: round1TellaskHead,
1522
+ tellaskBody: round1TellaskBodyForSubdialog || vcsRound1Body,
1523
+ language,
1524
+ collectiveTargets: [ensuredSpecialistId],
1525
+ });
1526
+ await (0, driver_1.driveDialogStream)(round1Sub, {
1527
+ content: round1Prompt,
1528
+ msgId: (0, id_1.generateShortId)(),
1529
+ grammar: 'markdown',
1530
+ skipTaskdoc: true,
1531
+ }, true);
1532
+ vcsRound1ResponseText = extractLastAssistantSaying(round1Sub.msgs).trim();
1533
+ if (!vcsRound1ResponseText) {
1534
+ throw new Error('Specialist VCS session round-1 returned empty output');
1535
+ }
1536
+ await dlg.withLock(async () => {
1537
+ await dlg.receiveTeammateResponse(ensuredSpecialistId, round1TellaskHead, 'completed', round1Sub.id, {
1538
+ response: vcsRound1ResponseText,
1539
+ agentId: ensuredSpecialistId,
1540
+ callId: round1CallId,
1541
+ originMemberId: dlg.agentId,
1542
+ });
1543
+ });
1544
+ vcsRound2Body = formatVcsSessionRound2TellaskBody(language, vcsRound1ResponseText);
1545
+ let round2CallId = '';
1546
+ let round2TellaskHead = '';
1547
+ let round2TellaskBodyForSubdialog = '';
1548
+ await dlg.withLock(async () => {
1549
+ try {
1550
+ await dlg.notifyGeneratingStart();
1551
+ const round2CallSaying = [
1552
+ `!?@${ensuredSpecialistId} !tellaskSession ${PRIMING_VCS_SESSION_SLUG}`,
1553
+ ...prefixTellaskBodyLines(vcsRound2Body).split('\n'),
1554
+ '',
1555
+ ].join('\n');
1556
+ const calls = await emitSayingEventsAndPersist(dlg, round2CallSaying);
1557
+ const call = calls.find((c) => c.validation.kind === 'valid');
1558
+ if (!call) {
1559
+ throw new Error('Failed to emit VCS session round-2 tellask call');
1560
+ }
1561
+ round2CallId = call.callId;
1562
+ round2TellaskHead = call.tellaskHead;
1563
+ round2TellaskBodyForSubdialog = call.body;
1564
+ }
1565
+ finally {
1566
+ try {
1567
+ await dlg.notifyGeneratingFinish();
1568
+ }
1569
+ catch (_finishErr) {
1570
+ // best-effort
1571
+ }
1572
+ }
1573
+ });
1574
+ const round2Prompt = (0, inter_dialog_format_1.formatAssignmentFromSupdialog)({
1575
+ fromAgentId: dlg.agentId,
1576
+ toAgentId: round1Sub.agentId,
1577
+ tellaskHead: round2TellaskHead,
1578
+ tellaskBody: round2TellaskBodyForSubdialog || vcsRound2Body,
1579
+ language,
1580
+ collectiveTargets: [ensuredSpecialistId],
1581
+ });
1582
+ await (0, driver_1.driveDialogStream)(round1Sub, {
1583
+ content: round2Prompt,
1584
+ msgId: (0, id_1.generateShortId)(),
1585
+ grammar: 'markdown',
1586
+ skipTaskdoc: true,
1587
+ }, true);
1588
+ vcsRound2ResponseText = extractLastAssistantSaying(round1Sub.msgs).trim();
1589
+ if (!vcsRound2ResponseText) {
1590
+ throw new Error('Specialist VCS session round-2 returned empty output');
1591
+ }
1592
+ await dlg.withLock(async () => {
1593
+ await dlg.receiveTeammateResponse(ensuredSpecialistId, round2TellaskHead, 'completed', round1Sub.id, {
1594
+ response: vcsRound2ResponseText,
1595
+ agentId: ensuredSpecialistId,
1596
+ callId: round2CallId,
1597
+ originMemberId: dlg.agentId,
1598
+ });
1599
+ });
1600
+ vcsInventoryText = [vcsRound1ResponseText, '', vcsRound2ResponseText].join('\n');
1601
+ }
1602
+ catch (err) {
1603
+ log_1.log.warn('VCS tellask-session drill via shell specialist failed; fallback to runtime inventory', err, {
1604
+ dialogId: dlg.id.valueOf(),
1605
+ specialistId: ensuredSpecialistId,
1606
+ });
1607
+ }
1608
+ }
1609
+ const runtimeInventory = await collectRtwsGitInventory();
1610
+ const runtimeRound1Text = formatRtwsGitInventoryRound1(language, runtimeInventory);
1611
+ const runtimeRound2Text = formatRtwsGitInventoryRound2(language, runtimeInventory);
1612
+ const runtimeInventoryText = [runtimeRound1Text, '', runtimeRound2Text].join('\n');
1613
+ if (shellPolicy === 'specialist_only' &&
1614
+ specialistId !== null &&
1615
+ vcsRound1ResponseText.trim() &&
1616
+ vcsRound2ResponseText.trim()) {
1617
+ // Keep teammate replies as collaboration transcript, but use runtime-verified
1618
+ // inventory as canonical facts for downstream FBR/distillation evidence.
1619
+ vcsEvidenceRound1Text = runtimeRound1Text;
1620
+ vcsEvidenceRound2Text = runtimeRound2Text;
1621
+ vcsInventoryText = runtimeInventoryText;
1622
+ }
1623
+ else {
1624
+ vcsRound1ResponseText = runtimeRound1Text;
1625
+ vcsRound2ResponseText = runtimeRound2Text;
1626
+ vcsEvidenceRound1Text = runtimeRound1Text;
1627
+ vcsEvidenceRound2Text = runtimeRound2Text;
1628
+ vcsRound1NoteMarkdown = formatRuntimeVcsRoundNote(language, 1, vcsRound1ResponseText);
1629
+ vcsRound2NoteMarkdown = formatRuntimeVcsRoundNote(language, 2, vcsRound2ResponseText);
1630
+ vcsInventoryText = runtimeInventoryText;
1631
+ await dlg.withLock(async () => {
1632
+ try {
1633
+ await dlg.notifyGeneratingStart();
1634
+ await emitSayingEventsAndPersist(dlg, vcsRound1NoteMarkdown);
1635
+ }
1636
+ finally {
1637
+ try {
1638
+ await dlg.notifyGeneratingFinish();
1639
+ }
1640
+ catch (_finishErr) {
1641
+ // best-effort
1642
+ }
1643
+ }
1644
+ });
1645
+ await dlg.withLock(async () => {
1646
+ try {
1647
+ await dlg.notifyGeneratingStart();
1648
+ await emitSayingEventsAndPersist(dlg, vcsRound2NoteMarkdown);
1649
+ }
1650
+ finally {
1651
+ try {
1652
+ await dlg.notifyGeneratingFinish();
1653
+ }
1654
+ catch (_finishErr) {
1655
+ // best-effort
1656
+ }
1657
+ }
1658
+ });
1659
+ }
1660
+ const fbrSnapshotText = [
1661
+ snapshotText.trim() ? snapshotText.trim() : '',
1662
+ vcsInventoryText.trim() ? vcsInventoryText.trim() : '',
1663
+ ]
1664
+ .filter((part) => part !== '')
1665
+ .join('\n\n---\n\n');
967
1666
  const rawFbrEffort = member ? member.fbr_effort : undefined;
968
1667
  fbrEffort = (() => {
969
1668
  if (typeof rawFbrEffort !== 'number' || !Number.isFinite(rawFbrEffort))
@@ -976,7 +1675,7 @@ async function runAgentPrimingLive(dlg) {
976
1675
  }
977
1676
  return n;
978
1677
  })();
979
- fbrCallBody = formatFbrTellaskBody(language, BASELINE_ENV_SNAPSHOT_CMD, snapshotText, shellPolicy, specialistId, { fbrEffort });
1678
+ fbrCallBody = formatFbrTellaskBody(language, fbrSnapshotText.trim() ? fbrSnapshotText : snapshotText, { fbrEffort });
980
1679
  selfTeaser = formatFbrSelfTeaser(language);
981
1680
  let fbrCallId = null;
982
1681
  let fbrTellaskHead = null;
@@ -1022,8 +1721,8 @@ async function runAgentPrimingLive(dlg) {
1022
1721
  fbrCallBody,
1023
1722
  '',
1024
1723
  language === 'zh'
1025
- ? '提示:请尽量提供与其它 FBR 草稿不同的视角(例如安全/限制/可验证性/工具优先级/风险点)。'
1026
- : 'Hint: try to provide a distinct angle vs other FBR drafts (e.g. security/constraints/verifiability/tool priority/risk).',
1724
+ ? '提示:请尽量提供与其它 FBR 草稿不同的视角(例如安全/限制/可验证性/风险点)。'
1725
+ : 'Hint: try to provide a distinct angle vs other FBR drafts (e.g. security/constraints/verifiability/risk).',
1027
1726
  ].join('\n')
1028
1727
  : fbrCallBody;
1029
1728
  const sub = await dlg.withLock(async () => {
@@ -1042,7 +1741,12 @@ async function runAgentPrimingLive(dlg) {
1042
1741
  language,
1043
1742
  collectiveTargets: [dlg.agentId],
1044
1743
  });
1045
- await (0, driver_1.driveDialogStream)(sub, { content: initPrompt, msgId: (0, id_1.generateShortId)(), grammar: 'markdown' }, true);
1744
+ await (0, driver_1.driveDialogStream)(sub, {
1745
+ content: initPrompt,
1746
+ msgId: (0, id_1.generateShortId)(),
1747
+ grammar: 'markdown',
1748
+ skipTaskdoc: true,
1749
+ }, true);
1046
1750
  const responseText = extractLastAssistantSaying(sub.msgs);
1047
1751
  return { sub, responseText };
1048
1752
  }));
@@ -1072,6 +1776,8 @@ async function runAgentPrimingLive(dlg) {
1072
1776
  dlg,
1073
1777
  shellSnapshotText: snapshotText,
1074
1778
  shellResponseText: shellResponseText,
1779
+ vcsRound1Text: vcsEvidenceRound1Text,
1780
+ vcsRound2Text: vcsEvidenceRound2Text,
1075
1781
  fbrResponses: fbrResponsesForInjection,
1076
1782
  fbrTellaskHead: fbrTellaskHead,
1077
1783
  fbrCallId: fbrCallId,
@@ -1093,6 +1799,33 @@ async function runAgentPrimingLive(dlg) {
1093
1799
  directNoteMarkdown,
1094
1800
  snapshotText,
1095
1801
  },
1802
+ vcs: shellPolicy === 'specialist_only' &&
1803
+ specialistId !== null &&
1804
+ vcsRound1ResponseText.trim() &&
1805
+ vcsRound2ResponseText.trim()
1806
+ ? {
1807
+ kind: 'specialist_session',
1808
+ specialistId,
1809
+ sessionSlug: PRIMING_VCS_SESSION_SLUG,
1810
+ round1: {
1811
+ tellaskBody: vcsRound1Body || formatVcsSessionRound1TellaskBody(language),
1812
+ responseText: vcsRound1ResponseText,
1813
+ },
1814
+ round2: {
1815
+ tellaskBody: vcsRound2Body ||
1816
+ formatVcsSessionRound2TellaskBody(language, vcsRound1ResponseText),
1817
+ responseText: vcsRound2ResponseText,
1818
+ },
1819
+ inventoryText: vcsInventoryText,
1820
+ }
1821
+ : {
1822
+ kind: 'runtime_inventory',
1823
+ round1NoteMarkdown: vcsRound1NoteMarkdown ||
1824
+ formatRuntimeVcsRoundNote(language, 1, vcsRound1ResponseText),
1825
+ round2NoteMarkdown: vcsRound2NoteMarkdown ||
1826
+ formatRuntimeVcsRoundNote(language, 2, vcsRound2ResponseText),
1827
+ inventoryText: vcsInventoryText,
1828
+ },
1096
1829
  fbr: {
1097
1830
  tellaskHead: '@self',
1098
1831
  tellaskBody: fbrCallBody,
@@ -1146,6 +1879,7 @@ async function runAgentPrimingLive(dlg) {
1146
1879
  throw err;
1147
1880
  }
1148
1881
  finally {
1882
+ dlg.disableDiligencePush = prevDisableDiligencePush;
1149
1883
  if (fatalRunState) {
1150
1884
  await (0, dialog_run_state_1.setDialogRunState)(dlg.id, fatalRunState);
1151
1885
  }