@astrosheep/keiyaku 1.0.0 → 1.0.2

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.
Files changed (123) hide show
  1. package/README.md +73 -56
  2. package/build/.tsbuildinfo +1 -1
  3. package/build/agents/call-terms_v2.js +103 -0
  4. package/build/agents/harness/activity-values.js +54 -0
  5. package/build/agents/harness/event-channel.js +55 -20
  6. package/build/agents/harness/events.js +47 -1
  7. package/build/agents/harness/execution-handle.js +292 -61
  8. package/build/agents/harness/index.js +103 -121
  9. package/build/agents/harness/pump.js +36 -47
  10. package/build/agents/harness/runtime.js +3 -0
  11. package/build/agents/launch-snapshot_v2.js +348 -0
  12. package/build/agents/opencode-sdk.js +42 -169
  13. package/build/agents/providers/claude-agent-sdk.js +240 -79
  14. package/build/agents/providers/codex-app-server.js +280 -72
  15. package/build/agents/providers/codex-sdk.js +159 -41
  16. package/build/agents/providers/event-type-tail.js +16 -0
  17. package/build/agents/providers/opencode-sdk.js +165 -59
  18. package/build/agents/providers/pi.js +254 -42
  19. package/build/agents/selector_v2.js +122 -0
  20. package/build/cli/commands/akuma.js +120 -42
  21. package/build/cli/completion.js +6 -7
  22. package/build/cli/flags.js +36 -10
  23. package/build/cli/help.js +42 -26
  24. package/build/cli/index.js +225 -93
  25. package/build/cli/parse.js +194 -75
  26. package/build/cli/projection-address.js +11 -0
  27. package/build/cli/render/address.js +88 -0
  28. package/build/cli/render/arc.js +10 -10
  29. package/build/cli/render/call.js +59 -0
  30. package/build/cli/render/compact-text.js +3 -0
  31. package/build/cli/render/errors.js +4 -2
  32. package/build/cli/render/format.js +6 -0
  33. package/build/cli/render/line-width.js +70 -0
  34. package/build/cli/render/misc.js +7 -4
  35. package/build/cli/render/petition.js +4 -3
  36. package/build/cli/render/projection-activity.js +201 -0
  37. package/build/cli/render/shared.js +46 -12
  38. package/build/cli/render/status.js +59 -10
  39. package/build/cli/render/tool-ledger-rollup.js +74 -0
  40. package/build/cli/render/tool-presentation.js +97 -0
  41. package/build/cli/render/wait.js +229 -0
  42. package/build/cli/skills-install.js +42 -24
  43. package/build/cli/subagent-guard.js +1 -1
  44. package/build/config/akuma-loader_v2.js +222 -0
  45. package/build/config/env-keys.js +0 -4
  46. package/build/config/env.js +0 -6
  47. package/build/config/settings.js +325 -12
  48. package/build/core/addressing.js +224 -0
  49. package/build/core/amend.js +30 -47
  50. package/build/core/arc.js +68 -60
  51. package/build/core/bind.js +105 -25
  52. package/build/core/call-persist.js +69 -0
  53. package/build/core/call.js +658 -0
  54. package/build/core/claim.js +72 -44
  55. package/build/core/command-io.js +19 -19
  56. package/build/core/context.js +11 -36
  57. package/build/core/draft.js +2 -3
  58. package/build/core/entry.js +101 -6
  59. package/build/core/execution-coordinate.js +62 -0
  60. package/build/core/execution-pact.js +141 -0
  61. package/build/core/forfeit.js +2 -3
  62. package/build/core/hints.js +10 -10
  63. package/build/core/ids.js +6 -0
  64. package/build/core/ledger.js +16 -1
  65. package/build/core/petition-claim-gates.js +14 -12
  66. package/build/core/petition-claim.js +1 -0
  67. package/build/core/petition-run.js +6 -2
  68. package/build/core/petition.js +63 -21
  69. package/build/core/places.js +106 -13
  70. package/build/core/projection/generation.js +412 -0
  71. package/build/core/projection/heart.js +316 -0
  72. package/build/core/projection/identity.js +81 -0
  73. package/build/core/projection/leash.js +87 -0
  74. package/build/core/projection/mint.js +154 -0
  75. package/build/core/projection-activity.js +219 -0
  76. package/build/core/projection-coordinate.js +35 -0
  77. package/build/core/projection-core.js +69 -463
  78. package/build/core/projection-generation-continuation.js +31 -0
  79. package/build/core/projection-generation-execution.js +148 -0
  80. package/build/core/projection-generation-identity.js +17 -0
  81. package/build/core/projection-generation-launcher.js +90 -0
  82. package/build/core/projection-generation-process.js +43 -0
  83. package/build/core/projection-generation-runner.js +144 -0
  84. package/build/core/projection-generation-runtime.js +15 -0
  85. package/build/core/projection-generation-store.js +707 -0
  86. package/build/core/projection-identity.js +11 -0
  87. package/build/core/projection-life-observer.js +87 -0
  88. package/build/core/projection-life-protocol.js +95 -0
  89. package/build/core/projection-mint.js +96 -24
  90. package/build/core/projection-runner-lock.js +230 -0
  91. package/build/core/projection-status.js +207 -107
  92. package/build/core/projection-tells.js +401 -0
  93. package/build/core/projection-wait.js +155 -0
  94. package/build/core/projection-wake.js +109 -231
  95. package/build/core/queue_v2.js +342 -0
  96. package/build/core/registry.js +6 -3
  97. package/build/core/render.js +63 -1
  98. package/build/core/renew.js +80 -53
  99. package/build/core/scope.js +186 -137
  100. package/build/core/seal.js +16 -19
  101. package/build/core/status.js +88 -25
  102. package/build/core/stored-agent-event.js +101 -0
  103. package/build/core/transcripts.js +214 -228
  104. package/build/core/verdict.js +27 -15
  105. package/build/core/worktree-bootstrap.js +187 -0
  106. package/build/core/worktree-path.js +72 -18
  107. package/build/flow-error.js +4 -6
  108. package/build/generated/version.js +1 -1
  109. package/build/git/branches.js +6 -1
  110. package/build/index.js +8 -5
  111. package/build/keiyaku.js +1 -3
  112. package/package.json +6 -5
  113. package/skills/keiyaku/SKILL.md +6 -47
  114. package/skills/keiyaku-akuma/SKILL.md +75 -0
  115. package/build/agents/effective-policy.js +0 -32
  116. package/build/agents/index.js +0 -114
  117. package/build/agents/selector.js +0 -28
  118. package/build/cli/render/summon.js +0 -17
  119. package/build/cli/render/tell.js +0 -11
  120. package/build/config/akuma-loader.js +0 -268
  121. package/build/core/queue.js +0 -73
  122. package/build/core/summon-persist.js +0 -73
  123. package/build/core/summon.js +0 -377
