crewly 1.20.365 → 1.20.366

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 (136) hide show
  1. package/config/skills/agent/core/attach-file/SKILL.md +7 -0
  2. package/config/skills/agent/core/attach-file/execute.sh +8 -3
  3. package/config/skills/agent/core/complete-task/SKILL.md +4 -2
  4. package/config/skills/agent/core/complete-task/execute.sh +9 -1
  5. package/config/skills/agent/core/complete-task/explicit-id.test.sh +13 -2
  6. package/config/skills/agent/core/create-task/SKILL.md +2 -0
  7. package/config/skills/agent/core/create-task/execute.sh +27 -1
  8. package/config/skills/agent/core/create-task/execute.test.sh +67 -0
  9. package/config/skills/agent/core/handoff-task/execute.sh +12 -5
  10. package/config/skills/agent/core/handoff-task/explicit-id.test.sh +70 -0
  11. package/config/skills/agent/core/reply-channel/SKILL.md +12 -5
  12. package/config/skills/agent/core/reply-channel/execute.sh +17 -2
  13. package/config/skills/agent/core/reply-channel/execute.test.sh +15 -2
  14. package/config/skills/agent/core/slack-post/SKILL.md +3 -3
  15. package/config/skills/orchestrator/delegate-task/SKILL.md +1 -1
  16. package/config/skills/orchestrator/reply-slack/execute.sh +6 -2
  17. package/config/skills/orchestrator/send-pdf-to-slack/SKILL.md +2 -1
  18. package/config/skills/orchestrator/send-pdf-to-slack/execute.sh +10 -2
  19. package/config/skills/registry.json +6 -6
  20. package/config/skills/team-leader/delegate-task/SKILL.md +1 -1
  21. package/config/skills/team-leader/delegate-task/execute.sh +6 -0
  22. package/dist/backend/backend/src/constants.d.ts +26 -0
  23. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  24. package/dist/backend/backend/src/constants.js +26 -0
  25. package/dist/backend/backend/src/constants.js.map +1 -1
  26. package/dist/backend/backend/src/controllers/agent-hooks/agent-hooks.controller.d.ts.map +1 -1
  27. package/dist/backend/backend/src/controllers/agent-hooks/agent-hooks.controller.js +7 -3
  28. package/dist/backend/backend/src/controllers/agent-hooks/agent-hooks.controller.js.map +1 -1
  29. package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts +12 -0
  30. package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts.map +1 -1
  31. package/dist/backend/backend/src/controllers/chat/chat.controller.js +56 -7
  32. package/dist/backend/backend/src/controllers/chat/chat.controller.js.map +1 -1
  33. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.d.ts +9 -0
  34. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.d.ts.map +1 -1
  35. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.js +111 -11
  36. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.js.map +1 -1
  37. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.d.ts.map +1 -1
  38. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js +52 -4
  39. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js.map +1 -1
  40. package/dist/backend/backend/src/controllers/slack/slack.controller.d.ts.map +1 -1
  41. package/dist/backend/backend/src/controllers/slack/slack.controller.js +58 -4
  42. package/dist/backend/backend/src/controllers/slack/slack.controller.js.map +1 -1
  43. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.d.ts.map +1 -1
  44. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js +36 -2
  45. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js.map +1 -1
  46. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts +16 -10
  47. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
  48. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +19 -11
  49. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
  50. package/dist/backend/backend/src/services/messaging/agent-message-envelope.d.ts +8 -0
  51. package/dist/backend/backend/src/services/messaging/agent-message-envelope.d.ts.map +1 -1
  52. package/dist/backend/backend/src/services/messaging/agent-message-envelope.js +10 -1
  53. package/dist/backend/backend/src/services/messaging/agent-message-envelope.js.map +1 -1
  54. package/dist/backend/backend/src/services/messaging/owner-hook-message.d.ts +62 -20
  55. package/dist/backend/backend/src/services/messaging/owner-hook-message.d.ts.map +1 -1
  56. package/dist/backend/backend/src/services/messaging/owner-hook-message.js +178 -39
  57. package/dist/backend/backend/src/services/messaging/owner-hook-message.js.map +1 -1
  58. package/dist/backend/backend/src/services/orc/agent-mention-post-guard.d.ts +8 -5
  59. package/dist/backend/backend/src/services/orc/agent-mention-post-guard.d.ts.map +1 -1
  60. package/dist/backend/backend/src/services/orc/agent-mention-post-guard.js +13 -10
  61. package/dist/backend/backend/src/services/orc/agent-mention-post-guard.js.map +1 -1
  62. package/dist/backend/backend/src/services/orc/message-route.d.ts +129 -0
  63. package/dist/backend/backend/src/services/orc/message-route.d.ts.map +1 -0
  64. package/dist/backend/backend/src/services/orc/message-route.js +197 -0
  65. package/dist/backend/backend/src/services/orc/message-route.js.map +1 -0
  66. package/dist/backend/backend/src/services/orc/reply-destination-resolver.d.ts +49 -6
  67. package/dist/backend/backend/src/services/orc/reply-destination-resolver.d.ts.map +1 -1
  68. package/dist/backend/backend/src/services/orc/reply-destination-resolver.js +284 -69
  69. package/dist/backend/backend/src/services/orc/reply-destination-resolver.js.map +1 -1
  70. package/dist/backend/backend/src/services/orc/reply-destination.wiring.d.ts +64 -8
  71. package/dist/backend/backend/src/services/orc/reply-destination.wiring.d.ts.map +1 -1
  72. package/dist/backend/backend/src/services/orc/reply-destination.wiring.js +215 -100
  73. package/dist/backend/backend/src/services/orc/reply-destination.wiring.js.map +1 -1
  74. package/dist/backend/backend/src/services/orc/triggered-by.d.ts.map +1 -1
  75. package/dist/backend/backend/src/services/orc/triggered-by.js +9 -0
  76. package/dist/backend/backend/src/services/orc/triggered-by.js.map +1 -1
  77. package/dist/backend/backend/src/services/orc/work-item-destination.d.ts +2 -1
  78. package/dist/backend/backend/src/services/orc/work-item-destination.d.ts.map +1 -1
  79. package/dist/backend/backend/src/services/orc/work-item-destination.js +1 -1
  80. package/dist/backend/backend/src/services/orc/work-item-destination.js.map +1 -1
  81. package/dist/backend/backend/src/services/orc/work-item-destination.wiring.d.ts +10 -1
  82. package/dist/backend/backend/src/services/orc/work-item-destination.wiring.d.ts.map +1 -1
  83. package/dist/backend/backend/src/services/orc/work-item-destination.wiring.js +25 -4
  84. package/dist/backend/backend/src/services/orc/work-item-destination.wiring.js.map +1 -1
  85. package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.d.ts +1 -0
  86. package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.d.ts.map +1 -1
  87. package/dist/backend/backend/src/services/slack/slack-agent-post.service.d.ts +1 -1
  88. package/dist/backend/backend/src/services/slack/slack-agent-post.service.d.ts.map +1 -1
  89. package/dist/backend/backend/src/services/slack/slack-agent-post.service.js +20 -13
  90. package/dist/backend/backend/src/services/slack/slack-agent-post.service.js.map +1 -1
  91. package/dist/backend/backend/src/services/slack/slack.service.d.ts +20 -1
  92. package/dist/backend/backend/src/services/slack/slack.service.d.ts.map +1 -1
  93. package/dist/backend/backend/src/services/slack/slack.service.js +58 -3
  94. package/dist/backend/backend/src/services/slack/slack.service.js.map +1 -1
  95. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +31 -0
  96. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  97. package/dist/backend/backend/src/services/task-pool/task-pool.service.js +62 -5
  98. package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  99. package/dist/backend/backend/src/services/trace/turn-trigger.d.ts +34 -1
  100. package/dist/backend/backend/src/services/trace/turn-trigger.d.ts.map +1 -1
  101. package/dist/backend/backend/src/services/trace/turn-trigger.js +74 -9
  102. package/dist/backend/backend/src/services/trace/turn-trigger.js.map +1 -1
  103. package/dist/backend/build-info.json +2 -2
  104. package/dist/cli/backend/src/constants.d.ts +26 -0
  105. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  106. package/dist/cli/backend/src/constants.js +26 -0
  107. package/dist/cli/backend/src/constants.js.map +1 -1
  108. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts +16 -10
  109. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
  110. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +19 -11
  111. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
  112. package/dist/cli/backend/src/services/messaging/agent-message-envelope.d.ts +8 -0
  113. package/dist/cli/backend/src/services/messaging/agent-message-envelope.d.ts.map +1 -1
  114. package/dist/cli/backend/src/services/messaging/agent-message-envelope.js +10 -1
  115. package/dist/cli/backend/src/services/messaging/agent-message-envelope.js.map +1 -1
  116. package/dist/cli/backend/src/services/orc/message-route.d.ts +129 -0
  117. package/dist/cli/backend/src/services/orc/message-route.d.ts.map +1 -0
  118. package/dist/cli/backend/src/services/orc/message-route.js +197 -0
  119. package/dist/cli/backend/src/services/orc/message-route.js.map +1 -0
  120. package/dist/cli/backend/src/services/orc/work-item-destination.d.ts +2 -1
  121. package/dist/cli/backend/src/services/orc/work-item-destination.d.ts.map +1 -1
  122. package/dist/cli/backend/src/services/orc/work-item-destination.js +1 -1
  123. package/dist/cli/backend/src/services/orc/work-item-destination.js.map +1 -1
  124. package/dist/cli/backend/src/services/slack/slack.service.d.ts +20 -1
  125. package/dist/cli/backend/src/services/slack/slack.service.d.ts.map +1 -1
  126. package/dist/cli/backend/src/services/slack/slack.service.js +58 -3
  127. package/dist/cli/backend/src/services/slack/slack.service.js.map +1 -1
  128. package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts +31 -0
  129. package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  130. package/dist/cli/backend/src/services/task-pool/task-pool.service.js +62 -5
  131. package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  132. package/dist/cli/backend/src/services/trace/turn-trigger.d.ts +34 -1
  133. package/dist/cli/backend/src/services/trace/turn-trigger.d.ts.map +1 -1
  134. package/dist/cli/backend/src/services/trace/turn-trigger.js +74 -9
  135. package/dist/cli/backend/src/services/trace/turn-trigger.js.map +1 -1
  136. package/package.json +1 -1
