@wrongstack/core 0.313.0 → 0.316.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 (343) hide show
  1. package/dist/chronicle/index.js +84 -6391
  2. package/dist/chronicle/legacy-journal-import.d.ts +0 -6
  3. package/dist/chronicle/metrics-ingest.d.ts +14 -0
  4. package/dist/chronicle/metrics-schema.d.ts +10 -1
  5. package/dist/chronicle/metrics-store.d.ts +20 -2
  6. package/dist/chronicle/project-server.js +98 -4874
  7. package/dist/chronicle/sink.d.ts +13 -0
  8. package/dist/chronicle/sqlite-journal.d.ts +20 -2
  9. package/dist/chunk-25LSLC3G.js +334 -0
  10. package/dist/chunk-27QIURLN.js +1073 -0
  11. package/dist/chunk-2FK4WTFF.js +207 -0
  12. package/dist/chunk-2YU4WVBW.js +134 -0
  13. package/dist/chunk-3AGWVSS7.js +4608 -0
  14. package/dist/chunk-3BDV7RL3.js +211 -0
  15. package/dist/chunk-3ECENVHL.js +325 -0
  16. package/dist/chunk-3XPVB7BA.js +135 -0
  17. package/dist/chunk-45WI72ZB.js +16884 -0
  18. package/dist/chunk-4BMVPOHO.js +3748 -0
  19. package/dist/chunk-4I7HGVVA.js +363 -0
  20. package/dist/chunk-4LCZVJVF.js +317 -0
  21. package/dist/chunk-4SJNS7OB.js +217 -0
  22. package/dist/chunk-4VWO3ZXL.js +342 -0
  23. package/dist/chunk-57GEWK5X.js +26 -0
  24. package/dist/chunk-5BMIE7QG.js +46 -0
  25. package/dist/chunk-5S437PRC.js +50 -0
  26. package/dist/chunk-5XDUGTKN.js +511 -0
  27. package/dist/chunk-5YPSXQXM.js +1443 -0
  28. package/dist/chunk-6FHWXLPT.js +10 -0
  29. package/dist/chunk-6H5GEOET.js +2406 -0
  30. package/dist/chunk-6NWEVFEL.js +151 -0
  31. package/dist/chunk-AYW5YINX.js +58 -0
  32. package/dist/chunk-B4AMLZPB.js +9 -0
  33. package/dist/chunk-B7F4WVP4.js +65 -0
  34. package/dist/chunk-BJHVULHO.js +55 -0
  35. package/dist/chunk-BPBKKBUK.js +2085 -0
  36. package/dist/chunk-BYD345OX.js +589 -0
  37. package/dist/chunk-C27KDLOX.js +279 -0
  38. package/dist/chunk-CU546ESW.js +597 -0
  39. package/dist/chunk-DLHHXUAM.js +172 -0
  40. package/dist/chunk-DOTHQSJ2.js +429 -0
  41. package/dist/chunk-DYLPMV4Q.js +711 -0
  42. package/dist/chunk-EODDVJBM.js +82 -0
  43. package/dist/chunk-F3JWNST7.js +361 -0
  44. package/dist/chunk-FC2ZGRF3.js +140 -0
  45. package/dist/chunk-FCBTO76Z.js +5786 -0
  46. package/dist/chunk-FHZVFYSL.js +396 -0
  47. package/dist/chunk-FNXVT7HF.js +52 -0
  48. package/dist/chunk-FWNLEZYG.js +259 -0
  49. package/dist/chunk-FXQLIX3K.js +211 -0
  50. package/dist/chunk-G5S3S5ZN.js +38 -0
  51. package/dist/chunk-GDQ7CZRQ.js +116 -0
  52. package/dist/chunk-GJJGJB2R.js +1374 -0
  53. package/dist/chunk-GTCU6DZ3.js +1 -0
  54. package/dist/chunk-HA4ZYA6T.js +178 -0
  55. package/dist/chunk-HI3JGZR2.js +188 -0
  56. package/dist/chunk-HMLIGAU7.js +395 -0
  57. package/dist/chunk-HXKZ7OBQ.js +303 -0
  58. package/dist/chunk-I7DALG7J.js +292 -0
  59. package/dist/chunk-IRUTEHCE.js +960 -0
  60. package/dist/chunk-IYFBFX34.js +86 -0
  61. package/dist/chunk-J2WRWR37.js +1104 -0
  62. package/dist/chunk-JFPJ6LLQ.js +129 -0
  63. package/dist/chunk-JMULFFLN.js +9 -0
  64. package/dist/chunk-JO4MGB6Z.js +1264 -0
  65. package/dist/chunk-JVKB2TBL.js +48 -0
  66. package/dist/chunk-JX7VBZDK.js +31 -0
  67. package/dist/chunk-K6BXGITA.js +931 -0
  68. package/dist/chunk-KDQJCT2J.js +45 -0
  69. package/dist/chunk-KJ2ZTQSL.js +47 -0
  70. package/dist/chunk-KZMSZV32.js +187 -0
  71. package/dist/chunk-LA7CLDRW.js +129 -0
  72. package/dist/chunk-LHOA5DWA.js +28 -0
  73. package/dist/chunk-LSMMOS2Z.js +119 -0
  74. package/dist/chunk-LX5QWLBL.js +27 -0
  75. package/dist/chunk-LXWCMQNJ.js +789 -0
  76. package/dist/chunk-M27LIEKV.js +2829 -0
  77. package/dist/chunk-MJPHJRAL.js +663 -0
  78. package/dist/chunk-MTL4O5YR.js +228 -0
  79. package/dist/chunk-NDBIPFNY.js +102 -0
  80. package/dist/chunk-NEMIWEXC.js +1199 -0
  81. package/dist/chunk-NHJ75HXY.js +1 -0
  82. package/dist/chunk-NIOAGFPB.js +1510 -0
  83. package/dist/chunk-NS52ISWS.js +355 -0
  84. package/dist/chunk-NSOFPKGT.js +5352 -0
  85. package/dist/chunk-NVIZG63R.js +757 -0
  86. package/dist/chunk-O37BQ65S.js +21 -0
  87. package/dist/chunk-OOYZPOXM.js +308 -0
  88. package/dist/chunk-OSGLYW5J.js +28 -0
  89. package/dist/chunk-PFCMSSUF.js +1640 -0
  90. package/dist/chunk-PFZO3C6H.js +14 -0
  91. package/dist/chunk-PGRVXIMY.js +158 -0
  92. package/dist/chunk-PHH7LD45.js +113 -0
  93. package/dist/chunk-PISBFBJN.js +109 -0
  94. package/dist/chunk-POOOIWE5.js +9 -0
  95. package/dist/chunk-PQNS3U7Z.js +1240 -0
  96. package/dist/chunk-QSTSJOCK.js +402 -0
  97. package/dist/chunk-RFQMOKWK.js +282 -0
  98. package/dist/chunk-RJIZEJ42.js +30 -0
  99. package/dist/chunk-RTOTNK3P.js +484 -0
  100. package/dist/chunk-RXKSDUAU.js +1172 -0
  101. package/dist/chunk-S45JPKQN.js +3317 -0
  102. package/dist/chunk-SAFHACFA.js +152 -0
  103. package/dist/chunk-SQJVFEBV.js +41 -0
  104. package/dist/chunk-SVT4RNTR.js +49 -0
  105. package/dist/chunk-SWUFN7XM.js +43 -0
  106. package/dist/chunk-SXMVYC5H.js +174 -0
  107. package/dist/chunk-SZ6AYUIZ.js +23 -0
  108. package/dist/chunk-TBRL2RCC.js +9 -0
  109. package/dist/chunk-TCCHINEF.js +655 -0
  110. package/dist/chunk-THEGTRAG.js +316 -0
  111. package/dist/chunk-TR4LQE7L.js +2256 -0
  112. package/dist/chunk-TRT2HRWZ.js +18 -0
  113. package/dist/chunk-TWJMGXCI.js +900 -0
  114. package/dist/chunk-U45AXT5D.js +1023 -0
  115. package/dist/chunk-U4FWBSO3.js +509 -0
  116. package/dist/chunk-UBGDX6FI.js +147 -0
  117. package/dist/chunk-UJILKYES.js +75 -0
  118. package/dist/chunk-ULMAQV3T.js +234 -0
  119. package/dist/chunk-VVBP6KGT.js +9 -0
  120. package/dist/chunk-W5VITDM2.js +168 -0
  121. package/dist/chunk-WAHQVNWT.js +194 -0
  122. package/dist/chunk-WBPVKEEE.js +227 -0
  123. package/dist/chunk-WGGYRBXH.js +5434 -0
  124. package/dist/chunk-WLYKU45P.js +5770 -0
  125. package/dist/chunk-WP7BVANJ.js +53 -0
  126. package/dist/chunk-WQQON3SV.js +473 -0
  127. package/dist/chunk-WQTOVMGV.js +119 -0
  128. package/dist/chunk-XBDP4QPW.js +7 -0
  129. package/dist/chunk-XEBHSJLT.js +103 -0
  130. package/dist/chunk-XF4VUMKW.js +231 -0
  131. package/dist/chunk-XQ2ECNK3.js +1 -0
  132. package/dist/chunk-Y5YXDM7D.js +74 -0
  133. package/dist/chunk-YOPAUVU4.js +2588 -0
  134. package/dist/chunk-YPT4A46F.js +362 -0
  135. package/dist/chunk-YWXT3JNM.js +425 -0
  136. package/dist/chunk-YY6APYUM.js +49 -0
  137. package/dist/chunk-Z2IJUO45.js +691 -0
  138. package/dist/chunk-ZHZ2Y2DH.js +1643 -0
  139. package/dist/chunk-ZT7JNIGX.js +152 -0
  140. package/dist/coordination/agent-monitor.d.ts +9 -1
  141. package/dist/coordination/agent-subagent-runner.d.ts +1 -1
  142. package/dist/coordination/agents/agent-prompts.d.ts +8 -0
  143. package/dist/coordination/agents/index.d.ts +33 -1
  144. package/dist/coordination/agents/index.js +184 -6269
  145. package/dist/coordination/agents/phase3-wave1-platform.d.ts +1 -3
  146. package/dist/coordination/agents/phase3-wave2-meta.d.ts +1 -3
  147. package/dist/coordination/agents/phase8-wave3-products.d.ts +1 -3
  148. package/dist/coordination/agents/phase9-wave4-platform-meta.d.ts +1 -3
  149. package/dist/coordination/agents/project-agent-identity.d.ts +11 -11
  150. package/dist/coordination/agents/types.d.ts +13 -2
  151. package/dist/coordination/brain-monitor.d.ts +30 -7
  152. package/dist/coordination/collab-debug.d.ts +1 -1
  153. package/dist/coordination/collab-pause.d.ts +1 -1
  154. package/dist/coordination/delegate-tool.d.ts +7 -5
  155. package/dist/coordination/director-kanban-queue-helpers.d.ts +1 -0
  156. package/dist/coordination/director-options.d.ts +7 -0
  157. package/dist/coordination/director-spawn-model.d.ts +17 -0
  158. package/dist/coordination/director-tools.d.ts +2 -2
  159. package/dist/coordination/director.d.ts +12 -0
  160. package/dist/coordination/dispatcher.d.ts +8 -0
  161. package/dist/coordination/fleet-bus.d.ts +35 -4
  162. package/dist/coordination/fleet-supervisor.d.ts +10 -2
  163. package/dist/coordination/fleet.d.ts +16 -7
  164. package/dist/coordination/index.d.ts +4 -0
  165. package/dist/coordination/index.js +402 -34324
  166. package/dist/coordination/kanban-dispatch-port.d.ts +2 -2
  167. package/dist/coordination/mailbox-http-router.d.ts +4 -3
  168. package/dist/coordination/mailbox-http-validation.d.ts +1 -1
  169. package/dist/coordination/mailbox-project-server.js +48 -3276
  170. package/dist/coordination/mailbox-types.d.ts +24 -6
  171. package/dist/coordination/model-tier-leader.d.ts +122 -0
  172. package/dist/coordination/model-tier.d.ts +122 -0
  173. package/dist/coordination/multi-agent-coordinator.d.ts +24 -0
  174. package/dist/coordination/origin-session.d.ts +16 -0
  175. package/dist/coordination/provider-status-tracker.d.ts +41 -5
  176. package/dist/coordination/session-note-hub.d.ts +44 -0
  177. package/dist/coordination/session-note-tool.d.ts +10 -0
  178. package/dist/core/agent.d.ts +15 -2
  179. package/dist/core/context.d.ts +22 -3
  180. package/dist/core/index.d.ts +2 -0
  181. package/dist/core/index.js +239 -12360
  182. package/dist/core/model-ref.js +5 -23
  183. package/dist/core/provider-runner.d.ts +36 -1
  184. package/dist/core/request-conversation-binding.d.ts +37 -0
  185. package/dist/core/session-notes.d.ts +25 -0
  186. package/dist/core/system-prompt-builder.d.ts +11 -2
  187. package/dist/core/system-prompt-variants.d.ts +78 -0
  188. package/dist/design/index.js +50 -1087
  189. package/dist/execution/auto-compaction-middleware.d.ts +11 -0
  190. package/dist/execution/autonomy-brain.d.ts +2 -1
  191. package/dist/execution/autonomy-prompt-contributor.d.ts +7 -2
  192. package/dist/execution/compaction-core.d.ts +4 -4
  193. package/dist/execution/eternal-autonomy.d.ts +1 -1
  194. package/dist/execution/index.d.ts +1 -1
  195. package/dist/execution/index.js +1615 -21895
  196. package/dist/execution/model-runtime.d.ts +0 -7
  197. package/dist/execution/parallel-eternal-engine.d.ts +7 -7
  198. package/dist/execution/prompt-enhancer.js +16 -535
  199. package/dist/execution/retry-policy.d.ts +31 -1
  200. package/dist/extension/index.js +7 -311
  201. package/dist/goal/index.js +33 -3435
  202. package/dist/hooks/index.js +14 -1138
  203. package/dist/hq/index.js +114 -5139
  204. package/dist/hq/persistence/event-log.d.ts +0 -1
  205. package/dist/hq/persistence.d.ts +4 -4
  206. package/dist/hq/protocol.js +21 -668
  207. package/dist/hq/publisher.d.ts +2 -0
  208. package/dist/index.d.ts +14 -11
  209. package/dist/index.js +1502 -92655
  210. package/dist/infrastructure/index.d.ts +4 -4
  211. package/dist/infrastructure/index.js +504 -5230
  212. package/dist/infrastructure/token-counter.d.ts +9 -0
  213. package/dist/kernel/events/agent-events.d.ts +77 -3
  214. package/dist/kernel/events/brain-events.d.ts +12 -0
  215. package/dist/kernel/events/provider-events.d.ts +22 -1
  216. package/dist/kernel/events/session-events.d.ts +14 -0
  217. package/dist/kernel/events/tool-events.d.ts +13 -0
  218. package/dist/kernel/index.js +14 -992
  219. package/dist/mailbox-attach.d.ts +1 -1
  220. package/dist/models/index.js +41 -1117
  221. package/dist/notifications/index.js +3 -108
  222. package/dist/observability/event-bridge.d.ts +25 -5
  223. package/dist/observability/index.d.ts +9 -8
  224. package/dist/observability/index.js +477 -631
  225. package/dist/observability/tool-usage-source.d.ts +65 -0
  226. package/dist/plugin/index.d.ts +5 -0
  227. package/dist/plugin/index.js +600 -14835
  228. package/dist/plugins/auto-review-plugin.d.ts +3 -2
  229. package/dist/plugins/review-finding-commands.d.ts +0 -8
  230. package/dist/plugins/review-finding-store.js +22 -0
  231. package/dist/plugins/review-finding-types.js +19 -0
  232. package/dist/plugins/review-report-integration.js +21 -0
  233. package/dist/plugins/review-report-store.js +20 -0
  234. package/dist/plugins/review-report-types.js +13 -0
  235. package/dist/prompts/index.js +14 -948
  236. package/dist/registry/index.js +9 -822
  237. package/dist/registry/tool-registry.d.ts +59 -9
  238. package/dist/registry-7N4O3E7W.js +14 -0
  239. package/dist/replay/index.js +6 -84
  240. package/dist/security/capabilities.d.ts +6 -0
  241. package/dist/security/file-permissions.d.ts +1 -1
  242. package/dist/security/index.js +161 -2235
  243. package/dist/security/permission-policy.d.ts +12 -1
  244. package/dist/security/secret-scrubber.d.ts +15 -0
  245. package/dist/session-catalog/index.d.ts +1 -0
  246. package/dist/session-catalog/index.js +41 -2103
  247. package/dist/session-catalog/project-server.js +59 -1435
  248. package/dist/session-catalog/protocol.d.ts +32 -1
  249. package/dist/session-catalog/registry.d.ts +17 -1
  250. package/dist/session-catalog/session-agents.d.ts +56 -0
  251. package/dist/session-catalog/store-rebuild.d.ts +14 -0
  252. package/dist/session-catalog/store-schema.d.ts +26 -0
  253. package/dist/session-catalog/store.d.ts +27 -1
  254. package/dist/session-note-attach.d.ts +9 -0
  255. package/dist/skills/index.js +35 -1578
  256. package/dist/statusline/index.d.ts +43 -0
  257. package/dist/statusline/index.js +102 -0
  258. package/dist/storage/board-store-port.d.ts +2 -2
  259. package/dist/storage/config-loader/in-project-policy.d.ts +29 -0
  260. package/dist/storage/config-loader.d.ts +3 -2
  261. package/dist/storage/file-session-writer.d.ts +4 -2
  262. package/dist/storage/goal-coordination.d.ts +6 -1
  263. package/dist/storage/goal-kanban.d.ts +4 -1
  264. package/dist/storage/index.d.ts +12 -4
  265. package/dist/storage/index.js +198 -15601
  266. package/dist/storage/input-history-store.d.ts +2 -4
  267. package/dist/storage/memory-curator.d.ts +133 -0
  268. package/dist/storage/session-agent-attribution.d.ts +39 -0
  269. package/dist/storage/session-doctor.d.ts +109 -0
  270. package/dist/storage/session-event-bridge.d.ts +5 -7
  271. package/dist/storage/session-outcome.d.ts +42 -0
  272. package/dist/storage/session-recovery.d.ts +55 -0
  273. package/dist/storage/session-store/load-session-data.d.ts +11 -0
  274. package/dist/storage/session-store/prune-helpers.d.ts +1 -1
  275. package/dist/storage/session-store/resume-session.d.ts +0 -2
  276. package/dist/storage/session-store/types.d.ts +8 -0
  277. package/dist/storage/session-store.d.ts +3 -3
  278. package/dist/storage/session-summary-tracker.d.ts +8 -1
  279. package/dist/storage/session-write-buffer.d.ts +18 -0
  280. package/dist/storage/session-writer-truncate.d.ts +2 -0
  281. package/dist/tasking/index.js +10 -676
  282. package/dist/tools/fallback-manage-tools.d.ts +6 -4
  283. package/dist/tools/index.js +52 -9590
  284. package/dist/tools/model-tier-set-tool.d.ts +66 -0
  285. package/dist/types/agent-bridge.d.ts +2 -1
  286. package/dist/types/config/autonomy.d.ts +5 -0
  287. package/dist/types/config/mcp-features.d.ts +7 -0
  288. package/dist/types/config/model-tiers.d.ts +148 -0
  289. package/dist/types/config/root.d.ts +9 -0
  290. package/dist/types/config/tools.d.ts +73 -0
  291. package/dist/types/config/ui.d.ts +1 -1
  292. package/dist/types/config.d.ts +1 -0
  293. package/dist/types/context.d.ts +2 -0
  294. package/dist/types/default-config.d.ts +6 -0
  295. package/dist/types/errors.d.ts +20 -1
  296. package/dist/types/index.d.ts +11 -9
  297. package/dist/types/index.js +131 -1342
  298. package/dist/types/multi-agent.d.ts +43 -0
  299. package/dist/types/plugin.d.ts +1 -1
  300. package/dist/types/provider-runner.d.ts +8 -0
  301. package/dist/types/provider.d.ts +15 -0
  302. package/dist/types/runtime-capability-manifest.d.ts +1 -1
  303. package/dist/types/secret-scrubber.d.ts +15 -0
  304. package/dist/types/session-markers.d.ts +37 -10
  305. package/dist/types/session-markers.js +8 -144
  306. package/dist/types/session-timeline.d.ts +197 -0
  307. package/dist/types/session-timeline.js +12 -0
  308. package/dist/types/session.d.ts +172 -11
  309. package/dist/types/system-prompt.d.ts +27 -0
  310. package/dist/utils/config-backup.d.ts +9 -1
  311. package/dist/utils/error.js +3 -4
  312. package/dist/utils/expect-defined.js +3 -9
  313. package/dist/utils/heap-watchdog.js +6 -706
  314. package/dist/utils/index.js +271 -5685
  315. package/dist/utils/message-invariants.d.ts +4 -1
  316. package/dist/utils/regex-guard.d.ts +1 -1
  317. package/dist/utils/sage-output-block.js +5 -42
  318. package/dist/utils/socket-path.d.ts +1 -1
  319. package/dist/utils/token-estimate.d.ts +6 -2
  320. package/dist/utils/wstack-paths.d.ts +2 -0
  321. package/dist/wiring/proxy-rewrite.d.ts +46 -0
  322. package/dist/wiring/proxy-rewrite.js +24 -121
  323. package/dist/worktree/index.js +6 -887
  324. package/instructions/agents/explore-companion.md +45 -18
  325. package/instructions/agents/memory-curator.md +34 -22
  326. package/instructions/coordination/director-preamble.md +12 -7
  327. package/instructions/coordination/subagent-baseline.md +26 -5
  328. package/instructions/leader-after-task.md +4 -1
  329. package/instructions/llm/chimera-review.md +30 -9
  330. package/instructions/llm/memory-curator.md +31 -0
  331. package/instructions/sections/tool/delegation-compact.md +2 -0
  332. package/instructions/sections/tool/delegation-full.md +5 -1
  333. package/instructions/sections/tool/mailbox-compact.md +5 -1
  334. package/instructions/sections/tool/mailbox-full.md +3 -0
  335. package/instructions/sections/tool/session-note-compact.md +3 -0
  336. package/instructions/sections/tool/session-note-full.md +15 -0
  337. package/instructions/system-lite.md +9 -4
  338. package/instructions/system-pro.md +66 -143
  339. package/instructions/system.md +73 -175
  340. package/package.json +32 -4
  341. package/dist/coordination/agents.d.ts +0 -8
  342. package/dist/coordination/transport.d.ts +0 -2
  343. package/dist/storage/session-writer/session-writer-summary-tracker.d.ts +0 -28
