@code-yeongyu/senpi 2026.11.10 → 2026.11.11

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 (320) hide show
  1. package/CHANGELOG.md +95 -0
  2. package/dist/bundle/{SKILL-B4R7BVOT.md → SKILL-R7FEIQKG.md} +1 -1
  3. package/dist/bundle/chunks/{SKILL-AZ6ONO52.js → SKILL-5O2UKORG.js} +1 -1
  4. package/dist/bundle/chunks/{SKILL-B4R7BVOT.md → SKILL-R7FEIQKG.md} +1 -1
  5. package/dist/bundle/chunks/{args-77GYOPEO.js → args-HFYB6URH.js} +1 -1
  6. package/dist/bundle/chunks/{azure-openai-responses-YFZ734T3.js → azure-openai-responses-MNN2TINI.js} +1 -1
  7. package/dist/bundle/chunks/{chunk-ZUQCYIRY.js → chunk-2ODGHBUD.js} +1 -1
  8. package/dist/bundle/chunks/chunk-3IYEGHBI.js +2 -0
  9. package/dist/bundle/chunks/{chunk-I5ASHSLZ.js → chunk-4JMGWVRH.js} +1 -1
  10. package/dist/bundle/chunks/{chunk-YKYWL2NO.js → chunk-5F2XC6UC.js} +3 -3
  11. package/dist/bundle/chunks/{chunk-MSDBBOB2.js → chunk-5H43O4MA.js} +1 -1
  12. package/dist/bundle/chunks/{chunk-R3OP7IA4.js → chunk-5PIZWSNG.js} +4 -4
  13. package/dist/bundle/chunks/{chunk-33MZJTQ3.js → chunk-B4WD5XHP.js} +1 -1
  14. package/dist/bundle/chunks/{chunk-Q63YLZMN.js → chunk-BPEA5SWW.js} +2 -2
  15. package/dist/bundle/chunks/{chunk-MOVJQVMC.js → chunk-BUDJLVMF.js} +3 -3
  16. package/dist/bundle/chunks/{chunk-V5FSENW6.js → chunk-COKX65TE.js} +1 -1
  17. package/dist/bundle/chunks/{chunk-2EJ4BGBM.js → chunk-DHORIIVQ.js} +1 -1
  18. package/dist/bundle/chunks/{chunk-NH7SYIGN.js → chunk-DLPV4B3R.js} +1 -1
  19. package/dist/bundle/chunks/{chunk-RCHIMH7N.js → chunk-DQY26AX3.js} +1 -1
  20. package/dist/bundle/chunks/{chunk-Y7Z7XPUF.js → chunk-DZQA5LVN.js} +1 -1
  21. package/dist/bundle/chunks/{chunk-2CNSCMYC.js → chunk-E5O4SP5I.js} +1 -1
  22. package/dist/bundle/chunks/{chunk-3Q5ZENSD.js → chunk-E6ZBTSC6.js} +1 -1
  23. package/dist/bundle/chunks/{chunk-GVPZPVVO.js → chunk-IBDAV2AL.js} +3 -3
  24. package/dist/bundle/chunks/chunk-IREUIMFE.js +11 -0
  25. package/dist/bundle/chunks/{chunk-KU7OCWJF.js → chunk-J4ADZ2OK.js} +1 -1
  26. package/dist/bundle/chunks/{chunk-T2SMQPRE.js → chunk-K3GAGIPX.js} +1 -1
  27. package/dist/bundle/chunks/{chunk-BELNOPAI.js → chunk-L3KVP7VJ.js} +3 -3
  28. package/dist/bundle/chunks/{chunk-IYSJFQUU.js → chunk-L6DF5G6K.js} +1 -1
  29. package/dist/bundle/chunks/{chunk-7MN7YNO5.js → chunk-L7DGTA3L.js} +1 -1
  30. package/dist/bundle/chunks/chunk-LJFQYCFH.js +2 -0
  31. package/dist/bundle/chunks/{chunk-J2NGJKXL.js → chunk-LXINMDMX.js} +1 -1
  32. package/dist/bundle/chunks/{chunk-H33A33M4.js → chunk-M2VJVJMK.js} +1 -1
  33. package/dist/bundle/chunks/{chunk-2U6HXWXS.js → chunk-NNQ34ZDW.js} +1 -1
  34. package/dist/bundle/chunks/chunk-NQKCJQHB.js +2 -0
  35. package/dist/bundle/chunks/{chunk-EJB5E2JK.js → chunk-NRZAJUUO.js} +2 -2
  36. package/dist/bundle/chunks/{chunk-R2Z7CX77.js → chunk-OSNR3IRD.js} +1 -1
  37. package/dist/bundle/chunks/{chunk-O3FG6HML.js → chunk-PJI5GT7U.js} +1 -1
  38. package/dist/bundle/chunks/{chunk-FDNM2DAE.js → chunk-PUZDKFRT.js} +164 -164
  39. package/dist/bundle/chunks/{chunk-BPNSOZ2C.js → chunk-QUVSIW2R.js} +1 -1
  40. package/dist/bundle/chunks/{chunk-WXYMAUFX.js → chunk-QX7WD3IM.js} +1 -1
  41. package/dist/bundle/chunks/{chunk-Y4ONXQMR.js → chunk-RGHVPUUX.js} +1 -1
  42. package/dist/bundle/chunks/{chunk-RYPM5BZQ.js → chunk-S7NAJQB3.js} +1 -1
  43. package/dist/bundle/chunks/{chunk-2BH54YQR.js → chunk-SANWO37B.js} +1 -1
  44. package/dist/bundle/chunks/{chunk-YQZNARTX.js → chunk-SS5VTBAV.js} +1 -1
  45. package/dist/bundle/chunks/{chunk-LT353NSF.js → chunk-T4CUD7RF.js} +1 -1
  46. package/dist/bundle/chunks/{chunk-J7FW7MED.js → chunk-TCZORL3V.js} +1 -1
  47. package/dist/bundle/chunks/{chunk-KU72IKV5.js → chunk-VGSWOLIY.js} +1 -1
  48. package/dist/bundle/chunks/{chunk-DBQBJTMF.js → chunk-VUY4BZDI.js} +1 -1
  49. package/dist/bundle/chunks/chunk-XI6THO4F.js +2 -0
  50. package/dist/bundle/chunks/{chunk-FAFIGBUD.js → chunk-XUDKT4UH.js} +3 -3
  51. package/dist/bundle/chunks/{cli-main-BX5AFWJQ.js → cli-main-7II7GCIR.js} +1 -1
  52. package/dist/bundle/chunks/{credential-accounts-LVVPKFEY.js → credential-accounts-N3B5YJS7.js} +1 -1
  53. package/dist/bundle/chunks/{dispatch-EP35KKJ3.js → dispatch-YUYZQXRP.js} +1 -1
  54. package/dist/bundle/chunks/github-copilot.js +1 -1
  55. package/dist/bundle/chunks/{hand-entry-F6PWKNPJ.js → hand-entry-ONOLRMVB.js} +3 -3
  56. package/dist/bundle/chunks/{headless-host-HKGNJGYT.js → headless-host-53UMJMM6.js} +1 -1
  57. package/dist/bundle/chunks/{health-write-FBF74QJ7.js → health-write-JLSF5EVV.js} +1 -1
  58. package/dist/bundle/chunks/{help-fast-path-5SCPY3OH.js → help-fast-path-552QLMWT.js} +1 -1
  59. package/dist/bundle/chunks/{host-command-47QQKJEY.js → host-command-KWMJLPBS.js} +1 -1
  60. package/dist/bundle/chunks/{host-lifecycle-VSAH4M3R.js → host-lifecycle-4WQDCN3Y.js} +1 -1
  61. package/dist/bundle/chunks/host-lifecycle.js +5 -5
  62. package/dist/bundle/chunks/{host-session-command-SL4AN5WD.js → host-session-command-ZDYEKCUB.js} +1 -1
  63. package/dist/bundle/chunks/{host-socket-request-DMYXC56U.js → host-socket-request-QN4Q2P5E.js} +1 -1
  64. package/dist/bundle/chunks/{interactive-mode-JDMIHJMQ.js → interactive-mode-EPE4M32G.js} +1 -1
  65. package/dist/bundle/chunks/{login-health-EVXVLHB2.js → login-health-TOSQT5RG.js} +1 -1
  66. package/dist/bundle/chunks/{main-4RITUAQF.js → main-OM7BKVZG.js} +1 -1
  67. package/dist/bundle/chunks/{multi-session-host-SKDD4OWM.js → multi-session-host-DB6XMY53.js} +11 -8
  68. package/dist/bundle/chunks/openai-codex-responses-VRGOAFEG.js +10 -0
  69. package/dist/bundle/chunks/{openai-responses-NIVBWE2H.js → openai-responses-I7PXRWCM.js} +2 -2
  70. package/dist/bundle/chunks/{package-manager-cli-B5VA4KFO.js → package-manager-cli-GLU5Q2KV.js} +1 -1
  71. package/dist/bundle/chunks/{role-HQUN4XXK.js → role-AEOLJRTP.js} +1 -1
  72. package/dist/bundle/chunks/{rotation-stream-F3BEMXBE.js → rotation-stream-E3FJFHXJ.js} +1 -1
  73. package/dist/bundle/chunks/rpc-mode-SDJVBT36.js +2 -0
  74. package/dist/bundle/chunks/{rpc-monitor-source-C6VQ3BC4.js → rpc-monitor-source-PGTDSGWP.js} +1 -1
  75. package/dist/bundle/chunks/{run-attached-tui-R3RB5P7G.js → run-attached-tui-4AENRP7P.js} +1 -1
  76. package/dist/bundle/chunks/{schedule-command-FPEQCX33.js → schedule-command-5SQD7M5N.js} +1 -1
  77. package/dist/bundle/chunks/session-control-endpoint-R25A2QGS.js +3 -0
  78. package/dist/bundle/chunks/{session-picker-2FZSNFS7.js → session-picker-GZM5CVQL.js} +1 -1
  79. package/dist/bundle/chunks/{session-slot-CZGQQCOC.js → session-slot-RH7JLO3F.js} +1 -1
  80. package/dist/bundle/chunks/session-worker.js +335 -332
  81. package/dist/bundle/chunks/{state-store-S7QAESIF.js → state-store-IECVTYXC.js} +1 -1
  82. package/dist/bundle/cli.js +2 -2
  83. package/dist/bundle/host-supervisor.js +5 -5
  84. package/dist/bundle/index.js +1 -1
  85. package/dist/bundle/rpc-entry.js +1 -1
  86. package/dist/bundle/runtime-manifest.json +1 -1
  87. package/dist/cli.js +9 -3
  88. package/dist/core/agent-session-runtime.d.ts +2 -0
  89. package/dist/core/agent-session-runtime.js +5 -0
  90. package/dist/core/agent-session.d.ts +15 -3
  91. package/dist/core/agent-session.js +91 -18
  92. package/dist/core/assistant-error-redaction.d.ts +9 -0
  93. package/dist/core/assistant-error-redaction.js +27 -0
  94. package/dist/core/config-reference-redaction.js +90 -10
  95. package/dist/core/context-files.d.ts +10 -0
  96. package/dist/core/context-files.js +58 -12
  97. package/dist/core/credential-accounts.d.ts +2 -0
  98. package/dist/core/credential-accounts.js +10 -1
  99. package/dist/core/dynamic-prompt/intent-gate.js +2 -2
  100. package/dist/core/dynamic-prompt/style.js +2 -2
  101. package/dist/core/dynamic-prompt/verification.js +2 -2
  102. package/dist/core/egress/wire.d.ts +13 -0
  103. package/dist/core/extensions/builtin/anthropic-subscription/accounts.d.ts +3 -0
  104. package/dist/core/extensions/builtin/anthropic-subscription/auth-lane.js +3 -2
  105. package/dist/core/extensions/builtin/anthropic-subscription/claude-cli-account-test.js +3 -1
  106. package/dist/core/extensions/builtin/anthropic-subscription/claude-cli-connection-test.d.ts +3 -1
  107. package/dist/core/extensions/builtin/anthropic-subscription/claude-cli-connection-test.js +47 -16
  108. package/dist/core/extensions/builtin/anthropic-subscription/claude-cli-login-slots.d.ts +1 -1
  109. package/dist/core/extensions/builtin/anthropic-subscription/claude-cli-login-slots.js +4 -2
  110. package/dist/core/extensions/builtin/anthropic-subscription/claude-settings-env.d.ts +20 -0
  111. package/dist/core/extensions/builtin/anthropic-subscription/claude-settings-env.js +39 -0
  112. package/dist/core/extensions/builtin/anthropic-subscription/context-window.d.ts +17 -0
  113. package/dist/core/extensions/builtin/anthropic-subscription/context-window.js +23 -0
  114. package/dist/core/extensions/builtin/anthropic-subscription/errors.d.ts +1 -0
  115. package/dist/core/extensions/builtin/anthropic-subscription/errors.js +14 -5
  116. package/dist/core/extensions/builtin/anthropic-subscription/oauth-login.js +3 -3
  117. package/dist/core/extensions/builtin/anthropic-subscription/prompt-cache-ttl.d.ts +10 -4
  118. package/dist/core/extensions/builtin/anthropic-subscription/prompt-cache-ttl.js +14 -5
  119. package/dist/core/extensions/builtin/anthropic-subscription/query-environment.d.ts +3 -2
  120. package/dist/core/extensions/builtin/anthropic-subscription/query-environment.js +5 -4
  121. package/dist/core/extensions/builtin/anthropic-subscription/sdk-boundary.lazy.d.ts +2 -1
  122. package/dist/core/extensions/builtin/anthropic-subscription/sdk-boundary.lazy.js +1 -0
  123. package/dist/core/extensions/builtin/anthropic-subscription/stream.js +11 -1
  124. package/dist/core/extensions/builtin/config-reload/change-groups.js +6 -2
  125. package/dist/core/extensions/builtin/goal/continuation.d.ts +6 -0
  126. package/dist/core/extensions/builtin/goal/continuation.js +3 -2
  127. package/dist/core/extensions/builtin/goal/index.js +14 -26
  128. package/dist/core/extensions/builtin/goal/lifecycle-helpers.d.ts +8 -6
  129. package/dist/core/extensions/builtin/goal/lifecycle-helpers.js +77 -39
  130. package/dist/core/extensions/builtin/goal/monitor-continuation.js +66 -7
  131. package/dist/core/extensions/builtin/goal/persistence.js +20 -0
  132. package/dist/core/extensions/builtin/goal/provider-retry.d.ts +9 -0
  133. package/dist/core/extensions/builtin/goal/provider-retry.js +16 -0
  134. package/dist/core/extensions/builtin/goal/reload-reengagement.d.ts +3 -2
  135. package/dist/core/extensions/builtin/goal/reload-reengagement.js +4 -4
  136. package/dist/core/extensions/builtin/goal/session-start-continuation.d.ts +28 -0
  137. package/dist/core/extensions/builtin/goal/session-start-continuation.js +75 -0
  138. package/dist/core/extensions/builtin/goal/store.d.ts +3 -2
  139. package/dist/core/extensions/builtin/goal/store.js +9 -2
  140. package/dist/core/extensions/builtin/goal/types.d.ts +9 -0
  141. package/dist/core/extensions/builtin/handoff-hint/index.js +15 -11
  142. package/dist/core/extensions/builtin/handoff-hint/replacement-relay.d.ts +16 -0
  143. package/dist/core/extensions/builtin/handoff-hint/replacement-relay.js +17 -0
  144. package/dist/core/extensions/builtin/html-render/tool.js +13 -3
  145. package/dist/core/extensions/builtin/imagegen/skill/SKILL.md +1 -1
  146. package/dist/core/extensions/builtin/imagegen/tool.js +4 -14
  147. package/dist/core/extensions/builtin/mcp/auth/catalog-identity.js +32 -8
  148. package/dist/core/extensions/builtin/mcp/auth/commands-auth.js +2 -1
  149. package/dist/core/extensions/builtin/mcp/auth/context.js +3 -0
  150. package/dist/core/extensions/builtin/mcp/auth/oauth-grant.d.ts +43 -0
  151. package/dist/core/extensions/builtin/mcp/auth/oauth-grant.js +196 -0
  152. package/dist/core/extensions/builtin/mcp/auth/oauth-issuer.d.ts +7 -1
  153. package/dist/core/extensions/builtin/mcp/auth/oauth-issuer.js +13 -0
  154. package/dist/core/extensions/builtin/mcp/auth/oauth-provider.d.ts +6 -17
  155. package/dist/core/extensions/builtin/mcp/auth/oauth-provider.js +67 -88
  156. package/dist/core/extensions/builtin/mcp/auth/oauth-refresh.d.ts +1 -1
  157. package/dist/core/extensions/builtin/mcp/auth/oauth-refresh.js +25 -4
  158. package/dist/core/extensions/builtin/mcp/auth/oauth.js +10 -7
  159. package/dist/core/extensions/builtin/mcp/auth/registered-redirect.d.ts +19 -0
  160. package/dist/core/extensions/builtin/mcp/auth/registered-redirect.js +55 -0
  161. package/dist/core/extensions/builtin/mcp/auth/token-store.d.ts +23 -1
  162. package/dist/core/extensions/builtin/mcp/auth/token-store.js +3 -0
  163. package/dist/core/extensions/builtin/mcp/catalog-cache.js +7 -6
  164. package/dist/core/extensions/builtin/mcp/catalog.js +3 -2
  165. package/dist/core/extensions/builtin/mcp/invocation.js +6 -0
  166. package/dist/core/extensions/builtin/mcp/service-register.js +16 -2
  167. package/dist/core/extensions/builtin/mcp/service-tools-changed.js +61 -54
  168. package/dist/core/extensions/builtin/mcp/startup-race.d.ts +2 -0
  169. package/dist/core/extensions/builtin/mcp/startup-race.js +25 -7
  170. package/dist/core/extensions/builtin/permission-system/parsers.js +1 -0
  171. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5-1.js +3 -3
  172. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5-2.js +9 -8
  173. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.js +3 -3
  174. package/dist/core/extensions/builtin/prompt-preset/claude-haiku-5-5.js +3 -3
  175. package/dist/core/extensions/builtin/prompt-preset/claude-opus-5-5.js +3 -3
  176. package/dist/core/extensions/builtin/prompt-preset/claude-opus-5.js +4 -4
  177. package/dist/core/extensions/builtin/prompt-preset/claude-sonnet-5-5.js +3 -3
  178. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-1-flash.js +3 -3
  179. package/dist/core/extensions/builtin/prompt-preset/gpt-5.5.js +3 -3
  180. package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js +2 -2
  181. package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.js +3 -3
  182. package/dist/core/extensions/builtin/prompt-preset/grok-4.5.js +1 -1
  183. package/dist/core/extensions/builtin/prompt-preset/grok-4.6.js +4 -4
  184. package/dist/core/extensions/builtin/prompt-preset/grok-4.7.js +5 -5
  185. package/dist/core/extensions/builtin/prompt-preset/kimi-k3-1.js +4 -4
  186. package/dist/core/extensions/builtin/prompt-preset/kimi-k3.js +7 -6
  187. package/dist/core/extensions/loader.js +24 -4
  188. package/dist/core/extensions/runner.d.ts +9 -1
  189. package/dist/core/extensions/runner.js +9 -4
  190. package/dist/core/extensions/types.d.ts +19 -3
  191. package/dist/core/hand/hook-advertise.d.ts +41 -0
  192. package/dist/core/hand/hook-advertise.js +98 -0
  193. package/dist/core/hand/hook-contract.d.ts +66 -0
  194. package/dist/core/hand/hook-contract.js +138 -0
  195. package/dist/core/open-timing.d.ts +2 -0
  196. package/dist/core/open-timing.js +7 -1
  197. package/dist/core/resource-loader.js +21 -3
  198. package/dist/core/retry-fallback/controller-types.d.ts +2 -0
  199. package/dist/core/retry-fallback/controller.js +9 -2
  200. package/dist/core/retry-fallback/cooldown.d.ts +7 -0
  201. package/dist/core/retry-fallback/cooldown.js +13 -1
  202. package/dist/core/retry-fallback/credential-recovery.d.ts +7 -0
  203. package/dist/core/retry-fallback/credential-recovery.js +24 -0
  204. package/dist/core/retry-fallback/log.d.ts +7 -1
  205. package/dist/core/retry-fallback/log.js +82 -5
  206. package/dist/core/retry-fallback/model-config-error.js +2 -1
  207. package/dist/core/retry-fallback/settings.d.ts +8 -5
  208. package/dist/core/retry-fallback/settings.js +9 -6
  209. package/dist/core/session-manager.d.ts +2 -0
  210. package/dist/core/session-manager.js +15 -1
  211. package/dist/core/settings-manager.d.ts +6 -0
  212. package/dist/core/settings-manager.js +8 -0
  213. package/dist/core/turn-origin.d.ts +18 -10
  214. package/dist/core/turn-origin.js +34 -30
  215. package/dist/core/ultrafast-lanes.d.ts +1 -0
  216. package/dist/core/ultrafast-lanes.js +4 -2
  217. package/dist/modes/interactive/components/footer.d.ts +23 -5
  218. package/dist/modes/interactive/components/footer.js +45 -16
  219. package/dist/modes/interactive/interactive-mode.js +9 -1
  220. package/dist/modes/interactive/session-control-rpc-commands.d.ts +1 -1
  221. package/dist/modes/interactive/session-control-rpc-commands.js +5 -0
  222. package/dist/modes/rpc/admit-external-message-command.d.ts +2 -0
  223. package/dist/modes/rpc/admit-external-message-command.js +5 -1
  224. package/dist/modes/rpc/compact-admission-validation.js +4 -1
  225. package/dist/modes/rpc/connection-authority.d.ts +2 -1
  226. package/dist/modes/rpc/connection-authority.js +11 -9
  227. package/dist/modes/rpc/connection-handler.d.ts +2 -0
  228. package/dist/modes/rpc/connection-handler.js +33 -7
  229. package/dist/modes/rpc/connection-roles.d.ts +7 -0
  230. package/dist/modes/rpc/connection-roles.js +15 -0
  231. package/dist/modes/rpc/custom-capability.d.ts +6 -0
  232. package/dist/modes/rpc/custom-capability.js +6 -0
  233. package/dist/modes/rpc/delegated-drive-origin.d.ts +6 -6
  234. package/dist/modes/rpc/delegated-drive-origin.js +7 -8
  235. package/dist/modes/rpc/delegation-declaration.d.ts +2 -0
  236. package/dist/modes/rpc/delegation-declaration.js +7 -3
  237. package/dist/modes/rpc/effect-commands.d.ts +33 -0
  238. package/dist/modes/rpc/host-capabilities.d.ts +1 -0
  239. package/dist/modes/rpc/host-capabilities.js +7 -1
  240. package/dist/modes/rpc/host-gc-evidence.d.ts +1 -1
  241. package/dist/modes/rpc/host-gc-evidence.js +9 -3
  242. package/dist/modes/rpc/host-gc.js +4 -1
  243. package/dist/modes/rpc/host-observe-request.d.ts +2 -0
  244. package/dist/modes/rpc/host-observe-request.js +6 -1
  245. package/dist/modes/rpc/host-park-ledger.d.ts +19 -0
  246. package/dist/modes/rpc/host-park-ledger.js +110 -0
  247. package/dist/modes/rpc/lifecycle-delivery.js +4 -1
  248. package/dist/modes/rpc/loopless-tool-handlers.d.ts +6 -0
  249. package/dist/modes/rpc/loopless-tool-handlers.js +14 -1
  250. package/dist/modes/rpc/media-placeholders.js +1 -0
  251. package/dist/modes/rpc/method-classes-schema-host.d.ts +42 -1
  252. package/dist/modes/rpc/method-classes-schema-host.js +24 -21
  253. package/dist/modes/rpc/method-classes-schema-session.d.ts +20 -0
  254. package/dist/modes/rpc/method-classes-schema-session.js +6 -0
  255. package/dist/modes/rpc/method-classes-schema.d.ts +62 -1
  256. package/dist/modes/rpc/method-classes-schema.js +5 -2
  257. package/dist/modes/rpc/method-classes.d.ts +4 -0
  258. package/dist/modes/rpc/method-classes.js +6 -0
  259. package/dist/modes/rpc/multi-session-host.js +1 -1
  260. package/dist/modes/rpc/project-file-commands.d.ts +32 -0
  261. package/dist/modes/rpc/project-file-commands.js +195 -0
  262. package/dist/modes/rpc/project-file-path.d.ts +34 -0
  263. package/dist/modes/rpc/project-file-path.js +93 -0
  264. package/dist/modes/rpc/rpc-error-types.d.ts +9 -1
  265. package/dist/modes/rpc/rpc-error-types.js +8 -0
  266. package/dist/modes/rpc/rpc-host-command-types.d.ts +14 -1
  267. package/dist/modes/rpc/rpc-host-response-types.d.ts +21 -0
  268. package/dist/modes/rpc/rpc-mutation-response-types.d.ts +7 -0
  269. package/dist/modes/rpc/rpc-read-response-types.d.ts +7 -0
  270. package/dist/modes/rpc/rpc-session-command-types.d.ts +10 -0
  271. package/dist/modes/rpc/rpc-session-state-types.d.ts +2 -0
  272. package/dist/modes/rpc/session-attachment-gate.js +6 -0
  273. package/dist/modes/rpc/session-binding.d.ts +1 -0
  274. package/dist/modes/rpc/session-binding.js +6 -1
  275. package/dist/modes/rpc/session-command-activity.js +1 -0
  276. package/dist/modes/rpc/session-connection-context.d.ts +2 -0
  277. package/dist/modes/rpc/session-connection-context.js +4 -0
  278. package/dist/modes/rpc/session-registry-attach.d.ts +2 -0
  279. package/dist/modes/rpc/session-registry-attach.js +15 -11
  280. package/dist/modes/rpc/session-registry-claims.js +2 -0
  281. package/dist/modes/rpc/session-registry-open.js +13 -7
  282. package/dist/modes/rpc/session-registry-opening.js +2 -1
  283. package/dist/modes/rpc/session-registry-types.d.ts +4 -0
  284. package/dist/modes/rpc/session-registry.d.ts +3 -0
  285. package/dist/modes/rpc/session-registry.js +27 -3
  286. package/dist/modes/rpc/session-router-close.js +1 -0
  287. package/dist/modes/rpc/session-router-context.d.ts +4 -2
  288. package/dist/modes/rpc/session-router-context.js +3 -0
  289. package/dist/modes/rpc/session-router-host-reads.js +1 -0
  290. package/dist/modes/rpc/session-router-occupancy.js +10 -1
  291. package/dist/modes/rpc/session-router-open-result.d.ts +12 -0
  292. package/dist/modes/rpc/session-router-open-result.js +63 -0
  293. package/dist/modes/rpc/session-router-open.d.ts +3 -0
  294. package/dist/modes/rpc/session-router-open.js +15 -63
  295. package/dist/modes/rpc/session-router-park.d.ts +15 -0
  296. package/dist/modes/rpc/session-router-park.js +176 -0
  297. package/dist/modes/rpc/session-router-routing.d.ts +1 -1
  298. package/dist/modes/rpc/session-router-routing.js +7 -0
  299. package/dist/modes/rpc/session-status-source.js +2 -2
  300. package/dist/private-fd-startup-fillers.d.ts +2 -2
  301. package/dist/private-fd-startup-fillers.js +34 -4
  302. package/dist/senpi +9 -3
  303. package/docs/engine-socket/fixtures/admission-routes/h-legacy.json +1 -1
  304. package/docs/engine-socket/fixtures/rpc-inbound-samples.json +44 -2
  305. package/docs/extensions.md +11 -1
  306. package/docs/rpc.md +106 -2
  307. package/docs/settings.md +5 -3
  308. package/docs/skills.md +1 -1
  309. package/docs/usage.md +1 -1
  310. package/native/socket-secret/prebuilds/win32-arm64/senpi_socket_secret.win32-arm64.node +0 -0
  311. package/native/socket-secret/prebuilds/win32-x64/senpi_socket_secret.win32-x64.node +0 -0
  312. package/package.json +6 -6
  313. package/dist/bundle/chunks/chunk-436DNN4Z.js +0 -2
  314. package/dist/bundle/chunks/chunk-DLAY7CIU.js +0 -2
  315. package/dist/bundle/chunks/chunk-SJI6UB23.js +0 -2
  316. package/dist/bundle/chunks/chunk-XH2MWTXA.js +0 -11
  317. package/dist/bundle/chunks/chunk-YK3ZZCHI.js +0 -2
  318. package/dist/bundle/chunks/openai-codex-responses-ABB2J43U.js +0 -10
  319. package/dist/bundle/chunks/rpc-mode-ZDUGW2IM.js +0 -2
  320. package/dist/bundle/chunks/session-control-endpoint-MEDV66PS.js +0 -3
