@oh-my-pi/pi-coding-agent 15.12.3 → 15.13.0

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 (457) hide show
  1. package/CHANGELOG.md +347 -7
  2. package/dist/cli.js +1615 -1231
  3. package/dist/types/async/job-manager.d.ts +15 -0
  4. package/dist/types/autolearn/controller.d.ts +25 -0
  5. package/dist/types/autolearn/managed-skills.d.ts +45 -0
  6. package/dist/types/autoresearch/state.d.ts +1 -1
  7. package/dist/types/autoresearch/tools/init-experiment.d.ts +1 -1
  8. package/dist/types/autoresearch/tools/log-experiment.d.ts +1 -1
  9. package/dist/types/autoresearch/tools/run-experiment.d.ts +1 -1
  10. package/dist/types/autoresearch/tools/update-notes.d.ts +1 -1
  11. package/dist/types/autoresearch/types.d.ts +1 -1
  12. package/dist/types/cli/args.d.ts +19 -2
  13. package/dist/types/cli/models-cli.d.ts +49 -0
  14. package/dist/types/cli/session-picker.d.ts +1 -1
  15. package/dist/types/cli/setup-cli.d.ts +1 -1
  16. package/dist/types/cli/setup-model-picker.d.ts +14 -0
  17. package/dist/types/collab/protocol.d.ts +1 -1
  18. package/dist/types/commands/launch.d.ts +0 -3
  19. package/dist/types/commands/models.d.ts +33 -0
  20. package/dist/types/commands/say.d.ts +24 -0
  21. package/dist/types/commands/token.d.ts +25 -0
  22. package/dist/types/commit/agentic/tools/analyze-file.d.ts +1 -1
  23. package/dist/types/commit/agentic/tools/git-file-diff.d.ts +1 -1
  24. package/dist/types/commit/agentic/tools/git-hunk.d.ts +1 -1
  25. package/dist/types/commit/agentic/tools/git-overview.d.ts +1 -1
  26. package/dist/types/commit/agentic/tools/propose-changelog.d.ts +1 -1
  27. package/dist/types/commit/agentic/tools/propose-commit.d.ts +1 -1
  28. package/dist/types/commit/agentic/tools/recent-commits.d.ts +1 -1
  29. package/dist/types/commit/agentic/tools/schemas.d.ts +1 -1
  30. package/dist/types/commit/agentic/tools/split-commit.d.ts +1 -1
  31. package/dist/types/commit/changelog/generate.d.ts +1 -1
  32. package/dist/types/commit/shared-llm.d.ts +1 -1
  33. package/dist/types/config/keybindings.d.ts +3 -3
  34. package/dist/types/config/model-registry.d.ts +17 -0
  35. package/dist/types/config/models-config-schema.d.ts +13 -1
  36. package/dist/types/config/models-config.d.ts +8 -2
  37. package/dist/types/config/settings-schema.d.ts +281 -58
  38. package/dist/types/edit/hashline/params.d.ts +1 -1
  39. package/dist/types/edit/modes/apply-patch.d.ts +1 -1
  40. package/dist/types/edit/modes/patch.d.ts +1 -1
  41. package/dist/types/edit/modes/replace.d.ts +1 -1
  42. package/dist/types/export/html/index.d.ts +2 -1
  43. package/dist/types/extensibility/custom-commands/types.d.ts +2 -2
  44. package/dist/types/extensibility/custom-tools/types.d.ts +2 -2
  45. package/dist/types/extensibility/extensions/model-api.d.ts +17 -0
  46. package/dist/types/extensibility/extensions/runner.d.ts +3 -1
  47. package/dist/types/extensibility/extensions/types.d.ts +49 -3
  48. package/dist/types/extensibility/hooks/index.d.ts +2 -1
  49. package/dist/types/extensibility/hooks/types.d.ts +2 -2
  50. package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +9 -0
  51. package/dist/types/extensibility/plugins/loader.d.ts +11 -0
  52. package/dist/types/extensibility/shared-events.d.ts +1 -1
  53. package/dist/types/extensibility/skills.d.ts +10 -0
  54. package/dist/types/goals/guided-setup.d.ts +18 -0
  55. package/dist/types/goals/state.d.ts +1 -1
  56. package/dist/types/goals/tools/goal-tool.d.ts +1 -1
  57. package/dist/types/hindsight/transcript.d.ts +1 -1
  58. package/dist/types/index.d.ts +5 -0
  59. package/dist/types/internal-urls/local-protocol.d.ts +4 -2
  60. package/dist/types/lsp/types.d.ts +1 -1
  61. package/dist/types/main.d.ts +4 -3
  62. package/dist/types/mcp/manager.d.ts +8 -0
  63. package/dist/types/mcp/startup-events.d.ts +11 -0
  64. package/dist/types/memories/index.d.ts +7 -0
  65. package/dist/types/memory-backend/local-backend.d.ts +4 -3
  66. package/dist/types/mnemopi/config.d.ts +28 -0
  67. package/dist/types/modes/acp/acp-agent.d.ts +1 -2
  68. package/dist/types/modes/components/agent-hub.d.ts +6 -0
  69. package/dist/types/modes/components/assistant-message.d.ts +1 -2
  70. package/dist/types/modes/components/compaction-summary-message.d.ts +15 -1
  71. package/dist/types/modes/components/custom-editor.d.ts +39 -1
  72. package/dist/types/modes/components/custom-editor.test.d.ts +1 -0
  73. package/dist/types/modes/components/index.d.ts +1 -0
  74. package/dist/types/modes/components/logout-account-selector.d.ts +8 -0
  75. package/dist/types/modes/components/session-selector.d.ts +1 -1
  76. package/dist/types/modes/components/status-line/component.d.ts +9 -5
  77. package/dist/types/modes/components/status-line/types.d.ts +2 -1
  78. package/dist/types/modes/components/tool-execution.d.ts +26 -16
  79. package/dist/types/modes/components/transcript-container.d.ts +23 -2
  80. package/dist/types/modes/components/tree-selector.d.ts +1 -1
  81. package/dist/types/modes/components/usage-row.d.ts +3 -0
  82. package/dist/types/modes/controllers/command-controller.d.ts +2 -2
  83. package/dist/types/modes/controllers/event-controller.d.ts +0 -17
  84. package/dist/types/modes/controllers/input-controller.d.ts +14 -0
  85. package/dist/types/modes/controllers/selector-controller.d.ts +3 -1
  86. package/dist/types/modes/gradient-highlight.d.ts +9 -4
  87. package/dist/types/modes/image-references.d.ts +6 -0
  88. package/dist/types/modes/interactive-mode.d.ts +27 -6
  89. package/dist/types/modes/magic-keywords.d.ts +13 -1
  90. package/dist/types/modes/rpc/rpc-mode.d.ts +35 -1
  91. package/dist/types/modes/rpc/rpc-types.d.ts +9 -1
  92. package/dist/types/modes/runtime-init.d.ts +4 -0
  93. package/dist/types/modes/theme/theme.d.ts +13 -2
  94. package/dist/types/modes/types.d.ts +8 -7
  95. package/dist/types/modes/utils/ui-helpers.d.ts +1 -1
  96. package/dist/types/registry/agent-registry.d.ts +17 -0
  97. package/dist/types/secrets/obfuscator.d.ts +1 -1
  98. package/dist/types/session/agent-session.d.ts +28 -35
  99. package/dist/types/session/agent-storage.d.ts +2 -1
  100. package/dist/types/session/indexed-session-storage.d.ts +3 -3
  101. package/dist/types/session/messages.d.ts +8 -10
  102. package/dist/types/session/session-context.d.ts +39 -0
  103. package/dist/types/session/session-entries.d.ts +159 -0
  104. package/dist/types/session/session-listing.d.ts +69 -0
  105. package/dist/types/session/session-loader.d.ts +16 -0
  106. package/dist/types/session/session-manager.d.ts +85 -462
  107. package/dist/types/session/session-migrations.d.ts +12 -0
  108. package/dist/types/session/session-paths.d.ts +25 -0
  109. package/dist/types/session/session-persistence.d.ts +8 -0
  110. package/dist/types/session/session-storage.d.ts +11 -7
  111. package/dist/types/session/snapcompact-inline.d.ts +12 -1
  112. package/dist/types/session/snapcompact-savings-journal.d.ts +46 -0
  113. package/dist/types/session/tool-choice-queue.d.ts +6 -6
  114. package/dist/types/slash-commands/helpers/logout.d.ts +15 -0
  115. package/dist/types/stt/asr-client.d.ts +90 -0
  116. package/dist/types/stt/asr-protocol.d.ts +97 -0
  117. package/dist/types/stt/asr-worker.d.ts +2 -0
  118. package/dist/types/stt/downloader.d.ts +38 -0
  119. package/dist/types/stt/endpointer.d.ts +59 -0
  120. package/dist/types/stt/index.d.ts +5 -1
  121. package/dist/types/stt/models.d.ts +120 -0
  122. package/dist/types/stt/recorder.d.ts +17 -0
  123. package/dist/types/stt/stt-controller.d.ts +6 -0
  124. package/dist/types/stt/transcriber.d.ts +5 -7
  125. package/dist/types/stt/wav.d.ts +29 -0
  126. package/dist/types/system-prompt.d.ts +4 -0
  127. package/dist/types/task/executor.d.ts +2 -0
  128. package/dist/types/task/index.d.ts +9 -1
  129. package/dist/types/task/types.d.ts +37 -1
  130. package/dist/types/tools/ask.d.ts +1 -1
  131. package/dist/types/tools/ast-edit.d.ts +1 -1
  132. package/dist/types/tools/ast-grep.d.ts +1 -1
  133. package/dist/types/tools/bash.d.ts +3 -3
  134. package/dist/types/tools/browser/cmux/cmux-tab.d.ts +202 -0
  135. package/dist/types/tools/browser/cmux/rpc.d.ts +70 -0
  136. package/dist/types/tools/browser/cmux/socket-client.d.ts +19 -0
  137. package/dist/types/tools/browser/registry.d.ts +16 -3
  138. package/dist/types/tools/browser/render.d.ts +2 -0
  139. package/dist/types/tools/browser/tab-protocol.d.ts +2 -0
  140. package/dist/types/tools/browser/tab-supervisor.d.ts +16 -4
  141. package/dist/types/tools/browser.d.ts +3 -1
  142. package/dist/types/tools/checkpoint.d.ts +1 -1
  143. package/dist/types/tools/debug.d.ts +1 -1
  144. package/dist/types/tools/eval-render.d.ts +1 -1
  145. package/dist/types/tools/eval.d.ts +1 -1
  146. package/dist/types/tools/find.d.ts +1 -1
  147. package/dist/types/tools/gh.d.ts +1 -1
  148. package/dist/types/tools/image-gen.d.ts +1 -1
  149. package/dist/types/tools/index.d.ts +14 -2
  150. package/dist/types/tools/inspect-image.d.ts +1 -1
  151. package/dist/types/tools/irc.d.ts +2 -1
  152. package/dist/types/tools/job.d.ts +1 -1
  153. package/dist/types/tools/learn.d.ts +51 -0
  154. package/dist/types/tools/manage-skill.d.ts +40 -0
  155. package/dist/types/tools/memory-edit.d.ts +1 -1
  156. package/dist/types/tools/memory-recall.d.ts +1 -1
  157. package/dist/types/tools/memory-reflect.d.ts +1 -1
  158. package/dist/types/tools/memory-retain.d.ts +1 -1
  159. package/dist/types/tools/plan-mode-guard.d.ts +10 -0
  160. package/dist/types/tools/read.d.ts +1 -1
  161. package/dist/types/tools/render-mermaid.d.ts +1 -1
  162. package/dist/types/tools/renderers.d.ts +7 -11
  163. package/dist/types/tools/resolve.d.ts +1 -1
  164. package/dist/types/tools/review.d.ts +1 -1
  165. package/dist/types/tools/search-tool-bm25.d.ts +1 -1
  166. package/dist/types/tools/search.d.ts +1 -1
  167. package/dist/types/tools/ssh.d.ts +2 -2
  168. package/dist/types/tools/todo.d.ts +2 -2
  169. package/dist/types/tools/tts.d.ts +26 -1
  170. package/dist/types/tools/write.d.ts +2 -2
  171. package/dist/types/tts/downloader.d.ts +20 -0
  172. package/dist/types/tts/index.d.ts +8 -0
  173. package/dist/types/tts/models.d.ts +82 -0
  174. package/dist/types/tts/player.d.ts +32 -0
  175. package/dist/types/tts/runtime.d.ts +6 -0
  176. package/dist/types/tts/streaming-player.d.ts +41 -0
  177. package/dist/types/tts/tts-client.d.ts +93 -0
  178. package/dist/types/tts/tts-protocol.d.ts +95 -0
  179. package/dist/types/tts/tts-worker.d.ts +2 -0
  180. package/dist/types/tts/vocalizer.d.ts +41 -0
  181. package/dist/types/tts/wav.d.ts +8 -0
  182. package/dist/types/utils/clipboard.d.ts +4 -3
  183. package/dist/types/utils/image-loading.d.ts +18 -1
  184. package/dist/types/utils/thinking-display.d.ts +17 -0
  185. package/dist/types/utils/tool-choice.d.ts +8 -0
  186. package/dist/types/utils/tools-manager.d.ts +2 -1
  187. package/dist/types/utils/tools-manager.test.d.ts +1 -0
  188. package/dist/types/web/scrapers/github.d.ts +1 -1
  189. package/dist/types/web/search/index.d.ts +1 -1
  190. package/package.json +17 -16
  191. package/src/async/job-manager.ts +49 -0
  192. package/src/autolearn/controller.ts +139 -0
  193. package/src/autolearn/managed-skills.ts +257 -0
  194. package/src/autoresearch/state.ts +1 -1
  195. package/src/autoresearch/storage.ts +2 -1
  196. package/src/autoresearch/tools/init-experiment.ts +1 -1
  197. package/src/autoresearch/tools/log-experiment.ts +1 -1
  198. package/src/autoresearch/tools/run-experiment.ts +1 -1
  199. package/src/autoresearch/tools/update-notes.ts +1 -1
  200. package/src/autoresearch/types.ts +1 -1
  201. package/src/cli/args.ts +56 -10
  202. package/src/cli/auth-gateway-cli.ts +1 -1
  203. package/src/cli/bench-cli.ts +1 -1
  204. package/src/cli/dry-balance-cli.ts +1 -1
  205. package/src/cli/models-cli.ts +427 -0
  206. package/src/cli/session-picker.ts +2 -1
  207. package/src/cli/setup-cli.ts +148 -47
  208. package/src/cli/setup-model-picker.ts +43 -0
  209. package/src/cli-commands.ts +3 -0
  210. package/src/cli.ts +45 -13
  211. package/src/collab/host.ts +10 -13
  212. package/src/collab/protocol.ts +1 -1
  213. package/src/commands/launch.ts +0 -3
  214. package/src/commands/models.ts +61 -0
  215. package/src/commands/say.ts +102 -0
  216. package/src/commands/setup.ts +1 -1
  217. package/src/commands/token.ts +89 -0
  218. package/src/commit/agentic/tools/analyze-file.ts +4 -1
  219. package/src/commit/agentic/tools/git-file-diff.ts +1 -1
  220. package/src/commit/agentic/tools/git-hunk.ts +1 -1
  221. package/src/commit/agentic/tools/git-overview.ts +1 -1
  222. package/src/commit/agentic/tools/propose-changelog.ts +1 -1
  223. package/src/commit/agentic/tools/propose-commit.ts +1 -1
  224. package/src/commit/agentic/tools/recent-commits.ts +1 -1
  225. package/src/commit/agentic/tools/schemas.ts +1 -1
  226. package/src/commit/agentic/tools/split-commit.ts +1 -1
  227. package/src/commit/analysis/summary.ts +1 -1
  228. package/src/commit/changelog/generate.ts +1 -1
  229. package/src/commit/shared-llm.ts +1 -1
  230. package/src/config/keybindings.ts +2 -2
  231. package/src/config/model-discovery.ts +11 -5
  232. package/src/config/model-registry.ts +79 -21
  233. package/src/config/model-resolver.ts +2 -2
  234. package/src/config/models-config-schema.ts +5 -2
  235. package/src/config/models-config.ts +2 -1
  236. package/src/config/settings-schema.ts +266 -32
  237. package/src/config/settings.ts +10 -0
  238. package/src/discovery/builtin.ts +23 -1
  239. package/src/discovery/claude-plugins.ts +44 -5
  240. package/src/discovery/helpers.ts +41 -1
  241. package/src/edit/hashline/params.ts +1 -1
  242. package/src/edit/modes/apply-patch.ts +1 -1
  243. package/src/edit/modes/patch.ts +1 -1
  244. package/src/edit/modes/replace.ts +1 -1
  245. package/src/eval/__tests__/budget-bridge.test.ts +1 -1
  246. package/src/eval/agent-bridge.ts +1 -1
  247. package/src/eval/completion-bridge.ts +1 -1
  248. package/src/eval/js/shared/prelude.txt +69 -17
  249. package/src/export/html/index.ts +3 -6
  250. package/src/export/html/template.js +24 -2
  251. package/src/export/html/tool-views.generated.js +2 -2
  252. package/src/extensibility/custom-commands/loader.ts +1 -1
  253. package/src/extensibility/custom-commands/types.ts +2 -2
  254. package/src/extensibility/custom-tools/loader.ts +1 -1
  255. package/src/extensibility/custom-tools/types.ts +2 -2
  256. package/src/extensibility/extensions/loader.ts +2 -2
  257. package/src/extensibility/extensions/model-api.ts +41 -0
  258. package/src/extensibility/extensions/runner.ts +4 -0
  259. package/src/extensibility/extensions/types.ts +54 -3
  260. package/src/extensibility/extensions/wrapper.ts +41 -5
  261. package/src/extensibility/hooks/index.ts +2 -1
  262. package/src/extensibility/hooks/loader.ts +1 -1
  263. package/src/extensibility/hooks/types.ts +2 -2
  264. package/src/extensibility/plugins/legacy-pi-compat.ts +43 -13
  265. package/src/extensibility/plugins/loader.ts +30 -19
  266. package/src/extensibility/plugins/manager.ts +221 -90
  267. package/src/extensibility/shared-events.ts +1 -1
  268. package/src/extensibility/skills.ts +101 -5
  269. package/src/goals/guided-setup.ts +133 -0
  270. package/src/goals/state.ts +1 -1
  271. package/src/goals/tools/goal-tool.ts +1 -1
  272. package/src/hindsight/transcript.ts +1 -1
  273. package/src/index.ts +5 -0
  274. package/src/internal-urls/docs-index.generated.ts +13 -10
  275. package/src/internal-urls/history-protocol.ts +1 -1
  276. package/src/internal-urls/local-protocol.ts +29 -7
  277. package/src/lsp/types.ts +1 -1
  278. package/src/main.ts +27 -32
  279. package/src/mcp/config-writer.ts +7 -3
  280. package/src/mcp/manager.ts +11 -0
  281. package/src/mcp/startup-events.ts +21 -0
  282. package/src/mcp/transports/stdio.ts +2 -1
  283. package/src/memories/index.ts +149 -12
  284. package/src/memories/storage.ts +2 -1
  285. package/src/memory-backend/local-backend.ts +11 -5
  286. package/src/mnemopi/backend.ts +1 -0
  287. package/src/mnemopi/config.ts +112 -12
  288. package/src/modes/acp/acp-agent.ts +8 -53
  289. package/src/modes/acp/acp-event-mapper.ts +5 -1
  290. package/src/modes/components/agent-hub.ts +51 -5
  291. package/src/modes/components/assistant-message.ts +12 -44
  292. package/src/modes/components/compaction-summary-message.ts +125 -26
  293. package/src/modes/components/custom-editor.test.ts +96 -0
  294. package/src/modes/components/custom-editor.ts +164 -8
  295. package/src/modes/components/index.ts +1 -0
  296. package/src/modes/components/logout-account-selector.ts +130 -0
  297. package/src/modes/components/mcp-add-wizard.ts +1 -1
  298. package/src/modes/components/model-selector.ts +2 -2
  299. package/src/modes/components/session-selector.ts +1 -1
  300. package/src/modes/components/settings-defs.ts +7 -0
  301. package/src/modes/components/status-line/component.ts +54 -157
  302. package/src/modes/components/status-line/segments.ts +1 -1
  303. package/src/modes/components/status-line/types.ts +2 -1
  304. package/src/modes/components/tool-execution.ts +82 -43
  305. package/src/modes/components/transcript-container.ts +70 -1
  306. package/src/modes/components/tree-selector.ts +1 -1
  307. package/src/modes/components/usage-row.ts +18 -0
  308. package/src/modes/components/user-message.ts +4 -2
  309. package/src/modes/controllers/command-controller.ts +14 -16
  310. package/src/modes/controllers/event-controller.ts +101 -73
  311. package/src/modes/controllers/extension-ui-controller.ts +6 -0
  312. package/src/modes/controllers/input-controller.ts +311 -57
  313. package/src/modes/controllers/mcp-command-controller.ts +44 -3
  314. package/src/modes/controllers/selector-controller.ts +68 -12
  315. package/src/modes/controllers/streaming-reveal.ts +4 -3
  316. package/src/modes/gradient-highlight.ts +21 -9
  317. package/src/modes/image-references.ts +20 -0
  318. package/src/modes/interactive-mode.ts +288 -48
  319. package/src/modes/magic-keywords.ts +27 -5
  320. package/src/modes/rpc/rpc-mode.ts +146 -14
  321. package/src/modes/rpc/rpc-subagents.ts +2 -2
  322. package/src/modes/rpc/rpc-types.ts +8 -2
  323. package/src/modes/runtime-init.ts +28 -3
  324. package/src/modes/theme/theme.ts +99 -51
  325. package/src/modes/types.ts +6 -7
  326. package/src/modes/utils/hotkeys-markdown.ts +1 -1
  327. package/src/modes/utils/ui-helpers.ts +36 -7
  328. package/src/priority.json +5 -1
  329. package/src/prompts/agents/task.md +1 -0
  330. package/src/prompts/goals/guided-goal-interview.md +8 -0
  331. package/src/prompts/goals/guided-goal-system.md +12 -0
  332. package/src/prompts/memories/read-path.md +6 -0
  333. package/src/prompts/system/autolearn-guidance-learn.md +1 -0
  334. package/src/prompts/system/autolearn-guidance.md +7 -0
  335. package/src/prompts/system/autolearn-nudge.md +3 -0
  336. package/src/prompts/system/eager-task.md +7 -0
  337. package/src/prompts/system/eager-todo.md +11 -6
  338. package/src/prompts/system/empty-stop-retry.md +4 -6
  339. package/src/prompts/system/subagent-system-prompt.md +4 -0
  340. package/src/prompts/system/system-prompt.md +10 -5
  341. package/src/prompts/system/title-marker-instruction.md +1 -0
  342. package/src/prompts/system/title-system-marker.md +16 -0
  343. package/src/prompts/tools/job.md +1 -0
  344. package/src/prompts/tools/learn.md +7 -0
  345. package/src/prompts/tools/manage-skill.md +9 -0
  346. package/src/prompts/tools/task.md +3 -0
  347. package/src/registry/agent-registry.ts +30 -0
  348. package/src/sdk.ts +103 -43
  349. package/src/secrets/obfuscator.ts +1 -1
  350. package/src/session/agent-session.ts +331 -318
  351. package/src/session/agent-storage.ts +18 -9
  352. package/src/session/history-storage.ts +3 -2
  353. package/src/session/indexed-session-storage.ts +7 -10
  354. package/src/session/messages.ts +9 -11
  355. package/src/session/session-context.ts +352 -0
  356. package/src/session/session-dump-format.ts +4 -2
  357. package/src/session/session-entries.ts +194 -0
  358. package/src/session/session-listing.ts +588 -0
  359. package/src/session/session-loader.ts +106 -0
  360. package/src/session/session-manager.ts +968 -3064
  361. package/src/session/session-migrations.ts +78 -0
  362. package/src/session/session-paths.ts +193 -0
  363. package/src/session/session-persistence.ts +131 -0
  364. package/src/session/session-storage.ts +91 -30
  365. package/src/session/snapcompact-inline.ts +21 -1
  366. package/src/session/snapcompact-savings-journal.ts +113 -0
  367. package/src/session/tool-choice-queue.ts +23 -11
  368. package/src/slash-commands/builtin-registry.ts +40 -4
  369. package/src/slash-commands/helpers/logout.ts +88 -0
  370. package/src/stt/asr-client.ts +520 -0
  371. package/src/stt/asr-protocol.ts +65 -0
  372. package/src/stt/asr-worker.ts +790 -0
  373. package/src/stt/downloader.ts +107 -47
  374. package/src/stt/endpointer.ts +259 -0
  375. package/src/stt/index.ts +5 -1
  376. package/src/stt/models.ts +150 -0
  377. package/src/stt/recorder.ts +247 -60
  378. package/src/stt/stt-controller.ts +201 -22
  379. package/src/stt/transcriber.ts +37 -68
  380. package/src/stt/wav.ts +173 -0
  381. package/src/system-prompt.ts +8 -0
  382. package/src/task/agents.ts +1 -2
  383. package/src/task/executor.ts +49 -15
  384. package/src/task/index.ts +60 -6
  385. package/src/task/render.ts +83 -8
  386. package/src/task/types.ts +54 -1
  387. package/src/tools/ask.ts +9 -1
  388. package/src/tools/ast-edit.ts +1 -1
  389. package/src/tools/ast-grep.ts +1 -1
  390. package/src/tools/bash.ts +5 -4
  391. package/src/tools/browser/cmux/cmux-tab.ts +1264 -0
  392. package/src/tools/browser/cmux/rpc.ts +156 -0
  393. package/src/tools/browser/cmux/socket-client.ts +309 -0
  394. package/src/tools/browser/registry.ts +37 -3
  395. package/src/tools/browser/render.ts +6 -1
  396. package/src/tools/browser/tab-protocol.ts +2 -0
  397. package/src/tools/browser/tab-supervisor.ts +189 -18
  398. package/src/tools/browser/tab-worker.ts +1 -1
  399. package/src/tools/browser.ts +16 -1
  400. package/src/tools/checkpoint.ts +1 -1
  401. package/src/tools/debug.ts +1 -1
  402. package/src/tools/eval-render.ts +4 -3
  403. package/src/tools/eval.ts +11 -6
  404. package/src/tools/fetch.ts +13 -2
  405. package/src/tools/find.ts +1 -1
  406. package/src/tools/gh.ts +1 -1
  407. package/src/tools/github-cache.ts +2 -1
  408. package/src/tools/image-gen.ts +1 -1
  409. package/src/tools/index.ts +43 -5
  410. package/src/tools/inspect-image.ts +3 -1
  411. package/src/tools/irc.ts +11 -3
  412. package/src/tools/job.ts +15 -3
  413. package/src/tools/learn.ts +144 -0
  414. package/src/tools/manage-skill.ts +104 -0
  415. package/src/tools/memory-edit.ts +1 -1
  416. package/src/tools/memory-recall.ts +1 -1
  417. package/src/tools/memory-reflect.ts +1 -1
  418. package/src/tools/memory-retain.ts +1 -1
  419. package/src/tools/plan-mode-guard.ts +53 -19
  420. package/src/tools/read.ts +8 -2
  421. package/src/tools/render-mermaid.ts +1 -1
  422. package/src/tools/renderers.ts +7 -11
  423. package/src/tools/report-tool-issue.ts +3 -2
  424. package/src/tools/resolve.ts +1 -1
  425. package/src/tools/review.ts +1 -1
  426. package/src/tools/search-tool-bm25.ts +1 -1
  427. package/src/tools/search.ts +1 -1
  428. package/src/tools/ssh.ts +5 -4
  429. package/src/tools/todo.ts +2 -2
  430. package/src/tools/tts.ts +204 -93
  431. package/src/tools/write.ts +19 -3
  432. package/src/tts/downloader.ts +64 -0
  433. package/src/tts/index.ts +8 -0
  434. package/src/tts/models.ts +137 -0
  435. package/src/tts/player.ts +137 -0
  436. package/src/tts/runtime.ts +21 -0
  437. package/src/tts/streaming-player.ts +266 -0
  438. package/src/tts/tts-client.ts +647 -0
  439. package/src/tts/tts-protocol.ts +60 -0
  440. package/src/tts/tts-worker.ts +497 -0
  441. package/src/tts/vocalizer.ts +162 -0
  442. package/src/tts/wav.ts +58 -0
  443. package/src/utils/clipboard.ts +35 -18
  444. package/src/utils/image-loading.ts +35 -4
  445. package/src/utils/thinking-display.ts +37 -0
  446. package/src/utils/title-generator.ts +48 -5
  447. package/src/utils/tool-choice.ts +16 -0
  448. package/src/utils/tools-manager.test.ts +25 -0
  449. package/src/utils/tools-manager.ts +19 -1
  450. package/src/web/scrapers/github.ts +96 -0
  451. package/src/web/search/index.ts +14 -1
  452. package/src/web/search/providers/searxng.ts +13 -1
  453. package/dist/types/cli/list-models.d.ts +0 -30
  454. package/dist/types/stt/setup.d.ts +0 -18
  455. package/src/cli/list-models.ts +0 -194
  456. package/src/stt/setup.ts +0 -52
  457. package/src/stt/transcribe.py +0 -70
