@autohq/cli 0.1.294 → 0.1.296
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/dist/agent-bridge.js +111 -22
- package/dist/index.js +128 -27
- package/package.json +1 -1
package/dist/agent-bridge.js
CHANGED
|
@@ -23399,7 +23399,7 @@ Object.assign(lookup, {
|
|
|
23399
23399
|
// package.json
|
|
23400
23400
|
var package_default = {
|
|
23401
23401
|
name: "@autohq/cli",
|
|
23402
|
-
version: "0.1.
|
|
23402
|
+
version: "0.1.296",
|
|
23403
23403
|
license: "SEE LICENSE IN README.md",
|
|
23404
23404
|
publishConfig: {
|
|
23405
23405
|
access: "public"
|
|
@@ -27210,7 +27210,16 @@ var SessionCheckTimeoutPhaseSchema = external_exports.enum(
|
|
|
27210
27210
|
);
|
|
27211
27211
|
var ManualSessionRequestSchema = external_exports.object({
|
|
27212
27212
|
message: external_exports.string().trim().min(1).max(2e4).optional(),
|
|
27213
|
-
interactive: external_exports.boolean().optional()
|
|
27213
|
+
interactive: external_exports.boolean().optional(),
|
|
27214
|
+
/**
|
|
27215
|
+
* Deliver the agent's configured `initialPrompt` as the session's kickoff
|
|
27216
|
+
* message so the agent opens the conversation. Agents without an
|
|
27217
|
+
* `initialPrompt` fall back to the default manual say-hello message, so a
|
|
27218
|
+
* kickoff always pings the agent. The kickoff is delivered through the
|
|
27219
|
+
* session's one idempotent start command and never renders as a user chat
|
|
27220
|
+
* bubble; the agent's greeting is the first visible content.
|
|
27221
|
+
*/
|
|
27222
|
+
kickoff: external_exports.boolean().optional()
|
|
27214
27223
|
});
|
|
27215
27224
|
var SessionArchiveRequestSchema = external_exports.object({
|
|
27216
27225
|
archived: external_exports.boolean()
|
|
@@ -57689,6 +57698,7 @@ function withClaudeStderrDiagnosticsPointer(error51, capturedStderr) {
|
|
|
57689
57698
|
// src/commands/agent-bridge/harness/claude-code/session.ts
|
|
57690
57699
|
var CLAUDE_AGENT_STARTUP_TIMEOUT_MS = 3e4;
|
|
57691
57700
|
var CLAUDE_INTERRUPT_SETTLE_TIMEOUT_MS = 1e4;
|
|
57701
|
+
var CLAUDE_INTERRUPT_ACK_TIMEOUT_MS = 1e4;
|
|
57692
57702
|
var CLAUDE_MCP_REGISTRATION_TIMEOUT_MS = 3e3;
|
|
57693
57703
|
var CLAUDE_MCP_REGISTRATION_POLL_INTERVAL_MS = 100;
|
|
57694
57704
|
var CLAUDE_STARTUP_PROFILE_HOOK_EVENTS = [
|
|
@@ -57728,10 +57738,18 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
57728
57738
|
// decrements — so interleaved interrupt/result deliveries stay balanced.
|
|
57729
57739
|
activeTurnCount = 0;
|
|
57730
57740
|
interruptInFlight = null;
|
|
57741
|
+
// turnResultCount at the moment an interrupt ack timed out, or null when no
|
|
57742
|
+
// timeout is latched. While turnResultCount still equals this value the same
|
|
57743
|
+
// wedged turn is running, so follow-up messages defer immediately instead of
|
|
57744
|
+
// each re-racing a fresh ack timeout against the unresponsive control
|
|
57745
|
+
// channel (and stacking pending control requests). Any terminal result
|
|
57746
|
+
// advances turnResultCount and un-latches.
|
|
57747
|
+
interruptAckTimeoutTurn = null;
|
|
57731
57748
|
exitReported = false;
|
|
57732
|
-
// Messages
|
|
57733
|
-
//
|
|
57734
|
-
//
|
|
57749
|
+
// Messages held for the turn's terminal result instead of injected mid-turn
|
|
57750
|
+
// (which would reject a pending tool_use): "deferred"-mode deliveries, plus
|
|
57751
|
+
// interrupt-mode deliveries whose interrupt ack timed out. Flushed once the
|
|
57752
|
+
// turn ends and the session is idle.
|
|
57735
57753
|
deferredMessages = [];
|
|
57736
57754
|
// tool_use ids the assistant has emitted whose tool_result has not yet been
|
|
57737
57755
|
// observed. A non-empty set means a tool call is in flight, so an immediate
|
|
@@ -57811,7 +57829,19 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
57811
57829
|
});
|
|
57812
57830
|
return;
|
|
57813
57831
|
}
|
|
57814
|
-
await this.interruptActiveTurnBeforeMessage();
|
|
57832
|
+
const interruption = await this.interruptActiveTurnBeforeMessage();
|
|
57833
|
+
if (interruption === "defer" && this.hasInterruptibleTurn()) {
|
|
57834
|
+
this.deferredMessages.push(message);
|
|
57835
|
+
this.input.runtimeLogger?.info(
|
|
57836
|
+
"agent_bridge_claude_message_deferred_after_interrupt_timeout",
|
|
57837
|
+
{
|
|
57838
|
+
active_turn_count: this.activeTurnCount,
|
|
57839
|
+
pending_tool_use_count: this.pendingToolUseIds.size,
|
|
57840
|
+
deferred_count: this.deferredMessages.length
|
|
57841
|
+
}
|
|
57842
|
+
);
|
|
57843
|
+
return;
|
|
57844
|
+
}
|
|
57815
57845
|
await this.awaitMcpRegistration();
|
|
57816
57846
|
this.enqueueUserMessage(message);
|
|
57817
57847
|
this.input.runtimeLogger?.info("agent_bridge_claude_send_message_queued", {
|
|
@@ -58060,14 +58090,19 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
58060
58090
|
}
|
|
58061
58091
|
async interruptActiveTurnBeforeMessage() {
|
|
58062
58092
|
if (!this.hasInterruptibleTurn()) {
|
|
58063
|
-
return;
|
|
58093
|
+
return "proceed";
|
|
58064
58094
|
}
|
|
58065
58095
|
if (this.interruptInFlight) {
|
|
58066
|
-
await this.interruptInFlight;
|
|
58067
|
-
|
|
58096
|
+
return await this.interruptInFlight;
|
|
58097
|
+
}
|
|
58098
|
+
if (this.interruptAckTimeoutTurn !== null) {
|
|
58099
|
+
if (this.interruptAckTimeoutTurn === this.turnResultCount) {
|
|
58100
|
+
return "defer";
|
|
58101
|
+
}
|
|
58102
|
+
this.interruptAckTimeoutTurn = null;
|
|
58068
58103
|
}
|
|
58069
58104
|
if (this.state.kind !== "running") {
|
|
58070
|
-
return;
|
|
58105
|
+
return "proceed";
|
|
58071
58106
|
}
|
|
58072
58107
|
const query = this.state.query;
|
|
58073
58108
|
const hadInFlightToolUse = this.hasInFlightToolUse();
|
|
@@ -58077,29 +58112,79 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
58077
58112
|
`agent_bridge_claude_mid_turn_interrupt_started at=${new Date(startedAt).toISOString()} in_flight_tool_use=${hadInFlightToolUse}`
|
|
58078
58113
|
);
|
|
58079
58114
|
const interruptPromise = (async () => {
|
|
58080
|
-
|
|
58081
|
-
|
|
58082
|
-
this.
|
|
58083
|
-
|
|
58084
|
-
);
|
|
58085
|
-
} catch (error51) {
|
|
58086
|
-
this.input.writeOutput?.(
|
|
58087
|
-
`agent_bridge_claude_mid_turn_interrupt_failed duration_ms=${Date.now() - startedAt} error=${error51 instanceof Error ? error51.message : String(error51)}`
|
|
58088
|
-
);
|
|
58115
|
+
const ack = await this.requestInterruptAck(query, startedAt);
|
|
58116
|
+
if (ack === "timeout") {
|
|
58117
|
+
this.interruptAckTimeoutTurn = settlementBaseline;
|
|
58118
|
+
return "defer";
|
|
58089
58119
|
}
|
|
58090
58120
|
if (hadInFlightToolUse) {
|
|
58091
58121
|
await this.awaitTurnSettlement(settlementBaseline, startedAt);
|
|
58092
58122
|
}
|
|
58123
|
+
return "proceed";
|
|
58093
58124
|
})();
|
|
58094
58125
|
this.interruptInFlight = interruptPromise;
|
|
58095
58126
|
try {
|
|
58096
|
-
await interruptPromise;
|
|
58127
|
+
return await interruptPromise;
|
|
58097
58128
|
} finally {
|
|
58098
58129
|
if (this.interruptInFlight === interruptPromise) {
|
|
58099
58130
|
this.interruptInFlight = null;
|
|
58100
58131
|
}
|
|
58101
58132
|
}
|
|
58102
58133
|
}
|
|
58134
|
+
// Fire the interrupt control request, bounded by the ack timeout. "ready" =
|
|
58135
|
+
// the SDK acked; "failed" = the SDK rejected it (a steering message is still
|
|
58136
|
+
// useful, so the caller falls back to normal queued delivery); "timeout" =
|
|
58137
|
+
// no answer within CLAUDE_INTERRUPT_ACK_TIMEOUT_MS (FRA-3465). The abandoned
|
|
58138
|
+
// request stays attached to late-outcome logging so it can never surface as
|
|
58139
|
+
// an unhandled rejection after the timeout won.
|
|
58140
|
+
requestInterruptAck(query, startedAt) {
|
|
58141
|
+
return new Promise((resolve2) => {
|
|
58142
|
+
let done = false;
|
|
58143
|
+
const finish = (outcome, line) => {
|
|
58144
|
+
if (done) {
|
|
58145
|
+
return;
|
|
58146
|
+
}
|
|
58147
|
+
done = true;
|
|
58148
|
+
clearTimeout(timer);
|
|
58149
|
+
this.input.writeOutput?.(line);
|
|
58150
|
+
resolve2(outcome);
|
|
58151
|
+
};
|
|
58152
|
+
const timer = setTimeout(() => {
|
|
58153
|
+
finish(
|
|
58154
|
+
"timeout",
|
|
58155
|
+
`agent_bridge_claude_mid_turn_interrupt_ack_timeout duration_ms=${Date.now() - startedAt}`
|
|
58156
|
+
);
|
|
58157
|
+
}, CLAUDE_INTERRUPT_ACK_TIMEOUT_MS);
|
|
58158
|
+
timer.unref?.();
|
|
58159
|
+
query.interrupt().then(
|
|
58160
|
+
() => {
|
|
58161
|
+
if (done) {
|
|
58162
|
+
this.input.writeOutput?.(
|
|
58163
|
+
`agent_bridge_claude_mid_turn_interrupt_late_ready duration_ms=${Date.now() - startedAt}`
|
|
58164
|
+
);
|
|
58165
|
+
return;
|
|
58166
|
+
}
|
|
58167
|
+
finish(
|
|
58168
|
+
"ready",
|
|
58169
|
+
`agent_bridge_claude_mid_turn_interrupt_ready duration_ms=${Date.now() - startedAt}`
|
|
58170
|
+
);
|
|
58171
|
+
},
|
|
58172
|
+
(error51) => {
|
|
58173
|
+
const detail = `duration_ms=${Date.now() - startedAt} error=${error51 instanceof Error ? error51.message : String(error51)}`;
|
|
58174
|
+
if (done) {
|
|
58175
|
+
this.input.writeOutput?.(
|
|
58176
|
+
`agent_bridge_claude_mid_turn_interrupt_late_failed ${detail}`
|
|
58177
|
+
);
|
|
58178
|
+
return;
|
|
58179
|
+
}
|
|
58180
|
+
finish(
|
|
58181
|
+
"failed",
|
|
58182
|
+
`agent_bridge_claude_mid_turn_interrupt_failed ${detail}`
|
|
58183
|
+
);
|
|
58184
|
+
}
|
|
58185
|
+
);
|
|
58186
|
+
});
|
|
58187
|
+
}
|
|
58103
58188
|
// Why this gate is correct without a provider-backed test (it relies on real
|
|
58104
58189
|
// SDK mcpServerStatus() timing that fakes cannot prove):
|
|
58105
58190
|
// - Safe-degrade on uncertainty: pollMcpRegistration never rejects — on
|
|
@@ -60269,15 +60354,19 @@ function replaceErrors(_key, value2) {
|
|
|
60269
60354
|
async function runAgentBridgeProcess(input) {
|
|
60270
60355
|
const runAgentBridge = input.runAgentBridge ?? runAgentBridgeHarness;
|
|
60271
60356
|
const log = createRuntimeLogger(input.env);
|
|
60357
|
+
const writeOutput = (line) => {
|
|
60358
|
+
input.writeOutput?.(line);
|
|
60359
|
+
log.info(line);
|
|
60360
|
+
};
|
|
60272
60361
|
log.info("agent bridge process starting", {
|
|
60273
60362
|
bridge_url_host: bridgeUrlHost(input.env.AUTO_BRIDGE_URL),
|
|
60274
60363
|
log_level: log.level
|
|
60275
60364
|
});
|
|
60276
60365
|
try {
|
|
60277
60366
|
await runAgentBridge({
|
|
60278
|
-
...agentBridgeOptionsFromEnv(input),
|
|
60367
|
+
...agentBridgeOptionsFromEnv({ env: input.env, writeOutput }),
|
|
60279
60368
|
runtimeLogger: log,
|
|
60280
|
-
onBootstrap: createGitCredentialRelayStarter(
|
|
60369
|
+
onBootstrap: createGitCredentialRelayStarter(writeOutput, log)
|
|
60281
60370
|
});
|
|
60282
60371
|
} catch (error51) {
|
|
60283
60372
|
log.error("agent bridge process failed", { error: error51 });
|
package/dist/index.js
CHANGED
|
@@ -18941,7 +18941,16 @@ var init_sessions = __esm({
|
|
|
18941
18941
|
);
|
|
18942
18942
|
ManualSessionRequestSchema = external_exports.object({
|
|
18943
18943
|
message: external_exports.string().trim().min(1).max(2e4).optional(),
|
|
18944
|
-
interactive: external_exports.boolean().optional()
|
|
18944
|
+
interactive: external_exports.boolean().optional(),
|
|
18945
|
+
/**
|
|
18946
|
+
* Deliver the agent's configured `initialPrompt` as the session's kickoff
|
|
18947
|
+
* message so the agent opens the conversation. Agents without an
|
|
18948
|
+
* `initialPrompt` fall back to the default manual say-hello message, so a
|
|
18949
|
+
* kickoff always pings the agent. The kickoff is delivered through the
|
|
18950
|
+
* session's one idempotent start command and never renders as a user chat
|
|
18951
|
+
* bubble; the agent's greeting is the first visible content.
|
|
18952
|
+
*/
|
|
18953
|
+
kickoff: external_exports.boolean().optional()
|
|
18945
18954
|
});
|
|
18946
18955
|
SessionArchiveRequestSchema = external_exports.object({
|
|
18947
18956
|
archived: external_exports.boolean()
|
|
@@ -23185,7 +23194,7 @@ var init_package = __esm({
|
|
|
23185
23194
|
"package.json"() {
|
|
23186
23195
|
package_default = {
|
|
23187
23196
|
name: "@autohq/cli",
|
|
23188
|
-
version: "0.1.
|
|
23197
|
+
version: "0.1.296",
|
|
23189
23198
|
license: "SEE LICENSE IN README.md",
|
|
23190
23199
|
publishConfig: {
|
|
23191
23200
|
access: "public"
|
|
@@ -25121,7 +25130,10 @@ function readApplyAssets(resources, readAsset) {
|
|
|
25121
25130
|
`Invalid identity avatar asset for "${target.resourceName}": asset path must be under .auto/assets`
|
|
25122
25131
|
);
|
|
25123
25132
|
}
|
|
25124
|
-
const source = readAsset(
|
|
25133
|
+
const source = readAsset({
|
|
25134
|
+
asset: target.asset,
|
|
25135
|
+
resourceName: target.resourceName
|
|
25136
|
+
});
|
|
25125
25137
|
if (!source) {
|
|
25126
25138
|
throw new Error(
|
|
25127
25139
|
`Invalid identity avatar asset for "${target.resourceName}": ${target.asset} does not exist`
|
|
@@ -25161,12 +25173,20 @@ function projectApplyAssetFromSource(input) {
|
|
|
25161
25173
|
}
|
|
25162
25174
|
function avatarAssetTarget(resource) {
|
|
25163
25175
|
if (resource.kind === RESOURCE_KIND_IDENTITY) {
|
|
25164
|
-
const
|
|
25165
|
-
return
|
|
25176
|
+
const avatar = resource.spec.avatar;
|
|
25177
|
+
return avatar ? {
|
|
25178
|
+
asset: avatar.asset,
|
|
25179
|
+
sha256: avatar.sha256,
|
|
25180
|
+
resourceName: resource.metadata.name
|
|
25181
|
+
} : void 0;
|
|
25166
25182
|
}
|
|
25167
25183
|
if (resource.kind === RESOURCE_KIND_AGENT && typeof resource.spec.identity === "object" && resource.spec.identity !== null && !Array.isArray(resource.spec.identity)) {
|
|
25168
|
-
const
|
|
25169
|
-
return
|
|
25184
|
+
const avatar = resource.spec.identity.avatar;
|
|
25185
|
+
return avatar ? {
|
|
25186
|
+
asset: avatar.asset,
|
|
25187
|
+
sha256: avatar.sha256,
|
|
25188
|
+
resourceName: resource.metadata.name
|
|
25189
|
+
} : void 0;
|
|
25170
25190
|
}
|
|
25171
25191
|
return void 0;
|
|
25172
25192
|
}
|
|
@@ -25432,6 +25452,7 @@ var init_project_apply_files = __esm({
|
|
|
25432
25452
|
init_assets();
|
|
25433
25453
|
init_source();
|
|
25434
25454
|
init_template_injection();
|
|
25455
|
+
init_assets();
|
|
25435
25456
|
init_template_injection();
|
|
25436
25457
|
init_template_bump_diagnostics();
|
|
25437
25458
|
init_template_staleness();
|
|
@@ -35138,6 +35159,7 @@ function withClaudeStderrDiagnosticsPointer(error51, capturedStderr) {
|
|
|
35138
35159
|
// src/commands/agent-bridge/harness/claude-code/session.ts
|
|
35139
35160
|
var CLAUDE_AGENT_STARTUP_TIMEOUT_MS = 3e4;
|
|
35140
35161
|
var CLAUDE_INTERRUPT_SETTLE_TIMEOUT_MS = 1e4;
|
|
35162
|
+
var CLAUDE_INTERRUPT_ACK_TIMEOUT_MS = 1e4;
|
|
35141
35163
|
var CLAUDE_MCP_REGISTRATION_TIMEOUT_MS = 3e3;
|
|
35142
35164
|
var CLAUDE_MCP_REGISTRATION_POLL_INTERVAL_MS = 100;
|
|
35143
35165
|
var CLAUDE_STARTUP_PROFILE_HOOK_EVENTS = [
|
|
@@ -35177,10 +35199,18 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
35177
35199
|
// decrements — so interleaved interrupt/result deliveries stay balanced.
|
|
35178
35200
|
activeTurnCount = 0;
|
|
35179
35201
|
interruptInFlight = null;
|
|
35202
|
+
// turnResultCount at the moment an interrupt ack timed out, or null when no
|
|
35203
|
+
// timeout is latched. While turnResultCount still equals this value the same
|
|
35204
|
+
// wedged turn is running, so follow-up messages defer immediately instead of
|
|
35205
|
+
// each re-racing a fresh ack timeout against the unresponsive control
|
|
35206
|
+
// channel (and stacking pending control requests). Any terminal result
|
|
35207
|
+
// advances turnResultCount and un-latches.
|
|
35208
|
+
interruptAckTimeoutTurn = null;
|
|
35180
35209
|
exitReported = false;
|
|
35181
|
-
// Messages
|
|
35182
|
-
//
|
|
35183
|
-
//
|
|
35210
|
+
// Messages held for the turn's terminal result instead of injected mid-turn
|
|
35211
|
+
// (which would reject a pending tool_use): "deferred"-mode deliveries, plus
|
|
35212
|
+
// interrupt-mode deliveries whose interrupt ack timed out. Flushed once the
|
|
35213
|
+
// turn ends and the session is idle.
|
|
35184
35214
|
deferredMessages = [];
|
|
35185
35215
|
// tool_use ids the assistant has emitted whose tool_result has not yet been
|
|
35186
35216
|
// observed. A non-empty set means a tool call is in flight, so an immediate
|
|
@@ -35260,7 +35290,19 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
35260
35290
|
});
|
|
35261
35291
|
return;
|
|
35262
35292
|
}
|
|
35263
|
-
await this.interruptActiveTurnBeforeMessage();
|
|
35293
|
+
const interruption = await this.interruptActiveTurnBeforeMessage();
|
|
35294
|
+
if (interruption === "defer" && this.hasInterruptibleTurn()) {
|
|
35295
|
+
this.deferredMessages.push(message);
|
|
35296
|
+
this.input.runtimeLogger?.info(
|
|
35297
|
+
"agent_bridge_claude_message_deferred_after_interrupt_timeout",
|
|
35298
|
+
{
|
|
35299
|
+
active_turn_count: this.activeTurnCount,
|
|
35300
|
+
pending_tool_use_count: this.pendingToolUseIds.size,
|
|
35301
|
+
deferred_count: this.deferredMessages.length
|
|
35302
|
+
}
|
|
35303
|
+
);
|
|
35304
|
+
return;
|
|
35305
|
+
}
|
|
35264
35306
|
await this.awaitMcpRegistration();
|
|
35265
35307
|
this.enqueueUserMessage(message);
|
|
35266
35308
|
this.input.runtimeLogger?.info("agent_bridge_claude_send_message_queued", {
|
|
@@ -35509,14 +35551,19 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
35509
35551
|
}
|
|
35510
35552
|
async interruptActiveTurnBeforeMessage() {
|
|
35511
35553
|
if (!this.hasInterruptibleTurn()) {
|
|
35512
|
-
return;
|
|
35554
|
+
return "proceed";
|
|
35513
35555
|
}
|
|
35514
35556
|
if (this.interruptInFlight) {
|
|
35515
|
-
await this.interruptInFlight;
|
|
35516
|
-
|
|
35557
|
+
return await this.interruptInFlight;
|
|
35558
|
+
}
|
|
35559
|
+
if (this.interruptAckTimeoutTurn !== null) {
|
|
35560
|
+
if (this.interruptAckTimeoutTurn === this.turnResultCount) {
|
|
35561
|
+
return "defer";
|
|
35562
|
+
}
|
|
35563
|
+
this.interruptAckTimeoutTurn = null;
|
|
35517
35564
|
}
|
|
35518
35565
|
if (this.state.kind !== "running") {
|
|
35519
|
-
return;
|
|
35566
|
+
return "proceed";
|
|
35520
35567
|
}
|
|
35521
35568
|
const query = this.state.query;
|
|
35522
35569
|
const hadInFlightToolUse = this.hasInFlightToolUse();
|
|
@@ -35526,29 +35573,79 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
35526
35573
|
`agent_bridge_claude_mid_turn_interrupt_started at=${new Date(startedAt).toISOString()} in_flight_tool_use=${hadInFlightToolUse}`
|
|
35527
35574
|
);
|
|
35528
35575
|
const interruptPromise = (async () => {
|
|
35529
|
-
|
|
35530
|
-
|
|
35531
|
-
this.
|
|
35532
|
-
|
|
35533
|
-
);
|
|
35534
|
-
} catch (error51) {
|
|
35535
|
-
this.input.writeOutput?.(
|
|
35536
|
-
`agent_bridge_claude_mid_turn_interrupt_failed duration_ms=${Date.now() - startedAt} error=${error51 instanceof Error ? error51.message : String(error51)}`
|
|
35537
|
-
);
|
|
35576
|
+
const ack = await this.requestInterruptAck(query, startedAt);
|
|
35577
|
+
if (ack === "timeout") {
|
|
35578
|
+
this.interruptAckTimeoutTurn = settlementBaseline;
|
|
35579
|
+
return "defer";
|
|
35538
35580
|
}
|
|
35539
35581
|
if (hadInFlightToolUse) {
|
|
35540
35582
|
await this.awaitTurnSettlement(settlementBaseline, startedAt);
|
|
35541
35583
|
}
|
|
35584
|
+
return "proceed";
|
|
35542
35585
|
})();
|
|
35543
35586
|
this.interruptInFlight = interruptPromise;
|
|
35544
35587
|
try {
|
|
35545
|
-
await interruptPromise;
|
|
35588
|
+
return await interruptPromise;
|
|
35546
35589
|
} finally {
|
|
35547
35590
|
if (this.interruptInFlight === interruptPromise) {
|
|
35548
35591
|
this.interruptInFlight = null;
|
|
35549
35592
|
}
|
|
35550
35593
|
}
|
|
35551
35594
|
}
|
|
35595
|
+
// Fire the interrupt control request, bounded by the ack timeout. "ready" =
|
|
35596
|
+
// the SDK acked; "failed" = the SDK rejected it (a steering message is still
|
|
35597
|
+
// useful, so the caller falls back to normal queued delivery); "timeout" =
|
|
35598
|
+
// no answer within CLAUDE_INTERRUPT_ACK_TIMEOUT_MS (FRA-3465). The abandoned
|
|
35599
|
+
// request stays attached to late-outcome logging so it can never surface as
|
|
35600
|
+
// an unhandled rejection after the timeout won.
|
|
35601
|
+
requestInterruptAck(query, startedAt) {
|
|
35602
|
+
return new Promise((resolve4) => {
|
|
35603
|
+
let done = false;
|
|
35604
|
+
const finish = (outcome, line) => {
|
|
35605
|
+
if (done) {
|
|
35606
|
+
return;
|
|
35607
|
+
}
|
|
35608
|
+
done = true;
|
|
35609
|
+
clearTimeout(timer);
|
|
35610
|
+
this.input.writeOutput?.(line);
|
|
35611
|
+
resolve4(outcome);
|
|
35612
|
+
};
|
|
35613
|
+
const timer = setTimeout(() => {
|
|
35614
|
+
finish(
|
|
35615
|
+
"timeout",
|
|
35616
|
+
`agent_bridge_claude_mid_turn_interrupt_ack_timeout duration_ms=${Date.now() - startedAt}`
|
|
35617
|
+
);
|
|
35618
|
+
}, CLAUDE_INTERRUPT_ACK_TIMEOUT_MS);
|
|
35619
|
+
timer.unref?.();
|
|
35620
|
+
query.interrupt().then(
|
|
35621
|
+
() => {
|
|
35622
|
+
if (done) {
|
|
35623
|
+
this.input.writeOutput?.(
|
|
35624
|
+
`agent_bridge_claude_mid_turn_interrupt_late_ready duration_ms=${Date.now() - startedAt}`
|
|
35625
|
+
);
|
|
35626
|
+
return;
|
|
35627
|
+
}
|
|
35628
|
+
finish(
|
|
35629
|
+
"ready",
|
|
35630
|
+
`agent_bridge_claude_mid_turn_interrupt_ready duration_ms=${Date.now() - startedAt}`
|
|
35631
|
+
);
|
|
35632
|
+
},
|
|
35633
|
+
(error51) => {
|
|
35634
|
+
const detail = `duration_ms=${Date.now() - startedAt} error=${error51 instanceof Error ? error51.message : String(error51)}`;
|
|
35635
|
+
if (done) {
|
|
35636
|
+
this.input.writeOutput?.(
|
|
35637
|
+
`agent_bridge_claude_mid_turn_interrupt_late_failed ${detail}`
|
|
35638
|
+
);
|
|
35639
|
+
return;
|
|
35640
|
+
}
|
|
35641
|
+
finish(
|
|
35642
|
+
"failed",
|
|
35643
|
+
`agent_bridge_claude_mid_turn_interrupt_failed ${detail}`
|
|
35644
|
+
);
|
|
35645
|
+
}
|
|
35646
|
+
);
|
|
35647
|
+
});
|
|
35648
|
+
}
|
|
35552
35649
|
// Why this gate is correct without a provider-backed test (it relies on real
|
|
35553
35650
|
// SDK mcpServerStatus() timing that fakes cannot prove):
|
|
35554
35651
|
// - Safe-degrade on uncertainty: pollMcpRegistration never rejects — on
|
|
@@ -37724,15 +37821,19 @@ function replaceErrors(_key, value) {
|
|
|
37724
37821
|
async function runAgentBridgeProcess(input) {
|
|
37725
37822
|
const runAgentBridge = input.runAgentBridge ?? runAgentBridgeHarness;
|
|
37726
37823
|
const log = createRuntimeLogger(input.env);
|
|
37824
|
+
const writeOutput = (line) => {
|
|
37825
|
+
input.writeOutput?.(line);
|
|
37826
|
+
log.info(line);
|
|
37827
|
+
};
|
|
37727
37828
|
log.info("agent bridge process starting", {
|
|
37728
37829
|
bridge_url_host: bridgeUrlHost(input.env.AUTO_BRIDGE_URL),
|
|
37729
37830
|
log_level: log.level
|
|
37730
37831
|
});
|
|
37731
37832
|
try {
|
|
37732
37833
|
await runAgentBridge({
|
|
37733
|
-
...agentBridgeOptionsFromEnv(input),
|
|
37834
|
+
...agentBridgeOptionsFromEnv({ env: input.env, writeOutput }),
|
|
37734
37835
|
runtimeLogger: log,
|
|
37735
|
-
onBootstrap: createGitCredentialRelayStarter(
|
|
37836
|
+
onBootstrap: createGitCredentialRelayStarter(writeOutput, log)
|
|
37736
37837
|
});
|
|
37737
37838
|
} catch (error51) {
|
|
37738
37839
|
log.error("agent bridge process failed", { error: error51 });
|