dominds 1.2.5 → 1.2.7

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/agent-priming.js +2051 -0
  2. package/dist/apps/app-lock-file.js +228 -0
  3. package/dist/apps/assigned-port.js +124 -0
  4. package/dist/apps/enabled-apps.js +472 -7
  5. package/dist/apps/manifest.js +37 -0
  6. package/dist/apps/override-paths.js +19 -6
  7. package/dist/apps/problems.js +43 -0
  8. package/dist/apps/resolution-file.js +370 -0
  9. package/dist/apps/runtime.js +5 -17
  10. package/dist/apps/teammates.js +102 -1
  11. package/dist/cli/disable.js +10 -6
  12. package/dist/cli/enable.js +21 -19
  13. package/dist/cli/install.js +40 -18
  14. package/dist/cli/uninstall.js +6 -6
  15. package/dist/cli/update.js +38 -13
  16. package/dist/dialog.js +5 -0
  17. package/dist/docs/app-constitution.md +85 -18
  18. package/dist/docs/app-constitution.zh.md +86 -21
  19. package/dist/docs/dialog-system.md +1 -1
  20. package/dist/docs/dialog-system.zh.md +1 -1
  21. package/dist/docs/dominds-agent-priming.md +218 -0
  22. package/dist/docs/dominds-agent-priming.zh.md +196 -0
  23. package/dist/docs/drive-logic-context-refactor-plan.zh.md +338 -0
  24. package/dist/docs/keep-going.md +176 -0
  25. package/dist/docs/keep-going.zh.md +162 -0
  26. package/dist/docs/showing-by-doing.md +208 -0
  27. package/dist/docs/showing-by-doing.zh.md +177 -0
  28. package/dist/docs/team-mgmt-toolset.md +482 -0
  29. package/dist/docs/team-mgmt-toolset.zh.md +426 -0
  30. package/dist/llm/defaults.yaml +1 -1
  31. package/dist/llm/driver.js +4093 -0
  32. package/dist/llm/kernel-driver/drive.js +5 -2
  33. package/dist/llm/kernel-driver/flow.js +3 -0
  34. package/dist/minds/promptdocs.js +263 -0
  35. package/dist/problems.js +67 -16
  36. package/dist/server/api-routes.js +333 -0
  37. package/dist/server/prompts-routes.js +545 -0
  38. package/dist/server/server-core.js +4 -0
  39. package/dist/server/websocket-handler.js +17 -0
  40. package/dist/shared/team-mgmt-manual.js +120 -0
  41. package/dist/shared/types/prompts.js +2 -0
  42. package/dist/shared/types/tellask.js +8 -0
  43. package/dist/showing-by-doing.js +1091 -0
  44. package/dist/snippets/README.en.md +3 -0
  45. package/dist/snippets/README.md +4 -0
  46. package/dist/static/assets/{_basePickBy-CF9r08iy.js → _basePickBy-BMCtwrV7.js} +3 -3
  47. package/dist/static/assets/{_basePickBy-CF9r08iy.js.map → _basePickBy-BMCtwrV7.js.map} +1 -1
  48. package/dist/static/assets/{_baseUniq-CxKv0cd4.js → _baseUniq-BuyCgJiA.js} +2 -2
  49. package/dist/static/assets/{_baseUniq-CxKv0cd4.js.map → _baseUniq-BuyCgJiA.js.map} +1 -1
  50. package/dist/static/assets/{arc-C9JyvnlB.js → arc-BDuN8lwA.js} +2 -2
  51. package/dist/static/assets/{arc-C9JyvnlB.js.map → arc-BDuN8lwA.js.map} +1 -1
  52. package/dist/static/assets/{architectureDiagram-VXUJARFQ-CpcUgjHf.js → architectureDiagram-VXUJARFQ-C-ekqGAD.js} +7 -7
  53. package/dist/static/assets/{architectureDiagram-VXUJARFQ-CpcUgjHf.js.map → architectureDiagram-VXUJARFQ-C-ekqGAD.js.map} +1 -1
  54. package/dist/static/assets/{blockDiagram-VD42YOAC-BA9vtmm7.js → blockDiagram-VD42YOAC-CgQiNuuQ.js} +7 -7
  55. package/dist/static/assets/{blockDiagram-VD42YOAC-BA9vtmm7.js.map → blockDiagram-VD42YOAC-CgQiNuuQ.js.map} +1 -1
  56. package/dist/static/assets/{c4Diagram-YG6GDRKO-D49MGNdF.js → c4Diagram-YG6GDRKO-DONC39q-.js} +3 -3
  57. package/dist/static/assets/{c4Diagram-YG6GDRKO-D49MGNdF.js.map → c4Diagram-YG6GDRKO-DONC39q-.js.map} +1 -1
  58. package/dist/static/assets/{channel-B4KzL0Kg.js → channel-CJTFwXIG.js} +2 -2
  59. package/dist/static/assets/{channel-B4KzL0Kg.js.map → channel-CJTFwXIG.js.map} +1 -1
  60. package/dist/static/assets/{chunk-4BX2VUAB-0F-1ayl0.js → chunk-4BX2VUAB-NaIy4uLJ.js} +2 -2
  61. package/dist/static/assets/{chunk-4BX2VUAB-0F-1ayl0.js.map → chunk-4BX2VUAB-NaIy4uLJ.js.map} +1 -1
  62. package/dist/static/assets/{chunk-55IACEB6-Dnl2HDTZ.js → chunk-55IACEB6-JUKI_Ayx.js} +2 -2
  63. package/dist/static/assets/{chunk-55IACEB6-Dnl2HDTZ.js.map → chunk-55IACEB6-JUKI_Ayx.js.map} +1 -1
  64. package/dist/static/assets/{chunk-B4BG7PRW-Bhx5RbkQ.js → chunk-B4BG7PRW-dIswFJDn.js} +5 -5
  65. package/dist/static/assets/{chunk-B4BG7PRW-Bhx5RbkQ.js.map → chunk-B4BG7PRW-dIswFJDn.js.map} +1 -1
  66. package/dist/static/assets/{chunk-DI55MBZ5-EYd1wL3E.js → chunk-DI55MBZ5-DU2b_N30.js} +4 -4
  67. package/dist/static/assets/{chunk-DI55MBZ5-EYd1wL3E.js.map → chunk-DI55MBZ5-DU2b_N30.js.map} +1 -1
  68. package/dist/static/assets/{chunk-FMBD7UC4-DAjkhhUU.js → chunk-FMBD7UC4-BgExcScw.js} +2 -2
  69. package/dist/static/assets/{chunk-FMBD7UC4-DAjkhhUU.js.map → chunk-FMBD7UC4-BgExcScw.js.map} +1 -1
  70. package/dist/static/assets/{chunk-QN33PNHL-CK6TY7IE.js → chunk-QN33PNHL-bitxyqh7.js} +2 -2
  71. package/dist/static/assets/{chunk-QN33PNHL-CK6TY7IE.js.map → chunk-QN33PNHL-bitxyqh7.js.map} +1 -1
  72. package/dist/static/assets/{chunk-QZHKN3VN-CketngiE.js → chunk-QZHKN3VN-Cor8u7DT.js} +2 -2
  73. package/dist/static/assets/{chunk-QZHKN3VN-CketngiE.js.map → chunk-QZHKN3VN-Cor8u7DT.js.map} +1 -1
  74. package/dist/static/assets/{chunk-TZMSLE5B-Bcuvqo45.js → chunk-TZMSLE5B-Aceoxav_.js} +2 -2
  75. package/dist/static/assets/{chunk-TZMSLE5B-Bcuvqo45.js.map → chunk-TZMSLE5B-Aceoxav_.js.map} +1 -1
  76. package/dist/static/assets/{classDiagram-2ON5EDUG-CaP4T3r4.js → classDiagram-2ON5EDUG-D1Q6a8Hg.js} +6 -6
  77. package/dist/static/assets/{classDiagram-2ON5EDUG-CaP4T3r4.js.map → classDiagram-2ON5EDUG-D1Q6a8Hg.js.map} +1 -1
  78. package/dist/static/assets/{classDiagram-v2-WZHVMYZB-CaP4T3r4.js → classDiagram-v2-WZHVMYZB-D1Q6a8Hg.js} +6 -6
  79. package/dist/static/assets/{classDiagram-v2-WZHVMYZB-CaP4T3r4.js.map → classDiagram-v2-WZHVMYZB-D1Q6a8Hg.js.map} +1 -1
  80. package/dist/static/assets/{clone-C-JULvnG.js → clone-MlWbv1V0.js} +2 -2
  81. package/dist/static/assets/{clone-C-JULvnG.js.map → clone-MlWbv1V0.js.map} +1 -1
  82. package/dist/static/assets/{cose-bilkent-S5V4N54A-vXCmi_eC.js → cose-bilkent-S5V4N54A-DWPCXSrn.js} +2 -2
  83. package/dist/static/assets/{cose-bilkent-S5V4N54A-vXCmi_eC.js.map → cose-bilkent-S5V4N54A-DWPCXSrn.js.map} +1 -1
  84. package/dist/static/assets/{dagre-6UL2VRFP-bhGzX6kO.js → dagre-6UL2VRFP-C8ptQ9V3.js} +7 -7
  85. package/dist/static/assets/{dagre-6UL2VRFP-bhGzX6kO.js.map → dagre-6UL2VRFP-C8ptQ9V3.js.map} +1 -1
  86. package/dist/static/assets/{diagram-PSM6KHXK-BUKfmfGk.js → diagram-PSM6KHXK-Bgf1FqkE.js} +8 -8
  87. package/dist/static/assets/{diagram-PSM6KHXK-BUKfmfGk.js.map → diagram-PSM6KHXK-Bgf1FqkE.js.map} +1 -1
  88. package/dist/static/assets/{diagram-QEK2KX5R-DYlq3uFq.js → diagram-QEK2KX5R-BZ5xzofU.js} +7 -7
  89. package/dist/static/assets/{diagram-QEK2KX5R-DYlq3uFq.js.map → diagram-QEK2KX5R-BZ5xzofU.js.map} +1 -1
  90. package/dist/static/assets/{diagram-S2PKOQOG-CjxkLHWG.js → diagram-S2PKOQOG-Dwp47T9I.js} +7 -7
  91. package/dist/static/assets/{diagram-S2PKOQOG-CjxkLHWG.js.map → diagram-S2PKOQOG-Dwp47T9I.js.map} +1 -1
  92. package/dist/static/assets/{erDiagram-Q2GNP2WA-S3hR85On.js → erDiagram-Q2GNP2WA-Cx4weIHl.js} +5 -5
  93. package/dist/static/assets/{erDiagram-Q2GNP2WA-S3hR85On.js.map → erDiagram-Q2GNP2WA-Cx4weIHl.js.map} +1 -1
  94. package/dist/static/assets/{flowDiagram-NV44I4VS-aBmNMuQ0.js → flowDiagram-NV44I4VS-vNUuIeRk.js} +6 -6
  95. package/dist/static/assets/{flowDiagram-NV44I4VS-aBmNMuQ0.js.map → flowDiagram-NV44I4VS-vNUuIeRk.js.map} +1 -1
  96. package/dist/static/assets/{ganttDiagram-JELNMOA3-DJxXaiW1.js → ganttDiagram-JELNMOA3-BEfozJAr.js} +3 -3
  97. package/dist/static/assets/{ganttDiagram-JELNMOA3-DJxXaiW1.js.map → ganttDiagram-JELNMOA3-BEfozJAr.js.map} +1 -1
  98. package/dist/static/assets/{gitGraphDiagram-V2S2FVAM-DEOBCM0G.js → gitGraphDiagram-V2S2FVAM-eHxwc3d9.js} +8 -8
  99. package/dist/static/assets/{gitGraphDiagram-V2S2FVAM-DEOBCM0G.js.map → gitGraphDiagram-V2S2FVAM-eHxwc3d9.js.map} +1 -1
  100. package/dist/static/assets/{graph-DwrKSIE7.js → graph-C6a6uAok.js} +3 -3
  101. package/dist/static/assets/{graph-DwrKSIE7.js.map → graph-C6a6uAok.js.map} +1 -1
  102. package/dist/static/assets/{index-HWTRvE2k.js → index-D3TQbAKh.js} +383 -59
  103. package/dist/static/assets/index-D3TQbAKh.js.map +1 -0
  104. package/dist/static/assets/{infoDiagram-HS3SLOUP-BH9kVuYd.js → infoDiagram-HS3SLOUP-CX0NiId3.js} +6 -6
  105. package/dist/static/assets/{infoDiagram-HS3SLOUP-BH9kVuYd.js.map → infoDiagram-HS3SLOUP-CX0NiId3.js.map} +1 -1
  106. package/dist/static/assets/{journeyDiagram-XKPGCS4Q-Dap7AcjR.js → journeyDiagram-XKPGCS4Q-C1IepPZ-.js} +5 -5
  107. package/dist/static/assets/{journeyDiagram-XKPGCS4Q-Dap7AcjR.js.map → journeyDiagram-XKPGCS4Q-C1IepPZ-.js.map} +1 -1
  108. package/dist/static/assets/{kanban-definition-3W4ZIXB7-4NOl8MEj.js → kanban-definition-3W4ZIXB7-uMNX4Z1W.js} +3 -3
  109. package/dist/static/assets/{kanban-definition-3W4ZIXB7-4NOl8MEj.js.map → kanban-definition-3W4ZIXB7-uMNX4Z1W.js.map} +1 -1
  110. package/dist/static/assets/{layout-D6uIxu1E.js → layout-CpE3kk5z.js} +5 -5
  111. package/dist/static/assets/{layout-D6uIxu1E.js.map → layout-CpE3kk5z.js.map} +1 -1
  112. package/dist/static/assets/{linear-CvBOGQA2.js → linear-DV8laXr9.js} +2 -2
  113. package/dist/static/assets/{linear-CvBOGQA2.js.map → linear-DV8laXr9.js.map} +1 -1
  114. package/dist/static/assets/{mindmap-definition-VGOIOE7T-ugsrLNY5.js → mindmap-definition-VGOIOE7T-CKjgVM9S.js} +4 -4
  115. package/dist/static/assets/{mindmap-definition-VGOIOE7T-ugsrLNY5.js.map → mindmap-definition-VGOIOE7T-CKjgVM9S.js.map} +1 -1
  116. package/dist/static/assets/{pieDiagram-ADFJNKIX-CdVZjM8g.js → pieDiagram-ADFJNKIX-BBonlNyT.js} +8 -8
  117. package/dist/static/assets/{pieDiagram-ADFJNKIX-CdVZjM8g.js.map → pieDiagram-ADFJNKIX-BBonlNyT.js.map} +1 -1
  118. package/dist/static/assets/{quadrantDiagram-AYHSOK5B-A6m5lZKd.js → quadrantDiagram-AYHSOK5B-BTI8HbBu.js} +3 -3
  119. package/dist/static/assets/{quadrantDiagram-AYHSOK5B-A6m5lZKd.js.map → quadrantDiagram-AYHSOK5B-BTI8HbBu.js.map} +1 -1
  120. package/dist/static/assets/{requirementDiagram-UZGBJVZJ-Cac3zSJH.js → requirementDiagram-UZGBJVZJ-ZtSr9Q5R.js} +4 -4
  121. package/dist/static/assets/{requirementDiagram-UZGBJVZJ-Cac3zSJH.js.map → requirementDiagram-UZGBJVZJ-ZtSr9Q5R.js.map} +1 -1
  122. package/dist/static/assets/{sankeyDiagram-TZEHDZUN-DXDdUUl1.js → sankeyDiagram-TZEHDZUN-DibLVGzg.js} +2 -2
  123. package/dist/static/assets/{sankeyDiagram-TZEHDZUN-DXDdUUl1.js.map → sankeyDiagram-TZEHDZUN-DibLVGzg.js.map} +1 -1
  124. package/dist/static/assets/{sequenceDiagram-WL72ISMW-Domsjl5Y.js → sequenceDiagram-WL72ISMW-qXatfzVt.js} +4 -4
  125. package/dist/static/assets/{sequenceDiagram-WL72ISMW-Domsjl5Y.js.map → sequenceDiagram-WL72ISMW-qXatfzVt.js.map} +1 -1
  126. package/dist/static/assets/{stateDiagram-FKZM4ZOC-Bu0lRQK1.js → stateDiagram-FKZM4ZOC-7fgxCQHo.js} +9 -9
  127. package/dist/static/assets/{stateDiagram-FKZM4ZOC-Bu0lRQK1.js.map → stateDiagram-FKZM4ZOC-7fgxCQHo.js.map} +1 -1
  128. package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-D0K-n3ic.js → stateDiagram-v2-4FDKWEC3-DcWlOAnF.js} +5 -5
  129. package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-D0K-n3ic.js.map → stateDiagram-v2-4FDKWEC3-DcWlOAnF.js.map} +1 -1
  130. package/dist/static/assets/{timeline-definition-IT6M3QCI-BGvpddwR.js → timeline-definition-IT6M3QCI-iX2MRdpY.js} +3 -3
  131. package/dist/static/assets/{timeline-definition-IT6M3QCI-BGvpddwR.js.map → timeline-definition-IT6M3QCI-iX2MRdpY.js.map} +1 -1
  132. package/dist/static/assets/{treemap-GDKQZRPO-BoOzOm2j.js → treemap-GDKQZRPO-AVRnyXu1.js} +5 -5
  133. package/dist/static/assets/{treemap-GDKQZRPO-BoOzOm2j.js.map → treemap-GDKQZRPO-AVRnyXu1.js.map} +1 -1
  134. package/dist/static/assets/{xychartDiagram-PRI3JC2R-C_h3_ICR.js → xychartDiagram-PRI3JC2R-DVYEo5aJ.js} +3 -3
  135. package/dist/static/assets/{xychartDiagram-PRI3JC2R-C_h3_ICR.js.map → xychartDiagram-PRI3JC2R-DVYEo5aJ.js.map} +1 -1
  136. package/dist/static/index.html +1 -1
  137. package/dist/team.js +52 -48
  138. package/dist/tellask.js +439 -0
  139. package/dist/tools/context-health.js +177 -0
  140. package/dist/tools/diag.js +583 -0
  141. package/dist/tools/fs.js +194 -68
  142. package/dist/tools/prompts/memory/en/principles.md +13 -5
  143. package/dist/tools/prompts/memory/en/tools.md +11 -36
  144. package/dist/tools/prompts/memory/zh/principles.md +18 -8
  145. package/dist/tools/prompts/memory/zh/tools.md +11 -36
  146. package/dist/tools/team-mgmt.js +3487 -0
  147. package/dist/utils/task-doc.js +236 -0
  148. package/package.json +1 -1
  149. package/dist/static/assets/index-HWTRvE2k.js.map +0 -1
