@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
@@ -26,7 +26,8 @@ import {
26
26
  markSubscriptionAuthenticationFailed,
27
27
  markSubscriptionRateLimited,
28
28
  markSubscriptionSuccess,
29
- parseRetryAfterHeader,
29
+ retryAfterMsFromHeaders,
30
+ retryAfterMsFromError,
30
31
  promoteSubscription,
31
32
  readRotationConfig,
32
33
  readSubscriptionPool,
@@ -60,6 +61,11 @@ const TRANSIENT_RETRY_BACKOFFS_MS = [250, 750];
60
61
  // so cool it down only briefly -- long enough to rotate to another credential / fallback
61
62
  // provider, short enough that it comes back quickly if it was the only option.
62
63
  const TRANSIENT_ROTATE_COOLDOWN_MS = 60 * 1000;
64
+ // A 401/403 before any content means the provider refused this credential (a lapsed
65
+ // plan, a revoked server-side key). That is not a transient blip, but it is not proof
66
+ // the account is gone either: cool the account for 30 minutes and rotate, rather than
67
+ // the 30-day invalid_grant backoff. Exact requests keep the auth error.
68
+ const AUTH_REJECTED_COOLDOWN_MS = 30 * 60 * 1000;
63
69
  // A few short outer retries absorb a normal multi-broker collision; if the metadata file
64
70
  // remains busy, the provider call still proceeds. Subscription bookkeeping must never turn a
65
71
  // healthy model response into a fatal generation fault.
@@ -124,15 +130,20 @@ type AttemptResult = {
124
130
  // `usage`/`quota` substrings stay out of the message match: they are false-positive
125
131
  // magnets (e.g. "usage" appears in normal assistant text), while the precise
126
132
  // terminal usage-limit signals above still cool the credential down and rotate to the
127
- // next one.
133
+ // next one. A status 401/403 rotates with AUTH_REJECTED_COOLDOWN_MS unless the request
134
+ // is exact.
128
135
  type ProviderErrorClassification = {
129
136
  kind: "rate_limit" | "transient" | "fatal";
130
137
  status?: number;
131
138
  reason: string;
132
139
  hadRetryAfterHeader: boolean;
140
+ /** Cooldown this classification imposes regardless of any Retry-After header. */
141
+ cooldownMs?: number;
133
142
  };
134
143
 
135
- function classifyProviderSignal(signal: ProviderErrorSignal): ProviderErrorClassification {
144
+ type ProviderClassificationPolicy = { rotateOnAuth: boolean };
145
+
146
+ function classifyProviderSignal(signal: ProviderErrorSignal, policy: ProviderClassificationPolicy): ProviderErrorClassification {
136
147
  const hadRetryAfterHeader = signal.retryAfterMs !== undefined;
137
148
  if (signal.kind === 'rate-limit' && signal.matchedOn === 'status') {
138
149
  return { kind: 'rate_limit', status: signal.status, reason: 'http 429', hadRetryAfterHeader };
@@ -144,6 +155,9 @@ function classifyProviderSignal(signal: ProviderErrorSignal): ProviderErrorClass
144
155
  return { kind: 'transient', status: signal.status, reason: `http ${signal.status}`, hadRetryAfterHeader };
145
156
  }
146
157
  const textMatches = signal.textMatches ?? (signal.matchedOn === 'text' && signal.match ? [{ kind: signal.kind, match: signal.match }] : []);
158
+ if (policy.rotateOnAuth && signal.kind === 'auth' && signal.matchedOn === 'status' && !textMatches.some(({ kind }) => kind === 'rate-limit')) {
159
+ return { kind: 'rate_limit', status: signal.status, reason: `http ${signal.status}`, hadRetryAfterHeader, cooldownMs: AUTH_REJECTED_COOLDOWN_MS };
160
+ }
147
161
  const transientMatch = textMatches.find(({ kind }) => kind === 'connection' || kind === 'socket' || kind === 'service-unavailable' || kind === 'overloaded');
148
162
  if (transientMatch) {
149
163
  return { kind: 'transient', status: signal.status, reason: transientMatch.match.toLowerCase(), hadRetryAfterHeader };
@@ -155,7 +169,7 @@ function classifyProviderSignal(signal: ProviderErrorSignal): ProviderErrorClass
155
169
  return { kind: 'fatal', status: signal.status, reason: 'unclassified', hadRetryAfterHeader };
156
170
  }
157
171
 
158
- function classifyProviderFailure(failure: NormalizedProviderFailure, retryAfterMs: number | undefined): ProviderErrorClassification {
172
+ function classifyProviderFailure(failure: NormalizedProviderFailure, retryAfterMs: number | undefined, policy: ProviderClassificationPolicy): ProviderErrorClassification {
159
173
  const nested = failure.causes ?? [];
160
174
  const code = failure.code ?? nested.find((cause) => cause.code !== undefined)?.code;
161
175
  const errno = failure.errno ?? nested.find((cause) => cause.errno !== undefined)?.errno;
@@ -168,16 +182,16 @@ function classifyProviderFailure(failure: NormalizedProviderFailure, retryAfterM
168
182
  code,
169
183
  errno,
170
184
  message,
171
- }));
172
- }
173
-
174
- function classifyProviderError(error: unknown, observed: { status?: number; retryAfterMs?: number }): ProviderErrorClassification {
175
- return classifyProviderFailure(normalizeProviderFailure(error, { status: observed.status }), observed.retryAfterMs);
185
+ }), policy);
176
186
  }
177
187
 
178
188
  /** Test seam for the policy mapping over the shared recognition signal. */
179
- export function __classifyProviderErrorForTest(error: unknown, observed: { status?: number; retryAfterMs?: number } = {}): ProviderErrorClassification {
180
- return classifyProviderError(error, observed);
189
+ export function __classifyProviderErrorForTest(
190
+ error: unknown,
191
+ observed: { status?: number; retryAfterMs?: number } = {},
192
+ policy: ProviderClassificationPolicy = { rotateOnAuth: false },
193
+ ): ProviderErrorClassification {
194
+ return classifyProviderFailure(normalizeProviderFailure(error, { status: observed.status }), observed.retryAfterMs, policy);
181
195
  }
182
196
 
183
197
  function providerFailureAssistantMessage(model: Model<any>, failure: NormalizedProviderFailure): AssistantMessage {
@@ -325,15 +339,6 @@ function toAssistantError(model: Model<any>, errorMessage: string): AssistantMes
325
339
  };
326
340
  }
327
341
 
328
- function retryAfterMs(headers: Record<string, string>): number | undefined {
329
- const retryAfterMsHeader = headers["retry-after-ms"];
330
- if (retryAfterMsHeader) {
331
- const millis = Number(retryAfterMsHeader);
332
- if (Number.isFinite(millis)) return Math.max(0, millis);
333
- }
334
- return parseRetryAfterHeader(headers["retry-after"]);
335
- }
336
-
337
342
  type RefreshedCredential = { refresh: string; access: string; expires: number };
338
343
  // Codex login carries the ChatGPT `accountId`; Anthropic identity is enriched from its OAuth
339
344
  // profile after login. Optional so both providers and the test seam fit.