package/src/sdk.ts CHANGED
@@ -34,8 +34,8 @@ import {
34
34
  prompt,
35
35
  Snowflake,
36
36
  } from "@oh-my-pi/pi-utils";
37
- import chalk from "chalk";
38
37
  import { type AsyncJob, AsyncJobManager } from "./async";
38
+ import { AutoLearnController, buildAutoLearnInstructions } from "./autolearn/controller";
39
39
  import { loadCapability } from "./capability";
40
40
  import { type Rule, ruleCapability, setActiveRules } from "./capability/rule";
41
41
  import { bucketRules } from "./capability/rule-buckets";
@@ -97,6 +97,7 @@ import {
97
97
  type MCPToolsLoadResult,
98
98
  parseMCPToolName,
99
99
  } from "./mcp";
100
+ import { MCP_CONNECTING_EVENT_CHANNEL, type McpConnectingEvent } from "./mcp/startup-events";
100
101
  import { createSessionMemoryRuntimeContext, resolveMemoryBackend } from "./memory-backend";
101
102
  import type { MnemopiSessionState } from "./mnemopi/state";
102
103
  import asyncResultTemplate from "./prompts/tools/async-result.md" with { type: "text" };
@@ -128,8 +129,10 @@ import {
128
129
  LSP_LATE_DIAGNOSTIC_MESSAGE_TYPE,
129
130
  wrapSteeringForModel,
130
131
  } from "./session/messages";
