crewly 1.20.154 → 1.20.156

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 (152) hide show
  1. package/config/skills/agent/core/attach-file/SKILL.md +1 -1
  2. package/config/skills/agent/core/attach-file/execute.sh +1 -1
  3. package/config/skills/agent/core/reply-channel/SKILL.md +4 -1
  4. package/config/skills/agent/core/reply-chat/SKILL.md +17 -0
  5. package/config/skills/agent/core/reply-chat/execute.sh +6 -1
  6. package/config/skills/agent/core/slack-post/SKILL.md +1 -1
  7. package/config/skills/team-leader/delegate-task/execute.sh +17 -4
  8. package/dist/backend/backend/src/constants.d.ts +138 -0
  9. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  10. package/dist/backend/backend/src/constants.js +149 -0
  11. package/dist/backend/backend/src/constants.js.map +1 -1
  12. package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts +18 -0
  13. package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts.map +1 -1
  14. package/dist/backend/backend/src/controllers/chat/chat.controller.js +42 -6
  15. package/dist/backend/backend/src/controllers/chat/chat.controller.js.map +1 -1
  16. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.d.ts +32 -0
  17. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.d.ts.map +1 -1
  18. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js +122 -8
  19. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js.map +1 -1
  20. package/dist/backend/backend/src/controllers/slack/slack.controller.d.ts.map +1 -1
  21. package/dist/backend/backend/src/controllers/slack/slack.controller.js +6 -1
  22. package/dist/backend/backend/src/controllers/slack/slack.controller.js.map +1 -1
  23. package/dist/backend/backend/src/index.d.ts.map +1 -1
  24. package/dist/backend/backend/src/index.js +20 -0
  25. package/dist/backend/backend/src/index.js.map +1 -1
  26. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +16 -0
  27. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  28. package/dist/backend/backend/src/services/agent/agent-registration.service.js +54 -4
  29. package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
  30. package/dist/backend/backend/src/services/agent/fresh-task-conversation.service.d.ts +153 -1
  31. package/dist/backend/backend/src/services/agent/fresh-task-conversation.service.d.ts.map +1 -1
  32. package/dist/backend/backend/src/services/agent/fresh-task-conversation.service.js +371 -22
  33. package/dist/backend/backend/src/services/agent/fresh-task-conversation.service.js.map +1 -1
  34. package/dist/backend/backend/src/services/ai/prompt-modules/communication.module.d.ts +13 -0
  35. package/dist/backend/backend/src/services/ai/prompt-modules/communication.module.d.ts.map +1 -1
  36. package/dist/backend/backend/src/services/ai/prompt-modules/communication.module.js +16 -0
  37. package/dist/backend/backend/src/services/ai/prompt-modules/communication.module.js.map +1 -1
  38. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts +30 -1
  39. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
  40. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +46 -3
  41. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
  42. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.d.ts.map +1 -1
  43. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.js +17 -4
  44. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.js.map +1 -1
  45. package/dist/backend/backend/src/services/event-bus/event-bus.service.d.ts.map +1 -1
  46. package/dist/backend/backend/src/services/event-bus/event-bus.service.js +6 -0
  47. package/dist/backend/backend/src/services/event-bus/event-bus.service.js.map +1 -1
  48. package/dist/backend/backend/src/services/slack/slack-agent-dm.service.d.ts +93 -6
  49. package/dist/backend/backend/src/services/slack/slack-agent-dm.service.d.ts.map +1 -1
  50. package/dist/backend/backend/src/services/slack/slack-agent-dm.service.js +169 -15
  51. package/dist/backend/backend/src/services/slack/slack-agent-dm.service.js.map +1 -1
  52. package/dist/backend/backend/src/services/slack/slack-agent-post.service.d.ts +2 -2
  53. package/dist/backend/backend/src/services/slack/slack-agent-post.service.d.ts.map +1 -1
  54. package/dist/backend/backend/src/services/slack/slack-agent-post.service.js +15 -2
  55. package/dist/backend/backend/src/services/slack/slack-agent-post.service.js.map +1 -1
  56. package/dist/backend/backend/src/services/slack/slack-initializer.d.ts.map +1 -1
  57. package/dist/backend/backend/src/services/slack/slack-initializer.js +7 -1
  58. package/dist/backend/backend/src/services/slack/slack-initializer.js.map +1 -1
  59. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts +40 -0
  60. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
  61. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js +86 -9
  62. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
  63. package/dist/backend/backend/src/services/slack/slack-team-channel.service.d.ts +1 -1
  64. package/dist/backend/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
  65. package/dist/backend/backend/src/services/slack/slack-team-channel.service.js +33 -4
  66. package/dist/backend/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
  67. package/dist/backend/backend/src/services/slack/slack-thread-context.service.d.ts +227 -0
  68. package/dist/backend/backend/src/services/slack/slack-thread-context.service.d.ts.map +1 -0
  69. package/dist/backend/backend/src/services/slack/slack-thread-context.service.js +455 -0
  70. package/dist/backend/backend/src/services/slack/slack-thread-context.service.js.map +1 -0
  71. package/dist/backend/backend/src/services/slack/slack-thread-key.d.ts +66 -0
  72. package/dist/backend/backend/src/services/slack/slack-thread-key.d.ts.map +1 -0
  73. package/dist/backend/backend/src/services/slack/slack-thread-key.js +109 -0
  74. package/dist/backend/backend/src/services/slack/slack-thread-key.js.map +1 -0
  75. package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.d.ts +89 -13
  76. package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.d.ts.map +1 -1
  77. package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.js +224 -50
  78. package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.js.map +1 -1
  79. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  80. package/dist/backend/backend/src/services/task-pool/task-pool.service.js +2 -0
  81. package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  82. package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.d.ts +47 -0
  83. package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.d.ts.map +1 -1
  84. package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.js +118 -3
  85. package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.js.map +1 -1
  86. package/dist/backend/backend/src/types/event-bus.types.d.ts +5 -0
  87. package/dist/backend/backend/src/types/event-bus.types.d.ts.map +1 -1
  88. package/dist/backend/backend/src/types/event-bus.types.js.map +1 -1
  89. package/dist/backend/backend/src/types/slack.types.d.ts +43 -0
  90. package/dist/backend/backend/src/types/slack.types.d.ts.map +1 -1
  91. package/dist/backend/backend/src/types/slack.types.js.map +1 -1
  92. package/dist/backend/build-info.json +2 -2
  93. package/dist/cli/backend/src/constants.d.ts +138 -0
  94. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  95. package/dist/cli/backend/src/constants.js +149 -0
  96. package/dist/cli/backend/src/constants.js.map +1 -1
  97. package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts +16 -0
  98. package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  99. package/dist/cli/backend/src/services/agent/agent-registration.service.js +54 -4
  100. package/dist/cli/backend/src/services/agent/agent-registration.service.js.map +1 -1
  101. package/dist/cli/backend/src/services/agent/fresh-task-conversation.service.d.ts +409 -0
  102. package/dist/cli/backend/src/services/agent/fresh-task-conversation.service.d.ts.map +1 -0
  103. package/dist/cli/backend/src/services/agent/fresh-task-conversation.service.js +961 -0
  104. package/dist/cli/backend/src/services/agent/fresh-task-conversation.service.js.map +1 -0
  105. package/dist/cli/backend/src/services/ai/prompt-modules/communication.module.d.ts +13 -0
  106. package/dist/cli/backend/src/services/ai/prompt-modules/communication.module.d.ts.map +1 -1
  107. package/dist/cli/backend/src/services/ai/prompt-modules/communication.module.js +16 -0
  108. package/dist/cli/backend/src/services/ai/prompt-modules/communication.module.js.map +1 -1
  109. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts +30 -1
  110. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
  111. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +46 -3
  112. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
  113. package/dist/cli/backend/src/services/chat-v2/chat-v2.service.d.ts.map +1 -1
  114. package/dist/cli/backend/src/services/chat-v2/chat-v2.service.js +17 -4
  115. package/dist/cli/backend/src/services/chat-v2/chat-v2.service.js.map +1 -1
  116. package/dist/cli/backend/src/services/event-bus/event-bus.service.d.ts.map +1 -1
  117. package/dist/cli/backend/src/services/event-bus/event-bus.service.js +6 -0
  118. package/dist/cli/backend/src/services/event-bus/event-bus.service.js.map +1 -1
  119. package/dist/cli/backend/src/services/slack/slack-agent-dm.service.d.ts +93 -6
  120. package/dist/cli/backend/src/services/slack/slack-agent-dm.service.d.ts.map +1 -1
  121. package/dist/cli/backend/src/services/slack/slack-agent-dm.service.js +169 -15
  122. package/dist/cli/backend/src/services/slack/slack-agent-dm.service.js.map +1 -1
  123. package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.d.ts +40 -0
  124. package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
  125. package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.js +86 -9
  126. package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
  127. package/dist/cli/backend/src/services/slack/slack-team-channel.service.d.ts +1 -1
  128. package/dist/cli/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
  129. package/dist/cli/backend/src/services/slack/slack-team-channel.service.js +33 -4
  130. package/dist/cli/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
  131. package/dist/cli/backend/src/services/slack/slack-thread-context.service.d.ts +227 -0
  132. package/dist/cli/backend/src/services/slack/slack-thread-context.service.d.ts.map +1 -0
  133. package/dist/cli/backend/src/services/slack/slack-thread-context.service.js +455 -0
  134. package/dist/cli/backend/src/services/slack/slack-thread-context.service.js.map +1 -0
  135. package/dist/cli/backend/src/services/slack/slack-thread-key.d.ts +66 -0
  136. package/dist/cli/backend/src/services/slack/slack-thread-key.d.ts.map +1 -0
  137. package/dist/cli/backend/src/services/slack/slack-thread-key.js +109 -0
  138. package/dist/cli/backend/src/services/slack/slack-thread-key.js.map +1 -0
  139. package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.d.ts +89 -13
  140. package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.d.ts.map +1 -1
  141. package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.js +224 -50
  142. package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.js.map +1 -1
  143. package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  144. package/dist/cli/backend/src/services/task-pool/task-pool.service.js +2 -0
  145. package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  146. package/dist/cli/backend/src/types/event-bus.types.d.ts +5 -0
  147. package/dist/cli/backend/src/types/event-bus.types.d.ts.map +1 -1
  148. package/dist/cli/backend/src/types/event-bus.types.js.map +1 -1
  149. package/dist/cli/backend/src/types/slack.types.d.ts +43 -0
  150. package/dist/cli/backend/src/types/slack.types.d.ts.map +1 -1
  151. package/dist/cli/backend/src/types/slack.types.js.map +1 -1
  152. package/package.json +1 -1
