@autohq/cli 0.1.600 → 0.1.602

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.
@@ -33828,7 +33828,9 @@ var RUNTIME_BRIDGE_SOCKET_PATH = "/runtime/socket.io";
33828
33828
  var RUNTIME_BRIDGE_BOOTSTRAP_EVENT = "bridge.bootstrap";
33829
33829
  var RUNTIME_BRIDGE_CONNECTED_EVENT = "bridge.connected";
33830
33830
  var RUNTIME_BRIDGE_COMMAND_EVENT = "runtime.command";
33831
+ var RUNTIME_BRIDGE_LEASE_AUTHORIZATION_EVENT = "runtime.lease_authorization";
33831
33832
  var RUNTIME_BRIDGE_OUTPUT_EVENT = "runtime.output";
33833
+ var RUNTIME_BRIDGE_USAGE_TURN_EVENT = "runtime.usage_turn";
33832
33834
  var AgentBridgeMcpServerConfigSchema = external_exports.object({
33833
33835
  type: external_exports.literal("http"),
33834
33836
  url: external_exports.string().trim().min(1),
@@ -33938,6 +33940,19 @@ var RuntimeBridgeConnectedPayloadSchema = external_exports.object({
33938
33940
  runtimeId: RuntimeIdSchema,
33939
33941
  bridgeLeaseId: RuntimeBridgeLeaseIdSchema
33940
33942
  });
33943
+ var RuntimeBridgeLeaseAuthorizationRequestSchema = external_exports.object({
33944
+ sessionId: SessionIdSchema,
33945
+ runtimeId: RuntimeIdSchema,
33946
+ bridgeLeaseId: RuntimeBridgeLeaseIdSchema
33947
+ }).strict();
33948
+ var RuntimeBridgeLeaseAuthorizationAckSchema = external_exports.object({
33949
+ sessionId: SessionIdSchema,
33950
+ runtimeId: RuntimeIdSchema,
33951
+ bridgeLeaseId: RuntimeBridgeLeaseIdSchema,
33952
+ status: external_exports.enum(["authorized", "failed"]),
33953
+ error: external_exports.string().trim().min(1).optional(),
33954
+ at: external_exports.string().datetime()
33955
+ }).strict();
33941
33956
  var RuntimeBridgeCommandDeliverySchema = external_exports.object({
33942
33957
  type: external_exports.literal("command.delivery"),
33943
33958
  deliveryId: external_exports.string().trim().min(1),
@@ -37736,7 +37751,7 @@ Object.assign(lookup, {
37736
37751
  // package.json
37737
37752
  var package_default = {
37738
37753
  name: "@autohq/cli",
37739
- version: "0.1.600",
37754
+ version: "0.1.602",
37740
37755
  license: "SEE LICENSE IN README.md",
37741
37756
  publishConfig: {
37742
37757
  access: "public"
@@ -37937,6 +37952,8 @@ async function runAgentBridgeSocket(options) {
37937
37952
  token: options.token,
37938
37953
  onBootstrap: options.onBootstrap,
37939
37954
  createHandler: (bootstrap) => options.createHandler({
37955
+ authorizeLease: (request) => authorizeLeaseWithAck(socket, request, options.runtimeLogger),
37956
+ authorizeUsageTurn: (output) => emitUsageTurnWithAck(socket, output, options.runtimeLogger),
37940
37957
  emitOutput: (output) => emitOutputWithAck(socket, output, options.runtimeLogger),
37941
37958
  onOutputAckProgress: terminalAuthDrain.handleOutputAckProgress,
37942
37959
  cycleSocket: () => {
@@ -38150,19 +38167,109 @@ function createRuntimeBridgeBootstrapListener(input) {
38150
38167
  };
38151
38168
  }
38152
38169
  function emitOutputWithAck(socket, output, runtimeLogger) {
38170
+ return emitRuntimeOutputWithAck({
38171
+ event: RUNTIME_BRIDGE_OUTPUT_EVENT,
38172
+ output,
38173
+ runtimeLogger,
38174
+ socket
38175
+ });
38176
+ }
38177
+ function authorizeLeaseWithAck(socket, request, runtimeLogger) {
38153
38178
  const startedAt = Date.now();
38154
- runtimeLogger?.info(
38179
+ runtimeLogger?.info("agent_bridge_lease_authorization_started", {
38180
+ session_id: request.sessionId,
38181
+ runtime_id: request.runtimeId,
38182
+ bridge_lease_id: request.bridgeLeaseId,
38183
+ socket_id: socket.id
38184
+ });
38185
+ return new Promise((resolve4, reject) => {
38186
+ socket.timeout(AGENT_BRIDGE_OUTPUT_ACK_TIMEOUT_MS).emit(
38187
+ RUNTIME_BRIDGE_LEASE_AUTHORIZATION_EVENT,
38188
+ request,
38189
+ (error51, rawAck) => {
38190
+ if (error51) {
38191
+ runtimeLogger?.warn("agent_bridge_lease_authorization_failed", {
38192
+ session_id: request.sessionId,
38193
+ runtime_id: request.runtimeId,
38194
+ bridge_lease_id: request.bridgeLeaseId,
38195
+ socket_id: socket.id,
38196
+ duration_ms: Date.now() - startedAt,
38197
+ error: error51.message
38198
+ });
38199
+ reject(
38200
+ new AgentBridgeOutputAckTimeoutError(
38201
+ `Bridge lease authorization ack timed out: ${error51.message}`
38202
+ )
38203
+ );
38204
+ return;
38205
+ }
38206
+ const ack = RuntimeBridgeLeaseAuthorizationAckSchema.safeParse(rawAck);
38207
+ if (!ack.success) {
38208
+ runtimeLogger?.warn("agent_bridge_lease_authorization_invalid", {
38209
+ session_id: request.sessionId,
38210
+ runtime_id: request.runtimeId,
38211
+ bridge_lease_id: request.bridgeLeaseId,
38212
+ socket_id: socket.id,
38213
+ duration_ms: Date.now() - startedAt,
38214
+ error: ack.error.message
38215
+ });
38216
+ reject(
38217
+ new Error(
38218
+ `Invalid bridge lease authorization ack: ${ack.error.message}`
38219
+ )
38220
+ );
38221
+ return;
38222
+ }
38223
+ if (ack.data.status === "failed") {
38224
+ runtimeLogger?.warn("agent_bridge_lease_authorization_rejected", {
38225
+ session_id: request.sessionId,
38226
+ runtime_id: request.runtimeId,
38227
+ bridge_lease_id: request.bridgeLeaseId,
38228
+ socket_id: socket.id,
38229
+ duration_ms: Date.now() - startedAt,
38230
+ error: ack.data.error
38231
+ });
38232
+ reject(
38233
+ new Error(
38234
+ ack.data.error ?? "Bridge lease is no longer authorized"
38235
+ )
38236
+ );
38237
+ return;
38238
+ }
38239
+ runtimeLogger?.info("agent_bridge_lease_authorization_ready", {
38240
+ session_id: request.sessionId,
38241
+ runtime_id: request.runtimeId,
38242
+ bridge_lease_id: request.bridgeLeaseId,
38243
+ socket_id: socket.id,
38244
+ duration_ms: Date.now() - startedAt
38245
+ });
38246
+ resolve4(ack.data);
38247
+ }
38248
+ );
38249
+ });
38250
+ }
38251
+ function emitUsageTurnWithAck(socket, output, runtimeLogger) {
38252
+ return emitRuntimeOutputWithAck({
38253
+ event: RUNTIME_BRIDGE_USAGE_TURN_EVENT,
38254
+ output,
38255
+ runtimeLogger,
38256
+ socket
38257
+ });
38258
+ }
38259
+ function emitRuntimeOutputWithAck(input) {
38260
+ const startedAt = Date.now();
38261
+ input.runtimeLogger?.info(
38155
38262
  "agent_bridge_output_emit_started",
38156
- outputLogContext(output, socket.id)
38263
+ outputLogContext(input.output, input.socket.id)
38157
38264
  );
38158
38265
  return new Promise((resolve4, reject) => {
38159
- socket.timeout(AGENT_BRIDGE_OUTPUT_ACK_TIMEOUT_MS).emit(
38160
- RUNTIME_BRIDGE_OUTPUT_EVENT,
38161
- output,
38266
+ input.socket.timeout(AGENT_BRIDGE_OUTPUT_ACK_TIMEOUT_MS).emit(
38267
+ input.event,
38268
+ input.output,
38162
38269
  (error51, rawAck) => {
38163
38270
  if (error51) {
38164
- runtimeLogger?.warn("agent_bridge_output_emit_ack_failed", {
38165
- ...outputLogContext(output, socket.id),
38271
+ input.runtimeLogger?.warn("agent_bridge_output_emit_ack_failed", {
38272
+ ...outputLogContext(input.output, input.socket.id),
38166
38273
  duration_ms: Date.now() - startedAt,
38167
38274
  error: error51.message
38168
38275
  });
@@ -38171,8 +38278,8 @@ function emitOutputWithAck(socket, output, runtimeLogger) {
38171
38278
  }
38172
38279
  const ack = RuntimeBridgeOutputAckSchema.safeParse(rawAck);
38173
38280
  if (!ack.success) {
38174
- runtimeLogger?.warn("agent_bridge_output_emit_ack_invalid", {
38175
- ...outputLogContext(output, socket.id),
38281
+ input.runtimeLogger?.warn("agent_bridge_output_emit_ack_invalid", {
38282
+ ...outputLogContext(input.output, input.socket.id),
38176
38283
  duration_ms: Date.now() - startedAt,
38177
38284
  error: ack.error.message
38178
38285
  });
@@ -38180,8 +38287,8 @@ function emitOutputWithAck(socket, output, runtimeLogger) {
38180
38287
  return;
38181
38288
  }
38182
38289
  if (ack.data.status === "failed") {
38183
- runtimeLogger?.warn("agent_bridge_output_emit_ack_rejected", {
38184
- ...outputLogContext(output, socket.id),
38290
+ input.runtimeLogger?.warn("agent_bridge_output_emit_ack_rejected", {
38291
+ ...outputLogContext(input.output, input.socket.id),
38185
38292
  duration_ms: Date.now() - startedAt,
38186
38293
  ack_status: ack.data.status,
38187
38294
  error: ack.data.error
@@ -38191,8 +38298,8 @@ function emitOutputWithAck(socket, output, runtimeLogger) {
38191
38298
  );
38192
38299
  return;
38193
38300
  }
38194
- runtimeLogger?.info("agent_bridge_output_emit_ack_ready", {
38195
- ...outputLogContext(output, socket.id),
38301
+ input.runtimeLogger?.info("agent_bridge_output_emit_ack_ready", {
38302
+ ...outputLogContext(input.output, input.socket.id),
38196
38303
  duration_ms: Date.now() - startedAt,
38197
38304
  ack_status: ack.data.status,
38198
38305
  cursor: ack.data.cursor
@@ -46909,7 +47016,8 @@ var SetupOnboardingPullRequestCreateResponseSchema = external_exports.discrimina
46909
47016
  var SetupOnboardingPullRequestStatusRequestSchema = external_exports.object({
46910
47017
  githubConnection: external_exports.string().trim().min(1).optional(),
46911
47018
  repo: GithubSyncRepositoryFullNameSchema,
46912
- // Absent in sync mode: there is no bootstrap PR, so readiness is apply-only.
47019
+ // Absent in sync mode: there is no bootstrap PR, so the deployment and
47020
+ // handoff gates do not also wait for a merge.
46913
47021
  pullRequestNumber: external_exports.coerce.number().int().positive().optional(),
46914
47022
  // Bootstrap PR head used to inspect the GitHub Sync apply check after merge.
46915
47023
  pullRequestHeadSha: external_exports.string().trim().min(1).optional(),
@@ -83758,6 +83866,15 @@ var AgentBridgeOutputBuffer = class {
83758
83866
  await this.flushPendingDelta();
83759
83867
  await this.enqueueProjectionAndDrain(context, projection, options);
83760
83868
  }
83869
+ async enqueueEntryProjection(context, projection) {
83870
+ await this.materializePendingUiDelta();
83871
+ this.materializePendingDelta();
83872
+ this.outputSeq += 1;
83873
+ this.enqueueOutput(
83874
+ buildOutputEnvelope(context, this.outputSeq, projection)
83875
+ );
83876
+ return { drained: this.drainPendingOutputs() };
83877
+ }
83761
83878
  async replayPendingOutputs() {
83762
83879
  await this.materializePendingUiDelta();
83763
83880
  await this.flushPendingDelta({ force: true });
@@ -83806,17 +83923,18 @@ var AgentBridgeOutputBuffer = class {
83806
83923
  * could attribute a billed call to the preceding turn.
83807
83924
  */
83808
83925
  async emitUsageTurn(context, turnId) {
83809
- this.outputSeq += 1;
83810
- this.enqueueOutput(
83811
- buildUsageTurnOutputEnvelope({
83812
- context,
83813
- outputSeq: this.outputSeq,
83814
- turnId,
83815
- createdAt: now2()
83816
- })
83817
- );
83926
+ this.enqueueOutput(this.nextUsageTurnOutput(context, turnId));
83818
83927
  await this.drainPendingOutputs({ failIfBlocked: true });
83819
83928
  }
83929
+ nextUsageTurnOutput(context, turnId) {
83930
+ this.outputSeq += 1;
83931
+ return buildUsageTurnOutputEnvelope({
83932
+ context,
83933
+ outputSeq: this.outputSeq,
83934
+ turnId,
83935
+ createdAt: now2()
83936
+ });
83937
+ }
83820
83938
  async emitUiMessageChunk(context, projection) {
83821
83939
  await this.flushPendingDelta();
83822
83940
  await this.emitLiveUiMessageChunk(context, projection.chunk);
@@ -84085,6 +84203,13 @@ var AgentBridgeOutputBuffer = class {
84085
84203
  this.deltaFlushTimer = null;
84086
84204
  }
84087
84205
  async flushPendingDelta(options = {}) {
84206
+ if (!this.pendingDelta) {
84207
+ return;
84208
+ }
84209
+ this.materializePendingDelta();
84210
+ await this.drainPendingOutputs(options);
84211
+ }
84212
+ materializePendingDelta() {
84088
84213
  const pendingDelta = this.pendingDelta;
84089
84214
  if (!pendingDelta) {
84090
84215
  return;
@@ -84092,14 +84217,14 @@ var AgentBridgeOutputBuffer = class {
84092
84217
  this.clearDeltaFlushTimer();
84093
84218
  this.pendingDelta = null;
84094
84219
  this.outputSeq += 1;
84095
- const output = buildDeltaOutputEnvelope({
84096
- context: pendingDelta.context,
84097
- outputSeq: this.outputSeq,
84098
- delta: pendingDelta.delta,
84099
- createdAt: pendingDelta.createdAt
84100
- });
84101
- this.enqueueOutput(output);
84102
- await this.drainPendingOutputs(options);
84220
+ this.enqueueOutput(
84221
+ buildDeltaOutputEnvelope({
84222
+ context: pendingDelta.context,
84223
+ outputSeq: this.outputSeq,
84224
+ delta: pendingDelta.delta,
84225
+ createdAt: pendingDelta.createdAt
84226
+ })
84227
+ );
84103
84228
  }
84104
84229
  async emitUntilAcked(output) {
84105
84230
  for (let attempt = 0; ; attempt += 1) {
@@ -84625,7 +84750,7 @@ function buildLivenessOutputEnvelope(input) {
84625
84750
  }
84626
84751
  function buildUsageTurnOutputEnvelope(input) {
84627
84752
  const { context } = input;
84628
- return RuntimeBridgeOutputEnvelopeSchema.parse({
84753
+ return RuntimeBridgeOutputUsageTurnEnvelopeSchema.parse({
84629
84754
  type: "runtime.usage_turn",
84630
84755
  sessionId: context.sessionId,
84631
84756
  runtimeId: context.runtimeId,
@@ -87130,30 +87255,24 @@ var ClaudeCodeCommandHandler = class {
87130
87255
  // original delivery and any redeliveries, so failures travel as values.
87131
87256
  async injectMessageCommand(activeContext, delivery, message, socketId) {
87132
87257
  try {
87133
- const emitStartedAt = Date.now();
87134
- this.input.runtimeLogger?.info(
87135
- "agent_bridge_claude_command_user_entry_emit_started",
87136
- commandLogContext(delivery, { socket_id: socketId })
87137
- );
87138
- await this.emitRequiredBridgeOutput(activeContext, {
87139
- type: "entry",
87140
- entry: {
87141
- messageId: delivery.commandId,
87142
- role: "user",
87143
- kind: "message",
87144
- status: "completed",
87145
- content: {
87146
- parts: [{ type: "text", text: message }]
87147
- }
87258
+ const enqueueStartedAt = Date.now();
87259
+ await this.enqueueUserEntryBridgeOutput(activeContext, {
87260
+ messageId: delivery.commandId,
87261
+ role: "user",
87262
+ kind: "message",
87263
+ status: "completed",
87264
+ content: {
87265
+ parts: [{ type: "text", text: message }]
87148
87266
  }
87149
87267
  });
87150
87268
  this.input.runtimeLogger?.info(
87151
- "agent_bridge_claude_command_user_entry_emit_ready",
87269
+ "agent_bridge_claude_command_user_entry_enqueued",
87152
87270
  commandLogContext(delivery, {
87153
87271
  socket_id: socketId,
87154
- duration_ms: Date.now() - emitStartedAt
87272
+ duration_ms: Date.now() - enqueueStartedAt
87155
87273
  })
87156
87274
  );
87275
+ await this.input.authorizeLease(activeContext);
87157
87276
  const sendStartedAt = Date.now();
87158
87277
  const mode = deliveryMode(delivery);
87159
87278
  this.applySelectionForMessage(delivery);
@@ -87247,18 +87366,16 @@ var ClaudeCodeCommandHandler = class {
87247
87366
  return;
87248
87367
  }
87249
87368
  const message = answerFallbackMessage(answer);
87250
- await this.emitRequiredBridgeOutput(activeContext, {
87251
- type: "entry",
87252
- entry: {
87253
- messageId: delivery.commandId,
87254
- role: "user",
87255
- kind: "message",
87256
- status: "completed",
87257
- content: {
87258
- parts: [{ type: "text", text: message }]
87259
- }
87369
+ await this.enqueueUserEntryBridgeOutput(activeContext, {
87370
+ messageId: delivery.commandId,
87371
+ role: "user",
87372
+ kind: "message",
87373
+ status: "completed",
87374
+ content: {
87375
+ parts: [{ type: "text", text: message }]
87260
87376
  }
87261
87377
  });
87378
+ await this.input.authorizeLease(activeContext);
87262
87379
  await this.ensureAgentSession().sendMessage(message, {
87263
87380
  commandId: delivery.commandId
87264
87381
  });
@@ -87340,7 +87457,13 @@ var ClaudeCodeCommandHandler = class {
87340
87457
  if (!activeContext) {
87341
87458
  throw new Error("Cannot publish usage turn without bridge context");
87342
87459
  }
87343
- await this.outputBuffer.emitUsageTurn(activeContext, turnId);
87460
+ if (turnId) {
87461
+ await this.input.authorizeUsageTurn(
87462
+ this.outputBuffer.nextUsageTurnOutput(activeContext, turnId)
87463
+ );
87464
+ return;
87465
+ }
87466
+ await this.outputBuffer.emitUsageTurn(activeContext, null);
87344
87467
  }
87345
87468
  async emitBridgeOutput(activeContext, projection) {
87346
87469
  try {
@@ -87351,6 +87474,17 @@ var ClaudeCodeCommandHandler = class {
87351
87474
  );
87352
87475
  }
87353
87476
  }
87477
+ async enqueueUserEntryBridgeOutput(activeContext, entry) {
87478
+ const { drained } = await this.outputBuffer.enqueueEntryProjection(
87479
+ activeContext,
87480
+ { type: "entry", entry }
87481
+ );
87482
+ drained.catch((error51) => {
87483
+ this.input.writeOutput?.(
87484
+ `agent_bridge_output_emit_failed error=${error51 instanceof Error ? error51.message : String(error51)}`
87485
+ );
87486
+ });
87487
+ }
87354
87488
  async emitRequiredBridgeOutput(activeContext, projection) {
87355
87489
  const options = {
87356
87490
  discardOnFailure: true,
@@ -90138,6 +90272,8 @@ function createHarnessCommandHandler(input) {
90138
90272
  const { kind, ...claude } = config2;
90139
90273
  return createClaudeCodeCommandHandler({
90140
90274
  ...base,
90275
+ authorizeLease: input.authorizeLease,
90276
+ authorizeUsageTurn: input.authorizeUsageTurn,
90141
90277
  claude,
90142
90278
  readState: fileClaudeReadStateStore(),
90143
90279
  sessionResume: fileClaudeSessionResumeStore()
package/dist/index.js CHANGED
@@ -24334,7 +24334,8 @@ var init_setup = __esm({
24334
24334
  SetupOnboardingPullRequestStatusRequestSchema = external_exports.object({
24335
24335
  githubConnection: external_exports.string().trim().min(1).optional(),
24336
24336
  repo: GithubSyncRepositoryFullNameSchema,
24337
- // Absent in sync mode: there is no bootstrap PR, so readiness is apply-only.
24337
+ // Absent in sync mode: there is no bootstrap PR, so the deployment and
24338
+ // handoff gates do not also wait for a merge.
24338
24339
  pullRequestNumber: external_exports.coerce.number().int().positive().optional(),
24339
24340
  // Bootstrap PR head used to inspect the GitHub Sync apply check after merge.
24340
24341
  pullRequestHeadSha: external_exports.string().trim().min(1).optional(),
@@ -91158,7 +91159,7 @@ var init_package = __esm({
91158
91159
  "package.json"() {
91159
91160
  package_default = {
91160
91161
  name: "@autohq/cli",
91161
- version: "0.1.600",
91162
+ version: "0.1.602",
91162
91163
  license: "SEE LICENSE IN README.md",
91163
91164
  publishConfig: {
91164
91165
  access: "public"
@@ -102110,7 +102111,9 @@ var RUNTIME_BRIDGE_SOCKET_PATH = "/runtime/socket.io";
102110
102111
  var RUNTIME_BRIDGE_BOOTSTRAP_EVENT = "bridge.bootstrap";
102111
102112
  var RUNTIME_BRIDGE_CONNECTED_EVENT = "bridge.connected";
102112
102113
  var RUNTIME_BRIDGE_COMMAND_EVENT = "runtime.command";
102114
+ var RUNTIME_BRIDGE_LEASE_AUTHORIZATION_EVENT = "runtime.lease_authorization";
102113
102115
  var RUNTIME_BRIDGE_OUTPUT_EVENT = "runtime.output";
102116
+ var RUNTIME_BRIDGE_USAGE_TURN_EVENT = "runtime.usage_turn";
102114
102117
  var AgentBridgeMcpServerConfigSchema = external_exports.object({
102115
102118
  type: external_exports.literal("http"),
102116
102119
  url: external_exports.string().trim().min(1),
@@ -102220,6 +102223,19 @@ var RuntimeBridgeConnectedPayloadSchema = external_exports.object({
102220
102223
  runtimeId: RuntimeIdSchema2,
102221
102224
  bridgeLeaseId: RuntimeBridgeLeaseIdSchema2
102222
102225
  });
102226
+ var RuntimeBridgeLeaseAuthorizationRequestSchema = external_exports.object({
102227
+ sessionId: SessionIdSchema2,
102228
+ runtimeId: RuntimeIdSchema2,
102229
+ bridgeLeaseId: RuntimeBridgeLeaseIdSchema2
102230
+ }).strict();
102231
+ var RuntimeBridgeLeaseAuthorizationAckSchema = external_exports.object({
102232
+ sessionId: SessionIdSchema2,
102233
+ runtimeId: RuntimeIdSchema2,
102234
+ bridgeLeaseId: RuntimeBridgeLeaseIdSchema2,
102235
+ status: external_exports.enum(["authorized", "failed"]),
102236
+ error: external_exports.string().trim().min(1).optional(),
102237
+ at: external_exports.string().datetime()
102238
+ }).strict();
102223
102239
  var RuntimeBridgeCommandDeliverySchema = external_exports.object({
102224
102240
  type: external_exports.literal("command.delivery"),
102225
102241
  deliveryId: external_exports.string().trim().min(1),
@@ -102607,6 +102623,8 @@ async function runAgentBridgeSocket(options) {
102607
102623
  token: options.token,
102608
102624
  onBootstrap: options.onBootstrap,
102609
102625
  createHandler: (bootstrap) => options.createHandler({
102626
+ authorizeLease: (request) => authorizeLeaseWithAck(socket, request, options.runtimeLogger),
102627
+ authorizeUsageTurn: (output) => emitUsageTurnWithAck(socket, output, options.runtimeLogger),
102610
102628
  emitOutput: (output) => emitOutputWithAck(socket, output, options.runtimeLogger),
102611
102629
  onOutputAckProgress: terminalAuthDrain.handleOutputAckProgress,
102612
102630
  cycleSocket: () => {
@@ -102820,19 +102838,109 @@ function createRuntimeBridgeBootstrapListener(input) {
102820
102838
  };
102821
102839
  }
102822
102840
  function emitOutputWithAck(socket, output, runtimeLogger) {
102841
+ return emitRuntimeOutputWithAck({
102842
+ event: RUNTIME_BRIDGE_OUTPUT_EVENT,
102843
+ output,
102844
+ runtimeLogger,
102845
+ socket
102846
+ });
102847
+ }
102848
+ function authorizeLeaseWithAck(socket, request, runtimeLogger) {
102823
102849
  const startedAt = Date.now();
102824
- runtimeLogger?.info(
102850
+ runtimeLogger?.info("agent_bridge_lease_authorization_started", {
102851
+ session_id: request.sessionId,
102852
+ runtime_id: request.runtimeId,
102853
+ bridge_lease_id: request.bridgeLeaseId,
102854
+ socket_id: socket.id
102855
+ });
102856
+ return new Promise((resolve6, reject) => {
102857
+ socket.timeout(AGENT_BRIDGE_OUTPUT_ACK_TIMEOUT_MS).emit(
102858
+ RUNTIME_BRIDGE_LEASE_AUTHORIZATION_EVENT,
102859
+ request,
102860
+ (error51, rawAck) => {
102861
+ if (error51) {
102862
+ runtimeLogger?.warn("agent_bridge_lease_authorization_failed", {
102863
+ session_id: request.sessionId,
102864
+ runtime_id: request.runtimeId,
102865
+ bridge_lease_id: request.bridgeLeaseId,
102866
+ socket_id: socket.id,
102867
+ duration_ms: Date.now() - startedAt,
102868
+ error: error51.message
102869
+ });
102870
+ reject(
102871
+ new AgentBridgeOutputAckTimeoutError(
102872
+ `Bridge lease authorization ack timed out: ${error51.message}`
102873
+ )
102874
+ );
102875
+ return;
102876
+ }
102877
+ const ack = RuntimeBridgeLeaseAuthorizationAckSchema.safeParse(rawAck);
102878
+ if (!ack.success) {
102879
+ runtimeLogger?.warn("agent_bridge_lease_authorization_invalid", {
102880
+ session_id: request.sessionId,
102881
+ runtime_id: request.runtimeId,
102882
+ bridge_lease_id: request.bridgeLeaseId,
102883
+ socket_id: socket.id,
102884
+ duration_ms: Date.now() - startedAt,
102885
+ error: ack.error.message
102886
+ });
102887
+ reject(
102888
+ new Error(
102889
+ `Invalid bridge lease authorization ack: ${ack.error.message}`
102890
+ )
102891
+ );
102892
+ return;
102893
+ }
102894
+ if (ack.data.status === "failed") {
102895
+ runtimeLogger?.warn("agent_bridge_lease_authorization_rejected", {
102896
+ session_id: request.sessionId,
102897
+ runtime_id: request.runtimeId,
102898
+ bridge_lease_id: request.bridgeLeaseId,
102899
+ socket_id: socket.id,
102900
+ duration_ms: Date.now() - startedAt,
102901
+ error: ack.data.error
102902
+ });
102903
+ reject(
102904
+ new Error(
102905
+ ack.data.error ?? "Bridge lease is no longer authorized"
102906
+ )
102907
+ );
102908
+ return;
102909
+ }
102910
+ runtimeLogger?.info("agent_bridge_lease_authorization_ready", {
102911
+ session_id: request.sessionId,
102912
+ runtime_id: request.runtimeId,
102913
+ bridge_lease_id: request.bridgeLeaseId,
102914
+ socket_id: socket.id,
102915
+ duration_ms: Date.now() - startedAt
102916
+ });
102917
+ resolve6(ack.data);
102918
+ }
102919
+ );
102920
+ });
102921
+ }
102922
+ function emitUsageTurnWithAck(socket, output, runtimeLogger) {
102923
+ return emitRuntimeOutputWithAck({
102924
+ event: RUNTIME_BRIDGE_USAGE_TURN_EVENT,
102925
+ output,
102926
+ runtimeLogger,
102927
+ socket
102928
+ });
102929
+ }
102930
+ function emitRuntimeOutputWithAck(input) {
102931
+ const startedAt = Date.now();
102932
+ input.runtimeLogger?.info(
102825
102933
  "agent_bridge_output_emit_started",
102826
- outputLogContext(output, socket.id)
102934
+ outputLogContext(input.output, input.socket.id)
102827
102935
  );
102828
102936
  return new Promise((resolve6, reject) => {
102829
- socket.timeout(AGENT_BRIDGE_OUTPUT_ACK_TIMEOUT_MS).emit(
102830
- RUNTIME_BRIDGE_OUTPUT_EVENT,
102831
- output,
102937
+ input.socket.timeout(AGENT_BRIDGE_OUTPUT_ACK_TIMEOUT_MS).emit(
102938
+ input.event,
102939
+ input.output,
102832
102940
  (error51, rawAck) => {
102833
102941
  if (error51) {
102834
- runtimeLogger?.warn("agent_bridge_output_emit_ack_failed", {
102835
- ...outputLogContext(output, socket.id),
102942
+ input.runtimeLogger?.warn("agent_bridge_output_emit_ack_failed", {
102943
+ ...outputLogContext(input.output, input.socket.id),
102836
102944
  duration_ms: Date.now() - startedAt,
102837
102945
  error: error51.message
102838
102946
  });
@@ -102841,8 +102949,8 @@ function emitOutputWithAck(socket, output, runtimeLogger) {
102841
102949
  }
102842
102950
  const ack = RuntimeBridgeOutputAckSchema.safeParse(rawAck);
102843
102951
  if (!ack.success) {
102844
- runtimeLogger?.warn("agent_bridge_output_emit_ack_invalid", {
102845
- ...outputLogContext(output, socket.id),
102952
+ input.runtimeLogger?.warn("agent_bridge_output_emit_ack_invalid", {
102953
+ ...outputLogContext(input.output, input.socket.id),
102846
102954
  duration_ms: Date.now() - startedAt,
102847
102955
  error: ack.error.message
102848
102956
  });
@@ -102850,8 +102958,8 @@ function emitOutputWithAck(socket, output, runtimeLogger) {
102850
102958
  return;
102851
102959
  }
102852
102960
  if (ack.data.status === "failed") {
102853
- runtimeLogger?.warn("agent_bridge_output_emit_ack_rejected", {
102854
- ...outputLogContext(output, socket.id),
102961
+ input.runtimeLogger?.warn("agent_bridge_output_emit_ack_rejected", {
102962
+ ...outputLogContext(input.output, input.socket.id),
102855
102963
  duration_ms: Date.now() - startedAt,
102856
102964
  ack_status: ack.data.status,
102857
102965
  error: ack.data.error
@@ -102861,8 +102969,8 @@ function emitOutputWithAck(socket, output, runtimeLogger) {
102861
102969
  );
102862
102970
  return;
102863
102971
  }
102864
- runtimeLogger?.info("agent_bridge_output_emit_ack_ready", {
102865
- ...outputLogContext(output, socket.id),
102972
+ input.runtimeLogger?.info("agent_bridge_output_emit_ack_ready", {
102973
+ ...outputLogContext(input.output, input.socket.id),
102866
102974
  duration_ms: Date.now() - startedAt,
102867
102975
  ack_status: ack.data.status,
102868
102976
  cursor: ack.data.cursor
@@ -105191,6 +105299,15 @@ var AgentBridgeOutputBuffer = class {
105191
105299
  await this.flushPendingDelta();
105192
105300
  await this.enqueueProjectionAndDrain(context, projection, options);
105193
105301
  }
105302
+ async enqueueEntryProjection(context, projection) {
105303
+ await this.materializePendingUiDelta();
105304
+ this.materializePendingDelta();
105305
+ this.outputSeq += 1;
105306
+ this.enqueueOutput(
105307
+ buildOutputEnvelope(context, this.outputSeq, projection)
105308
+ );
105309
+ return { drained: this.drainPendingOutputs() };
105310
+ }
105194
105311
  async replayPendingOutputs() {
105195
105312
  await this.materializePendingUiDelta();
105196
105313
  await this.flushPendingDelta({ force: true });
@@ -105239,17 +105356,18 @@ var AgentBridgeOutputBuffer = class {
105239
105356
  * could attribute a billed call to the preceding turn.
105240
105357
  */
105241
105358
  async emitUsageTurn(context, turnId) {
105242
- this.outputSeq += 1;
105243
- this.enqueueOutput(
105244
- buildUsageTurnOutputEnvelope({
105245
- context,
105246
- outputSeq: this.outputSeq,
105247
- turnId,
105248
- createdAt: now2()
105249
- })
105250
- );
105359
+ this.enqueueOutput(this.nextUsageTurnOutput(context, turnId));
105251
105360
  await this.drainPendingOutputs({ failIfBlocked: true });
105252
105361
  }
105362
+ nextUsageTurnOutput(context, turnId) {
105363
+ this.outputSeq += 1;
105364
+ return buildUsageTurnOutputEnvelope({
105365
+ context,
105366
+ outputSeq: this.outputSeq,
105367
+ turnId,
105368
+ createdAt: now2()
105369
+ });
105370
+ }
105253
105371
  async emitUiMessageChunk(context, projection) {
105254
105372
  await this.flushPendingDelta();
105255
105373
  await this.emitLiveUiMessageChunk(context, projection.chunk);
@@ -105518,6 +105636,13 @@ var AgentBridgeOutputBuffer = class {
105518
105636
  this.deltaFlushTimer = null;
105519
105637
  }
105520
105638
  async flushPendingDelta(options = {}) {
105639
+ if (!this.pendingDelta) {
105640
+ return;
105641
+ }
105642
+ this.materializePendingDelta();
105643
+ await this.drainPendingOutputs(options);
105644
+ }
105645
+ materializePendingDelta() {
105521
105646
  const pendingDelta = this.pendingDelta;
105522
105647
  if (!pendingDelta) {
105523
105648
  return;
@@ -105525,14 +105650,14 @@ var AgentBridgeOutputBuffer = class {
105525
105650
  this.clearDeltaFlushTimer();
105526
105651
  this.pendingDelta = null;
105527
105652
  this.outputSeq += 1;
105528
- const output = buildDeltaOutputEnvelope({
105529
- context: pendingDelta.context,
105530
- outputSeq: this.outputSeq,
105531
- delta: pendingDelta.delta,
105532
- createdAt: pendingDelta.createdAt
105533
- });
105534
- this.enqueueOutput(output);
105535
- await this.drainPendingOutputs(options);
105653
+ this.enqueueOutput(
105654
+ buildDeltaOutputEnvelope({
105655
+ context: pendingDelta.context,
105656
+ outputSeq: this.outputSeq,
105657
+ delta: pendingDelta.delta,
105658
+ createdAt: pendingDelta.createdAt
105659
+ })
105660
+ );
105536
105661
  }
105537
105662
  async emitUntilAcked(output) {
105538
105663
  for (let attempt = 0; ; attempt += 1) {
@@ -106058,7 +106183,7 @@ function buildLivenessOutputEnvelope(input) {
106058
106183
  }
106059
106184
  function buildUsageTurnOutputEnvelope(input) {
106060
106185
  const { context } = input;
106061
- return RuntimeBridgeOutputEnvelopeSchema.parse({
106186
+ return RuntimeBridgeOutputUsageTurnEnvelopeSchema.parse({
106062
106187
  type: "runtime.usage_turn",
106063
106188
  sessionId: context.sessionId,
106064
106189
  runtimeId: context.runtimeId,
@@ -108570,30 +108695,24 @@ var ClaudeCodeCommandHandler = class {
108570
108695
  // original delivery and any redeliveries, so failures travel as values.
108571
108696
  async injectMessageCommand(activeContext, delivery, message, socketId) {
108572
108697
  try {
108573
- const emitStartedAt = Date.now();
108574
- this.input.runtimeLogger?.info(
108575
- "agent_bridge_claude_command_user_entry_emit_started",
108576
- commandLogContext(delivery, { socket_id: socketId })
108577
- );
108578
- await this.emitRequiredBridgeOutput(activeContext, {
108579
- type: "entry",
108580
- entry: {
108581
- messageId: delivery.commandId,
108582
- role: "user",
108583
- kind: "message",
108584
- status: "completed",
108585
- content: {
108586
- parts: [{ type: "text", text: message }]
108587
- }
108698
+ const enqueueStartedAt = Date.now();
108699
+ await this.enqueueUserEntryBridgeOutput(activeContext, {
108700
+ messageId: delivery.commandId,
108701
+ role: "user",
108702
+ kind: "message",
108703
+ status: "completed",
108704
+ content: {
108705
+ parts: [{ type: "text", text: message }]
108588
108706
  }
108589
108707
  });
108590
108708
  this.input.runtimeLogger?.info(
108591
- "agent_bridge_claude_command_user_entry_emit_ready",
108709
+ "agent_bridge_claude_command_user_entry_enqueued",
108592
108710
  commandLogContext(delivery, {
108593
108711
  socket_id: socketId,
108594
- duration_ms: Date.now() - emitStartedAt
108712
+ duration_ms: Date.now() - enqueueStartedAt
108595
108713
  })
108596
108714
  );
108715
+ await this.input.authorizeLease(activeContext);
108597
108716
  const sendStartedAt = Date.now();
108598
108717
  const mode = deliveryMode(delivery);
108599
108718
  this.applySelectionForMessage(delivery);
@@ -108687,18 +108806,16 @@ var ClaudeCodeCommandHandler = class {
108687
108806
  return;
108688
108807
  }
108689
108808
  const message = answerFallbackMessage(answer);
108690
- await this.emitRequiredBridgeOutput(activeContext, {
108691
- type: "entry",
108692
- entry: {
108693
- messageId: delivery.commandId,
108694
- role: "user",
108695
- kind: "message",
108696
- status: "completed",
108697
- content: {
108698
- parts: [{ type: "text", text: message }]
108699
- }
108809
+ await this.enqueueUserEntryBridgeOutput(activeContext, {
108810
+ messageId: delivery.commandId,
108811
+ role: "user",
108812
+ kind: "message",
108813
+ status: "completed",
108814
+ content: {
108815
+ parts: [{ type: "text", text: message }]
108700
108816
  }
108701
108817
  });
108818
+ await this.input.authorizeLease(activeContext);
108702
108819
  await this.ensureAgentSession().sendMessage(message, {
108703
108820
  commandId: delivery.commandId
108704
108821
  });
@@ -108780,7 +108897,13 @@ var ClaudeCodeCommandHandler = class {
108780
108897
  if (!activeContext) {
108781
108898
  throw new Error("Cannot publish usage turn without bridge context");
108782
108899
  }
108783
- await this.outputBuffer.emitUsageTurn(activeContext, turnId);
108900
+ if (turnId) {
108901
+ await this.input.authorizeUsageTurn(
108902
+ this.outputBuffer.nextUsageTurnOutput(activeContext, turnId)
108903
+ );
108904
+ return;
108905
+ }
108906
+ await this.outputBuffer.emitUsageTurn(activeContext, null);
108784
108907
  }
108785
108908
  async emitBridgeOutput(activeContext, projection) {
108786
108909
  try {
@@ -108791,6 +108914,17 @@ var ClaudeCodeCommandHandler = class {
108791
108914
  );
108792
108915
  }
108793
108916
  }
108917
+ async enqueueUserEntryBridgeOutput(activeContext, entry) {
108918
+ const { drained } = await this.outputBuffer.enqueueEntryProjection(
108919
+ activeContext,
108920
+ { type: "entry", entry }
108921
+ );
108922
+ drained.catch((error51) => {
108923
+ this.input.writeOutput?.(
108924
+ `agent_bridge_output_emit_failed error=${error51 instanceof Error ? error51.message : String(error51)}`
108925
+ );
108926
+ });
108927
+ }
108794
108928
  async emitRequiredBridgeOutput(activeContext, projection) {
108795
108929
  const options = {
108796
108930
  discardOnFailure: true,
@@ -111583,6 +111717,8 @@ function createHarnessCommandHandler(input) {
111583
111717
  const { kind, ...claude } = config2;
111584
111718
  return createClaudeCodeCommandHandler({
111585
111719
  ...base,
111720
+ authorizeLease: input.authorizeLease,
111721
+ authorizeUsageTurn: input.authorizeUsageTurn,
111586
111722
  claude,
111587
111723
  readState: fileClaudeReadStateStore(),
111588
111724
  sessionResume: fileClaudeSessionResumeStore()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autohq/cli",
3
- "version": "0.1.600",
3
+ "version": "0.1.602",
4
4
  "license": "SEE LICENSE IN README.md",
5
5
  "publishConfig": {
6
6
  "access": "public"