@@ -19,10 +19,16 @@
19
19
  * and the harness reads the sender back from it ({@link parseAgentMessageSender})
20
20
  * to route a bare `reply` to that agent.
21
21
  *
22
+ * The header also carries the sender's route — the owner message or work
23
+ * item the sender is answering (message-route.ts) — so the destination of
24
+ * the original request travels across every agent hop
25
+ * (message-routing audit 2026-10-18).
26
+ *
22
27
  * Pure helpers; the member lookup is injected.
23
28
  *
24
29
  * @module services/messaging/agent-message-envelope
25
30
  */
31
+ import { type MessageRoute } from '../orc/message-route.js';
26
32
  /** Opening of the header. */
27
33
  export declare const AGENT_MESSAGE_HEADER_PREFIX = "[MESSAGE from ";
28
34
  /** Who sent a message, as the recipient should read it. */
@@ -33,6 +39,8 @@ export interface AgentMessageSender {
33
39
  name?: string;
34
40
  /** Team display name, when known */
35
41
  team?: string;
42
+ /** What the sender is answering (owner message / work item), carried to the recipient */
43
+ route?: MessageRoute;
36
44
  }
37
45
  /**
38
46
  * Whether a text already opens with a harness envelope.
@@ -1 +1 @@
1
- {"version":3,"file":"agent-message-envelope.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/messaging/agent-message-envelope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,6BAA6B;AAC7B,eAAO,MAAM,2BAA2B,mBAAmB,CAAC;AAc5D,2DAA2D;AAC3D,MAAM,WAAW,kBAAkB;IACjC,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAQ3E;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAGjF;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGxE;AAED,2CAA2C;AAC3C,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IAAE,MAAM,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAAC,IAAI,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAAG,IAAI,CAAC,CAAC;AAEvH;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CASnH"}
1
+ {"version":3,"file":"agent-message-envelope.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/messaging/agent-message-envelope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAmC,KAAK,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE7F,6BAA6B;AAC7B,eAAO,MAAM,2BAA2B,mBAAmB,CAAC;AAc5D,2DAA2D;AAC3D,MAAM,WAAW,kBAAkB;IACjC,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yFAAyF;IACzF,KAAK,CAAC,EAAE,YAAY,CAAC;CACtB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAW3E;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAGjF;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGxE;AAED,2CAA2C;AAC3C,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IAAE,MAAM,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAAC,IAAI,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAAG,IAAI,CAAC,CAAC;AAEvH;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CASnH"}
@@ -19,10 +19,16 @@
19
19
  * and the harness reads the sender back from it ({@link parseAgentMessageSender})
20
20
  * to route a bare `reply` to that agent.
21
21
  *
22
+ * The header also carries the sender's route — the owner message or work
23
+ * item the sender is answering (message-route.ts) — so the destination of
24
+ * the original request travels across every agent hop
25
+ * (message-routing audit 2026-10-18).
26
+ *
22
27
  * Pure helpers; the member lookup is injected.
23
28
  *
24
29
  * @module services/messaging/agent-message-envelope
25
30
  */
