@selesai/code 0.3.0 → 0.3.1

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 (230) hide show
  1. package/dist/core/diagnostics.d.ts +1 -0
  2. package/dist/core/diagnostics.d.ts.map +1 -1
  3. package/dist/core/diagnostics.js.map +1 -1
  4. package/dist/core/package-manager.d.ts +10 -0
  5. package/dist/core/package-manager.d.ts.map +1 -1
  6. package/dist/core/package-manager.js +93 -8
  7. package/dist/core/package-manager.js.map +1 -1
  8. package/dist/core/package-manager.test.d.ts +2 -0
  9. package/dist/core/package-manager.test.d.ts.map +1 -0
  10. package/dist/core/package-manager.test.js +20 -0
  11. package/dist/core/package-manager.test.js.map +1 -0
  12. package/dist/core/resource-loader.d.ts +3 -0
  13. package/dist/core/resource-loader.d.ts.map +1 -1
  14. package/dist/core/resource-loader.js +10 -0
  15. package/dist/core/resource-loader.js.map +1 -1
  16. package/dist/core/settings-manager.d.ts +1 -0
  17. package/dist/core/settings-manager.d.ts.map +1 -1
  18. package/dist/core/settings-manager.js.map +1 -1
  19. package/dist/extensions/caveman/caveman-instructions.cjs +39 -0
  20. package/dist/extensions/caveman/index.js +116 -0
  21. package/dist/extensions/caveman/package.json +8 -0
  22. package/dist/extensions/caveman/test/extension.test.js +185 -0
  23. package/dist/extensions/caveman/test/helpers.test.js +67 -0
  24. package/dist/extensions/pi-intercom/broker/broker.ts +2 -3
  25. package/dist/extensions/pi-intercom/broker/paths.ts +10 -5
  26. package/dist/extensions/pi-intercom/broker/spawn.ts +2 -3
  27. package/dist/extensions/pi-intercom/config.ts +2 -2
  28. package/dist/extensions/pi-intercom/index.ts +2 -2
  29. package/dist/extensions/pi-intercom/package.json +2 -2
  30. package/dist/extensions/pi-intercom/ui/compose.ts +3 -3
  31. package/dist/extensions/pi-intercom/ui/inline-message.ts +3 -3
  32. package/dist/extensions/pi-intercom/ui/session-list.ts +3 -3
  33. package/dist/extensions/pi-powerline-footer/bash-mode/history.ts +2 -1
  34. package/dist/extensions/pi-powerline-footer/index.ts +9 -16
  35. package/dist/extensions/pi-powerline-footer/welcome.ts +23 -16
  36. package/dist/extensions/pi-powerline-footer/working-vibes.ts +2 -9
  37. package/dist/extensions/pi-rewind-hook/index.ts +1 -1
  38. package/dist/extensions/pi-rewind-hook/package.json +1 -1
  39. package/dist/extensions/pi-subagents/README.md +224 -52
  40. package/dist/extensions/pi-subagents/install.mjs +93 -0
  41. package/dist/extensions/pi-subagents/package.json +4 -5
  42. package/dist/extensions/pi-subagents/prompts/parallel-context-build.md +1 -1
  43. package/dist/extensions/pi-subagents/prompts/parallel-handoff-plan.md +1 -1
  44. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +76 -13
  45. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +179 -2
  46. package/dist/extensions/pi-subagents/src/agents/agent-memory.ts +254 -0
  47. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +11 -0
  48. package/dist/extensions/pi-subagents/src/agents/agents.ts +193 -19
  49. package/dist/extensions/pi-subagents/src/agents/chain-serializer.ts +27 -2
  50. package/dist/extensions/pi-subagents/src/extension/config.ts +27 -4
  51. package/dist/extensions/pi-subagents/src/extension/doctor.ts +1 -7
  52. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +3 -2
  53. package/dist/extensions/pi-subagents/src/extension/index.ts +73 -71
  54. package/dist/extensions/pi-subagents/src/extension/rpc.ts +369 -0
  55. package/dist/extensions/pi-subagents/src/extension/schemas.ts +54 -10
  56. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +200 -0
  57. package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +21 -253
  58. package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +519 -0
  59. package/dist/extensions/pi-subagents/src/profiles/profiles.ts +1 -1
  60. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +195 -105
  61. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +88 -2
  62. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +67 -10
  63. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +34 -4
  64. package/dist/extensions/pi-subagents/src/runs/background/completion-batcher.ts +166 -0
  65. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +156 -1
  66. package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +515 -0
  67. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +161 -44
  68. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +1 -2
  69. package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +3 -2
  70. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +167 -6
  71. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +514 -0
  72. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +28 -1
  73. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +873 -204
  74. package/dist/extensions/pi-subagents/src/runs/background/wait.ts +353 -0
  75. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +123 -27
  76. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +174 -70
  77. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +569 -81
  78. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +45 -22
  79. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +3 -1
  80. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +2 -2
  81. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +172 -21
  82. package/dist/extensions/pi-subagents/src/runs/shared/model-scope.ts +128 -0
  83. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +89 -0
  84. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +50 -1
  85. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +35 -4
  86. package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +63 -45
  87. package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +2 -0
  88. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +125 -5
  89. package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +74 -0
  90. package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +52 -0
  91. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +28 -5
  92. package/dist/extensions/pi-subagents/src/shared/artifacts.ts +16 -1
  93. package/dist/extensions/pi-subagents/src/shared/atomic-json.ts +15 -2
  94. package/dist/extensions/pi-subagents/src/shared/child-transcript.ts +212 -0
  95. package/dist/extensions/pi-subagents/src/shared/fork-context.ts +133 -22
  96. package/dist/extensions/pi-subagents/src/shared/settings.ts +3 -1
  97. package/dist/extensions/pi-subagents/src/shared/types.ts +197 -4
  98. package/dist/extensions/pi-subagents/src/shared/utils.ts +100 -15
  99. package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +330 -0
  100. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +135 -4
  101. package/dist/extensions/pi-subagents/src/tui/render.ts +32 -12
  102. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +94 -0
  103. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +2772 -0
  104. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +1107 -0
  105. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +463 -0
  106. package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +274 -0
  107. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +1535 -0
  108. package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +242 -0
  109. package/dist/extensions/pi-subagents/test/integration/doctor-executor.test.ts +128 -0
  110. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +252 -0
  111. package/dist/extensions/pi-subagents/test/integration/foreground-result-size.test.ts +188 -0
  112. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +1306 -0
  113. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +1033 -0
  114. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +397 -0
  115. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +583 -0
  116. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +691 -0
  117. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +892 -0
  118. package/dist/extensions/pi-subagents/test/integration/session-tokens.test.ts +62 -0
  119. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1824 -0
  120. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +1284 -0
  121. package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +127 -0
  122. package/dist/extensions/pi-subagents/test/integration/template-resolution.test.ts +299 -0
  123. package/dist/extensions/pi-subagents/test/integration/top-level-async.test.ts +37 -0
  124. package/dist/extensions/pi-subagents/test/support/helpers.ts +189 -0
  125. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +335 -0
  126. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +129 -0
  127. package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +184 -0
  128. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +285 -0
  129. package/dist/extensions/pi-subagents/test/support/register-loader.mjs +15 -0
  130. package/dist/extensions/pi-subagents/test/support/ts-loader.mjs +108 -0
  131. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +421 -0
  132. package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +213 -0
  133. package/dist/extensions/pi-subagents/test/unit/agent-eject-disable.test.ts +343 -0
  134. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +1199 -0
  135. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +556 -0
  136. package/dist/extensions/pi-subagents/test/unit/agent-memory.test.ts +420 -0
  137. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +579 -0
  138. package/dist/extensions/pi-subagents/test/unit/agent-scope.test.ts +20 -0
  139. package/dist/extensions/pi-subagents/test/unit/agent-selection.test.ts +88 -0
  140. package/dist/extensions/pi-subagents/test/unit/artifacts.test.ts +24 -0
  141. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +86 -0
  142. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +221 -0
  143. package/dist/extensions/pi-subagents/test/unit/async-permission-session.test.ts +98 -0
  144. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +285 -0
  145. package/dist/extensions/pi-subagents/test/unit/atomic-json.test.ts +112 -0
  146. package/dist/extensions/pi-subagents/test/unit/chain-append.test.ts +206 -0
  147. package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +159 -0
  148. package/dist/extensions/pi-subagents/test/unit/chain-serializer.test.ts +229 -0
  149. package/dist/extensions/pi-subagents/test/unit/child-transcript.test.ts +225 -0
  150. package/dist/extensions/pi-subagents/test/unit/close-grace-timer.test.ts +101 -0
  151. package/dist/extensions/pi-subagents/test/unit/completion-batcher.test.ts +228 -0
  152. package/dist/extensions/pi-subagents/test/unit/completion-dedupe.test.ts +36 -0
  153. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +152 -0
  154. package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +72 -0
  155. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +327 -0
  156. package/dist/extensions/pi-subagents/test/unit/control-notices.test.ts +161 -0
  157. package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +159 -0
  158. package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +217 -0
  159. package/dist/extensions/pi-subagents/test/unit/extra-agent-dirs.test.ts +88 -0
  160. package/dist/extensions/pi-subagents/test/unit/file-coalescer.test.ts +68 -0
  161. package/dist/extensions/pi-subagents/test/unit/foreground-tool-call-compaction.test.ts +78 -0
  162. package/dist/extensions/pi-subagents/test/unit/fork-context.test.ts +415 -0
  163. package/dist/extensions/pi-subagents/test/unit/get-final-output.test.ts +126 -0
  164. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +271 -0
  165. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +173 -0
  166. package/dist/extensions/pi-subagents/test/unit/jsonl-writer.test.ts +119 -0
  167. package/dist/extensions/pi-subagents/test/unit/live-async-resume.test.ts +170 -0
  168. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +346 -0
  169. package/dist/extensions/pi-subagents/test/unit/model-info.test.ts +62 -0
  170. package/dist/extensions/pi-subagents/test/unit/model-scope-settings.test.ts +87 -0
  171. package/dist/extensions/pi-subagents/test/unit/model-scope.test.ts +145 -0
  172. package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +162 -0
  173. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +470 -0
  174. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +329 -0
  175. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +319 -0
  176. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +70 -0
  177. package/dist/extensions/pi-subagents/test/unit/parallel-utils.test.ts +247 -0
  178. package/dist/extensions/pi-subagents/test/unit/path-handling.test.ts +113 -0
  179. package/dist/extensions/pi-subagents/test/unit/path-resolution.test.ts +94 -0
  180. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +803 -0
  181. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +209 -0
  182. package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +238 -0
  183. package/dist/extensions/pi-subagents/test/unit/proactive-skills.test.ts +118 -0
  184. package/dist/extensions/pi-subagents/test/unit/profiles.test.ts +299 -0
  185. package/dist/extensions/pi-subagents/test/unit/prompt-template-bridge.test.ts +408 -0
  186. package/dist/extensions/pi-subagents/test/unit/prompt-workflows.test.ts +134 -0
  187. package/dist/extensions/pi-subagents/test/unit/recursion-guard.test.ts +257 -0
  188. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +209 -0
  189. package/dist/extensions/pi-subagents/test/unit/result-intercom.test.ts +226 -0
  190. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +294 -0
  191. package/dist/extensions/pi-subagents/test/unit/run-id-resolver.test.ts +147 -0
  192. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +997 -0
  193. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +478 -0
  194. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +562 -0
  195. package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +213 -0
  196. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +438 -0
  197. package/dist/extensions/pi-subagents/test/unit/slash-bridge.test.ts +54 -0
  198. package/dist/extensions/pi-subagents/test/unit/slash-chain-groups.test.ts +464 -0
  199. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +255 -0
  200. package/dist/extensions/pi-subagents/test/unit/status-format.test.ts +19 -0
  201. package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +245 -0
  202. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +517 -0
  203. package/dist/extensions/pi-subagents/test/unit/temp-paths.test.ts +72 -0
  204. package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +52 -0
  205. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +237 -0
  206. package/dist/extensions/pi-subagents/test/unit/total-cost.test.ts +60 -0
  207. package/dist/extensions/pi-subagents/test/unit/ts-loader.test.ts +33 -0
  208. package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +202 -0
  209. package/dist/extensions/pi-subagents/test/unit/types-fork-preamble.test.ts +23 -0
  210. package/dist/extensions/pi-subagents/test/unit/wait.test.ts +398 -0
  211. package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +88 -0
  212. package/dist/extensions/pi-subagents/test/unit/windows-hide-spawn.test.ts +26 -0
  213. package/dist/extensions/pi-subagents/test/unit/workflow-graph.test.ts +134 -0
  214. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +479 -0
  215. package/dist/extensions/pi-web-agent/src/changelog-notice.ts +5 -2
  216. package/dist/extensions/pi-web-agent/src/presentation/config-store.ts +6 -4
  217. package/dist/main.d.ts.map +1 -1
  218. package/dist/main.js +4 -0
  219. package/dist/main.js.map +1 -1
  220. package/dist/modes/interactive/components/first-time-setup.d.ts +1 -1
  221. package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
  222. package/dist/modes/interactive/components/first-time-setup.js +19 -5
  223. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  224. package/dist/skills/caveman/SKILL.md +49 -0
  225. package/dist/skills/handoff-text/SKILL.md +13 -0
  226. package/docs/docs.json +4 -0
  227. package/docs/extensions.md +2 -0
  228. package/docs/settings.md +15 -0
  229. package/docs/shared-host-extensions.md +109 -0
  230. package/package.json +1 -1