@@ -1,9 +1,35 @@
1
1
  import { z } from "zod";
2
2
  import { appendDebugLog } from "../../telemetry/debug-log.js";
3
3
  import { SUBAGENT_SESSION_VERSION } from "../session.js";
4
- import { coerceString } from "../index.js";
5
4
  import { createProjectionDriver } from "../harness/execution-handle.js";
6
- import { buildSubagentEnv, createAbortError, emitProviderEvidence, linkAbortSignal, sha256Utf8 } from "../harness/runtime.js";
5
+ import { activityCallFromNamedTool, boundActivityExcerpt } from "../harness/activity-values.js";
6
+ import { buildSubagentEnv, coerceString, createAbortError, emitProviderEvidence, linkAbortSignal, sha256Utf8 } from "../harness/runtime.js";
7
+ import { AGENT_PLAN_ITEM_TEXT_MAX_CHARS, AGENT_PLAN_MAX_ITEMS, AGENT_THOUGHT_TEXT_MAX_CHARS, } from "../harness/events.js";
8
+ const CLAUDE_MAPPED = new Set(["assistant", "user", "result", "system", "fallback"]);
9
+ const CLAUDE_ACKNOWLEDGED_UNPERSISTED = new Set([
10
+ "stream_event",
11
+ "rate_limit_event",
12
+ "control_cancel_request",
13
+ "control_request",
14
+ "control_response",
15
+ "conversation_reset",
16
+ "keep_alive",
17
+ "local",
18
+ "prompt_suggestion",
19
+ "tool_progress",
20
+ "tool_use_summary",
21
+ "auth_status",
22
+ ]);
23
+ function claudeIngressDisposition(type) {
24
+ if (CLAUDE_MAPPED.has(type))
25
+ return "mapped";
26
+ if (CLAUDE_ACKNOWLEDGED_UNPERSISTED.has(type))
27
+ return "acknowledged-unpersisted";
28
+ return "unknown";
29
+ }
30
+ function toClaudeSdkEffort(effort) {
31
+ return effort; // opacity boundary
32
+ }
7
33
  export const claudeSessionSchema = z.object({ sessionId: z.string().trim().min(1) });
