@vibe-forge/core 0.7.5 → 0.8.3
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 +4 -46
- package/src/env.ts +5 -25
- package/src/index.ts +0 -5
- package/src/types.ts +13 -72
- package/src/ws.ts +2 -12
- package/src/adapter/index.ts +0 -6
- package/src/adapter/loader.ts +0 -11
- package/src/adapter/type.ts +0 -117
- package/src/config/load.ts +0 -122
- package/src/config/types.ts +0 -289
- package/src/config.ts +0 -2
- package/src/controllers/benchmark/discover.ts +0 -89
- package/src/controllers/benchmark/index.ts +0 -24
- package/src/controllers/benchmark/result-store.ts +0 -46
- package/src/controllers/benchmark/runner.ts +0 -415
- package/src/controllers/benchmark/schema.ts +0 -60
- package/src/controllers/benchmark/types.ts +0 -80
- package/src/controllers/benchmark/utils.ts +0 -144
- package/src/controllers/benchmark/workspace.ts +0 -179
- package/src/controllers/config/index.ts +0 -214
- package/src/controllers/system/assets/completed.mp3 +0 -0
- package/src/controllers/system/assets/mcp.png +0 -0
- package/src/controllers/system/index.ts +0 -102
- package/src/controllers/task/generate-adapter-query-options.ts +0 -25
- package/src/controllers/task/index.ts +0 -2
- package/src/controllers/task/prepare.ts +0 -74
- package/src/controllers/task/run.ts +0 -231
- package/src/controllers/task/schema.ts +0 -131
- package/src/controllers/task/type.ts +0 -6
- package/src/hooks/bridge.ts +0 -368
- package/src/hooks/call.ts +0 -74
- package/src/hooks/index.ts +0 -41
- package/src/hooks/loader.ts +0 -79
- package/src/hooks/native.ts +0 -116
- package/src/hooks/runtime.ts +0 -139
- package/src/hooks/type.ts +0 -145
- package/src/utils/cache.ts +0 -58
- package/src/utils/create-logger.ts +0 -89
- package/src/utils/definition-loader.ts +0 -530
- package/src/utils/filter.ts +0 -26
- package/src/utils/string-transform.ts +0 -37
- package/src/utils/uuid.ts +0 -6
- package/src/utils/workspace-assets.ts +0 -919
package/src/hooks/runtime.ts
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import { Buffer } from 'node:buffer'
|
|
2
|
-
import process from 'node:process'
|
|
3
|
-
|
|
4
|
-
import { loadConfig, resetConfigCache } from '#~/config/load.js'
|
|
5
|
-
import { resolveServerLogLevel } from '#~/env.js'
|
|
6
|
-
import { createLogger } from '#~/utils/create-logger.js'
|
|
7
|
-
import { transformCamelKey } from '#~/utils/string-transform.js'
|
|
8
|
-
|
|
9
|
-
import type { HookInput, HookInputs, HookOutputCore, HookOutputs } from './type'
|
|
10
|
-
import type { HookContext, Plugin } from './index'
|
|
11
|
-
import { resolvePlugins } from './loader'
|
|
12
|
-
|
|
13
|
-
export const callPluginHook = async <K extends keyof HookInputs>(
|
|
14
|
-
eventName: K,
|
|
15
|
-
context: HookContext,
|
|
16
|
-
input: HookInputs[K],
|
|
17
|
-
plugins: Partial<Plugin>[] = []
|
|
18
|
-
): Promise<HookOutputs[K]> => {
|
|
19
|
-
const { logger } = context
|
|
20
|
-
const filteredPlugins = plugins.filter(
|
|
21
|
-
(
|
|
22
|
-
item
|
|
23
|
-
): item is
|
|
24
|
-
& {
|
|
25
|
-
name?: string
|
|
26
|
-
}
|
|
27
|
-
& {
|
|
28
|
-
[P in K]: NonNullable<Plugin[P]>
|
|
29
|
-
} => !!item && !!item[eventName]
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
let index = 0
|
|
33
|
-
|
|
34
|
-
const next = async (): Promise<HookOutputs[K]> => {
|
|
35
|
-
if (index >= filteredPlugins.length) {
|
|
36
|
-
return { continue: true }
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const currentPlugin = filteredPlugins[index]
|
|
40
|
-
const { name = '<anonymous>', [eventName]: hook } = currentPlugin
|
|
41
|
-
index++
|
|
42
|
-
|
|
43
|
-
const withNameLogger = {
|
|
44
|
-
...logger,
|
|
45
|
-
info: logger.info.bind(logger, `[plugin.${name}]`),
|
|
46
|
-
warn: logger.warn.bind(logger, `[plugin.${name}]`),
|
|
47
|
-
debug: logger.debug.bind(logger, `[plugin.${name}]`),
|
|
48
|
-
error: logger.error.bind(logger, `[plugin.${name}]`)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
return await hook(
|
|
53
|
-
{
|
|
54
|
-
...context,
|
|
55
|
-
logger: withNameLogger
|
|
56
|
-
},
|
|
57
|
-
input,
|
|
58
|
-
next
|
|
59
|
-
)
|
|
60
|
-
} catch (error) {
|
|
61
|
-
if (error instanceof Error && !error.name.includes('[plugin.')) {
|
|
62
|
-
error.name = `${error.name}[plugin.${name}]`
|
|
63
|
-
}
|
|
64
|
-
throw error
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return next()
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export const executeHookInput = async (
|
|
72
|
-
input: HookInput,
|
|
73
|
-
env: Record<string, string | null | undefined> = process.env
|
|
74
|
-
) => {
|
|
75
|
-
const workspaceFolder = env.__VF_PROJECT_WORKSPACE_FOLDER__ ?? input.cwd ?? process.env.HOME ?? '/'
|
|
76
|
-
const ctxId = env.__VF_PROJECT_AI_CTX_ID__ ?? input.sessionId ?? 'default'
|
|
77
|
-
const logPrefix = env.__VF_PROJECT_AI_LOG_PREFIX__ ?? ''
|
|
78
|
-
const loggerBase = createLogger(
|
|
79
|
-
workspaceFolder,
|
|
80
|
-
ctxId,
|
|
81
|
-
input.sessionId,
|
|
82
|
-
logPrefix,
|
|
83
|
-
resolveServerLogLevel(env)
|
|
84
|
-
)
|
|
85
|
-
|
|
86
|
-
const logger: typeof loggerBase = {
|
|
87
|
-
...loggerBase,
|
|
88
|
-
info: (...args) => loggerBase.info(`[${input.hookEventName}]`, ...args),
|
|
89
|
-
warn: (...args) => loggerBase.warn(`[${input.hookEventName}]`, ...args),
|
|
90
|
-
debug: (...args) => loggerBase.debug(`[${input.hookEventName}]`, ...args),
|
|
91
|
-
error: (...args) => loggerBase.error(`[${input.hookEventName}]`, ...args)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
resetConfigCache()
|
|
95
|
-
const jsonVariables = {
|
|
96
|
-
...env,
|
|
97
|
-
WORKSPACE_FOLDER: workspaceFolder,
|
|
98
|
-
__VF_PROJECT_WORKSPACE_FOLDER__: workspaceFolder
|
|
99
|
-
}
|
|
100
|
-
const [config, userConfig] = await loadConfig({ jsonVariables })
|
|
101
|
-
const plugins = [
|
|
102
|
-
...await resolvePlugins(config?.plugins ?? [], config?.enabledPlugins ?? {}),
|
|
103
|
-
...await resolvePlugins(userConfig?.plugins ?? [], userConfig?.enabledPlugins ?? {})
|
|
104
|
-
]
|
|
105
|
-
|
|
106
|
-
return callPluginHook(
|
|
107
|
-
input.hookEventName,
|
|
108
|
-
{ logger },
|
|
109
|
-
input as HookInputs[typeof input.hookEventName],
|
|
110
|
-
plugins
|
|
111
|
-
)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export const readHookInput = async () => {
|
|
115
|
-
const stdoutBuffer = await new Promise<Buffer>((resolve) => {
|
|
116
|
-
const chunks: Buffer[] = []
|
|
117
|
-
process.stdin.on('data', chunk => chunks.push(chunk))
|
|
118
|
-
process.stdin.once('end', () => resolve(Buffer.concat(chunks)))
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
return transformCamelKey<HookInput>(
|
|
122
|
-
JSON.parse(stdoutBuffer.toString() || '{}')
|
|
123
|
-
)
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export const runHookCli = async () => {
|
|
127
|
-
try {
|
|
128
|
-
const input = await readHookInput()
|
|
129
|
-
const result = await executeHookInput(input)
|
|
130
|
-
console.log(JSON.stringify(result))
|
|
131
|
-
} catch (error) {
|
|
132
|
-
console.log(
|
|
133
|
-
JSON.stringify({
|
|
134
|
-
continue: false,
|
|
135
|
-
stopReason: `run hook error: ${String(error)}`
|
|
136
|
-
} satisfies HookOutputCore)
|
|
137
|
-
)
|
|
138
|
-
}
|
|
139
|
-
}
|
package/src/hooks/type.ts
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import type { AdapterQueryOptions } from '../adapter'
|
|
2
|
-
|
|
3
|
-
export type HookSource = 'native' | 'bridge'
|
|
4
|
-
|
|
5
|
-
export interface HookToolCall {
|
|
6
|
-
toolCallId?: string
|
|
7
|
-
toolName: string
|
|
8
|
-
toolInput?: unknown
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface HookToolResult extends HookToolCall {
|
|
12
|
-
toolResponse?: unknown
|
|
13
|
-
isError?: boolean
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* https://docs.anthropic.com/en/docs/claude-code/hooks#hook-input
|
|
18
|
-
*/
|
|
19
|
-
export interface HookInputCore {
|
|
20
|
-
cwd: string
|
|
21
|
-
sessionId: string
|
|
22
|
-
hookEventName: keyof HookInputs
|
|
23
|
-
adapter?: string
|
|
24
|
-
runtime?: AdapterQueryOptions['runtime']
|
|
25
|
-
hookSource?: HookSource
|
|
26
|
-
canBlock?: boolean
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface HookInputs {
|
|
30
|
-
/**
|
|
31
|
-
* https://docs.anthropic.com/en/docs/claude-code/hooks#pretooluse-input
|
|
32
|
-
*/
|
|
33
|
-
PreToolUse: HookInputCore & HookToolCall
|
|
34
|
-
/**
|
|
35
|
-
* https://docs.anthropic.com/en/docs/claude-code/hooks#posttooluse-input
|
|
36
|
-
*/
|
|
37
|
-
PostToolUse: HookInputCore & HookToolResult
|
|
38
|
-
Notification: HookInputCore
|
|
39
|
-
UserPromptSubmit: HookInputCore & { prompt: string }
|
|
40
|
-
Stop: HookInputCore & {
|
|
41
|
-
lastAssistantMessage?: string
|
|
42
|
-
}
|
|
43
|
-
SubagentStop: HookInputCore
|
|
44
|
-
PreCompact: HookInputCore
|
|
45
|
-
SessionStart: HookInputCore & {
|
|
46
|
-
source?: 'startup' | 'resume'
|
|
47
|
-
model?: string
|
|
48
|
-
}
|
|
49
|
-
SessionEnd: HookInputCore & {
|
|
50
|
-
reason: string
|
|
51
|
-
exitCode?: number
|
|
52
|
-
stderr?: string
|
|
53
|
-
lastAssistantMessage?: string
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
StartTasks: HookInputCore & {
|
|
57
|
-
tasks: Array<{
|
|
58
|
-
description: string
|
|
59
|
-
type: 'default' | 'spec' | 'entity'
|
|
60
|
-
name?: string
|
|
61
|
-
adapter?: string
|
|
62
|
-
background?: boolean
|
|
63
|
-
}>
|
|
64
|
-
}
|
|
65
|
-
GenerateSystemPrompt: HookInputCore & {
|
|
66
|
-
type?: 'spec' | 'entity'
|
|
67
|
-
name?: string
|
|
68
|
-
data?: unknown
|
|
69
|
-
}
|
|
70
|
-
TaskStart: HookInputCore & {
|
|
71
|
-
adapter?: string
|
|
72
|
-
options: unknown
|
|
73
|
-
adapterOptions: unknown
|
|
74
|
-
}
|
|
75
|
-
TaskStop: HookInputCore & {
|
|
76
|
-
exitCode?: number
|
|
77
|
-
stderr?: string
|
|
78
|
-
adapter?: string
|
|
79
|
-
|
|
80
|
-
options: unknown
|
|
81
|
-
adapterOptions: unknown
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export type HookInput = HookInputs[keyof HookInputs]
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* https://docs.anthropic.com/en/docs/claude-code/hooks#common-json-fields
|
|
89
|
-
*/
|
|
90
|
-
export interface HookOutputCore {
|
|
91
|
-
/**
|
|
92
|
-
* Whether Claude should continue after hook execution
|
|
93
|
-
* @default true
|
|
94
|
-
*/
|
|
95
|
-
continue?: boolean
|
|
96
|
-
/**
|
|
97
|
-
* Message shown when continue is false
|
|
98
|
-
*/
|
|
99
|
-
stopReason?: string
|
|
100
|
-
/**
|
|
101
|
-
* Hide stdout from transcript mode
|
|
102
|
-
* @default false
|
|
103
|
-
*/
|
|
104
|
-
suppressOutput?: boolean
|
|
105
|
-
/**
|
|
106
|
-
* Optional warning message shown to the user
|
|
107
|
-
*/
|
|
108
|
-
systemMessage?: string
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export interface HookOutputs {
|
|
112
|
-
/**
|
|
113
|
-
* https://docs.anthropic.com/en/docs/claude-code/hooks#pretooluse-decision-control
|
|
114
|
-
*/
|
|
115
|
-
PreToolUse: HookOutputCore & {
|
|
116
|
-
hookSpecificOutput?: {
|
|
117
|
-
hookEventName: 'PreToolUse'
|
|
118
|
-
permissionDecision: 'allow' | 'deny' | 'ask'
|
|
119
|
-
permissionDecisionReason: string
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* https://docs.anthropic.com/en/docs/claude-code/hooks#posttooluse-decision-control
|
|
124
|
-
*/
|
|
125
|
-
PostToolUse: HookOutputCore & {
|
|
126
|
-
hookSpecificOutput?: {
|
|
127
|
-
hookEventName: 'PostToolUse'
|
|
128
|
-
additionalContext: string
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
Notification: HookOutputCore
|
|
132
|
-
UserPromptSubmit: HookOutputCore
|
|
133
|
-
Stop: HookOutputCore
|
|
134
|
-
SessionStart: HookOutputCore
|
|
135
|
-
SessionEnd: HookOutputCore
|
|
136
|
-
SubagentStop: HookOutputCore
|
|
137
|
-
PreCompact: HookOutputCore
|
|
138
|
-
|
|
139
|
-
StartTasks: HookOutputCore
|
|
140
|
-
GenerateSystemPrompt: HookOutputCore
|
|
141
|
-
TaskStart: HookOutputCore
|
|
142
|
-
TaskStop: HookOutputCore
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export type HookOutput = HookOutputs[keyof HookOutputs]
|
package/src/utils/cache.ts
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import * as fs from 'node:fs/promises'
|
|
2
|
-
import { dirname, resolve } from 'node:path'
|
|
3
|
-
|
|
4
|
-
import type { Cache } from '@vibe-forge/core'
|
|
5
|
-
|
|
6
|
-
declare module '@vibe-forge/core' {
|
|
7
|
-
interface Cache {
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export const getCachePath = (
|
|
12
|
-
cwd: string,
|
|
13
|
-
taskId: string,
|
|
14
|
-
sessionId: string | undefined,
|
|
15
|
-
key: keyof Cache
|
|
16
|
-
) => {
|
|
17
|
-
const taskDir = resolve(cwd, '.ai/caches', taskId)
|
|
18
|
-
const cacheDir = sessionId ? resolve(taskDir, sessionId) : taskDir
|
|
19
|
-
return resolve(cacheDir, `${key}.json`)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export const setCache = async <K extends keyof Cache>(
|
|
23
|
-
cwd: string,
|
|
24
|
-
taskId: string,
|
|
25
|
-
sessionId: string | undefined,
|
|
26
|
-
key: K,
|
|
27
|
-
value: Cache[K]
|
|
28
|
-
) => {
|
|
29
|
-
const cachePath = getCachePath(cwd, taskId, sessionId, key)
|
|
30
|
-
const cacheDir = dirname(cachePath)
|
|
31
|
-
try {
|
|
32
|
-
await fs.access(cacheDir)
|
|
33
|
-
} catch {
|
|
34
|
-
await fs.mkdir(cacheDir, { recursive: true })
|
|
35
|
-
}
|
|
36
|
-
await fs.writeFile(cachePath, JSON.stringify(value, null, 2), {
|
|
37
|
-
flag: 'w'
|
|
38
|
-
})
|
|
39
|
-
return { cachePath }
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export const getCache = async <K extends keyof Cache>(
|
|
43
|
-
cwd: string,
|
|
44
|
-
taskId: string,
|
|
45
|
-
sessionId: string | undefined,
|
|
46
|
-
key: K
|
|
47
|
-
): Promise<Cache[K] | undefined> => {
|
|
48
|
-
const cachePath = getCachePath(cwd, taskId, sessionId, key)
|
|
49
|
-
try {
|
|
50
|
-
await fs.access(cachePath)
|
|
51
|
-
} catch (error) {
|
|
52
|
-
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
53
|
-
return undefined
|
|
54
|
-
}
|
|
55
|
-
throw error
|
|
56
|
-
}
|
|
57
|
-
return JSON.parse(await fs.readFile(cachePath, 'utf-8'))
|
|
58
|
-
}
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { createWriteStream, existsSync, mkdirSync } from 'node:fs'
|
|
2
|
-
import { dirname, resolve } from 'node:path'
|
|
3
|
-
|
|
4
|
-
import type { LogLevel } from '#~/env.js'
|
|
5
|
-
|
|
6
|
-
export interface Logger {
|
|
7
|
-
stream: NodeJS.WritableStream
|
|
8
|
-
info: (...args: unknown[]) => void
|
|
9
|
-
warn: (...args: unknown[]) => void
|
|
10
|
-
debug: (...args: unknown[]) => void
|
|
11
|
-
error: (...args: unknown[]) => void
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {
|
|
15
|
-
debug: 10,
|
|
16
|
-
info: 20,
|
|
17
|
-
warn: 30,
|
|
18
|
-
error: 40
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export const createLogger = (
|
|
22
|
-
cwd: string,
|
|
23
|
-
taskId: string,
|
|
24
|
-
sessionId: string,
|
|
25
|
-
logPrefix = '',
|
|
26
|
-
level: LogLevel = 'info'
|
|
27
|
-
) => {
|
|
28
|
-
const normalizedSessionId = sessionId ?? 'default'
|
|
29
|
-
const taskDir = resolve(
|
|
30
|
-
cwd,
|
|
31
|
-
`.ai${logPrefix}/logs/${taskId}`
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
const loggerFilePath = resolve(
|
|
35
|
-
taskDir,
|
|
36
|
-
`${normalizedSessionId}.log.md`
|
|
37
|
-
)
|
|
38
|
-
// 默认日志文件不存在时,创建一个默认的日志文件
|
|
39
|
-
if (!existsSync(loggerFilePath)) {
|
|
40
|
-
mkdirSync(dirname(loggerFilePath), { recursive: true })
|
|
41
|
-
}
|
|
42
|
-
const loggerStream = createWriteStream(loggerFilePath, {
|
|
43
|
-
flags: 'a'
|
|
44
|
-
})
|
|
45
|
-
const createLog = (tag: string, currentLevel: LogLevel) => (...args: unknown[]) => {
|
|
46
|
-
if (LOG_LEVEL_PRIORITY[currentLevel] < LOG_LEVEL_PRIORITY[level]) {
|
|
47
|
-
return
|
|
48
|
-
}
|
|
49
|
-
const msg = args
|
|
50
|
-
.map((arg) => {
|
|
51
|
-
if (typeof arg === 'string') {
|
|
52
|
-
return arg
|
|
53
|
-
}
|
|
54
|
-
if (arg instanceof Error) {
|
|
55
|
-
return (
|
|
56
|
-
'\n```text\n' +
|
|
57
|
-
`${arg.stack}\n` +
|
|
58
|
-
'```'
|
|
59
|
-
)
|
|
60
|
-
}
|
|
61
|
-
return (
|
|
62
|
-
'\n```json\n' +
|
|
63
|
-
`${JSON.stringify(arg, null, 2)}\n` +
|
|
64
|
-
'```'
|
|
65
|
-
)
|
|
66
|
-
})
|
|
67
|
-
.join(' ')
|
|
68
|
-
const now = new Date().toLocaleString()
|
|
69
|
-
if (loggerStream.writableEnded) {
|
|
70
|
-
const tempLoggerStream = createWriteStream(loggerFilePath, {
|
|
71
|
-
flags: 'a'
|
|
72
|
-
})
|
|
73
|
-
tempLoggerStream.write(
|
|
74
|
-
`# [${now}] __E__ UNEXPECTED LOGGER STREAM ENDED\n`
|
|
75
|
-
)
|
|
76
|
-
tempLoggerStream.write(`# [${now}] __${tag}__ ${msg}\n`)
|
|
77
|
-
tempLoggerStream.end()
|
|
78
|
-
return
|
|
79
|
-
}
|
|
80
|
-
loggerStream.write(`# [${now}] __${tag}__ ${msg}\n`)
|
|
81
|
-
}
|
|
82
|
-
return {
|
|
83
|
-
stream: loggerStream,
|
|
84
|
-
info: createLog('I', 'info'),
|
|
85
|
-
warn: createLog('W', 'warn'),
|
|
86
|
-
debug: createLog('D', 'debug'),
|
|
87
|
-
error: createLog('E', 'error')
|
|
88
|
-
}
|
|
89
|
-
}
|