@vibe-forge/mcp 3.1.1 → 3.2.0
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/AGENTS.md +4 -9
- package/__tests__/tools.spec.ts +6 -2
- package/package.json +4 -8
- package/src/index.ts +1 -13
- package/src/tools/index.ts +1 -3
- package/src/types.ts +0 -13
- package/__tests__/sync.spec.ts +0 -23
- package/__tests__/task-manager.spec.ts +0 -871
- package/__tests__/task-tool.spec.ts +0 -378
- package/src/sync.ts +0 -70
- package/src/tools/task/index.ts +0 -126
- package/src/tools/task/manager.ts +0 -875
- package/src/tools/task/permission-recovery.ts +0 -172
- package/src/tools/task/permission-state.ts +0 -200
- package/src/tools/task/presentation.ts +0 -125
- package/src/tools/task/register-task-runtime-tools.ts +0 -193
- package/src/tools/task/task-tool-responses.ts +0 -40
|
@@ -1,378 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
-
|
|
3
|
-
import { createToolTester } from './mcp-test-utils.js'
|
|
4
|
-
|
|
5
|
-
const mocks = vi.hoisted(() => {
|
|
6
|
-
return {
|
|
7
|
-
callHook: vi.fn(),
|
|
8
|
-
createChildSession: vi.fn(),
|
|
9
|
-
getParentSessionId: vi.fn(),
|
|
10
|
-
startTask: vi.fn(),
|
|
11
|
-
sendTaskMessage: vi.fn(),
|
|
12
|
-
submitTaskInput: vi.fn(),
|
|
13
|
-
respondToTaskInteraction: vi.fn(),
|
|
14
|
-
getTask: vi.fn(),
|
|
15
|
-
stopTask: vi.fn(),
|
|
16
|
-
getAllTasks: vi.fn(),
|
|
17
|
-
uuid: vi.fn()
|
|
18
|
-
}
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
vi.mock('@vibe-forge/hooks', () => ({
|
|
22
|
-
callHook: mocks.callHook
|
|
23
|
-
}))
|
|
24
|
-
|
|
25
|
-
vi.mock('@vibe-forge/utils/uuid', () => ({
|
|
26
|
-
uuid: mocks.uuid
|
|
27
|
-
}))
|
|
28
|
-
|
|
29
|
-
vi.mock('#~/sync.js', () => ({
|
|
30
|
-
createChildSession: mocks.createChildSession,
|
|
31
|
-
getParentSessionId: mocks.getParentSessionId
|
|
32
|
-
}))
|
|
33
|
-
|
|
34
|
-
vi.mock('#~/tools/task/manager.js', () => ({
|
|
35
|
-
TaskManager: class {
|
|
36
|
-
startTask = mocks.startTask
|
|
37
|
-
sendTaskMessage = mocks.sendTaskMessage
|
|
38
|
-
submitTaskInput = mocks.submitTaskInput
|
|
39
|
-
respondToTaskInteraction = mocks.respondToTaskInteraction
|
|
40
|
-
getTask = mocks.getTask
|
|
41
|
-
stopTask = mocks.stopTask
|
|
42
|
-
getAllTasks = mocks.getAllTasks
|
|
43
|
-
}
|
|
44
|
-
}))
|
|
45
|
-
|
|
46
|
-
describe('task tool integration', () => {
|
|
47
|
-
beforeEach(() => {
|
|
48
|
-
vi.clearAllMocks()
|
|
49
|
-
process.env.__VF_PROJECT_AI_SESSION_ID__ = 'sess-1'
|
|
50
|
-
delete process.env.__VF_PROJECT_AI_PERMISSION_MODE__
|
|
51
|
-
let nextTaskId = 1
|
|
52
|
-
mocks.uuid.mockImplementation(() => `task-${nextTaskId++}`)
|
|
53
|
-
mocks.callHook.mockResolvedValue({ continue: true })
|
|
54
|
-
mocks.getParentSessionId.mockReturnValue(undefined)
|
|
55
|
-
mocks.createChildSession.mockResolvedValue({})
|
|
56
|
-
mocks.startTask.mockResolvedValue(undefined)
|
|
57
|
-
mocks.sendTaskMessage.mockResolvedValue(undefined)
|
|
58
|
-
mocks.submitTaskInput.mockResolvedValue(undefined)
|
|
59
|
-
mocks.respondToTaskInteraction.mockResolvedValue(undefined)
|
|
60
|
-
mocks.getTask.mockImplementation((taskId: string) => ({
|
|
61
|
-
taskId,
|
|
62
|
-
status: 'completed',
|
|
63
|
-
logs: []
|
|
64
|
-
}))
|
|
65
|
-
mocks.stopTask.mockReturnValue(true)
|
|
66
|
-
mocks.getAllTasks.mockReturnValue([])
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
it('passes resolved task ids to the StartTasks hook', async () => {
|
|
70
|
-
const { createTaskRegister } = await import('#~/tools/task/index.js')
|
|
71
|
-
|
|
72
|
-
const tester = createToolTester()
|
|
73
|
-
createTaskRegister()(tester.mockRegister)
|
|
74
|
-
|
|
75
|
-
await tester.callTool('StartTasks', {
|
|
76
|
-
tasks: [{
|
|
77
|
-
description: 'only output ok',
|
|
78
|
-
type: 'default',
|
|
79
|
-
background: false
|
|
80
|
-
}]
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
expect(mocks.callHook).toHaveBeenCalledWith(
|
|
84
|
-
'StartTasks',
|
|
85
|
-
expect.objectContaining({
|
|
86
|
-
sessionId: 'sess-1',
|
|
87
|
-
tasks: [expect.objectContaining({
|
|
88
|
-
taskId: 'task-1',
|
|
89
|
-
description: 'only output ok',
|
|
90
|
-
type: 'default',
|
|
91
|
-
background: false
|
|
92
|
-
})]
|
|
93
|
-
})
|
|
94
|
-
)
|
|
95
|
-
expect(mocks.startTask).toHaveBeenCalledWith(expect.objectContaining({
|
|
96
|
-
taskId: 'task-1'
|
|
97
|
-
}))
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
it('accepts workspace tasks without a separate workspace tool', async () => {
|
|
101
|
-
const { createTaskRegister } = await import('#~/tools/task/index.js')
|
|
102
|
-
|
|
103
|
-
const tester = createToolTester()
|
|
104
|
-
createTaskRegister()(tester.mockRegister)
|
|
105
|
-
|
|
106
|
-
await tester.callTool('StartTasks', {
|
|
107
|
-
tasks: [{
|
|
108
|
-
description: 'fix billing',
|
|
109
|
-
type: 'workspace',
|
|
110
|
-
name: 'billing'
|
|
111
|
-
}]
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
expect(mocks.startTask).toHaveBeenCalledWith(expect.objectContaining({
|
|
115
|
-
taskId: 'task-1',
|
|
116
|
-
description: 'fix billing',
|
|
117
|
-
type: 'workspace',
|
|
118
|
-
name: 'billing'
|
|
119
|
-
}))
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
it('passes explicit task model overrides to the hook and task manager', async () => {
|
|
123
|
-
const { createTaskRegister } = await import('#~/tools/task/index.js')
|
|
124
|
-
|
|
125
|
-
const tester = createToolTester()
|
|
126
|
-
createTaskRegister()(tester.mockRegister)
|
|
127
|
-
|
|
128
|
-
await tester.callTool('StartTasks', {
|
|
129
|
-
tasks: [{
|
|
130
|
-
description: 'investigate flaky tests',
|
|
131
|
-
type: 'default',
|
|
132
|
-
model: 'gpt-5.4-mini'
|
|
133
|
-
}]
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
expect(mocks.callHook).toHaveBeenCalledWith(
|
|
137
|
-
'StartTasks',
|
|
138
|
-
expect.objectContaining({
|
|
139
|
-
tasks: [expect.objectContaining({
|
|
140
|
-
taskId: 'task-1',
|
|
141
|
-
model: 'gpt-5.4-mini'
|
|
142
|
-
})]
|
|
143
|
-
})
|
|
144
|
-
)
|
|
145
|
-
expect(mocks.startTask).toHaveBeenCalledWith(expect.objectContaining({
|
|
146
|
-
taskId: 'task-1',
|
|
147
|
-
model: 'gpt-5.4-mini'
|
|
148
|
-
}))
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
it('inherits the parent permission mode when the task does not specify one', async () => {
|
|
152
|
-
process.env.__VF_PROJECT_AI_PERMISSION_MODE__ = 'dontAsk'
|
|
153
|
-
mocks.getParentSessionId.mockReturnValue('parent-session')
|
|
154
|
-
|
|
155
|
-
const { createTaskRegister } = await import('#~/tools/task/index.js')
|
|
156
|
-
|
|
157
|
-
const tester = createToolTester()
|
|
158
|
-
createTaskRegister()(tester.mockRegister)
|
|
159
|
-
|
|
160
|
-
await tester.callTool('StartTasks', {
|
|
161
|
-
tasks: [{
|
|
162
|
-
description: 'inherit permissions',
|
|
163
|
-
type: 'default'
|
|
164
|
-
}]
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
expect(mocks.callHook).toHaveBeenCalledWith(
|
|
168
|
-
'StartTasks',
|
|
169
|
-
expect.objectContaining({
|
|
170
|
-
tasks: [expect.objectContaining({
|
|
171
|
-
taskId: 'task-1',
|
|
172
|
-
permissionMode: 'dontAsk'
|
|
173
|
-
})]
|
|
174
|
-
})
|
|
175
|
-
)
|
|
176
|
-
expect(mocks.createChildSession).toHaveBeenCalledWith(expect.objectContaining({
|
|
177
|
-
id: 'task-1',
|
|
178
|
-
parentSessionId: 'parent-session',
|
|
179
|
-
permissionMode: 'dontAsk'
|
|
180
|
-
}))
|
|
181
|
-
expect(mocks.startTask).toHaveBeenCalledWith(expect.objectContaining({
|
|
182
|
-
taskId: 'task-1',
|
|
183
|
-
permissionMode: 'dontAsk',
|
|
184
|
-
enableServerSync: true
|
|
185
|
-
}))
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
it('keeps an explicit task permission mode over the inherited parent mode', async () => {
|
|
189
|
-
process.env.__VF_PROJECT_AI_PERMISSION_MODE__ = 'dontAsk'
|
|
190
|
-
|
|
191
|
-
const { createTaskRegister } = await import('#~/tools/task/index.js')
|
|
192
|
-
|
|
193
|
-
const tester = createToolTester()
|
|
194
|
-
createTaskRegister()(tester.mockRegister)
|
|
195
|
-
|
|
196
|
-
await tester.callTool('StartTasks', {
|
|
197
|
-
tasks: [{
|
|
198
|
-
description: 'override permissions',
|
|
199
|
-
type: 'default',
|
|
200
|
-
permissionMode: 'plan'
|
|
201
|
-
}]
|
|
202
|
-
})
|
|
203
|
-
|
|
204
|
-
expect(mocks.startTask).toHaveBeenCalledWith(expect.objectContaining({
|
|
205
|
-
taskId: 'task-1',
|
|
206
|
-
permissionMode: 'plan'
|
|
207
|
-
}))
|
|
208
|
-
})
|
|
209
|
-
|
|
210
|
-
it('registers recovery guidance in task tool descriptions', async () => {
|
|
211
|
-
const { createTaskRegister } = await import('#~/tools/task/index.js')
|
|
212
|
-
|
|
213
|
-
const tester = createToolTester()
|
|
214
|
-
createTaskRegister()(tester.mockRegister)
|
|
215
|
-
|
|
216
|
-
expect(tester.getRegisteredTools()).toContain('SendTaskMessage')
|
|
217
|
-
expect(tester.getRegisteredTools()).toContain('SubmitTaskInput')
|
|
218
|
-
expect(tester.getRegisteredTools()).toContain('RespondTaskInteraction')
|
|
219
|
-
expect(tester.getToolInfo('StartTasks')?.description).toContain('GetTaskInfo')
|
|
220
|
-
expect(tester.getToolInfo('StartTasks')?.description).toContain('SendTaskMessage')
|
|
221
|
-
expect(tester.getToolInfo('GetTaskInfo')?.description).toContain('10 most recent logs')
|
|
222
|
-
expect(tester.getToolInfo('GetTaskInfo')?.description).toContain('logOrder')
|
|
223
|
-
expect(tester.getToolInfo('GetTaskInfo')?.description).toContain('SendTaskMessage')
|
|
224
|
-
expect(tester.getToolInfo('SendTaskMessage')?.description).toContain('mode "direct"')
|
|
225
|
-
expect(tester.getToolInfo('SendTaskMessage')?.description).toContain('mode "steer"')
|
|
226
|
-
expect(tester.getToolInfo('ListTasks')?.description).toContain('10 most recent logs')
|
|
227
|
-
expect(tester.getToolInfo('ListTasks')?.description).toContain('SendTaskMessage')
|
|
228
|
-
expect(tester.getToolInfo('ListTasks')?.description).toContain('pendingInput')
|
|
229
|
-
expect(tester.getToolInfo('SubmitTaskInput')?.description).toContain('SendTaskMessage')
|
|
230
|
-
expect(tester.getToolInfo('SubmitTaskInput')?.description).toContain('allow_once')
|
|
231
|
-
expect(tester.getToolInfo('RespondTaskInteraction')?.description).toContain('Deprecated alias')
|
|
232
|
-
})
|
|
233
|
-
|
|
234
|
-
it('returns the 10 most recent logs in descending order by default', async () => {
|
|
235
|
-
mocks.getTask.mockReturnValue({
|
|
236
|
-
taskId: 'task-1',
|
|
237
|
-
status: 'running',
|
|
238
|
-
logs: Array.from({ length: 12 }, (_, index) => `log-${index + 1}`)
|
|
239
|
-
})
|
|
240
|
-
|
|
241
|
-
const { createTaskRegister } = await import('#~/tools/task/index.js')
|
|
242
|
-
|
|
243
|
-
const tester = createToolTester()
|
|
244
|
-
createTaskRegister()(tester.mockRegister)
|
|
245
|
-
|
|
246
|
-
const result = await tester.callTool('GetTaskInfo', {
|
|
247
|
-
taskId: 'task-1'
|
|
248
|
-
}) as { content: Array<{ text: string }> }
|
|
249
|
-
const [task] = JSON.parse(result.content[0].text) as Array<{ logs: string[] }>
|
|
250
|
-
|
|
251
|
-
expect(task.logs).toEqual([
|
|
252
|
-
'log-12',
|
|
253
|
-
'log-11',
|
|
254
|
-
'log-10',
|
|
255
|
-
'log-9',
|
|
256
|
-
'log-8',
|
|
257
|
-
'log-7',
|
|
258
|
-
'log-6',
|
|
259
|
-
'log-5',
|
|
260
|
-
'log-4',
|
|
261
|
-
'log-3'
|
|
262
|
-
])
|
|
263
|
-
})
|
|
264
|
-
|
|
265
|
-
it('supports custom log windows and ascending order in ListTasks', async () => {
|
|
266
|
-
mocks.getAllTasks.mockReturnValue([
|
|
267
|
-
{
|
|
268
|
-
taskId: 'task-1',
|
|
269
|
-
status: 'running',
|
|
270
|
-
logs: ['a', 'b', 'c', 'd']
|
|
271
|
-
},
|
|
272
|
-
{
|
|
273
|
-
taskId: 'task-2',
|
|
274
|
-
status: 'completed',
|
|
275
|
-
logs: ['1', '2', '3']
|
|
276
|
-
}
|
|
277
|
-
])
|
|
278
|
-
|
|
279
|
-
const { createTaskRegister } = await import('#~/tools/task/index.js')
|
|
280
|
-
|
|
281
|
-
const tester = createToolTester()
|
|
282
|
-
createTaskRegister()(tester.mockRegister)
|
|
283
|
-
|
|
284
|
-
const result = await tester.callTool('ListTasks', {
|
|
285
|
-
logLimit: 2,
|
|
286
|
-
logOrder: 'asc'
|
|
287
|
-
}) as { content: Array<{ text: string }> }
|
|
288
|
-
const tasks = JSON.parse(result.content[0].text) as Array<{ taskId: string; logs: string[] }>
|
|
289
|
-
|
|
290
|
-
expect(tasks).toEqual([
|
|
291
|
-
{
|
|
292
|
-
taskId: 'task-1',
|
|
293
|
-
status: 'running',
|
|
294
|
-
logs: ['c', 'd'],
|
|
295
|
-
guidance: []
|
|
296
|
-
},
|
|
297
|
-
{
|
|
298
|
-
taskId: 'task-2',
|
|
299
|
-
status: 'completed',
|
|
300
|
-
logs: ['2', '3'],
|
|
301
|
-
guidance: []
|
|
302
|
-
}
|
|
303
|
-
])
|
|
304
|
-
})
|
|
305
|
-
|
|
306
|
-
it('forwards SubmitTaskInput to the task manager', async () => {
|
|
307
|
-
mocks.getTask.mockReturnValue({
|
|
308
|
-
taskId: 'task-1',
|
|
309
|
-
status: 'running',
|
|
310
|
-
logs: ['Interaction response submitted: allow_once']
|
|
311
|
-
})
|
|
312
|
-
|
|
313
|
-
const { createTaskRegister } = await import('#~/tools/task/index.js')
|
|
314
|
-
|
|
315
|
-
const tester = createToolTester()
|
|
316
|
-
createTaskRegister()(tester.mockRegister)
|
|
317
|
-
|
|
318
|
-
await tester.callTool('SubmitTaskInput', {
|
|
319
|
-
taskId: 'task-1',
|
|
320
|
-
data: 'allow_once'
|
|
321
|
-
})
|
|
322
|
-
|
|
323
|
-
expect(mocks.submitTaskInput).toHaveBeenCalledWith({
|
|
324
|
-
taskId: 'task-1',
|
|
325
|
-
interactionId: undefined,
|
|
326
|
-
data: 'allow_once'
|
|
327
|
-
})
|
|
328
|
-
})
|
|
329
|
-
|
|
330
|
-
it('forwards SendTaskMessage to the task manager', async () => {
|
|
331
|
-
mocks.getTask.mockReturnValue({
|
|
332
|
-
taskId: 'task-1',
|
|
333
|
-
status: 'running',
|
|
334
|
-
logs: ['Queued task message (steer): keep checking logs']
|
|
335
|
-
})
|
|
336
|
-
|
|
337
|
-
const { createTaskRegister } = await import('#~/tools/task/index.js')
|
|
338
|
-
|
|
339
|
-
const tester = createToolTester()
|
|
340
|
-
createTaskRegister()(tester.mockRegister)
|
|
341
|
-
|
|
342
|
-
await tester.callTool('SendTaskMessage', {
|
|
343
|
-
taskId: 'task-1',
|
|
344
|
-
message: 'keep checking logs',
|
|
345
|
-
mode: 'steer'
|
|
346
|
-
})
|
|
347
|
-
|
|
348
|
-
expect(mocks.sendTaskMessage).toHaveBeenCalledWith({
|
|
349
|
-
taskId: 'task-1',
|
|
350
|
-
message: 'keep checking logs',
|
|
351
|
-
mode: 'steer'
|
|
352
|
-
})
|
|
353
|
-
})
|
|
354
|
-
|
|
355
|
-
it('keeps RespondTaskInteraction as a deprecated alias', async () => {
|
|
356
|
-
mocks.getTask.mockReturnValue({
|
|
357
|
-
taskId: 'task-1',
|
|
358
|
-
status: 'running',
|
|
359
|
-
logs: ['Interaction response submitted: allow_once']
|
|
360
|
-
})
|
|
361
|
-
|
|
362
|
-
const { createTaskRegister } = await import('#~/tools/task/index.js')
|
|
363
|
-
|
|
364
|
-
const tester = createToolTester()
|
|
365
|
-
createTaskRegister()(tester.mockRegister)
|
|
366
|
-
|
|
367
|
-
await tester.callTool('RespondTaskInteraction', {
|
|
368
|
-
taskId: 'task-1',
|
|
369
|
-
response: 'allow_once'
|
|
370
|
-
})
|
|
371
|
-
|
|
372
|
-
expect(mocks.submitTaskInput).toHaveBeenCalledWith({
|
|
373
|
-
taskId: 'task-1',
|
|
374
|
-
interactionId: undefined,
|
|
375
|
-
data: 'allow_once'
|
|
376
|
-
})
|
|
377
|
-
})
|
|
378
|
-
})
|
package/src/sync.ts
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import process from 'node:process'
|
|
2
|
-
|
|
3
|
-
import type { SessionPermissionMode, WSEvent } from '@vibe-forge/types'
|
|
4
|
-
import { extractTextFromMessage } from '@vibe-forge/utils/chat-message'
|
|
5
|
-
|
|
6
|
-
const getServerBaseUrl = () => {
|
|
7
|
-
const host = process.env.__VF_PROJECT_AI_SERVER_HOST__ ?? 'localhost'
|
|
8
|
-
const port = process.env.__VF_PROJECT_AI_SERVER_PORT__ ?? '8787'
|
|
9
|
-
return `http://${host}:${port}`
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const getParentSessionId = () => {
|
|
13
|
-
const sessionId = process.env.__VF_PROJECT_AI_SESSION_ID__
|
|
14
|
-
if (sessionId != null && sessionId !== '') {
|
|
15
|
-
return sessionId
|
|
16
|
-
}
|
|
17
|
-
const ctxId = process.env.__VF_PROJECT_AI_CTX_ID__
|
|
18
|
-
return ctxId ?? undefined
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export const createChildSession = async (params: {
|
|
22
|
-
id: string
|
|
23
|
-
title?: string
|
|
24
|
-
parentSessionId?: string
|
|
25
|
-
permissionMode?: SessionPermissionMode
|
|
26
|
-
}) => {
|
|
27
|
-
const baseUrl = getServerBaseUrl()
|
|
28
|
-
const response = await fetch(`${baseUrl}/api/sessions`, {
|
|
29
|
-
method: 'POST',
|
|
30
|
-
headers: { 'Content-Type': 'application/json' },
|
|
31
|
-
body: JSON.stringify({
|
|
32
|
-
id: params.id,
|
|
33
|
-
title: params.title,
|
|
34
|
-
parentSessionId: params.parentSessionId,
|
|
35
|
-
permissionMode: params.permissionMode,
|
|
36
|
-
start: false
|
|
37
|
-
})
|
|
38
|
-
})
|
|
39
|
-
if (!response.ok) {
|
|
40
|
-
const errorText = await response.text()
|
|
41
|
-
throw new Error(`Failed to create session: ${response.statusText} - ${errorText}`)
|
|
42
|
-
}
|
|
43
|
-
return response.json()
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export const postSessionEvent = async (sessionId: string, payload: Record<string, unknown>) => {
|
|
47
|
-
const baseUrl = getServerBaseUrl()
|
|
48
|
-
const response = await fetch(`${baseUrl}/api/sessions/${sessionId}/events`, {
|
|
49
|
-
method: 'POST',
|
|
50
|
-
headers: { 'Content-Type': 'application/json' },
|
|
51
|
-
body: JSON.stringify(payload)
|
|
52
|
-
})
|
|
53
|
-
if (!response.ok) {
|
|
54
|
-
const errorText = await response.text()
|
|
55
|
-
throw new Error(`Failed to post session event: ${response.statusText} - ${errorText}`)
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export const fetchSessionMessages = async (sessionId: string) => {
|
|
60
|
-
const baseUrl = getServerBaseUrl()
|
|
61
|
-
const response = await fetch(`${baseUrl}/api/sessions/${sessionId}/messages`)
|
|
62
|
-
if (!response.ok) {
|
|
63
|
-
const errorText = await response.text()
|
|
64
|
-
throw new Error(`Failed to fetch session messages: ${response.statusText} - ${errorText}`)
|
|
65
|
-
}
|
|
66
|
-
const data = await response.json() as { messages: WSEvent[] }
|
|
67
|
-
return data.messages ?? []
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export { extractTextFromMessage }
|
package/src/tools/task/index.ts
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import process from 'node:process'
|
|
2
|
-
|
|
3
|
-
import { callHook } from '@vibe-forge/hooks'
|
|
4
|
-
import { uuid } from '@vibe-forge/utils/uuid'
|
|
5
|
-
import { z } from 'zod'
|
|
6
|
-
|
|
7
|
-
import { createChildSession, getParentSessionId } from '#~/sync.js'
|
|
8
|
-
import type { McpManagedTaskInput } from '../../types'
|
|
9
|
-
import { defineRegister } from '../types'
|
|
10
|
-
import { TaskManager } from './manager'
|
|
11
|
-
import {
|
|
12
|
-
SESSION_PERMISSION_MODES,
|
|
13
|
-
START_TASKS_DESCRIPTION,
|
|
14
|
-
TASK_BACKGROUND_DESCRIPTION,
|
|
15
|
-
TASK_MODEL_DESCRIPTION,
|
|
16
|
-
TASK_PERMISSION_MODE_DESCRIPTION,
|
|
17
|
-
resolveInheritedPermissionMode,
|
|
18
|
-
serializeTaskInfo
|
|
19
|
-
} from './presentation'
|
|
20
|
-
import { registerTaskRuntimeTools } from './register-task-runtime-tools'
|
|
21
|
-
|
|
22
|
-
export const createTaskRegister = () => {
|
|
23
|
-
const taskManager = new TaskManager()
|
|
24
|
-
|
|
25
|
-
return defineRegister((server) => {
|
|
26
|
-
server.registerTool(
|
|
27
|
-
'StartTasks',
|
|
28
|
-
{
|
|
29
|
-
title: 'Start Tasks',
|
|
30
|
-
description: START_TASKS_DESCRIPTION,
|
|
31
|
-
inputSchema: z.object({
|
|
32
|
-
tasks: z
|
|
33
|
-
.array(
|
|
34
|
-
z.object({
|
|
35
|
-
description: z
|
|
36
|
-
.string()
|
|
37
|
-
.describe('The description or prompt for the task'),
|
|
38
|
-
type: z
|
|
39
|
-
.enum([
|
|
40
|
-
'default',
|
|
41
|
-
'spec',
|
|
42
|
-
'entity',
|
|
43
|
-
'workspace'
|
|
44
|
-
])
|
|
45
|
-
.describe('The type of definition to load (default, spec, entity or workspace)'),
|
|
46
|
-
name: z
|
|
47
|
-
.string()
|
|
48
|
-
.describe('The name of the spec or entity to load, if type is spec or entity. Otherwise, ignored.')
|
|
49
|
-
.optional(),
|
|
50
|
-
adapter: z
|
|
51
|
-
.string()
|
|
52
|
-
.describe('The adapter to use for the task (e.g. claude-code)')
|
|
53
|
-
.optional(),
|
|
54
|
-
model: z
|
|
55
|
-
.string()
|
|
56
|
-
.describe(TASK_MODEL_DESCRIPTION)
|
|
57
|
-
.optional(),
|
|
58
|
-
permissionMode: z
|
|
59
|
-
.enum(SESSION_PERMISSION_MODES)
|
|
60
|
-
.describe(TASK_PERMISSION_MODE_DESCRIPTION)
|
|
61
|
-
.optional(),
|
|
62
|
-
background: z
|
|
63
|
-
.boolean()
|
|
64
|
-
.describe(TASK_BACKGROUND_DESCRIPTION)
|
|
65
|
-
.optional()
|
|
66
|
-
})
|
|
67
|
-
)
|
|
68
|
-
.describe('List of tasks to start')
|
|
69
|
-
})
|
|
70
|
-
},
|
|
71
|
-
async ({ tasks }) => {
|
|
72
|
-
const inheritedPermissionMode = resolveInheritedPermissionMode()
|
|
73
|
-
const resolvedTasks = tasks.map((task): McpManagedTaskInput & {
|
|
74
|
-
taskId: string
|
|
75
|
-
type: NonNullable<McpManagedTaskInput['type']>
|
|
76
|
-
} => ({
|
|
77
|
-
...task,
|
|
78
|
-
permissionMode: task.permissionMode ?? inheritedPermissionMode,
|
|
79
|
-
type: task.type ?? 'default',
|
|
80
|
-
taskId: uuid()
|
|
81
|
-
}))
|
|
82
|
-
const parentSessionId = getParentSessionId()
|
|
83
|
-
|
|
84
|
-
await callHook('StartTasks', {
|
|
85
|
-
cwd: process.cwd(),
|
|
86
|
-
sessionId: process.env.__VF_PROJECT_AI_SESSION_ID__!,
|
|
87
|
-
tasks: resolvedTasks
|
|
88
|
-
})
|
|
89
|
-
const syncResults = parentSessionId
|
|
90
|
-
? await Promise.allSettled(resolvedTasks.map(task =>
|
|
91
|
-
createChildSession({
|
|
92
|
-
id: task.taskId,
|
|
93
|
-
title: task.name ?? task.description,
|
|
94
|
-
parentSessionId,
|
|
95
|
-
permissionMode: task.permissionMode
|
|
96
|
-
})
|
|
97
|
-
))
|
|
98
|
-
: []
|
|
99
|
-
const results = await Promise.allSettled(resolvedTasks
|
|
100
|
-
.map((task, idx) =>
|
|
101
|
-
taskManager.startTask({
|
|
102
|
-
...task,
|
|
103
|
-
enableServerSync: parentSessionId != null && syncResults[idx]?.status === 'fulfilled'
|
|
104
|
-
})
|
|
105
|
-
))
|
|
106
|
-
|
|
107
|
-
return {
|
|
108
|
-
content: [{
|
|
109
|
-
type: 'text',
|
|
110
|
-
text: JSON.stringify(results.map((r, idx) => {
|
|
111
|
-
const { taskId, description } = resolvedTasks[idx]
|
|
112
|
-
return serializeTaskInfo({
|
|
113
|
-
taskId,
|
|
114
|
-
description,
|
|
115
|
-
status: r.status === 'rejected' ? 'failed' : 'running',
|
|
116
|
-
info: taskManager.getTask(taskId)
|
|
117
|
-
})
|
|
118
|
-
}))
|
|
119
|
-
}]
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
)
|
|
123
|
-
|
|
124
|
-
registerTaskRuntimeTools(server, taskManager)
|
|
125
|
-
})
|
|
126
|
-
}
|