@@ -1,21 +1,101 @@
1
+ /**
2
+ * Resolved-value registry shared by every copy of this module in one JavaScript realm (omo#12965).
3
+ *
4
+ * A process can evaluate this module more than once (the bundle's shared chunk, its self-contained session-worker
5
+ * entry, and the SDK graph an in-process child loads), so the values are not kept in a module-local set: the first
6
+ * copy pins a frozen registry on `globalThis` under `SLOT_KEY` (non-writable, non-configurable, non-enumerable) and
7
+ * every later copy adopts it. The backing `Set` lives only in the installing copy's closure; the registry offers no
8
+ * delete, clear or setter, so in-realm code cannot remove a value, replace the slot or turn redaction off. Any
9
+ * in-realm code can `add` a string, which can only over-redact. This is a stopgap until one engine instance serves
10
+ * the whole process; other realms (workers, `vm` contexts, child processes) keep their own registry.
11
+ *
12
+ * Compatibility contract, permanent: the key string never changes. The v1 members `version` (1), `add(value)`,
13
+ * `size` (an accessor reporting the live count) and `values()` (a fresh array) are never removed or repurposed; a
14
+ * later contract keeps writing through this same slot and only adds members, and adopters ignore members they do not
15
+ * know. A copy adopts only a slot pinned the way `pin` pins it, frozen, with those four members; anything else (a
16
+ * slot planted before the first copy loaded, an accessor, another version) makes the import throw
17
+ * `ConfigReferenceRedactionSlotError`, because a copy running with a private set is the leak this registry removes.
18
+ */
19
+ const SLOT_KEY_NAME = "@code-yeongyu/senpi/config-reference-redaction/v1";
20
+ const SLOT_KEY = Symbol.for(SLOT_KEY_NAME);
1
21
  const MIN_REDACTED_LENGTH = 4;