8
34
  const CLAUDE_AGENT_SDK_PROVIDER = "claude-agent-sdk";
9
35
  let claudeAgentSdkLoader;
@@ -31,6 +57,119 @@ function extractAssistantMessage(event) {
31
57
  function extractAssistantMessageModel(event) {
32
58
  return coerceString(event.message.model);
33
59
  }
60
+ function claudeActivityCall(name, input) {
61
+ if (!isRecord(input))
62
+ return { kind: "other", display: name };
63
+ return activityCallFromNamedTool(name, {
64
+ ...(typeof input.command === "string" ? { command: input.command } : {}),
65
+ ...(typeof input.description === "string" ? { description: input.description } : {}),
66
+ ...(typeof input.file_path === "string" ? { path: input.file_path } : {}),
67
+ ...(typeof input.offset === "number" && Number.isFinite(input.offset) ? { offset: input.offset } : {}),
68
+ ...(typeof input.limit === "number" && Number.isFinite(input.limit) ? { limit: input.limit } : {}),
69
+ ...(typeof input.query === "string" ? { query: input.query } : {}),
70
+ });
71
+ }
72
+ function claudeResultMessage(content) {
73
+ if (typeof content === "string")
74
+ return content ? boundActivityExcerpt(content) : undefined;
75
+ if (!Array.isArray(content))
76
+ return undefined;
77
+ const text = content.flatMap((entry) => {
78
+ if (!isRecord(entry) || entry.type !== "text" || typeof entry.text !== "string")
79
+ return [];
80
+ return [entry.text];
81
+ }).join("\n");
82
+ return text ? boundActivityExcerpt(text) : undefined;
83
+ }
84
+ function emitClaudeToolStarts(builder, event, seenToolUses) {
85
+ if (!Array.isArray(event.message.content))
86
+ return;
87
+ for (const block of event.message.content) {
88
+ if (!isRecord(block) || block.type !== "tool_use")
89
+ continue;
90
+ const id = coerceString(block.id);
91
+ const name = coerceString(block.name);
92
+ if (!id || !name)
93
+ continue;
94
+ const call = claudeActivityCall(name, block.input);
95
+ seenToolUses.set(id, { tool: name, call });
96
+ builder.emit({
97
+ type: "activity",
98
+ phase: "started",
99
+ id,
100
+ tool: name,
101
+ call,
102
+ });
103
+ if (name === "TodoWrite" && isRecord(block.input) && Array.isArray(block.input.todos)) {
104
+ const items = block.input.todos.slice(0, AGENT_PLAN_MAX_ITEMS).flatMap((todo) => {
105
+ if (!isRecord(todo) || typeof todo.content !== "string" || typeof todo.status !== "string") {
106
+ return [];
107
+ }
108
+ return [{
109
+ text: todo.content.slice(0, AGENT_PLAN_ITEM_TEXT_MAX_CHARS),
110
+ done: todo.status === "completed",
111
+ ...(todo.status === "in_progress" ? { active: true } : {}),
112
+ }];
113
+ });
114
+ builder.emit({ type: "plan", id, items });
115
+ }
116
+ }
117
+ }
118
+ function emitClaudeThoughts(builder, event) {
119
+ if (!Array.isArray(event.message.content))
120
+ return;
121
+ event.message.content.forEach((block, blockIndex) => {
122
+ if (!isRecord(block) || block.type !== "thinking" || typeof block.thinking !== "string")
123
+ return;
124
+ const truncated = block.thinking.length > AGENT_THOUGHT_TEXT_MAX_CHARS;
125
+ builder.emit({
126
+ type: "thought",
127
+ id: `${event.uuid}:${blockIndex}`,
128
+ text: block.thinking.slice(0, AGENT_THOUGHT_TEXT_MAX_CHARS),
129
+ final: true,
130
+ ...(truncated ? { truncated: true } : {}),
131
+ });
132
+ });
133
+ }
134
+ function emitClaudeToolResults(builder, event, seenToolUses) {
135
+ const content = event.message.content;
136
+ if (!Array.isArray(content))
137
+ return;
138
+ for (const block of content) {
139
+ if (!isRecord(block) || block.type !== "tool_result")
140
+ continue;
141
+ const id = coerceString(block.tool_use_id);
142
+ if (!id)
143
+ continue;
144
+ const observed = seenToolUses.get(id);
145
+ if (!observed)
146
+ continue;
147
+ seenToolUses.delete(id);
148
+ const message = claudeResultMessage(block.content);
149
+ builder.emit({
150
+ type: "activity",
151
+ phase: "completed",
152
+ id,
153
+ tool: observed.tool,
154
+ call: observed.call,
155
+ result: {
156
+ status: block.is_error === true ? "error" : "ok",
157
+ ...(message ? { message } : {}),
158
+ },
159
+ });
160
+ }
161
+ }
162
+ function emitClaudeUsage(builder, event, model) {
163
+ const usage = event.usage;
164
+ builder.emit({
165
+ type: "usage",
166
+ inputTokens: usage.input_tokens,
167
+ outputTokens: usage.output_tokens,
168
+ cachedInputTokens: usage.cache_read_input_tokens,
169
+ ...(typeof event.total_cost_usd === "number" ? { costUsd: event.total_cost_usd } : {}),
170
+ ...(model ? { model } : {}),
171
+ });
172
+ }
34
173
  function isRecord(value) {
35
174
  return typeof value === "object" && value !== null;
36
175
  }
@@ -253,6 +392,7 @@ export async function startClaudeAgentSdk(prompt, cwd, options) {
253
392
  let completedResultOrdinal = 0;
254
393
  let openSteerCount = 0;
255
394
  let sawSuccessfulResult = false;
395
+ let emitTurnStarted;
256
396
  const activeWaiters = new Set();
257
397
  const notifyActive = () => {
258
398
  for (const resolve of [...activeWaiters]) {
@@ -305,7 +445,7 @@ export async function startClaudeAgentSdk(prompt, cwd, options) {
305
445
  throw new Error(`${CLAUDE_AGENT_SDK_PROVIDER} cannot enqueue: query ended before yield`);
306
446
  }
307
447
  if (message.effort) {
308
- await liveQuery.applyFlagSettings({ effortLevel: message.effort === "max" ? "xhigh" : message.effort });
448
+ await liveQuery.applyFlagSettings({ effortLevel: toClaudeSdkEffort(message.effort) });
309
449
  }
310
450
  // The pump calls enqueue at a successful result checkpoint. Push now;
311
451
  // waiting for another result before pushing would deadlock the next turn.
@@ -313,6 +453,7 @@ export async function startClaudeAgentSdk(prompt, cwd, options) {
313
453
  const submitted = inputStream.push(toUserMessage(message.text));
314
454
  // submitted = NEXT source next() after this tell is yielded (not the yield pull itself).
315
455
  await submitted.waitSubmitted();
456
+ emitTurnStarted?.();
316
457
  // 落账:记录提交时越过的 result ordinal(generation fence 落点)。
317
458
  const submittedAfterResultOrdinal = completedResultOrdinal;
318
459
  if (options.onEvidence)
@@ -326,7 +467,9 @@ export async function startClaudeAgentSdk(prompt, cwd, options) {
326
467
  };
327
468
  return createProjectionDriver({
328
469
  steerMode: "mid-execution",
470
+ initialTurn: options.initialTurn,
329
471
  enqueue,
472
+ onIngress: options.onIngress,
330
473
  async abort() {
331
474
  queryEnded = true;
332
475
  queryActive = false;
@@ -343,6 +486,7 @@ export async function startClaudeAgentSdk(prompt, cwd, options) {
343
486
  },
344
487
  async run(builder) {
345
488
  builderDiagnostic = (text) => builder.emit({ type: "diagnostic", text });
489
+ emitTurnStarted = () => builder.emit({ type: "turn", phase: "started" });
346
490
  while (pendingEvidenceDiagnostics > 0) {
347
491
  pendingEvidenceDiagnostics -= 1;
348
492
  builderDiagnostic("provider evidence callback failed");
@@ -366,12 +510,10 @@ export async function startClaudeAgentSdk(prompt, cwd, options) {
366
510
  emitProviderEvidence(options.onEvidence, { type: "outbound", provider: CLAUDE_AGENT_SDK_PROVIDER, direction: "input", kind: "steer", ...sha256Utf8(text) }, (text) => builder.emit({ type: "diagnostic", text }));
367
511
  });
368
512
  inputStream.push(initialMessage);
513
+ builder.emit({ type: "turn", phase: "started" });
369
514
  const queryOptions = {
370
515
  cwd,
371
516
  model: options.model,
372
- permissionMode: options.permissionMode,
373
- allowDangerouslySkipPermissions: options.permissionMode === "bypassPermissions",
374
- settingSources: [...options.settingSources],
375
517
  resume: sessionId,
376
518
  env: buildSubagentEnv(),
377
519
  abortController: queryAbortController,
@@ -381,10 +523,22 @@ export async function startClaudeAgentSdk(prompt, cwd, options) {
381
523
  builder.emit({ type: "diagnostic", text: data });
382
524
  },
383
525
  };
526
+ if (options.permissionMode !== undefined) {
527
+ queryOptions.permissionMode = options.permissionMode;
528
+ if (options.permissionMode === "bypassPermissions") {
529
+ queryOptions.allowDangerouslySkipPermissions = true;
530
+ }
531
+ }
532
+ if (options.settingSources !== undefined) {
533
+ queryOptions.settingSources = [...options.settingSources];
534
+ }
535
+ if (options.disallowedTools !== undefined) {
536
+ queryOptions.disallowedTools = [...options.disallowedTools];
537
+ }
384
538
  const execPathKey = `pathToClaudeCode${"Ex"}ecutable`;
385
539
  queryOptions[execPathKey] = options.executable;
386
540
  if (options.effort !== undefined) {
387
- queryOptions.effort = options.effort;
541
+ queryOptions.effort = toClaudeSdkEffort(options.effort);
388
542
  }
389
543
  // Long-lived push-AsyncIterable: one stream for the whole Query lifetime (Tier 1).
390
544
  // Never mount short per-tell streams (that would endInput and break stdin).
@@ -400,87 +554,94 @@ export async function startClaudeAgentSdk(prompt, cwd, options) {
400
554
  let resumedSessionId = sessionId;
401
555
  let finalMessage;
402
556
  let latestAssistantMessageModel;
557
+ const seenToolUses = new Map();
403
558
  for await (const event of query) {
404
- builder.emit({ type: "output", value: event });
405
- resumedSessionId = extractResumeToken(event) ?? resumedSessionId;
406
- const overloadWarning = extractOverloadFallbackWarning(event);
407
- if (overloadWarning) {
408
- builder.emit({ type: "warning", warning: overloadWarning });
409
- }
410
- if (isClaudeModelRefusalFallbackEvent(event)) {
411
- builder.emit({
412
- type: "warning",
413
- warning: {
414
- reason: "refusal",
415
- originalModel: event.original_model,
416
- fallbackModel: event.fallback_model,
417
- direction: event.direction,
418
- requestId: event.request_id,
419
- ...(latestAssistantMessageModel ? { signerModel: latestAssistantMessageModel } : {}),
420
- },
421
- });
422
- }
423
- else if (isClaudeModelRefusalNoFallbackEvent(event)) {
424
- builder.emit({
425
- type: "warning",
426
- warning: {
427
- reason: "refusal",
428
- originalModel: event.original_model,
429
- requestId: event.request_id,
430
- ...(latestAssistantMessageModel ? { signerModel: latestAssistantMessageModel } : {}),
431
- },
432
- });
433
- }
434
- switch (event.type) {
435
- case "assistant": {
436
- latestAssistantMessageModel = extractAssistantMessageModel(event) ?? latestAssistantMessageModel;
437
- finalMessage = extractAssistantMessage(event) ?? finalMessage;
438
- if (finalMessage) {
439
- builder.emit({ type: "message", text: finalMessage });
440
- }
441
- break;
559
+ builder.ingress(CLAUDE_AGENT_SDK_PROVIDER, event.type, event, claudeIngressDisposition(event.type), () => {
560
+ resumedSessionId = extractResumeToken(event) ?? resumedSessionId;
561
+ const overloadWarning = extractOverloadFallbackWarning(event);
562
+ if (overloadWarning) {
563
+ builder.emit({ type: "warning", warning: overloadWarning });
442
564
  }
443
- case "result": {
444
- const resultText = extractResultText(event);
445
- if (event.subtype === "success") {
446
- finalMessage = resultText ?? finalMessage;
565
+ if (isClaudeModelRefusalFallbackEvent(event)) {
566
+ builder.emit({
567
+ type: "warning",
568
+ warning: {
569
+ reason: "refusal",
570
+ originalModel: event.original_model,
571
+ fallbackModel: event.fallback_model,
572
+ direction: event.direction,
573
+ requestId: event.request_id,
574
+ ...(latestAssistantMessageModel ? { signerModel: latestAssistantMessageModel } : {}),
575
+ },
576
+ });
577
+ }
578
+ else if (isClaudeModelRefusalNoFallbackEvent(event)) {
579
+ builder.emit({
580
+ type: "warning",
581
+ warning: {
582
+ reason: "refusal",
583
+ originalModel: event.original_model,
584
+ requestId: event.request_id,
585
+ ...(latestAssistantMessageModel ? { signerModel: latestAssistantMessageModel } : {}),
586
+ },
587
+ });
588
+ }
589
+ switch (event.type) {
590
+ case "assistant": {
591
+ latestAssistantMessageModel = extractAssistantMessageModel(event) ?? latestAssistantMessageModel;
592
+ emitClaudeThoughts(builder, event);
593
+ emitClaudeToolStarts(builder, event, seenToolUses);
594
+ finalMessage = extractAssistantMessage(event) ?? finalMessage;
447
595
  if (finalMessage) {
448
596
  builder.emit({ type: "message", text: finalMessage });
449
597
  }
450
- sawSuccessfulResult = true;
451
- // Advance generation fence BEFORE maybe-ending the stream so gated tells can yield.
452
- bumpResultOrdinal();
453
- const checkpoint = {
454
- fence: { kind: "ordinal", ordinal: completedResultOrdinal },
455
- };
456
- // Record the native result before the synchronous pump can
457
- // consume any tell fenced to an earlier result.
458
- if (options.onEvidence) {
459
- emitProviderEvidence(options.onEvidence, {
460
- type: "checkpoint",
461
- provider: CLAUDE_AGENT_SDK_PROVIDER,
462
- ...checkpoint,
463
- source: "response",
464
- }, (text) => builder.emit({ type: "diagnostic", text }));
465
- }
466
- // Sync checkpoint: claim inbox tells and deliver them via steer control.
467
- options.onSyncCheckpoint?.({ enqueue }, checkpoint);
468
- // Defer end so concurrent enqueue after this result can register openSteerCount.
469
- queueMicrotask(() => maybeEndInputStream());
470
598
  break;
471
599
  }
472
- bumpResultOrdinal();
473
- if (resultText) {
474
- builder.emit({ type: "diagnostic", text: resultText });
600
+ case "user": {
601
+ emitClaudeToolResults(builder, event, seenToolUses);
602
+ break;
475
603
  }
476
- const message = resultText ?? `${CLAUDE_AGENT_SDK_PROVIDER} exec failed`;
477
- builder.emit({ type: "fail", message });
478
- inputStream.end();
479
- throw new Error(message);
604
+ case "result": {
605
+ const resultText = extractResultText(event);
606
+ if (event.subtype === "success") {
607
+ finalMessage = resultText ?? finalMessage;
608
+ emitClaudeUsage(builder, event, latestAssistantMessageModel);
609
+ builder.emit({ type: "turn", phase: "completed" });
610
+ sawSuccessfulResult = true;
611
+ // Advance generation fence BEFORE maybe-ending the stream so gated tells can yield.
612
+ bumpResultOrdinal();
613
+ const checkpoint = {
614
+ fence: { kind: "ordinal", ordinal: completedResultOrdinal },
615
+ };
616
+ // Record the native result before the synchronous pump can
617
+ // consume any tell fenced to an earlier result.
618
+ if (options.onEvidence) {
619
+ emitProviderEvidence(options.onEvidence, {
620
+ type: "checkpoint",
621
+ provider: CLAUDE_AGENT_SDK_PROVIDER,
622
+ ...checkpoint,
623
+ source: "response",
624
+ }, (text) => builder.emit({ type: "diagnostic", text }));
625
+ }
626
+ // Sync checkpoint: claim inbox tells and deliver them via steer control.
627
+ options.onSyncCheckpoint?.({ enqueue }, checkpoint);
628
+ // Defer end so concurrent enqueue after this result can register openSteerCount.
629
+ queueMicrotask(() => maybeEndInputStream());
630
+ break;
631
+ }
632
+ bumpResultOrdinal();
633
+ if (resultText) {
634
+ builder.emit({ type: "diagnostic", text: resultText });
635
+ }
636
+ const message = resultText ?? `${CLAUDE_AGENT_SDK_PROVIDER} exec failed`;
637
+ builder.emit({ type: "fail", message });
638
+ inputStream?.end();
639
+ throw new Error(message);
640
+ }
641
+ default:
642
+ break;
480
643
  }
481
- default:
482
- break;
483
- }
644
+ });
484
645
  }
485
646
  if (queryAbortController.signal.aborted) {
486
647
  throw createAbortError(`${CLAUDE_AGENT_SDK_PROVIDER} exec cancelled by client`);