31
+ import { describeRoute, formatRouteToken } from '../orc/message-route.js';
26
32
  /** Opening of the header. */
27
33
  export const AGENT_MESSAGE_HEADER_PREFIX = '[MESSAGE from ';
28
34
  /**
@@ -65,8 +71,11 @@ export function formatAgentMessageHeader(sender) {
65
71
  const name = sender.name?.trim() || sender.session;
66
72
  const team = sender.team?.trim();
67
73
  const who = team && team !== name ? `${name} (${team})` : name;
74
+ const route = sender.route
75
+ ? ` It concerns ${describeRoute(sender.route)} ${formatRouteToken(sender.route)}; ${name} answers the owner on it.`
76
+ : '';
68
77
  return (`${AGENT_MESSAGE_HEADER_PREFIX}${who} — a colleague, not the owner. ` +
69
- `Answer with send-message --to ${sender.session}; do not post it in an owner thread.]`);
78
+ `Answer with send-message --to ${sender.session}; do not post it in an owner thread.${route}]`);
70
79
  }
71
80
  /**
72
81
  * The text with the sender's header in front, unless it already carries a
@@ -1 +1 @@
1
- {"version":3,"file":"agent-message-envelope.js","sourceRoot":"","sources":["../../../../../../backend/src/services/messaging/agent-message-envelope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,6BAA6B;AAC7B,MAAM,CAAC,MAAM,2BAA2B,GAAG,gBAAgB,CAAC;AAE5D;;;;;GAKG;AACH,MAAM,gBAAgB,GACpB,kIAAkI,CAAC;AAErI,sDAAsD;AACtD,MAAM,aAAa,GAAG,iEAAiE,CAAC;AAYxF;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,OAAO,gBAAgB,CAAC,IAAI,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AACrE,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,wBAAwB,CAAC,MAA0B;IACjE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,MAAM,CAAC,OAAO,CAAC;IACnD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IACjC,MAAM,GAAG,GAAG,IAAI,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/D,OAAO,CACL,GAAG,2BAA2B,GAAG,GAAG,iCAAiC;QACrE,iCAAiC,MAAM,CAAC,OAAO,uCAAuC,CACvF,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,MAA0B;IACvE,IAAI,kBAAkB,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1C,OAAO,GAAG,wBAAwB,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;AACxD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAY;IAClD,MAAM,CAAC,GAAG,aAAa,CAAC,IAAI,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACnE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC9B,CAAC;AAKD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,OAAe,EAAE,MAAoB;IAC7E,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACtD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,OAAO;QACL,OAAO;QACP,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1D,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACvD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"agent-message-envelope.js","sourceRoot":"","sources":["../../../../../../backend/src/services/messaging/agent-message-envelope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAqB,MAAM,yBAAyB,CAAC;AAE7F,6BAA6B;AAC7B,MAAM,CAAC,MAAM,2BAA2B,GAAG,gBAAgB,CAAC;AAE5D;;;;;GAKG;AACH,MAAM,gBAAgB,GACpB,kIAAkI,CAAC;AAErI,sDAAsD;AACtD,MAAM,aAAa,GAAG,iEAAiE,CAAC;AAcxF;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,OAAO,gBAAgB,CAAC,IAAI,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AACrE,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,wBAAwB,CAAC,MAA0B;IACjE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,MAAM,CAAC,OAAO,CAAC;IACnD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IACjC,MAAM,GAAG,GAAG,IAAI,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/D,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK;QACxB,CAAC,CAAC,gBAAgB,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,gBAAgB,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI,2BAA2B;QACnH,CAAC,CAAC,EAAE,CAAC;IACP,OAAO,CACL,GAAG,2BAA2B,GAAG,GAAG,iCAAiC;QACrE,iCAAiC,MAAM,CAAC,OAAO,uCAAuC,KAAK,GAAG,CAC/F,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,MAA0B;IACvE,IAAI,kBAAkB,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1C,OAAO,GAAG,wBAAwB,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;AACxD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAY;IAClD,MAAM,CAAC,GAAG,aAAa,CAAC,IAAI,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACnE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC9B,CAAC;AAKD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,OAAe,EAAE,MAAoB;IAC7E,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACtD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,OAAO;QACL,OAAO;QACP,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1D,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACvD,CAAC;AACJ,CAAC"}
@@ -16,6 +16,16 @@
16
16
  * @module services/messaging/owner-hook-message
17
17
  */