@@ -0,0 +1,2051 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.getAgentPrimingCacheStatus = getAgentPrimingCacheStatus;
37
+ exports.resolveInheritedSubdialogAgentPrimingMode = resolveInheritedSubdialogAgentPrimingMode;
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");
48
+ const dialog_run_state_1 = require("./dialog-run-state");
49
+ const driver_entry_1 = require("./llm/driver-entry");
50
+ const log_1 = require("./log");
51
+ const runtime_language_1 = require("./shared/runtime-language");
52
+ const id_1 = require("./shared/utils/id");
53
+ const inter_dialog_format_1 = require("./shared/utils/inter-dialog-format");
54
+ const time_1 = require("./shared/utils/time");
55
+ const team_1 = require("./team");
56
+ const BASELINE_ENV_SNAPSHOT_CMD = 'uname -a';
57
+ const PRIMING_VCS_SESSION_SLUG = 'rtws-vcs-inventory';
58
+ const cacheByAgentId = new Map();
59
+ const inflightByAgentId = new Map();
60
+ class AgentPrimingInterruptedError extends Error {
61
+ constructor(reason) {
62
+ super(`Agent Priming interrupted: ${reason}`);
63
+ this.name = 'AgentPrimingInterruptedError';
64
+ this.reason = reason;
65
+ }
66
+ }
67
+ function isAgentPrimingInterruptedError(error) {
68
+ return error instanceof AgentPrimingInterruptedError;
69
+ }
70
+ function throwIfAgentPrimingStopped(dlg, abortSignal) {
71
+ if (!abortSignal.aborted) {
72
+ return;
73
+ }
74
+ const reason = (0, dialog_run_state_1.getStopRequestedReason)(dlg.id);
75
+ if (reason === 'emergency_stop' || reason === 'user_stop') {
76
+ throw new AgentPrimingInterruptedError(reason);
77
+ }
78
+ throw new AgentPrimingInterruptedError('user_stop');
79
+ }
80
+ async function emitSayingEventsAndPersist(dlg, content) {
81
+ await (0, driver_entry_1.emitSayingEvents)(dlg, content);
82
+ const genseq = dlg.activeGenSeqOrUndefined;
83
+ if (dlg.generationStarted &&
84
+ typeof genseq === 'number' &&
85
+ Number.isFinite(genseq) &&
86
+ genseq > 0 &&
87
+ content.trim()) {
88
+ try {
89
+ await dlg.persistAgentMessage(content, genseq, 'saying_msg');
90
+ }
91
+ catch (err) {
92
+ log_1.log.warn('Failed to persist Agent Priming synthetic saying content (best-effort)', err, {
93
+ dialogId: dlg.id.valueOf(),
94
+ genseq,
95
+ });
96
+ }
97
+ }
98
+ }
99
+ async function emitSyntheticTellaskCall(dlg, payload) {
100
+ const callId = payload.callId?.trim() ? payload.callId.trim() : `priming-${(0, id_1.generateShortId)()}`;
101
+ const activeGenseq = dlg.activeGenSeqOrUndefined;
102
+ if (typeof activeGenseq !== 'number' || !Number.isFinite(activeGenseq) || activeGenseq <= 0) {
103
+ throw new Error('emitSyntheticTellaskCall requires an active genseq');
104
+ }
105
+ switch (payload.callName) {
106
+ case 'tellask':
107
+ case 'tellaskSessionless': {
108
+ const mentionList = (payload.mentionList ?? [])
109
+ .map((value) => value.trim())
110
+ .filter((value) => value !== '');
111
+ if (mentionList.length < 1) {
112
+ throw new Error('emitSyntheticTellaskCall requires mentionList for teammate tellasks');
113
+ }
114
+ const normalizedTargetAgentId = payload.targetAgentId?.trim() ?? '';
115
+ if (normalizedTargetAgentId === '') {
116
+ throw new Error('emitSyntheticTellaskCall requires targetAgentId for teammate tellasks');
117
+ }
118
+ let functionCallArguments;
119
+ if (payload.callName === 'tellask') {
120
+ const sessionSlug = payload.sessionSlug?.trim() ?? '';
121
+ if (sessionSlug === '') {
122
+ throw new Error('emitSyntheticTellaskCall requires sessionSlug for tellask');
123
+ }
124
+ functionCallArguments = {
125
+ targetAgentId: normalizedTargetAgentId,
126
+ sessionSlug,
127
+ tellaskContent: payload.tellaskContent,
128
+ };
129
+ }
130
+ else {
131
+ functionCallArguments = {
132
+ targetAgentId: normalizedTargetAgentId,
133
+ tellaskContent: payload.tellaskContent,
134
+ };
135
+ }
136
+ await dlg.persistFunctionCall(callId, payload.callName, functionCallArguments, Math.floor(activeGenseq));
137
+ await dlg.callingStart({
138
+ callName: payload.callName,
139
+ callId,
140
+ mentionList,
141
+ sessionSlug: payload.callName === 'tellask' ? payload.sessionSlug?.trim() : undefined,
142
+ tellaskContent: payload.tellaskContent,
143
+ });
144
+ return {
145
+ callId,
146
+ callName: payload.callName,
147
+ mentionList,
148
+ tellaskContent: payload.tellaskContent,
149
+ };
150
+ }
151
+ case 'freshBootsReasoning': {
152
+ if (payload.mentionList !== undefined && payload.mentionList.length > 0) {
153
+ throw new Error('emitSyntheticTellaskCall: freshBootsReasoning must not carry mentionList');
154
+ }
155
+ const functionCallArguments = {
156
+ tellaskContent: payload.tellaskContent,
157
+ };
158
+ await dlg.persistFunctionCall(callId, payload.callName, functionCallArguments, Math.floor(activeGenseq));
159
+ await dlg.callingStart({
160
+ callName: payload.callName,
161
+ callId,
162
+ tellaskContent: payload.tellaskContent,
163
+ });
164
+ return {
165
+ callId,
166
+ callName: payload.callName,
167
+ tellaskContent: payload.tellaskContent,
168
+ };
169
+ }
170
+ }
171
+ }
172
+ async function emitUiOnlyMarkdownEventsAndPersist(dlg, content) {
173
+ const trimmed = content.trim();
174
+ if (!trimmed)
175
+ return;
176
+ await dlg.markdownStart();
177
+ await dlg.markdownChunk(content);
178
+ await dlg.markdownFinish();
179
+ const genseq = dlg.activeGenSeqOrUndefined;
180
+ if (dlg.generationStarted &&
181
+ typeof genseq === 'number' &&
182
+ Number.isFinite(genseq) &&
183
+ genseq > 0) {
184
+ try {
185
+ await dlg.persistUiOnlyMarkdown(content, genseq);
186
+ }
187
+ catch (err) {
188
+ log_1.log.warn('Failed to persist UI-only markdown (best-effort)', err, {
189
+ dialogId: dlg.id.valueOf(),
190
+ genseq,
191
+ });
192
+ }
193
+ }
194
+ }
195
+ function parseUnifiedTimestamp(value) {
196
+ const m = value.trim().match(/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/);
197
+ if (!m)
198
+ return null;
199
+ const year = Number(m[1]);
200
+ const month = Number(m[2]);
201
+ const day = Number(m[3]);
202
+ const hour = Number(m[4]);
203
+ const minute = Number(m[5]);
204
+ const second = Number(m[6]);
205
+ if (!Number.isFinite(year) ||
206
+ !Number.isFinite(month) ||
207
+ !Number.isFinite(day) ||
208
+ !Number.isFinite(hour) ||
209
+ !Number.isFinite(minute) ||
210
+ !Number.isFinite(second)) {
211
+ return null;
212
+ }
213
+ return new Date(year, month - 1, day, hour, minute, second);
214
+ }
215
+ function getAgentPrimingCacheStatus(agentId) {
216
+ const entry = cacheByAgentId.get(agentId);
217
+ if (!entry)
218
+ return { hasCache: false };
219
+ const createdAt = entry.createdAt;
220
+ const parsed = parseUnifiedTimestamp(createdAt);
221
+ const ageSeconds = parsed === null ? 0 : Math.max(0, Math.floor((Date.now() - parsed.getTime()) / 1000));
222
+ return { hasCache: true, createdAt, ageSeconds };
223
+ }
224
+ function resolveInheritedSubdialogAgentPrimingMode(requestedMode, agentId) {
225
+ if (requestedMode === 'skip')
226
+ return 'skip';
227
+ if (requestedMode === 'reuse')
228
+ return 'reuse';
229
+ const hasCache = cacheByAgentId.has(agentId);
230
+ // "do" without cache means "show it once now"; subdialogs may still reuse once cache appears.
231
+ return hasCache ? 'do' : 'reuse';
232
+ }
233
+ function scheduleAgentPrimingForNewDialog(dlg, options) {
234
+ if (options.mode === 'skip')
235
+ return Promise.resolve();
236
+ const agentId = dlg.agentId;
237
+ const existing = cacheByAgentId.get(agentId);
238
+ if (options.mode === 'reuse' && existing) {
239
+ dlg.setCoursePrefixMsgs(buildCoursePrefixMsgs(existing));
240
+ return replayAgentPriming(dlg, existing);
241
+ }
242
+ const inflight = inflightByAgentId.get(agentId);
243
+ if (inflight) {
244
+ return inflight.then((entry) => {
245
+ if (options.mode === 'reuse' && entry) {
246
+ dlg.setCoursePrefixMsgs(buildCoursePrefixMsgs(entry));
247
+ return replayAgentPriming(dlg, entry);
248
+ }
249
+ // mode === 'do': wait for in-flight then run again for this dialog.
250
+ if (options.mode === 'do') {
251
+ return runAgentPrimingLive(dlg)
252
+ .then((next) => {
253
+ cacheByAgentId.set(agentId, next);
254
+ })
255
+ .catch((err) => {
256
+ if (isAgentPrimingInterruptedError(err)) {
257
+ log_1.log.debug('Agent Priming interrupted; will retry on next dialog', undefined, {
258
+ agentId,
259
+ reason: err.reason,
260
+ });
261
+ }
262
+ else {
263
+ log_1.log.warn('Agent Priming live run failed; will retry on next dialog', err, {
264
+ agentId,
265
+ });
266
+ }
267
+ return undefined;
268
+ });
269
+ }
270
+ return Promise.resolve();
271
+ });
272
+ }
273
+ const task = runAgentPrimingLive(dlg)
274
+ .then((entry) => {
275
+ cacheByAgentId.set(agentId, entry);
276
+ return entry;
277
+ })
278
+ .catch((err) => {
279
+ // Best-effort: avoid unhandled rejections; the dialog itself is already marked interrupted.
280
+ if (isAgentPrimingInterruptedError(err)) {
281
+ log_1.log.debug('Agent Priming interrupted; will retry on next dialog', undefined, {
282
+ agentId,
283
+ reason: err.reason,
284
+ });
285
+ }
286
+ else {
287
+ log_1.log.warn('Agent Priming live run failed; will retry on next dialog', err, { agentId });
288
+ }
289
+ return null;
290
+ })
291
+ .finally(() => {
292
+ inflightByAgentId.delete(agentId);
293
+ });
294
+ inflightByAgentId.set(agentId, task);
295
+ return task.then(() => undefined);
296
+ }
297
+ function takeFirstNonEmptyLine(text) {
298
+ const lines = text.replace(/\r\n/g, '\n').split('\n');
299
+ for (const line of lines) {
300
+ const trimmed = line.trim();
301
+ if (trimmed)
302
+ return trimmed;
303
+ }
304
+ return null;
305
+ }
306
+ function extractLastAssistantSaying(messages) {
307
+ for (let i = messages.length - 1; i >= 0; i--) {
308
+ const msg = messages[i];
309
+ if (msg.type === 'saying_msg' && typeof msg.content === 'string' && msg.content.trim()) {
310
+ return msg.content;
311
+ }
312
+ }
313
+ for (let i = messages.length - 1; i >= 0; i--) {
314
+ const msg = messages[i];
315
+ if (msg.type === 'thinking_msg' && typeof msg.content === 'string' && msg.content.trim()) {
316
+ return msg.content;
317
+ }
318
+ }
319
+ return '';
320
+ }
321
+ function extractLastShellCmdResultText(messages) {
322
+ for (let i = messages.length - 1; i >= 0; i--) {
323
+ const msg = messages[i];
324
+ if (typeof msg !== 'object' || msg === null)
325
+ continue;
326
+ if (!('type' in msg) || !('name' in msg) || !('content' in msg))
327
+ continue;
328
+ const type = msg.type;
329
+ const name = msg.name;
330
+ const content = msg.content;
331
+ if (type !== 'func_result_msg')
332
+ continue;
333
+ if (name !== 'shell_cmd')
334
+ continue;
335
+ if (typeof content !== 'string')
336
+ continue;
337
+ if (!content.trim())
338
+ continue;
339
+ return content;
340
+ }
341
+ return null;
342
+ }
343
+ async function runUnameA() {
344
+ return await new Promise((resolveUname) => {
345
+ const child = (0, node_child_process_1.spawn)('uname', ['-a'], { stdio: ['ignore', 'pipe', 'pipe'] });
346
+ let out = '';
347
+ let err = '';
348
+ child.stdout.on('data', (buf) => {
349
+ out += buf.toString();
350
+ });
351
+ child.stderr.on('data', (buf) => {
352
+ err += buf.toString();
353
+ });
354
+ child.on('close', (code) => {
355
+ const trimmedOut = out.trim();
356
+ const trimmedErr = err.trim();
357
+ if (code === 0 && trimmedOut) {
358
+ resolveUname(trimmedOut);
359
+ return;
360
+ }
361
+ const fallback = trimmedErr ? trimmedErr : `uname exited with code ${String(code)}`;
362
+ resolveUname(fallback);
363
+ });
364
+ child.on('error', (e) => {
365
+ resolveUname(e instanceof Error ? e.message : String(e));
366
+ });
367
+ });
368
+ }
369
+ async function runCommand(command, args, cwd) {
370
+ return await new Promise((resolveExec) => {
371
+ const child = (0, node_child_process_1.spawn)(command, args, {
372
+ cwd,
373
+ stdio: ['ignore', 'pipe', 'pipe'],
374
+ });
375
+ let out = '';
376
+ let err = '';
377
+ child.stdout.on('data', (buf) => {
378
+ out += buf.toString();
379
+ });
380
+ child.stderr.on('data', (buf) => {
381
+ err += buf.toString();
382
+ });
383
+ child.on('close', (code) => {
384
+ resolveExec({
385
+ ok: code === 0,
386
+ stdout: out.trim(),
387
+ stderr: err.trim(),
388
+ exitCode: code,
389
+ });
390
+ });
391
+ child.on('error', (e) => {
392
+ resolveExec({
393
+ ok: false,
394
+ stdout: out.trim(),
395
+ stderr: err.trim(),
396
+ exitCode: null,
397
+ errorText: e instanceof Error ? e.message : String(e),
398
+ });
399
+ });
400
+ });
401
+ }
402
+ async function runGit(args, cwd) {
403
+ return await runCommand('git', args, cwd);
404
+ }
405
+ async function isGitRepo(dir) {
406
+ const res = await runGit(['rev-parse', '--is-inside-work-tree'], dir);
407
+ return res.ok && res.stdout === 'true';
408
+ }
409
+ async function inspectRtwsRootGitPosition(rtws) {
410
+ // Equivalent to comparing:
411
+ // - `git rev-parse --show-toplevel`
412
+ // - `pwd`
413
+ // to determine whether rtws itself is repo root vs a subdirectory of a repo.
414
+ const showTopRes = await runGit(['rev-parse', '--show-toplevel'], rtws);
415
+ if (!showTopRes.ok || !showTopRes.stdout) {
416
+ return { kind: 'not_git' };
417
+ }
418
+ const rtwsAbs = path.resolve(rtws);
419
+ const topLevelAbsPath = path.resolve(showTopRes.stdout);
420
+ if (topLevelAbsPath === rtwsAbs) {
421
+ return { kind: 'repo_root', topLevelAbsPath };
422
+ }
423
+ const relFromTopLevel = path.relative(topLevelAbsPath, rtwsAbs).replace(/\\/g, '/');
424
+ return {
425
+ kind: 'repo_subdir',
426
+ topLevelAbsPath,
427
+ relFromTopLevel: relFromTopLevel || '.',
428
+ };
429
+ }
430
+ async function listSubmoduleRelPaths(rootDir) {
431
+ const out = new Set();
432
+ const res = await runGit(['submodule', 'status', '--recursive'], rootDir);
433
+ if (!res.ok || !res.stdout)
434
+ return out;
435
+ const lines = res.stdout.split('\n');
436
+ for (const line of lines) {
437
+ const trimmed = line.trim();
438
+ if (!trimmed)
439
+ continue;
440
+ const m = trimmed.match(/^[+\-U ]?[0-9a-fA-F]+\s+([^\s]+)/);
441
+ if (!m)
442
+ continue;
443
+ const rel = (m[1] ?? '').trim();
444
+ if (!rel)
445
+ continue;
446
+ out.add(rel.replace(/\\/g, '/'));
447
+ }
448
+ return out;
449
+ }
450
+ async function findGitMarkerDirs(rootDir) {
451
+ const skipDirs = new Set([
452
+ '.git',
453
+ 'node_modules',
454
+ '.pnpm-store',
455
+ '.yarn',
456
+ '.next',
457
+ 'dist',
458
+ 'build',
459
+ 'out',
460
+ 'target',
461
+ '.cache',
462
+ ]);
463
+ const queue = [rootDir];
464
+ const found = new Set();
465
+ const maxVisited = 20000;
466
+ let visited = 0;
467
+ while (queue.length > 0) {
468
+ const current = queue.shift();
469
+ if (!current)
470
+ continue;
471
+ visited += 1;
472
+ if (visited > maxVisited)
473
+ break;
474
+ let entries;
475
+ try {
476
+ entries = await fs.readdir(current, { withFileTypes: true });
477
+ }
478
+ catch {
479
+ continue;
480
+ }
481
+ const hasGitMarker = entries.some((e) => e.name === '.git' && (e.isDirectory() || e.isFile()));
482
+ if (hasGitMarker) {
483
+ found.add(current);
484
+ if (current !== rootDir) {
485
+ // Treat a nested repo as its own boundary to keep traversal bounded.
486
+ continue;
487
+ }
488
+ }
489
+ for (const entry of entries) {
490
+ if (!entry.isDirectory())
491
+ continue;
492
+ if (skipDirs.has(entry.name))
493
+ continue;
494
+ const next = path.join(current, entry.name);
495
+ queue.push(next);
496
+ }
497
+ }
498
+ return Array.from(found);
499
+ }
500
+ async function collectRtwsGitInventory() {
501
+ const rtws = process.cwd();
502
+ const rootGitPosition = await inspectRtwsRootGitPosition(rtws);
503
+ const rootIsRepo = rootGitPosition.kind === 'repo_root';
504
+ const markerDirs = await findGitMarkerDirs(rtws);
505
+ const submoduleSet = rootIsRepo ? await listSubmoduleRelPaths(rtws) : new Set();
506
+ const repoAbsSet = new Set();
507
+ if (rootGitPosition.kind === 'repo_root' || rootGitPosition.kind === 'repo_subdir') {
508
+ repoAbsSet.add(rtws);
509
+ }
510
+ for (const candidate of markerDirs) {
511
+ if (candidate === rtws)
512
+ continue;
513
+ if (await isGitRepo(candidate)) {
514
+ repoAbsSet.add(candidate);
515
+ }
516
+ }
517
+ const allRepoAbs = Array.from(repoAbsSet).sort();
518
+ const allRepoRel = allRepoAbs.map((abs) => {
519
+ const rel = path.relative(rtws, abs).replace(/\\/g, '/');
520
+ return rel === '' ? '.' : rel;
521
+ });
522
+ const submoduleRelPaths = allRepoRel.filter((rel) => submoduleSet.has(rel));
523
+ const nestedRepoRelPaths = allRepoRel.filter((rel) => rel !== '.' && !submoduleSet.has(rel));
524
+ const repoStatuses = [];
525
+ const maxRepos = 40;
526
+ for (let i = 0; i < Math.min(allRepoAbs.length, maxRepos); i++) {
527
+ const repoAbs = allRepoAbs[i];
528
+ const rel = allRepoRel[i] ?? '.';
529
+ const branchRes = await runGit(['branch', '--show-current'], repoAbs);
530
+ const headRes = await runGit(['rev-parse', '--short', 'HEAD'], repoAbs);
531
+ const upstreamRes = await runGit(['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{upstream}'], repoAbs);
532
+ const remoteRes = await runGit(['remote', '-v'], repoAbs);
533
+ const dirtyRes = await runGit(['status', '--porcelain'], repoAbs);
534
+ const remotes = (() => {
535
+ if (!remoteRes.ok || !remoteRes.stdout)
536
+ return [];
537
+ const lines = remoteRes.stdout.split('\n');
538
+ const items = new Set();
539
+ for (const line of lines) {
540
+ const m = line.match(/^([^\s]+)\s+([^\s]+)\s+\((fetch|push)\)$/);
541
+ if (!m)
542
+ continue;
543
+ const name = m[1] ?? '';
544
+ const url = m[2] ?? '';
545
+ const kind = m[3] ?? '';
546
+ if (!name || !url || !kind)
547
+ continue;
548
+ items.add(`${name}:${kind}=${url}`);
549
+ }
550
+ return Array.from(items).sort();
551
+ })();
552
+ const dirtyCount = (() => {
553
+ if (!dirtyRes.ok || !dirtyRes.stdout)
554
+ return 0;
555
+ return dirtyRes.stdout
556
+ .split('\n')
557
+ .map((line) => line.trim())
558
+ .filter((line) => line.length > 0).length;
559
+ })();
560
+ const statusErrorParts = [];
561
+ if (!branchRes.ok)
562
+ statusErrorParts.push(`branch: ${branchRes.errorText ?? branchRes.stderr}`);
563
+ if (!headRes.ok)
564
+ statusErrorParts.push(`head: ${headRes.errorText ?? headRes.stderr}`);
565
+ if (!remoteRes.ok)
566
+ statusErrorParts.push(`remote: ${remoteRes.errorText ?? remoteRes.stderr}`);
567
+ if (!dirtyRes.ok)
568
+ statusErrorParts.push(`status: ${dirtyRes.errorText ?? dirtyRes.stderr}`);
569
+ repoStatuses.push({
570
+ relPath: rel,
571
+ branch: branchRes.ok && branchRes.stdout ? branchRes.stdout : '(detached-or-unknown)',
572
+ upstream: upstreamRes.ok && upstreamRes.stdout ? upstreamRes.stdout : '(no-upstream-or-unavailable)',
573
+ remotes,
574
+ dirtyCount,
575
+ headShort: headRes.ok && headRes.stdout ? headRes.stdout : '(unknown)',
576
+ statusError: statusErrorParts.length > 0 ? statusErrorParts.join('; ') : undefined,
577
+ });
578
+ }
579
+ return {
580
+ rootIsRepo,
581
+ rootGitPosition,
582
+ submoduleRelPaths,
583
+ nestedRepoRelPaths,
584
+ repoStatuses,
585
+ };
586
+ }
587
+ function formatRtwsGitInventoryRound1(language, inventory) {
588
+ const relationLineZh = (() => {
589
+ if (inventory.rootGitPosition.kind === 'repo_root') {
590
+ return '- rtws 与 git 关系:rtws 本身就是 repo 根路径';
591
+ }
592
+ if (inventory.rootGitPosition.kind === 'repo_subdir') {
593
+ return [
594
+ '- rtws 与 git 关系:rtws 是某个 repo 的子目录(rtws 本身不是 repo 根)',
595
+ `- 上级 repo 顶层:${inventory.rootGitPosition.topLevelAbsPath}`,
596
+ `- rtws 相对上级 repo 路径:${inventory.rootGitPosition.relFromTopLevel}`,
597
+ ].join('\n');
598
+ }
599
+ return '- rtws 与 git 关系:不在任何 git worktree 内';
600
+ })();
601
+ const relationLineEn = (() => {
602
+ if (inventory.rootGitPosition.kind === 'repo_root') {
603
+ return '- rtws vs git: rtws itself is the repo root';
604
+ }
605
+ if (inventory.rootGitPosition.kind === 'repo_subdir') {
606
+ return [
607
+ '- rtws vs git: rtws is a subdirectory inside a repo (rtws itself is not the repo root)',
608
+ `- enclosing repo top-level: ${inventory.rootGitPosition.topLevelAbsPath}`,
609
+ `- rtws path relative to repo root: ${inventory.rootGitPosition.relFromTopLevel}`,
610
+ ].join('\n');
611
+ }
612
+ return '- rtws vs git: not inside any git worktree';
613
+ })();
614
+ if (language === 'zh') {
615
+ const submoduleText = inventory.submoduleRelPaths.length < 1
616
+ ? '无'
617
+ : inventory.submoduleRelPaths.map((p) => `- ${p}`).join('\n');
618
+ const nestedText = inventory.nestedRepoRelPaths.length < 1
619
+ ? '无'
620
+ : inventory.nestedRepoRelPaths.map((p) => `- ${p}`).join('\n');
621
+ return [
622
+ 'VCS 长线诉请 Round-1(rtws 仓库拓扑)',
623
+ '',
624
+ `- 根路径是否 git repo:${inventory.rootIsRepo ? '是' : '否'}`,
625
+ relationLineZh,
626
+ `- submodule 数量:${inventory.submoduleRelPaths.length}`,
627
+ `- 子目录独立 repo 数量:${inventory.nestedRepoRelPaths.length}`,
628
+ '',
629
+ 'submodule 列表:',
630
+ submoduleText,
631
+ '',
632
+ '子目录独立 repo 列表:',
633
+ nestedText,
634
+ ].join('\n');
635
+ }
636
+ const submoduleText = inventory.submoduleRelPaths.length < 1
637
+ ? 'none'
638
+ : inventory.submoduleRelPaths.map((p) => `- ${p}`).join('\n');
639
+ const nestedText = inventory.nestedRepoRelPaths.length < 1
640
+ ? 'none'
641
+ : inventory.nestedRepoRelPaths.map((p) => `- ${p}`).join('\n');
642
+ return [
643
+ 'VCS Tellask Session Round-1 (rtws repo topology)',
644
+ '',
645
+ `- Root path is git repo: ${inventory.rootIsRepo ? 'yes' : 'no'}`,
646
+ relationLineEn,
647
+ `- Submodule count: ${inventory.submoduleRelPaths.length}`,
648
+ `- Nested independent repo count: ${inventory.nestedRepoRelPaths.length}`,
649
+ '',
650
+ 'Submodule list:',
651
+ submoduleText,
652
+ '',
653
+ 'Nested independent repo list:',
654
+ nestedText,
655
+ ].join('\n');
656
+ }
657
+ function formatRtwsGitInventoryRound2(language, inventory) {
658
+ const rows = inventory.repoStatuses.map((repo, idx) => {
659
+ const remotes = repo.remotes.length < 1 ? '(none)' : repo.remotes.join(', ');
660
+ if (language === 'zh') {
661
+ return [
662
+ `${idx + 1}. repo: ${repo.relPath}`,
663
+ ` - head: ${repo.headShort}`,
664
+ ` - branch: ${repo.branch}`,
665
+ ` - upstream: ${repo.upstream}`,
666
+ ` - dirty: ${repo.dirtyCount > 0 ? `yes (${repo.dirtyCount})` : 'no'}`,
667
+ ` - remotes: ${remotes}`,
668
+ repo.statusError ? ` - errors: ${repo.statusError}` : '',
669
+ ]
670
+ .filter((line) => line !== '')
671
+ .join('\n');
672
+ }
673
+ return [
674
+ `${idx + 1}. repo: ${repo.relPath}`,
675
+ ` - head: ${repo.headShort}`,
676
+ ` - branch: ${repo.branch}`,
677
+ ` - upstream: ${repo.upstream}`,
678
+ ` - dirty: ${repo.dirtyCount > 0 ? `yes (${repo.dirtyCount})` : 'no'}`,
679
+ ` - remotes: ${remotes}`,
680
+ repo.statusError ? ` - errors: ${repo.statusError}` : '',
681
+ ]
682
+ .filter((line) => line !== '')
683
+ .join('\n');
684
+ });
685
+ if (language === 'zh') {
686
+ return [
687
+ 'VCS 长线诉请 Round-2(每个 repo 的 remote / branch 现状)',
688
+ '',
689
+ rows.length < 1 ? '未发现可报告的 repo。' : rows.join('\n\n'),
690
+ ].join('\n');
691
+ }
692
+ return [
693
+ 'VCS Tellask Session Round-2 (remote / branch status per repo)',
694
+ '',
695
+ rows.length < 1 ? 'No repos available to report.' : rows.join('\n\n'),
696
+ ].join('\n');
697
+ }
698
+ function formatPreludeIntro(language, reused, shellPolicy, shellSpecialistId) {
699
+ if (shellPolicy === 'specialist_only' &&
700
+ (!shellSpecialistId || shellSpecialistId.trim() === '')) {
701
+ throw new Error('Missing shell specialist id for specialist_only prelude');
702
+ }
703
+ const shellSpecialistMention = shellSpecialistId && shellSpecialistId.trim() ? `@${shellSpecialistId.trim()}` : '';
704
+ const shellPolicyLinesZh = shellPolicy === 'specialist_only'
705
+ ? [
706
+ `规则:此智能体**不执行任何 shell 命令**。所有 shell 命令必须由 shell 专员(${shellSpecialistMention})执行并回传。`,
707
+ `下面将诉请 shell 专员(${shellSpecialistMention})仅执行一个低风险命令:\`uname -a\`。`,
708
+ ]
709
+ : shellPolicy === 'self_is_specialist'
710
+ ? [
711
+ '本次对话主理人属于 `shell_specialists`,将略去 shell 诉请环节。',
712
+ '由 Dominds 运行时获取标准环境事实(`uname -a` + rtws git 现状),随后进入 `freshBootsReasoning` FBR。',
713
+ ]
714
+ : [
715
+ '本团队未配置 shell 专员。',
716
+ '这是标准支持模式:由 Dominds 运行时主动获取环境事实(`uname -a` + rtws git 现状)并用于后续 FBR。',
717
+ '规则:此智能体仍然不得自行执行任意 shell 命令。',
718
+ ];
719
+ const shellPolicyLinesEn = shellPolicy === 'specialist_only'
720
+ ? [
721
+ `Rule: this agent must **not run any shell commands**. All shell commands must be executed by the shell specialist (${shellSpecialistMention}) and returned.`,
722
+ `Next, we Tellask the shell specialist (${shellSpecialistMention}) to run one low-risk command only: \`uname -a\`.`,
723
+ ]
724
+ : shellPolicy === 'self_is_specialist'
725
+ ? [
726
+ 'The dialog owner is a member of `shell_specialists`, so we skip the shell Tellask step.',
727
+ 'Dominds runtime collects standard environment facts (`uname -a` + rtws git state), then we enter `freshBootsReasoning` FBR.',
728
+ ]
729
+ : [
730
+ 'This team has no configured shell specialist.',
731
+ 'This is a standard support mode: Dominds runtime proactively collects environment facts (`uname -a` + rtws git state) for FBR.',
732
+ 'Rule: this agent still must not run arbitrary shell commands directly.',
733
+ ];
734
+ if (language === 'zh') {
735
+ return reused
736
+ ? [
737
+ '## Prelude:智能体启动(复用缓存)',
738
+ '',
739
+ '这段序幕用于把“诉请 + 回传 + FBR + 综合提炼”变成体感(引导祂做给自己看)。',
740
+ '关键时序:`freshBootsReasoning` 只表示发起;必须等待 FBR 支线回贴返回后,才在主线做综合决策。',
741
+ '本次对话复用了本进程内缓存:未重复执行命令。',
742
+ '',
743
+ ...shellPolicyLinesZh,
744
+ '',
745
+ ].join('\n')
746
+ : [
747
+ '## Prelude:智能体启动',
748
+ '',
749
+ '这段序幕用于把“诉请 + 回传 + FBR + 综合提炼”变成体感(引导祂做给自己看)。',
750
+ '关键时序:`freshBootsReasoning` 只表示发起;必须等待 FBR 支线回贴返回后,才在主线做综合决策。',
751
+ '',
752
+ ...shellPolicyLinesZh,
753
+ '',
754
+ ].join('\n');
755
+ }
756
+ return reused
757
+ ? [
758
+ '## Prelude: Agent Priming (Reused)',
759
+ '',
760
+ 'This prelude makes Tellask + return + FBR + distillation feel real (guiding the agent to show it to itself).',
761
+ 'Critical timing: `freshBootsReasoning` is initiation only; mainline distillation/decision happens only after FBR sideline feedback returns.',
762
+ 'This dialog reused the in-process cache (no commands were re-run).',
763
+ '',
764
+ ...shellPolicyLinesEn,
765
+ '',
766
+ ].join('\n')
767
+ : [
768
+ '## Prelude: Agent Priming',
769
+ '',
770
+ 'This prelude makes Tellask + return + FBR + distillation feel real (guiding the agent to show it to itself).',
771
+ 'Critical timing: `freshBootsReasoning` is initiation only; mainline distillation/decision happens only after FBR sideline feedback returns.',
772
+ '',
773
+ ...shellPolicyLinesEn,
774
+ '',
775
+ ].join('\n');
776
+ }
777
+ function formatShellTellaskBody(language, shellSpecialistId) {
778
+ const shellSpecialistMention = `@${shellSpecialistId.trim()}`;
779
+ if (language === 'zh') {
780
+ return [
781
+ `你是 shell 专员(${shellSpecialistMention}):请代我执行 \`uname -a\` 获取当前运行环境的基本信息。`,
782
+ '',
783
+ '背景规则:对话主理人不得执行任何 shell 命令;所有 shell 命令必须通过你执行并回传。',
784
+ '请不要建议我“自己在本地跑一下”。',
785
+ '收到回传后,我会基于该环境信息发起一次 `freshBootsReasoning` 扪心自问(FBR),先等待该次 FBR 的全部支线回贴,再在主线做综合提炼并形成一条可复用的“智能体启动(Agent Priming)”笔记。',
786
+ '',
787
+ '要求:',
788
+ '- 通过 shell 工具执行:uname -a(只执行这一条)',
789
+ '- 原样返回输出(不要改写/解释)',
790
+ '- 若命令不可用/失败:返回错误信息,并给出一个安全的替代命令',
791
+ '',
792
+ '输出格式:优先只给出原始输出,其次才是必要的简短说明。',
793
+ ].join('\n');
794
+ }
795
+ return [
796
+ `You are the shell specialist (${shellSpecialistMention}): please run \`uname -a\` on my behalf to capture the basic runtime environment.`,
797
+ '',
798
+ 'Rule: the dialog owner must not run any shell commands; all shell commands must be executed by you and returned.',
799
+ 'Do not suggest that I “just run it locally”.',
800
+ 'After I receive your output, I will initiate `freshBootsReasoning` Fresh Boots Reasoning (FBR) on this environment, wait for all feedback from that FBR run, then distill a reusable “Agent Priming” note in mainline.',
801
+ '',
802
+ 'Requirements:',
803
+ '- Use shell tools to run exactly: uname -a (and only this command)',
804
+ '- Return the raw output verbatim (no paraphrase)',
805
+ '- If the command fails: include the error and suggest one safe alternative command',
806
+ '',
807
+ 'Output format: prefer raw output only; keep any explanation minimal.',
808
+ ].join('\n');
809
+ }
810
+ function formatVcsSessionRound1TellaskBody(language) {
811
+ if (language === 'zh') {
812
+ return [
813
+ `这是同一长线诉请(session: ${PRIMING_VCS_SESSION_SLUG})的 Round-1,请你只做仓库拓扑盘点。`,
814
+ '',
815
+ '在当前 rtws 中确认:',
816
+ '- 根路径是否是 git repo',
817
+ '- 是否存在 submodule(给出路径列表)',
818
+ '- 是否存在子目录独立 repo(给出路径列表)',
819
+ '',
820
+ '要求:',
821
+ '- 只使用 git / find 命令采集事实;不要用 python/node/perl 等脚本探测',
822
+ '- 建议命令:`git rev-parse --is-inside-work-tree`、`git submodule status --recursive`、`find . -name .git`',
823
+ '- 仅做事实盘点,不做下一步建议',
824
+ '- 输出必须短且结构化,便于我在 Round-2 继续诉请',
825
+ ].join('\n');
826
+ }
827
+ return [
828
+ `This is Round-1 of the same Tellask Session (${PRIMING_VCS_SESSION_SLUG}); do topology inventory only.`,
829
+ '',
830
+ 'In the current rtws, confirm:',
831
+ '- whether the root path is a git repo',
832
+ '- whether submodules exist (with path list)',
833
+ '- whether nested independent repos exist (with path list)',
834
+ '',
835
+ 'Requirements:',
836
+ '- use git/find commands only; do not use python/node/perl scripts for discovery',
837
+ '- suggested commands: `git rev-parse --is-inside-work-tree`, `git submodule status --recursive`, `find . -name .git`',
838
+ '- facts only, no next-step suggestions',
839
+ '- keep output short and structured so I can continue in Round-2',
840
+ ].join('\n');
841
+ }
842
+ function formatVcsSessionRound2TellaskBody(language, round1Response) {
843
+ const round1Anchor = takeFirstNonEmptyLine(round1Response) ?? '(empty)';
844
+ if (language === 'zh') {
845
+ return [
846
+ `这是同一长线诉请(session: ${PRIMING_VCS_SESSION_SLUG})的 Round-2。Round-1 已结束,本轮是新的续推诉请。`,
847
+ `Round-1 摘要锚点:${round1Anchor}`,
848
+ '',
849
+ '请继续确认 Round-1 涉及到的每一个 repo:',
850
+ '- remote(fetch/push)现状',
851
+ '- 当前 branch / upstream 现状',
852
+ '- 工作区是否脏(可给简要计数)',
853
+ '',
854
+ '要求:',
855
+ '- 只使用 git 命令逐 repo 采集,不要用 python/node/perl',
856
+ '- 建议命令:`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`',
857
+ '- 覆盖全部 repo;缺失时明确写 unavailable',
858
+ '- 输出保持结构化与简短,不扩展到修复建议',
859
+ ].join('\n');
860
+ }
861
+ return [
862
+ `This is Round-2 of the same Tellask Session (${PRIMING_VCS_SESSION_SLUG}). Round-1 is closed; this is a new continuation Tellask.`,
863
+ `Round-1 anchor: ${round1Anchor}`,
864
+ '',
865
+ 'For every repo covered by Round-1, continue with:',
866
+ '- remote status (fetch/push)',
867
+ '- current branch / upstream status',
868
+ '- whether working tree is dirty (brief count is enough)',
869
+ '',
870
+ 'Requirements:',
871
+ '- use git commands repo-by-repo; do not use python/node/perl scripts',
872
+ '- 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`',
873
+ '- cover all repos; mark unavailable when missing',
874
+ '- keep output structured and short; do not expand into fix proposals',
875
+ ].join('\n');
876
+ }
877
+ function formatRuntimeVcsRoundNote(language, round, content) {
878
+ if (language === 'zh') {
879
+ return [
880
+ `由 Dominds 运行时执行 VCS 盘点 Round-${round}(标准模式,非降级):`,
881
+ '',
882
+ content,
883
+ '',
884
+ ].join('\n');
885
+ }
886
+ return [
887
+ `Dominds runtime VCS inventory Round-${round} (standard mode, not degraded):`,
888
+ '',
889
+ content,
890
+ '',
891
+ ].join('\n');
892
+ }
893
+ function formatFbrSelfTeaser(language) {
894
+ if (language === 'zh') {
895
+ return '(我会先等待该次 FBR 的全部支线反馈返回;在收齐前不做最终行动决策。收齐后再综合提炼,并在主线对话中输出一条可复用的“智能体启动(Agent Priming)”笔记。)';
896
+ }
897
+ 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.)';
898
+ }
899
+ function formatFbrTellaskBody(language, snapshotText, options) {
900
+ const effortLineZh = options.fbrEffort >= 1
901
+ ? '对话设定:你现在是被唤起的一份“初心自我”。术语映射:在本 FBR 支线中,你是被诉请者(tellaskee,初心自我);诉请者(tellasker)就是外表自我(当前主线)。同一轮里还会有其他“初心自我”并行给出草稿(彼此没有稳定映射关系,不要当作固定身份)。外表自我会在收齐全部回贴后再统一决策;你只需给出这一份独立分析,不要替外表自我下最终行动决策。'
902
+ : '对话设定:当前成员未启用 FBR(无并行“初心自我”草稿)。';
903
+ const effortLineEn = options.fbrEffort >= 1
904
+ ? 'Conversation setup: you are one awakened “fresh-boots self.” Terminology mapping: in this FBR sideline, you are the tellaskee (the fresh-boots self), and the tellasker is the outer self (current mainline). In this same round, other fresh-boots selves also provide parallel drafts (no stable mapping—do not treat them as fixed identities). The outer self will make unified decisions only after all feedback returns; provide only this one independent draft and do not finalize next-action decisions for the outer self.'
905
+ : 'Conversation setup: FBR is disabled for this member (no parallel fresh-boots drafts).';
906
+ const missingContextHintZh = '提示:本 FBR 支线禁止任何诉请/函数调用;若信息不足,请直接列出“缺失信息 + 为什么阻塞判断”。';
907
+ const missingContextHintEn = 'Hint: this FBR sideline forbids all tellask/function calls; if context is missing, list the missing facts and why they block reasoning.';
908
+ if (language === 'zh') {
909
+ return [
910
+ effortLineZh,
911
+ '',
912
+ missingContextHintZh,
913
+ '',
914
+ '请基于下面环境信息回答:',
915
+ '- 在这个环境里要注意些什么?',
916
+ '- 哪些关键上下文仍然缺失?',
917
+ '- 请明确区分:事实依据 / 不确定项 / 建议下一步(供诉请者 tellasker(外表自我)在收齐草稿后综合提炼)。',
918
+ '',
919
+ '环境信息(由诉请者 tellasker(外表自我)提供的当前环境快照):',
920
+ snapshotText,
921
+ ].join('\n');
922
+ }
923
+ return [
924
+ effortLineEn,
925
+ '',
926
+ missingContextHintEn,
927
+ '',
928
+ 'Based on the environment info below, answer:',
929
+ '- What should we watch out for in this environment?',
930
+ '- What critical context is still missing?',
931
+ '- Clearly separate: factual evidence / uncertainties / suggested next step (for tellasker / outer-self distillation after all drafts return).',
932
+ '',
933
+ 'Environment info (the current snapshot provided by the tellasker / outer self):',
934
+ snapshotText,
935
+ ].join('\n');
936
+ }
937
+ async function generatePrimingNoteViaMainlineAgent(options) {
938
+ const { dlg, shellSnapshotText, shellResponseText, vcsRound1Text, vcsRound2Text, fbrResponses, fbrCallId, assertNotStopped, } = options;
939
+ // Trigger a normal drive and rely on driver.ts context assembly.
940
+ // Agent Priming must not trigger Diligence Push (“鞭策”); it should be best-effort
941
+ // one-shot distillation with no keep-going injection.
942
+ const prevDisableDiligencePush = dlg.disableDiligencePush;
943
+ try {
944
+ dlg.disableDiligencePush = true;
945
+ const beforeMsgs = dlg.msgs.length;
946
+ const language = (0, runtime_language_1.getWorkLanguage)();
947
+ // IMPORTANT: include shell snapshot + FBR drafts in the internal prompt itself.
948
+ // - Must be non-persisted (persistMode: 'internal')
949
+ // - Must be robust even if the driver loop iterates (context health remediation)
950
+ // - Must avoid relying on the subdialog-response queue
951
+ const evidenceParts = [];
952
+ const snapshotTrimmed = shellSnapshotText.trim();
953
+ if (snapshotTrimmed) {
954
+ evidenceParts.push(language === 'zh'
955
+ ? ['环境快照(来自 `uname -a`):', snapshotTrimmed].join('\n')
956
+ : ['Environment snapshot (from `uname -a`):', snapshotTrimmed].join('\n'));
957
+ }
958
+ const shellReturnTrimmed = typeof shellResponseText === 'string' ? shellResponseText.trim() : '';
959
+ if (shellReturnTrimmed && shellReturnTrimmed !== snapshotTrimmed) {
960
+ evidenceParts.push(language === 'zh'
961
+ ? ['Shell 反馈(完整回传):', shellReturnTrimmed].join('\n')
962
+ : ['Shell feedback (full return):', shellReturnTrimmed].join('\n'));
963
+ }
964
+ const vcsRound1Trimmed = typeof vcsRound1Text === 'string' ? vcsRound1Text.trim() : '';
965
+ if (vcsRound1Trimmed) {
966
+ evidenceParts.push(language === 'zh'
967
+ ? ['VCS Session Round-1 结果:', vcsRound1Trimmed].join('\n')
968
+ : ['VCS session Round-1 result:', vcsRound1Trimmed].join('\n'));
969
+ }
970
+ const vcsRound2Trimmed = typeof vcsRound2Text === 'string' ? vcsRound2Text.trim() : '';
971
+ if (vcsRound2Trimmed) {
972
+ evidenceParts.push(language === 'zh'
973
+ ? ['VCS Session Round-2 结果:', vcsRound2Trimmed].join('\n')
974
+ : ['VCS session Round-2 result:', vcsRound2Trimmed].join('\n'));
975
+ }
976
+ const maxDrafts = Math.min(6, fbrResponses.length);
977
+ for (let i = 0; i < maxDrafts; i++) {
978
+ const r = fbrResponses[i];
979
+ const trimmed = r.response.trim();
980
+ if (!trimmed)
981
+ continue;
982
+ const cap = 4000;
983
+ const capped = trimmed.length <= cap
984
+ ? trimmed
985
+ : language === 'zh'
986
+ ? `${trimmed.slice(0, cap).trimEnd()}\n\n(已截断:仅显示前 ${cap} 字符)`
987
+ : `${trimmed.slice(0, cap).trimEnd()}\n\n(truncated: first ${cap} chars only)`;
988
+ const fbrLabel = (() => {
989
+ const callId = fbrCallId.trim();
990
+ if (callId) {
991
+ return language === 'zh'
992
+ ? `FBR 草稿 #${i + 1}(callId: ${callId})`
993
+ : `FBR draft #${i + 1} (callId: ${callId})`;
994
+ }
995
+ return language === 'zh' ? `FBR 草稿 #${i + 1}` : `FBR draft #${i + 1}`;
996
+ })();
997
+ evidenceParts.push([fbrLabel, capped].join('\n'));
998
+ }
999
+ const evidenceBlock = evidenceParts.length > 0 ? evidenceParts.join('\n\n---\n\n') : '';
1000
+ if (!evidenceBlock.trim()) {
1001
+ throw new Error('Missing evidence for Agent Priming distillation (snapshot + FBR drafts are empty).');
1002
+ }
1003
+ const internalPrompt = language === 'zh'
1004
+ ? [
1005
+ '你正在进行智能体启动(Agent Priming)的“综合提炼”步骤。',
1006
+ '你收到本提示时,意味着该次 `freshBootsReasoning` FBR 的并发回贴已经收齐;本步骤只做综合提炼,不重新发起 FBR。',
1007
+ '请基于下方提供的环境快照(以及可选的 `freshBootsReasoning` FBR 草稿),综合提炼出一条可复用的“智能体启动(Agent Priming)笔记”。',
1008
+ '',
1009
+ '证据材料(仅供综合提炼;不要逐条复述):',
1010
+ evidenceBlock ? evidenceBlock : '(无)',
1011
+ '',
1012
+ '重要:只提炼“本次运行环境相关”的结论(例如:OS/架构、shell userland 差异、文件系统、端口/防火墙、全局链接/工具链等)。',
1013
+ '禁止:输出元话语、推理过程,或复述实现细节(例如 driver/缓存/持久化等)。',
1014
+ '若某条结论无法从环境快照或 FBR 草稿中直接支撑,请省略。',
1015
+ '',
1016
+ '要求:',
1017
+ '- 去重并消解冲突,只保留最关键的结论',
1018
+ '- 用 6~12 条 bullet points 输出(每条尽量短)',
1019
+ '- 只写结论要点;不要输出推理过程,也不要出现“我在考虑/我将要/让我们检查”等元话语',
1020
+ '- 必须明确写出:收到回贴代表该轮诉请结束;继续推进必须显式发起下一轮诉请',
1021
+ ].join('\n')
1022
+ : [
1023
+ 'You are in the Agent Priming distillation step.',
1024
+ 'Receiving this prompt means feedback from this `freshBootsReasoning` FBR run has already been collected; this step is distillation only, not another FBR initiation.',
1025
+ 'Based on the environment snapshot (and optional `freshBootsReasoning` FBR drafts) below, distill a reusable “Agent Priming note”.',
1026
+ '',
1027
+ 'Evidence (for distillation only; do not repeat draft-by-draft):',
1028
+ evidenceBlock ? evidenceBlock : '(empty)',
1029
+ '',
1030
+ 'Important: output only conclusions about this runtime environment (e.g., OS/arch, shell userland differences, filesystem behavior, ports/firewall, global links/toolchain).',
1031
+ 'Do NOT include meta talk, reasoning narration, or implementation details (e.g. driver/caching/persistence).',
1032
+ 'If a point is not directly supported by the environment snapshot or the FBR drafts, omit it.',
1033
+ '',
1034
+ 'Requirements:',
1035
+ '- Dedupe and reconcile conflicts; keep only the key conclusions',
1036
+ '- Output 6–12 concise bullet points',
1037
+ '- Conclusion bullets only; no reasoning narration or meta talk (e.g. “I think / I will / let’s inspect”)',
1038
+ '- Explicitly include this rule: a delivered response closes the current Tellask round; continuation requires a new explicit Tellask',
1039
+ ].join('\n');
1040
+ // IMPORTANT: this is an internal (non-persisted) prompt. driver.ts will inject it into
1041
+ // the LLM context for this drive only, without polluting dialog history.
1042
+ assertNotStopped?.();
1043
+ await (0, driver_entry_1.driveDialogStream)(dlg, {
1044
+ content: internalPrompt,
1045
+ msgId: (0, id_1.generateShortId)(),
1046
+ grammar: 'markdown',
1047
+ persistMode: 'internal',
1048
+ skipTaskdoc: true,
1049
+ }, true);
1050
+ assertNotStopped?.();
1051
+ const afterMsgs = dlg.msgs.length;
1052
+ if (afterMsgs <= beforeMsgs) {
1053
+ throw new Error('Agent Priming distillation produced no new messages.');
1054
+ }
1055
+ const saying = extractLastAssistantSaying(dlg.msgs).trim();
1056
+ if (!saying) {
1057
+ throw new Error('Agent Priming distillation produced empty output.');
1058
+ }
1059
+ return saying;
1060
+ }
1061
+ finally {
1062
+ dlg.disableDiligencePush = prevDisableDiligencePush;
1063
+ }
1064
+ }
1065
+ function buildCoursePrefixMsgs(entry) {
1066
+ const language = entry.workLanguage;
1067
+ const header = (() => {
1068
+ if (language === 'zh') {
1069
+ if (entry.shellPolicy === 'specialist_only') {
1070
+ return '智能体启动(Agent Priming)上下文:本进程在对话创建时已真实跑通一次“诉请(shell 专员)+ 回传 + `freshBootsReasoning` FBR + 综合提炼”,并遵循“发起 FBR → 等待回贴 → 综合决策”的时序。以下为压缩转录,作为每一程对话的开头上下文注入。';
1071
+ }
1072
+ if (entry.shellPolicy === 'no_specialist') {
1073
+ return '智能体启动(Agent Priming)上下文:本进程在对话创建时已获取环境快照并完成一次 `freshBootsReasoning` FBR + 综合提炼(无 shell 专员;不得执行任意 shell 命令),并遵循“发起 FBR → 等待回贴 → 综合决策”的时序。以下为压缩转录,作为每一程对话的开头上下文注入。';
1074
+ }
1075
+ return '智能体启动(Agent Priming)上下文:本进程在对话创建时已获取环境快照并完成一次 `freshBootsReasoning` FBR + 综合提炼,并遵循“发起 FBR → 等待回贴 → 综合决策”的时序。以下为压缩转录,作为每一程对话的开头上下文注入。';
1076
+ }
1077
+ if (entry.shellPolicy === 'specialist_only') {
1078
+ return 'Agent Priming context: this process already ran a real Tellask (shell specialist) + return + `freshBootsReasoning` 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.';
1079
+ }
1080
+ if (entry.shellPolicy === 'no_specialist') {
1081
+ return 'Agent Priming context: this process captured an environment snapshot and ran `freshBootsReasoning` 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.';
1082
+ }
1083
+ return 'Agent Priming context: this process captured an environment snapshot and ran `freshBootsReasoning` 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.';
1084
+ })();
1085
+ const shellSnapshotLabel = language === 'zh'
1086
+ ? 'Shell 环境快照(当前 Dominds 运行时;来自 `uname -a`)'
1087
+ : 'Shell environment snapshot (current Dominds runtime; `uname -a`)';
1088
+ const shellSnapshot = entry.shell.snapshotText.trim()
1089
+ ? entry.shell.snapshotText.trim()
1090
+ : language === 'zh'
1091
+ ? '(无)'
1092
+ : '(empty)';
1093
+ const vcsInventoryLabel = language === 'zh' ? 'VCS 现状盘点(rtws)' : 'VCS inventory (rtws)';
1094
+ const vcsInventory = entry.vcs.inventoryText.trim()
1095
+ ? entry.vcs.inventoryText.trim()
1096
+ : language === 'zh'
1097
+ ? '(无)'
1098
+ : '(empty)';
1099
+ const effort = Math.max(0, Math.floor(entry.fbr.effort));
1100
+ const fbrLabel = language === 'zh'
1101
+ ? 'FBR 输出(摘要;主线在收齐回贴后综合)'
1102
+ : 'FBR outputs (summary; synthesized after all feedback is collected)';
1103
+ const previewCap = Math.min(entry.fbr.responses.length, Math.max(0, Math.min(6, effort)));
1104
+ const previewResponses = previewCap > 0 ? entry.fbr.responses.slice(0, previewCap) : [];
1105
+ const blocks = [];
1106
+ for (let i = 0; i < previewResponses.length; i++) {
1107
+ const raw = previewResponses[i] ?? '';
1108
+ const trimmed = raw.trim();
1109
+ const cap = 4000;
1110
+ const capped = trimmed.length <= cap
1111
+ ? trimmed
1112
+ : language === 'zh'
1113
+ ? `${trimmed.slice(0, cap).trimEnd()}\n\n(已截断:仅显示前 ${cap} 字符)`
1114
+ : `${trimmed.slice(0, cap).trimEnd()}\n\n(truncated: first ${cap} chars only)`;
1115
+ blocks.push(language === 'zh'
1116
+ ? [`### FBR 草稿 #${i + 1}`, '', capped || '(无)'].join('\n')
1117
+ : [`### FBR draft #${i + 1}`, '', capped || '(empty)'].join('\n'));
1118
+ }
1119
+ const fbrPreview = effort < 1
1120
+ ? language === 'zh'
1121
+ ? '(已跳过:已禁用)'
1122
+ : '(skipped: disabled)'
1123
+ : blocks.length < 1
1124
+ ? language === 'zh'
1125
+ ? '(无)'
1126
+ : '(empty)'
1127
+ : blocks.join('\n\n---\n\n');
1128
+ const priming = entry.primingNote.trim();
1129
+ const out = [
1130
+ { type: 'transient_guide_msg', role: 'assistant', content: header },
1131
+ {
1132
+ type: 'environment_msg',
1133
+ role: 'user',
1134
+ content: `${shellSnapshotLabel}:\n\n${shellSnapshot}`,
1135
+ },
1136
+ {
1137
+ type: 'environment_msg',
1138
+ role: 'user',
1139
+ content: `${vcsInventoryLabel}:\n\n${vcsInventory}`,
1140
+ },
1141
+ {
1142
+ type: 'environment_msg',
1143
+ role: 'user',
1144
+ content: language === 'zh' ? `${fbrLabel}:\n\n${fbrPreview}` : `${fbrLabel}:\n\n${fbrPreview}`,
1145
+ },
1146
+ ];
1147
+ if (entry.shell.kind === 'specialist_tellask') {
1148
+ const fullReturn = entry.shell.responseText.trim();
1149
+ const snapshot = entry.shell.snapshotText.trim();
1150
+ if (fullReturn && fullReturn !== snapshot) {
1151
+ out.push({
1152
+ type: 'environment_msg',
1153
+ role: 'user',
1154
+ content: language === 'zh'
1155
+ ? `Shell 反馈(完整回传):\n\n${fullReturn}`
1156
+ : `Shell feedback (full return):\n\n${fullReturn}`,
1157
+ });
1158
+ }
1159
+ }
1160
+ if (priming) {
1161
+ out.push({
1162
+ type: 'environment_msg',
1163
+ role: 'user',
1164
+ content: language === 'zh'
1165
+ ? `智能体启动(Agent Priming)笔记(综合提炼):\n\n${priming}`
1166
+ : `Agent Priming note (distilled):\n\n${priming}`,
1167
+ });
1168
+ }
1169
+ return out;
1170
+ }
1171
+ async function replayAgentPriming(dlg, entry) {
1172
+ const hadActiveRunBefore = (0, dialog_run_state_1.hasActiveRun)(dlg.id);
1173
+ const primingAbortSignal = (0, dialog_run_state_1.createActiveRun)(dlg.id);
1174
+ const ownsActiveRun = !hadActiveRunBefore;
1175
+ const assertNotStopped = () => {
1176
+ throwIfAgentPrimingStopped(dlg, primingAbortSignal);
1177
+ };
1178
+ const release = await dlg.acquire();
1179
+ let interruptedRunState = null;
1180
+ try {
1181
+ const language = (0, runtime_language_1.getWorkLanguage)();
1182
+ dlg.setCoursePrefixMsgs(buildCoursePrefixMsgs(entry));
1183
+ await (0, dialog_run_state_1.setDialogRunState)(dlg.id, { kind: 'proceeding' });
1184
+ assertNotStopped();
1185
+ // Phase 1: shell ask (and optional prelude intro)
1186
+ let shellCallId = null;
1187
+ let shellMentionList = null;
1188
+ try {
1189
+ assertNotStopped();
1190
+ await dlg.notifyGeneratingStart();
1191
+ await emitUiOnlyMarkdownEventsAndPersist(dlg, formatPreludeIntro(language, true, entry.shellPolicy, entry.shell.kind === 'specialist_tellask' ? entry.shell.specialistId : null));
1192
+ if (entry.shell.kind === 'specialist_tellask') {
1193
+ const shellCall = await emitSyntheticTellaskCall(dlg, {
1194
+ callName: 'tellaskSessionless',
1195
+ mentionList: [`@${entry.shell.specialistId}`],
1196
+ targetAgentId: entry.shell.specialistId,
1197
+ tellaskContent: entry.shell.tellaskBody,
1198
+ });
1199
+ shellCallId = shellCall.callId;
1200
+ shellMentionList = shellCall.mentionList ?? null;
1201
+ }
1202
+ else {
1203
+ await emitSayingEventsAndPersist(dlg, entry.shell.directNoteMarkdown);
1204
+ }
1205
+ }
1206
+ finally {
1207
+ try {
1208
+ await dlg.notifyGeneratingFinish();
1209
+ }
1210
+ catch (_finishErr) {
1211
+ // best-effort
1212
+ }
1213
+ }
1214
+ // Phase 2: shell response (separate bubble)
1215
+ if (entry.shell.kind === 'specialist_tellask' && shellCallId && shellMentionList) {
1216
+ assertNotStopped();
1217
+ await dlg.receiveTeammateResponse(entry.shell.specialistId, 'tellaskSessionless', shellMentionList, entry.shell.tellaskBody, 'completed', dlg.id, {
1218
+ response: entry.shell.responseText,
1219
+ agentId: entry.shell.specialistId,
1220
+ callId: shellCallId,
1221
+ originMemberId: dlg.agentId,
1222
+ });
1223
+ }
1224
+ // Phase 2.5: VCS long-session drill (two rounds)
1225
+ if (entry.vcs.kind === 'specialist_session') {
1226
+ let round1CallId = null;
1227
+ let round1MentionList = null;
1228
+ let round2CallId = null;
1229
+ let round2MentionList = null;
1230
+ try {
1231
+ assertNotStopped();
1232
+ await dlg.notifyGeneratingStart();
1233
+ const round1 = await emitSyntheticTellaskCall(dlg, {
1234
+ callName: 'tellask',
1235
+ mentionList: [`@${entry.vcs.specialistId}`],
1236
+ targetAgentId: entry.vcs.specialistId,
1237
+ sessionSlug: entry.vcs.sessionSlug,
1238
+ tellaskContent: entry.vcs.round1.tellaskBody,
1239
+ });
1240
+ round1CallId = round1.callId;
1241
+ round1MentionList = round1.mentionList ?? null;
1242
+ }
1243
+ finally {
1244
+ try {
1245
+ await dlg.notifyGeneratingFinish();
1246
+ }
1247
+ catch (_finishErr) {
1248
+ // best-effort
1249
+ }
1250
+ }
1251
+ if (round1CallId && round1MentionList) {
1252
+ assertNotStopped();
1253
+ await dlg.receiveTeammateResponse(entry.vcs.specialistId, 'tellask', round1MentionList, entry.vcs.round1.tellaskBody, 'completed', dlg.id, {
1254
+ response: entry.vcs.round1.responseText,
1255
+ agentId: entry.vcs.specialistId,
1256
+ callId: round1CallId,
1257
+ originMemberId: dlg.agentId,
1258
+ });
1259
+ }
1260
+ try {
1261
+ assertNotStopped();
1262
+ await dlg.notifyGeneratingStart();
1263
+ const round2 = await emitSyntheticTellaskCall(dlg, {
1264
+ callName: 'tellask',
1265
+ mentionList: [`@${entry.vcs.specialistId}`],
1266
+ targetAgentId: entry.vcs.specialistId,
1267
+ sessionSlug: entry.vcs.sessionSlug,
1268
+ tellaskContent: entry.vcs.round2.tellaskBody,
1269
+ });
1270
+ round2CallId = round2.callId;
1271
+ round2MentionList = round2.mentionList ?? null;
1272
+ }
1273
+ finally {
1274
+ try {
1275
+ await dlg.notifyGeneratingFinish();
1276
+ }
1277
+ catch (_finishErr) {
1278
+ // best-effort
1279
+ }
1280
+ }
1281
+ if (round2CallId && round2MentionList) {
1282
+ assertNotStopped();
1283
+ await dlg.receiveTeammateResponse(entry.vcs.specialistId, 'tellask', round2MentionList, entry.vcs.round2.tellaskBody, 'completed', dlg.id, {
1284
+ response: entry.vcs.round2.responseText,
1285
+ agentId: entry.vcs.specialistId,
1286
+ callId: round2CallId,
1287
+ originMemberId: dlg.agentId,
1288
+ });
1289
+ }
1290
+ }
1291
+ else {
1292
+ try {
1293
+ assertNotStopped();
1294
+ await dlg.notifyGeneratingStart();
1295
+ await emitSayingEventsAndPersist(dlg, entry.vcs.round1NoteMarkdown);
1296
+ }
1297
+ finally {
1298
+ try {
1299
+ await dlg.notifyGeneratingFinish();
1300
+ }
1301
+ catch (_finishErr) {
1302
+ // best-effort
1303
+ }
1304
+ }
1305
+ try {
1306
+ assertNotStopped();
1307
+ await dlg.notifyGeneratingStart();
1308
+ await emitSayingEventsAndPersist(dlg, entry.vcs.round2NoteMarkdown);
1309
+ }
1310
+ finally {
1311
+ try {
1312
+ await dlg.notifyGeneratingFinish();
1313
+ }
1314
+ catch (_finishErr) {
1315
+ // best-effort
1316
+ }
1317
+ }
1318
+ }
1319
+ // Phase 3: FBR ask (call bubble)
1320
+ let fbrCallId = null;
1321
+ const effort = Math.max(0, Math.floor(entry.fbr.effort));
1322
+ if (effort >= 1 && entry.fbr.responses.length > 0) {
1323
+ try {
1324
+ assertNotStopped();
1325
+ await dlg.notifyGeneratingStart();
1326
+ const fbrCallBody = [entry.fbr.selfTeaser, '', entry.fbr.tellaskContent].join('\n');
1327
+ const fbrCall = await emitSyntheticTellaskCall(dlg, {
1328
+ callName: 'freshBootsReasoning',
1329
+ tellaskContent: fbrCallBody,
1330
+ });
1331
+ fbrCallId = fbrCall.callId;
1332
+ }
1333
+ finally {
1334
+ try {
1335
+ await dlg.notifyGeneratingFinish();
1336
+ }
1337
+ catch (_finishErr) {
1338
+ // best-effort
1339
+ }
1340
+ }
1341
+ // Phase 4: FBR responses (separate bubbles, in stable index order)
1342
+ if (fbrCallId) {
1343
+ const normalized = Math.max(1, effort);
1344
+ const responses = entry.fbr.responses.slice(0, normalized);
1345
+ for (let i = 0; i < responses.length; i++) {
1346
+ assertNotStopped();
1347
+ const raw = responses[i] ?? '';
1348
+ await dlg.receiveTeammateResponse(entry.fbr.responderAgentId, 'freshBootsReasoning', undefined, entry.fbr.tellaskContent, 'completed', dlg.id, {
1349
+ response: raw,
1350
+ agentId: entry.fbr.responderAgentId,
1351
+ callId: fbrCallId,
1352
+ originMemberId: dlg.agentId,
1353
+ });
1354
+ }
1355
+ }
1356
+ }
1357
+ // Phase 5: summary bubble
1358
+ try {
1359
+ assertNotStopped();
1360
+ await dlg.notifyGeneratingStart();
1361
+ await emitSayingEventsAndPersist(dlg, entry.primingNote);
1362
+ }
1363
+ finally {
1364
+ try {
1365
+ await dlg.notifyGeneratingFinish();
1366
+ }
1367
+ catch (_finishErr) {
1368
+ // best-effort
1369
+ }
1370
+ }
1371
+ }
1372
+ catch (err) {
1373
+ if (isAgentPrimingInterruptedError(err)) {
1374
+ interruptedRunState = {
1375
+ kind: 'interrupted',
1376
+ reason: { kind: err.reason },
1377
+ };
1378
+ log_1.log.debug('Agent Priming replay interrupted by stop request', undefined, {
1379
+ dialogId: dlg.id.valueOf(),
1380
+ reason: err.reason,
1381
+ });
1382
+ }
1383
+ else {
1384
+ log_1.log.warn('Agent Priming replay failed (best-effort)', err, { dialogId: dlg.id.valueOf() });
1385
+ }
1386
+ }
1387
+ finally {
1388
+ try {
1389
+ if (interruptedRunState) {
1390
+ await (0, dialog_run_state_1.setDialogRunState)(dlg.id, interruptedRunState);
1391
+ }
1392
+ else {
1393
+ let nextIdle = { kind: 'idle_waiting_user' };
1394
+ try {
1395
+ nextIdle = await (0, dialog_run_state_1.computeIdleRunState)(dlg);
1396
+ }
1397
+ catch (err) {
1398
+ log_1.log.warn('Failed to compute idle runState after Agent Priming replay; falling back', err, {
1399
+ dialogId: dlg.id.valueOf(),
1400
+ });
1401
+ }
1402
+ await (0, dialog_run_state_1.setDialogRunState)(dlg.id, nextIdle);
1403
+ }
1404
+ }
1405
+ finally {
1406
+ if (ownsActiveRun) {
1407
+ (0, dialog_run_state_1.clearActiveRun)(dlg.id);
1408
+ }
1409
+ release();
1410
+ }
1411
+ }
1412
+ }
1413
+ async function runAgentPrimingLive(dlg) {
1414
+ const createdAt = (0, time_1.formatUnifiedTimestamp)(new Date());
1415
+ const language = (0, runtime_language_1.getWorkLanguage)();
1416
+ const hadActiveRunBefore = (0, dialog_run_state_1.hasActiveRun)(dlg.id);
1417
+ const primingAbortSignal = (0, dialog_run_state_1.createActiveRun)(dlg.id);
1418
+ const ownsActiveRun = !hadActiveRunBefore;
1419
+ const assertNotStopped = () => {
1420
+ throwIfAgentPrimingStopped(dlg, primingAbortSignal);
1421
+ };
1422
+ const prevDisableDiligencePush = dlg.disableDiligencePush;
1423
+ // Agent Priming is a bounded bootstrap routine; no keep-going injection should appear
1424
+ // during the priming lifecycle (including any auto-revive drives triggered by subdialog replies).
1425
+ dlg.disableDiligencePush = true;
1426
+ let fatalRunState = null;
1427
+ let shellPolicy = 'no_specialist';
1428
+ let specialistId = null;
1429
+ let shellTellaskBody = '';
1430
+ let shellResponseText = '';
1431
+ let snapshotText = '';
1432
+ let directNoteMarkdown = '';
1433
+ let vcsRound1Body = '';
1434
+ let vcsRound2Body = '';
1435
+ let vcsRound1ResponseText = '';
1436
+ let vcsRound2ResponseText = '';
1437
+ let vcsEvidenceRound1Text = '';
1438
+ let vcsEvidenceRound2Text = '';
1439
+ let vcsRound1NoteMarkdown = '';
1440
+ let vcsRound2NoteMarkdown = '';
1441
+ let vcsInventoryText = '';
1442
+ let fbrCallBody = '';
1443
+ let selfTeaser = '';
1444
+ let fbrEffort = 0;
1445
+ const fbrResponsesForCache = [];
1446
+ const fbrResponsesForInjection = [];
1447
+ try {
1448
+ await (0, dialog_run_state_1.setDialogRunState)(dlg.id, { kind: 'proceeding' });
1449
+ assertNotStopped();
1450
+ const team = await team_1.Team.load();
1451
+ assertNotStopped();
1452
+ const member = team.getMember(dlg.agentId);
1453
+ const specialists = team.shellSpecialists
1454
+ .filter((s) => typeof s === 'string')
1455
+ .map((s) => s.trim())
1456
+ .filter((s) => s !== '');
1457
+ const selfIsShellSpecialist = specialists.includes(dlg.agentId);
1458
+ specialistId = specialists.find((s) => s !== dlg.agentId) ?? null;
1459
+ shellPolicy =
1460
+ specialists.length < 1
1461
+ ? 'no_specialist'
1462
+ : selfIsShellSpecialist
1463
+ ? 'self_is_specialist'
1464
+ : 'specialist_only';
1465
+ let shellCallId = null;
1466
+ let shellMentionList = null;
1467
+ let shellTellaskBodyForSubdialog = null;
1468
+ // Phase 1: shell ask (and optional prelude intro)
1469
+ if (shellPolicy === 'specialist_only' && specialistId !== null) {
1470
+ const ensuredSpecialistId = specialistId;
1471
+ shellTellaskBody = formatShellTellaskBody(language, specialistId);
1472
+ assertNotStopped();
1473
+ await dlg.withLock(async () => {
1474
+ try {
1475
+ await dlg.notifyGeneratingStart();
1476
+ await emitUiOnlyMarkdownEventsAndPersist(dlg, formatPreludeIntro(language, false, shellPolicy, ensuredSpecialistId));
1477
+ const call = await emitSyntheticTellaskCall(dlg, {
1478
+ callName: 'tellaskSessionless',
1479
+ mentionList: [`@${ensuredSpecialistId}`],
1480
+ targetAgentId: ensuredSpecialistId,
1481
+ tellaskContent: shellTellaskBody,
1482
+ });
1483
+ shellCallId = call.callId;
1484
+ shellMentionList = call.mentionList;
1485
+ shellTellaskBodyForSubdialog = call.tellaskContent;
1486
+ }
1487
+ finally {
1488
+ try {
1489
+ await dlg.notifyGeneratingFinish();
1490
+ }
1491
+ catch (_finishErr) {
1492
+ // best-effort
1493
+ }
1494
+ }
1495
+ });
1496
+ }
1497
+ else {
1498
+ // Either no shell specialist is configured, or the dialog owner is itself a shell specialist.
1499
+ // In both cases we skip the shell Tellask step and let the runtime capture a baseline snapshot.
1500
+ // Keep it safe and deterministic: no network, no writes.
1501
+ const unameOutput = await runUnameA();
1502
+ assertNotStopped();
1503
+ shellResponseText = unameOutput;
1504
+ snapshotText = unameOutput;
1505
+ const directNote = (() => {
1506
+ if (shellPolicy === 'self_is_specialist') {
1507
+ return language === 'zh'
1508
+ ? ['由 Dominds 运行时执行:`uname -a`', '', '```console', unameOutput, '```', ''].join('\n')
1509
+ : ['Dominds runtime ran: `uname -a`', '', '```console', unameOutput, '```', ''].join('\n');
1510
+ }
1511
+ return language === 'zh'
1512
+ ? [
1513
+ '未配置 shell 专员:由 Dominds 运行时仅执行基线命令 `uname -a` 以获取环境快照。',
1514
+ '约束:后续**不得执行任意 shell 命令**;只能通过文件读写等非 shell 工具推进。',
1515
+ '',
1516
+ '```console',
1517
+ unameOutput,
1518
+ '```',
1519
+ '',
1520
+ ].join('\n')
1521
+ : [
1522
+ 'No shell specialist configured: Dominds runtime ran only the baseline command `uname -a` to capture an environment snapshot.',
1523
+ 'Constraint: do **not** run arbitrary shell commands; proceed only with non-shell tools like file read/write.',
1524
+ '',
1525
+ '```console',
1526
+ unameOutput,
1527
+ '```',
1528
+ '',
1529
+ ].join('\n');
1530
+ })();
1531
+ directNoteMarkdown = directNote;
1532
+ assertNotStopped();
1533
+ await dlg.withLock(async () => {
1534
+ try {
1535
+ await dlg.notifyGeneratingStart();
1536
+ await emitUiOnlyMarkdownEventsAndPersist(dlg, formatPreludeIntro(language, false, shellPolicy, specialistId));
1537
+ await emitSayingEventsAndPersist(dlg, directNoteMarkdown);
1538
+ }
1539
+ finally {
1540
+ try {
1541
+ await dlg.notifyGeneratingFinish();
1542
+ }
1543
+ catch (_finishErr) {
1544
+ // best-effort
1545
+ }
1546
+ }
1547
+ });
1548
+ }
1549
+ // Phase 2: shell response (separate bubble)
1550
+ if (shellPolicy === 'specialist_only' &&
1551
+ specialistId !== null &&
1552
+ shellCallId &&
1553
+ shellMentionList) {
1554
+ const ensuredSpecialistId = specialistId;
1555
+ const ensuredShellCallId = shellCallId;
1556
+ const ensuredShellMentionList = shellMentionList;
1557
+ const tellaskBody = shellTellaskBodyForSubdialog ?? shellTellaskBody;
1558
+ assertNotStopped();
1559
+ const sub = await dlg.withLock(async () => {
1560
+ return await dlg.createSubDialog(ensuredSpecialistId, ensuredShellMentionList, tellaskBody, {
1561
+ callName: 'tellaskSessionless',
1562
+ originMemberId: dlg.agentId,
1563
+ callerDialogId: dlg.id.selfId,
1564
+ callId: ensuredShellCallId,
1565
+ collectiveTargets: [ensuredSpecialistId],
1566
+ });
1567
+ });
1568
+ const initPrompt = (0, inter_dialog_format_1.formatAssignmentFromSupdialog)({
1569
+ callName: 'tellaskSessionless',
1570
+ fromAgentId: dlg.agentId,
1571
+ toAgentId: sub.agentId,
1572
+ mentionList: ensuredShellMentionList,
1573
+ tellaskContent: tellaskBody,
1574
+ language,
1575
+ collectiveTargets: [ensuredSpecialistId],
1576
+ });
1577
+ await (0, driver_entry_1.driveDialogStream)(sub, { content: initPrompt, msgId: (0, id_1.generateShortId)(), grammar: 'markdown', skipTaskdoc: true }, true);
1578
+ assertNotStopped();
1579
+ shellResponseText = extractLastAssistantSaying(sub.msgs);
1580
+ const toolResult = extractLastShellCmdResultText(sub.msgs);
1581
+ snapshotText = toolResult ? toolResult : shellResponseText;
1582
+ if (!snapshotText.trim()) {
1583
+ // Specialist produced no usable output (misconfigured tools, provider issues, etc.).
1584
+ // Fall back to a runtime-executed `uname -a` so we can still proceed to FBR.
1585
+ snapshotText = await runUnameA();
1586
+ assertNotStopped();
1587
+ }
1588
+ assertNotStopped();
1589
+ await dlg.withLock(async () => {
1590
+ await dlg.receiveTeammateResponse(ensuredSpecialistId, 'tellaskSessionless', ensuredShellMentionList, tellaskBody, 'completed', sub.id, {
1591
+ response: shellResponseText,
1592
+ agentId: ensuredSpecialistId,
1593
+ callId: ensuredShellCallId,
1594
+ originMemberId: dlg.agentId,
1595
+ });
1596
+ });
1597
+ }
1598
+ // Phase 2.5: VCS tellask-session drill (two rounds) or runtime inventory.
1599
+ if (shellPolicy === 'specialist_only' && specialistId !== null) {
1600
+ const ensuredSpecialistId = specialistId;
1601
+ try {
1602
+ vcsRound1Body = formatVcsSessionRound1TellaskBody(language);
1603
+ let round1CallId = '';
1604
+ let round1MentionList = [];
1605
+ let round1TellaskBodyForSubdialog = '';
1606
+ await dlg.withLock(async () => {
1607
+ try {
1608
+ await dlg.notifyGeneratingStart();
1609
+ const call = await emitSyntheticTellaskCall(dlg, {
1610
+ callName: 'tellask',
1611
+ mentionList: [`@${ensuredSpecialistId}`],
1612
+ targetAgentId: ensuredSpecialistId,
1613
+ sessionSlug: PRIMING_VCS_SESSION_SLUG,
1614
+ tellaskContent: vcsRound1Body,
1615
+ });
1616
+ round1CallId = call.callId;
1617
+ round1MentionList = call.mentionList;
1618
+ round1TellaskBodyForSubdialog = call.tellaskContent;
1619
+ }
1620
+ finally {
1621
+ try {
1622
+ await dlg.notifyGeneratingFinish();
1623
+ }
1624
+ catch (_finishErr) {
1625
+ // best-effort
1626
+ }
1627
+ }
1628
+ });
1629
+ assertNotStopped();
1630
+ const round1Sub = await dlg.withLock(async () => {
1631
+ return await dlg.createSubDialog(ensuredSpecialistId, round1MentionList, round1TellaskBodyForSubdialog || vcsRound1Body, {
1632
+ callName: 'tellask',
1633
+ originMemberId: dlg.agentId,
1634
+ callerDialogId: dlg.id.selfId,
1635
+ callId: round1CallId,
1636
+ sessionSlug: PRIMING_VCS_SESSION_SLUG,
1637
+ collectiveTargets: [ensuredSpecialistId],
1638
+ });
1639
+ });
1640
+ const rootDialog = dlg instanceof dialog_1.RootDialog ? dlg : dlg instanceof dialog_1.SubDialog ? dlg.rootDialog : undefined;
1641
+ if (rootDialog) {
1642
+ assertNotStopped();
1643
+ rootDialog.registerSubdialog(round1Sub);
1644
+ await rootDialog.saveSubdialogRegistry();
1645
+ }
1646
+ const round1Prompt = (0, inter_dialog_format_1.formatAssignmentFromSupdialog)({
1647
+ callName: 'tellask',
1648
+ fromAgentId: dlg.agentId,
1649
+ toAgentId: round1Sub.agentId,
1650
+ mentionList: round1MentionList,
1651
+ tellaskContent: round1TellaskBodyForSubdialog || vcsRound1Body,
1652
+ language,
1653
+ collectiveTargets: [ensuredSpecialistId],
1654
+ });
1655
+ await (0, driver_entry_1.driveDialogStream)(round1Sub, {
1656
+ content: round1Prompt,
1657
+ msgId: (0, id_1.generateShortId)(),
1658
+ grammar: 'markdown',
1659
+ skipTaskdoc: true,
1660
+ }, true);
1661
+ assertNotStopped();
1662
+ vcsRound1ResponseText = extractLastAssistantSaying(round1Sub.msgs).trim();
1663
+ if (!vcsRound1ResponseText) {
1664
+ throw new Error('Specialist VCS session round-1 returned empty output');
1665
+ }
1666
+ assertNotStopped();
1667
+ await dlg.withLock(async () => {
1668
+ await dlg.receiveTeammateResponse(ensuredSpecialistId, 'tellask', round1MentionList, round1TellaskBodyForSubdialog || vcsRound1Body, 'completed', round1Sub.id, {
1669
+ response: vcsRound1ResponseText,
1670
+ agentId: ensuredSpecialistId,
1671
+ callId: round1CallId,
1672
+ originMemberId: dlg.agentId,
1673
+ });
1674
+ });
1675
+ vcsRound2Body = formatVcsSessionRound2TellaskBody(language, vcsRound1ResponseText);
1676
+ let round2CallId = '';
1677
+ let round2MentionList = [];
1678
+ let round2TellaskBodyForSubdialog = '';
1679
+ await dlg.withLock(async () => {
1680
+ try {
1681
+ await dlg.notifyGeneratingStart();
1682
+ const call = await emitSyntheticTellaskCall(dlg, {
1683
+ callName: 'tellask',
1684
+ mentionList: [`@${ensuredSpecialistId}`],
1685
+ targetAgentId: ensuredSpecialistId,
1686
+ sessionSlug: PRIMING_VCS_SESSION_SLUG,
1687
+ tellaskContent: vcsRound2Body,
1688
+ });
1689
+ round2CallId = call.callId;
1690
+ round2MentionList = call.mentionList;
1691
+ round2TellaskBodyForSubdialog = call.tellaskContent;
1692
+ }
1693
+ finally {
1694
+ try {
1695
+ await dlg.notifyGeneratingFinish();
1696
+ }
1697
+ catch (_finishErr) {
1698
+ // best-effort
1699
+ }
1700
+ }
1701
+ });
1702
+ const round2Prompt = (0, inter_dialog_format_1.formatAssignmentFromSupdialog)({
1703
+ callName: 'tellask',
1704
+ fromAgentId: dlg.agentId,
1705
+ toAgentId: round1Sub.agentId,
1706
+ mentionList: round2MentionList,
1707
+ tellaskContent: round2TellaskBodyForSubdialog || vcsRound2Body,
1708
+ language,
1709
+ collectiveTargets: [ensuredSpecialistId],
1710
+ });
1711
+ await (0, driver_entry_1.driveDialogStream)(round1Sub, {
1712
+ content: round2Prompt,
1713
+ msgId: (0, id_1.generateShortId)(),
1714
+ grammar: 'markdown',
1715
+ skipTaskdoc: true,
1716
+ }, true);
1717
+ assertNotStopped();
1718
+ vcsRound2ResponseText = extractLastAssistantSaying(round1Sub.msgs).trim();
1719
+ if (!vcsRound2ResponseText) {
1720
+ throw new Error('Specialist VCS session round-2 returned empty output');
1721
+ }
1722
+ assertNotStopped();
1723
+ await dlg.withLock(async () => {
1724
+ await dlg.receiveTeammateResponse(ensuredSpecialistId, 'tellask', round2MentionList, round2TellaskBodyForSubdialog || vcsRound2Body, 'completed', round1Sub.id, {
1725
+ response: vcsRound2ResponseText,
1726
+ agentId: ensuredSpecialistId,
1727
+ callId: round2CallId,
1728
+ originMemberId: dlg.agentId,
1729
+ });
1730
+ });
1731
+ vcsInventoryText = [vcsRound1ResponseText, '', vcsRound2ResponseText].join('\n');
1732
+ }
1733
+ catch (err) {
1734
+ log_1.log.warn('VCS tellask-session drill via shell specialist failed; fallback to runtime inventory', err, {
1735
+ dialogId: dlg.id.valueOf(),
1736
+ specialistId: ensuredSpecialistId,
1737
+ });
1738
+ }
1739
+ }
1740
+ const runtimeInventory = await collectRtwsGitInventory();
1741
+ assertNotStopped();
1742
+ const runtimeRound1Text = formatRtwsGitInventoryRound1(language, runtimeInventory);
1743
+ const runtimeRound2Text = formatRtwsGitInventoryRound2(language, runtimeInventory);
1744
+ const runtimeInventoryText = [runtimeRound1Text, '', runtimeRound2Text].join('\n');
1745
+ if (shellPolicy === 'specialist_only' &&
1746
+ specialistId !== null &&
1747
+ vcsRound1ResponseText.trim() &&
1748
+ vcsRound2ResponseText.trim()) {
1749
+ // Keep teammate replies as collaboration transcript, but use runtime-verified
1750
+ // inventory as canonical facts for downstream FBR/distillation evidence.
1751
+ vcsEvidenceRound1Text = runtimeRound1Text;
1752
+ vcsEvidenceRound2Text = runtimeRound2Text;
1753
+ vcsInventoryText = runtimeInventoryText;
1754
+ }
1755
+ else {
1756
+ vcsRound1ResponseText = runtimeRound1Text;
1757
+ vcsRound2ResponseText = runtimeRound2Text;
1758
+ vcsEvidenceRound1Text = runtimeRound1Text;
1759
+ vcsEvidenceRound2Text = runtimeRound2Text;
1760
+ vcsRound1NoteMarkdown = formatRuntimeVcsRoundNote(language, 1, vcsRound1ResponseText);
1761
+ vcsRound2NoteMarkdown = formatRuntimeVcsRoundNote(language, 2, vcsRound2ResponseText);
1762
+ vcsInventoryText = runtimeInventoryText;
1763
+ assertNotStopped();
1764
+ await dlg.withLock(async () => {
1765
+ try {
1766
+ await dlg.notifyGeneratingStart();
1767
+ await emitSayingEventsAndPersist(dlg, vcsRound1NoteMarkdown);
1768
+ }
1769
+ finally {
1770
+ try {
1771
+ await dlg.notifyGeneratingFinish();
1772
+ }
1773
+ catch (_finishErr) {
1774
+ // best-effort
1775
+ }
1776
+ }
1777
+ });
1778
+ assertNotStopped();
1779
+ await dlg.withLock(async () => {
1780
+ try {
1781
+ await dlg.notifyGeneratingStart();
1782
+ await emitSayingEventsAndPersist(dlg, vcsRound2NoteMarkdown);
1783
+ }
1784
+ finally {
1785
+ try {
1786
+ await dlg.notifyGeneratingFinish();
1787
+ }
1788
+ catch (_finishErr) {
1789
+ // best-effort
1790
+ }
1791
+ }
1792
+ });
1793
+ }
1794
+ const fbrSnapshotText = [
1795
+ snapshotText.trim() ? snapshotText.trim() : '',
1796
+ vcsInventoryText.trim() ? vcsInventoryText.trim() : '',
1797
+ ]
1798
+ .filter((part) => part !== '')
1799
+ .join('\n\n---\n\n');
1800
+ const rawFbrEffort = member ? member.fbr_effort : undefined;
1801
+ fbrEffort = (() => {
1802
+ if (typeof rawFbrEffort !== 'number' || !Number.isFinite(rawFbrEffort))
1803
+ return 3;
1804
+ const n = Math.floor(rawFbrEffort);
1805
+ if (n < 0)
1806
+ return 0;
1807
+ if (n > 100) {
1808
+ throw new Error('Invalid fbr_effort: must be <= 100');
1809
+ }
1810
+ return n;
1811
+ })();
1812
+ fbrCallBody = formatFbrTellaskBody(language, fbrSnapshotText.trim() ? fbrSnapshotText : snapshotText, { fbrEffort });
1813
+ selfTeaser = formatFbrSelfTeaser(language);
1814
+ let fbrCallId = null;
1815
+ let fbrCallName = null;
1816
+ // Phase 3: FBR ask (call bubble)
1817
+ if (fbrEffort >= 1) {
1818
+ assertNotStopped();
1819
+ await dlg.withLock(async () => {
1820
+ try {
1821
+ await dlg.notifyGeneratingStart();
1822
+ await emitUiOnlyMarkdownEventsAndPersist(dlg, selfTeaser);
1823
+ const fbrCall = await emitSyntheticTellaskCall(dlg, {
1824
+ callName: 'freshBootsReasoning',
1825
+ tellaskContent: fbrCallBody,
1826
+ });
1827
+ fbrCallId = fbrCall.callId;
1828
+ fbrCallName = fbrCall.callName;
1829
+ }
1830
+ finally {
1831
+ try {
1832
+ await dlg.notifyGeneratingFinish();
1833
+ }
1834
+ catch (_finishErr) {
1835
+ // best-effort
1836
+ }
1837
+ }
1838
+ });
1839
+ // Phase 4: FBR responses (separate bubbles; order is not meaningful)
1840
+ if (!fbrCallId || fbrCallName !== 'freshBootsReasoning') {
1841
+ throw new Error('Missing FBR callId/callName');
1842
+ }
1843
+ const ensuredFbrCallId = fbrCallId;
1844
+ const ensuredFbrCallName = fbrCallName;
1845
+ const perInstance = Array.from({ length: fbrEffort }, (_, idx) => idx + 1);
1846
+ const created = await Promise.all(perInstance.map(async (i) => {
1847
+ assertNotStopped();
1848
+ const instanceBody = fbrEffort > 1
1849
+ ? [
1850
+ fbrCallBody,
1851
+ '',
1852
+ language === 'zh'
1853
+ ? '提示:请尽量提供与其它 FBR 草稿不同的视角(例如安全/限制/可验证性/风险点)。'
1854
+ : 'Hint: try to provide a distinct angle vs other FBR drafts (e.g. security/constraints/verifiability/risk).',
1855
+ ].join('\n')
1856
+ : fbrCallBody;
1857
+ assertNotStopped();
1858
+ const sub = await dlg.withLock(async () => {
1859
+ return await dlg.createSubDialog(dlg.agentId, undefined, instanceBody, {
1860
+ callName: ensuredFbrCallName,
1861
+ originMemberId: dlg.agentId,
1862
+ callerDialogId: dlg.id.selfId,
1863
+ callId: ensuredFbrCallId,
1864
+ collectiveTargets: [dlg.agentId],
1865
+ });
1866
+ });
1867
+ const initPrompt = (0, inter_dialog_format_1.formatAssignmentFromSupdialog)({
1868
+ callName: ensuredFbrCallName,
1869
+ fromAgentId: dlg.agentId,
1870
+ toAgentId: sub.agentId,
1871
+ tellaskContent: instanceBody,
1872
+ language,
1873
+ collectiveTargets: [dlg.agentId],
1874
+ });
1875
+ await (0, driver_entry_1.driveDialogStream)(sub, {
1876
+ content: initPrompt,
1877
+ msgId: (0, id_1.generateShortId)(),
1878
+ grammar: 'markdown',
1879
+ skipTaskdoc: true,
1880
+ }, true);
1881
+ assertNotStopped();
1882
+ const responseText = extractLastAssistantSaying(sub.msgs);
1883
+ return { sub, responseText };
1884
+ }));
1885
+ assertNotStopped();
1886
+ for (const r of created) {
1887
+ assertNotStopped();
1888
+ const responseText = r.responseText;
1889
+ fbrResponsesForCache.push(responseText);
1890
+ fbrResponsesForInjection.push({ subdialogId: r.sub.id.selfId, response: responseText });
1891
+ await dlg.withLock(async () => {
1892
+ await dlg.receiveTeammateResponse(dlg.agentId, ensuredFbrCallName, undefined, fbrCallBody, 'completed', r.sub.id, {
1893
+ response: responseText,
1894
+ agentId: dlg.agentId,
1895
+ callId: ensuredFbrCallId,
1896
+ originMemberId: dlg.agentId,
1897
+ });
1898
+ });
1899
+ }
1900
+ }
1901
+ if (!fbrCallId || fbrCallName !== 'freshBootsReasoning') {
1902
+ if (fbrEffort >= 1) {
1903
+ throw new Error('Missing FBR callId/callName for Agent Priming distillation.');
1904
+ }
1905
+ // FBR disabled (fbr_effort == 0): distill from shell snapshot only.
1906
+ fbrCallId = '';
1907
+ fbrCallName = 'freshBootsReasoning';
1908
+ }
1909
+ const primingNote = await generatePrimingNoteViaMainlineAgent({
1910
+ dlg,
1911
+ shellSnapshotText: snapshotText,
1912
+ shellResponseText: shellResponseText,
1913
+ vcsRound1Text: vcsEvidenceRound1Text,
1914
+ vcsRound2Text: vcsEvidenceRound2Text,
1915
+ fbrResponses: fbrResponsesForInjection,
1916
+ fbrCallId: fbrCallId,
1917
+ assertNotStopped,
1918
+ });
1919
+ assertNotStopped();
1920
+ const entry = {
1921
+ createdAt,
1922
+ workLanguage: language,
1923
+ shellPolicy,
1924
+ shell: shellPolicy === 'specialist_only' && specialistId !== null
1925
+ ? {
1926
+ kind: 'specialist_tellask',
1927
+ specialistId,
1928
+ tellaskBody: shellTellaskBody,
1929
+ responseText: shellResponseText,
1930
+ snapshotText,
1931
+ }
1932
+ : {
1933
+ kind: 'direct_shell',
1934
+ directNoteMarkdown,
1935
+ snapshotText,
1936
+ },
1937
+ vcs: shellPolicy === 'specialist_only' &&
1938
+ specialistId !== null &&
1939
+ vcsRound1ResponseText.trim() &&
1940
+ vcsRound2ResponseText.trim()
1941
+ ? {
1942
+ kind: 'specialist_session',
1943
+ specialistId,
1944
+ sessionSlug: PRIMING_VCS_SESSION_SLUG,
1945
+ round1: {
1946
+ tellaskBody: vcsRound1Body || formatVcsSessionRound1TellaskBody(language),
1947
+ responseText: vcsRound1ResponseText,
1948
+ },
1949
+ round2: {
1950
+ tellaskBody: vcsRound2Body ||
1951
+ formatVcsSessionRound2TellaskBody(language, vcsRound1ResponseText),
1952
+ responseText: vcsRound2ResponseText,
1953
+ },
1954
+ inventoryText: vcsInventoryText,
1955
+ }
1956
+ : {
1957
+ kind: 'runtime_inventory',
1958
+ round1NoteMarkdown: vcsRound1NoteMarkdown ||
1959
+ formatRuntimeVcsRoundNote(language, 1, vcsRound1ResponseText),
1960
+ round2NoteMarkdown: vcsRound2NoteMarkdown ||
1961
+ formatRuntimeVcsRoundNote(language, 2, vcsRound2ResponseText),
1962
+ inventoryText: vcsInventoryText,
1963
+ },
1964
+ fbr: {
1965
+ tellaskContent: fbrCallBody,
1966
+ selfTeaser,
1967
+ responderAgentId: dlg.agentId,
1968
+ effort: fbrEffort,
1969
+ responses: fbrResponsesForCache,
1970
+ },
1971
+ primingNote,
1972
+ };
1973
+ await dlg.withLock(async () => {
1974
+ dlg.setCoursePrefixMsgs(buildCoursePrefixMsgs(entry));
1975
+ });
1976
+ return entry;
1977
+ }
1978
+ catch (err) {
1979
+ if (isAgentPrimingInterruptedError(err)) {
1980
+ fatalRunState = {
1981
+ kind: 'interrupted',
1982
+ reason: { kind: err.reason },
1983
+ };
1984
+ log_1.log.debug('Agent Priming live run interrupted by stop request', undefined, {
1985
+ dialogId: dlg.id.valueOf(),
1986
+ reason: err.reason,
1987
+ });
1988
+ throw err;
1989
+ }
1990
+ const errText = err instanceof Error ? (err.stack ?? err.message) : String(err);
1991
+ const errTextTrimmed = errText.trim().slice(0, 4000);
1992
+ fatalRunState = {
1993
+ kind: 'interrupted',
1994
+ reason: { kind: 'system_stop', detail: `Agent Priming failed: ${errTextTrimmed}` },
1995
+ };
1996
+ log_1.log.warn('Agent Priming live run failed (fatal)', err, { dialogId: dlg.id.valueOf() });
1997
+ const msg = language === 'zh'
1998
+ ? [
1999
+ '错误:智能体启动(Agent Priming)失败;无法继续对话。',
2000
+ '',
2001
+ '根因(详细信息):',
2002
+ '```text',
2003
+ errTextTrimmed,
2004
+ '```',
2005
+ ].join('\n')
2006
+ : [
2007
+ 'Error: Agent Priming failed; cannot continue this dialog.',
2008
+ '',
2009
+ 'Root cause (details):',
2010
+ '```text',
2011
+ errTextTrimmed,
2012
+ '```',
2013
+ ].join('\n');
2014
+ try {
2015
+ await dlg.withLock(async () => {
2016
+ await dlg.notifyGeneratingStart();
2017
+ await emitSayingEventsAndPersist(dlg, msg);
2018
+ await dlg.notifyGeneratingFinish();
2019
+ });
2020
+ }
2021
+ catch (_emitErr) {
2022
+ // best-effort
2023
+ }
2024
+ throw err;
2025
+ }
2026
+ finally {
2027
+ dlg.disableDiligencePush = prevDisableDiligencePush;
2028
+ try {
2029
+ if (fatalRunState) {
2030
+ await (0, dialog_run_state_1.setDialogRunState)(dlg.id, fatalRunState);
2031
+ }
2032
+ else {
2033
+ let nextIdle = { kind: 'idle_waiting_user' };
2034
+ try {
2035
+ nextIdle = await (0, dialog_run_state_1.computeIdleRunState)(dlg);
2036
+ }
2037
+ catch (err) {
2038
+ log_1.log.warn('Failed to compute idle runState after Agent Priming live run; falling back', err, {
2039
+ dialogId: dlg.id.valueOf(),
2040
+ });
2041
+ }
2042
+ await (0, dialog_run_state_1.setDialogRunState)(dlg.id, nextIdle);
2043
+ }
2044
+ }
2045
+ finally {
2046
+ if (ownsActiveRun) {
2047
+ (0, dialog_run_state_1.clearActiveRun)(dlg.id);
2048
+ }
2049
+ }
2050
+ }
2051
+ }