@autohq/cli 0.1.187 → 0.1.196

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.
@@ -20856,6 +20856,11 @@ var GithubSyncBindingCreateResponseSchema = external_exports.object({
20856
20856
  var GithubSyncBindingListResponseSchema = external_exports.object({
20857
20857
  bindings: external_exports.array(GithubSyncBindingSchema)
20858
20858
  });
20859
+ var GithubSyncTriggerArtifactSchema = external_exports.object({
20860
+ type: external_exports.string().trim().min(1),
20861
+ externalId: external_exports.string().trim().min(1),
20862
+ payload: JsonValueSchema2.optional()
20863
+ }).strict();
20859
20864
  var GithubSyncWorkflowInputSchema = external_exports.discriminatedUnion("kind", [
20860
20865
  external_exports.object({
20861
20866
  kind: external_exports.literal("pull_request"),
@@ -20871,7 +20876,8 @@ var GithubSyncWorkflowInputSchema = external_exports.discriminatedUnion("kind",
20871
20876
  pullRequestNumber: external_exports.number().int().positive(),
20872
20877
  headSha: external_exports.string().trim().min(1),
20873
20878
  baseSha: external_exports.string().trim().min(1).optional(),
20874
- baseRef: GithubSyncProductionBranchSchema
20879
+ baseRef: GithubSyncProductionBranchSchema,
20880
+ triggerArtifact: GithubSyncTriggerArtifactSchema.optional()
20875
20881
  }),
20876
20882
  external_exports.object({
20877
20883
  kind: external_exports.literal("push"),
@@ -20887,7 +20893,8 @@ var GithubSyncWorkflowInputSchema = external_exports.discriminatedUnion("kind",
20887
20893
  ref: external_exports.string().trim().min(1),
20888
20894
  branch: GithubSyncProductionBranchSchema,
20889
20895
  before: external_exports.string().trim().min(1).optional(),
20890
- after: external_exports.string().trim().min(1)
20896
+ after: external_exports.string().trim().min(1),
20897
+ triggerArtifact: GithubSyncTriggerArtifactSchema.optional()
20891
20898
  })
20892
20899
  ]);
20893
20900
  var GithubSyncWorkflowResultSchema = external_exports.discriminatedUnion("status", [
@@ -21472,29 +21479,53 @@ var TriggerEventsSchema = external_exports.array(TriggerEventSchema).min(1).supe
21472
21479
  seen.add(event);
21473
21480
  }
21474
21481
  });
21475
- var TriggerSharedFields = {
21476
- message: external_exports.string().trim().min(1).max(2e4).optional(),
21477
- checks: external_exports.array(
21478
- external_exports.object({
21479
- name: ResourceNameSchema,
21480
- displayName: external_exports.string().trim().min(1).max(256),
21481
- description: external_exports.string().trim().min(1).max(65535),
21482
- instructions: external_exports.string().trim().min(1).max(2e4).optional(),
21483
- timeout: TriggerCheckTimeoutSchema.optional(),
21484
- beginTimeout: TriggerCheckTimeoutSchema.optional(),
21485
- completeTimeout: TriggerCheckTimeoutSchema.optional()
21486
- }).strict().superRefine((check2, context) => {
21487
- if (check2.timeout && check2.beginTimeout) {
21488
- context.addIssue({
21489
- code: external_exports.ZodIssueCode.custom,
21490
- path: ["beginTimeout"],
21491
- message: "Use either timeout or beginTimeout for the creation-to-begin timeout, not both"
21492
- });
21493
- }
21494
- })
21495
- ).optional(),
21496
- routing: TriggerRoutingSchema
21497
- };
21482
+ var PAYLOAD_PREFIXED_TEMPLATE_TOKEN = /\{\{\s*(payload(?:\.[A-Za-z0-9_.-]+)?)\s*\}\}/g;
21483
+ function refineNoPayloadPrefixedTemplateTokens(value2, context) {
21484
+ if (value2 === void 0) {
21485
+ return;
21486
+ }
21487
+ const offending = new Set(
21488
+ [...value2.matchAll(PAYLOAD_PREFIXED_TEMPLATE_TOKEN)].map(
21489
+ (match) => match[0]
21490
+ )
21491
+ );
21492
+ if (offending.size > 0) {
21493
+ context.addIssue({
21494
+ code: external_exports.ZodIssueCode.custom,
21495
+ message: `Template renders against the event payload; drop the "payload." prefix (use "{{github.\u2026}}", not "{{payload.github.\u2026}}"). Offending tokens: ${[...offending].join(", ")}`
21496
+ });
21497
+ }
21498
+ }
21499
+ function templateField(guard) {
21500
+ const field = external_exports.string().trim().min(1).max(2e4).optional();
21501
+ return guard === "authoring" ? field.superRefine(refineNoPayloadPrefixedTemplateTokens) : field;
21502
+ }
21503
+ var TriggerChecksField = external_exports.array(
21504
+ external_exports.object({
21505
+ name: ResourceNameSchema,
21506
+ displayName: external_exports.string().trim().min(1).max(256),
21507
+ description: external_exports.string().trim().min(1).max(65535),
21508
+ instructions: external_exports.string().trim().min(1).max(2e4).optional(),
21509
+ timeout: TriggerCheckTimeoutSchema.optional(),
21510
+ beginTimeout: TriggerCheckTimeoutSchema.optional(),
21511
+ completeTimeout: TriggerCheckTimeoutSchema.optional()
21512
+ }).strict().superRefine((check2, context) => {
21513
+ if (check2.timeout && check2.beginTimeout) {
21514
+ context.addIssue({
21515
+ code: external_exports.ZodIssueCode.custom,
21516
+ path: ["beginTimeout"],
21517
+ message: "Use either timeout or beginTimeout for the creation-to-begin timeout, not both"
21518
+ });
21519
+ }
21520
+ })
21521
+ ).optional();
21522
+ function triggerSharedFields(guard) {
21523
+ return {
21524
+ message: templateField(guard),
21525
+ checks: TriggerChecksField,
21526
+ routing: TriggerRoutingSchema
21527
+ };
21528
+ }
21498
21529
  var TriggerEventSourceFields = {
21499
21530
  connection: ConnectionNameSchema.optional(),
21500
21531
  endpoint: external_exports.string().trim().min(1).optional(),
@@ -21512,67 +21543,79 @@ var TriggerEventSourceFields = {
21512
21543
  })
21513
21544
  ]).optional()
21514
21545
  };
