@ai-sdk/harness-claude-code 1.0.96 → 1.0.97
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 +16 -0
- package/dist/bridge/index.mjs +60 -13
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/bridge/package.json +3 -3
- package/dist/bridge/pnpm-lock.yaml +128 -126
- package/dist/bridge/pnpm-workspace.yaml +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +32 -25
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/src/bridge/index.ts +69 -8
- package/src/bridge/package.json +3 -3
- package/src/bridge/pnpm-lock.yaml +128 -126
- package/src/bridge/pnpm-workspace.yaml +1 -1
- package/src/claude-code-harness.ts +49 -35
|
@@ -90,6 +90,8 @@ export type ClaudeCodeHarnessSettings = {
|
|
|
90
90
|
/**
|
|
91
91
|
* Anthropic model id the underlying `claude` CLI should use. Leaving this
|
|
92
92
|
* unset defers to the CLI's default.
|
|
93
|
+
*
|
|
94
|
+
* @deprecated Use `model` on `HarnessAgent` instead.
|
|
93
95
|
*/
|
|
94
96
|
readonly model?: string;
|
|
95
97
|
/**
|
|
@@ -829,6 +831,7 @@ export function createClaudeCode(
|
|
|
829
831
|
lifecycleStateSchema: claudeCodeResumeStateSchema,
|
|
830
832
|
getBootstrap: getClaudeCodeBootstrap,
|
|
831
833
|
doStart: async startOpts => {
|
|
834
|
+
const model = startOpts.model ?? settings.model;
|
|
832
835
|
const sandboxSession = startOpts.sandboxSession;
|
|
833
836
|
const toolSafeSandboxSession =
|
|
834
837
|
getRestrictedSandboxSession(sandboxSession);
|
|
@@ -920,6 +923,10 @@ export function createClaudeCode(
|
|
|
920
923
|
);
|
|
921
924
|
|
|
922
925
|
const workDir = startOpts.sessionWorkDir;
|
|
926
|
+
const sandboxHomeDir = await resolveSandboxHomeDir({
|
|
927
|
+
sandbox: toolSafeSandboxSession,
|
|
928
|
+
abortSignal: startOpts.abortSignal,
|
|
929
|
+
});
|
|
923
930
|
const sessionDataDir = `${defaultWorkingDirectory}/.agent-runs/${startOpts.sessionId}`;
|
|
924
931
|
const bridgeStateDir = `${sessionDataDir}/bridge`;
|
|
925
932
|
const timeoutMs = settings.startupTimeoutMs ?? 120_000;
|
|
@@ -991,7 +998,7 @@ export function createClaudeCode(
|
|
|
991
998
|
// process handle. The session lifecycle method decides whether the
|
|
992
999
|
// sandbox is left running, stopped, or destroyed.
|
|
993
1000
|
proc: undefined,
|
|
994
|
-
model
|
|
1001
|
+
model,
|
|
995
1002
|
maxTurns: settings.maxTurns,
|
|
996
1003
|
env: sandboxClaudeEnvironment,
|
|
997
1004
|
thinking,
|
|
@@ -1006,7 +1013,8 @@ export function createClaudeCode(
|
|
|
1006
1013
|
debug: startOpts.observability?.debug,
|
|
1007
1014
|
permissionMode: startOpts.permissionMode,
|
|
1008
1015
|
builtinToolFiltering: startOpts.builtinToolFiltering,
|
|
1009
|
-
|
|
1016
|
+
sandbox: toolSafeSandboxSession,
|
|
1017
|
+
sandboxHomeDir,
|
|
1010
1018
|
mcpServers: settings.mcpServers,
|
|
1011
1019
|
supportsUserMessageResponses: () => supportsUserMessageResponses,
|
|
1012
1020
|
});
|
|
@@ -1039,13 +1047,6 @@ export function createClaudeCode(
|
|
|
1039
1047
|
}
|
|
1040
1048
|
}
|
|
1041
1049
|
|
|
1042
|
-
const sandboxHomeDir =
|
|
1043
|
-
startOpts.skills && startOpts.skills.length > 0
|
|
1044
|
-
? await resolveSandboxHomeDir({
|
|
1045
|
-
sandbox: toolSafeSandboxSession,
|
|
1046
|
-
abortSignal: startOpts.abortSignal,
|
|
1047
|
-
})
|
|
1048
|
-
: undefined;
|
|
1049
1050
|
const port = resolveBridgePort({
|
|
1050
1051
|
sandboxSession,
|
|
1051
1052
|
override: settings.port,
|
|
@@ -1057,35 +1058,21 @@ export function createClaudeCode(
|
|
|
1057
1058
|
const env = {
|
|
1058
1059
|
BRIDGE_CHANNEL_TOKEN: token,
|
|
1059
1060
|
BRIDGE_WS_PORT: String(port),
|
|
1060
|
-
...(sandboxHomeDir ? { HOME: sandboxHomeDir } : {}),
|
|
1061
1061
|
...(respawnStrategy === 'replay'
|
|
1062
1062
|
? { BRIDGE_REPLAY_FROM_DISK: '1' }
|
|
1063
1063
|
: {}),
|
|
1064
1064
|
};
|
|
1065
1065
|
|
|
1066
1066
|
/*
|
|
1067
|
-
* On a fresh start the workdir
|
|
1068
|
-
*
|
|
1069
|
-
*
|
|
1070
|
-
* spawn — `BRIDGE_CHANNEL_TOKEN` rotates per start.
|
|
1067
|
+
* On a fresh start the workdir and bridge-state directory must be
|
|
1068
|
+
* created. The env is sent fresh on every spawn —
|
|
1069
|
+
* `BRIDGE_CHANNEL_TOKEN` rotates per start.
|
|
1071
1070
|
*/
|
|
1072
1071
|
if (respawnStrategy === undefined) {
|
|
1073
1072
|
await toolSafeSandboxSession.run({
|
|
1074
1073
|
command: `mkdir -p ${shellQuote(workDir)} ${shellQuote(bridgeStateDir)}`,
|
|
1075
1074
|
abortSignal: startOpts.abortSignal,
|
|
1076
1075
|
});
|
|
1077
|
-
|
|
1078
|
-
if (startOpts.skills && startOpts.skills.length > 0) {
|
|
1079
|
-
if (!sandboxHomeDir) {
|
|
1080
|
-
throw new Error('Unable to resolve sandbox HOME directory.');
|
|
1081
|
-
}
|
|
1082
|
-
await writeClaudeCodeSkills({
|
|
1083
|
-
sandbox: toolSafeSandboxSession,
|
|
1084
|
-
homeDir: sandboxHomeDir,
|
|
1085
|
-
skills: startOpts.skills,
|
|
1086
|
-
abortSignal: startOpts.abortSignal,
|
|
1087
|
-
});
|
|
1088
|
-
}
|
|
1089
1076
|
}
|
|
1090
1077
|
|
|
1091
1078
|
await markBridgeStarting({
|
|
@@ -1162,7 +1149,7 @@ export function createClaudeCode(
|
|
|
1162
1149
|
sessionId: startOpts.sessionId,
|
|
1163
1150
|
channel,
|
|
1164
1151
|
proc,
|
|
1165
|
-
model
|
|
1152
|
+
model,
|
|
1166
1153
|
maxTurns: settings.maxTurns,
|
|
1167
1154
|
env: sandboxClaudeEnvironment,
|
|
1168
1155
|
thinking,
|
|
@@ -1177,7 +1164,8 @@ export function createClaudeCode(
|
|
|
1177
1164
|
debug: startOpts.observability?.debug,
|
|
1178
1165
|
permissionMode: startOpts.permissionMode,
|
|
1179
1166
|
builtinToolFiltering: startOpts.builtinToolFiltering,
|
|
1180
|
-
|
|
1167
|
+
sandbox: toolSafeSandboxSession,
|
|
1168
|
+
sandboxHomeDir,
|
|
1181
1169
|
mcpServers: settings.mcpServers,
|
|
1182
1170
|
supportsUserMessageResponses: () => supportsUserMessageResponses,
|
|
1183
1171
|
});
|
|
@@ -1506,7 +1494,8 @@ function createSession({
|
|
|
1506
1494
|
debug,
|
|
1507
1495
|
permissionMode,
|
|
1508
1496
|
builtinToolFiltering,
|
|
1509
|
-
|
|
1497
|
+
sandbox,
|
|
1498
|
+
sandboxHomeDir,
|
|
1510
1499
|
mcpServers,
|
|
1511
1500
|
supportsUserMessageResponses,
|
|
1512
1501
|
}: {
|
|
@@ -1529,7 +1518,8 @@ function createSession({
|
|
|
1529
1518
|
debug: HarnessV1DebugConfig | undefined;
|
|
1530
1519
|
permissionMode: HarnessV1PermissionMode | undefined;
|
|
1531
1520
|
builtinToolFiltering: HarnessV1BuiltinToolFiltering | undefined;
|
|
1532
|
-
|
|
1521
|
+
sandbox: SandboxSession;
|
|
1522
|
+
sandboxHomeDir: string;
|
|
1533
1523
|
mcpServers: Record<string, unknown> | undefined;
|
|
1534
1524
|
supportsUserMessageResponses: () => boolean;
|
|
1535
1525
|
}): HarnessV1Session {
|
|
@@ -1705,11 +1695,27 @@ function createSession({
|
|
|
1705
1695
|
harnessId: 'claude-code',
|
|
1706
1696
|
});
|
|
1707
1697
|
}
|
|
1698
|
+
await writeClaudeCodeSkills({
|
|
1699
|
+
sandbox,
|
|
1700
|
+
homeDir: sandboxHomeDir,
|
|
1701
|
+
skills: promptOpts.skills,
|
|
1702
|
+
abortSignal: promptOpts.abortSignal,
|
|
1703
|
+
});
|
|
1708
1704
|
const control = wireTurn({
|
|
1709
1705
|
emit: promptOpts.emit,
|
|
1710
1706
|
abortSignal: promptOpts.abortSignal,
|
|
1711
1707
|
});
|
|
1712
1708
|
|
|
1709
|
+
/*
|
|
1710
|
+
* A signal that was already aborted has settled the turn inside
|
|
1711
|
+
* `wireTurn`. Sending `start` anyway would run a full unattended turn
|
|
1712
|
+
* in the bridge — consuming tokens and possibly acting on the
|
|
1713
|
+
* workspace — after the caller has already observed the abort.
|
|
1714
|
+
*/
|
|
1715
|
+
if (promptOpts.abortSignal?.aborted) {
|
|
1716
|
+
return control;
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1713
1719
|
const startMessage = {
|
|
1714
1720
|
type: 'start' as const,
|
|
1715
1721
|
prompt: extractUserText(promptOpts.prompt),
|
|
@@ -1729,8 +1735,8 @@ function createSession({
|
|
|
1729
1735
|
...(env !== undefined ? { env } : {}),
|
|
1730
1736
|
thinking,
|
|
1731
1737
|
...(effort !== undefined ? { effort } : {}),
|
|
1732
|
-
...(skills.length > 0
|
|
1733
|
-
? { skills: skills.map(skill => skill.name) }
|
|
1738
|
+
...(promptOpts.skills.length > 0
|
|
1739
|
+
? { skills: promptOpts.skills.map(skill => skill.name) }
|
|
1734
1740
|
: {}),
|
|
1735
1741
|
...(mcpServers == null ? {} : { mcpServers }),
|
|
1736
1742
|
...(permissionMode ? { permissionMode } : {}),
|
|
@@ -1754,6 +1760,12 @@ function createSession({
|
|
|
1754
1760
|
harnessId: 'claude-code',
|
|
1755
1761
|
});
|
|
1756
1762
|
}
|
|
1763
|
+
await writeClaudeCodeSkills({
|
|
1764
|
+
sandbox,
|
|
1765
|
+
homeDir: sandboxHomeDir,
|
|
1766
|
+
skills: continueOpts.skills,
|
|
1767
|
+
abortSignal: continueOpts.abortSignal,
|
|
1768
|
+
});
|
|
1757
1769
|
const control = wireTurn({
|
|
1758
1770
|
emit: continueOpts.emit,
|
|
1759
1771
|
abortSignal: continueOpts.abortSignal,
|
|
@@ -1772,7 +1784,9 @@ function createSession({
|
|
|
1772
1784
|
* recomputed. This is the rare bridge-died fallback; the common slice path
|
|
1773
1785
|
* is `attach`.
|
|
1774
1786
|
*/
|
|
1775
|
-
|
|
1787
|
+
// Same as `doPromptTurn`: an already-aborted signal settled the turn in
|
|
1788
|
+
// `wireTurn`, so don't re-drive the thread nobody is waiting on.
|
|
1789
|
+
if (rerunContinue && !continueOpts.abortSignal?.aborted) {
|
|
1776
1790
|
pendingResumeFlag = false;
|
|
1777
1791
|
channel.send({
|
|
1778
1792
|
type: 'start' as const,
|
|
@@ -1800,8 +1814,8 @@ function createSession({
|
|
|
1800
1814
|
...(env !== undefined ? { env } : {}),
|
|
1801
1815
|
thinking,
|
|
1802
1816
|
...(effort !== undefined ? { effort } : {}),
|
|
1803
|
-
...(skills.length > 0
|
|
1804
|
-
? { skills: skills.map(skill => skill.name) }
|
|
1817
|
+
...(continueOpts.skills.length > 0
|
|
1818
|
+
? { skills: continueOpts.skills.map(skill => skill.name) }
|
|
1805
1819
|
: {}),
|
|
1806
1820
|
...(mcpServers == null ? {} : { mcpServers }),
|
|
1807
1821
|
...(permissionMode ? { permissionMode } : {}),
|