@northflare/runner 0.0.19 → 0.0.20
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/bin/northflare-runner +17 -3
- package/dist/components/claude-sdk-manager.d.ts +6 -3
- package/dist/components/claude-sdk-manager.d.ts.map +1 -1
- package/dist/components/claude-sdk-manager.js +62 -42
- package/dist/components/claude-sdk-manager.js.map +1 -1
- package/dist/components/codex-sdk-manager.d.ts +6 -3
- package/dist/components/codex-sdk-manager.d.ts.map +1 -1
- package/dist/components/codex-sdk-manager.js +60 -16
- package/dist/components/codex-sdk-manager.js.map +1 -1
- package/dist/components/enhanced-repository-manager.d.ts.map +1 -1
- package/dist/components/enhanced-repository-manager.js +2 -1
- package/dist/components/enhanced-repository-manager.js.map +1 -1
- package/dist/components/message-handler-sse.d.ts.map +1 -1
- package/dist/components/message-handler-sse.js +157 -116
- package/dist/components/message-handler-sse.js.map +1 -1
- package/dist/components/northflare-agent-sdk-manager.d.ts +10 -6
- package/dist/components/northflare-agent-sdk-manager.d.ts.map +1 -1
- package/dist/components/northflare-agent-sdk-manager.js +350 -98
- package/dist/components/northflare-agent-sdk-manager.js.map +1 -1
- package/dist/components/repository-manager.d.ts.map +1 -1
- package/dist/components/repository-manager.js +2 -1
- package/dist/components/repository-manager.js.map +1 -1
- package/dist/runner-sse.d.ts.map +1 -1
- package/dist/runner-sse.js +7 -0
- package/dist/runner-sse.js.map +1 -1
- package/dist/types/claude.d.ts +4 -1
- package/dist/types/claude.d.ts.map +1 -1
- package/dist/utils/console.d.ts +5 -8
- package/dist/utils/console.d.ts.map +1 -1
- package/dist/utils/console.js +28 -10
- package/dist/utils/console.js.map +1 -1
- package/dist/utils/debug.d.ts +10 -0
- package/dist/utils/debug.d.ts.map +1 -1
- package/dist/utils/debug.js +86 -8
- package/dist/utils/debug.js.map +1 -1
- package/dist/utils/logger.d.ts +2 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +43 -13
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/message-log.d.ts +23 -0
- package/dist/utils/message-log.d.ts.map +1 -0
- package/dist/utils/message-log.js +69 -0
- package/dist/utils/message-log.js.map +1 -0
- package/dist/utils/status-line.d.ts +5 -1
- package/dist/utils/status-line.d.ts.map +1 -1
- package/dist/utils/status-line.js +13 -3
- package/dist/utils/status-line.js.map +1 -1
- package/package.json +1 -2
|
@@ -4,10 +4,14 @@
|
|
|
4
4
|
import { SSEClient } from '../services/SSEClient.js';
|
|
5
5
|
import { RunnerAPIClient } from '../services/RunnerAPIClient.js';
|
|
6
6
|
import { statusLineManager } from '../utils/status-line.js';
|
|
7
|
-
import { console } from '../utils/console.js';
|
|
8
7
|
import { createLogger } from '../utils/logger.js';
|
|
9
|
-
import {
|
|
10
|
-
|
|
8
|
+
import { isDebugEnabledFor } from '../utils/debug.js';
|
|
9
|
+
import { buildIncomingMessageLog, messageFlowLogger, messagesDebugEnabled, } from '../utils/message-log.js';
|
|
10
|
+
const logger = createLogger("MessageHandler", "rpc");
|
|
11
|
+
const sseLogger = createLogger("MessageHandler:SSE", "sse");
|
|
12
|
+
// Use getters so debug state is checked at call time, not module load time
|
|
13
|
+
const rpcDebugEnabled = () => isDebugEnabledFor("rpc");
|
|
14
|
+
const sseDebugEnabled = () => isDebugEnabledFor("sse");
|
|
11
15
|
export class MessageHandler {
|
|
12
16
|
methodHandlers;
|
|
13
17
|
runner;
|
|
@@ -22,7 +26,9 @@ export class MessageHandler {
|
|
|
22
26
|
this.registerHandlers();
|
|
23
27
|
}
|
|
24
28
|
async startProcessing() {
|
|
25
|
-
|
|
29
|
+
logger.info("Starting message processing with SSE", {
|
|
30
|
+
runnerId: this.runner.getRunnerId(),
|
|
31
|
+
});
|
|
26
32
|
if (this.isProcessing) {
|
|
27
33
|
logger.warn("Message processing already started");
|
|
28
34
|
return;
|
|
@@ -39,7 +45,7 @@ export class MessageHandler {
|
|
|
39
45
|
await this.connectSSE();
|
|
40
46
|
}
|
|
41
47
|
async stopProcessing() {
|
|
42
|
-
|
|
48
|
+
logger.info("Stopping message processing");
|
|
43
49
|
this.isProcessing = false;
|
|
44
50
|
// Stop SSE client
|
|
45
51
|
if (this.sseClient) {
|
|
@@ -58,22 +64,21 @@ export class MessageHandler {
|
|
|
58
64
|
logger.debug("No lastProcessedAt timestamp, skipping catch-up");
|
|
59
65
|
return;
|
|
60
66
|
}
|
|
61
|
-
|
|
67
|
+
logger.info("Catching up on messages", {
|
|
68
|
+
since: lastProcessedAt.toISOString(),
|
|
69
|
+
});
|
|
62
70
|
try {
|
|
63
71
|
const messages = await this.apiClient.fetchMissedMessages({
|
|
64
72
|
since: lastProcessedAt,
|
|
65
73
|
limit: 1000,
|
|
66
74
|
});
|
|
67
75
|
if (messages.length > 0) {
|
|
68
|
-
|
|
76
|
+
logger.info("Processing missed messages", { count: messages.length });
|
|
69
77
|
// Process messages in order
|
|
70
78
|
for (const message of messages) {
|
|
71
79
|
await this.processMessage(message);
|
|
72
80
|
}
|
|
73
81
|
}
|
|
74
|
-
else {
|
|
75
|
-
console.log("MessageHandler: No missed messages to process");
|
|
76
|
-
}
|
|
77
82
|
}
|
|
78
83
|
catch (error) {
|
|
79
84
|
logger.error("Failed to catch up on missed messages:", error);
|
|
@@ -92,7 +97,7 @@ export class MessageHandler {
|
|
|
92
97
|
if (!token) {
|
|
93
98
|
throw new Error("Missing NORTHFLARE_RUNNER_TOKEN");
|
|
94
99
|
}
|
|
95
|
-
|
|
100
|
+
logger.info("Connecting to SSE endpoint", { runnerId });
|
|
96
101
|
this.sseClient = new SSEClient({
|
|
97
102
|
url: `${this.runner.config_.orchestratorUrl}/api/runner-events`,
|
|
98
103
|
runnerId,
|
|
@@ -102,10 +107,10 @@ export class MessageHandler {
|
|
|
102
107
|
logger.error("SSE connection error:", error);
|
|
103
108
|
},
|
|
104
109
|
onConnect: () => {
|
|
105
|
-
|
|
110
|
+
sseLogger.info("SSE connection established", { runnerId });
|
|
106
111
|
},
|
|
107
112
|
onDisconnect: () => {
|
|
108
|
-
|
|
113
|
+
sseLogger.info("SSE connection closed", { runnerId });
|
|
109
114
|
},
|
|
110
115
|
reconnectInterval: 1000,
|
|
111
116
|
maxReconnectInterval: 30000,
|
|
@@ -121,8 +126,8 @@ export class MessageHandler {
|
|
|
121
126
|
async handleSSEEvent(event) {
|
|
122
127
|
if (event.type === "runner.message") {
|
|
123
128
|
const message = event.data;
|
|
124
|
-
if (
|
|
125
|
-
|
|
129
|
+
if (sseDebugEnabled()) {
|
|
130
|
+
sseLogger.debug("Received SSE event", {
|
|
126
131
|
eventId: event.id,
|
|
127
132
|
type: event.type,
|
|
128
133
|
messageId: message?.id,
|
|
@@ -142,14 +147,14 @@ export class MessageHandler {
|
|
|
142
147
|
}
|
|
143
148
|
}
|
|
144
149
|
else if (event.type === "connection.established") {
|
|
145
|
-
|
|
150
|
+
sseLogger.debug("SSE connection established", event.data);
|
|
146
151
|
}
|
|
147
152
|
else {
|
|
148
|
-
|
|
153
|
+
sseLogger.debug(`Received event type: ${event.type}`, event.data);
|
|
149
154
|
}
|
|
150
155
|
}
|
|
151
156
|
async processMessage(message) {
|
|
152
|
-
if (
|
|
157
|
+
if (rpcDebugEnabled()) {
|
|
153
158
|
logger.debug("processMessage called", {
|
|
154
159
|
messageId: message.id,
|
|
155
160
|
method: message.payload?.method,
|
|
@@ -161,6 +166,9 @@ export class MessageHandler {
|
|
|
161
166
|
if (this.processedMessages.has(message.id)) {
|
|
162
167
|
return;
|
|
163
168
|
}
|
|
169
|
+
if (messagesDebugEnabled()) {
|
|
170
|
+
messageFlowLogger.debug("[incoming] orchestrator -> runner", buildIncomingMessageLog(message));
|
|
171
|
+
}
|
|
164
172
|
// Check if we should process this message based on ownership
|
|
165
173
|
if (!this.shouldProcessMessage(message)) {
|
|
166
174
|
return;
|
|
@@ -175,7 +183,7 @@ export class MessageHandler {
|
|
|
175
183
|
await this.sendError(message, `Unknown method: ${method}`);
|
|
176
184
|
return;
|
|
177
185
|
}
|
|
178
|
-
if (
|
|
186
|
+
if (rpcDebugEnabled()) {
|
|
179
187
|
logger.debug("Processing message", {
|
|
180
188
|
messageId: message.id,
|
|
181
189
|
method: method,
|
|
@@ -188,7 +196,7 @@ export class MessageHandler {
|
|
|
188
196
|
await this.markProcessed(message);
|
|
189
197
|
// Acknowledge ALL messages to update lastProcessedAt
|
|
190
198
|
await this.acknowledgeMessage(message);
|
|
191
|
-
if (
|
|
199
|
+
if (rpcDebugEnabled()) {
|
|
192
200
|
logger.debug("Message acknowledged", {
|
|
193
201
|
messageId: message.id,
|
|
194
202
|
method: method,
|
|
@@ -198,7 +206,7 @@ export class MessageHandler {
|
|
|
198
206
|
}
|
|
199
207
|
}
|
|
200
208
|
catch (error) {
|
|
201
|
-
if (
|
|
209
|
+
if (rpcDebugEnabled()) {
|
|
202
210
|
logger.debug("Message processing error", {
|
|
203
211
|
messageId: message.id,
|
|
204
212
|
method: method,
|
|
@@ -248,7 +256,7 @@ export class MessageHandler {
|
|
|
248
256
|
reason: "active runner, message after watermark",
|
|
249
257
|
};
|
|
250
258
|
})();
|
|
251
|
-
if (
|
|
259
|
+
if (rpcDebugEnabled()) {
|
|
252
260
|
logger.debug("Message processing decision", {
|
|
253
261
|
messageId: message.id,
|
|
254
262
|
method: message.payload?.method,
|
|
@@ -274,17 +282,24 @@ export class MessageHandler {
|
|
|
274
282
|
}
|
|
275
283
|
async acknowledgeMessage(message) {
|
|
276
284
|
const runnerId = this.runner.getRunnerId();
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
285
|
+
if (rpcDebugEnabled()) {
|
|
286
|
+
logger.debug("Sending message.acknowledge", {
|
|
287
|
+
runnerId,
|
|
288
|
+
messageTimestamp: message.createdAt,
|
|
289
|
+
messageId: message.id,
|
|
290
|
+
method: message.payload?.method,
|
|
291
|
+
});
|
|
292
|
+
}
|
|
283
293
|
try {
|
|
284
294
|
await this.apiClient.acknowledgeMessage(message.createdAt);
|
|
285
295
|
// Update local lastProcessedAt
|
|
286
296
|
await this.runner.updateLastProcessedAt(new Date(message.createdAt));
|
|
287
|
-
|
|
297
|
+
if (rpcDebugEnabled()) {
|
|
298
|
+
logger.debug("message.acknowledge sent", {
|
|
299
|
+
runnerId,
|
|
300
|
+
messageId: message.id,
|
|
301
|
+
});
|
|
302
|
+
}
|
|
288
303
|
}
|
|
289
304
|
catch (error) {
|
|
290
305
|
logger.error("Failed to acknowledge message:", error);
|
|
@@ -300,15 +315,12 @@ export class MessageHandler {
|
|
|
300
315
|
const conversationObjectType = message.conversationObjectType || (message.taskId ? "Task" : undefined);
|
|
301
316
|
const conversationObjectId = message.conversationObjectId || message.taskId;
|
|
302
317
|
if (!conversationObjectId) {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
runnerId: message.runnerId,
|
|
310
|
-
});
|
|
311
|
-
}
|
|
318
|
+
logger.warn("Cannot send error report - missing conversationObjectId", {
|
|
319
|
+
messageId: message.id,
|
|
320
|
+
method: message.payload?.method,
|
|
321
|
+
error: errorMessage,
|
|
322
|
+
runnerId: message.runnerId,
|
|
323
|
+
});
|
|
312
324
|
return;
|
|
313
325
|
}
|
|
314
326
|
await this.runner.notify("error.report", {
|
|
@@ -330,16 +342,13 @@ export class MessageHandler {
|
|
|
330
342
|
const conversationObjectType = message.conversationObjectType || (message.taskId ? "Task" : undefined);
|
|
331
343
|
const conversationObjectId = message.conversationObjectId || message.taskId;
|
|
332
344
|
if (!conversationObjectId) {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
runnerId: message.runnerId,
|
|
341
|
-
});
|
|
342
|
-
}
|
|
345
|
+
logger.warn("Cannot send processing error report - missing conversationObjectId", {
|
|
346
|
+
messageId: message.id,
|
|
347
|
+
method: message.payload?.method,
|
|
348
|
+
error: errorMessage,
|
|
349
|
+
stack: errorStack,
|
|
350
|
+
runnerId: message.runnerId,
|
|
351
|
+
});
|
|
343
352
|
return;
|
|
344
353
|
}
|
|
345
354
|
await this.runner.notify("error.report", {
|
|
@@ -356,7 +365,7 @@ export class MessageHandler {
|
|
|
356
365
|
});
|
|
357
366
|
}
|
|
358
367
|
registerHandlers() {
|
|
359
|
-
|
|
368
|
+
logger.info("Registering message handlers");
|
|
360
369
|
this.methodHandlers = new Map([
|
|
361
370
|
["conversation.start", this.handleConversationStart.bind(this)],
|
|
362
371
|
["conversation.stop", this.handleConversationStop.bind(this)],
|
|
@@ -387,34 +396,37 @@ export class MessageHandler {
|
|
|
387
396
|
if (!finalObjectId) {
|
|
388
397
|
throw new Error("Missing conversationObjectId");
|
|
389
398
|
}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
399
|
+
if (rpcDebugEnabled()) {
|
|
400
|
+
// Debug log the config
|
|
401
|
+
logger.debug("conversation.start config", {
|
|
402
|
+
conversationObjectId,
|
|
403
|
+
hasConfig: !!config,
|
|
404
|
+
hasRepository: !!config?.repository,
|
|
405
|
+
repositoryType: config?.repository?.type,
|
|
406
|
+
repositoryUrl: config?.repository?.url,
|
|
407
|
+
workspaceId: config?.workspaceId,
|
|
408
|
+
fullConfig: JSON.stringify(config, null, 2),
|
|
409
|
+
});
|
|
410
|
+
logger.debug("Received conversation instructions", {
|
|
411
|
+
conversationId: conversationData.id,
|
|
412
|
+
hasWorkspaceInstructions: !!conversationData.workspaceInstructions,
|
|
413
|
+
workspaceInstructionsLength: conversationData.workspaceInstructions?.length ?? 0,
|
|
414
|
+
workspaceInstructionsPreview: conversationData.workspaceInstructions?.slice(0, 100),
|
|
415
|
+
hasGlobalInstructions: !!conversationData.globalInstructions,
|
|
416
|
+
globalInstructionsLength: conversationData.globalInstructions?.length ?? 0,
|
|
417
|
+
});
|
|
418
|
+
}
|
|
409
419
|
// Check if conversation is already active (prevent duplicate starts on catch-up)
|
|
410
420
|
const conversationId = conversationData.id;
|
|
411
421
|
if (this.runner.activeConversations_.has(conversationId)) {
|
|
412
|
-
|
|
422
|
+
logger.info("Conversation already active, skipping duplicate start", {
|
|
423
|
+
conversationId,
|
|
424
|
+
});
|
|
413
425
|
return;
|
|
414
426
|
}
|
|
415
427
|
// Check if this conversation was recently completed (prevent restart on catch-up)
|
|
416
428
|
if (this.runner.wasConversationCompleted(conversationId)) {
|
|
417
|
-
|
|
429
|
+
logger.info("Conversation already completed recently, skipping restart", { conversationId });
|
|
418
430
|
return;
|
|
419
431
|
}
|
|
420
432
|
const provider = this.resolveAgentProvider(conversationData, config);
|
|
@@ -433,15 +445,17 @@ export class MessageHandler {
|
|
|
433
445
|
async handleConversationStop(params, message) {
|
|
434
446
|
// Require conversationId (present at message level); do not fall back to agentSessionId/taskId
|
|
435
447
|
const { conversationId = message.conversationId, reason } = params;
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
448
|
+
if (rpcDebugEnabled()) {
|
|
449
|
+
logger.debug("handleConversationStop invoked", {
|
|
450
|
+
conversationId,
|
|
451
|
+
messageConversationId: message.conversationId,
|
|
452
|
+
agentSessionId: params?.agentSessionId,
|
|
453
|
+
taskId: params?.taskId,
|
|
454
|
+
params: JSON.stringify(params),
|
|
455
|
+
activeConversations: this.runner.activeConversations_.size,
|
|
456
|
+
conversationIds: Array.from(this.runner.activeConversations_.keys()),
|
|
457
|
+
});
|
|
458
|
+
}
|
|
445
459
|
// Lookup strictly by conversationId
|
|
446
460
|
let context;
|
|
447
461
|
let targetConversationId;
|
|
@@ -449,12 +463,14 @@ export class MessageHandler {
|
|
|
449
463
|
context = this.runner.getConversationContext(conversationId);
|
|
450
464
|
targetConversationId = conversationId;
|
|
451
465
|
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
466
|
+
if (rpcDebugEnabled()) {
|
|
467
|
+
logger.debug("handleConversationStop lookup", {
|
|
468
|
+
contextFound: !!context,
|
|
469
|
+
targetConversationId,
|
|
470
|
+
contextTaskId: context?.taskId,
|
|
471
|
+
contextAgentSessionId: context?.agentSessionId,
|
|
472
|
+
});
|
|
473
|
+
}
|
|
458
474
|
// Check if we have any identifier to work with
|
|
459
475
|
if (!conversationId) {
|
|
460
476
|
throw new Error("Missing required parameter: conversationId");
|
|
@@ -473,7 +489,9 @@ export class MessageHandler {
|
|
|
473
489
|
else {
|
|
474
490
|
// No conversation found - this is expected as conversations may have already ended
|
|
475
491
|
// or been cleaned up. Just log it and update status line.
|
|
476
|
-
|
|
492
|
+
logger.info("Conversation stop requested but not found", {
|
|
493
|
+
conversationId,
|
|
494
|
+
});
|
|
477
495
|
// If we have a targetConversationId, ensure it's removed from tracking
|
|
478
496
|
if (targetConversationId) {
|
|
479
497
|
this.runner.activeConversations_.delete(targetConversationId);
|
|
@@ -508,12 +526,14 @@ export class MessageHandler {
|
|
|
508
526
|
}
|
|
509
527
|
async handleConversationConfig(params, message) {
|
|
510
528
|
const { conversationId, model, permissionsMode, config } = params;
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
529
|
+
if (rpcDebugEnabled()) {
|
|
530
|
+
logger.debug("handleConversationConfig invoked", {
|
|
531
|
+
conversationId,
|
|
532
|
+
model,
|
|
533
|
+
permissionsMode,
|
|
534
|
+
hasConfig: !!config,
|
|
535
|
+
});
|
|
536
|
+
}
|
|
517
537
|
// Find the active conversation by conversationId only
|
|
518
538
|
let context;
|
|
519
539
|
if (conversationId) {
|
|
@@ -533,14 +553,18 @@ export class MessageHandler {
|
|
|
533
553
|
...(permissionsMode && { permissionsMode }),
|
|
534
554
|
...config, // Allow full config overrides if provided
|
|
535
555
|
};
|
|
536
|
-
|
|
556
|
+
logger.info("Stopping conversation to apply new config", {
|
|
557
|
+
conversationId: context.conversationId,
|
|
558
|
+
});
|
|
537
559
|
// Stop the current conversation
|
|
538
560
|
const manager = this.getManagerForConversationContext(context);
|
|
539
561
|
await manager.stopConversation(context.agentSessionId, context, false // Not a runner shutdown, just updating config
|
|
540
562
|
);
|
|
541
563
|
// Remove from active conversations
|
|
542
564
|
this.runner.activeConversations_.delete(context.conversationId);
|
|
543
|
-
|
|
565
|
+
logger.info("Resuming conversation with updated config", {
|
|
566
|
+
conversationId: context.conversationId,
|
|
567
|
+
});
|
|
544
568
|
// Resume with new config
|
|
545
569
|
// For CodexManager (openai) we pass the provider to distinguish
|
|
546
570
|
const contextProvider = context.provider?.toLowerCase();
|
|
@@ -570,7 +594,9 @@ export class MessageHandler {
|
|
|
570
594
|
}
|
|
571
595
|
// Update status line
|
|
572
596
|
statusLineManager.updateActiveCount(this.runner.activeConversations_.size);
|
|
573
|
-
|
|
597
|
+
logger.info("Conversation config updated", {
|
|
598
|
+
conversationId: context.conversationId,
|
|
599
|
+
});
|
|
574
600
|
}
|
|
575
601
|
async handleUserMessage(params, message) {
|
|
576
602
|
const { conversationId, content, config, conversationObjectType = message.conversationObjectType || "Task", conversationObjectId = message.conversationObjectId, conversation, agentSessionId, } = params;
|
|
@@ -596,8 +622,11 @@ export class MessageHandler {
|
|
|
596
622
|
}
|
|
597
623
|
async handleUidChanged(params, _message) {
|
|
598
624
|
const { runnerUid, lastProcessedAt } = params;
|
|
599
|
-
|
|
600
|
-
|
|
625
|
+
logger.info("Handling UID change notification", {
|
|
626
|
+
runnerUid,
|
|
627
|
+
lastProcessedAt,
|
|
628
|
+
});
|
|
629
|
+
if (rpcDebugEnabled()) {
|
|
601
630
|
logger.debug("UID change notification received", {
|
|
602
631
|
newUid: runnerUid,
|
|
603
632
|
currentUid: this.runner.getRunnerUid(),
|
|
@@ -611,10 +640,12 @@ export class MessageHandler {
|
|
|
611
640
|
// This ensures we activate even if we received the message during catch-up
|
|
612
641
|
if (runnerUid === this.runner.getRunnerUid()) {
|
|
613
642
|
// This is our UID - we're the active runner
|
|
614
|
-
|
|
643
|
+
logger.info("Runner activated as primary", {
|
|
644
|
+
runnerUid,
|
|
645
|
+
});
|
|
615
646
|
this.runner.setIsActiveRunner(true);
|
|
616
647
|
await this.runner.updateLastProcessedAt(lastProcessedAt ? new Date(lastProcessedAt) : null);
|
|
617
|
-
if (
|
|
648
|
+
if (rpcDebugEnabled()) {
|
|
618
649
|
logger.debug("Runner activated as primary", {
|
|
619
650
|
runnerUid: runnerUid,
|
|
620
651
|
lastProcessedAt: lastProcessedAt,
|
|
@@ -629,15 +660,17 @@ export class MessageHandler {
|
|
|
629
660
|
});
|
|
630
661
|
}
|
|
631
662
|
catch (error) {
|
|
632
|
-
|
|
633
|
-
if (
|
|
663
|
+
logger.error("Failed to send activation notification", error);
|
|
664
|
+
if (rpcDebugEnabled()) {
|
|
634
665
|
logger.debug("Activation notification failed", {
|
|
635
666
|
error: error instanceof Error ? error.message : String(error),
|
|
636
667
|
});
|
|
637
668
|
}
|
|
638
669
|
}
|
|
639
670
|
// Start processing messages from the lastProcessedAt point
|
|
640
|
-
|
|
671
|
+
logger.info("Activation complete; setting message watermark", {
|
|
672
|
+
after: lastProcessedAt || "beginning",
|
|
673
|
+
});
|
|
641
674
|
}
|
|
642
675
|
else {
|
|
643
676
|
// Different UID - check if this is an old UID change that we should ignore
|
|
@@ -645,8 +678,11 @@ export class MessageHandler {
|
|
|
645
678
|
if (currentLastProcessedAt && lastProcessedAt) {
|
|
646
679
|
const newTime = new Date(lastProcessedAt);
|
|
647
680
|
if (newTime < currentLastProcessedAt) {
|
|
648
|
-
|
|
649
|
-
|
|
681
|
+
logger.info("Ignoring old UID change", {
|
|
682
|
+
lastProcessedAt,
|
|
683
|
+
currentLastProcessedAt: currentLastProcessedAt.toISOString(),
|
|
684
|
+
});
|
|
685
|
+
if (rpcDebugEnabled()) {
|
|
650
686
|
logger.debug("Ignoring old UID change", {
|
|
651
687
|
newUid: runnerUid,
|
|
652
688
|
newLastProcessedAt: lastProcessedAt,
|
|
@@ -657,7 +693,7 @@ export class MessageHandler {
|
|
|
657
693
|
}
|
|
658
694
|
}
|
|
659
695
|
// Different UID - we're being replaced
|
|
660
|
-
|
|
696
|
+
logger.info("Runner deactivated; replacement detected", { runnerUid });
|
|
661
697
|
this.runner.setIsActiveRunner(false);
|
|
662
698
|
// Remember which conversations were active before handoff (by conversationId)
|
|
663
699
|
for (const [conversationId, context] of this.runner
|
|
@@ -666,7 +702,7 @@ export class MessageHandler {
|
|
|
666
702
|
this.runner.getPreHandoffConversations().add(conversationId);
|
|
667
703
|
}
|
|
668
704
|
}
|
|
669
|
-
if (
|
|
705
|
+
if (rpcDebugEnabled()) {
|
|
670
706
|
logger.debug("Runner deactivated - being replaced", {
|
|
671
707
|
newRunnerUid: runnerUid,
|
|
672
708
|
ourUid: this.runner.getRunnerUid(),
|
|
@@ -674,7 +710,9 @@ export class MessageHandler {
|
|
|
674
710
|
activeConversationsCount: this.runner.getPreHandoffConversations().size,
|
|
675
711
|
});
|
|
676
712
|
}
|
|
677
|
-
|
|
713
|
+
logger.info("Runner replacement: completing active conversations", {
|
|
714
|
+
activeConversationCount: this.runner.getPreHandoffConversations().size,
|
|
715
|
+
});
|
|
678
716
|
// Emit deactivation notification - wrap in try/catch to handle failures gracefully
|
|
679
717
|
try {
|
|
680
718
|
await this.runner.notify("runner.deactivate", {
|
|
@@ -684,8 +722,8 @@ export class MessageHandler {
|
|
|
684
722
|
});
|
|
685
723
|
}
|
|
686
724
|
catch (error) {
|
|
687
|
-
|
|
688
|
-
if (
|
|
725
|
+
logger.error("Failed to send deactivation notification", error);
|
|
726
|
+
if (rpcDebugEnabled()) {
|
|
689
727
|
logger.debug("Deactivation notification failed", {
|
|
690
728
|
error: error instanceof Error ? error.message : String(error),
|
|
691
729
|
});
|
|
@@ -698,7 +736,7 @@ export class MessageHandler {
|
|
|
698
736
|
if (!taskId || !operation) {
|
|
699
737
|
throw new Error("Missing required parameters: taskId and operation");
|
|
700
738
|
}
|
|
701
|
-
|
|
739
|
+
logger.info("Handling Git operation", { operation, taskId });
|
|
702
740
|
const repoManager = this.runner.repositoryManager_;
|
|
703
741
|
try {
|
|
704
742
|
switch (operation) {
|
|
@@ -718,7 +756,7 @@ export class MessageHandler {
|
|
|
718
756
|
break;
|
|
719
757
|
case "push":
|
|
720
758
|
// TODO: Implement push operation
|
|
721
|
-
|
|
759
|
+
logger.warn("Git push operation not yet implemented", { taskId });
|
|
722
760
|
break;
|
|
723
761
|
case "rebase":
|
|
724
762
|
if (!opParams?.targetBranch) {
|
|
@@ -741,7 +779,10 @@ export class MessageHandler {
|
|
|
741
779
|
}
|
|
742
780
|
}
|
|
743
781
|
catch (error) {
|
|
744
|
-
|
|
782
|
+
logger.error(`Git operation ${operation} failed`, {
|
|
783
|
+
taskId,
|
|
784
|
+
error,
|
|
785
|
+
});
|
|
745
786
|
await this.recordGitOperation(taskId, operation, "failed", {
|
|
746
787
|
error: error instanceof Error ? error.message : String(error),
|
|
747
788
|
});
|
|
@@ -753,14 +794,14 @@ export class MessageHandler {
|
|
|
753
794
|
if (!taskId) {
|
|
754
795
|
throw new Error("Missing required parameter: taskId");
|
|
755
796
|
}
|
|
756
|
-
|
|
797
|
+
logger.info("Cleaning up Git worktree", { taskId });
|
|
757
798
|
const repoManager = this.runner.repositoryManager_;
|
|
758
799
|
try {
|
|
759
800
|
await repoManager.removeTaskWorktree(taskId, { preserveBranch });
|
|
760
|
-
|
|
801
|
+
logger.info("Git worktree cleaned up", { taskId, preserveBranch });
|
|
761
802
|
}
|
|
762
803
|
catch (error) {
|
|
763
|
-
|
|
804
|
+
logger.error(`Failed to clean up worktree for task ${taskId}`, error);
|
|
764
805
|
throw error;
|
|
765
806
|
}
|
|
766
807
|
}
|
|
@@ -768,7 +809,7 @@ export class MessageHandler {
|
|
|
768
809
|
const repoManager = this.runner.repositoryManager_;
|
|
769
810
|
const gitState = await repoManager.getTaskState(taskId);
|
|
770
811
|
if (!gitState) {
|
|
771
|
-
|
|
812
|
+
logger.warn(`No Git state found for task ${taskId}`);
|
|
772
813
|
return;
|
|
773
814
|
}
|
|
774
815
|
// Send state update to orchestrator
|