21515
- var TriggerBaseSchema = external_exports.object({
21516
- event: TriggerEventSchema,
21517
- ...TriggerSharedFields,
21518
- ...TriggerEventSourceFields
21519
- }).strict().superRefine((trigger, context) => {
21520
- validateTriggerChecks(trigger, context, [trigger.event]);
21521
- });
21522
- var TriggerDefinitionBaseSchema = external_exports.object({
21523
- event: TriggerEventSchema.optional(),
21524
- events: TriggerEventsSchema.optional(),
21525
- ...TriggerSharedFields,
21526
- ...TriggerEventSourceFields
21527
- }).strict().superRefine((trigger, context) => {
21528
- if (trigger.event && trigger.events) {
21529
- context.addIssue({
21530
- code: external_exports.ZodIssueCode.custom,
21531
- path: ["events"],
21532
- message: "Use either event or events, not both"
21533
- });
21534
- }
21535
- if (!trigger.event && !trigger.events) {
21536
- context.addIssue({
21537
- code: external_exports.ZodIssueCode.custom,
21538
- path: ["event"],
21539
- message: "Trigger requires event or events"
21540
- });
21541
- }
21542
- validateTriggerChecks(
21543
- trigger,
21544
- context,
21545
- trigger.event ? [trigger.event] : trigger.events ?? []
21546
- );
21547
- });
21548
- var TriggerSchema = TriggerBaseSchema.extend({
21546
+ function triggerBaseSchema(guard) {
21547
+ return external_exports.object({
21548
+ event: TriggerEventSchema,
21549
+ ...triggerSharedFields(guard),
21550
+ ...TriggerEventSourceFields
21551
+ }).strict().superRefine((trigger, context) => {
21552
+ validateTriggerChecks(trigger, context, [trigger.event]);
21553
+ });
21554
+ }
21555
+ function triggerDefinitionBaseSchema(guard) {
21556
+ return external_exports.object({
21557
+ event: TriggerEventSchema.optional(),
21558
+ events: TriggerEventsSchema.optional(),
21559
+ ...triggerSharedFields(guard),
21560
+ ...TriggerEventSourceFields
21561
+ }).strict().superRefine((trigger, context) => {
21562
+ if (trigger.event && trigger.events) {
21563
+ context.addIssue({
21564
+ code: external_exports.ZodIssueCode.custom,
21565
+ path: ["events"],
21566
+ message: "Use either event or events, not both"
21567
+ });
21568
+ }
21569
+ if (!trigger.event && !trigger.events) {
21570
+ context.addIssue({
21571
+ code: external_exports.ZodIssueCode.custom,
21572
+ path: ["event"],
21573
+ message: "Trigger requires event or events"
21574
+ });
21575
+ }
21576
+ validateTriggerChecks(
21577
+ trigger,
21578
+ context,
21579
+ trigger.event ? [trigger.event] : trigger.events ?? []
21580
+ );
21581
+ });
21582
+ }
21583
+ function heartbeatTriggerBaseSchema(guard) {
21584
+ return external_exports.object({
21585
+ kind: external_exports.literal("heartbeat"),
21586
+ event: external_exports.never().optional(),
21587
+ connection: external_exports.never().optional(),
21588
+ endpoint: external_exports.never().optional(),
21589
+ auth: external_exports.never().optional(),
21590
+ cron: external_exports.string().trim().min(1).max(512),
21591
+ timezone: external_exports.string().trim().min(1).max(128).default("UTC"),
21592
+ ...triggerSharedFields(guard)
21593
+ }).strict().superRefine((trigger, context) => {
21594
+ validateTriggerChecks(trigger, context, ["heartbeat"]);
21595
+ });
21596
+ }
21597
+ var TriggerSchema = triggerBaseSchema("stored").extend({
21549
21598
  where: external_exports.record(external_exports.string(), JsonValueSchema2).default({})
21550
21599
  });
21551
- var ApplyTriggerSchema = TriggerBaseSchema.extend({
21600
+ var ApplyTriggerSchema = triggerBaseSchema("authoring").extend({
21552
21601
  where: TriggerFilterSchema
21553
21602
  });
21554
- var HeartbeatTriggerBaseSchema = external_exports.object({
21555
- kind: external_exports.literal("heartbeat"),
21556
- event: external_exports.never().optional(),
21557
- connection: external_exports.never().optional(),
21558
- endpoint: external_exports.never().optional(),
21559
- auth: external_exports.never().optional(),
21560
- cron: external_exports.string().trim().min(1).max(512),
21561
- timezone: external_exports.string().trim().min(1).max(128).default("UTC"),
21562
- ...TriggerSharedFields
21563
- }).strict().superRefine((trigger, context) => {
21564
- validateTriggerChecks(trigger, context, ["heartbeat"]);
21565
- });
21566
- var HeartbeatTriggerSchema = HeartbeatTriggerBaseSchema.extend({
21603
+ var HeartbeatTriggerSchema = heartbeatTriggerBaseSchema(
21604
+ "stored"
21605
+ ).extend({
21567
21606
  where: external_exports.record(external_exports.string(), JsonValueSchema2).default({})
21568
21607
  });
21569
- var ApplyHeartbeatTriggerSchema = HeartbeatTriggerBaseSchema.extend({
21608
+ var ApplyHeartbeatTriggerSchema = heartbeatTriggerBaseSchema(
21609
+ "authoring"
21610
+ ).extend({
21570
21611
  where: TriggerFilterSchema
21571
21612
  });
21572
- var TriggerDefinitionSchema = TriggerDefinitionBaseSchema.extend({
21613
+ var TriggerDefinitionSchema = triggerDefinitionBaseSchema("stored").extend({
21573
21614
  where: external_exports.record(external_exports.string(), JsonValueSchema2).default({})
21574
21615
  });
21575
- var ApplyTriggerDefinitionSchema = TriggerDefinitionBaseSchema.extend({
21616
+ var ApplyTriggerDefinitionSchema = triggerDefinitionBaseSchema(
21617
+ "authoring"
21618
+ ).extend({
21576
21619
  where: TriggerFilterSchema
21577
21620
  });
21578
21621
  var TriggersSchema = external_exports.array(external_exports.union([TriggerDefinitionSchema, HeartbeatTriggerSchema])).transform(expandTriggerDefinitions).superRefine(validateAttributedRunsTriggerPairing);
@@ -21631,7 +21674,7 @@ var AgentSpecFieldsSchema = external_exports.object({
21631
21674
  systemPrompt: external_exports.string().trim().min(1).max(1e5).optional(),
21632
21675
  environment: ResourceNameSchema.optional(),
21633
21676
  identity: external_exports.union([ResourceNameSchema, AgentIdentitySchema]).optional(),
21634
- initialPrompt: external_exports.string().trim().min(1).max(2e4).optional(),
21677
+ initialPrompt: templateField("stored"),
21635
21678
  env: SecretEnvSchema.default({}),
21636
21679
  mounts: external_exports.array(AgentMountSchema).default([]),
21637
21680
  triggers: TriggersSchema.default([]),
@@ -21658,6 +21701,7 @@ var AgentSpecSchema = AgentSpecFieldsSchema.superRefine(
21658
21701
  validateRunnableConfig
21659
21702
  );
21660
21703
  var AgentApplySpecSchema = AgentSpecFieldsSchema.extend({
21704
+ initialPrompt: templateField("authoring"),
21661
21705
  triggers: ApplyTriggersSchema.default([])
21662
21706
  }).superRefine(validateRunnableConfig);
21663
21707
  var AgentStatusSchema = external_exports.object({
@@ -22251,6 +22295,11 @@ var ProjectResourceApplyAuditActionSchema = external_exports.enum([
22251
22295
  "github_sync.apply"
22252
22296
  ]);
22253
22297
  var ProjectResourceApplyOperationIdSchema = external_exports.string().trim().min(1).max(512);
22298
+ var ProjectResourceApplyTriggerArtifactSchema = external_exports.object({
22299
+ type: external_exports.string().trim().min(1),
22300
+ externalId: external_exports.string().trim().min(1),
22301
+ payload: JsonValueSchema2.optional()
22302
+ }).strict();
22254
22303
  var ProjectResourceApplyWorkflowErrorSchema = external_exports.object({
22255
22304
  name: external_exports.string().trim().min(1),
22256
22305
  message: external_exports.string().trim().min(1)
@@ -22262,7 +22311,8 @@ var ProjectResourceApplyWorkflowInputSchema = external_exports.object({
22262
22311
  organizationId: OrganizationIdSchema,
22263
22312
  projectId: ProjectIdSchema.nullable().optional(),
22264
22313
  actor: AuthActorSchema,
22265
- auditAction: ProjectResourceApplyAuditActionSchema
22314
+ auditAction: ProjectResourceApplyAuditActionSchema,
22315
+ triggerArtifact: ProjectResourceApplyTriggerArtifactSchema.optional()
22266
22316
  }).superRefine((input, context) => {
22267
22317
  if ((input.request ? 1 : 0) + (input.sourceRequest ? 1 : 0) !== 1) {
22268
22318
  context.addIssue({
@@ -22680,8 +22730,27 @@ var SessionCommandSenderSchema = external_exports.discriminatedUnion("type", [
22680
22730
  type: external_exports.literal("system")
22681
22731
  })
22682
22732
  ]);
22733
+ var MESSAGE_DELIVERY_MODES = ["interrupt", "deferred"];
22734
+ var MessageDeliveryModeSchema = external_exports.enum(MESSAGE_DELIVERY_MODES);
22735
+ var TRIGGER_INJECTION_MODALITIES = [
22736
+ "chat",
22737
+ "githubCheck",
22738
+ "githubCheckAction",
22739
+ "githubPullRequest",
22740
+ "other"
22741
+ ];
22742
+ var TriggerInjectionModalitySchema = external_exports.enum(
22743
+ TRIGGER_INJECTION_MODALITIES
22744
+ );
22683
22745
  var RunMessageCommandPayloadSchema = external_exports.object({
22684
22746
  message: external_exports.string().trim().min(1),
22747
+ // Optional so existing payloads and direct operator/agent messages stay
22748
+ // valid without it; trigger routing sets "deferred" for GitHub check
22749
+ // events. An absent mode is treated as "interrupt" at the delivery
22750
+ // boundary (commandDeliveryPayload / the runtime handler), so the default
22751
+ // lives where the value is consumed rather than as a required field every
22752
+ // call site must construct.
22753
+ deliveryMode: MessageDeliveryModeSchema.optional(),
22685
22754
  metadata: JsonValueSchema2.optional()
22686
22755
  }).strict();
22687
22756
  var RunAnswerCommandPayloadSchema = external_exports.object({
@@ -26571,7 +26640,7 @@ Object.assign(lookup, {
26571
26640
  // package.json
26572
26641
  var package_default = {
26573
26642
  name: "@autohq/cli",
26574
- version: "0.1.187",
26643
+ version: "0.1.196",
26575
26644
  license: "SEE LICENSE IN README.md",
26576
26645
  publishConfig: {
26577
26646
  access: "public"
@@ -46886,6 +46955,7 @@ function withClaudeStderrDiagnosticsPointer(error51, capturedStderr) {
46886
46955
 
46887
46956
  // src/commands/agent-bridge/harness/claude-code/session.ts
46888
46957
  var CLAUDE_AGENT_STARTUP_TIMEOUT_MS = 3e4;
46958
+ var CLAUDE_INTERRUPT_SETTLE_TIMEOUT_MS = 1e4;
46889
46959
  var CLAUDE_STARTUP_PROFILE_HOOK_EVENTS = [
46890
46960
  "Setup",
46891
46961
  "SessionStart",
@@ -46918,6 +46988,21 @@ var ClaudeAgentBridgeSessionImpl = class {
46918
46988
  activeTurnCount = 0;
46919
46989
  interruptInFlight = null;
46920
46990
  exitReported = false;
46991
+ // Messages delivered in "deferred" mode while a turn is in flight. They are
46992
+ // held here instead of injected mid-turn (which would reject a pending
46993
+ // tool_use) and flushed once the turn ends and the session is idle.
46994
+ deferredMessages = [];
46995
+ // tool_use ids the assistant has emitted whose tool_result has not yet been
46996
+ // observed. A non-empty set means a tool call is in flight, so an immediate
46997
+ // interrupt would append the new user message after an unresolved
46998
+ // stop_reason=tool_use — the invalid transcript that trips Claude Code's
46999
+ // ede_diagnostic and auto-restarts the session (FRA-3049).
47000
+ pendingToolUseIds = /* @__PURE__ */ new Set();
47001
+ // Incremented on every turn-terminal `result`. An interrupt that aborts an
47002
+ // in-flight tool call waits for this to advance before injecting, so the
47003
+ // message lands only once the interrupted turn has settled its tool_use.
47004
+ turnResultCount = 0;
47005
+ turnSettlementWaiters = /* @__PURE__ */ new Set();
46921
47006
  constructor(input) {
46922
47007
  const optionsStartedAt = Date.now();
46923
47008
  this.input = input;
@@ -46960,13 +47045,17 @@ var ClaudeAgentBridgeSessionImpl = class {
46960
47045
  throw error51;
46961
47046
  }
46962
47047
  }
46963
- async sendMessage(message) {
47048
+ async sendMessage(message, options) {
47049
+ const mode = options?.mode ?? "interrupt";
47050
+ if (mode === "deferred" && this.hasInterruptibleTurn()) {
47051
+ this.deferredMessages.push(message);
47052
+ this.input.writeOutput?.(
47053
+ `agent_bridge_claude_message_deferred active_turn_count=${this.activeTurnCount}`
47054
+ );
47055
+ return;
47056
+ }
46964
47057
  await this.interruptActiveTurnBeforeMessage();
46965
- this.inputQueue.push(claudeAgentUserMessage(message));
46966
- this.activeTurnCount += 1;
46967
- void this.ensureRunningQuery().catch((error51) => {
46968
- void this.input.onError(error51);
46969
- });
47058
+ this.enqueueUserMessage(message);
46970
47059
  }
46971
47060
  close() {
46972
47061
  const previousState = this.state;
@@ -46975,6 +47064,14 @@ var ClaudeAgentBridgeSessionImpl = class {
46975
47064
  }
46976
47065
  this.state = { kind: "closed" };
46977
47066
  this.activeTurnCount = 0;
47067
+ this.pendingToolUseIds.clear();
47068
+ this.resolveTurnSettlement(false);
47069
+ if (this.deferredMessages.length > 0) {
47070
+ this.input.writeOutput?.(
47071
+ `agent_bridge_claude_deferred_dropped count=${this.deferredMessages.length} reason=session_closed`
47072
+ );
47073
+ this.deferredMessages.length = 0;
47074
+ }
46978
47075
  this.stderr.flush();
46979
47076
  this.inputQueue.close();
46980
47077
  if (previousState.kind === "started") {
@@ -47057,8 +47154,15 @@ var ClaudeAgentBridgeSessionImpl = class {
47057
47154
  void (async () => {
47058
47155
  try {
47059
47156
  for await (const message of query) {
47157
+ this.trackToolUseLifecycle(message);
47060
47158
  if (isClaudeAgentTurnResult(message)) {
47061
47159
  this.activeTurnCount = Math.max(0, this.activeTurnCount - 1);
47160
+ this.pendingToolUseIds.clear();
47161
+ this.turnResultCount += 1;
47162
+ this.resolveTurnSettlement(true);
47163
+ if (this.activeTurnCount === 0) {
47164
+ this.flushDeferredMessages();
47165
+ }
47062
47166
  }
47063
47167
  const failure = probeClaudeAgentMessage(
47064
47168
  message,
@@ -47082,23 +47186,116 @@ var ClaudeAgentBridgeSessionImpl = class {
47082
47186
  }
47083
47187
  } finally {
47084
47188
  this.activeTurnCount = 0;
47189
+ this.pendingToolUseIds.clear();
47190
+ this.resolveTurnSettlement(false);
47085
47191
  this.state = { kind: "closed" };
47086
47192
  this.reportExit();
47087
47193
  }
47088
47194
  })();
47089
47195
  }
47196
+ // Queue a user message as a fresh turn. Pushing before ensureRunningQuery()
47197
+ // lets injection work while the SDK session is still starting; the queue
47198
+ // drains once the query attaches. Startup failures surface through onError
47199
+ // instead of failing injection.
47200
+ enqueueUserMessage(message) {
47201
+ this.inputQueue.push(claudeAgentUserMessage(message));
47202
+ this.activeTurnCount += 1;
47203
+ void this.ensureRunningQuery().catch((error51) => {
47204
+ void this.input.onError(error51);
47205
+ });
47206
+ }
47207
+ // A turn the SDK is actively running, so a new user message would either
47208
+ // interrupt it or land mid-turn. Startup/idle states have nothing to disturb.
47209
+ hasInterruptibleTurn() {
47210
+ return this.activeTurnCount > 0 && this.state.kind === "running";
47211
+ }
47212
+ // True while the assistant has an emitted tool_use with no matching
47213
+ // tool_result yet — the window where an immediate interrupt would strand an
47214
+ // unresolved stop_reason=tool_use ahead of the injected user message.
47215
+ hasInFlightToolUse() {
47216
+ return this.pendingToolUseIds.size > 0;
47217
+ }
47218
+ // Track tool_use/tool_result pairs as they stream so hasInFlightToolUse()
47219
+ // reflects the live transcript. tool_use opens a call; the matching
47220
+ // tool_result closes it; the turn's terminal result clears any remainder.
47221
+ trackToolUseLifecycle(message) {
47222
+ for (const id of toolUseIds(message)) {
47223
+ this.pendingToolUseIds.add(id);
47224
+ }
47225
+ for (const id of toolResultIds(message)) {
47226
+ this.pendingToolUseIds.delete(id);
47227
+ }
47228
+ }
47229
+ // Resolve once the interrupted turn emits its terminal `result` (turnResultCount
47230
+ // advances past the pre-interrupt baseline), bounded so a tool that never
47231
+ // returns after interrupt cannot wedge delivery. On timeout the caller falls
47232
+ // back to immediate injection rather than hanging or dropping the message.
47233
+ awaitTurnSettlement(baseline, startedAt) {
47234
+ if (this.turnResultCount > baseline) {
47235
+ return Promise.resolve();
47236
+ }
47237
+ return new Promise((resolve) => {
47238
+ let done = false;
47239
+ const finish = (outcome) => {
47240
+ if (done) {
47241
+ return;
47242
+ }
47243
+ done = true;
47244
+ clearTimeout(timer);
47245
+ this.turnSettlementWaiters.delete(waiter);
47246
+ this.input.writeOutput?.(
47247
+ `agent_bridge_claude_interrupt_settle_${outcome} duration_ms=${Date.now() - startedAt}`
47248
+ );
47249
+ resolve();
47250
+ };
47251
+ const waiter = (settled) => finish(settled ? "ready" : "aborted");
47252
+ const timer = setTimeout(
47253
+ () => finish("timeout"),
47254
+ CLAUDE_INTERRUPT_SETTLE_TIMEOUT_MS
47255
+ );
47256
+ timer.unref?.();
47257
+ this.turnSettlementWaiters.add(waiter);
47258
+ });
47259
+ }
47260
+ resolveTurnSettlement(settled) {
47261
+ if (this.turnSettlementWaiters.size === 0) {
47262
+ return;
47263
+ }
47264
+ const waiters = [...this.turnSettlementWaiters];
47265
+ this.turnSettlementWaiters.clear();
47266
+ for (const waiter of waiters) {
47267
+ waiter(settled);
47268
+ }
47269
+ }
47270
+ flushDeferredMessages() {
47271
+ if (this.deferredMessages.length === 0) {
47272
+ return;
47273
+ }
47274
+ const pending = this.deferredMessages.splice(0);
47275
+ this.input.writeOutput?.(
47276
+ `agent_bridge_claude_deferred_flush count=${pending.length}`
47277
+ );
47278
+ for (const message of pending) {
47279
+ this.enqueueUserMessage(message);
47280
+ }
47281
+ }
47090
47282
  async interruptActiveTurnBeforeMessage() {
47091
- if (this.activeTurnCount === 0 || this.state.kind !== "running") {
47283
+ if (!this.hasInterruptibleTurn()) {
47092
47284
  return;
47093
47285
  }
47094
47286
  if (this.interruptInFlight) {
47095
47287
  await this.interruptInFlight;
47096
47288
  return;
47097
47289
  }
47290
+ if (this.state.kind !== "running") {
47291
+ return;
47292
+ }
47098
47293
  const query = this.state.query;
47294
+ const hadInFlightToolUse = this.hasInFlightToolUse();
47295
+ const settlementBaseline = this.turnResultCount;
47099
47296
  const startedAt = Date.now();
47100
47297
  this.input.writeOutput?.(
47101
- `agent_bridge_claude_mid_turn_interrupt_started at=${new Date(startedAt).toISOString()}`
47298
+ `agent_bridge_claude_mid_turn_interrupt_started at=${new Date(startedAt).toISOString()} in_flight_tool_use=${hadInFlightToolUse}`
47102
47299
  );
47103
47300
  const interruptPromise = (async () => {
47104
47301
  try {
@@ -47111,6 +47308,9 @@ var ClaudeAgentBridgeSessionImpl = class {
47111
47308
  `agent_bridge_claude_mid_turn_interrupt_failed duration_ms=${Date.now() - startedAt} error=${error51 instanceof Error ? error51.message : String(error51)}`
47112
47309
  );
47113
47310
  }
47311
+ if (hadInFlightToolUse) {
47312
+ await this.awaitTurnSettlement(settlementBaseline, startedAt);
47313
+ }
47114
47314
  })();
47115
47315
  this.interruptInFlight = interruptPromise;
47116
47316
  try {
@@ -47268,6 +47468,30 @@ function claudeAgentUserMessage(message) {
47268
47468
  function isClaudeAgentTurnResult(message) {
47269
47469
  return message.type === "result";
47270
47470
  }
47471
+ function toolUseIds(message) {
47472
+ if (message.type !== "assistant") {
47473
+ return [];
47474
+ }
47475
+ return contentBlocks(message.message.content).flatMap(
47476
+ (block) => block.type === "tool_use" && typeof block.id === "string" ? [block.id] : []
47477
+ );
47478
+ }
47479
+ function toolResultIds(message) {
47480
+ if (message.type !== "user") {
47481
+ return [];
47482
+ }
47483
+ return contentBlocks(message.message.content).flatMap(
47484
+ (block) => block.type === "tool_result" && typeof block.tool_use_id === "string" ? [block.tool_use_id] : []
47485
+ );
47486
+ }
47487
+ function contentBlocks(content) {
47488
+ if (!Array.isArray(content)) {
47489
+ return [];
47490
+ }
47491
+ return content.filter(
47492
+ (block) => typeof block === "object" && block !== null
47493
+ );
47494
+ }
47271
47495
 
47272
47496
  // src/commands/agent-bridge/harness/claude-code/index.ts
47273
47497
  async function runAgentBridgeClaudeCode(options) {
@@ -47371,7 +47595,9 @@ var ClaudeCodeCommandHandler = class {
47371
47595
  }
47372
47596
  }
47373
47597
  });
47374
- await this.ensureAgentSession().sendMessage(message);
47598
+ await this.ensureAgentSession().sendMessage(message, {
47599
+ mode: deliveryMode(delivery)
47600
+ });
47375
47601
  } catch (error51) {
47376
47602
  this.injectedCommands.delete(delivery.commandId);
47377
47603
  return commandAck({
@@ -47617,6 +47843,16 @@ function deliveryMessage(delivery) {
47617
47843
  }
47618
47844
  return null;
47619
47845
  }
47846
+ function deliveryMode(delivery) {
47847
+ const payload = delivery.payload;
47848
+ if (payload && typeof payload === "object" && "deliveryMode" in payload) {
47849
+ const parsed = MessageDeliveryModeSchema.safeParse(payload.deliveryMode);
47850
+ if (parsed.success) {
47851
+ return parsed.data;
47852
+ }
47853
+ }
47854
+ return "interrupt";
47855
+ }
47620
47856
 
47621
47857
  // src/commands/agent-bridge/entrypoint.ts
47622
47858
  async function runAgentBridgeProcess(input) {