18
18
  import { SubAgentMessageQueue, type SurfacedOwnerMessage } from './sub-agent-message-queue.service.js';
19
+ /**
20
+ * Writes an owner message too long for the note to a file, returning its
21
+ * path (null when it could not be written).
22
+ */
23
+ export type OwnerMessageOverflowWriter = (fullText: string) => string | null;
24
+ /** Options of {@link buildOwnerHookNote}. */
25
+ export interface OwnerHookNoteOptions {
26
+ /** Where an owner message too long for the note is written in full */
27
+ overflow?: OwnerMessageOverflowWriter;
28
+ }
19
29
  /**
20
30
  * The note for one surfaced owner message (English harness text). The queued
21
31
  * text already carries where the message came from and how to reply, as the
@@ -23,31 +33,51 @@ import { SubAgentMessageQueue, type SurfacedOwnerMessage } from './sub-agent-mes
23
33
  *
24
34
  * @param message - The surfaced message
25
35
  * @param maxChars - Ceiling on the note's length
36
+ * @param options - Overflow writer (default: a file under CREWLY_HOME)
26
37
  * @returns The note
27
38
  */
28
- export declare function buildOwnerHookNote(message: SurfacedOwnerMessage, maxChars?: number): string;
39
+ export declare function buildOwnerHookNote(message: SurfacedOwnerMessage, maxChars?: number, options?: OwnerHookNoteOptions): string;
29
40
  /**
30
- * Fit a queued message into `room` characters, keeping what the agent needs
31
- * to act on: its first block (`[CHAT:…]` header — where it came from) and
32
- * its end (the newest thread lines, the message itself, how to reply). The
33
- * older middle is cut and the cut is said.
34
- *
35
- * The end used to be cut instead. A 13.5k-char thread prompt lost its newest
36
- * posts and the owner's ping itself, so the agent saw only the thread's old
37
- * topics and answered something else (2026-10-08, #content-team).
41
+ * Fit a queued owner message into `room` characters. The owner's own text
42
+ * is never cut (message-routing audit 2026-10-18, R0): what gives way is,
43
+ * in order, the reply instructions after the `---` line (down to their
44
+ * start, which holds the reply command) and the older thread context (its
45
+ * newest lines are kept). When the owner's text alone is still too long, it
46
+ * is written in full to a file and the note quotes its start and points to
47
+ * the file.
38
48
  *
39
- * The reply instructions after the `---` line can alone be longer than the
40
- * room. Keeping only the end then kept those instructions and cut the
41
- * message, which sits just before them: the agent told the owner their
42
- * message arrived empty (2026-10-18, #awesome-videos). So the instructions
43
- * get at most {@link REPLY_TAIL_SHARE} of the room (their start, which holds
44
- * the reply command), and the message part is fitted into the rest.
49
+ * History: the end used to be cut, and a 13.5k-char thread prompt lost its
50
+ * newest posts and the owner's ping (2026-10-08, #content-team). Then the
51
+ * middle was cut, and with long reply instructions the cut took the owner's
52
+ * question just before them: the agent said the message arrived empty
53
+ * (2026-10-18, #awesome-videos, I1–I5).
45
54
  *
46
55
  * @param data - The queued text
47
56
  * @param room - Characters available
48
- * @returns The text, whole or cut in the middle
57
+ * @param overflow - Writes the full text when the owner's text cannot fit
58
+ * @returns The text, whole or fitted
59
+ */
60
+ export declare function fitKeepingNewest(data: string, room: number, overflow?: OwnerMessageOverflowWriter): string;
61
+ /**
62
+ * Split a queued text into its header (where it came from), the thread
63
+ * context, and the owner's own message (after the last context-closing
64
+ * line; the whole text after the header when there is none).
65
+ *
66
+ * @param body - The queued text without its reply instructions
67
+ * @returns The three parts (concatenated, they are `body`)
49
68
  */
50
- export declare function fitKeepingNewest(data: string, room: number): string;
69
+ export declare function splitOwnerMessage(body: string): {
70
+ lead: string;
71
+ context: string;
72
+ message: string;
73
+ };
74
+ /**
75
+ * The default overflow writer: `<CREWLY_HOME>/runtime/owner-messages/<label>-<ts>.md`.
76
+ *
77
+ * @param label - File name prefix (the agent's session)
78
+ * @returns The writer
79
+ */
80
+ export declare function defaultOverflowWriter(label: string): OwnerMessageOverflowWriter;
51
81
  /**
52
82
  * The owner-message note for an agent's PostToolUse hook, or null. One
53
83
  * message at most per call. Off when {@link OWNER_HOOK_MESSAGE_CONSTANTS.KILL_SWITCH_ENV}
@@ -56,16 +86,28 @@ export declare function fitKeepingNewest(data: string, room: number): string;
56
86
  * @param sessionName - The agent
57
87
  * @param env - Environment (kill switch)
58
88
  * @param queue - The message queue
89
+ * @param maxChars - Room for the note (what the other notes of this hook call leave)
90
+ * @param overflow - Where an owner message too long for the note is written in full
59
91
  * @returns The note, or null
60
92
  */
61
- export declare function ownerHookNoteFor(sessionName: string, env?: NodeJS.ProcessEnv, queue?: SubAgentMessageQueue): string | null;
93
+ export declare function ownerHookNoteFor(sessionName: string, env?: NodeJS.ProcessEnv, queue?: SubAgentMessageQueue, maxChars?: number, overflow?: OwnerMessageOverflowWriter): string | null;
62
94
  /**
63
- * Join the notes for one hook response, owner message first, within the
64
- * size ceiling (a later note that does not fit is dropped, not cut).
95
+ * Join the notes for one hook response, in priority order, within the size
96
+ * ceiling. Nothing goes silently (message-routing audit 2026-10-18): a note
97
+ * that does not fit is dropped and the result says how many were, and a
98
+ * first note longer than the ceiling is cut with a marker. Owner notes are
99
+ * built to fit their room ({@link ownerHookNoteFor}'s `maxChars`), so they
100
+ * are never cut here.
65
101
  *
66
102
  * @param notes - Notes in priority order (nulls skipped)
67
103
  * @param maxChars - Ceiling
68
104
  * @returns The joined text, or null when there is none
69
105
  */
