@ai-sdk/harness-claude-code 1.0.22 → 1.0.23
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/README.md +3 -1
- package/dist/bridge/index.mjs +152 -45
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/index.d.ts +11 -4
- package/dist/index.js +36 -113
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/bridge/index.ts +105 -80
- package/src/claude-code-bridge-protocol.ts +15 -1
- package/src/claude-code-harness.ts +33 -140
- package/src/claude-code-thinking.ts +8 -0
- package/src/index.ts +1 -0
package/dist/index.js
CHANGED
|
@@ -9,6 +9,10 @@ import {
|
|
|
9
9
|
} from "@ai-sdk/harness";
|
|
10
10
|
import {
|
|
11
11
|
classifyDiskLog,
|
|
12
|
+
createBridgeErrorHandler,
|
|
13
|
+
createBridgeStartupError,
|
|
14
|
+
drainBridgeProcessStream,
|
|
15
|
+
forwardBridgeProcessStream,
|
|
12
16
|
markBridgeStarting,
|
|
13
17
|
resolveSandboxHomeDir,
|
|
14
18
|
SandboxChannel,
|
|
@@ -116,8 +120,20 @@ import {
|
|
|
116
120
|
} from "@ai-sdk/harness";
|
|
117
121
|
import { z } from "zod/v4";
|
|
118
122
|
var outboundMessageSchema = harnessV1BridgeOutboundMessageSchema;
|
|
123
|
+
var thinkingDisplaySchema = z.enum(["summarized", "omitted"]).optional();
|
|
124
|
+
var thinkingSchema = z.discriminatedUnion("type", [
|
|
125
|
+
z.object({
|
|
126
|
+
type: z.literal("adaptive"),
|
|
127
|
+
display: thinkingDisplaySchema
|
|
128
|
+
}),
|
|
129
|
+
z.object({
|
|
130
|
+
type: z.literal("enabled"),
|
|
131
|
+
display: thinkingDisplaySchema
|
|
132
|
+
}),
|
|
133
|
+
z.object({ type: z.literal("disabled") })
|
|
134
|
+
]);
|
|
119
135
|
var startMessageSchema = harnessV1BridgeStartBaseSchema.extend({
|
|
120
|
-
thinking:
|
|
136
|
+
thinking: thinkingSchema,
|
|
121
137
|
maxTurns: z.number().optional(),
|
|
122
138
|
skills: z.array(z.string()).optional(),
|
|
123
139
|
// Resume signal. When true, the bridge passes `{ continue: true }` to the
|
|
@@ -131,7 +147,7 @@ var inboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
131
147
|
]);
|
|
132
148
|
|
|
133
149
|
// src/version.ts
|
|
134
|
-
var VERSION = true ? "1.0.
|
|
150
|
+
var VERSION = true ? "1.0.23" : "0.0.0-test";
|
|
135
151
|
|
|
136
152
|
// src/claude-code-harness.ts
|
|
137
153
|
var CLAUDE_CODE_CLIENT_APP = `ai-sdk/harness-claude-code/${VERSION}`;
|
|
@@ -409,6 +425,10 @@ var claudeCodeResumeStateSchema = z2.looseObject({
|
|
|
409
425
|
});
|
|
410
426
|
function createClaudeCode(settings = {}) {
|
|
411
427
|
let cachedBootstrap;
|
|
428
|
+
const thinking = settings.thinking ?? {
|
|
429
|
+
type: "adaptive",
|
|
430
|
+
display: "summarized"
|
|
431
|
+
};
|
|
412
432
|
return {
|
|
413
433
|
specificationVersion: "harness-v1",
|
|
414
434
|
harnessId: "claude-code",
|
|
@@ -462,6 +482,10 @@ function createClaudeCode(settings = {}) {
|
|
|
462
482
|
timestamp: Date.now()
|
|
463
483
|
})
|
|
464
484
|
) : void 0;
|
|
485
|
+
const onBridgeError = createBridgeErrorHandler({
|
|
486
|
+
harnessId: "claude-code",
|
|
487
|
+
sessionId: startOpts.sessionId
|
|
488
|
+
});
|
|
465
489
|
const buildConnect = (wsUrl2) => async () => {
|
|
466
490
|
return openBridgeWebSocket({ wsUrl: wsUrl2, timeoutMs });
|
|
467
491
|
};
|
|
@@ -475,7 +499,8 @@ function createClaudeCode(settings = {}) {
|
|
|
475
499
|
connect: buildConnect(attachUrl),
|
|
476
500
|
outboundSchema: outboundMessageSchema,
|
|
477
501
|
initialLastSeenEventId: coords.lastSeenEventId,
|
|
478
|
-
onDiagnostic
|
|
502
|
+
onDiagnostic,
|
|
503
|
+
onBridgeError
|
|
479
504
|
});
|
|
480
505
|
await attachChannel.open(isContinue ? { resume: true } : void 0);
|
|
481
506
|
return createSession({
|
|
@@ -487,7 +512,7 @@ function createClaudeCode(settings = {}) {
|
|
|
487
512
|
proc: void 0,
|
|
488
513
|
model: settings.model,
|
|
489
514
|
maxTurns: settings.maxTurns,
|
|
490
|
-
thinking
|
|
515
|
+
thinking,
|
|
491
516
|
isResume: true,
|
|
492
517
|
continueOnFirstPrompt: false,
|
|
493
518
|
rerunContinue: false,
|
|
@@ -563,8 +588,10 @@ function createClaudeCode(settings = {}) {
|
|
|
563
588
|
abortSignal: startOpts.abortSignal
|
|
564
589
|
});
|
|
565
590
|
const bridgeStartupStderr = [];
|
|
566
|
-
const bridgeStartupStderrDone =
|
|
591
|
+
const bridgeStartupStderrDone = forwardBridgeProcessStream({
|
|
567
592
|
stream: proc.stderr,
|
|
593
|
+
streamName: "stderr",
|
|
594
|
+
source: "claude-code",
|
|
568
595
|
collectTail: bridgeStartupStderr
|
|
569
596
|
});
|
|
570
597
|
void bridgeStartupStderrDone;
|
|
@@ -590,7 +617,7 @@ function createClaudeCode(settings = {}) {
|
|
|
590
617
|
stderrDone: bridgeStartupStderrDone
|
|
591
618
|
})
|
|
592
619
|
});
|
|
593
|
-
void
|
|
620
|
+
void drainBridgeProcessStream(proc.stdout);
|
|
594
621
|
const wsUrl = await sandboxSession.getPortUrl({
|
|
595
622
|
port: boundPort,
|
|
596
623
|
protocol: "ws"
|
|
@@ -599,6 +626,7 @@ function createClaudeCode(settings = {}) {
|
|
|
599
626
|
connect: buildConnect(wsUrl),
|
|
600
627
|
outboundSchema: outboundMessageSchema,
|
|
601
628
|
onDiagnostic,
|
|
629
|
+
onBridgeError,
|
|
602
630
|
// In replay mode the respawned bridge reloaded the finished turn from
|
|
603
631
|
// disk; seed the cursor and resume so it streams the tail (incl.
|
|
604
632
|
// `finish`) rather than starting empty.
|
|
@@ -613,7 +641,7 @@ function createClaudeCode(settings = {}) {
|
|
|
613
641
|
proc,
|
|
614
642
|
model: settings.model,
|
|
615
643
|
maxTurns: settings.maxTurns,
|
|
616
|
-
thinking
|
|
644
|
+
thinking,
|
|
617
645
|
isResume: respawnStrategy !== void 0,
|
|
618
646
|
continueOnFirstPrompt: respawnStrategy !== void 0,
|
|
619
647
|
rerunContinue: respawnStrategy === "rerun",
|
|
@@ -669,112 +697,6 @@ async function readBridgeAsset(name) {
|
|
|
669
697
|
}
|
|
670
698
|
throw lastErr ?? new Error(`bridge asset not found: ${name}`);
|
|
671
699
|
}
|
|
672
|
-
async function createBridgeStartupError({
|
|
673
|
-
message,
|
|
674
|
-
proc,
|
|
675
|
-
stdoutTail,
|
|
676
|
-
stderrTail,
|
|
677
|
-
stderrDone
|
|
678
|
-
}) {
|
|
679
|
-
await Promise.race([
|
|
680
|
-
stderrDone,
|
|
681
|
-
new Promise((resolve) => setTimeout(resolve, 250))
|
|
682
|
-
]).catch(() => {
|
|
683
|
-
});
|
|
684
|
-
let exitStatus = "";
|
|
685
|
-
try {
|
|
686
|
-
const result = await Promise.race([
|
|
687
|
-
proc.wait(),
|
|
688
|
-
new Promise((resolve) => setTimeout(resolve, 250))
|
|
689
|
-
]);
|
|
690
|
-
if (result?.exitCode !== void 0) {
|
|
691
|
-
exitStatus = ` Exit code: ${result.exitCode}.`;
|
|
692
|
-
}
|
|
693
|
-
} catch {
|
|
694
|
-
}
|
|
695
|
-
const details = [];
|
|
696
|
-
if (stdoutTail.length > 0) {
|
|
697
|
-
details.push(`stdout:
|
|
698
|
-
${stdoutTail.join("\n")}`);
|
|
699
|
-
}
|
|
700
|
-
if (stderrTail.length > 0) {
|
|
701
|
-
details.push(`stderr:
|
|
702
|
-
${stderrTail.join("\n")}`);
|
|
703
|
-
}
|
|
704
|
-
return new Error(
|
|
705
|
-
`${message}${exitStatus}${details.length > 0 ? `
|
|
706
|
-
|
|
707
|
-
${details.join("\n\n")}` : ""}`
|
|
708
|
-
);
|
|
709
|
-
}
|
|
710
|
-
function lineDecoder() {
|
|
711
|
-
let buffer = "";
|
|
712
|
-
return {
|
|
713
|
-
push(chunk) {
|
|
714
|
-
buffer += chunk;
|
|
715
|
-
const lines = [];
|
|
716
|
-
let nl;
|
|
717
|
-
while ((nl = buffer.indexOf("\n")) !== -1) {
|
|
718
|
-
const raw = buffer.slice(0, nl);
|
|
719
|
-
buffer = buffer.slice(nl + 1);
|
|
720
|
-
const line = raw.replace(/\r$/, "").trim();
|
|
721
|
-
if (line.length > 0) lines.push(line);
|
|
722
|
-
}
|
|
723
|
-
return lines;
|
|
724
|
-
},
|
|
725
|
-
flush() {
|
|
726
|
-
const line = buffer.replace(/\r$/, "").trim();
|
|
727
|
-
buffer = "";
|
|
728
|
-
return line.length > 0 ? [line] : [];
|
|
729
|
-
}
|
|
730
|
-
};
|
|
731
|
-
}
|
|
732
|
-
async function forwardBridgeStderr({
|
|
733
|
-
stream,
|
|
734
|
-
collectTail
|
|
735
|
-
}) {
|
|
736
|
-
try {
|
|
737
|
-
const reader = stream.pipeThrough(new TextDecoderStream()).getReader();
|
|
738
|
-
const decoder = lineDecoder();
|
|
739
|
-
while (true) {
|
|
740
|
-
const { value, done } = await reader.read();
|
|
741
|
-
if (done) {
|
|
742
|
-
for (const line of decoder.flush()) {
|
|
743
|
-
const trimmed = line.trim();
|
|
744
|
-
if (!trimmed) continue;
|
|
745
|
-
if (collectTail) {
|
|
746
|
-
collectTail.push(trimmed);
|
|
747
|
-
if (collectTail.length > 20) collectTail.shift();
|
|
748
|
-
}
|
|
749
|
-
console.log(`[bridge stderr] ${trimmed}`);
|
|
750
|
-
}
|
|
751
|
-
return;
|
|
752
|
-
}
|
|
753
|
-
if (value) {
|
|
754
|
-
for (const line of decoder.push(value)) {
|
|
755
|
-
const trimmed = line.trim();
|
|
756
|
-
if (!trimmed) continue;
|
|
757
|
-
if (collectTail) {
|
|
758
|
-
collectTail.push(trimmed);
|
|
759
|
-
if (collectTail.length > 20) collectTail.shift();
|
|
760
|
-
}
|
|
761
|
-
console.log(`[bridge stderr] ${trimmed}`);
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
} catch {
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
async function drainRest(stream) {
|
|
769
|
-
try {
|
|
770
|
-
const reader = stream.pipeThrough(new TextDecoderStream()).getReader();
|
|
771
|
-
while (true) {
|
|
772
|
-
const { done } = await reader.read();
|
|
773
|
-
if (done) return;
|
|
774
|
-
}
|
|
775
|
-
} catch {
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
700
|
async function waitForBridgeHello({
|
|
779
701
|
ws,
|
|
780
702
|
timeoutMs
|
|
@@ -1229,6 +1151,7 @@ function createSession({
|
|
|
1229
1151
|
);
|
|
1230
1152
|
}
|
|
1231
1153
|
stopped = true;
|
|
1154
|
+
await channel.interrupt();
|
|
1232
1155
|
const lastSeenEventId = await channel.suspend();
|
|
1233
1156
|
const payload = {
|
|
1234
1157
|
type: "continue-turn",
|