@tekmidian/pai 0.42.4 → 0.42.6

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 (292) hide show
  1. package/ARCHITECTURE.md +9 -9
  2. package/README.md +26 -8
  3. package/dist/{aibroker-client-BP74gGwD.mjs → aibroker-client-Bn9SnGMa.mjs} +3 -3
  4. package/dist/{aibroker-client-BP74gGwD.mjs.map → aibroker-client-Bn9SnGMa.mjs.map} +1 -1
  5. package/dist/{aibroker-client-C6m71p6O.mjs → aibroker-client-D5NT0S1N.mjs} +1 -1
  6. package/dist/{auto-route-_5zzJz5q.mjs → auto-route-CcD0OWWB.mjs} +4 -4
  7. package/dist/{auto-route-_5zzJz5q.mjs.map → auto-route-CcD0OWWB.mjs.map} +1 -1
  8. package/dist/{chain-DTII7xeL.mjs → chain-BbcfP77K.mjs} +5 -4
  9. package/dist/{chain-DTII7xeL.mjs.map → chain-BbcfP77K.mjs.map} +1 -1
  10. package/dist/cli/index.mjs +23 -21
  11. package/dist/cli/index.mjs.map +1 -1
  12. package/dist/cli/program.d.mts.map +1 -1
  13. package/dist/cli/program.mjs +23 -21
  14. package/dist/{clusters-j0ZuNYp9.mjs → clusters-Cw_P6lO-.mjs} +2 -2
  15. package/dist/{clusters-j0ZuNYp9.mjs.map → clusters-Cw_P6lO-.mjs.map} +1 -1
  16. package/dist/{config-B64vFg14.mjs → config-DCu8THKi.mjs} +41 -9
  17. package/dist/{config-B64vFg14.mjs.map → config-DCu8THKi.mjs.map} +1 -1
  18. package/dist/config-DeqFqa1N.mjs +3 -0
  19. package/dist/config-DxMZjpvY.mjs +1289 -0
  20. package/dist/config-DxMZjpvY.mjs.map +1 -0
  21. package/dist/context-handover-cache-B9NKSjwR.mjs +3242 -0
  22. package/dist/context-handover-cache-B9NKSjwR.mjs.map +1 -0
  23. package/dist/daemon/index.mjs +23 -22
  24. package/dist/daemon/index.mjs.map +1 -1
  25. package/dist/daemon-BNjbVsQU.mjs +24 -0
  26. package/dist/{daemon-B8N1egl0.mjs → daemon-BppziPi6.mjs} +52 -38
  27. package/dist/daemon-BppziPi6.mjs.map +1 -0
  28. package/dist/daemon-mcp/index.mjs +144 -117
  29. package/dist/daemon-mcp/index.mjs.map +1 -1
  30. package/dist/db-BOBfewFH.mjs +3 -0
  31. package/dist/{db-a1ixZQjr.mjs → db-DJ8rk0VM.mjs} +15 -6
  32. package/dist/{db-a1ixZQjr.mjs.map → db-DJ8rk0VM.mjs.map} +1 -1
  33. package/dist/db-DbY2O8QO.mjs +3 -0
  34. package/dist/{db-Ca5qfsMC.mjs → db-Ddns80yf.mjs} +15 -6
  35. package/dist/{db-Ca5qfsMC.mjs.map → db-Ddns80yf.mjs.map} +1 -1
  36. package/dist/{detect-CdaA48EI.mjs → detect-Bf2z-oKB.mjs} +1 -1
  37. package/dist/{detect-CdaA48EI.mjs.map → detect-Bf2z-oKB.mjs.map} +1 -1
  38. package/dist/detector-CkwkXuGh.mjs +5 -0
  39. package/dist/{detector-C73Nxm94.mjs → detector-DWXkeTlk.mjs} +2 -2
  40. package/dist/{detector-C73Nxm94.mjs.map → detector-DWXkeTlk.mjs.map} +1 -1
  41. package/dist/{embeddings-CEBGrzwu.mjs → embeddings-ClqKtLZ8.mjs} +1 -1
  42. package/dist/{embeddings-DOLZnT1X.mjs → embeddings-DvRKcQyt.mjs} +1 -1
  43. package/dist/{embeddings-DOLZnT1X.mjs.map → embeddings-DvRKcQyt.mjs.map} +1 -1
  44. package/dist/factory-47Qf_df7.mjs +3 -0
  45. package/dist/{factory-DEb9NmHJ.mjs → factory-DNYAqjH0.mjs} +8 -8
  46. package/dist/{factory-DEb9NmHJ.mjs.map → factory-DNYAqjH0.mjs.map} +1 -1
  47. package/dist/{fallback-oJl3BaIN.mjs → fallback-Cwt4hmh5.mjs} +182 -122
  48. package/dist/fallback-Cwt4hmh5.mjs.map +1 -0
  49. package/dist/{helpers-IjZkXBhj.mjs → helpers-crDEr6S2.mjs} +1 -1
  50. package/dist/{helpers-IjZkXBhj.mjs.map → helpers-crDEr6S2.mjs.map} +1 -1
  51. package/dist/hooks/capture-all-events.mjs +117 -34
  52. package/dist/hooks/capture-all-events.mjs.map +4 -4
  53. package/dist/hooks/capture-session-summary.mjs +110 -33
  54. package/dist/hooks/capture-session-summary.mjs.map +4 -4
  55. package/dist/hooks/capture-tool-output.mjs +105 -28
  56. package/dist/hooks/capture-tool-output.mjs.map +4 -4
  57. package/dist/hooks/cleanup-session-files.mjs +54 -13
  58. package/dist/hooks/cleanup-session-files.mjs.map +2 -2
  59. package/dist/hooks/context-compression-hook.mjs +7565 -122
  60. package/dist/hooks/context-compression-hook.mjs.map +4 -4
  61. package/dist/hooks/initialize-session.mjs +55 -14
  62. package/dist/hooks/initialize-session.mjs.map +2 -2
  63. package/dist/hooks/inject-observations.mjs +79 -18
  64. package/dist/hooks/inject-observations.mjs.map +3 -3
  65. package/dist/hooks/load-core-context.mjs +55 -14
  66. package/dist/hooks/load-core-context.mjs.map +2 -2
  67. package/dist/hooks/load-project-context.mjs +185 -103
  68. package/dist/hooks/load-project-context.mjs.map +4 -4
  69. package/dist/hooks/mcp-deferred-gate.mjs +54 -13
  70. package/dist/hooks/mcp-deferred-gate.mjs.map +2 -2
  71. package/dist/hooks/mcp-deferred-reminder.mjs +9 -0
  72. package/dist/hooks/mcp-deferred-reminder.mjs.map +3 -3
  73. package/dist/hooks/observe.mjs +54 -13
  74. package/dist/hooks/observe.mjs.map +2 -2
  75. package/dist/hooks/post-compact-inject.mjs +7419 -16
  76. package/dist/hooks/post-compact-inject.mjs.map +4 -4
  77. package/dist/hooks/route-agents-to-worker.mjs +7778 -171
  78. package/dist/hooks/route-agents-to-worker.mjs.map +4 -4
  79. package/dist/hooks/route-edits-to-worker.mjs +90 -0
  80. package/dist/hooks/route-edits-to-worker.mjs.map +7 -0
  81. package/dist/hooks/security-validator.mjs +147 -6
  82. package/dist/hooks/security-validator.mjs.map +4 -4
  83. package/dist/hooks/session-commands.mjs +9 -0
  84. package/dist/hooks/session-commands.mjs.map +3 -3
  85. package/dist/hooks/stop-hook.mjs +182 -105
  86. package/dist/hooks/stop-hook.mjs.map +4 -4
  87. package/dist/hooks/subagent-stop-hook.mjs +3 -0
  88. package/dist/hooks/subagent-stop-hook.mjs.map +1 -1
  89. package/dist/hooks/sync-todo-to-md.mjs +54 -13
  90. package/dist/hooks/sync-todo-to-md.mjs.map +2 -2
  91. package/dist/hooks/update-tab-on-action.mjs +3 -0
  92. package/dist/hooks/update-tab-on-action.mjs.map +1 -1
  93. package/dist/hooks/update-tab-titles.mjs +3 -0
  94. package/dist/hooks/update-tab-titles.mjs.map +1 -1
  95. package/dist/hooks/whisper-reinject.mjs +3 -0
  96. package/dist/hooks/whisper-reinject.mjs.map +1 -1
  97. package/dist/hooks/whisper-rules.mjs +134 -29
  98. package/dist/hooks/whisper-rules.mjs.map +4 -4
  99. package/dist/hooks/worker-proxy.mjs +7737 -117
  100. package/dist/hooks/worker-proxy.mjs.map +4 -4
  101. package/dist/hooks/worker-status-line.mjs +7791 -144
  102. package/dist/hooks/worker-status-line.mjs.map +4 -4
  103. package/dist/hooks/worker-supervision.mjs +7721 -115
  104. package/dist/hooks/worker-supervision.mjs.map +4 -4
  105. package/dist/index.d.mts +4 -2
  106. package/dist/index.d.mts.map +1 -1
  107. package/dist/index.mjs +10 -10
  108. package/dist/{indexer-backend-BPTzKFZU.mjs → indexer-backend-CdvCJCkD.mjs} +3 -3
  109. package/dist/{indexer-backend-BPTzKFZU.mjs.map → indexer-backend-CdvCJCkD.mjs.map} +1 -1
  110. package/dist/{ipc-client-BmypMNYk.mjs → ipc-client-C6NryMMb.mjs} +2 -2
  111. package/dist/{ipc-client-BmypMNYk.mjs.map → ipc-client-C6NryMMb.mjs.map} +1 -1
  112. package/dist/{kg-entity-r8duqhi9.mjs → kg-entity-BSjM5xZh.mjs} +1 -1
  113. package/dist/{kg-entity-r8duqhi9.mjs.map → kg-entity-BSjM5xZh.mjs.map} +1 -1
  114. package/dist/{latent-ideas-CtSca4qG.mjs → latent-ideas-BfL4nCQ3.mjs} +4 -4
  115. package/dist/{latent-ideas-CtSca4qG.mjs.map → latent-ideas-BfL4nCQ3.mjs.map} +1 -1
  116. package/dist/{link-boost-Bucnz3n8.mjs → link-boost-C5PaNdzm.mjs} +1 -1
  117. package/dist/{link-boost-Bucnz3n8.mjs.map → link-boost-C5PaNdzm.mjs.map} +1 -1
  118. package/dist/main-resolver-CnfnWa8C.mjs +7 -0
  119. package/dist/{main-resolver-DnkxPYkr.mjs → main-resolver-DvYu9jbl.mjs} +21 -11
  120. package/dist/main-resolver-DvYu9jbl.mjs.map +1 -0
  121. package/dist/{migrate-Cjzeefn9.mjs → migrate-CfERwXhY.mjs} +2 -2
  122. package/dist/{migrate-Cjzeefn9.mjs.map → migrate-CfERwXhY.mjs.map} +1 -1
  123. package/dist/{neighborhood-CM7Jgb51.mjs → neighborhood-CETR_P4y.mjs} +2 -2
  124. package/dist/{neighborhood-CM7Jgb51.mjs.map → neighborhood-CETR_P4y.mjs.map} +1 -1
  125. package/dist/{note-context-DCwE2A-M.mjs → note-context-DCcRWBoN.mjs} +1 -1
  126. package/dist/{note-context-DCwE2A-M.mjs.map → note-context-DCcRWBoN.mjs.map} +1 -1
  127. package/dist/pai-home-ChAOupZc.mjs +164 -0
  128. package/dist/pai-home-ChAOupZc.mjs.map +1 -0
  129. package/dist/{pai-marker-CHtbJMwJ.mjs → pai-marker-B20KqhA8.mjs} +1 -1
  130. package/dist/{pai-marker-CHtbJMwJ.mjs.map → pai-marker-B20KqhA8.mjs.map} +1 -1
  131. package/dist/{planner-D5Ui7DAm.mjs → planner-pXRc-8yt.mjs} +7 -6
  132. package/dist/{planner-D5Ui7DAm.mjs.map → planner-pXRc-8yt.mjs.map} +1 -1
  133. package/dist/{postgres-CtOzfoQU.mjs → postgres-CUSXWgTG.mjs} +2 -2
  134. package/dist/{postgres-CtOzfoQU.mjs.map → postgres-CUSXWgTG.mjs.map} +1 -1
  135. package/dist/{program-zpoYnJGz.mjs → program-LLNPpxlj.mjs} +8308 -6065
  136. package/dist/program-LLNPpxlj.mjs.map +1 -0
  137. package/dist/query-feedback-C7rSfiXU.mjs +3 -0
  138. package/dist/{query-feedback-Dqz-HC__.mjs → query-feedback-CYyOGi3y.mjs} +20 -6
  139. package/dist/query-feedback-CYyOGi3y.mjs.map +1 -0
  140. package/dist/{reranker-CwTCNsgA.mjs → reranker-B5qUTamW.mjs} +1 -1
  141. package/dist/{reranker-xPm04PXx.mjs → reranker-HHmhZk6v.mjs} +1 -1
  142. package/dist/{reranker-xPm04PXx.mjs.map → reranker-HHmhZk6v.mjs.map} +1 -1
  143. package/dist/router-CremHKTI.mjs +3 -0
  144. package/dist/{router-DD6D4j31.mjs → router-DBAZfE7X.mjs} +2 -2
  145. package/dist/{router-DD6D4j31.mjs.map → router-DBAZfE7X.mjs.map} +1 -1
  146. package/dist/{run-D7K5UALn.mjs → run-DDdT9teG.mjs} +530 -210
  147. package/dist/run-DDdT9teG.mjs.map +1 -0
  148. package/dist/{runtime-paths-rni52zHX.mjs → runtime-paths-B0P1TvUr.mjs} +1 -1
  149. package/dist/{runtime-paths-rni52zHX.mjs.map → runtime-paths-B0P1TvUr.mjs.map} +1 -1
  150. package/dist/{search-Rpk1cSBC.mjs → search-B69cQwDB.mjs} +3 -3
  151. package/dist/{search-Rpk1cSBC.mjs.map → search-B69cQwDB.mjs.map} +1 -1
  152. package/dist/{search-CfPpJAWQ.mjs → search-fb-5ovj4.mjs} +2 -2
  153. package/dist/{server-D4vAieF4.mjs → server-Ch99xt5K.mjs} +15 -14
  154. package/dist/server-Ch99xt5K.mjs.map +1 -0
  155. package/dist/skills/Advisor/SKILL.md +3 -3
  156. package/dist/skills/Providers/SKILL.md +30 -0
  157. package/dist/skills/Reconstruct/SKILL.md +1 -1
  158. package/dist/skills/VaultContext/SKILL.md +1 -1
  159. package/dist/skills/Whisper/SKILL.md +3 -3
  160. package/dist/skills/Worker/SKILL.md +1 -1
  161. package/dist/{sources-CS43CpuS.mjs → sources-KBGEA_E6.mjs} +2 -2
  162. package/dist/{sources-CS43CpuS.mjs.map → sources-KBGEA_E6.mjs.map} +1 -1
  163. package/dist/{sqlite-Cq3gJcq9.mjs → sqlite-By6r2YhZ.mjs} +3 -3
  164. package/dist/{sqlite-Cq3gJcq9.mjs.map → sqlite-By6r2YhZ.mjs.map} +1 -1
  165. package/dist/{state-CY6I-Hnc.mjs → state-DnYGRmS7.mjs} +1 -1
  166. package/dist/{state-BRdB-Bf1.mjs → state-PJrgfDLW.mjs} +1 -1
  167. package/dist/{state-BRdB-Bf1.mjs.map → state-PJrgfDLW.mjs.map} +1 -1
  168. package/dist/{stop-words-Hfu8u22w.mjs → stop-words-BaMEGVeY.mjs} +1 -1
  169. package/dist/{stop-words-Hfu8u22w.mjs.map → stop-words-BaMEGVeY.mjs.map} +1 -1
  170. package/dist/{sync-BWbe8JTg.mjs → sync-Btcb6xA4.mjs} +3 -3
  171. package/dist/{sync-BWbe8JTg.mjs.map → sync-Btcb6xA4.mjs.map} +1 -1
  172. package/dist/{themes-B7h9YDiy.mjs → themes-BVoAnLZj.mjs} +3 -3
  173. package/dist/{themes-B7h9YDiy.mjs.map → themes-BVoAnLZj.mjs.map} +1 -1
  174. package/dist/{tools-BW3NLMPk.mjs → tools-BradfQk7.mjs} +4 -3
  175. package/dist/{tools-LlzcV_eK.mjs → tools-UrSHIe29.mjs} +30 -233
  176. package/dist/tools-UrSHIe29.mjs.map +1 -0
  177. package/dist/{trace-u4hT-pLD.mjs → trace-Cy8quQTm.mjs} +1 -1
  178. package/dist/{trace-u4hT-pLD.mjs.map → trace-Cy8quQTm.mjs.map} +1 -1
  179. package/dist/{utils-DhMex3Ox.mjs → utils-BD8g8oSf.mjs} +1 -1
  180. package/dist/{utils-9Err2RBW.mjs → utils-CJymHkYm.mjs} +1 -1
  181. package/dist/{utils-9Err2RBW.mjs.map → utils-CJymHkYm.mjs.map} +1 -1
  182. package/dist/{vault-indexer-mata9S7b.mjs → vault-indexer-C5i-OAyr.mjs} +2 -2
  183. package/dist/{vault-indexer-mata9S7b.mjs.map → vault-indexer-C5i-OAyr.mjs.map} +1 -1
  184. package/dist/wakeup-TnGjJY3I.mjs +218 -0
  185. package/dist/wakeup-TnGjJY3I.mjs.map +1 -0
  186. package/dist/work-queue-worker-BA5IDBwQ.mjs +567 -0
  187. package/dist/work-queue-worker-BA5IDBwQ.mjs.map +1 -0
  188. package/dist/work-queue-worker-DLM2wlqM.mjs +14 -0
  189. package/dist/{zettelkasten-F0D_XfQ4.mjs → zettelkasten-BBjA7GcP.mjs} +4 -4
  190. package/dist/{zettelkasten-F0D_XfQ4.mjs.map → zettelkasten-BBjA7GcP.mjs.map} +1 -1
  191. package/docs/commands/README.md +30 -3
  192. package/docs/commands/audit.md +88 -0
  193. package/docs/commands/backup.md +2 -2
  194. package/docs/commands/clear-names.md +1 -1
  195. package/docs/commands/config.md +59 -0
  196. package/docs/commands/daemon.md +1 -1
  197. package/docs/commands/db.md +1 -1
  198. package/docs/commands/end.md +1 -1
  199. package/docs/commands/help.md +1 -1
  200. package/docs/commands/identity.md +1 -1
  201. package/docs/commands/kg.md +1 -1
  202. package/docs/commands/launch.md +45 -0
  203. package/docs/commands/mcp.md +1 -1
  204. package/docs/commands/memory.md +3 -3
  205. package/docs/commands/notify.md +1 -1
  206. package/docs/commands/observation.md +1 -1
  207. package/docs/commands/obsidian.md +1 -1
  208. package/docs/commands/pause.md +1 -1
  209. package/docs/commands/project.md +46 -1
  210. package/docs/commands/projects.md +46 -1
  211. package/docs/commands/registry.md +1 -1
  212. package/docs/commands/restore.md +1 -1
  213. package/docs/commands/session.md +1 -1
  214. package/docs/commands/sessions.md +1 -1
  215. package/docs/commands/setup.md +1 -1
  216. package/docs/commands/shell-init.md +1 -1
  217. package/docs/commands/skill.md +1 -1
  218. package/docs/commands/task.md +1 -1
  219. package/docs/commands/topic.md +1 -1
  220. package/docs/commands/update.md +1 -1
  221. package/docs/commands/worker.md +95 -6
  222. package/docs/commands/zettel.md +1 -1
  223. package/docs/provider-abstraction.md +1 -1
  224. package/docs/provider-independence-details.md +8 -5
  225. package/docs/task-bus.md +1 -1
  226. package/docs/worker.md +136 -83
  227. package/docs/workers-config.md +446 -0
  228. package/package.json +4 -2
  229. package/scripts/build-hooks.mjs +56 -3
  230. package/src/hooks/pre-compact.sh +5 -2
  231. package/src/hooks/session-stop.sh +29 -4
  232. package/src/hooks/ts/capture-all-events.ts +3 -3
  233. package/src/hooks/ts/lib/advisor-budget.test.ts +98 -0
  234. package/src/hooks/ts/lib/advisor-budget.ts +90 -0
  235. package/src/hooks/ts/lib/agent-gate.test.ts +101 -0
  236. package/src/hooks/ts/lib/agent-gate.ts +112 -0
  237. package/src/hooks/ts/lib/context-fill.ts +2 -2
  238. package/src/hooks/ts/lib/edit-gate.test.ts +52 -0
  239. package/src/hooks/ts/lib/edit-gate.ts +51 -0
  240. package/src/hooks/ts/lib/mcp-deferred-reminder.test.ts +8 -0
  241. package/src/hooks/ts/lib/pai-paths.test.ts +93 -0
  242. package/src/hooks/ts/lib/pai-paths.ts +168 -24
  243. package/src/hooks/ts/lib/project-utils/index.ts +1 -0
  244. package/src/hooks/ts/lib/project-utils/paths.ts +5 -4
  245. package/src/hooks/ts/lib/project-utils.ts +1 -0
  246. package/src/hooks/ts/post-tool-use/capture-tool-output.ts +2 -2
  247. package/src/hooks/ts/pre-compact/context-compression-hook.ts +1 -1
  248. package/src/hooks/ts/pre-tool-use/route-agents-to-worker.ts +46 -99
  249. package/src/hooks/ts/pre-tool-use/route-edits-to-worker.test.ts +47 -0
  250. package/src/hooks/ts/pre-tool-use/route-edits-to-worker.ts +96 -0
  251. package/src/hooks/ts/pre-tool-use/security-validator.ts +2 -1
  252. package/src/hooks/ts/session-end/capture-session-summary.ts +4 -4
  253. package/src/hooks/ts/session-start/initialize-session.ts +3 -3
  254. package/src/hooks/ts/session-start/inject-observations.test.ts +56 -0
  255. package/src/hooks/ts/session-start/inject-observations.ts +28 -8
  256. package/src/hooks/ts/session-start/load-core-context.ts +4 -4
  257. package/src/hooks/ts/session-start/load-project-context.ts +2 -2
  258. package/src/hooks/ts/session-start/mcp-deferred-reminder.ts +2 -0
  259. package/src/hooks/ts/session-start/session-commands.ts +4 -0
  260. package/src/hooks/ts/session-start/session-start-worker-guard.test.ts +36 -0
  261. package/src/hooks/ts/stop/stop-hook.ts +6 -11
  262. package/src/hooks/ts/user-prompt/whisper-rules.test.ts +49 -0
  263. package/src/hooks/ts/user-prompt/whisper-rules.ts +88 -47
  264. package/statusline-command.sh +277 -116
  265. package/templates/agent-prefs.example.md +8 -8
  266. package/templates/claude-md.template.md +1 -1
  267. package/templates/voices.example.json +3 -3
  268. package/dist/config-C_ErGddD.mjs +0 -3
  269. package/dist/config-_lQI_W08.mjs +0 -640
  270. package/dist/config-_lQI_W08.mjs.map +0 -1
  271. package/dist/context-handover-cache-pNFdBNrU.mjs +0 -1548
  272. package/dist/context-handover-cache-pNFdBNrU.mjs.map +0 -1
  273. package/dist/daemon-B8N1egl0.mjs.map +0 -1
  274. package/dist/daemon-DHfyoTlk.mjs +0 -23
  275. package/dist/db-O-cyAPfS.mjs +0 -3
  276. package/dist/db-XEwJbuGO.mjs +0 -3
  277. package/dist/detector-C-7KRi42.mjs +0 -5
  278. package/dist/factory-Dbo8yNPi.mjs +0 -3
  279. package/dist/fallback-oJl3BaIN.mjs.map +0 -1
  280. package/dist/main-resolver-BAfOMppW.mjs +0 -7
  281. package/dist/main-resolver-DnkxPYkr.mjs.map +0 -1
  282. package/dist/program-zpoYnJGz.mjs.map +0 -1
  283. package/dist/query-feedback-DGoVRaWD.mjs +0 -3
  284. package/dist/query-feedback-Dqz-HC__.mjs.map +0 -1
  285. package/dist/router-BTIGZR2_.mjs +0 -3
  286. package/dist/run-D7K5UALn.mjs.map +0 -1
  287. package/dist/server-D4vAieF4.mjs.map +0 -1
  288. package/dist/tools-LlzcV_eK.mjs.map +0 -1
  289. package/dist/work-queue-worker-AEmfVE0F.mjs +0 -14
  290. package/dist/work-queue-worker-DIT-VLSh.mjs +0 -2136
  291. package/dist/work-queue-worker-DIT-VLSh.mjs.map +0 -1
  292. /package/dist/{indexer-D7MvSQPY.mjs → indexer-C5Le7XE7.mjs} +0 -0