@@ -64,12 +64,5 @@ export interface ModelRuntimeMiddlewareOptions {
64
64
  /** Optional sink for suppressed-setting warnings (e.g. emit to event bus). */
65
65
  onWarning?: ((message: string) => void) | undefined;
66
66
  }
67
- /**
68
- * Build a `request`-pipeline middleware that applies runtime settings. The
69
- * returned function mutates the outgoing request by overlaying resolved
70
- * `reasoning` / `cache` fields and generic parameters. Existing fields on
71
- * the request are preserved only when the resolver produces nothing for
72
- * that field.
73
- */
74
67
  export declare function applyModelRuntime(req: Request, opts: ModelRuntimeMiddlewareOptions): Request;
75
68
  //# sourceMappingURL=model-runtime.d.ts.map
@@ -1,11 +1,11 @@
1
- import type { Agent } from '../core/agent.js';
2
1
  import type { AgentFactory } from '../coordination/agent-subagent-runner.js';
3
2
  import type { DispatchClassifier } from '../coordination/dispatcher.js';
3
+ import { DefaultMultiAgentCoordinator } from '../coordination/multi-agent-coordinator.js';
4
+ import type { Agent } from '../core/agent.js';
4
5
  import type { EventBus } from '../kernel/events.js';
5
- import type { Logger } from '../types/logger.js';
6
6
  import type { JournalEntry } from '../storage/goal-store.js';
