mcp-codex-worker 0.1.11 → 0.1.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/dist/src/execution/base-adapter.d.ts +63 -0
- package/dist/src/execution/base-adapter.js +74 -0
- package/dist/src/execution/base-adapter.js.map +1 -0
- package/dist/src/execution/claude-adapter.d.ts +12 -0
- package/dist/src/execution/claude-adapter.js +23 -0
- package/dist/src/execution/claude-adapter.js.map +1 -0
- package/dist/src/execution/codex-adapter.d.ts +21 -0
- package/dist/src/execution/codex-adapter.js +35 -0
- package/dist/src/execution/codex-adapter.js.map +1 -0
- package/dist/src/execution/codex-pause-flow.d.ts +23 -0
- package/dist/src/execution/codex-pause-flow.js +185 -0
- package/dist/src/execution/codex-pause-flow.js.map +1 -0
- package/dist/src/execution/copilot-adapter.d.ts +12 -0
- package/dist/src/execution/copilot-adapter.js +23 -0
- package/dist/src/execution/copilot-adapter.js.map +1 -0
- package/dist/src/execution/provider-capabilities.d.ts +35 -0
- package/dist/src/execution/provider-capabilities.js +58 -0
- package/dist/src/execution/provider-capabilities.js.map +1 -0
- package/dist/src/execution/provider-registry.d.ts +37 -0
- package/dist/src/execution/provider-registry.js +69 -0
- package/dist/src/execution/provider-registry.js.map +1 -0
- package/dist/src/mcp/resource-renderers.d.ts +25 -0
- package/dist/src/mcp/resource-renderers.js +190 -0
- package/dist/src/mcp/resource-renderers.js.map +1 -0
- package/dist/src/mcp/sep1686-handlers.d.ts +56 -0
- package/dist/src/mcp/sep1686-handlers.js +98 -0
- package/dist/src/mcp/sep1686-handlers.js.map +1 -0
- package/dist/src/mcp/tool-definitions.d.ts +157 -0
- package/dist/src/mcp/tool-definitions.js +242 -0
- package/dist/src/mcp/tool-definitions.js.map +1 -1
- package/dist/src/task/fsm-transitions.d.ts +17 -0
- package/dist/src/task/fsm-transitions.js +66 -0
- package/dist/src/task/fsm-transitions.js.map +1 -0
- package/dist/src/task/task-handle-impl.d.ts +10 -0
- package/dist/src/task/task-handle-impl.js +139 -0
- package/dist/src/task/task-handle-impl.js.map +1 -0
- package/dist/src/task/task-handle.d.ts +88 -0
- package/dist/src/task/task-handle.js +2 -0
- package/dist/src/task/task-handle.js.map +1 -0
- package/dist/src/task/task-manager.d.ts +99 -0
- package/dist/src/task/task-manager.js +246 -0
- package/dist/src/task/task-manager.js.map +1 -0
- package/dist/src/task/task-persistence.d.ts +18 -0
- package/dist/src/task/task-persistence.js +61 -0
- package/dist/src/task/task-persistence.js.map +1 -0
- package/dist/src/task/task-state.d.ts +79 -0
- package/dist/src/task/task-state.js +24 -0
- package/dist/src/task/task-state.js.map +1 -0
- package/dist/src/task/task-store.d.ts +46 -0
- package/dist/src/task/task-store.js +104 -0
- package/dist/src/task/task-store.js.map +1 -0
- package/dist/src/task/wire-state-mapper.d.ts +21 -0
- package/dist/src/task/wire-state-mapper.js +63 -0
- package/dist/src/task/wire-state-mapper.js.map +1 -0
- package/package.json +2 -1
- package/src/execution/base-adapter.ts +133 -0
- package/src/execution/claude-adapter.ts +40 -0
- package/src/execution/codex-adapter.ts +67 -0
- package/src/execution/codex-pause-flow.ts +225 -0
- package/src/execution/copilot-adapter.ts +40 -0
- package/src/execution/provider-capabilities.ts +100 -0
- package/src/execution/provider-registry.ts +81 -0
- package/src/mcp/resource-renderers.ts +224 -0
- package/src/mcp/sep1686-handlers.ts +149 -0
- package/src/mcp/tool-definitions.ts +255 -0
- package/src/task/fsm-transitions.ts +72 -0
- package/src/task/task-handle-impl.ts +170 -0
- package/src/task/task-handle.ts +135 -0
- package/src/task/task-manager.ts +328 -0
- package/src/task/task-persistence.ts +95 -0
- package/src/task/task-state.ts +121 -0
- package/src/task/task-store.ts +121 -0
- package/src/task/wire-state-mapper.ts +77 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { TaskStatus } from './task-state.js';
|
|
2
|
+
import type { TaskState, TaskTypeName, Provider, PendingQuestion } from './task-state.js';
|
|
3
|
+
import type { TaskHandle } from './task-handle.js';
|
|
4
|
+
export interface TaskManagerOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Root directory for persistence files.
|
|
7
|
+
* `undefined` means persistence is disabled (in-memory only).
|
|
8
|
+
*/
|
|
9
|
+
persistenceRoot: string | undefined;
|
|
10
|
+
}
|
|
11
|
+
export interface CreateTaskInput {
|
|
12
|
+
prompt: string;
|
|
13
|
+
cwd: string;
|
|
14
|
+
provider: Provider;
|
|
15
|
+
taskType: TaskTypeName;
|
|
16
|
+
model?: string;
|
|
17
|
+
timeoutMs?: number;
|
|
18
|
+
dependsOn?: string[];
|
|
19
|
+
labels?: string[];
|
|
20
|
+
}
|
|
21
|
+
export type StatusChangeListener = (task: TaskState, previousStatus: TaskStatus) => void;
|
|
22
|
+
export type OutputListener = (taskId: string, line: string) => void;
|
|
23
|
+
/**
|
|
24
|
+
* Central orchestrator for task lifecycle management.
|
|
25
|
+
*
|
|
26
|
+
* Wraps {@link TaskStore} with:
|
|
27
|
+
* - Human-readable ID generation (adjective-animal-number)
|
|
28
|
+
* - {@link TaskHandle} creation for provider adapters
|
|
29
|
+
* - Event bus (status changes, output lines)
|
|
30
|
+
* - Output ring buffer capping
|
|
31
|
+
*
|
|
32
|
+
* Spec reference: §3.1 (layer model), §3.2 (TaskHandle)
|
|
33
|
+
*/
|
|
34
|
+
export declare class TaskManager {
|
|
35
|
+
private readonly store;
|
|
36
|
+
private readonly handles;
|
|
37
|
+
private readonly abortControllers;
|
|
38
|
+
private readonly abortListeners;
|
|
39
|
+
private readonly statusListeners;
|
|
40
|
+
private readonly outputListeners;
|
|
41
|
+
readonly persistenceRoot: string | undefined;
|
|
42
|
+
constructor(options: TaskManagerOptions);
|
|
43
|
+
/**
|
|
44
|
+
* Create a new task with a human-readable ID, store it, and return
|
|
45
|
+
* the initial {@link TaskState}.
|
|
46
|
+
*/
|
|
47
|
+
createTask(input: CreateTaskInput): TaskState;
|
|
48
|
+
getTask(id: string): TaskState | undefined;
|
|
49
|
+
getBySessionId(sessionId: string): TaskState | undefined;
|
|
50
|
+
getHandle(id: string): TaskHandle | undefined;
|
|
51
|
+
getAllTasks(): TaskState[];
|
|
52
|
+
/**
|
|
53
|
+
* Apply a partial update to a task.
|
|
54
|
+
*
|
|
55
|
+
* If the update includes a status change, the FSM is validated by the store.
|
|
56
|
+
* On successful status change the event bus is notified.
|
|
57
|
+
*/
|
|
58
|
+
updateTask(id: string, updates: Partial<TaskState>): TaskState | undefined;
|
|
59
|
+
/**
|
|
60
|
+
* Append a line to the task's in-memory output ring buffer.
|
|
61
|
+
* Caps at {@link OUTPUT_RING_BUFFER_MAX} lines (oldest lines evicted).
|
|
62
|
+
*/
|
|
63
|
+
appendOutput(id: string, line: string): void;
|
|
64
|
+
/**
|
|
65
|
+
* Record a verbose-only output line.
|
|
66
|
+
* Updates lastOutputAt and fires the output listener with a prefix,
|
|
67
|
+
* but does NOT push to the in-memory ring buffer.
|
|
68
|
+
*/
|
|
69
|
+
appendOutputFileOnly(id: string, line: string): void;
|
|
70
|
+
registerAbort(id: string, controller: AbortController): void;
|
|
71
|
+
unregisterAbort(id: string): void;
|
|
72
|
+
getAbortController(id: string): AbortController | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* Register a callback for when a task's abort controller fires.
|
|
75
|
+
* Returns an unsubscribe function.
|
|
76
|
+
*/
|
|
77
|
+
onAborted(id: string, cb: () => void): () => void;
|
|
78
|
+
/** Fire abort listeners for a task. Called when AbortController signals. */
|
|
79
|
+
fireAbortListeners(id: string): void;
|
|
80
|
+
queuePendingQuestion(id: string, q: PendingQuestion): void;
|
|
81
|
+
dequeuePendingQuestion(id: string): PendingQuestion | undefined;
|
|
82
|
+
getPendingQuestions(id: string): readonly PendingQuestion[];
|
|
83
|
+
/**
|
|
84
|
+
* Subscribe to status change events.
|
|
85
|
+
* Returns an unsubscribe function.
|
|
86
|
+
*/
|
|
87
|
+
onStatusChange(cb: StatusChangeListener): () => void;
|
|
88
|
+
/**
|
|
89
|
+
* Subscribe to output line events.
|
|
90
|
+
* Returns an unsubscribe function.
|
|
91
|
+
*/
|
|
92
|
+
onOutput(cb: OutputListener): () => void;
|
|
93
|
+
/**
|
|
94
|
+
* Emit a status change event to all listeners.
|
|
95
|
+
* Public so that the TaskHandle implementation can call it directly.
|
|
96
|
+
*/
|
|
97
|
+
emitStatusChange(task: TaskState, previousStatus: TaskStatus): void;
|
|
98
|
+
private generateId;
|
|
99
|
+
}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { uniqueNamesGenerator, adjectives, animals, } from 'unique-names-generator';
|
|
2
|
+
import { TaskStatus } from './task-state.js';
|
|
3
|
+
import { TaskStore } from './task-store.js';
|
|
4
|
+
import { createTaskHandle } from './task-handle-impl.js';
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Configuration
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
/** Maximum lines retained in the in-memory output ring buffer. */
|
|
9
|
+
const OUTPUT_RING_BUFFER_MAX = 500;
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// TaskManager
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
/**
|
|
14
|
+
* Central orchestrator for task lifecycle management.
|
|
15
|
+
*
|
|
16
|
+
* Wraps {@link TaskStore} with:
|
|
17
|
+
* - Human-readable ID generation (adjective-animal-number)
|
|
18
|
+
* - {@link TaskHandle} creation for provider adapters
|
|
19
|
+
* - Event bus (status changes, output lines)
|
|
20
|
+
* - Output ring buffer capping
|
|
21
|
+
*
|
|
22
|
+
* Spec reference: §3.1 (layer model), §3.2 (TaskHandle)
|
|
23
|
+
*/
|
|
24
|
+
export class TaskManager {
|
|
25
|
+
store = new TaskStore();
|
|
26
|
+
handles = new Map();
|
|
27
|
+
abortControllers = new Map();
|
|
28
|
+
abortListeners = new Map();
|
|
29
|
+
statusListeners = new Set();
|
|
30
|
+
outputListeners = new Set();
|
|
31
|
+
persistenceRoot;
|
|
32
|
+
constructor(options) {
|
|
33
|
+
this.persistenceRoot = options.persistenceRoot;
|
|
34
|
+
}
|
|
35
|
+
// -------------------------------------------------------------------------
|
|
36
|
+
// Task creation
|
|
37
|
+
// -------------------------------------------------------------------------
|
|
38
|
+
/**
|
|
39
|
+
* Create a new task with a human-readable ID, store it, and return
|
|
40
|
+
* the initial {@link TaskState}.
|
|
41
|
+
*/
|
|
42
|
+
createTask(input) {
|
|
43
|
+
const id = this.generateId();
|
|
44
|
+
const now = new Date().toISOString();
|
|
45
|
+
const task = {
|
|
46
|
+
id,
|
|
47
|
+
status: TaskStatus.PENDING,
|
|
48
|
+
provider: input.provider,
|
|
49
|
+
taskType: input.taskType,
|
|
50
|
+
prompt: input.prompt,
|
|
51
|
+
cwd: input.cwd,
|
|
52
|
+
createdAt: now,
|
|
53
|
+
updatedAt: now,
|
|
54
|
+
labels: input.labels ?? [],
|
|
55
|
+
output: [],
|
|
56
|
+
pendingQuestions: [],
|
|
57
|
+
};
|
|
58
|
+
// Only set optional properties when defined (exactOptionalPropertyTypes)
|
|
59
|
+
if (input.model !== undefined)
|
|
60
|
+
task.model = input.model;
|
|
61
|
+
if (input.timeoutMs !== undefined)
|
|
62
|
+
task.timeoutMs = input.timeoutMs;
|
|
63
|
+
if (input.dependsOn !== undefined)
|
|
64
|
+
task.dependsOn = input.dependsOn;
|
|
65
|
+
this.store.create(task);
|
|
66
|
+
// Pre-create the handle so getHandle never returns undefined for a known task
|
|
67
|
+
const handle = createTaskHandle(this, id);
|
|
68
|
+
this.handles.set(id, handle);
|
|
69
|
+
return task;
|
|
70
|
+
}
|
|
71
|
+
// -------------------------------------------------------------------------
|
|
72
|
+
// Lookups
|
|
73
|
+
// -------------------------------------------------------------------------
|
|
74
|
+
getTask(id) {
|
|
75
|
+
return this.store.get(id);
|
|
76
|
+
}
|
|
77
|
+
getBySessionId(sessionId) {
|
|
78
|
+
return this.store.getBySessionId(sessionId);
|
|
79
|
+
}
|
|
80
|
+
getHandle(id) {
|
|
81
|
+
return this.handles.get(id);
|
|
82
|
+
}
|
|
83
|
+
getAllTasks() {
|
|
84
|
+
return this.store.getAll();
|
|
85
|
+
}
|
|
86
|
+
// -------------------------------------------------------------------------
|
|
87
|
+
// Mutations (called by TaskHandle implementation)
|
|
88
|
+
// -------------------------------------------------------------------------
|
|
89
|
+
/**
|
|
90
|
+
* Apply a partial update to a task.
|
|
91
|
+
*
|
|
92
|
+
* If the update includes a status change, the FSM is validated by the store.
|
|
93
|
+
* On successful status change the event bus is notified.
|
|
94
|
+
*/
|
|
95
|
+
updateTask(id, updates) {
|
|
96
|
+
const prev = this.store.get(id);
|
|
97
|
+
if (!prev)
|
|
98
|
+
return undefined;
|
|
99
|
+
const previousStatus = prev.status;
|
|
100
|
+
const result = this.store.update(id, updates);
|
|
101
|
+
if (result && result.status !== previousStatus) {
|
|
102
|
+
this.emitStatusChange(result, previousStatus);
|
|
103
|
+
}
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Append a line to the task's in-memory output ring buffer.
|
|
108
|
+
* Caps at {@link OUTPUT_RING_BUFFER_MAX} lines (oldest lines evicted).
|
|
109
|
+
*/
|
|
110
|
+
appendOutput(id, line) {
|
|
111
|
+
const task = this.store.get(id);
|
|
112
|
+
if (!task)
|
|
113
|
+
return;
|
|
114
|
+
task.output.push(line);
|
|
115
|
+
if (task.output.length > OUTPUT_RING_BUFFER_MAX) {
|
|
116
|
+
task.output.splice(0, task.output.length - OUTPUT_RING_BUFFER_MAX);
|
|
117
|
+
}
|
|
118
|
+
task.lastOutputAt = new Date().toISOString();
|
|
119
|
+
task.updatedAt = task.lastOutputAt;
|
|
120
|
+
for (const listener of this.outputListeners) {
|
|
121
|
+
listener(id, line);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Record a verbose-only output line.
|
|
126
|
+
* Updates lastOutputAt and fires the output listener with a prefix,
|
|
127
|
+
* but does NOT push to the in-memory ring buffer.
|
|
128
|
+
*/
|
|
129
|
+
appendOutputFileOnly(id, line) {
|
|
130
|
+
const task = this.store.get(id);
|
|
131
|
+
if (!task)
|
|
132
|
+
return;
|
|
133
|
+
task.lastOutputAt = new Date().toISOString();
|
|
134
|
+
task.updatedAt = task.lastOutputAt;
|
|
135
|
+
for (const listener of this.outputListeners) {
|
|
136
|
+
listener(id, `[verbose-only] ${line}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// -------------------------------------------------------------------------
|
|
140
|
+
// Abort management
|
|
141
|
+
// -------------------------------------------------------------------------
|
|
142
|
+
registerAbort(id, controller) {
|
|
143
|
+
this.abortControllers.set(id, controller);
|
|
144
|
+
}
|
|
145
|
+
unregisterAbort(id) {
|
|
146
|
+
this.abortControllers.delete(id);
|
|
147
|
+
}
|
|
148
|
+
getAbortController(id) {
|
|
149
|
+
return this.abortControllers.get(id);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Register a callback for when a task's abort controller fires.
|
|
153
|
+
* Returns an unsubscribe function.
|
|
154
|
+
*/
|
|
155
|
+
onAborted(id, cb) {
|
|
156
|
+
let listeners = this.abortListeners.get(id);
|
|
157
|
+
if (!listeners) {
|
|
158
|
+
listeners = new Set();
|
|
159
|
+
this.abortListeners.set(id, listeners);
|
|
160
|
+
}
|
|
161
|
+
listeners.add(cb);
|
|
162
|
+
return () => {
|
|
163
|
+
listeners.delete(cb);
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/** Fire abort listeners for a task. Called when AbortController signals. */
|
|
167
|
+
fireAbortListeners(id) {
|
|
168
|
+
const listeners = this.abortListeners.get(id);
|
|
169
|
+
if (!listeners)
|
|
170
|
+
return;
|
|
171
|
+
for (const cb of listeners) {
|
|
172
|
+
cb();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// -------------------------------------------------------------------------
|
|
176
|
+
// Pending question queue
|
|
177
|
+
// -------------------------------------------------------------------------
|
|
178
|
+
queuePendingQuestion(id, q) {
|
|
179
|
+
const task = this.store.get(id);
|
|
180
|
+
if (!task)
|
|
181
|
+
return;
|
|
182
|
+
task.pendingQuestions.push(q);
|
|
183
|
+
task.updatedAt = new Date().toISOString();
|
|
184
|
+
}
|
|
185
|
+
dequeuePendingQuestion(id) {
|
|
186
|
+
const task = this.store.get(id);
|
|
187
|
+
if (!task)
|
|
188
|
+
return undefined;
|
|
189
|
+
const q = task.pendingQuestions.shift();
|
|
190
|
+
if (q !== undefined) {
|
|
191
|
+
task.updatedAt = new Date().toISOString();
|
|
192
|
+
}
|
|
193
|
+
return q;
|
|
194
|
+
}
|
|
195
|
+
getPendingQuestions(id) {
|
|
196
|
+
const task = this.store.get(id);
|
|
197
|
+
if (!task)
|
|
198
|
+
return [];
|
|
199
|
+
return task.pendingQuestions;
|
|
200
|
+
}
|
|
201
|
+
// -------------------------------------------------------------------------
|
|
202
|
+
// Event bus
|
|
203
|
+
// -------------------------------------------------------------------------
|
|
204
|
+
/**
|
|
205
|
+
* Subscribe to status change events.
|
|
206
|
+
* Returns an unsubscribe function.
|
|
207
|
+
*/
|
|
208
|
+
onStatusChange(cb) {
|
|
209
|
+
this.statusListeners.add(cb);
|
|
210
|
+
return () => {
|
|
211
|
+
this.statusListeners.delete(cb);
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Subscribe to output line events.
|
|
216
|
+
* Returns an unsubscribe function.
|
|
217
|
+
*/
|
|
218
|
+
onOutput(cb) {
|
|
219
|
+
this.outputListeners.add(cb);
|
|
220
|
+
return () => {
|
|
221
|
+
this.outputListeners.delete(cb);
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Emit a status change event to all listeners.
|
|
226
|
+
* Public so that the TaskHandle implementation can call it directly.
|
|
227
|
+
*/
|
|
228
|
+
emitStatusChange(task, previousStatus) {
|
|
229
|
+
for (const listener of this.statusListeners) {
|
|
230
|
+
listener(task, previousStatus);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// -------------------------------------------------------------------------
|
|
234
|
+
// Internal helpers
|
|
235
|
+
// -------------------------------------------------------------------------
|
|
236
|
+
generateId() {
|
|
237
|
+
const name = uniqueNamesGenerator({
|
|
238
|
+
dictionaries: [adjectives, animals],
|
|
239
|
+
separator: '-',
|
|
240
|
+
length: 2,
|
|
241
|
+
});
|
|
242
|
+
const num = Math.floor(Math.random() * 900) + 100; // 100-999
|
|
243
|
+
return `${name}-${num}`;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=task-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-manager.js","sourceRoot":"","sources":["../../../src/task/task-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { TaskState } from './task-state.js';
|
|
2
|
+
export interface PersistedProfileState {
|
|
3
|
+
id: string;
|
|
4
|
+
configDir: string;
|
|
5
|
+
cooldownUntil?: number;
|
|
6
|
+
failureCount: number;
|
|
7
|
+
lastFailureReason?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface PersistedState {
|
|
10
|
+
version: 1;
|
|
11
|
+
tasks: TaskState[];
|
|
12
|
+
profiles: PersistedProfileState[];
|
|
13
|
+
lastSavedAt: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function persistenceDir(root: string, cwd: string): string;
|
|
16
|
+
export declare function saveState(dir: string, state: PersistedState): Promise<void>;
|
|
17
|
+
export declare function loadState(dir: string): Promise<PersistedState | null>;
|
|
18
|
+
export declare function applyRecovery(task: TaskState, hasCrashRecovery: boolean): TaskState;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { TaskStatus, isTerminalStatus } from './task-state.js';
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// persistenceDir — deterministic per-workspace directory
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
export function persistenceDir(root, cwd) {
|
|
9
|
+
const hash = createHash('md5').update(cwd).digest('hex');
|
|
10
|
+
return join(root, hash);
|
|
11
|
+
}
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// saveState — atomic write: write tmp → rename
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
export async function saveState(dir, state) {
|
|
16
|
+
await mkdir(dir, { recursive: true });
|
|
17
|
+
const target = join(dir, 'state.json');
|
|
18
|
+
const tmp = join(dir, `state.json.tmp.${process.pid}`);
|
|
19
|
+
await writeFile(tmp, JSON.stringify(state, null, 2), 'utf-8');
|
|
20
|
+
await rename(tmp, target);
|
|
21
|
+
}
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// loadState — read + parse, null on missing or corrupt
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
export async function loadState(dir) {
|
|
26
|
+
try {
|
|
27
|
+
const raw = await readFile(join(dir, 'state.json'), 'utf-8');
|
|
28
|
+
return JSON.parse(raw);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// applyRecovery — per-task recovery on server restart
|
|
36
|
+
// Spec reference: §9.2 steps 1–2
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
export function applyRecovery(task, hasCrashRecovery) {
|
|
39
|
+
// 1. Terminal states restore as-is
|
|
40
|
+
if (isTerminalStatus(task.status)) {
|
|
41
|
+
return task;
|
|
42
|
+
}
|
|
43
|
+
// 2. Adapters without crash recovery → UNKNOWN
|
|
44
|
+
if (!hasCrashRecovery) {
|
|
45
|
+
const now = new Date().toISOString();
|
|
46
|
+
return {
|
|
47
|
+
...task,
|
|
48
|
+
status: TaskStatus.UNKNOWN,
|
|
49
|
+
error: `Server restarted; ${task.provider} sessions don't survive restarts`,
|
|
50
|
+
completedAt: now,
|
|
51
|
+
output: [
|
|
52
|
+
...task.output,
|
|
53
|
+
`[recovery] Task was ${task.status} when server restarted; marked UNKNOWN`,
|
|
54
|
+
],
|
|
55
|
+
recovered: true,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
// 3. Has crash recovery (e.g. Codex) — return as-is; adapter handles externally
|
|
59
|
+
return task;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=task-persistence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-persistence.js","sourceRoot":"","sources":["../../../src/task/task-persistence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AA2B/D,8EAA8E;AAC9E,yDAAyD;AACzD,8EAA8E;AAE9E,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,GAAW;IACtD,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACzD,OAAO,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,8EAA8E;AAC9E,+CAA+C;AAC/C,8EAA8E;AAE9E,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAW,EAAE,KAAqB;IAChE,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IACvC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,kBAAkB,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACvD,MAAM,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAC9D,MAAM,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAC5B,CAAC;AAED,8EAA8E;AAC9E,uDAAuD;AACvD,8EAA8E;AAE9E,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAW;IACzC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC;QAC7D,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAmB,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,sDAAsD;AACtD,iCAAiC;AACjC,8EAA8E;AAE9E,MAAM,UAAU,aAAa,CAAC,IAAe,EAAE,gBAAyB;IACtE,mCAAmC;IACnC,IAAI,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,+CAA+C;IAC/C,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,OAAO;YACL,GAAG,IAAI;YACP,MAAM,EAAE,UAAU,CAAC,OAAO;YAC1B,KAAK,EAAE,qBAAqB,IAAI,CAAC,QAAQ,kCAAkC;YAC3E,WAAW,EAAE,GAAG;YAChB,MAAM,EAAE;gBACN,GAAG,IAAI,CAAC,MAAM;gBACd,uBAAuB,IAAI,CAAC,MAAM,wCAAwC;aAC3E;YACD,SAAS,EAAE,IAAI;SAChB,CAAC;IACJ,CAAC;IAED,gFAAgF;IAChF,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export declare enum TaskStatus {
|
|
2
|
+
WAITING = "waiting",
|
|
3
|
+
PENDING = "pending",
|
|
4
|
+
RUNNING = "running",
|
|
5
|
+
RATE_LIMITED = "rate_limited",
|
|
6
|
+
WAITING_ANSWER = "waiting_answer",
|
|
7
|
+
COMPLETED = "completed",
|
|
8
|
+
FAILED = "failed",
|
|
9
|
+
TIMED_OUT = "timed_out",
|
|
10
|
+
CANCELLED = "cancelled",
|
|
11
|
+
UNKNOWN = "unknown"
|
|
12
|
+
}
|
|
13
|
+
export declare const TERMINAL_STATUSES: ReadonlySet<TaskStatus>;
|
|
14
|
+
export declare function isTerminalStatus(status: TaskStatus): boolean;
|
|
15
|
+
export type TaskTypeName = 'coder' | 'planner' | 'tester' | 'researcher' | 'general';
|
|
16
|
+
export type Provider = 'codex' | 'copilot' | 'claude-cli';
|
|
17
|
+
export type PendingQuestion = {
|
|
18
|
+
type: 'user_input';
|
|
19
|
+
requestId: string;
|
|
20
|
+
questions: Array<{
|
|
21
|
+
id: string;
|
|
22
|
+
text: string;
|
|
23
|
+
options?: string[];
|
|
24
|
+
allowFreeform?: boolean;
|
|
25
|
+
}>;
|
|
26
|
+
} | {
|
|
27
|
+
type: 'command_approval';
|
|
28
|
+
requestId: string;
|
|
29
|
+
command: string;
|
|
30
|
+
sandboxPolicy?: string;
|
|
31
|
+
} | {
|
|
32
|
+
type: 'file_approval';
|
|
33
|
+
requestId: string;
|
|
34
|
+
fileChanges: Array<{
|
|
35
|
+
path: string;
|
|
36
|
+
patch: string;
|
|
37
|
+
}>;
|
|
38
|
+
} | {
|
|
39
|
+
type: 'elicitation';
|
|
40
|
+
requestId: string;
|
|
41
|
+
serverName?: string;
|
|
42
|
+
message: string;
|
|
43
|
+
schema?: unknown;
|
|
44
|
+
} | {
|
|
45
|
+
type: 'dynamic_tool';
|
|
46
|
+
requestId: string;
|
|
47
|
+
toolName: string;
|
|
48
|
+
arguments: string;
|
|
49
|
+
};
|
|
50
|
+
export type PendingQuestionType = PendingQuestion['type'];
|
|
51
|
+
export interface TaskState {
|
|
52
|
+
id: string;
|
|
53
|
+
status: TaskStatus;
|
|
54
|
+
provider: Provider;
|
|
55
|
+
taskType: TaskTypeName;
|
|
56
|
+
prompt: string;
|
|
57
|
+
cwd: string;
|
|
58
|
+
model?: string;
|
|
59
|
+
sessionId?: string;
|
|
60
|
+
operationId?: string;
|
|
61
|
+
createdAt: string;
|
|
62
|
+
updatedAt: string;
|
|
63
|
+
startedAt?: string;
|
|
64
|
+
completedAt?: string;
|
|
65
|
+
lastOutputAt?: string;
|
|
66
|
+
timeoutMs?: number;
|
|
67
|
+
timeoutAt?: string;
|
|
68
|
+
keepAlive?: number;
|
|
69
|
+
output: string[];
|
|
70
|
+
outputFilePath?: string;
|
|
71
|
+
dependsOn?: string[];
|
|
72
|
+
labels: string[];
|
|
73
|
+
pendingQuestions: PendingQuestion[];
|
|
74
|
+
error?: string;
|
|
75
|
+
exitCode?: number;
|
|
76
|
+
result?: unknown;
|
|
77
|
+
recovered?: boolean;
|
|
78
|
+
degraded?: boolean;
|
|
79
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export var TaskStatus;
|
|
2
|
+
(function (TaskStatus) {
|
|
3
|
+
TaskStatus["WAITING"] = "waiting";
|
|
4
|
+
TaskStatus["PENDING"] = "pending";
|
|
5
|
+
TaskStatus["RUNNING"] = "running";
|
|
6
|
+
TaskStatus["RATE_LIMITED"] = "rate_limited";
|
|
7
|
+
TaskStatus["WAITING_ANSWER"] = "waiting_answer";
|
|
8
|
+
TaskStatus["COMPLETED"] = "completed";
|
|
9
|
+
TaskStatus["FAILED"] = "failed";
|
|
10
|
+
TaskStatus["TIMED_OUT"] = "timed_out";
|
|
11
|
+
TaskStatus["CANCELLED"] = "cancelled";
|
|
12
|
+
TaskStatus["UNKNOWN"] = "unknown";
|
|
13
|
+
})(TaskStatus || (TaskStatus = {}));
|
|
14
|
+
export const TERMINAL_STATUSES = new Set([
|
|
15
|
+
TaskStatus.COMPLETED,
|
|
16
|
+
TaskStatus.FAILED,
|
|
17
|
+
TaskStatus.CANCELLED,
|
|
18
|
+
TaskStatus.TIMED_OUT,
|
|
19
|
+
TaskStatus.UNKNOWN,
|
|
20
|
+
]);
|
|
21
|
+
export function isTerminalStatus(status) {
|
|
22
|
+
return TERMINAL_STATUSES.has(status);
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=task-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-state.js","sourceRoot":"","sources":["../../../src/task/task-state.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,UAWX;AAXD,WAAY,UAAU;IACpB,iCAAmB,CAAA;IACnB,iCAAmB,CAAA;IACnB,iCAAmB,CAAA;IACnB,2CAA6B,CAAA;IAC7B,+CAAiC,CAAA;IACjC,qCAAuB,CAAA;IACvB,+BAAiB,CAAA;IACjB,qCAAuB,CAAA;IACvB,qCAAuB,CAAA;IACvB,iCAAmB,CAAA;AACrB,CAAC,EAXW,UAAU,KAAV,UAAU,QAWrB;AAED,MAAM,CAAC,MAAM,iBAAiB,GAA4B,IAAI,GAAG,CAAC;IAChE,UAAU,CAAC,SAAS;IACpB,UAAU,CAAC,MAAM;IACjB,UAAU,CAAC,SAAS;IACpB,UAAU,CAAC,SAAS;IACpB,UAAU,CAAC,OAAO;CACnB,CAAC,CAAC;AAEH,MAAM,UAAU,gBAAgB,CAAC,MAAkB;IACjD,OAAO,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { TaskState, TaskStatus } from './task-state.js';
|
|
2
|
+
/**
|
|
3
|
+
* In-memory task store with FSM-validated state transitions.
|
|
4
|
+
*
|
|
5
|
+
* This is the single source of truth for task state. It enforces the FSM at
|
|
6
|
+
* the data layer — illegal transitions are rejected before any mutation occurs.
|
|
7
|
+
*
|
|
8
|
+
* Terminal tasks can be evicted by age to prevent unbounded memory growth.
|
|
9
|
+
*/
|
|
10
|
+
export declare class TaskStore {
|
|
11
|
+
private readonly tasks;
|
|
12
|
+
/** Store a new task. Overwrites if the ID already exists. */
|
|
13
|
+
create(task: TaskState): void;
|
|
14
|
+
/** Retrieve a task by its unique ID. */
|
|
15
|
+
get(id: string): TaskState | undefined;
|
|
16
|
+
/** Linear scan for a task matching the given session ID. */
|
|
17
|
+
getBySessionId(sessionId: string): TaskState | undefined;
|
|
18
|
+
/** Return all tasks as an array. */
|
|
19
|
+
getAll(): TaskState[];
|
|
20
|
+
/**
|
|
21
|
+
* Transition a task to a new status.
|
|
22
|
+
*
|
|
23
|
+
* Returns `true` if the transition was valid and applied, `false` if the
|
|
24
|
+
* task was not found or the transition is illegal per the FSM.
|
|
25
|
+
*/
|
|
26
|
+
updateStatus(id: string, next: TaskStatus): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Apply a partial update to a task. If the update includes a `status`
|
|
29
|
+
* change, the FSM is validated first — an illegal transition causes the
|
|
30
|
+
* entire update to be rejected (returns `undefined`).
|
|
31
|
+
*/
|
|
32
|
+
update(id: string, updates: Partial<TaskState>): TaskState | undefined;
|
|
33
|
+
/** Remove a task by ID. Returns `true` if it existed. */
|
|
34
|
+
delete(id: string): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Remove terminal tasks whose `updatedAt` timestamp is older than
|
|
37
|
+
* `maxAgeMs` milliseconds from now.
|
|
38
|
+
*
|
|
39
|
+
* Returns the number of tasks evicted.
|
|
40
|
+
*/
|
|
41
|
+
evict(maxAgeMs: number): number;
|
|
42
|
+
/** Remove all tasks. */
|
|
43
|
+
clear(): void;
|
|
44
|
+
/** Return the number of stored tasks. */
|
|
45
|
+
size(): number;
|
|
46
|
+
}
|