@ai-sdk/harness-claude-code 1.0.97 → 1.0.98
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 +12 -0
- package/dist/bridge/index.mjs +77 -14
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/index.js +48 -13
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/bridge/create-emit-stream-event.ts +74 -13
- package/src/bridge/index.ts +65 -12
- package/src/claude-code-bridge-protocol.ts +8 -0
- package/src/claude-code-harness.ts +72 -11
package/dist/index.js
CHANGED
|
@@ -258,7 +258,15 @@ var startMessageSchema = harnessV1BridgeStartBaseSchema.extend({
|
|
|
258
258
|
// Resume signal. When true, the bridge passes `{ continue: true }` to the
|
|
259
259
|
// Claude SDK so the in-workdir thread state is rehydrated. The host sets this
|
|
260
260
|
// on the first prompt after a cross-process resume.
|
|
261
|
-
continue: z.boolean().optional()
|
|
261
|
+
continue: z.boolean().optional(),
|
|
262
|
+
// Exact conversation to resume, as the Claude SDK's `resume` option.
|
|
263
|
+
//
|
|
264
|
+
// Preferred over `continue` whenever the host knows which conversation it
|
|
265
|
+
// means: `continue` resolves to the most recent thread in the workdir, which
|
|
266
|
+
// is the wrong one as soon as anything else has run there since — including
|
|
267
|
+
// a resume that itself started a new thread. Mutually exclusive with
|
|
268
|
+
// `continue` in the SDK, so the bridge sends one or the other.
|
|
269
|
+
resumeSessionId: z.string().optional()
|
|
262
270
|
});
|
|
263
271
|
var inboundMessageSchema = z.discriminatedUnion("type", [
|
|
264
272
|
startMessageSchema,
|
|
@@ -266,7 +274,7 @@ var inboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
266
274
|
]);
|
|
267
275
|
|
|
268
276
|
// src/version.ts
|
|
269
|
-
var VERSION = true ? "1.0.
|
|
277
|
+
var VERSION = true ? "1.0.98" : "0.0.0-test";
|
|
270
278
|
|
|
271
279
|
// src/claude-code-harness.ts
|
|
272
280
|
var CLAUDE_CODE_CLIENT_APP = `ai-sdk/harness-claude-code/${VERSION}`;
|
|
@@ -871,7 +879,18 @@ var claudeCodeBridgeCoordsSchema = z2.object({
|
|
|
871
879
|
});
|
|
872
880
|
var claudeCodeResumeStateSchema = z2.looseObject({
|
|
873
881
|
bridge: claudeCodeBridgeCoordsSchema.optional(),
|
|
874
|
-
sandboxCredentialEnvironment: z2.record(z2.string(), z2.string()).optional()
|
|
882
|
+
sandboxCredentialEnvironment: z2.record(z2.string(), z2.string()).optional(),
|
|
883
|
+
/**
|
|
884
|
+
* The exact Claude conversation to rehydrate on resume. Written by the
|
|
885
|
+
* adapter on `doStop()`/`doDetach()`/`doSuspendTurn()` from the session id
|
|
886
|
+
* the bridge observed, so a resume names the conversation instead of
|
|
887
|
+
* relying on the SDK's `continue` flag — "most recent thread in this
|
|
888
|
+
* workdir" — which silently picks the wrong one once a second thread
|
|
889
|
+
* exists there. Hosts that captured the id themselves (it is surfaced as
|
|
890
|
+
* `harnessMetadata['claude-code'].sessionId` on `finish` parts) may also
|
|
891
|
+
* set it explicitly.
|
|
892
|
+
*/
|
|
893
|
+
claudeSessionId: z2.string().optional()
|
|
875
894
|
});
|
|
876
895
|
function createClaudeCode(settings = {}) {
|
|
877
896
|
if (settings.mcpServers != null && Object.prototype.hasOwnProperty.call(settings.mcpServers, "harness-tools")) {
|
|
@@ -892,7 +911,6 @@ function createClaudeCode(settings = {}) {
|
|
|
892
911
|
lifecycleStateSchema: claudeCodeResumeStateSchema,
|
|
893
912
|
getBootstrap: getClaudeCodeBootstrap,
|
|
894
913
|
doStart: async (startOpts) => {
|
|
895
|
-
const model = startOpts.model ?? settings.model;
|
|
896
914
|
const sandboxSession = startOpts.sandboxSession;
|
|
897
915
|
const toolSafeSandboxSession = getRestrictedSandboxSession(sandboxSession);
|
|
898
916
|
const sandboxId = "id" in sandboxSession ? sandboxSession.id : void 0;
|
|
@@ -965,6 +983,7 @@ function createClaudeCode(settings = {}) {
|
|
|
965
983
|
defaultWorkingDirectory,
|
|
966
984
|
CLAUDE_CODE_BOOTSTRAP_DIR
|
|
967
985
|
);
|
|
986
|
+
const resumeSessionId = resumeData?.claudeSessionId;
|
|
968
987
|
const workDir = startOpts.sessionWorkDir;
|
|
969
988
|
const sandboxHomeDir = await resolveSandboxHomeDir({
|
|
970
989
|
sandbox: toolSafeSandboxSession,
|
|
@@ -1016,11 +1035,12 @@ function createClaudeCode(settings = {}) {
|
|
|
1016
1035
|
return createSession({
|
|
1017
1036
|
sessionId: startOpts.sessionId,
|
|
1018
1037
|
channel: attachChannel,
|
|
1038
|
+
...resumeSessionId ? { resumeSessionId } : {},
|
|
1019
1039
|
// The live bridge was spawned by another process; this one owns no
|
|
1020
1040
|
// process handle. The session lifecycle method decides whether the
|
|
1021
1041
|
// sandbox is left running, stopped, or destroyed.
|
|
1022
1042
|
proc: void 0,
|
|
1023
|
-
model,
|
|
1043
|
+
model: settings.model,
|
|
1024
1044
|
maxTurns: settings.maxTurns,
|
|
1025
1045
|
env: sandboxClaudeEnvironment,
|
|
1026
1046
|
thinking,
|
|
@@ -1136,13 +1156,14 @@ function createClaudeCode(settings = {}) {
|
|
|
1136
1156
|
sessionId: startOpts.sessionId,
|
|
1137
1157
|
channel,
|
|
1138
1158
|
proc,
|
|
1139
|
-
model,
|
|
1159
|
+
model: settings.model,
|
|
1140
1160
|
maxTurns: settings.maxTurns,
|
|
1141
1161
|
env: sandboxClaudeEnvironment,
|
|
1142
1162
|
thinking,
|
|
1143
1163
|
effort: settings.effort,
|
|
1144
1164
|
isResume: respawnStrategy !== void 0,
|
|
1145
1165
|
continueOnFirstPrompt: respawnStrategy !== void 0,
|
|
1166
|
+
...resumeSessionId ? { resumeSessionId } : {},
|
|
1146
1167
|
rerunContinue: respawnStrategy === "rerun",
|
|
1147
1168
|
bridgePort: boundPort,
|
|
1148
1169
|
bridgeToken: token,
|
|
@@ -1392,6 +1413,7 @@ function createSession({
|
|
|
1392
1413
|
effort,
|
|
1393
1414
|
isResume,
|
|
1394
1415
|
continueOnFirstPrompt,
|
|
1416
|
+
resumeSessionId,
|
|
1395
1417
|
rerunContinue,
|
|
1396
1418
|
bridgePort,
|
|
1397
1419
|
bridgeToken,
|
|
@@ -1408,6 +1430,7 @@ function createSession({
|
|
|
1408
1430
|
let stopped = false;
|
|
1409
1431
|
let stopPromise;
|
|
1410
1432
|
let pendingResumeFlag = continueOnFirstPrompt;
|
|
1433
|
+
let lastClaudeSessionId = resumeSessionId;
|
|
1411
1434
|
const wireTurn = (turnOpts) => {
|
|
1412
1435
|
let pendingResolve;
|
|
1413
1436
|
let pendingReject;
|
|
@@ -1450,6 +1473,9 @@ function createSession({
|
|
|
1450
1473
|
"reasoning-start",
|
|
1451
1474
|
"reasoning-delta",
|
|
1452
1475
|
"reasoning-end",
|
|
1476
|
+
"tool-input-start",
|
|
1477
|
+
"tool-input-delta",
|
|
1478
|
+
"tool-input-end",
|
|
1453
1479
|
"tool-call",
|
|
1454
1480
|
"tool-approval-request",
|
|
1455
1481
|
"tool-result",
|
|
@@ -1465,6 +1491,10 @@ function createSession({
|
|
|
1465
1491
|
}
|
|
1466
1492
|
unsubs.push(
|
|
1467
1493
|
channel.on("finish", (msg) => {
|
|
1494
|
+
const metadata = msg.harnessMetadata?.["claude-code"]?.sessionId;
|
|
1495
|
+
if (typeof metadata === "string" && metadata.length > 0) {
|
|
1496
|
+
lastClaudeSessionId = metadata;
|
|
1497
|
+
}
|
|
1468
1498
|
forward(msg);
|
|
1469
1499
|
settleSuccess();
|
|
1470
1500
|
})
|
|
@@ -1533,7 +1563,6 @@ function createSession({
|
|
|
1533
1563
|
return {
|
|
1534
1564
|
sessionId,
|
|
1535
1565
|
isResume,
|
|
1536
|
-
modelId: model,
|
|
1537
1566
|
doPromptTurn: async (promptOpts) => {
|
|
1538
1567
|
if (promptOpts.responseFormat?.type === "json" && promptOpts.responseFormat.schema == null) {
|
|
1539
1568
|
throw new HarnessCapabilityUnsupportedError({
|
|
@@ -1564,7 +1593,7 @@ function createSession({
|
|
|
1564
1593
|
})),
|
|
1565
1594
|
...promptOpts.responseFormat == null ? {} : { responseFormat: promptOpts.responseFormat },
|
|
1566
1595
|
...promptOpts.instructions ? { instructions: promptOpts.instructions } : {},
|
|
1567
|
-
model,
|
|
1596
|
+
model: promptOpts.model ?? model,
|
|
1568
1597
|
maxTurns,
|
|
1569
1598
|
...env !== void 0 ? { env } : {},
|
|
1570
1599
|
thinking,
|
|
@@ -1574,7 +1603,7 @@ function createSession({
|
|
|
1574
1603
|
...permissionMode ? { permissionMode } : {},
|
|
1575
1604
|
...builtinToolFiltering ? { builtinToolFiltering } : {},
|
|
1576
1605
|
...debug ? { debug } : {},
|
|
1577
|
-
...pendingResumeFlag ? { continue: true } : {}
|
|
1606
|
+
...lastClaudeSessionId ? { resumeSessionId: lastClaudeSessionId } : pendingResumeFlag ? { continue: true } : {}
|
|
1578
1607
|
};
|
|
1579
1608
|
pendingResumeFlag = false;
|
|
1580
1609
|
channel.send(startMessage);
|
|
@@ -1616,7 +1645,7 @@ function createSession({
|
|
|
1616
1645
|
})),
|
|
1617
1646
|
...continueOpts.responseFormat == null ? {} : { responseFormat: continueOpts.responseFormat },
|
|
1618
1647
|
...continueOpts.instructions ? { instructions: continueOpts.instructions } : {},
|
|
1619
|
-
model,
|
|
1648
|
+
model: continueOpts.model ?? model,
|
|
1620
1649
|
maxTurns,
|
|
1621
1650
|
...env !== void 0 ? { env } : {},
|
|
1622
1651
|
thinking,
|
|
@@ -1626,7 +1655,7 @@ function createSession({
|
|
|
1626
1655
|
...permissionMode ? { permissionMode } : {},
|
|
1627
1656
|
...builtinToolFiltering ? { builtinToolFiltering } : {},
|
|
1628
1657
|
...debug ? { debug } : {},
|
|
1629
|
-
continue: true
|
|
1658
|
+
...lastClaudeSessionId ? { resumeSessionId: lastClaudeSessionId } : { continue: true }
|
|
1630
1659
|
});
|
|
1631
1660
|
}
|
|
1632
1661
|
return control;
|
|
@@ -1654,7 +1683,8 @@ function createSession({
|
|
|
1654
1683
|
token: bridgeToken,
|
|
1655
1684
|
lastSeenEventId,
|
|
1656
1685
|
...sandboxId == null ? {} : { sandboxId }
|
|
1657
|
-
}
|
|
1686
|
+
},
|
|
1687
|
+
...lastClaudeSessionId ? { claudeSessionId: lastClaudeSessionId } : {}
|
|
1658
1688
|
}
|
|
1659
1689
|
};
|
|
1660
1690
|
return payload;
|
|
@@ -1747,7 +1777,11 @@ function createSession({
|
|
|
1747
1777
|
type: "resume-session",
|
|
1748
1778
|
harnessId: "claude-code",
|
|
1749
1779
|
specificationVersion: "harness-v1",
|
|
1780
|
+
// The bridge's stop reply carries the session id it observed; the
|
|
1781
|
+
// adapter's own record backfills it when the reply predates the
|
|
1782
|
+
// field or the channel was already closed.
|
|
1750
1783
|
data: {
|
|
1784
|
+
...lastClaudeSessionId ? { claudeSessionId: lastClaudeSessionId } : {},
|
|
1751
1785
|
...lifecycleData,
|
|
1752
1786
|
...sandboxCredentialEnvironment == null ? {} : { sandboxCredentialEnvironment }
|
|
1753
1787
|
}
|
|
@@ -1773,7 +1807,8 @@ function createSession({
|
|
|
1773
1807
|
token: bridgeToken,
|
|
1774
1808
|
lastSeenEventId,
|
|
1775
1809
|
...sandboxId == null ? {} : { sandboxId }
|
|
1776
|
-
}
|
|
1810
|
+
},
|
|
1811
|
+
...lastClaudeSessionId ? { claudeSessionId: lastClaudeSessionId } : {}
|
|
1777
1812
|
}
|
|
1778
1813
|
};
|
|
1779
1814
|
return payload;
|