7
7
  import type { Compactor } from '../types/compactor.js';
8
- import { DefaultMultiAgentCoordinator } from '../coordination/multi-agent-coordinator.js';
8
+ import type { Logger } from '../types/logger.js';
9
9
  export type ParallelEngineState = 'idle' | 'running' | 'stopped';
10
10
  export type ParallelIterationStage = {
11
11
  phase: 'idle';
@@ -50,12 +50,12 @@ export interface ParallelEternalOptions {
50
50
  parallelSlots?: number | undefined;
51
51
  /** Per-subagent default timeout in ms. Default: 300_000 (5 min). */
52
52
  iterationTimeoutMs?: number | undefined;
53
- onIteration?: (((entry: JournalEntry) => void)) | undefined;
53
+ onIteration?: ((entry: JournalEntry) => void) | undefined;
54
54
  onError?: (err: Error | undefined, iteration: number) => void;
55
55
  /** Per-tick phase notifications for live UI/status updates. */
56
- onStage?: (((stage: ParallelIterationStage) => void)) | undefined;
57
- gitStatusReader?: ((() => Promise<string>)) | undefined;
58
- now?: ((() => Date)) | undefined;
56
+ onStage?: ((stage: ParallelIterationStage) => void) | undefined;
57
+ gitStatusReader?: (() => Promise<string>) | undefined;
58
+ now?: (() => Date) | undefined;
59
59
  compactor?: Compactor | undefined;
60
60
  compactEveryNIterations?: number | undefined;
61
61
  aggressiveCompactRatio?: number | undefined;
@@ -1,538 +1,19 @@
1
- // src/types/blocks.ts
2
- function isTextBlock(b) {
3
- return b.type === "text";
4
- }
5
-
6
- // src/utils/error.ts
7
- function toErrorMessage(err) {
8
- return err instanceof Error ? err.message : String(err);
9
- }
10
-
11
- // src/utils/instruction-file.ts
12
- import { readFileSync, statSync } from "node:fs";
13
- import * as path from "node:path";
14
- import { fileURLToPath } from "node:url";
15
- var textCache = /* @__PURE__ */ new Map();
16
- var rootCandidates;
17
- function readBundledInstructionText(relativePath) {
18
- const cached = textCache.get(relativePath);
19
- if (cached !== void 0) return cached;
20
- let resolved = "";
21
- for (const root of instructionRootCandidates()) {
22
- try {
23
- resolved = readFileSync(path.join(root, relativePath), "utf8").trimEnd();
24
- break;
25
- } catch {
26
- }
27
- }
28
- textCache.set(relativePath, resolved);
29
- return resolved;
30
- }
31
- function instructionRootCandidates() {
32
- if (rootCandidates !== void 0) return rootCandidates;
33
- const here = path.dirname(fileURLToPath(import.meta.url));
34
- const candidates = [
35
- path.resolve(here, "../../instructions"),
36
- path.resolve(here, "../instructions"),
37
- path.resolve(here, "instructions")
38
- ];
39
- rootCandidates = candidates.sort((a, b) => Number(!isDirectory(a)) - Number(!isDirectory(b)));
40
- return rootCandidates;
41
- }
42
- function isDirectory(candidate) {
43
- try {
44
- return statSync(candidate).isDirectory();
45
- } catch {
46
- return false;
47
- }
48
- }
49
-
50
- // src/execution/prompt-enhancer.ts
51
- var ENHANCER_SYSTEM_PROMPT = readBundledInstructionText("llm/prompt-enhancer.md");
52
- var AFFIRMATION_RE = /^(y|n|yes|no|yep|nope|ok|okay|sure|go|go ahead|continue|proceed|stop|cancel|done|next|skip|retry|again|please do|do it)\b[.! ]*$/i;
53
- function shouldEnhance(text) {
54
- const t = text.trim();
55
- if (!t) return false;
56
- if (t.startsWith("/")) return false;
57
- if (t.length < 12) return false;
58
- if (AFFIRMATION_RE.test(t)) return false;
59
- if (/^[\d\s.,]+$/.test(t)) return false;
60
- const words = t.split(/\s+/).filter(Boolean);
61
- if (words.length < 3) return false;
62
- return true;
63
- }
64
- var EFFORT_PREFERENCE = [
65
- "low",
66
- "minimal",
67
- "medium",
68
- "high",
69
- "xhigh",
70
- "max",
71
- "none"
72
- ];
73
- function gatedEnhancerReasoning(rc) {
74
- if (!rc) return void 0;
75
- if (rc.effortSupported && rc.effortLevels.length > 0) {
76
- const lowest = EFFORT_PREFERENCE.find((e) => rc.effortLevels.includes(e)) ?? rc.effortLevels[0];
77
- if (lowest) return { effort: lowest };
78
- }
79
- if (rc.disableSupported) return { enabled: false };
80
- return void 0;
81
- }
82
- function normalizedEqual(a, b) {
83
- const norm = (s) => s.trim().replace(/\s+/g, " ").toLowerCase();
84
- return norm(a) === norm(b);
85
- }
86
- var ENGLISH_PROMPT_WORDS = /* @__PURE__ */ new Set([
87
- "a",
88
- "add",
89
- "analyze",
90
- "and",
91
- "api",
92
- "as",
93
- "build",
94
- "change",
95
- "check",
96
- "code",
97
- "configure",
98
- "create",
99
- "delete",
100
- "document",
101
- "ensure",
102
- "error",
103
- "explain",
104
- "failure",
105
- "feature",
106
- "file",
107
- "fix",
108
- "for",
109
- "from",
110
- "function",
111
- "implement",
112
- "improve",
113
- "in",
114
- "into",
115
- "is",
116
- "issue",
117
- "it",
118
- "keep",
119
- "make",
120
- "model",
121
- "of",
122
- "only",
123
- "output",
124
- "parser",
125
- "preserve",
126
- "prompt",
127
- "race",
128
- "refactor",
129
- "remove",
130
- "request",
131
- "resolve",
132
- "response",
133
- "return",
134
- "run",
135
- "should",
136
- "test",
137
- "that",
138
- "the",
139
- "this",
140
- "to",
141
- "translate",
142
- "update",
143
- "use",
144
- "validate",
145
- "version",
146
- "when",
147
- "with",
148
- "write",
149
- "condition"
150
- ]);
151
- var NON_ENGLISH_PROMPT_WORDS = /* @__PURE__ */ new Set([
152
- // Turkish
153
- "ama",
154
- "bir",
155
- "bu",
156
- "de",
157
- "d\xFCzelt",
158
- "et",
159
- "hata",
160
- "hatas\u0131n\u0131",
161
- "hatay\u0131",
162
- "i\xE7in",
163
- "ile",
164
- "olarak",
165
- "sadece",
166
- "ve",
167
- "yap",
168
- "\u015Fu",
169
- // Spanish / Portuguese
170
- "con",
171
- "corrige",
172
- "debe",
173
- "el",
174
- "en",
175
- "erro",
176
- "la",
177
- "para",
178
- "que",
179
- "sin",
180
- "una",
181
- // French
182
- "avec",
183
- "dans",
184
- "des",
185
- "doit",
186
- "erreur",
187
- "et",
188
- "le",
189
- "les",
190
- "pour",
191
- "sans",
192
- "une",
193
- // German
194
- "das",
195
- "den",
196
- "der",
197
- "die",
198
- "ein",
199
- "fehler",
200
- "f\xFCr",
201
- "mit",
202
- "ohne",
203
- "und"
204
- ]);
205
- function languageWords(text) {
206
- return text.replaceAll("\u0130", "i").toLowerCase().match(/\p{L}+/gu) ?? [];
207
- }
208
- function hasNonLatinScript(text) {
209
- return /[\p{Script=Arabic}\p{Script=Cyrillic}\p{Script=Han}\p{Script=Hangul}\p{Script=Hiragana}\p{Script=Katakana}]/u.test(
210
- text
211
- );
212
- }
213
- function languageScores(text) {
214
- const words = languageWords(text);
215
- let english = 0;
216
- let nonEnglish = 0;
217
- for (const word of words) {
218
- if (ENGLISH_PROMPT_WORDS.has(word)) english++;
219
- if (NON_ENGLISH_PROMPT_WORDS.has(word)) nonEnglish++;
220
- }
221
- if (/[çğıöşüİı]/u.test(text)) nonEnglish += 2;
222
- if (hasNonLatinScript(text)) nonEnglish += 3;
223
- return { english, nonEnglish, words };
224
- }
225
- function isValidEnglishRefinement(text) {
226
- const trimmed = text.trim();
227
- if (!trimmed) return false;
228
- const scores = languageScores(trimmed);
229
- return scores.nonEnglish === 0 && scores.english > 0;
230
- }
231
- var VIBE_TAG_PATTERN = /\[vibe\]/iu;
232
- function preserveVibeTag(original, candidate) {
233
- if (!VIBE_TAG_PATTERN.test(original) || VIBE_TAG_PATTERN.test(candidate)) return candidate;
234
- return `[VIBE] ${candidate}`;
235
- }
236
- function latestMessageLanguage(text) {
237
- const scores = languageScores(text);
238
- if (scores.nonEnglish > scores.english) return "non_english";
239
- if (scores.english > scores.nonEnglish) return "english";
240
- return "unknown";
241
- }
242
- function parseBilingualEnhancement(raw, original) {
243
- const separator = /^[\t \u00a0\u200b-\u200d\ufeff]*---[\t \u00a0\u200b-\u200d\ufeff]*\r?$/gm;
244
- const matches = [...raw.matchAll(separator)];
245
- if (matches.length !== 1) return null;
246
- const [match] = matches;
247
- if (!match) return null;
248
- const rawRefined = raw.slice(0, match.index).trim();
249
- const rawEnglish = raw.slice(match.index + match[0].length).trim();
250
- if (!rawRefined || !rawEnglish) return null;
251
- const refined = preserveVibeTag(original, rawRefined);
252
- const english = preserveVibeTag(original, rawEnglish);
253
- if (!isValidEnglishRefinement(english)) return null;
254
- const inputLanguage = latestMessageLanguage(original);
255
- const refinedLanguage = latestMessageLanguage(refined);
256
- if (inputLanguage === "non_english" && refinedLanguage === "english") return null;
257
- if (inputLanguage === "unknown" && refinedLanguage === "unknown") return null;
258
- return { refined, english };
259
- }
260
- var DEFAULT_REFINER_RETRY_FEEDBACK = "Make another pass that is sharper and more self-contained. Use the provided project memory, current session context, and recent conversation only to resolve references and preserve project vocabulary; keep the original scope unchanged.";
261
- function buildRefinerInput(text, history, contextSections, previousRefinement, retryFeedback) {
262
- const parts = [];
263
- const renderedContext = renderRefinerContextSections(contextSections);
264
- if (renderedContext) parts.push(renderedContext);
265
- if (previousRefinement || retryFeedback) {
266
- const retryLines = [
267
- "Retry context (context only - the user asked for another refinement pass):"
268
- ];
269
- if (previousRefinement?.refined) {
270
- retryLines.push(`Previous refined version: ${compactText(previousRefinement.refined, 900)}`);
271
- }
272
- if (previousRefinement?.english && previousRefinement.english.trim() !== previousRefinement.refined.trim()) {
273
- retryLines.push(`Previous English version: ${compactText(previousRefinement.english, 900)}`);
274
- }
275
- retryLines.push(`Retry instruction: ${retryFeedback ?? DEFAULT_REFINER_RETRY_FEEDBACK}`);
276
- parts.push(retryLines.join("\n"));
277
- }
278
- if (history && history.length > 0) {
279
- const lines = history.map((t) => `${t.role === "user" ? "User" : "Assistant"}: ${t.text}`);
280
- parts.push(
281
- [
282
- "Recent conversation (context only - do not act on it):",
283
- ...lines
284
- ].join("\n")
285
- );
286
- }
287
- if (parts.length === 0) return text;
288
- return [
289
- ...parts,
290
- "",
291
- "Latest message to refine:",
292
- text
293
- ].join("\n\n");
294
- }
295
- function renderRefinerContextSections(contextSections) {
296
- const sections = (contextSections ?? []).map((section) => ({
297
- title: section.title.trim(),
298
- items: section.items.map((item) => compactText(item, 360)).filter(Boolean)
299
- })).filter((section) => section.title && section.items.length > 0);
300
- if (sections.length === 0) return void 0;
301
- const lines = [
302
- "Additional project/session context (context only - use to resolve references, conventions, and constraints; do not add new requirements):"
303
- ];
304
- for (const section of sections) {
305
- lines.push("", `${section.title}:`);
306
- for (const item of section.items) lines.push(`- ${item}`);
307
- }
308
- return lines.join("\n");
309
- }
310
- function compactText(text, maxChars) {
311
- const compacted = text.replace(/\s+/g, " ").trim();
312
- if (compacted.length <= maxChars) return compacted;
313
- return `${compacted.slice(0, Math.max(0, maxChars - 3)).trimEnd()}...`;
314
- }
315
- function unknownString(value) {
316
- return typeof value === "string" && value.trim() ? value.trim() : void 0;
317
- }
318
- function iterableStrings(value) {
319
- if (!value || typeof value === "string") return [];
320
- if (Array.isArray(value)) {
321
- return value.flatMap((item) => {
322
- const text = unknownString(item);
323
- return text ? [text] : [];
324
- });
325
- }
326
- if (value instanceof Set) {
327
- return [...value].flatMap((item) => {
328
- const text = unknownString(item);
329
- return text ? [text] : [];
330
- });
331
- }
332
- if (typeof value === "object" && typeof value[Symbol.iterator] === "function") {
333
- try {
334
- return Array.from(value).flatMap((item) => {
335
- const text = unknownString(item);
336
- return text ? [text] : [];
337
- });
338
- } catch {
339
- return [];
340
- }
341
- }
342
- return [];
343
- }
344
- function lastItems(values, maxItems) {
345
- return values.slice(Math.max(0, values.length - maxItems));
346
- }
347
- function todoLines(value, maxItems) {
348
- if (!Array.isArray(value)) return [];
349
- const open = value.filter((item) => {
350
- if (!item || typeof item !== "object") return false;
351
- const status = item["status"];
352
- return status === "pending" || status === "in_progress";
353
- });
354
- return open.slice(0, maxItems).flatMap((todo) => {
355
- const content = unknownString(todo["activeForm"]) ?? unknownString(todo["content"]);
356
- if (!content) return [];
357
- return [`open todo (${String(todo["status"])}): ${compactText(content, 220)}`];
358
- });
359
- }
360
- function buildRefinerSessionContextSection(context) {
361
- if (!context) return void 0;
362
- const items = [];
363
- const projectRoot = unknownString(context.projectRoot);
364
- const workingDir = unknownString(context.workingDir) ?? unknownString(context.cwd);
365
- if (projectRoot) items.push(`project root: ${projectRoot}`);
366
- if (workingDir && workingDir !== projectRoot) items.push(`working dir: ${workingDir}`);
367
- for (const file of lastItems(iterableStrings(context.readFiles), 6)) {
368
- items.push(`recently read file: ${file}`);
369
- }
370
- for (const file of lastItems(iterableStrings(context.writtenFiles), 6)) {
371
- items.push(`recently written file: ${file}`);
372
- }
373
- items.push(...todoLines(context.todos, 6));
374
- return items.length > 0 ? { title: "Current session state", items } : void 0;
375
- }
376
- function formatMemoryEntry(entry) {
377
- const meta = [entry.scope, entry.type, entry.priority].filter(Boolean).join("/");
378
- const tags = entry.tags && entry.tags.length > 0 ? ` tags: ${entry.tags.slice(0, 5).join(", ")}` : "";
379
- return `${meta ? `[${meta}] ` : ""}${compactText(entry.text, 260)}${tags}`;
380
- }
381
- async function collectMemoryEntries(memoryStore, text, scope, limit) {
382
- const scored = memoryStore.scoreRelevant ? await memoryStore.scoreRelevant({ currentTask: text }, scope, limit).catch(() => []) : [];
383
- if (scored.length > 0) return scored;
384
- return memoryStore.search(text || "prompt refinement", scope, limit).catch(() => []);
385
- }
386
- async function buildRefinerMemoryContextSection(memoryStore, text) {
387
- if (!memoryStore) return void 0;
388
- const seen = /* @__PURE__ */ new Set();
389
- const entries = [];
390
- for (const scope of ["project-memory", "user-memory"]) {
391
- const remaining = Math.max(0, 6 - entries.length);
392
- if (remaining === 0) break;
393
- for (const entry of await collectMemoryEntries(memoryStore, text.trim(), scope, remaining)) {
394
- const key = `${entry.scope}:${entry.text}`;
395
- if (seen.has(key)) continue;
396
- seen.add(key);
397
- entries.push(entry);
398
- if (entries.length >= 6) break;
399
- }
400
- }
401
- if (entries.length === 0) return void 0;
402
- return { title: "Relevant project memory", items: entries.map(formatMemoryEntry) };
403
- }
404
- async function buildRefinerContextSections(opts) {
405
- const sections = [];
406
- const memory = await buildRefinerMemoryContextSection(opts.memoryStore, opts.text);
407
- if (memory) sections.push(memory);
408
- const session = buildRefinerSessionContextSection(opts.context);
409
- if (session) sections.push(session);
410
- return sections;
411
- }
412
- async function completeRefinerPass(input, opts) {
413
- if (opts.oneShotOrchestrator) {
414
- const result = await opts.oneShotOrchestrator.call({
415
- system: ENHANCER_SYSTEM_PROMPT,
416
- messages: [{ role: "user", content: input }],
417
- maxTokens: opts.request.maxTokens,
418
- timeoutMs: opts.timeoutMs,
419
- signal: opts.signal
420
- });
421
- return result.error ? { text: "", error: result.error } : { text: result.text.trim() };
422
- }
423
- const response = await opts.provider.complete(
424
- { ...opts.request, messages: [{ role: "user", content: input }] },
425
- { signal: opts.signal }
426
- );
427
- return {
428
- text: response.content.filter(isTextBlock).map((block) => block.text).join("\n").trim()
429
- };
430
- }
431
- async function enhanceUserPrompt(opts) {
432
- const { provider, model, text } = opts;
433
- const timeoutMs = opts.timeoutMs ?? 9e4;
434
- const maxTokens = opts.maxTokens ?? 2048;
435
- const refinerInput = buildRefinerInput(
436
- text,
437
- opts.history,
438
- opts.contextSections,
439
- opts.previousRefinement,
440
- opts.retryFeedback
441
- );
442
- const req = {
443
- model,
444
- system: [{ type: "text", text: ENHANCER_SYSTEM_PROMPT }],
445
- messages: [{ role: "user", content: refinerInput }],
446
- maxTokens,
447
- // NOTE: deliberately NO `temperature`. The main agent loop never sets it,
448
- // and reasoning models (DeepSeek reasoner, o1/o3, …) return HTTP 400 when
449
- // `temperature` is present — which would make every refine call fail and
450
- // silently fall back to the original (no panel shown).
451
- //
452
- // A reasoning hint is forwarded ONLY when the caller supplies one (it must
453
- // already be gated to the model's advertised support — see
454
- // `gatedEnhancerReasoning`). Absent it, no reasoning field is sent, which
455
- // is identical to the original behavior.
456
- ...opts.reasoning ? { reasoning: opts.reasoning } : {}
457
- };
458
- let timedOut = false;
459
- const runPass = async (input) => {
460
- const timer = new AbortController();
461
- const timeout = setTimeout(() => timer.abort(new Error("enhancer timeout")), timeoutMs);
462
- const signal = opts.signal ? AbortSignal.any([opts.signal, timer.signal]) : timer.signal;
463
- try {
464
- return await completeRefinerPass(input, {
465
- provider,
466
- oneShotOrchestrator: opts.oneShotOrchestrator,
467
- request: req,
468
- signal,
469
- timeoutMs
470
- });
471
- } catch (error) {
472
- if (timer.signal.aborted && !opts.signal?.aborted) timedOut = true;
473
- throw error;
474
- } finally {
475
- timer.abort();
476
- clearTimeout(timeout);
477
- }
478
- };
479
- try {
480
- const first = await runPass(refinerInput);
481
- if (first.error) {
482
- opts.onError?.(first.error, "provider_error");
483
- return null;
484
- }
485
- const parsed = parseBilingualEnhancement(first.text, text);
486
- if (parsed) return parsed;
487
- const correctionInput = [
488
- "Your previous response did not satisfy the required bilingual output contract.",
489
- 'Return exactly two non-empty versions separated by one line containing only "---".',
490
- "The first version must match the language of the latest message. The second version must be English.",
491
- "Do not add labels, headings, fences, commentary, or additional separators.",
492
- "",
493
- `Latest message to refine:
494
- ${text}`,
495
- "",
496
- `Invalid previous response:
497
- ${compactText(first.text || "(empty response)", 1800)}`
498
- ].join("\n");
499
- const corrected = await runPass(correctionInput);
500
- if (corrected.error) {
501
- opts.onError?.(corrected.error, "provider_error");
502
- return null;
503
- }
504
- const correctedParsed = parseBilingualEnhancement(corrected.text, text);
505
- if (correctedParsed) return correctedParsed;
506
- opts.onError?.("model returned malformed bilingual output after one corrective retry", "empty");
507
- return null;
508
- } catch (err) {
509
- if (opts.signal?.aborted) return null;
510
- if (timedOut) {
511
- opts.onError?.(`timed out after ${Math.round(timeoutMs / 1e3)}s`, "timeout");
512
- return null;
513
- }
514
- opts.onError?.(toErrorMessage(err), "provider_error");
515
- return null;
516
- }
517
- }
518
- function messageText(content) {
519
- if (typeof content === "string") return content;
520
- return content.filter(isTextBlock).map((b) => b.text).join("\n").trim();
521
- }
522
- function recentTextTurns(messages, maxTurns = 6, maxChars = 1500) {
523
- const turns = [];
524
- for (let i = messages.length - 1; i >= 0 && turns.length < maxTurns; i--) {
525
- const m = messages[i];
526
- if (!m || m.role !== "user" && m.role !== "assistant") continue;
527
- const text = messageText(m.content);
528
- if (!text) continue;
529
- turns.unshift({
530
- role: m.role,
531
- text: text.length > maxChars ? `${text.slice(0, maxChars - 1)}\u2026` : text
532
- });
533
- }
534
- return turns;
535
- }
1
+ import {
2
+ DEFAULT_REFINER_RETRY_FEEDBACK,
3
+ ENHANCER_SYSTEM_PROMPT,
4
+ buildRefinerContextSections,
5
+ completeRefinerPass,
6
+ enhanceUserPrompt,
7
+ gatedEnhancerReasoning,
8
+ isValidEnglishRefinement,
9
+ normalizedEqual,
10
+ parseBilingualEnhancement,
11
+ recentTextTurns,
12
+ shouldEnhance
13
+ } from "../chunk-5XDUGTKN.js";
14
+ import "../chunk-5S437PRC.js";
15
+ import "../chunk-O37BQ65S.js";
16
+ import "../chunk-TBRL2RCC.js";
536
17
  export {
537
18
  DEFAULT_REFINER_RETRY_FEEDBACK,
538
19
  ENHANCER_SYSTEM_PROMPT,
@@ -27,6 +27,35 @@ import type { RetryPolicy } from '../types/retry-policy.js';
27
27
  * kind IS fallback-worthy, so another provider gets tried immediately.
28
28
  */
29
29
  export declare const MODEL_RETRIES = 3;
30
+ /**
31
+ * First-retry wait for the exponential schedule, in ms.
32
+ *
33
+ * The schedule is `RETRY_BASE_DELAY_MS * 2^attempt + jitter`, so with a
34
+ * base of 4s and {@link MODEL_RETRIES} attempts a struggling route waits
35
+ * 4s → 8s → 16s before the turn hands over to the fallback chain.
36
+ *
37
+ * It used to be 1000 (1s → 2s → 4s). That schedule was too eager for the
38
+ * failure it actually fires on: a provider that just refused a request
39
+ * because of a network blip, an overload, or a burst-rate window is
40
+ * almost never healthy again 1 second later, so the first two retries
41
+ * mostly bought another two failures — three requests hammered out inside
42
+ * ~7 seconds — and then reported the same error anyway. Starting at 4s
43
+ * gives the far side a realistic window to recover, and still exhausts
44
+ * all three in-place attempts in well under half a minute.
45
+ *
46
+ * NOTE: this is only the *fallback* schedule. A provider that sends a
47
+ * `Retry-After` still wins outright (see {@link DefaultRetryPolicy.delayMs}).
48
+ */
49
+ export declare const RETRY_BASE_DELAY_MS = 4000;
50
+ /**
51
+ * Width of the uniform jitter added to every exponential wait, in ms.
52
+ *
53
+ * Deliberately decoupled from {@link RETRY_BASE_DELAY_MS}: jitter exists to
54
+ * de-synchronise concurrent agents retrying the same route, and one second
55
+ * of spread is plenty for that. Scaling it with the base would have turned
56
+ * the first retry into a 4–8s coin flip for no added benefit.
57
+ */
58
+ export declare const RETRY_JITTER_MS = 1000;
30
59
  export declare class DefaultRetryPolicy implements RetryPolicy {
31
60
  shouldRetry(err: Error | ProviderError, attempt: number): boolean;
32
61
  maxAttempts(err: Error | ProviderError): number;
@@ -39,7 +68,8 @@ export declare class DefaultRetryPolicy implements RetryPolicy {
39
68
  * [0, MAX_RETRY_AFTER_MS]. The provider told us exactly when
40
69
  * to come back; we should listen.
41
70
  * 2. Otherwise fall through to the exponential-with-jitter
42
- * schedule (`1000 * 2^attempt + jitter`, capped at 30s).
71
+ * schedule (`RETRY_BASE_DELAY_MS * 2^attempt + jitter`, capped
72
+ * at 30s) — 4s → 8s → 16s for the three in-place attempts.
43
73
  *
44
74
  * `err` is optional for back-compat with the existing interface;
45
75
  * callers should pass it whenever available.