pi-crew 0.5.2 → 0.5.6
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.
- package/CHANGELOG.md +183 -0
- package/README.md +17 -1
- package/docs/architecture.md +2 -0
- package/docs/bugs/cross-session-notification-leakage.md +82 -0
- package/docs/coding-agent-optimization.md +268 -0
- package/docs/deep-review-report.md +384 -0
- package/docs/distillation/cybersecurity-patterns.md +294 -0
- package/docs/migration-v0.4-v0.5.md +208 -0
- package/docs/optimization-plan.md +642 -0
- package/docs/pi-crew-v0.5.5-audit-fix-plan.md +133 -0
- package/docs/pi-mono-opportunities.md +969 -0
- package/docs/pi-mono-review.md +291 -0
- package/docs/skills/REFERENCE.md +144 -0
- package/package.json +12 -9
- package/skills/artifact-analysis-loop/SKILL.md +302 -0
- package/skills/async-worker-recovery/SKILL.md +19 -1
- package/skills/child-pi-spawning/SKILL.md +19 -6
- package/skills/context-artifact-hygiene/SKILL.md +19 -2
- package/skills/delegation-patterns/SKILL.md +68 -3
- package/skills/detection-pipeline-design/SKILL.md +285 -0
- package/skills/event-log-tracing/SKILL.md +20 -6
- package/skills/git-master/SKILL.md +20 -6
- package/skills/hunting-investigation-loop/SKILL.md +401 -0
- package/skills/incident-playbook-construction/SKILL.md +383 -0
- package/skills/live-agent-lifecycle/SKILL.md +20 -6
- package/skills/mailbox-interactive/SKILL.md +19 -6
- package/skills/model-routing-context/SKILL.md +19 -1
- package/skills/multi-perspective-review/SKILL.md +19 -4
- package/skills/observability-reliability/SKILL.md +19 -2
- package/skills/orchestration/SKILL.md +20 -2
- package/skills/ownership-session-security/SKILL.md +20 -2
- package/skills/pi-extension-lifecycle/SKILL.md +20 -2
- package/skills/post-mortem/SKILL.md +7 -2
- package/skills/read-only-explorer/SKILL.md +20 -6
- package/skills/requirements-to-task-packet/SKILL.md +23 -3
- package/skills/resource-discovery-config/SKILL.md +20 -2
- package/skills/runtime-state-reader/SKILL.md +20 -2
- package/skills/safe-bash/SKILL.md +21 -6
- package/skills/scrutinize/SKILL.md +20 -2
- package/skills/secure-agent-orchestration-review/SKILL.md +29 -2
- package/skills/security-review/SKILL.md +560 -0
- package/skills/state-mutation-locking/SKILL.md +22 -2
- package/skills/systematic-debugging/SKILL.md +8 -6
- package/skills/threat-hypothesis-framework/SKILL.md +175 -0
- package/skills/ui-render-performance/SKILL.md +20 -2
- package/skills/verification-before-done/SKILL.md +17 -2
- package/skills/widget-rendering/SKILL.md +21 -6
- package/skills/workspace-isolation/SKILL.md +20 -6
- package/skills/worktree-isolation/SKILL.md +20 -6
- package/src/agents/agent-config.ts +40 -1
- package/src/benchmark/benchmark-runner.ts +45 -0
- package/src/benchmark/feedback-loop.ts +5 -0
- package/src/config/config.ts +32 -5
- package/src/config/role-tools.ts +82 -0
- package/src/config/suggestions.ts +8 -0
- package/src/config/types.ts +4 -0
- package/src/extension/async-notifier.ts +10 -1
- package/src/extension/crew-cleanup.ts +114 -0
- package/src/extension/cross-extension-rpc.ts +1 -1
- package/src/extension/notification-router.ts +18 -0
- package/src/extension/register.ts +27 -19
- package/src/extension/registration/subagent-tools.ts +1 -1
- package/src/extension/team-tool/anchor.ts +201 -0
- package/src/extension/team-tool/api.ts +2 -1
- package/src/extension/team-tool/auto-summarize.ts +154 -0
- package/src/extension/team-tool/run.ts +42 -7
- package/src/extension/team-tool.ts +44 -2
- package/src/hooks/registry.ts +1 -3
- package/src/observability/event-bus.ts +69 -0
- package/src/observability/event-to-metric.ts +0 -2
- package/src/runtime/anchor-manager.ts +473 -0
- package/src/runtime/async-runner.ts +8 -4
- package/src/runtime/auto-summarize.ts +350 -0
- package/src/runtime/background-runner.ts +10 -3
- package/src/runtime/budget-tracker.ts +354 -0
- package/src/runtime/chain-runner.ts +507 -0
- package/src/runtime/child-pi.ts +123 -35
- package/src/runtime/crash-recovery.ts +5 -4
- package/src/runtime/crew-agent-runtime.ts +1 -0
- package/src/runtime/custom-tools/irc-tool.ts +13 -0
- package/src/runtime/custom-tools/submit-result-tool.ts +3 -2
- package/src/runtime/delivery-coordinator.ts +10 -3
- package/src/runtime/dynamic-script-runner.ts +482 -0
- package/src/runtime/foreground-control.ts +87 -17
- package/src/runtime/handoff-manager.ts +589 -0
- package/src/runtime/hidden-handoff.ts +424 -0
- package/src/runtime/live-agent-manager.ts +20 -4
- package/src/runtime/live-session-runtime.ts +39 -4
- package/src/runtime/manifest-cache.ts +2 -1
- package/src/runtime/model-resolver.ts +16 -4
- package/src/runtime/phase-tracker.ts +373 -0
- package/src/runtime/pi-args.ts +11 -1
- package/src/runtime/pi-json-output.ts +31 -0
- package/src/runtime/pipeline-runner.ts +514 -0
- package/src/runtime/progress-tracker.ts +124 -0
- package/src/runtime/retry-runner.ts +354 -0
- package/src/runtime/sandbox.ts +252 -0
- package/src/runtime/scheduler.ts +7 -2
- package/src/runtime/skill-effectiveness.ts +473 -0
- package/src/runtime/skill-instructions.ts +37 -3
- package/src/runtime/subagent-manager.ts +1 -1
- package/src/runtime/task-graph.ts +11 -1
- package/src/runtime/task-runner.ts +92 -18
- package/src/runtime/team-runner.ts +13 -12
- package/src/runtime/tool-progress.ts +10 -3
- package/src/runtime/verification-gates.ts +367 -0
- package/src/schema/team-tool-schema.ts +37 -0
- package/src/skills/discover-skills.ts +5 -0
- package/src/state/active-run-registry.ts +9 -2
- package/src/state/contracts.ts +9 -0
- package/src/state/crew-init.ts +3 -3
- package/src/state/decision-ledger.ts +98 -55
- package/src/state/event-log-rotation.ts +2 -2
- package/src/state/event-log.ts +144 -10
- package/src/state/hook-instinct-bridge.ts +5 -5
- package/src/state/mailbox.ts +10 -0
- package/src/state/run-cache.ts +18 -8
- package/src/state/state-store.ts +3 -1
- package/src/state/types.ts +4 -0
- package/src/tools/safe-bash-extension.ts +1 -0
- package/src/tools/safe-bash.ts +152 -20
- package/src/types/new-api-types.ts +34 -0
- package/src/ui/agent-management-overlay.ts +5 -1
- package/src/ui/crew-widget.ts +29 -15
- package/src/ui/overlays/mailbox-detail-overlay.ts +13 -2
- package/src/ui/powerbar-publisher.ts +101 -7
- package/src/ui/tool-render.ts +15 -15
- package/src/ui/transcript-cache.ts +13 -0
- package/src/utils/bm25-search.ts +16 -8
- package/src/utils/env-filter.ts +8 -5
- package/src/utils/redaction.ts +169 -15
- package/src/utils/session-utils.ts +52 -0
- package/src/utils/sse-parser.ts +10 -1
- package/src/worktree/cleanup.ts +6 -1
- package/src/worktree/worktree-manager.ts +32 -13
- package/workflows/chain.workflow.md +252 -0
- package/workflows/pipeline.workflow.md +27 -0
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AutoSummarizeService - Enables auto-summarization with token/tool thresholds.
|
|
3
|
+
*
|
|
4
|
+
* Based on pi-boomerang's autoBoomerang pattern:
|
|
5
|
+
* - toggle() enables/disables auto-summarization
|
|
6
|
+
* - shouldAutoSummarize() checks if task should auto-summarize
|
|
7
|
+
* - Token and tool thresholds control when summarization triggers
|
|
8
|
+
*
|
|
9
|
+
* @see docs/pi-boomerang-integration-plan.md
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { TaskPacket, TaskResult } from "./handoff-manager.ts";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Configuration for AutoSummarizeService.
|
|
16
|
+
*/
|
|
17
|
+
export interface AutoSummarizeConfig {
|
|
18
|
+
/** Whether auto-summarize is enabled */
|
|
19
|
+
enabled: boolean;
|
|
20
|
+
/** Token threshold to trigger summarization */
|
|
21
|
+
threshold: number;
|
|
22
|
+
/** Minimum tools used to trigger summarization (default: 5) */
|
|
23
|
+
minToolsUsed?: number;
|
|
24
|
+
/** Whether to collapse context after summarization */
|
|
25
|
+
collapseContext?: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Default configuration values.
|
|
30
|
+
*/
|
|
31
|
+
export const DEFAULT_AUTO_SUMMARIZE_CONFIG: Required<Omit<AutoSummarizeConfig, "enabled">> = {
|
|
32
|
+
threshold: 5000,
|
|
33
|
+
minToolsUsed: 5,
|
|
34
|
+
collapseContext: true,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Options for AutoSummarizeService.
|
|
39
|
+
*/
|
|
40
|
+
export interface AutoSummarizeServiceOptions {
|
|
41
|
+
/** Initial configuration */
|
|
42
|
+
config?: Partial<AutoSummarizeConfig>;
|
|
43
|
+
/** Custom event emitter */
|
|
44
|
+
eventEmitter?: AutoSummarizeEventEmitter;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Event emitter for auto-summarize events.
|
|
49
|
+
*/
|
|
50
|
+
export interface AutoSummarizeEventEmitter {
|
|
51
|
+
emit(event: string, data: unknown): void;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Event data for auto-summarize toggle event.
|
|
56
|
+
*/
|
|
57
|
+
export interface AutoSummarizeToggledEventData {
|
|
58
|
+
enabled: boolean;
|
|
59
|
+
previousEnabled: boolean;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Event data for auto-summarize triggered event.
|
|
64
|
+
*/
|
|
65
|
+
export interface AutoSummarizeTriggeredEventData {
|
|
66
|
+
packet: TaskPacket;
|
|
67
|
+
result: TaskResult;
|
|
68
|
+
trigger: AutoSummarizeTrigger;
|
|
69
|
+
tokenCount: number;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* What triggered the auto-summarize.
|
|
74
|
+
*/
|
|
75
|
+
export type AutoSummarizeTrigger =
|
|
76
|
+
| "token_threshold"
|
|
77
|
+
| "tools_threshold"
|
|
78
|
+
| "manual"
|
|
79
|
+
| "high_usage";
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* AutoSummarizeService enables automatic summarization based on configurable thresholds.
|
|
83
|
+
* When enabled, it monitors task completion and triggers summarization for tasks
|
|
84
|
+
* that exceed token or tool usage thresholds.
|
|
85
|
+
*/
|
|
86
|
+
export class AutoSummarizeService {
|
|
87
|
+
private config: AutoSummarizeConfig & Required<Omit<AutoSummarizeConfig, "enabled">>;
|
|
88
|
+
private eventEmitter: AutoSummarizeEventEmitter | null = null;
|
|
89
|
+
|
|
90
|
+
constructor(options: AutoSummarizeServiceOptions = {}) {
|
|
91
|
+
this.config = {
|
|
92
|
+
enabled: options.config?.enabled ?? false,
|
|
93
|
+
threshold: options.config?.threshold ?? DEFAULT_AUTO_SUMMARIZE_CONFIG.threshold,
|
|
94
|
+
minToolsUsed: options.config?.minToolsUsed ?? DEFAULT_AUTO_SUMMARIZE_CONFIG.minToolsUsed,
|
|
95
|
+
collapseContext: options.config?.collapseContext ?? DEFAULT_AUTO_SUMMARIZE_CONFIG.collapseContext,
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
if (options.eventEmitter) {
|
|
99
|
+
this.eventEmitter = options.eventEmitter;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Check if auto-summarization is currently enabled.
|
|
105
|
+
*/
|
|
106
|
+
isEnabled(): boolean {
|
|
107
|
+
return this.config.enabled;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Toggle auto-summarize mode.
|
|
112
|
+
* Returns the new enabled state.
|
|
113
|
+
*/
|
|
114
|
+
toggle(): boolean {
|
|
115
|
+
const previousEnabled = this.config.enabled;
|
|
116
|
+
this.config.enabled = !this.config.enabled;
|
|
117
|
+
|
|
118
|
+
this.eventEmitter?.emit("auto-summarize:toggled", {
|
|
119
|
+
enabled: this.config.enabled,
|
|
120
|
+
previousEnabled,
|
|
121
|
+
} as AutoSummarizeToggledEventData);
|
|
122
|
+
|
|
123
|
+
return this.config.enabled;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Enable auto-summarize.
|
|
128
|
+
*/
|
|
129
|
+
enable(): void {
|
|
130
|
+
if (!this.config.enabled) {
|
|
131
|
+
this.toggle();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Disable auto-summarize.
|
|
137
|
+
*/
|
|
138
|
+
disable(): void {
|
|
139
|
+
if (this.config.enabled) {
|
|
140
|
+
this.toggle();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Check if a task should auto-summarize.
|
|
146
|
+
*
|
|
147
|
+
* @param packet - The task packet
|
|
148
|
+
* @param result - The task result
|
|
149
|
+
* @returns True if the task should auto-summarize
|
|
150
|
+
*/
|
|
151
|
+
shouldAutoSummarize(packet: TaskPacket, result: TaskResult): boolean {
|
|
152
|
+
if (!this.config.enabled) {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const tokenCount = result.usage?.totalTokens ?? 0;
|
|
157
|
+
|
|
158
|
+
// Check token threshold
|
|
159
|
+
if (tokenCount >= this.config.threshold) {
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Check tools threshold
|
|
164
|
+
const toolsUsed = result.toolsUsed?.length ?? 0;
|
|
165
|
+
if (toolsUsed >= (this.config.minToolsUsed ?? 5)) {
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// High usage check: high token count relative to tools
|
|
170
|
+
// More tokens per tool suggests complex work that should be summarized
|
|
171
|
+
if (tokenCount > 2000 && toolsUsed >= 3) {
|
|
172
|
+
const tokensPerTool = tokenCount / toolsUsed;
|
|
173
|
+
if (tokensPerTool > 1000) {
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Get the reason why a task should (or should not) auto-summarize.
|
|
183
|
+
*
|
|
184
|
+
* @param packet - The task packet
|
|
185
|
+
* @param result - The task result
|
|
186
|
+
* @returns Object with shouldSummarize flag and reason
|
|
187
|
+
*/
|
|
188
|
+
getAutoSummarizeDecision(packet: TaskPacket, result: TaskResult): AutoSummarizeDecision {
|
|
189
|
+
if (!this.config.enabled) {
|
|
190
|
+
return {
|
|
191
|
+
shouldSummarize: false,
|
|
192
|
+
reason: "auto-summarize is disabled",
|
|
193
|
+
trigger: undefined,
|
|
194
|
+
tokenCount: result.usage?.totalTokens ?? 0,
|
|
195
|
+
toolsUsed: result.toolsUsed?.length ?? 0,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const tokenCount = result.usage?.totalTokens ?? 0;
|
|
200
|
+
const toolsUsed = result.toolsUsed?.length ?? 0;
|
|
201
|
+
|
|
202
|
+
// Check token threshold
|
|
203
|
+
if (tokenCount >= this.config.threshold) {
|
|
204
|
+
return {
|
|
205
|
+
shouldSummarize: true,
|
|
206
|
+
reason: `Token count ${tokenCount} exceeds threshold ${this.config.threshold}`,
|
|
207
|
+
trigger: "token_threshold",
|
|
208
|
+
tokenCount,
|
|
209
|
+
toolsUsed,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Check tools threshold
|
|
214
|
+
const minTools = this.config.minToolsUsed ?? 5;
|
|
215
|
+
if (toolsUsed >= minTools) {
|
|
216
|
+
return {
|
|
217
|
+
shouldSummarize: true,
|
|
218
|
+
reason: `Tool count ${toolsUsed} meets minimum ${minTools}`,
|
|
219
|
+
trigger: "tools_threshold",
|
|
220
|
+
tokenCount,
|
|
221
|
+
toolsUsed,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// High usage check
|
|
226
|
+
if (tokenCount > 2000 && toolsUsed >= 3) {
|
|
227
|
+
const tokensPerTool = tokenCount / toolsUsed;
|
|
228
|
+
if (tokensPerTool > 1000) {
|
|
229
|
+
return {
|
|
230
|
+
shouldSummarize: true,
|
|
231
|
+
reason: `High token-to-tool ratio: ${Math.round(tokensPerTool)} tokens/tool`,
|
|
232
|
+
trigger: "high_usage",
|
|
233
|
+
tokenCount,
|
|
234
|
+
toolsUsed,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return {
|
|
240
|
+
shouldSummarize: false,
|
|
241
|
+
reason: `Below thresholds (tokens: ${tokenCount}/${this.config.threshold}, tools: ${toolsUsed}/${minTools})`,
|
|
242
|
+
trigger: undefined,
|
|
243
|
+
tokenCount,
|
|
244
|
+
toolsUsed,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Get the current configuration.
|
|
250
|
+
*/
|
|
251
|
+
getConfig(): AutoSummarizeConfig & Required<Omit<AutoSummarizeConfig, "enabled">> {
|
|
252
|
+
return { ...this.config };
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Update configuration.
|
|
257
|
+
*/
|
|
258
|
+
updateConfig(config: Partial<AutoSummarizeConfig>): void {
|
|
259
|
+
const previousEnabled = this.config.enabled;
|
|
260
|
+
|
|
261
|
+
if (config.enabled !== undefined) {
|
|
262
|
+
this.config.enabled = config.enabled;
|
|
263
|
+
}
|
|
264
|
+
if (config.threshold !== undefined) {
|
|
265
|
+
this.config.threshold = config.threshold;
|
|
266
|
+
}
|
|
267
|
+
if (config.minToolsUsed !== undefined) {
|
|
268
|
+
this.config.minToolsUsed = config.minToolsUsed;
|
|
269
|
+
}
|
|
270
|
+
if (config.collapseContext !== undefined) {
|
|
271
|
+
this.config.collapseContext = config.collapseContext;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Emit event if enabled state changed
|
|
275
|
+
if (config.enabled !== undefined && config.enabled !== previousEnabled) {
|
|
276
|
+
this.eventEmitter?.emit("auto-summarize:toggled", {
|
|
277
|
+
enabled: this.config.enabled,
|
|
278
|
+
previousEnabled,
|
|
279
|
+
} as AutoSummarizeToggledEventData);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Get current threshold value.
|
|
285
|
+
*/
|
|
286
|
+
getThreshold(): number {
|
|
287
|
+
return this.config.threshold;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Set token threshold.
|
|
292
|
+
*/
|
|
293
|
+
setThreshold(threshold: number): void {
|
|
294
|
+
if (threshold < 0) {
|
|
295
|
+
throw new Error("Threshold must be non-negative");
|
|
296
|
+
}
|
|
297
|
+
this.config.threshold = threshold;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Get current minToolsUsed value.
|
|
302
|
+
*/
|
|
303
|
+
getMinToolsUsed(): number {
|
|
304
|
+
return this.config.minToolsUsed ?? 5;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Set minimum tools threshold.
|
|
309
|
+
*/
|
|
310
|
+
setMinToolsUsed(minTools: number): void {
|
|
311
|
+
if (minTools < 0) {
|
|
312
|
+
throw new Error("minToolsUsed must be non-negative");
|
|
313
|
+
}
|
|
314
|
+
this.config.minToolsUsed = minTools;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Check if context should be collapsed after summarization.
|
|
319
|
+
*/
|
|
320
|
+
shouldCollapseContext(): boolean {
|
|
321
|
+
return this.config.collapseContext ?? true;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Set event emitter.
|
|
326
|
+
*/
|
|
327
|
+
setEventEmitter(eventEmitter: AutoSummarizeEventEmitter): void {
|
|
328
|
+
this.eventEmitter = eventEmitter;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Decision result from shouldAutoSummarize check.
|
|
334
|
+
*/
|
|
335
|
+
export interface AutoSummarizeDecision {
|
|
336
|
+
shouldSummarize: boolean;
|
|
337
|
+
reason: string;
|
|
338
|
+
trigger: AutoSummarizeTrigger | undefined;
|
|
339
|
+
tokenCount: number;
|
|
340
|
+
toolsUsed: number;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Create an AutoSummarizeService with default options.
|
|
345
|
+
*/
|
|
346
|
+
export function createAutoSummarizeService(
|
|
347
|
+
options?: AutoSummarizeServiceOptions,
|
|
348
|
+
): AutoSummarizeService {
|
|
349
|
+
return new AutoSummarizeService(options);
|
|
350
|
+
}
|
|
@@ -24,6 +24,7 @@ import { directTeamAndWorkflowFromRun } from "./direct-run.ts";
|
|
|
24
24
|
import { expandParallelResearchWorkflow } from "./parallel-research.ts";
|
|
25
25
|
import { writeAsyncStartMarker } from "./async-marker.ts";
|
|
26
26
|
import { startParentGuard, stopParentGuard } from "./parent-guard.ts";
|
|
27
|
+
import { logInternalError } from "../utils/internal-error.ts";
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* Heartbeat mechanism: periodically write a heartbeat file so the stale reconciler
|
|
@@ -127,6 +128,8 @@ function setupUnhandledRejectionGuard(state: { cwd?: string; runId?: string; eve
|
|
|
127
128
|
}
|
|
128
129
|
|
|
129
130
|
async function main(): Promise<void> {
|
|
131
|
+
// FIX: Store logFd so it can be closed on exit to prevent file descriptor leak
|
|
132
|
+
let logFd: number | undefined;
|
|
130
133
|
// Redirect console to background.log since stdio is "ignore" in detached mode.
|
|
131
134
|
// Must be BEFORE any console.log/console.error calls.
|
|
132
135
|
const _cwd = argValue("--cwd");
|
|
@@ -134,13 +137,17 @@ async function main(): Promise<void> {
|
|
|
134
137
|
if (_cwd && _runId) {
|
|
135
138
|
try {
|
|
136
139
|
const logPath = path.join(_cwd, ".crew/state/runs", _runId, "background.log");
|
|
137
|
-
|
|
140
|
+
logFd = fs.openSync(logPath, "a");
|
|
138
141
|
const origWrite = (prefix: string) => (data: any, ...args: any[]) => {
|
|
139
142
|
const msg = [data, ...args].map(String).join(" ") + "\n";
|
|
140
|
-
fs.writeSync(logFd
|
|
143
|
+
fs.writeSync(logFd!, msg);
|
|
141
144
|
};
|
|
142
145
|
console.log = origWrite("OUT");
|
|
143
146
|
console.error = origWrite("ERR");
|
|
147
|
+
// FIX: Close logFd on process exit to prevent file descriptor leak
|
|
148
|
+
process.on("exit", () => {
|
|
149
|
+
try { if (logFd !== undefined) fs.closeSync(logFd); } catch { /* ignore */ }
|
|
150
|
+
});
|
|
144
151
|
} catch { /* best-effort */ }
|
|
145
152
|
}
|
|
146
153
|
|
|
@@ -317,7 +324,7 @@ async function main(): Promise<void> {
|
|
|
317
324
|
if (loaded) {
|
|
318
325
|
// LAZY: live-agent-manager only needed on failure cleanup path; avoid module load at hot path.
|
|
319
326
|
const { terminateLiveAgentsForRun } = await import("./live-agent-manager.ts");
|
|
320
|
-
void terminateLiveAgentsForRun(loaded.manifest.runId, "failed", appendEvent, loaded.manifest.eventsPath).catch(() => {});
|
|
327
|
+
void terminateLiveAgentsForRun(loaded.manifest.runId, "failed", appendEvent, loaded.manifest.eventsPath).catch((error) => logInternalError("background-runner.terminate", error, `runId=${loaded.manifest.runId}`));
|
|
321
328
|
}
|
|
322
329
|
} catch { /* best-effort */ }
|
|
323
330
|
const message = error instanceof Error ? error.message : String(error);
|