@@ -0,0 +1,409 @@
1
+ /**
2
+ * Fresh Task Conversation Service
3
+ *
4
+ * Claude Code agents keep one conversation forever, so a small new task
5
+ * re-reads hundreds of thousands of tokens of unrelated history on every
6
+ * turn (81% of measured usage came from turns over 300k context). This
7
+ * service starts a fresh conversation when a team member is handed a task
8
+ * whose ROOT differs from the last one it was given:
9
+ *
10
+ * 1. The old conversation is saved server-side — a handover file under
11
+ * `<CREWLY_HOME>/handover/` (same format the orchestrator uses at
12
+ * restart) and a concise copy through the memory `remember` path, which
13
+ * mirrors into the wiki. No agent turn is spent on it.
14
+ * 2. `/clear` is written to the PTY the same way context compaction writes
15
+ * its command (Escape, 200 ms, command + CR), then a short pause for the
16
+ * prompt to come back.
17
+ * 3. The dispatch goes on with a one-line note pointing at the handover.
18
+ * 4. In the background the new transcript Claude Code starts is found and
19
+ * its id stored, so a restart resumes the NEW conversation; if it cannot
20
+ * be found the stored id is cleared so a restart starts fresh instead of
21
+ * resuming the huge pre-clear one.
22
+ *
23
+ * Retries, verifications and reviews of the same task share its root
24
+ * (`<id>:retry:N`, `<id>:verify:<id>`, `<id>:review:…`), so they keep their
25
+ * context. Never the orchestrator, only Claude Code, only when the agent is
26
+ * idle and nobody else just wrote to it; any failure falls back to plain
27
+ * delivery — nothing here throws into dispatch.
28
+ *
29
+ * Idle-boundary context cap: one task can run for 1000+ turns, so a new root
30
+ * alone does not bound the context. A periodic sweep
31
+ * ({@link FreshTaskConversationService.startContextCapSweep}) saves and
32
+ * clears an idle Claude Code member whose last turn carried more than
33
+ * `CREWLY_MEMBER_CONTEXT_CAP_TOKENS` (300k by default, `0` disables), then
34
+ * writes one line naming its active WorkItem and the handover. Same safety
35
+ * rules — never the orchestrator, never mid-turn, never while a message is
36
+ * queued for or being delivered to it — plus at most one cap per 20 minutes.
37
+ *
38
+ * @module services/agent/fresh-task-conversation.service
39
+ */
40
+ import type { WorkItem } from '../../types/v2/work-item.types.js';
41
+ /**
42
+ * The root task id of a work item: its id with any follow-up suffix
43
+ * (`:retry:N`, `:verify:…`, `:review:…`) removed, so every follow-up of one
44
+ * task maps to the same root.
45
+ *
46
+ * @param workItemId - WorkItem id
47
+ * @returns The root id
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * rootWorkItemId('abc:retry:2'); // 'abc'
52
+ * rootWorkItemId('abc:verify:abc'); // 'abc'
53
+ * rootWorkItemId('abc:retry:1:retry:2'); // 'abc'
54
+ * ```
55
+ */
56
+ export declare function rootWorkItemId(workItemId: string): string;
57
+ /**
58
+ * Whether the feature is switched on by the environment.
59
+ *
60
+ * @param env - Environment (tests)
61
+ * @returns False when CREWLY_FRESH_TASK_CONVERSATION is 0 / false / off / no
62
+ */
63
+ export declare function freshTaskConversationEnvEnabled(env?: NodeJS.ProcessEnv): boolean;
64
+ /** Everything the clear decision depends on. */
65
+ export interface FreshTaskDecisionInput {
66
+ /** Agent session */
67
+ sessionName: string;
68
+ /** Its runtime (from session persistence) */
69
+ runtimeType?: string;
70
+ /** Root of the last task delivered to it, if any */
71
+ previousRoot: string | null;
72
+ /** Root of the task being delivered */
73
+ newRoot: string;
74
+ /** Env + settings kill-switch */
75
+ enabled: boolean;
76
+ /** Agent is mid-turn */
77
+ busy: boolean;
78
+ /** Someone else wrote to the session moments ago */
79
+ recentDelivery: boolean;
80
+ /** Roots of OTHER work the agent is actively running */
81
+ otherActiveRoots: string[];
82
+ /**
83
+ * The agent already started this very task a while ago (e.g. the lead
84
+ * handed it over directly and this is a re-delivery). Clearing now would
85
+ * wipe the live context of work in progress.
86
+ */
87
+ alreadyStarted?: boolean;
88
+ }
89
+ /** The clear decision and why. */
90
+ export interface FreshTaskDecision {
91
+ /** Clear before delivering */
92
+ clear: boolean;
93
+ /** Short reason (logged) */
94
+ reason: string;
95
+ }
96
+ /**
97
+ * Decide whether to start a fresh conversation before delivering a task.
98
+ *
99
+ * @param input - Decision inputs
100
+ * @returns The decision
101
+ */
102
+ export declare function decideFreshConversation(input: FreshTaskDecisionInput): FreshTaskDecision;
103
+ /**
104
+ * The line put in front of the task text after a fresh start.
105
+ *
106
+ * @param handoverPath - Handover file written for the old conversation
107
+ * @returns One line
108
+ */
109
+ export declare function freshConversationNote(handoverPath: string): string;
110
+ /**
111
+ * The context cap for members, from the environment.
112
+ *
113
+ * @param env - Environment (tests)
114
+ * @returns Tokens; 0 means the cap is off. Unset or invalid → the default.
115
+ */
116
+ export declare function memberContextCapTokens(env?: NodeJS.ProcessEnv): number;
117
+ /** Everything the idle-boundary context-cap decision depends on. */
118
+ export interface ContextCapDecisionInput {
119
+ /** Agent session */
120
+ sessionName: string;
121
+ /** Its runtime */
122
+ runtimeType?: string;
123
+ /** Cap in tokens (0 = off) */
124
+ capTokens: number;
125
+ /** Env + settings kill-switch of the fresh-conversation feature */
126
+ enabled: boolean;
127
+ /** Last turn's context, or null when unknown */
128
+ contextTokens: number | null;
129
+ /** Agent is mid-turn */
130
+ busy: boolean;
131
+ /** How long the PTY has been quiet (null = unknown) */
132
+ quietMs: number | null;
133
+ /** A message is being delivered, was just delivered, or a prepare/clear is running */
134
+ deliveryActive: boolean;
135
+ /** Messages are queued for the agent */
136
+ queuedMessages: boolean;
137
+ /** When the session was last capped (ms), if ever */
138
+ lastCapAt: number | null;
139
+ /** Now (ms) */
140
+ now: number;
141
+ /** Id of the WorkItem the agent is on (null = none) */
142
+ activeWorkItemId: string | null;
143
+ }
144
+ /**
145
+ * Decide whether to cap (save + clear + re-orient) a member's conversation.
146
+ * Pure; the order of checks is also the order of the logged reasons.
147
+ *
148
+ * @param input - Decision inputs
149
+ * @returns The decision
150
+ */
151
+ export declare function decideContextCap(input: ContextCapDecisionInput): FreshTaskDecision;
152
+ /**
153
+ * The one line written after a context-cap clear. It must carry the WorkItem
154
+ * id: the new conversation id is found by it.
155
+ *
156
+ * @param args - WorkItem, handover file and the old context size
157
+ * @returns One line
158
+ */
159
+ export declare function contextCapReorientation(args: {
160
+ workItem: Pick<WorkItem, 'id' | 'title'>;
161
+ handoverPath: string;
162
+ contextTokens: number;
163
+ }): string;
164
+ /** What the service needs to know about a session. */
165
+ export interface FreshTaskSessionInfo {
166
+ /** Runtime */
167
+ runtimeType?: string;
168
+ /** Working directory (Claude Code transcripts are keyed on it) */
169
+ cwd?: string;
170
+ /** Current Claude conversation id */
171
+ sessionId?: string;
172
+ }
173
+ /** Collaborators; the defaults talk to the running backend. */
174
+ export interface FreshTaskDeps {
175
+ /** Session runtime / cwd / conversation id */
176
+ getSessionInfo: (sessionName: string) => FreshTaskSessionInfo | null;
177
+ /** Conversation ids of every OTHER registered session */
178
+ getClaimedSessionIds: (sessionName: string) => Set<string>;
179
+ /** Store the new conversation id */
180
+ updateSessionId: (sessionName: string, id: string) => void;
181
+ /** Forget the conversation id (restart starts fresh) */
182
+ clearSessionId: (sessionName: string) => void;
183
+ /** Agent is mid-turn */
184
+ isBusy: (sessionName: string) => Promise<boolean>;
185
+ /** Settings flag (general.freshConversationPerTask, default true) */
186
+ settingEnabled: () => Promise<boolean>;
187
+ /** Open work items targeting the session */
188
+ getActiveItems: (sessionName: string) => Promise<WorkItem[]>;
189
+ /** Raw PTY write; false when the session is gone */
190
+ writeToSession: (sessionName: string, data: string) => boolean;
191
+ /** Store the concise handover through memory (mirrors into the wiki) */
192
+ remember: (args: {
193
+ agentId: string;
194
+ projectPath?: string;
195
+ content: string;
196
+ title: string;
197
+ }) => Promise<unknown>;
198
+ /** Crewly home (handover + state files) */
199
+ crewlyHome: () => string;
200
+ /** Claude home override (tests) */
201
+ claudeHome?: string;
202
+ /** Clock */
203
+ now: () => number;
204
+ /** Sleep */
205
+ sleep: (ms: number) => Promise<void>;
206
+ /** Environment */
207
+ env: NodeJS.ProcessEnv;
208
+ /** Registered agent sessions (context-cap sweep) */
209
+ listSessions: () => string[];
210
+ /** Messages are queued for the session and not yet written */
211
+ hasQueuedMessages: (sessionName: string) => boolean;
212
+ /** How long the session's PTY has been quiet (ms), or null when unknown */
213
+ getQuietMs: (sessionName: string) => number | null;
214
+ /** Write one message into the session (paste + Enter); false when the session is gone */
215
+ sendMessage: (sessionName: string, text: string) => Promise<boolean>;
216
+ }
217
+ /** Result of {@link FreshTaskConversationService.prepareForTask}. */
218
+ export interface PrepareForTaskResult {
219
+ /** A fresh conversation was started */
220
+ cleared: boolean;
221
+ /** Handover file for the old conversation (when cleared) */
222
+ handoverPath?: string;
223
+ }
224
+ /** Result of {@link FreshTaskConversationService.capContextIfNeeded}. */
225
+ export interface ContextCapResult {
226
+ /** The conversation was saved, cleared and the agent re-oriented */
227
+ capped: boolean;
228
+ /** Why (logged; the decision reason when not capped) */
229
+ reason: string;
230
+ /** Handover file for the old conversation (when capped) */
231
+ handoverPath?: string;
232
+ /** WorkItem the agent was re-oriented on (when capped) */
233
+ workItemId?: string;
234
+ }
235
+ /**
236
+ * Singleton that starts a fresh Claude Code conversation per new task, and
237
+ * caps a long task's conversation at idle boundaries.
238
+ */
239
+ export declare class FreshTaskConversationService {
240
+ private static instance;
241
+ private readonly logger;
242
+ private deps;
243
+ private state;
244
+ /** Per-session in-flight prepare (serialises prepares; waited on by terminal writes) */
245
+ private readonly inFlight;
246
+ /** Last time a message was written to a session (terminal write / deliver) */
247
+ private readonly lastDelivery;
248
+ /** Deliveries currently being written to a session (see {@link beginDelivery}) */
249
+ private readonly deliveriesInFlight;
250
+ /** Last context-cap clear per session (rate limit) */
251
+ private readonly lastCapAt;
252
+ /** Context-cap sweep timer */
253
+ private capSweepTimer;
254
+ /** A sweep is running (sweeps never overlap) */
255
+ private capSweepRunning;
256
+ private constructor();
257
+ /**
258
+ * @returns The singleton
259
+ */
260
+ static getInstance(): FreshTaskConversationService;
261
+ /**
262
+ * Replace the singleton with one using the given collaborators (tests).
263
+ *
264
+ * @param deps - Overrides for the default deps
265
+ * @returns The new singleton
266
+ */
267
+ static createForTesting(deps: Partial<FreshTaskDeps>): FreshTaskConversationService;
268
+ /** Drop the singleton (tests). */
269
+ static resetInstance(): void;
270
+ /**
271
+ * Mark a delivery to a session as in progress until the returned function
272
+ * is called. Neither a new-task clear nor a context-cap clear starts while
273
+ * one is running: it would wipe the message before the agent reads it.
274
+ *
275
+ * @param sessionName - Session being written to
276
+ * @returns Call when the delivery has finished (idempotent)
277
+ */
278
+ beginDelivery(sessionName: string): () => void;
279
+ /**
280
+ * Whether a delivery is being written to the session right now.
281
+ *
282
+ * @param sessionName - Session
283
+ * @returns True while a {@link beginDelivery} is open
284
+ */
285
+ isDelivering(sessionName: string): boolean;
286
+ /**
287
+ * Record that a message is being written to a session. A clear right after
288
+ * would wipe it before the agent reads it, so {@link prepareForTask} skips
289
+ * clearing for a short window (this includes the dispatcher's own briefs,
290
+ * so two tasks dispatched back to back never clear each other).
291
+ *
292
+ * @param sessionName - Session written to
293
+ */
294
+ noteDelivery(sessionName: string): void;
295
+ /**
296
+ * Wait (bounded) while a prepare — possibly a `/clear` — is running for the
297
+ * session, so a message written now is not wiped by it.
298
+ *
299
+ * @param sessionName - Session about to be written to
300
+ * @param maxMs - Upper bound on the wait
301
+ */
302
+ waitIfClearing(sessionName: string, maxMs?: number): Promise<void>;
303
+ /**
304
+ * Root of the last task delivered to a session.
305
+ *
306
+ * @param sessionName - Session
307
+ * @returns Root id or null
308
+ */
309
+ getLastRoot(sessionName: string): string | null;
310
+ /**
311
+ * Called right before a task is written to an agent. Starts a fresh
312
+ * conversation when the task's root differs from the previous one and it
313
+ * is safe to; always records the new root. Never throws.
314
+ *
315
+ * @param sessionName - Target session
316
+ * @param workItem - Task being delivered
317
+ * @returns Whether it cleared, and the handover file when it did
318
+ */
319
+ prepareForTask(sessionName: string, workItem: Pick<WorkItem, 'id' | 'metadata'>): Promise<PrepareForTaskResult>;
320
+ /**
321
+ * Start the periodic context-cap sweep (idempotent). The timer is unref'd
322
+ * so it never keeps the process alive.
323
+ *
324
+ * @param intervalMs - Sweep interval
325
+ */
326
+ startContextCapSweep(intervalMs?: number): void;
327
+ /** Stop the periodic context-cap sweep. */
328
+ stopContextCapSweep(): void;
329
+ /**
330
+ * Check every registered session once. Sessions are handled one after
331
+ * another and sweeps never overlap. Never throws.
332
+ *
333
+ * @returns Per-session results (sessions skipped cheaply are omitted)
334
+ */
335
+ runContextCapSweep(): Promise<Record<string, ContextCapResult>>;
336
+ /**
337
+ * If the member is idle between turns and its last turn carried more than
338
+ * the cap, save the conversation (handover file + wiki), `/clear` it and
339
+ * write one line naming its WorkItem and the handover. Runs in the same
340
+ * per-session chain as {@link prepareForTask}, so terminal writes wait for
341
+ * it. Never throws.
342
+ *
343
+ * @param sessionName - Member session
344
+ * @returns What happened
345
+ */
346
+ capContextIfNeeded(sessionName: string): Promise<ContextCapResult>;
347
+ private doCapContext;
348
+ /**
349
+ * The WorkItem a member is on: running before accepted before proposed,
350
+ * then the most recently started.
351
+ */
352
+ private pickCurrentItem;
353
+ private doPrepare;
354
+ /**
355
+ * Save the current conversation (handover file + memory/wiki copy, no
356
+ * agent turn) and write `/clear`. Shared by the new-task and the
357
+ * context-cap paths.
358
+ *
359
+ * @param sessionName - Agent session
360
+ * @param conv - Its cwd and current conversation id
361
+ * @param handover - Task the old conversation was on, and why it closed
362
+ * @returns The handover file and the time `/clear` was written, or null
363
+ * when nothing was cleared (transcript missing, session gone)
364
+ */
365
+ private saveAndClear;
366
+ /**
367
+ * Write the handover file (same shape as the orchestrator's restart handover).
368
+ *
369
+ * @returns Its path
370
+ */
371
+ private writeHandover;
372
+ /**
373
+ * The capped text stored through memory: where the handover is plus the
374
+ * newest part of what was said.
375
+ */
376
+ private conciseHandover;
377
+ /**
378
+ * After `/clear`, find the transcript Claude Code starts for this agent and
379
+ * store its id; if none shows up in time, clear the stored id so a restart
380
+ * starts fresh rather than resuming the pre-clear conversation.
381
+ *
382
+ * A candidate is a `.jsonl` in the agent's transcript directory that was
383
+ * STARTED after the clear (its first entry, not just a later write), is not
384
+ * the old id or claimed by another session, and contains this task's
385
+ * work-item id — the dispatch text written right after the clear carries
386
+ * it. Several agents share one cwd and their transcripts mention each
387
+ * other's session names, so matching on the name alone picked another
388
+ * agent's conversation (Atlas resumed Ella's, 2026-09-28).
389
+ */
390
+ private trackNewConversation;
391
+ /**
392
+ * One scan of the transcript directory.
393
+ *
394
+ * @returns The new conversation id, or null
395
+ */
396
+ private findNewTranscript;
397
+ /**
398
+ * Whether a transcript's first timestamped entry is at or after `since`,
399
+ * i.e. the conversation began after the clear rather than being an older
400
+ * one that happened to be written to recently.
401
+ */
402
+ private startedAfter;
403
+ /** Whether the start of a transcript contains the given text. */
404
+ private fileMentions;
405
+ private statePath;
406
+ private loadState;
407
+ private recordRoot;
408
+ }
409
+ //# sourceMappingURL=fresh-task-conversation.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fresh-task-conversation.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/agent/fresh-task-conversation.service.ts"],"names":[],"mappings":"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"}