@vibe-forge/mcp 3.0.0 → 3.1.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.
@@ -197,6 +197,40 @@ describe('taskManager fatal error scenarios', () => {
197
197
  }))
198
198
  })
199
199
 
200
+ it('uses the task id as the adapter cache context instead of an inherited parent context', async () => {
201
+ process.env.__VF_PROJECT_AI_CTX_ID__ = 'parent-ctx'
202
+ const { TaskManager } = await import('#~/tools/task/manager.js')
203
+
204
+ mocks.run.mockResolvedValueOnce({
205
+ session: {
206
+ emit: vi.fn(),
207
+ kill: vi.fn()
208
+ }
209
+ })
210
+
211
+ try {
212
+ const managedTaskManager = new TaskManager()
213
+ await managedTaskManager.startTask({
214
+ taskId: 'task-stable-context',
215
+ description: 'trigger',
216
+ adapter: 'codex'
217
+ })
218
+ } finally {
219
+ delete process.env.__VF_PROJECT_AI_CTX_ID__
220
+ }
221
+
222
+ expect(mocks.run).toHaveBeenCalledWith(
223
+ expect.objectContaining({
224
+ env: expect.objectContaining({
225
+ __VF_PROJECT_AI_CTX_ID__: 'task-stable-context'
226
+ })
227
+ }),
228
+ expect.objectContaining({
229
+ sessionId: 'task-stable-context'
230
+ })
231
+ )
232
+ })
233
+
200
234
  it('responds to pending interactions and syncs the response', async () => {
201
235
  const { TaskManager } = await import('#~/tools/task/manager.js')
202
236
  const respondInteraction = vi.fn()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibe-forge/mcp",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "Vibe Forge MCP server",
5
5
  "imports": {
6
6
  "#~/*.js": {
@@ -33,13 +33,13 @@
33
33
  "@modelcontextprotocol/sdk": "^1.25.3",
34
34
  "commander": "^12.1.0",
35
35
  "zod": "^3.24.1",
36
- "@vibe-forge/config": "3.0.0",
37
- "@vibe-forge/hooks": "3.0.0",
38
- "@vibe-forge/register": "3.0.0",
39
- "@vibe-forge/task": "3.0.0",
40
- "@vibe-forge/types": "3.0.0",
41
- "@vibe-forge/utils": "3.0.0",
42
- "@vibe-forge/cli-helper": "3.0.0"
36
+ "@vibe-forge/cli-helper": "3.0.1",
37
+ "@vibe-forge/config": "3.1.0",
38
+ "@vibe-forge/hooks": "3.1.0",
39
+ "@vibe-forge/register": "3.0.1",
40
+ "@vibe-forge/task": "3.1.0",
41
+ "@vibe-forge/types": "3.1.0",
42
+ "@vibe-forge/utils": "3.1.0"
43
43
  },
44
44
  "scripts": {
45
45
  "test": "pnpm -C ../.. exec vitest run --workspace vitest.workspace.ts --project bundler packages/mcp/__tests__"
@@ -342,7 +342,7 @@ export class TaskManager {
342
342
  task.workspaceCwd = resolvedConfig.workspace?.cwd
343
343
  const env = {
344
344
  ...process.env,
345
- __VF_PROJECT_AI_CTX_ID__: process.env.__VF_PROJECT_AI_CTX_ID__ ?? task.taskId,
345
+ __VF_PROJECT_AI_CTX_ID__: task.taskId,
346
346
  __VF_PROJECT_WORKSPACE_FOLDER__: taskCwd,
347
347
  __VF_PROJECT_PRIMARY_WORKSPACE_FOLDER__: rootCwd
348
348
  }
@@ -355,7 +355,7 @@ export class TaskManager {
355
355
  }, env)
356
356
 
357
357
  const injectDefaultSystemPrompt = await loadInjectDefaultSystemPromptValue(taskCwd)
358
- const ctxId = process.env.__VF_PROJECT_AI_CTX_ID__ ?? task.taskId
358
+ const ctxId = task.taskId
359
359
  const { session, resolvedAdapter } = await run({
360
360
  adapter: task.adapter,
361
361
  cwd: taskCwd,
@@ -78,7 +78,9 @@ const buildTaskGuidance = (task: {
78
78
  }
79
79
 
80
80
  if (task.status === 'failed' && hints.length === 0) {
81
- hints.push('Task failed. Inspect logs and lastError, then use SendTaskMessage to resume it or StartTasks to replace it if needed.')
81
+ hints.push(
82
+ 'Task failed. Inspect logs and lastError, then use SendTaskMessage to resume it or StartTasks to replace it if needed.'
83
+ )
82
84
  }
83
85
 
84
86
  return hints
@@ -11,10 +11,14 @@ import {
11
11
  STOP_TASK_DESCRIPTION,
12
12
  SUBMIT_TASK_INPUT_DESCRIPTION,
13
13
  TASK_LOG_LIMIT_DESCRIPTION,
14
- TASK_LOG_ORDER_DESCRIPTION,
15
14
  TASK_LOG_ORDERS,
16
- serializeTaskInfo
15
+ TASK_LOG_ORDER_DESCRIPTION
17
16
  } from './presentation'
17
+ import {
18
+ createSerializedTaskInfoContent,
19
+ createSerializedTaskListContent,
20
+ createTextContent
21
+ } from './task-tool-responses'
18
22
 
19
23
  export const registerTaskRuntimeTools = (
20
24
  server: Parameters<Register>[0],
@@ -43,15 +47,12 @@ export const registerTaskRuntimeTools = (
43
47
  const task = taskManager.getTask(taskId)
44
48
  if (!task) {
45
49
  return {
46
- content: [{ type: 'text', text: `Task ${taskId} not found.` }],
50
+ content: createTextContent(`Task ${taskId} not found.`),
47
51
  isError: true
48
52
  }
49
53
  }
50
54
  return {
51
- content: [{
52
- type: 'text',
53
- text: JSON.stringify([serializeTaskInfo({ taskId, info: task, logLimit, logOrder })])
54
- }]
55
+ content: createSerializedTaskInfoContent({ taskId, info: task, logLimit, logOrder })
55
56
  }
56
57
  }
57
58
  )
@@ -82,15 +83,7 @@ export const registerTaskRuntimeTools = (
82
83
  })
83
84
  const task = taskManager.getTask(taskId)
84
85
  return {
85
- content: [{
86
- type: 'text',
87
- text: JSON.stringify([serializeTaskInfo({
88
- taskId,
89
- info: task,
90
- logLimit: DEFAULT_TASK_LOG_LIMIT,
91
- logOrder: 'desc'
92
- })])
93
- }]
86
+ content: createSerializedTaskInfoContent({ taskId, info: task })
94
87
  }
95
88
  }
96
89
  )
@@ -119,15 +112,7 @@ export const registerTaskRuntimeTools = (
119
112
  })
120
113
  const task = taskManager.getTask(taskId)
121
114
  return {
122
- content: [{
123
- type: 'text',
124
- text: JSON.stringify([serializeTaskInfo({
125
- taskId,
126
- info: task,
127
- logLimit: DEFAULT_TASK_LOG_LIMIT,
128
- logOrder: 'desc'
129
- })])
130
- }]
115
+ content: createSerializedTaskInfoContent({ taskId, info: task })
131
116
  }
132
117
  }
133
118
  )
@@ -156,15 +141,7 @@ export const registerTaskRuntimeTools = (
156
141
  })
