@ai-sdk/harness-claude-code 1.0.65 → 1.0.67
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/CHANGELOG.md +19 -0
- package/README.md +13 -0
- package/dist/bridge/index.mjs +49 -36
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/index.d.ts +24674 -397
- package/dist/index.js +361 -23
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/bridge/create-emit-stream-event.ts +18 -1
- package/src/bridge/index.ts +11 -63
- package/src/bridge/tool-filtering.ts +58 -0
- package/src/claude-code-bridge-protocol.ts +2 -0
- package/src/claude-code-harness.ts +401 -19
package/src/bridge/index.ts
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
import { createCompactionLatch } from './compaction-latch';
|
|
13
13
|
import type { StartMessage } from '../claude-code-bridge-protocol';
|
|
14
14
|
import { randomUUID } from 'node:crypto';
|
|
15
|
-
import { argv, stdout } from 'node:process';
|
|
15
|
+
import { argv, env as procEnv, stdout } from 'node:process';
|
|
16
16
|
|
|
17
17
|
/*
|
|
18
18
|
* CONSTRAINT — the third-party imports below are NEVER bundled into the
|
|
@@ -44,6 +44,10 @@ import {
|
|
|
44
44
|
type ClaudeMessage,
|
|
45
45
|
} from './create-emit-stream-event';
|
|
46
46
|
import { jsonSchemaToZodShape } from './json-schema-to-zod';
|
|
47
|
+
import {
|
|
48
|
+
resolveInactiveNativeTools,
|
|
49
|
+
resolveNativeTools,
|
|
50
|
+
} from './tool-filtering';
|
|
47
51
|
|
|
48
52
|
/*
|
|
49
53
|
* Native Claude Code tool name → cross-harness common name. Tools outside this
|
|
@@ -69,37 +73,6 @@ const NATIVE_TO_COMMON: Readonly<Record<string, CommonBuiltinToolName>> = {
|
|
|
69
73
|
WebSearch: 'webSearch',
|
|
70
74
|
};
|
|
71
75
|
|
|
72
|
-
const PUBLIC_TO_NATIVE: Readonly<Record<string, string>> = {
|
|
73
|
-
read: 'Read',
|
|
74
|
-
write: 'Write',
|
|
75
|
-
edit: 'Edit',
|
|
76
|
-
bash: 'Bash',
|
|
77
|
-
glob: 'Glob',
|
|
78
|
-
grep: 'Grep',
|
|
79
|
-
webSearch: 'WebSearch',
|
|
80
|
-
WebFetch: 'WebFetch',
|
|
81
|
-
NotebookEdit: 'NotebookEdit',
|
|
82
|
-
TodoWrite: 'TodoWrite',
|
|
83
|
-
Agent: 'Agent',
|
|
84
|
-
TaskCreate: 'TaskCreate',
|
|
85
|
-
TaskGet: 'TaskGet',
|
|
86
|
-
TaskUpdate: 'TaskUpdate',
|
|
87
|
-
TaskList: 'TaskList',
|
|
88
|
-
TaskStop: 'TaskStop',
|
|
89
|
-
TaskOutput: 'TaskOutput',
|
|
90
|
-
Monitor: 'Monitor',
|
|
91
|
-
ListMcpResources: 'ListMcpResources',
|
|
92
|
-
ReadMcpResource: 'ReadMcpResource',
|
|
93
|
-
ExitPlanMode: 'ExitPlanMode',
|
|
94
|
-
EnterWorktree: 'EnterWorktree',
|
|
95
|
-
ExitWorktree: 'ExitWorktree',
|
|
96
|
-
AskUserQuestion: 'AskUserQuestion',
|
|
97
|
-
Skill: 'Skill',
|
|
98
|
-
ToolSearch: 'ToolSearch',
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const PUBLIC_TOOL_NAMES = Object.keys(PUBLIC_TO_NATIVE);
|
|
102
|
-
|
|
103
76
|
const NATIVE_TOOL_KINDS: Readonly<
|
|
104
77
|
Record<string, 'readonly' | 'edit' | 'bash'>
|
|
105
78
|
> = {
|
|
@@ -134,34 +107,6 @@ function toCommonName(nativeName: string): CommonBuiltinToolName | string {
|
|
|
134
107
|
return NATIVE_TO_COMMON[nativeName] ?? nativeName;
|
|
135
108
|
}
|
|
136
109
|
|
|
137
|
-
function toNativeName(toolName: string): string {
|
|
138
|
-
return PUBLIC_TO_NATIVE[toolName] ?? toolName;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function resolveNativeTools(start: StartMessage): string[] | undefined {
|
|
142
|
-
const toolFiltering = start.builtinToolFiltering;
|
|
143
|
-
if (toolFiltering == null) return undefined;
|
|
144
|
-
const activeToolNames =
|
|
145
|
-
toolFiltering.mode === 'allow'
|
|
146
|
-
? toolFiltering.toolNames
|
|
147
|
-
: PUBLIC_TOOL_NAMES.filter(
|
|
148
|
-
name => !toolFiltering.toolNames.includes(name),
|
|
149
|
-
);
|
|
150
|
-
return activeToolNames.map(name => toNativeName(name));
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function resolveInactiveNativeTools(start: StartMessage): string[] {
|
|
154
|
-
const toolFiltering = start.builtinToolFiltering;
|
|
155
|
-
if (toolFiltering == null) return [];
|
|
156
|
-
const inactiveToolNames =
|
|
157
|
-
toolFiltering.mode === 'allow'
|
|
158
|
-
? PUBLIC_TOOL_NAMES.filter(
|
|
159
|
-
name => !toolFiltering.toolNames.includes(name),
|
|
160
|
-
)
|
|
161
|
-
: toolFiltering.toolNames;
|
|
162
|
-
return inactiveToolNames.map(name => toNativeName(name));
|
|
163
|
-
}
|
|
164
|
-
|
|
165
110
|
const args = parseArgs(argv.slice(2));
|
|
166
111
|
const workdir = args.workdir;
|
|
167
112
|
const bridgeStateDir = args.bridgeStateDir;
|
|
@@ -315,7 +260,7 @@ async function runTurn(start: StartMessage, turn: BridgeTurn): Promise<void> {
|
|
|
315
260
|
|
|
316
261
|
const streamEventState = createClaudeStreamEventState();
|
|
317
262
|
|
|
318
|
-
const mcpServers: Record<string, unknown> = {};
|
|
263
|
+
const mcpServers: Record<string, unknown> = { ...(start.mcpServers ?? {}) };
|
|
319
264
|
if (start.tools && start.tools.length > 0) {
|
|
320
265
|
const server = new mcpModule.McpServer({
|
|
321
266
|
name: 'harness-tools',
|
|
@@ -372,8 +317,10 @@ async function runTurn(start: StartMessage, turn: BridgeTurn): Promise<void> {
|
|
|
372
317
|
abortSignal: abortCtl.signal,
|
|
373
318
|
});
|
|
374
319
|
const skillsOption = toClaudeSkillsOption(start.skills);
|
|
375
|
-
const nativeTools = resolveNativeTools(start);
|
|
376
|
-
const inactiveNativeTools = resolveInactiveNativeTools(
|
|
320
|
+
const nativeTools = resolveNativeTools(start.builtinToolFiltering);
|
|
321
|
+
const inactiveNativeTools = resolveInactiveNativeTools(
|
|
322
|
+
start.builtinToolFiltering,
|
|
323
|
+
);
|
|
377
324
|
const permissionOptions = createPermissionOptions({
|
|
378
325
|
start,
|
|
379
326
|
inactiveNativeTools,
|
|
@@ -391,6 +338,7 @@ async function runTurn(start: StartMessage, turn: BridgeTurn): Promise<void> {
|
|
|
391
338
|
options: {
|
|
392
339
|
...(start.model ? { model: start.model } : {}),
|
|
393
340
|
...(start.maxTurns !== undefined ? { maxTurns: start.maxTurns } : {}),
|
|
341
|
+
...(start.env !== undefined ? { env: { ...procEnv, ...start.env } } : {}),
|
|
394
342
|
...(skillsOption ? { skills: skillsOption } : {}),
|
|
395
343
|
...(nativeTools !== undefined ? { tools: nativeTools } : {}),
|
|
396
344
|
...(inactiveNativeTools.length > 0
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { StartMessage } from '../claude-code-bridge-protocol';
|
|
2
|
+
|
|
3
|
+
type BuiltinToolFiltering = StartMessage['builtinToolFiltering'];
|
|
4
|
+
|
|
5
|
+
const PUBLIC_TO_NATIVE: Readonly<Record<string, string>> = {
|
|
6
|
+
read: 'Read',
|
|
7
|
+
write: 'Write',
|
|
8
|
+
edit: 'Edit',
|
|
9
|
+
bash: 'Bash',
|
|
10
|
+
glob: 'Glob',
|
|
11
|
+
grep: 'Grep',
|
|
12
|
+
webSearch: 'WebSearch',
|
|
13
|
+
WebFetch: 'WebFetch',
|
|
14
|
+
NotebookEdit: 'NotebookEdit',
|
|
15
|
+
TodoWrite: 'TodoWrite',
|
|
16
|
+
Agent: 'Agent',
|
|
17
|
+
TaskCreate: 'TaskCreate',
|
|
18
|
+
TaskGet: 'TaskGet',
|
|
19
|
+
TaskUpdate: 'TaskUpdate',
|
|
20
|
+
TaskList: 'TaskList',
|
|
21
|
+
TaskStop: 'TaskStop',
|
|
22
|
+
TaskOutput: 'TaskOutput',
|
|
23
|
+
Monitor: 'Monitor',
|
|
24
|
+
ListMcpResources: 'ListMcpResources',
|
|
25
|
+
ReadMcpResource: 'ReadMcpResource',
|
|
26
|
+
ExitPlanMode: 'ExitPlanMode',
|
|
27
|
+
EnterWorktree: 'EnterWorktree',
|
|
28
|
+
ExitWorktree: 'ExitWorktree',
|
|
29
|
+
AskUserQuestion: 'AskUserQuestion',
|
|
30
|
+
Skill: 'Skill',
|
|
31
|
+
ToolSearch: 'ToolSearch',
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const PUBLIC_TOOL_NAMES = Object.keys(PUBLIC_TO_NATIVE);
|
|
35
|
+
|
|
36
|
+
function toNativeName(toolName: string): string {
|
|
37
|
+
return PUBLIC_TO_NATIVE[toolName] ?? toolName;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function resolveNativeTools(
|
|
41
|
+
toolFiltering: BuiltinToolFiltering,
|
|
42
|
+
): string[] | undefined {
|
|
43
|
+
if (toolFiltering == null || toolFiltering.mode === 'deny') return undefined;
|
|
44
|
+
return toolFiltering.toolNames.map(name => toNativeName(name));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function resolveInactiveNativeTools(
|
|
48
|
+
toolFiltering: BuiltinToolFiltering,
|
|
49
|
+
): string[] {
|
|
50
|
+
if (toolFiltering == null) return [];
|
|
51
|
+
const inactiveToolNames =
|
|
52
|
+
toolFiltering.mode === 'allow'
|
|
53
|
+
? PUBLIC_TOOL_NAMES.filter(
|
|
54
|
+
name => !toolFiltering.toolNames.includes(name),
|
|
55
|
+
)
|
|
56
|
+
: toolFiltering.toolNames;
|
|
57
|
+
return inactiveToolNames.map(name => toNativeName(name));
|
|
58
|
+
}
|
|
@@ -33,7 +33,9 @@ const thinkingSchema = z.discriminatedUnion('type', [
|
|
|
33
33
|
export const startMessageSchema = harnessV1BridgeStartBaseSchema.extend({
|
|
34
34
|
thinking: thinkingSchema,
|
|
35
35
|
maxTurns: z.number().optional(),
|
|
36
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
36
37
|
skills: z.array(z.string()).optional(),
|
|
38
|
+
mcpServers: z.record(z.string(), z.unknown()).optional(),
|
|
37
39
|
// Resume signal. When true, the bridge passes `{ continue: true }` to the
|
|
38
40
|
// Claude SDK so the in-workdir thread state is rehydrated. The host sets this
|
|
39
41
|
// on the first prompt after a cross-process resume.
|