@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.
- package/dist/agent-bridge.js +324 -88
- package/dist/index.js +572 -194
- package/package.json +1 -1
package/dist/agent-bridge.js
CHANGED
|
@@ -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
|
|
21476
|
-
|
|
21477
|
-
|
|
21478
|
-
|
|
21479
|
-
|
|
21480
|
-
|
|
21481
|
-
|
|
21482
|
-
|
|
21483
|
-
|
|
21484
|
-
|
|
21485
|
-
|
|
21486
|
-
|
|
21487
|
-
|
|
21488
|
-
|
|
21489
|
-
|
|
21490
|
-
|
|
21491
|
-
|
|
21492
|
-
|
|
21493
|
-
|
|
21494
|
-
|
|
21495
|
-
|
|
21496
|
-
|
|
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
|
-
|
|
21516
|
-
|
|
21517
|
-
|
|
21518
|
-
|
|
21519
|
-
|
|
21520
|
-
|
|
21521
|
-
|
|
21522
|
-
|
|
21523
|
-
|
|
21524
|
-
|
|
21525
|
-
|
|
21526
|
-
|
|
21527
|
-
|
|
21528
|
-
|
|
21529
|
-
|
|
21530
|
-
|
|
21531
|
-
|
|
21532
|
-
|
|
21533
|
-
|
|
21534
|
-
|
|
21535
|
-
|
|
21536
|
-
|
|
21537
|
-
|
|
21538
|
-
|
|
21539
|
-
|
|
21540
|
-
|
|
21541
|
-
|
|
21542
|
-
|
|
21543
|
-
|
|
21544
|
-
|
|
21545
|
-
|
|
21546
|
-
|
|
21547
|
-
|
|
21548
|
-
|
|
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 =
|
|
21600
|
+
var ApplyTriggerSchema = triggerBaseSchema("authoring").extend({
|
|
21552
21601
|
where: TriggerFilterSchema
|
|
21553
21602
|
});
|
|
21554
|
-
var
|
|
21555
|
-
|
|
21556
|
-
|
|
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 =
|
|
21608
|
+
var ApplyHeartbeatTriggerSchema = heartbeatTriggerBaseSchema(
|
|
21609
|
+
"authoring"
|
|
21610
|
+
).extend({
|
|
21570
21611
|
where: TriggerFilterSchema
|
|
21571
21612
|
});
|
|
21572
|
-
var TriggerDefinitionSchema =
|
|
21613
|
+
var TriggerDefinitionSchema = triggerDefinitionBaseSchema("stored").extend({
|
|
21573
21614
|
where: external_exports.record(external_exports.string(), JsonValueSchema2).default({})
|
|
21574
21615
|
});
|
|
21575
|
-
var ApplyTriggerDefinitionSchema =
|
|
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:
|
|
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.
|
|
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.
|
|
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.
|
|
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) {
|