157
142
  const task = taskManager.getTask(taskId)
158
143
  return {
159
- content: [{
160
- type: 'text',
161
- text: JSON.stringify([serializeTaskInfo({
162
- taskId,
163
- info: task,
164
- logLimit: DEFAULT_TASK_LOG_LIMIT,
165
- logOrder: 'desc'
166
- })])
167
- }]
144
+ content: createSerializedTaskInfoContent({ taskId, info: task })
168
145
  }
169
146
  }
170
147
  )
@@ -181,10 +158,9 @@ export const registerTaskRuntimeTools = (
181
158
  async ({ taskId }) => {
182
159
  const success = taskManager.stopTask(taskId)
183
160
  return {
184
- content: [{
185
- type: 'text',
186
- text: success ? `Task ${taskId} stopped.` : `Failed to stop task ${taskId} (not found or already stopped).`
187
- }]
161
+ content: createTextContent(
162
+ success ? `Task ${taskId} stopped.` : `Failed to stop task ${taskId} (not found or already stopped).`
163
+ )
188
164
  }
189
165
  }
190
166
  )
@@ -210,15 +186,7 @@ export const registerTaskRuntimeTools = (
210
186
  async ({ logLimit, logOrder }) => {
211
187
  const tasks = taskManager.getAllTasks()
212
188
  return {
213
- content: [{
214
- type: 'text',
215
- text: JSON.stringify(tasks.map(task => serializeTaskInfo({
216
- taskId: task.taskId,
217
- info: task,
218
- logLimit,
219
- logOrder
220
- })))
221
- }]
189
+ content: createSerializedTaskListContent(tasks, logLimit, logOrder)
222
190
  }
223
191
  }
224
192
  )
@@ -0,0 +1,40 @@
1
+ import type { TaskInfo } from './manager'
2
+ import { DEFAULT_TASK_LOG_LIMIT, serializeTaskInfo } from './presentation'
3
+ import type { TaskLogsOrder } from './presentation'
4
+
5
+ interface TextContent {
6
+ type: 'text'
7
+ text: string
8
+ }
9
+
10
+ export const createTextContent = (text: string): TextContent[] => [{
11
+ type: 'text',
12
+ text
13
+ }]
14
+
15
+ export const createSerializedTaskInfoContent = (params: {
16
+ taskId: string
17
+ info?: TaskInfo
18
+ logLimit?: number
19
+ logOrder?: TaskLogsOrder
20
+ }) =>
21
+ createTextContent(JSON.stringify([serializeTaskInfo({
22
+ taskId: params.taskId,
23
+ info: params.info,
24
+ logLimit: params.logLimit ?? DEFAULT_TASK_LOG_LIMIT,
25
+ logOrder: params.logOrder ?? 'desc'
26
+ })]))
27
+
28
+ export const createSerializedTaskListContent = (
29
+ tasks: TaskInfo[],
30
+ logLimit: number,
31
+ logOrder: TaskLogsOrder
32
+ ) =>
33
+ createTextContent(JSON.stringify(tasks.map(task =>
34
+ serializeTaskInfo({
35
+ taskId: task.taskId,
36
+ info: task,
37
+ logLimit,
38
+ logOrder
39
+ })
40
+ )))