@code-yeongyu/senpi 2026.11.2-3 → 2026.11.3-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 (307) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/dist/bundle/chunks/anthropic-messages-LJAKRKMX.js +11 -0
  3. package/dist/bundle/chunks/{args-AOI4NEA6.js → args-GQTXDYS3.js} +1 -1
  4. package/dist/bundle/chunks/{azure-openai-responses-YLBBQXI7.js → azure-openai-responses-HDEKTPMZ.js} +1 -1
  5. package/dist/bundle/chunks/chatgpt-subscription.js +10 -2
  6. package/dist/bundle/chunks/{chunk-ED7VJGL4.js → chunk-2PGSRQBF.js} +1 -1
  7. package/dist/bundle/chunks/{chunk-LMIETUPG.js → chunk-3LDASCJN.js} +1 -1
  8. package/dist/bundle/chunks/{chunk-PIAY636U.js → chunk-3QPE75AR.js} +1 -1
  9. package/dist/bundle/chunks/{chunk-FQZZGSYH.js → chunk-4ZGQUOBV.js} +1 -1
  10. package/dist/bundle/chunks/{chunk-S2M5D5GS.js → chunk-5BMIET5O.js} +2 -2
  11. package/dist/bundle/chunks/{chunk-XLLQJALL.js → chunk-67M7HKXO.js} +1 -1
  12. package/dist/bundle/chunks/chunk-6ISOXWH2.js +2 -0
  13. package/dist/bundle/chunks/{chunk-IWM5QRAE.js → chunk-6NPK2O3C.js} +2 -2
  14. package/dist/bundle/chunks/{chunk-FO56LSUK.js → chunk-7C4W5HMU.js} +1 -1
  15. package/dist/bundle/chunks/chunk-7KIHKE2T.js +2 -0
  16. package/dist/bundle/chunks/{chunk-BW4YXS7X.js → chunk-A4KOQUHT.js} +1 -1
  17. package/dist/bundle/chunks/{chunk-FJSJUVQQ.js → chunk-A5PZGQCP.js} +3 -3
  18. package/dist/bundle/chunks/{chunk-TBARMJ75.js → chunk-AVP6DDBF.js} +1 -1
  19. package/dist/bundle/chunks/{chunk-KVPRQ5KN.js → chunk-B3GTID4P.js} +1 -1
  20. package/dist/bundle/chunks/{chunk-2XBKE2BZ.js → chunk-BIWFWGUA.js} +1 -1
  21. package/dist/bundle/chunks/{chunk-6LDUM5CL.js → chunk-DCI4QOUX.js} +1 -1
  22. package/dist/bundle/chunks/{chunk-2YFPDNNP.js → chunk-DNZKKG4V.js} +1 -1
  23. package/dist/bundle/chunks/{chunk-W2V7RIBF.js → chunk-E7SA75PP.js} +1 -1
  24. package/dist/bundle/chunks/{chunk-YWD54RHU.js → chunk-EBZ6IP4V.js} +1 -1
  25. package/dist/bundle/chunks/{chunk-N4TSAHRL.js → chunk-EVTTLPIY.js} +1 -1
  26. package/dist/bundle/chunks/{chunk-J2OBN7TI.js → chunk-G5XUGK4B.js} +1 -1
  27. package/dist/bundle/chunks/{chunk-IHOQR7TU.js → chunk-GKP34H3C.js} +2 -2
  28. package/dist/bundle/chunks/{chunk-PP52OWBB.js → chunk-GLTOBXZY.js} +1 -1
  29. package/dist/bundle/chunks/{chunk-ZSVWKOAJ.js → chunk-IJGXAACA.js} +263 -237
  30. package/dist/bundle/chunks/{chunk-LGO25HPL.js → chunk-JCTODLUP.js} +1 -1
  31. package/dist/bundle/chunks/{chunk-3ESZE3DG.js → chunk-KHBCZ6TR.js} +1 -1
  32. package/dist/bundle/chunks/chunk-KJR3XXMI.js +2 -0
  33. package/dist/bundle/chunks/{chunk-TVMW2SUP.js → chunk-KY4V3TSO.js} +2 -2
  34. package/dist/bundle/chunks/{chunk-T5ZJ2Q4O.js → chunk-MCXOJHN2.js} +1 -1
  35. package/dist/bundle/chunks/{chunk-GIY7PGOH.js → chunk-NKI7L5UM.js} +3 -3
  36. package/dist/bundle/chunks/{chunk-L3V65XW7.js → chunk-OD7RT7G7.js} +1 -1
  37. package/dist/bundle/chunks/{chunk-NYXXKS6D.js → chunk-OOU3BRUY.js} +3 -2
  38. package/dist/bundle/chunks/{chunk-LPHUMR6R.js → chunk-OT6ALXSJ.js} +1 -1
  39. package/dist/bundle/chunks/{chunk-XGBRBCIQ.js → chunk-Q5CKFBQT.js} +1 -1
  40. package/dist/bundle/chunks/{chunk-F7GBSQRV.js → chunk-QPYDQ4QK.js} +1 -1
  41. package/dist/bundle/chunks/{chunk-7FUO655J.js → chunk-QSMT5KVJ.js} +1 -1
  42. package/dist/bundle/chunks/{chunk-SAZ6E74O.js → chunk-RUOTFZQR.js} +1 -1
  43. package/dist/bundle/chunks/chunk-RWF6IJQL.js +448 -0
  44. package/dist/bundle/chunks/{chunk-P4AT7SBE.js → chunk-S5Y7NEHB.js} +1 -1
  45. package/dist/bundle/chunks/{chunk-QLTQ3UUI.js → chunk-SCBTASM4.js} +1 -1
  46. package/dist/bundle/chunks/chunk-SJWTZ3Z2.js +2 -0
  47. package/dist/bundle/chunks/{chunk-ISZ4EWIS.js → chunk-SODMQEHO.js} +1 -1
  48. package/dist/bundle/chunks/{chunk-WEGTCUO3.js → chunk-SQAQEITV.js} +1 -1
  49. package/dist/bundle/chunks/{chunk-UFVZTQKN.js → chunk-TQQG5L4D.js} +1 -1
  50. package/dist/bundle/chunks/{chunk-662SCMTH.js → chunk-U6A4X3FV.js} +1 -1
  51. package/dist/bundle/chunks/{chunk-ACIFXWJ6.js → chunk-UHUM55TR.js} +1 -1
  52. package/dist/bundle/chunks/{chunk-L5OFGHDA.js → chunk-USKWGPA6.js} +1 -1
  53. package/dist/bundle/chunks/{chunk-7ORS33CE.js → chunk-VDDJADPV.js} +1 -1
  54. package/dist/bundle/chunks/{chunk-R65P6LAT.js → chunk-VIHXG53S.js} +1 -1
  55. package/dist/bundle/chunks/{chunk-SGS76663.js → chunk-VPVD5G32.js} +1 -1
  56. package/dist/bundle/chunks/chunk-WO6I5PRF.js +3 -0
  57. package/dist/bundle/chunks/{chunk-ETCYVVVO.js → chunk-WVEIJ437.js} +1 -1
  58. package/dist/bundle/chunks/{chunk-VRWJJMHO.js → chunk-XKFG4N3Z.js} +1 -1
  59. package/dist/bundle/chunks/{chunk-57MRFI6E.js → chunk-XMWPCJU6.js} +1 -1
  60. package/dist/bundle/chunks/{chunk-GDPWQJDQ.js → chunk-XPSXUKSD.js} +1 -1
  61. package/dist/bundle/chunks/{chunk-FNBEICAA.js → chunk-YI6KRJDC.js} +1 -1
  62. package/dist/bundle/chunks/{chunk-UURGXV5B.js → chunk-YP47G4YP.js} +1 -1
  63. package/dist/bundle/chunks/{chunk-TXOR5BQL.js → chunk-YRYDCKUI.js} +1 -1
  64. package/dist/bundle/chunks/{chunk-QAM6AXA2.js → chunk-YTKZSGMQ.js} +12 -9
  65. package/dist/bundle/chunks/{chunk-V36CXIIB.js → chunk-YXL3PNTL.js} +1 -1
  66. package/dist/bundle/chunks/chunk-Z7HTHT6K.js +2 -0
  67. package/dist/bundle/chunks/{chunk-27XEDYQA.js → chunk-ZTPG27EJ.js} +1 -1
  68. package/dist/bundle/chunks/{cli-main-534A3WSC.js → cli-main-RN7YB427.js} +1 -1
  69. package/dist/bundle/chunks/{cloudflare-workers-ai-system-one-FC7QLRU2.js → cloudflare-workers-ai-system-one-N5KFNKK4.js} +1 -1
  70. package/dist/bundle/chunks/credential-accounts-BJX55MTT.js +2 -0
  71. package/dist/bundle/chunks/devin.js +10 -2
  72. package/dist/bundle/chunks/{dispatch-UY6LBJJE.js → dispatch-M7UAPGVY.js} +1 -1
  73. package/dist/bundle/chunks/{google-generative-ai-7PQ4QRHJ.js → google-generative-ai-2TZSCSIS.js} +1 -1
  74. package/dist/bundle/chunks/{google-vertex-DY7EO4EJ.js → google-vertex-7NJJOI7V.js} +1 -1
  75. package/dist/bundle/chunks/{health-write-EB4CPHXN.js → health-write-YUSPVH7U.js} +1 -1
  76. package/dist/bundle/chunks/{help-fast-path-U2PSNNWO.js → help-fast-path-DWCA77QP.js} +1 -1
  77. package/dist/bundle/chunks/host-command-KJXUTSQ7.js +2 -0
  78. package/dist/bundle/chunks/{host-lifecycle-TGG7KGQH.js → host-lifecycle-QHIJ4G2K.js} +1 -1
  79. package/dist/bundle/chunks/host-lifecycle.js +1 -1
  80. package/dist/bundle/chunks/{host-session-command-PWVPQ2OV.js → host-session-command-IPH3WXSG.js} +1 -1
  81. package/dist/bundle/chunks/{host-socket-request-F2R5P34M.js → host-socket-request-XPXJV3CS.js} +1 -1
  82. package/dist/bundle/chunks/interactive-mode-XUXMDYLA.js +2 -0
  83. package/dist/bundle/chunks/{list-tips-3D3A6GFK.js → list-tips-XJY7EL5S.js} +1 -1
  84. package/dist/bundle/chunks/{login-health-7G2DZVOV.js → login-health-226NO44U.js} +1 -1
  85. package/dist/bundle/chunks/main-P7PKMJUG.js +2 -0
  86. package/dist/bundle/chunks/{mistral-conversations-6F2RAIB2.js → mistral-conversations-QMHMHSUF.js} +1 -1
  87. package/dist/bundle/chunks/{multi-session-host-7E26R5JF.js → multi-session-host-ZQY4AN46.js} +4 -4
  88. package/dist/bundle/chunks/{native-loader-NMDTMHMA.js → native-loader-A6DNMGCK.js} +1 -1
  89. package/dist/bundle/chunks/openai-chatgpt.js +11 -3
  90. package/dist/bundle/chunks/{openai-codex-responses-VNBMMIL3.js → openai-codex-responses-GUAHKQE2.js} +1 -1
  91. package/dist/bundle/chunks/{openai-completions-JLR32APM.js → openai-completions-UPRTFM54.js} +1 -1
  92. package/dist/bundle/chunks/{openai-images-LEBNERSM.js → openai-images-IKWNS6VB.js} +1 -1
  93. package/dist/bundle/chunks/{openai-responses-JCDUNMHA.js → openai-responses-AXN5NUHH.js} +1 -1
  94. package/dist/bundle/chunks/openrouter.js +10 -2
  95. package/dist/bundle/chunks/{package-manager-cli-CBSDV36M.js → package-manager-cli-PP7L2Q5M.js} +1 -1
  96. package/dist/bundle/chunks/radius.js +10 -2
  97. package/dist/bundle/chunks/{rg-engine-JDUYBM6L.js → rg-engine-VRSXT6HG.js} +1 -1
  98. package/dist/bundle/chunks/{role-LP6LVNCY.js → role-L5J7ZPCF.js} +1 -1
  99. package/dist/bundle/chunks/rotation-stream-6INZXQFC.js +2 -0
  100. package/dist/bundle/chunks/rpc-mode-W4UATRAT.js +2 -0
  101. package/dist/bundle/chunks/{rpc-monitor-source-5TUR27NY.js → rpc-monitor-source-RMMUPBMS.js} +1 -1
  102. package/dist/bundle/chunks/{run-attached-tui-PVLUHHJX.js → run-attached-tui-RLXFGCEP.js} +1 -1
  103. package/dist/bundle/chunks/{schedule-command-W45NYTTK.js → schedule-command-ZNFEJNTT.js} +1 -1
  104. package/dist/bundle/chunks/{session-control-endpoint-LFLUNALC.js → session-control-endpoint-TWTONJWF.js} +1 -1
  105. package/dist/bundle/chunks/{session-picker-OZUINLD7.js → session-picker-KRUVCHOV.js} +1 -1
  106. package/dist/bundle/chunks/session-slot-NJOZCOHQ.js +2 -0
  107. package/dist/bundle/chunks/session-worker.js +492 -461
  108. package/dist/bundle/chunks/{state-store-SZARKD36.js → state-store-ZAFZ4JOM.js} +1 -1
  109. package/dist/bundle/chunks/{typesafe-system-one-5JYDJK6S.js → typesafe-system-one-CICIRAYN.js} +1 -1
  110. package/dist/bundle/cli.js +2 -2
  111. package/dist/bundle/host-supervisor.js +1 -1
  112. package/dist/bundle/index.js +1 -1
  113. package/dist/bundle/rpc-entry.js +1 -1
  114. package/dist/bundle/runtime-manifest.json +1 -1
  115. package/dist/core/agent-session.d.ts +8 -0
  116. package/dist/core/agent-session.js +73 -63
  117. package/dist/core/auth-storage.d.ts +19 -0
  118. package/dist/core/auth-storage.js +99 -24
  119. package/dist/core/auth-store-load-error.d.ts +29 -0
  120. package/dist/core/auth-store-load-error.js +74 -0
  121. package/dist/core/brand.d.ts +2 -0
  122. package/dist/core/brand.js +1 -0
  123. package/dist/core/credential-pool/classify.d.ts +3 -2
  124. package/dist/core/credential-pool/classify.js +10 -3
  125. package/dist/core/credential-pool/failover.d.ts +8 -0
  126. package/dist/core/credential-pool/failover.js +18 -5
  127. package/dist/core/credential-pool/rotation-stream.d.ts +1 -1
  128. package/dist/core/credential-pool/rotation-stream.js +2 -7
  129. package/dist/core/credential-pool/session-slot.d.ts +20 -0
  130. package/dist/core/credential-pool/session-slot.js +26 -0
  131. package/dist/core/credential-recovery-revision.d.ts +10 -0
  132. package/dist/core/credential-recovery-revision.js +19 -0
  133. package/dist/core/dynamic-prompt/build.d.ts +2 -1
  134. package/dist/core/dynamic-prompt/build.js +1 -2
  135. package/dist/core/dynamic-prompt/handoff.d.ts +1 -1
  136. package/dist/core/dynamic-prompt/handoff.js +9 -9
  137. package/dist/core/dynamic-prompt/identity.js +1 -1
  138. package/dist/core/dynamic-prompt/intent-gate.d.ts +1 -1
  139. package/dist/core/dynamic-prompt/intent-gate.js +8 -8
  140. package/dist/core/dynamic-prompt/policies.d.ts +1 -1
  141. package/dist/core/dynamic-prompt/policies.js +5 -7
  142. package/dist/core/dynamic-prompt/style.js +5 -5
  143. package/dist/core/dynamic-prompt/tool-section.d.ts +5 -0
  144. package/dist/core/dynamic-prompt/tool-section.js +8 -6
  145. package/dist/core/dynamic-prompt/verification.d.ts +6 -6
  146. package/dist/core/dynamic-prompt/verification.js +12 -12
  147. package/dist/core/dynamic-prompt/working-task.d.ts +1 -1
  148. package/dist/core/dynamic-prompt/working-task.js +3 -3
  149. package/dist/core/dynamic-prompt/workstation.js +1 -1
  150. package/dist/core/execution/executor-body.d.ts +22 -0
  151. package/dist/core/execution/executor-body.js +73 -0
  152. package/dist/core/execution/executor-freeze.d.ts +17 -0
  153. package/dist/core/execution/executor-freeze.js +53 -0
  154. package/dist/core/execution/executor-pipeline.d.ts +9 -0
  155. package/dist/core/execution/executor-pipeline.js +25 -0
  156. package/dist/core/execution/executor-types.d.ts +82 -0
  157. package/dist/core/execution/executor-types.js +2 -0
  158. package/dist/core/execution/executor.d.ts +8 -0
  159. package/dist/core/execution/executor.js +216 -0
  160. package/dist/core/extensions/builtin/anthropic-subscription/account-block-log.d.ts +15 -0
  161. package/dist/core/extensions/builtin/anthropic-subscription/account-block-log.js +18 -0
  162. package/dist/core/extensions/builtin/anthropic-subscription/affinity.d.ts +9 -1
  163. package/dist/core/extensions/builtin/anthropic-subscription/affinity.js +15 -4
  164. package/dist/core/extensions/builtin/anthropic-subscription/failover.d.ts +7 -1
  165. package/dist/core/extensions/builtin/anthropic-subscription/failover.js +19 -2
  166. package/dist/core/extensions/builtin/anthropic-subscription/guidance.d.ts +8 -2
  167. package/dist/core/extensions/builtin/anthropic-subscription/guidance.js +25 -1
  168. package/dist/core/extensions/builtin/anthropic-subscription/provider-diagnostic.d.ts +9 -0
  169. package/dist/core/extensions/builtin/anthropic-subscription/provider-diagnostic.js +59 -0
  170. package/dist/core/extensions/builtin/anthropic-subscription/session-registry-pump.d.ts +13 -0
  171. package/dist/core/extensions/builtin/anthropic-subscription/session-registry-pump.js +64 -2
  172. package/dist/core/extensions/builtin/anthropic-subscription/session-registry-wiring.js +7 -0
  173. package/dist/core/extensions/builtin/anthropic-subscription/session-stream.js +5 -1
  174. package/dist/core/extensions/builtin/anthropic-subscription/session-turn-attempt.d.ts +7 -0
  175. package/dist/core/extensions/builtin/anthropic-subscription/session-turn-attempt.js +28 -1
  176. package/dist/core/extensions/builtin/anthropic-subscription/session-turn-types.d.ts +2 -0
  177. package/dist/core/extensions/builtin/anthropic-subscription/stream-guidance.js +5 -3
  178. package/dist/core/extensions/builtin/anthropic-subscription/stream.js +4 -0
  179. package/dist/core/extensions/builtin/bash-timeout/index.d.ts +1 -1
  180. package/dist/core/extensions/builtin/bash-timeout/index.js +3 -28
  181. package/dist/core/extensions/builtin/bash-timeout/timeout.d.ts +0 -11
  182. package/dist/core/extensions/builtin/bash-timeout/timeout.js +0 -11
  183. package/dist/core/extensions/builtin/btw/index.js +3 -1
  184. package/dist/core/extensions/builtin/cache-keepalive/index.js +3 -1
  185. package/dist/core/extensions/builtin/compaction/index.js +1 -1
  186. package/dist/core/extensions/builtin/compaction/openai-remote.d.ts +3 -1
  187. package/dist/core/extensions/builtin/compaction/openai-remote.js +1 -1
  188. package/dist/core/extensions/builtin/compaction/speculative.js +3 -2
  189. package/dist/core/extensions/builtin/cursor-cli-oauth/account-command.js +3 -1
  190. package/dist/core/extensions/builtin/cursor-cli-oauth/native-bootstrap.js +3 -1
  191. package/dist/core/extensions/builtin/imagegen/index.d.ts +0 -1
  192. package/dist/core/extensions/builtin/imagegen/index.js +0 -11
  193. package/dist/core/extensions/builtin/look-at/runner.js +3 -1
  194. package/dist/core/extensions/builtin/mcp/auth/callback.js +3 -4
  195. package/dist/core/extensions/builtin/mcp/auth/oauth-provider.js +2 -1
  196. package/dist/core/extensions/builtin/prompt-preset/execution-tooling.d.ts +5 -5
  197. package/dist/core/extensions/builtin/prompt-preset/execution-tooling.js +5 -5
  198. package/dist/core/extensions/builtin/prompt-preset/glm-5.d.ts +1 -1
  199. package/dist/core/extensions/builtin/prompt-preset/glm-5.js +1 -1
  200. package/dist/core/extensions/builtin/terminal/extension.js +8 -1
  201. package/dist/core/extensions/builtin/terminal/notify.js +9 -3
  202. package/dist/core/extensions/builtin/terminal/prompt.d.ts +7 -1
  203. package/dist/core/extensions/builtin/terminal/prompt.js +27 -60
  204. package/dist/core/extensions/builtin/terminal/tools/bash.js +10 -2
  205. package/dist/core/extensions/builtin/todotools/normalize.d.ts +20 -3
  206. package/dist/core/extensions/builtin/todotools/normalize.js +251 -5
  207. package/dist/core/extensions/builtin/todotools/prompt.d.ts +2 -2
  208. package/dist/core/extensions/builtin/todotools/prompt.js +5 -5
  209. package/dist/core/extensions/builtin/todotools/tools/todo.js +9 -8
  210. package/dist/core/extensions/builtin/webfetch/webfetch/tool.js +0 -5
  211. package/dist/core/extensions/builtin/websearch/index.js +9 -4
  212. package/dist/core/extensions/builtin/websearch/websearch/tool.d.ts +2 -0
  213. package/dist/core/extensions/builtin/websearch/websearch/tool.js +3 -1
  214. package/dist/core/model-registry.d.ts +10 -2
  215. package/dist/core/model-registry.js +12 -4
  216. package/dist/core/model-runtime.d.ts +8 -0
  217. package/dist/core/model-runtime.js +39 -1
  218. package/dist/core/provider-failure.d.ts +6 -0
  219. package/dist/core/provider-failure.js +6 -2
  220. package/dist/core/retry-fallback/controller-types.d.ts +7 -0
  221. package/dist/core/retry-fallback/controller.d.ts +2 -0
  222. package/dist/core/retry-fallback/controller.js +13 -4
  223. package/dist/core/retry-fallback/credential-recovery.d.ts +18 -0
  224. package/dist/core/retry-fallback/credential-recovery.js +32 -0
  225. package/dist/core/retry-fallback/exhaustion.d.ts +18 -0
  226. package/dist/core/retry-fallback/exhaustion.js +20 -0
  227. package/dist/core/retry-fallback/settings.d.ts +8 -1
  228. package/dist/core/retry-fallback/settings.js +12 -6
  229. package/dist/core/session-log.js +1 -1
  230. package/dist/core/settings-manager.js +4 -1
  231. package/dist/core/system-prompt.js +1 -1
  232. package/dist/core/tools/bash.d.ts +3 -1
  233. package/dist/core/tools/bash.js +14 -4
  234. package/dist/core/tools/edit.d.ts +1 -1
  235. package/dist/core/tools/edit.js +1 -6
  236. package/dist/core/tools/grep/index.js +2 -3
  237. package/dist/core/tools/powershell.d.ts +1 -1
  238. package/dist/core/tools/powershell.js +1 -1
  239. package/dist/core/tools/read.d.ts +1 -1
  240. package/dist/core/tools/read.js +1 -1
  241. package/dist/core/tools/write.d.ts +1 -1
  242. package/dist/core/tools/write.js +1 -1
  243. package/dist/engine-trust/shell-trust.d.ts +36 -0
  244. package/dist/engine-trust/shell-trust.js +44 -0
  245. package/dist/engine-trust/transport-failure.d.ts +12 -0
  246. package/dist/engine-trust/transport-failure.js +48 -0
  247. package/dist/modes/interactive/interactive-mode.js +9 -3
  248. package/dist/modes/print-mode.js +2 -1
  249. package/dist/modes/rpc/compact-catalog-families.d.ts +5 -2
  250. package/dist/modes/rpc/compact-catalog-families.js +5 -2
  251. package/dist/modes/rpc/compact-catalog-registry.d.ts +9 -1
  252. package/dist/modes/rpc/compact-catalog-registry.js +9 -2
  253. package/dist/modes/rpc/compact-recovery-manifest-kinds.d.ts +17 -0
  254. package/dist/modes/rpc/compact-recovery-manifest-kinds.js +21 -0
  255. package/dist/modes/rpc/compact-recovery-manifest-shape.d.ts +7 -0
  256. package/dist/modes/rpc/compact-recovery-manifest.js +11 -3
  257. package/dist/modes/rpc/compact-socket-commands.js +6 -0
  258. package/dist/modes/rpc/connection-handler.js +24 -6
  259. package/dist/modes/rpc/connection-question-bridge.d.ts +3 -1
  260. package/dist/modes/rpc/connection-question-bridge.js +4 -1
  261. package/dist/modes/rpc/connection-roles.d.ts +8 -0
  262. package/dist/modes/rpc/connection-roles.js +18 -0
  263. package/dist/modes/rpc/effect-commands.d.ts +1 -0
  264. package/dist/modes/rpc/loopless-execute-grant.d.ts +20 -0
  265. package/dist/modes/rpc/loopless-execute-grant.js +26 -0
  266. package/dist/modes/rpc/loopless-runtime-settings.d.ts +30 -0
  267. package/dist/modes/rpc/loopless-runtime-settings.js +69 -0
  268. package/dist/modes/rpc/loopless-tool-call.d.ts +12 -0
  269. package/dist/modes/rpc/loopless-tool-call.js +22 -0
  270. package/dist/modes/rpc/method-classes-schema-session.d.ts +4 -0
  271. package/dist/modes/rpc/method-classes-schema-session.js +1 -0
  272. package/dist/modes/rpc/method-classes-schema.d.ts +4 -0
  273. package/dist/modes/rpc/protocol-identity.js +2 -0
  274. package/dist/modes/rpc/remote-origin.d.ts +31 -0
  275. package/dist/modes/rpc/remote-origin.js +58 -0
  276. package/dist/modes/rpc/rpc-protocol-info-types.d.ts +8 -0
  277. package/dist/modes/rpc/rpc-question-types.d.ts +7 -0
  278. package/dist/modes/rpc/rpc-question-types.js +0 -3
  279. package/dist/modes/rpc/rpc-read-response-types.d.ts +2 -1
  280. package/dist/modes/rpc/rpc-session-command-types.d.ts +3 -0
  281. package/dist/modes/rpc/rpc-session-state-types.d.ts +10 -0
  282. package/dist/modes/rpc/rpc-types.d.ts +1 -1
  283. package/dist/modes/rpc/runtime-factory-loopless.d.ts +57 -0
  284. package/dist/modes/rpc/runtime-factory-loopless.js +131 -0
  285. package/dist/modes/rpc/session-registry.js +12 -3
  286. package/dist/modes/rpc/session-worker-client.js +2 -0
  287. package/dist/modes/rpc/session-worker-protocol.d.ts +3 -0
  288. package/dist/modes/rpc/session-worker.js +2 -0
  289. package/docs/development.md +1 -1
  290. package/docs/engine-socket/fixtures/admission-routes/c-baseline.json +3 -3
  291. package/docs/engine-socket/fixtures/admission-routes/h-legacy.json +1 -1
  292. package/docs/engine-socket/fixtures/admission-routes/i-reset-stream.json +3 -3
  293. package/docs/engine-socket/fixtures/recovery-manifest/index.json +32 -0
  294. package/docs/engine-socket/fixtures/recovery-manifest/one-partial-family.json +118 -0
  295. package/docs/rpc.md +95 -3
  296. package/package.json +6 -6
  297. package/dist/bundle/chunks/anthropic-messages-WUPLDYD6.js +0 -10
  298. package/dist/bundle/chunks/chunk-7UC4W2T2.js +0 -2
  299. package/dist/bundle/chunks/chunk-O4GRBX4R.js +0 -3
  300. package/dist/bundle/chunks/chunk-R23WXN4L.js +0 -448
  301. package/dist/bundle/chunks/chunk-W5NLCRB3.js +0 -2
  302. package/dist/bundle/chunks/credential-accounts-OAK2E5O2.js +0 -2
  303. package/dist/bundle/chunks/host-command-WJIMRBGN.js +0 -2
  304. package/dist/bundle/chunks/interactive-mode-NPHFDPGH.js +0 -2
  305. package/dist/bundle/chunks/main-I6FJAFUP.js +0 -2
  306. package/dist/bundle/chunks/rotation-stream-ZDCNHIBE.js +0 -2
  307. package/dist/bundle/chunks/rpc-mode-GBBTN2WP.js +0 -2
