@vibe-forge/mcp 2.0.0 → 2.0.1
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.
|
@@ -94,6 +94,28 @@ describe('task tool integration', () => {
|
|
|
94
94
|
}))
|
|
95
95
|
})
|
|
96
96
|
|
|
97
|
+
it('accepts workspace tasks without a separate workspace tool', async () => {
|
|
98
|
+
const { createTaskRegister } = await import('#~/tools/task/index.js')
|
|
99
|
+
|
|
100
|
+
const tester = createToolTester()
|
|
101
|
+
createTaskRegister()(tester.mockRegister)
|
|
102
|
+
|
|
103
|
+
await tester.callTool('StartTasks', {
|
|
104
|
+
tasks: [{
|
|
105
|
+
description: 'fix billing',
|
|
106
|
+
type: 'workspace',
|
|
107
|
+
name: 'billing'
|
|
108
|
+
}]
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
expect(mocks.startTask).toHaveBeenCalledWith(expect.objectContaining({
|
|
112
|
+
taskId: 'task-1',
|
|
113
|
+
description: 'fix billing',
|
|
114
|
+
type: 'workspace',
|
|
115
|
+
name: 'billing'
|
|
116
|
+
}))
|
|
117
|
+
})
|
|
118
|
+
|
|
97
119
|
it('inherits the parent permission mode when the task does not specify one', async () => {
|
|
98
120
|
process.env.__VF_PROJECT_AI_PERMISSION_MODE__ = 'dontAsk'
|
|
99
121
|
mocks.getParentSessionId.mockReturnValue('parent-session')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibe-forge/mcp",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Vibe Forge MCP server",
|
|
5
5
|
"imports": {
|
|
6
6
|
"#~/*.js": {
|
|
@@ -31,15 +31,15 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@modelcontextprotocol/sdk": "^1.25.3",
|
|
34
|
+
"@vibe-forge/config": "^2.0.2",
|
|
34
35
|
"commander": "^12.1.0",
|
|
35
36
|
"zod": "^3.24.1",
|
|
36
|
-
"@vibe-forge/hooks": "^2.0.
|
|
37
|
-
"@vibe-forge/
|
|
38
|
-
"@vibe-forge/
|
|
39
|
-
"@vibe-forge/
|
|
40
|
-
"@vibe-forge/
|
|
41
|
-
"@vibe-forge/
|
|
42
|
-
"@vibe-forge/cli-helper": "^2.0.0"
|
|
37
|
+
"@vibe-forge/hooks": "^2.0.1",
|
|
38
|
+
"@vibe-forge/register": "^2.0.1",
|
|
39
|
+
"@vibe-forge/cli-helper": "^2.0.1",
|
|
40
|
+
"@vibe-forge/utils": "^2.0.1",
|
|
41
|
+
"@vibe-forge/types": "^2.0.1",
|
|
42
|
+
"@vibe-forge/task": "^2.0.1"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
45
|
"test": "pnpm -C ../.. exec vitest run --workspace vitest.workspace.ts --project bundler packages/mcp/__tests__"
|
package/src/tools/task/index.ts
CHANGED
|
@@ -38,9 +38,10 @@ export const createTaskRegister = () => {
|
|
|
38
38
|
.enum([
|
|
39
39
|
'default',
|
|
40
40
|
'spec',
|
|
41
|
-
'entity'
|
|
41
|
+
'entity',
|
|
42
|
+
'workspace'
|
|
42
43
|
])
|
|
43
|
-
.describe('The type of definition to load (default, spec or
|
|
44
|
+
.describe('The type of definition to load (default, spec, entity or workspace)'),
|
|
44
45
|
name: z
|
|
45
46
|
.string()
|
|
46
47
|
.describe('The name of the spec or entity to load, if type is spec or entity. Otherwise, ignored.')
|
|
@@ -52,8 +52,9 @@ export interface TaskInfo {
|
|
|
52
52
|
taskId: string
|
|
53
53
|
adapter?: string
|
|
54
54
|
description: string
|
|
55
|
-
type?: 'default' | 'spec' | 'entity'
|
|
55
|
+
type?: 'default' | 'spec' | 'entity' | 'workspace'
|
|
56
56
|
name?: string
|
|
57
|
+
workspaceCwd?: string
|
|
57
58
|
permissionMode?: SessionPermissionMode
|
|
58
59
|
background?: boolean
|
|
59
60
|
status: 'running' | 'waiting_input' | 'completed' | 'failed'
|
|
@@ -230,7 +231,7 @@ export class TaskManager {
|
|
|
230
231
|
public async startTask(options: {
|
|
231
232
|
taskId: string
|
|
232
233
|
description: string
|
|
233
|
-
type?: 'default' | 'spec' | 'entity'
|
|
234
|
+
type?: 'default' | 'spec' | 'entity' | 'workspace'
|
|
234
235
|
name?: string
|
|
235
236
|
permissionMode?: 'default' | 'acceptEdits' | 'plan' | 'dontAsk' | 'bypassPermissions'
|
|
236
237
|
adapter?: string
|
|
@@ -286,6 +287,7 @@ export class TaskManager {
|
|
|
286
287
|
|
|
287
288
|
private async launchTask(task: TaskInfo, runType: 'create' | 'resume') {
|
|
288
289
|
try {
|
|
290
|
+
const rootCwd = process.cwd()
|
|
289
291
|
const promptType = task.type !== 'default' ? task.type : undefined
|
|
290
292
|
const promptName = task.name
|
|
291
293
|
const promptCWD = process.cwd()
|
|
@@ -297,25 +299,29 @@ export class TaskManager {
|
|
|
297
299
|
adapter: task.adapter
|
|
298
300
|
}
|
|
299
301
|
)
|
|
302
|
+
const taskCwd = resolvedConfig.workspace?.cwd ?? promptCWD
|
|
303
|
+
task.workspaceCwd = resolvedConfig.workspace?.cwd
|
|
300
304
|
const env = {
|
|
301
305
|
...process.env,
|
|
302
|
-
__VF_PROJECT_AI_CTX_ID__: process.env.__VF_PROJECT_AI_CTX_ID__ ?? task.taskId
|
|
306
|
+
__VF_PROJECT_AI_CTX_ID__: process.env.__VF_PROJECT_AI_CTX_ID__ ?? task.taskId,
|
|
307
|
+
__VF_PROJECT_WORKSPACE_FOLDER__: taskCwd,
|
|
308
|
+
__VF_PROJECT_PRIMARY_WORKSPACE_FOLDER__: rootCwd
|
|
303
309
|
}
|
|
304
310
|
await callHook('GenerateSystemPrompt', {
|
|
305
|
-
cwd:
|
|
311
|
+
cwd: taskCwd,
|
|
306
312
|
sessionId: task.taskId,
|
|
307
313
|
type: promptType,
|
|
308
314
|
name: promptName,
|
|
309
315
|
data
|
|
310
316
|
}, env)
|
|
311
317
|
|
|
312
|
-
const injectDefaultSystemPrompt = await loadInjectDefaultSystemPromptValue(
|
|
318
|
+
const injectDefaultSystemPrompt = await loadInjectDefaultSystemPromptValue(taskCwd)
|
|
313
319
|
const ctxId = process.env.__VF_PROJECT_AI_CTX_ID__ ?? task.taskId
|
|
314
320
|
const { session, resolvedAdapter } = await run({
|
|
315
321
|
adapter: task.adapter,
|
|
316
|
-
cwd:
|
|
322
|
+
cwd: taskCwd,
|
|
317
323
|
env: {
|
|
318
|
-
...
|
|
324
|
+
...env,
|
|
319
325
|
__VF_PROJECT_AI_CTX_ID__: ctxId
|
|
320
326
|
}
|
|
321
327
|
}, {
|
|
@@ -352,7 +358,7 @@ export class TaskManager {
|
|
|
352
358
|
current.lastError = undefined
|
|
353
359
|
try {
|
|
354
360
|
await syncTaskPermissionStateMirror({
|
|
355
|
-
cwd:
|
|
361
|
+
cwd: taskCwd,
|
|
356
362
|
adapter: current.adapter,
|
|
357
363
|
sessionId: current.taskId,
|
|
358
364
|
permissionState: current.permissionState
|
|
@@ -7,7 +7,7 @@ import type { TaskInfo } from './manager'
|
|
|
7
7
|
export const SESSION_PERMISSION_MODES = ['default', 'acceptEdits', 'plan', 'dontAsk', 'bypassPermissions'] as const
|
|
8
8
|
|
|
9
9
|
export const START_TASKS_DESCRIPTION =
|
|
10
|
-
'Start multiple tasks in background or foreground. If a task stalls, fails, or asks for permission/input, call GetTaskInfo. If GetTaskInfo returns pendingInput or pendingInteraction, resolve it with SubmitTaskInput. If logs show permission_required, you can answer the recovery prompt with SubmitTaskInput instead of restarting manually.'
|
|
10
|
+
'Start multiple tasks in background or foreground. Use type "workspace" plus name to run in a configured workspace. If a task stalls, fails, or asks for permission/input, call GetTaskInfo. If GetTaskInfo returns pendingInput or pendingInteraction, resolve it with SubmitTaskInput. If logs show permission_required, you can answer the recovery prompt with SubmitTaskInput instead of restarting manually.'
|
|
11
11
|
|
|
12
12
|
export const GET_TASK_INFO_DESCRIPTION =
|
|
13
13
|
'Get the detailed status, logs, pendingInput, pendingInteraction, lastError, and guidance for a task. Use this when a task seems stuck, is waiting for permission/input, or has failed. If pendingInput is present, answer it with SubmitTaskInput.'
|