2
- const resolvedValues = new Set();
3
- let redactionForms;
22
+ /** The largest `$file` reference value (`config-reference-file.ts`); longer strings are never remembered. */
23
+ const MAX_REMEMBERED_LENGTH = 65_536;
24
+ class ConfigReferenceRedactionSlotError extends Error {
25
+ constructor(cause) {
26
+ super(`The process-wide redaction registry ${SLOT_KEY_NAME} was not installed by senpi or is incompatible; restart the process.`, cause === undefined ? undefined : { cause });
27
+ this.name = "ConfigReferenceRedactionSlotError";
28
+ this.code = "SENPI_REDACTION_SLOT_INCOMPATIBLE";
29
+ }
30
+ }
31
+ function createRegistry() {
32
+ const values = new Set();
33
+ return Object.freeze({
34
+ version: 1,
35
+ add(value) {
36
+ if (typeof value !== "string" || value.length < MIN_REDACTED_LENGTH || value.length > MAX_REMEMBERED_LENGTH)
37
+ return;
38
+ values.add(value);
39
+ },
40
+ get size() {
41
+ return values.size;
42
+ },
43
+ values: () => [...values],
44
+ });
45
+ }
46
+ function isFrozenV1Registry(value) {
47
+ return (typeof value === "object" &&
48
+ value !== null &&
49
+ Object.isFrozen(value) &&
50
+ Reflect.get(value, "version") === 1 &&
51
+ typeof Reflect.get(value, "add") === "function" &&
52
+ typeof Reflect.get(value, "values") === "function" &&
53
+ typeof Reflect.get(value, "size") === "number");
54
+ }
55
+ function pin(registry) {
56
+ try {
57
+ Object.defineProperty(globalThis, SLOT_KEY, {
58
+ value: registry,
59
+ writable: false,
60
+ configurable: false,
61
+ enumerable: false,
62
+ });
63
+ }
64
+ catch (error) {
65
+ throw new ConfigReferenceRedactionSlotError(error);
66
+ }
67
+ return registry;
68
+ }
69
+ function sharedRegistry() {
70
+ const slot = Reflect.getOwnPropertyDescriptor(globalThis, SLOT_KEY);
71
+ if (slot === undefined)
72
+ return pin(createRegistry());
73
+ const value = slot.value;
74
+ if (slot.writable !== false || slot.configurable !== false || !isFrozenV1Registry(value)) {
75
+ throw new ConfigReferenceRedactionSlotError();
76
+ }
77
+ return value;
78
+ }
79
+ const registry = sharedRegistry();
80
+ let redactionForms = [];
81
+ let formsSize = 0;
4
82
  /** Every value a reference resolves to is kept for the process lifetime, including rotated ones: no cap, no eviction. */