@@ -12,6 +12,7 @@ import {
12
12
  writeArtifact,
13
13
  writeMetadata,
14
14
  } from "../../shared/artifacts.ts";
15
+ import { createChildTranscriptWriter, type ChildTranscriptWriter } from "../../shared/child-transcript.ts";
15
16
  import {
16
17
  type AgentProgress,
17
18
  type ArtifactPaths,
@@ -43,12 +44,12 @@ import {
43
44
  extractTextFromContent,
44
45
  } from "../../shared/utils.ts";
45
46
  import { buildSkillInjection, resolveSkillsWithFallback } from "../../agents/skills.ts";
47
+ import { buildAgentMemoryInjection } from "../../agents/agent-memory.ts";
46
48
  import { evaluateCompletionMutationGuard } from "../shared/completion-guard.ts";
47
49
  import { getSelesaiSpawnCommand } from "../shared/pi-spawn.ts";
48
50
  import { createJsonlWriter } from "../../shared/jsonl-writer.ts";
49
51
  import { attachPostExitStdioGuard, trySignalChild } from "../../shared/post-exit-stdio-guard.ts";
50
52
  import { applyThinkingSuffix, buildPiArgs, cleanupTempDir } from "../shared/pi-args.ts";
51
- import { createSpawnTimingMarkers, emitSpawnTiming } from "../shared/spawn-timing.ts";
52
53
  import { readStructuredOutput } from "../shared/structured-output.ts";
53
54
  import { captureSingleOutputSnapshot, formatSavedOutputReference, injectOutputPathSystemPrompt, resolveSingleOutput, validateFileOnlyOutputMode, type SingleOutputSnapshot } from "../shared/single-output.ts";
54
55
  import {
@@ -68,6 +69,8 @@ import {
68
69
  summarizeRecentMutatingFailures,
69
70
  } from "../shared/long-running-guard.ts";
70
71
  import { acceptanceFailureMessage, evaluateAcceptance, formatAcceptancePrompt, resolveEffectiveAcceptance, stripAcceptanceReport } from "../shared/acceptance.ts";
72
+ import { appendTurnBudgetSystemPrompt, formatTurnBudgetOutput, initialTurnBudgetState, shouldAbortForTurnBudget, turnBudgetExceededMessage, turnBudgetSoftNote, turnBudgetState } from "../shared/turn-budget.ts";
73
+ import { initialToolBudgetState, toolBudgetState } from "../shared/tool-budget.ts";
71
74
 
72
75
  const artifactOutputByResult = new WeakMap<SingleResult, string>();
73
76
  const acceptanceOutputByResult = new WeakMap<SingleResult, string>();
@@ -99,7 +102,7 @@ function resolveAttemptTimeout(options: RunSyncOptions): { timeoutMs: number; re
99
102
  };
100
103
  }
101
104
 
102
- function buildTimedOutAcceptanceLedger(acceptance: ResolvedAcceptanceConfig): AcceptanceLedger {
105
+ function buildSkippedAcceptanceLedger(acceptance: ResolvedAcceptanceConfig, input: { id: string; message: string }): AcceptanceLedger {
103
106
  return {
104
107
  status: acceptance.level === "none" ? "not-required" : "rejected",
105
108
  explicit: acceptance.explicit,
@@ -108,7 +111,7 @@ function buildTimedOutAcceptanceLedger(acceptance: ResolvedAcceptanceConfig): Ac
108
111
  criteria: acceptance.criteria,
109
112
  runtimeChecks: acceptance.level === "none"
110
113
  ? []
111
- : [{ id: "timeout", status: "failed", message: "Acceptance was not evaluated because the subagent timed out." }],
114
+ : [{ id: input.id, status: "failed", message: input.message }],
112
115
  verifyRuns: [],
113
116
  };
114
117
  }
@@ -176,20 +179,22 @@ async function runSingleAttempt(
176
179
  skillsWarning?: string;
177
180
  jsonlPath?: string;
178
181
  artifactPaths?: ArtifactPaths;
182
+ transcriptWriter?: ChildTranscriptWriter;
179
183
  attemptNotes: string[];
180
184
  outputSnapshot?: SingleOutputSnapshot;
181
185
  originalTask?: string;
182
186
  },
183
187
  ): Promise<SingleResult> {
184
- const modelArg = applyThinkingSuffix(model, agent.thinking);
185
- const { args, env: sharedEnv, tempDir } = buildPiArgs({
188
+ const effectiveThinking = options.thinkingOverride ?? agent.thinking;
189
+ const modelArg = applyThinkingSuffix(model, effectiveThinking, options.thinkingOverride !== undefined);
190
+ const { args, env: sharedEnv, tempDir } = buildPiArgs({
186
191
  baseArgs: ["--offline", "--mode", "json", "-p"],
187
192
  task,
188
193
  sessionEnabled: shared.sessionEnabled,
189
194
  sessionDir: options.sessionDir,
190
195
  sessionFile: options.sessionFile,
191
- model,
192
- thinking: agent.thinking,
196
+ model: modelArg,
197
+ thinking: effectiveThinking,
193
198
  systemPromptMode: agent.systemPromptMode,
194
199
  inheritProjectContext: agent.inheritProjectContext,
195
200
  inheritSkills: agent.inheritSkills,
@@ -197,7 +202,7 @@ async function runSingleAttempt(
197
202
  tools: agent.tools,
198
203
  extensions: agent.extensions,
199
204
  subagentOnlyExtensions: agent.subagentOnlyExtensions,
200
- systemPrompt: shared.systemPrompt,
205
+ systemPrompt: appendTurnBudgetSystemPrompt(shared.systemPrompt, options.turnBudget),
201
206
  mcpDirectTools: agent.mcpDirectTools,
202
207
  cwd: options.cwd ?? runtimeCwd,
203
208
  promptFileStem: agent.name,
@@ -208,11 +213,12 @@ async function runSingleAttempt(
208
213
  childIndex: options.index ?? 0,
209
214
  parentEventSink: options.nestedRoute?.eventSink,
210
215
  parentControlInbox: options.nestedRoute?.controlInbox,
211
- parentRootRunId: options.nestedRoute?.rootRunId,
212
- parentCapabilityToken: options.nestedRoute?.capabilityToken,
213
- parentSessionId: options.parentSessionId,
214
- structuredOutput: options.structuredOutput,
215
- });
216
+ parentRootRunId: options.nestedRoute?.rootRunId,
217
+ parentCapabilityToken: options.nestedRoute?.capabilityToken,
218
+ parentSessionId: options.parentSessionId,
219
+ structuredOutput: options.structuredOutput,
220
+ toolBudget: options.toolBudget,
221
+ });
216
222
 
217
223
  const result: SingleResult = {
218
224
  agent: agent.name,
@@ -222,8 +228,11 @@ async function runSingleAttempt(
222
228
  usage: emptyUsage(),
223
229
  model: modelArg,
224
230
  artifactPaths: shared.artifactPaths,
231
+ transcriptPath: shared.transcriptWriter ? shared.artifactPaths?.transcriptPath : undefined,
225
232
  skills: shared.resolvedSkillNames,
226
233
  skillsWarning: shared.skillsWarning,
234
+ ...(options.turnBudget ? { turnBudget: initialTurnBudgetState(options.turnBudget) } : {}),
235
+ ...(options.toolBudget ? { toolBudget: initialToolBudgetState(options.toolBudget) } : {}),
227
236
  };
228
237
  const startTime = Date.now();
229
238
  if (options.structuredOutput) {
@@ -279,24 +288,7 @@ async function runSingleAttempt(
279
288
  let observedMutationAttempt = false;
280
289
 
281
290
  const exitCode = await new Promise<number>((resolve) => {
282
- const markers = createSpawnTimingMarkers();
283
291
  const spawnSpec = getSelesaiSpawnCommand(args);
284
- emitSpawnTiming({
285
- eventsPath: shared.jsonlPath,
286
- marker: "spawn_start",
287
- markers,
288
- runId: options.runId,
289
- stepIndex: options.index ?? 0,
290
- agent: agent.name,
291
- });
292
- emitSpawnTiming({
293
- eventsPath: shared.jsonlPath,
294
- marker: "spawn_command_resolved",
295
- markers,
296
- runId: options.runId,
297
- stepIndex: options.index ?? 0,
298
- agent: agent.name,
299
- });
300
292
  const proc = spawn(spawnSpec.command, spawnSpec.args, {
301
293
  cwd: options.cwd ?? runtimeCwd,
302
294
  env: spawnEnv,
@@ -304,8 +296,6 @@ async function runSingleAttempt(
304
296
  windowsHide: true,
305
297
  });
306
298
  const jsonlWriter = createJsonlWriter(shared.jsonlPath, proc.stdout);
307
- let firstEventEmitted = false;
308
- let firstJsonlEventEmitted = false;
309
299
  let buf = "";
310
300
  let processClosed = false;
311
301
  let settled = false;
@@ -318,6 +308,19 @@ async function runSingleAttempt(
318
308
  let timeoutTimer: NodeJS.Timeout | undefined;
319
309
  let timeoutTerminationTimer: NodeJS.Timeout | undefined;
320
310
  let timeoutHardKillTimer: NodeJS.Timeout | undefined;
311
+ let turnBudgetSoftReached = false;
312
+ let turnBudgetTerminationTimer: NodeJS.Timeout | undefined;
313
+ let turnBudgetHardKillTimer: NodeJS.Timeout | undefined;
314
+ const clearTurnBudgetTimers = () => {
315
+ if (turnBudgetTerminationTimer) {
316
+ clearTimeout(turnBudgetTerminationTimer);
317
+ turnBudgetTerminationTimer = undefined;
318
+ }
319
+ if (turnBudgetHardKillTimer) {
320
+ clearTimeout(turnBudgetHardKillTimer);
321
+ turnBudgetHardKillTimer = undefined;
322
+ }
323
+ };
321
324
  const clearTimeoutTimers = () => {
322
325
  if (timeoutTimer) {
323
326
  clearTimeout(timeoutTimer);
@@ -401,6 +404,7 @@ async function runSingleAttempt(
401
404
  clearFinalDrainTimers();
402
405
  clearStdioGuard();
403
406
  clearTimeoutTimers();
407
+ clearTurnBudgetTimers();
404
408
  if (activityTimer) {
405
409
  clearInterval(activityTimer);
406
410
  activityTimer = undefined;
@@ -474,6 +478,50 @@ async function runSingleAttempt(
474
478
  }));
475
479
  return true;
476
480
  };
481
+ const requestTurnBudgetAbort = (turnCount: number) => {
482
+ const budget = options.turnBudget;
483
+ if (!budget || result.timedOut || result.turnBudgetExceeded || interruptedByControl || processClosed || settled || detached) return;
484
+ const message = turnBudgetExceededMessage(budget, turnCount);
485
+ result.turnBudgetExceeded = true;
486
+ result.wrapUpRequested = true;
487
+ result.turnBudget = turnBudgetState(budget, turnCount, true);
488
+ result.error = message;
489
+ result.finalOutput = message;
490
+ progress.status = "failed";
491
+ progress.error = message;
492
+ progress.durationMs = Date.now() - startTime;
493
+ fireUpdate();
494
+ trySignalChild(proc, "SIGINT");
495
+ turnBudgetTerminationTimer = setTimeout(() => {
496
+ if (processClosed || settled || detached || result.timedOut) return;
497
+ trySignalChild(proc, "SIGTERM");
498
+ }, 1000);
499
+ turnBudgetTerminationTimer.unref?.();
500
+ turnBudgetHardKillTimer = setTimeout(() => {
501
+ if (processClosed || settled || detached || result.timedOut) return;
502
+ trySignalChild(proc, "SIGKILL");
503
+ }, 4000);
504
+ turnBudgetHardKillTimer.unref?.();
505
+ };
506
+
507
+ const updateTurnBudget = (turnCount: number, terminalAssistantStop: boolean) => {
508
+ const budget = options.turnBudget;
509
+ if (!budget || result.timedOut || result.turnBudgetExceeded) return;
510
+ if (turnCount < budget.maxTurns) {
511
+ result.turnBudget = { ...budget, outcome: "within-budget", turnCount };
512
+ return;
513
+ }
514
+ if (!turnBudgetSoftReached) {
515
+ turnBudgetSoftReached = true;
516
+ result.wrapUpRequested = true;
517
+ appendRecentOutput(progress, [turnBudgetSoftNote(budget, turnCount)]);
518
+ }
519
+ result.turnBudget = turnBudgetState(budget, turnCount, false);
520
+ if (shouldAbortForTurnBudget(budget, turnCount, terminalAssistantStop)) {
521
+ requestTurnBudgetAbort(turnCount);
522
+ }
523
+ };
524
+
477
525
  const updateActivityState = (now: number): boolean => {
478
526
  if (!controlConfig.enabled) return false;
479
527
  const idleState = deriveActivityState({
@@ -514,35 +562,22 @@ async function runSingleAttempt(
514
562
  const fireUpdate = () => {
515
563
  if (!options.onUpdate || processClosed) return;
516
564
  progress.durationMs = Date.now() - startTime;
517
- const output = result.timedOut && result.finalOutput ? result.finalOutput : getFinalOutput(result.messages);
565
+ const output = (result.timedOut || result.turnBudgetExceeded) && result.finalOutput ? result.finalOutput : getFinalOutput(result.messages);
518
566
  emitUpdateSnapshot(output || "(running...)");
519
567
  };
520
568
 
521
- const emitTiming = (marker: import("../shared/spawn-timing.ts").SpawnTimingMarker) => {
522
- emitSpawnTiming({
523
- eventsPath: shared.jsonlPath,
524
- marker,
525
- markers,
526
- runId: options.runId,
527
- stepIndex: options.index ?? 0,
528
- agent: agent.name,
529
- });
530
- };
531
-
532
569
  const processLine = (line: string) => {
533
570
  if (!line.trim()) return;
534
571
  jsonlWriter.writeLine(line);
535
572
  let evt: { type?: string; message?: Message; toolName?: string; args?: unknown };
536
573
  try {
537
574
  evt = JSON.parse(line) as { type?: string; message?: Message; toolName?: string; args?: unknown };
538
- if (!firstJsonlEventEmitted) {
539
- firstJsonlEventEmitted = true;
540
- emitTiming("child_first_jsonl_event");
541
- }
542
575
  } catch {
576
+ shared.transcriptWriter?.writeStdoutLine(line);
543
577
  // Non-JSON stdout lines are expected; only structured events are parsed.
544
578
  return;
545
579
  }
580
+ shared.transcriptWriter?.writeChildEvent(evt);
546
581
 
547
582
  const now = Date.now();
548
583
  progress.durationMs = now - startTime;
@@ -553,10 +588,16 @@ async function runSingleAttempt(
553
588
  const toolArgs = evt.args && typeof evt.args === "object" && !Array.isArray(evt.args)
554
589
  ? evt.args as Record<string, unknown>
555
590
  : {};
591
+ let shouldDetachForBlockingIntercom = false;
556
592
  if (options.allowIntercomDetach && (evt.toolName === "intercom" || evt.toolName === "contact_supervisor")) {
557
593
  intercomStarted = true;
594
+ shouldDetachForBlockingIntercom = (evt.toolName === "intercom" && toolArgs.action === "ask")
595
+ || (evt.toolName === "contact_supervisor" && (toolArgs.reason === "need_decision" || toolArgs.reason === "interview_request"));
558
596
  }
559
597
  progress.toolCount++;
598
+ if (options.toolBudget) {
599
+ result.toolBudget = toolBudgetState(options.toolBudget, progress.toolCount);
600
+ }
560
601
  progress.currentTool = evt.toolName;
561
602
  progress.currentToolArgs = extractToolArgsPreview(toolArgs);
562
603
  progress.currentToolStartedAt = now;
@@ -565,6 +606,9 @@ async function runSingleAttempt(
565
606
  observedMutationAttempt = observedMutationAttempt || mutates;
566
607
  pendingToolResult = { tool: evt.toolName ?? "tool", path: progress.currentPath, mutates, startedAt: now };
567
608
  fireUpdate();
609
+ if (shouldDetachForBlockingIntercom && !detached && !processClosed) {
610
+ detachForIntercom();
611
+ }
568
612
  }
569
613
 
570
614
  if (evt.type === "tool_execution_end") {
@@ -587,6 +631,11 @@ async function runSingleAttempt(
587
631
  if (evt.message.role === "assistant") {
588
632
  result.usage.turns++;
589
633
  progress.turnCount = result.usage.turns;
634
+ const stopReason = (evt.message as { stopReason?: string }).stopReason;
635
+ const hasToolCall = Array.isArray(evt.message.content)
636
+ && evt.message.content.some((part) => (part as { type?: string }).type === "toolCall");
637
+ const terminalAssistantStop = stopReason === "stop" && !hasToolCall;
638
+ updateTurnBudget(result.usage.turns, terminalAssistantStop);
590
639
  const u = evt.message.usage;
591
640
  if (u) {
592
641
  result.usage.input += u.input || 0;
@@ -601,10 +650,7 @@ async function runSingleAttempt(
601
650
  const assistantText = extractTextFromContent(evt.message.content);
602
651
  appendRecentOutput(progress, assistantText.split("\n").slice(-10));
603
652
  // Final assistant message: start the exit drain window.
604
- const stopReason = (evt.message as { stopReason?: string }).stopReason;
605
- const hasToolCall = Array.isArray(evt.message.content)
606
- && evt.message.content.some((part) => (part as { type?: string }).type === "toolCall");
607
- if (stopReason === "stop" && !hasToolCall) {
653
+ if (terminalAssistantStop) {
608
654
  if (!evt.message.errorMessage && assistantText.trim()) assistantError = undefined;
609
655
  cleanTerminalAssistantStopReceived ||= !evt.message.errorMessage;
610
656
  startFinalDrain();
@@ -617,6 +663,10 @@ async function runSingleAttempt(
617
663
  if (evt.type === "tool_result_end" && evt.message) {
618
664
  result.messages.push(evt.message);
619
665
  const resultText = extractTextFromContent(evt.message.content);
666
+ if (options.toolBudget && pendingToolResult && resultText.includes("Tool budget hard limit reached")) {
667
+ result.toolBudgetBlocked = true;
668
+ result.toolBudget = toolBudgetState(options.toolBudget, progress.toolCount, pendingToolResult.tool);
669
+ }
620
670
  appendRecentOutput(progress, resultText.split("\n").slice(-10));
621
671
  const toolSnapshot = pendingToolResult;
622
672
  pendingToolResult = undefined;
@@ -685,20 +735,12 @@ async function runSingleAttempt(
685
735
 
686
736
  const clearStdioGuard = attachPostExitStdioGuard(proc, { idleMs: 2000, hardMs: 8000 });
687
737
  proc.stdout.on("data", (d) => {
688
- if (!firstEventEmitted) {
689
- firstEventEmitted = true;
690
- emitTiming("child_first_event");
691
- }
692
738
  buf += d.toString();
693
739
  const lines = buf.split("\n");
694
740
  buf = lines.pop() || "";
695
741
  lines.forEach(processLine);
696
742
  });
697
743
  proc.stderr.on("data", (d) => {
698
- if (!firstEventEmitted) {
699
- firstEventEmitted = true;
700
- emitTiming("child_first_event");
701
- }
702
744
  stderrBuf += d.toString();
703
745
  });
704
746
  proc.on("exit", () => {
@@ -712,18 +754,38 @@ async function runSingleAttempt(
712
754
  // JSONL artifact flush is best effort.
713
755
  });
714
756
  cleanupTempDir(tempDir);
715
- if (detached) {
716
- finish(-2);
717
- return;
718
- }
719
- processClosed = true;
720
757
  if (buf.trim()) processLine(buf);
758
+ if (stderrBuf.trim()) shared.transcriptWriter?.writeStderrText(stderrBuf);
721
759
  if (!result.error && assistantError) result.error = assistantError;
722
760
  const forcedDrainAfterFinalSuccess = forcedTerminationSignal && cleanTerminalAssistantStopReceived && !result.error;
723
761
  if (code !== 0 && stderrBuf.trim() && !result.error && !forcedDrainAfterFinalSuccess) {
724
762
  result.error = stderrBuf.trim();
725
763
  }
726
764
  const finalCode = forcedDrainAfterFinalSuccess ? 0 : forcedTerminationSignal || signal ? (code ?? 1) : (code ?? 0);
765
+ if (detached) {
766
+ result.exitCode = result.error && finalCode === 0 ? 1 : finalCode;
767
+ progress.status = result.exitCode === 0 ? "completed" : "failed";
768
+ progress.durationMs = Date.now() - startTime;
769
+ if (result.error) progress.error = result.error;
770
+ result.progressSummary = {
771
+ toolCount: progress.toolCount,
772
+ tokens: progress.tokens,
773
+ durationMs: progress.durationMs,
774
+ };
775
+ const finalOutput = getFinalOutput(result.messages);
776
+ result.finalOutput = finalOutput.trim() || result.error || result.finalOutput || "Detached child exited without final output.";
777
+ if (result.artifactPaths && options.artifactConfig?.enabled !== false && options.artifactConfig?.includeOutput !== false) {
778
+ try {
779
+ writeArtifact(result.artifactPaths.outputPath, result.finalOutput);
780
+ } catch {
781
+ // Detached children may outlive test/temp cleanup; recovered status is best-effort.
782
+ }
783
+ }
784
+ options.onDetachedExit?.(snapshotResult(result, snapshotProgress(progress)));
785
+ finish(-2);
786
+ return;
787
+ }
788
+ processClosed = true;
727
789
  finish(finalCode);
728
790
  });
729
791
  proc.on("error", (error) => {
@@ -733,6 +795,7 @@ async function runSingleAttempt(
733
795
  // JSONL artifact flush is best effort.
734
796
  });
735
797
  cleanupTempDir(tempDir);
798
+ if (stderrBuf.trim()) shared.transcriptWriter?.writeStderrText(stderrBuf);
736
799
  if (!result.error) {
737
800
  result.error = error instanceof Error ? error.message : String(error);
738
801
  }
@@ -815,6 +878,16 @@ async function runSingleAttempt(
815
878
  : `${errInfo.errorType} failed with exit code ${errInfo.exitCode}`;
816
879
  }
817
880
  }
881
+ if (result.exitCode === 0 && !result.error) {
882
+ const finalText = getFinalOutput(result.messages);
883
+ const missingStructuredOutput = options.structuredOutput
884
+ ? !existsSync(options.structuredOutput.outputPath)
885
+ : false;
886
+ if (!finalText?.trim() && (!options.structuredOutput || missingStructuredOutput)) {
887
+ result.exitCode = 1;
888
+ result.error = "Subagent produced no output (possible model cold-start or empty response).";
889
+ }
890
+ }
818
891
  if (options.structuredOutput && result.exitCode === 0 && !result.error) {
819
892
  const structured = readStructuredOutput({
820
893
  schema: options.structuredOutput.schema,
@@ -853,6 +926,11 @@ async function runSingleAttempt(
853
926
  fullOutput = fullOutput.trim()
854
927
  ? `${timeoutMessage}\n\nPartial output before timeout:\n${fullOutput}`
855
928
  : timeoutMessage;
929
+ } else if (result.turnBudgetExceeded && result.turnBudget) {
930
+ fullOutput = formatTurnBudgetOutput(turnBudgetExceededMessage(result.turnBudget, result.turnBudget.turnCount), fullOutput);
931
+ } else if (result.wrapUpRequested && result.turnBudget?.outcome === "wrap-up-requested") {
932
+ const note = turnBudgetSoftNote(result.turnBudget, result.turnBudget.wrapUpRequestedAtTurn ?? result.turnBudget.turnCount);
933
+ fullOutput = fullOutput.trim() ? `${note}\n\n${fullOutput}` : note;
856
934
  }
857
935
  const completionGuard = result.exitCode === 0 && !result.error && agent.completionGuard !== false
858
936
  ? evaluateCompletionMutationGuard({
@@ -977,6 +1055,10 @@ export async function runSync(
977
1055
  const skillInjection = buildSkillInjection(resolvedSkills);
978
1056
  systemPrompt = systemPrompt ? `${systemPrompt}\n\n${skillInjection}` : skillInjection;
979
1057
  }
1058
+ const memoryInjection = buildAgentMemoryInjection(agent, skillCwd);
1059
+ if (memoryInjection) {
1060
+ systemPrompt = systemPrompt ? `${systemPrompt}\n\n${memoryInjection}` : memoryInjection;
1061
+ }
980
1062
  systemPrompt = injectOutputPathSystemPrompt(systemPrompt, options.outputPath);
981
1063
 
982
1064
  const candidates = buildModelCandidates(
@@ -984,6 +1066,7 @@ export async function runSync(
984
1066
  agent.fallbackModels,
985
1067
  options.availableModels,
986
1068
  options.preferredModelProvider,
1069
+ { scope: options.modelScope },
987
1070
  );
988
1071
  const attemptedModels: string[] = [];
989
1072
  const modelAttempts: ModelAttempt[] = [];
@@ -994,6 +1077,7 @@ export async function runSync(
994
1077
 
995
1078
  let artifactPathsResult: ArtifactPaths | undefined;
996
1079
  let jsonlPath: string | undefined;
1080
+ let transcriptWriter: ChildTranscriptWriter | undefined;
997
1081
  if (options.artifactsDir && options.artifactConfig?.enabled !== false) {
998
1082
  artifactPathsResult = getArtifactPaths(options.artifactsDir, options.runId, agentName, options.index);
999
1083
  ensureArtifactsDir(options.artifactsDir);
@@ -1003,13 +1087,23 @@ export async function runSync(
1003
1087
  if (options.artifactConfig?.includeJsonl !== false) {
1004
1088
  jsonlPath = artifactPathsResult.jsonlPath;
1005
1089
  }
1090
+ if (options.artifactConfig?.includeTranscript !== false) {
1091
+ transcriptWriter = createChildTranscriptWriter({
1092
+ transcriptPath: artifactPathsResult.transcriptPath,
1093
+ source: "foreground",
1094
+ runId: options.runId,
1095
+ agent: agentName,
1096
+ childIndex: options.index,
1097
+ cwd: options.cwd ?? runtimeCwd,
1098
+ });
1099
+ transcriptWriter.writeInitialUserMessage(taskWithAcceptance);
1100
+ }
1006
1101
  }
1007
1102
 
1008
1103
  let lastResult: SingleResult | undefined;
1009
1104
  const modelsToTry = candidates.length > 0 ? candidates : [undefined];
1010
1105
  for (let i = 0; i < modelsToTry.length; i++) {
1011
1106
  const candidate = modelsToTry[i];
1012
- if (candidate) attemptedModels.push(candidate);
1013
1107
  const outputSnapshot = captureSingleOutputSnapshot(options.outputPath);
1014
1108
  const result = await runSingleAttempt(runtimeCwd, agent, taskWithAcceptance, candidate, options, {
1015
1109
  sessionEnabled,
@@ -1018,24 +1112,27 @@ export async function runSync(
1018
1112
  skillsWarning: missingSkills.length > 0 ? `Skills not found: ${missingSkills.join(", ")}` : undefined,
1019
1113
  jsonlPath,
1020
1114
  artifactPaths: artifactPathsResult,
1115
+ transcriptWriter,
1021
1116
  attemptNotes,
1022
1117
  outputSnapshot,
1023
1118
  originalTask: task,
1024
1119
  });
1025
1120
  lastResult = result;
1121
+ if (result.model) attemptedModels.push(result.model);
1122
+ else if (candidate) attemptedModels.push(candidate);
1026
1123
  sumUsage(aggregateUsage, result.usage);
1027
1124
  totalToolCount += result.progressSummary?.toolCount ?? 0;
1028
1125
  totalDurationMs += result.progressSummary?.durationMs ?? 0;
1029
1126
  const attemptSucceeded = result.exitCode === 0 && !result.error;
1030
1127
  const attempt: ModelAttempt = {
1031
- model: candidate ?? result.model ?? agent.model ?? "default",
1128
+ model: result.model ?? candidate ?? agent.model ?? "default",
1032
1129
  success: attemptSucceeded,
1033
1130
  exitCode: result.exitCode,
1034
1131
  error: result.error,
1035
1132
  usage: { ...result.usage },
1036
1133
  };
1037
1134
  modelAttempts.push(attempt);
1038
- if (result.timedOut) {
1135
+ if (result.timedOut || result.turnBudgetExceeded) {
1039
1136
  break;
1040
1137
  }
1041
1138
  if (attemptSucceeded) {
@@ -1071,6 +1168,9 @@ export async function runSync(
1071
1168
  }
1072
1169
  }
1073
1170
 
1171
+ if (transcriptWriter) result.transcriptPath = artifactPathsResult?.transcriptPath;
1172
+ if (transcriptWriter?.getError()) result.transcriptError = transcriptWriter.getError();
1173
+
1074
1174
  if (artifactPathsResult && options.artifactConfig?.enabled !== false) {
1075
1175
  result.artifactPaths = artifactPathsResult;
1076
1176
  if (options.artifactConfig?.includeOutput !== false) {
@@ -1089,6 +1189,8 @@ export async function runSync(
1089
1189
  durationMs: result.progressSummary?.durationMs,
1090
1190
  toolCount: result.progressSummary?.toolCount,
1091
1191
  error: result.error,
1192
+ ...(transcriptWriter ? { transcriptPath: artifactPathsResult.transcriptPath } : {}),
1193
+ transcriptError: result.transcriptError,
1092
1194
  skills: result.skills,
1093
1195
  skillsWarning: result.skillsWarning,
1094
1196
  timestamp: Date.now(),
@@ -1114,8 +1216,10 @@ export async function runSync(
1114
1216
  }
1115
1217
 
1116
1218
  result.acceptance = result.timedOut
1117
- ? buildTimedOutAcceptanceLedger(effectiveAcceptance)
1118
- : await evaluateAcceptance({
1219
+ ? buildSkippedAcceptanceLedger(effectiveAcceptance, { id: "timeout", message: "Acceptance was not evaluated because the subagent timed out." })
1220
+ : result.turnBudgetExceeded
1221
+ ? buildSkippedAcceptanceLedger(effectiveAcceptance, { id: "turn-budget", message: "Acceptance was not evaluated because the subagent exceeded its turn budget." })
1222
+ : await evaluateAcceptance({
1119
1223
  acceptance: effectiveAcceptance,
1120
1224
  output: acceptanceOutputByResult.get(result) ?? result.finalOutput ?? "",
1121
1225
  cwd: options.cwd ?? runtimeCwd,