131
- import { getRestorableSessionModels, SessionManager } from "./session/session-manager";
132
+ import { getRestorableSessionModels } from "./session/session-context";
133
+ import { SessionManager } from "./session/session-manager";
132
134
  import { SnapcompactInlineTransformer } from "./session/snapcompact-inline";
135
+ import { createSnapcompactSavingsRecorder } from "./session/snapcompact-savings-journal";
133
136
  import { closeAllConnections } from "./ssh/connection-manager";
134
137
  import { unmountAll } from "./ssh/sshfs-mount";
135
138
  import {
@@ -316,10 +319,6 @@ type DeferredMCPActivation = {
316
319
  activateAllMCPTools: boolean;
317
320
  };
318
321
 
319
- function formatMCPConnectingMessage(serverNames: string[]): string {
320
- return `Connecting to MCP servers: ${serverNames.join(", ")}…`;
321
- }
322
-
323
322
  function createPendingMCPTool(name: string): Tool {
324
323
  const parsed = parseMCPToolName(name);
325
324
  const serverName = parsed?.serverName;
@@ -1166,20 +1165,15 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1166
1165
  SessionManager.create(cwd, SessionManager.getDefaultSessionDir(cwd, agentDir)),
1167
1166
  );
1168
1167
  const providerSessionId = options.providerSessionId ?? sessionManager.getSessionId();
1169
- const modelApiKeyAvailability = new Map<string, boolean>();
1170
- const getModelAvailabilityKey = (candidate: Model): string =>
1171
- `${candidate.provider}\u0000${candidate.baseUrl ?? ""}`;
1172
- const hasModelApiKey = async (candidate: Model): Promise<boolean> => {
1173
- const availabilityKey = getModelAvailabilityKey(candidate);
1174
- const cached = modelApiKeyAvailability.get(availabilityKey);
1175
- if (cached !== undefined) {
1176
- return cached;
1177
- }
1178
-
1179
- const hasKey = !!(await modelRegistry.getApiKey(candidate, providerSessionId));
1180
- modelApiKeyAvailability.set(availabilityKey, hasKey);
1181
- return hasKey;
1182
- };
1168
+ // Startup model *selection* only needs to know whether auth is configured for
1169
+ // a candidate's provider never the resolved key bytes. Use the synchronous,
1170
+ // side-effect-free probe (`hasConfiguredAuth`): it refreshes no OAuth tokens,
1171
+ // executes no `!command` keys, and issues no auth-broker requests. Resolving the
1172
+ // real key here (`getApiKey`) blocks resume on those network paths — a slow or
1173
+ // unreachable OAuth/broker endpoint stalls startup for the full ~10s refresh
1174
+ // timeout per candidate (observed as a hang in `restoreSessionModel`). The real
1175
+ // key is resolved lazily per request via ModelRegistry.resolver.
1176
+ const hasModelAuth = (candidate: Model): boolean => modelRegistry.hasConfiguredAuth(candidate);
1183
1177
 
1184
1178
  // Load and create secret obfuscator early so resumed session state and prompt warnings
1185
1179
  // reflect actual loaded secrets, not just the setting toggle.
@@ -1228,7 +1222,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1228
1222
  : [];
1229
1223
  let restoredSessionModelIndex = -1;
1230
1224
  if (!hasExplicitModel && !model && sessionModelStrings.length > 0) {
1231
- await logger.time("restoreSessionModel", async () => {
1225
+ logger.time("restoreSessionModel", () => {
1232
1226
  let failedSessionModel: string | undefined;
1233
1227
  for (let i = 0; i < sessionModelStrings.length; i++) {
1234
1228
  const sessionModelStr = sessionModelStrings[i];
@@ -1239,7 +1233,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1239
1233
  }
1240
1234
 
1241
1235
  const restoredModel = modelRegistry.find(parsedModel.provider, parsedModel.id);
1242
- if (restoredModel && (await hasModelApiKey(restoredModel))) {
1236
+ if (restoredModel && hasModelAuth(restoredModel)) {
1243
1237
  model = restoredModel;
1244
1238
  restoredSessionModelIndex = i;
1245
1239
  break;
@@ -1492,6 +1486,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1492
1486
  getSessionSpawns: () => options.spawns ?? "*",
1493
1487
  getModelString: () => (hasExplicitModel && model ? formatModelString(model) : undefined),
1494
1488
  getActiveModelString,
1489
+ getActiveModel: () => agent?.state.model ?? model,
1495
1490
  getPlanModeState: () => session?.getPlanModeState(),
1496
1491
  getPlanReferencePath: () => session?.getPlanReferencePath() ?? "local://PLAN.md",
1497
1492
  getGoalModeState: () => session?.getGoalModeState(),
@@ -1603,7 +1598,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1603
1598
  | undefined;
1604
1599
  const onMCPConnecting = (serverNames: string[]) => {
1605
1600
  if (!options.hasUI || serverNames.length === 0) return;
1606
- process.stderr.write(`${chalk.gray(formatMCPConnectingMessage(serverNames))}\n`);
1601
+ eventBus.emit(MCP_CONNECTING_EVENT_CHANNEL, { serverNames } satisfies McpConnectingEvent);
1607
1602
  };
1608
1603
  const mcpDiscoverOptions = {
1609
1604
  onConnecting: onMCPConnecting,
@@ -1730,7 +1725,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1730
1725
  customTools.push(...(imageGenTools as unknown as CustomTool[]));
1731
1726
  }
1732
1727
 
1733
- if (settings.get("tts.enabled")) {
1728
+ if (settings.get("speechgen.enabled")) {
1734
1729
  customTools.push(ttsTool as unknown as CustomTool);
1735
1730
  }
1736
1731
 
@@ -1866,7 +1861,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1866
1861
  const parsedModel = parseModelString(sessionModelStr);
1867
1862
  if (!parsedModel) continue;
1868
1863
  const restoredModel = modelRegistry.find(parsedModel.provider, parsedModel.id);
1869
- if (restoredModel && (await hasModelApiKey(restoredModel))) {
1864
+ if (restoredModel && hasModelAuth(restoredModel)) {
1870
1865
  model = restoredModel;
1871
1866
  modelFallbackMessage = undefined;
1872
1867
  restoredSessionModelIndex = i;
@@ -1918,7 +1913,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1918
1913
  const preferred = fallbackCandidates.find(
1919
1914
  candidate => candidate.provider === provider && candidate.id === defaultId,
1920
1915
  );
1921
- if (preferred && (await hasModelApiKey(preferred))) {
1916
+ if (preferred && hasModelAuth(preferred)) {
1922
1917
  model = preferred;
1923
1918
  break;
1924
1919
  }
@@ -1926,7 +1921,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1926
1921
  // Otherwise, first available model with a valid API key.
1927
1922
  if (!model) {
1928
1923
  for (const candidate of fallbackCandidates) {
1929
- if (await hasModelApiKey(candidate)) {
1924
+ if (hasModelAuth(candidate)) {
1930
1925
  model = candidate;
1931
1926
  break;
1932
1927
  }
@@ -1969,6 +1964,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1969
1964
  sessionManager,
1970
1965
  modelRegistry,
1971
1966
  () => (hasSession ? createSessionMemoryRuntimeContext(session, agentDir, cwd) : undefined),
1967
+ settings,
1972
1968
  );
1973
1969
 
1974
1970
  credentialDisabledTarget = extensionRunner;
@@ -2086,7 +2082,8 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2086
2082
  });
2087
2083
 
2088
2084
  const repeatToolDescriptions = settings.get("repeatToolDescriptions");
2089
- const eagerTasks = settings.get("task.eager");
2085
+ const eagerTasks = settings.get("task.eager") !== "default";
2086
+ const eagerTasksAlways = settings.get("task.eager") === "always";
2090
2087
  const intentField = $flag("PI_INTENT_TRACING", settings.get("tools.intentTracing")) ? INTENT_FIELD : undefined;
2091
2088
  const rebuildSystemPrompt = async (
2092
2089
  toolNames: string[],
@@ -2116,13 +2113,27 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2116
2113
  const memoryBackend = await resolveMemoryBackend(settings);
2117
2114
  const memoryInstructions = await memoryBackend.buildDeveloperInstructions(agentDir, settings, session);
2118
2115
 
2119
- // Build combined append prompt: memory instructions + MCP server instructions.
2120
- // For UI sessions MCP discovery is deferred, so `getServerInstructions()` is
2121
- // empty until the background connect completes; the rebuild that
2122
- // `refreshMCPTools` triggers post-discovery then picks up the now-connected
2123
- // servers' instructions, so they join the prompt for the rest of the session.
2116
+ // Build combined append prompt: memory instructions + auto-learn guidance
2117
+ // + MCP server instructions. For UI sessions MCP discovery is deferred, so
2118
+ // `getServerInstructions()` is empty until the background connect completes;
2119
+ // the rebuild that `refreshMCPTools` triggers post-discovery then picks up
2120
+ // the now-connected servers' instructions, so they join the prompt for the
2121
+ // rest of the session.
2124
2122
  const serverInstructions = mcpManager?.getServerInstructions();
2125
- let appendPrompt: string | undefined = memoryInstructions ?? undefined;
2123
+ // Drive guidance off the auto-learn BUILTINS that createTools actually built
2124
+ // (provenance, not just an active name): `builtInToolNames` excludes a
2125
+ // custom/extension tool that merely shares the name, and reflects the
2126
+ // session-start build — so a subagent that filtered them out, a mid-session
2127
+ // enable that never built them, or a same-named custom tool while auto-learn
2128
+ // is off all get no guidance.
2129
+ const autoLearnInstructions = buildAutoLearnInstructions({
2130
+ manageSkill: builtInToolNames.includes("manage_skill"),
2131
+ learn: builtInToolNames.includes("learn"),
2132
+ });
2133
+ const appendParts: string[] = [];
2134
+ if (memoryInstructions) appendParts.push(memoryInstructions);
2135
+ if (autoLearnInstructions) appendParts.push(autoLearnInstructions);
2136
+ let appendPrompt: string | undefined = appendParts.length > 0 ? appendParts.join("\n\n") : undefined;
2126
2137
  if (serverInstructions && serverInstructions.size > 0) {
2127
2138
  const parts: string[] = [];
2128
2139
  if (appendPrompt) parts.push(appendPrompt);
@@ -2153,6 +2164,8 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2153
2164
  mcpDiscoveryMode: hasDiscoverableTools,
2154
2165
  mcpDiscoveryServerSummaries: discoverableToolSummary.servers.map(formatDiscoverableToolServerSummary),
2155
2166
  eagerTasks,
2167
+ eagerTasksAlways,
2168
+ taskBatch: settings.get("task.batch"),
2156
2169
  secretsEnabled,
2157
2170
  workspaceTree: workspaceTreePromise,
2158
2171
  memoryRootEnabled: memoryBackend.id === "local",
@@ -2187,6 +2200,20 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2187
2200
  ) {
2188
2201
  explicitlyRequestedToolNames.push("yield");
2189
2202
  }
2203
+ // Auto-learn builtins are force-included into the registry by `createTools`
2204
+ // for enabled top-level sessions (tools/index.ts), but — like `yield` above —
2205
+ // an explicit `toolNames` list would otherwise drop them from the ACTIVE set,
2206
+ // leaving the nudge/guidance pointing at tools the model cannot call. Activate
2207
+ // exactly the builtins createTools built (`builtInToolNames` — provenance, so a
2208
+ // same-named custom/extension tool is never force-activated when auto-learn is
2209
+ // off) to keep guidance, controller, and the active set consistent.
2210
+ if (explicitlyRequestedToolNames) {
2211
+ for (const name of ["manage_skill", "learn"]) {
2212
+ if (builtInToolNames.includes(name) && !explicitlyRequestedToolNames.includes(name)) {
2213
+ explicitlyRequestedToolNames.push(name);
2214
+ }
2215
+ }
2216
+ }
2190
2217
  const requestedToolNames = explicitlyRequestedToolNames ?? toolNamesFromRegistry;
2191
2218
  const normalizedRequested = requestedToolNames.filter(name => toolRegistry.has(name));
2192
2219
  const requestedToolNameSet = new Set(normalizedRequested);
@@ -2251,11 +2278,17 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2251
2278
  if (effectiveDiscoveryMode === "all") {
2252
2279
  // Tools a forced tool_choice will target must stay active, or the named
2253
2280
  // choice references a tool absent from the request (provider 400). Eager
2254
- // todos force a named `todo` choice on the first turn.
2281
+ // todos force a named `todo` choice on the first turn. `task` is also kept
2282
+ // active under discovery-all when `task.eager` is not `default`, so eager delegation is
2283
+ // possible and the Eager Tasks prompt section renders, even though nothing
2284
+ // forces a `task` tool_choice.
2255
2285
  const forceActive = new Set<string>();
2256
- if (settings.get("todo.eager") && settings.get("todo.enabled") && toolRegistry.has("todo")) {
2286
+ if (settings.get("todo.eager") !== "default" && settings.get("todo.enabled") && toolRegistry.has("todo")) {
2257
2287
  forceActive.add("todo");
2258
2288
  }
2289
+ if (settings.get("task.eager") !== "default" && toolRegistry.has("task")) {
2290
+ forceActive.add("task");
2291
+ }
2259
2292
  initialToolNames = filterInitialToolsForDiscoveryAll(initialToolNames, {
2260
2293
  loadModeOf: name => toolRegistry.get(name)?.loadMode,
2261
2294
  essentialNames: new Set(computeEssentialBuiltinNames(settings)),
@@ -2343,11 +2376,16 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2343
2376
  const snapcompactSystemPromptMode = settings.get("snapcompact.systemPrompt");
2344
2377
  const snapcompactInline =
2345
2378
  snapcompactSystemPromptMode !== "none" || settings.get("snapcompact.toolResults")
2346
- ? new SnapcompactInlineTransformer({
2347
- renderSystemPrompt: snapcompactSystemPromptMode,
2348
- renderToolResults: settings.get("snapcompact.toolResults"),
2349
- shape: settings.get("snapcompact.shape"),
2350
- })
2379
+ ? new SnapcompactInlineTransformer(
2380
+ {
2381
+ renderSystemPrompt: snapcompactSystemPromptMode,
2382
+ renderToolResults: settings.get("snapcompact.toolResults"),
2383
+ shape: settings.get("snapcompact.shape"),
2384
+ },
2385
+ // Journal the tokens each imaged tool result keeps off the wire
2386
+ // (frames never reach session.jsonl, so this is their only trace).
2387
+ createSnapcompactSavingsRecorder(() => sessionManager.getSessionFile() ?? null),
2388
+ )
2351
2389
  : undefined;
2352
2390
  const transformProviderContext =
2353
2391
  obfuscator || snapcompactInline
@@ -2531,6 +2569,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2531
2569
  ttsrManager,
2532
2570
  obfuscator,
2533
2571
  agentId: resolvedAgentId,
2572
+ agentKind,
2534
2573
  providerSessionId: options.providerSessionId,
2535
2574
  parentEvalSessionId: options.parentEvalSessionId,
2536
2575
  });
@@ -2655,7 +2694,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2655
2694
  }
2656
2695
  }
2657
2696
 
2658
- logger.time("startMemoryStartupTask", async () => {
2697
+ const startMemoryBackend = async () => {
2659
2698
  const memoryBackend = await resolveMemoryBackend(settings);
2660
2699
  await memoryBackend.start({
2661
2700
  session,
@@ -2666,7 +2705,28 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2666
2705
  parentHindsightSessionState: options.parentHindsightSessionState,
2667
2706
  parentMnemopiSessionState: options.parentMnemopiSessionState,
2668
2707
  });
2669
- });
2708
+ };
2709
+
2710
+ // Auto-learn can immediately trigger a synthetic capture turn after the
2711
+ // first real stop. When a memory backend is selected, install that backend's
2712
+ // per-session state first so the capture turn's `learn` tool observes the
2713
+ // same initialized state as normal memory tools. Other sessions keep memory
2714
+ // startup in the background to preserve the existing startup profile.
2715
+ //
2716
+ // Gated on `autolearn.enabled` to match the tools: `createTools` builds the
2717
+ // `learn`/`manage_skill` registry ONCE at session start and no settings
2718
+ // change rebuilds it, so installing the controller while disabled would let a
2719
+ // mid-session enable fire a nudge pointing at tools the session never built.
2720
+ // Activation is therefore a session-start decision for BOTH the controller
2721
+ // and the tools; the fire-time re-check in `#onAgentEnd` still handles a
2722
+ // mid-session DISABLE. The subscription lives for the session's lifetime; the
2723
+ // reference is intentionally discarded (the listener retains it).
2724
+ if (settings.get("autolearn.enabled") && taskDepth === 0) {
2725
+ await logger.time("startMemoryStartupTask", startMemoryBackend);
2726
+ new AutoLearnController({ session, settings });
2727
+ } else {
2728
+ void logger.time("startMemoryStartupTask", startMemoryBackend);
2729
+ }
2670
2730
 
2671
2731
  // Wire MCP manager callbacks to session for reactive tool updates.
2672
2732
  // Skip when reusing a parent's manager — the parent owns the callbacks.
@@ -1,6 +1,6 @@
1
1
  import type { Context, Message, Tool } from "@oh-my-pi/pi-ai";
2
2
  import { toolWireSchema } from "@oh-my-pi/pi-ai/utils/schema";
3
- import type { SessionContext } from "../session/session-manager";
3
+ import type { SessionContext } from "../session/session-context";
4
4
  import { compileSecretRegex } from "./regex";
5
5
 
6
6
  // ═══════════════════════════════════════════════════════════════════════════