70
106
  export declare function joinHookNotes(notes: ReadonlyArray<string | null | undefined>, maxChars?: number): string | null;
107
+ /**
108
+ * Room {@link joinHookNotes} keeps after a note that is not the last, for
109
+ * the line naming notes left out. A note built to go first takes at most
110
+ * the ceiling less this.
111
+ */
112
+ export declare const HOOK_NOTE_JOIN_RESERVE: number;
71
113
  //# sourceMappingURL=owner-hook-message.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"owner-hook-message.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/messaging/owner-hook-message.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,oBAAoB,EAAE,KAAK,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAEvG;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,oBAAoB,EAAE,QAAQ,GAAE,MAAuD,GAAG,MAAM,CAgB3I;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAWnE;AA+BD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC/B,WAAW,EAAE,MAAM,EACnB,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,KAAK,GAAE,oBAAyD,GAC9D,MAAM,GAAG,IAAI,CAKf;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,QAAQ,GAAE,MAAuD,GAAG,MAAM,GAAG,IAAI,CAY/J"}
1
+ {"version":3,"file":"owner-hook-message.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/messaging/owner-hook-message.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,EAAE,oBAAoB,EAAE,KAAK,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAEvG;;;GAGG;AACH,MAAM,MAAM,0BAA0B,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;AAE7E,6CAA6C;AAC7C,MAAM,WAAW,oBAAoB;IACpC,sEAAsE;IACtE,QAAQ,CAAC,EAAE,0BAA0B,CAAC;CACtC;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,oBAAoB,EAC7B,QAAQ,GAAE,MAAuD,EACjE,OAAO,GAAE,oBAAyB,GAChC,MAAM,CAgBR;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,0BAA0B,GAAG,MAAM,CA+B1G;AAeD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAOlG;AA6CD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,0BAA0B,CAS/E;AAuBD;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAC/B,WAAW,EAAE,MAAM,EACnB,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,KAAK,GAAE,oBAAyD,EAChE,QAAQ,GAAE,MAAuD,EACjE,QAAQ,GAAE,0BAA+D,GACvE,MAAM,GAAG,IAAI,CAKf;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,QAAQ,GAAE,MAAuD,GAAG,MAAM,GAAG,IAAI,CAmB/J;AAOD;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,QAA0B,CAAC"}
@@ -15,7 +15,10 @@
15
15
  *
16
16
  * @module services/messaging/owner-hook-message
17
17
  */
18
+ import * as fs from 'fs';
19
+ import * as path from 'path';
18
20
  import { OWNER_HOOK_MESSAGE_CONSTANTS } from '../../constants.js';
21
+ import { getCrewlyHomePath } from '../core/crewly-home.utils.js';
19
22
  import { SubAgentMessageQueue } from './sub-agent-message-queue.service.js';
20
23
  /**
21
24
  * The note for one surfaced owner message (English harness text). The queued
@@ -24,9 +27,10 @@ import { SubAgentMessageQueue } from './sub-agent-message-queue.service.js';
24
27
  *
25
28
  * @param message - The surfaced message
26
29
  * @param maxChars - Ceiling on the note's length
30
+ * @param options - Overflow writer (default: a file under CREWLY_HOME)
27
31
  * @returns The note
28
32
  */