5
83
  export function rememberResolvedReferenceValue(value) {
6
- if (value.length < MIN_REDACTED_LENGTH || resolvedValues.has(value))
7
- return;
8
- resolvedValues.add(value);
9
- redactionForms = undefined;
84
+ registry.add(value);
10
85
  }
11
86
  function encodings(value) {
12
87
  const form = new URLSearchParams([["", value]]).toString().slice(1);
13
88
  return [value, JSON.stringify(value).slice(1, -1), encodeURIComponent(value), encodeURI(value), form];
14
89
  }
90
+ /** The registry is append-only, so a changed size is the only way its content can change. */
15
91
  function forms() {
16
- redactionForms ??= [...new Set([...resolvedValues].flatMap(encodings))]
17
- .filter((form) => form.length >= MIN_REDACTED_LENGTH)
18
- .sort((left, right) => right.length - left.length);
92
+ const size = registry.size;
93
+ if (size !== formsSize) {
94
+ redactionForms = [...new Set(registry.values().flatMap(encodings))]
95
+ .filter((form) => form.length >= MIN_REDACTED_LENGTH)
96
+ .sort((left, right) => right.length - left.length);
97
+ formsSize = size;
98
+ }
19
99
  return redactionForms;
20
100
  }
21
101
  /** Replaces every resolved reference value, raw or encoded, before text reaches a sink outside the process. */
