@north-light/crouter 0.3.349 → 0.3.350

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 (629) hide show
  1. package/bin/crtr-launcher +4 -0
  2. package/bin/runtime-generation-manifest.mjs +12 -2
  3. package/dist/api/client.d.ts +50 -7
  4. package/dist/api/client.js +2 -2
  5. package/dist/api/dto/analytics.d.ts +184 -0
  6. package/dist/api/dto/analytics.js +0 -0
  7. package/dist/api/dto/broker-ops.d.ts +43 -1
  8. package/dist/api/dto/config.d.ts +11 -0
  9. package/dist/api/dto/grants.d.ts +14 -0
  10. package/dist/api/dto/grants.js +0 -0
  11. package/dist/api/dto/human-requests.d.ts +14 -0
  12. package/dist/api/dto/memory.d.ts +6 -0
  13. package/dist/api/dto/modelauth.d.ts +35 -0
  14. package/dist/api/dto/node-records.d.ts +35 -0
  15. package/dist/api/dto/node-records.js +0 -0
  16. package/dist/api/dto/nodes.d.ts +5 -0
  17. package/dist/api/dto/profiles.d.ts +38 -3
  18. package/dist/api/dto/worktree.d.ts +11 -0
  19. package/dist/api/errors.d.ts +23 -1
  20. package/dist/api/errors.js +1 -1
  21. package/dist/api/index.d.ts +2 -0
  22. package/dist/api/index.js +1 -1
  23. package/dist/api/node-transport.js +1 -1
  24. package/dist/api/routes.d.ts +22 -0
  25. package/dist/api/routes.js +1 -1
  26. package/dist/build-root.d.ts +6 -1
  27. package/dist/build-root.js +1 -1
  28. package/dist/builtin-memory/crouter-sdk/client.md +34 -0
  29. package/dist/builtin-memory/crouter-sdk/errors.md +2 -0
  30. package/dist/builtin-memory/crouter-sdk/memory.md +2 -2
  31. package/dist/builtin-memory/crouter-sdk/streaming.md +21 -0
  32. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/claude-plugin-commands.ts +8 -4
  33. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +39 -118
  34. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +6 -1
  35. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +41 -27
  36. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +52 -29
  37. package/dist/cli.js +9 -8
  38. package/dist/clients/attach/chrome/inbox-strip.js +1 -1
  39. package/dist/clients/attach/chrome/roster.js +1 -1
  40. package/dist/clients/attach/config.js +1 -1
  41. package/dist/clients/attach/overlays/auth.js +2 -2
  42. package/dist/clients/attach/overlays/graph.js +1 -1
  43. package/dist/clients/attach/render/tool-calls.js +3 -3
  44. package/dist/clients/attach/session/connection.js +1 -1
  45. package/dist/clients/attach/session/profile-files.js +1 -1
  46. package/dist/clients/attach/viewer.js +1569 -816
  47. package/dist/commands/api-client.js +3 -3
  48. package/dist/commands/broker-permissions.d.ts +2 -0
  49. package/dist/commands/broker-permissions.js +1 -0
  50. package/dist/commands/canvas-analytics/chart.d.ts +52 -0
  51. package/dist/commands/canvas-analytics/chart.js +1 -0
  52. package/dist/commands/canvas-analytics/drilldown.d.ts +34 -0
  53. package/dist/commands/canvas-analytics/drilldown.js +1 -0
  54. package/dist/commands/canvas-analytics/format.d.ts +29 -0
  55. package/dist/commands/canvas-analytics/format.js +1 -0
  56. package/dist/commands/canvas-analytics/graph-detail.d.ts +2 -0
  57. package/dist/commands/canvas-analytics/graph-detail.js +2 -0
  58. package/dist/commands/canvas-analytics/graphs.d.ts +9 -0
  59. package/dist/commands/canvas-analytics/graphs.js +1 -0
  60. package/dist/commands/canvas-analytics/memory.d.ts +2 -0
  61. package/dist/commands/canvas-analytics/memory.js +1 -0
  62. package/dist/commands/canvas-analytics/overview.d.ts +2 -0
  63. package/dist/commands/canvas-analytics/overview.js +1 -0
  64. package/dist/commands/canvas-analytics/shell.d.ts +60 -0
  65. package/dist/commands/canvas-analytics/shell.js +2 -0
  66. package/dist/commands/canvas-analytics/time.d.ts +2 -0
  67. package/dist/commands/canvas-analytics/time.js +1 -0
  68. package/dist/commands/canvas-analytics/usage.d.ts +2 -0
  69. package/dist/commands/canvas-analytics/usage.js +1 -0
  70. package/dist/commands/canvas-analytics/view.d.ts +85 -0
  71. package/dist/commands/canvas-analytics/view.js +1 -0
  72. package/dist/commands/canvas-analytics.d.ts +2 -0
  73. package/dist/commands/canvas-analytics.js +1 -0
  74. package/dist/commands/canvas-prune.js +1 -1
  75. package/dist/commands/canvas.js +1 -1
  76. package/dist/commands/cron.js +5 -5
  77. package/dist/commands/human/components.d.ts +2 -0
  78. package/dist/commands/human/components.js +2 -2
  79. package/dist/commands/human/prompts.js +1 -1
  80. package/dist/commands/human/queue.js +1 -1
  81. package/dist/commands/memory/client.d.ts +11 -0
  82. package/dist/commands/memory/client.js +1 -0
  83. package/dist/commands/memory/delete.js +1 -1
  84. package/dist/commands/memory/edit.js +3 -3
  85. package/dist/commands/memory/find.js +1 -1
  86. package/dist/commands/memory/history.js +4 -4
  87. package/dist/commands/memory/lint.js +1 -1
  88. package/dist/commands/memory/list.d.ts +0 -2
  89. package/dist/commands/memory/list.js +1 -1
  90. package/dist/commands/memory/move.js +1 -1
  91. package/dist/commands/memory/origin.js +1 -1
  92. package/dist/commands/memory/read.d.ts +0 -5
  93. package/dist/commands/memory/read.js +3 -3
  94. package/dist/commands/memory/shared.d.ts +0 -178
  95. package/dist/commands/memory/shared.js +1 -12
  96. package/dist/commands/memory/write.js +5 -5
  97. package/dist/commands/node/bash.js +5 -5
  98. package/dist/commands/node/create.d.ts +0 -17
  99. package/dist/commands/node/create.js +2 -3
  100. package/dist/commands/node/inspect.js +6 -6
  101. package/dist/commands/node/lifecycle.js +2 -2
  102. package/dist/commands/node-context.js +2 -2
  103. package/dist/commands/node-inspect-artifacts.js +6 -6
  104. package/dist/commands/pkg/browse/catalog.js +1 -1
  105. package/dist/commands/pkg/browse/model.d.ts +1 -1
  106. package/dist/commands/pkg/market-manage.js +1 -1
  107. package/dist/commands/pkg/plugin-manage.js +10 -10
  108. package/dist/commands/profile/daemon-profiles.d.ts +13 -0
  109. package/dist/commands/profile/daemon-profiles.js +4 -0
  110. package/dist/commands/profile/delete.js +1 -1
  111. package/dist/commands/profile/env.d.ts +6 -0
  112. package/dist/commands/profile/env.js +2 -2
  113. package/dist/commands/profile/kind.js +1 -2
  114. package/dist/commands/profile/list.js +1 -1
  115. package/dist/commands/profile/meta.js +1 -1
  116. package/dist/commands/profile/new.js +1 -1
  117. package/dist/commands/profile/pause.js +1 -1
  118. package/dist/commands/profile/project.js +1 -1
  119. package/dist/commands/profile/rename.js +1 -1
  120. package/dist/commands/profile/show.js +1 -1
  121. package/dist/commands/profile.js +1 -1
  122. package/dist/commands/push.js +3 -3
  123. package/dist/commands/surface-inspect.js +1 -1
  124. package/dist/commands/sys/branch.js +1 -1
  125. package/dist/commands/sys/config.js +1 -1
  126. package/dist/commands/sys/connect.js +3 -3
  127. package/dist/commands/sys/context/admin/actions.js +1 -1
  128. package/dist/commands/sys/context/admin/model.d.ts +1 -0
  129. package/dist/commands/sys/context/admin/model.js +1 -1
  130. package/dist/commands/sys/context/admin.js +1 -1
  131. package/dist/commands/sys/context/expose.js +2 -1
  132. package/dist/commands/sys/context/prompt-review.js +2 -2
  133. package/dist/commands/sys/context/resolve.js +7 -7
  134. package/dist/commands/sys/context/sysprompt.js +1 -1
  135. package/dist/commands/sys/join.d.ts +1 -0
  136. package/dist/commands/sys/join.js +1 -0
  137. package/dist/commands/sys/migrate.js +1 -1
  138. package/dist/commands/sys/panels/models-panel.js +1 -1
  139. package/dist/commands/sys/panels/profiles-panel.d.ts +0 -1
  140. package/dist/commands/sys/panels/profiles-panel.js +1 -1
  141. package/dist/commands/sys/provider-login.js +6 -6
  142. package/dist/commands/sys/setup-core.d.ts +1 -1
  143. package/dist/commands/sys/setup-core.js +6 -6
  144. package/dist/commands/sys/setup-settings-runner.js +1 -1
  145. package/dist/commands/sys/setup.js +1 -1
  146. package/dist/commands/sys/spaces.d.ts +1 -0
  147. package/dist/commands/sys/spaces.js +2 -0
  148. package/dist/commands/sys/sync-deps.js +2 -2
  149. package/dist/commands/sys/sync-project-guidance.js +4 -4
  150. package/dist/commands/sys/sync-skills.js +2 -2
  151. package/dist/commands/sys/worktrees.d.ts +1 -0
  152. package/dist/commands/sys/worktrees.js +1 -1
  153. package/dist/commands/sys.js +1 -1
  154. package/dist/core/auth-file.js +2 -2
  155. package/dist/core/bash-job-supervisor.d.ts +6 -0
  156. package/dist/core/bash-job-supervisor.js +4 -0
  157. package/dist/core/bash-jobs.d.ts +13 -6
  158. package/dist/core/bash-jobs.js +8 -7
  159. package/dist/core/broker-client/transport-relay.d.ts +6 -3
  160. package/dist/core/broker-client/transport-relay.js +1 -1
  161. package/dist/core/broker-client/transport-socket.d.ts +6 -1
  162. package/dist/core/broker-client/transport-socket.js +1 -1
  163. package/dist/core/canvas/canvas.d.ts +39 -18
  164. package/dist/core/canvas/canvas.js +21 -20
  165. package/dist/core/canvas/context-strip.d.ts +20 -0
  166. package/dist/core/canvas/context-strip.js +5 -0
  167. package/dist/core/canvas/crons.d.ts +12 -20
  168. package/dist/core/canvas/crons.js +15 -13
  169. package/dist/core/canvas/db.js +2 -2
  170. package/dist/core/canvas/deliveries.d.ts +4 -1
  171. package/dist/core/canvas/deliveries.js +1 -1
  172. package/dist/core/canvas/executions.js +1 -1
  173. package/dist/core/canvas/history.d.ts +2 -1
  174. package/dist/core/canvas/history.js +17 -18
  175. package/dist/core/canvas/memory-reads.d.ts +19 -0
  176. package/dist/core/canvas/memory-reads.js +1 -0
  177. package/dist/core/canvas/migrations.d.ts +0 -4
  178. package/dist/core/canvas/migrations.js +99 -32
  179. package/dist/core/canvas/nav-render.js +1 -1
  180. package/dist/core/canvas/node-agent-paths.d.ts +8 -0
  181. package/dist/core/canvas/node-agent-paths.js +1 -0
  182. package/dist/core/canvas/node-recap.d.ts +2 -2
  183. package/dist/core/canvas/node-recap.js +2 -2
  184. package/dist/core/canvas/node-tokens.d.ts +24 -0
  185. package/dist/core/canvas/node-tokens.js +5 -0
  186. package/dist/core/canvas/paths.d.ts +16 -19
  187. package/dist/core/canvas/paths.js +1 -1
  188. package/dist/core/canvas/render-source.d.ts +2 -2
  189. package/dist/core/canvas/render-source.js +6 -9
  190. package/dist/core/canvas/sessions.d.ts +18 -0
  191. package/dist/core/canvas/sessions.js +4 -1
  192. package/dist/core/canvas/types.d.ts +22 -6
  193. package/dist/core/command-hooks/compose.js +1 -1
  194. package/dist/core/command-hooks/discovery.d.ts +15 -1
  195. package/dist/core/command-hooks/discovery.js +1 -1
  196. package/dist/core/command-hooks/help.d.ts +2 -2
  197. package/dist/core/command-hooks/lifecycle-create.d.ts +1 -1
  198. package/dist/core/command-hooks/lifecycle-create.js +1 -1
  199. package/dist/core/command-hooks/transport/exec-invoke.d.ts +2 -0
  200. package/dist/core/command-hooks/transport/exec-invoke.js +1 -1
  201. package/dist/core/command-hooks/transport/exec-lifecycle.d.ts +1 -0
  202. package/dist/core/command-hooks/transport/exec-lifecycle.js +1 -1
  203. package/dist/core/command-hooks/transport/plan.d.ts +3 -0
  204. package/dist/core/command-hooks/transport/plan.js +1 -0
  205. package/dist/core/command-plugins/discovery.js +1 -1
  206. package/dist/core/command.d.ts +6 -2
  207. package/dist/core/command.js +6 -6
  208. package/dist/core/config.d.ts +8 -5
  209. package/dist/core/config.js +1 -1
  210. package/dist/core/conversation-store/client-worker.d.ts +1 -0
  211. package/dist/core/conversation-store/client-worker.js +1 -0
  212. package/dist/core/conversation-store/client.d.ts +2 -0
  213. package/dist/core/conversation-store/client.js +2 -0
  214. package/dist/core/conversation-store/file-store.d.ts +37 -0
  215. package/dist/core/conversation-store/file-store.js +9 -0
  216. package/dist/core/conversation-store/index.d.ts +50 -0
  217. package/dist/core/conversation-store/index.js +1 -0
  218. package/dist/core/conversation-store/listener.d.ts +4 -0
  219. package/dist/core/conversation-store/listener.js +3 -0
  220. package/dist/core/conversation-store/patch.d.ts +1 -0
  221. package/dist/core/conversation-store/patch.js +1 -0
  222. package/dist/core/directory/join.d.ts +27 -0
  223. package/dist/core/directory/join.js +1 -0
  224. package/dist/core/disk-usage.d.ts +4 -0
  225. package/dist/core/disk-usage.js +1 -0
  226. package/dist/core/events/emit.d.ts +2 -0
  227. package/dist/core/events/emit.js +3 -1
  228. package/dist/core/feed/feed.js +4 -4
  229. package/dist/core/feed/messages.d.ts +3 -0
  230. package/dist/core/feed/messages.js +6 -6
  231. package/dist/core/fs-utils.d.ts +2 -0
  232. package/dist/core/fs-utils.js +3 -3
  233. package/dist/core/grants/local.d.ts +4 -0
  234. package/dist/core/grants/local.js +1 -0
  235. package/dist/core/grants/mirror.d.ts +44 -0
  236. package/dist/core/grants/mirror.js +4 -0
  237. package/dist/core/grants/on-sync.d.ts +22 -0
  238. package/dist/core/grants/on-sync.js +1 -0
  239. package/dist/core/grants/remove.d.ts +7 -0
  240. package/dist/core/grants/remove.js +1 -0
  241. package/dist/core/grants/sandboxes.d.ts +7 -0
  242. package/dist/core/grants/sandboxes.js +1 -0
  243. package/dist/core/grants/sync.d.ts +12 -0
  244. package/dist/core/grants/sync.js +1 -0
  245. package/dist/core/help/memory-extensions.d.ts +3 -0
  246. package/dist/core/help/memory-extensions.js +2 -0
  247. package/dist/core/help.d.ts +14 -0
  248. package/dist/core/help.js +7 -7
  249. package/dist/core/host-exports/builtins.js +3 -3
  250. package/dist/core/host-exports/export.js +3 -3
  251. package/dist/core/human/action-binding.d.ts +2 -0
  252. package/dist/core/human/action-binding.js +1 -1
  253. package/dist/core/human/feedback-companion.d.ts +0 -1
  254. package/dist/core/human/feedback-companion.js +1 -1
  255. package/dist/core/human/page-schema.d.ts +1 -1
  256. package/dist/core/inspector/core.d.ts +2 -0
  257. package/dist/core/inspector/core.js +1 -1
  258. package/dist/core/inspector/tui.js +2 -2
  259. package/dist/core/installed-plugins.js +1 -1
  260. package/dist/core/io.js +6 -6
  261. package/dist/core/keybindings/catalog.d.ts +1 -1
  262. package/dist/core/keybindings/catalog.js +1 -1
  263. package/dist/core/layout-migrate/index.d.ts +15 -0
  264. package/dist/core/layout-migrate/index.js +4 -0
  265. package/dist/core/layout-migrate/paths.d.ts +26 -0
  266. package/dist/core/layout-migrate/paths.js +1 -0
  267. package/dist/core/layout-migrate/stored-paths.d.ts +2 -0
  268. package/dist/core/layout-migrate/stored-paths.js +11 -0
  269. package/dist/core/layout-migrate/stores.d.ts +17 -0
  270. package/dist/core/layout-migrate/stores.js +4 -0
  271. package/dist/core/layout.d.ts +26 -0
  272. package/dist/core/layout.js +2 -0
  273. package/dist/core/llm/run.d.ts +60 -0
  274. package/dist/core/llm/run.js +4 -0
  275. package/dist/core/memory/cli-selector.d.ts +13 -0
  276. package/dist/core/memory/cli-selector.js +1 -0
  277. package/dist/core/memory/history.d.ts +5 -4
  278. package/dist/core/memory/history.js +6 -6
  279. package/dist/core/memory/inline-ref-inventory.d.ts +2 -1
  280. package/dist/core/memory/inline-ref-inventory.js +1 -1
  281. package/dist/core/memory/lint.js +2 -2
  282. package/dist/core/memory/mutation-domain.d.ts +2 -2
  283. package/dist/core/memory/mutation-domain.js +8 -7
  284. package/dist/core/memory/mutations.js +1 -1
  285. package/dist/core/memory/service.d.ts +5 -0
  286. package/dist/core/memory/service.js +2 -2
  287. package/dist/core/memory-resolver.d.ts +11 -7
  288. package/dist/core/memory-resolver.js +2 -2
  289. package/dist/core/model-auth/daemon-login.d.ts +13 -0
  290. package/dist/core/model-auth/daemon-login.js +1 -0
  291. package/dist/core/model-auth/flows.d.ts +45 -0
  292. package/dist/core/model-auth/flows.js +1 -0
  293. package/dist/core/model-auth/handoff-jti.d.ts +4 -0
  294. package/dist/core/model-auth/handoff-jti.js +1 -0
  295. package/dist/core/model-routes.js +1 -1
  296. package/dist/core/nested-stores.d.ts +2 -1
  297. package/dist/core/nested-stores.js +1 -2
  298. package/dist/core/preview-registry.js +2 -2
  299. package/dist/core/profiles/env-store.js +2 -2
  300. package/dist/core/profiles/manifest.d.ts +16 -5
  301. package/dist/core/profiles/manifest.js +1 -1
  302. package/dist/core/provider-management.js +1 -1
  303. package/dist/core/review/birth.js +1 -1
  304. package/dist/core/review/companion.d.ts +0 -2
  305. package/dist/core/review/companion.js +1 -1
  306. package/dist/core/review/fork.js +2 -2
  307. package/dist/core/review/realize.js +1 -1
  308. package/dist/core/review/stage.d.ts +1 -1
  309. package/dist/core/review/stage.js +1 -1
  310. package/dist/core/review/types.d.ts +1 -1
  311. package/dist/core/runs/events.d.ts +34 -0
  312. package/dist/core/runs/events.js +1 -0
  313. package/dist/core/runs/operations.d.ts +43 -0
  314. package/dist/core/runs/operations.js +12 -0
  315. package/dist/core/runtime/bearings-render.d.ts +2 -2
  316. package/dist/core/runtime/bearings-render.js +11 -11
  317. package/dist/core/runtime/bearings.js +2 -2
  318. package/dist/core/runtime/broker/cli-relay.d.ts +5 -0
  319. package/dist/core/runtime/broker/cli-relay.js +1 -0
  320. package/dist/core/runtime/broker/client-registry.d.ts +0 -5
  321. package/dist/core/runtime/broker/client-registry.js +1 -1
  322. package/dist/core/runtime/broker/daemon-ops.d.ts +28 -1
  323. package/dist/core/runtime/broker/daemon-ops.js +1 -1
  324. package/dist/core/runtime/broker/engine-drive.d.ts +0 -2
  325. package/dist/core/runtime/broker/engine-drive.js +1 -1
  326. package/dist/core/runtime/broker/fault-retry.d.ts +9 -0
  327. package/dist/core/runtime/broker/fault-retry.js +1 -1
  328. package/dist/core/runtime/broker/frame-dispatch.d.ts +5 -9
  329. package/dist/core/runtime/broker/frame-dispatch.js +1 -1
  330. package/dist/core/runtime/broker/frame-engine-control.d.ts +3 -2
  331. package/dist/core/runtime/broker/frame-engine-control.js +1 -1
  332. package/dist/core/runtime/broker/frame-memory-refs.d.ts +4 -3
  333. package/dist/core/runtime/broker/frame-memory-refs.js +1 -1
  334. package/dist/core/runtime/broker/frame-read.js +1 -1
  335. package/dist/core/runtime/broker/frame-session.js +1 -1
  336. package/dist/core/runtime/broker/held-deferred-inbox.d.ts +3 -1
  337. package/dist/core/runtime/broker/held-deferred-inbox.js +1 -1
  338. package/dist/core/runtime/broker/inbox.d.ts +1 -2
  339. package/dist/core/runtime/broker/inbox.js +7 -10
  340. package/dist/core/runtime/broker/model-adapter.d.ts +9 -0
  341. package/dist/core/runtime/broker/model-adapter.js +2 -0
  342. package/dist/core/runtime/broker/node-token.d.ts +3 -0
  343. package/dist/core/runtime/broker/node-token.js +1 -0
  344. package/dist/core/runtime/broker/read-ops.js +1 -1
  345. package/dist/core/runtime/broker/rebind.d.ts +2 -0
  346. package/dist/core/runtime/broker/rebind.js +1 -1
  347. package/dist/core/runtime/broker/tool-groups.js +1 -1
  348. package/dist/core/runtime/broker/turn-ignition.d.ts +3 -3
  349. package/dist/core/runtime/broker/turn-ignition.js +1 -1
  350. package/dist/core/runtime/broker-cli.js +3 -3
  351. package/dist/core/runtime/broker-extension-render.d.ts +2 -5
  352. package/dist/core/runtime/broker-extension-render.js +4 -4
  353. package/dist/core/runtime/broker-persona-guidance.js +3 -3
  354. package/dist/core/runtime/broker-protocol.d.ts +7 -8
  355. package/dist/core/runtime/broker.js +1 -1
  356. package/dist/core/runtime/canvas-extensions.d.ts +1 -0
  357. package/dist/core/runtime/canvas-extensions.js +1 -1
  358. package/dist/core/runtime/close.d.ts +9 -0
  359. package/dist/core/runtime/close.js +1 -1
  360. package/dist/core/runtime/deliver-live.js +1 -1
  361. package/dist/core/runtime/fleet.d.ts +1 -1
  362. package/dist/core/runtime/front-door-login.js +1 -1
  363. package/dist/core/runtime/front-door.js +2 -2
  364. package/dist/core/runtime/headless-pi.d.ts +1 -1
  365. package/dist/core/runtime/headless-pi.js +1 -1
  366. package/dist/core/runtime/host.d.ts +1 -1
  367. package/dist/core/runtime/host.js +3 -1
  368. package/dist/core/runtime/invocation.d.ts +3 -0
  369. package/dist/core/runtime/kickoff.d.ts +1 -0
  370. package/dist/core/runtime/kickoff.js +16 -16
  371. package/dist/core/runtime/launch-target.d.ts +1 -1
  372. package/dist/core/runtime/launch-target.js +1 -1
  373. package/dist/core/runtime/launch.d.ts +10 -35
  374. package/dist/core/runtime/launch.js +1 -1
  375. package/dist/core/runtime/lifecycle.js +2 -2
  376. package/dist/core/runtime/memory.d.ts +1 -1
  377. package/dist/core/runtime/memory.js +1 -1
  378. package/dist/core/runtime/model-registry.js +1 -1
  379. package/dist/core/runtime/model-swap.d.ts +17 -19
  380. package/dist/core/runtime/model-swap.js +1 -1
  381. package/dist/core/runtime/node-read.js +3 -2
  382. package/dist/core/runtime/nodes.d.ts +7 -0
  383. package/dist/core/runtime/nodes.js +1 -1
  384. package/dist/core/runtime/outcome-document.js +1 -1
  385. package/dist/core/runtime/package-health.js +2 -2
  386. package/dist/core/runtime/persona.js +2 -2
  387. package/dist/core/runtime/pi-vendored.js +1 -1
  388. package/dist/core/runtime/placement-tmux.d.ts +1 -1
  389. package/dist/core/runtime/placement-tmux.js +1 -1
  390. package/dist/core/runtime/placement.js +1 -1
  391. package/dist/core/runtime/promote.js +1 -1
  392. package/dist/core/runtime/provider-credential-gate.js +2 -2
  393. package/dist/core/runtime/recovery-hold.d.ts +2 -0
  394. package/dist/core/runtime/recovery-hold.js +1 -0
  395. package/dist/core/runtime/recycle.js +1 -1
  396. package/dist/core/runtime/reopen.js +1 -1
  397. package/dist/core/runtime/reset.js +1 -1
  398. package/dist/core/runtime/revive.d.ts +1 -1
  399. package/dist/core/runtime/revive.js +2 -3
  400. package/dist/core/runtime/roadmap.js +4 -4
  401. package/dist/core/runtime/run-command.d.ts +6 -0
  402. package/dist/core/runtime/run-command.js +1 -1
  403. package/dist/core/runtime/session-branch.d.ts +2 -8
  404. package/dist/core/runtime/session-branch.js +1 -1
  405. package/dist/core/runtime/session-list-cache.d.ts +6 -22
  406. package/dist/core/runtime/session-list-cache.js +1 -1
  407. package/dist/core/runtime/situational-context.js +2 -2
  408. package/dist/core/runtime/spawn-env.d.ts +6 -6
  409. package/dist/core/runtime/spawn-env.js +1 -1
  410. package/dist/core/runtime/spawn.d.ts +5 -0
  411. package/dist/core/runtime/spawn.js +2 -2
  412. package/dist/core/runtime/stop-guard.js +2 -2
  413. package/dist/core/runtime/stop-signals.d.ts +2 -2
  414. package/dist/core/runtime/stop-signals.js +1 -1
  415. package/dist/core/runtime/structured-output.d.ts +10 -4
  416. package/dist/core/runtime/structured-output.js +4 -4
  417. package/dist/core/runtime/tmux-bindings.js +3 -3
  418. package/dist/core/runtime/tmux-driver.d.ts +4 -0
  419. package/dist/core/runtime/tmux-driver.js +7 -7
  420. package/dist/core/runtime/view-socket.d.ts +9 -2
  421. package/dist/core/runtime/view-socket.js +1 -1
  422. package/dist/core/runtime/warm-pool.js +1 -1
  423. package/dist/core/scope.d.ts +3 -2
  424. package/dist/core/scope.js +1 -1
  425. package/dist/core/scoped-state/db.js +1 -1
  426. package/dist/core/scoped-state/migrate.js +3 -3
  427. package/dist/core/scoped-state/profiles.d.ts +2 -1
  428. package/dist/core/scoped-state/profiles.js +1 -1
  429. package/dist/core/scoped-state/schema.d.ts +2 -1
  430. package/dist/core/scoped-state/schema.js +4 -4
  431. package/dist/core/scopes.d.ts +2 -2
  432. package/dist/core/scopes.js +1 -1
  433. package/dist/core/secrets.d.ts +1 -0
  434. package/dist/core/secrets.js +2 -2
  435. package/dist/core/spaces/mounts.d.ts +32 -0
  436. package/dist/core/spaces/mounts.js +1 -0
  437. package/dist/core/spaces/open-beneath.d.ts +71 -0
  438. package/dist/core/spaces/open-beneath.js +1 -0
  439. package/dist/core/spaces/permissions.d.ts +46 -0
  440. package/dist/core/spaces/permissions.js +1 -0
  441. package/dist/core/spaces/process.d.ts +27 -0
  442. package/dist/core/spaces/process.js +1 -0
  443. package/dist/core/spaces/space.d.ts +8 -0
  444. package/dist/core/spaces/space.js +2 -0
  445. package/dist/core/spaces/stop.d.ts +8 -0
  446. package/dist/core/spaces/stop.js +2 -0
  447. package/dist/core/spaces/users.d.ts +19 -0
  448. package/dist/core/spaces/users.js +1 -0
  449. package/dist/core/subscription-state.d.ts +2 -0
  450. package/dist/core/subscription-state.js +3 -3
  451. package/dist/core/substrate/frontmatter-validation.js +1 -1
  452. package/dist/core/substrate/injected-store.d.ts +28 -3
  453. package/dist/core/substrate/injected-store.js +2 -1
  454. package/dist/core/substrate/listings.js +1 -1
  455. package/dist/core/substrate/memory-events.d.ts +6 -0
  456. package/dist/core/substrate/memory-events.js +1 -0
  457. package/dist/core/substrate/on-read-node.js +1 -1
  458. package/dist/core/substrate/on-read.d.ts +6 -6
  459. package/dist/core/substrate/on-read.js +5 -5
  460. package/dist/core/substrate/plan.js +1 -1
  461. package/dist/core/substrate/render-node.js +1 -1
  462. package/dist/core/substrate/render.d.ts +4 -3
  463. package/dist/core/substrate/render.js +38 -38
  464. package/dist/core/substrate/schema.d.ts +6 -0
  465. package/dist/core/substrate/schema.js +1 -1
  466. package/dist/core/tui/panel.js +1 -1
  467. package/dist/core/user-settings.d.ts +12 -0
  468. package/dist/core/user-settings.js +1 -1
  469. package/dist/core/worktree-mutation-async.js +5 -5
  470. package/dist/core/worktree-quarantine.js +1 -1
  471. package/dist/core/worktree-remove.d.ts +15 -0
  472. package/dist/core/worktree-remove.js +1 -0
  473. package/dist/core/worktree-sweep.js +6 -6
  474. package/dist/daemon/analytics/compute.d.ts +37 -0
  475. package/dist/daemon/analytics/compute.js +1 -0
  476. package/dist/daemon/analytics/scan-worker.d.ts +1 -0
  477. package/dist/daemon/analytics/scan-worker.js +2 -0
  478. package/dist/daemon/analytics/scan.d.ts +37 -0
  479. package/dist/daemon/analytics/scan.js +1 -0
  480. package/dist/daemon/api/app-listener.d.ts +11 -0
  481. package/dist/daemon/api/app-listener.js +21 -0
  482. package/dist/daemon/api/bridge.js +5 -5
  483. package/dist/daemon/api/handlers/analytics.d.ts +2 -0
  484. package/dist/daemon/api/handlers/analytics.js +1 -0
  485. package/dist/daemon/api/handlers/attach.js +1 -1
  486. package/dist/daemon/api/handlers/bash-jobs.js +2 -2
  487. package/dist/daemon/api/handlers/bash.js +1 -1
  488. package/dist/daemon/api/handlers/broker-ops.js +1 -1
  489. package/dist/daemon/api/handlers/canvas.d.ts +1 -1
  490. package/dist/daemon/api/handlers/canvas.js +6 -6
  491. package/dist/daemon/api/handlers/crons.js +1 -1
  492. package/dist/daemon/api/handlers/files.d.ts +1 -1
  493. package/dist/daemon/api/handlers/files.js +1 -1
  494. package/dist/daemon/api/handlers/health.js +2 -2
  495. package/dist/daemon/api/handlers/hook-exec.d.ts +2 -0
  496. package/dist/daemon/api/handlers/hook-exec.js +1 -0
  497. package/dist/daemon/api/handlers/human-requests.js +1 -1
  498. package/dist/daemon/api/handlers/inbox.js +1 -1
  499. package/dist/daemon/api/handlers/llm.d.ts +2 -0
  500. package/dist/daemon/api/handlers/llm.js +3 -0
  501. package/dist/daemon/api/handlers/memory-reads.d.ts +4 -0
  502. package/dist/daemon/api/handlers/memory-reads.js +1 -0
  503. package/dist/daemon/api/handlers/memory.js +5 -1
  504. package/dist/daemon/api/handlers/messages.js +2 -2
  505. package/dist/daemon/api/handlers/modelauth.js +1 -1
  506. package/dist/daemon/api/handlers/node-outcomes.js +1 -1
  507. package/dist/daemon/api/handlers/node-records.d.ts +2 -0
  508. package/dist/daemon/api/handlers/node-records.js +3 -0
  509. package/dist/daemon/api/handlers/nodes.d.ts +1 -1
  510. package/dist/daemon/api/handlers/nodes.js +1 -1
  511. package/dist/daemon/api/handlers/profiles.d.ts +4 -1
  512. package/dist/daemon/api/handlers/profiles.js +1 -1
  513. package/dist/daemon/api/handlers/reports.js +5 -3
  514. package/dist/daemon/api/handlers/reviews.d.ts +1 -1
  515. package/dist/daemon/api/handlers/reviews.js +1 -1
  516. package/dist/daemon/api/handlers/run-routes.d.ts +2 -0
  517. package/dist/daemon/api/handlers/run-routes.js +1 -0
  518. package/dist/daemon/api/handlers/runs.d.ts +9 -0
  519. package/dist/daemon/api/handlers/runs.js +1 -0
  520. package/dist/daemon/api/handlers/subscriptions.js +1 -1
  521. package/dist/daemon/api/handlers/worktree.js +1 -1
  522. package/dist/daemon/api/map.d.ts +10 -4
  523. package/dist/daemon/api/map.js +2 -2
  524. package/dist/daemon/api/operations.d.ts +18 -0
  525. package/dist/daemon/api/operations.js +1 -0
  526. package/dist/daemon/api/principal.d.ts +42 -0
  527. package/dist/daemon/api/principal.js +1 -0
  528. package/dist/daemon/api/router.d.ts +27 -3
  529. package/dist/daemon/api/router.js +1 -1
  530. package/dist/daemon/api/server.d.ts +4 -0
  531. package/dist/daemon/api/server.js +1 -1
  532. package/dist/daemon/api/vendor-signin.d.ts +7 -0
  533. package/dist/daemon/api/vendor-signin.js +77 -0
  534. package/dist/daemon/api/viewer-presence.d.ts +3 -0
  535. package/dist/daemon/api/viewer-presence.js +1 -0
  536. package/dist/daemon/cron/armed-context.d.ts +4 -0
  537. package/dist/daemon/cron/armed-context.js +1 -1
  538. package/dist/daemon/cron/escalation.js +3 -3
  539. package/dist/daemon/cron/lease-recovery.js +1 -1
  540. package/dist/daemon/cron/sinks.js +2 -2
  541. package/dist/daemon/cron-run.d.ts +5 -5
  542. package/dist/daemon/cron-run.js +1 -1
  543. package/dist/daemon/crtrd.js +8 -7
  544. package/dist/daemon/delivery/run-delivery.d.ts +4 -0
  545. package/dist/daemon/delivery/run-delivery.js +1 -1
  546. package/dist/daemon/fleet.d.ts +1 -1
  547. package/dist/daemon/fleet.js +6 -6
  548. package/dist/daemon/human/finish.js +7 -7
  549. package/dist/daemon/joined-owner.d.ts +5 -0
  550. package/dist/daemon/joined-owner.js +1 -0
  551. package/dist/daemon/manage.js +2 -2
  552. package/dist/daemon/messaging/node-message.js +1 -1
  553. package/dist/daemon/park-activity.js +1 -1
  554. package/dist/daemon/reconcilers/bash-deadline.js +1 -1
  555. package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
  556. package/dist/daemon/reconcilers/broker-supervision.js +4 -4
  557. package/dist/daemon/reconcilers/delivery-lane.js +1 -1
  558. package/dist/daemon/reconcilers/live-obligation.d.ts +7 -0
  559. package/dist/daemon/reconcilers/live-obligation.js +1 -1
  560. package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
  561. package/dist/daemon/reconcilers/storage-maintenance.d.ts +20 -1
  562. package/dist/daemon/reconcilers/storage-maintenance.js +1 -1
  563. package/dist/daemon/runs/append-section.d.ts +6 -0
  564. package/dist/daemon/runs/append-section.js +2 -0
  565. package/dist/daemon/runs/observer.d.ts +5 -0
  566. package/dist/daemon/runs/observer.js +4 -0
  567. package/dist/launcher/bwrap.d.ts +4 -0
  568. package/dist/launcher/bwrap.js +2 -0
  569. package/dist/launcher/client.d.ts +2 -0
  570. package/dist/launcher/client.js +3 -0
  571. package/dist/launcher/main.d.ts +1 -0
  572. package/dist/launcher/main.js +3 -0
  573. package/dist/launcher/netrule.d.ts +1 -0
  574. package/dist/launcher/netrule.js +1 -0
  575. package/dist/launcher/seccomp.d.ts +1 -0
  576. package/dist/launcher/seccomp.js +1 -0
  577. package/dist/launcher/spec.d.ts +88 -0
  578. package/dist/launcher/spec.js +1 -0
  579. package/dist/launcher/users.d.ts +18 -0
  580. package/dist/launcher/users.js +7 -0
  581. package/dist/launcher/validate.d.ts +22 -0
  582. package/dist/launcher/validate.js +1 -0
  583. package/dist/migrations/corpus.js +3 -3
  584. package/dist/migrations/runner.js +1 -1
  585. package/dist/native/linux/addon.node +0 -0
  586. package/dist/native/linux.d.ts +29 -0
  587. package/dist/native/linux.js +1 -0
  588. package/dist/pi-extensions/broker-local.js +2 -2
  589. package/dist/pi-extensions/canvas-bash-valve.d.ts +1 -3
  590. package/dist/pi-extensions/canvas-bash-valve.js +4 -7
  591. package/dist/pi-extensions/canvas-context-intro.d.ts +1 -2
  592. package/dist/pi-extensions/canvas-context-intro.js +2 -2
  593. package/dist/pi-extensions/canvas-doc-substrate.js +6 -6
  594. package/dist/pi-extensions/canvas-inbox-watcher.d.ts +2 -1
  595. package/dist/pi-extensions/canvas-inbox-watcher.js +2 -1
  596. package/dist/pi-extensions/canvas-passive-context.d.ts +1 -1
  597. package/dist/pi-extensions/canvas-passive-context.js +11 -11
  598. package/dist/pi-extensions/canvas-recap.js +6 -6
  599. package/dist/pi-extensions/canvas-stophook.js +1 -1
  600. package/dist/pi-extensions/canvas-structured-output.js +4 -4
  601. package/dist/pi-extensions/canvas-tool-guide.js +1 -1
  602. package/dist/pi-extensions/system-prompt-entry.d.ts +15 -0
  603. package/dist/pi-extensions/system-prompt-entry.js +1 -0
  604. package/dist/shared/env.d.ts +5 -1
  605. package/dist/shared/env.js +1 -1
  606. package/dist/shared/strip-cd-prefix.d.ts +1 -0
  607. package/dist/shared/strip-cd-prefix.js +1 -0
  608. package/dist/types.d.ts +31 -15
  609. package/docs/cli/memory-and-preferences.md +3 -1
  610. package/docs/sdk/client.md +34 -0
  611. package/docs/sdk/errors.md +2 -0
  612. package/docs/sdk/memory.md +2 -2
  613. package/docs/sdk/streaming.md +21 -0
  614. package/package.json +18 -4
  615. package/packages/crouter-identity/dist/index.d.ts +54 -0
  616. package/packages/crouter-identity/dist/index.js +166 -0
  617. package/packages/crouter-identity/package.json +33 -0
  618. package/runtime.lock.json +34 -8
  619. package/scripts/build-native-linux.mjs +16 -0
  620. package/scripts/install-runtime.mjs +9 -7
  621. package/scripts/lib/isolation-env.mjs +42 -0
  622. package/scripts/runtime-smoke.mjs +49 -0
  623. package/src/native/linux/addon.c +249 -0
  624. package/dist/core/profiles/state-block.d.ts +0 -4
  625. package/dist/core/profiles/state-block.js +0 -3
  626. package/dist/core/runtime/broker/auth-reload.d.ts +0 -41
  627. package/dist/core/runtime/broker/auth-reload.js +0 -1
  628. package/dist/core/substrate/cli-context-delivery.d.ts +0 -22
  629. package/dist/core/substrate/cli-context-delivery.js +0 -1