29
- export function buildOwnerHookNote(message, maxChars = OWNER_HOOK_MESSAGE_CONSTANTS.MAX_CONTEXT_CHARS) {
33
+ export function buildOwnerHookNote(message, maxChars = OWNER_HOOK_MESSAGE_CONSTANTS.MAX_CONTEXT_CHARS, options = {}) {
30
34
  const C = OWNER_HOOK_MESSAGE_CONSTANTS;
31
35
  // Drive mode (specs/2026-10-09-drive-mode-v3.md §4): the owner is listening
32
36
  // on the phone; a quick ack now beats a full answer later.
@@ -41,68 +45,168 @@ export function buildOwnerHookNote(message, maxChars = OWNER_HOOK_MESSAGE_CONSTA
41
45
  'Answer it now, in the conversation it came from, before your next step of the current work; then carry on with that work.';
42
46
  const sep = '\n\n';
43
47
  const room = maxChars - head.length - sep.length;
44
- return `${head}${sep}${fitKeepingNewest(message.data, room)}`;
48
+ return `${head}${sep}${fitKeepingNewest(message.data, room, options.overflow ?? defaultOverflowWriter('owner-message'))}`;
45
49
  }
46
50
  /**
47
- * Fit a queued message into `room` characters, keeping what the agent needs
48
- * to act on: its first block (`[CHAT:…]` header — where it came from) and
49
- * its end (the newest thread lines, the message itself, how to reply). The
50
- * older middle is cut and the cut is said.
51
+ * Fit a queued owner message into `room` characters. The owner's own text
52
+ * is never cut (message-routing audit 2026-10-18, R0): what gives way is,
53
+ * in order, the reply instructions after the `---` line (down to their
54
+ * start, which holds the reply command) and the older thread context (its
55
+ * newest lines are kept). When the owner's text alone is still too long, it
56
+ * is written in full to a file and the note quotes its start and points to
57
+ * the file.
51
58
  *
52
- * The end used to be cut instead. A 13.5k-char thread prompt lost its newest
53
- * posts and the owner's ping itself, so the agent saw only the thread's old
54
- * topics and answered something else (2026-10-08, #content-team).
55
- *
56
- * The reply instructions after the `---` line can alone be longer than the
57
- * room. Keeping only the end then kept those instructions and cut the
58
- * message, which sits just before them: the agent told the owner their
59
- * message arrived empty (2026-10-18, #awesome-videos). So the instructions
60
- * get at most {@link REPLY_TAIL_SHARE} of the room (their start, which holds
61
- * the reply command), and the message part is fitted into the rest.
59
+ * History: the end used to be cut, and a 13.5k-char thread prompt lost its
60
+ * newest posts and the owner's ping (2026-10-08, #content-team). Then the
61
+ * middle was cut, and with long reply instructions the cut took the owner's
62
+ * question just before them: the agent said the message arrived empty
63
+ * (2026-10-18, #awesome-videos, I1–I5).
62
64
  *
63
65
  * @param data - The queued text
64
66
  * @param room - Characters available
65
- * @returns The text, whole or cut in the middle
67
+ * @param overflow - Writes the full text when the owner's text cannot fit
68
+ * @returns The text, whole or fitted
66
69
  */
67
- export function fitKeepingNewest(data, room) {
70
+ export function fitKeepingNewest(data, room, overflow) {
68
71
  if (data.length <= room)
69
72
  return data;
70
73
  const split = data.lastIndexOf(REPLY_TAIL_SEPARATOR);
71
- if (split > 0) {
72
- const body = data.slice(0, split);
73
- let tail = data.slice(split);
74
- const tailRoom = Math.floor(room * REPLY_TAIL_SHARE);
75
- if (tail.length > tailRoom)
76
- tail = `${tail.slice(0, Math.max(0, tailRoom - TAIL_CUT_MARKER.length))}${TAIL_CUT_MARKER}`;
77
- return `${fitBody(body, room - tail.length)}${tail}`;
74
+ const body = split > 0 ? data.slice(0, split) : data;
75
+ const fullTail = split > 0 ? data.slice(split) : '';
76
+ const { lead, context, message } = splitOwnerMessage(body);
77
+ // 1. The reply instructions: at most their share of the room, and less
78
+ // when the owner's text needs it (never below their opening).
79
+ const minTail = Math.min(fullTail.length, MIN_TAIL_CHARS);
80
+ const fixed = lead.length + message.length;
81
+ const tailRoom = Math.max(minTail, Math.min(Math.floor(room * REPLY_TAIL_SHARE), room - fixed - CONTEXT_CUT_MARKER.length));
82
+ const tail = cutTail(fullTail, tailRoom);
83
+ // 2. The thread context: its newest lines, in whatever room is left.
84
+ const contextRoom = room - fixed - tail.length;
85
+ if (contextRoom >= 0)
86
+ return `${lead}${fitContext(context, contextRoom)}${message}${tail}`;
87
+ // 3. The owner's text alone does not fit: point to it in full.
88
+ const file = overflow ? safeWrite(overflow, data) : null;
89
+ if (file) {
90
+ const open = `\n[The owner's message is ${message.trim().length} characters, too long to show here. Its start:]\n`;
91
+ const close = `\n[… Read the whole message, with its thread, before you answer: ${file}]\n`;
92
+ // The pointer always fits; the preview and the reply command share the rest.
93
+ const spare = Math.max(0, room - lead.length - open.length - close.length);
94
+ const previewChars = Math.min(OWNER_HOOK_MESSAGE_CONSTANTS.OVERFLOW_PREVIEW_CHARS, Math.max(0, spare - Math.min(fullTail.length, MIN_TAIL_CHARS)));
95
+ const pointer = `${open}${message.trim().slice(0, previewChars)}${close}`;
96
+ return `${lead}${pointer}${cutTail(fullTail, Math.max(0, room - lead.length - pointer.length))}`;
78
97
  }
98
+ // No file: the old middle cut, and it says the owner's text was cut.
79
99
  return fitBody(data, room);
80
100
  }
81
101
  /** Line that opens the reply instructions in a queued chat message */
82
102
  const REPLY_TAIL_SEPARATOR = '\n---\n';
83
103
  /** Most of the room the reply instructions may take when the message is cut */
84
104
  const REPLY_TAIL_SHARE = 0.35;
105
+ /** The opening of the reply instructions (the reply command) is kept at least this long */
106
+ const MIN_TAIL_CHARS = 400;
85
107
  /** Said where the reply instructions were cut */
86
108
  const TAIL_CUT_MARKER = '\n… (rest of the reply instructions cut to fit)';
109
+ /** Said where the older thread context was cut */
110
+ const CONTEXT_CUT_MARKER = '\n… (older thread lines cut here to fit; the newest ones and the owner\'s message follow in full)\n';
111
+ /** Lines that close the thread context; the owner's message follows them */
112
+ const CONTEXT_END_RE = /\n\[end of (?:Slack (?:thread|channel context)|context-only messages)[^\n]*\]/g;
113
+ /**
114
+ * Split a queued text into its header (where it came from), the thread
115
+ * context, and the owner's own message (after the last context-closing
116
+ * line; the whole text after the header when there is none).
117
+ *
118
+ * @param body - The queued text without its reply instructions
119
+ * @returns The three parts (concatenated, they are `body`)
120
+ */
121
+ export function splitOwnerMessage(body) {
122
+ let contextEnd = -1;
123
+ for (const m of body.matchAll(CONTEXT_END_RE))
124
+ contextEnd = (m.index ?? 0) + m[0].length;
125
+ const firstBreak = body.indexOf('\n\n');
126
+ const leadEnd = firstBreak > 0 && (contextEnd < 0 || firstBreak < contextEnd) ? firstBreak : 0;
127
+ if (contextEnd < 0)
128
+ return { lead: body.slice(0, leadEnd), context: '', message: body.slice(leadEnd) };
129
+ return { lead: body.slice(0, leadEnd), context: body.slice(leadEnd, contextEnd), message: body.slice(contextEnd) };
130
+ }
131
+ /**
132
+ * The reply instructions within `room`: whole, or their start and a marker.
133
+ *
134
+ * @param tail - Instructions (from the `---` line)
135
+ * @param room - Characters available
136
+ * @returns The fitted instructions
137
+ */
138
+ function cutTail(tail, room) {
139
+ if (tail.length <= room)
140
+ return tail;
141
+ return `${tail.slice(0, Math.max(0, room - TAIL_CUT_MARKER.length))}${TAIL_CUT_MARKER}`.slice(0, Math.max(0, room));
142
+ }
143
+ /**
144
+ * The thread context within `room`: whole, or its newest lines after a marker.
145
+ *
146
+ * @param context - Thread context
147
+ * @param room - Characters available
148
+ * @returns The fitted context
149
+ */
150
+ function fitContext(context, room) {
151
+ if (context.length <= room)
152
+ return context;
153
+ if (room <= CONTEXT_CUT_MARKER.length)
154
+ return '';
155
+ let start = context.length - (room - CONTEXT_CUT_MARKER.length);
156
+ const nl = context.indexOf('\n', start);
157
+ if (nl >= 0 && nl - start < 200 && nl + 1 < context.length)
158
+ start = nl + 1;
159
+ return `${CONTEXT_CUT_MARKER}${context.slice(start)}`;
160
+ }
161
+ /**
162
+ * Run an overflow writer, never throwing.
163
+ *
164
+ * @param write - The writer
165
+ * @param text - Full text
166
+ * @returns Its path, or null
167
+ */
168
+ function safeWrite(write, text) {
169
+ try {
170
+ return write(text);
171
+ }
172
+ catch {
173
+ return null;
174
+ }
175
+ }
87
176
  /**
88
- * Fit text into `room` characters by cutting its older middle, keeping the
89
- * first block and the end.
177
+ * The default overflow writer: `<CREWLY_HOME>/runtime/owner-messages/<label>-<ts>.md`.
178
+ *
179
+ * @param label - File name prefix (the agent's session)
180
+ * @returns The writer
181
+ */
182
+ export function defaultOverflowWriter(label) {
183
+ return (fullText) => {
184
+ const dir = path.join(getCrewlyHomePath(), OWNER_HOOK_MESSAGE_CONSTANTS.OVERFLOW_DIR);
185
+ fs.mkdirSync(dir, { recursive: true });
186
+ const safe = label.replace(/[^A-Za-z0-9_-]/g, '_').slice(0, 80) || 'owner-message';
187
+ const file = path.join(dir, `${safe}-${Date.now()}.md`);
188
+ fs.writeFileSync(file, fullText, 'utf8');
189
+ return file;
190
+ };
191
+ }
192
+ /**
193
+ * Last resort when the full text cannot be written: cut the older middle,
194
+ * keeping the first block and the end, and say the owner's text was cut.
90
195
  *
91
196
  * @param data - The text
92
197
  * @param room - Characters available
93
- * @returns The text, whole or cut in the middle
198
+ * @returns The text, cut in the middle
94
199
  */
95
200
  function fitBody(data, room) {
96
201
  if (data.length <= room)
97
202
  return data;
98
- const marker = '\n… (older part cut here to fit; the newest lines and the message itself follow; read the full thread in its conversation before you answer)\n';
203
+ const marker = '\n… (cut here to fit — the owner\'s message may be incomplete; read it in full in its conversation before you answer)\n';
99
204
  if (room <= marker.length + 20)
100
205
  return data.slice(data.length - Math.max(0, room));
101
206
  const firstBreak = data.indexOf('\n\n');
102
207
  const lead = firstBreak > 0 && firstBreak <= Math.floor(room / 4) ? data.slice(0, firstBreak) : '';
103
208
  const keep = room - lead.length - marker.length;
104
209
  let start = data.length - keep;
105
- // Start the kept end on a whole line when one begins soon.
106
210
  const nl = data.indexOf('\n', start);
107
211
  if (nl >= 0 && nl - start < 200 && nl + 1 < data.length)
108
212
  start = nl + 1;
@@ -116,36 +220,71 @@ function fitBody(data, room) {
116
220
  * @param sessionName - The agent
117
221
  * @param env - Environment (kill switch)
118
222
  * @param queue - The message queue
223
+ * @param maxChars - Room for the note (what the other notes of this hook call leave)
224
+ * @param overflow - Where an owner message too long for the note is written in full
119
225
  * @returns The note, or null
120
226
  */
121
- export function ownerHookNoteFor(sessionName, env = process.env, queue = SubAgentMessageQueue.getInstance()) {
227
+ export function ownerHookNoteFor(sessionName, env = process.env, queue = SubAgentMessageQueue.getInstance(), maxChars = OWNER_HOOK_MESSAGE_CONSTANTS.MAX_CONTEXT_CHARS, overflow = defaultOverflowWriter(sessionName)) {
122
228
  const C = OWNER_HOOK_MESSAGE_CONSTANTS;
123
229
  if (env[C.KILL_SWITCH_ENV] === C.KILL_SWITCH_OFF_VALUE)
124
230
  return null;
125
231
  const message = queue.takeOwnerMessageForHook(sessionName);
126
- return message ? buildOwnerHookNote(message) : null;
232
+ return message ? buildOwnerHookNote(message, maxChars, { overflow }) : null;
127
233
  }
128
234
  /**
129
- * Join the notes for one hook response, owner message first, within the
130
- * size ceiling (a later note that does not fit is dropped, not cut).
235
+ * Join the notes for one hook response, in priority order, within the size
236
+ * ceiling. Nothing goes silently (message-routing audit 2026-10-18): a note
237
+ * that does not fit is dropped and the result says how many were, and a
238
+ * first note longer than the ceiling is cut with a marker. Owner notes are
239
+ * built to fit their room ({@link ownerHookNoteFor}'s `maxChars`), so they
240
+ * are never cut here.
131
241
  *
132
242
  * @param notes - Notes in priority order (nulls skipped)
133
243
  * @param maxChars - Ceiling
134
244
  * @returns The joined text, or null when there is none
135
245
  */
136
246
  export function joinHookNotes(notes, maxChars = OWNER_HOOK_MESSAGE_CONSTANTS.MAX_CONTEXT_CHARS) {
247
+ const present = notes.filter((n) => !!n);
248
+ const reserve = HOOK_NOTE_JOIN_RESERVE;
137
249
  let out = '';
138
- for (const note of notes) {
139
- if (!note)
140
- continue;
250
+ const dropped = [];
251
+ for (const [i, note] of present.entries()) {
252
+ const last = i === present.length - 1;
253
+ // Keep room for the "dropped" line unless nothing can follow.
254
+ const limit = last && dropped.length === 0 ? maxChars : maxChars - reserve;
141
255
  const next = out ? `${out}\n\n${note}` : note;
142
- if (next.length > maxChars) {
256
+ if (next.length > limit) {
143
257
  if (!out)
144
- out = note.slice(0, maxChars);
258
+ out = `${note.slice(0, Math.max(0, limit - NOTE_CUT_MARKER.length))}${NOTE_CUT_MARKER}`;
259
+ else
260
+ dropped.push(note);
145
261
  continue;
146
262
  }
147
263
  out = next;
148
264
  }
265
+ if (dropped.length > 0)
266
+ out = `${out}\n\n${droppedNotice(dropped)}`;
149
267
  return out || null;
150
268
  }
269
+ /** Said at the end of a cut note */
270
+ const NOTE_CUT_MARKER = '\n… (note cut to fit)';
271
+ /** Room kept for the line that names the notes left out */
272
+ const DROPPED_NOTICE_ROOM = 200;
273
+ /**
274
+ * Room {@link joinHookNotes} keeps after a note that is not the last, for
275
+ * the line naming notes left out. A note built to go first takes at most
276
+ * the ceiling less this.
277
+ */
278
+ export const HOOK_NOTE_JOIN_RESERVE = DROPPED_NOTICE_ROOM + 2;
279
+ /**
280
+ * The line that says which notes were left out (their openings).
281
+ *
282
+ * @param dropped - Notes left out
283
+ * @returns The line, at most {@link DROPPED_NOTICE_ROOM} characters
284
+ */
285
+ function droppedNotice(dropped) {
286
+ const n = dropped.length;
287
+ const openings = dropped.map((d) => d.replace(/\s+/g, ' ').trim().slice(0, 60)).join(' | ');
288
+ return `[Left out to fit: ${n} more Crewly note${n === 1 ? '' : 's'} — ${openings}]`.slice(0, DROPPED_NOTICE_ROOM);
289
+ }
151
290
  //# sourceMappingURL=owner-hook-message.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"owner-hook-message.js","sourceRoot":"","sources":["../../../../../../backend/src/services/messaging/owner-hook-message.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"owner-hook-message.js","sourceRoot":"","sources":["../../../../../../backend/src/services/messaging/owner-hook-message.ts"],"names":[],"mappings":"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"}
@@ -8,13 +8,16 @@
8
8
  * a cost/timing report about another project, in the middle of the owner's
9
9
  * conversation.
10
10
  *
11
- * Conservative by construction — the post is refused only when ALL hold:
12
- * - the poster's latest input is another agent's message (its turn was not
13
- * prompted by this conversation);
11
+ * R6 of the message-routing audit (2026-10-18): agents never converse
12
+ * inside an owner thread, whatever prompted the post. The post is taken out
13
+ * of the thread (and delivered privately to the agents it addresses) when
14
+ * BOTH hold:
14
15
  * - the owner wrote to the poster in this conversation recently (it is an
15
16
  * owner thread, not an agents' room);
16
17
  * - the text @-mentions someone, and every @-mention is a known agent (an
17
18
  * unknown name or the owner keeps the post).
19
+ * Only the final consolidated answer, written to the owner, goes in the
20
+ * owner's thread.
18
21
  *
19
22
  * Pure decision; the lookups are injected.
20
23
  *
@@ -36,8 +39,8 @@ export interface AgentMentionPostInput {
36
39
  }
37
40
  /** A refused post. */
38
41
  export interface MisdirectedAgentMention {
39
- /** The agent whose message the poster is answering */
40
- sender: string;
42
+ /** The agent whose message the poster is answering, when its latest input is one */
43
+ sender?: string;
41
44
  /** Agent sessions the post @-mentions */
42
45
  mentioned: string[];
43
46
  /** What the poster is told */
@@ -1 +1 @@
1
- {"version":3,"file":"agent-mention-post-guard.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/orc/agent-mention-post-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAKnE,gDAAgD;AAChD,MAAM,WAAW,qBAAqB;IACpC,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,gCAAgC;IAChC,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B,0EAA0E;IAC1E,cAAc,EAAE,OAAO,CAAC;IACxB,mFAAmF;IACnF,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CAC9C;AAED,sBAAsB;AACtB,MAAM,WAAW,uBAAuB;IACtC,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,8BAA8B;IAC9B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAOrD;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,qBAAqB,GAAG,uBAAuB,GAAG,IAAI,CAqBpG"}
1
+ {"version":3,"file":"agent-mention-post-guard.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/orc/agent-mention-post-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAKnE,gDAAgD;AAChD,MAAM,WAAW,qBAAqB;IACpC,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,gCAAgC;IAChC,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B,0EAA0E;IAC1E,cAAc,EAAE,OAAO,CAAC;IACxB,mFAAmF;IACnF,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CAC9C;AAED,sBAAsB;AACtB,MAAM,WAAW,uBAAuB;IACtC,oFAAoF;IACpF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,8BAA8B;IAC9B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAOrD;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,qBAAqB,GAAG,uBAAuB,GAAG,IAAI,CAsBpG"}