@@ -134,7 +214,7 @@ function isProtocolValue(key, value) {
134
214
  return Object.hasOwn(PROTOCOL_VALUES, key) && PROTOCOL_VALUES[key]?.has(value) === true;
135
215
  }
136
216
  export function redactResolvedReferenceData(value) {
137
- if (resolvedValues.size === 0)
217
+ if (registry.size === 0)
138
218
  return value;
139
219
  const copies = new WeakMap();
140
220
  const pending = [];
@@ -16,6 +16,16 @@ export type ContextFiles = ContextFile[] & {
16
16
  export interface ContextFileLimits {
17
17
  maxBytesPerFile?: number;
18
18
  maxTotalBytes?: number;
19
+ /**
20
+ * The global (user-scope) context file to load instead of the agent-dir probe (senpi#5567).
21
+ * Honored from the user's own settings only (`SettingsManager.getGlobalContextFilePath`); a
22
+ * project's settings never set it. A leading `~` is expanded; a relative path resolves against
23
+ * the agent dir, like other paths in global settings; a directory runs the same candidate probe
24
+ * as the agent dir. Unset or blank keeps the agent-dir file. A path that is set but missing,
25
+ * unreadable, a special file, or a directory with no candidate falls back to the agent-dir probe
26
+ * and reports one warning diagnostic instead of erroring.
27
+ */
28
+ globalPath?: string;
19
29
  }
20
30
  export declare const DEFAULT_CONTEXT_FILE_MAX_BYTES: number;
21
31
  export declare const DEFAULT_CONTEXT_FILES_MAX_TOTAL_BYTES: number;
@@ -29,6 +29,47 @@ function loadContextFileFromDir(dir) {
29
29
  }
30
30
  return null;
31
31
  }
32
+ /**
33
+ * The global user-scope context file (senpi#5567). `contextFiles.globalPath` names a file (or a
34
+ * directory to probe for the usual candidates) to load in place of the agent-dir file. Precedence
35
+ * is defined and never errors: a blank or unset path keeps the agent-dir probe silently; a
36
+ * configured target that is missing, unreadable, a special file, or a directory with no candidates
37
+ * falls back to the agent-dir probe and returns one warning naming the configured path.
38
+ */
39
+ function loadGlobalContextFile(agentDir, globalPath) {
40
+ const explicit = typeof globalPath === "string" ? globalPath.trim() : "";
41
+ if (explicit === "")
42
+ return { file: loadContextFileFromDir(agentDir) };
43
+ const resolved = resolvePath(explicit, agentDir);
44
+ const fallBack = (problem) => ({
45
+ file: loadContextFileFromDir(agentDir),
46
+ diagnostic: {
47
+ type: "warning",
48
+ path: resolved,
49
+ message: `contextFiles.globalPath ${problem}; using the global context file from ${agentDir} instead.`,
50
+ },
51
+ });
52
+ let stats;
53
+ try {
54
+ stats = statSync(resolved);
55
+ }
56
+ catch (error) {
57
+ const code = error.code;
58
+ return fallBack(code === "ENOENT" || code === "ENOTDIR" ? "does not exist" : `could not be read (${String(error)})`);
59
+ }
60
+ if (stats.isDirectory()) {
61
+ const file = loadContextFileFromDir(resolved);
62
+ return file ? { file } : fallBack("is a directory with no AGENTS.md or CLAUDE.md");
63
+ }
64
+ if (!stats.isFile())
65
+ return fallBack("is not a regular file or directory");
66
+ try {
67
+ return { file: { path: resolved, content: stripBom(readFileSync(resolved, "utf-8")) } };
68
+ }
69
+ catch (error) {
70
+ return fallBack(`could not be read (${String(error)})`);
71
+ }
72
+ }
32
73
  /**
33
74
  * The main repo's context file that a nested linked worktree's own copy shadows: both
34
75
  * occupy the same logical repository scope, so loading both applies that context twice. Returns
@@ -142,21 +183,22 @@ function applyContextFileLimits(files, limits) {
142
183
  }
143
184
  return Object.assign(kept, { diagnostics });
144
185
  }
145
- /** Compares directories by their real path, ignoring case where the filesystem does (Windows). */
146
- function directoryKey(dir) {
147
- const real = canonicalizePath(resolvePath(dir));
186
+ /** Compares files and directories by their real path, ignoring case where the filesystem does (Windows). */
187
+ function pathKey(path) {
188
+ const real = canonicalizePath(resolvePath(path));
148
189
  return process.platform === "win32" ? real.toLowerCase() : real;
149
190
  }
150
191
  export function loadProjectContextFiles(options) {
151
192
  const resolvedCwd = resolvePath(options.cwd);
152
193
  const resolvedAgentDir = resolvePath(options.agentDir);
153
- const homeKey = directoryKey(options.homeDir ?? homedir());
194
+ const homeKey = pathKey(options.homeDir ?? homedir());
154
195
  const contextFiles = [];
196
+ // Real-path keys: a symlinked ancestor file that points at an already loaded file is the same file.
155
197
  const seenPaths = new Set();
156
- const globalContext = loadContextFileFromDir(resolvedAgentDir);
157
- if (globalContext) {
158
- contextFiles.push({ ...globalContext, scope: "user" });
159
- seenPaths.add(globalContext.path);
198
+ const globalContext = loadGlobalContextFile(resolvedAgentDir, options.globalPath);
199
+ if (globalContext.file) {
200
+ contextFiles.push({ ...globalContext.file, scope: "user" });
201
+ seenPaths.add(pathKey(globalContext.file.path));
160
202
  }
161
203
  const ancestorContextFiles = [];
162
204
  const shadowedContextFile = findShadowedContextFile(resolvedCwd);
@@ -164,9 +206,10 @@ export function loadProjectContextFiles(options) {
164
206
  while (true) {
165
207
  const contextFile = loadContextFileFromDir(currentDir);
166
208
  const isShadowed = shadowedContextFile !== undefined && canonicalizePath(contextFile?.path ?? "") === shadowedContextFile;
167
- if (contextFile && !isShadowed && !seenPaths.has(contextFile.path)) {
168
- ancestorContextFiles.unshift(directoryKey(currentDir) === homeKey ? { ...contextFile, scope: "user" } : contextFile);
169
- seenPaths.add(contextFile.path);
209
+ const contextFileKey = contextFile ? pathKey(contextFile.path) : undefined;
210
+ if (contextFile && contextFileKey !== undefined && !isShadowed && !seenPaths.has(contextFileKey)) {
211
+ ancestorContextFiles.unshift(pathKey(currentDir) === homeKey ? { ...contextFile, scope: "user" } : contextFile);
212
+ seenPaths.add(contextFileKey);
170
213
  }
171
214
  const parentDir = dirname(currentDir);
172
215
  if (parentDir === currentDir)
@@ -174,6 +217,9 @@ export function loadProjectContextFiles(options) {
174
217
  currentDir = parentDir;
175
218
  }
176
219
  contextFiles.push(...ancestorContextFiles);
177
- return applyContextFileLimits(contextFiles, options);
220
+ const limited = applyContextFileLimits(contextFiles, options);
221
+ if (globalContext.diagnostic)
222
+ limited.diagnostics.unshift(globalContext.diagnostic);
223
+ return limited;
178
224
  }
179
225
  //# sourceMappingURL=context-files.js.map
@@ -53,6 +53,8 @@ export type CredentialAccountCheck = {
53
53
  readonly model: string;
54
54
  readonly outcome: "ok" | "failed";
55
55
  readonly reason?: string;
56
+ readonly message?: string;
57
+ readonly status?: number;
56
58
  readonly at: number;
57
59
  };
58
60
  export declare function assertValidAccountName(name: string): void;
@@ -38,7 +38,16 @@ function storedCheck(slot) {
38
38
  if (model === undefined || at === undefined || (outcome !== "ok" && outcome !== "failed"))
39
39
  return undefined;
40
40
  const reason = stringField(check, "reason");
41
- return { model, outcome, ...(reason === undefined ? {} : { reason }), at };
41
+ const message = stringField(check, "message");
42
+ const status = numberField(check, "status");
43
+ return {
44
+ model,
45
+ outcome,
46
+ ...(reason === undefined ? {} : { reason }),
47
+ ...(message === undefined ? {} : { message }),
48
+ ...(status === undefined ? {} : { status }),
49
+ at,
50
+ };
42
51
  }
43
52
  /** The listing fields of a stored `claude-cli` slot, read defensively: auth.json is a trust boundary. */
44
53
  function claudeCliSlotFields(slot) {
@@ -24,7 +24,7 @@ const ROUTE_RULES = {
24
24
  full: `Route by true intent, not surface form:
25
25
  - Information asks (explain, look into, investigate): read the code, report the answer or findings - no edits, no fixes yet.
26
26
  - Judgment asks (what do you think, review) and open-ended changes (refactor, improve, clean up): assess and propose, then wait for confirmation.
27
- - 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.
27
+ - Change asks (implement, add, fix this error): build, or diagnose and fix at the cause, at exactly the asked scope - what fully satisfies an open-ended goal and nothing beyond it; name an ambiguity and resolve it from context when possible.
28
28
 
29
29
  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.
30
30
 
@@ -32,7 +32,7 @@ Derive intent from the latest user turn alone: a new direction drops the stale p
32
32
  diet: `Route by true intent, not surface form:
33
33
  - Information ask (explain, look into, investigate): read code, report answer/findings; no edits, no fixes yet.
34
34
  - Judgment ask (what do you think, review) / open-ended change (refactor, improve, clean up): assess, propose, wait for confirmation.
35
- - 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.
35
+ - Change ask (implement, add, fix this error): build, or diagnose + fix at the cause, exactly at asked scope = what fully satisfies an open-ended goal, nothing beyond; name ambiguity, resolve from context when possible.
36
36
 
37
37
  Deliver at asked scope; never quietly narrow, widen, swap. Routine calls: decide yourself; ask only when readings diverge into materially different work.
38
38
 
@@ -4,7 +4,7 @@ export function buildStyleSection(options = {}) {
4
4
  if (options.sharedSections === "full") {
5
5
  return `## Style
6
6
 
7
- 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.
7
+ This codebase is yours: what it's for and how it's built are your call, and you'll keep building on it. Change it the way its owner would: build on the code that already does the job instead of adding a parallel copy, fit new behavior into the structure that is there, and leave no duplicate or dead code behind. A defect in the code you are changing is yours to fix now; one elsewhere goes in your summary as a follow-up. 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.
8
8
 
9
9
  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.
10
10
 
@@ -16,7 +16,7 @@ Do not stop, summarize, or suggest a new session on account of context limits: t
16
16
  }
17
17
  return `## Style
18
18
 
19
- 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.
19
+ This codebase is yours: what it's for and how it's built are your call, and you'll keep building on it. Change it as its owner would: build on the code that already does the job, not a parallel copy; fit new behavior into the structure that is there; leave no duplicate or dead code behind. Defect in the code you are changing -> fix it now; elsewhere -> follow-up in your summary. 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.
20
20
 
21
21
  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.
22
22
 
@@ -69,7 +69,7 @@ Tier the scope, never the rigor.
69
69
 
70
70
  ${buildTestDisciplineSection("full")}
71
71
 
72
- "Should pass" is not verification - run the validator. Before reporting progress, audit each claim against a tool result from this session: ${FULL_CLAIM_AUDIT[terminalOrApp(options.surface ?? "terminal")]} Fix only issues your changes caused; note pre-existing failures separately.`;
72
+ "Should pass" is not verification - run the validator. Before reporting progress, audit each claim against a tool result from this session: ${FULL_CLAIM_AUDIT[terminalOrApp(options.surface ?? "terminal")]} Fix failures your change caused and any that sit in the code you changed; note other pre-existing failures separately.`;
73
73
  }
74
74
  return `## Verification
75
75
 
@@ -81,6 +81,6 @@ Tier the scope, never the rigor.
81
81
 
82
82
  ${buildTestDisciplineSection()}
83
83
 
84
- Before reporting progress: audit each claim against a tool result from this session; ${CLAIM_AUDIT[terminalOrApp(options.surface ?? "terminal")]} Fix only issues your changes caused; note pre-existing failures separately.`;
84
+ Before reporting progress: audit each claim against a tool result from this session; ${CLAIM_AUDIT[terminalOrApp(options.surface ?? "terminal")]} Fix failures your change caused and any that sit in the code you changed; note other pre-existing failures separately.`;
85
85
  }
86
86
  //# sourceMappingURL=verification.js.map
@@ -168,11 +168,24 @@ export interface HookModelRequest {
168
168
  readonly claim: SignedPlacementClaim;
169
169
  readonly input: HookModelRequestInput;
170
170
  }
171
+ /** A user hook's failure on the hand: reported with the reply, as a fused session reports it, never thrown. */
172
+ export interface HookFailure {
173
+ readonly extensionPath: string;
174
+ readonly event: string;
175
+ readonly error: string;
176
+ }
171
177
  export interface HookModelRequestReply {
172
178
  readonly t: "hook.model_request.reply";
173
179
  readonly sessionId: string;
174
180
  readonly stepId: string;
175
181
  readonly output: HookModelRequestInput;
182
+ /** The hooks that failed; `output` is what the others produced. Absent: none failed. */
183
+ readonly errors?: readonly HookFailure[];
184
+ /** The messages and notices the hooks sent during the call, as on every loop-hook reply (S33). Absent: none. */
185
+ readonly sent?: readonly WireJson[];
186
+ readonly notices?: readonly WireJson[];
187
+ /** Late messages and notices the hand dropped past its per-session bound. Absent: none. */
188
+ readonly droppedLate?: number;
176
189
  }
177
190
  export interface HandSessionAdvertisement {
178
191
  readonly t: "hand.session.advertise";
@@ -36,6 +36,9 @@ export type ClaudeCliAccountCheck = {
36
36
  model: string;
37
37
  outcome: "ok" | "failed";
38
38
  reason?: string;
39
+ /** Provider diagnostics, redacted before they enter the credential store. */
40
+ message?: string;
41
+ status?: number;
39
42
  at: number;
40
43
  };
41
44
  /**
@@ -12,7 +12,7 @@ import { accountDirFor, claudeCliSharedRoot, ensureAccountDir } from "./claude-c
12
12
  import { buildClaudeCliEnvironment } from "./claude-cli-environment.js";
13
13
  import { profileChanged, verifyClaudeCliInitialization } from "./claude-cli-token-source.js";
14
14
  import { writeConfigDirCredential } from "./config-dir-credentials.js";
15
- import { asksLegacyLongContext, CLAUDE_CODE_DEFAULT_CONTEXT_WINDOW } from "./context-window.js";
15
+ import { asksLegacyLongContext, CLAUDE_CODE_DEFAULT_CONTEXT_WINDOW, claudeCodeMaxContextTokens, } from "./context-window.js";
16
16
  import { isExtraUsageExhausted } from "./errors.js";
17
17
  import { runFailover } from "./failover.js";
18
18
  import { logContinuityEvent } from "./session-observability.js";
@@ -153,7 +153,8 @@ export async function* queryWithAuthLane(input) {
153
153
  options.model = options.model?.replace(/\[1m\]$/, "");
154
154
  options.env = {
155
155
  ...options.env,
156
- CLAUDE_CODE_MAX_CONTEXT_TOKENS: String(CLAUDE_CODE_DEFAULT_CONTEXT_WINDOW),
156
+ // Claude Code then refuses only past the 200k window itself; the prompt-plus-output check below keeps the fit.
157
+ CLAUDE_CODE_MAX_CONTEXT_TOKENS: String(claudeCodeMaxContextTokens(CLAUDE_CODE_DEFAULT_CONTEXT_WINDOW, outputReserveTokens)),
157
158
  // Reserve and request the same output budget, not the model catalog's ceiling.
158
159
  CLAUDE_CODE_MAX_OUTPUT_TOKENS: String(outputReserveTokens),
159
160
  };
@@ -61,7 +61,9 @@ export async function testClaudeCliAccount(input) {
61
61
  return stored;
62
62
  return {
63
63
  ...credential,
64
- accounts: (credential.accounts ?? []).map((slot) => slot.name === input.name ? checkedSlot(slot, check) : slot),
64
+ accounts: (credential.accounts ?? []).map((slot) => slot.name === input.name && slot.store === "claude-cli" && slot.dirId === before.dirId
65
+ ? checkedSlot(slot, check)
66
+ : slot),
65
67
  };
66
68
  });
67
69
  return check;
@@ -4,6 +4,8 @@ export type DefaultModelSelection = {
4
4
  readonly provider?: string;
5
5
  readonly model?: string;
6
6
  };
7
+ /** auth.json keeps the redacted provider message for the UI; a proxy's HTML error page must not bloat it. */
8
+ export declare const STORED_CHECK_MESSAGE_MAX_CHARS = 2000;
7
9
  /**
8
10
  * The model the sign-in connection test runs on: the default model when the default provider is this one, else the
9
11
  * provider's own default (`defaultModelPerProvider`), so the test exercises the model the user's turns will use.
@@ -21,7 +23,7 @@ export type ClaudeCliConnectionTestInput = {
21
23
  };
22
24
  /**
23
25
  * One "Reply with OK" turn on the named account, pinned with account fallback off, no tools, no setting sources and
24
- * no persisted session. The outcome is classified with the turn classifiers; only the kind is kept, never error text.
26
+ * no persisted session. The outcome uses the turn classifiers and retains the provider status and redacted message.
25
27
  */
26
28
  export declare function runClaudeCliConnectionTest(input: ClaudeCliConnectionTestInput): Promise<ClaudeCliAccountCheck>;
27
29
  //# sourceMappingURL=claude-cli-connection-test.d.ts.map
@@ -1,11 +1,25 @@
1
1
  import { defaultModelPerProvider } from "../../../model-resolver.js";
2
+ import { redactSecrets } from "../../../sensitive-output.js";
2
3
  import { ANTHROPIC_SUBSCRIPTION_PROVIDER_ID } from "./account-management.js";
3
4
  import { queryWithAuthLane } from "./auth-lane.js";
4
- import { classifySdkError, sdkAssistantFailure, sdkResultFailure } from "./errors.js";
5
+ import { classifySdkError, errorText, sdkAssistantFailure, sdkResultFailure } from "./errors.js";
5
6
  import { refusalError } from "./refusal.js";
6
7
  import { getSdkBoundary, loadClaudeAgentSdk } from "./sdk-boundary.js";
7
8
  const CONNECTION_TEST_PROMPT = "Reply with OK";
8
9
  const CONNECTION_TEST_TIMEOUT_MS = 60_000;
10
+ /** auth.json keeps the redacted provider message for the UI; a proxy's HTML error page must not bloat it. */
11
+ export const STORED_CHECK_MESSAGE_MAX_CHARS = 2_000;
12
+ function storedMessage(error) {
13
+ const message = redactSecrets(errorText(error));
14
+ if (message.length <= STORED_CHECK_MESSAGE_MAX_CHARS)
15
+ return message;
16
+ let end = STORED_CHECK_MESSAGE_MAX_CHARS - 1;
17
+ // Never end on the first half of a surrogate pair.
18
+ const last = message.charCodeAt(end - 1);
19
+ if (last >= 0xd800 && last <= 0xdbff)
20
+ end -= 1;
21
+ return `${message.slice(0, end)}…`;
22
+ }
9
23
  /**
10
24
  * The model the sign-in connection test runs on: the default model when the default provider is this one, else the
11
25
  * provider's own default (`defaultModelPerProvider`), so the test exercises the model the user's turns will use.
@@ -20,7 +34,7 @@ export function connectionTestModel(defaults) {
20
34
  }
21
35
  /**
22
36
  * One "Reply with OK" turn on the named account, pinned with account fallback off, no tools, no setting sources and
23
- * no persisted session. The outcome is classified with the turn classifiers; only the kind is kept, never error text.
37
+ * no persisted session. The outcome uses the turn classifiers and retains the provider status and redacted message.
24
38
  */
25
39
  export async function runClaudeCliConnectionTest(input) {
26
40
  const now = input.now ?? Date.now;
@@ -29,12 +43,27 @@ export async function runClaudeCliConnectionTest(input) {
29
43
  let handle;
30
44
  const closeOnAbort = () => handle?.close();
31
45
  signal.addEventListener("abort", closeOnAbort, { once: true });
32
- const finish = (outcome, reason) => ({
33
- model: input.model,
34
- outcome,
35
- ...(reason === undefined ? {} : { reason }),
36
- at: now(),
37
- });
46
+ const finish = (failure) => {
47
+ if (failure === undefined)
48
+ return { model: input.model, outcome: "ok", at: now() };
49
+ const { reason, error } = failure;
50
+ const status = failure.providerStatus ??
51
+ (error !== null && typeof error === "object" && "status" in error ? error.status : undefined);
52
+ return {
53
+ model: input.model,
54
+ outcome: "failed",
55
+ reason,
56
+ message: storedMessage(error),
57
+ ...(typeof status === "number" ? { status } : {}),
58
+ at: now(),
59
+ };
60
+ };
61
+ // The deadline and the caller's cancel win over whatever the SDK reports after close().
62
+ const abortedCheck = () => deadline.aborted
63
+ ? finish({ reason: "timeout", error: "Connection test timed out." })
64
+ : input.signal?.aborted
65
+ ? finish({ reason: "cancelled", error: "Connection test was cancelled." })
66
+ : undefined;
38
67
  try {
39
68
  await loadClaudeAgentSdk();
40
69
  const messages = queryWithAuthLane({
@@ -69,18 +98,20 @@ export async function runClaudeCliConnectionTest(input) {
69
98
  ? sdkResultFailure(message)
70
99
  : undefined);
71
100
  if (failure)
72
- throw failure;
101
+ return (abortedCheck() ??
102
+ finish({
103
+ reason: classifySdkError(failure).kind,
104
+ error: failure,
105
+ providerStatus: message.type === "result" && "api_error_status" in message ? message.api_error_status : undefined,
106
+ }));
73
107
  if (message.type === "result")
74
- return finish("ok");
108
+ return finish();
75
109
  }
76
- return finish("failed", signal.aborted ? (deadline.aborted ? "timeout" : "cancelled") : "no_result");
110
+ return (abortedCheck() ??
111
+ finish({ reason: "no_result", error: "Claude Code ended the connection test without a result." }));
77
112
  }
78
113
  catch (error) {
79
- if (deadline.aborted)
80
- return finish("failed", "timeout");
81
- if (input.signal?.aborted)
82
- return finish("failed", "cancelled");
83
- return finish("failed", classifySdkError(error).kind);
114
+ return abortedCheck() ?? finish({ reason: classifySdkError(error).kind, error });
84
115
  }
85
116
  finally {
86
117
  signal.removeEventListener("abort", closeOnAbort);
@@ -6,7 +6,7 @@ import type { ClaudeCliProfile } from "./claude-cli-auth-status.ts";
6
6
  */
7
7
  export declare function signedInSlot(previous: AccountSlot | undefined, name: string, dirId: string, profile: ClaudeCliProfile, at: number): ClaudeCliAccountSlot;
8
8
  export declare function withSlot(credential: AnthropicSubscriptionCredential, slot: AccountSlot): AnthropicSubscriptionCredential;
9
- export declare function withCheck(credential: AnthropicSubscriptionCredential, name: string, check: ClaudeCliAccountCheck): AnthropicSubscriptionCredential;
9
+ export declare function withCheck(credential: AnthropicSubscriptionCredential, name: string, check: ClaudeCliAccountCheck, dirId: string): AnthropicSubscriptionCredential;
10
10
  /**
11
11
  * The accounts with this login taken back. Only a slot that still points at this login's dir is touched: a new
12
12
  * account's slot is removed. For a re-login the login-bound fields always return to their previous values; every
@@ -27,10 +27,12 @@ export function withSlot(credential, slot) {
27
27
  ? { ...credential, accounts: accounts.map((candidate) => (candidate.name === slot.name ? slot : candidate)) }
28
28
  : { ...credential, accounts: [...accounts, slot] };
29
29
  }
30
- export function withCheck(credential, name, check) {
30
+ export function withCheck(credential, name, check, dirId) {
31
31
  return {
32
32
  ...credential,
33
- accounts: (credential.accounts ?? []).map((candidate) => candidate.name === name && candidate.store === "claude-cli" ? { ...candidate, check } : candidate),
33
+ accounts: (credential.accounts ?? []).map((candidate) => candidate.name === name && candidate.store === "claude-cli" && candidate.dirId === dirId
34
+ ? { ...candidate, check }
35
+ : candidate),
34
36
  };
35
37
  }
36
38
  /**
@@ -0,0 +1,20 @@
1
+ import type { ResolveSettingsOptions, ResolvedSettings, SettingSource } from "@anthropic-ai/claude-agent-sdk";
2
+ import { type AnthropicSubscriptionProviderSettings } from "./settings.ts";
3
+ export type ClaudeSettingsEnvResolver = (options: ResolveSettingsOptions) => Promise<ResolvedSettings>;
4
+ /**
5
+ * Read the effective `env` block Claude Code will apply from the settings files a query loads (senpi#2988 item 4).
6
+ * Uses the SDK's own settings merge engine, so the files, lookup rules and precedence are the CLI's, not a re-read.
7
+ * Returns undefined when no loaded settings file sets an `env` block, or when the merge fails — the caller then pins
8
+ * as if no settings lifetime existed, instead of failing the turn.
9
+ */
10
+ export declare function resolveClaudeSettingsEnv(input: {
11
+ cwd: string;
12
+ settingSources: SettingSource[];
13
+ }, resolveSettings?: ClaudeSettingsEnvResolver): Promise<Readonly<Record<string, string>> | undefined>;
14
+ /**
15
+ * The settings env for one stream's queries. An explicit `settingSources` list applies to every lane; otherwise only
16
+ * a preset-append ambient attempt loads user/project settings (the same rule `buildAnthropicSubscriptionQueryOptions`
17
+ * uses), so anything else resolves to nothing and no merge runs.
18
+ */
19
+ export declare function resolveQuerySettingsEnv(cwd: string, providerSettings: AnthropicSubscriptionProviderSettings): Promise<Readonly<Record<string, string>> | undefined>;
20
+ //# sourceMappingURL=claude-settings-env.d.ts.map
@@ -0,0 +1,39 @@
1
+ import { loadedClaudeAgentSdk } from "./sdk-boundary.lazy.js";
2
+ import { resolveSystemPromptMode } from "./settings.js";
3
+ async function defaultResolveSettings(options) {
4
+ const sdk = loadedClaudeAgentSdk();
5
+ if (!sdk) {
6
+ throw new Error(`Claude Agent SDK was not preloaded before 'resolveSettings'. ` +
7
+ `Await loadClaudeAgentSdk() on the entry path before reaching the SDK boundary.`);
8
+ }
9
+ return sdk.resolveSettings(options);
10
+ }
11
+ /**
12
+ * Read the effective `env` block Claude Code will apply from the settings files a query loads (senpi#2988 item 4).
13
+ * Uses the SDK's own settings merge engine, so the files, lookup rules and precedence are the CLI's, not a re-read.
14
+ * Returns undefined when no loaded settings file sets an `env` block, or when the merge fails — the caller then pins
15
+ * as if no settings lifetime existed, instead of failing the turn.
16
+ */
17
+ export async function resolveClaudeSettingsEnv(input, resolveSettings = defaultResolveSettings) {
18
+ try {
19
+ const resolved = await resolveSettings({ cwd: input.cwd, settingSources: input.settingSources });
20
+ const env = resolved.effective.env;
21
+ return env !== undefined && Object.keys(env).length > 0 ? env : undefined;
22
+ }
23
+ catch {
24
+ return undefined;
25
+ }
26
+ }
27
+ /**
28
+ * The settings env for one stream's queries. An explicit `settingSources` list applies to every lane; otherwise only
29
+ * a preset-append ambient attempt loads user/project settings (the same rule `buildAnthropicSubscriptionQueryOptions`
30
+ * uses), so anything else resolves to nothing and no merge runs.
31
+ */
32
+ export async function resolveQuerySettingsEnv(cwd, providerSettings) {
33
+ const settingSources = providerSettings.settingSources ??
34
+ (resolveSystemPromptMode(providerSettings).mode === "preset-append" ? ["user", "project"] : []);
35
+ if (settingSources.length === 0)
36
+ return undefined;
37
+ return resolveClaudeSettingsEnv({ cwd, settingSources });
38
+ }
39
+ //# sourceMappingURL=claude-settings-env.js.map
@@ -1,6 +1,23 @@
1
1
  import type { Api, Model } from "@earendil-works/pi-ai";
2
2
  /** Claude Code's default window when a request does not ask for the long context. */
3
3
  export declare const CLAUDE_CODE_DEFAULT_CONTEXT_WINDOW = 200000;
4
+ /**
5
+ * The `CLAUDE_CODE_MAX_CONTEXT_TOKENS` that makes Claude Code accept a conversation up to `window`.
6
+ *
7
+ * With `DISABLE_COMPACT` set, Claude Code takes that variable as the model's window, then refuses a
8
+ * request on its own, with no API call, once the conversation passes the window minus its output reserve
9
+ * (the request's output budget, capped at 20k) minus a 3k buffer. Handing it the bare planned window put
10
+ * that limit 23k below the window senpi compacts against, so every turn between the two failed in
11
+ * milliseconds with "Prompt is too long", and so did the summarization request of the recovery
12
+ * compaction. senpi keeps its own output reserve below `window`, so the variable carries the window plus
13
+ * Claude Code's reserve and Claude Code's limit lands on `window` itself.
14
+ *
15
+ * `outputTokens` is the output budget Claude Code reserves for the request. Without an explicit
16
+ * `CLAUDE_CODE_MAX_OUTPUT_TOKENS` it is the model's own default, which is at least the cap for every
17
+ * Claude model, so the cap is the default here; a larger addition only lets a request reach the API's own
18
+ * window check, whose error senpi's overflow recovery already parses.
19
+ */
20
+ export declare function claudeCodeMaxContextTokens(window: number, outputTokens?: number): number;
4
21
  /**
5
22
  * Models whose 1M window is reachable only through Claude Code's `[1m]` opt-in, which sends the legacy
6
23
  * `context-1m-2025-08-07` beta that a subscription without extra usage refuses. These are the rows of