@@ -556,6 +561,7 @@ async function streamProviderAttempt(
556
561
  credential: ResolvedCredential | undefined,
557
562
  outer: AssistantMessageEventStream,
558
563
  ): Promise<AttemptResult> {
564
+ const policy: ProviderClassificationPolicy = { rotateOnAuth: !isExactModel(state) };
559
565
  for (let attempt = 1; ; attempt++) {
560
566
  const attemptAt = Date.now();
561
567
  let observedStatus: number | undefined;
@@ -594,7 +600,7 @@ async function streamProviderAttempt(
594
600
  onResponse: async (response: { status: number; headers: Record<string, string> }, responseModel: Model<any>) => {
595
601
  observedStatus = response.status;
596
602
  if (response.status === 429 || response.status === 503) {
597
- requestedRetryAfterMs = retryAfterMs(response.headers);
603
+ requestedRetryAfterMs = retryAfterMsFromHeaders(response.headers);
598
604
  }
599
605
  await options?.onResponse?.(response as any, responseModel);
600
606
  },
@@ -639,7 +645,7 @@ async function streamProviderAttempt(
639
645
  }
640
646
  failure = normalizeProviderFailure(event.error, { status: observedStatus });
641
647
  failureMessage = failure.message;
642
- classification = classifyProviderFailure(failure, requestedRetryAfterMs);
648
+ classification = classifyProviderFailure(failure, requestedRetryAfterMs, policy);
643
649
  if (classification.kind === "fatal" || sawContent) {
644
650
  emit({ ...event, error: providerFailureAssistantMessage(model, failure) });
645
651
  flush();
@@ -663,9 +669,10 @@ async function streamProviderAttempt(
663
669
  flush();
664
670
  return { result: "fatal", attemptAt };
665
671
  }
672
+ requestedRetryAfterMs ??= retryAfterMsFromError(error);
666
673
  failure = normalizeProviderFailure(error, { status: observedStatus });
667
674
  failureMessage = failure.message;
668
- classification = classifyProviderFailure(failure, requestedRetryAfterMs);
675
+ classification = classifyProviderFailure(failure, requestedRetryAfterMs, policy);
669
676
  if (classification.kind === "fatal" || sawContent) {
670
677
  emit({
671
678
  type: "error",
@@ -689,7 +696,7 @@ async function streamProviderAttempt(
689
696
  }
690
697
 
691
698
  if (classification.kind === "rate_limit") {
692
- return { result: "rate_limited", retryAfterMs: requestedRetryAfterMs, attemptAt, classification };
699
+ return { result: "rate_limited", retryAfterMs: classification.cooldownMs ?? requestedRetryAfterMs, attemptAt, classification, failureMessage };
693
700
  }
694
701
 
695
702
  // Transient: retry the SAME credential/provider in place first -- no cooldown for the
@@ -787,7 +794,11 @@ async function runManagedProvider(
787
794
  configuredValue(state, 'nodeCwd', 'CRTR_NODE_CWD'),
788
795
  configuredValue(state, 'profileId', 'CRTR_PROFILE_ID'),
789
796
  ) : [];
790
- const liveRank = expanded.find((candidate) => candidate.providerId === model.provider && candidate.modelId === model.id && candidate.thinkingLevel === liveThinking)?.rank ?? 0;
797
+ // The node's thinking level holds on its own model; a route to another
798
+ // provider or model takes that cell's thinking.
799
+ const onLiveModel = (candidate: { providerId: string; modelId: string }): boolean =>
800
+ candidate.providerId === model.provider && candidate.modelId === model.id;
801
+ const liveRank = (expanded.find((candidate) => onLiveModel(candidate) && candidate.thinkingLevel === liveThinking) ?? expanded.find(onLiveModel))?.rank ?? 0;
791
802
  const routeCandidates: RouteCandidate[] = expanded.slice(liveRank)
792
803
  .map((route) => {
793
804
  const registry = state.runtimeContext?.modelRegistry;
@@ -795,9 +806,10 @@ async function runManagedProvider(
795
806
  if (!registry || !routeModel) return undefined;
796
807
  const availability = probeRouteAvailability(route, registry);
797
808
  if (!availability.registered || (!isManagedProvider(route.providerId) && !availability.authenticated)) return undefined;
798
- return { routeId: route.routeId, credentialSource: route.credentialSource, rank: route.rank, providerId: route.providerId, model: routeModel, thinkingLevel: route.thinkingLevel };
809
+ return { routeId: route.routeId, credentialSource: route.credentialSource, rank: route.rank, providerId: route.providerId, model: routeModel, thinkingLevel: onLiveModel(route) ? liveThinking : route.thinkingLevel };
799
810
  })
800
- .filter((candidate): candidate is RouteCandidate => candidate !== undefined);
811
+ .filter((candidate): candidate is RouteCandidate => candidate !== undefined)
812
+ .filter((candidate, index, all) => all.findIndex((other) => other.routeId === candidate.routeId && other.providerId === candidate.providerId && other.model.id === candidate.model.id && other.thinkingLevel === candidate.thinkingLevel) === index);
801
813
  const isLiveRoute = (candidate: RouteCandidate): boolean =>
802
814
  candidate.providerId === model.provider && candidate.model.id === model.id && candidate.thinkingLevel === liveThinking;
803
815
  // A cooling or unauthenticated managed route contributes its diagnostic and may
@@ -822,6 +834,9 @@ async function runManagedProvider(
822
834
  const cooldownAttempts = new Map<string, number>();
823
835
  let terminalModel = model;
824
836
  let lastTransientFailure: AttemptResult | undefined;
837
+ // The last pre-content 401/403 that cooled a route; its text is the only
838
+ // record of why the routes ran out when they end in a cooling error.
839
+ let lastAuthRejection: AttemptResult | undefined;
825
840
  // Any HTTP response observed this pass (a status, a Retry-After header, or a
826
841
  // rate-limit classification) proves this process can still reach a provider,
827
842
  // clearing the poisoned-transport suspicion.
@@ -858,6 +873,7 @@ async function runManagedProvider(
858
873
  if (result.result === 'rate_limited' || result.classification?.status !== undefined || result.classification?.hadRetryAfterHeader === true) sawHttpEvidence = true;
859
874
  const cooldownMs = result.result === 'rate_limited' ? result.retryAfterMs ?? DEFAULT_RATE_LIMIT_BACKOFF_MS : TRANSIENT_ROTATE_COOLDOWN_MS;
860
875
  if (result.result === 'transient_exhausted') lastTransientFailure = result;
876
+ if (result.result === 'rate_limited' && (result.classification?.status === 401 || result.classification?.status === 403)) lastAuthRejection = result;
861
877
  localCoolingDeadlines.set(routeId, Math.max(localCoolingDeadlines.get(routeId) ?? 0, Date.now() + cooldownMs));
862
878
  logRouteQueueAdvance(candidate, candidates[0], result);
863
879
  continue;
@@ -898,6 +914,7 @@ async function runManagedProvider(
898
914
  if (result.result === 'rate_limited' || result.classification?.status !== undefined || result.classification?.hadRetryAfterHeader === true) sawHttpEvidence = true;
899
915
  const cooldownMs = result.result === 'rate_limited' ? result.retryAfterMs ?? DEFAULT_RATE_LIMIT_BACKOFF_MS : TRANSIENT_ROTATE_COOLDOWN_MS;
900
916
  if (result.result === 'transient_exhausted') lastTransientFailure = result;
917
+ if (result.result === 'rate_limited' && (result.classification?.status === 401 || result.classification?.status === 403)) lastAuthRejection = result;
901
918
  if (result.result === 'rate_limited' && result.retryAfterMs !== undefined) {
902
919
  const persisted = await recordSubscriptionMutation(`recording ${getProviderLabel(providerId)} server cooldown`, () => markSubscriptionRateLimited(providerId, freshCredential.label, cooldownMs, result.attemptAt));
903
920
  if (persisted) cooldownAttempts.set(`${routeId}/${freshCredential.label}`, result.attemptAt);
@@ -931,7 +948,11 @@ async function runManagedProvider(
931
948
  }
932
949
  state.transportOnlyExhaustedPasses = 0;
933
950
  if (coolingDeadline !== undefined) {
934
- emitCoolingError(stream, terminalModel, new ManagedProviderCoolingError(`All provider routes are rate limited (cooling down ~${Math.ceil((coolingDeadline - Date.now()) / 1000)}s; tried ${tried})`, coolingDeadline));
951
+ const cooling = `cooling down ~${Math.ceil((coolingDeadline - Date.now()) / 1000)}s`;
952
+ const message = lastAuthRejection === undefined
953
+ ? `All provider routes are rate limited (${cooling}; tried ${tried})`
954
+ : `All provider routes are rate limited or rejected (${cooling}; last rejection ${lastAuthRejection.classification!.reason}: ${lastAuthRejection.failureMessage ?? 'no error message'}; tried ${tried})`;
955
+ emitCoolingError(stream, terminalModel, new ManagedProviderCoolingError(message, coolingDeadline));
935
956
  return;
936
957
  }
937
958
  const authFailure = [...authFailures][0];
@@ -1047,7 +1068,9 @@ async function restoreHigherRankIfAvailable(state: ProviderRotationState, pi: Ex
1047
1068
  configuredValue(state, 'nodeCwd', 'CRTR_NODE_CWD'),
1048
1069
  configuredValue(state, 'profileId', 'CRTR_PROFILE_ID'),
1049
1070
  );
1050
- const liveRank = candidates.find((candidate) => candidate.providerId === ctx.model?.provider && candidate.modelId === ctx.model?.id && candidate.thinkingLevel === liveThinking)?.rank;
1071
+ const onLiveModel = (candidate: { providerId: string; modelId: string }): boolean =>
1072
+ candidate.providerId === ctx.model?.provider && candidate.modelId === ctx.model?.id;
1073
+ const liveRank = (candidates.find((candidate) => onLiveModel(candidate) && candidate.thinkingLevel === liveThinking) ?? candidates.find(onLiveModel))?.rank;
1051
1074
  if (liveRank === undefined) return false;
1052
1075
  const preferred = candidates.find((candidate) => candidate.rank < liveRank && resolveProviderCandidates([{
1053
1076
  ...candidate,
package/dist/cli.js CHANGED
@@ -1,10 +1,11 @@
1
1
  #!/usr/bin/env node
2
- var l=Object.defineProperty;var i=(r,t)=>l(r,"name",{value:t,configurable:!0});import"./suppress-experimental-warnings.js";import{mkdirSync as d,openSync as u,renameSync as y,rmSync as g,statSync as a,writeFileSync as w}from"node:fs";import{homedir as v}from"node:os";import{dirname as p,join as c}from"node:path";import{enableCompileCache as h}from"node:module";import{fileURLToPath as m}from"node:url";import{isDaemonControlInvocation as R,resolveDaemonControlRoot as S,resolveRoot as E}from"./build-root.js";import{maybeBootRoot as _}from"./core/runtime/front-door.js";import{maybeAutoUpdate as b}from"./core/auto-update.js";import{ensureProjectScope as A}from"./core/bootstrap.js";import{provisionExports as C,pruneLegacyExports as $}from"./core/host-exports/export.js";import{revalidateBundlePlugins as k}from"./core/command-plugins/revalidate.js";import{runCli as I}from"./core/command.js";import{dispatchWithStaleRecovery as x}from"./core/manifest-recovery.js";import{installStdoutErrorPolicy as N}from"./core/stdout-errors.js";import{handle as O}from"./core/io.js";import{CrtrError as T}from"./core/errors.js";import{ApiError as F}from"./api/index.js";import{mark as o}from"./core/timing.js";u(m(import.meta.url),"r"),N(),o("cli.entry",{cmd:process.argv[2]??"(bare)"});try{h()}catch{}o("cli.compile_cache");const P=c(p(m(import.meta.url)),".."),n=c(v(),".crouter","first-run.json");function s(r){return(r instanceof Error?r.message:String(r)).split(/\r?\n/,1)[0]??""}i(s,"errorMessage");function D(r){const t=p(n);d(t,{recursive:!0});const e=`${n}.${process.pid}.${Date.now()}.tmp`;try{w(e,JSON.stringify({packageVersion:r,completedAt:new Date().toISOString()})+`
3
- `,"utf8"),y(e,n)}finally{g(e,{force:!0})}}i(D,"writeFirstRunMarker");async function U(){if(process.env.CRTR_NO_AUTO_INIT==="1")return;try{if(a(n,{throwIfNoEntry:!1})!==void 0)return}catch(t){process.stderr.write(`crtr: first-run reconcile marker check failed: ${s(t)}
4
- `);return}try{if(a(c(P,".git"),{throwIfNoEntry:!1})!==void 0)return}catch(t){process.stderr.write(`crtr: first-run reconcile source check failed: ${s(t)}
5
- `);return}let r;try{const{reconcileFirstRun:t}=await import("./commands/sys/setup-core.js");r=await t((e,f)=>{process.stderr.write(`crtr: first-run reconcile ${e} failed: ${s(f)}
6
- `)})}catch(t){process.stderr.write(`crtr: first-run reconcile failed: ${s(t)}
7
- `)}finally{if(r!==void 0)try{D(r)}catch(t){process.stderr.write(`crtr: first-run reconcile marker failed: ${s(t)}
8
- `)}}}i(U,"maybeReconcileFirstRun");async function j(){if($(process.argv),await U(),await _(process.argv),o("cli.front_door_passed"),R(process.argv)){await I(await S(),process.argv);return}await k(process.argv),o("cli.plugins_revalidated");const r=await E(process.argv[2]);o("cli.root_resolved"),C(r,process.argv),A(process.argv),b(process.argv),o("cli.dispatch_start"),await x(r,process.argv),o("cli.dispatch_done")}i(j,"main"),j().catch(r=>{(r instanceof Error&&r.name==="AbortError"||r instanceof Error&&/operation was aborted/i.test(r.message))&&(process.stderr.write(`crtr: Interrupted
9
- `),process.exit(130)),(r instanceof F||r instanceof T)&&(O(r),process.exit(typeof process.exitCode=="number"?process.exitCode:1));const e=r instanceof Error?r.message:String(r);process.stderr.write(`crtr: ${e}
2
+ var h=Object.defineProperty;var s=(r,o)=>h(r,"name",{value:o,configurable:!0});import"./suppress-experimental-warnings.js";import{mkdirSync as w,openSync as v,readFileSync as R,renameSync as S,rmSync as E,statSync as f,writeFileSync as _}from"node:fs";import{dirname as l,join as c}from"node:path";import{enableCompileCache as b}from"node:module";import{fileURLToPath as d}from"node:url";import{isDaemonControlInvocation as u,isLayoutMigrationInvocation as x,personOnlyInvocation as C,resolveDaemonControlRoot as N,resolveLayoutMigrationRoot as A,resolveRoot as I}from"./build-root.js";import{maybeBootRoot as $}from"./core/runtime/front-door.js";import{maybeAutoUpdate as k}from"./core/auto-update.js";import{ensureProjectScope as O}from"./core/bootstrap.js";import{provisionExports as T,pruneLegacyExports as F}from"./core/host-exports/export.js";import{revalidateBundlePlugins as M}from"./core/command-plugins/revalidate.js";import{renderNode as D,runCli as g,walk as L}from"./core/command.js";import{dispatchWithStaleRecovery as P}from"./core/manifest-recovery.js";import{installStdoutErrorPolicy as U}from"./core/stdout-errors.js";import{handle as j}from"./core/io.js";import{CrtrError as m}from"./core/errors.js";import{ExitCode as y}from"./types.js";import{layoutNeedsMigration as B,runtimeRoot as K}from"./core/layout.js";import{ApiError as G}from"./api/index.js";import{mark as i}from"./core/timing.js";import{isSandboxedNode as J,envNodeId as W}from"./shared/env.js";import{nodeRunDir as q}from"./core/canvas/paths.js";import{installBrokerConfigSnapshot as V}from"./core/config.js";v(d(import.meta.url),"r"),U(),i("cli.entry",{cmd:process.argv[2]??"(bare)"});try{b()}catch{}i("cli.compile_cache");const z=c(l(d(import.meta.url)),".."),p=c(K(),"first-run.json");function a(r){return(r instanceof Error?r.message:String(r)).split(/\r?\n/,1)[0]??""}s(a,"errorMessage");function H(r){const o=l(p);w(o,{recursive:!0});const t=`${p}.${process.pid}.${Date.now()}.tmp`;try{_(t,JSON.stringify({packageVersion:r,completedAt:new Date().toISOString()})+`
3
+ `,"utf8"),S(t,p)}finally{E(t,{force:!0})}}s(H,"writeFirstRunMarker");async function Q(){if(process.env.CRTR_NO_AUTO_INIT==="1")return;try{if(f(p,{throwIfNoEntry:!1})!==void 0)return}catch(o){process.stderr.write(`crtr: first-run reconcile marker check failed: ${a(o)}
4
+ `);return}try{if(f(c(z,".git"),{throwIfNoEntry:!1})!==void 0)return}catch(o){process.stderr.write(`crtr: first-run reconcile source check failed: ${a(o)}
5
+ `);return}let r;try{const{reconcileFirstRun:o}=await import("./commands/sys/setup-core.js");r=await o((t,e)=>{process.stderr.write(`crtr: first-run reconcile ${t} failed: ${a(e)}
6
+ `)})}catch(o){process.stderr.write(`crtr: first-run reconcile failed: ${a(o)}
7
+ `)}finally{if(r!==void 0)try{H(r)}catch(o){process.stderr.write(`crtr: first-run reconcile marker failed: ${a(o)}
8
+ `)}}}s(Q,"maybeReconcileFirstRun");async function X(){const r=x(process.argv),o=J();if(o){const e=C(process.argv);if(e!==null)throw new m("permission_error",`crtr ${e} is not available to an app's node`,y.USAGE,{next:"Run this command from the person's terminal."});const n=JSON.parse(R(c(q(W()),"broker-launch.json"),"utf8"));if(!n.configSnapshot)throw new Error("node launch is missing its config snapshot");V(n.configSnapshot)}if(!o&&B()&&!u(process.argv)&&!r)throw new m("layout_migration_required","run crtr sys migrate while the runtime is offline",y.NETWORK,{next:"Run `crtr sys migrate` while the runtime is offline, then restart it."});if(r){const e=await A();if(process.argv.slice(4).some(n=>n==="-h"||n==="--help")){process.stdout.write(D(L(e,["sys","migrate"]).node)+`
9
+ `);return}await g(e,process.argv);return}if(o||(F(process.argv),await Q()),await $(process.argv),i("cli.front_door_passed"),u(process.argv)){await g(await N(),process.argv);return}o||await M(process.argv),i("cli.plugins_revalidated");const t=await I(process.argv[2]);i("cli.root_resolved"),o||(T(t,process.argv),O(process.argv),k(process.argv)),i("cli.dispatch_start"),await P(t,process.argv),i("cli.dispatch_done")}s(X,"main"),X().catch(r=>{(r instanceof Error&&r.name==="AbortError"||r instanceof Error&&/operation was aborted/i.test(r.message))&&(process.stderr.write(`crtr: Interrupted
10
+ `),process.exit(130)),(r instanceof G||r instanceof m)&&(j(r),process.exit(typeof process.exitCode=="number"?process.exitCode:1));const t=r instanceof Error?r.message:String(r);process.stderr.write(`crtr: ${t}
10
11
  `),process.exit(1)});
@@ -1 +1 @@
1
- var T=Object.defineProperty;var o=(u,d)=>T(u,"name",{value:d,configurable:!0});import{Container as v,Text as I,decodeKittyPrintable as D,matchesKey as b}from"@earendil-works/pi-tui";import{DynamicBorder as L}from"@earendil-works/pi-coding-agent";import{byNewestFirst as K,inboxRowFromDTO as $}from"../../inbox/dto-adapt.js";import{cliClient as O}from"../../../commands/api-client.js";import{fillBar as F,fillWidth as W,navLabel as _,stripSgr as q,truncate as A,REVERSE as B,YELLOW as H,RESET as P}from"../../../core/canvas/nav-render.js";const x=3;function j(u){return u.kind==="page"?u.emittedAt:u.blockedSince}o(j,"ticketTime");function V(u){const d=Date.now()-Date.parse(u);if(!Number.isFinite(d)||d<0)return"now";const a=Math.floor(d/6e4);if(a<1)return"now";if(a<60)return`${a}m`;const m=Math.floor(a/60);return m<24?`${m}h`:`${Math.floor(m/24)}d`}o(V,"ageLabel");function Z(u,d){const{nodeId:a,remote:m,canvasSource:y,tui:k,pal:M}=u,h=new v;let i=[],w=new Map,r,l=0;const R=o(e=>{const n=e.source.nodeId,t=n!==void 0&&n!==a?` \xB7 ${_(w.get(n)??null,n)}`:"";return A(` ${H}\u2691${P} ${e.title}${M.faint(` \xB7 ${V(j(e))}${t}`)}`)},"rowLine"),p=o(()=>{if(d.syncCursor(),h.clear(),i.length>0&&!d.suppressed()){const e=r===void 0?-1:i.findIndex(t=>t.dir===r);e>=0&&(l=Math.min(Math.max(l,e-x+1),e)),l=Math.max(0,Math.min(l,Math.max(0,i.length-x)));for(const t of i.slice(l,l+x)){const c=R(t);h.addChild(new I(t.dir===r?F(q(c),W(),B):c,1,0))}const n=i.length-Math.min(x,i.length-l);n>0&&h.addChild(new I(M.faint(` +${n} more`),1,0)),h.addChild(new L(M.border))}k.requestRender()},"paint"),S=o(async()=>{const e=new Map,n=o(async t=>{if(e.has(t))return;const c=await y.getNode(t).catch(()=>null);if(t!==a&&c?.kind==="human")return;e.set(t,c);const f=await y.subscriptionsOf(t).catch(()=>[]);for(const s of f)await n(s.node_id)},"visit");return await n(a),e},"subtreeNodes"),C=o(async()=>{if(m)return;w=await S();const e=O(),[n,t]=await Promise.all([e.listHumanInbox(),e.getInboxHistory()]),c=new Map;for(const f of n.tickets){const s=$(f);c.set(s.dir,s)}for(const f of t.tickets){const s=$(f);s.kind==="page"&&(s.source.nodeId===void 0||!w.has(s.source.nodeId)||s.state!=="pending"||!s.awaitsResponse||s.inbox||c.has(s.dir)||c.set(s.dir,s))}i=[...c.values()].filter(f=>f.source.nodeId!==void 0&&w.has(f.source.nodeId)).sort(K),r!==void 0&&!i.some(f=>f.dir===r)&&(r=void 0),p()},"refresh"),g=o(()=>{r!==void 0&&(r=void 0,p())},"exit"),E=o(()=>{if(!m){if(r!==void 0){g();return}if(i.length===0){d.setNotice("No pending human requests in this subtree");return}d.exitRoster(),r=i[0].dir,l=0,p()}},"toggle"),N=o(()=>{const e=i.find(n=>n.dir===r);e!==void 0&&(g(),d.openTicket(e))},"openSelected");return{component:h,refresh:C,handleKey:o(e=>{if(r===void 0)return!1;const n=i.findIndex(c=>c.dir===r),t=D(e)??(e.length===1?e:void 0);return b(e,"up")||t==="k"?(n>0&&(r=i[n-1].dir,p()),!0):b(e,"down")||t==="j"?(n>=0&&n<i.length-1?(r=i[n+1].dir,p()):g(),!0):b(e,"enter")?(N(),!0):b(e,"escape")?(g(),!0):(g(),!1)},"handleKey"),toggle:E,active:o(()=>r!==void 0,"active"),pendingTickets:o(()=>[...i],"pendingTickets")}}o(Z,"createInboxStrip");export{Z as createInboxStrip};
1
+ var v=Object.defineProperty;var o=(u,c)=>v(u,"name",{value:c,configurable:!0});import{Container as D,Text as I,decodeKittyPrintable as L,matchesKey as b}from"@earendil-works/pi-tui";import{DynamicBorder as K}from"@earendil-works/pi-coding-agent";import{byNewestFirst as O,inboxRowFromDTO as $}from"../../inbox/dto-adapt.js";import{cliClient as _}from"../../../commands/api-client.js";import{fillBar as F,fillWidth as W,navLabel as q,stripSgr as A,truncate as B,REVERSE as H,YELLOW as P,RESET as j}from"../../../core/canvas/nav-render.js";const x=3;function V(u){return u.kind==="page"?u.emittedAt:u.blockedSince}o(V,"ticketTime");function X(u){const c=Date.now()-Date.parse(u);if(!Number.isFinite(c)||c<0)return"now";const a=Math.floor(c/6e4);if(a<1)return"now";if(a<60)return`${a}m`;const m=Math.floor(a/60);return m<24?`${m}h`:`${Math.floor(m/24)}d`}o(X,"ageLabel");function ee(u,c){const{nodeId:a,remote:m,canvasSource:y,tui:k,pal:M}=u,h=new D;let i=[],g=new Map,r,l=0;const R=o(e=>{const n=e.source.nodeId,s=n!==void 0&&n!==a?` \xB7 ${q(g.get(n)??null,n)}`:"";return B(` ${P}\u2691${j} ${e.title}${M.faint(` \xB7 ${X(V(e))}${s}`)}`)},"rowLine"),p=o(()=>{if(c.syncCursor(),h.clear(),i.length>0&&!c.suppressed()){const e=r===void 0?-1:i.findIndex(s=>s.dir===r);e>=0&&(l=Math.min(Math.max(l,e-x+1),e)),l=Math.max(0,Math.min(l,Math.max(0,i.length-x)));for(const s of i.slice(l,l+x)){const t=R(s);h.addChild(new I(s.dir===r?F(A(t),W(),H):t,1,0))}const n=i.length-Math.min(x,i.length-l);n>0&&h.addChild(new I(M.faint(` +${n} more`),1,0)),h.addChild(new K(M.border))}k.requestRender()},"paint"),S=o(async()=>{const e=new Map((await y.listNodes()).map(t=>[t.node_id,t])),n=new Map,s=o(async t=>{if(n.has(t))return;const f=e.get(t)??null;if(t!==a&&f?.kind==="human")return;n.set(t,f);const d=await y.subscriptionsOf(t).catch(()=>[]);for(const T of d)await s(T.node_id)},"visit");return await s(a),n},"subtreeNodes"),C=o(async()=>{if(m)return;g=await S();const e=_(),[n,s]=await Promise.all([e.listHumanInbox(),e.getInboxHistory()]),t=new Map;for(const f of n.tickets){const d=$(f);t.set(d.dir,d)}for(const f of s.tickets){const d=$(f);d.kind==="page"&&(d.source.nodeId===void 0||!g.has(d.source.nodeId)||d.state!=="pending"||!d.awaitsResponse||d.inbox||t.has(d.dir)||t.set(d.dir,d))}i=[...t.values()].filter(f=>f.source.nodeId!==void 0&&g.has(f.source.nodeId)).sort(O),r!==void 0&&!i.some(f=>f.dir===r)&&(r=void 0),p()},"refresh"),w=o(()=>{r!==void 0&&(r=void 0,p())},"exit"),E=o(()=>{if(!m){if(r!==void 0){w();return}if(i.length===0){c.setNotice("No pending human requests in this subtree");return}c.exitRoster(),r=i[0].dir,l=0,p()}},"toggle"),N=o(()=>{const e=i.find(n=>n.dir===r);e!==void 0&&(w(),c.openTicket(e))},"openSelected");return{component:h,refresh:C,handleKey:o(e=>{if(r===void 0)return!1;const n=i.findIndex(t=>t.dir===r),s=L(e)??(e.length===1?e:void 0);return b(e,"up")||s==="k"?(n>0&&(r=i[n-1].dir,p()),!0):b(e,"down")||s==="j"?(n>=0&&n<i.length-1?(r=i[n+1].dir,p()):w(),!0):b(e,"enter")?(N(),!0):b(e,"escape")?(w(),!0):(w(),!1)},"handleKey"),toggle:E,active:o(()=>r!==void 0,"active"),pendingTickets:o(()=>[...i],"pendingTickets")}}o(ee,"createInboxStrip");export{ee as createInboxStrip};
@@ -1,4 +1,4 @@
1
- var M=Object.defineProperty;var i=(b,n)=>M(b,"name",{value:n,configurable:!0});import{execFile as C}from"node:child_process";import{Text as P,decodeKittyPrintable as H,matchesKey as h}from"@earendil-works/pi-tui";import{cliClient as S}from"../../../commands/api-client.js";import{activeBackgroundBashJobs as I}from"../../../core/bash-jobs.js";import{contextDir as T}from"../../../core/canvas/paths.js";import{fillBar as O,fillWidth as D,stripSgr as J,REVERSE as U}from"../../../core/canvas/nav-render.js";import{buildCanvasPanelLines as F}from"./canvas-panels.js";const L=15e3;function ne(b,n){const{editor:_,tui:x,pal:K,nodeId:l,remote:a,role:v,canvasSource:$}=b,w=b.containers.reports;let o=[],r,y=process.env.CRTR_ATTACH_ROSTER;y!==void 0&&delete process.env.CRTR_ATTACH_ROSTER;let u,g;const p=i(()=>{n.syncCursor(),w.clear();for(const e of o){const t=e.key===r;w.addChild(new P(t?O(J(e.line),D(),U):e.line,1,0))}x.requestRender()},"paint"),A=i(async()=>{const e=a?[]:(await S().listCrons()).filter(c=>c.created_by===l),t=a?[]:I(T(l)),d=a?[]:(await S().listReviews({state:"open",origin_node_id:l})).reviews;if(o=(await F(l,n.asks(),K,$,e,t,d)).items,y!==void 0){const c=y;y=void 0;const R=o.find(j=>j.kind==="node"&&j.nodeId===c);R!==void 0&&(r=R.key)}r!==void 0&&!o.some(c=>c.key===r)&&(r=void 0),u!==void 0&&!t.some(c=>c.jobId===u?.jobId)&&m(!0),p()},"refresh"),m=i(e=>{g!==void 0&&(clearTimeout(g),g=void 0),u!==void 0&&(u=void 0,e&&n.setNotice(""))},"disarmKill"),f=i(()=>{m(!0),r!==void 0&&(r=void 0,p())},"exit"),N=i(e=>H(e)??(e.length===1?e:void 0),"typed"),E=i((e,t=40)=>{const d=(e.split(`
1
+ var M=Object.defineProperty;var i=(b,n)=>M(b,"name",{value:n,configurable:!0});import{execFile as C}from"node:child_process";import{Text as P,decodeKittyPrintable as H,matchesKey as h}from"@earendil-works/pi-tui";import{cliClient as S}from"../../../commands/api-client.js";import{activeBackgroundBashJobs as I}from"../../../core/bash-jobs.js";import{contextDir as T}from"../../../core/canvas/node-agent-paths.js";import{fillBar as O,fillWidth as D,stripSgr as J,REVERSE as U}from"../../../core/canvas/nav-render.js";import{buildCanvasPanelLines as F}from"./canvas-panels.js";const L=15e3;function ne(b,n){const{editor:_,tui:x,pal:K,nodeId:l,remote:a,role:v,canvasSource:$}=b,w=b.containers.reports;let o=[],r,y=process.env.CRTR_ATTACH_ROSTER;y!==void 0&&delete process.env.CRTR_ATTACH_ROSTER;let u,g;const p=i(()=>{n.syncCursor(),w.clear();for(const e of o){const t=e.key===r;w.addChild(new P(t?O(J(e.line),D(),U):e.line,1,0))}x.requestRender()},"paint"),A=i(async()=>{const e=a?[]:(await S().listCrons()).filter(c=>c.created_by===l),t=a?[]:I(T(l)),d=a?[]:(await S().listReviews({state:"open",origin_node_id:l})).reviews;if(o=(await F(l,n.asks(),K,$,e,t,d)).items,y!==void 0){const c=y;y=void 0;const R=o.find(j=>j.kind==="node"&&j.nodeId===c);R!==void 0&&(r=R.key)}r!==void 0&&!o.some(c=>c.key===r)&&(r=void 0),u!==void 0&&!t.some(c=>c.jobId===u?.jobId)&&m(!0),p()},"refresh"),m=i(e=>{g!==void 0&&(clearTimeout(g),g=void 0),u!==void 0&&(u=void 0,e&&n.setNotice(""))},"disarmKill"),f=i(()=>{m(!0),r!==void 0&&(r=void 0,p())},"exit"),N=i(e=>H(e)??(e.length===1?e:void 0),"typed"),E=i((e,t=40)=>{const d=(e.split(`
2
2
  `)[0]??"").replace(/\s+/g," ").trim();return d.length>t?`${d.slice(0,t-1)}\u2026`:d},"commandHead"),B=i(()=>{if(v!=="controller"){n.setNotice("Read-only observer attach \u2014 cannot stop background jobs");return}const e=I(T(l));if(e.length===0){n.setNotice("Background job already finished"),n.requestChromeRefresh();return}if(e.length>1){n.setNotice(`${e.length} background jobs \u2014 press \u21B5 to pick one in the Inspector`);return}const t=e[0];u={jobId:t.jobId,label:E(t.command)},n.setNotice(`Stop \u201C${u.label}\u201D? Press y to confirm.`,{sticky:!0}),g=setTimeout(()=>m(!0),L)},"armKill"),k=i(()=>{const e=u;e!==void 0&&(m(!1),n.setNotice(`Stopping \u201C${e.label}\u201D\u2026`),C("crtr",["node","bash","kill",e.jobId,"--node",l],t=>{n.setNotice(t===null?`Stopped \u201C${e.label}\u201D.`:`Could not stop the job: ${t.message.split(`
3
3
  `)[0]}`),n.requestChromeRefresh()}))},"confirmKill");_.onCursorDownAtBottom=a?void 0:()=>{r!==void 0||o.length===0||(r=o[0].key,p())};const q=i(()=>{const e=o.find(s=>s.key===r);if(e===void 0||a)return;if(e.kind==="crons"){f(),n.openInspector("schedule");return}if(e.kind==="review"){if(v!=="controller"){n.setNotice("Read-only observer attach \u2014 cannot open the review companion");return}f(),C("crtr",["surface","node","focus",e.companionNodeId],s=>{s!==null&&n.setNotice(`Could not open the companion: ${s.message.split(`
4
4
  `)[0]}`)});return}if(e.kind==="bash"){if(I(T(l)).length===0){n.setNotice("Background job already finished"),n.requestChromeRefresh();return}f(),n.openInspector("jobs");return}const t=e.nodeId;if(t===l){f();return}if(v!=="controller"){n.setNotice("Read-only observer attach \u2014 cannot focus nodes");return}const d=process.env.TMUX_PANE;if(d===void 0||d===""){n.setNotice("cannot swap \u2014 no tmux pane");return}C("tmux",["run-shell","-b",`crtr surface node focus ${t} --pane ${d} --in-place >/dev/null 2>&1`],()=>{})},"openSelected");return{refresh:A,handleKey:i(e=>{if(a)return!1;const t=h(e,"down"),d=h(e,"up");if(r===void 0)return!1;const s=o.findIndex(R=>R.key===r),c=o[s];if(u!==void 0){if(N(e)==="y")return k(),!0;m(!0)}return c?.kind==="bash"&&N(e)==="x"?(B(),!0):d?(s<=0?f():(r=o[s-1].key,p()),!0):t?(s>=0&&s<o.length-1&&(r=o[s+1].key,p()),!0):h(e,"enter")?(q(),!0):h(e,"escape")?(f(),!0):(f(),!1)},"handleKey"),active:i(()=>r!==void 0,"active"),exit:f}}i(ne,"createRoster");export{ne as createRoster};
@@ -1 +1 @@
1
- var y=Object.defineProperty;var t=(e,o)=>y(e,"name",{value:o,configurable:!0});import{readFileSync as p}from"node:fs";import{createRequire as b}from"node:module";import{homedir as h}from"node:os";import{join as i}from"node:path";import{pathToFileURL as x}from"node:url";import{KeybindingsManager as K,TUI_KEYBINDINGS as w,setKeybindings as k}from"@earendil-works/pi-tui";import{initTheme as T,getMarkdownTheme as l,getSelectListTheme as E}from"@earendil-works/pi-coding-agent";import{surfaceBgAnsi as B}from"../../core/runtime/surface-bg.js";function s(){return i(h(),".pi","agent")}t(s,"defaultAgentDir");const I={"app.interrupt":{defaultKeys:"escape",description:"Cancel or abort"},"app.clear":{defaultKeys:"ctrl+c",description:"Clear editor"},"app.exit":{defaultKeys:"ctrl+d",description:"Exit when editor is empty"},"app.suspend":{defaultKeys:"ctrl+z",description:"Suspend to background"},"app.thinking.cycle":{defaultKeys:"shift+tab",description:"Cycle thinking level"},"app.model.cycleForward":{defaultKeys:"ctrl+p",description:"Cycle to next model"},"app.model.cycleBackward":{defaultKeys:"shift+ctrl+p",description:"Cycle to previous model"},"app.model.select":{defaultKeys:"ctrl+l",description:"Open model selector"},"app.tools.expand":{defaultKeys:"ctrl+o",description:"Toggle tool output"},"app.thinking.toggle":{defaultKeys:"ctrl+t",description:"Toggle thinking blocks"},"app.editor.external":{defaultKeys:"ctrl+g",description:"Open external editor"},"app.message.followUp":{defaultKeys:[],description:"Queue follow-up message"},"app.message.dequeue":{defaultKeys:"alt+up",description:"Restore queued messages"},"app.clipboard.pasteImage":{defaultKeys:["alt+v","ctrl+v"],description:"Paste image from clipboard"},"app.session.new":{defaultKeys:[],description:"Start a new session"},"app.session.tree":{defaultKeys:[],description:"Open session tree"},"app.session.fork":{defaultKeys:[],description:"Fork current session"},"app.session.resume":{defaultKeys:[],description:"Resume a session"}};function R(e=s()){try{const o=JSON.parse(p(i(e,"keybindings.json"),"utf8")),n=o&&typeof o=="object"&&"keybindings"in o?o.keybindings:o;return!n||typeof n!="object"?void 0:n}catch{return}}t(R,"loadUserKeybindings");const $={"tui.input.newLine":{defaultKeys:["shift+enter","alt+enter"],description:"Insert new line"}};function q(e=s()){const o={...w,...I,...$},n=new K(o,R(e));return k(n),n}t(q,"createKeybindingsManager");let a;function u(){return a||(a=(async()=>{try{const e=import.meta.resolve("@earendil-works/pi-coding-agent"),o=b(e).resolve("@earendil-works/pi-tui");return await import(x(o).href)}catch{return}})()),a}t(u,"editorPiTui");async function H(e){(await u())?.setKeybindings(e)}t(H,"mirrorKeybindingsToEditor");async function J(e){(await u())?.setKittyProtocolActive(e)}t(J,"mirrorKittyProtocolToEditor");let c;function V(){return c||(c=(async()=>{try{const e=import.meta.resolve("@earendil-works/pi-coding-agent");return await(await import(new URL("./utils/tools-manager.js",e).href)).ensureTool("fd",!0)??null}catch{return null}})()),c}t(V,"resolveFdPath");function N(e){const o=[i(e?.cwd??process.cwd(),".pi","settings.json"),i(e?.agentDir??s(),"settings.json")];for(const n of o)try{const r=JSON.parse(p(n,"utf8"));if(r&&typeof r=="object"&&typeof r.theme=="string")return r.theme}catch{}}t(N,"loadThemeName");function z(e){T(N(e))}t(z,"applyTheme");const P=t(e=>`\x1B[2m${e}\x1B[22m`,"FAINT"),C=t(e=>`\x1B[31m${e}\x1B[39m`,"RED"),O=t(e=>`\x1B[33m${e}\x1B[39m`,"YELLOW"),f=t(e=>`\x1B[32m${e}\x1B[39m`,"GREEN"),v=t(e=>`\x1B[92m${e}\x1B[39m`,"BRIGHT_GREEN"),D=t(e=>`\x1B[91m${e}\x1B[39m`,"DIFF_REMOVED"),d="\x1B[48;2;36;36;36m";function M(e,o){return`${d}${e(o).replace(/\x1b\[0m/g,`\x1B[0m${d}`)}`}t(M,"codeSurfaceFragment");function Q(){const e=l(),o=t((n,r)=>M(n,r),"paint");return{...e,codeBlockIndent:`${d}${e.codeBlockIndent??" "}`,codeBlock:t(n=>o(e.codeBlock,n),"codeBlock"),codeBlockBorder:t(n=>o(e.codeBlockBorder,n),"codeBlockBorder"),highlightCode:e.highlightCode?(n,r)=>e.highlightCode(n,r).map(m=>o(g=>g,m)):void 0}}t(Q,"attachMarkdownTheme");function W(){const e=l(),o=E(),n=B();return{accent:e.heading,active:e.code,info:e.link,muted:o.description,faint:P,border:e.hr,bold:e.bold,error:C,warning:O,diffAdded:f,diffRemoved:D,bashMode:f,bashModeAlt:v,surface:t(r=>`${n}${r.replace(/\x1b\[0m/g,`\x1B[0m${n}`)}\x1B[49m`,"surface")}}t(W,"attachPalette");export{z as applyTheme,Q as attachMarkdownTheme,W as attachPalette,q as createKeybindingsManager,s as defaultAgentDir,N as loadThemeName,R as loadUserKeybindings,H as mirrorKeybindingsToEditor,J as mirrorKittyProtocolToEditor,V as resolveFdPath};
1
+ var y=Object.defineProperty;var t=(e,o)=>y(e,"name",{value:o,configurable:!0});import{readFileSync as p}from"node:fs";import{createRequire as b}from"node:module";import{piAgentDir as h}from"../../core/runtime/package-health.js";import{join as i}from"node:path";import{pathToFileURL as x}from"node:url";import{KeybindingsManager as K,TUI_KEYBINDINGS as w,setKeybindings as k}from"@earendil-works/pi-tui";import{initTheme as T,getMarkdownTheme as l,getSelectListTheme as E}from"@earendil-works/pi-coding-agent";import{surfaceBgAnsi as B}from"../../core/runtime/surface-bg.js";function s(){return h()}t(s,"defaultAgentDir");const I={"app.interrupt":{defaultKeys:"escape",description:"Cancel or abort"},"app.clear":{defaultKeys:"ctrl+c",description:"Clear editor"},"app.exit":{defaultKeys:"ctrl+d",description:"Exit when editor is empty"},"app.suspend":{defaultKeys:"ctrl+z",description:"Suspend to background"},"app.thinking.cycle":{defaultKeys:"shift+tab",description:"Cycle thinking level"},"app.model.cycleForward":{defaultKeys:"ctrl+p",description:"Cycle to next model"},"app.model.cycleBackward":{defaultKeys:"shift+ctrl+p",description:"Cycle to previous model"},"app.model.select":{defaultKeys:"ctrl+l",description:"Open model selector"},"app.tools.expand":{defaultKeys:"ctrl+o",description:"Toggle tool output"},"app.thinking.toggle":{defaultKeys:"ctrl+t",description:"Toggle thinking blocks"},"app.editor.external":{defaultKeys:"ctrl+g",description:"Open external editor"},"app.message.followUp":{defaultKeys:[],description:"Queue follow-up message"},"app.message.dequeue":{defaultKeys:"alt+up",description:"Restore queued messages"},"app.clipboard.pasteImage":{defaultKeys:["alt+v","ctrl+v"],description:"Paste image from clipboard"},"app.session.new":{defaultKeys:[],description:"Start a new session"},"app.session.tree":{defaultKeys:[],description:"Open session tree"},"app.session.fork":{defaultKeys:[],description:"Fork current session"},"app.session.resume":{defaultKeys:[],description:"Resume a session"}};function R(e=s()){try{const o=JSON.parse(p(i(e,"keybindings.json"),"utf8")),n=o&&typeof o=="object"&&"keybindings"in o?o.keybindings:o;return!n||typeof n!="object"?void 0:n}catch{return}}t(R,"loadUserKeybindings");const $={"tui.input.newLine":{defaultKeys:["shift+enter","alt+enter"],description:"Insert new line"}};function q(e=s()){const o={...w,...I,...$},n=new K(o,R(e));return k(n),n}t(q,"createKeybindingsManager");let a;function u(){return a||(a=(async()=>{try{const e=import.meta.resolve("@earendil-works/pi-coding-agent"),o=b(e).resolve("@earendil-works/pi-tui");return await import(x(o).href)}catch{return}})()),a}t(u,"editorPiTui");async function H(e){(await u())?.setKeybindings(e)}t(H,"mirrorKeybindingsToEditor");async function J(e){(await u())?.setKittyProtocolActive(e)}t(J,"mirrorKittyProtocolToEditor");let c;function V(){return c||(c=(async()=>{try{const e=import.meta.resolve("@earendil-works/pi-coding-agent");return await(await import(new URL("./utils/tools-manager.js",e).href)).ensureTool("fd",!0)??null}catch{return null}})()),c}t(V,"resolveFdPath");function N(e){const o=[i(e?.cwd??process.cwd(),".pi","settings.json"),i(e?.agentDir??s(),"settings.json")];for(const n of o)try{const r=JSON.parse(p(n,"utf8"));if(r&&typeof r=="object"&&typeof r.theme=="string")return r.theme}catch{}}t(N,"loadThemeName");function z(e){T(N(e))}t(z,"applyTheme");const P=t(e=>`\x1B[2m${e}\x1B[22m`,"FAINT"),C=t(e=>`\x1B[31m${e}\x1B[39m`,"RED"),D=t(e=>`\x1B[33m${e}\x1B[39m`,"YELLOW"),f=t(e=>`\x1B[32m${e}\x1B[39m`,"GREEN"),O=t(e=>`\x1B[92m${e}\x1B[39m`,"BRIGHT_GREEN"),v=t(e=>`\x1B[91m${e}\x1B[39m`,"DIFF_REMOVED"),d="\x1B[48;2;36;36;36m";function A(e,o){return`${d}${e(o).replace(/\x1b\[0m/g,`\x1B[0m${d}`)}`}t(A,"codeSurfaceFragment");function Q(){const e=l(),o=t((n,r)=>A(n,r),"paint");return{...e,codeBlockIndent:`${d}${e.codeBlockIndent??" "}`,codeBlock:t(n=>o(e.codeBlock,n),"codeBlock"),codeBlockBorder:t(n=>o(e.codeBlockBorder,n),"codeBlockBorder"),highlightCode:e.highlightCode?(n,r)=>e.highlightCode(n,r).map(m=>o(g=>g,m)):void 0}}t(Q,"attachMarkdownTheme");function W(){const e=l(),o=E(),n=B();return{accent:e.heading,active:e.code,info:e.link,muted:o.description,faint:P,border:e.hr,bold:e.bold,error:C,warning:D,diffAdded:f,diffRemoved:v,bashMode:f,bashModeAlt:O,surface:t(r=>`${n}${r.replace(/\x1b\[0m/g,`\x1B[0m${n}`)}\x1B[49m`,"surface")}}t(W,"attachPalette");export{z as applyTheme,Q as attachMarkdownTheme,W as attachPalette,q as createKeybindingsManager,s as defaultAgentDir,N as loadThemeName,R as loadUserKeybindings,H as mirrorKeybindingsToEditor,J as mirrorKittyProtocolToEditor,V as resolveFdPath};
@@ -1,2 +1,2 @@
1
- var N=Object.defineProperty;var t=(o,i)=>N(o,"name",{value:i,configurable:!0});import{join as C}from"node:path";import{execFile as _}from"node:child_process";import{CredentialSynchronizationError as B,ModelRuntime as D,OAuthSelectorComponent as A,LoginDialogComponent as O}from"@earendil-works/pi-coding-agent";import{deleteAuthCredential as T,setAuthCredential as z}from"../../../core/auth-file.js";import{PoolCredentialStore as F}from"../../../core/pool-credential-store.js";import{dialogAuthInteraction as U}from"../../../core/auth-interaction.js";import{commitManagedLogin as q,isManagedProvider as S,readSubscriptionPool as G,removeManagedProvider as H}from"../../../core/subscription-state.js";async function M(o){const i=C(o,"auth.json"),a=C(o,"models.json"),e=new F(i);let l;const P={read:t(r=>e.read(r),"read"),list:t(()=>e.list(),"list"),modify:t((r,d)=>{const m=l;return l=void 0,m!==void 0&&!m()?Promise.reject(new Error("Login cancelled")):e.modify(r,d)},"modify"),delete:t(r=>e.delete(r),"delete")};return{runtime:await D.create({credentials:P,modelsPath:a}),authPath:i,beforeNextCredentialMutation:t(r=>{l=r},"beforeNextCredentialMutation")}}t(M,"buildLocalAuth");async function j(o){const i=o.getProviders(),a=[...i.filter(e=>e.auth.oauth!==void 0),...i.filter(e=>e.auth.oauth===void 0)];return Promise.all(a.map(async e=>({id:e.id,name:e.name,authType:e.auth.oauth!==void 0?"oauth":"api_key",status:await o.checkAuth(e.id)})))}t(j,"buildProviderList");function J(o){const i=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";_(i,[o],{timeout:5e3},()=>{})}t(J,"openBrowser");async function I(o,i,a,e){const{runtime:l,authPath:P,beforeNextCredentialMutation:w}=await M(i),r=await j(l);return({close:d,replace:m})=>{const b=t(u=>{const s=r.find(n=>n.id===u);if(s===void 0){e(`Unknown provider: ${u}`),d();return}let L=!1,y=!1;const h=t(()=>{L||(L=!0,d())},"finish"),c=new O(o,u,(n,g)=>{L||(n?(e(`Logged in to ${s.name}`),a()):e(g?`Login failed: ${g}`:`Login to ${s.name} was cancelled`),h())},s.name);m(c,c);const E=c.handleInput.bind(c);c.handleInput=n=>{y||E(n)};const $=t(()=>L||c.signal.aborted?!1:(y=!0,c.showDetails(["Saving credentials\u2026"]),!0),"beginCommit"),k=U(c,{openBrowser:J,isActive:t(()=>!L&&!c.signal.aborted,"isActive")}),x=t(n=>{if(n instanceof B){e(`Logged in to ${s.name}; provider refresh failed: ${n.message}`),a(),h();return}const g=n;g?.name!=="AbortError"&&g?.message!=="Login cancelled"&&e(`Login error: ${String(g?.message??n)}`),h()},"fail");if(S(u)){const n=l.getProvider(u)?.auth.oauth;if(n===void 0){e(`Provider "${s.name}" has no OAuth flow`),h();return}const g=Math.max(0,...G(u).map(p=>p.lastRateLimitedAt));n.login(k).then(async p=>{if(!$())return;const v=typeof p.accountId=="string"&&p.accountId.trim()?p.accountId.trim():void 0;await q(u,u,{refresh:p.refresh,access:p.access,expires:p.expires,accountId:v,lastRateLimitedAt:g,autoLabel:!0}),e(`Logged in to ${s.name}`),a(),h()}).catch(x);return}if(s.authType==="oauth"){if(l.getProvider(u)?.auth.oauth===void 0){c.showInfo([`Provider "${s.name}" is extension-registered and cannot be logged in`,"from the viewer (the extension runs in the broker, not here).","Run /login directly in the node's terminal, or log in via the pi CLI."].join(`
2
- `));return}w($),l.login(u,"oauth",k).then(()=>{L||(e(`Logged in to ${s.name}`),a(),h())}).catch(x).finally(()=>w(void 0))}else c.showPrompt(`Enter API key for ${s.name}:`,"sk-...").then(async n=>{if(!L){if(n.trim()){if(!$())return;await z(u,{type:"api_key",key:n.trim()},P),e(`API key saved for ${s.name}`),a()}else e("No key entered \u2014 login cancelled");h()}}).catch(()=>h())},"onSelect"),f=new A("login",r,b,()=>d());return{component:f,focus:f}}}t(I,"buildLoginPicker");async function ee(o,i,a){const{runtime:e,authPath:l}=await M(o),P=await j(e);return({close:w})=>{const r=t(m=>{const b=P.find(f=>f.id===m);(async()=>{try{S(m)?await H(m):await T(m,l),w(),a(`Logged out of ${b?.name??m}`),i()}catch(f){w(),a(`Logout error: ${f instanceof Error?f.message:String(f)}`)}})()},"onSelect"),d=new A("logout",P,r,()=>w());return{component:d,focus:d}}}t(ee,"buildLogoutPicker");export{I as buildLoginPicker,ee as buildLogoutPicker};
1
+ var v=Object.defineProperty;var t=(i,n)=>v(i,"name",{value:n,configurable:!0});import{join as C}from"node:path";import{execFile as E}from"node:child_process";import{CredentialSynchronizationError as D,ModelRuntime as N,OAuthSelectorComponent as x,LoginDialogComponent as _}from"@earendil-works/pi-coding-agent";import{deleteAuthCredential as B,setAuthCredential as T}from"../../../core/auth-file.js";import{PoolCredentialStore as z}from"../../../core/pool-credential-store.js";import{secretsDir as F}from"../../../core/layout.js";import{dialogAuthInteraction as O}from"../../../core/auth-interaction.js";import{isManagedProvider as S,removeManagedProvider as U}from"../../../core/subscription-state.js";import{daemonManagedLogin as q}from"../../../core/model-auth/daemon-login.js";import{cliClient as G}from"../../../commands/api-client.js";async function A(i){const n=C(F(),"auth.json"),r=C(i,"models.json"),e=new z(n);let l;const w={read:t(a=>e.read(a),"read"),list:t(()=>e.list(),"list"),modify:t((a,m)=>{const u=l;return l=void 0,u!==void 0&&!u()?Promise.reject(new Error("Login cancelled")):e.modify(a,m)},"modify"),delete:t(a=>e.delete(a),"delete")};return{runtime:await N.create({credentials:w,modelsPath:r}),authPath:n,beforeNextCredentialMutation:t(a=>{l=a},"beforeNextCredentialMutation")}}t(A,"buildLocalAuth");async function M(i){const n=i.getProviders(),r=[...n.filter(e=>e.auth.oauth!==void 0),...n.filter(e=>e.auth.oauth===void 0)];return Promise.all(r.map(async e=>({id:e.id,name:e.name,authType:e.auth.oauth!==void 0?"oauth":"api_key",status:await i.checkAuth(e.id)})))}t(M,"buildProviderList");function H(i){const n=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";E(n,[i],{timeout:5e3},()=>{})}t(H,"openBrowser");async function te(i,n,r,e){const{runtime:l,authPath:w,beforeNextCredentialMutation:h}=await A(n),a=await M(l);return({close:m,replace:u})=>{const P=t(f=>{const s=a.find(o=>o.id===f);if(s===void 0){e(`Unknown provider: ${f}`),m();return}let g=!1,$=!1;const p=t(()=>{g||(g=!0,m())},"finish"),c=new _(i,f,(o,L)=>{g||(o?(e(`Logged in to ${s.name}`),r()):e(L?`Login failed: ${L}`:`Login to ${s.name} was cancelled`),p())},s.name);u(c,c);const j=c.handleInput.bind(c);c.handleInput=o=>{$||j(o)};const b=t(()=>g||c.signal.aborted?!1:($=!0,c.showDetails(["Saving credentials\u2026"]),!0),"beginCommit"),y=O(c,{openBrowser:H,isActive:t(()=>!g&&!c.signal.aborted,"isActive")}),k=t(o=>{if(o instanceof D){e(`Logged in to ${s.name}; provider refresh failed: ${o.message}`),r(),p();return}const L=o;L?.name!=="AbortError"&&L?.message!=="Login cancelled"&&e(`Login error: ${String(L?.message??o)}`),p()},"fail");if(S(f)){q(G(),f,y).then(()=>{g||(e(`Logged in to ${s.name}`),r(),p())}).catch(k);return}if(s.authType==="oauth"){if(l.getProvider(f)?.auth.oauth===void 0){c.showInfo([`Provider "${s.name}" is extension-registered and cannot be logged in`,"from the viewer (the extension runs in the broker, not here).","Run /login directly in the node's terminal, or log in via the pi CLI."].join(`
2
+ `));return}h(b),l.login(f,"oauth",y).then(()=>{g||(e(`Logged in to ${s.name}`),r(),p())}).catch(k).finally(()=>h(void 0))}else c.showPrompt(`Enter API key for ${s.name}:`,"sk-...").then(async o=>{if(!g){if(o.trim()){if(!b())return;await T(f,{type:"api_key",key:o.trim()},w),e(`API key saved for ${s.name}`),r()}else e("No key entered \u2014 login cancelled");p()}}).catch(()=>p())},"onSelect"),d=new x("login",a,P,()=>m());return{component:d,focus:d}}}t(te,"buildLoginPicker");async function ne(i,n,r){const{runtime:e,authPath:l}=await A(i),w=await M(e);return({close:h})=>{const a=t(u=>{const P=w.find(d=>d.id===u);(async()=>{try{S(u)?await U(u):await B(u,l),h(),r(`Logged out of ${P?.name??u}`),n()}catch(d){h(),r(`Logout error: ${d instanceof Error?d.message:String(d)}`)}})()},"onSelect"),m=new x("logout",w,a,()=>h());return{component:m,focus:m}}}t(ne,"buildLogoutPicker");export{te as buildLoginPicker,ne as buildLogoutPicker};
@@ -1 +1 @@
1
- var O=Object.defineProperty;var m=(u,t)=>O(u,"name",{value:t,configurable:!0});import{execFile as q}from"node:child_process";import{matchesKey as P,truncateToWidth as T}from"@earendil-works/pi-tui";import{formatBinding as H,matchesPiTuiInput as L}from"../../../core/keybindings/index.js";import{fullName as B}from"../../../core/canvas/labels.js";import{faultSummary as G,resolveNodeVisual as C}from"../../../core/canvas/status-glyph.js";import{RemoteCanvasSource as W}from"../../../core/canvas/remote-canvas-source.js";import{cliClient as F}from"../../../commands/api-client.js";import{statusRank as M}from"../../../core/canvas/node-order.js";import{navLabel as K,nodeGlyph as j,tokensCell as D,cycleBadge as V,askBadge as Y,activityCell as z,shortId as E,visibleWidth as k,fillBar as A,fillWidth as N,truncate as U,isAttached as X,VIEWPORT_FALLBACK_ROWS as J,ESC as Q,DIM as R,RESET as g,BOLD as S,YELLOW as Z,REVERSE as ee,BG_ATTACHED as te,GREEN as se}from"../../../core/canvas/nav-render.js";const ie=.72,ne={anchor:"center",width:"72%",minWidth:48,maxHeight:"72%",margin:1},re=[["crtr.graph.dismiss","dismiss"],["crtr.graph.focus","focus"],["crtr.graph.revive","revive"],["crtr.graph.close-subtree","close"],["crtr.graph.focus-manager","manager"]],oe=[["crtr.graph.dismiss","dismiss"]],ce=[["crtr.graph.down","down"],["crtr.graph.up","up"],["crtr.graph.first","first"],["crtr.graph.last","last"],["crtr.graph.collapse-or-manager","fold/manager"],["crtr.graph.expand-or-child","expand/child"]],ae=[...["active","idle","done","dead","canceled"].map(u=>[C(u,{}),u]),[C("active",{streaming:!0}),"live"],[C("active",{frozen:!0}),"frozen"],[C("active",{hanging:{kind:"wedged"}}),"fault"]].map(([u,t])=>`${Q}${u.color}m${u.glyph}${g} ${R}${t}${g}`).join(" ");function he(u){return{node_id:u.node_id,name:u.name,kind:u.kind,description:u.description??void 0,cycles:u.cycles??void 0,status:u.status,frozen_at:u.frozen_at,pi_pid:u.pi_pid,telemetry_context_tokens:u.telemetry_context_tokens,telemetry_last_activity:u.telemetry_last_activity,fault:u.fault??null,streaming:u.streaming}}m(he,"graphRow");class be{static{m(this,"GraphOverlay")}tui;self;getAsks;palette;bindings;source;role;onRefreshFailure;onNotice;handle;userExpanded=new Set;userCollapsed=new Set;folds={userExpanded:this.userExpanded,userCollapsed:this.userCollapsed};cursorId;scrollTop=0;pendingConfirm;snapshot;snapshotSeq=0;remote;constructor(t,s,i,e,n,o,f="controller",p=()=>{},r=()=>{}){this.tui=t,this.self=s,this.getAsks=i,this.palette=e,this.bindings=n,this.source=o,this.role=f,this.onRefreshFailure=p,this.onNotice=r,this.remote=o instanceof W}setBindings(t){this.bindings=t,this.handle!==void 0&&this.tui.requestRender()}matches(t,s){return L(this.bindings,t,s,(i,e)=>P(i,e))}hint(t){return t.flatMap(([s,i])=>this.bindings.gestures(s).length===0?[]:[`${H(this.bindings,s)} ${i}`])}fitHints(t,s){const e=[];let n=0;for(const o of this.hint(t)){const f=(e.length===0?0:3)+k(o);if(n+f>s)break;e.push(o),n+=f}return e.join(" \xB7 ")}isOpen(){return this.handle!==void 0}open(){this.handle===void 0&&(this.scrollTop=0,this.pendingConfirm=void 0,this.cursorId=this.self,this.handle=this.tui.showOverlay(this,ne),this.refresh())}close(){this.handle!==void 0&&(this.pendingConfirm=void 0,this.handle.hide(),this.handle=void 0,this.tui.requestRender())}toggle(){this.handle===void 0?this.open():this.close()}refresh(){if(this.handle===void 0)return;const t=++this.snapshotSeq;this.buildSnapshot().then(s=>{t===this.snapshotSeq&&(this.snapshot=s,this.tui.requestRender())}).catch(s=>{this.onRefreshFailure(s),this.tui.requestRender()})}invalidate(){this.refresh()}async fetchInput(){if(this.remote){const e=await this.source.listNodes().catch(()=>[]);return{nodes:new Map(e.map(n=>[n.node_id,n])),subscriptions:m(async n=>(await this.source.subscriptionsOf(n)).map(o=>o.node_id),"subscriptions"),subscribers:m(async n=>(await this.source.subscribersOf(n)).map(o=>o.node_id),"subscribers"),focused:new Set}}const t=await F().canvasGraph(),s=new Map,i=new Map;for(const e of t.edges){const n=s.get(e.from_id);n===void 0?s.set(e.from_id,[e.to_id]):n.push(e.to_id);const o=i.get(e.to_id);o===void 0?i.set(e.to_id,[e.from_id]):o.push(e.from_id)}return{nodes:new Map(t.nodes.map(e=>[e.node_id,he(e)])),subscriptions:m(e=>Promise.resolve(s.get(e)??[]),"subscriptions"),subscribers:m(e=>Promise.resolve(i.get(e)??[]),"subscribers"),focused:new Set(t.focused_node_ids)}}async buildSnapshot(){const t=await this.fetchInput(),{nodes:s,focused:i}=t,e=new Map,n=new Map,o=new Map,f=new Map,p=m(async c=>{const l=e.get(c);if(l!==void 0)return l;let a;try{a=await t.subscriptions(c)}catch{a=[]}const $=a.filter(b=>s.get(b)?.kind!=="human");return e.set(c,$),$},"children"),r=m(async c=>{if(o.has(c))return o.get(c);let l;try{l=(await t.subscribers(c))[0]}catch{l=void 0}return o.set(c,l),l},"manager"),h=m(async()=>{let c=this.self;const l=new Set([c]);for(;;){const a=await r(c);if(a===void 0||l.has(a))break;l.add(a),c=a}return c},"climbRoot"),d=m(async c=>{const l=n.get(c);if(l!==void 0)return l;const a=[...await p(c)];return a.sort(($,b)=>M(s.get($)?.status)-M(s.get(b)?.status)),n.set(c,a),a},"sortedChildren"),w=new Set,v=new Set,I=m(async c=>{const l=s.get(c)?.status==="active";if(v.has(c))return{active:l?1:0,reveal:l||c===this.self};v.add(c);let a=0,$=!1;for(const b of await p(c)){const x=await I(b);a+=x.active,x.reveal&&($=!0)}return f.set(c,a),$&&w.add(c),{active:a+(l?1:0),reveal:$||l||c===this.self}},"visitActivity"),_=await h();await I(_),await Promise.all([...e.keys()].map(c=>d(c)));const y={root:_,rows:[],autoExpanded:w,activeBelow:f,nodes:s,childIds:e,sortedChildIds:n,managerOf:o,focused:i};return y.rows=this.projectRows(y),y}projectRows(t){const s=[],i=new Set,e=[{id:t.root,prefix:"",isRoot:!0,isLast:!0}];for(;e.length>0;){const{id:n,prefix:o,isRoot:f,isLast:p}=e.pop(),r=f?"":p?"\u2514\u2500 ":"\u251C\u2500 ";if(i.has(n)){s.push({id:n,hasKids:!1,isSelf:n===this.self,branch:o+r,cycle:!0,collapsed:!1});continue}i.add(n);const h=t.sortedChildIds.get(n)??[],d=this.folds.userExpanded.has(n)?!1:this.folds.userCollapsed.has(n)?!0:!t.autoExpanded.has(n);if(s.push({id:n,hasKids:h.length>0,isSelf:n===this.self,branch:o+r,cycle:!1,collapsed:d}),d)continue;const w=f?"":o+(p?" ":"\u2502 ");for(let v=h.length-1;v>=0;v--)e.push({id:h[v],prefix:w,isRoot:!1,isLast:v===h.length-1})}return s}repaintFolds(){this.snapshot!==void 0&&(this.snapshot.rows=this.projectRows(this.snapshot)),this.tui.requestRender()}renderSnapshotRow(t,s,i,e){const n=m((b,x)=>i?A(b,N(),ee):x?A(b,N(),te):U(b),"wrap");if(s.cycle){const b=`${s.branch} ${R}\u21BA ${E(s.id)}${g}`;return n(b,!1)}const o=t.nodes.get(s.id)??null,f=j(o),p=K(o,s.id),r=s.isSelf?`${S}${p}${g}`:p,h=`${R}${o?.kind??""}${g}`,d=`${R}${D(o,this.remote)}${g}`,w=s.hasKids&&s.collapsed,v=!i&&w?`${R}\u25B8${g} `:" ",I=V(o),_=t.childIds.get(s.id)?.length??0,y=o!==null&&_>0?` ${R}\u2933${_}${g}`:"",c=o!==null&&o.status!=="active"&&(t.activeBelow.get(o.node_id)??0)>0?` ${se}\u21E3${t.activeBelow.get(o.node_id)??0}${g}`:"",l=o?.fault??null,a=l!==null?` \xB7 ${G(l)}`:"",$=`${s.branch}${v}${f} ${r} ${h} ${d}${I}${y}${c}${Y(s.id,e)}${z(o,this.remote)}${a}`;return n($,X(s.id,o,t.focused,this.remote))}render(t){const s=this.getAsks(),i=this.snapshot?.rows??[];let e=i.findIndex(a=>a.id===this.cursorId);e<0&&(e=i.findIndex(a=>a.id===this.self),e<0&&(e=0)),this.cursorId=i[e]?.id??this.self;const n=process.stdout.rows??J,o=Math.max(3,Math.min(Math.floor(n*ie),n-2)),f=Math.min(o-2,Math.max(2,i.length)),p=f-1,r=p>=3;let h=p;for(let a=0;p>0&&a<4;a++){e<this.scrollTop&&(this.scrollTop=e),e>=this.scrollTop+h&&(this.scrollTop=e-h+1),this.scrollTop=Math.max(0,Math.min(this.scrollTop,Math.max(0,i.length-h)));const $=p-(r&&this.scrollTop>0?1:0)-(r&&this.scrollTop+h<i.length?1:0);if($===h)break;h=Math.max(1,$)}const d=Math.min(i.length,this.scrollTop+h),w=[];r&&this.scrollTop>0&&w.push(`${R} \u2191 ${this.scrollTop} more${g}`);for(let a=this.scrollTop;a<d;a++){const $=this.snapshot;w.push($!==void 0?this.renderSnapshotRow($,i[a],a===e,s):"")}for(r&&d<i.length&&w.push(`${R} \u2193 ${i.length-d} more${g}`),w.unshift(ae);w.length<f;)w.push("");const v=i.length>0?`${S}\u2317 canvas graph${g} ${R}(${e+1}/${i.length})${g}`:`${S}\u2317 canvas graph${g} ${R}(loading)${g}`,I=this.pendingConfirm!==void 0?`${Z}${this.pendingConfirm.label} ${S}${this.hint([["crtr.graph.confirm.accept","accept"],["crtr.graph.confirm.cancel","cancel"]]).join(" \xB7 ")}${g}`:`${R}${this.fitHints([...this.remote||this.role!=="controller"?oe:re,...ce],Math.max(1,t-5))}${g}`,_=this.palette.border,y=Math.max(1,t-4),c=w.map(a=>`${_("\u2502")} ${T(a,y,"",!0)} ${_("\u2502")}`),l=this.palette.surface;return[this.borderRow("\u256D","\u256E",v,t),...c,this.borderRow("\u2570","\u256F",I,t)].map(l)}borderRow(t,s,i,e){const n=this.palette.border,o=Math.max(1,e-5),f=T(i,o,"\u2026"),p=Math.max(0,e-5-k(f));return`${n(`${t}\u2500`)} ${f} ${n("\u2500".repeat(p)+s)}`}handleInput(t){try{this.dispatch(t)}catch{}}dispatch(t){if(this.pendingConfirm!==void 0){if(this.matches("crtr.graph.confirm.accept",t)){const r=this.pendingConfirm.action;this.pendingConfirm=void 0,r()}else this.pendingConfirm=void 0;this.tui.requestRender();return}if(this.matches("crtr.graph.dismiss",t)){this.close();return}const s=this.snapshot,i=s?.rows??[];let e=i.findIndex(r=>r.id===this.cursorId);e<0&&(e=Math.max(0,i.findIndex(r=>r.id===this.self)));const n=i[e],o=m(r=>r!==void 0&&!r.cycle,"isSelectable"),f=m((r,h)=>{for(let d=r+h;d>=0&&d<i.length;d+=h)if(o(i[d]))return d;return r},"step"),p=m(r=>{const h=r===1?0:i.length-1;for(let d=h;d>=0&&d<i.length;d+=r)if(o(i[d]))return d;return e},"edge");if(this.matches("crtr.graph.down",t)){e=f(e,1),this.cursorId=i[e]?.id??this.cursorId,this.tui.requestRender();return}if(this.matches("crtr.graph.up",t)){e=f(e,-1),this.cursorId=i[e]?.id??this.cursorId,this.tui.requestRender();return}if(this.matches("crtr.graph.first",t)){this.cursorId=i[p(1)]?.id??this.cursorId,this.tui.requestRender();return}if(this.matches("crtr.graph.last",t)){this.cursorId=i[p(-1)]?.id??this.cursorId,this.tui.requestRender();return}if(this.matches("crtr.graph.collapse-or-manager",t)){if(n!==void 0&&n.hasKids&&!n.collapsed)this.userCollapsed.add(n.id),this.userExpanded.delete(n.id),this.repaintFolds();else{const r=s?.managerOf.get(this.cursorId??this.self);r!==void 0&&i.some(h=>h.id===r)&&(this.cursorId=r),this.tui.requestRender()}return}if(this.matches("crtr.graph.expand-or-child",t)){if(n!==void 0&&n.collapsed&&n.hasKids)this.userExpanded.add(n.id),this.userCollapsed.delete(n.id),this.repaintFolds();else if(n!==void 0&&n.hasKids){const r=s?.sortedChildIds.get(n.id)?.[0];r!==void 0&&(this.cursorId=r),this.tui.requestRender()}return}if(this.matches("crtr.graph.focus",t)){if(this.remote)return;if(this.role!=="controller"){this.onNotice("Read-only observer attach \u2014 cannot focus nodes");return}this.cursorId!==void 0&&this.focusTarget(this.cursorId),this.close();return}if(this.matches("crtr.graph.revive",t)){if(this.remote)return;if(this.role!=="controller"){this.onNotice("Read-only observer attach \u2014 cannot revive nodes");return}const r=this.cursorId,h=r===void 0?null:s?.nodes.get(r)??null;r!==void 0&&h!==null&&h.status!=="active"&&h.status!=="idle"&&(this.reviveTarget(r),this.close());return}if(this.matches("crtr.graph.focus-manager",t)){if(this.remote)return;if(this.role!=="controller"){this.onNotice("Read-only observer attach \u2014 cannot focus nodes");return}const r=s?.managerOf.get(this.self);r!==void 0&&(this.focusTarget(r),this.close());return}if(this.matches("crtr.graph.close-subtree",t)){if(this.remote)return;if(this.role!=="controller"){this.onNotice("Read-only observer attach \u2014 cannot close nodes");return}const r=this.cursorId??this.self,h=s?.nodes.get(r)??null,d=h!==null?B(h):E(r);this.pendingConfirm={label:`kill ${d}?`,action:m(()=>this.shellCrtr(["node","lifecycle","close","--node",r]),"action")},this.tui.requestRender();return}}focusTarget(t){const s=["surface","node","focus",t],i=process.env.TMUX_PANE;i!==void 0&&i!==""&&s.push("--pane",i),this.shellCrtr(s)}reviveTarget(t){this.shellCrtr(["node","lifecycle","revive",t],()=>this.focusTarget(t))}shellCrtr(t,s){try{q("crtr",t,e=>{e==null&&s?.()}).stdin?.end()}catch{}}}export{be as GraphOverlay};
1
+ var O=Object.defineProperty;var m=(u,t)=>O(u,"name",{value:t,configurable:!0});import{execFile as q}from"node:child_process";import{matchesKey as P,truncateToWidth as T}from"@earendil-works/pi-tui";import{formatBinding as H,matchesPiTuiInput as L}from"../../../core/keybindings/index.js";import{fullName as B}from"../../../core/canvas/labels.js";import{faultSummary as G,resolveNodeVisual as C}from"../../../core/canvas/status-glyph.js";import{RemoteCanvasSource as W}from"../../../core/canvas/remote-canvas-source.js";import{cliClient as F}from"../../../commands/api-client.js";import{statusRank as M}from"../../../core/canvas/node-order.js";import{navLabel as K,nodeGlyph as j,tokensCell as D,cycleBadge as V,askBadge as Y,activityCell as z,shortId as E,visibleWidth as k,fillBar as A,fillWidth as N,truncate as U,isAttached as X,VIEWPORT_FALLBACK_ROWS as J,ESC as Q,DIM as R,RESET as g,BOLD as S,YELLOW as Z,REVERSE as ee,BG_ATTACHED as te,GREEN as se}from"../../../core/canvas/nav-render.js";const ie=.72,ne={anchor:"center",width:"72%",minWidth:48,maxHeight:"72%",margin:1},re=[["crtr.graph.dismiss","dismiss"],["crtr.graph.focus","focus"],["crtr.graph.revive","revive"],["crtr.graph.close-subtree","close"],["crtr.graph.focus-manager","manager"]],oe=[["crtr.graph.dismiss","dismiss"]],ce=[["crtr.graph.down","down"],["crtr.graph.up","up"],["crtr.graph.first","first"],["crtr.graph.last","last"],["crtr.graph.collapse-or-manager","fold/manager"],["crtr.graph.expand-or-child","expand/child"]],ae=[...["active","idle","done","dead","canceled"].map(u=>[C(u,{}),u]),[C("active",{streaming:!0}),"live"],[C("active",{frozen:!0}),"frozen"],[C("active",{hanging:{kind:"wedged"}}),"fault"]].map(([u,t])=>`${Q}${u.color}m${u.glyph}${g} ${R}${t}${g}`).join(" ");function he(u){return{node_id:u.node_id,name:u.name,kind:u.kind,description:u.description??void 0,cycles:u.cycles??void 0,status:u.status,frozen_at:u.frozen_at,pi_pid:u.pi_pid,telemetry_context_tokens:u.telemetry_context_tokens,telemetry_last_activity:u.telemetry_last_activity,fault:u.fault??null,streaming:u.streaming}}m(he,"graphRow");class be{static{m(this,"GraphOverlay")}tui;self;getAsks;palette;bindings;source;role;onRefreshFailure;onNotice;handle;userExpanded=new Set;userCollapsed=new Set;folds={userExpanded:this.userExpanded,userCollapsed:this.userCollapsed};cursorId;scrollTop=0;pendingConfirm;snapshot;snapshotSeq=0;remote;constructor(t,s,i,e,n,o,f="controller",p=()=>{},r=()=>{}){this.tui=t,this.self=s,this.getAsks=i,this.palette=e,this.bindings=n,this.source=o,this.role=f,this.onRefreshFailure=p,this.onNotice=r,this.remote=o instanceof W}setBindings(t){this.bindings=t,this.handle!==void 0&&this.tui.requestRender()}matches(t,s){return L(this.bindings,t,s,(i,e)=>P(i,e))}hint(t){return t.flatMap(([s,i])=>this.bindings.gestures(s).length===0?[]:[`${H(this.bindings,s)} ${i}`])}fitHints(t,s){const e=[];let n=0;for(const o of this.hint(t)){const f=(e.length===0?0:3)+k(o);if(n+f>s)break;e.push(o),n+=f}return e.join(" \xB7 ")}isOpen(){return this.handle!==void 0}open(){this.handle===void 0&&(this.scrollTop=0,this.pendingConfirm=void 0,this.cursorId=this.self,this.handle=this.tui.showOverlay(this,ne),this.refresh())}close(){this.handle!==void 0&&(this.pendingConfirm=void 0,this.handle.hide(),this.handle=void 0,this.tui.requestRender())}toggle(){this.handle===void 0?this.open():this.close()}refresh(){if(this.handle===void 0)return;const t=++this.snapshotSeq;this.buildSnapshot().then(s=>{t===this.snapshotSeq&&(this.snapshot=s,this.tui.requestRender())}).catch(s=>{this.onRefreshFailure(s),this.tui.requestRender()})}invalidate(){this.refresh()}async fetchInput(){if(this.remote){const e=await this.source.listNodes().catch(()=>[]);return{nodes:new Map(e.map(n=>[n.node_id,n])),subscriptions:m(async n=>(await this.source.subscriptionsOf(n)).map(o=>o.node_id),"subscriptions"),subscribers:m(async n=>(await this.source.subscribersOf(n)).map(o=>o.node_id),"subscribers"),focused:new Set}}const t=await F().canvasGraph(),s=new Map,i=new Map;for(const e of t.edges){const n=s.get(e.from_id);n===void 0?s.set(e.from_id,[e.to_id]):n.push(e.to_id);const o=i.get(e.to_id);o===void 0?i.set(e.to_id,[e.from_id]):o.push(e.from_id)}return{nodes:new Map(t.nodes.map(e=>[e.node_id,he(e)])),subscriptions:m(e=>Promise.resolve(s.get(e)??[]),"subscriptions"),subscribers:m(e=>Promise.resolve(i.get(e)??[]),"subscribers"),focused:new Set(t.focused_node_ids)}}async buildSnapshot(){const t=await this.fetchInput(),{nodes:s,focused:i}=t,e=new Map,n=new Map,o=new Map,f=new Map,p=m(async c=>{const l=e.get(c);if(l!==void 0)return l;let a;try{a=await t.subscriptions(c)}catch{a=[]}const $=a.filter(b=>s.get(b)?.kind!=="human");return e.set(c,$),$},"children"),r=m(async c=>{if(o.has(c))return o.get(c);let l;try{l=(await t.subscribers(c))[0]}catch{l=void 0}return o.set(c,l),l},"manager"),h=m(async()=>{let c=this.self;const l=new Set([c]);for(;;){const a=await r(c);if(a===void 0||l.has(a))break;l.add(a),c=a}return c},"climbRoot"),d=m(async c=>{const l=n.get(c);if(l!==void 0)return l;const a=[...await p(c)];return a.sort(($,b)=>M(s.get($)?.status)-M(s.get(b)?.status)),n.set(c,a),a},"sortedChildren"),w=new Set,v=new Set,I=m(async c=>{const l=s.get(c)?.status==="active";if(v.has(c))return{active:l?1:0,reveal:l||c===this.self};v.add(c);let a=0,$=!1;for(const b of await p(c)){const x=await I(b);a+=x.active,x.reveal&&($=!0)}return f.set(c,a),$&&w.add(c),{active:a+(l?1:0),reveal:$||l||c===this.self}},"visitActivity"),_=await h();await I(_),await Promise.all([...e.keys()].map(c=>d(c)));const y={root:_,rows:[],autoExpanded:w,activeBelow:f,nodes:s,childIds:e,sortedChildIds:n,managerOf:o,focused:i};return y.rows=this.projectRows(y),y}projectRows(t){const s=[],i=new Set,e=[{id:t.root,prefix:"",isRoot:!0,isLast:!0}];for(;e.length>0;){const{id:n,prefix:o,isRoot:f,isLast:p}=e.pop(),r=f?"":p?"\u2514\u2500 ":"\u251C\u2500 ";if(i.has(n)){s.push({id:n,hasKids:!1,isSelf:n===this.self,branch:o+r,cycle:!0,collapsed:!1});continue}i.add(n);const h=t.sortedChildIds.get(n)??[],d=this.folds.userExpanded.has(n)?!1:this.folds.userCollapsed.has(n)?!0:!t.autoExpanded.has(n);if(s.push({id:n,hasKids:h.length>0,isSelf:n===this.self,branch:o+r,cycle:!1,collapsed:d}),d)continue;const w=f?"":o+(p?" ":"\u2502 ");for(let v=h.length-1;v>=0;v--)e.push({id:h[v],prefix:w,isRoot:!1,isLast:v===h.length-1})}return s}repaintFolds(){this.snapshot!==void 0&&(this.snapshot.rows=this.projectRows(this.snapshot)),this.tui.requestRender()}renderSnapshotRow(t,s,i,e){const n=m((b,x)=>i?A(b,N(),ee):x?A(b,N(),te):U(b),"wrap");if(s.cycle){const b=`${s.branch} ${R}\u21BA ${E(s.id)}${g}`;return n(b,!1)}const o=t.nodes.get(s.id)??null,f=j(o),p=K(o,s.id),r=s.isSelf?`${S}${p}${g}`:p,h=`${R}${o?.kind??""}${g}`,d=`${R}${D(o,this.remote)}${g}`,w=s.hasKids&&s.collapsed,v=!i&&w?`${R}\u25B8${g} `:" ",I=V(o),_=t.childIds.get(s.id)?.length??0,y=o!==null&&_>0?` ${R}\u2933${_}${g}`:"",c=o!==null&&o.status!=="active"&&(t.activeBelow.get(o.node_id)??0)>0?` ${se}\u21E3${t.activeBelow.get(o.node_id)??0}${g}`:"",l=o?.fault??null,a=l!==null?` \xB7 ${G(l)}`:"",$=`${s.branch}${v}${f} ${r} ${h} ${d}${I}${y}${c}${Y(s.id,e)}${z(o,this.remote)}${a}`;return n($,X(s.id,o,t.focused,this.remote))}render(t){const s=this.getAsks(),i=this.snapshot?.rows??[];let e=i.findIndex(a=>a.id===this.cursorId);e<0&&(e=i.findIndex(a=>a.id===this.self),e<0&&(e=0)),this.cursorId=i[e]?.id??this.self;const n=process.stdout.rows??J,o=Math.max(3,Math.min(Math.floor(n*ie),n-2)),f=Math.min(o-2,1+Math.max(1,i.length)),p=f-1,r=p>=3;let h=p;for(let a=0;p>0&&a<4;a++){e<this.scrollTop&&(this.scrollTop=e),e>=this.scrollTop+h&&(this.scrollTop=e-h+1),this.scrollTop=Math.max(0,Math.min(this.scrollTop,Math.max(0,i.length-h)));const $=p-(r&&this.scrollTop>0?1:0)-(r&&this.scrollTop+h<i.length?1:0);if($===h)break;h=Math.max(1,$)}const d=Math.min(i.length,this.scrollTop+h),w=[];r&&this.scrollTop>0&&w.push(`${R} \u2191 ${this.scrollTop} more${g}`);for(let a=this.scrollTop;a<d;a++){const $=this.snapshot;w.push($!==void 0?this.renderSnapshotRow($,i[a],a===e,s):"")}for(r&&d<i.length&&w.push(`${R} \u2193 ${i.length-d} more${g}`),w.unshift(ae);w.length<f;)w.push("");const v=i.length>0?`${S}\u2317 canvas graph${g} ${R}(${e+1}/${i.length})${g}`:`${S}\u2317 canvas graph${g} ${R}(loading)${g}`,I=this.pendingConfirm!==void 0?`${Z}${this.pendingConfirm.label} ${S}${this.hint([["crtr.graph.confirm.accept","accept"],["crtr.graph.confirm.cancel","cancel"]]).join(" \xB7 ")}${g}`:`${R}${this.fitHints([...this.remote||this.role!=="controller"?oe:re,...ce],Math.max(1,t-5))}${g}`,_=this.palette.border,y=Math.max(1,t-4),c=w.map(a=>`${_("\u2502")} ${T(a,y,"",!0)} ${_("\u2502")}`),l=this.palette.surface;return[this.borderRow("\u256D","\u256E",v,t),...c,this.borderRow("\u2570","\u256F",I,t)].map(l)}borderRow(t,s,i,e){const n=this.palette.border,o=Math.max(1,e-5),f=T(i,o,"\u2026"),p=Math.max(0,e-5-k(f));return`${n(`${t}\u2500`)} ${f} ${n("\u2500".repeat(p)+s)}`}handleInput(t){try{this.dispatch(t)}catch{}}dispatch(t){if(this.pendingConfirm!==void 0){if(this.matches("crtr.graph.confirm.accept",t)){const r=this.pendingConfirm.action;this.pendingConfirm=void 0,r()}else this.pendingConfirm=void 0;this.tui.requestRender();return}if(this.matches("crtr.graph.dismiss",t)){this.close();return}const s=this.snapshot,i=s?.rows??[];let e=i.findIndex(r=>r.id===this.cursorId);e<0&&(e=Math.max(0,i.findIndex(r=>r.id===this.self)));const n=i[e],o=m(r=>r!==void 0&&!r.cycle,"isSelectable"),f=m((r,h)=>{for(let d=r+h;d>=0&&d<i.length;d+=h)if(o(i[d]))return d;return r},"step"),p=m(r=>{const h=r===1?0:i.length-1;for(let d=h;d>=0&&d<i.length;d+=r)if(o(i[d]))return d;return e},"edge");if(this.matches("crtr.graph.down",t)){e=f(e,1),this.cursorId=i[e]?.id??this.cursorId,this.tui.requestRender();return}if(this.matches("crtr.graph.up",t)){e=f(e,-1),this.cursorId=i[e]?.id??this.cursorId,this.tui.requestRender();return}if(this.matches("crtr.graph.first",t)){this.cursorId=i[p(1)]?.id??this.cursorId,this.tui.requestRender();return}if(this.matches("crtr.graph.last",t)){this.cursorId=i[p(-1)]?.id??this.cursorId,this.tui.requestRender();return}if(this.matches("crtr.graph.collapse-or-manager",t)){if(n!==void 0&&n.hasKids&&!n.collapsed)this.userCollapsed.add(n.id),this.userExpanded.delete(n.id),this.repaintFolds();else{const r=s?.managerOf.get(this.cursorId??this.self);r!==void 0&&i.some(h=>h.id===r)&&(this.cursorId=r),this.tui.requestRender()}return}if(this.matches("crtr.graph.expand-or-child",t)){if(n!==void 0&&n.collapsed&&n.hasKids)this.userExpanded.add(n.id),this.userCollapsed.delete(n.id),this.repaintFolds();else if(n!==void 0&&n.hasKids){const r=s?.sortedChildIds.get(n.id)?.[0];r!==void 0&&(this.cursorId=r),this.tui.requestRender()}return}if(this.matches("crtr.graph.focus",t)){if(this.remote)return;if(this.role!=="controller"){this.onNotice("Read-only observer attach \u2014 cannot focus nodes");return}this.cursorId!==void 0&&this.focusTarget(this.cursorId),this.close();return}if(this.matches("crtr.graph.revive",t)){if(this.remote)return;if(this.role!=="controller"){this.onNotice("Read-only observer attach \u2014 cannot revive nodes");return}const r=this.cursorId,h=r===void 0?null:s?.nodes.get(r)??null;r!==void 0&&h!==null&&h.status!=="active"&&h.status!=="idle"&&(this.reviveTarget(r),this.close());return}if(this.matches("crtr.graph.focus-manager",t)){if(this.remote)return;if(this.role!=="controller"){this.onNotice("Read-only observer attach \u2014 cannot focus nodes");return}const r=s?.managerOf.get(this.self);r!==void 0&&(this.focusTarget(r),this.close());return}if(this.matches("crtr.graph.close-subtree",t)){if(this.remote)return;if(this.role!=="controller"){this.onNotice("Read-only observer attach \u2014 cannot close nodes");return}const r=this.cursorId??this.self,h=s?.nodes.get(r)??null,d=h!==null?B(h):E(r);this.pendingConfirm={label:`kill ${d}?`,action:m(()=>this.shellCrtr(["node","lifecycle","close","--node",r]),"action")},this.tui.requestRender();return}}focusTarget(t){const s=["surface","node","focus",t],i=process.env.TMUX_PANE;i!==void 0&&i!==""&&s.push("--pane",i),this.shellCrtr(s)}reviveTarget(t){this.shellCrtr(["node","lifecycle","revive",t],()=>this.focusTarget(t))}shellCrtr(t,s){try{q("crtr",t,e=>{e==null&&s?.()}).stdin?.end()}catch{}}}export{be as GraphOverlay};
@@ -1,3 +1,3 @@
1
- var F=Object.defineProperty;var d=(t,e)=>F(t,"name",{value:e,configurable:!0});import{createBashToolDefinition as B,createReadToolDefinition as E,createWriteToolDefinition as S}from"@earendil-works/pi-coding-agent";import{Text as D,getCapabilities as H,hyperlink as M,truncateToWidth as m,visibleWidth as g,wrapTextWithAnsi as I}from"@earendil-works/pi-tui";import{homedir as j}from"node:os";import{isAbsolute as N,resolve as P}from"node:path";import{pathToFileURL as z}from"node:url";import{normalizeBashJobPurpose as U}from"../../../core/bash-jobs.js";import{TOOL_ICON as C}from"../../../core/preview-registry.js";function x(t){return typeof t=="string"?t:""}d(x,"str");const G=5e3;function J(t,e,n,i){if(e===void 0||Date.now()-e<G)return[];const s=n?.()??null;return s===null?[]:[m(` ${t.fg("muted",`\u29D7 ${s}`)}`,i,"\u2026")]}d(J,"backgroundHintLines");class b{static{d(this,"FoldedToolCallController")}folded=!1;component;setFolded(e){this.folded=e}capture(e){return this.component=e,e}callComponent(){return this.component}}function K(t){return t.length===0?0:(t.match(/\n/g)?.length??0)+(t.endsWith(`
2
- `)?0:1)}d(K,"countFileLines");function X(t,e){if(!t)return"";const n=[];return t.added>0&&n.push(e.fg("toolDiffAdded",`+${t.added}`)),t.removed>0&&n.push(e.fg("toolDiffRemoved",`-${t.removed}`)),n.length>0?` ${n.join(" ")}`:""}d(X,"lineChangesDisplay");function k(t,e){return t===void 0?"":` ${e.fg("toolDiffAdded",`+${t}`)}`}d(k,"lineCountDisplay");function q(t,e,n,i,s){return`${O(C[t],t,n)} ${A(e,n,i)}${X(s,n)}`}d(q,"foldedFileCallLine");function Q(t){const e=j();return t.startsWith(e)?`~${t.slice(e.length)}`:t}d(Q,"shortenPath");function A(t,e,n){if(!t)return e.fg("toolOutput","...");const i=Q(t);if(!H().hyperlinks)return i;const s=N(t)?t:P(n,t);return M(i,z(s).href)}d(A,"pathDisplay");function O(t,e,n){return`${n.fg("accent",t)} ${n.fg("toolTitle",n.bold(e))}`}d(O,"header");class V{static{d(this,"IconPrefixedToolCall")}child;prefix;constructor(e,n){this.child=e,this.prefix=n}update(e,n){this.child=e,this.prefix=n}invalidate(){this.child.invalidate()}render(e){const n=g(this.prefix),i=this.child.render(Math.max(1,e-n));return i.length===0?[m(this.prefix.trimEnd(),e,"")]:i.map((s,r)=>r===0?m(`${this.prefix}${s}`,e,""):s)}}function le(t,e=new b){const n=E(t);return{name:"read",label:"read",description:"Render read calls with a crtr icon header in the attach viewer.",parameters:{},renderCall(i,s,r){const o=i,a=x(o?.file_path??o?.path);let l="";if(o?.offset!==void 0||o?.limit!==void 0){const h=typeof o?.offset=="number"?o.offset:1,c=typeof o?.limit=="number"?h+o.limit-1:void 0;l=s.fg("warning",`:${h}${c!==void 0?`-${c}`:""}`)}const u=`${O(C.read,"read",s)} ${A(a,s,r.cwd??t)}${l}`,f=r.lastComponent??new D("",0,0);return f.setText(u),e.capture(f)},renderResult(i,s,r,o){return n.renderResult(i,s,r,o)}}}d(le,"createCrtrReadToolDefinition");function ue(t,e=new b){const n=S(t);let i,s;return{name:"write",label:"write",description:"Render write calls with a crtr icon header in the attach viewer.",parameters:{},renderCall(r,o,a){if(e.folded){const u=r,f=a.isError?void 0:K(x(u?.content)),h=q("write",x(u?.file_path??u?.path),o,a.cwd??t)+k(f,o);return e.capture(new D(h,0,0))}i=n.renderCall(r,o,{...a,lastComponent:i});const l=`${o.fg("accent",C.write)} `;return s?s.update(i,l):s=new V(i,l),e.capture(s)},renderResult(r,o,a,l){return n.renderResult(r,o,a,l)}}}d(ue,"createCrtrWriteToolDefinition");const Y=/^(&&|\|\||\||;|>>|>|<|2>&1|&)$/,v=/^cd\s+(?:"[^"]*"|'[^']*'|\S+)\s*(?:&&|;)\s*/;function Z(t){let e=t;for(;v.test(e);)e=e.replace(v,"");return e}d(Z,"stripCdPrefix");function ee(t){return t.match(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|\S+/g)??[]}d(ee,"tokenize");function W(t,e){const n=ee(t);let i=!0;return n.map(r=>Y.test(r)?(i=!0,e.fg("syntaxOperator",r)):i&&!r.includes("=")?(i=!1,e.fg("syntaxFunction",e.bold(r))):(i=!1,r.startsWith("-")?e.fg("muted",r):/^["']/.test(r)?e.fg("syntaxString",r):e.fg("toolOutput",r))).join(" ")}d(W,"styleCommandLine");class R{static{d(this,"BashCallComponent")}command="";purpose;expanded=!1;folded=!1;timeout;theme;startedAt;hint;invalidate(){}update(e,n,i,s,r,o,a,l){this.theme=e,this.command=n,this.purpose=i,this.expanded=s,this.folded=r,this.timeout=o,this.startedAt=a,this.hint=l}backgroundHintLines(e){const n=this.theme;return n===void 0?[]:J(n,this.startedAt,this.hint,e)}render(e){const n=this.theme;if(!n)return[];const i=n.fg("accent",C.bash);if(this.purpose!==void 0)return[m(`${i} ${n.fg("toolOutput",this.purpose)}`,e,"\u2026")];const s=this.command.split(`
3
- `).map(c=>c.trim()).filter(c=>c.length>0),r=this.folded?s.map(Z):s,o=this.timeout?n.fg("muted",` (timeout ${this.timeout}s)`):"";if(r.length===0)return[`${i} ${n.fg("toolOutput","...")}`];if(this.expanded){const c=g(`${i} `),_=" ".repeat(c),L=Math.max(1,e-c),y=[];for(let p=0;p<r.length;p++){let T=W(r[p],n);p===r.length-1&&(T+=o);const w=I(T,L);for(let $=0;$<w.length;$++)y.push(`${p===0&&$===0?`${i} `:_}${w[$]}`)}return y.map(p=>m(p,e,""))}const a=r.length>1?n.fg("muted",` +${r.length-1} lines`):"",l=g(`${i} `)+g(a)+g(o),u=Math.max(8,e-l),f=r[0],h=f.length>u?`${f.slice(0,Math.max(1,u-1))}\u2026`:f;return[m(`${i} ${W(h,n)}${a}${o}`,e)]}}function fe(t,e){return t instanceof R?t.backgroundHintLines(e):[]}d(fe,"bashCallBackgroundHintLines");function ce(t,e=new b,n){const i=B(t);return{name:"bash",label:"bash",description:"Render plain bash calls as a compact styled command line in the attach viewer.",parameters:{},renderCall(s,r,o){const a=s,l=o.state;l&&o.executionStarted&&l.startedAt===void 0&&(l.startedAt=Date.now(),l.endedAt=void 0);const u=o.lastComponent instanceof R?o.lastComponent:new R,f=l?.startedAt!==void 0&&l.endedAt===void 0;return u.update(r,x(a?.command),e.folded?U(a?.purpose)??void 0:void 0,!!o.expanded&&!e.folded,e.folded,typeof a?.timeout=="number"?a.timeout:void 0,f?l?.startedAt:void 0,n),e.capture(u)},renderResult(s,r,o,a){return i.renderResult(s,r,o,a)}}}d(ce,"createCrtrPlainBashToolDefinition");export{b as FoldedToolCallController,fe as bashCallBackgroundHintLines,ce as createCrtrPlainBashToolDefinition,le as createCrtrReadToolDefinition,ue as createCrtrWriteToolDefinition,q as foldedFileCallLine};
1
+ var _=Object.defineProperty;var l=(t,e)=>_(t,"name",{value:e,configurable:!0});import{createBashToolDefinition as B,createReadToolDefinition as F,createWriteToolDefinition as S}from"@earendil-works/pi-coding-agent";import{Text as A,getCapabilities as E,hyperlink as H,truncateToWidth as m,visibleWidth as g,wrapTextWithAnsi as M}from"@earendil-works/pi-tui";import{homedir as j}from"node:os";import{isAbsolute as I,resolve as N}from"node:path";import{pathToFileURL as z}from"node:url";import{normalizeBashJobPurpose as P}from"../../../core/bash-jobs.js";import{TOOL_ICON as x}from"../../../core/preview-registry.js";import{stripCdPrefix as U}from"../../../shared/strip-cd-prefix.js";function C(t){return typeof t=="string"?t:""}l(C,"str");const G=5e3;function J(t,e,n,i){if(e===void 0||Date.now()-e<G)return[];const s=n?.()??null;return s===null?[]:[m(` ${t.fg("muted",`\u29D7 ${s}`)}`,i,"\u2026")]}l(J,"backgroundHintLines");class b{static{l(this,"FoldedToolCallController")}folded=!1;component;setFolded(e){this.folded=e}capture(e){return this.component=e,e}callComponent(){return this.component}}function K(t){return t.length===0?0:(t.match(/\n/g)?.length??0)+(t.endsWith(`
2
+ `)?0:1)}l(K,"countFileLines");function k(t,e){if(!t)return"";const n=[];return t.added>0&&n.push(e.fg("toolDiffAdded",`+${t.added}`)),t.removed>0&&n.push(e.fg("toolDiffRemoved",`-${t.removed}`)),n.length>0?` ${n.join(" ")}`:""}l(k,"lineChangesDisplay");function q(t,e){return t===void 0?"":` ${e.fg("toolDiffAdded",`+${t}`)}`}l(q,"lineCountDisplay");function Q(t,e,n,i,s){return`${O(x[t],t,n)} ${D(e,n,i)}${k(s,n)}`}l(Q,"foldedFileCallLine");function V(t){const e=j();return t.startsWith(e)?`~${t.slice(e.length)}`:t}l(V,"shortenPath");function D(t,e,n){if(!t)return e.fg("toolOutput","...");const i=V(t);if(!E().hyperlinks)return i;const s=I(t)?t:N(n,t);return H(i,z(s).href)}l(D,"pathDisplay");function O(t,e,n){return`${n.fg("accent",t)} ${n.fg("toolTitle",n.bold(e))}`}l(O,"header");class X{static{l(this,"IconPrefixedToolCall")}child;prefix;constructor(e,n){this.child=e,this.prefix=n}update(e,n){this.child=e,this.prefix=n}invalidate(){this.child.invalidate()}render(e){const n=g(this.prefix),i=this.child.render(Math.max(1,e-n));return i.length===0?[m(this.prefix.trimEnd(),e,"")]:i.map((s,r)=>r===0?m(`${this.prefix}${s}`,e,""):s)}}function le(t,e=new b){const n=F(t);return{name:"read",label:"read",description:"Render read calls with a crtr icon header in the attach viewer.",parameters:{},renderCall(i,s,r){const o=i,d=C(o?.file_path??o?.path);let a="";if(o?.offset!==void 0||o?.limit!==void 0){const h=typeof o?.offset=="number"?o.offset:1,c=typeof o?.limit=="number"?h+o.limit-1:void 0;a=s.fg("warning",`:${h}${c!==void 0?`-${c}`:""}`)}const u=`${O(x.read,"read",s)} ${D(d,s,r.cwd??t)}${a}`,f=r.lastComponent??new A("",0,0);return f.setText(u),e.capture(f)},renderResult(i,s,r,o){return n.renderResult(i,s,r,o)}}}l(le,"createCrtrReadToolDefinition");function ue(t,e=new b){const n=S(t);let i,s;return{name:"write",label:"write",description:"Render write calls with a crtr icon header in the attach viewer.",parameters:{},renderCall(r,o,d){if(e.folded){const u=r,f=d.isError?void 0:K(C(u?.content)),h=Q("write",C(u?.file_path??u?.path),o,d.cwd??t)+q(f,o);return e.capture(new A(h,0,0))}i=n.renderCall(r,o,{...d,lastComponent:i});const a=`${o.fg("accent",x.write)} `;return s?s.update(i,a):s=new X(i,a),e.capture(s)},renderResult(r,o,d,a){return n.renderResult(r,o,d,a)}}}l(ue,"createCrtrWriteToolDefinition");const Y=/^(&&|\|\||\||;|>>|>|<|2>&1|&)$/;function Z(t){return t.match(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|\S+/g)??[]}l(Z,"tokenize");function v(t,e){const n=Z(t);let i=!0;return n.map(r=>Y.test(r)?(i=!0,e.fg("syntaxOperator",r)):i&&!r.includes("=")?(i=!1,e.fg("syntaxFunction",e.bold(r))):(i=!1,r.startsWith("-")?e.fg("muted",r):/^["']/.test(r)?e.fg("syntaxString",r):e.fg("toolOutput",r))).join(" ")}l(v,"styleCommandLine");class y{static{l(this,"BashCallComponent")}command="";purpose;expanded=!1;folded=!1;timeout;theme;startedAt;hint;invalidate(){}update(e,n,i,s,r,o,d,a){this.theme=e,this.command=n,this.purpose=i,this.expanded=s,this.folded=r,this.timeout=o,this.startedAt=d,this.hint=a}backgroundHintLines(e){const n=this.theme;return n===void 0?[]:J(n,this.startedAt,this.hint,e)}render(e){const n=this.theme;if(!n)return[];const i=n.fg("accent",x.bash);if(this.purpose!==void 0)return[m(`${i} ${n.fg("toolOutput",this.purpose)}`,e,"\u2026")];const s=this.command.split(`
3
+ `).map(c=>c.trim()).filter(c=>c.length>0),r=this.folded?s.map(U):s,o=this.timeout?n.fg("muted",` (timeout ${this.timeout}s)`):"";if(r.length===0)return[`${i} ${n.fg("toolOutput","...")}`];if(this.expanded){const c=g(`${i} `),W=" ".repeat(c),L=Math.max(1,e-c),R=[];for(let p=0;p<r.length;p++){let T=v(r[p],n);p===r.length-1&&(T+=o);const w=M(T,L);for(let $=0;$<w.length;$++)R.push(`${p===0&&$===0?`${i} `:W}${w[$]}`)}return R.map(p=>m(p,e,""))}const d=r.length>1?n.fg("muted",` +${r.length-1} lines`):"",a=g(`${i} `)+g(d)+g(o),u=Math.max(8,e-a),f=r[0],h=f.length>u?`${f.slice(0,Math.max(1,u-1))}\u2026`:f;return[m(`${i} ${v(h,n)}${d}${o}`,e)]}}function fe(t,e){return t instanceof y?t.backgroundHintLines(e):[]}l(fe,"bashCallBackgroundHintLines");function ce(t,e=new b,n){const i=B(t);return{name:"bash",label:"bash",description:"Render plain bash calls as a compact styled command line in the attach viewer.",parameters:{},renderCall(s,r,o){const d=s,a=o.state;a&&o.executionStarted&&a.startedAt===void 0&&(a.startedAt=Date.now(),a.endedAt=void 0);const u=o.lastComponent instanceof y?o.lastComponent:new y,f=a?.startedAt!==void 0&&a.endedAt===void 0;return u.update(r,C(d?.command),e.folded?P(d?.purpose)??void 0:void 0,!!o.expanded&&!e.folded,e.folded,typeof d?.timeout=="number"?d.timeout:void 0,f?a?.startedAt:void 0,n),e.capture(u)},renderResult(s,r,o,d){return i.renderResult(s,r,o,d)}}}l(ce,"createCrtrPlainBashToolDefinition");export{b as FoldedToolCallController,fe as bashCallBackgroundHintLines,ce as createCrtrPlainBashToolDefinition,le as createCrtrReadToolDefinition,ue as createCrtrWriteToolDefinition,Q as foldedFileCallLine};
@@ -1 +1 @@
1
- var S=Object.defineProperty;var o=(e,r)=>S(e,"name",{value:r,configurable:!0});import{createConnection as T}from"node:net";import{viewSocketPath as y}from"../../../core/canvas/paths.js";import{BrokerClient as A,BrokerUnavailableError as x,RelayTransport as E}from"../../../core/broker-client/index.js";import{resolveRemoteCanvasTarget as _}from"../../../core/remote-canvas-target.js";import{ApiCanvasSource as P,cliCanvasSource as R,cliClient as g,rethrowAsCliError as F}from"../../../commands/api-client.js";import{InputError as d}from"../../../core/io.js";function L(e,r){return e||r?"observer":"controller"}o(L,"resolveHelloRole");async function M(e){const r=Number(process.env.CRTR_ATTACH_WAIT_MS??"");if(!Number.isFinite(r)||r<=0)return;const w=y(e),c=Date.now()+r;for(;Date.now()<c;){if(await new Promise(i=>{const s=T(w),l=o(n=>{s.destroy(),i(n)},"settle");s.once("connect",()=>l(!0)),s.once("error",()=>l(!1))}))return;await new Promise(i=>setTimeout(i,100))}}o(M,"preWaitForViewSocket");async function U(e,r,w=!0){const c=r!==void 0,h=c?R({canvasName:r}):new P;let i,s,l,n,p;if(c)i={cwd:process.cwd()},l=new E(e,_(r));else{const t=await h.getNode(e);if(t===null)throw new d({error:"not_found",message:`no node: ${e}`,received:e,next:"List nodes with `crtr node inspect list`."});i=t,s=t;try{if((await g().ensureAttach(e,{resume:!0,revive:!0,wakeParked:w})).parked){const u=await g().getSnapshot(e);n=u.snapshot,p=u.commands}}catch(m){F(m,"The node may be finalized or otherwise not attachable.")}n===void 0&&await M(e)}const a=new A(e,{transport:l}),v=o(t=>t instanceof x?new d({error:"no_broker",message:t.message,received:e,next:"Focus or revive the node first \u2014 attach needs a running headless broker."}):new d({error:"socket_error",message:`could not attach to node ${e}: ${String(t?.message??t)}`,received:e,next:"Check the node has a running headless broker."}),"toAttachError");let f;return a.on("error",t=>{f===void 0&&(f=t)}),n===void 0&&await new Promise((t,m)=>{const u=o(()=>{C(),t()},"onConnect"),k=o(b=>{C(),m(b)},"onErr"),C=o(()=>{a.off("connect",u),a.off("error",k)},"cleanup");a.on("connect",u),a.on("error",k),a.connect()}).catch(t=>{throw v(t)}),{remote:c,canvasSource:h,meta:i,nodeIdentity:s,socket:a,...n===void 0?{}:{initialSnapshot:n,initialCommands:p},assertConnected:o(()=>{if(n===void 0&&f!==void 0)throw v(f)},"assertConnected")}}o(U,"connectToNode");export{U as connectToNode,M as preWaitForViewSocket,L as resolveHelloRole};
1
+ var T=Object.defineProperty;var o=(e,r)=>T(e,"name",{value:r,configurable:!0});import{createConnection as y}from"node:net";import{apiSocketPath as A,viewSocketPath as P}from"../../../core/canvas/paths.js";import{BrokerClient as x,BrokerUnavailableError as E,RelayTransport as g}from"../../../core/broker-client/index.js";import{resolveRemoteCanvasTarget as _}from"../../../core/remote-canvas-target.js";import{ApiCanvasSource as R,cliCanvasSource as F,cliClient as S,rethrowAsCliError as M}from"../../../commands/api-client.js";import{InputError as p}from"../../../core/io.js";function U(e,r){return e||r?"observer":"controller"}o(U,"resolveHelloRole");async function $(e){const r=Number(process.env.CRTR_ATTACH_WAIT_MS??"");if(!Number.isFinite(r)||r<=0)return;const w=P(e),l=Date.now()+r;for(;Date.now()<l;){if(await new Promise(a=>{const s=y(w),c=o(n=>{s.destroy(),a(n)},"settle");s.once("connect",()=>c(!0)),s.once("error",()=>c(!1))}))return;await new Promise(a=>setTimeout(a,100))}}o($,"preWaitForViewSocket");async function V(e,r,w=!0){const l=r!==void 0,h=l?F({canvasName:r}):new R;let a,s,c,n,d;if(l)a={cwd:process.cwd()},c=new g(e,_(r));else{const t=await h.getNode(e);if(t===null)throw new p({error:"not_found",message:`no node: ${e}`,received:e,next:"List nodes with `crtr node inspect list`."});a=t,s=t;try{if((await S().ensureAttach(e,{resume:!0,revive:!0,wakeParked:w})).parked){const u=await S().getSnapshot(e);n=u.snapshot,d=u.commands}}catch(m){M(m,"The node may be finalized or otherwise not attachable.")}n===void 0&&await $(e),c=new g(e,{socketPath:A()})}const i=new x(e,{transport:c}),k=o(t=>t instanceof E?new p({error:"no_broker",message:t.message,received:e,next:"Focus or revive the node first \u2014 attach needs a running headless broker."}):new p({error:"socket_error",message:`could not attach to node ${e}: ${String(t?.message??t)}`,received:e,next:"Check the node has a running headless broker."}),"toAttachError");let f;return i.on("error",t=>{f===void 0&&(f=t)}),n===void 0&&await new Promise((t,m)=>{const u=o(()=>{C(),t()},"onConnect"),v=o(b=>{C(),m(b)},"onErr"),C=o(()=>{i.off("connect",u),i.off("error",v)},"cleanup");i.on("connect",u),i.on("error",v),i.connect()}).catch(t=>{throw k(t)}),{remote:l,canvasSource:h,meta:a,nodeIdentity:s,socket:i,...n===void 0?{}:{initialSnapshot:n,initialCommands:d},assertConnected:o(()=>{if(n===void 0&&f!==void 0)throw k(f)},"assertConnected")}}o(V,"connectToNode");export{V as connectToNode,$ as preWaitForViewSocket,U as resolveHelloRole};
@@ -1 +1 @@
1
- var j=Object.defineProperty;var l=(e,t)=>j(e,"name",{value:t,configurable:!0});import{constants as k,accessSync as P,existsSync as E,mkdtempSync as z,readFileSync as F,rmSync as p,statSync as C}from"node:fs";import{tmpdir as I}from"node:os";import{delimiter as M,dirname as T,join as a,resolve as g,sep as v}from"node:path";import{execFile as S,spawnSync as q}from"node:child_process";import{loadProfileManifest as O,profileMemoryDir as A}from"../../../core/profiles/manifest.js";import{contextDir as H,reportsDir as L}from"../../../core/canvas/paths.js";import{shellQuote as c}from"../../../core/runtime/placement-tmux.js";import{surfaceTmuxStyleArgs as b}from"../../../core/runtime/surface-bg.js";function R(e,t){const r=new Map(e.map(o=>[o.node_id,o])),n=new Set([t]);for(let o=r.get(t);o?.parent!==null&&o?.parent!==void 0;){const f=o.parent;if(n.has(f))break;n.add(f),o=r.get(f)}const s=[t];for(;s.length>0;){const o=s.pop();for(const f of e)f.parent!==o||n.has(f.node_id)||(n.add(f.node_id),s.push(f.node_id))}return e.filter(o=>n.has(o.node_id)).map(o=>o.node_id)}l(R,"relatedNodeIds");function se(e,t){const r=new Set(R(e,t));return e.filter(n=>r.has(n.node_id)).map(n=>n.cwd)}l(se,"relatedNodeDirs");function W(e){const t=[];for(const r of e)try{t.push(H(r),L(r))}catch{continue}return m(t)}l(W,"familyDocumentDirs");function w(e){try{return C(e).isDirectory()}catch{return!1}}l(w,"isDirectory");function B(e,t){const r=[...t==null?[]:[t],...(process.env.PATH??"").split(M).filter(Boolean).map(n=>a(n,e))];return[...new Set(r)]}l(B,"executableCandidates");function y(e,t){for(const r of B(e,t)){try{P(r,k.X_OK)}catch{continue}if(q(r,["--version"],{stdio:"ignore"}).status===0)return r}return null}l(y,"workingExecutable");function K(e){if(e===null||e==="")return{projects:[],memory:null};try{const{profileId:t,manifest:r}=O(e);return{projects:r.projects.map(n=>n.path),memory:A(t)}}catch{return{projects:[],memory:null}}}l(K,"profileSearchRoots");function m(e){const t=new Set,r=[];for(const n of e){const s=g(n);t.has(s)||!w(s)||(t.add(s),r.push(s))}return r}l(m,"dedupeExistingDirs");function Q(e){return e.filter(t=>!e.some(r=>r!==t&&t.startsWith(r+v)))}l(Q,"outermostDirs");function X(e){const t=[];for(const r of e){let n=g(r);for(;;){const s=a(n,".crouter","memory");w(s)&&t.push(s);const o=T(n);if(o===n)break;n=o}}return m(t)}l(X,"ancestorMemoryDirs");const G=20;function J(e){try{const t=F(e);if(t.length===0)return null;const r=t[t.length-1]===0?t.length-1:t.length;return t.subarray(0,r).toString("utf8")||null}catch{return null}}l(J,"selectionPath");function le(e){const t=y("fd",e.fdPath);if(t===null){e.onNotice("fd is required for profile file search");return}const r=y("fzf");if(r===null){e.onNotice("fzf is required for profile file search");return}const n=y("nvim");if(n===null){e.onNotice("Neovim is required for profile file search");return}const s=K(e.profileId),o=m([e.cwd,...e.nodeDirs,...s.projects]);if(o.length===0){e.onNotice("No profile file-search directories exist");return}const f=Q(o),D=m([...s.memory===null?[]:[s.memory],...X(o)]),u=z(a(I(),"crtr-profile-files-")),x=a(u,"selection"),$=a(u,"candidates"),N=W(e.nodeIds).filter(i=>!f.some(d=>i===d||i.startsWith(d+v))),_=`{ ${[...f.map(i=>`${c(t)} --type f --hidden --exclude .git --exclude ${c("**/.crouter/memory/**")} . ${c(i)}`),...N.map(i=>`${c(t)} --type f --hidden --exclude .git --exclude ${c("/jobs")} . ${c(i)}`),...D.map(i=>`${c(t)} --type f --hidden --exclude .git --no-ignore . ${c(i)}`)].map(i=>`${i} &`).join(" ")} wait; } > ${c($)} && ${c(r)} --print0 --scheme=path --hscroll-off=${G} --header ${c("fuzzy path \u2022 ctrl-y yank file path")} --bind ${c("ctrl-y:execute-silent(printf '%s' {} | { if command -v pbcopy >/dev/null 2>&1; then pbcopy; elif command -v wl-copy >/dev/null 2>&1; then wl-copy; elif command -v xclip >/dev/null 2>&1; then xclip -selection clipboard; else cat >/dev/null; fi; }; printf '%s' {} | tmux load-buffer -w -)+abort")} --preview ${c("head -100 -- {}")} < ${c($)} > ${c(x)}`;try{S("tmux",["display-popup","-E","-T"," profile files ","-w","80%","-h","60%",...b(),_],()=>{const i=J(x);if(i===null||!E(i)){p(u,{recursive:!0,force:!0});return}const d=`exec ${c(n)} -- ${c(i)}`;try{S("tmux",["display-popup","-E","-T"," profile file ","-w","90%","-h","90%",...b(),d],()=>p(u,{recursive:!0,force:!0}))}catch(h){p(u,{recursive:!0,force:!0}),e.onNotice(`Could not open profile file: ${h instanceof Error?h.message:String(h)}`)}})}catch(i){p(u,{recursive:!0,force:!0}),e.onNotice(`Could not open profile file search: ${i instanceof Error?i.message:String(i)}`)}}l(le,"launchProfileFileSearch");export{le as launchProfileFileSearch,se as relatedNodeDirs,R as relatedNodeIds};
1
+ var j=Object.defineProperty;var l=(e,t)=>j(e,"name",{value:t,configurable:!0});import{constants as k,accessSync as P,existsSync as E,mkdtempSync as z,readFileSync as F,rmSync as p,statSync as C}from"node:fs";import{tmpdir as I}from"node:os";import{delimiter as M,dirname as T,join as a,resolve as g,sep as v}from"node:path";import{execFile as S,spawnSync as q}from"node:child_process";import{loadProfileManifest as O,profileMemoryDir as A}from"../../../core/profiles/manifest.js";import{contextDir as H,reportsDir as L}from"../../../core/canvas/node-agent-paths.js";import{shellQuote as c}from"../../../core/runtime/placement-tmux.js";import{surfaceTmuxStyleArgs as b}from"../../../core/runtime/surface-bg.js";function R(e,t){const r=new Map(e.map(o=>[o.node_id,o])),n=new Set([t]);for(let o=r.get(t);o?.parent!==null&&o?.parent!==void 0;){const f=o.parent;if(n.has(f))break;n.add(f),o=r.get(f)}const s=[t];for(;s.length>0;){const o=s.pop();for(const f of e)f.parent!==o||n.has(f.node_id)||(n.add(f.node_id),s.push(f.node_id))}return e.filter(o=>n.has(o.node_id)).map(o=>o.node_id)}l(R,"relatedNodeIds");function se(e,t){const r=new Set(R(e,t));return e.filter(n=>r.has(n.node_id)).map(n=>n.cwd)}l(se,"relatedNodeDirs");function W(e){const t=[];for(const r of e)try{t.push(H(r),L(r))}catch{continue}return m(t)}l(W,"familyDocumentDirs");function w(e){try{return C(e).isDirectory()}catch{return!1}}l(w,"isDirectory");function B(e,t){const r=[...t==null?[]:[t],...(process.env.PATH??"").split(M).filter(Boolean).map(n=>a(n,e))];return[...new Set(r)]}l(B,"executableCandidates");function y(e,t){for(const r of B(e,t)){try{P(r,k.X_OK)}catch{continue}if(q(r,["--version"],{stdio:"ignore"}).status===0)return r}return null}l(y,"workingExecutable");function K(e){if(e===null||e==="")return{projects:[],memory:null};try{const{profileId:t,manifest:r}=O(e);return{projects:r.projects.map(n=>n.path),memory:A(t)}}catch{return{projects:[],memory:null}}}l(K,"profileSearchRoots");function m(e){const t=new Set,r=[];for(const n of e){const s=g(n);t.has(s)||!w(s)||(t.add(s),r.push(s))}return r}l(m,"dedupeExistingDirs");function Q(e){return e.filter(t=>!e.some(r=>r!==t&&t.startsWith(r+v)))}l(Q,"outermostDirs");function X(e){const t=[];for(const r of e){let n=g(r);for(;;){const s=a(n,".crouter","memory");w(s)&&t.push(s);const o=T(n);if(o===n)break;n=o}}return m(t)}l(X,"ancestorMemoryDirs");const G=20;function J(e){try{const t=F(e);if(t.length===0)return null;const r=t[t.length-1]===0?t.length-1:t.length;return t.subarray(0,r).toString("utf8")||null}catch{return null}}l(J,"selectionPath");function le(e){const t=y("fd",e.fdPath);if(t===null){e.onNotice("fd is required for profile file search");return}const r=y("fzf");if(r===null){e.onNotice("fzf is required for profile file search");return}const n=y("nvim");if(n===null){e.onNotice("Neovim is required for profile file search");return}const s=K(e.profileId),o=m([e.cwd,...e.nodeDirs,...s.projects]);if(o.length===0){e.onNotice("No profile file-search directories exist");return}const f=Q(o),D=m([...s.memory===null?[]:[s.memory],...X(o)]),u=z(a(I(),"crtr-profile-files-")),x=a(u,"selection"),$=a(u,"candidates"),N=W(e.nodeIds).filter(i=>!f.some(d=>i===d||i.startsWith(d+v))),_=`{ ${[...f.map(i=>`${c(t)} --type f --hidden --exclude .git --exclude ${c("**/.crouter/memory/**")} . ${c(i)}`),...N.map(i=>`${c(t)} --type f --hidden --exclude .git --exclude ${c("/jobs")} . ${c(i)}`),...D.map(i=>`${c(t)} --type f --hidden --exclude .git --no-ignore . ${c(i)}`)].map(i=>`${i} &`).join(" ")} wait; } > ${c($)} && ${c(r)} --print0 --scheme=path --hscroll-off=${G} --header ${c("fuzzy path \u2022 ctrl-y yank file path")} --bind ${c("ctrl-y:execute-silent(printf '%s' {} | { if command -v pbcopy >/dev/null 2>&1; then pbcopy; elif command -v wl-copy >/dev/null 2>&1; then wl-copy; elif command -v xclip >/dev/null 2>&1; then xclip -selection clipboard; else cat >/dev/null; fi; }; printf '%s' {} | tmux load-buffer -w -)+abort")} --preview ${c("head -100 -- {}")} < ${c($)} > ${c(x)}`;try{S("tmux",["display-popup","-E","-T"," profile files ","-w","80%","-h","60%",...b(),_],()=>{const i=J(x);if(i===null||!E(i)){p(u,{recursive:!0,force:!0});return}const d=`exec ${c(n)} -- ${c(i)}`;try{S("tmux",["display-popup","-E","-T"," profile file ","-w","90%","-h","90%",...b(),d],()=>p(u,{recursive:!0,force:!0}))}catch(h){p(u,{recursive:!0,force:!0}),e.onNotice(`Could not open profile file: ${h instanceof Error?h.message:String(h)}`)}})}catch(i){p(u,{recursive:!0,force:!0}),e.onNotice(`Could not open profile file search: ${i instanceof Error?i.message:String(i)}`)}}l(le,"launchProfileFileSearch");export{le as launchProfileFileSearch,se as relatedNodeDirs,R as relatedNodeIds};