@code-yeongyu/senpi 2026.8.9 → 2026.8.11-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 (321) hide show
  1. package/CHANGELOG.md +122 -0
  2. package/dist/brand-dir-migration.d.ts +28 -0
  3. package/dist/brand-dir-migration.d.ts.map +1 -0
  4. package/dist/brand-dir-migration.js +77 -0
  5. package/dist/brand-dir-migration.js.map +1 -0
  6. package/dist/cli/grok-neo-gate.d.ts +0 -8
  7. package/dist/cli/grok-neo-gate.d.ts.map +1 -1
  8. package/dist/cli/grok-neo-gate.js +4 -2
  9. package/dist/cli/grok-neo-gate.js.map +1 -1
  10. package/dist/cli-main.js +3 -0
  11. package/dist/cli-main.js.map +1 -1
  12. package/dist/cli.js +2 -2
  13. package/dist/cli.js.map +1 -1
  14. package/dist/config.d.ts +27 -1
  15. package/dist/config.d.ts.map +1 -1
  16. package/dist/config.js +41 -9
  17. package/dist/config.js.map +1 -1
  18. package/dist/core/agent-session.d.ts +4 -0
  19. package/dist/core/agent-session.d.ts.map +1 -1
  20. package/dist/core/agent-session.js +21 -3
  21. package/dist/core/agent-session.js.map +1 -1
  22. package/dist/core/brand.d.ts +79 -0
  23. package/dist/core/brand.d.ts.map +1 -0
  24. package/dist/core/brand.js +141 -0
  25. package/dist/core/brand.js.map +1 -0
  26. package/dist/core/dynamic-prompt/identity.d.ts.map +1 -1
  27. package/dist/core/dynamic-prompt/identity.js +2 -1
  28. package/dist/core/dynamic-prompt/identity.js.map +1 -1
  29. package/dist/core/experimental.d.ts.map +1 -1
  30. package/dist/core/experimental.js +2 -1
  31. package/dist/core/experimental.js.map +1 -1
  32. package/dist/core/extensions/builtin/cache-keepalive/index.d.ts +30 -0
  33. package/dist/core/extensions/builtin/cache-keepalive/index.d.ts.map +1 -0
  34. package/dist/core/extensions/builtin/cache-keepalive/index.js +281 -0
  35. package/dist/core/extensions/builtin/cache-keepalive/index.js.map +1 -0
  36. package/dist/core/extensions/builtin/claude-sdk-oauth/session-commit-boundary.d.ts.map +1 -1
  37. package/dist/core/extensions/builtin/claude-sdk-oauth/session-commit-boundary.js +10 -1
  38. package/dist/core/extensions/builtin/claude-sdk-oauth/session-commit-boundary.js.map +1 -1
  39. package/dist/core/extensions/builtin/compaction/index.js +9 -9
  40. package/dist/core/extensions/builtin/compaction/index.js.map +1 -1
  41. package/dist/core/extensions/builtin/compaction/log.d.ts.map +1 -1
  42. package/dist/core/extensions/builtin/compaction/log.js +2 -1
  43. package/dist/core/extensions/builtin/compaction/log.js.map +1 -1
  44. package/dist/core/extensions/builtin/config-reload/generated-shim-filter.d.ts.map +1 -1
  45. package/dist/core/extensions/builtin/config-reload/generated-shim-filter.js +4 -4
  46. package/dist/core/extensions/builtin/config-reload/generated-shim-filter.js.map +1 -1
  47. package/dist/core/extensions/builtin/goal/cache-warm-renderer.d.ts.map +1 -1
  48. package/dist/core/extensions/builtin/goal/cache-warm-renderer.js +21 -8
  49. package/dist/core/extensions/builtin/goal/cache-warm-renderer.js.map +1 -1
  50. package/dist/core/extensions/builtin/goal/cache-warm.d.ts +11 -2
  51. package/dist/core/extensions/builtin/goal/cache-warm.d.ts.map +1 -1
  52. package/dist/core/extensions/builtin/goal/cache-warm.js +16 -0
  53. package/dist/core/extensions/builtin/goal/cache-warm.js.map +1 -1
  54. package/dist/core/extensions/builtin/goal/index.d.ts.map +1 -1
  55. package/dist/core/extensions/builtin/goal/index.js +36 -1
  56. package/dist/core/extensions/builtin/goal/index.js.map +1 -1
  57. package/dist/core/extensions/builtin/goal/lifecycle-helpers.d.ts +2 -2
  58. package/dist/core/extensions/builtin/goal/lifecycle-helpers.d.ts.map +1 -1
  59. package/dist/core/extensions/builtin/goal/lifecycle-helpers.js +3 -3
  60. package/dist/core/extensions/builtin/goal/lifecycle-helpers.js.map +1 -1
  61. package/dist/core/extensions/builtin/goal/monitor-continuation.d.ts +2 -1
  62. package/dist/core/extensions/builtin/goal/monitor-continuation.d.ts.map +1 -1
  63. package/dist/core/extensions/builtin/goal/monitor-continuation.js +121 -54
  64. package/dist/core/extensions/builtin/goal/monitor-continuation.js.map +1 -1
  65. package/dist/core/extensions/builtin/goal/prompt.d.ts.map +1 -1
  66. package/dist/core/extensions/builtin/goal/prompt.js +4 -4
  67. package/dist/core/extensions/builtin/goal/prompt.js.map +1 -1
  68. package/dist/core/extensions/builtin/goal/store-changed-event.d.ts +8 -0
  69. package/dist/core/extensions/builtin/goal/store-changed-event.d.ts.map +1 -0
  70. package/dist/core/extensions/builtin/goal/store-changed-event.js +9 -0
  71. package/dist/core/extensions/builtin/goal/store-changed-event.js.map +1 -0
  72. package/dist/core/extensions/builtin/goal/store.d.ts +3 -2
  73. package/dist/core/extensions/builtin/goal/store.d.ts.map +1 -1
  74. package/dist/core/extensions/builtin/goal/store.js +128 -101
  75. package/dist/core/extensions/builtin/goal/store.js.map +1 -1
  76. package/dist/core/extensions/builtin/goal/wait-progress.js +5 -5
  77. package/dist/core/extensions/builtin/goal/wait-progress.js.map +1 -1
  78. package/dist/core/extensions/builtin/help/index.d.ts.map +1 -1
  79. package/dist/core/extensions/builtin/help/index.js +3 -2
  80. package/dist/core/extensions/builtin/help/index.js.map +1 -1
  81. package/dist/core/extensions/builtin/index.d.ts.map +1 -1
  82. package/dist/core/extensions/builtin/index.js +2 -0
  83. package/dist/core/extensions/builtin/index.js.map +1 -1
  84. package/dist/core/extensions/builtin/monitor-state-event.d.ts +16 -0
  85. package/dist/core/extensions/builtin/monitor-state-event.d.ts.map +1 -1
  86. package/dist/core/extensions/builtin/monitor-state-event.js +15 -0
  87. package/dist/core/extensions/builtin/monitor-state-event.js.map +1 -1
  88. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.d.ts.map +1 -1
  89. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.js +2 -1
  90. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.js.map +1 -1
  91. package/dist/core/extensions/builtin/prompt-preset/claude-opus-5.d.ts.map +1 -1
  92. package/dist/core/extensions/builtin/prompt-preset/claude-opus-5.js +2 -1
  93. package/dist/core/extensions/builtin/prompt-preset/claude-opus-5.js.map +1 -1
  94. package/dist/core/extensions/builtin/prompt-preset/gpt-5.5.d.ts.map +1 -1
  95. package/dist/core/extensions/builtin/prompt-preset/gpt-5.5.js +2 -1
  96. package/dist/core/extensions/builtin/prompt-preset/gpt-5.5.js.map +1 -1
  97. package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.d.ts.map +1 -1
  98. package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js +2 -1
  99. package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js.map +1 -1
  100. package/dist/core/extensions/builtin/prompt-preset/grok-4.5.d.ts.map +1 -1
  101. package/dist/core/extensions/builtin/prompt-preset/grok-4.5.js +6 -5
  102. package/dist/core/extensions/builtin/prompt-preset/grok-4.5.js.map +1 -1
  103. package/dist/core/extensions/builtin/prompt-preset/kimi-k3.d.ts.map +1 -1
  104. package/dist/core/extensions/builtin/prompt-preset/kimi-k3.js +2 -1
  105. package/dist/core/extensions/builtin/prompt-preset/kimi-k3.js.map +1 -1
  106. package/dist/core/extensions/builtin/terminal/extension.d.ts.map +1 -1
  107. package/dist/core/extensions/builtin/terminal/extension.js +7 -8
  108. package/dist/core/extensions/builtin/terminal/extension.js.map +1 -1
  109. package/dist/core/extensions/builtin/terminal/session-bundle.d.ts +3 -3
  110. package/dist/core/extensions/builtin/terminal/session-bundle.d.ts.map +1 -1
  111. package/dist/core/extensions/builtin/terminal/session-bundle.js.map +1 -1
  112. package/dist/core/extensions/index.d.ts +1 -1
  113. package/dist/core/extensions/index.d.ts.map +1 -1
  114. package/dist/core/extensions/index.js.map +1 -1
  115. package/dist/core/extensions/loader.d.ts.map +1 -1
  116. package/dist/core/extensions/loader.js +7 -0
  117. package/dist/core/extensions/loader.js.map +1 -1
  118. package/dist/core/extensions/runner.d.ts +4 -0
  119. package/dist/core/extensions/runner.d.ts.map +1 -1
  120. package/dist/core/extensions/runner.js +19 -2
  121. package/dist/core/extensions/runner.js.map +1 -1
  122. package/dist/core/extensions/types.d.ts +50 -0
  123. package/dist/core/extensions/types.d.ts.map +1 -1
  124. package/dist/core/extensions/types.js.map +1 -1
  125. package/dist/core/footer-data-provider.d.ts +1 -4
  126. package/dist/core/footer-data-provider.d.ts.map +1 -1
  127. package/dist/core/footer-data-provider.js +0 -7
  128. package/dist/core/footer-data-provider.js.map +1 -1
  129. package/dist/core/generated-shim-banner.d.ts +15 -0
  130. package/dist/core/generated-shim-banner.d.ts.map +1 -0
  131. package/dist/core/generated-shim-banner.js +26 -0
  132. package/dist/core/generated-shim-banner.js.map +1 -0
  133. package/dist/core/model-runtime.d.ts.map +1 -1
  134. package/dist/core/model-runtime.js +7 -3
  135. package/dist/core/model-runtime.js.map +1 -1
  136. package/dist/core/package-manager.d.ts.map +1 -1
  137. package/dist/core/package-manager.js +2 -1
  138. package/dist/core/package-manager.js.map +1 -1
  139. package/dist/core/resource-loader.d.ts +4 -0
  140. package/dist/core/resource-loader.d.ts.map +1 -1
  141. package/dist/core/resource-loader.js +9 -5
  142. package/dist/core/resource-loader.js.map +1 -1
  143. package/dist/core/session-log.d.ts.map +1 -1
  144. package/dist/core/session-log.js +4 -2
  145. package/dist/core/session-log.js.map +1 -1
  146. package/dist/core/session-manager.d.ts +1 -1
  147. package/dist/core/session-manager.d.ts.map +1 -1
  148. package/dist/core/session-manager.js.map +1 -1
  149. package/dist/core/settings-manager.d.ts +10 -0
  150. package/dist/core/settings-manager.d.ts.map +1 -1
  151. package/dist/core/settings-manager.js +17 -2
  152. package/dist/core/settings-manager.js.map +1 -1
  153. package/dist/core/telemetry.d.ts.map +1 -1
  154. package/dist/core/telemetry.js +2 -1
  155. package/dist/core/telemetry.js.map +1 -1
  156. package/dist/core/timings.d.ts +0 -4
  157. package/dist/core/timings.d.ts.map +1 -1
  158. package/dist/core/timings.js +2 -1
  159. package/dist/core/timings.js.map +1 -1
  160. package/dist/core/tools/edit.d.ts +3 -1
  161. package/dist/core/tools/edit.d.ts.map +1 -1
  162. package/dist/core/tools/edit.js +12 -0
  163. package/dist/core/tools/edit.js.map +1 -1
  164. package/dist/core/tools/filesystem-policy.d.ts +10 -0
  165. package/dist/core/tools/filesystem-policy.d.ts.map +1 -0
  166. package/dist/core/tools/filesystem-policy.js +59 -0
  167. package/dist/core/tools/filesystem-policy.js.map +1 -0
  168. package/dist/core/tools/find.d.ts +3 -1
  169. package/dist/core/tools/find.d.ts.map +1 -1
  170. package/dist/core/tools/find.js +15 -0
  171. package/dist/core/tools/find.js.map +1 -1
  172. package/dist/core/tools/grep.d.ts +3 -1
  173. package/dist/core/tools/grep.d.ts.map +1 -1
  174. package/dist/core/tools/grep.js +16 -1
  175. package/dist/core/tools/grep.js.map +1 -1
  176. package/dist/core/tools/ls.d.ts +3 -1
  177. package/dist/core/tools/ls.d.ts.map +1 -1
  178. package/dist/core/tools/ls.js +11 -0
  179. package/dist/core/tools/ls.js.map +1 -1
  180. package/dist/core/tools/read.d.ts +3 -1
  181. package/dist/core/tools/read.d.ts.map +1 -1
  182. package/dist/core/tools/read.js +13 -0
  183. package/dist/core/tools/read.js.map +1 -1
  184. package/dist/core/tools/write.d.ts +3 -1
  185. package/dist/core/tools/write.d.ts.map +1 -1
  186. package/dist/core/tools/write.js +12 -0
  187. package/dist/core/tools/write.js.map +1 -1
  188. package/dist/index.d.ts +1 -1
  189. package/dist/index.d.ts.map +1 -1
  190. package/dist/index.js.map +1 -1
  191. package/dist/inspector-policy.d.ts.map +1 -1
  192. package/dist/inspector-policy.js +2 -1
  193. package/dist/inspector-policy.js.map +1 -1
  194. package/dist/main.d.ts.map +1 -1
  195. package/dist/main.js +5 -4
  196. package/dist/main.js.map +1 -1
  197. package/dist/migrations.d.ts.map +1 -1
  198. package/dist/migrations.js +4 -0
  199. package/dist/migrations.js.map +1 -1
  200. package/dist/modes/app-server/threads/goal-handlers.d.ts.map +1 -1
  201. package/dist/modes/app-server/threads/goal-handlers.js +7 -0
  202. package/dist/modes/app-server/threads/goal-handlers.js.map +1 -1
  203. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  204. package/dist/modes/interactive/components/footer.js +1 -6
  205. package/dist/modes/interactive/components/footer.js.map +1 -1
  206. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  207. package/dist/modes/interactive/interactive-mode.js +7 -7
  208. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  209. package/dist/modes/interactive/tips/catalog/cli-tips.d.ts.map +1 -1
  210. package/dist/modes/interactive/tips/catalog/cli-tips.js +2 -1
  211. package/dist/modes/interactive/tips/catalog/cli-tips.js.map +1 -1
  212. package/dist/modes/interactive/tips/catalog/ethos-tips.d.ts.map +1 -1
  213. package/dist/modes/interactive/tips/catalog/ethos-tips.js +4 -3
  214. package/dist/modes/interactive/tips/catalog/ethos-tips.js.map +1 -1
  215. package/dist/modes/interactive/tips/catalog/model-tips.d.ts.map +1 -1
  216. package/dist/modes/interactive/tips/catalog/model-tips.js +2 -1
  217. package/dist/modes/interactive/tips/catalog/model-tips.js.map +1 -1
  218. package/dist/modes/interactive/tips/catalog/session-tips.d.ts.map +1 -1
  219. package/dist/modes/interactive/tips/catalog/session-tips.js +2 -1
  220. package/dist/modes/interactive/tips/catalog/session-tips.js.map +1 -1
  221. package/dist/modes/interactive/tips/catalog/settings-tips.d.ts.map +1 -1
  222. package/dist/modes/interactive/tips/catalog/settings-tips.js +3 -2
  223. package/dist/modes/interactive/tips/catalog/settings-tips.js.map +1 -1
  224. package/dist/modes/interactive/tips/catalog/workspace-tips.d.ts.map +1 -1
  225. package/dist/modes/interactive/tips/catalog/workspace-tips.js +4 -3
  226. package/dist/modes/interactive/tips/catalog/workspace-tips.js.map +1 -1
  227. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  228. package/dist/modes/rpc/rpc-mode.js +2 -1
  229. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  230. package/dist/nearest-parent-config.d.ts +6 -1
  231. package/dist/nearest-parent-config.d.ts.map +1 -1
  232. package/dist/nearest-parent-config.js +18 -2
  233. package/dist/nearest-parent-config.js.map +1 -1
  234. package/dist/package-manager-cli.d.ts.map +1 -1
  235. package/dist/package-manager-cli.js +13 -1
  236. package/dist/package-manager-cli.js.map +1 -1
  237. package/dist/rpc-entry.js +2 -0
  238. package/dist/rpc-entry.js.map +1 -1
  239. package/dist/self-update-bootstrap.d.ts.map +1 -1
  240. package/dist/self-update-bootstrap.js +6 -0
  241. package/dist/self-update-bootstrap.js.map +1 -1
  242. package/dist/senpi +2 -2
  243. package/dist/utils/pi-user-agent.d.ts +1 -1
  244. package/dist/utils/pi-user-agent.d.ts.map +1 -1
  245. package/dist/utils/pi-user-agent.js +4 -3
  246. package/dist/utils/pi-user-agent.js.map +1 -1
  247. package/dist/utils/tools-manager.d.ts.map +1 -1
  248. package/dist/utils/tools-manager.js +2 -1
  249. package/dist/utils/tools-manager.js.map +1 -1
  250. package/dist/utils/version-check.d.ts +3 -0
  251. package/dist/utils/version-check.d.ts.map +1 -1
  252. package/dist/utils/version-check.js +37 -6
  253. package/dist/utils/version-check.js.map +1 -1
  254. package/docs/extensions.md +76 -0
  255. package/docs/providers.md +23 -3
  256. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +50 -0
  257. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  258. package/node_modules/@code-yeongyu/senpi-codemode/src/extension/{resumption-channel.ts → wake-source-state.ts} +9 -9
  259. package/node_modules/@code-yeongyu/senpi-codemode/src/index.ts +7 -7
  260. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-manager.ts +12 -11
  261. package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
  262. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts +3 -1
  263. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts.map +1 -1
  264. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js +13 -0
  265. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js.map +1 -1
  266. package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.d.ts.map +1 -1
  267. package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.js +6 -3
  268. package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.js.map +1 -1
  269. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.d.ts.map +1 -1
  270. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js +4 -2
  271. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js.map +1 -1
  272. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts.map +1 -1
  273. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +6 -2
  274. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js.map +1 -1
  275. package/node_modules/@earendil-works/pi-ai/dist/api/warm-prompt-cache.d.ts +17 -0
  276. package/node_modules/@earendil-works/pi-ai/dist/api/warm-prompt-cache.d.ts.map +1 -0
  277. package/node_modules/@earendil-works/pi-ai/dist/api/warm-prompt-cache.js +52 -0
  278. package/node_modules/@earendil-works/pi-ai/dist/api/warm-prompt-cache.js.map +1 -0
  279. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/openai-codex.d.ts.map +1 -1
  280. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/openai-codex.js +2 -1
  281. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/openai-codex.js.map +1 -1
  282. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +3 -1
  283. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
  284. package/node_modules/@earendil-works/pi-ai/dist/index.js +3 -1
  285. package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
  286. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  287. package/node_modules/@earendil-works/pi-ai/dist/providers/data/moonshotai-cn.json +1 -1
  288. package/node_modules/@earendil-works/pi-ai/dist/providers/data/moonshotai.json +1 -1
  289. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  290. package/node_modules/@earendil-works/pi-ai/dist/providers/data/together.json +1 -1
  291. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  292. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/recovery-stream.d.ts.map +1 -1
  293. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/recovery-stream.js +120 -1
  294. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/recovery-stream.js.map +1 -1
  295. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +2 -0
  296. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
  297. package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
  298. package/node_modules/@earendil-works/pi-ai/dist/utils/prompt-cache-ttl.d.ts +3 -1
  299. package/node_modules/@earendil-works/pi-ai/dist/utils/prompt-cache-ttl.d.ts.map +1 -1
  300. package/node_modules/@earendil-works/pi-ai/dist/utils/prompt-cache-ttl.js +17 -3
  301. package/node_modules/@earendil-works/pi-ai/dist/utils/prompt-cache-ttl.js.map +1 -1
  302. package/node_modules/@earendil-works/pi-ai/dist/wire-identity.d.ts +14 -0
  303. package/node_modules/@earendil-works/pi-ai/dist/wire-identity.d.ts.map +1 -0
  304. package/node_modules/@earendil-works/pi-ai/dist/wire-identity.js +24 -0
  305. package/node_modules/@earendil-works/pi-ai/dist/wire-identity.js.map +1 -0
  306. package/node_modules/@earendil-works/pi-ai/package.json +1 -1
  307. package/node_modules/@earendil-works/pi-pty/dist/pipe-fallback.d.ts.map +1 -1
  308. package/node_modules/@earendil-works/pi-pty/dist/pipe-fallback.js +11 -3
  309. package/node_modules/@earendil-works/pi-pty/dist/pipe-fallback.js.map +1 -1
  310. package/node_modules/@earendil-works/pi-pty/native/prebuilds/darwin-arm64/senpi_pty.darwin-arm64.node +0 -0
  311. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  312. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  313. package/package.json +6 -6
  314. package/dist/core/extensions/builtin/resumption-channel-event.d.ts +0 -13
  315. package/dist/core/extensions/builtin/resumption-channel-event.d.ts.map +0 -1
  316. package/dist/core/extensions/builtin/resumption-channel-event.js +0 -13
  317. package/dist/core/extensions/builtin/resumption-channel-event.js.map +0 -1
  318. package/dist/core/omo-native-detect.d.ts +0 -3
  319. package/dist/core/omo-native-detect.d.ts.map +0 -1
  320. package/dist/core/omo-native-detect.js +0 -58
  321. package/dist/core/omo-native-detect.js.map +0 -1
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Brand profile resolution.
3
+ *
4
+ * A distribution that repackages this engine (for example the `omo-ai` package) injects a
5
+ * single JSON environment variable describing how the product presents itself. The engine
6
+ * parses it once at startup and then REMOVES it from the environment, so nested processes
7
+ * spawned by tools inherit a clean environment and keep the engine's own identity.
8
+ *
9
+ * Absent or malformed input leaves every brand-derived value at its standalone default, so a
10
+ * plain install behaves exactly as it did before this module existed.
11
+ */
12
+ /** Environment variable carrying the JSON brand profile. */
13
+ export declare const BRAND_ENV_VAR = "SENPI_BRAND";
14
+ /**
15
+ * Where a repackaging distribution publishes itself. Without this the engine keeps checking
16
+ * its own package, which would advertise an update the branded product cannot install.
17
+ */
18
+ export interface BrandUpdateChannel {
19
+ /** Registry package that ships the branded product, e.g. `omo-ai`. */
20
+ readonly packageName: string;
21
+ /** Dist-tag the product publishes on, e.g. `beta`. */
22
+ readonly distTag: string;
23
+ /** Command shown to the user, e.g. `npm i -g omo-ai@beta`. */
24
+ readonly command: string;
25
+ /** Release notes URL; `{version}` is replaced with the available version. */
26
+ readonly changelogUrl?: string;
27
+ }
28
+ export interface BrandProfile {
29
+ /** Product name shown to users and to the model. */
30
+ readonly name: string;
31
+ /** Version shown in the header, terminal titles and `--version`. */
32
+ readonly displayVersion?: string;
33
+ /** Config directory name, e.g. `.omo`. */
34
+ readonly configDir: string;
35
+ /** When true the agent state lives directly under the config directory, with no `agent` segment. */
36
+ readonly flatLayout: boolean;
37
+ /** Prefix for the product's environment variables, e.g. `OMO`. */
38
+ readonly envPrefix: string;
39
+ /** Product token used in the outgoing user agent. */
40
+ readonly userAgent: string;
41
+ /** Product token used as the provider-side originator, when the distribution overrides it. */
42
+ readonly originator?: string;
43
+ /** Update channel of the branded product; absent means the product manages updates itself. */
44
+ readonly update?: BrandUpdateChannel;
45
+ }
46
+ /**
47
+ * Parses a brand profile. Returns undefined for absent, malformed, or nameless input; a
48
+ * malformed profile is reported once on stderr and never throws, because a broken brand
49
+ * must not stop the agent from starting.
50
+ */
51
+ export declare function parseBrandProfile(raw: string | undefined): BrandProfile | undefined;
52
+ /**
53
+ * Parses the brand profile without touching the environment.
54
+ *
55
+ * The CLI entrypoint re-spawns the real agent as a child process and hands it `process.env`,
56
+ * so the variable has to survive that hop. Scrubbing therefore happens explicitly in the
57
+ * process that actually runs the agent - see `scrubBrandFromEnvironment`.
58
+ */
59
+ export declare function consumeBrandProfile(env?: NodeJS.ProcessEnv): BrandProfile | undefined;
60
+ /**
61
+ * Removes the brand variable so tools spawning the engine again inherit a clean environment
62
+ * and keep the engine's own identity. Called once the profile has been resolved by the
63
+ * process that runs the agent loop.
64
+ */
65
+ export declare function scrubBrandFromEnvironment(env?: NodeJS.ProcessEnv): void;
66
+ /**
67
+ * The active brand profile, resolved (and scrubbed from the environment) on first use.
68
+ */
69
+ export declare function brandProfile(): BrandProfile | undefined;
70
+ /** exported for tests only */
71
+ export declare function resetBrandProfileForTests(): void;
72
+ /** Environment variable names for one setting, most specific first. */
73
+ export declare function brandEnvNames(suffix: string, profile?: BrandProfile | undefined): string[];
74
+ /**
75
+ * Reads one setting across the brand's prefix and the legacy prefixes, returning the first
76
+ * DEFINED value so that an explicitly empty value keeps its existing meaning.
77
+ */
78
+ export declare function envValue(suffix: string, env?: NodeJS.ProcessEnv): string | undefined;
79
+ //# sourceMappingURL=brand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brand.d.ts","sourceRoot":"","sources":["../../src/core/brand.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,4DAA4D;AAC5D,eAAO,MAAM,aAAa,gBAAgB,CAAC;AAE3C;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IAClC,sEAAsE;IACtE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,sDAAsD;IACtD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,6EAA6E;IAC7E,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,YAAY;IAC5B,oDAAoD;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,0CAA0C;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,oGAAoG;IACpG,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,kEAAkE;IAClE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,qDAAqD;IACrD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,8FAA8F;IAC9F,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,8FAA8F;IAC9F,QAAQ,CAAC,MAAM,CAAC,EAAE,kBAAkB,CAAC;CACrC;AAiCD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,GAAG,SAAS,CAuCnF;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,YAAY,GAAG,SAAS,CAElG;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,IAAI,CAEpF;AAWD;;GAEG;AACH,wBAAgB,YAAY,IAAI,YAAY,GAAG,SAAS,CAMvD;AAED,8BAA8B;AAC9B,wBAAgB,yBAAyB,IAAI,IAAI,CAGhD;AAED,uEAAuE;AACvE,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,2BAAiB,GAAG,MAAM,EAAE,CAKhF;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,SAAS,CAMjG"}
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Brand profile resolution.
3
+ *
4
+ * A distribution that repackages this engine (for example the `omo-ai` package) injects a
5
+ * single JSON environment variable describing how the product presents itself. The engine
6
+ * parses it once at startup and then REMOVES it from the environment, so nested processes
7
+ * spawned by tools inherit a clean environment and keep the engine's own identity.
8
+ *
9
+ * Absent or malformed input leaves every brand-derived value at its standalone default, so a
10
+ * plain install behaves exactly as it did before this module existed.
11
+ */
12
+ /** Environment variable carrying the JSON brand profile. */
13
+ export const BRAND_ENV_VAR = "SENPI_BRAND";
14
+ function readUpdateChannel(source) {
15
+ const update = source.update;
16
+ if (typeof update !== "object" || update === null || Array.isArray(update))
17
+ return undefined;
18
+ const channel = update;
19
+ const packageName = readString(channel, "packageName");
20
+ const command = readString(channel, "command");
21
+ if (!packageName || !command)
22
+ return undefined;
23
+ return {
24
+ packageName,
25
+ distTag: readString(channel, "distTag") || "latest",
26
+ command,
27
+ changelogUrl: readString(channel, "changelogUrl"),
28
+ };
29
+ }
30
+ /**
31
+ * A config directory names ONE entry inside the home directory. Anything carrying a separator or
32
+ * a parent reference would move agent state - and the migration that copies into it - somewhere
33
+ * the user never agreed to, so such a profile is rejected rather than sanitised.
34
+ */
35
+ function isSafeConfigDirName(value) {
36
+ return value !== "." && value !== ".." && !/[\\/]/.test(value);
37
+ }
38
+ function readString(source, key) {
39
+ const value = source[key];
40
+ return typeof value === "string" && value.trim() ? value.trim() : undefined;
41
+ }
42
+ /**
43
+ * Parses a brand profile. Returns undefined for absent, malformed, or nameless input; a
44
+ * malformed profile is reported once on stderr and never throws, because a broken brand
45
+ * must not stop the agent from starting.
46
+ */
47
+ export function parseBrandProfile(raw) {
48
+ if (!raw?.trim())
49
+ return undefined;
50
+ let parsed;
51
+ try {
52
+ parsed = JSON.parse(raw);
53
+ }
54
+ catch {
55
+ process.stderr.write(`warning: ignoring malformed ${BRAND_ENV_VAR} (expected JSON)\n`);
56
+ return undefined;
57
+ }
58
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
59
+ process.stderr.write(`warning: ignoring malformed ${BRAND_ENV_VAR} (expected a JSON object)\n`);
60
+ return undefined;
61
+ }
62
+ const source = parsed;
63
+ const name = readString(source, "name");
64
+ if (!name) {
65
+ process.stderr.write(`warning: ignoring ${BRAND_ENV_VAR} without a "name"\n`);
66
+ return undefined;
67
+ }
68
+ const configDir = readString(source, "configDir") || `.${name}`;
69
+ if (!isSafeConfigDirName(configDir)) {
70
+ process.stderr.write(`warning: ignoring ${BRAND_ENV_VAR} with an unsafe "configDir"\n`);
71
+ return undefined;
72
+ }
73
+ return {
74
+ name,
75
+ displayVersion: readString(source, "displayVersion"),
76
+ configDir,
77
+ flatLayout: source.flatLayout === true,
78
+ envPrefix: (readString(source, "envPrefix") || name).toUpperCase(),
79
+ userAgent: readString(source, "userAgent") || name,
80
+ originator: readString(source, "originator"),
81
+ update: readUpdateChannel(source),
82
+ };
83
+ }
84
+ /**
85
+ * Parses the brand profile without touching the environment.
86
+ *
87
+ * The CLI entrypoint re-spawns the real agent as a child process and hands it `process.env`,
88
+ * so the variable has to survive that hop. Scrubbing therefore happens explicitly in the
89
+ * process that actually runs the agent - see `scrubBrandFromEnvironment`.
90
+ */
91
+ export function consumeBrandProfile(env = process.env) {
92
+ return parseBrandProfile(env[BRAND_ENV_VAR]);
93
+ }
94
+ /**
95
+ * Removes the brand variable so tools spawning the engine again inherit a clean environment
96
+ * and keep the engine's own identity. Called once the profile has been resolved by the
97
+ * process that runs the agent loop.
98
+ */
99
+ export function scrubBrandFromEnvironment(env = process.env) {
100
+ delete env[BRAND_ENV_VAR];
101
+ }
102
+ /**
103
+ * Environment prefixes read after the brand's own prefix, so a machine configured before the
104
+ * rebrand keeps working unchanged.
105
+ */
106
+ const LEGACY_ENV_PREFIXES = ["SENPI", "PI"];
107
+ let cachedProfile;
108
+ let profileResolved = false;
109
+ /**
110
+ * The active brand profile, resolved (and scrubbed from the environment) on first use.
111
+ */
112
+ export function brandProfile() {
113
+ if (!profileResolved) {
114
+ cachedProfile = consumeBrandProfile();
115
+ profileResolved = true;
116
+ }
117
+ return cachedProfile;
118
+ }
119
+ /** exported for tests only */
120
+ export function resetBrandProfileForTests() {
121
+ cachedProfile = undefined;
122
+ profileResolved = false;
123
+ }
124
+ /** Environment variable names for one setting, most specific first. */
125
+ export function brandEnvNames(suffix, profile = brandProfile()) {
126
+ const prefixes = [profile?.envPrefix, ...LEGACY_ENV_PREFIXES].filter((prefix) => typeof prefix === "string" && prefix.length > 0);
127
+ return [...new Set(prefixes)].map((prefix) => `${prefix}_${suffix}`);
128
+ }
129
+ /**
130
+ * Reads one setting across the brand's prefix and the legacy prefixes, returning the first
131
+ * DEFINED value so that an explicitly empty value keeps its existing meaning.
132
+ */
133
+ export function envValue(suffix, env = process.env) {
134
+ for (const name of brandEnvNames(suffix)) {
135
+ const value = env[name];
136
+ if (value !== undefined)
137
+ return value;
138
+ }
139
+ return undefined;
140
+ }
141
+ //# sourceMappingURL=brand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brand.js","sourceRoot":"","sources":["../../src/core/brand.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Brand profile resolution.\n *\n * A distribution that repackages this engine (for example the `omo-ai` package) injects a\n * single JSON environment variable describing how the product presents itself. The engine\n * parses it once at startup and then REMOVES it from the environment, so nested processes\n * spawned by tools inherit a clean environment and keep the engine's own identity.\n *\n * Absent or malformed input leaves every brand-derived value at its standalone default, so a\n * plain install behaves exactly as it did before this module existed.\n */\n\n/** Environment variable carrying the JSON brand profile. */\nexport const BRAND_ENV_VAR = \"SENPI_BRAND\";\n\n/**\n * Where a repackaging distribution publishes itself. Without this the engine keeps checking\n * its own package, which would advertise an update the branded product cannot install.\n */\nexport interface BrandUpdateChannel {\n\t/** Registry package that ships the branded product, e.g. `omo-ai`. */\n\treadonly packageName: string;\n\t/** Dist-tag the product publishes on, e.g. `beta`. */\n\treadonly distTag: string;\n\t/** Command shown to the user, e.g. `npm i -g omo-ai@beta`. */\n\treadonly command: string;\n\t/** Release notes URL; `{version}` is replaced with the available version. */\n\treadonly changelogUrl?: string;\n}\n\nexport interface BrandProfile {\n\t/** Product name shown to users and to the model. */\n\treadonly name: string;\n\t/** Version shown in the header, terminal titles and `--version`. */\n\treadonly displayVersion?: string;\n\t/** Config directory name, e.g. `.omo`. */\n\treadonly configDir: string;\n\t/** When true the agent state lives directly under the config directory, with no `agent` segment. */\n\treadonly flatLayout: boolean;\n\t/** Prefix for the product's environment variables, e.g. `OMO`. */\n\treadonly envPrefix: string;\n\t/** Product token used in the outgoing user agent. */\n\treadonly userAgent: string;\n\t/** Product token used as the provider-side originator, when the distribution overrides it. */\n\treadonly originator?: string;\n\t/** Update channel of the branded product; absent means the product manages updates itself. */\n\treadonly update?: BrandUpdateChannel;\n}\n\nfunction readUpdateChannel(source: Record<string, unknown>): BrandUpdateChannel | undefined {\n\tconst update = source.update;\n\tif (typeof update !== \"object\" || update === null || Array.isArray(update)) return undefined;\n\n\tconst channel = update as Record<string, unknown>;\n\tconst packageName = readString(channel, \"packageName\");\n\tconst command = readString(channel, \"command\");\n\tif (!packageName || !command) return undefined;\n\n\treturn {\n\t\tpackageName,\n\t\tdistTag: readString(channel, \"distTag\") || \"latest\",\n\t\tcommand,\n\t\tchangelogUrl: readString(channel, \"changelogUrl\"),\n\t};\n}\n\n/**\n * A config directory names ONE entry inside the home directory. Anything carrying a separator or\n * a parent reference would move agent state - and the migration that copies into it - somewhere\n * the user never agreed to, so such a profile is rejected rather than sanitised.\n */\nfunction isSafeConfigDirName(value: string): boolean {\n\treturn value !== \".\" && value !== \"..\" && !/[\\\\/]/.test(value);\n}\n\nfunction readString(source: Record<string, unknown>, key: string): string | undefined {\n\tconst value = source[key];\n\treturn typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n}\n\n/**\n * Parses a brand profile. Returns undefined for absent, malformed, or nameless input; a\n * malformed profile is reported once on stderr and never throws, because a broken brand\n * must not stop the agent from starting.\n */\nexport function parseBrandProfile(raw: string | undefined): BrandProfile | undefined {\n\tif (!raw?.trim()) return undefined;\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch {\n\t\tprocess.stderr.write(`warning: ignoring malformed ${BRAND_ENV_VAR} (expected JSON)\\n`);\n\t\treturn undefined;\n\t}\n\n\tif (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n\t\tprocess.stderr.write(`warning: ignoring malformed ${BRAND_ENV_VAR} (expected a JSON object)\\n`);\n\t\treturn undefined;\n\t}\n\n\tconst source = parsed as Record<string, unknown>;\n\tconst name = readString(source, \"name\");\n\tif (!name) {\n\t\tprocess.stderr.write(`warning: ignoring ${BRAND_ENV_VAR} without a \"name\"\\n`);\n\t\treturn undefined;\n\t}\n\n\tconst configDir = readString(source, \"configDir\") || `.${name}`;\n\tif (!isSafeConfigDirName(configDir)) {\n\t\tprocess.stderr.write(`warning: ignoring ${BRAND_ENV_VAR} with an unsafe \"configDir\"\\n`);\n\t\treturn undefined;\n\t}\n\n\treturn {\n\t\tname,\n\t\tdisplayVersion: readString(source, \"displayVersion\"),\n\t\tconfigDir,\n\t\tflatLayout: source.flatLayout === true,\n\t\tenvPrefix: (readString(source, \"envPrefix\") || name).toUpperCase(),\n\t\tuserAgent: readString(source, \"userAgent\") || name,\n\t\toriginator: readString(source, \"originator\"),\n\t\tupdate: readUpdateChannel(source),\n\t};\n}\n\n/**\n * Parses the brand profile without touching the environment.\n *\n * The CLI entrypoint re-spawns the real agent as a child process and hands it `process.env`,\n * so the variable has to survive that hop. Scrubbing therefore happens explicitly in the\n * process that actually runs the agent - see `scrubBrandFromEnvironment`.\n */\nexport function consumeBrandProfile(env: NodeJS.ProcessEnv = process.env): BrandProfile | undefined {\n\treturn parseBrandProfile(env[BRAND_ENV_VAR]);\n}\n\n/**\n * Removes the brand variable so tools spawning the engine again inherit a clean environment\n * and keep the engine's own identity. Called once the profile has been resolved by the\n * process that runs the agent loop.\n */\nexport function scrubBrandFromEnvironment(env: NodeJS.ProcessEnv = process.env): void {\n\tdelete env[BRAND_ENV_VAR];\n}\n\n/**\n * Environment prefixes read after the brand's own prefix, so a machine configured before the\n * rebrand keeps working unchanged.\n */\nconst LEGACY_ENV_PREFIXES = [\"SENPI\", \"PI\"] as const;\n\nlet cachedProfile: BrandProfile | undefined;\nlet profileResolved = false;\n\n/**\n * The active brand profile, resolved (and scrubbed from the environment) on first use.\n */\nexport function brandProfile(): BrandProfile | undefined {\n\tif (!profileResolved) {\n\t\tcachedProfile = consumeBrandProfile();\n\t\tprofileResolved = true;\n\t}\n\treturn cachedProfile;\n}\n\n/** exported for tests only */\nexport function resetBrandProfileForTests(): void {\n\tcachedProfile = undefined;\n\tprofileResolved = false;\n}\n\n/** Environment variable names for one setting, most specific first. */\nexport function brandEnvNames(suffix: string, profile = brandProfile()): string[] {\n\tconst prefixes = [profile?.envPrefix, ...LEGACY_ENV_PREFIXES].filter(\n\t\t(prefix): prefix is string => typeof prefix === \"string\" && prefix.length > 0,\n\t);\n\treturn [...new Set(prefixes)].map((prefix) => `${prefix}_${suffix}`);\n}\n\n/**\n * Reads one setting across the brand's prefix and the legacy prefixes, returning the first\n * DEFINED value so that an explicitly empty value keeps its existing meaning.\n */\nexport function envValue(suffix: string, env: NodeJS.ProcessEnv = process.env): string | undefined {\n\tfor (const name of brandEnvNames(suffix)) {\n\t\tconst value = env[name];\n\t\tif (value !== undefined) return value;\n\t}\n\treturn undefined;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../../src/core/dynamic-prompt/identity.ts"],"names":[],"mappings":"AAAA,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C"}
1
+ {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../../src/core/dynamic-prompt/identity.ts"],"names":[],"mappings":"AAEA,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C"}
@@ -1,4 +1,5 @@
1
+ import { APP_NAME } from "../../config.js";
1
2
  export function buildIdentitySection() {
2
- return "You are senpi, a coding agent. Your work should be indistinguishable from a careful senior engineer's.";
3
+ return `You are ${APP_NAME}, a coding agent. Your work should be indistinguishable from a careful senior engineer's.`;
3
4
  }
4
5
  //# sourceMappingURL=identity.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"identity.js","sourceRoot":"","sources":["../../../src/core/dynamic-prompt/identity.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,oBAAoB;IACnC,OAAO,wGAAwG,CAAC;AACjH,CAAC","sourcesContent":["export function buildIdentitySection(): string {\n\treturn \"You are senpi, a coding agent. Your work should be indistinguishable from a careful senior engineer's.\";\n}\n"]}
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../../../src/core/dynamic-prompt/identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C,MAAM,UAAU,oBAAoB;IACnC,OAAO,WAAW,QAAQ,2FAA2F,CAAC;AACvH,CAAC","sourcesContent":["import { APP_NAME } from \"../../config.ts\";\n\nexport function buildIdentitySection(): string {\n\treturn `You are ${APP_NAME}, a coding agent. Your work should be indistinguishable from a careful senior engineer's.`;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"experimental.d.ts","sourceRoot":"","sources":["../../src/core/experimental.ts"],"names":[],"mappings":"AAAA,wBAAgB,8BAA8B,IAAI,OAAO,CAExD"}
1
+ {"version":3,"file":"experimental.d.ts","sourceRoot":"","sources":["../../src/core/experimental.ts"],"names":[],"mappings":"AACA,wBAAgB,8BAA8B,IAAI,OAAO,CAExD"}
@@ -1,4 +1,5 @@
1
+ import { envValue } from "./brand.js";
1
2
  export function areExperimentalFeaturesEnabled() {
2
- return process.env.PI_EXPERIMENTAL === "1";
3
+ return envValue("EXPERIMENTAL") === "1";
3
4
  }
4
5
  //# sourceMappingURL=experimental.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"experimental.js","sourceRoot":"","sources":["../../src/core/experimental.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,8BAA8B;IAC7C,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,KAAK,GAAG,CAAC;AAC5C,CAAC","sourcesContent":["export function areExperimentalFeaturesEnabled(): boolean {\n\treturn process.env.PI_EXPERIMENTAL === \"1\";\n}\n"]}
1
+ {"version":3,"file":"experimental.js","sourceRoot":"","sources":["../../src/core/experimental.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,MAAM,UAAU,8BAA8B;IAC7C,OAAO,QAAQ,CAAC,cAAc,CAAC,KAAK,GAAG,CAAC;AACzC,CAAC","sourcesContent":["import { envValue } from \"./brand.ts\";\nexport function areExperimentalFeaturesEnabled(): boolean {\n\treturn envValue(\"EXPERIMENTAL\") === \"1\";\n}\n"]}
@@ -0,0 +1,30 @@
1
+ import { type Context, type Model, type WarmPromptCacheOptions, type WarmPromptCacheResult } from "@earendil-works/pi-ai";
2
+ import type { EntryRenderer, ExtensionFactory } from "../../types.ts";
3
+ export declare const CACHE_KEEPALIVE_ENTRY_TYPE = "cache-keepalive";
4
+ export declare const CACHE_WARM_PING_EVENT = "cache_warm_ping";
5
+ interface StartedEntry {
6
+ readonly phase: "started";
7
+ }
8
+ interface PingEntry {
9
+ readonly phase: "ping";
10
+ readonly iteration: number;
11
+ readonly cacheRead: number;
12
+ readonly cacheWrite: number;
13
+ readonly estimatedCostUsd: number;
14
+ readonly cumulativeEstimatedUsd: number;
15
+ }
16
+ interface StoppedEntry {
17
+ readonly phase: "stopped";
18
+ readonly iterations: number;
19
+ readonly stopReason: string;
20
+ readonly cumulativeEstimatedUsd: number;
21
+ }
22
+ export type CacheKeepAliveEntryData = StartedEntry | PingEntry | StoppedEntry;
23
+ type WarmPromptCacheFn = (model: Model<any>, context: Context, options?: WarmPromptCacheOptions) => Promise<WarmPromptCacheResult>;
24
+ export declare const renderCacheKeepAliveEntry: EntryRenderer<CacheKeepAliveEntryData>;
25
+ export declare function createCacheKeepAliveExtension(dependencies?: {
26
+ readonly warmPromptCache?: WarmPromptCacheFn;
27
+ }): ExtensionFactory;
28
+ declare const _default: ExtensionFactory;
29
+ export default _default;
30
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/cache-keepalive/index.ts"],"names":[],"mappings":"AACA,OAAO,EACN,KAAK,OAAO,EAEZ,KAAK,KAAK,EAGV,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAE1B,MAAM,uBAAuB,CAAC;AAG/B,OAAO,KAAK,EAAE,aAAa,EAAkC,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAItG,eAAO,MAAM,0BAA0B,oBAAoB,CAAC;AAC5D,eAAO,MAAM,qBAAqB,oBAAoB,CAAC;AAEvD,UAAU,YAAY;IACrB,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;CAC1B;AAED,UAAU,SAAS;IAClB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;CACxC;AAED,UAAU,YAAY;IACrB,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;CACxC;AAED,MAAM,MAAM,uBAAuB,GAAG,YAAY,GAAG,SAAS,GAAG,YAAY,CAAC;AAE9E,KAAK,iBAAiB,GAAG,CACxB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,sBAAsB,KAC5B,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAEpC,eAAO,MAAM,yBAAyB,EAAE,aAAa,CAAC,uBAAuB,CAS3E,CAAC;AAEH,wBAAgB,6BAA6B,CAC5C,YAAY,GAAE;IAAE,QAAQ,CAAC,eAAe,CAAC,EAAE,iBAAiB,CAAA;CAAO,GACjE,gBAAgB,CAwNlB"}
@@ -0,0 +1,281 @@
1
+ import { isAnthropicApiBaseUrl, resolvePromptCacheTtlSeconds, warmPromptCache, } from "@earendil-works/pi-ai";
2
+ import { convertToLlm, filterContextExcludedMessages } from "../../../messages.js";
3
+ import { noticeEntryRenderer } from "../../notice/index.js";
4
+ import { formatWarmTokenCount } from "../goal/cache-warm.js";
5
+ import { GOAL_CONTINUATION_TIMER_STATE_EVENT } from "../goal/monitor-continuation.js";
6
+ export const CACHE_KEEPALIVE_ENTRY_TYPE = "cache-keepalive";
7
+ export const CACHE_WARM_PING_EVENT = "cache_warm_ping";
8
+ export const renderCacheKeepAliveEntry = noticeEntryRenderer((entry) => {
9
+ const data = entry.data;
10
+ if (data?.phase !== "ping")
11
+ return undefined;
12
+ const refreshed = data.cacheRead + data.cacheWrite;
13
+ return {
14
+ title: `⚡ Warm ping #${data.iteration} · ~${formatWarmTokenCount(refreshed)} tokens refreshed · ${formatUsd(data.estimatedCostUsd)}`,
15
+ why: "Refreshed the active Anthropic prompt cache while the session was idle.",
16
+ expandedLine: `cache read ${data.cacheRead} · cache write ${data.cacheWrite} · session total ${formatUsd(data.cumulativeEstimatedUsd)}`,
17
+ };
18
+ });
19
+ export function createCacheKeepAliveExtension(dependencies = {}) {
20
+ const warm = dependencies.warmPromptCache ?? warmPromptCache;
21
+ return (pi) => {
22
+ let ctx;
23
+ let timer;
24
+ let inFlight = false;
25
+ let generation = 0;
26
+ let active = false;
27
+ let goalTimerArmed = false;
28
+ let attempts = 0;
29
+ let cumulativeEstimatedUsd = 0;
30
+ let lastCompletedAtMs;
31
+ let lastMessages = [];
32
+ let lastUsage;
33
+ pi.registerEntryRenderer(CACHE_KEEPALIVE_ENTRY_TYPE, renderCacheKeepAliveEntry);
34
+ const unsubscribeGoalTimer = pi.events?.on(GOAL_CONTINUATION_TIMER_STATE_EVENT, (data) => {
35
+ if (!isGoalTimerState(data))
36
+ return;
37
+ goalTimerArmed = data.armed;
38
+ if (data.armed)
39
+ stop("goal-timer-armed");
40
+ });
41
+ function append(data) {
42
+ pi.appendEntry(CACHE_KEEPALIVE_ENTRY_TYPE, data);
43
+ }
44
+ function stop(reason, forceEntry = false) {
45
+ const shouldAppend = active || inFlight || timer !== undefined || forceEntry;
46
+ generation += 1;
47
+ if (timer !== undefined)
48
+ clearTimeout(timer);
49
+ timer = undefined;
50
+ active = false;
51
+ if (shouldAppend) {
52
+ append({
53
+ phase: "stopped",
54
+ iterations: attempts,
55
+ stopReason: reason,
56
+ cumulativeEstimatedUsd,
57
+ });
58
+ }
59
+ }
60
+ function arm() {
61
+ if (timer !== undefined || inFlight)
62
+ return;
63
+ const current = ctx;
64
+ const settings = current?.getPromptCacheKeepAliveSettings?.();
65
+ if (!settings?.enabled || current?.model === undefined || lastCompletedAtMs === undefined)
66
+ return;
67
+ if (!isWarmSupportedModel(current.model))
68
+ return;
69
+ if (!current.isIdle()) {
70
+ stop("agent-busy");
71
+ return;
72
+ }
73
+ if (current.hasPendingMessages()) {
74
+ stop("pending-messages");
75
+ return;
76
+ }
77
+ if (goalTimerArmed) {
78
+ stop("goal-timer-armed");
79
+ return;
80
+ }
81
+ const safeWaitSeconds = current.getPromptCacheSafeWaitSeconds?.();
82
+ if (safeWaitSeconds === undefined || !Number.isFinite(safeWaitSeconds))
83
+ return;
84
+ if (attempts >= Math.max(0, settings.maxRequestsPerSession)) {
85
+ stop("max-requests", true);
86
+ return;
87
+ }
88
+ const projectedUsd = projectedPingCost(current.model, lastUsage);
89
+ if (cumulativeEstimatedUsd + projectedUsd > Math.max(0, settings.maxCostUsdPerSession)) {
90
+ stop("cost-cap", true);
91
+ return;
92
+ }
93
+ if (!active) {
94
+ active = true;
95
+ append({ phase: "started" });
96
+ }
97
+ const intervalMs = Math.max(0, safeWaitSeconds - Math.max(0, settings.marginSeconds)) * 1000;
98
+ const delayMs = Math.max(0, lastCompletedAtMs + intervalMs - Date.now());
99
+ const scheduledGeneration = generation;
100
+ timer = setTimeout(() => {
101
+ timer = undefined;
102
+ void ping(scheduledGeneration);
103
+ }, delayMs);
104
+ }
105
+ async function ping(scheduledGeneration) {
106
+ if (scheduledGeneration !== generation)
107
+ return;
108
+ const current = ctx;
109
+ const settings = current?.getPromptCacheKeepAliveSettings?.();
110
+ if (current === undefined ||
111
+ settings?.enabled !== true ||
112
+ current.model === undefined ||
113
+ !isWarmSupportedModel(current.model) ||
114
+ !current.isIdle() ||
115
+ current.hasPendingMessages() ||
116
+ goalTimerArmed ||
117
+ attempts >= Math.max(0, settings.maxRequestsPerSession) ||
118
+ cumulativeEstimatedUsd + projectedPingCost(current.model, lastUsage) >
119
+ Math.max(0, settings.maxCostUsdPerSession)) {
120
+ arm();
121
+ return;
122
+ }
123
+ inFlight = true;
124
+ attempts += 1;
125
+ const iteration = attempts;
126
+ const pingGeneration = generation;
127
+ try {
128
+ const preparation = await current.prepareProviderRequest?.(lastMessages);
129
+ if (pingGeneration !== generation) {
130
+ inFlight = false;
131
+ arm();
132
+ return;
133
+ }
134
+ const preparedMessages = preparation?.messages ?? lastMessages;
135
+ const activeToolNames = new Set(pi.getActiveTools());
136
+ const tools = pi
137
+ .getAllTools()
138
+ .filter((tool) => activeToolNames.has(tool.name))
139
+ .map(({ name, description, parameters }) => ({ name, description, parameters }));
140
+ const auth = await current.modelRegistry.getApiKeyAndHeaders(current.model);
141
+ if (pingGeneration !== generation) {
142
+ inFlight = false;
143
+ arm();
144
+ return;
145
+ }
146
+ if (!auth.ok)
147
+ throw new Error(auth.error);
148
+ const authHeaders = auth.headers ?? {};
149
+ const headers = preparation ? await preparation.transformHeaders(authHeaders) : authHeaders;
150
+ const result = await warm(current.model, {
151
+ systemPrompt: current.getSystemPrompt(),
152
+ messages: convertToLlm(filterContextExcludedMessages(preparedMessages)),
153
+ ...(tools.length > 0 ? { tools } : {}),
154
+ }, {
155
+ apiKey: auth.apiKey,
156
+ headers,
157
+ sessionId: current.sessionManager.getSessionId(),
158
+ cacheRetention: current.model.cacheRetention,
159
+ onPayload: preparation ? async (payload) => await preparation.transformPayload(payload) : undefined,
160
+ });
161
+ if (pingGeneration !== generation) {
162
+ inFlight = false;
163
+ arm();
164
+ return;
165
+ }
166
+ if (!result.supported) {
167
+ inFlight = false;
168
+ stop("unsupported-model");
169
+ return;
170
+ }
171
+ const estimatedCostUsd = actualPingCost(current.model, result.usage);
172
+ cumulativeEstimatedUsd += estimatedCostUsd;
173
+ lastCompletedAtMs = Date.now();
174
+ const cachedTokens = result.usage.cacheRead + result.usage.cacheWrite;
175
+ const ttlSeconds = resolvePromptCacheTtlSeconds(current.model) ?? 0;
176
+ pi.events?.emit(CACHE_WARM_PING_EVENT, { iteration, cachedTokens, ttlSeconds, estimatedCostUsd });
177
+ append({
178
+ phase: "ping",
179
+ iteration,
180
+ cacheRead: result.usage.cacheRead,
181
+ cacheWrite: result.usage.cacheWrite,
182
+ estimatedCostUsd,
183
+ cumulativeEstimatedUsd,
184
+ });
185
+ inFlight = false;
186
+ arm();
187
+ }
188
+ catch {
189
+ inFlight = false;
190
+ if (pingGeneration === generation)
191
+ stop("provider-error");
192
+ else
193
+ arm();
194
+ }
195
+ }
196
+ pi.on("session_start", (_event, nextCtx) => {
197
+ stop("session-restart");
198
+ ctx = nextCtx;
199
+ attempts = 0;
200
+ cumulativeEstimatedUsd = 0;
201
+ lastMessages = nextCtx.sessionManager.buildSessionContext().messages;
202
+ const usage = lastAssistantUsage(lastMessages);
203
+ lastUsage = usage;
204
+ lastCompletedAtMs = lastAssistantTimestamp(lastMessages);
205
+ arm();
206
+ });
207
+ pi.on("agent_end", (event, nextCtx) => {
208
+ ctx = nextCtx;
209
+ const usage = lastAssistantUsage(event.messages);
210
+ if (usage?.stopReason === "error") {
211
+ stop("provider-error");
212
+ return;
213
+ }
214
+ lastMessages = [...event.messages];
215
+ lastUsage = usage;
216
+ lastCompletedAtMs = Date.now();
217
+ arm();
218
+ });
219
+ pi.on("model_select", (_event, nextCtx) => {
220
+ ctx = nextCtx;
221
+ stop("model-changed");
222
+ arm();
223
+ });
224
+ pi.on("agent_start", () => stop("agent-busy"));
225
+ pi.on("input", () => stop("user-input"));
226
+ pi.on("session_shutdown", () => {
227
+ stop("session-dispose");
228
+ unsubscribeGoalTimer?.();
229
+ ctx = undefined;
230
+ });
231
+ };
232
+ }
233
+ function isWarmSupportedModel(model) {
234
+ return model.api === "anthropic-messages" && isAnthropicApiBaseUrl(model.baseUrl);
235
+ }
236
+ function lastAssistantUsage(messages) {
237
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
238
+ const message = messages[index];
239
+ if (message.role !== "assistant")
240
+ continue;
241
+ return {
242
+ input: finiteTokens(message.usage.input),
243
+ cacheRead: finiteTokens(message.usage.cacheRead),
244
+ cacheWrite: finiteTokens(message.usage.cacheWrite),
245
+ stopReason: message.stopReason,
246
+ };
247
+ }
248
+ return undefined;
249
+ }
250
+ function lastAssistantTimestamp(messages) {
251
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
252
+ const message = messages[index];
253
+ if (message.role === "assistant" && Number.isFinite(message.timestamp))
254
+ return message.timestamp;
255
+ }
256
+ return undefined;
257
+ }
258
+ function projectedPingCost(model, usage) {
259
+ const promptTokens = (usage?.input ?? 0) + (usage?.cacheRead ?? 0) + (usage?.cacheWrite ?? 0);
260
+ return (promptTokens * Math.max(model.cost.cacheRead, model.cost.cacheWrite)) / 1_000_000;
261
+ }
262
+ function actualPingCost(model, usage) {
263
+ return ((usage.cacheRead * model.cost.cacheRead +
264
+ usage.cacheWrite * model.cost.cacheWrite +
265
+ usage.input * model.cost.input) /
266
+ 1_000_000);
267
+ }
268
+ function finiteTokens(value) {
269
+ return Number.isFinite(value) && value > 0 ? value : 0;
270
+ }
271
+ function formatUsd(value) {
272
+ return `$${value.toFixed(3)}`;
273
+ }
274
+ function isGoalTimerState(value) {
275
+ return (typeof value === "object" &&
276
+ value !== null &&
277
+ typeof value.armed === "boolean" &&
278
+ typeof value.kind === "string");
279
+ }
280
+ export default createCacheKeepAliveExtension();
281
+ //# sourceMappingURL=index.js.map