@@ -1,640 +0,0 @@
1
- import { n as CONFIG_FILE } from "./config-B64vFg14.mjs";
2
- import { copyFileSync, existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
3
- import { homedir } from "node:os";
4
- import { dirname, join } from "node:path";
5
-
6
- //#region src/config/json-store.ts
7
- /**
8
- * json-store.ts — read/write JSON config files without destroying them
9
- *
10
- * The failure this exists to prevent:
11
- *
12
- * try { return JSON.parse(read(path)); } catch { return {}; }
13
- * ... later ...
14
- * write(path, JSON.stringify(ourData));
15
- *
16
- * An unreadable file becomes an empty object, and the next write makes that
17
- * permanent. Silently, exit code 0. This shape appeared three times in this
18
- * repo against three different files, and twice in AIBroker.
19
- *
20
- * The distinction that matters is between *missing* and *unreadable*:
21
- *
22
- * missing — legitimate first run. Start fresh; writing is safe.
23
- * unreadable — the file exists and we could not parse it. Those bytes are
24
- * the only copy of something. Never overwrite them.
25
- *
26
- * Collapsing the second into the first is the bug.
27
- *
28
- * NOT everything deserves this guard. For a transient buffer — an undelivered
29
- * message queue, a cache — starting fresh IS the correct recovery, and
30
- * refusing to write would disable the feature permanently. Use `writeJsonAtomic`
31
- * alone there: it still prevents a crash from truncating a good file, without
32
- * blocking recovery. Reserve `readJsonStrict` for data a user cannot rebuild.
33
- */
34
- /**
35
- * Read a JSON file, distinguishing "absent" from "damaged".
36
- *
37
- * @param path file to read
38
- * @param label how to name it to the user, e.g. "~/.claude.json"
39
- * @throws if the file exists but cannot be read or parsed
40
- */
41
- function readJsonStrict(path, label = path) {
42
- if (!existsSync(path)) return {};
43
- let raw;
44
- try {
45
- raw = readFileSync(path, "utf8");
46
- } catch (e) {
47
- throw new Error(`Could not read ${label}: ${e instanceof Error ? e.message : String(e)}\nRefusing to continue — writing now would replace its contents with ours alone.`);
48
- }
49
- try {
50
- return JSON.parse(raw);
51
- } catch (e) {
52
- throw new Error(`${label} exists but is not valid JSON: ${e instanceof Error ? e.message : String(e)}\nRefusing to continue — overwriting it would destroy whatever it holds.\nRepair the file, or move it aside and re-run this command.`);
53
- }
54
- }
55
- /**
56
- * Leaf values that mean "type word", not data.
57
- *
58
- * A config whose top-level keys map to bare type words is a serialized schema,
59
- * not a configuration — the exact shape found over the live config on
60
- * 2026-09-18 (399 bytes: `socketPath: string`, `indexIntervalSecs: int`, …).
61
- * No real config carries three of these at its top level; a dump carries
62
- * nothing else.
63
- */
64
- const SCHEMA_TYPE_WORDS = new Set([
65
- "string",
66
- "int",
67
- "integer",
68
- "number",
69
- "bool",
70
- "boolean",
71
- "float",
72
- "double",
73
- "object",
74
- "array",
75
- "any",
76
- "unknown"
77
- ]);
78
- function schemaDumpHits(data) {
79
- let hits = 0;
80
- for (const v of Object.values(data)) if (typeof v === "string" && SCHEMA_TYPE_WORDS.has(v.trim())) hits += 1;
81
- return hits;
82
- }
83
- /**
84
- * Write JSON without risking the existing file.
85
- *
86
- * Keeps a `.bak-pai` copy of the previous contents, then writes to a temp file
87
- * and renames. Rename is atomic within a filesystem, so a crash mid-write
88
- * leaves the original intact rather than truncated — which is how these files
89
- * become corrupt in the first place.
90
- */
91
- function writeJsonAtomic(path, data, opts = {}) {
92
- const { backup = true, label = path } = opts;
93
- if (schemaDumpHits(data) >= 3) throw new Error(`${label}: refusing to write — the object looks like a type schema, not values (several top-level keys map to bare type words). That is the corruption signature of 2026-09-18: the caller serialized the schema instead of the config. Nothing was written.`);
94
- const serialized = JSON.stringify(data, null, 2) + "\n";
95
- const dir = dirname(path);
96
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
97
- if (backup && existsSync(path)) try {
98
- copyFileSync(path, `${path}.bak-pai`);
99
- } catch (e) {
100
- throw new Error(`Could not back up ${label}: ${e instanceof Error ? e.message : String(e)}\nRefusing to write without a backup.`);
101
- }
102
- const tmp = `${path}.tmp-pai-${process.pid}`;
103
- try {
104
- writeFileSync(tmp, serialized, "utf8");
105
- renameSync(tmp, path);
106
- } catch (e) {
107
- try {
108
- if (existsSync(tmp)) unlinkSync(tmp);
109
- } catch {}
110
- throw new Error(`Failed to write ${label}: ${e instanceof Error ? e.message : String(e)}\nThe original is unchanged.`);
111
- }
112
- }
113
-
114
- //#endregion
115
- //#region src/utils/model-window.ts
116
- /**
117
- * model-window.ts — facts derivable from a bare model id.
118
- *
119
- * Shared by the worker stack (provider registry) and the session hooks
120
- * (context-fill). Zero imports on purpose: this leaf is bundled into hooks
121
- * (scripts/build-hooks.mjs) and must never drag config or path machinery
122
- * into a hook process.
123
- */
124
- /** Last-resort window when nothing on hand reports one and the model id
125
- * carries no window information. */
126
- const DEFAULT_CONTEXT_WINDOW = 2e5;
127
- /** Strip a bracketed variant suffix: "glm-5.3[1m]" → "glm-5.3". The suffix
128
- * selects a variant of the same base model (a context-window tier, a
129
- * quantization), so the prefix is the id's family. */
130
- function stripModelVariant(model) {
131
- return model.replace(/\[[^\]]*\]\s*$/, "").trim() || model;
132
- }
133
- /**
134
- * The context window a model id itself declares, or null when the id carries
135
- * no window information. Only the bracketed variant suffix is read
136
- * ("[1m]" → 1,000,000); a bare id says nothing and stays null so callers can
137
- * fall back to whatever they measured themselves.
138
- */
139
- function contextWindowFromModelId(model) {
140
- if (typeof model !== "string" || model === "") return null;
141
- const m = /\[(\d+)m\]$/i.exec(model.trim());
142
- if (!m) return null;
143
- const millions = Number(m[1]);
144
- if (!Number.isFinite(millions) || millions < 1) return null;
145
- return millions * 1e6;
146
- }
147
-
148
- //#endregion
149
- //#region src/workers/config.ts
150
- /**
151
- * config.ts — the `workers` section of ~/.config/pai/config.json
152
- *
153
- * Everything that knows about worker providers reads this module: the CLI
154
- * (`pai worker …`), the MCP tools (worker_*), and the Agent-routing hook.
155
- * Keep it free of commander/MCP imports so all three layers stay thin over it.
156
- *
157
- * Keys are never stored here — only paths to 0600 files. A provider without a
158
- * keyFile is a local server and gets the placeholder token "local".
159
- *
160
- * `protocol: "openai"` providers run through the PAI proxy (src/workers/proxy):
161
- * `upstreamUrl` is their Chat Completions base, and `run` points
162
- * ANTHROPIC_BASE_URL at the local proxy with the provider name in the path.
163
- * `engine: "codex"` providers run through the Codex CLI instead of Claude
164
- * Code.
165
- */
166
- /**
167
- * Reserved provider name for plain Anthropic: Claude Code's own OAuth/Max-plan
168
- * login, no base URL override and no API key. It never needs (or accepts) a
169
- * `providers.anthropic` config entry — resolveTarget/mustExist synthesize it
170
- * on demand via `nativeAnthropicProvider()`.
171
- */
172
- const ANTHROPIC_NATIVE = "anthropic";
173
- /**
174
- * The synthetic provider object for ANTHROPIC_NATIVE. `baseUrl` is empty and
175
- * `models.default` is "" (unresolved) so buildRunEnv/run.ts skip passing
176
- * --model and env overrides entirely, leaving Claude Code to use whatever it
177
- * would use when run bare.
178
- */
179
- function nativeAnthropicProvider() {
180
- return {
181
- enabled: true,
182
- protocol: "anthropic",
183
- baseUrl: "",
184
- keyFile: null,
185
- models: { default: "" },
186
- env: {},
187
- native: true
188
- };
189
- }
190
- /** Provider by name, synthesizing ANTHROPIC_NATIVE when it is asked for. */
191
- function getProviderOrNative(config, name) {
192
- if (name === ANTHROPIC_NATIVE) return nativeAnthropicProvider();
193
- return config.providers[name];
194
- }
195
- const MODEL_TIERS = [
196
- "haiku",
197
- "sonnet",
198
- "opus"
199
- ];
200
- const DEFAULT_COST_TIER = 3;
201
- /** Tags a provider may carry; classes filter auto-routing on them. */
202
- const PROVIDER_TAGS = [
203
- "code",
204
- "vision",
205
- "image-gen",
206
- "long-context",
207
- "fast",
208
- "reasoning"
209
- ];
210
- /** The standard task classes; `workers.classes` maps each to a target. */
211
- const WORKER_CLASSES = [
212
- "draft",
213
- "plan",
214
- "implement",
215
- "review",
216
- "research",
217
- "spotcheck",
218
- "simple",
219
- "complex",
220
- "image"
221
- ];
222
- /**
223
- * The named model capabilities a provider may carry a preference for, set
224
- * per provider under `workers.providers.<name>.models`. "default" is the
225
- * required catch-all; the others name what a model is *for* — "fast" the
226
- * cheap tier (spotcheck, haiku-tier spawns), "image" the image class.
227
- * Everything resolves through resolveModelCapability, falling back to default.
228
- */
229
- const MODEL_CAPABILITIES = [
230
- "default",
231
- "fast",
232
- "image"
233
- ];
234
- /** Is this string the name of a known model capability? */
235
- function isModelCapability(v) {
236
- return MODEL_CAPABILITIES.includes(v);
237
- }
238
- /**
239
- * Which model capability a class runs on when its target names no alias: the
240
- * image class uses the image model; every other class the provider default.
241
- */
242
- const CLASS_MODEL_CAPABILITY = {
243
- draft: "default",
244
- plan: "default",
245
- implement: "default",
246
- review: "default",
247
- research: "default",
248
- spotcheck: "default",
249
- simple: "default",
250
- complex: "default",
251
- image: "image"
252
- };
253
- /** Capability for a run's class (default when unset or not a standard class). */
254
- function classModelCapability(className) {
255
- return className && CLASS_MODEL_CAPABILITY[className] || "default";
256
- }
257
- const DEFAULT_LOG_DIR = "~/.claude/logs/workers";
258
- const DEFAULT_PANE = {
259
- enabled: true,
260
- fontSize: 13,
261
- autoExitSecs: 60
262
- };
263
- const DEFAULT_ROUTING = {
264
- order: [],
265
- cooldownMinutes: 30,
266
- retryOnQuota: true
267
- };
268
- const DEFAULT_TREE = {
269
- maxDepth: 2,
270
- maxChildren: 4
271
- };
272
- /**
273
- * Cache-keepalive cadence when the config names none. Measured 2026-09-18
274
- * (pair probes through the real worker spawn path, numbers in
275
- * docs/cache-keepalive.md): the implicit provider cache only serves a fresh
276
- * worker warm within roughly the first minute (positive back-to-back, gone
277
- * at 2 min), and it covers only ~2.6k of the ~18k-token prefix. Holding it
278
- * needs a beat every <2 min — a continuous bill for a small saving — so the
279
- * default is OFF and arming it is the operator's explicit call (set e.g.
280
- * "cacheKeepaliveSecs": 60).
281
- */
282
- const DEFAULT_CACHE_KEEPALIVE_SECS = 0;
283
- /**
284
- * The default MCP sets every config starts from. `desktop` names the clickr
285
- * server so `--mcp desktop` hands a worker the machine controls (read-only
286
- * tools always; actuating ones after the operator hands the controls over,
287
- * see `pai worker controls`). A user's mcpSets section is merged over this,
288
- * so `desktop: []` removes the set deliberately.
289
- */
290
- const DEFAULT_MCP_SETS = { desktop: ["clickr"] };
291
- function defaultWorkersConfig() {
292
- return {
293
- enabled: false,
294
- active: null,
295
- providers: {},
296
- classes: {},
297
- mcpSets: { ...DEFAULT_MCP_SETS },
298
- pane: { ...DEFAULT_PANE },
299
- logDir: DEFAULT_LOG_DIR,
300
- routing: {
301
- ...DEFAULT_ROUTING,
302
- order: []
303
- },
304
- tree: { ...DEFAULT_TREE },
305
- cacheKeepaliveSecs: DEFAULT_CACHE_KEEPALIVE_SECS,
306
- fallback: null
307
- };
308
- }
309
- var WorkersConfigError = class extends Error {};
310
- function bad(path, why) {
311
- throw new WorkersConfigError(`workers${path}: ${why}`);
312
- }
313
- function str(v) {
314
- return typeof v === "string" ? v : "";
315
- }
316
- function parseProvider(name, raw) {
317
- if (name === ANTHROPIC_NATIVE) bad(`.providers.${name}`, `"${ANTHROPIC_NATIVE}" is reserved for plain Anthropic (Claude Code's own OAuth/Max-plan login) and cannot be configured here — remove this entry; use --provider ${ANTHROPIC_NATIVE} or "pai worker providers use ${ANTHROPIC_NATIVE}" instead`);
318
- if (typeof raw !== "object" || raw === null) bad(`.providers.${name}`, "must be an object");
319
- const p = raw;
320
- const protocol = p.protocol === void 0 ? "anthropic" : str(p.protocol);
321
- if (protocol !== "anthropic" && protocol !== "openai") bad(`.providers.${name}.protocol`, `"${str(p.protocol)}" is neither "anthropic" nor "openai"`);
322
- const engine = p.engine === void 0 ? "claude" : str(p.engine);
323
- if (engine !== "claude" && engine !== "codex") bad(`.providers.${name}.engine`, `"${str(p.engine)}" is neither "claude" nor "codex"`);
324
- const baseUrl = str(p.baseUrl);
325
- if (!baseUrl && protocol !== "openai") bad(`.providers.${name}.baseUrl`, "is required");
326
- const keyFile = p.keyFile === void 0 || p.keyFile === null || str(p.keyFile) === "" ? null : str(p.keyFile);
327
- const modelsRaw = p.models === void 0 ? {} : p.models;
328
- if (typeof modelsRaw !== "object" || modelsRaw === null) bad(`.providers.${name}.models`, "must be an object");
329
- const m = modelsRaw;
330
- const defaultModel = str(m.default);
331
- if (!defaultModel) bad(`.providers.${name}.models.default`, "is required");
332
- const models = { default: defaultModel };
333
- for (const key of Object.keys(m)) {
334
- if (key === "default") continue;
335
- if (!isModelCapability(key)) bad(`.providers.${name}.models.${key}`, `"${key}" is not a model capability (from: ${MODEL_CAPABILITIES.join(", ")})`);
336
- const id = str(m[key]);
337
- if (!id) bad(`.providers.${name}.models.${key}`, "must be a non-empty model id");
338
- models[key] = id;
339
- }
340
- let modelTiers;
341
- if (p.modelTiers !== void 0) {
342
- if (typeof p.modelTiers !== "object" || p.modelTiers === null || Array.isArray(p.modelTiers)) bad(`.providers.${name}.modelTiers`, "must be an object of model id → haiku | sonnet | opus");
343
- modelTiers = {};
344
- for (const [id, tier] of Object.entries(p.modelTiers)) {
345
- if (typeof tier !== "string" || !MODEL_TIERS.includes(tier)) bad(`.providers.${name}.modelTiers.${id}`, `must be "haiku", "sonnet" or "opus" (got ${JSON.stringify(tier)})`);
346
- modelTiers[id] = tier;
347
- }
348
- }
349
- const env = {};
350
- if (p.env !== void 0) {
351
- if (typeof p.env !== "object" || p.env === null || Array.isArray(p.env)) bad(`.providers.${name}.env`, "must be an object of string values");
352
- for (const [k, v] of Object.entries(p.env)) {
353
- if (typeof v !== "string") bad(`.providers.${name}.env.${k}`, "must be a string");
354
- env[k] = v;
355
- }
356
- }
357
- const quotaSkipAt = p.quotaSkipAt === void 0 ? void 0 : p.quotaSkipAt;
358
- if (quotaSkipAt !== void 0) {
359
- if (typeof quotaSkipAt !== "number" || quotaSkipAt < 0 || quotaSkipAt > 100) bad(`.providers.${name}.quotaSkipAt`, "must be a number between 0 and 100");
360
- }
361
- const contextWindow = p.contextWindow === void 0 ? void 0 : p.contextWindow;
362
- if (contextWindow !== void 0) {
363
- if (typeof contextWindow !== "number" || contextWindow <= 0) bad(`.providers.${name}.contextWindow`, "must be a positive number of tokens");
364
- }
365
- const upstreamUrl = str(p.upstreamUrl);
366
- if (protocol === "openai" && !upstreamUrl) bad(`.providers.${name}.upstreamUrl`, `is required for protocol "openai" (the Chat Completions base, e.g. "https://api.openai.com/v1")`);
367
- const costTier = p.costTier === void 0 ? void 0 : p.costTier;
368
- if (costTier !== void 0) {
369
- if (typeof costTier !== "number" || !Number.isInteger(costTier) || costTier < 1 || costTier > 5) bad(`.providers.${name}.costTier`, "must be an integer 1 (cheapest) … 5 (most expensive)");
370
- }
371
- let tags;
372
- if (p.tags !== void 0) {
373
- if (!Array.isArray(p.tags) || p.tags.some((x) => typeof x !== "string")) bad(`.providers.${name}.tags`, `must be an array of tags from: ${PROVIDER_TAGS.join(", ")}`);
374
- for (const t of p.tags) if (!PROVIDER_TAGS.includes(t)) bad(`.providers.${name}.tags`, `"${t}" is not a tag (from: ${PROVIDER_TAGS.join(", ")})`);
375
- tags = p.tags;
376
- }
377
- let usage;
378
- if (p.usage !== void 0) {
379
- if (typeof p.usage !== "object" || p.usage === null || Array.isArray(p.usage)) bad(`.providers.${name}.usage`, "must be an object");
380
- const u = p.usage;
381
- const usageUrl = str(u.url);
382
- if (!usageUrl) bad(`.providers.${name}.usage.url`, "is required");
383
- if (!Array.isArray(u.windows) || u.windows.length === 0) bad(`.providers.${name}.usage.windows`, "must be a non-empty array");
384
- const windows = [];
385
- for (const [i, wRaw] of u.windows.entries()) {
386
- const wpath = `.providers.${name}.usage.windows[${i}]`;
387
- if (typeof wRaw !== "object" || wRaw === null || Array.isArray(wRaw)) bad(wpath, "must be an object");
388
- const w = wRaw;
389
- const wname = str(w.name);
390
- if (!wname) bad(`${wpath}.name`, "is required");
391
- const percent = str(w.percent);
392
- if (!percent) bad(`${wpath}.percent`, "is required (a jq expression yielding 0–100)");
393
- const resetUnit = w.resetUnit === void 0 ? void 0 : str(w.resetUnit);
394
- if (resetUnit !== void 0 && resetUnit !== "ms" && resetUnit !== "s" && resetUnit !== "iso") bad(`${wpath}.resetUnit`, `must be "ms", "s" or "iso"`);
395
- windows.push({
396
- name: wname,
397
- percent,
398
- ...str(w.resetAt) ? { resetAt: str(w.resetAt) } : {},
399
- ...resetUnit ? { resetUnit } : {}
400
- });
401
- }
402
- const ttlSeconds = u.ttlSeconds === void 0 ? void 0 : u.ttlSeconds;
403
- if (ttlSeconds !== void 0 && (typeof ttlSeconds !== "number" || ttlSeconds <= 0)) bad(`.providers.${name}.usage.ttlSeconds`, "must be a positive number of seconds");
404
- usage = {
405
- url: usageUrl,
406
- ...str(u.authHeader) ? { authHeader: str(u.authHeader) } : {},
407
- ...str(u.label) ? { label: str(u.label) } : {},
408
- windows,
409
- ...ttlSeconds !== void 0 ? { ttlSeconds } : {}
410
- };
411
- }
412
- return {
413
- enabled: p.enabled === void 0 ? true : p.enabled === true,
414
- protocol,
415
- baseUrl,
416
- keyFile,
417
- models,
418
- ...modelTiers ? { modelTiers } : {},
419
- env,
420
- ...str(p.note) ? { note: str(p.note) } : {},
421
- ...upstreamUrl ? { upstreamUrl } : {},
422
- ...engine !== "claude" ? { engine } : {},
423
- ...str(p.quotaProbe) ? { quotaProbe: str(p.quotaProbe) } : {},
424
- ...quotaSkipAt !== void 0 ? { quotaSkipAt } : {},
425
- ...contextWindow !== void 0 ? { contextWindow } : {},
426
- ...costTier !== void 0 ? { costTier } : {},
427
- ...tags ? { tags } : {},
428
- ...usage ? { usage } : {}
429
- };
430
- }
431
- /**
432
- * Parse and validate a raw `workers` value. Missing section → defaults.
433
- * Unknown-but-typed garbage → WorkersConfigError naming the offending field.
434
- */
435
- function parseWorkersConfig(raw) {
436
- const d = defaultWorkersConfig();
437
- if (raw === void 0 || raw === null) return d;
438
- if (typeof raw !== "object" || Array.isArray(raw)) bad("", "section must be an object");
439
- const w = raw;
440
- const providers = {};
441
- if (w.providers !== void 0) {
442
- if (typeof w.providers !== "object" || w.providers === null || Array.isArray(w.providers)) bad(".providers", "must be an object keyed by provider name");
443
- for (const [name, p] of Object.entries(w.providers)) providers[name] = parseProvider(name, p);
444
- }
445
- const classes = {};
446
- const classesRaw = w.classes !== void 0 ? w.classes : w.roles;
447
- if (classesRaw !== void 0) {
448
- if (typeof classesRaw !== "object" || classesRaw === null || Array.isArray(classesRaw)) bad(w.classes !== void 0 ? ".classes" : ".roles", "must be an object of class → provider[/alias] or {provider, mcp, maxCostTier, requireTags, order}");
449
- for (const [cls, target] of Object.entries(classesRaw)) if (typeof target === "object" && target !== null && !Array.isArray(target)) {
450
- const o = target;
451
- const provider = str(o.provider);
452
- if (o.provider !== void 0 && (!provider || provider.includes(" "))) bad(`.classes.${cls}.provider`, `invalid provider "${provider}"`);
453
- let mcp;
454
- if (o.mcp !== void 0) {
455
- if (!Array.isArray(o.mcp) || o.mcp.some((x) => typeof x !== "string")) bad(`.classes.${cls}.mcp`, "must be an array of MCP server or set names");
456
- mcp = o.mcp;
457
- }
458
- let maxCostTier;
459
- if (o.maxCostTier !== void 0) {
460
- if (typeof o.maxCostTier !== "number" || !Number.isInteger(o.maxCostTier) || o.maxCostTier < 1 || o.maxCostTier > 5) bad(`.classes.${cls}.maxCostTier`, "must be an integer 1 … 5");
461
- maxCostTier = o.maxCostTier;
462
- }
463
- let requireTags;
464
- if (o.requireTags !== void 0) {
465
- if (!Array.isArray(o.requireTags) || o.requireTags.some((x) => typeof x !== "string")) bad(`.classes.${cls}.requireTags`, `must be an array of tags from: ${PROVIDER_TAGS.join(", ")}`);
466
- for (const t of o.requireTags) if (!PROVIDER_TAGS.includes(t)) bad(`.classes.${cls}.requireTags`, `"${t}" is not a tag (from: ${PROVIDER_TAGS.join(", ")})`);
467
- requireTags = o.requireTags;
468
- }
469
- let order;
470
- if (o.order !== void 0) {
471
- if (!Array.isArray(o.order) || o.order.some((x) => typeof x !== "string")) bad(`.classes.${cls}.order`, "must be an array of provider names");
472
- order = o.order;
473
- }
474
- const obj = {
475
- ...provider ? { provider } : {},
476
- ...mcp ? { mcp } : {},
477
- ...maxCostTier !== void 0 ? { maxCostTier } : {},
478
- ...requireTags ? { requireTags } : {},
479
- ...order ? { order } : {}
480
- };
481
- classes[cls] = Object.keys(obj).length ? obj : {};
482
- } else {
483
- const t = str(target);
484
- if (!t || t.includes(" ")) bad(`.classes.${cls}`, `invalid target "${t}"`);
485
- classes[cls] = t;
486
- }
487
- }
488
- const mcpSets = { ...DEFAULT_MCP_SETS };
489
- if (w.mcpSets !== void 0) {
490
- if (typeof w.mcpSets !== "object" || w.mcpSets === null || Array.isArray(w.mcpSets)) bad(".mcpSets", "must be an object of set name → [server names]");
491
- for (const [setName, servers] of Object.entries(w.mcpSets)) {
492
- if (!Array.isArray(servers) || servers.some((x) => typeof x !== "string")) bad(`.mcpSets.${setName}`, "must be an array of MCP server names");
493
- mcpSets[setName] = servers;
494
- }
495
- }
496
- let pane = { ...DEFAULT_PANE };
497
- if (w.pane !== void 0) {
498
- if (typeof w.pane !== "object" || w.pane === null) bad(".pane", "must be an object");
499
- const pc = w.pane;
500
- if (pc.enabled !== void 0 && typeof pc.enabled !== "boolean") bad(".pane.enabled", "must be boolean");
501
- if (pc.fontSize !== void 0 && (typeof pc.fontSize !== "number" || pc.fontSize <= 0)) bad(".pane.fontSize", "must be a positive number of points");
502
- if (pc.autoExitSecs !== void 0 && typeof pc.autoExitSecs !== "number") bad(".pane.autoExitSecs", "must be a number");
503
- pane = {
504
- enabled: pc.enabled === void 0 ? DEFAULT_PANE.enabled : pc.enabled === true,
505
- fontSize: pc.fontSize === void 0 ? DEFAULT_PANE.fontSize : pc.fontSize,
506
- autoExitSecs: pc.autoExitSecs === void 0 ? DEFAULT_PANE.autoExitSecs : pc.autoExitSecs
507
- };
508
- }
509
- let routing = {
510
- ...DEFAULT_ROUTING,
511
- order: []
512
- };
513
- if (w.routing !== void 0) {
514
- if (typeof w.routing !== "object" || w.routing === null) bad(".routing", "must be an object");
515
- const r = w.routing;
516
- if (r.order !== void 0) {
517
- if (!Array.isArray(r.order) || r.order.some((x) => typeof x !== "string")) bad(".routing.order", "must be an array of provider names");
518
- routing.order = r.order;
519
- }
520
- if (r.cooldownMinutes !== void 0 && typeof r.cooldownMinutes !== "number") bad(".routing.cooldownMinutes", "must be a number");
521
- if (r.retryOnQuota !== void 0 && typeof r.retryOnQuota !== "boolean") bad(".routing.retryOnQuota", "must be boolean");
522
- routing = {
523
- order: routing.order,
524
- cooldownMinutes: r.cooldownMinutes === void 0 ? DEFAULT_ROUTING.cooldownMinutes : r.cooldownMinutes,
525
- retryOnQuota: r.retryOnQuota === void 0 ? DEFAULT_ROUTING.retryOnQuota : r.retryOnQuota === true
526
- };
527
- }
528
- let tree = { ...DEFAULT_TREE };
529
- if (w.tree !== void 0) {
530
- if (typeof w.tree !== "object" || w.tree === null || Array.isArray(w.tree)) bad(".tree", "must be an object");
531
- const t = w.tree;
532
- if (t.maxDepth !== void 0) {
533
- if (typeof t.maxDepth !== "number" || !Number.isInteger(t.maxDepth) || t.maxDepth < 0) bad(".tree.maxDepth", "must be a non-negative integer");
534
- }
535
- if (t.maxChildren !== void 0) {
536
- if (typeof t.maxChildren !== "number" || !Number.isInteger(t.maxChildren) || t.maxChildren < 1) bad(".tree.maxChildren", "must be a positive integer");
537
- }
538
- tree = {
539
- maxDepth: t.maxDepth === void 0 ? DEFAULT_TREE.maxDepth : t.maxDepth,
540
- maxChildren: t.maxChildren === void 0 ? DEFAULT_TREE.maxChildren : t.maxChildren
541
- };
542
- }
543
- let cacheKeepaliveSecs = DEFAULT_CACHE_KEEPALIVE_SECS;
544
- if (w.cacheKeepaliveSecs !== void 0) {
545
- if (typeof w.cacheKeepaliveSecs !== "number" || !Number.isInteger(w.cacheKeepaliveSecs) || w.cacheKeepaliveSecs < 0) bad(".cacheKeepaliveSecs", "must be a non-negative integer (seconds, 0 = off)");
546
- cacheKeepaliveSecs = w.cacheKeepaliveSecs;
547
- }
548
- const active = w.active === void 0 || w.active === null ? null : str(w.active);
549
- if (active !== null && active !== "auto" && !(active in providers)) {}
550
- let fallback = null;
551
- if (w.fallback !== void 0 && w.fallback !== null) {
552
- if (typeof w.fallback !== "object" || Array.isArray(w.fallback)) bad(".fallback", "must be an object (written by `pai worker fallback on`)");
553
- const f = w.fallback;
554
- const provider = str(f.provider);
555
- if (!provider) bad(".fallback.provider", "is required");
556
- const savedRaw = f.saved;
557
- if (typeof savedRaw !== "object" || savedRaw === null || Array.isArray(savedRaw)) bad(".fallback.saved", "must be an object");
558
- const s = savedRaw;
559
- if (typeof s.env !== "object" || s.env === null || Array.isArray(s.env)) bad(".fallback.saved.env", "must be an object of env key → previous value or null");
560
- const env = {};
561
- for (const [k, v] of Object.entries(s.env)) env[k] = v === null || typeof v === "string" ? v : null;
562
- if (s.model !== null && s.model !== void 0 && typeof s.model !== "string") bad(".fallback.saved.model", "must be a string or null");
563
- fallback = {
564
- provider,
565
- saved: {
566
- env,
567
- model: typeof s.model === "string" ? s.model : null,
568
- envExisted: s.envExisted === true
569
- },
570
- on: str(f.on) || (/* @__PURE__ */ new Date(0)).toISOString()
571
- };
572
- }
573
- return {
574
- enabled: w.enabled === void 0 ? d.enabled : w.enabled === true,
575
- active,
576
- providers,
577
- classes,
578
- mcpSets,
579
- pane,
580
- logDir: str(w.logDir) || d.logDir,
581
- routing,
582
- tree,
583
- cacheKeepaliveSecs,
584
- fallback
585
- };
586
- }
587
- /**
588
- * Read the whole config file and return (raw, workers) — the raw record so
589
- * callers can rewrite it preserving every other section, the parsed+validated
590
- * workers section. Unreadable config throws (readJsonStrict), missing is fine.
591
- * `path` overrides the config location (tests, CLAUDE_SETTINGS_PATH-style
592
- * dry runs); default ~/.config/pai/config.json.
593
- */
594
- function readWorkersSection(path = CONFIG_FILE) {
595
- const raw = readJsonStrict(path, "~/.config/pai/config.json");
596
- return {
597
- raw,
598
- workers: parseWorkersConfig(raw.workers)
599
- };
600
- }
601
- /** Write the workers section back into the config file, atomically. */
602
- function writeWorkersSection(raw, workers, path = CONFIG_FILE) {
603
- raw.workers = workers.fallback ? workers : {
604
- ...workers,
605
- fallback: void 0
606
- };
607
- writeJsonAtomic(path, raw, { label: "~/.config/pai/config.json" });
608
- }
609
- /** Expand a leading ~ (config values are written with `~` to stay portable). */
610
- function expandHome(p) {
611
- if (p === "~" || p.startsWith("~/")) return join(homedir(), p.slice(1));
612
- return p;
613
- }
614
- function assertProviderRunnable(name, p) {
615
- if (p.protocol === "openai" && !p.upstreamUrl) throw new WorkersConfigError(`provider "${name}" uses protocol "openai" but has no upstreamUrl — set its Chat Completions base (e.g. "https://api.openai.com/v1") so the PAI proxy knows where to translate to.`);
616
- }
617
- /** Where a provider's key file lives, or null. Shared by run + test + add. */
618
- function providerKeyPath(p) {
619
- return p.keyFile ? expandHome(p.keyFile) : null;
620
- }
621
- /** Cost tier of a provider for class filtering (unset = 3, the middle). */
622
- function providerCostTier(p) {
623
- return p.costTier ?? DEFAULT_COST_TIER;
624
- }
625
- /**
626
- * The model id for a capability: the provider's preference for it, else its
627
- * default model — the one resolution rule every consumer (image class, fast
628
- * tier spawns, env pins) goes through.
629
- */
630
- function resolveModelCapability(p, capability) {
631
- return p.models[capability] ?? p.models.default;
632
- }
633
- /** Directory under which inline keys (MCP `key` field) are stored, 0600. */
634
- function keysDir() {
635
- return join(homedir(), ".config", "pai", "keys");
636
- }
637
-
638
- //#endregion
639
- export { readJsonStrict as C, stripModelVariant as S, readWorkersSection as _, WORKER_CLASSES as a, DEFAULT_CONTEXT_WINDOW as b, classModelCapability as c, getProviderOrNative as d, isModelCapability as f, providerKeyPath as g, providerCostTier as h, PROVIDER_TAGS as i, defaultWorkersConfig as l, parseWorkersConfig as m, DEFAULT_LOG_DIR as n, WorkersConfigError as o, keysDir as p, MODEL_CAPABILITIES as r, assertProviderRunnable as s, ANTHROPIC_NATIVE as t, expandHome as u, resolveModelCapability as v, writeJsonAtomic as w, contextWindowFromModelId as x, writeWorkersSection as y };
640
- //# sourceMappingURL=config-_lQI_W08.mjs.map