@northflare/runner 0.0.12 → 0.0.13
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/package.json +2 -3
- package/coverage/base.css +0 -224
- package/coverage/block-navigation.js +0 -87
- package/coverage/coverage-final.json +0 -12
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +0 -176
- package/coverage/lib/index.html +0 -116
- package/coverage/lib/preload-script.js.html +0 -964
- package/coverage/prettify.css +0 -1
- package/coverage/prettify.js +0 -2
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +0 -196
- package/coverage/src/collections/index.html +0 -116
- package/coverage/src/collections/runner-messages.ts.html +0 -312
- package/coverage/src/components/claude-manager.ts.html +0 -1290
- package/coverage/src/components/index.html +0 -146
- package/coverage/src/components/message-handler.ts.html +0 -730
- package/coverage/src/components/repository-manager.ts.html +0 -841
- package/coverage/src/index.html +0 -131
- package/coverage/src/index.ts.html +0 -448
- package/coverage/src/runner.ts.html +0 -1239
- package/coverage/src/utils/config.ts.html +0 -780
- package/coverage/src/utils/console.ts.html +0 -121
- package/coverage/src/utils/index.html +0 -161
- package/coverage/src/utils/logger.ts.html +0 -475
- package/coverage/src/utils/status-line.ts.html +0 -445
- package/exceptions.log +0 -24
- package/lib/codex-sdk/src/codex.ts +0 -38
- package/lib/codex-sdk/src/codexOptions.ts +0 -10
- package/lib/codex-sdk/src/events.ts +0 -80
- package/lib/codex-sdk/src/exec.ts +0 -336
- package/lib/codex-sdk/src/index.ts +0 -39
- package/lib/codex-sdk/src/items.ts +0 -127
- package/lib/codex-sdk/src/outputSchemaFile.ts +0 -40
- package/lib/codex-sdk/src/thread.ts +0 -155
- package/lib/codex-sdk/src/threadOptions.ts +0 -18
- package/lib/codex-sdk/src/turnOptions.ts +0 -6
- package/lib/codex-sdk/tests/abort.test.ts +0 -165
- package/lib/codex-sdk/tests/codexExecSpy.ts +0 -37
- package/lib/codex-sdk/tests/responsesProxy.ts +0 -225
- package/lib/codex-sdk/tests/run.test.ts +0 -687
- package/lib/codex-sdk/tests/runStreamed.test.ts +0 -211
- package/lib/codex-sdk/tsconfig.json +0 -24
- package/rejections.log +0 -68
- package/runner.log +0 -488
- package/src/components/claude-sdk-manager.ts +0 -1425
- package/src/components/codex-sdk-manager.ts +0 -1358
- package/src/components/enhanced-repository-manager.ts +0 -823
- package/src/components/message-handler-sse.ts +0 -1097
- package/src/components/repository-manager.ts +0 -337
- package/src/index.ts +0 -168
- package/src/runner-sse.ts +0 -917
- package/src/services/RunnerAPIClient.ts +0 -175
- package/src/services/SSEClient.ts +0 -258
- package/src/types/claude.ts +0 -66
- package/src/types/computer-name.d.ts +0 -4
- package/src/types/index.ts +0 -64
- package/src/types/messages.ts +0 -39
- package/src/types/runner-interface.ts +0 -36
- package/src/utils/StateManager.ts +0 -187
- package/src/utils/config.ts +0 -327
- package/src/utils/console.ts +0 -15
- package/src/utils/debug.ts +0 -18
- package/src/utils/expand-env.ts +0 -22
- package/src/utils/logger.ts +0 -134
- package/src/utils/model.ts +0 -29
- package/src/utils/status-line.ts +0 -122
- package/src/utils/tool-response-sanitizer.ts +0 -160
- package/test-debug.sh +0 -26
- package/tests/retry-strategies.test.ts +0 -410
- package/tests/sdk-integration.test.ts +0 -329
- package/tests/sdk-streaming.test.ts +0 -1180
- package/tests/setup.ts +0 -5
- package/tests/test-claude-manager.ts +0 -120
- package/tests/tool-response-sanitizer.test.ts +0 -63
- package/tsconfig.json +0 -36
- package/vitest.config.ts +0 -27
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* HTTP API client for runner-specific endpoints
|
|
3
|
-
*
|
|
4
|
-
* Provides methods to interact with the server's runner API endpoints
|
|
5
|
-
* including fetching missed messages and other runner operations.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { createLogger } from "../utils/logger";
|
|
9
|
-
import { RunnerConfig, RunnerMessage } from "../types";
|
|
10
|
-
|
|
11
|
-
const logger = createLogger("RunnerAPIClient");
|
|
12
|
-
|
|
13
|
-
export interface FetchMissedMessagesOptions {
|
|
14
|
-
since: Date | string;
|
|
15
|
-
limit?: number;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export class RunnerAPIClient {
|
|
19
|
-
private baseUrl: string;
|
|
20
|
-
private token: string;
|
|
21
|
-
private runnerId: string;
|
|
22
|
-
|
|
23
|
-
constructor(config: RunnerConfig) {
|
|
24
|
-
this.baseUrl = config.orchestratorUrl;
|
|
25
|
-
this.token = process.env["NORTHFLARE_RUNNER_TOKEN"] || "";
|
|
26
|
-
this.runnerId = config.runnerId || "";
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Update the runner ID after registration
|
|
31
|
-
*/
|
|
32
|
-
setRunnerId(runnerId: string): void {
|
|
33
|
-
this.runnerId = runnerId;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Fetch missed messages since a given timestamp
|
|
38
|
-
*/
|
|
39
|
-
async fetchMissedMessages(
|
|
40
|
-
options: FetchMissedMessagesOptions
|
|
41
|
-
): Promise<RunnerMessage[]> {
|
|
42
|
-
const since =
|
|
43
|
-
options.since instanceof Date
|
|
44
|
-
? options.since.toISOString()
|
|
45
|
-
: options.since;
|
|
46
|
-
const limit = options.limit || 1000;
|
|
47
|
-
|
|
48
|
-
logger.debug(`Fetching missed messages since ${since} (limit: ${limit})`);
|
|
49
|
-
|
|
50
|
-
try {
|
|
51
|
-
const url = `${this.baseUrl}/api/runner/messages/since`;
|
|
52
|
-
const params = new URLSearchParams({
|
|
53
|
-
since,
|
|
54
|
-
limit: limit.toString(),
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
const response = await fetch(`${url}?${params}`, {
|
|
58
|
-
method: "GET",
|
|
59
|
-
headers: {
|
|
60
|
-
Authorization: `Bearer ${this.token}`,
|
|
61
|
-
"X-Runner-Id": this.runnerId,
|
|
62
|
-
"Content-Type": "application/json",
|
|
63
|
-
},
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
if (!response.ok) {
|
|
67
|
-
const error = await response.text();
|
|
68
|
-
throw new Error(
|
|
69
|
-
`Failed to fetch missed messages: ${response.status} - ${error}`
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const data = (await response.json()) as any;
|
|
74
|
-
|
|
75
|
-
// Transform the raw database records to our internal RunnerMessage format
|
|
76
|
-
const messages: RunnerMessage[] = data.messages.map((msg: any) => ({
|
|
77
|
-
id: msg.id,
|
|
78
|
-
direction: msg.direction,
|
|
79
|
-
runnerId: msg.runner || msg.runnerId,
|
|
80
|
-
taskId: msg.task || msg.taskId || null,
|
|
81
|
-
workspaceId: msg.workspace || msg.workspaceId || null,
|
|
82
|
-
conversationId: msg.conversation || msg.conversationId || null,
|
|
83
|
-
conversationObjectType: msg.conversationObjectType,
|
|
84
|
-
conversationObjectId: msg.conversationObjectId,
|
|
85
|
-
payload: msg.payload,
|
|
86
|
-
expiresAt: msg.expiresAt,
|
|
87
|
-
createdAt: msg.createdAt,
|
|
88
|
-
}));
|
|
89
|
-
|
|
90
|
-
logger.info(`Fetched ${messages.length} missed messages`);
|
|
91
|
-
return messages;
|
|
92
|
-
} catch (error) {
|
|
93
|
-
logger.error("Failed to fetch missed messages:", error);
|
|
94
|
-
throw error;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Send a message acknowledgment to update the high-water mark
|
|
100
|
-
*/
|
|
101
|
-
async acknowledgeMessage(messageTimestamp: string): Promise<void> {
|
|
102
|
-
logger.debug(`Acknowledging message with timestamp: ${messageTimestamp}`);
|
|
103
|
-
|
|
104
|
-
try {
|
|
105
|
-
const response = await fetch(`${this.baseUrl}/api/runner/messages`, {
|
|
106
|
-
method: "POST",
|
|
107
|
-
headers: {
|
|
108
|
-
Authorization: `Bearer ${this.token}`,
|
|
109
|
-
"X-Runner-Id": this.runnerId,
|
|
110
|
-
"Content-Type": "application/json",
|
|
111
|
-
},
|
|
112
|
-
body: JSON.stringify({
|
|
113
|
-
jsonrpc: "2.0",
|
|
114
|
-
method: "message.acknowledge",
|
|
115
|
-
params: {
|
|
116
|
-
runnerId: this.runnerId,
|
|
117
|
-
messageTimestamp,
|
|
118
|
-
},
|
|
119
|
-
}),
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
if (!response.ok) {
|
|
123
|
-
const error = await response.text();
|
|
124
|
-
throw new Error(
|
|
125
|
-
`Failed to acknowledge message: ${response.status} - ${error}`
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
logger.debug("Message acknowledged successfully");
|
|
130
|
-
} catch (error) {
|
|
131
|
-
logger.error("Failed to acknowledge message:", error);
|
|
132
|
-
throw error;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Sync runner repositories with the orchestrator
|
|
138
|
-
*/
|
|
139
|
-
async syncRunnerRepos(
|
|
140
|
-
repos: Array<{ uuid: string; name: string; path: string }>
|
|
141
|
-
): Promise<{ success: boolean; syncedCount: number }> {
|
|
142
|
-
logger.debug(`Syncing ${repos.length} runner repos with orchestrator`);
|
|
143
|
-
|
|
144
|
-
try {
|
|
145
|
-
const response = await fetch(`${this.baseUrl}/api/runner/repos/sync`, {
|
|
146
|
-
method: "POST",
|
|
147
|
-
headers: {
|
|
148
|
-
Authorization: `Bearer ${this.token}`,
|
|
149
|
-
"Content-Type": "application/json",
|
|
150
|
-
},
|
|
151
|
-
body: JSON.stringify({ repos }),
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
if (!response.ok) {
|
|
155
|
-
const error = await response.text();
|
|
156
|
-
throw new Error(
|
|
157
|
-
`Failed to sync runner repos: ${response.status} - ${error}`
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
const data = (await response.json()) as any;
|
|
162
|
-
logger.info(
|
|
163
|
-
`Successfully synced ${data.syncedCount} runner repos with orchestrator`
|
|
164
|
-
);
|
|
165
|
-
|
|
166
|
-
return {
|
|
167
|
-
success: data.success,
|
|
168
|
-
syncedCount: data.syncedCount,
|
|
169
|
-
};
|
|
170
|
-
} catch (error) {
|
|
171
|
-
logger.error("Failed to sync runner repos:", error);
|
|
172
|
-
throw error;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
@@ -1,258 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SSE (Server-Sent Events) Client for real-time message streaming
|
|
3
|
-
*
|
|
4
|
-
* Connects to the server's SSE endpoint to receive real-time runner messages
|
|
5
|
-
* and handles automatic reconnection with exponential backoff.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { createLogger } from '../utils/logger';
|
|
9
|
-
import { RunnerConfig } from '../types';
|
|
10
|
-
import { EventSource as NodeEventSource } from 'eventsource';
|
|
11
|
-
|
|
12
|
-
const logger = createLogger('SSEClient');
|
|
13
|
-
|
|
14
|
-
export interface SSEEvent {
|
|
15
|
-
id?: string;
|
|
16
|
-
type: string;
|
|
17
|
-
data: any;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface SSEClientOptions {
|
|
21
|
-
url: string;
|
|
22
|
-
runnerId: string;
|
|
23
|
-
token: string;
|
|
24
|
-
onMessage: (event: SSEEvent) => void;
|
|
25
|
-
onError?: (error: Error) => void;
|
|
26
|
-
onConnect?: () => void;
|
|
27
|
-
onDisconnect?: () => void;
|
|
28
|
-
reconnectInterval?: number;
|
|
29
|
-
maxReconnectInterval?: number;
|
|
30
|
-
reconnectMultiplier?: number;
|
|
31
|
-
maxReconnectAttempts?: number;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export class SSEClient {
|
|
35
|
-
private eventSource: EventSource | null = null;
|
|
36
|
-
private reconnectTimer: NodeJS.Timeout | null = null;
|
|
37
|
-
private reconnectAttempts = 0;
|
|
38
|
-
private currentReconnectInterval: number;
|
|
39
|
-
private isConnected = false;
|
|
40
|
-
private isStopped = false;
|
|
41
|
-
private lastEventId: string | undefined;
|
|
42
|
-
|
|
43
|
-
constructor(private options: SSEClientOptions) {
|
|
44
|
-
this.currentReconnectInterval = options.reconnectInterval || 1000;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Connect to the SSE endpoint
|
|
49
|
-
*/
|
|
50
|
-
async connect(since?: string): Promise<void> {
|
|
51
|
-
if (this.eventSource) {
|
|
52
|
-
logger.warn('SSE client already connected');
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
this.isStopped = false;
|
|
57
|
-
|
|
58
|
-
try {
|
|
59
|
-
// Build URL with query parameters
|
|
60
|
-
const url = new URL(this.options.url);
|
|
61
|
-
// Include token as query param as a fallback in case proxies strip headers
|
|
62
|
-
url.searchParams.set('token', this.options.token);
|
|
63
|
-
if (since) {
|
|
64
|
-
url.searchParams.set('since', since);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Sanitize token from logs
|
|
68
|
-
const sanitized = new URL(url.toString());
|
|
69
|
-
if (sanitized.searchParams.has('token')) {
|
|
70
|
-
sanitized.searchParams.set('token', '[redacted]');
|
|
71
|
-
}
|
|
72
|
-
logger.info(`Connecting to SSE endpoint: ${sanitized.toString()}`);
|
|
73
|
-
logger.debug(`SSE auth header set: ${this.options.token ? 'yes' : 'no'}`);
|
|
74
|
-
|
|
75
|
-
// Create EventSource with authorization header (Node polyfill supports headers)
|
|
76
|
-
this.eventSource = new (NodeEventSource as any)(url.toString(), {
|
|
77
|
-
headers: {
|
|
78
|
-
'Authorization': `Bearer ${this.options.token}`,
|
|
79
|
-
},
|
|
80
|
-
withCredentials: false,
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
// Set up event listeners
|
|
84
|
-
this.eventSource!.onopen = () => {
|
|
85
|
-
logger.info('SSE connection established');
|
|
86
|
-
this.isConnected = true;
|
|
87
|
-
this.reconnectAttempts = 0;
|
|
88
|
-
this.currentReconnectInterval = this.options.reconnectInterval || 1000;
|
|
89
|
-
|
|
90
|
-
if (this.options.onConnect) {
|
|
91
|
-
this.options.onConnect();
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
this.eventSource!.onmessage = (event: MessageEvent) => {
|
|
96
|
-
try {
|
|
97
|
-
const parsed = JSON.parse(event.data);
|
|
98
|
-
const envelope = parsed && typeof parsed === 'object' ? parsed : { data: parsed };
|
|
99
|
-
const inner = (envelope && 'data' in envelope) ? (envelope as any).data : parsed;
|
|
100
|
-
const sseEvent: SSEEvent = {
|
|
101
|
-
id: (envelope as any).id || (event as any).lastEventId,
|
|
102
|
-
type: (envelope as any).type || (event as any).type || 'message',
|
|
103
|
-
data: inner,
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
// Update last event ID for reconnection
|
|
107
|
-
if (sseEvent.id) {
|
|
108
|
-
this.lastEventId = sseEvent.id;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
this.options.onMessage(sseEvent);
|
|
112
|
-
} catch (error) {
|
|
113
|
-
logger.error('Failed to parse SSE message:', error);
|
|
114
|
-
}
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
this.eventSource!.onerror = (error: Event) => {
|
|
118
|
-
logger.error('SSE connection error:', error);
|
|
119
|
-
this.isConnected = false;
|
|
120
|
-
|
|
121
|
-
if (this.options.onError) {
|
|
122
|
-
this.options.onError(new Error('SSE connection error'));
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Close the connection and attempt reconnection
|
|
126
|
-
this.disconnect();
|
|
127
|
-
|
|
128
|
-
if (!this.isStopped) {
|
|
129
|
-
this.scheduleReconnect();
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
// Listen for specific event types
|
|
134
|
-
this.eventSource!.addEventListener('runner.message', ((event: MessageEvent) => {
|
|
135
|
-
try {
|
|
136
|
-
const parsed = JSON.parse(event.data);
|
|
137
|
-
const envelope = parsed && typeof parsed === 'object' ? parsed : { data: parsed };
|
|
138
|
-
const inner = (envelope && 'data' in envelope) ? (envelope as any).data : parsed;
|
|
139
|
-
const sseEvent: SSEEvent = {
|
|
140
|
-
id: (envelope as any).id || (event as any).lastEventId,
|
|
141
|
-
type: 'runner.message',
|
|
142
|
-
data: inner,
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
// Update last event ID
|
|
146
|
-
if (sseEvent.id) {
|
|
147
|
-
this.lastEventId = sseEvent.id;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
this.options.onMessage(sseEvent);
|
|
151
|
-
} catch (error) {
|
|
152
|
-
logger.error('Failed to parse runner.message event:', error);
|
|
153
|
-
}
|
|
154
|
-
}) as any);
|
|
155
|
-
|
|
156
|
-
// Listen for connection established event
|
|
157
|
-
this.eventSource!.addEventListener('connection.established', ((event: MessageEvent) => {
|
|
158
|
-
logger.debug('Received connection.established event:', event.data);
|
|
159
|
-
}) as any);
|
|
160
|
-
|
|
161
|
-
// Listen for error events
|
|
162
|
-
this.eventSource!.addEventListener('error', ((event: MessageEvent) => {
|
|
163
|
-
logger.error('Received error event from server:', event.data);
|
|
164
|
-
}) as any);
|
|
165
|
-
|
|
166
|
-
// Listen for shutdown events
|
|
167
|
-
this.eventSource!.addEventListener('shutdown', ((event: MessageEvent) => {
|
|
168
|
-
logger.warn('Server is shutting down:', event.data);
|
|
169
|
-
this.stop();
|
|
170
|
-
}) as any);
|
|
171
|
-
|
|
172
|
-
} catch (error) {
|
|
173
|
-
logger.error('Failed to connect to SSE endpoint:', error);
|
|
174
|
-
|
|
175
|
-
if (this.options.onError) {
|
|
176
|
-
this.options.onError(error instanceof Error ? error : new Error(String(error)));
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// Schedule reconnection
|
|
180
|
-
if (!this.isStopped) {
|
|
181
|
-
this.scheduleReconnect();
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Disconnect from the SSE endpoint
|
|
188
|
-
*/
|
|
189
|
-
disconnect(): void {
|
|
190
|
-
if (this.eventSource) {
|
|
191
|
-
this.eventSource.close();
|
|
192
|
-
this.eventSource = null;
|
|
193
|
-
this.isConnected = false;
|
|
194
|
-
|
|
195
|
-
if (this.options.onDisconnect) {
|
|
196
|
-
this.options.onDisconnect();
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// Clear reconnection timer
|
|
201
|
-
if (this.reconnectTimer) {
|
|
202
|
-
clearTimeout(this.reconnectTimer);
|
|
203
|
-
this.reconnectTimer = null;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Stop the client and prevent reconnection
|
|
209
|
-
*/
|
|
210
|
-
stop(): void {
|
|
211
|
-
logger.info('Stopping SSE client');
|
|
212
|
-
this.isStopped = true;
|
|
213
|
-
this.disconnect();
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Schedule a reconnection attempt
|
|
218
|
-
*/
|
|
219
|
-
private scheduleReconnect(): void {
|
|
220
|
-
const maxAttempts = this.options.maxReconnectAttempts || Infinity;
|
|
221
|
-
|
|
222
|
-
if (this.reconnectAttempts >= maxAttempts) {
|
|
223
|
-
logger.error(`Max reconnection attempts (${maxAttempts}) reached. Giving up.`);
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
this.reconnectAttempts++;
|
|
228
|
-
|
|
229
|
-
logger.info(`Scheduling reconnection attempt ${this.reconnectAttempts} in ${this.currentReconnectInterval}ms`);
|
|
230
|
-
|
|
231
|
-
this.reconnectTimer = setTimeout(() => {
|
|
232
|
-
this.connect(this.lastEventId);
|
|
233
|
-
}, this.currentReconnectInterval);
|
|
234
|
-
|
|
235
|
-
// Exponential backoff
|
|
236
|
-
const multiplier = this.options.reconnectMultiplier || 2;
|
|
237
|
-
const maxInterval = this.options.maxReconnectInterval || 60000;
|
|
238
|
-
|
|
239
|
-
this.currentReconnectInterval = Math.min(
|
|
240
|
-
this.currentReconnectInterval * multiplier,
|
|
241
|
-
maxInterval
|
|
242
|
-
);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Check if the client is currently connected
|
|
247
|
-
*/
|
|
248
|
-
isConnectedToServer(): boolean {
|
|
249
|
-
return this.isConnected;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Get the last received event ID
|
|
254
|
-
*/
|
|
255
|
-
getLastEventId(): string | undefined {
|
|
256
|
-
return this.lastEventId;
|
|
257
|
-
}
|
|
258
|
-
}
|
package/src/types/claude.ts
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Types related to Claude SDK integration
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { Conversation } from "@botanicastudios/claude-code-sdk-ts";
|
|
6
|
-
import type { Thread } from "@northflare/codex-sdk";
|
|
7
|
-
|
|
8
|
-
// Repository information passed in conversation config
|
|
9
|
-
export interface RepositoryInfo {
|
|
10
|
-
url: string;
|
|
11
|
-
branch: string;
|
|
12
|
-
commit?: string;
|
|
13
|
-
type?: "github" | "local"; // Repository type
|
|
14
|
-
localPath?: string; // For local repositories
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Extended conversation config with repository info
|
|
18
|
-
export interface ConversationConfig {
|
|
19
|
-
systemPrompt?: string;
|
|
20
|
-
accessToken?: string;
|
|
21
|
-
accessKey?: string; // TODO remove
|
|
22
|
-
workspaceId?: string;
|
|
23
|
-
githubToken?: string;
|
|
24
|
-
anthropicApiKey?: string; // API key provided via runner message
|
|
25
|
-
mcpServers?: Record<string, any>;
|
|
26
|
-
repository?: RepositoryInfo; // Repository details from orchestrator
|
|
27
|
-
sessionId?: string; // For resume operations
|
|
28
|
-
runnerRepoPath?: string; // Path to local runner repo for local workspaces
|
|
29
|
-
codexAuth?: CodexAuthConfig;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Internal conversation tracking
|
|
33
|
-
export interface ConversationContext {
|
|
34
|
-
conversationId: string; // Primary key - our conversation.id from the database
|
|
35
|
-
agentSessionId: string; // SDK session ID (from SDK's onSessionId callback)
|
|
36
|
-
conversationObjectType: "Task" | "TaskPlan";
|
|
37
|
-
conversationObjectId: string;
|
|
38
|
-
taskId?: string; // Optional for non-task conversations
|
|
39
|
-
workspaceId?: string;
|
|
40
|
-
status: "starting" | "active" | "stopping" | "stopped" | "error";
|
|
41
|
-
config: ConversationConfig;
|
|
42
|
-
startedAt: Date;
|
|
43
|
-
lastActivityAt: Date;
|
|
44
|
-
conversation?: Conversation | Thread; // Conversation or Codex thread instance
|
|
45
|
-
provider?: "claude" | "openai" | string;
|
|
46
|
-
metadata?: Record<string, any>;
|
|
47
|
-
|
|
48
|
-
// Additional conversation details from database
|
|
49
|
-
model: string;
|
|
50
|
-
globalInstructions: string;
|
|
51
|
-
workspaceInstructions: string;
|
|
52
|
-
permissionsMode: string;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export interface CodexAuthConfig {
|
|
56
|
-
accessToken: string;
|
|
57
|
-
idToken: string;
|
|
58
|
-
accountId: string;
|
|
59
|
-
lastRefresh?: string | null;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Message type for initial messages
|
|
63
|
-
export interface Message {
|
|
64
|
-
content: string;
|
|
65
|
-
role?: "user" | "assistant";
|
|
66
|
-
}
|
package/src/types/index.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Main type definitions for the runner app
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export * from "./messages";
|
|
6
|
-
export * from "./claude";
|
|
7
|
-
export * from "./runner-interface";
|
|
8
|
-
|
|
9
|
-
// Retry strategy types
|
|
10
|
-
export type RetryStrategy = "none" | "interval" | "exponential";
|
|
11
|
-
|
|
12
|
-
// RunnerRepo type for local runner repos
|
|
13
|
-
export interface RunnerRepo {
|
|
14
|
-
uuid?: string; // UUID for identifying the repo across runner restarts
|
|
15
|
-
name: string;
|
|
16
|
-
path: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Runner configuration (in-memory)
|
|
20
|
-
export interface RunnerConfig {
|
|
21
|
-
runnerId?: string; // Stable external ID from server (for namespacing state/config)
|
|
22
|
-
orchestratorUrl: string; // From process.env.NORTHFLARE_ORCHESTRATOR_URL
|
|
23
|
-
dataDir: string;
|
|
24
|
-
workspaceDir?: string; // Directory for workspace/repository operations
|
|
25
|
-
heartbeatInterval: number;
|
|
26
|
-
retryStrategy: RetryStrategy; // Strategy for registration retries
|
|
27
|
-
retryIntervalSecs: number; // For interval strategy
|
|
28
|
-
retryDurationSecs: number; // Max duration for exponential strategy
|
|
29
|
-
runnerRepos?: RunnerRepo[]; // In-memory: repos for this specific runner session
|
|
30
|
-
// Authentication via environment variable or --token CLI option
|
|
31
|
-
// process.env.NORTHFLARE_RUNNER_TOKEN
|
|
32
|
-
// This token is generated by the server and must be provided
|
|
33
|
-
// either as an environment variable or via the --token CLI flag
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Config file format (on-disk)
|
|
37
|
-
export interface RunnerConfigFile {
|
|
38
|
-
orchestratorUrl?: string;
|
|
39
|
-
dataDir?: string;
|
|
40
|
-
workspaceDir?: string;
|
|
41
|
-
heartbeatInterval?: number;
|
|
42
|
-
retryStrategy?: RetryStrategy;
|
|
43
|
-
retryIntervalSecs?: number;
|
|
44
|
-
retryDurationSecs?: number;
|
|
45
|
-
runnerRepos?: Record<string, RunnerRepo[]>; // On-disk: namespaced by runnerId (stable external ID)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Repository management types
|
|
49
|
-
export interface WorkspaceRepository {
|
|
50
|
-
workspaceId: string;
|
|
51
|
-
repoUrl: string;
|
|
52
|
-
branch: string;
|
|
53
|
-
localPath: string;
|
|
54
|
-
lastAccessed: Date;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Environment configuration
|
|
58
|
-
export interface EnvironmentConfig {
|
|
59
|
-
NORTHFLARE_RUNNER_TOKEN: string;
|
|
60
|
-
NORTHFLARE_WORKSPACE_DIR: string;
|
|
61
|
-
NORTHFLARE_ORCHESTRATOR_URL: string;
|
|
62
|
-
NORTHFLARE_RUNNER_DEBUG?: string;
|
|
63
|
-
DEBUG?: string;
|
|
64
|
-
}
|
package/src/types/messages.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* JSONRPC message types for communication between runner and orchestrator
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export interface JsonRpcMessage {
|
|
6
|
-
jsonrpc: "2.0";
|
|
7
|
-
id?: string | number;
|
|
8
|
-
method?: string;
|
|
9
|
-
params?: any;
|
|
10
|
-
result?: any;
|
|
11
|
-
error?: JsonRpcError;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface JsonRpcError {
|
|
15
|
-
code: number;
|
|
16
|
-
message: string;
|
|
17
|
-
data?: any;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// Messages received from orchestrator via SSE
|
|
21
|
-
export interface RunnerMessage {
|
|
22
|
-
id: string;
|
|
23
|
-
direction: "to_runner" | "to_orchestrator";
|
|
24
|
-
runnerId: string;
|
|
25
|
-
taskId: string | null; // Task ID from orchestrator for correlation (optional)
|
|
26
|
-
workspaceId: string | null; // Workspace ID for workspace-scoped messages
|
|
27
|
-
conversationObjectType?: "Task" | "TaskPlan";
|
|
28
|
-
conversationObjectId?: string;
|
|
29
|
-
conversationId?: string; // Conversation ID for direct conversation management
|
|
30
|
-
payload: JsonRpcMessage;
|
|
31
|
-
createdAt: string;
|
|
32
|
-
expiresAt: string;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Method handler type
|
|
36
|
-
export type MethodHandler = (
|
|
37
|
-
params: any,
|
|
38
|
-
message: RunnerMessage
|
|
39
|
-
) => Promise<void>;
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Interface for RunnerApp to ensure compatibility between different implementations
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { RunnerConfig, ConversationContext, JsonRpcMessage } from './index';
|
|
6
|
-
import { ClaudeManager } from '../components/claude-sdk-manager';
|
|
7
|
-
import { CodexManager } from '../components/codex-sdk-manager';
|
|
8
|
-
import { EnhancedRepositoryManager } from '../components/enhanced-repository-manager';
|
|
9
|
-
|
|
10
|
-
export interface IRunnerApp {
|
|
11
|
-
// Core methods
|
|
12
|
-
notify(method: string, params: any): Promise<void>;
|
|
13
|
-
sendToOrchestrator(message: JsonRpcMessage): Promise<any>;
|
|
14
|
-
|
|
15
|
-
// Conversation management
|
|
16
|
-
getConversationContext(conversationId: string): ConversationContext | undefined;
|
|
17
|
-
|
|
18
|
-
// Configuration and state
|
|
19
|
-
get config_(): RunnerConfig;
|
|
20
|
-
get activeConversations_(): Map<string, ConversationContext>;
|
|
21
|
-
get claudeManager_(): ClaudeManager;
|
|
22
|
-
get codexManager_(): CodexManager;
|
|
23
|
-
get repositoryManager_(): EnhancedRepositoryManager;
|
|
24
|
-
|
|
25
|
-
// Runner state
|
|
26
|
-
getRunnerId(): string | undefined;
|
|
27
|
-
getRunnerUid(): string | null;
|
|
28
|
-
getLastProcessedAt(): Date | null;
|
|
29
|
-
getIsActiveRunner(): boolean;
|
|
30
|
-
setIsActiveRunner(active: boolean): void;
|
|
31
|
-
setLastProcessedAt(timestamp: Date | null): void;
|
|
32
|
-
getPreHandoffConversations(): Set<string>;
|
|
33
|
-
|
|
34
|
-
// Optional methods for SSE implementation
|
|
35
|
-
updateLastProcessedAt?(timestamp: Date | null): Promise<void>;
|
|
36
|
-
}
|