@@ -1 +1 @@
1
- var u=Object.defineProperty;var l=(o,t)=>u(o,"name",{value:t,configurable:!0});import{defineLeaf as h}from"../../core/command.js";import{general as m,usage as f}from"../../core/errors.js";import{resolve as y}from"node:path";import{pathExists as w}from"../../core/fs-utils.js";import{cliClient as g,rethrowAsCliError as v}from"../api-client.js";const A=h({name:"migrate",description:"converge every profile manifest and writable memory store to the current on-disk format",whenToUse:"after a crtr update whose release notes name a state migration, when profiles stop resolving on a home that predates the update, or when old-format docs resurface (a restore, a sync, a hand-authored file). Convergent and idempotent: re-running over current state changes nothing, so use --dry-run first only when you want to review the rewrite.",help:{name:"sys migrate",summary:"run the registered state migrations over every profile manifest and discovered memory store",guide:"Discovery decides what is migrated: the profiles and the projects they name, the ancestors of this directory, every nested store below any project root it reaches (a node's recorded cwd included), every installed plugin (disabled included), the node stores holding documents, and builtin as read-only input. A store outside that frontier is invisible to the run \u2014 add it with --dir; discovery_roots reports the frontier the run actually searched. A migration that changes a canonical identity plans across the whole corpus at once and applies in two phases, every reference rewrite before any identity rewrite, so one blocker writes nothing anywhere.",params:[{kind:"flag",name:"dry-run",type:"bool",required:!1,constraint:"Plan and report every rewrite without writing any file."},{kind:"flag",name:"dir",type:"path",required:!1,repeatable:!0,constraint:"Project directory (the one containing `.crouter/`, not the memory dir) to add to discovery, once per occurrence. For a store no profile names and this directory does not sit under. The path must exist."}],output:[{name:"profiles",type:"number",required:!0,constraint:"Profile manifests scanned."},{name:"stores",type:"number",required:!0,constraint:"Memory stores discovered, deduped by realpath. Builtin is counted: it is read-only corpus input."},{name:"changed",type:"number",required:!0,constraint:"Files rewritten (or, under --dry-run, that would be) \u2014 manifests, per-store documents, and corpus phases together."},{name:"applied",type:"object[]",required:!0,constraint:"One row per migration that changed files: {store, lane, migration, files}, lane one of profile-manifest, convergent, corpus. Empty when the state is already current."},{name:"skipped",type:"object[]",required:!0,constraint:"Files left untouched because they could not be parsed \u2014 a doc whose frontmatter is not valid YAML, or a manifest that is not valid JSON: {store, relPath, error}. Fix the file, then re-run."},{name:"blockers",type:"object[]",required:!0,constraint:"Why the corpus lane may not write: {kind, message, store?, target?, path?, name?, paths?}. kind is inaccessible-root, inaccessible-target, parse-failure, namespace, association, front-door, divergent-reference, unsafe-route, collision, package-owned-corpus, or verification. A non-empty list with a corpus migration registered fails the run, and `received` carries this whole report plus {corpus_phase, wrote} \u2014 corpus_phase is not-started (the corpus is untouched), planned (--dry-run), or written (both phases landed and verification then failed, so `wrote` is the inventory on disk)."},{name:"discovery_roots",type:"object[]",required:!0,constraint:"The frontier searched: {reason, root, boundary, detail?}. reason is user, profile, profile-project, cwd-ancestor, descendant, node, plugin, builtin, or explicit-dir; boundary is store, ancestors, descendants, plugins, or nodes."},{name:"discovered_stores",type:"object[]",required:!0,constraint:"One row per physical store: {store, scope, namespace, mount_status, writable, reasons, targets, docs}. reasons holds every way the store was reached; targets the target ids that mount it; docs its parseable document count."},{name:"discovered_targets",type:"object[]",required:!0,constraint:"One row per resolution view: {id, kind, origin, cwd, profile_id, node_id, stores}. stores lists store keys in that target's precedence order."},{name:"repository_namespaces",type:"object[]",required:!0,constraint:"Repository-root namespace decisions this run makes: {repository_root, repository_key, declaration_path, namespace, source, action}. A nested store inherits this declaration; its reported effective prefix is not a declaration."},{name:"store_prefixes",type:"object[]",required:!0,constraint:"Effective prefix facts for each project store: {store_root, owner_dir, repository_root, owner_relative_path, old_prefix, old_rule, effective_prefix, nested_declaration_action, front_door_action}. A nonempty owner_relative_path always reports front_door_action `none`; a nested effective_prefix is derived, not a declaration."},{name:"renames",type:"object[]",required:!0,constraint:"Canonical identity changes: {store_root, path, from, to}."},{name:"references",type:"object[]",required:!0,constraint:"Rewritten pointers at a changed identity: {store_root, path, kind, from, to}, kind link or memory-read."},{name:"dryRun",type:"boolean",required:!0,constraint:"True when nothing was written (preview only)."},{name:"resumed",type:"boolean",required:!0,constraint:"True only when this repair resumed the blocked daemon startup."},{name:"resume_error",type:"string",required:!1,constraint:"Present when corpus repair succeeded but normal daemon startup then failed."}],outputKind:"object",effects:["The daemon that owns this canvas runs the migration. Rewrites old-format `profile.json` manifests in place (atomic, under the same per-profile lock `profile project add/remove` take). A manifest whose structure cannot be converted fails the whole run \u2014 no project setting is ever guessed.","Rewrites old-format memory documents in place (atomic per-file writes) across every writable discovered store: profiles, profile-owned projects, this directory's ancestors, nested descendant stores, installed plugin stores, and node stores. Builtin docs are package-owned and never touched.","Applies corpus-wide identity changes in two ordered phases across every writable store, after the global plan comes back blocker-free; a post-write pass re-reads the corpus from disk and verifies it.","Under --dry-run: read-only, writes nothing."]},run:l(async o=>{const t=o.dryRun===!0,a=(o.dir??[]).map(r=>y(r)),n=a.filter(r=>!w(r));if(n.length>0)throw f(`--dir path does not exist: ${n.join(", ")}`,{received:n,field:"dir",next:"Pass the project directory that contains `.crouter/`, or omit --dir to migrate the discovered frontier only."});let e;try{e=await g().migrateState({dry_run:t,dirs:a})}catch(r){v(r)}if(e.blocked){const r=e.blockers,d=e.applied.filter(s=>s.lane!=="corpus").flatMap(s=>s.files),i=e.corpus_phase,c=e.wrote,p=t?"\u2014 this was a --dry-run; nothing was written":i==="written"?`after both write phases \u2014 ${c.corpus_consumers.length} reference and ${c.corpus_identities.length} identity rewrite(s) are on disk and are NOT rolled back`:d.length>0?`before any corpus write \u2014 the corpus is unchanged, but ${d.length} earlier manifest/document rewrite(s) are already on disk`:"\u2014 nothing was written";throw m(`corpus migration ${i==="written"?"verification failed with":"blocked by"} ${r.length} finding(s) ${p}`,{received:e,next:i==="written"?"Resolve every verification finding against the files listed in received.wrote.corpus_identities and .corpus_consumers, then re-run `crtr sys migrate` \u2014 the lane converges from file truth.":"Resolve every blocker, then re-run `crtr sys migrate` \u2014 the earlier lanes are convergent and re-running them is a no-op."})}return{...e,follow_up:e.skipped.length>0?"Some files could not be parsed and were left untouched \u2014 fix each named file, then re-run `crtr sys migrate`.":e.changed===0?"State already current \u2014 nothing to rewrite.":t?"Preview only \u2014 re-run without --dry-run to write these changes.":void 0}},"run")});export{A as sysMigrateLeaf};
1
+ var h=Object.defineProperty;var u=(n,t)=>h(n,"name",{value:t,configurable:!0});import{defineLeaf as m}from"../../core/command.js";import{general as f,usage as y}from"../../core/errors.js";import{resolve as w}from"node:path";import{pathExists as g}from"../../core/fs-utils.js";import{cliClient as v,rethrowAsCliError as b}from"../api-client.js";import{layoutNeedsMigration as _}from"../../core/layout.js";import{migrateLayout as k}from"../../core/layout-migrate/index.js";const $=m({name:"migrate",description:"migrate an old runtime layout offline, then converge profile and memory formats",whenToUse:"after a crtr update whose release notes name a state migration, when profiles stop resolving on a home that predates the update, or when old-format docs resurface (a restore, a sync, a hand-authored file). Convergent and idempotent: re-running over current state changes nothing, so use --dry-run first only when you want to review the rewrite.",help:{name:"sys migrate",summary:"move an old runtime layout offline before running daemon-owned profile and memory migrations",guide:"A layout migration requires the daemon to be stopped and runs in this process. It moves runtime files, rewrites stored paths, and writes the layout version last, then stops. Start the daemon and run `crtr sys migrate` again: the daemon then runs profile and memory migrations. Discovery decides what is migrated: the profiles and the projects they name, the ancestors of this directory, every nested store below any project root it reaches (a node's recorded cwd included), every installed plugin (disabled included), the node stores holding documents, and builtin as read-only input. A store outside that frontier is invisible to the run \u2014 add it with --dir; discovery_roots reports the frontier the run actually searched. A migration that changes a canonical identity plans across the whole corpus at once and applies in two phases, every reference rewrite before any identity rewrite, so one blocker writes nothing anywhere.",params:[{kind:"flag",name:"dry-run",type:"bool",required:!1,constraint:"Plan and report every rewrite without writing any file."},{kind:"flag",name:"dir",type:"path",required:!1,repeatable:!0,constraint:"Project directory (the one containing `.crouter/`, not the memory dir) to add to discovery, once per occurrence. For a store no profile names and this directory does not sit under. The path must exist."}],output:[{name:"layout_moved",type:"number",required:!1,constraint:"Old-layout paths moved or stored paths rewritten on this run; present when the layout migration ran."},{name:"layout_absent_credentials",type:"string[]",required:!1,constraint:"Old credential files the layout migration looked for and did not find (or, under --dry-run, will not find); present when the layout migration ran. An absent file is legitimate when the old home never held that credential."},{name:"profiles",type:"number",required:!1,constraint:"Profile manifests scanned after the layout migration completed."},{name:"stores",type:"number",required:!1,constraint:"Memory stores discovered, deduped by realpath. Builtin is counted: it is read-only corpus input."},{name:"changed",type:"number",required:!1,constraint:"Files rewritten (or, under --dry-run, that would be) \u2014 manifests, per-store documents, and corpus phases together."},{name:"applied",type:"object[]",required:!1,constraint:"One row per migration that changed files: {store, lane, migration, files}, lane one of profile-manifest, convergent, corpus. Empty when the state is already current."},{name:"skipped",type:"object[]",required:!1,constraint:"Files left untouched because they could not be parsed \u2014 a doc whose frontmatter is not valid YAML, or a manifest that is not valid JSON: {store, relPath, error}. Fix the file, then re-run."},{name:"blockers",type:"object[]",required:!1,constraint:"Why the corpus lane may not write: {kind, message, store?, target?, path?, name?, paths?}. kind is inaccessible-root, inaccessible-target, parse-failure, namespace, association, front-door, divergent-reference, unsafe-route, collision, package-owned-corpus, or verification. A non-empty list with a corpus migration registered fails the run, and `received` carries this whole report plus {corpus_phase, wrote} \u2014 corpus_phase is not-started (the corpus is untouched), planned (--dry-run), or written (both phases landed and verification then failed, so `wrote` is the inventory on disk)."},{name:"discovery_roots",type:"object[]",required:!1,constraint:"The frontier searched: {reason, root, boundary, detail?}. reason is user, profile, profile-project, cwd-ancestor, descendant, node, plugin, builtin, or explicit-dir; boundary is store, ancestors, descendants, plugins, or nodes."},{name:"discovered_stores",type:"object[]",required:!1,constraint:"One row per physical store: {store, scope, namespace, mount_status, writable, reasons, targets, docs}. reasons holds every way the store was reached; targets the target ids that mount it; docs its parseable document count."},{name:"discovered_targets",type:"object[]",required:!1,constraint:"One row per resolution view: {id, kind, origin, cwd, profile_id, node_id, stores}. stores lists store keys in that target's precedence order."},{name:"repository_namespaces",type:"object[]",required:!1,constraint:"Repository-root namespace decisions this run makes: {repository_root, repository_key, declaration_path, namespace, source, action}. A nested store inherits this declaration; its reported effective prefix is not a declaration."},{name:"store_prefixes",type:"object[]",required:!1,constraint:"Effective prefix facts for each project store: {store_root, owner_dir, repository_root, owner_relative_path, old_prefix, old_rule, effective_prefix, nested_declaration_action, front_door_action}. A nonempty owner_relative_path always reports front_door_action `none`; a nested effective_prefix is derived, not a declaration."},{name:"renames",type:"object[]",required:!1,constraint:"Canonical identity changes: {store_root, path, from, to}."},{name:"references",type:"object[]",required:!1,constraint:"Rewritten pointers at a changed identity: {store_root, path, kind, from, to}, kind link or memory-read."},{name:"dryRun",type:"boolean",required:!0,constraint:"True when nothing was written (preview only)."},{name:"resumed",type:"boolean",required:!1,constraint:"True only when this repair resumed the blocked daemon startup."},{name:"resume_error",type:"string",required:!1,constraint:"Present when corpus repair succeeded but normal daemon startup then failed."}],outputKind:"object",effects:["With an old layout and no layout version, refuses while a daemon answers, moves the runtime records, rewrites stored paths and writes the layout version last, then stops; the next run, with the daemon started, runs the daemon-owned state migration.","After layout migration is complete, the daemon that owns this canvas runs the migration. Rewrites old-format `profile.json` manifests in place (atomic, under the same per-profile lock `profile project add/remove` take). A manifest whose structure cannot be converted fails the whole run \u2014 no project setting is ever guessed.","Rewrites old-format memory documents in place (atomic per-file writes) across every writable discovered store: profiles, profile-owned projects, this directory's ancestors, nested descendant stores, installed plugin stores, and node stores. Builtin docs are package-owned and never touched.","Applies corpus-wide identity changes in two ordered phases across every writable store, after the global plan comes back blocker-free; a post-write pass re-reads the corpus from disk and verifies it.","Under --dry-run: read-only, writes nothing."]},run:u(async n=>{const t=n.dryRun===!0,d=(n.dir??[]).map(r=>w(r)),i=d.filter(r=>!g(r));if(i.length>0)throw y(`--dir path does not exist: ${i.join(", ")}`,{received:i,field:"dir",next:"Pass the project directory that contains `.crouter/`, or omit --dir to migrate the discovered frontier only."});const o=_()?await k(t):null;if(t&&o!==null)return{layout_moved:o.moved,layout_absent_credentials:o.absentCredentials,dryRun:t,follow_up:"Preview only \u2014 re-run without --dry-run to migrate the layout."};if(o!==null)return{layout_moved:o.moved,layout_absent_credentials:o.absentCredentials,dryRun:t,follow_up:"Layout migrated. Start the daemon, then run `crtr sys migrate` again against it (in a container, `docker compose exec`) to converge profile and memory formats."};let e;try{e=await v().migrateState({dry_run:t,dirs:d})}catch(r){b(r)}if(e.blocked){const r=e.blockers,c=e.applied.filter(s=>s.lane!=="corpus").flatMap(s=>s.files),a=e.corpus_phase,l=e.wrote,p=t?"\u2014 this was a --dry-run; nothing was written":a==="written"?`after both write phases \u2014 ${l.corpus_consumers.length} reference and ${l.corpus_identities.length} identity rewrite(s) are on disk and are NOT rolled back`:c.length>0?`before any corpus write \u2014 the corpus is unchanged, but ${c.length} earlier manifest/document rewrite(s) are already on disk`:"\u2014 nothing was written";throw f(`corpus migration ${a==="written"?"verification failed with":"blocked by"} ${r.length} finding(s) ${p}`,{received:e,next:a==="written"?"Resolve every verification finding against the files listed in received.wrote.corpus_identities and .corpus_consumers, then re-run `crtr sys migrate` \u2014 the lane converges from file truth.":"Resolve every blocker, then re-run `crtr sys migrate` \u2014 the earlier lanes are convergent and re-running them is a no-op."})}return{...e,follow_up:e.skipped.length>0?"Some files could not be parsed and were left untouched \u2014 fix each named file, then re-run `crtr sys migrate`.":e.changed===0?"State already current \u2014 nothing to rewrite.":t?"Preview only \u2014 re-run without --dry-run to write these changes.":void 0}},"run")});export{$ as sysMigrateLeaf};
@@ -1 +1 @@
1
- var ge=Object.defineProperty;var y=(p,e)=>ge(p,"name",{value:e,configurable:!0});import{envProfileId as pe}from"../../../shared/env.js";import{ModelSelectorComponent as $e,ThinkingSelectorComponent as ee}from"@earendil-works/pi-coding-agent";import{Input as ve,truncateToWidth as V}from"@earendil-works/pi-tui";import{basename as ye,dirname as ke,join as S}from"node:path";import{ANTHROPIC_PROVIDER_ID as be,OPENAI_CODEX_PROVIDER_ID as Re,isManagedProvider as we,readSubscriptionPool as xe}from"../../../core/subscription-state.js";import{readRawConfigAtRoot as P,persistDefaultKindModel as Ie,persistModelLadders as te,persistModelRoute as ie,readMergedLaunchConfig as re}from"../../../core/config.js";import{findProjectScopeRoots as Me,userScopeRoot as Se}from"../../../core/scope.js";import{loadProfileManifest as Pe,profileRoot as Ce}from"../../../core/profiles/manifest.js";import{configuredLadderProviders as Te,inferPortableModelSelection as q,MODEL_PROVIDER_KEYS as oe,MODEL_STRENGTHS as k,THINKING_SUFFIXES as se}from"../../../core/runtime/model-selection.js";import{fitTail as U,padAnsi as f,renderRows as Fe,theme as o,wrapText as Oe}from"../../../core/tui/panel.js";const ne=3,Le={anthropic:be,openai:Re},ce={anthropic:"Anthropic",openai:"OpenAI"},de=[{mode:"base",dimension:"family"},{mode:"base",dimension:"strength"},{mode:"orchestrator",dimension:"family"},{mode:"orchestrator",dimension:"strength"}];function Ee(){const p=Se(),e=pe()||null;let t;if(e!==null)try{const s=Pe(e);t={label:`Profile: ${s.manifest.name}`,root:Ce(s.profileId)}}catch{}const i=Me(process.cwd(),e),r=i.map(s=>({label:`Project: ${ye(ke(s))}`,root:s}));return{targets:[{label:"User",root:p},...t?[t]:[],...r],precedenceRoots:[...i,...t?[t.root]:[],p]}}y(Ee,"modelConfigTargets");function j(p){if(!p)return{};const e=p.trim(),t=e.indexOf("/"),i=t===-1?void 0:e.slice(0,t),r=t===-1?e:e.slice(t+1),s=r.match(/^(.*?):(off|minimal|low|medium|high|xhigh|max)$/i);return{provider:i,id:s?s[1]:r,level:s?s[2].toLowerCase():void 0}}y(j,"parseModelRef");function G(p){if(!p)return"\u2014";const e=p.indexOf("/");return e===-1?p:p.slice(e+1)}y(G,"shortRef");class Xe{static{y(this,"ModelsPanel")}tui;runtime;registry;matches;label;mode="list";ladders;modelRoutes;legacyModelRoutes;kinds;providerKeys=oe;targets;precedenceRoots;targetIndex=0;rawTarget;rows=[];selected=0;column=0;notice="";modelSelector;thinkingSelector;pending;choice;choiceIndex=0;routeForm;routeInput=new ve;pendingRouteCell;onChange;constructor(e,t,i,r,s){this.tui=e,this.runtime=t,this.registry=i,this.matches=r,this.label=s;const n=Ee();this.targets=n.targets,this.precedenceRoots=n.precedenceRoots,this.rawTarget=P(this.currentTarget().root);const c=re();this.ladders=c.modelLadders,this.modelRoutes=c.modelRoutes??{},this.legacyModelRoutes=c.legacyModelRoutes??{},this.kinds=c.kinds,this.providerKeys=this.offeredProviders(),this.rows=this.buildRows(),this.routeInput.onSubmit=l=>{const u=this.routeForm;!u||u.editing===null||(u.text[u.editing]=l.trim(),u.editing=null,this.routeInput.focused=!1,this.notify())},this.routeInput.onEscape=()=>{this.routeForm&&(this.routeForm.editing=null,this.routeInput.focused=!1,this.notify())}}offeredProviders(){try{return Te(e=>we(e)&&xe(e).length>0||this.registry.getProviderAuthStatus(e).configured,this.ladders)}catch{return oe}}currentTarget(){return this.targets[this.targetIndex]}cycleTarget(){this.targetIndex=(this.targetIndex+1)%this.targets.length,this.rawTarget=P(this.currentTarget().root),this.notice="",this.notify()}shadowingPath(e){for(const t of this.precedenceRoots){if(t===this.currentTarget().root)break;const i=P(t);if(i&&e(i))return S(t,"config.json")}}savedButShadowed(e){return`Saved to ${this.currentTarget().label}; overridden by ${e??"a more specific config"}`}routeIds(){return[...new Set([...Object.keys(this.modelRoutes),...Object.keys(this.legacyModelRoutes)])]}routeFamilies(){return[...new Set(this.routeIds().map(e=>(this.modelRoutes[e]??this.legacyModelRoutes[e]).family))]}buildRows(){const e=[{section:"ladder",kind:"defaultProvider"}];for(const t of k)e.push({section:"ladder",kind:"strength",strength:t});for(const t of this.routeIds())e.push({section:"route",routeId:t});e.push({section:"route",routeId:null});for(const t of Object.keys(this.kinds))t.includes("/")||e.push({section:"kind",name:t});return e}reload(){const e=re();this.ladders=e.modelLadders,this.modelRoutes=e.modelRoutes??{},this.legacyModelRoutes=e.legacyModelRoutes??{},this.kinds=e.kinds,this.rawTarget=P(this.currentTarget().root),this.providerKeys=this.offeredProviders(),this.rows=this.buildRows(),this.selected=Math.min(this.selected,this.rows.length-1),this.clampColumn()}refresh(){this.reload(),this.notify()}notify(){this.onChange?.(),this.tui.requestRender()}isPickerOpen(){return this.mode!=="list"}currentRow(){return this.rows[Math.min(this.selected,this.rows.length-1)]}columnsFor(e){return e.section==="ladder"?e.kind==="strength"?this.providerKeys.length:1:e.section==="route"?1:de.length}clampColumn(){this.column=Math.min(this.column,this.columnsFor(this.currentRow())-1)}handleInput(e){if(this.mode==="route-form"){const t=this.routeForm;return t?t.editing!==null?(this.routeInput.handleInput(e),!0):this.matches("crtr.setup.models.cancel",e)?(this.closeRouteForm(),!0):this.matches("crtr.setup.list-down",e)?(t.index=Math.min(t.fields.length-1,t.index+1),this.notice="",!0):this.matches("crtr.setup.list-up",e)?(t.index=Math.max(0,t.index-1),this.notice="",!0):((this.matches("crtr.setup.models.open",e)||this.matches("crtr.setup.models.commit",e))&&this.activateRouteField(),!0):(this.mode="list",!0)}if(this.mode==="route-delete")return this.matches("crtr.setup.confirm.accept",e)?(this.deleteRoute(),!0):(this.matches("crtr.setup.confirm.back",e)&&(this.mode="route-form",this.notify()),!0);if(this.mode==="dimension-picker")return this.matches("crtr.setup.models.commit",e)?(this.commitChoice(),!0):this.matches("crtr.setup.models.cancel",e)?(this.closePicker(),!0):this.matches("crtr.setup.list-down",e)?(this.choiceIndex=Math.min((this.choice?.options.length??1)-1,this.choiceIndex+1),!0):(this.matches("crtr.setup.list-up",e)&&(this.choiceIndex=Math.max(0,this.choiceIndex-1)),!0);if(this.mode==="model-picker"){const t=this.matches("crtr.setup.models.commit",e)?"\r":this.matches("crtr.setup.models.cancel",e)?"\x1B":e;return this.modelSelector?.handleInput(t),!0}if(this.mode==="thinking-picker"){const t=this.matches("crtr.setup.models.commit",e)?"\r":this.matches("crtr.setup.models.cancel",e)?"\x1B":e;return this.thinkingSelector?.getSelectList().handleInput(t),!0}return this.matches("crtr.setup.list-down",e)?(this.selected=Math.min(this.rows.length-1,this.selected+1),this.clampColumn(),this.notice="",!0):this.matches("crtr.setup.list-up",e)?(this.selected=Math.max(0,this.selected-1),this.clampColumn(),this.notice="",!0):this.matches("crtr.setup.cell-previous",e)?(this.column=Math.max(0,this.column-1),!0):this.matches("crtr.setup.cell-next",e)?(this.column=Math.min(this.columnsFor(this.currentRow())-1,this.column+1),!0):this.matches("crtr.setup.models.scope-next",e)?(this.cycleTarget(),!0):this.matches("crtr.setup.models.open",e)?(this.activateCell(),!0):!1}activateCell(){const e=this.currentRow();if(this.notice="",e.section==="ladder"&&e.kind==="defaultProvider"){const t=q(void 0,this.ladders).provider,i=this.providerKeys,r=i[(Math.max(0,i.indexOf(t))+1)%i.length];if(r===t)return;try{te(this.currentTarget().root,{defaultProvider:r})}catch(s){this.notice=`Could not save: ${s instanceof Error?s.message:String(s)}`,this.notify();return}if(this.reload(),(this.ladders.defaultProvider??"anthropic")!==r){const s=this.shadowingPath(n=>n.modelLadders?.defaultProvider!==void 0);this.notice=this.savedButShadowed(s)}this.notify();return}if(e.section==="ladder"&&e.kind==="strength"){this.openModelPicker(this.providerKeys[this.column],e.strength);return}if(e.section==="route"){this.openRouteForm(e.routeId);return}if(e.section==="kind"){const t=de[this.column];if(!t)return;this.openDimensionPicker(e.name,t.mode,t.dimension)}}portableSelection(e){if(e!==void 0){const i=e.lastIndexOf("/"),r=i===-1?"":e.slice(0,i),s=i===-1?"":e.slice(i+1);if(this.routeFamilies().includes(r)&&k.includes(s))return{family:r,strength:s}}const t=q(e,this.ladders);return{family:t.provider,strength:t.strength}}familyLabel(e){return e==="anthropic"||e==="openai"?ce[e]:e}familyOptions(){return[...new Set([...this.providerKeys,...this.routeFamilies()])]}kindSelection(e,t){const i=this.kinds[e],r=t==="orchestrator"?i?.orchestratorModel??i?.model:i?.model;return this.portableSelection(r)}openDimensionPicker(e,t,i){const r=this.kindSelection(e,t),s=i==="family"?this.familyOptions():k,n=i==="family"?r.family:r.strength,c=t==="orchestrator"?"orchestrator":"base",l=i==="family"?`strength ${r.strength}`:`family ${this.familyLabel(r.family)}`;this.choice={title:`Choose ${c} ${i}`,subtitle:`${e} \xB7 keeps ${c} ${l}`,options:s,label:y(u=>i==="family"?this.familyLabel(u):u,"label"),commit:y(u=>{const m=i==="family"?u:r.family,a=i==="strength"?u:r.strength;this.writeKindSelection(e,t,m,a)},"commit")},this.choiceIndex=Math.max(0,s.indexOf(n)),this.mode="dimension-picker",this.notify()}writeKindSelection(e,t,i,r){const s=`${i}/${r}`;try{Ie({root:this.currentTarget().root,kind:e,model:s,orchestrator:t==="orchestrator"})}catch(l){this.notice=`Could not save: ${l instanceof Error?l.message:String(l)}`;return}this.reload();const n=this.kinds[e];if((t==="orchestrator"?n?.orchestratorModel:n?.model)!==s){const l=t==="orchestrator"?"orchestratorModel":"model",u=this.shadowingPath(m=>m.kinds?.[e]?.[l]!==void 0);this.notice=this.savedButShadowed(u)}}commitChoice(){const e=this.choice,t=e?.options[this.choiceIndex];e&&t!==void 0&&e.commit(t),this.closePicker()}openRouteForm(e){const t=e===null?void 0:this.modelRoutes[e]??this.legacyModelRoutes[e],i=[...e===null?[{kind:"text",key:"routeId",label:"Route id"}]:[],{kind:"text",key:"family",label:"Family"},{kind:"text",key:"credentialSource",label:"Credential source"},{kind:"provider",label:"Provider id"},...k.map(r=>({kind:"cell",strength:r})),{kind:"save"},...e===null?[]:[{kind:"delete"}]];this.routeForm={existing:e,text:{routeId:e??"",family:t?.family??"",credentialSource:t?.credentialSource??""},providerId:t?.providerId??"",models:{...t?.models},fields:i,index:0,editing:null},this.mode="route-form",this.notice="",this.notify()}closeRouteForm(){this.routeInput.focused=!1,this.routeForm=void 0,this.mode="list",this.notice="",this.notify()}activateRouteField(){const e=this.routeForm,t=e?.fields[e.index];if(!(!e||!t)){if(t.kind==="text"){e.editing=t.key,this.routeInput.setValue(e.text[t.key]),this.routeInput.handleInput(""),this.routeInput.focused=!0,this.notify();return}if(t.kind==="provider"){const i=[...new Set([...this.registry.getAll().map(r=>r.provider),...e.providerId?[e.providerId]:[]])].sort();this.choice={title:"Choose provider id",subtitle:"Route cells must all belong to this registry provider",options:i,label:y(r=>r,"label"),commit:y(r=>this.setRouteProvider(r),"commit")},this.choiceIndex=Math.max(0,i.indexOf(e.providerId)),this.mode="dimension-picker",this.notify();return}if(t.kind==="cell"){this.openRouteCell(t.strength);return}if(t.kind==="save"){this.saveRoute();return}this.mode="route-delete",this.notify()}}setRouteProvider(e){const t=this.routeForm;if(!t)return;t.providerId=e;const i=[];for(const r of k){const s=t.models[r];s!==void 0&&!s.startsWith(`${e}/`)&&(delete t.models[r],i.push(r))}this.notice=i.length===0?"":`Cleared ${i.join(", ")} because those models belong to another provider.`}openRouteCell(e){const t=this.routeForm;if(!t)return;if(!t.providerId){this.notice="Choose the provider id first",this.notify();return}const i=this.registry.getAll().filter(n=>n.provider===t.providerId);if(i.length===0){this.notice=`No models registered for provider "${t.providerId}" \u2014 this route cannot be edited here.`,this.notify();return}const r=j(t.models[e]),s=r.provider&&r.id?this.registry.find(r.provider,r.id):void 0;this.pendingRouteCell={strength:e},this.showModelSelector(i,s,n=>this.onRouteModelPicked(n))}onRouteModelPicked(e){const t=this.pendingRouteCell,i=this.routeForm;if(!t||!i){this.closePicker();return}if(e.provider!==i.providerId){this.notice=`That is a ${e.provider} model \u2014 pick a ${i.providerId} model for this route.`,this.closePicker();return}if(t.model=e,e.reasoning){const r=j(i.models[t.strength]).level??"medium";this.thinkingSelector=new ee(r,[...se],s=>this.onThinkingPicked(s),()=>this.closePicker()),this.modelSelector=void 0,this.mode="thinking-picker",this.notify();return}i.models[t.strength]=`${e.provider}/${e.id}`,this.closePicker()}saveRoute(){const e=this.routeForm;if(!e)return;const t=e.text.routeId.trim();if(!t){this.notice="Route id is required.",this.notify();return}if(!e.text.family.trim()){this.notice="Family is required.",this.notify();return}if(!e.text.credentialSource.trim()){this.notice="Credential source is required.",this.notify();return}if(!e.providerId.trim()){this.notice="Provider id is required.",this.notify();return}const i=k.filter(n=>e.models[n]===void 0);if(i.length>0){this.notice=`Choose models for ${i.join(", ")} before saving.`,this.notify();return}const r={family:e.text.family.trim(),credentialSource:e.text.credentialSource.trim(),providerId:e.providerId.trim(),models:{ultra:e.models.ultra,strong:e.models.strong,medium:e.models.medium,light:e.models.light}};try{ie(this.currentTarget().root,t,r)}catch(n){this.notice=`Could not save: ${n instanceof Error?n.message:String(n)}`,this.notify();return}this.routeForm=void 0,this.mode="list",this.reload();const s=this.rows.findIndex(n=>n.section==="route"&&n.routeId===t);if(s>=0&&(this.selected=s),JSON.stringify(this.modelRoutes[t])!==JSON.stringify(r)){const n=this.shadowingPath(c=>c.modelRoutes?.[t]!==void 0);this.notice=this.savedButShadowed(n)}else this.notice=`Saved route "${t}" to ${this.currentTarget().label}.`;this.notify()}declaringPath(e){for(const t of this.precedenceRoots){if(t===this.currentTarget().root)continue;if(P(t)?.modelRoutes?.[e]!==void 0)return S(t,"config.json")}}deleteRoute(){const e=this.routeForm?.existing;if(!e){this.mode="route-form",this.notify();return}try{ie(this.currentTarget().root,e,void 0)}catch(i){this.mode="route-form",this.notice=`Could not delete: ${i instanceof Error?i.message:String(i)}`,this.notify();return}const t=this.declaringPath(e);this.routeForm=void 0,this.mode="list",this.reload(),this.notice=t?`Removed route "${e}" from ${this.currentTarget().label}; it is still declared by ${t}.`:`Removed route "${e}" from ${this.currentTarget().label}.`,this.notify()}showModelSelector(e,t,i){this.modelSelector=new $e(this.tui,t,this.runtime,e.map(r=>({model:r})),i,()=>this.closePicker()),this.modelSelector.focused=!0,this.mode="model-picker",this.notify()}openModelPicker(e,t){const i=Le[e],r=this.registry,s=j(this.ladders[e][t]),n=s.provider&&s.id?r.find(s.provider,s.id):void 0,c=r.getAvailable().filter(l=>l.provider===i);if(c.length===0){this.notice=`No ${e} models available \u2014 sign in first.`,this.notify();return}this.pending={providerKey:e,strength:t,expectedRuntime:i},this.showModelSelector(c,n,l=>this.onModelPicked(l))}onModelPicked(e){if(!this.pending){this.closePicker();return}if(e.provider!==this.pending.expectedRuntime){this.notice=`That is a ${e.provider} model \u2014 pick an ${this.pending.providerKey} model for this column.`,this.closePicker();return}if(this.pending.model=e,e.reasoning){const t=j(this.ladders[this.pending.providerKey][this.pending.strength]).level??"medium";this.thinkingSelector=new ee(t,[...se],i=>this.onThinkingPicked(i),()=>this.closePicker()),this.modelSelector=void 0,this.mode="thinking-picker",this.notify();return}this.writeLadder(e,void 0),this.closePicker()}onThinkingPicked(e){if(this.pendingRouteCell?.model&&this.routeForm){const{model:t,strength:i}=this.pendingRouteCell;this.routeForm.models[i]=`${t.provider}/${t.id}${e!=="off"?`:${e}`:""}`}else this.pending?.model&&this.writeLadder(this.pending.model,e);this.closePicker()}writeLadder(e,t){if(!this.pending)return;const i=`${e.provider}/${e.id}${t&&t!=="off"?`:${t}`:""}`,{providerKey:r,strength:s}=this.pending;try{te(this.currentTarget().root,{[r]:{[s]:i}})}catch(n){this.notice=`Could not save: ${n instanceof Error?n.message:String(n)}`;return}if(this.reload(),this.ladders[r][s]!==i){const n=this.shadowingPath(c=>c.modelLadders?.[r]?.[s]!==void 0);this.notice=this.savedButShadowed(n)}}closePicker(){this.mode=this.routeForm!==void 0?"route-form":"list",this.modelSelector=void 0,this.thinkingSelector=void 0,this.pending=void 0,this.pendingRouteCell=void 0,this.choice=void 0,this.notify()}dispose(){this.routeForm=void 0,this.closePicker()}targetLadderOverride(e,t){return this.rawTarget?.modelLadders?.[e]?.[t]!==void 0}targetKindOverride(e,t){const i=this.rawTarget?.kinds,r=t?"orchestratorModel":"model";return i?.[e]?.[r]!==void 0}footerHint(){return this.mode==="dimension-picker"?`${this.label("crtr.setup.list-down")}/${this.label("crtr.setup.list-up")} choice \xB7 ${this.label("crtr.setup.models.commit")} save \xB7 ${this.label("crtr.setup.models.cancel")} cancel`:this.mode==="model-picker"?`type to search \xB7 ${this.label("crtr.setup.models.commit")} select \xB7 tab all/scoped \xB7 ${this.label("crtr.setup.models.cancel")} cancel`:this.mode==="thinking-picker"?`\u2191/\u2193 level \xB7 ${this.label("crtr.setup.models.commit")} set \xB7 ${this.label("crtr.setup.models.cancel")} cancel`:this.mode==="route-delete"?`${this.label("crtr.setup.confirm.accept")} delete \xB7 ${this.label("crtr.setup.confirm.back")} cancel`:this.mode==="route-form"?typeof this.routeForm?.editing=="string"?"type a value \xB7 enter save \xB7 esc cancel":`${this.label("crtr.setup.list-down")}/${this.label("crtr.setup.list-up")} field \xB7 ${this.label("crtr.setup.models.open")} edit \xB7 ${this.label("crtr.setup.models.cancel")} back`:""}renderChoicePicker(){const e=this.choice;if(!e)return[o.fg("warning","No setting selected.")];const t=[o.fg("accent",o.bold(e.title)),o.fg("dim",e.subtitle),""];for(const[i,r]of e.options.entries()){const s=i===this.choiceIndex,n=s?o.fg("accent","\u25B6"):" ",c=e.label(r);t.push(`${n} ${s?o.fg("accent",`[${c}]`):o.fg("dim",` ${c} `)}`)}return t}renderRouteForm(e){const t=this.routeForm;if(!t)return[o.fg("warning","No route selected.")];const i=this.currentTarget(),r=[o.fg("accent",o.bold(t.existing===null?"New provider route":`Provider route: ${t.existing}`)),o.fg("dim",`${i.label} \xB7 ${S(i.root,"config.json")}`),""],s=20;for(const[n,c]of t.fields.entries()){const l=n===t.index,u=l?o.fg("accent","\u25B6"):" ";let m,a;if(c.kind==="text"){if(m=c.label,a=t.text[c.key]||"\u2014",l&&t.editing===c.key){const K=Math.max(8,e-s-4);a=this.routeInput.render(K)[0]??""}}else c.kind==="provider"?(m=c.label,a=t.providerId||"\u2014"):c.kind==="cell"?(m=c.strength,a=G(t.models[c.strength])):c.kind==="save"?(m="",a="Save route"):(m="",a="Delete route");const C=a==="\u2014",T=l?o.fg("accent",`[${a}]`):o.fg(C?"warning":"dim",` ${a} `);r.push(`${u} ${f(m,s)}${T}`)}return this.notice&&r.push("",o.fg("warning",this.notice)),r}renderRouteDelete(e){const t=this.routeForm?.existing??"this route",i=this.currentTarget(),r=Oe(`This removes the entry from ${i.label}. Any "${t}" declared by a lower-precedence config becomes effective again; this does not guarantee the route is gone.`,e).map(s=>o.fg("warning",s));return[o.fg("accent",o.bold(`Delete provider route: ${t}`)),o.fg("dim",S(i.root,"config.json")),"",...r,"",o.fg("dim",`${this.label("crtr.setup.confirm.accept")} delete ${this.label("crtr.setup.confirm.back")} cancel`)]}fitBody(e,t,i){if(e.length<=i)return e;const r=Math.min(ne,e.length-i),s=e.slice(r);if(s.length<=i)return s;const n=Math.max(0,t-r),c=Math.max(0,Math.min(n-i+2,s.length-i));return s.slice(c,c+i)}render(e,t){const i=Math.max(1,t),r=y(d=>Fe(d,e),"frame");if(this.mode==="dimension-picker")return r(this.fitBody(this.renderChoicePicker(),ne+this.choiceIndex,i));if(this.mode==="model-picker")return r(U(this.modelSelector?.render(e)??[],i));if(this.mode==="thinking-picker")return r(U(this.thinkingSelector?.render(e)??[],i));if(this.mode==="route-form"){const d=3+(this.routeForm?.index??0);return r(this.fitBody(this.renderRouteForm(e),d,i))}if(this.mode==="route-delete")return r(U(this.renderRouteDelete(e),i));let s=0;const n=[o.fg("accent",o.bold("Models")),o.fg("dim","global user defaults \xB7 project/profile scopes can shadow these"),""],c=this.currentRow(),l=c.section==="ladder"&&c.kind==="strength",u=Math.max(1,e),m=Math.max(12,Math.min(20,Math.floor(u*.24))),a=this.providerKeys.length,C=Math.max(1,u-2-m),T=12,K=Math.max(1,Math.floor((C+1)/(T+1))),b=Math.min(a,K),N=Math.max(T,Math.floor((C-(b-1))/b)),J=l?Math.min(this.column,a-1):0,F=Math.max(0,Math.min(J>=b?J-b+1:0,a-b)),_=F+b,X=this.providerKeys.map((d,h)=>({provider:d,column:h})).slice(F,_),Y=F>0,z=_<a,he=Y||z?` ${o.fg("dim",`${Y?"\u2039 ":""}${F+1}\u2013${_} of ${a}${z?" \u203A":""}`)}`:"",O=this.currentTarget();n.push(`${o.fg("accent","Editing config")} ${o.fg("accent",`[${O.label}]`)}${o.fg("dim",` ${this.targetIndex+1}/${this.targets.length}`)}`),n.push(o.fg("muted",S(O.root,"config.json")),""),n.push(o.fg("accent","Strength ladders")+he);const le=q(void 0,this.ladders).provider,W=this.rows.find(d=>d.section==="ladder"&&d.kind==="defaultProvider")===c;W&&(s=n.length),n.push(`${W?o.fg("accent","\u25B6"):" "} ${f(W?o.fg("accent","Default provider"):"Default provider",20)} ${o.fg("success",le)}`);const ue=y((d,h)=>{const g=f(o.bold(ce[d]),N);return l&&this.column===h?o.fg("accent",g):o.fg("dim",g)},"providerHeading"),ae=y((d,h)=>{const g=f(V(d,Math.max(1,N-2)),Math.max(1,N-2));return h?o.fg("accent",`[${g}]`):o.fg("dim",` ${g} `)},"ladderCell");n.push(`${" ".repeat(2)}${f(o.fg("dim","Strength"),m)}${X.map(({provider:d,column:h})=>ue(d,h)).join(" ")}`);for(const d of this.rows){if(d.section!=="ladder"||d.kind!=="strength")continue;const h=d===c,g=h?o.fg("accent","\u25B6"):" ";h&&(s=n.length);const $=X.map(({provider:v,column:R})=>{const w=this.targetLadderOverride(v,d.strength)?o.fg("warning","\u2022"):" ";return ae(`${w}${G(this.ladders[v][d.strength])}`,h&&R===this.column)});n.push(`${g} ${f(d.strength,m)}${$.join(" ")}`)}n.push("",o.fg("accent","Provider routes")),n.push(o.fg("dim",`${o.fg("warning","\u2022")} override in ${O.label} \xB7 a declared route replaces the ladders above at launch \xB7 id, then family \xB7 source \xB7 provider`));const A=Math.max(10,Math.floor((u-8)/4));n.push(`${" ".repeat(4)}${k.map(d=>f(o.fg("dim",d),A)).join(" ")}`),this.routeIds().length===0&&n.push(o.fg("dim"," No routes declared \u2014 the ladders above are used."));for(const d of this.rows){if(d.section!=="route"||d.routeId===null)continue;const h=d.routeId,g=this.modelRoutes[h],$=g??this.legacyModelRoutes[h],v=d===c;v&&(s=n.length);const R=v?o.fg("accent","\u25B6"):" ",w=this.rawTarget?.modelRoutes?.[h]!==void 0?o.fg("warning","\u2022"):" ",E=g?"":o.fg("warning"," \xB7 incomplete"),D=o.fg("dim",`${$.family} \xB7 ${$.credentialSource} \xB7 ${$.providerId}`);n.push(`${R} ${w}${o.fg(v?"accent":"dim",h)} ${D}${E}`);const x=k.map(fe=>{const Z=$.models[fe],me=f(V(G(Z),A),A);return o.fg(Z===void 0?"warning":"dim",me)});n.push(`${" ".repeat(4)}${x.join(" ")}`)}const B=this.rows.find(d=>d.section==="route"&&d.routeId===null)===c;B&&(s=n.length),n.push(`${B?o.fg("accent","\u25B6"):" "} ${o.fg(B?"accent":"dim","+ New route")}`),n.push("",o.fg("accent","Kind defaults")),n.push(o.fg("dim",`${o.fg("warning","\u2022")} override in ${O.label} \xB7 orchestrator inherits base until you set it`));const H=16,I=12,M=9,Q=I+1+M,L=y((d,h,g,$)=>{const v=f(V(d,Math.max(1,h-2)),Math.max(1,h-2));return g?o.fg("accent",`[${v}]`):$?o.fg("muted",` ${v} `):o.fg("dim",` ${v} `)},"cell");n.push(`${" ".repeat(2+H)}${f(o.bold(o.fg("dim","Base")),Q)} ${f(o.bold(o.fg("dim","Orchestrator")),Q)}`),n.push(`${" ".repeat(2)}${f(o.fg("dim","Kind"),H)}${f(o.fg("dim","Family"),I)} ${f(o.fg("dim","Strength"),M)} ${f(o.fg("dim","Family"),I)} ${f(o.fg("dim","Strength"),M)}`);for(const d of this.rows){if(d.section!=="kind")continue;const h=d===c,g=h?o.fg("accent","\u25B6"):" ";h&&(s=n.length);const $=this.kinds[d.name],v=this.portableSelection($?.model),R=$?.orchestratorModel===void 0,w=this.portableSelection($?.orchestratorModel??$?.model),E=this.targetKindOverride(d.name,!1)?o.fg("warning","\u2022"):" ",D=this.targetKindOverride(d.name,!0)?o.fg("warning","\u2022"):" ",x=[L(`${E}${this.familyLabel(v.family)}`,I,h&&this.column===0,!1),L(`${E}${v.strength}`,M,h&&this.column===1,!1),L(`${D}${this.familyLabel(w.family)}`,I,h&&this.column===2,R),L(`${D}${w.strength}`,M,h&&this.column===3,R)];n.push(`${g} ${f(d.name,H)}${x[0]} ${x[1]} ${x[2]} ${x[3]}`)}return this.notice&&n.push("",o.fg("warning",this.notice)),r(this.fitBody(n,s,i))}}export{Xe as ModelsPanel};
1
+ var ge=Object.defineProperty;var v=(p,e)=>ge(p,"name",{value:e,configurable:!0});import{envProfileId as pe}from"../../../shared/env.js";import{ModelSelectorComponent as $e,ThinkingSelectorComponent as ee}from"@earendil-works/pi-coding-agent";import{Input as ye,truncateToWidth as V}from"@earendil-works/pi-tui";import{basename as ve,dirname as ke,join as S}from"node:path";import{ANTHROPIC_PROVIDER_ID as be,OPENAI_CODEX_PROVIDER_ID as Re,isManagedProvider as we,readSubscriptionPool as xe}from"../../../core/subscription-state.js";import{readRawConfigAtRoot as P,persistDefaultKindModel as Me,persistModelLadders as te,persistModelRoute as ie,readMergedLaunchConfig as re}from"../../../core/config.js";import{findProjectScopeRoots as Ie,userScopeRoot as Se}from"../../../core/scope.js";import{loadProfileManifest as Pe,profileMemoryDir as Ce}from"../../../core/profiles/manifest.js";import{configuredLadderProviders as Te,inferPortableModelSelection as q,MODEL_PROVIDER_KEYS as oe,MODEL_STRENGTHS as k,THINKING_SUFFIXES as se}from"../../../core/runtime/model-selection.js";import{fitTail as U,padAnsi as f,renderRows as Fe,theme as o,wrapText as Oe}from"../../../core/tui/panel.js";const ne=3,Le={anthropic:be,openai:Re},ce={anthropic:"Anthropic",openai:"OpenAI"},de=[{mode:"base",dimension:"family"},{mode:"base",dimension:"strength"},{mode:"orchestrator",dimension:"family"},{mode:"orchestrator",dimension:"strength"}];function Ee(){const p=Se(),e=pe()||null;let t;if(e!==null)try{const s=Pe(e);t={label:`Profile: ${s.manifest.name}`,root:Ce(s.profileId)}}catch{}const i=Ie(process.cwd(),e),r=i.map(s=>({label:`Project: ${ve(ke(s))}`,root:s}));return{targets:[{label:"User",root:p},...t?[t]:[],...r],precedenceRoots:[...i,...t?[t.root]:[],p]}}v(Ee,"modelConfigTargets");function j(p){if(!p)return{};const e=p.trim(),t=e.indexOf("/"),i=t===-1?void 0:e.slice(0,t),r=t===-1?e:e.slice(t+1),s=r.match(/^(.*?):(off|minimal|low|medium|high|xhigh|max)$/i);return{provider:i,id:s?s[1]:r,level:s?s[2].toLowerCase():void 0}}v(j,"parseModelRef");function G(p){if(!p)return"\u2014";const e=p.indexOf("/");return e===-1?p:p.slice(e+1)}v(G,"shortRef");class Xe{static{v(this,"ModelsPanel")}tui;runtime;registry;matches;label;mode="list";ladders;modelRoutes;legacyModelRoutes;kinds;providerKeys=oe;targets;precedenceRoots;targetIndex=0;rawTarget;rows=[];selected=0;column=0;notice="";modelSelector;thinkingSelector;pending;choice;choiceIndex=0;routeForm;routeInput=new ye;pendingRouteCell;onChange;constructor(e,t,i,r,s){this.tui=e,this.runtime=t,this.registry=i,this.matches=r,this.label=s;const n=Ee();this.targets=n.targets,this.precedenceRoots=n.precedenceRoots,this.rawTarget=P(this.currentTarget().root);const c=re();this.ladders=c.modelLadders,this.modelRoutes=c.modelRoutes??{},this.legacyModelRoutes=c.legacyModelRoutes??{},this.kinds=c.kinds,this.providerKeys=this.offeredProviders(),this.rows=this.buildRows(),this.routeInput.onSubmit=l=>{const u=this.routeForm;!u||u.editing===null||(u.text[u.editing]=l.trim(),u.editing=null,this.routeInput.focused=!1,this.notify())},this.routeInput.onEscape=()=>{this.routeForm&&(this.routeForm.editing=null,this.routeInput.focused=!1,this.notify())}}offeredProviders(){try{return Te(e=>we(e)&&xe(e).length>0||this.registry.getProviderAuthStatus(e).configured,this.ladders)}catch{return oe}}currentTarget(){return this.targets[this.targetIndex]}cycleTarget(){this.targetIndex=(this.targetIndex+1)%this.targets.length,this.rawTarget=P(this.currentTarget().root),this.notice="",this.notify()}shadowingPath(e){for(const t of this.precedenceRoots){if(t===this.currentTarget().root)break;const i=P(t);if(i&&e(i))return S(t,"config.json")}}savedButShadowed(e){return`Saved to ${this.currentTarget().label}; overridden by ${e??"a more specific config"}`}routeIds(){return[...new Set([...Object.keys(this.modelRoutes),...Object.keys(this.legacyModelRoutes)])]}routeFamilies(){return[...new Set(this.routeIds().map(e=>(this.modelRoutes[e]??this.legacyModelRoutes[e]).family))]}buildRows(){const e=[{section:"ladder",kind:"defaultProvider"}];for(const t of k)e.push({section:"ladder",kind:"strength",strength:t});for(const t of this.routeIds())e.push({section:"route",routeId:t});e.push({section:"route",routeId:null});for(const t of Object.keys(this.kinds))t.includes("/")||e.push({section:"kind",name:t});return e}reload(){const e=re();this.ladders=e.modelLadders,this.modelRoutes=e.modelRoutes??{},this.legacyModelRoutes=e.legacyModelRoutes??{},this.kinds=e.kinds,this.rawTarget=P(this.currentTarget().root),this.providerKeys=this.offeredProviders(),this.rows=this.buildRows(),this.selected=Math.min(this.selected,this.rows.length-1),this.clampColumn()}refresh(){this.reload(),this.notify()}notify(){this.onChange?.(),this.tui.requestRender()}isPickerOpen(){return this.mode!=="list"}currentRow(){return this.rows[Math.min(this.selected,this.rows.length-1)]}columnsFor(e){return e.section==="ladder"?e.kind==="strength"?this.providerKeys.length:1:e.section==="route"?1:de.length}clampColumn(){this.column=Math.min(this.column,this.columnsFor(this.currentRow())-1)}handleInput(e){if(this.mode==="route-form"){const t=this.routeForm;return t?t.editing!==null?(this.routeInput.handleInput(e),!0):this.matches("crtr.setup.models.cancel",e)?(this.closeRouteForm(),!0):this.matches("crtr.setup.list-down",e)?(t.index=Math.min(t.fields.length-1,t.index+1),this.notice="",!0):this.matches("crtr.setup.list-up",e)?(t.index=Math.max(0,t.index-1),this.notice="",!0):((this.matches("crtr.setup.models.open",e)||this.matches("crtr.setup.models.commit",e))&&this.activateRouteField(),!0):(this.mode="list",!0)}if(this.mode==="route-delete")return this.matches("crtr.setup.confirm.accept",e)?(this.deleteRoute(),!0):(this.matches("crtr.setup.confirm.back",e)&&(this.mode="route-form",this.notify()),!0);if(this.mode==="dimension-picker")return this.matches("crtr.setup.models.commit",e)?(this.commitChoice(),!0):this.matches("crtr.setup.models.cancel",e)?(this.closePicker(),!0):this.matches("crtr.setup.list-down",e)?(this.choiceIndex=Math.min((this.choice?.options.length??1)-1,this.choiceIndex+1),!0):(this.matches("crtr.setup.list-up",e)&&(this.choiceIndex=Math.max(0,this.choiceIndex-1)),!0);if(this.mode==="model-picker"){const t=this.matches("crtr.setup.models.commit",e)?"\r":this.matches("crtr.setup.models.cancel",e)?"\x1B":e;return this.modelSelector?.handleInput(t),!0}if(this.mode==="thinking-picker"){const t=this.matches("crtr.setup.models.commit",e)?"\r":this.matches("crtr.setup.models.cancel",e)?"\x1B":e;return this.thinkingSelector?.getSelectList().handleInput(t),!0}return this.matches("crtr.setup.list-down",e)?(this.selected=Math.min(this.rows.length-1,this.selected+1),this.clampColumn(),this.notice="",!0):this.matches("crtr.setup.list-up",e)?(this.selected=Math.max(0,this.selected-1),this.clampColumn(),this.notice="",!0):this.matches("crtr.setup.cell-previous",e)?(this.column=Math.max(0,this.column-1),!0):this.matches("crtr.setup.cell-next",e)?(this.column=Math.min(this.columnsFor(this.currentRow())-1,this.column+1),!0):this.matches("crtr.setup.models.scope-next",e)?(this.cycleTarget(),!0):this.matches("crtr.setup.models.open",e)?(this.activateCell(),!0):!1}activateCell(){const e=this.currentRow();if(this.notice="",e.section==="ladder"&&e.kind==="defaultProvider"){const t=q(void 0,this.ladders).provider,i=this.providerKeys,r=i[(Math.max(0,i.indexOf(t))+1)%i.length];if(r===t)return;try{te(this.currentTarget().root,{defaultProvider:r})}catch(s){this.notice=`Could not save: ${s instanceof Error?s.message:String(s)}`,this.notify();return}if(this.reload(),(this.ladders.defaultProvider??"anthropic")!==r){const s=this.shadowingPath(n=>n.modelLadders?.defaultProvider!==void 0);this.notice=this.savedButShadowed(s)}this.notify();return}if(e.section==="ladder"&&e.kind==="strength"){this.openModelPicker(this.providerKeys[this.column],e.strength);return}if(e.section==="route"){this.openRouteForm(e.routeId);return}if(e.section==="kind"){const t=de[this.column];if(!t)return;this.openDimensionPicker(e.name,t.mode,t.dimension)}}portableSelection(e){if(e!==void 0){const i=e.lastIndexOf("/"),r=i===-1?"":e.slice(0,i),s=i===-1?"":e.slice(i+1);if(this.routeFamilies().includes(r)&&k.includes(s))return{family:r,strength:s}}const t=q(e,this.ladders);return{family:t.provider,strength:t.strength}}familyLabel(e){return e==="anthropic"||e==="openai"?ce[e]:e}familyOptions(){return[...new Set([...this.providerKeys,...this.routeFamilies()])]}kindSelection(e,t){const i=this.kinds[e],r=t==="orchestrator"?i?.orchestratorModel??i?.model:i?.model;return this.portableSelection(r)}openDimensionPicker(e,t,i){const r=this.kindSelection(e,t),s=i==="family"?this.familyOptions():k,n=i==="family"?r.family:r.strength,c=t==="orchestrator"?"orchestrator":"base",l=i==="family"?`strength ${r.strength}`:`family ${this.familyLabel(r.family)}`;this.choice={title:`Choose ${c} ${i}`,subtitle:`${e} \xB7 keeps ${c} ${l}`,options:s,label:v(u=>i==="family"?this.familyLabel(u):u,"label"),commit:v(u=>{const m=i==="family"?u:r.family,a=i==="strength"?u:r.strength;this.writeKindSelection(e,t,m,a)},"commit")},this.choiceIndex=Math.max(0,s.indexOf(n)),this.mode="dimension-picker",this.notify()}writeKindSelection(e,t,i,r){const s=`${i}/${r}`;try{Me({root:this.currentTarget().root,kind:e,model:s,orchestrator:t==="orchestrator"})}catch(l){this.notice=`Could not save: ${l instanceof Error?l.message:String(l)}`;return}this.reload();const n=this.kinds[e];if((t==="orchestrator"?n?.orchestratorModel:n?.model)!==s){const l=t==="orchestrator"?"orchestratorModel":"model",u=this.shadowingPath(m=>m.kinds?.[e]?.[l]!==void 0);this.notice=this.savedButShadowed(u)}}commitChoice(){const e=this.choice,t=e?.options[this.choiceIndex];e&&t!==void 0&&e.commit(t),this.closePicker()}openRouteForm(e){const t=e===null?void 0:this.modelRoutes[e]??this.legacyModelRoutes[e],i=[...e===null?[{kind:"text",key:"routeId",label:"Route id"}]:[],{kind:"text",key:"family",label:"Family"},{kind:"text",key:"credentialSource",label:"Credential source"},{kind:"provider",label:"Provider id"},...k.map(r=>({kind:"cell",strength:r})),{kind:"save"},...e===null?[]:[{kind:"delete"}]];this.routeForm={existing:e,text:{routeId:e??"",family:t?.family??"",credentialSource:t?.credentialSource??""},providerId:t?.providerId??"",models:{...t?.models},fields:i,index:0,editing:null},this.mode="route-form",this.notice="",this.notify()}closeRouteForm(){this.routeInput.focused=!1,this.routeForm=void 0,this.mode="list",this.notice="",this.notify()}activateRouteField(){const e=this.routeForm,t=e?.fields[e.index];if(!(!e||!t)){if(t.kind==="text"){e.editing=t.key,this.routeInput.setValue(e.text[t.key]),this.routeInput.handleInput(""),this.routeInput.focused=!0,this.notify();return}if(t.kind==="provider"){const i=[...new Set([...this.registry.getAll().map(r=>r.provider),...e.providerId?[e.providerId]:[]])].sort();this.choice={title:"Choose provider id",subtitle:"Route cells must all belong to this registry provider",options:i,label:v(r=>r,"label"),commit:v(r=>this.setRouteProvider(r),"commit")},this.choiceIndex=Math.max(0,i.indexOf(e.providerId)),this.mode="dimension-picker",this.notify();return}if(t.kind==="cell"){this.openRouteCell(t.strength);return}if(t.kind==="save"){this.saveRoute();return}this.mode="route-delete",this.notify()}}setRouteProvider(e){const t=this.routeForm;if(!t)return;t.providerId=e;const i=[];for(const r of k){const s=t.models[r];s!==void 0&&!s.startsWith(`${e}/`)&&(delete t.models[r],i.push(r))}this.notice=i.length===0?"":`Cleared ${i.join(", ")} because those models belong to another provider.`}openRouteCell(e){const t=this.routeForm;if(!t)return;if(!t.providerId){this.notice="Choose the provider id first",this.notify();return}const i=this.registry.getAll().filter(n=>n.provider===t.providerId);if(i.length===0){this.notice=`No models registered for provider "${t.providerId}" \u2014 this route cannot be edited here.`,this.notify();return}const r=j(t.models[e]),s=r.provider&&r.id?this.registry.find(r.provider,r.id):void 0;this.pendingRouteCell={strength:e},this.showModelSelector(i,s,n=>this.onRouteModelPicked(n))}onRouteModelPicked(e){const t=this.pendingRouteCell,i=this.routeForm;if(!t||!i){this.closePicker();return}if(e.provider!==i.providerId){this.notice=`That is a ${e.provider} model \u2014 pick a ${i.providerId} model for this route.`,this.closePicker();return}if(t.model=e,e.reasoning){const r=j(i.models[t.strength]).level??"medium";this.thinkingSelector=new ee(r,[...se],s=>this.onThinkingPicked(s),()=>this.closePicker()),this.modelSelector=void 0,this.mode="thinking-picker",this.notify();return}i.models[t.strength]=`${e.provider}/${e.id}`,this.closePicker()}saveRoute(){const e=this.routeForm;if(!e)return;const t=e.text.routeId.trim();if(!t){this.notice="Route id is required.",this.notify();return}if(!e.text.family.trim()){this.notice="Family is required.",this.notify();return}if(!e.text.credentialSource.trim()){this.notice="Credential source is required.",this.notify();return}if(!e.providerId.trim()){this.notice="Provider id is required.",this.notify();return}const i=k.filter(n=>e.models[n]===void 0);if(i.length>0){this.notice=`Choose models for ${i.join(", ")} before saving.`,this.notify();return}const r={family:e.text.family.trim(),credentialSource:e.text.credentialSource.trim(),providerId:e.providerId.trim(),models:{ultra:e.models.ultra,strong:e.models.strong,medium:e.models.medium,light:e.models.light}};try{ie(this.currentTarget().root,t,r)}catch(n){this.notice=`Could not save: ${n instanceof Error?n.message:String(n)}`,this.notify();return}this.routeForm=void 0,this.mode="list",this.reload();const s=this.rows.findIndex(n=>n.section==="route"&&n.routeId===t);if(s>=0&&(this.selected=s),JSON.stringify(this.modelRoutes[t])!==JSON.stringify(r)){const n=this.shadowingPath(c=>c.modelRoutes?.[t]!==void 0);this.notice=this.savedButShadowed(n)}else this.notice=`Saved route "${t}" to ${this.currentTarget().label}.`;this.notify()}declaringPath(e){for(const t of this.precedenceRoots){if(t===this.currentTarget().root)continue;if(P(t)?.modelRoutes?.[e]!==void 0)return S(t,"config.json")}}deleteRoute(){const e=this.routeForm?.existing;if(!e){this.mode="route-form",this.notify();return}try{ie(this.currentTarget().root,e,void 0)}catch(i){this.mode="route-form",this.notice=`Could not delete: ${i instanceof Error?i.message:String(i)}`,this.notify();return}const t=this.declaringPath(e);this.routeForm=void 0,this.mode="list",this.reload(),this.notice=t?`Removed route "${e}" from ${this.currentTarget().label}; it is still declared by ${t}.`:`Removed route "${e}" from ${this.currentTarget().label}.`,this.notify()}showModelSelector(e,t,i){this.modelSelector=new $e(this.tui,t,this.runtime,e.map(r=>({model:r})),i,()=>this.closePicker()),this.modelSelector.focused=!0,this.mode="model-picker",this.notify()}openModelPicker(e,t){const i=Le[e],r=this.registry,s=j(this.ladders[e][t]),n=s.provider&&s.id?r.find(s.provider,s.id):void 0,c=r.getAvailable().filter(l=>l.provider===i);if(c.length===0){this.notice=`No ${e} models available \u2014 sign in first.`,this.notify();return}this.pending={providerKey:e,strength:t,expectedRuntime:i},this.showModelSelector(c,n,l=>this.onModelPicked(l))}onModelPicked(e){if(!this.pending){this.closePicker();return}if(e.provider!==this.pending.expectedRuntime){this.notice=`That is a ${e.provider} model \u2014 pick an ${this.pending.providerKey} model for this column.`,this.closePicker();return}if(this.pending.model=e,e.reasoning){const t=j(this.ladders[this.pending.providerKey][this.pending.strength]).level??"medium";this.thinkingSelector=new ee(t,[...se],i=>this.onThinkingPicked(i),()=>this.closePicker()),this.modelSelector=void 0,this.mode="thinking-picker",this.notify();return}this.writeLadder(e,void 0),this.closePicker()}onThinkingPicked(e){if(this.pendingRouteCell?.model&&this.routeForm){const{model:t,strength:i}=this.pendingRouteCell;this.routeForm.models[i]=`${t.provider}/${t.id}${e!=="off"?`:${e}`:""}`}else this.pending?.model&&this.writeLadder(this.pending.model,e);this.closePicker()}writeLadder(e,t){if(!this.pending)return;const i=`${e.provider}/${e.id}${t&&t!=="off"?`:${t}`:""}`,{providerKey:r,strength:s}=this.pending;try{te(this.currentTarget().root,{[r]:{[s]:i}})}catch(n){this.notice=`Could not save: ${n instanceof Error?n.message:String(n)}`;return}if(this.reload(),this.ladders[r][s]!==i){const n=this.shadowingPath(c=>c.modelLadders?.[r]?.[s]!==void 0);this.notice=this.savedButShadowed(n)}}closePicker(){this.mode=this.routeForm!==void 0?"route-form":"list",this.modelSelector=void 0,this.thinkingSelector=void 0,this.pending=void 0,this.pendingRouteCell=void 0,this.choice=void 0,this.notify()}dispose(){this.routeForm=void 0,this.closePicker()}targetLadderOverride(e,t){return this.rawTarget?.modelLadders?.[e]?.[t]!==void 0}targetKindOverride(e,t){const i=this.rawTarget?.kinds,r=t?"orchestratorModel":"model";return i?.[e]?.[r]!==void 0}footerHint(){return this.mode==="dimension-picker"?`${this.label("crtr.setup.list-down")}/${this.label("crtr.setup.list-up")} choice \xB7 ${this.label("crtr.setup.models.commit")} save \xB7 ${this.label("crtr.setup.models.cancel")} cancel`:this.mode==="model-picker"?`type to search \xB7 ${this.label("crtr.setup.models.commit")} select \xB7 tab all/scoped \xB7 ${this.label("crtr.setup.models.cancel")} cancel`:this.mode==="thinking-picker"?`\u2191/\u2193 level \xB7 ${this.label("crtr.setup.models.commit")} set \xB7 ${this.label("crtr.setup.models.cancel")} cancel`:this.mode==="route-delete"?`${this.label("crtr.setup.confirm.accept")} delete \xB7 ${this.label("crtr.setup.confirm.back")} cancel`:this.mode==="route-form"?typeof this.routeForm?.editing=="string"?"type a value \xB7 enter save \xB7 esc cancel":`${this.label("crtr.setup.list-down")}/${this.label("crtr.setup.list-up")} field \xB7 ${this.label("crtr.setup.models.open")} edit \xB7 ${this.label("crtr.setup.models.cancel")} back`:""}renderChoicePicker(){const e=this.choice;if(!e)return[o.fg("warning","No setting selected.")];const t=[o.fg("accent",o.bold(e.title)),o.fg("dim",e.subtitle),""];for(const[i,r]of e.options.entries()){const s=i===this.choiceIndex,n=s?o.fg("accent","\u25B6"):" ",c=e.label(r);t.push(`${n} ${s?o.fg("accent",`[${c}]`):o.fg("dim",` ${c} `)}`)}return t}renderRouteForm(e){const t=this.routeForm;if(!t)return[o.fg("warning","No route selected.")];const i=this.currentTarget(),r=[o.fg("accent",o.bold(t.existing===null?"New provider route":`Provider route: ${t.existing}`)),o.fg("dim",`${i.label} \xB7 ${S(i.root,"config.json")}`),""],s=20;for(const[n,c]of t.fields.entries()){const l=n===t.index,u=l?o.fg("accent","\u25B6"):" ";let m,a;if(c.kind==="text"){if(m=c.label,a=t.text[c.key]||"\u2014",l&&t.editing===c.key){const K=Math.max(8,e-s-4);a=this.routeInput.render(K)[0]??""}}else c.kind==="provider"?(m=c.label,a=t.providerId||"\u2014"):c.kind==="cell"?(m=c.strength,a=G(t.models[c.strength])):c.kind==="save"?(m="",a="Save route"):(m="",a="Delete route");const C=a==="\u2014",T=l?o.fg("accent",`[${a}]`):o.fg(C?"warning":"dim",` ${a} `);r.push(`${u} ${f(m,s)}${T}`)}return this.notice&&r.push("",o.fg("warning",this.notice)),r}renderRouteDelete(e){const t=this.routeForm?.existing??"this route",i=this.currentTarget(),r=Oe(`This removes the entry from ${i.label}. Any "${t}" declared by a lower-precedence config becomes effective again; this does not guarantee the route is gone.`,e).map(s=>o.fg("warning",s));return[o.fg("accent",o.bold(`Delete provider route: ${t}`)),o.fg("dim",S(i.root,"config.json")),"",...r,"",o.fg("dim",`${this.label("crtr.setup.confirm.accept")} delete ${this.label("crtr.setup.confirm.back")} cancel`)]}fitBody(e,t,i){if(e.length<=i)return e;const r=Math.min(ne,e.length-i),s=e.slice(r);if(s.length<=i)return s;const n=Math.max(0,t-r),c=Math.max(0,Math.min(n-i+2,s.length-i));return s.slice(c,c+i)}render(e,t){const i=Math.max(1,t),r=v(d=>Fe(d,e),"frame");if(this.mode==="dimension-picker")return r(this.fitBody(this.renderChoicePicker(),ne+this.choiceIndex,i));if(this.mode==="model-picker")return r(U(this.modelSelector?.render(e)??[],i));if(this.mode==="thinking-picker")return r(U(this.thinkingSelector?.render(e)??[],i));if(this.mode==="route-form"){const d=3+(this.routeForm?.index??0);return r(this.fitBody(this.renderRouteForm(e),d,i))}if(this.mode==="route-delete")return r(U(this.renderRouteDelete(e),i));let s=0;const n=[o.fg("accent",o.bold("Models")),o.fg("dim","global user defaults \xB7 project/profile scopes can shadow these"),""],c=this.currentRow(),l=c.section==="ladder"&&c.kind==="strength",u=Math.max(1,e),m=Math.max(12,Math.min(20,Math.floor(u*.24))),a=this.providerKeys.length,C=Math.max(1,u-2-m),T=12,K=Math.max(1,Math.floor((C+1)/(T+1))),b=Math.min(a,K),N=Math.max(T,Math.floor((C-(b-1))/b)),J=l?Math.min(this.column,a-1):0,F=Math.max(0,Math.min(J>=b?J-b+1:0,a-b)),_=F+b,X=this.providerKeys.map((d,h)=>({provider:d,column:h})).slice(F,_),Y=F>0,z=_<a,he=Y||z?` ${o.fg("dim",`${Y?"\u2039 ":""}${F+1}\u2013${_} of ${a}${z?" \u203A":""}`)}`:"",O=this.currentTarget();n.push(`${o.fg("accent","Editing config")} ${o.fg("accent",`[${O.label}]`)}${o.fg("dim",` ${this.targetIndex+1}/${this.targets.length}`)}`),n.push(o.fg("muted",S(O.root,"config.json")),""),n.push(o.fg("accent","Strength ladders")+he);const le=q(void 0,this.ladders).provider,W=this.rows.find(d=>d.section==="ladder"&&d.kind==="defaultProvider")===c;W&&(s=n.length),n.push(`${W?o.fg("accent","\u25B6"):" "} ${f(W?o.fg("accent","Default provider"):"Default provider",20)} ${o.fg("success",le)}`);const ue=v((d,h)=>{const g=f(o.bold(ce[d]),N);return l&&this.column===h?o.fg("accent",g):o.fg("dim",g)},"providerHeading"),ae=v((d,h)=>{const g=f(V(d,Math.max(1,N-2)),Math.max(1,N-2));return h?o.fg("accent",`[${g}]`):o.fg("dim",` ${g} `)},"ladderCell");n.push(`${" ".repeat(2)}${f(o.fg("dim","Strength"),m)}${X.map(({provider:d,column:h})=>ue(d,h)).join(" ")}`);for(const d of this.rows){if(d.section!=="ladder"||d.kind!=="strength")continue;const h=d===c,g=h?o.fg("accent","\u25B6"):" ";h&&(s=n.length);const $=X.map(({provider:y,column:R})=>{const w=this.targetLadderOverride(y,d.strength)?o.fg("warning","\u2022"):" ";return ae(`${w}${G(this.ladders[y][d.strength])}`,h&&R===this.column)});n.push(`${g} ${f(d.strength,m)}${$.join(" ")}`)}n.push("",o.fg("accent","Provider routes")),n.push(o.fg("dim",`${o.fg("warning","\u2022")} override in ${O.label} \xB7 a declared route replaces the ladders above at launch \xB7 id, then family \xB7 source \xB7 provider`));const A=Math.max(10,Math.floor((u-8)/4));n.push(`${" ".repeat(4)}${k.map(d=>f(o.fg("dim",d),A)).join(" ")}`),this.routeIds().length===0&&n.push(o.fg("dim"," No routes declared \u2014 the ladders above are used."));for(const d of this.rows){if(d.section!=="route"||d.routeId===null)continue;const h=d.routeId,g=this.modelRoutes[h],$=g??this.legacyModelRoutes[h],y=d===c;y&&(s=n.length);const R=y?o.fg("accent","\u25B6"):" ",w=this.rawTarget?.modelRoutes?.[h]!==void 0?o.fg("warning","\u2022"):" ",E=g?"":o.fg("warning"," \xB7 incomplete"),D=o.fg("dim",`${$.family} \xB7 ${$.credentialSource} \xB7 ${$.providerId}`);n.push(`${R} ${w}${o.fg(y?"accent":"dim",h)} ${D}${E}`);const x=k.map(fe=>{const Z=$.models[fe],me=f(V(G(Z),A),A);return o.fg(Z===void 0?"warning":"dim",me)});n.push(`${" ".repeat(4)}${x.join(" ")}`)}const B=this.rows.find(d=>d.section==="route"&&d.routeId===null)===c;B&&(s=n.length),n.push(`${B?o.fg("accent","\u25B6"):" "} ${o.fg(B?"accent":"dim","+ New route")}`),n.push("",o.fg("accent","Kind defaults")),n.push(o.fg("dim",`${o.fg("warning","\u2022")} override in ${O.label} \xB7 orchestrator inherits base until you set it`));const H=16,M=12,I=9,Q=M+1+I,L=v((d,h,g,$)=>{const y=f(V(d,Math.max(1,h-2)),Math.max(1,h-2));return g?o.fg("accent",`[${y}]`):$?o.fg("muted",` ${y} `):o.fg("dim",` ${y} `)},"cell");n.push(`${" ".repeat(2+H)}${f(o.bold(o.fg("dim","Base")),Q)} ${f(o.bold(o.fg("dim","Orchestrator")),Q)}`),n.push(`${" ".repeat(2)}${f(o.fg("dim","Kind"),H)}${f(o.fg("dim","Family"),M)} ${f(o.fg("dim","Strength"),I)} ${f(o.fg("dim","Family"),M)} ${f(o.fg("dim","Strength"),I)}`);for(const d of this.rows){if(d.section!=="kind")continue;const h=d===c,g=h?o.fg("accent","\u25B6"):" ";h&&(s=n.length);const $=this.kinds[d.name],y=this.portableSelection($?.model),R=$?.orchestratorModel===void 0,w=this.portableSelection($?.orchestratorModel??$?.model),E=this.targetKindOverride(d.name,!1)?o.fg("warning","\u2022"):" ",D=this.targetKindOverride(d.name,!0)?o.fg("warning","\u2022"):" ",x=[L(`${E}${this.familyLabel(y.family)}`,M,h&&this.column===0,!1),L(`${E}${y.strength}`,I,h&&this.column===1,!1),L(`${D}${this.familyLabel(w.family)}`,M,h&&this.column===2,R),L(`${D}${w.strength}`,I,h&&this.column===3,R)];n.push(`${g} ${f(d.name,H)}${x[0]} ${x[1]} ${x[2]} ${x[3]}`)}return this.notice&&n.push("",o.fg("warning",this.notice)),r(this.fitBody(n,s,i))}}export{Xe as ModelsPanel};
@@ -49,7 +49,6 @@ export declare class ProfilesPanel implements SetupPanel {
49
49
  private submitName;
50
50
  private submitDir;
51
51
  private cycleMemory;
52
- private setHome;
53
52
  private askRemoveDir;
54
53
  private removeDir;
55
54
  private togglePause;
@@ -1 +1 @@
1
- var L=Object.defineProperty;var g=(m,e)=>L(m,"name",{value:e,configurable:!0});import{envNodeId as R}from"../../../shared/env.js";import{Input as C,matchesKey as I,truncateToWidth as u}from"@earendil-works/pi-tui";import{basename as O}from"node:path";import{PROFILE_PROJECT_MEMORY_VALUES as w}from"../../../api/dto/profiles.js";import{cliClient as N}from"../../api-client.js";import{clearDefaultProfile as E,defaultProfileDirs as F,getDefaultProfileId as H,setDefaultProfileId as S}from"../../../core/profiles/default-binding.js";import{ROOT_PROFILE_ID as P,addProfileProject as v,createProfile as V,listProfiles as A,pauseProfile as U,removeProfileProject as W,renameProfile as B,resumeProfile as J}from"../../../core/profiles/manifest.js";import{tildify as d}from"../../../core/fs-utils.js";import{profileCoversCwd as M}from"../../../core/profiles/select.js";import{padAnsi as l,theme as o,visibleRange as _,wrapText as j}from"../../../core/tui/panel.js";function D(m){if(m===null)return"never used";const e=Date.parse(m);if(Number.isNaN(e))return"used recently";const t=Math.max(0,Math.floor((Date.now()-e)/1e3));if(t<60)return"used just now";const n=Math.floor(t/60);if(n<60)return`used ${n}m ago`;const i=Math.floor(n/60);if(i<24)return`used ${i}h ago`;const s=Math.floor(i/24);if(s<30)return`used ${s}d ago`;const r=Math.floor(s/30);return r<12?`used ${r}mo ago`:`used ${Math.floor(r/12)}y ago`}g(D,"relativeUsed");function T(m){return m instanceof Error?m.message:String(m)}g(T,"messageOf");class ie{static{g(this,"ProfilesPanel")}cwd;onChange;nameInput=new C;dirInput=new C;entries=[];listIndex=0;dirIndex=0;mode="list";openId=null;notice;noticeTone="success";mutating=!1;constructor(e,t){this.cwd=e,this.onChange=t,this.nameInput.onSubmit=()=>{this.submitName(),this.onChange()},this.nameInput.onEscape=()=>{this.mode=this.openId!==null?"detail":"list",this.leaveField(),this.onChange()},this.dirInput.onSubmit=()=>{this.submitDir(),this.onChange()},this.dirInput.onEscape=()=>{this.mode="detail",this.leaveField(),this.onChange()},this.reload()}badge(){return String(this.entries.length)}ownsInput(e){return this.mode==="list"?!1:this.mode==="detail"?I(e,"escape")||I(e,"left"):!0}reload(){const e=g(i=>i.profileId===P?2:M(i,this.cwd)?0:1,"rank"),t=g(i=>i.manifest.last_used_at??"","used");this.entries=A().sort((i,s)=>{const r=e(i)-e(s);if(r!==0)return r;const h=t(s).localeCompare(t(i));return h!==0?h:i.manifest.name.localeCompare(s.manifest.name)}),this.listIndex>=this.entries.length&&(this.listIndex=Math.max(0,this.entries.length-1));const n=this.open();n===null?(this.mode!=="list"&&(this.mode="list"),this.openId=null):this.dirIndex>=n.manifest.projects.length&&(this.dirIndex=Math.max(0,n.manifest.projects.length-1))}selected(){return this.entries[this.listIndex]??null}open(){return this.openId===null?null:this.entries.find(e=>e.profileId===this.openId)??null}currentDir(){return this.open()?.manifest.projects[this.dirIndex]??null}pinnedHere(){return H(this.cwd)}say(e,t="success"){this.notice=e,this.noticeTone=t}attempt(e,t){try{e(),this.reload(),this.say(t)}catch(n){this.say(T(n),"warning")}}handleInput(e,t){const n=this.route(e,t);return n&&this.onChange(),n}route(e,t){switch(this.mode){case"new-name":case"rename":return this.routeText(this.nameInput,e);case"add-dir":return this.routeText(this.dirInput,e);case"confirm-delete":return this.routeConfirm(e,()=>{this.deleteOpen()});case"confirm-remove-dir":return this.routeConfirm(e,()=>this.removeDir());case"detail":return this.routeDetail(e,t);case"list":return this.routeList(e,t)}}routeText(e,t){return e.handleInput(t),!0}routeConfirm(e,t){const n=e.toLowerCase();return n==="y"?t():(n==="n"||I(e,"escape")||I(e,"return"))&&(this.mode=this.openId!==null?"detail":"list",this.say("Cancelled.")),!0}routeList(e,t){if(t?.("crtr.setup.list-down",e)===!0)return this.move(1),!0;if(t?.("crtr.setup.list-up",e)===!0)return this.move(-1),!0;if(t?.("crtr.setup.advance",e)===!0){const n=this.selected();return n!==null&&(this.openId=n.profileId,this.dirIndex=0,this.mode="detail",this.notice=void 0),!0}switch(e.toLowerCase()){case"a":return this.addCwdTo(this.selected());case"d":return this.togglePin();case"n":return this.mode="new-name",this.edit(this.nameInput,O(this.cwd)||"profile"),!0;case"x":return this.askDelete();default:return!1}}routeDetail(e,t){const n=this.open();if(n===null)return this.mode="list",!0;if(I(e,"escape")||I(e,"left"))return this.mode="list",this.notice=void 0,!0;if(t?.("crtr.setup.list-down",e)===!0)return this.moveDir(1),!0;if(t?.("crtr.setup.list-up",e)===!0)return this.moveDir(-1),!0;switch(e.toLowerCase()){case"a":return this.mode="add-dir",this.edit(this.dirInput,this.cwd),!0;case"m":return this.cycleMemory();case"h":return this.setHome();case"x":return this.askRemoveDir();case"r":return this.mode="rename",this.edit(this.nameInput,n.manifest.name),!0;case"p":return this.togglePause();default:return!1}}edit(e,t){e.setValue(t),e.handleInput(""),e.focused=!0,this.notice=void 0}leaveField(){this.nameInput.focused=!1,this.dirInput.focused=!1}move(e){this.entries.length!==0&&(this.listIndex=(this.listIndex+e+this.entries.length)%this.entries.length,this.notice=void 0)}moveDir(e){const t=this.open()?.manifest.projects.length??0;t!==0&&(this.dirIndex=(this.dirIndex+e+t)%t,this.notice=void 0)}addCwdTo(e){return e===null||this.attempt(()=>v(e.profileId,this.cwd,{memory:"content"}),`${d(this.cwd)} now belongs to "${e.manifest.name}".`),!0}togglePin(){const e=this.selected();return e===null||(this.pinnedHere()===e.profileId?(E(this.cwd),this.say(`${d(this.cwd)} no longer defaults to any profile.`)):(S(this.cwd,e.profileId),this.say(`${d(this.cwd)} now starts as "${e.manifest.name}" without asking.`)),this.onChange()),!0}submitName(){const e=this.nameInput.getValue().trim(),t=this.mode==="new-name";if(this.mode=t?"list":"detail",this.leaveField(),e===""){this.say("A profile name cannot be empty.","warning");return}if(t){let i=null;this.attempt(()=>{i=V(e,[{path:this.cwd,memory:"content"}]).profileId},`Created "${e}", owning ${d(this.cwd)}.`);const s=this.entries.findIndex(r=>r.profileId===i);s>=0&&(this.listIndex=s);return}const n=this.open();n!==null&&this.attempt(()=>B(n.profileId,e),`Renamed to "${e}".`)}submitDir(){const e=this.dirInput.getValue().trim(),t=this.open();if(this.mode="detail",this.leaveField(),t!==null){if(e===""){this.say("Type the directory to add.","warning");return}this.attempt(()=>v(t.profileId,e,{memory:"content"}),`${d(e)} added to "${t.manifest.name}".`)}}cycleMemory(){const e=this.open(),t=this.currentDir();if(e===null||t===null)return!0;const n=w[(w.indexOf(t.memory)+1)%w.length];return this.attempt(()=>v(e.profileId,t.path,{memory:n}),`${d(t.path)} discloses up to "${n}".`),!0}setHome(){const e=this.open(),t=this.currentDir();return e===null||t===null||this.attempt(()=>v(e.profileId,t.path,{memory:t.memory,home:!0}),`Nodes under "${e.manifest.name}" now run in ${d(t.path)}.`),!0}askRemoveDir(){return this.currentDir()===null?(this.say("This profile owns no directories.","warning"),!0):(this.mode="confirm-remove-dir",this.notice=void 0,!0)}removeDir(){const e=this.open(),t=this.currentDir();this.mode="detail",!(e===null||t===null)&&this.attempt(()=>W(e.profileId,t.path),`${d(t.path)} removed from "${e.manifest.name}".`)}togglePause(){const e=this.open();if(e===null)return!0;const t=e.manifest.paused_at!==null;return this.attempt(()=>t?J(e.profileId):U(e.profileId),t?`"${e.manifest.name}" is active again.`:`"${e.manifest.name}" is paused \u2014 no new nodes start under it.`),!0}askDelete(){const e=this.selected();return e===null?!0:e.profileId===P?(this.say("The root profile is the fallback identity for uncovered directories and cannot be deleted.","warning"),!0):(this.openId=e.profileId,this.mode="confirm-delete",this.notice=void 0,!0)}async deleteOpen(){const e=this.open();if(this.mode="list",!(e===null||this.mutating)){this.mutating=!0,this.say(`Deleting "${e.manifest.name}"\u2026`),this.onChange();try{const t=await N().deleteProfile(e.profileId,{force:!0,caller_node_id:R()??null});this.openId=null,this.reload(),this.say(`Deleted "${t.name}" \u2014 ${t.nodes} nodes, ${t.crons} crons, ${t.default_pins} pins.`)}catch(t){this.say(T(t),"warning")}finally{this.mutating=!1,this.onChange()}}}footerHint(){switch(this.mode){case"new-name":return"type a name \xB7 enter create \xB7 esc cancel";case"rename":return"type a name \xB7 enter save \xB7 esc cancel";case"add-dir":return"type a directory \xB7 enter add \xB7 esc cancel";case"confirm-delete":case"confirm-remove-dir":return"y confirm \xB7 n cancel";case"detail":return"\u2191\u2193 dir \xB7 a add \xB7 m memory \xB7 h home \xB7 x remove \xB7 r rename \xB7 p pause \xB7 esc back";case"list":return"\u2191\u2193 move \xB7 enter open \xB7 a add this dir \xB7 d pin here \xB7 n new \xB7 x delete"}}render(e,t){const i=this.mode==="list"||this.mode==="new-name"||this.mode==="confirm-delete"?this.renderList(e,t):this.renderDetail(e,t);if(this.notice!==void 0){i.push("");for(const s of j(this.notice,e))i.push(u(o.fg(this.noticeTone,s),e))}return i}header(e,t,n){const i=o.fg("accent",o.bold(t)),s=o.fg("dim",n);return u(`${i} ${s}`,e)}renderList(e,t){const n=[this.header(e,"Profiles",`${this.entries.length} profile${this.entries.length===1?"":"s"}`),u(o.fg("dim",`Identities your sessions run under. Here: ${d(this.cwd)}`),e),""];if(this.mode==="new-name")return[...n,...this.field(e,"New profile name",this.nameInput)];if(this.mode==="confirm-delete")return[...n,...this.deletePrompt(e)];if(this.entries.length===0)return n.push(u(o.fg("dim"," No profiles yet \u2014 press n to create one here."),e)),n;const i=this.pinnedHere(),s=Math.min(22,Math.max(...this.entries.map(f=>f.manifest.name.length))),r=Math.max(1,t-8),h=_(this.entries.length,this.listIndex,r);for(let f=h.start;f<h.end;f+=1){const c=this.entries[f],y=c.manifest.projects.length,$=y===0?"\u2014":`${y} dir${y===1?"":"s"}`,a=[];M(c,this.cwd)&&a.push("covers here"),i===c.profileId&&a.push("pinned"),c.manifest.paused_at!==null&&a.push("paused");const p=`${l(c.manifest.name,s)} ${l($,8)} ${l(D(c.manifest.last_used_at),14)} ${a.join(" \xB7 ")}`;f===this.listIndex?n.push(o.bg("selectedBg",l(`\u25B8 ${p}`,e))):n.push(u(` ${l(c.manifest.name,s)} ${o.fg("dim",`${l($,8)} ${l(D(c.manifest.last_used_at),14)}`)} ${o.fg("muted",a.join(" \xB7 "))}`,e))}return(h.start>0||h.end<this.entries.length)&&n.push(u(o.fg("dim",` ${this.listIndex+1}/${this.entries.length}`),e)),n}renderDetail(e,t){const n=this.open();if(n===null)return this.renderList(e,t);const i=n.manifest,s=[i.home!==null?`home ${d(i.home)}`:"no home",`kind ${i.default_kind??"general"}`,D(i.last_used_at),...i.paused_at!==null?["paused"]:[]],r=[this.header(e,i.name,n.profileId),u(o.fg("dim",s.join(" \xB7 ")),e),""];if(this.mode==="rename")return[...r,...this.field(e,"Rename profile",this.nameInput)];if(this.mode==="add-dir")return[...r,...this.field(e,"Directory to add to this profile",this.dirInput)];const h=i.projects;if(h.length===0)return r.push(u(o.fg("dim"," Owns no directories \u2014 press a to add one."),e)),r;const f=new Set(F(n.profileId)),c=Math.min(Math.max(20,e-26),Math.max(...h.map(a=>d(a.path).length))),y=Math.max(1,t-8),$=_(h.length,this.dirIndex,y);for(let a=$.start;a<$.end;a+=1){const p=h[a],x=[];p.path===i.home&&x.push("home"),f.has(p.path)&&x.push("pinned"),p.path===this.cwd&&x.push("\u2190 here");const b=l(d(p.path),c),k=`${b} ${l(p.memory,8)} ${x.join(" \xB7 ")}`;a===this.dirIndex?r.push(o.bg("selectedBg",l(`\u25B8 ${k}`,e))):r.push(u(` ${b} ${o.fg("success",l(p.memory,8))} ${o.fg("muted",x.join(" \xB7 "))}`,e))}if(this.mode==="confirm-remove-dir"){const a=this.currentDir();r.push(""),r.push(u(o.fg("warning",`Remove ${a!==null?d(a.path):"this directory"} from "${i.name}"? Its files are untouched. y / n`),e))}return r}field(e,t,n){return[u(o.fg("accent",t),e),u(` ${n.render(Math.max(8,e-2))[0]??""}`,e)]}deletePrompt(e){const n=this.open()?.manifest.name??"",i=[];for(const s of j(`Delete "${n}" and everything it owns \u2014 every node, cron, inbox ticket and review under it, plus its memory store and directory pins? This cannot be undone.`,e))i.push(u(o.fg("warning",s),e));return i.push(""),i.push(u(o.fg("dim"," y delete n cancel"),e)),i}}export{ie as ProfilesPanel};
1
+ var L=Object.defineProperty;var g=(m,e)=>L(m,"name",{value:e,configurable:!0});import{envNodeId as R}from"../../../shared/env.js";import{Input as C,matchesKey as I,truncateToWidth as u}from"@earendil-works/pi-tui";import{basename as O}from"node:path";import{PROFILE_PROJECT_MEMORY_VALUES as v}from"../../../api/dto/profiles.js";import{cliClient as E}from"../../api-client.js";import{clearDefaultProfile as N,defaultProfileDirs as F,getDefaultProfileId as S,setDefaultProfileId as H}from"../../../core/profiles/default-binding.js";import{ROOT_PROFILE_ID as P,addProfileProject as w,createProfile as V,listProfiles as A,pauseProfile as U,removeProfileProject as W,renameProfile as B,resumeProfile as J}from"../../../core/profiles/manifest.js";import{tildify as l}from"../../../core/fs-utils.js";import{profileCoversCwd as M}from"../../../core/profiles/select.js";import{padAnsi as h,theme as o,visibleRange as _,wrapText as j}from"../../../core/tui/panel.js";function D(m){if(m===null)return"never used";const e=Date.parse(m);if(Number.isNaN(e))return"used recently";const t=Math.max(0,Math.floor((Date.now()-e)/1e3));if(t<60)return"used just now";const n=Math.floor(t/60);if(n<60)return`used ${n}m ago`;const i=Math.floor(n/60);if(i<24)return`used ${i}h ago`;const s=Math.floor(i/24);if(s<30)return`used ${s}d ago`;const r=Math.floor(s/30);return r<12?`used ${r}mo ago`:`used ${Math.floor(r/12)}y ago`}g(D,"relativeUsed");function T(m){return m instanceof Error?m.message:String(m)}g(T,"messageOf");class ie{static{g(this,"ProfilesPanel")}cwd;onChange;nameInput=new C;dirInput=new C;entries=[];listIndex=0;dirIndex=0;mode="list";openId=null;notice;noticeTone="success";mutating=!1;constructor(e,t){this.cwd=e,this.onChange=t,this.nameInput.onSubmit=()=>{this.submitName(),this.onChange()},this.nameInput.onEscape=()=>{this.mode=this.openId!==null?"detail":"list",this.leaveField(),this.onChange()},this.dirInput.onSubmit=()=>{this.submitDir(),this.onChange()},this.dirInput.onEscape=()=>{this.mode="detail",this.leaveField(),this.onChange()},this.reload()}badge(){return String(this.entries.length)}ownsInput(e){return this.mode==="list"?!1:this.mode==="detail"?I(e,"escape")||I(e,"left"):!0}reload(){const e=g(i=>i.profileId===P?2:M(i,this.cwd)?0:1,"rank"),t=g(i=>i.manifest.last_used_at??"","used");this.entries=A().sort((i,s)=>{const r=e(i)-e(s);if(r!==0)return r;const d=t(s).localeCompare(t(i));return d!==0?d:i.manifest.name.localeCompare(s.manifest.name)}),this.listIndex>=this.entries.length&&(this.listIndex=Math.max(0,this.entries.length-1));const n=this.open();n===null?(this.mode!=="list"&&(this.mode="list"),this.openId=null):this.dirIndex>=n.manifest.projects.length&&(this.dirIndex=Math.max(0,n.manifest.projects.length-1))}selected(){return this.entries[this.listIndex]??null}open(){return this.openId===null?null:this.entries.find(e=>e.profileId===this.openId)??null}currentDir(){return this.open()?.manifest.projects[this.dirIndex]??null}pinnedHere(){return S(this.cwd)}say(e,t="success"){this.notice=e,this.noticeTone=t}attempt(e,t){try{e(),this.reload(),this.say(t)}catch(n){this.say(T(n),"warning")}}handleInput(e,t){const n=this.route(e,t);return n&&this.onChange(),n}route(e,t){switch(this.mode){case"new-name":case"rename":return this.routeText(this.nameInput,e);case"add-dir":return this.routeText(this.dirInput,e);case"confirm-delete":return this.routeConfirm(e,()=>{this.deleteOpen()});case"confirm-remove-dir":return this.routeConfirm(e,()=>this.removeDir());case"detail":return this.routeDetail(e,t);case"list":return this.routeList(e,t)}}routeText(e,t){return e.handleInput(t),!0}routeConfirm(e,t){const n=e.toLowerCase();return n==="y"?t():(n==="n"||I(e,"escape")||I(e,"return"))&&(this.mode=this.openId!==null?"detail":"list",this.say("Cancelled.")),!0}routeList(e,t){if(t?.("crtr.setup.list-down",e)===!0)return this.move(1),!0;if(t?.("crtr.setup.list-up",e)===!0)return this.move(-1),!0;if(t?.("crtr.setup.advance",e)===!0){const n=this.selected();return n!==null&&(this.openId=n.profileId,this.dirIndex=0,this.mode="detail",this.notice=void 0),!0}switch(e.toLowerCase()){case"a":return this.addCwdTo(this.selected());case"d":return this.togglePin();case"n":return this.mode="new-name",this.edit(this.nameInput,O(this.cwd)||"profile"),!0;case"x":return this.askDelete();default:return!1}}routeDetail(e,t){const n=this.open();if(n===null)return this.mode="list",!0;if(I(e,"escape")||I(e,"left"))return this.mode="list",this.notice=void 0,!0;if(t?.("crtr.setup.list-down",e)===!0)return this.moveDir(1),!0;if(t?.("crtr.setup.list-up",e)===!0)return this.moveDir(-1),!0;switch(e.toLowerCase()){case"a":return this.mode="add-dir",this.edit(this.dirInput,this.cwd),!0;case"m":return this.cycleMemory();case"x":return this.askRemoveDir();case"r":return this.mode="rename",this.edit(this.nameInput,n.manifest.name),!0;case"p":return this.togglePause();default:return!1}}edit(e,t){e.setValue(t),e.handleInput(""),e.focused=!0,this.notice=void 0}leaveField(){this.nameInput.focused=!1,this.dirInput.focused=!1}move(e){this.entries.length!==0&&(this.listIndex=(this.listIndex+e+this.entries.length)%this.entries.length,this.notice=void 0)}moveDir(e){const t=this.open()?.manifest.projects.length??0;t!==0&&(this.dirIndex=(this.dirIndex+e+t)%t,this.notice=void 0)}addCwdTo(e){return e===null||this.attempt(()=>w(e.profileId,this.cwd,{memory:"content"}),`${l(this.cwd)} now belongs to "${e.manifest.name}".`),!0}togglePin(){const e=this.selected();return e===null||(this.pinnedHere()===e.profileId?(N(this.cwd),this.say(`${l(this.cwd)} no longer defaults to any profile.`)):(H(this.cwd,e.profileId),this.say(`${l(this.cwd)} now starts as "${e.manifest.name}" without asking.`)),this.onChange()),!0}submitName(){const e=this.nameInput.getValue().trim(),t=this.mode==="new-name";if(this.mode=t?"list":"detail",this.leaveField(),e===""){this.say("A profile name cannot be empty.","warning");return}if(t){let i=null;this.attempt(()=>{i=V(e,[{path:this.cwd,memory:"content"}]).profileId},`Created "${e}", owning ${l(this.cwd)}.`);const s=this.entries.findIndex(r=>r.profileId===i);s>=0&&(this.listIndex=s);return}const n=this.open();n!==null&&this.attempt(()=>B(n.profileId,e),`Renamed to "${e}".`)}submitDir(){const e=this.dirInput.getValue().trim(),t=this.open();if(this.mode="detail",this.leaveField(),t!==null){if(e===""){this.say("Type the directory to add.","warning");return}this.attempt(()=>w(t.profileId,e,{memory:"content"}),`${l(e)} added to "${t.manifest.name}".`)}}cycleMemory(){const e=this.open(),t=this.currentDir();if(e===null||t===null)return!0;const n=v[(v.indexOf(t.memory)+1)%v.length];return this.attempt(()=>w(e.profileId,t.path,{memory:n}),`${l(t.path)} discloses up to "${n}".`),!0}askRemoveDir(){return this.currentDir()===null?(this.say("This profile owns no directories.","warning"),!0):(this.mode="confirm-remove-dir",this.notice=void 0,!0)}removeDir(){const e=this.open(),t=this.currentDir();this.mode="detail",!(e===null||t===null)&&this.attempt(()=>W(e.profileId,t.path),`${l(t.path)} removed from "${e.manifest.name}".`)}togglePause(){const e=this.open();if(e===null)return!0;const t=e.manifest.paused_at!==null;return this.attempt(()=>t?J(e.profileId):U(e.profileId),t?`"${e.manifest.name}" is active again.`:`"${e.manifest.name}" is paused \u2014 no new nodes start under it.`),!0}askDelete(){const e=this.selected();return e===null?!0:e.profileId===P?(this.say("The root profile is the fallback identity for uncovered directories and cannot be deleted.","warning"),!0):(this.openId=e.profileId,this.mode="confirm-delete",this.notice=void 0,!0)}async deleteOpen(){const e=this.open();if(this.mode="list",!(e===null||this.mutating)){this.mutating=!0,this.say(`Deleting "${e.manifest.name}"\u2026`),this.onChange();try{const t=await E().deleteProfile(e.profileId,{force:!0,caller_node_id:R()??null});this.openId=null,this.reload(),this.say(`Deleted "${t.name}" \u2014 ${t.nodes} nodes, ${t.crons} crons, ${t.default_pins} pins.`)}catch(t){this.say(T(t),"warning")}finally{this.mutating=!1,this.onChange()}}}footerHint(){switch(this.mode){case"new-name":return"type a name \xB7 enter create \xB7 esc cancel";case"rename":return"type a name \xB7 enter save \xB7 esc cancel";case"add-dir":return"type a directory \xB7 enter add \xB7 esc cancel";case"confirm-delete":case"confirm-remove-dir":return"y confirm \xB7 n cancel";case"detail":return"\u2191\u2193 dir \xB7 a add \xB7 m memory \xB7 x remove \xB7 r rename \xB7 p pause \xB7 esc back";case"list":return"\u2191\u2193 move \xB7 enter open \xB7 a add this dir \xB7 d pin here \xB7 n new \xB7 x delete"}}render(e,t){const i=this.mode==="list"||this.mode==="new-name"||this.mode==="confirm-delete"?this.renderList(e,t):this.renderDetail(e,t);if(this.notice!==void 0){i.push("");for(const s of j(this.notice,e))i.push(u(o.fg(this.noticeTone,s),e))}return i}header(e,t,n){const i=o.fg("accent",o.bold(t)),s=o.fg("dim",n);return u(`${i} ${s}`,e)}renderList(e,t){const n=[this.header(e,"Profiles",`${this.entries.length} profile${this.entries.length===1?"":"s"}`),u(o.fg("dim",`Identities your sessions run under. Here: ${l(this.cwd)}`),e),""];if(this.mode==="new-name")return[...n,...this.field(e,"New profile name",this.nameInput)];if(this.mode==="confirm-delete")return[...n,...this.deletePrompt(e)];if(this.entries.length===0)return n.push(u(o.fg("dim"," No profiles yet \u2014 press n to create one here."),e)),n;const i=this.pinnedHere(),s=Math.min(22,Math.max(...this.entries.map(f=>f.manifest.name.length))),r=Math.max(1,t-8),d=_(this.entries.length,this.listIndex,r);for(let f=d.start;f<d.end;f+=1){const c=this.entries[f],y=c.manifest.projects.length,$=y===0?"\u2014":`${y} dir${y===1?"":"s"}`,a=[];M(c,this.cwd)&&a.push("covers here"),i===c.profileId&&a.push("pinned"),c.manifest.paused_at!==null&&a.push("paused");const p=`${h(c.manifest.name,s)} ${h($,8)} ${h(D(c.manifest.last_used_at),14)} ${a.join(" \xB7 ")}`;f===this.listIndex?n.push(o.bg("selectedBg",h(`\u25B8 ${p}`,e))):n.push(u(` ${h(c.manifest.name,s)} ${o.fg("dim",`${h($,8)} ${h(D(c.manifest.last_used_at),14)}`)} ${o.fg("muted",a.join(" \xB7 "))}`,e))}return(d.start>0||d.end<this.entries.length)&&n.push(u(o.fg("dim",` ${this.listIndex+1}/${this.entries.length}`),e)),n}renderDetail(e,t){const n=this.open();if(n===null)return this.renderList(e,t);const i=n.manifest,s=[`app ${i.grantee??"app:terminal"}`,`kind ${i.default_kind??"general"}`,D(i.last_used_at),...i.paused_at!==null?["paused"]:[]],r=[this.header(e,i.name,n.profileId),u(o.fg("dim",s.join(" \xB7 ")),e),""];if(this.mode==="rename")return[...r,...this.field(e,"Rename profile",this.nameInput)];if(this.mode==="add-dir")return[...r,...this.field(e,"Directory to add to this profile",this.dirInput)];const d=i.projects;if(d.length===0)return r.push(u(o.fg("dim"," Owns no directories \u2014 press a to add one."),e)),r;const f=new Set(F(n.profileId)),c=Math.min(Math.max(20,e-26),Math.max(...d.map(a=>l(a.path).length))),y=Math.max(1,t-8),$=_(d.length,this.dirIndex,y);for(let a=$.start;a<$.end;a+=1){const p=d[a],x=[];f.has(p.path)&&x.push("pinned"),p.path===this.cwd&&x.push("\u2190 here");const b=h(l(p.path),c),k=`${b} ${h(p.memory,8)} ${x.join(" \xB7 ")}`;a===this.dirIndex?r.push(o.bg("selectedBg",h(`\u25B8 ${k}`,e))):r.push(u(` ${b} ${o.fg("success",h(p.memory,8))} ${o.fg("muted",x.join(" \xB7 "))}`,e))}if(this.mode==="confirm-remove-dir"){const a=this.currentDir();r.push(""),r.push(u(o.fg("warning",`Remove ${a!==null?l(a.path):"this directory"} from "${i.name}"? Its files are untouched. y / n`),e))}return r}field(e,t,n){return[u(o.fg("accent",t),e),u(` ${n.render(Math.max(8,e-2))[0]??""}`,e)]}deletePrompt(e){const n=this.open()?.manifest.name??"",i=[];for(const s of j(`Delete "${n}" and everything it owns \u2014 every node, cron, inbox ticket and review under it, plus its memory store and directory pins? This cannot be undone.`,e))i.push(u(o.fg("warning",s),e));return i.push(""),i.push(u(o.fg("dim"," y delete n cancel"),e)),i}}export{ie as ProfilesPanel};
@@ -1,9 +1,9 @@
1
- var y=Object.defineProperty;var o=(e,r)=>y(e,"name",{value:r,configurable:!0});import{execFile as b}from"node:child_process";import{createInterface as x}from"node:readline/promises";import{join as u}from"node:path";import{ModelRuntime as $}from"@earendil-works/pi-coding-agent";import{cliClient as d}from"../api-client.js";import{InputError as f}from"../../core/io.js";import{PoolCredentialStore as k}from"../../core/pool-credential-store.js";import{isManagedProvider as m,readSubscriptionPool as C}from"../../core/subscription-state.js";import{piAgentDir as P}from"../../core/runtime/package-health.js";async function U(){const e=P();return $.create({credentials:new k(u(e,"auth.json")),modelsPath:u(e,"models.json")})}o(U,"openProviderLoginRuntime");async function Y(e,r,i,t={}){const c=e.getProvider(r)?.auth.oauth;if(c===void 0)throw new f({error:"provider_login_unavailable",message:`provider ${r} has no OAuth login flow`,next:"Configure an API key through `crtr sys setup`, then run `crtr sys connect` again."});const g=m(r)?Math.max(0,...C(r).map(a=>a.lastRateLimitedAt)):void 0,n=await c.login(i);if(t.beforeInstall?.()===!1)return!1;if(m(r)){const a=typeof n.accountId=="string"&&n.accountId.trim()?n.accountId.trim():void 0;return await d().installCredential(r,{kind:"managed_account",...t.label?{label:t.label}:{auto_label:!0},...a?{account_id:a}:{},access_token:n.access,refresh_token:n.refresh,expires_at:new Date(n.expires).toISOString(),last_rate_limited_at:g}),!0}const{type:I,access:h,refresh:w,expires:_,...l}=n;return await d().installCredential(r,{kind:"oauth",access_token:h,refresh_token:w,expires_at:new Date(_).toISOString(),...Object.keys(l).length>0?{extra:l}:{}}),!0}o(Y,"loginProvider");function p(e){const r=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",i=process.platform==="win32"?["/c","start","",e]:[e];b(r,i,{timeout:5e3},()=>{})}o(p,"openBrowser");function A(e){switch(e.type){case"auth_url":process.stderr.write(`${e.instructions}
1
+ var h=Object.defineProperty;var o=(e,r)=>h(e,"name",{value:r,configurable:!0});import{execFile as w}from"node:child_process";import{createInterface as y}from"node:readline/promises";import{join as c}from"node:path";import{ModelRuntime as $}from"@earendil-works/pi-coding-agent";import{cliClient as l}from"../api-client.js";import{InputError as u}from"../../core/io.js";import{PoolCredentialStore as b}from"../../core/pool-credential-store.js";import{isManagedProvider as _}from"../../core/subscription-state.js";import{daemonManagedLogin as x}from"../../core/model-auth/daemon-login.js";import{piAgentDir as k}from"../../core/runtime/package-health.js";import{secretsDir as C}from"../../core/layout.js";async function Y(){const e=k();return $.create({credentials:new b(c(C(),"auth.json")),modelsPath:c(e,"models.json")})}o(Y,"openProviderLoginRuntime");async function B(e,r,n,t={}){if(_(r))return await x(l(),r,n,t.label?{label:t.label}:{}),!0;const s=e.getProvider(r)?.auth.oauth;if(s===void 0)throw new u({error:"provider_login_unavailable",message:`provider ${r} has no OAuth login flow`,next:"Configure an API key through `crtr sys setup`, then run `crtr sys connect` again."});const m=await s.login(n);if(t.beforeInstall?.()===!1)return!1;const{type:j,access:d,refresh:p,expires:g,...a}=m;return await l().installCredential(r,{kind:"oauth",access_token:d,refresh_token:p,expires_at:new Date(g).toISOString(),...Object.keys(a).length>0?{extra:a}:{}}),!0}o(B,"loginProvider");function f(e){const r=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",n=process.platform==="win32"?["/c","start","",e]:[e];w(r,n,{timeout:5e3},()=>{})}o(f,"openBrowser");function P(e){switch(e.type){case"auth_url":process.stderr.write(`${e.instructions}
2
2
  ${e.url}
3
- `),p(e.url);break;case"device_code":process.stderr.write(`${e.verificationUri}
3
+ `),f(e.url);break;case"device_code":process.stderr.write(`${e.verificationUri}
4
4
  Code: ${e.userCode}
5
- `),p(e.verificationUri);break;case"info":case"progress":process.stderr.write(`${e.message}
6
- `);break}}o(A,"notify");async function S(e){if(!process.stdin.isTTY||!process.stderr.isTTY)throw new f({error:"interactive_login_required",message:"provider login requires an interactive terminal",next:"Run `crtr sys connect` from an interactive terminal, or configure the provider credential through `crtr sys setup` first."});const r=e.type==="select"?`${e.message}
7
- ${e.options.map((t,s)=>`${s+1}. ${t.label}`).join(`
5
+ `),f(e.verificationUri);break;case"info":case"progress":process.stderr.write(`${e.message}
6
+ `);break}}o(P,"notify");async function v(e){if(!process.stdin.isTTY||!process.stderr.isTTY)throw new u({error:"interactive_login_required",message:"provider login requires an interactive terminal",next:"Run `crtr sys connect` from an interactive terminal, or configure the provider credential through `crtr sys setup` first."});const r=e.type==="select"?`${e.message}
7
+ ${e.options.map((t,i)=>`${i+1}. ${t.label}`).join(`
8
8
  `)}
9
- Select: `:`${e.message}${e.placeholder?` (${e.placeholder})`:""}: `,i=x({input:process.stdin,output:process.stderr});try{const t=await i.question(r,{signal:e.signal});if(e.type!=="select")return t;const s=e.options[Number.parseInt(t,10)-1]?.id;if(s===void 0)throw new Error("Login cancelled");return s}finally{i.close()}}o(S,"promptTerminal");function B(){return{signal:new AbortController().signal,notify:A,prompt:S}}o(B,"terminalAuthInteraction");export{Y as loginProvider,U as openProviderLoginRuntime,B as terminalAuthInteraction};
9
+ Select: `:`${e.message}${e.placeholder?` (${e.placeholder})`:""}: `,n=y({input:process.stdin,output:process.stderr});try{const t=await n.question(r,{signal:e.signal});if(e.type!=="select")return t;const i=e.options[Number.parseInt(t,10)-1]?.id;if(i===void 0)throw new Error("Login cancelled");return i}finally{n.close()}}o(v,"promptTerminal");function F(){return{signal:new AbortController().signal,notify:P,prompt:v}}o(F,"terminalAuthInteraction");export{B as loginProvider,Y as openProviderLoginRuntime,F as terminalAuthInteraction};
@@ -2,7 +2,7 @@ import { type BindingId, type BindingResolution, type KeybindingDiagnostic, type
2
2
  export declare const OFFICIAL_MARKETPLACE_NAME = "crouter-official-marketplace";
3
3
  export declare const OFFICIAL_MARKETPLACE_URL = "https://github.com/crouton-labs/crouter-official-marketplace.git";
4
4
  export declare const OFFICIAL_MARKETPLACE_REF = "main";
5
- export type SetupPackageId = 'official-marketplace' | 'crtr-extensions' | 'oauth-adapter' | 'capture-plugin' | 'search-plugin' | 'dev-plugin';
5
+ export type SetupPackageId = 'official-marketplace' | 'crtr-extensions' | 'oauth-adapter' | 'capture-plugin' | 'exa-search-plugin' | 'dev-plugin';
6
6
  /** `nerd-font` is not a command on PATH like the other two — it is an installed
7
7
  * font face, detected by fontconfig/font-directory scan. The viewer renders
8
8
  * every tool and command icon with Nerd Font codepoints, so without it a fresh
@@ -1,9 +1,9 @@
1
- var V=Object.defineProperty;var s=(e,t)=>V(e,"name",{value:t,configurable:!0});import{spawn as X,spawnSync as Q}from"node:child_process";import{homedir as k}from"node:os";import{basename as Z,dirname as R,join as P,relative as ee,resolve as te}from"node:path";import{isDeepStrictEqual as m}from"node:util";import{BINDING_CATALOG as ne,normalizeGesture as re,splitGestureExpression as ie,inboxShortcut as se,resolveKeybindings as I}from"../../core/keybindings/index.js";import{runtimeManifest as ae}from"./shared.js";import{atomicWriteJson as oe,readJsonIfExists as ce,readJsonOrNull as D}from"../../core/fs-utils.js";import{resolveBundledPiCliPath as ue}from"../../core/runtime/pi-cli.js";import{crtrVersion as le}from"../../shared/crtr-version.js";import{installTmuxBindings as de}from"../../core/runtime/tmux-chrome.js";import{normalizeTmuxPassthrough as pe}from"../../core/config.js";import{detectNerdFont as he,nerdFontInstallCommand as fe,createCurlPercentReader as me,NERD_FONT_MANUAL_LINUX_COMMAND as ge,NERD_FONT_SELECT_HINT as ke}from"../../core/runtime/nerd-font.js";import{startProgressBar as be}from"../../core/runtime/progress-bar.js";import{ensureRenderer as ve,isRendererReady as O}from"../../core/termrender/termrender.js";import{installFromMarketplace as we}from"../pkg/plugin-manage.js";import{addMarketplace as T}from"../pkg/market-manage.js";import{findPluginByName as xe,findMarketplaceByName as N}from"../../core/resolver.js";import{expandTilde as ye}from"../../core/fs-utils.js";const L="crouter-official-marketplace",_="https://github.com/crouton-labs/crouter-official-marketplace.git",M="main";function K(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}s(K,"isKeybindingsObject");function f(e){return K(e)?Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Array.isArray(n)?[...n]:n])):{}}s(f,"cloneKeybindings");class tt{static{s(this,"SetupKeybindingsDraft")}expected;baseline;current;baselineInvalidRoot;invalidRoot;resolutionCache;expectedPassthrough;baselinePassthrough;currentPassthrough;constructor(t,n=void 0){this.expected=t,this.baseline=f(t),this.current=f(t),this.baselineInvalidRoot=t!==void 0&&!K(t)?t:void 0,this.invalidRoot=this.baselineInvalidRoot,this.expectedPassthrough=n,this.baselinePassthrough=pe(n),this.currentPassthrough=[...this.baselinePassthrough]}get dirty(){return!m(this.current,this.baseline)||!m(this.invalidRoot,this.baselineInvalidRoot)||!m(this.currentPassthrough,this.baselinePassthrough)}overrides(){return f(this.current)}expectedKeybindings(){return this.expected}tmuxPassthrough(){return[...this.currentPassthrough]}expectedTmuxPassthrough(){return this.expectedPassthrough}usesTmuxPassthrough(t){return this.currentPassthrough.includes(t)}toggleTmuxPassthrough(t){this.currentPassthrough=this.currentPassthrough.includes(t)?this.currentPassthrough.filter(n=>n!==t):[...this.currentPassthrough,t]}resolution(){return this.resolutionCache===void 0&&(this.resolutionCache=I(this.invalidRoot===void 0?this.current:this.invalidRoot)),this.resolutionCache}hasInvalidRoot(){return this.invalidRoot!==void 0}expression(t){return this.resolution().gestures(t).join(", ")}edit(t,n){if(this.invalidRoot!==void 0)return{ok:!1,diagnostics:[{severity:"error",code:"invalid-keybindings",offendingValue:this.invalidRoot,message:"Reset all before editing: the saved keybindings root is invalid."}]};const r=ne.find(p=>p.id===t);let o;try{o=n.trim()===""?[]:ie(n).map(p=>re(p.trim(),r))}catch(p){return{ok:!1,diagnostics:[{severity:"error",code:"invalid-override",bindingId:t,offendingValue:n,message:p instanceof Error?p.message:String(p)}]}}const i=[...new Set(o)],u={...this.current};delete u[t];const c=[...I(u).gestures(t)],l=m(i,c)?u:{...this.current,[t]:i},a=I(l),d=a.diagnostics.filter(p=>p.bindingId===t||p.relatedBindingIds?.includes(t));return d.length>0?{ok:!1,diagnostics:d}:(this.current=l,this.resolutionCache=void 0,{ok:!0,diagnostics:a.diagnostics})}unbind(t){return this.edit(t,"")}resetRow(t){delete this.current[t],this.resolutionCache=void 0}resetAll(){this.current={},this.currentPassthrough=[],this.invalidRoot=void 0,this.resolutionCache=void 0}discard(){this.current=f(this.baseline),this.currentPassthrough=[...this.baselinePassthrough],this.invalidRoot=this.baselineInvalidRoot,this.resolutionCache=void 0}markSaved(t,n=[]){this.expected=Object.keys(t).length===0?void 0:f(t),this.baseline=f(t),this.current=f(t),this.expectedPassthrough=n.length===0?void 0:[...n],this.baselinePassthrough=[...n],this.currentPassthrough=[...n],this.baselineInvalidRoot=void 0,this.invalidRoot=void 0,this.resolutionCache=void 0}}const Pe={"official-marketplace":{name:L,shortDescription:"the official crtr plugin catalog \u2014 registered as a source so its plugins are installable by ref.",longDescription:"Shallow-clones github.com/crouton-labs/crouter-official-marketplace into the user scope and registers it, which is what makes `crtr pkg plugin install crouter-official-marketplace/<name>` resolve and what fills `crtr pkg market browse`. Registering the source installs no plugin by itself. Uncheck it on a machine that should reach no external catalog \u2014 a plugin selected below still registers the marketplace it comes from, because its ref cannot resolve otherwise."},"crtr-extensions":{name:"pi-crtr-extensions",shortDescription:"crtr companion extensions \u2014 command palette, help gating, subscription/OAuth rotation, nested context.",longDescription:"Bundles the extensions built for crtr: a crtr slash-command palette, crtr/crouter help gating, surfacing of Claude Code marketplace plugin commands, nested AGENTS.md/CLAUDE.md loading, OAuth login + rotation across multiple Claude subscriptions (provider-rotation), and system-prompt trimming. The OAuth/rotation piece is what lets crtr authenticate your Claude account."},"oauth-adapter":{name:"pi-claude-oauth-adapter",shortDescription:"Anthropic OAuth / Claude Code credential compatibility for pi.",longDescription:"Third-party adapter (minzique/dotfiles-agents) letting pi authenticate with Claude using Claude Code OAuth credentials. Installed from npm, pinned to 0.1.2."},"capture-plugin":{name:"capture",shortDescription:"crtr plugin mounting `crtr capture` \u2014 browser automation and UI measurement over CDP.",longDescription:"Installs the `capture` plugin from the official crtr marketplace. It mounts `crtr capture` as a transparent passthrough to the external Capture CLI (`npm install -g @crouton-kit/capture`) for CDP screenshots, rendered-geometry measurement, HAR, accessibility trees, and JS execution against a live page. Uncheck it on a machine where agents never drive a browser \u2014 the command then costs nothing in their root prompt."},"search-plugin":{name:"search",shortDescription:"crtr plugin mounting `crtr search` \u2014 public-web discovery, grounded answers, and content extraction.",longDescription:"Installs the `search` plugin from the official crtr marketplace. It mounts `crtr search` and calls Exa directly, resolving its own API key from EXA_API_KEY or ~/.crouter/exa.key \u2014 crouter never handles that credential. Uncheck it on a machine whose agents get web search from somewhere else, such as a Northlight home where the platform serves `crtr search` from its own plugin."},"dev-plugin":{name:"dev",shortDescription:"crtr plugin mounting the development workflow \u2014 repository setup, worktrees, pull requests, and a dev track in the tutorial.",longDescription:"Installs the dev plugin from the official crtr marketplace. It adds the /dev: workflow commands (init, spec, design, plan, pr-loop), mounts crtr dev for a repository's own lifecycle commands and Grove instances, and contributes the crtr sys tutorial dev track. Uncheck it on a machine whose agents do not work in source repositories."}},C={"official-marketplace":{kind:"marketplace-source",source:_},"crtr-extensions":{kind:"local-path",source:F("pi-crtr-extensions")},"oauth-adapter":{kind:"npm",source:"npm:pi-claude-oauth-adapter@0.1.2"},"capture-plugin":{kind:"marketplace-plugin",source:"crouter-official-marketplace/capture"},"search-plugin":{kind:"marketplace-plugin",source:"crouter-official-marketplace/search"},"dev-plugin":{kind:"marketplace-plugin",source:"crouter-official-marketplace/dev"}},j=["extensions/*.ts","extensions/*/index.ts","!extensions/**/*.d.ts"],Ie={"official-marketplace":[],"crtr-extensions":["pi-crtr-extensions"],"oauth-adapter":[],"capture-plugin":[],"search-plugin":[],"dev-plugin":[]};function F(e){return P(ae.runtimeHome(),"selected","dist","builtin-pi-packages",e)}s(F,"selectedPiPackageDir");function S(e=F){return["official-marketplace","crtr-extensions","oauth-adapter","capture-plugin","search-plugin","dev-plugin"].map(t=>{const n=Pe[t],r=C[t].kind==="local-path"?e(n.name):C[t].source;return{id:t,name:n.name,sourceKind:C[t].kind,installSource:r,shortDescription:n.shortDescription,longDescription:n.longDescription}})}s(S,"buildSetupManifest");function nt(e){switch(e.sourceKind){case"marketplace-source":return`clone + register ${e.installSource}`;case"marketplace-plugin":return`crtr pkg plugin install ${e.installSource}`;default:return`pi install ${e.installSource}`}}s(nt,"packagePlanAction");function Ce(e){if(!e.startsWith("npm:"))return null;const t=e.slice(4),n=t.startsWith("@")?t.indexOf("@",1):t.lastIndexOf("@");return n>0?t.slice(0,n):t}s(Ce,"npmPackageName");function b(e,t,n){const r=Ce(e);if(r!==null)return`npm:${r}`;const o=ye(e,n);return te(t,o)}s(b,"normalizePackageIdentity");function v(e){return`package:${e}`}s(v,"packageNameIdentity");function B(e){return e.startsWith("npm:")?[]:[v(Z(e))]}s(B,"localPackageNameIdentities");function Se(e,t,n){const r=[b(e.installSource,t,n)];if(e.sourceKind==="local-path"){r.push(v(e.name));for(const o of Ie[e.id])r.push(v(o))}return r}s(Se,"manifestIdentities");function G(e,t=S(),n=P(k(),".pi","agent","settings.json"),r=k()){const o=R(n),i=new Set,u=new Map;for(const l of t)for(const a of Se(l,o,r))u.set(a,l.id);const c=e&&typeof e=="object"?e.packages:void 0;if(!Array.isArray(c))return i;for(const l of c){const a=typeof l=="string"?l:l&&typeof l=="object"&&typeof l.source=="string"?l.source:null;if(a===null)continue;const d=[b(a,o,r),...B(a)];for(const p of d){const h=u.get(p);if(h==="crtr-extensions"){const x=t.find(y=>y.id===h);if(b(a,o,r)!==b(x.installSource,o,r)||!l||typeof l!="object"||!m(l.extensions,j))continue}h!==void 0&&i.add(h)}}return i}s(G,"detectInstalledSetupPackageIds");function g(e){return Q("sh",["-lc",`command -v ${e} >/dev/null 2>&1`],{stdio:"ignore"}).status===0}s(g,"detectCommandOnPath");function Ae(e=process.platform,t=g){switch(e){case"darwin":return t("brew")?"brew":"manual";case"linux":return t("apt-get")?"apt-get":t("dnf")?"dnf":t("pacman")?"pacman":"manual";default:return"manual"}}s(Ae,"detectPackageManager");function $e(e,t,n=g){if(e==="nerd-font"?he().installed:n(e))return{tool:e,installed:!0,command:null,hint:"already installed",autoInstall:!1};if(e==="nerd-font"){const i=fe(t);return{tool:e,installed:!1,command:i.command,hint:`${i.hint} \u2014 ${ke}`,autoInstall:i.autoInstall}}const o=e==="nvim"?"neovim":"tmux";switch(t){case"brew":return{tool:e,installed:!1,command:`brew install ${o}`,hint:"Homebrew install",autoInstall:!0};case"apt-get":return{tool:e,installed:!1,command:`sudo apt-get update && sudo apt-get install -y ${o}`,hint:"apt-get install",autoInstall:!0};case"dnf":return{tool:e,installed:!1,command:`sudo dnf install -y ${o}`,hint:"dnf install",autoInstall:!0};case"pacman":return{tool:e,installed:!1,command:`sudo pacman -S --noconfirm ${o}`,hint:"pacman install",autoInstall:!0};default:return{tool:e,installed:!1,command:null,hint:`manual install required for ${e}`,autoInstall:!1}}}s($e,"buildSystemInstallPlan");function A(e=k()){return P(e,".pi","agent","settings.json")}s(A,"resolveSettingsPath");function rt(e={}){const t=e.homeDir??k(),n=e.settingsPath??A(t),r=e.manifest??S(),o=ce(n),i=G(o,r,n,t);for(const a of H(r))i.add(a);const u=e.commandExists??g,c=e.packageManager??Ae(process.platform,u),l=["tmux","nvim","nerd-font"].map(a=>$e(a,c,u));return{manifest:r,installedPackageIds:i,systemPlans:l}}s(rt,"buildSetupInitialState");function it(e){const t=e.manifest.map(r=>{const o=e.installedPackageIds.has(r.id)?"installed":"not installed";return`- ${r.name} \u2014 ${r.shortDescription} (${o})`}),n=e.systemPlans.map(r=>r.installed?`- ${r.tool}: \u2713 installed`:r.command?`- ${r.tool}: ${r.command}`:`- ${r.tool}: ${r.hint}`);return["crtr sys setup (non-interactive)","","Provider login: open the wizard in a TTY and use the Providers tab (same flow as /login) to authenticate a model provider.","","Packages:",...t,"","System deps:",...n,"",`Inbox: the inbox-toggle key (${se()??"disabled"}) is a crouter keybinding \u2014 view or rebind it in \`crtr sys settings\`; it is installed on the same tmux server as every other crouter binding.`,"Run `crtr sys setup` in a TTY to open the wizard."].join(`
1
+ var X=Object.defineProperty;var i=(e,t)=>X(e,"name",{value:t,configurable:!0});import{spawn as Q,spawnSync as Z}from"node:child_process";import{homedir as k}from"node:os";import{piAgentDir as P}from"../../core/runtime/package-health.js";import{basename as ee,dirname as D,join as x,relative as te,resolve as ne}from"node:path";import{isDeepStrictEqual as m}from"node:util";import{BINDING_CATALOG as re,normalizeGesture as ie,splitGestureExpression as se,inboxShortcut as ae,resolveKeybindings as C}from"../../core/keybindings/index.js";import{runtimeManifest as oe}from"./shared.js";import{atomicWriteJson as ce,readJsonIfExists as ue,readJsonOrNull as O}from"../../core/fs-utils.js";import{resolveBundledPiCliPath as le}from"../../core/runtime/pi-cli.js";import{crtrVersion as de}from"../../shared/crtr-version.js";import{installTmuxBindings as pe}from"../../core/runtime/tmux-chrome.js";import{normalizeTmuxPassthrough as he}from"../../core/config.js";import{detectNerdFont as fe,nerdFontInstallCommand as me,createCurlPercentReader as ge,NERD_FONT_MANUAL_LINUX_COMMAND as ke,NERD_FONT_SELECT_HINT as xe}from"../../core/runtime/nerd-font.js";import{startProgressBar as be}from"../../core/runtime/progress-bar.js";import{ensureRenderer as ve,isRendererReady as T}from"../../core/termrender/termrender.js";import{installFromMarketplace as we}from"../pkg/plugin-manage.js";import{addMarketplace as N}from"../pkg/market-manage.js";import{findPluginByName as ye,findMarketplaceByName as _}from"../../core/resolver.js";import{expandTilde as Ie}from"../../core/fs-utils.js";const L="crouter-official-marketplace",M="https://github.com/crouton-labs/crouter-official-marketplace.git",K="main";function j(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}i(j,"isKeybindingsObject");function f(e){return j(e)?Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Array.isArray(n)?[...n]:n])):{}}i(f,"cloneKeybindings");class rt{static{i(this,"SetupKeybindingsDraft")}expected;baseline;current;baselineInvalidRoot;invalidRoot;resolutionCache;expectedPassthrough;baselinePassthrough;currentPassthrough;constructor(t,n=void 0){this.expected=t,this.baseline=f(t),this.current=f(t),this.baselineInvalidRoot=t!==void 0&&!j(t)?t:void 0,this.invalidRoot=this.baselineInvalidRoot,this.expectedPassthrough=n,this.baselinePassthrough=he(n),this.currentPassthrough=[...this.baselinePassthrough]}get dirty(){return!m(this.current,this.baseline)||!m(this.invalidRoot,this.baselineInvalidRoot)||!m(this.currentPassthrough,this.baselinePassthrough)}overrides(){return f(this.current)}expectedKeybindings(){return this.expected}tmuxPassthrough(){return[...this.currentPassthrough]}expectedTmuxPassthrough(){return this.expectedPassthrough}usesTmuxPassthrough(t){return this.currentPassthrough.includes(t)}toggleTmuxPassthrough(t){this.currentPassthrough=this.currentPassthrough.includes(t)?this.currentPassthrough.filter(n=>n!==t):[...this.currentPassthrough,t]}resolution(){return this.resolutionCache===void 0&&(this.resolutionCache=C(this.invalidRoot===void 0?this.current:this.invalidRoot)),this.resolutionCache}hasInvalidRoot(){return this.invalidRoot!==void 0}expression(t){return this.resolution().gestures(t).join(", ")}edit(t,n){if(this.invalidRoot!==void 0)return{ok:!1,diagnostics:[{severity:"error",code:"invalid-keybindings",offendingValue:this.invalidRoot,message:"Reset all before editing: the saved keybindings root is invalid."}]};const r=re.find(p=>p.id===t);let o;try{o=n.trim()===""?[]:se(n).map(p=>ie(p.trim(),r))}catch(p){return{ok:!1,diagnostics:[{severity:"error",code:"invalid-override",bindingId:t,offendingValue:n,message:p instanceof Error?p.message:String(p)}]}}const a=[...new Set(o)],u={...this.current};delete u[t];const l=[...C(u).gestures(t)],c=m(a,l)?u:{...this.current,[t]:a},s=C(c),d=s.diagnostics.filter(p=>p.bindingId===t||p.relatedBindingIds?.includes(t));return d.length>0?{ok:!1,diagnostics:d}:(this.current=c,this.resolutionCache=void 0,{ok:!0,diagnostics:s.diagnostics})}unbind(t){return this.edit(t,"")}resetRow(t){delete this.current[t],this.resolutionCache=void 0}resetAll(){this.current={},this.currentPassthrough=[],this.invalidRoot=void 0,this.resolutionCache=void 0}discard(){this.current=f(this.baseline),this.currentPassthrough=[...this.baselinePassthrough],this.invalidRoot=this.baselineInvalidRoot,this.resolutionCache=void 0}markSaved(t,n=[]){this.expected=Object.keys(t).length===0?void 0:f(t),this.baseline=f(t),this.current=f(t),this.expectedPassthrough=n.length===0?void 0:[...n],this.baselinePassthrough=[...n],this.currentPassthrough=[...n],this.baselineInvalidRoot=void 0,this.invalidRoot=void 0,this.resolutionCache=void 0}}const Pe={"official-marketplace":{name:L,shortDescription:"the official crtr plugin catalog \u2014 registered as a source so its plugins are installable by ref.",longDescription:"Shallow-clones github.com/crouton-labs/crouter-official-marketplace into the user scope and registers it, which is what makes `crtr pkg plugin install crouter-official-marketplace/<name>` resolve and what fills `crtr pkg market browse`. Registering the source installs no plugin by itself. Uncheck it on a machine that should reach no external catalog \u2014 a plugin selected below still registers the marketplace it comes from, because its ref cannot resolve otherwise."},"crtr-extensions":{name:"pi-crtr-extensions",shortDescription:"crtr companion extensions \u2014 command palette, help gating, subscription/OAuth rotation, nested context.",longDescription:"Bundles the extensions built for crtr: a crtr slash-command palette, crtr/crouter help gating, surfacing of Claude Code marketplace plugin commands, nested AGENTS.md/CLAUDE.md loading, OAuth login + rotation across multiple Claude subscriptions (provider-rotation), and system-prompt trimming. The OAuth/rotation piece is what lets crtr authenticate your Claude account."},"oauth-adapter":{name:"pi-claude-oauth-adapter",shortDescription:"Anthropic OAuth / Claude Code credential compatibility for pi.",longDescription:"Third-party adapter (minzique/dotfiles-agents) letting pi authenticate with Claude using Claude Code OAuth credentials. Installed from npm, pinned to 0.2.2."},"capture-plugin":{name:"capture",shortDescription:"crtr plugin mounting `crtr capture` \u2014 browser automation and UI measurement over CDP.",longDescription:"Installs the `capture` plugin from the official crtr marketplace. It mounts `crtr capture` as a transparent passthrough to the external Capture CLI (`npm install -g @crouton-kit/capture`) for CDP screenshots, rendered-geometry measurement, HAR, accessibility trees, and JS execution against a live page. Uncheck it on a machine where agents never drive a browser \u2014 the command then costs nothing in their root prompt."},"exa-search-plugin":{name:"exa-search",shortDescription:"crtr plugin mounting `crtr exa-search` \u2014 public-web discovery, grounded answers, and content extraction.",longDescription:"Installs the `exa-search` plugin from the official crtr marketplace. It mounts `crtr exa-search` and calls Exa directly, resolving its own API key from EXA_API_KEY or ~/.crouter/exa.key \u2014 crouter never handles that credential. Uncheck it on a machine whose agents get web search from somewhere else, such as a Northlight home where the platform serves `crtr search` from its own plugin."},"dev-plugin":{name:"dev",shortDescription:"crtr plugin mounting the development workflow \u2014 repository setup, worktrees, pull requests, and a dev track in the tutorial.",longDescription:"Installs the dev plugin from the official crtr marketplace. It adds the /dev: workflow commands (init, spec, design, plan, pr-loop), mounts crtr dev for a repository's own lifecycle commands and Grove instances, and contributes the crtr sys tutorial dev track. Uncheck it on a machine whose agents do not work in source repositories."}},S={"official-marketplace":{kind:"marketplace-source",source:M},"crtr-extensions":{kind:"local-path",source:G("pi-crtr-extensions")},"oauth-adapter":{kind:"npm",source:"npm:pi-claude-oauth-adapter@0.2.2"},"capture-plugin":{kind:"marketplace-plugin",source:"crouter-official-marketplace/capture"},"exa-search-plugin":{kind:"marketplace-plugin",source:"crouter-official-marketplace/exa-search"},"dev-plugin":{kind:"marketplace-plugin",source:"crouter-official-marketplace/dev"}},F=["extensions/*.ts","extensions/*/index.ts","!extensions/**/*.d.ts"],Ce={"official-marketplace":[],"crtr-extensions":["pi-crtr-extensions"],"oauth-adapter":[],"capture-plugin":[],"exa-search-plugin":[],"dev-plugin":[]};function G(e){return x(oe.runtimeHome(),"selected","dist","builtin-pi-packages",e)}i(G,"selectedPiPackageDir");function A(e=G){return["official-marketplace","crtr-extensions","oauth-adapter","capture-plugin","exa-search-plugin","dev-plugin"].map(t=>{const n=Pe[t],r=S[t].kind==="local-path"?e(n.name):S[t].source;return{id:t,name:n.name,sourceKind:S[t].kind,installSource:r,shortDescription:n.shortDescription,longDescription:n.longDescription}})}i(A,"buildSetupManifest");function it(e){switch(e.sourceKind){case"marketplace-source":return`clone + register ${e.installSource}`;case"marketplace-plugin":return`crtr pkg plugin install ${e.installSource}`;default:return`pi install ${e.installSource}`}}i(it,"packagePlanAction");function Se(e){if(!e.startsWith("npm:"))return null;const t=e.slice(4),n=t.startsWith("@")?t.indexOf("@",1):t.lastIndexOf("@");return n>0?t.slice(0,n):t}i(Se,"npmPackageName");function b(e,t,n){const r=Se(e);if(r!==null)return`npm:${r}`;const o=Ie(e,n);return ne(t,o)}i(b,"normalizePackageIdentity");function v(e){return`package:${e}`}i(v,"packageNameIdentity");function B(e){return e.startsWith("npm:")?[]:[v(ee(e))]}i(B,"localPackageNameIdentities");function Ae(e,t,n){const r=[b(e.installSource,t,n)];if(e.sourceKind==="local-path"){r.push(v(e.name));for(const o of Ce[e.id])r.push(v(o))}return r}i(Ae,"manifestIdentities");function U(e,t=A(),n=x(P(),"settings.json"),r=k()){const o=D(n),a=new Set,u=new Map;for(const c of t)for(const s of Ae(c,o,r))u.set(s,c.id);const l=e&&typeof e=="object"?e.packages:void 0;if(!Array.isArray(l))return a;for(const c of l){const s=typeof c=="string"?c:c&&typeof c=="object"&&typeof c.source=="string"?c.source:null;if(s===null)continue;const d=[b(s,o,r),...B(s)];for(const p of d){const h=u.get(p);if(h==="crtr-extensions"){const y=t.find(I=>I.id===h);if(b(s,o,r)!==b(y.installSource,o,r)||!c||typeof c!="object"||!m(c.extensions,F))continue}h!==void 0&&a.add(h)}}return a}i(U,"detectInstalledSetupPackageIds");function g(e){return Z("sh",["-lc",`command -v ${e} >/dev/null 2>&1`],{stdio:"ignore"}).status===0}i(g,"detectCommandOnPath");function $e(e=process.platform,t=g){switch(e){case"darwin":return t("brew")?"brew":"manual";case"linux":return t("apt-get")?"apt-get":t("dnf")?"dnf":t("pacman")?"pacman":"manual";default:return"manual"}}i($e,"detectPackageManager");function Ee(e,t,n=g){if(e==="nerd-font"?fe().installed:n(e))return{tool:e,installed:!0,command:null,hint:"already installed",autoInstall:!1};if(e==="nerd-font"){const a=me(t);return{tool:e,installed:!1,command:a.command,hint:`${a.hint} \u2014 ${xe}`,autoInstall:a.autoInstall}}const o=e==="nvim"?"neovim":"tmux";switch(t){case"brew":return{tool:e,installed:!1,command:`brew install ${o}`,hint:"Homebrew install",autoInstall:!0};case"apt-get":return{tool:e,installed:!1,command:`sudo apt-get update && sudo apt-get install -y ${o}`,hint:"apt-get install",autoInstall:!0};case"dnf":return{tool:e,installed:!1,command:`sudo dnf install -y ${o}`,hint:"dnf install",autoInstall:!0};case"pacman":return{tool:e,installed:!1,command:`sudo pacman -S --noconfirm ${o}`,hint:"pacman install",autoInstall:!0};default:return{tool:e,installed:!1,command:null,hint:`manual install required for ${e}`,autoInstall:!1}}}i(Ee,"buildSystemInstallPlan");function $(e=k()){return x(e===k()?P():x(e,".pi","agent"),"settings.json")}i($,"resolveSettingsPath");function st(e={}){const t=e.homeDir??k(),n=e.settingsPath??$(t),r=e.manifest??A(),o=ue(n),a=U(o,r,n,t);for(const s of J(r))a.add(s);const u=e.commandExists??g,l=e.packageManager??$e(process.platform,u),c=["tmux","nvim","nerd-font"].map(s=>Ee(s,l,u));return{manifest:r,installedPackageIds:a,systemPlans:c}}i(st,"buildSetupInitialState");function at(e){const t=e.manifest.map(r=>{const o=e.installedPackageIds.has(r.id)?"installed":"not installed";return`- ${r.name} \u2014 ${r.shortDescription} (${o})`}),n=e.systemPlans.map(r=>r.installed?`- ${r.tool}: \u2713 installed`:r.command?`- ${r.tool}: ${r.command}`:`- ${r.tool}: ${r.hint}`);return["crtr sys setup (non-interactive)","","Provider login: open the wizard in a TTY and use the Providers tab (same flow as /login) to authenticate a model provider.","","Packages:",...t,"","System deps:",...n,"",`Inbox: the inbox-toggle key (${ae()??"disabled"}) is a crouter keybinding \u2014 view or rebind it in \`crtr sys settings\`; it is installed on the same tmux server as every other crouter binding.`,"Run `crtr sys setup` in a TTY to open the wizard."].join(`
2
2
  `)+`
3
- `}s(it,"renderSetupStaticInstructions");class w extends Error{static{s(this,"SetupCommandError")}output;constructor(t,n){super(t),this.output=n}}function st(e){return`${e.stdout?.toString()??""}${e.stderr?.toString()??""}`}s(st,"commandOutput");function U(e,t,n){return new Promise((r,o)=>{const i=X(e,t,{stdio:["ignore","pipe","pipe"]});let u="";i.stdout.setEncoding("utf8"),i.stderr.setEncoding("utf8"),i.stdout.on("data",c=>{u+=c}),i.stderr.on("data",c=>{u+=c,n?.(c)}),i.on("error",c=>o(new w(`${e} failed: ${c.message}`,u))),i.on("close",c=>{c===0?r():o(new w(`${e} failed with status ${c??"unknown"}`,u))})})}s(U,"runCapturedCommand");function $(e,t){return U("sh",["-lc",e],t)}s($,"runShellCommand");function Ee(e,t=ue()){return U(process.execPath,[t,"install",e])}s(Ee,"installPiPackage");async function Y(){g("capture")||await $("npm install -g @crouton-kit/capture")}s(Y,"installCaptureCliIfMissing");function z(e){return e instanceof w?e.output:void 0}s(z,"capturedFailureOutput");function Re(e){const n=z(e)?.split(/\r?\n/).find(r=>r.trim()!=="");return n!==void 0?n.trim():e instanceof Error?e.message:String(e)}s(Re,"firstFailureLine");function De(e){const t=z(e);t===void 0||t.length===0||process.stderr.write(t.endsWith(`
3
+ `}i(at,"renderSetupStaticInstructions");class w extends Error{static{i(this,"SetupCommandError")}output;constructor(t,n){super(t),this.output=n}}function ot(e){return`${e.stdout?.toString()??""}${e.stderr?.toString()??""}`}i(ot,"commandOutput");function Y(e,t,n,r=process.env){return new Promise((o,a)=>{const u=Q(e,t,{stdio:["ignore","pipe","pipe"],env:r});let l="";u.stdout.setEncoding("utf8"),u.stderr.setEncoding("utf8"),u.stdout.on("data",c=>{l+=c}),u.stderr.on("data",c=>{l+=c,n?.(c)}),u.on("error",c=>a(new w(`${e} failed: ${c.message}`,l))),u.on("close",c=>{c===0?o():a(new w(`${e} failed with status ${c??"unknown"}`,l))})})}i(Y,"runCapturedCommand");function E(e,t){return Y("sh",["-lc",e],t)}i(E,"runShellCommand");function Re(e,t=le()){return Y(process.execPath,[t,"install",e],void 0,{...process.env,PI_CODING_AGENT_DIR:P()})}i(Re,"installPiPackage");async function z(){g("capture")||await E("npm install -g @crouton-kit/capture")}i(z,"installCaptureCliIfMissing");function W(e){return e instanceof w?e.output:void 0}i(W,"capturedFailureOutput");function De(e){const n=W(e)?.split(/\r?\n/).find(r=>r.trim()!=="");return n!==void 0?n.trim():e instanceof Error?e.message:String(e)}i(De,"firstFailureLine");function Oe(e){const t=W(e);t===void 0||t.length===0||process.stderr.write(t.endsWith(`
4
4
  `)?t:`${t}
5
- `)}s(De,"printCapturedFailure");class Oe{static{s(this,"SetupProgress")}interactive;bar=null;constructor(t=!!process.stdout.isTTY){this.interactive=t}start(t){return this.interactive?(this.bar=be(`Installing ${t}\u2026`),this.bar):null}async clear(){await this.bar?.stop(),this.bar=null}async succeed(t){await this.clear(),this.interactive&&process.stdout.write(`\r\x1B[2K\u2713 ${t}
6
- `)}async fail(t,n){await this.clear(),this.interactive&&process.stdout.write(`\r\x1B[2K\u2717 ${t} \u2014 ${Re(n)}
7
- `),De(n)}async run(t,n){const r=this.start(t);try{const o=await n(r);return await this.succeed(t),o}catch(o){throw await this.fail(t,o),o}}}function W(e,t){return O()?"current":(e?.(),ve(t),O()?"provisioned":"unavailable")}s(W,"ensureManagedRenderer");async function Te(){try{de()}catch{}}s(Te,"reconcileInboxFrontDoor");function q(e,t){return t.length===0?[`${e}: none`]:[`${e}:`,...t.map(n=>` - ${n}`)]}s(q,"summarySection");function at(e){return["crtr sys setup complete",...q("installed",e.installed),...q("skipped",e.skipped),"New to crouter? Ask for the tutorial in your first conversation, or run /tutorial any time."].join(`
5
+ `)}i(Oe,"printCapturedFailure");class Te{static{i(this,"SetupProgress")}interactive;bar=null;constructor(t=!!process.stdout.isTTY){this.interactive=t}start(t){return this.interactive?(this.bar=be(`Installing ${t}\u2026`),this.bar):null}async clear(){await this.bar?.stop(),this.bar=null}async succeed(t){await this.clear(),this.interactive&&process.stdout.write(`\r\x1B[2K\u2713 ${t}
6
+ `)}async fail(t,n){await this.clear(),this.interactive&&process.stdout.write(`\r\x1B[2K\u2717 ${t} \u2014 ${De(n)}
7
+ `),Oe(n)}async run(t,n){const r=this.start(t);try{const o=await n(r);return await this.succeed(t),o}catch(o){throw await this.fail(t,o),o}}}function q(e,t){return T()?"current":(e?.(),ve(t),T()?"provisioned":"unavailable")}i(q,"ensureManagedRenderer");async function Ne(){try{pe()}catch{}}i(Ne,"reconcileInboxFrontDoor");function H(e,t){return t.length===0?[`${e}: none`]:[`${e}:`,...t.map(n=>` - ${n}`)]}i(H,"summarySection");function ct(e){return["crtr sys setup complete",...H("installed",e.installed),...H("skipped",e.skipped),"New to crouter? Ask for the tutorial in your first conversation, or run /tutorial any time."].join(`
8
8
  `)+`
9
- `}s(at,"formatSetupExecutionSummary");function H(e,t){const n=[];for(const r of e)try{r.sourceKind==="marketplace-source"?N(r.name,t)!==null&&n.push(r.id):r.sourceKind==="marketplace-plugin"&&xe(r.name,t)!==null&&n.push(r.id)}catch{}return n}s(H,"detectInstalledMarketplaceEntries");function Ne(e,t="user"){if(N(e,t)!==null)return null;if(e!==L)throw new Error(`marketplace not registered: ${e}`);return T({url:_,ref:M,scope:t}),e}s(Ne,"ensureMarketplaceRegistered");function Le(e){const t=A(),n=D(t);if(!n||typeof n!="object"||Array.isArray(n))throw new Error(`invalid pi settings: ${t}`);const r=n.packages;if(!Array.isArray(r))throw new Error(`invalid pi packages: ${t}`);const o=s(c=>{const l=typeof c=="string"?c:c&&typeof c=="object"?c.source:void 0;return typeof l=="string"&&B(l).includes(v("pi-crtr-extensions"))},"isCrtrExtensions"),i=r.findIndex(o),u=r.filter(c=>!o(c));u.splice(i<0?u.length:i,0,{source:ee(R(t),e),extensions:j}),oe(t,{...n,packages:u})}s(Le,"configureCrtrExtensions");async function J(e){if(e.sourceKind==="marketplace-source")return T({url:e.installSource,ref:M,scope:"user"}),[e.name];if(e.sourceKind==="marketplace-plugin"){const[t,n]=e.installSource.split("/"),r=Ne(t);return await we({marketplace:t,plugin:n},"user"),e.id==="capture-plugin"&&await Y(),r===null?[e.name]:[r,e.name]}return await Ee(e.installSource),e.id==="crtr-extensions"&&Le(e.installSource),[e.name]}s(J,"installSetupPackage");async function ot(e){const t=S(),n=G(D(A()),t);for(const i of H(t,"user"))n.add(i);const r=new Map(t.map(i=>[i.id,i])),o=process.stdin.isTTY&&process.stdout.isTTY?["crtr-extensions","official-marketplace","oauth-adapter","capture-plugin","search-plugin"]:["crtr-extensions","official-marketplace","capture-plugin","search-plugin"];for(const i of o){const u=r.get(i);if(!n.has(i))try{await J(u)}catch(c){e(u.name,c)}}try{W(void 0,()=>{})==="unavailable"&&e("termrender renderer",new Error("unavailable \u2014 install uv"))}catch(i){e("termrender renderer",i)}return le()}s(ot,"reconcileFirstRun");async function ct(e){const t=[],n=[],r=[],o=[],i=new Oe;for(const a of e.packages){if(e.installedPackageIds.has(a.id)){if(n.push(`${a.name} (already installed)`),a.id==="capture-plugin"&&!g("capture"))try{await i.run("Capture CLI",()=>Y()),t.push("Capture CLI")}catch(d){n.push(`Capture CLI (${d instanceof Error?d.message:String(d)})`)}continue}try{t.push(...await i.run(a.name,()=>J(a)))}catch(d){if(a.sourceKind!=="marketplace-source"&&a.sourceKind!=="marketplace-plugin")throw d;n.push(`${a.name} (${d instanceof Error?d.message:String(d)})`)}}for(const a of e.systemDeps){if(a.installed){o.push(`${a.tool} (already installed)`);continue}if(!a.autoInstall||!a.command){o.push(`${a.tool} (${a.hint})`);continue}const d=a.command,p=d===ge;await i.run(a.tool,h=>{if(!p||h===null)return $(d);const x=me();return $(d,y=>{const E=x(y);E!==null&&h.setFraction(E/100)})}),r.push(a.tool)}const u=[];let c=!1,l;try{l=W(()=>{c=!0,i.start("termrender renderer")},a=>u.push(a))}catch(a){throw c&&await i.fail("termrender renderer",a),a}switch(l){case"provisioned":c&&await i.succeed("termrender renderer"),t.push("termrender renderer");break;case"current":n.push("termrender renderer (current)");break;case"unavailable":{const a=new w("unavailable \u2014 install uv",u.join(""));c&&await i.fail("termrender renderer",a),n.push("termrender renderer (unavailable \u2014 install uv)");break}}return await Te(),{installed:[...t,...r],skipped:[...n,...o]}}s(ct,"executeSetupSubmission");export{L as OFFICIAL_MARKETPLACE_NAME,M as OFFICIAL_MARKETPLACE_REF,_ as OFFICIAL_MARKETPLACE_URL,tt as SetupKeybindingsDraft,rt as buildSetupInitialState,S as buildSetupManifest,$e as buildSystemInstallPlan,g as detectCommandOnPath,G as detectInstalledSetupPackageIds,Ae as detectPackageManager,ct as executeSetupSubmission,at as formatSetupExecutionSummary,b as normalizePackageIdentity,nt as packagePlanAction,ot as reconcileFirstRun,Te as reconcileInboxFrontDoor,it as renderSetupStaticInstructions,A as resolveSettingsPath};
9
+ `}i(ct,"formatSetupExecutionSummary");function J(e,t){const n=[];for(const r of e)try{r.sourceKind==="marketplace-source"?_(r.name,t)!==null&&n.push(r.id):r.sourceKind==="marketplace-plugin"&&ye(r.name,t)!==null&&n.push(r.id)}catch{}return n}i(J,"detectInstalledMarketplaceEntries");function _e(e,t="user"){if(_(e,t)!==null)return null;if(e!==L)throw new Error(`marketplace not registered: ${e}`);return N({url:M,ref:K,scope:t}),e}i(_e,"ensureMarketplaceRegistered");function Le(e){const t=$(),n=O(t);if(!n||typeof n!="object"||Array.isArray(n))throw new Error(`invalid pi settings: ${t}`);const r=n.packages;if(!Array.isArray(r))throw new Error(`invalid pi packages: ${t}`);const o=i(l=>{const c=typeof l=="string"?l:l&&typeof l=="object"?l.source:void 0;return typeof c=="string"&&B(c).includes(v("pi-crtr-extensions"))},"isCrtrExtensions"),a=r.findIndex(o),u=r.filter(l=>!o(l));u.splice(a<0?u.length:a,0,{source:te(D(t),e),extensions:F}),ce(t,{...n,packages:u})}i(Le,"configureCrtrExtensions");async function V(e){if(e.sourceKind==="marketplace-source")return N({url:e.installSource,ref:K,scope:"user"}),[e.name];if(e.sourceKind==="marketplace-plugin"){const[t,n]=e.installSource.split("/"),r=_e(t);return await we({marketplace:t,plugin:n},"user"),e.id==="capture-plugin"&&await z(),r===null?[e.name]:[r,e.name]}return await Re(e.installSource),e.id==="crtr-extensions"&&Le(e.installSource),[e.name]}i(V,"installSetupPackage");async function ut(e){const t=A(),n=U(O($()),t);for(const a of J(t,"user"))n.add(a);const r=new Map(t.map(a=>[a.id,a])),o=process.stdin.isTTY&&process.stdout.isTTY?["crtr-extensions","official-marketplace","oauth-adapter","capture-plugin","exa-search-plugin"]:["crtr-extensions","official-marketplace","capture-plugin","exa-search-plugin"];for(const a of o){const u=r.get(a);if(!n.has(a))try{await V(u)}catch(l){e(u.name,l)}}try{q(void 0,()=>{})==="unavailable"&&e("termrender renderer",new Error("unavailable \u2014 install uv"))}catch(a){e("termrender renderer",a)}return de()}i(ut,"reconcileFirstRun");async function lt(e){const t=[],n=[],r=[],o=[],a=new Te;for(const s of e.packages){if(e.installedPackageIds.has(s.id)){if(n.push(`${s.name} (already installed)`),s.id==="capture-plugin"&&!g("capture"))try{await a.run("Capture CLI",()=>z()),t.push("Capture CLI")}catch(d){n.push(`Capture CLI (${d instanceof Error?d.message:String(d)})`)}continue}try{t.push(...await a.run(s.name,()=>V(s)))}catch(d){if(s.sourceKind!=="marketplace-source"&&s.sourceKind!=="marketplace-plugin")throw d;n.push(`${s.name} (${d instanceof Error?d.message:String(d)})`)}}for(const s of e.systemDeps){if(s.installed){o.push(`${s.tool} (already installed)`);continue}if(!s.autoInstall||!s.command){o.push(`${s.tool} (${s.hint})`);continue}const d=s.command,p=d===ke;await a.run(s.tool,h=>{if(!p||h===null)return E(d);const y=ge();return E(d,I=>{const R=y(I);R!==null&&h.setFraction(R/100)})}),r.push(s.tool)}const u=[];let l=!1,c;try{c=q(()=>{l=!0,a.start("termrender renderer")},s=>u.push(s))}catch(s){throw l&&await a.fail("termrender renderer",s),s}switch(c){case"provisioned":l&&await a.succeed("termrender renderer"),t.push("termrender renderer");break;case"current":n.push("termrender renderer (current)");break;case"unavailable":{const s=new w("unavailable \u2014 install uv",u.join(""));l&&await a.fail("termrender renderer",s),n.push("termrender renderer (unavailable \u2014 install uv)");break}}return await Ne(),{installed:[...t,...r],skipped:[...n,...o]}}i(lt,"executeSetupSubmission");export{L as OFFICIAL_MARKETPLACE_NAME,K as OFFICIAL_MARKETPLACE_REF,M as OFFICIAL_MARKETPLACE_URL,rt as SetupKeybindingsDraft,st as buildSetupInitialState,A as buildSetupManifest,Ee as buildSystemInstallPlan,g as detectCommandOnPath,U as detectInstalledSetupPackageIds,$e as detectPackageManager,lt as executeSetupSubmission,ct as formatSetupExecutionSummary,b as normalizePackageIdentity,it as packagePlanAction,ut as reconcileFirstRun,Ne as reconcileInboxFrontDoor,at as renderSetupStaticInstructions,$ as resolveSettingsPath};
@@ -1 +1 @@
1
- var p=Object.defineProperty;var i=(r,t)=>p(r,"name",{value:t,configurable:!0});import{ModelRegistry as c,ModelRuntime as d}from"@earendil-works/pi-coding-agent";import{join as n}from"node:path";import{piAgentDir as u}from"../../core/runtime/package-health.js";import{PoolCredentialStore as l}from"../../core/pool-credential-store.js";import{initializeFreshScopedStore as f}from"../../core/scoped-state/migrate.js";import{runTuiPage as g}from"../../core/tui/page-host.js";async function M(r,t){const o=u();f({kind:"provider",root:o});const e=await d.create({credentials:new l(n(o,"auth.json")),modelsPath:n(o,"models.json")}),m=new c(e);return g((s,a)=>r({...s,agentDir:o,runtime:e,registry:m},a),t)}i(M,"runSetupSettingsProcess");export{M as runSetupSettingsProcess};
1
+ var c=Object.defineProperty;var i=(r,o)=>c(r,"name",{value:o,configurable:!0});import{ModelRegistry as d,ModelRuntime as u}from"@earendil-works/pi-coding-agent";import{join as n}from"node:path";import{piAgentDir as f}from"../../core/runtime/package-health.js";import{secretsDir as m}from"../../core/layout.js";import{PoolCredentialStore as l}from"../../core/pool-credential-store.js";import{initializeFreshScopedStore as g}from"../../core/scoped-state/migrate.js";import{runTuiPage as S}from"../../core/tui/page-host.js";async function k(r,o){const t=f();g({kind:"provider",root:m()});const e=await u.create({credentials:new l(n(m(),"auth.json")),modelsPath:n(t,"models.json")}),s=new d(e);return S((p,a)=>r({...p,agentDir:t,runtime:e,registry:s},a),o)}i(k,"runSetupSettingsProcess");export{k as runSetupSettingsProcess};
@@ -1 +1 @@
1
- var a=Object.defineProperty;var e=(n,t)=>a(n,"name",{value:t,configurable:!0});import{defineLeaf as s}from"../../core/command.js";const r="Valid CRTR_WARN_LIVE_BROKERS and CRTR_MAX_LIVE_BROKERS environment overrides take precedence over their corresponding configured limits.",l=s({name:"setup",description:"bootstrap a fresh machine \u2014 provider login, companion packages, system dependencies",whenToUse:"you are setting up crouter on a machine for the first time and need credentials and installs in place. Use sys settings to change configuration on an installed machine, and sys config set for scriptable edits.",help:{name:"sys setup",summary:"run the first-run installer: provider login, companion packages, system dependencies",inputNote:"No input parameters.",output:[],outputKind:"object",effects:["Opens a three-step pi-tui installer. Step one logs in to a model provider (pi's real OAuth/API-key flow, same as in-app /login) so a fresh install has credentials before running any node.","The remaining steps collect companion package installs and system dependency installs, then confirm them all at once.","Runs the bundled pi CLI to install the selected companion packages and prints a summary.","The companion-package list includes the official crtr marketplace and the plugins installed from it (currently `capture` and `search`), all checked by default and registered or installed into the user scope when left checked. Nothing else registers a marketplace, so an install that never runs setup fetches no catalog. An unreachable marketplace is reported as skipped rather than failing setup. Vendor credentials belong to the plugin that needs them, never to setup.","On every invocation (best-effort, idempotent), refreshes crouter-owned tmux bindings and registers known nodes' interaction roots so resolved tickets can call back into the asking node. The inbox popup toggle is a crouter-owned keybinding, editable on the keybindings tab."]},run:e(async()=>{await(await import("./setup-wizard.js")).runSetup()},"run"),render:e(()=>"","render")});export{r as BROKER_LIMIT_OVERRIDE_PRECEDENCE,l as sysSetupLeaf};
1
+ var a=Object.defineProperty;var e=(n,t)=>a(n,"name",{value:t,configurable:!0});import{defineLeaf as s}from"../../core/command.js";const r="Valid CRTR_WARN_LIVE_BROKERS and CRTR_MAX_LIVE_BROKERS environment overrides take precedence over their corresponding configured limits.",l=s({name:"setup",description:"bootstrap a fresh machine \u2014 provider login, companion packages, system dependencies",whenToUse:"you are setting up crouter on a machine for the first time and need credentials and installs in place. Use sys settings to change configuration on an installed machine, and sys config set for scriptable edits.",help:{name:"sys setup",summary:"run the first-run installer: provider login, companion packages, system dependencies",inputNote:"No input parameters.",output:[],outputKind:"object",effects:["Opens a three-step pi-tui installer. Step one logs in to a model provider (pi's real OAuth/API-key flow, same as in-app /login) so a fresh install has credentials before running any node.","The remaining steps collect companion package installs and system dependency installs, then confirm them all at once.","Runs the bundled pi CLI to install the selected companion packages and prints a summary.","The companion-package list includes the official crtr marketplace and the plugins installed from it (currently `capture` and `exa-search`), all checked by default and registered or installed into the user scope when left checked. Nothing else registers a marketplace, so an install that never runs setup fetches no catalog. An unreachable marketplace is reported as skipped rather than failing setup. Vendor credentials belong to the plugin that needs them, never to setup.","On every invocation (best-effort, idempotent), refreshes crouter-owned tmux bindings and registers known nodes' interaction roots so resolved tickets can call back into the asking node. The inbox popup toggle is a crouter-owned keybinding, editable on the keybindings tab."]},run:e(async()=>{await(await import("./setup-wizard.js")).runSetup()},"run"),render:e(()=>"","render")});export{r as BROKER_LIMIT_OVERRIDE_PRECEDENCE,l as sysSetupLeaf};
@@ -0,0 +1 @@
1
+ export declare const sysSpacesLeaf: import("../../core/command.js").LeafDef;
@@ -0,0 +1,2 @@
1
+ var t=Object.defineProperty;var a=(s,e)=>t(s,"name",{value:e,configurable:!0});import{defineLeaf as p}from"../../core/command.js";import{cliClient as c}from"../api-client.js";import{formatSize as i}from"./worktrees.js";const m=p({name:"spaces",description:"list every space on the runtime with its size",whenToUse:"you need to see how much disk the person's space and each app's space occupy on this runtime",help:{name:"sys spaces",summary:"list the person's space and every app space with its size",params:[],output:[{name:"spaces",type:"SpaceDTO[]",required:!0,constraint:"`user` first, then each app space by id. Each record: {space, path, size_bytes}; size_bytes is null when the space cannot be measured."}],outputKind:"object",effects:["None. Read-only."]},run:a(async()=>({spaces:(await c().listSpaces()).spaces}),"run"),render:a(s=>s.spaces.map(e=>`- \`${e.space}\` \u2014 ${i(e.size_bytes)} \xB7 \`${e.path}\``).join(`
2
+ `),"render")});export{m as sysSpacesLeaf};
@@ -1,9 +1,9 @@
1
- var ce=Object.defineProperty;var u=(s,n)=>ce(s,"name",{value:n,configurable:!0});import{copyFileSync as de,mkdirSync as ae,readdirSync as le,rmSync as pe}from"node:fs";import{basename as ue,dirname as S,join as m,relative as P,resolve as H,sep as z}from"node:path";import{defineLeaf as me}from"../../core/command.js";import{usage as A}from"../../core/errors.js";import{parseFrontmatterGeneric as J}from"../../core/frontmatter.js";import{pathExists as N,readJsonIfExists as U,readText as I,walkFiles as Q,writeText as W}from"../../core/fs-utils.js";import{composeCanonicalName as ge}from"../../core/memory/identity.js";import{openProjectMemoryStore as fe}from"../../core/memory-resolver.js";import{requireMountedStore as he,serializeMemoryDoc as C}from"../memory/shared.js";import{routeFromDescription as ke,scalarString as ye}from"./sync-shared.js";import{isRecord as L}from"../../shared/predicates.js";const T="crtr sys sync deps";function y(s){throw A(`--deps: invalid package.json crtr.sync.deps.exclude: ${s}`)}u(y,"invalidDepsConfig");function be(s){const n=U(m(s,"package.json"));L(n)||y("package.json must contain an object");const o=n.crtr;if(o===void 0)return[];L(o)||y("crtr must be an object");const a=o.sync;if(a===void 0)return[];L(a)||y("crtr.sync must be an object");const r=a.deps;if(r===void 0)return[];L(r)||y("crtr.sync.deps must be an object");const l=r.exclude;if(l===void 0)return[];Array.isArray(l)||y("exclude must be an array of {package, version, skill} selectors");const g=new Set;return l.map(($,i)=>{L($)||y(`exclude[${i}] must be an object with exactly package, version, and skill`),Object.keys($).sort().join(",")!=="package,skill,version"&&y(`exclude[${i}] must contain exactly package, version, and skill`);const f=$.package,x=$.version,h=$.skill;(typeof f!="string"||!$e.test(f))&&y(`exclude[${i}].package must be one exact npm package name`),(typeof x!="string"||!we.test(x))&&y(`exclude[${i}].version must be one exact installed semver version`),(typeof h!="string"||h===""||h!=="."&&(h.startsWith("/")||h.split("/").some(R=>R===""||R==="."||R==="..")||/[\\*?[\]{}]/.test(h)))&&y(`exclude[${i}].skill must be one exact POSIX path relative to the package skills/ directory (use . for a root SKILL.md)`);const w={package:f,version:x,skill:h},D=`${f}\0${x}\0${h}`;return g.has(D)&&y(`exclude[${i}] duplicates ${f}@${x} skill ${h}`),g.add(D),w})}u(be,"readDepsExclusions");const $e=/^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/,Y="(?:0|[1-9]\\d*|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*)",we=new RegExp(`^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-${Y}(?:\\.${Y})*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$`);function _(s,n,o){return`${s}\0${n}\0${o}`}u(_,"exclusionKey");function ve(s,n,o){return s.has(_(n.pkg,n.version,o))}u(ve,"isExcluded");function je(s){if(s!==void 0)return H(s);let n=H(process.cwd());for(;;){if(N(m(n,"package.json")))return n;const o=S(n);if(o===n)throw A("--deps: no package.json found from cwd upward; run inside a Node project or pass --source <project-dir>");n=o}}u(je,"depsProjectDir");function xe(s){const n=[];for(const a of ee(s))if(!a.startsWith("."))if(a.startsWith("@"))for(const r of ee(m(s,a)))n.push(m(s,a,r));else n.push(m(s,a));const o=[];for(const a of n.sort()){const r=m(a,"skills");if(!N(r))continue;const l=U(m(a,"package.json"));o.push({pkg:l?.name??P(s,a).split(z).join("/"),version:l?.version??"",skillsRoot:r})}return o}u(xe,"skillsPackages");function ee(s){try{return le(s)}catch{return[]}}u(ee,"listDirNames");function Re(s,n){return n.find(o=>s===o||s.startsWith(`${o}${z}`))}u(Re,"owningBundle");function se(s,n=220){const o=s.replace(/\s+/g," ").trim(),a=o.split(/(?<=[.!?])\s+/)[0]??o,r=a.length>=30?a:o;if(r.length<=n)return r;const l=r.slice(0,n),g=l.lastIndexOf(" ");return`${l.slice(0,g>80?g:n).trimEnd()}\u2026`}u(se,"condenseDescription");const Ee=["name","description","type","keywords","kind","when-and-why-to-read","short-form","unlisted","surfaces","gate","rationale"];function ne(s){const n={...s};for(const o of Ee)delete n[o];return n}u(ne,"passthroughFm");function Se(s){const n=s.match(/^#{1,6}\s+(.+)$/m);return n?n[1].trim():void 0}u(Se,"firstHeading");function De(s){const n=je(s.sourceArg),o=m(n,"node_modules");if(!N(o))throw A(`sys sync deps: ${o} does not exist; install dependencies first (npm ci / npm install), then re-run`);const a=he(fe(n)),r=m(a.storeRoot,"deps"),l=ge(a.namespace,"deps"),g=be(n),$=new Set(g.map(e=>_(e.package,e.version,e.skill))),i=new Map(g.map(e=>[_(e.package,e.version,e.skill),0])),j=new Map,f=[],x=xe(o),h=[];for(const e of x){const t=[],c=new Set;for(const d of Q(e.skillsRoot,p=>p==="SKILL.md",p=>p==="node_modules"||p===".git")){const p=S(d);t.push(p);const k=S(P(e.skillsRoot,d).split(z).join("/"));if(!ve($,e,k))continue;const v=_(e.pkg,e.version,k);i.set(v,(i.get(v)??0)+1),c.add(p),f.push({source:d,target:"\u2014",name:`${e.pkg}@${e.version}:${k}`,scope:"project",status:"excluded",reason:"matched package.json crtr.sync.deps.exclude"})}h.push({...e,bundleRoots:t.sort((d,p)=>p.length-d.length),excludedBundleRoots:c})}for(const e of g){const t=_(e.package,e.version,e.skill),c=i.get(t);if(c!==1)throw A(`--deps: package.json crtr.sync.deps.exclude selector ${e.package}@${e.version}:${e.skill} ${c===0?"does not match an installed dependency skill bundle":`matches ${c} installed dependency skill bundles`}; update or remove the selector before syncing`)}for(const e of h){const t=e.bundleRoots??[],c=e.excludedBundleRoots??new Set;for(const d of Q(e.skillsRoot,()=>!0,p=>p==="node_modules"||p===".git")){const p=Re(d,t);if(p===void 0||c.has(p))continue;const k=P(e.skillsRoot,d).split(z).join("/");let v,b;if(ue(d)==="SKILL.md"){const Z=S(k),q=Z==="."?e.pkg.split("/").pop()??e.pkg:Z;b=`${q}/INDEX.md`;let X={},K="";try{const V=J(I(d));X=V.data??{},K=V.body}catch{K=I(d)}v={kind:"skill",sourceAbs:d,pkg:e.pkg,version:e.version,bundleRel:q,fm:X,body:K,description:ye(X.description)??""}}else k.toLowerCase().endsWith(".md")?(b=k,v={kind:"sidecar-md",sourceAbs:d,pkg:e.pkg,version:e.version}):(b=k,v={kind:"asset",sourceAbs:d,pkg:e.pkg});if(b==="INDEX.md")continue;const E=j.get(b);if(E){v.kind==="skill"&&f.push({source:d,target:m(r,...b.split("/")),name:`${l}/${S(b)}`,scope:"project",status:"skipped",reason:`collides with same-named bundle from ${E.pkg}`});continue}j.set(b,v)}}const w=[...j.entries()].filter(e=>e[1].kind==="skill"),D=w.map(([,e])=>e.bundleRel).sort((e,t)=>t.length-e.length),R=new Map;for(const[e,t]of j){if(t.kind==="skill")continue;const c=D.find(d=>e.startsWith(`${d}/`));c&&R.set(c,(R.get(c)??0)+1)}const B=new Set(w.map(([,e])=>`${e.pkg}@${e.version}`)),G=s.dryRun?"would-import":"imported";for(const[e,t]of w){const c=R.get(t.bundleRel)??0;f.push({source:t.sourceAbs,target:m(r,...e.split("/")),name:`${l}/${t.bundleRel}`,scope:"project",status:G,...c>0?{reason:`+${c} sidecar file${c===1?"":"s"}`}:{}})}if(f.push({source:o,target:m(r,"INDEX.md"),name:l,scope:"project",status:G,reason:`generated catalog of ${w.length} docs from ${B.size} package${B.size===1?"":"s"}`}),s.dryRun)return f;if(N(r)){const e=m(r,"INDEX.md");if(!(N(e)&&I(e).includes(T)))throw A(`--deps: ${r} exists but its INDEX.md does not carry the "${T}" marker; it may be hand-authored \u2014 move or delete it manually before vendoring dependency docs there`);pe(r,{recursive:!0,force:!0})}for(const[e,t]of j){const c=m(r,...e.split("/"));if(t.kind==="skill"){const d={kind:"knowledge","when-and-why-to-read":ke(t.description,"knowledge"),"short-form":t.description!==""?se(t.description):`Vendored agent doc shipped by ${t.pkg}.`,surfaces:[{on:"boot",at:"name"}],"source-package":`${t.pkg}@${t.version}`,...ne(t.fm)};W(c,C(d,t.body))}else if(t.kind==="sidecar-md"){let d={},p;try{const E=J(I(t.sourceAbs));d=E.data??{},p=E.body}catch{p=I(t.sourceAbs)}const k=D.find(E=>e.startsWith(`${E}/`)),b={kind:"knowledge","when-and-why-to-read":`When ${k?`${l}/${k}`:`a ${l} document`} links to this file, this knowledge should be read because it carries the linked supporting reference.`,"short-form":Se(p)??`Supporting reference vendored from ${t.pkg}.`,surfaces:[{on:"boot",at:"name"}],"source-package":`${t.pkg}@${t.version}`,...ne(d)};W(c,C(b,p))}else ae(S(c),{recursive:!0}),de(t.sourceAbs,c)}const O=[...new Set(w.map(([,e])=>e.pkg))],te=O.slice(0,6).join(", ")+(O.length>6?", \u2026":""),F=new Map;for(const[,e]of w){const t=`${e.pkg}@${e.version}`,c=F.get(t)??{version:e.version,lines:[]},d=e.description!==""?` \u2014 ${se(e.description,180)}`:"";c.lines.push(`- \`${l}/${e.bundleRel}\`${d}`),F.set(t,c)}const oe=[...F.entries()].map(([e,{lines:t}])=>`## ${e}
1
+ var ce=Object.defineProperty;var u=(s,n)=>ce(s,"name",{value:n,configurable:!0});import{copyFileSync as de,mkdirSync as ae,readdirSync as le,rmSync as pe}from"node:fs";import{basename as ue,dirname as S,join as m,relative as P,resolve as H,sep as z}from"node:path";import{defineLeaf as me}from"../../core/command.js";import{usage as A}from"../../core/errors.js";import{parseFrontmatterGeneric as J}from"../../core/frontmatter.js";import{pathExists as N,readJsonIfExists as U,readText as I,walkFiles as Q,writeText as W}from"../../core/fs-utils.js";import{composeCanonicalName as ge}from"../../core/memory/identity.js";import{openProjectMemoryStore as fe}from"../../core/memory-resolver.js";import{requireMountedStore as he,serializeMemoryDoc as C}from"../../core/memory/mutation-domain.js";import{routeFromDescription as ke,scalarString as ye}from"./sync-shared.js";import{isRecord as L}from"../../shared/predicates.js";const T="crtr sys sync deps";function y(s){throw A(`--deps: invalid package.json crtr.sync.deps.exclude: ${s}`)}u(y,"invalidDepsConfig");function be(s){const n=U(m(s,"package.json"));L(n)||y("package.json must contain an object");const o=n.crtr;if(o===void 0)return[];L(o)||y("crtr must be an object");const a=o.sync;if(a===void 0)return[];L(a)||y("crtr.sync must be an object");const r=a.deps;if(r===void 0)return[];L(r)||y("crtr.sync.deps must be an object");const l=r.exclude;if(l===void 0)return[];Array.isArray(l)||y("exclude must be an array of {package, version, skill} selectors");const g=new Set;return l.map(($,i)=>{L($)||y(`exclude[${i}] must be an object with exactly package, version, and skill`),Object.keys($).sort().join(",")!=="package,skill,version"&&y(`exclude[${i}] must contain exactly package, version, and skill`);const f=$.package,x=$.version,h=$.skill;(typeof f!="string"||!$e.test(f))&&y(`exclude[${i}].package must be one exact npm package name`),(typeof x!="string"||!we.test(x))&&y(`exclude[${i}].version must be one exact installed semver version`),(typeof h!="string"||h===""||h!=="."&&(h.startsWith("/")||h.split("/").some(R=>R===""||R==="."||R==="..")||/[\\*?[\]{}]/.test(h)))&&y(`exclude[${i}].skill must be one exact POSIX path relative to the package skills/ directory (use . for a root SKILL.md)`);const w={package:f,version:x,skill:h},D=`${f}\0${x}\0${h}`;return g.has(D)&&y(`exclude[${i}] duplicates ${f}@${x} skill ${h}`),g.add(D),w})}u(be,"readDepsExclusions");const $e=/^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/,Y="(?:0|[1-9]\\d*|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*)",we=new RegExp(`^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-${Y}(?:\\.${Y})*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$`);function _(s,n,o){return`${s}\0${n}\0${o}`}u(_,"exclusionKey");function ve(s,n,o){return s.has(_(n.pkg,n.version,o))}u(ve,"isExcluded");function je(s){if(s!==void 0)return H(s);let n=H(process.cwd());for(;;){if(N(m(n,"package.json")))return n;const o=S(n);if(o===n)throw A("--deps: no package.json found from cwd upward; run inside a Node project or pass --source <project-dir>");n=o}}u(je,"depsProjectDir");function xe(s){const n=[];for(const a of ee(s))if(!a.startsWith("."))if(a.startsWith("@"))for(const r of ee(m(s,a)))n.push(m(s,a,r));else n.push(m(s,a));const o=[];for(const a of n.sort()){const r=m(a,"skills");if(!N(r))continue;const l=U(m(a,"package.json"));o.push({pkg:l?.name??P(s,a).split(z).join("/"),version:l?.version??"",skillsRoot:r})}return o}u(xe,"skillsPackages");function ee(s){try{return le(s)}catch{return[]}}u(ee,"listDirNames");function Re(s,n){return n.find(o=>s===o||s.startsWith(`${o}${z}`))}u(Re,"owningBundle");function se(s,n=220){const o=s.replace(/\s+/g," ").trim(),a=o.split(/(?<=[.!?])\s+/)[0]??o,r=a.length>=30?a:o;if(r.length<=n)return r;const l=r.slice(0,n),g=l.lastIndexOf(" ");return`${l.slice(0,g>80?g:n).trimEnd()}\u2026`}u(se,"condenseDescription");const Ee=["name","description","type","keywords","kind","when-and-why-to-read","short-form","unlisted","surfaces","gate","rationale"];function ne(s){const n={...s};for(const o of Ee)delete n[o];return n}u(ne,"passthroughFm");function Se(s){const n=s.match(/^#{1,6}\s+(.+)$/m);return n?n[1].trim():void 0}u(Se,"firstHeading");function De(s){const n=je(s.sourceArg),o=m(n,"node_modules");if(!N(o))throw A(`sys sync deps: ${o} does not exist; install dependencies first (npm ci / npm install), then re-run`);const a=he(fe(n)),r=m(a.storeRoot,"deps"),l=ge(a.namespace,"deps"),g=be(n),$=new Set(g.map(e=>_(e.package,e.version,e.skill))),i=new Map(g.map(e=>[_(e.package,e.version,e.skill),0])),j=new Map,f=[],x=xe(o),h=[];for(const e of x){const t=[],c=new Set;for(const d of Q(e.skillsRoot,p=>p==="SKILL.md",p=>p==="node_modules"||p===".git")){const p=S(d);t.push(p);const k=S(P(e.skillsRoot,d).split(z).join("/"));if(!ve($,e,k))continue;const v=_(e.pkg,e.version,k);i.set(v,(i.get(v)??0)+1),c.add(p),f.push({source:d,target:"\u2014",name:`${e.pkg}@${e.version}:${k}`,scope:"project",status:"excluded",reason:"matched package.json crtr.sync.deps.exclude"})}h.push({...e,bundleRoots:t.sort((d,p)=>p.length-d.length),excludedBundleRoots:c})}for(const e of g){const t=_(e.package,e.version,e.skill),c=i.get(t);if(c!==1)throw A(`--deps: package.json crtr.sync.deps.exclude selector ${e.package}@${e.version}:${e.skill} ${c===0?"does not match an installed dependency skill bundle":`matches ${c} installed dependency skill bundles`}; update or remove the selector before syncing`)}for(const e of h){const t=e.bundleRoots??[],c=e.excludedBundleRoots??new Set;for(const d of Q(e.skillsRoot,()=>!0,p=>p==="node_modules"||p===".git")){const p=Re(d,t);if(p===void 0||c.has(p))continue;const k=P(e.skillsRoot,d).split(z).join("/");let v,b;if(ue(d)==="SKILL.md"){const Z=S(k),q=Z==="."?e.pkg.split("/").pop()??e.pkg:Z;b=`${q}/INDEX.md`;let X={},K="";try{const V=J(I(d));X=V.data??{},K=V.body}catch{K=I(d)}v={kind:"skill",sourceAbs:d,pkg:e.pkg,version:e.version,bundleRel:q,fm:X,body:K,description:ye(X.description)??""}}else k.toLowerCase().endsWith(".md")?(b=k,v={kind:"sidecar-md",sourceAbs:d,pkg:e.pkg,version:e.version}):(b=k,v={kind:"asset",sourceAbs:d,pkg:e.pkg});if(b==="INDEX.md")continue;const E=j.get(b);if(E){v.kind==="skill"&&f.push({source:d,target:m(r,...b.split("/")),name:`${l}/${S(b)}`,scope:"project",status:"skipped",reason:`collides with same-named bundle from ${E.pkg}`});continue}j.set(b,v)}}const w=[...j.entries()].filter(e=>e[1].kind==="skill"),D=w.map(([,e])=>e.bundleRel).sort((e,t)=>t.length-e.length),R=new Map;for(const[e,t]of j){if(t.kind==="skill")continue;const c=D.find(d=>e.startsWith(`${d}/`));c&&R.set(c,(R.get(c)??0)+1)}const B=new Set(w.map(([,e])=>`${e.pkg}@${e.version}`)),G=s.dryRun?"would-import":"imported";for(const[e,t]of w){const c=R.get(t.bundleRel)??0;f.push({source:t.sourceAbs,target:m(r,...e.split("/")),name:`${l}/${t.bundleRel}`,scope:"project",status:G,...c>0?{reason:`+${c} sidecar file${c===1?"":"s"}`}:{}})}if(f.push({source:o,target:m(r,"INDEX.md"),name:l,scope:"project",status:G,reason:`generated catalog of ${w.length} docs from ${B.size} package${B.size===1?"":"s"}`}),s.dryRun)return f;if(N(r)){const e=m(r,"INDEX.md");if(!(N(e)&&I(e).includes(T)))throw A(`--deps: ${r} exists but its INDEX.md does not carry the "${T}" marker; it may be hand-authored \u2014 move or delete it manually before vendoring dependency docs there`);pe(r,{recursive:!0,force:!0})}for(const[e,t]of j){const c=m(r,...e.split("/"));if(t.kind==="skill"){const d={kind:"knowledge",privacy:"public","when-and-why-to-read":ke(t.description,"knowledge"),"short-form":t.description!==""?se(t.description):`Vendored agent doc shipped by ${t.pkg}.`,surfaces:[{on:"boot",at:"name"}],"source-package":`${t.pkg}@${t.version}`,...ne(t.fm)};W(c,C(d,t.body))}else if(t.kind==="sidecar-md"){let d={},p;try{const E=J(I(t.sourceAbs));d=E.data??{},p=E.body}catch{p=I(t.sourceAbs)}const k=D.find(E=>e.startsWith(`${E}/`)),b={kind:"knowledge",privacy:"public","when-and-why-to-read":`When ${k?`${l}/${k}`:`a ${l} document`} links to this file, this knowledge should be read because it carries the linked supporting reference.`,"short-form":Se(p)??`Supporting reference vendored from ${t.pkg}.`,surfaces:[{on:"boot",at:"name"}],"source-package":`${t.pkg}@${t.version}`,...ne(d)};W(c,C(b,p))}else ae(S(c),{recursive:!0}),de(t.sourceAbs,c)}const O=[...new Set(w.map(([,e])=>e.pkg))],te=O.slice(0,6).join(", ")+(O.length>6?", \u2026":""),F=new Map;for(const[,e]of w){const t=`${e.pkg}@${e.version}`,c=F.get(t)??{version:e.version,lines:[]},d=e.description!==""?` \u2014 ${se(e.description,180)}`:"";c.lines.push(`- \`${l}/${e.bundleRel}\`${d}`),F.set(t,c)}const oe=[...F.entries()].map(([e,{lines:t}])=>`## ${e}
2
2
 
3
3
  ${t.sort().join(`
4
4
  `)}`).join(`
5
5
 
6
- `),M=w.length===0,re={kind:"knowledge","when-and-why-to-read":M?"When deciding whether dependency-shipped agent docs are available in this project, this catalog should be read because no dependency guides are currently vendored.":`When writing code against this project's dependencies (${te}), this catalog should be read because those packages ship their own authoritative agent guides, vendored below and readable with \`crtr memory read ${l}/<name>\`.`,"short-form":M?"No dependency-shipped agent docs are currently vendored.":"Generated catalog of the agent docs shipped inside this project's npm dependencies.",surfaces:[{on:"boot",at:"preview"}],"generated-by":T},ie=M?`# Dependency-shipped agent docs (generated)
6
+ `),M=w.length===0,re={kind:"knowledge",privacy:"public","when-and-why-to-read":M?"When deciding whether dependency-shipped agent docs are available in this project, this catalog should be read because no dependency guides are currently vendored.":`When writing code against this project's dependencies (${te}), this catalog should be read because those packages ship their own authoritative agent guides, vendored below and readable with \`crtr memory read ${l}/<name>\`.`,"short-form":M?"No dependency-shipped agent docs are currently vendored.":"Generated catalog of the agent docs shipped inside this project's npm dependencies.",surfaces:[{on:"boot",at:"preview"}],"generated-by":T},ie=M?`# Dependency-shipped agent docs (generated)
7
7
 
8
8
  No dependency agent docs are currently vendored. \`crtr sys sync deps\` found no included Agent Skill bundles.
9
9
  `:`# Dependency-shipped agent docs (generated)