@@ -0,0 +1,74 @@
1
+ import { stripBom } from "../utils/text.js";
2
+ import { CredentialStoreBusyError } from "./lockfile-policy.js";
3
+ export class AuthStoreUnreadableError extends Error {
4
+ constructor(loadError) {
5
+ super(`Your sign-in store (auth.json) could not be read: ${loadError.reason}. Nothing was changed; repair or move auth.json in the agent directory, then sign in again.`);
6
+ this.name = "AuthStoreUnreadableError";
7
+ this.loadError = loadError;
8
+ }
9
+ }
10
+ /**
11
+ * A store load that failed after auth.json was read and parsed: saving its repaired or migrated copy
12
+ * failed (`wroteBack`), or the lock was lost once the read was done. Neither means the file is unreadable.
13
+ */
14
+ class AuthStoreAfterReadError extends Error {
15
+ constructor(cause, wroteBack) {
16
+ const detail = cause instanceof Error ? cause.message : String(cause);
17
+ super(wroteBack
18
+ ? `auth.json was read, but saving its repaired or migrated copy failed: ${detail}`
19
+ : `auth.json was read, but its lock was lost before the read finished: ${detail}`, { cause });
20
+ this.name = "AuthStoreAfterReadError";
21
+ this.wroteBack = wroteBack;
22
+ }
23
+ }
24
+ /** The top-level object of an auth.json document; anything else is refused rather than read as empty. */
25
+ export function parseAuthDocument(content) {
26
+ let parsed;
27
+ try {
28
+ parsed = JSON.parse(stripBom(content));
29
+ }
30
+ catch {
31
+ throw new AuthStoreUnreadableError({ kind: "malformed_json", reason: "it is not valid JSON" });
32
+ }
33
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
34
+ throw new AuthStoreUnreadableError({ kind: "invalid_format", reason: "it does not hold a JSON object" });
35
+ }
36
+ return parsed;
37
+ }
38
+ /**
39
+ * The load error a failed store read stands for, or undefined when the failure says nothing about
40
+ * the file: a lock held by another writer, a read the caller aborted, or a lock lost after a clean read.
41
+ */
42
+ export function describeAuthStoreLoadFailure(error) {
43
+ if (error instanceof AuthStoreUnreadableError)
44
+ return error.loadError;
45
+ if (error instanceof CredentialStoreBusyError)
46
+ return undefined;
47
+ if (error instanceof Error && error.name === "AbortError")
48
+ return undefined;
49
+ if (error instanceof AuthStoreAfterReadError) {
50
+ if (!error.wroteBack)
51
+ return undefined;
52
+ const code = errnoCode(error.cause);
53
+ const reason = "it was read, but its repaired or migrated copy could not be saved";
54
+ return { kind: "write_back_failed", reason: code ? `${reason} (${code})` : reason };
55
+ }
56
+ const code = errnoCode(error);
57
+ return {
58
+ kind: "unreadable",
59
+ reason: code ? `the file could not be read (${code})` : "the file could not be read",
60
+ };
61
+ }
62
+ /**
63
+ * The error a store load surfaces: once auth.json parsed, a later failure (a write-back or a lost lock)
64
+ * becomes an AuthStoreAfterReadError so it is never reported as an unreadable file. Aborts pass through.
65
+ */
66
+ export function failureAfterRead(error, load) {
67
+ if (!load.parsed || (error instanceof Error && error.name === "AbortError"))
68
+ return error;
69
+ return new AuthStoreAfterReadError(error, load.writeBack);
70
+ }
71
+ function errnoCode(error) {
72
+ return error instanceof Error && "code" in error && typeof error.code === "string" ? error.code : undefined;
73
+ }
74
+ //# sourceMappingURL=auth-store-load-error.js.map
@@ -46,6 +46,8 @@ export interface BrandProfile {
46
46
  readonly userAgent: string;
47
47
  /** Product token used as the provider-side originator, when the distribution overrides it. */
48
48
  readonly originator?: string;
49
+ /** Product logo for the sign-in result pages, as a base64 image data URI. */
50
+ readonly logo?: string;
49
51
  /** Update channel of the branded product; absent means the product manages updates itself. */
50
52
  readonly update?: BrandUpdateChannel;
51
53
  readonly changelog?: BrandChangelog;
@@ -91,6 +91,7 @@ export function parseBrandProfile(raw) {
91
91
  envPrefix: (readString(source, "envPrefix") || name).toUpperCase(),
92
92
  userAgent: readString(source, "userAgent") || name,
93
93
  originator: readString(source, "originator"),
94
+ logo: readString(source, "logo"),
94
95
  update: readUpdateChannel(source),
95
96
  ...(changelog ? { changelog } : {}),
96
97
  };
@@ -31,8 +31,9 @@ export type CredentialAction = {
31
31
  };
32
32
  /**
33
33
  * Per-slot exponential cooldown with the server hint as a FLOOR, never an
34
- * override: a hint can only lengthen the wait the failure count already earned,
35
- * and everything caps at 48 hours with the capping recorded.
34
+ * override: a hint can only lengthen the wait the failure count already earned.
35
+ * The guessed backoff stops growing at GUESSED_BACKOFF_CAP_MS; everything caps at
36
+ * 48 hours with the capping recorded.
36
37
  */
37
38
  export declare function rateLimitCooldown(failureCount: number, serverHintMs?: number, policy?: {
38
39
  baseMs?: number;
@@ -11,6 +11,12 @@ import { usageLimitResetMs } from "./reset-time.js";
11
11
  import { isAccountUsageLimitText } from "./usage-limit.js";
12
12
  export const COOLDOWN_BASE_MS = DEFAULT_SLOT_BLOCK_MS;
13
13
  export const COOLDOWN_CAP_MS = MAX_SLOT_BLOCK_MS;
14
+ /**
15
+ * The longest a guessed backoff may grow. A block with no provider-stated reset is only a guess, so
16
+ * the slot is re-probed at least this often: doubling to the 48 h cap across failed probes kept a
17
+ * spent account blocked for hours after its provider window had reset (senpi#4091).
18
+ */
19
+ const GUESSED_BACKOFF_CAP_MS = 30 * 60 * 1_000;
14
20
  export const RETRY_SAME_MAX_ATTEMPTS = 2;
15
21
  /**
16
22
  * Carried by every refusal a provider that runs its own account pool (Anthropic Subscription) makes
@@ -22,13 +28,14 @@ export const RETRY_SAME_MAX_ATTEMPTS = 2;
22
28
  export const ACCOUNT_POOL_REFUSAL_NOTE = "No request was sent: the account pool refused it locally.";
23
29
  /**
24
30
  * Per-slot exponential cooldown with the server hint as a FLOOR, never an
25
- * override: a hint can only lengthen the wait the failure count already earned,
26
- * and everything caps at 48 hours with the capping recorded.
31
+ * override: a hint can only lengthen the wait the failure count already earned.
32
+ * The guessed backoff stops growing at GUESSED_BACKOFF_CAP_MS; everything caps at
33
+ * 48 hours with the capping recorded.
27
34
  */
28
35
  export function rateLimitCooldown(failureCount, serverHintMs, policy = {}) {
29
36
  const cap = policy.capMs ?? COOLDOWN_CAP_MS;
30
37
  const base = policy.baseMs ?? COOLDOWN_BASE_MS;
31
- const backoff = Math.min(cap, base * 2 ** Math.max(0, failureCount));
38
+ const backoff = Math.min(cap, GUESSED_BACKOFF_CAP_MS, base * 2 ** Math.max(0, failureCount));
32
39
  const floored = serverHintMs === undefined ? backoff : Math.max(backoff, serverHintMs);
33
40
  return {
34
41
  cooldownMs: Math.min(cap, floored),
@@ -82,6 +82,14 @@ export declare class CredentialFailoverError extends Error {
82
82
  });
83
83
  }
84
84
  export declare function isAvailable(slot: Pick<RunSlot, "blockReason" | "blockedUntil">, now: number): boolean;
85
+ /**
86
+ * The slots a request's next attempt may pick from: the untried, unblocked ones, else the cooling
87
+ * probe. Empty means the request is refused. Shared by the stream and by auxiliary callers that
88
+ * resolve the session's account outside it (senpi#3924), so both treat an all-blocked pool alike.
89
+ */
90
+ export declare function attemptCandidates<TSlot extends RunSlot>(slots: readonly TSlot[], attempted: ReadonlySet<string>, now: number): TSlot[];
91
+ /** The refusal a request gets when {@link attemptCandidates} is empty before any attempt ran. */
92
+ export declare function noSlotsError(slots: readonly RunSlot[], now: number): CredentialFailoverError;
85
93
  /**
86
94
  * Generic in-lane credential failover. Runs at most one failover attempt per
87
95
  * slot per request, retries provider-scoped faults on the SAME slot up to the
@@ -46,6 +46,20 @@ function coolingProbe(slots, attempted) {
46
46
  const soonest = cooling.reduce((best, slot) => (best === undefined || (slot.blockedUntil ?? 0) < (best.blockedUntil ?? 0) ? slot : best), undefined);
47
47
  return soonest === undefined ? [] : [soonest];
48
48
  }
49
+ /**
50
+ * The slots a request's next attempt may pick from: the untried, unblocked ones, else the cooling
51
+ * probe. Empty means the request is refused. Shared by the stream and by auxiliary callers that
52
+ * resolve the session's account outside it (senpi#3924), so both treat an all-blocked pool alike.
53
+ */
54
+ export function attemptCandidates(slots, attempted, now) {
55
+ const available = slots.filter((slot) => !attempted.has(slot.name) && isAvailable(slot, now));
56
+ return available.length > 0 ? available : coolingProbe(slots, attempted);
57
+ }
58
+ /** The refusal a request gets when {@link attemptCandidates} is empty before any attempt ran. */
59
+ export function noSlotsError(slots, now) {
60
+ const retryAt = soonestRetryAt(slots, now);
61
+ return new CredentialFailoverError({ kind: "fail_request" }, new Error(noSlotsMessage(slots, now)), retryAt === undefined ? {} : { retryAt });
62
+ }
49
63
  /**
50
64
  * A slot's due-back time as the reader's local clock shows it, followed by the ISO instant that the goal
51
65
  * provider-retry scan (`providerRetryAt`) and turn-end liveness read from this text (senpi#4329).
@@ -134,17 +148,16 @@ export async function* runCredentialFailover(options) {
134
148
  try {
135
149
  while (true) {
136
150
  const slots = await options.listSlots();
137
- const available = slots.filter((slot) => !attempted.has(slot.name) && isAvailable(slot, now()));
138
- const candidates = available.length > 0 ? available : coolingProbe(slots, attempted);
151
+ const candidates = attemptCandidates(slots, attempted, now());
139
152
  if (candidates.length === 0) {
140
153
  if (lastTerminalEvent !== undefined) {
141
154
  yield lastTerminalEvent;
142
155
  return;
143
156
  }
157
+ if (lastError === undefined || lastOriginal === undefined)
158
+ throw noSlotsError(slots, now());
144
159
  const retryAt = soonestRetryAt(slots, now());
145
- throw lastError !== undefined && lastOriginal !== undefined
146
- ? new CredentialFailoverError(lastError.action, lastOriginal, retryAt === undefined ? {} : { retryAt })
147
- : new CredentialFailoverError({ kind: "fail_request" }, new Error(noSlotsMessage(slots, now())), retryAt === undefined ? {} : { retryAt });
160
+ throw new CredentialFailoverError(lastError.action, lastOriginal, retryAt === undefined ? {} : { retryAt });
148
161
  }
149
162
  const slot = options.select(candidates);
150
163
  unsettled = slot;
@@ -1,5 +1,5 @@
1
1
  import type { AssistantMessageEvent } from "@earendil-works/pi-ai";
2
- import { type SlotHasher } from "@earendil-works/pi-ai/auth/pool/select";
2
+ import type { SlotHasher } from "@earendil-works/pi-ai/auth/pool/select";
3
3
  import { type RotationSlot, type RotationSources } from "./rotation-slots.ts";
4
4
  export { listRotationSlots, type RotationLane, type RotationSlot, type RotationSources } from "./rotation-slots.ts";
5
5
  /** The exact hash the claude-sdk-oauth affinity oracle uses, so pools never remap. */
@@ -1,5 +1,4 @@
1
1
  import { createHash, randomUUID } from "node:crypto";
2
- import { applyAccountOrder, rendezvousOrder } from "@earendil-works/pi-ai/auth/pool/select";
3
2
  import { emitProviderAccountFailover, emitProviderAccountsChanged, } from "../extensions/builtin/anthropic-subscription/account-events.js";
4
3
  import { AUTH_BLOCK_REPROBE_MS } from "./auth-reprobe.js";
5
4
  import { classifyCredentialFailure } from "./classify.js";
@@ -8,6 +7,7 @@ import { STORE_BUSY, writeHealthUnlessStoreBusy } from "./health-write.js";
8
7
  import { modelBlockKey, pruneModelBlocks, withModelBlock } from "./model-scope.js";
9
8
  import { isCommittedRotationOutput, isRotationStreamStart, rotationErrorFromEvent } from "./rotation-events.js";
10
9
  import { listRotationSlots, releaseProbeLease } from "./rotation-slots.js";
10
+ import { pickRotationSlot } from "./session-slot.js";
11
11
  export { listRotationSlots } from "./rotation-slots.js";
12
12
  /** The exact hash the claude-sdk-oauth affinity oracle uses, so pools never remap. */
13
13
  export const sha256SlotHasher = (input) => createHash("sha256").update(input).digest().readBigUInt64BE(0);
@@ -79,12 +79,7 @@ export function streamWithCredentialRotation(options) {
79
79
  return runCredentialFailover({
80
80
  listSlots: () => listRotationSlots(sources, options.modelId === undefined ? {} : { modelId: options.modelId }),
81
81
  select: (candidates) => {
82
- const pinned = candidates.find((candidate) => candidate.pinned === true);
83
- if (pinned)
84
- return pinned;
85
- const ranked = useAffinity ? rendezvousOrder(affinityKey, candidates, hasher) : candidates;
86
- const ordered = applyAccountOrder(pooled?.order, ranked);
87
- const winner = ordered[0];
82
+ const winner = pickRotationSlot(candidates, { affinityKey, useAffinity, hasher, order: pooled?.order });
88
83
  if (!winner)
89
84
  throw new Error("credential rotation selected from an empty candidate set");
90
85
  return winner;
@@ -0,0 +1,20 @@
1
+ import { type SlotHasher } from "@earendil-works/pi-ai/auth/pool/select";
2
+ import type { RotationSlot } from "./rotation-slots.ts";
3
+ export type SlotPickPolicy = {
4
+ affinityKey: string;
5
+ useAffinity: boolean;
6
+ hasher: SlotHasher;
7
+ /** The pool's user account order, applied after the pin (senpi#3591). */
8
+ order?: readonly string[];
9
+ };
10
+ /** The pin when present, else the first account of the affinity order with the user's order applied. */
11
+ export declare function pickRotationSlot<TSlot extends RotationSlot>(candidates: readonly TSlot[], policy: SlotPickPolicy): TSlot | undefined;
12
+ /**
13
+ * The account a session's next streamed request starts on, for callers that send a resolved key
14
+ * outside the rotation stream (compaction, /btw, look-at, cache keepalive). It is the stream's own
15
+ * first pick: the same candidates (unblocked accounts, else the rate-limited one due back first) and
16
+ * the same order. When the stream would refuse, this throws the stream's refusal, so an auxiliary
17
+ * request never authenticates as an account the stream would not use.
18
+ */
19
+ export declare function selectSessionSlot<TSlot extends RotationSlot>(slots: readonly TSlot[], policy: SlotPickPolicy, now: number): TSlot | undefined;
20
+ //# sourceMappingURL=session-slot.d.ts.map
@@ -0,0 +1,26 @@
1
+ import { applyAccountOrder, rendezvousOrder } from "@earendil-works/pi-ai/auth/pool/select";
2
+ import { attemptCandidates, noSlotsError } from "./failover.js";
3
+ /** The pin when present, else the first account of the affinity order with the user's order applied. */
4
+ export function pickRotationSlot(candidates, policy) {
5
+ const pinned = candidates.find((candidate) => candidate.pinned === true);
6
+ if (pinned)
7
+ return pinned;
8
+ const ranked = policy.useAffinity ? rendezvousOrder(policy.affinityKey, candidates, policy.hasher) : candidates;
9
+ return applyAccountOrder(policy.order, ranked)[0];
10
+ }
11
+ /**
12
+ * The account a session's next streamed request starts on, for callers that send a resolved key
13
+ * outside the rotation stream (compaction, /btw, look-at, cache keepalive). It is the stream's own
14
+ * first pick: the same candidates (unblocked accounts, else the rate-limited one due back first) and
15
+ * the same order. When the stream would refuse, this throws the stream's refusal, so an auxiliary
16
+ * request never authenticates as an account the stream would not use.
17
+ */
18
+ export function selectSessionSlot(slots, policy, now) {
19
+ if (slots.length === 0)
20
+ return undefined;
21
+ const candidates = attemptCandidates(slots, new Set(), now);
22
+ if (candidates.length === 0)
23
+ throw noSlotsError(slots, now);
24
+ return pickRotationSlot(candidates, policy);
25
+ }
26
+ //# sourceMappingURL=session-slot.js.map
@@ -0,0 +1,10 @@
1
+ import type { AuthStorage } from "./auth-storage.ts";
2
+ /**
3
+ * The retry-fallback recovery revision of `provider` (senpi#4099): the `loginId` the last sign-in
4
+ * stored, or "" when none did. A token refresh keeps the id or drops it to "" and never mints one, so
5
+ * only a sign-in moves it to a new non-empty value. The
6
+ * metadata read reloads another process's write without resolving key references. An unreadable
7
+ * store answers `undefined`, which never releases anything.
8
+ */
9
+ export declare function credentialRecoveryRevision(storage: AuthStorage | undefined, provider: string): Promise<string | undefined>;
10
+ //# sourceMappingURL=credential-recovery-revision.d.ts.map
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The retry-fallback recovery revision of `provider` (senpi#4099): the `loginId` the last sign-in
3
+ * stored, or "" when none did. A token refresh keeps the id or drops it to "" and never mints one, so
4
+ * only a sign-in moves it to a new non-empty value. The
5
+ * metadata read reloads another process's write without resolving key references. An unreadable
6
+ * store answers `undefined`, which never releases anything.
7
+ */
8
+ export async function credentialRecoveryRevision(storage, provider) {
9
+ if (!storage)
10
+ return undefined;
11
+ try {
12
+ await storage.list();
13
+ return storage.get(provider)?.loginId ?? "";
14
+ }
15
+ catch {
16
+ return undefined;
17
+ }
18
+ }
19
+ //# sourceMappingURL=credential-recovery-revision.js.map
@@ -10,7 +10,7 @@ export interface DynamicPromptCoreContext {
10
10
  tools: AvailableTool[];
11
11
  surface: PromptSurface;
12
12
  appName?: string;
13
- /** Rendered "## Available Tools" (+ "## Tool Guidelines") section. */
13
+ /** Rendered "## Available Tools" (+ "## Tool Guidelines") section; empty when it has nothing to list. */
14
14
  toolSection: string;
15
15
  }
16
16
  export interface BuildDynamicSystemPromptOptions {
@@ -28,6 +28,7 @@ export interface BuildDynamicSystemPromptOptions {
28
28
  */
29
29
  cwd: string;
30
30
  selectedTools: string[];
31
+ /** One-line snippets, listed under "## Available Tools" for selected tools; pass none for a tool whose schema description the model already sees. */
31
32
  toolSnippets: Record<string, string>;
32
33
  promptGuidelines: string[];
33
34
  contextFiles: Array<{
@@ -45,8 +45,7 @@ export function buildDynamicSystemPromptParts(options) {
45
45
  "",
46
46
  buildVerificationSection({ surface }),
47
47
  "",
48
- toolSection,
49
- "",
48
+ ...(toolSection ? [toolSection, ""] : []),
50
49
  buildPoliciesSection(),
51
50
  "",
52
51
  buildHandoffSection({ surface }),
@@ -22,7 +22,7 @@ export interface HandoffSectionOptions {
22
22
  * the whole reply into English (senpi#2366). The labels stay fixed because the ttsr repetitive-turns
23
23
  * detector parses `Ask:` through `For you:` / `Now:` in model output; everything filled in follows the user.
24
24
  */
25
- export declare const HANDOFF_LANGUAGE_RULE = "Keep the labels Ask, wanted, For you, Now, and Next exactly as written; write everything else - the routing line, slot contents, todo labels, and the reply itself - in the user's language (the one their instructions name, else the one they write in), with Now and Next repeating the todo labels verbatim.";
25
+ export declare const HANDOFF_LANGUAGE_RULE = "Labels Ask, wanted, For you, Now, Next: exactly as written. Everything else (routing line, slot contents, todo labels, reply) in user's language (named in their instructions, else the one they write in); Now/Next repeat todo labels verbatim.";
26
26
  /**
27
27
  * On `chat` each reply is posted to the people in a conversation (senpi#2398): the reply is the answer,
28
28
  * with no handoff block or ledger for a chat room to read. Shared by every core that states handoffs.
@@ -3,11 +3,11 @@
3
3
  * the whole reply into English (senpi#2366). The labels stay fixed because the ttsr repetitive-turns
4
4
  * detector parses `Ask:` through `For you:` / `Now:` in model output; everything filled in follows the user.
5
5
  */
6
- export const HANDOFF_LANGUAGE_RULE = "Keep the labels Ask, wanted, For you, Now, and Next exactly as written; write everything else - the routing line, slot contents, todo labels, and the reply itself - in the user's language (the one their instructions name, else the one they write in), with Now and Next repeating the todo labels verbatim.";
7
- const APP_HANDOFF_LANGUAGE_RULE = HANDOFF_LANGUAGE_RULE.replace("the routing line, ", "");
6
+ export const HANDOFF_LANGUAGE_RULE = "Labels Ask, wanted, For you, Now, Next: exactly as written. Everything else (routing line, slot contents, todo labels, reply) in user's language (named in their instructions, else the one they write in); Now/Next repeat todo labels verbatim.";
7
+ const APP_HANDOFF_LANGUAGE_RULE = HANDOFF_LANGUAGE_RULE.replace("routing line, ", "");
8
8
  const HANDOFF_MOMENTS = {
9
- terminal: "A handoff is a multi-task todo list's creation (in the message that creates it, after the routing line, or the next one), each todo phase change, a blocker or plan change, and the end of a turn that changed something; the routing line is not one, and an answer stays an answer, even after tool calls.",
10
- app: "A handoff is a multi-task todo list's creation (in the message that creates it or the next one), each todo phase change, a blocker or plan change, and the end of a turn that changed something; an answer stays an answer, even after tool calls.",
9
+ terminal: "Handoff moments: multi-task todo list created (same message after routing line, or next one), each todo phase change, blocker or plan change, end of a turn that changed something. Routing line is not one; an answer stays an answer even after tool calls.",
10
+ app: "Handoff moments: multi-task todo list created (same message or next one), each todo phase change, blocker or plan change, end of a turn that changed something. An answer stays an answer even after tool calls.",
11
11
  };
12
12
  /**
13
13
  * On `chat` each reply is posted to the people in a conversation (senpi#2398): the reply is the answer,
@@ -22,15 +22,15 @@ export function buildHandoffSection(options = {}) {
22
22
  if (surface === "chat")
23
23
  return CHAT_REPLIES_SECTION;
24
24
  const nextRule = options.turnEndRuleStatedElsewhere
25
- ? "The Next you name is executed in this same response with tool calls."
26
- : "The Next you name is executed in this same response with tool calls; a Next with nothing after it is a defect.";
25
+ ? "The named Next is executed in this same response with tool calls."
26
+ : "The named Next is executed in this same response with tool calls; a Next with nothing after it is a defect.";
27
27
  const betweenRule = options.briefUpdatesBetweenHandoffs
28
- ? "Between handoffs, after each tool wave that changes what you know, write one line of reply text: what you found, then `Now: [task]. Next: [task].`"
29
- : "Between handoffs, work without narration.";
28
+ ? "Between handoffs: after each tool wave that changes what you know, one line of reply text - what you found, then `Now: [task]. Next: [task].`"
29
+ : "Between handoffs: work without narration.";
30
30
  const languageRule = surface === "app" ? APP_HANDOFF_LANGUAGE_RULE : HANDOFF_LANGUAGE_RULE;
31
31
  return `## Handoff
32
32
 
33
- ${HANDOFF_MOMENTS[surface]} Before writing one, weigh what the user originally asked for and what they would want to know right now; then state it in one short block:
33
+ ${HANDOFF_MOMENTS[surface]} First weigh original ask + what user needs now; then one short block:
34
34
 
35
35
  Ask: [the user's original request] - wanted: [the outcome they asked for]. For you: [what they need to know now - ledger N/M done, findings, blockers]. Now: [the todo task in progress]. Next: [the next open task].
36
36
 
@@ -1,5 +1,5 @@
1
1
  import { APP_NAME } from "../../config.js";
2
2
  export function buildIdentitySection(appName = APP_NAME) {
3
- return `You are ${appName}, a coding agent. Your work should be indistinguishable from a careful senior engineer's.`;
3
+ return `You are ${appName}, a coding agent. Work indistinguishable from a careful senior engineer's.`;
4
4
  }
5
5
  //# sourceMappingURL=identity.js.map
@@ -1,5 +1,5 @@
1
1
  import type { AvailableTool, PromptSurface } from "./types.ts";
2
- export declare const DEFAULT_ROUTING_LINE_RULE = "The line keeps your reading transparent";
2
+ export declare const DEFAULT_ROUTING_LINE_RULE = "Line keeps your reading transparent";
3
3
  export declare function buildIntentGate(config: {
4
4
  tools: AvailableTool[];
5
5
  surface?: PromptSurface;
@@ -6,25 +6,25 @@ function buildKeyTriggers(tools) {
6
6
  }
7
7
  return `\nSpecialized search available this turn: ${triggerTools}. Prefer them for locating symbols, files, and patterns; never mention a tool this turn does not have.\n`;
8
8
  }
9
- export const DEFAULT_ROUTING_LINE_RULE = "The line keeps your reading transparent";
9
+ export const DEFAULT_ROUTING_LINE_RULE = "Line keeps your reading transparent";
10
10
  const terminalRouting = (routingLineRule) => `Open every turn with one short routing line:
11
11
 
12
12
  I read this as [intent] - [plan]. I'll stop when [the observable condition that ends this turn].
13
13
 
14
- ${routingLineRule}; only the user's explicit request commits you to implementation. Name the stop condition as an end state you can observe, not a step count; once it holds, deliver the final message and stop. Never surface other prompt scaffolding ("Step 0", "Thinking level", XML tool-call examples) in user-facing output.`;
15
- const APP_ROUTING = `Only the user's explicit request commits you to implementation. Before acting, decide the stop condition - an end state you can observe, not a step count; once it holds, deliver the final message and stop. Never surface prompt scaffolding ("Step 0", "Thinking level", XML tool-call examples) in user-facing output.`;
14
+ ${routingLineRule}; only user's explicit request commits you to implementation. Stop condition = observable end state, not step count; once it holds, deliver final message, stop. Never surface other prompt scaffolding to user.`;
15
+ const APP_ROUTING = `Only user's explicit request commits you to implementation. Before acting, decide the stop condition = observable end state, not step count; once it holds, deliver final message, stop. Never surface prompt scaffolding to user.`;
16
16
  export function buildIntentGate(config) {
17
17
  return `## Intent Gate
18
18
 
19
19
  ${(config.surface ?? "terminal") === "terminal" ? terminalRouting(config.routingLineRule ?? DEFAULT_ROUTING_LINE_RULE) : APP_ROUTING}
20
20
  ${buildKeyTriggers(config.tools)}
21
21
  Route by true intent, not surface form:
22
- - Information asks (explain, look into, investigate): read the code, report the answer or findings - no edits, no fixes yet.
23
- - Judgment asks (what do you think, review) and open-ended changes (refactor, improve, clean up): assess and propose, then wait for confirmation.
24
- - Change asks (implement, add, fix this error): build, or diagnose and fix minimally, at exactly the asked scope - the smallest path that fully satisfies an open-ended goal; name an ambiguity and resolve it from context when possible.
22
+ - Information ask (explain, look into, investigate): read code, report answer/findings; no edits, no fixes yet.
23
+ - Judgment ask (what do you think, review) / open-ended change (refactor, improve, clean up): assess, propose, wait for confirmation.
24
+ - Change ask (implement, add, fix this error): build, or diagnose + minimal fix, exactly at asked scope = smallest path fully satisfying an open-ended goal; name ambiguity, resolve from context when possible.
25
25
 
26
- Deliver the task at the scope asked - never quietly narrow, widen, or swap it. Make routine judgment calls yourself; ask only when different readings of the request would lead to materially different work.
26
+ Deliver at asked scope; never quietly narrow, widen, swap. Routine calls: decide yourself; ask only when readings diverge into materially different work.
27
27
 
28
- Derive intent from the latest user turn alone: a new direction drops the stale plan; queued steering messages outrank earlier intent. Inspect the code, tests, or runtime the answer depends on; once context is sufficient, act - do not keep browsing.`;
28
+ Intent from latest user turn only: new direction drops stale plan; queued steering messages outrank earlier intent.`;
29
29
  }
30
30
  //# sourceMappingURL=intent-gate.js.map
@@ -1,4 +1,4 @@
1
- export declare const DEFAULT_ERROR_RULE = "Never silently swallow errors; never shotgun-debug with unrelated edits or blind retries.";
1
+ export declare const DEFAULT_ERROR_RULE = "Never swallow errors silently; no shotgun debugging (unrelated edits, blind retries).";
2
2
  export declare function buildPoliciesSection(options?: {
3
3
  errorRule?: string;
4
4
  }): string;
@@ -1,12 +1,10 @@
1
- export const DEFAULT_ERROR_RULE = "Never silently swallow errors; never shotgun-debug with unrelated edits or blind retries.";
1
+ export const DEFAULT_ERROR_RULE = "Never swallow errors silently; no shotgun debugging (unrelated edits, blind retries).";
2
2
  export function buildPoliciesSection(options = {}) {
3
- return `## Policies
3
+ return `## Hard Limits
4
4
 
5
- ### Hard Blocks
6
- - Never create a git commit unless the user explicitly requested it.
7
- - Never present unread code or unrun commands as verified fact.
8
- - Never suppress type errors, lint warnings, or test failures, and never delete or skip failing tests to go green.
5
+ - No git commit unless user explicitly asked.
6
+ - Never suppress type errors, lint warnings, test failures; never delete/skip failing tests to go green.
9
7
  - ${options.errorRule ?? DEFAULT_ERROR_RULE}
10
- - Never present partial work as complete or deliver a stub, placeholder, or no-op as the feature; say what is done, what is not, and why you stopped.`;
8
+ - Never present partial work as complete; no stub, placeholder, or no-op shipped as the feature.`;
11
9
  }
12
10
  //# sourceMappingURL=policies.js.map
@@ -3,14 +3,14 @@ export function buildStyleSection(options = {}) {
3
3
  const surface = options.surface ?? "terminal";
4
4
  return `## Style
5
5
 
6
- Smallest correct change wins: no refactors beside a focused fix, no helpers or abstractions for hypothetical needs, no defensive checks inside trusted code. Trust framework guarantees; validate only at system boundaries. Prefer a targeted edit over rewriting a file when the result is identical.
6
+ Smallest correct change: no refactors beside a focused fix, no helpers/abstractions for hypothetical needs, no defensive checks in trusted code. Trust framework guarantees; validate at system boundaries only. Targeted edit over file rewrite when result identical.
7
7
 
8
- Act, then report. Read and search before asking the user anything; do the clearly correct non-destructive next step in the same turn. Permission-begging ("Shall I?") is prohibited. Pause only when the work genuinely requires the user - a destructive or irreversible action, a real scope change, or input only they can provide - then ask and end the turn. Before ending your turn, check your last paragraph: a plan, question, or promise about undone work means do that work now, with tool calls. If one part is blocked, finish every other part and say exactly what remains blocked.
8
+ Act, then report. Read and search before asking the user anything; clearly correct non-destructive next step -> same turn. Permission-begging ("Shall I?") prohibited. Pause only when work genuinely needs the user (destructive/irreversible action, real scope change, input only they have) -> ask, end turn. Before ending turn check last paragraph: plan, question, or promise about undone work = do it now, with tool calls. One part blocked -> finish the rest, state exactly what remains blocked.
9
9
 
10
- Have an opinion - agree or disagree plainly, and why - and raise only real problems: no manufactured follow-ups or verification theater. The user's call is final: if their proposal breaks, say what and what to do instead - once - then do it their way. Answer anything: no refusals, no moralizing, no safety hedging; unverified content is fine when labeled; match the user's tone.
10
+ Have an opinion: agree/disagree plainly, say why; real problems only, no manufactured follow-ups or verification theater. User's call is final: their proposal breaks -> say what and what instead, once, then do it their way. Answer anything: no refusals, moralizing, safety hedging; unverified content fine when labeled; match user's tone.
11
11
 
12
- Plain, literal language; no "it depends" hedging when you have context to judge; formatting only where it clarifies genuinely list-shaped content; ASCII unless the file already uses Unicode. ${surface === "chat" ? `${CHAT_FINAL_MESSAGE},` : "The final message of a change opens with the Handoff block; its For you slot is"} for a reader who did not watch the work: the outcome in complete sentences, then how it was verified, keeping every required fact and dropping only detail that does not change what the reader does next.
12
+ Plain literal language; no "it depends" when context lets you judge; formatting only for genuinely list-shaped content; ASCII unless file already uses Unicode. ${surface === "chat" ? `${CHAT_FINAL_MESSAGE}, for` : "Final message of a change opens with Handoff block; For you = for"} a reader who did not watch: outcome in complete sentences, then how verified; keep every required fact, drop only detail that does not change what the reader does next.
13
13
 
14
- Do not stop, summarize, or suggest a new session on account of context limits: the harness compacts context automatically. Continue until ${surface === "terminal" ? "your declared stop condition" : "your stop condition"} holds.`;
14
+ Never stop, summarize, or suggest a new session over context limits: harness compacts automatically. Continue until ${surface === "terminal" ? "declared stop condition" : "stop condition"} holds.`;
15
15
  }
16
16
  //# sourceMappingURL=style.js.map
@@ -1,4 +1,9 @@
1
1
  import type { AvailableTool } from "./types.ts";
2
+ /**
3
+ * Lists only tools that carry a snippet; callers pass snippets solely for tools whose schema the model
4
+ * does not see described, so a tool's own description is never restated here (senpi#5335). With no
5
+ * listed tool and no guideline the section renders empty.
6
+ */
2
7
  export declare function buildToolSection(options: {
3
8
  tools: AvailableTool[];
4
9
  toolSnippets: Record<string, string>;
@@ -6,6 +6,11 @@ const CATEGORY_LABELS = {
6
6
  session: "Session",
7
7
  command: "Commands",
8
8
  };
9
+ /**
10
+ * Lists only tools that carry a snippet; callers pass snippets solely for tools whose schema the model
11
+ * does not see described, so a tool's own description is never restated here (senpi#5335). With no
12
+ * listed tool and no guideline the section renders empty.
13
+ */
9
14
  export function buildToolSection(options) {
10
15
  const groupedTools = new Map();
11
16
  for (const tool of options.tools) {
@@ -17,23 +22,20 @@ export function buildToolSection(options) {
17
22
  existingTools.push({ name: tool.name, snippet });
18
23
  groupedTools.set(tool.category, existingTools);
19
24
  }
20
- const lines = ["## Available Tools", ""];
21
- let hasVisibleTools = false;
25
+ const lines = [];
22
26
  for (const category of CATEGORY_ORDER) {
23
27
  const categoryTools = groupedTools.get(category);
24
28
  if (!categoryTools || categoryTools.length === 0) {
25
29
  continue;
26
30
  }
27
- hasVisibleTools = true;
31
+ if (lines.length === 0)
32
+ lines.push("## Available Tools", "");
28
33
  lines.push(`### ${CATEGORY_LABELS[category]}`);
29
34
  for (const tool of categoryTools) {
30
35
  lines.push(`- ${tool.name}: ${tool.snippet}`);
31
36
  }
32
37
  lines.push("");
33
38
  }
34
- if (!hasVisibleTools) {
35
- lines.push("(none)", "");
36
- }
37
39
  const guidelines = options.promptGuidelines?.map((guideline) => guideline.trim()).filter((guideline) => guideline) ?? [];
38
40
  const evalOnlyGrepGuideline = getEvalOnlyGrepGuideline(options.tools.map(({ name }) => name), options.toolSnippets);
39
41
  if (evalOnlyGrepGuideline)
@@ -7,27 +7,27 @@ export type TestDisciplineRule = {
7
7
  export declare const TEST_DISCIPLINE_RULES: readonly [{
8
8
  readonly id: "deterministic-tests";
9
9
  readonly concern: "test-determinism";
10
- readonly directive: "When you read or edit test code, treat nondeterminism as a bug; tests must not pass by timing luck.";
10
+ readonly directive: "Reading/editing test code: nondeterminism = bug; no passing by timing luck.";
11
11
  }, {
12
12
  readonly id: "fixed-wait-ban";
13
13
  readonly concern: "async-test-orchestration";
14
- readonly directive: "Unless time itself is the behavior under test, fixed sleeps, polling delays, and wait-for-time patterns are forbidden.";
14
+ readonly directive: "Fixed sleeps, polling delays, wait-for-time: forbidden unless time itself is under test.";
15
15
  }, {
16
16
  readonly id: "event-timeout-pattern";
17
17
  readonly concern: "async-test-orchestration";
18
- readonly directive: "For async behavior, subscribe to the exact event or state change before triggering the action, then await that signal with a bounded timeout.";
18
+ readonly directive: "Async: subscribe to the exact event/state change before triggering, then await it with a bounded timeout.";
19
19
  }, {
20
20
  readonly id: "mock-contract-integrity";
21
21
  readonly concern: "mock-contracts";
22
- readonly directive: "Mocks must preserve the behavior being asserted; do not isolate so heavily that the integration under test cannot fail.";
22
+ readonly directive: "Mocks keep the asserted behavior; never isolate so hard the integration cannot fail.";
23
23
  }, {
24
24
  readonly id: "prompt-behavior-coverage";
25
25
  readonly concern: "prompt-tests";
26
- readonly directive: "Never pin prose, prompt wording, or doc text with a test; test only machine-consumed values (parsed fields, sentinel tokens, shipped-copy equality). A pure-prose change ships with no new test.";
26
+ readonly directive: "Never pin prose, prompt wording, or doc text with a test; test machine-consumed values only (parsed fields, sentinel tokens, shipped-copy equality). Pure-prose change = no new test.";
27
27
  }, {
28
28
  readonly id: "single-pass-runner";
29
29
  readonly concern: "test-runner";
30
- readonly directive: "Run the relevant test command once and make that pass reliable; for Bun test targets, bun test must pass in a single run.";
30
+ readonly directive: "Run the relevant test command once, make that pass reliable; Bun targets: bun test passes in a single run.";
31
31
  }];
32
32
  export declare function buildTestDisciplineSection(): string;
33
33
  /**