@north-light/crouter 0.3.227 → 0.3.229

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 (312) hide show
  1. package/dist/api/client.d.ts +5 -5
  2. package/dist/api/client.js +3 -3
  3. package/dist/api/dto/broker-ops.d.ts +8 -0
  4. package/dist/api/dto/memory.d.ts +8 -7
  5. package/dist/api/dto/memory.js +2 -2
  6. package/dist/builtin-memory/04-base-worker.md +1 -1
  7. package/dist/builtin-memory/insights/init.md +5 -5
  8. package/dist/builtin-memory/internal/INDEX.md +1 -1
  9. package/dist/builtin-memory/internal/agent-shaping.md +11 -11
  10. package/dist/builtin-memory/internal/examples/INDEX.md +1 -1
  11. package/dist/builtin-memory/internal/memory-loading.md +6 -6
  12. package/dist/builtin-memory/internal/plugins.md +1 -1
  13. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +50 -37
  14. package/dist/clients/attach/__tests__/pane-tag-successor.test.js +56 -0
  15. package/dist/clients/attach/__tests__/profile-files.test.js +21 -0
  16. package/dist/clients/attach/chrome/inbox-strip.js +11 -7
  17. package/dist/clients/attach/session/pane-tag.d.ts +28 -2
  18. package/dist/clients/attach/session/pane-tag.js +48 -22
  19. package/dist/clients/attach/session/profile-files.d.ts +6 -0
  20. package/dist/clients/attach/session/profile-files.js +44 -11
  21. package/dist/clients/attach/slash/dispatch.js +4 -7
  22. package/dist/clients/attach/viewer.js +588 -596
  23. package/dist/commands/__tests__/surface-reload-target.test.js +21 -0
  24. package/dist/commands/api-client.d.ts +3 -7
  25. package/dist/commands/api-client.js +7 -12
  26. package/dist/commands/memory/__tests__/command-selector-and-mutation-guards.test.js +292 -0
  27. package/dist/commands/memory/__tests__/repository-root-lint.test.js +146 -0
  28. package/dist/commands/memory/delete.js +51 -24
  29. package/dist/commands/memory/edit.js +50 -10
  30. package/dist/commands/memory/find.js +105 -56
  31. package/dist/commands/memory/history.js +51 -31
  32. package/dist/commands/memory/lint.d.ts +0 -9
  33. package/dist/commands/memory/lint.js +78 -322
  34. package/dist/commands/memory/list.d.ts +12 -4
  35. package/dist/commands/memory/list.js +64 -25
  36. package/dist/commands/memory/move.js +103 -73
  37. package/dist/commands/memory/origin.js +35 -5
  38. package/dist/commands/memory/read.d.ts +4 -0
  39. package/dist/commands/memory/read.js +132 -80
  40. package/dist/commands/memory/shared.d.ts +115 -25
  41. package/dist/commands/memory/shared.js +331 -74
  42. package/dist/commands/memory/write.js +72 -21
  43. package/dist/commands/memory.js +2 -2
  44. package/dist/commands/node/create.d.ts +1 -1
  45. package/dist/commands/node/create.js +1 -1
  46. package/dist/commands/node/inspect.js +1 -1
  47. package/dist/commands/node/lifecycle.js +5 -5
  48. package/dist/commands/pkg/market-manage.js +25 -24
  49. package/dist/commands/pkg/plugin-manage.d.ts +22 -6
  50. package/dist/commands/pkg/plugin-manage.js +118 -25
  51. package/dist/commands/pkg/shared.d.ts +8 -0
  52. package/dist/commands/pkg/shared.js +23 -20
  53. package/dist/commands/surface-reload.d.ts +5 -0
  54. package/dist/commands/surface-reload.js +9 -1
  55. package/dist/commands/sys/__tests__/migrate.test.js +1140 -22
  56. package/dist/commands/sys/__tests__/sync-project-guidance.test.js +218 -0
  57. package/dist/commands/sys/migrate.js +126 -140
  58. package/dist/commands/sys/panels/profiles-panel.d.ts +66 -0
  59. package/dist/commands/sys/panels/profiles-panel.js +599 -0
  60. package/dist/commands/sys/settings-shell.d.ts +4 -2
  61. package/dist/commands/sys/settings-shell.js +35 -4
  62. package/dist/commands/sys/settings.js +21 -5
  63. package/dist/commands/sys/sync-deps.d.ts +2 -0
  64. package/dist/commands/sys/sync-deps.js +26 -15
  65. package/dist/commands/sys/sync-project-guidance.js +228 -145
  66. package/dist/commands/sys/sync-skills.js +28 -17
  67. package/dist/commands/sys/update.js +11 -3
  68. package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +15 -2
  69. package/dist/core/__tests__/config-change-delta.test.js +106 -0
  70. package/dist/core/__tests__/context-intro.test.js +13 -9
  71. package/dist/core/__tests__/daemon-boot.test.js +22 -16
  72. package/dist/core/__tests__/fixtures/memory-slash-live-probe.js +5 -1
  73. package/dist/core/__tests__/human-deliver.test.js +19 -0
  74. package/dist/core/__tests__/inline-memory-refs.test.js +50 -46
  75. package/dist/core/__tests__/{serial → integration}/broker-fork-seam.test.js +1 -1
  76. package/dist/core/__tests__/{serial → integration}/broker-sdk-wiring.test.js +1 -1
  77. package/dist/core/__tests__/{serial → integration}/broker-snapshot-history.test.js +1 -1
  78. package/dist/core/__tests__/{serial → integration}/command-plugins.test.js +94 -3
  79. package/dist/core/__tests__/{serial → integration}/deferred-no-wake.test.js +1 -1
  80. package/dist/core/__tests__/{serial → integration}/flagship-lifecycle.test.js +13 -27
  81. package/dist/core/__tests__/{serial → integration}/host-teardown-process-group.test.js +1 -1
  82. package/dist/core/__tests__/{serial → integration}/human-deliver-e2e.test.js +1 -1
  83. package/dist/core/__tests__/{live-mutation-verbs.test.js → integration/live-mutation-verbs.test.js} +22 -33
  84. package/dist/core/__tests__/{serial → integration}/live-mutation.test.js +21 -41
  85. package/dist/core/__tests__/integration/refresh-stall-recycle.test.d.ts +1 -0
  86. package/dist/core/__tests__/{serial → integration}/refresh-stall-recycle.test.js +1 -1
  87. package/dist/core/__tests__/integration/revive.test.d.ts +1 -0
  88. package/dist/core/__tests__/{serial → integration}/revive.test.js +38 -19
  89. package/dist/core/__tests__/integration/spawn-root.test.d.ts +1 -0
  90. package/dist/core/__tests__/{serial → integration}/spawn-root.test.js +104 -1
  91. package/dist/core/__tests__/integration/subscription-delivery.test.d.ts +1 -0
  92. package/dist/core/__tests__/{serial → integration}/subscription-delivery.test.js +1 -1
  93. package/dist/core/__tests__/integration/tmux-surface.test.d.ts +1 -0
  94. package/dist/core/__tests__/{serial → integration}/tmux-surface.test.js +1 -1
  95. package/dist/core/__tests__/integration/worktree-land.test.d.ts +1 -0
  96. package/dist/core/__tests__/integration/worktree-land.test.js +400 -0
  97. package/dist/core/__tests__/integration/worktree-reap.test.d.ts +1 -0
  98. package/dist/core/__tests__/{serial/worktree.test.js → integration/worktree-reap.test.js} +6 -338
  99. package/dist/core/__tests__/kickoff.test.js +16 -5
  100. package/dist/core/__tests__/memory-resolver-precedence.test.js +122 -91
  101. package/dist/core/__tests__/nested-store-discovery.test.js +5 -3
  102. package/dist/core/__tests__/on-read-crouter-home-fence.test.js +2 -1
  103. package/dist/core/__tests__/on-read-dedup-resume.test.js +39 -27
  104. package/dist/core/__tests__/on-read-nested-store.test.js +19 -13
  105. package/dist/core/__tests__/profile-project-memory-delivery.test.js +138 -44
  106. package/dist/core/__tests__/repository-association.test.d.ts +1 -0
  107. package/dist/core/__tests__/repository-association.test.js +153 -0
  108. package/dist/core/__tests__/repository-root-identity.test.d.ts +1 -0
  109. package/dist/core/__tests__/repository-root-identity.test.js +219 -0
  110. package/dist/core/__tests__/review-model-floor.test.js +12 -4
  111. package/dist/core/__tests__/seam/memory-slash-node-relative-inventory.test.js +27 -11
  112. package/dist/core/__tests__/warm-claim-preference-snapshot.test.d.ts +1 -0
  113. package/dist/core/__tests__/warm-claim-preference-snapshot.test.js +40 -0
  114. package/dist/core/canvas/canvas.d.ts +3 -0
  115. package/dist/core/canvas/canvas.js +30 -10
  116. package/dist/core/canvas/db.js +28 -1
  117. package/dist/core/canvas/paths.d.ts +4 -6
  118. package/dist/core/canvas/paths.js +8 -6
  119. package/dist/core/canvas/render-source.js +2 -2
  120. package/dist/core/canvas/types.d.ts +9 -13
  121. package/dist/core/config.d.ts +3 -3
  122. package/dist/core/config.js +3 -3
  123. package/dist/core/exclusive-lock.d.ts +2 -0
  124. package/dist/core/exclusive-lock.js +21 -0
  125. package/dist/core/git.d.ts +0 -1
  126. package/dist/core/git.js +0 -3
  127. package/dist/core/human/__tests__/integration/inbox-core.test.d.ts +1 -0
  128. package/dist/core/human/feedback-companion.js +3 -0
  129. package/dist/core/human/scan.js +8 -1
  130. package/dist/core/keybindings/catalog.d.ts +2 -2
  131. package/dist/core/keybindings/catalog.js +2 -1
  132. package/dist/core/memory/doc-link-grammar.js +2 -2
  133. package/dist/core/memory/history.d.ts +24 -0
  134. package/dist/core/memory/history.js +66 -1
  135. package/dist/core/memory/identity.d.ts +65 -0
  136. package/dist/core/memory/identity.js +185 -0
  137. package/dist/core/memory/inline-ref-guidance.d.ts +1 -1
  138. package/dist/core/memory/inline-ref-guidance.js +1 -1
  139. package/dist/core/memory/inline-ref-inventory.d.ts +3 -10
  140. package/dist/core/memory/inline-ref-inventory.js +30 -62
  141. package/dist/core/memory/lint.d.ts +129 -0
  142. package/dist/core/memory/lint.js +517 -0
  143. package/dist/core/memory/project-namespace.d.ts +31 -0
  144. package/dist/core/memory/project-namespace.js +85 -0
  145. package/dist/core/memory/repository-association.d.ts +31 -0
  146. package/dist/core/memory/repository-association.js +129 -0
  147. package/dist/core/memory/tree.d.ts +39 -0
  148. package/dist/core/memory/tree.js +93 -0
  149. package/dist/core/memory-resolver.d.ts +193 -90
  150. package/dist/core/memory-resolver.js +461 -375
  151. package/dist/core/nested-stores.js +6 -13
  152. package/dist/core/profiles/select.d.ts +4 -1
  153. package/dist/core/profiles/select.js +108 -48
  154. package/dist/core/review/__tests__/capture-origin.test.js +2 -2
  155. package/dist/core/review/__tests__/stage-identity.test.js +2 -2
  156. package/dist/core/review/companion.js +11 -2
  157. package/dist/core/runtime/bearings.d.ts +2 -2
  158. package/dist/core/runtime/bearings.js +3 -3
  159. package/dist/core/runtime/broker/daemon-ops.d.ts +2 -2
  160. package/dist/core/runtime/broker/rebind.js +5 -0
  161. package/dist/core/runtime/broker-extension-render.d.ts +7 -3
  162. package/dist/core/runtime/broker-extension-render.js +10 -5
  163. package/dist/core/runtime/broker-persona-guidance.d.ts +19 -5
  164. package/dist/core/runtime/broker-persona-guidance.js +122 -27
  165. package/dist/core/runtime/deliver-live.d.ts +16 -4
  166. package/dist/core/runtime/deliver-live.js +29 -15
  167. package/dist/core/runtime/kickoff.d.ts +3 -3
  168. package/dist/core/runtime/kickoff.js +8 -16
  169. package/dist/core/runtime/launch.js +1 -1
  170. package/dist/core/runtime/lifecycle.js +2 -3
  171. package/dist/core/runtime/nodes.d.ts +3 -4
  172. package/dist/core/runtime/nodes.js +3 -4
  173. package/dist/core/runtime/persona.d.ts +8 -12
  174. package/dist/core/runtime/persona.js +24 -96
  175. package/dist/core/runtime/promote.d.ts +2 -2
  176. package/dist/core/runtime/promote.js +8 -21
  177. package/dist/core/runtime/revive.js +20 -17
  178. package/dist/core/runtime/spawn.js +18 -7
  179. package/dist/core/runtime/tmux-bindings.js +2 -3
  180. package/dist/core/runtime/warm-pool.js +3 -4
  181. package/dist/core/scope.js +2 -0
  182. package/dist/core/self-update.d.ts +0 -2
  183. package/dist/core/self-update.js +2 -35
  184. package/dist/core/substrate/__tests__/surface-match-memory-read.test.d.ts +1 -0
  185. package/dist/core/substrate/__tests__/surface-match-memory-read.test.js +28 -0
  186. package/dist/core/substrate/index.d.ts +2 -2
  187. package/dist/core/substrate/index.js +1 -1
  188. package/dist/core/substrate/injected-store.d.ts +43 -27
  189. package/dist/core/substrate/injected-store.js +208 -104
  190. package/dist/core/substrate/listings.d.ts +19 -12
  191. package/dist/core/substrate/listings.js +75 -52
  192. package/dist/core/substrate/on-read-node.d.ts +4 -7
  193. package/dist/core/substrate/on-read-node.js +6 -8
  194. package/dist/core/substrate/on-read.d.ts +22 -25
  195. package/dist/core/substrate/on-read.js +103 -147
  196. package/dist/core/substrate/render-node.d.ts +4 -7
  197. package/dist/core/substrate/render-node.js +5 -7
  198. package/dist/core/substrate/render.d.ts +21 -3
  199. package/dist/core/substrate/render.js +291 -223
  200. package/dist/core/substrate/schema.d.ts +1 -13
  201. package/dist/core/substrate/schema.js +5 -40
  202. package/dist/core/substrate/session-cache.d.ts +14 -4
  203. package/dist/core/substrate/session-cache.js +40 -22
  204. package/dist/core/substrate/surface-match.d.ts +9 -7
  205. package/dist/core/substrate/surface-match.js +26 -25
  206. package/dist/daemon/__tests__/helpers/source-daemon.d.ts +30 -0
  207. package/dist/daemon/__tests__/helpers/source-daemon.js +174 -0
  208. package/dist/daemon/__tests__/integration/migration-startup.test.d.ts +1 -0
  209. package/dist/daemon/__tests__/integration/migration-startup.test.js +97 -0
  210. package/dist/daemon/api/__tests__/bridge-heartbeat.test.js +21 -5
  211. package/dist/daemon/api/handlers/broker-ops.js +21 -16
  212. package/dist/daemon/api/handlers/memory.js +2 -0
  213. package/dist/daemon/crtrd.js +2 -0
  214. package/dist/daemon/human/finish.js +8 -1
  215. package/dist/daemon/manage.d.ts +0 -1
  216. package/dist/daemon/manage.js +7 -16
  217. package/dist/daemon/startup-policy.d.ts +1 -0
  218. package/dist/daemon/startup-policy.js +1 -0
  219. package/dist/migrations/001-surfaces-frontmatter.js +21 -109
  220. package/dist/migrations/002-profile-project-memory.js +1 -0
  221. package/dist/migrations/003-repository-root-memory-identity/front-door.d.ts +26 -0
  222. package/dist/migrations/003-repository-root-memory-identity/front-door.js +231 -0
  223. package/dist/migrations/003-repository-root-memory-identity/index.d.ts +2 -0
  224. package/dist/migrations/003-repository-root-memory-identity/index.js +513 -0
  225. package/dist/migrations/003-repository-root-memory-identity/references.d.ts +95 -0
  226. package/dist/migrations/003-repository-root-memory-identity/references.js +469 -0
  227. package/dist/migrations/003-repository-root-memory-identity/repository-facts.d.ts +39 -0
  228. package/dist/migrations/003-repository-root-memory-identity/repository-facts.js +349 -0
  229. package/dist/migrations/__tests__/activation-concurrency.test.d.ts +1 -0
  230. package/dist/migrations/__tests__/activation-concurrency.test.js +145 -0
  231. package/dist/migrations/__tests__/activation.test.d.ts +1 -0
  232. package/dist/migrations/__tests__/activation.test.js +149 -0
  233. package/dist/migrations/__tests__/deletion-and-root-declaration.test.d.ts +1 -0
  234. package/dist/migrations/__tests__/deletion-and-root-declaration.test.js +149 -0
  235. package/dist/migrations/activation.d.ts +16 -0
  236. package/dist/migrations/activation.js +78 -0
  237. package/dist/migrations/convergent.d.ts +14 -3
  238. package/dist/migrations/convergent.js +21 -10
  239. package/dist/migrations/corpus.d.ts +78 -0
  240. package/dist/migrations/corpus.js +497 -0
  241. package/dist/migrations/frontmatter-splice.d.ts +15 -0
  242. package/dist/migrations/frontmatter-splice.js +176 -0
  243. package/dist/migrations/registry.d.ts +6 -1
  244. package/dist/migrations/registry.js +7 -2
  245. package/dist/migrations/runner.d.ts +41 -0
  246. package/dist/migrations/runner.js +81 -0
  247. package/dist/migrations/types.d.ts +148 -9
  248. package/dist/migrations/types.js +9 -2
  249. package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +225 -17
  250. package/dist/pi-extensions/__tests__/canvas-goal-capture-envelope.test.js +11 -3
  251. package/dist/pi-extensions/canvas-context-intro.d.ts +3 -5
  252. package/dist/pi-extensions/canvas-context-intro.js +50 -46
  253. package/dist/pi-extensions/canvas-doc-substrate.d.ts +1 -8
  254. package/dist/pi-extensions/canvas-doc-substrate.js +55 -122
  255. package/dist/pi-extensions/canvas-stophook.js +6 -13
  256. package/dist/shared/generated-context.d.ts +0 -3
  257. package/dist/shared/generated-context.js +0 -57
  258. package/dist/shared/tool-groups.js +2 -3
  259. package/dist/types.d.ts +8 -11
  260. package/dist/types.js +4 -31
  261. package/package.json +5 -4
  262. package/runtime.lock.json +2 -2
  263. package/dist/builtin-memory/05-kinds/design/00-base.md +0 -17
  264. package/dist/builtin-memory/05-kinds/design/01-orchestrator.md +0 -15
  265. package/dist/builtin-memory/05-kinds/design/design-contract.md +0 -19
  266. package/dist/builtin-memory/05-kinds/developer/00-base.md +0 -17
  267. package/dist/builtin-memory/05-kinds/developer/01-orchestrator.md +0 -15
  268. package/dist/builtin-memory/05-kinds/plan/00-base.md +0 -17
  269. package/dist/builtin-memory/05-kinds/plan/01-orchestrator.md +0 -17
  270. package/dist/builtin-memory/05-kinds/plan/plan-contract.md +0 -28
  271. package/dist/builtin-memory/05-kinds/plan/reviewers/architecture-fit.md +0 -15
  272. package/dist/builtin-memory/05-kinds/plan/reviewers/code-smells.md +0 -15
  273. package/dist/builtin-memory/05-kinds/plan/reviewers/lens-contract.md +0 -13
  274. package/dist/builtin-memory/05-kinds/plan/reviewers/pattern-consistency.md +0 -17
  275. package/dist/builtin-memory/05-kinds/plan/reviewers/requirements-coverage.md +0 -17
  276. package/dist/builtin-memory/05-kinds/plan/reviewers/security.md +0 -17
  277. package/dist/builtin-memory/05-kinds/spec/00-base.md +0 -17
  278. package/dist/builtin-memory/05-kinds/spec/01-orchestrator.md +0 -15
  279. package/dist/builtin-memory/05-kinds/spec/requirements.md +0 -15
  280. package/dist/builtin-memory/design/guide.md +0 -35
  281. package/dist/builtin-memory/design/roadmap.md +0 -21
  282. package/dist/builtin-memory/development.md +0 -113
  283. package/dist/builtin-memory/plan/roadmap.md +0 -25
  284. package/dist/builtin-memory/spec/guide.md +0 -53
  285. package/dist/builtin-memory/spec/requirements.md +0 -29
  286. package/dist/builtin-memory/spec/roadmap.md +0 -36
  287. package/dist/builtin-memory/testing.md +0 -39
  288. /package/dist/api/__tests__/{serial → integration}/client.test.d.ts +0 -0
  289. /package/dist/api/__tests__/{serial → integration}/client.test.js +0 -0
  290. /package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/{serial → integration}/provider-rotation.test.ts +0 -0
  291. /package/dist/clients/{inbox/__tests__/serial/inbox-controller.test.d.ts → attach/__tests__/pane-tag-successor.test.d.ts} +0 -0
  292. /package/dist/clients/{inbox/__tests__/serial/mount-panel.test.d.ts → attach/__tests__/profile-files.test.d.ts} +0 -0
  293. /package/dist/{core/__tests__/live-mutation-verbs.test.d.ts → clients/inbox/__tests__/integration/inbox-controller.test.d.ts} +0 -0
  294. /package/dist/clients/inbox/__tests__/{serial → integration}/inbox-controller.test.js +0 -0
  295. /package/dist/{core/__tests__/serial/broker-fork-seam.test.d.ts → clients/inbox/__tests__/integration/mount-panel.test.d.ts} +0 -0
  296. /package/dist/clients/inbox/__tests__/{serial → integration}/mount-panel.test.js +0 -0
  297. /package/dist/{core/__tests__/serial/broker-sdk-wiring.test.d.ts → commands/__tests__/surface-reload-target.test.d.ts} +0 -0
  298. /package/dist/{core/__tests__/serial/broker-snapshot-history.test.d.ts → commands/memory/__tests__/command-selector-and-mutation-guards.test.d.ts} +0 -0
  299. /package/dist/{core/__tests__/serial/command-plugins.test.d.ts → commands/memory/__tests__/repository-root-lint.test.d.ts} +0 -0
  300. /package/dist/{core/__tests__/serial/deferred-no-wake.test.d.ts → commands/sys/__tests__/sync-project-guidance.test.d.ts} +0 -0
  301. /package/dist/core/__tests__/{serial/flagship-lifecycle.test.d.ts → config-change-delta.test.d.ts} +0 -0
  302. /package/dist/core/__tests__/{serial/host-teardown-process-group.test.d.ts → integration/broker-fork-seam.test.d.ts} +0 -0
  303. /package/dist/core/__tests__/{serial/human-deliver-e2e.test.d.ts → integration/broker-sdk-wiring.test.d.ts} +0 -0
  304. /package/dist/core/__tests__/{serial/live-mutation.test.d.ts → integration/broker-snapshot-history.test.d.ts} +0 -0
  305. /package/dist/core/__tests__/{serial/refresh-stall-recycle.test.d.ts → integration/command-plugins.test.d.ts} +0 -0
  306. /package/dist/core/__tests__/{serial/revive.test.d.ts → integration/deferred-no-wake.test.d.ts} +0 -0
  307. /package/dist/core/__tests__/{serial/spawn-root.test.d.ts → integration/flagship-lifecycle.test.d.ts} +0 -0
  308. /package/dist/core/__tests__/{serial/subscription-delivery.test.d.ts → integration/host-teardown-process-group.test.d.ts} +0 -0
  309. /package/dist/core/__tests__/{serial/tmux-surface.test.d.ts → integration/human-deliver-e2e.test.d.ts} +0 -0
  310. /package/dist/core/__tests__/{serial/worktree.test.d.ts → integration/live-mutation-verbs.test.d.ts} +0 -0
  311. /package/dist/core/{human/__tests__/serial/inbox-core.test.d.ts → __tests__/integration/live-mutation.test.d.ts} +0 -0
  312. /package/dist/core/human/__tests__/{serial → integration}/inbox-core.test.js +0 -0
@@ -0,0 +1,599 @@
1
+ // The Profiles settings destination: a map of profiles × their directories,
2
+ // anchored on the directory the page was opened in.
3
+ //
4
+ // The startup profile menu (`core/profiles/select.ts`) is a CHOOSER — it shows
5
+ // only profiles covering cwd, one matched dir each. This panel is the manager
6
+ // behind its `v` key: every profile, every directory each one owns, which
7
+ // directory is pinned where, and the edits that follow from seeing that
8
+ // (adopt this dir, pin here, rename, remove a stale dir, delete).
9
+ //
10
+ // Mutations go straight through `core/profiles/manifest.ts` and
11
+ // `default-binding.ts`, exactly as the `crtr profile` leaves do. Deletion is
12
+ // the one exception: it cascades across nodes, crons, tickets and reviews, so
13
+ // it routes through crtrd like `crtr profile delete`.
14
+ import { Input, matchesKey, truncateToWidth } from "@earendil-works/pi-tui";
15
+ import { basename } from "node:path";
16
+ import { PROFILE_PROJECT_MEMORY_VALUES } from "../../../api/dto/profiles.js";
17
+ import { cliClient } from "../../api-client.js";
18
+ import { clearDefaultProfile, defaultProfileDirs, getDefaultProfileId, setDefaultProfileId, } from "../../../core/profiles/default-binding.js";
19
+ import { ROOT_PROFILE_ID, addProfileProject, createProfile, listProfiles, pauseProfile, removeProfileProject, renameProfile, resumeProfile, } from "../../../core/profiles/manifest.js";
20
+ import { profileCoversCwd, tildify } from "../../../core/profiles/select.js";
21
+ import { padAnsi, theme, visibleRange, wrapText, } from "../../../core/tui/panel.js";
22
+ /** Coarse "used ..." for telling otherwise-alike profiles apart. */
23
+ function relativeUsed(iso) {
24
+ if (iso === null)
25
+ return "never used";
26
+ const then = Date.parse(iso);
27
+ if (Number.isNaN(then))
28
+ return "used recently";
29
+ const secs = Math.max(0, Math.floor((Date.now() - then) / 1000));
30
+ if (secs < 60)
31
+ return "used just now";
32
+ const mins = Math.floor(secs / 60);
33
+ if (mins < 60)
34
+ return `used ${mins}m ago`;
35
+ const hours = Math.floor(mins / 60);
36
+ if (hours < 24)
37
+ return `used ${hours}h ago`;
38
+ const days = Math.floor(hours / 24);
39
+ if (days < 30)
40
+ return `used ${days}d ago`;
41
+ const months = Math.floor(days / 30);
42
+ if (months < 12)
43
+ return `used ${months}mo ago`;
44
+ return `used ${Math.floor(months / 12)}y ago`;
45
+ }
46
+ function messageOf(error) {
47
+ return error instanceof Error ? error.message : String(error);
48
+ }
49
+ export class ProfilesPanel {
50
+ cwd;
51
+ onChange;
52
+ nameInput = new Input();
53
+ dirInput = new Input();
54
+ entries = [];
55
+ listIndex = 0;
56
+ dirIndex = 0;
57
+ mode = "list";
58
+ /** Profile the detail level / a confirm is about. */
59
+ openId = null;
60
+ notice;
61
+ noticeTone = "success";
62
+ mutating = false;
63
+ constructor(cwd, onChange) {
64
+ this.cwd = cwd;
65
+ this.onChange = onChange;
66
+ this.nameInput.onSubmit = () => {
67
+ this.submitName();
68
+ this.onChange();
69
+ };
70
+ this.nameInput.onEscape = () => {
71
+ this.mode = this.openId !== null ? "detail" : "list";
72
+ this.leaveField();
73
+ this.onChange();
74
+ };
75
+ this.dirInput.onSubmit = () => {
76
+ this.submitDir();
77
+ this.onChange();
78
+ };
79
+ this.dirInput.onEscape = () => {
80
+ this.mode = "detail";
81
+ this.leaveField();
82
+ this.onChange();
83
+ };
84
+ this.reload();
85
+ }
86
+ badge() {
87
+ return String(this.entries.length);
88
+ }
89
+ /** A live text field or a confirm keeps EVERY key, so a name containing `q`
90
+ * can never close the page. The detail level claims only Escape and ← — they
91
+ * mean "back to the profile list" here rather than "jump to the settings
92
+ * rail" — and leaves the page's own navigation and cancel keys alone. */
93
+ ownsInput(data) {
94
+ if (this.mode === "list")
95
+ return false;
96
+ if (this.mode === "detail")
97
+ return matchesKey(data, "escape") || matchesKey(data, "left");
98
+ return true;
99
+ }
100
+ // --- state ----------------------------------------------------------------
101
+ /** Profiles covering cwd first (most recently used within), then the rest by
102
+ * recency, with root last — the ones a startup pick is deciding between sit
103
+ * at the top, where the eye starts. */
104
+ reload() {
105
+ const rank = (entry) => {
106
+ if (entry.profileId === ROOT_PROFILE_ID)
107
+ return 2;
108
+ return profileCoversCwd(entry, this.cwd) ? 0 : 1;
109
+ };
110
+ const used = (entry) => entry.manifest.last_used_at ?? "";
111
+ this.entries = listProfiles().sort((a, b) => {
112
+ const byRank = rank(a) - rank(b);
113
+ if (byRank !== 0)
114
+ return byRank;
115
+ const byUsed = used(b).localeCompare(used(a));
116
+ return byUsed !== 0 ? byUsed : a.manifest.name.localeCompare(b.manifest.name);
117
+ });
118
+ if (this.listIndex >= this.entries.length)
119
+ this.listIndex = Math.max(0, this.entries.length - 1);
120
+ const open = this.open();
121
+ if (open === null) {
122
+ if (this.mode !== "list")
123
+ this.mode = "list";
124
+ this.openId = null;
125
+ }
126
+ else if (this.dirIndex >= open.manifest.projects.length) {
127
+ this.dirIndex = Math.max(0, open.manifest.projects.length - 1);
128
+ }
129
+ }
130
+ selected() {
131
+ return this.entries[this.listIndex] ?? null;
132
+ }
133
+ open() {
134
+ if (this.openId === null)
135
+ return null;
136
+ return this.entries.find((e) => e.profileId === this.openId) ?? null;
137
+ }
138
+ currentDir() {
139
+ return this.open()?.manifest.projects[this.dirIndex] ?? null;
140
+ }
141
+ pinnedHere() {
142
+ return getDefaultProfileId(this.cwd);
143
+ }
144
+ say(text, tone = "success") {
145
+ this.notice = text;
146
+ this.noticeTone = tone;
147
+ }
148
+ /** Run a manifest mutation, turning its structured failure into the panel's
149
+ * notice line rather than tearing the page down. */
150
+ attempt(what, ok) {
151
+ try {
152
+ what();
153
+ this.reload();
154
+ this.say(ok);
155
+ }
156
+ catch (error) {
157
+ this.say(messageOf(error), "warning");
158
+ }
159
+ }
160
+ // --- input ----------------------------------------------------------------
161
+ handleInput(data, matches) {
162
+ const handled = this.route(data, matches);
163
+ if (handled)
164
+ this.onChange();
165
+ return handled;
166
+ }
167
+ route(data, matches) {
168
+ switch (this.mode) {
169
+ case "new-name":
170
+ case "rename":
171
+ return this.routeText(this.nameInput, data);
172
+ case "add-dir":
173
+ return this.routeText(this.dirInput, data);
174
+ case "confirm-delete":
175
+ return this.routeConfirm(data, () => void this.deleteOpen());
176
+ case "confirm-remove-dir":
177
+ return this.routeConfirm(data, () => this.removeDir());
178
+ case "detail":
179
+ return this.routeDetail(data, matches);
180
+ case "list":
181
+ return this.routeList(data, matches);
182
+ }
183
+ }
184
+ routeText(input, data) {
185
+ input.handleInput(data);
186
+ return true;
187
+ }
188
+ routeConfirm(data, confirm) {
189
+ const key = data.toLowerCase();
190
+ if (key === "y")
191
+ confirm();
192
+ else if (key === "n" || matchesKey(data, "escape") || matchesKey(data, "return")) {
193
+ this.mode = this.openId !== null ? "detail" : "list";
194
+ this.say("Cancelled.");
195
+ }
196
+ return true;
197
+ }
198
+ routeList(data, matches) {
199
+ if (matches?.("crtr.setup.list-down", data) === true) {
200
+ this.move(1);
201
+ return true;
202
+ }
203
+ if (matches?.("crtr.setup.list-up", data) === true) {
204
+ this.move(-1);
205
+ return true;
206
+ }
207
+ if (matches?.("crtr.setup.advance", data) === true) {
208
+ const entry = this.selected();
209
+ if (entry !== null) {
210
+ this.openId = entry.profileId;
211
+ this.dirIndex = 0;
212
+ this.mode = "detail";
213
+ this.notice = undefined;
214
+ }
215
+ return true;
216
+ }
217
+ switch (data.toLowerCase()) {
218
+ case "a":
219
+ return this.addCwdTo(this.selected());
220
+ case "d":
221
+ return this.togglePin();
222
+ case "n":
223
+ this.mode = "new-name";
224
+ this.edit(this.nameInput, basename(this.cwd) || "profile");
225
+ return true;
226
+ case "x":
227
+ return this.askDelete();
228
+ default:
229
+ return false;
230
+ }
231
+ }
232
+ routeDetail(data, matches) {
233
+ const open = this.open();
234
+ if (open === null) {
235
+ this.mode = "list";
236
+ return true;
237
+ }
238
+ if (matchesKey(data, "escape") || matchesKey(data, "left")) {
239
+ this.mode = "list";
240
+ this.notice = undefined;
241
+ return true;
242
+ }
243
+ if (matches?.("crtr.setup.list-down", data) === true) {
244
+ this.moveDir(1);
245
+ return true;
246
+ }
247
+ if (matches?.("crtr.setup.list-up", data) === true) {
248
+ this.moveDir(-1);
249
+ return true;
250
+ }
251
+ switch (data.toLowerCase()) {
252
+ case "a":
253
+ this.mode = "add-dir";
254
+ this.edit(this.dirInput, this.cwd);
255
+ return true;
256
+ case "m":
257
+ return this.cycleMemory();
258
+ case "h":
259
+ return this.setHome();
260
+ case "x":
261
+ return this.askRemoveDir();
262
+ case "r":
263
+ this.mode = "rename";
264
+ this.edit(this.nameInput, open.manifest.name);
265
+ return true;
266
+ case "p":
267
+ return this.togglePause();
268
+ default:
269
+ return false;
270
+ }
271
+ }
272
+ /** Seed a field with the value the user most likely wants, cursor at its end
273
+ * (`\x05` — the field is an edit-or-accept, never a blank you must retype). */
274
+ edit(input, value) {
275
+ input.setValue(value);
276
+ input.handleInput("\x05");
277
+ input.focused = true;
278
+ this.notice = undefined;
279
+ }
280
+ leaveField() {
281
+ this.nameInput.focused = false;
282
+ this.dirInput.focused = false;
283
+ }
284
+ move(delta) {
285
+ if (this.entries.length === 0)
286
+ return;
287
+ this.listIndex =
288
+ (this.listIndex + delta + this.entries.length) % this.entries.length;
289
+ this.notice = undefined;
290
+ }
291
+ moveDir(delta) {
292
+ const count = this.open()?.manifest.projects.length ?? 0;
293
+ if (count === 0)
294
+ return;
295
+ this.dirIndex = (this.dirIndex + delta + count) % count;
296
+ this.notice = undefined;
297
+ }
298
+ // --- actions --------------------------------------------------------------
299
+ addCwdTo(entry) {
300
+ if (entry === null)
301
+ return true;
302
+ this.attempt(() => addProfileProject(entry.profileId, this.cwd, { memory: "content" }), `${tildify(this.cwd)} now belongs to "${entry.manifest.name}".`);
303
+ return true;
304
+ }
305
+ togglePin() {
306
+ const entry = this.selected();
307
+ if (entry === null)
308
+ return true;
309
+ if (this.pinnedHere() === entry.profileId) {
310
+ clearDefaultProfile(this.cwd);
311
+ this.say(`${tildify(this.cwd)} no longer defaults to any profile.`);
312
+ }
313
+ else {
314
+ setDefaultProfileId(this.cwd, entry.profileId);
315
+ this.say(`${tildify(this.cwd)} now starts as "${entry.manifest.name}" without asking.`);
316
+ }
317
+ this.onChange();
318
+ return true;
319
+ }
320
+ submitName() {
321
+ const value = this.nameInput.getValue().trim();
322
+ const creating = this.mode === "new-name";
323
+ this.mode = creating ? "list" : "detail";
324
+ this.leaveField();
325
+ if (value === "") {
326
+ this.say("A profile name cannot be empty.", "warning");
327
+ return;
328
+ }
329
+ if (creating) {
330
+ let createdId = null;
331
+ this.attempt(() => {
332
+ createdId = createProfile(value, [
333
+ { path: this.cwd, memory: "content" },
334
+ ]).profileId;
335
+ }, `Created "${value}", owning ${tildify(this.cwd)}.`);
336
+ const at = this.entries.findIndex((e) => e.profileId === createdId);
337
+ if (at >= 0)
338
+ this.listIndex = at;
339
+ return;
340
+ }
341
+ const open = this.open();
342
+ if (open === null)
343
+ return;
344
+ this.attempt(() => renameProfile(open.profileId, value), `Renamed to "${value}".`);
345
+ }
346
+ submitDir() {
347
+ const value = this.dirInput.getValue().trim();
348
+ const open = this.open();
349
+ this.mode = "detail";
350
+ this.leaveField();
351
+ if (open === null)
352
+ return;
353
+ if (value === "") {
354
+ this.say("Type the directory to add.", "warning");
355
+ return;
356
+ }
357
+ this.attempt(() => addProfileProject(open.profileId, value, { memory: "content" }), `${tildify(value)} added to "${open.manifest.name}".`);
358
+ }
359
+ cycleMemory() {
360
+ const open = this.open();
361
+ const dir = this.currentDir();
362
+ if (open === null || dir === null)
363
+ return true;
364
+ const next = PROFILE_PROJECT_MEMORY_VALUES[(PROFILE_PROJECT_MEMORY_VALUES.indexOf(dir.memory) + 1) %
365
+ PROFILE_PROJECT_MEMORY_VALUES.length];
366
+ this.attempt(() => addProfileProject(open.profileId, dir.path, { memory: next }), `${tildify(dir.path)} discloses up to "${next}".`);
367
+ return true;
368
+ }
369
+ setHome() {
370
+ const open = this.open();
371
+ const dir = this.currentDir();
372
+ if (open === null || dir === null)
373
+ return true;
374
+ this.attempt(() => addProfileProject(open.profileId, dir.path, {
375
+ memory: dir.memory,
376
+ home: true,
377
+ }), `Nodes under "${open.manifest.name}" now run in ${tildify(dir.path)}.`);
378
+ return true;
379
+ }
380
+ askRemoveDir() {
381
+ if (this.currentDir() === null) {
382
+ this.say("This profile owns no directories.", "warning");
383
+ return true;
384
+ }
385
+ this.mode = "confirm-remove-dir";
386
+ this.notice = undefined;
387
+ return true;
388
+ }
389
+ removeDir() {
390
+ const open = this.open();
391
+ const dir = this.currentDir();
392
+ this.mode = "detail";
393
+ if (open === null || dir === null)
394
+ return;
395
+ this.attempt(() => removeProfileProject(open.profileId, dir.path), `${tildify(dir.path)} removed from "${open.manifest.name}".`);
396
+ }
397
+ togglePause() {
398
+ const open = this.open();
399
+ if (open === null)
400
+ return true;
401
+ const paused = open.manifest.paused_at !== null;
402
+ this.attempt(() => paused ? resumeProfile(open.profileId) : pauseProfile(open.profileId), paused
403
+ ? `"${open.manifest.name}" is active again.`
404
+ : `"${open.manifest.name}" is paused — no new nodes start under it.`);
405
+ return true;
406
+ }
407
+ askDelete() {
408
+ const entry = this.selected();
409
+ if (entry === null)
410
+ return true;
411
+ if (entry.profileId === ROOT_PROFILE_ID) {
412
+ this.say("The root profile is the fallback identity for uncovered directories and cannot be deleted.", "warning");
413
+ return true;
414
+ }
415
+ this.openId = entry.profileId;
416
+ this.mode = "confirm-delete";
417
+ this.notice = undefined;
418
+ return true;
419
+ }
420
+ async deleteOpen() {
421
+ const open = this.open();
422
+ this.mode = "list";
423
+ if (open === null || this.mutating)
424
+ return;
425
+ this.mutating = true;
426
+ this.say(`Deleting "${open.manifest.name}"…`);
427
+ this.onChange();
428
+ try {
429
+ const result = await cliClient().deleteProfile(open.profileId, {
430
+ force: true,
431
+ caller_node_id: process.env["CRTR_NODE_ID"] ?? null,
432
+ });
433
+ this.openId = null;
434
+ this.reload();
435
+ this.say(`Deleted "${result.name}" — ${result.nodes} nodes, ${result.crons} crons, ${result.default_pins} pins.`);
436
+ }
437
+ catch (error) {
438
+ this.say(messageOf(error), "warning");
439
+ }
440
+ finally {
441
+ this.mutating = false;
442
+ this.onChange();
443
+ }
444
+ }
445
+ // --- rendering ------------------------------------------------------------
446
+ footerHint() {
447
+ switch (this.mode) {
448
+ case "new-name":
449
+ return "type a name · enter create · esc cancel";
450
+ case "rename":
451
+ return "type a name · enter save · esc cancel";
452
+ case "add-dir":
453
+ return "type a directory · enter add · esc cancel";
454
+ case "confirm-delete":
455
+ case "confirm-remove-dir":
456
+ return "y confirm · n cancel";
457
+ case "detail":
458
+ return "↑↓ dir · a add · m memory · h home · x remove · r rename · p pause · esc back";
459
+ case "list":
460
+ return "↑↓ move · enter open · a add this dir · d pin here · n new · x delete";
461
+ }
462
+ }
463
+ render(width, height) {
464
+ // Each prompt renders over the level it acts on: naming a new profile and
465
+ // confirming a deletion belong to the list, while renaming, adding a
466
+ // directory and confirming its removal belong to the open profile.
467
+ const overList = this.mode === "list" ||
468
+ this.mode === "new-name" ||
469
+ this.mode === "confirm-delete";
470
+ const out = overList
471
+ ? this.renderList(width, height)
472
+ : this.renderDetail(width, height);
473
+ if (this.notice !== undefined) {
474
+ out.push("");
475
+ for (const line of wrapText(this.notice, width))
476
+ out.push(truncateToWidth(theme.fg(this.noticeTone, line), width));
477
+ }
478
+ return out;
479
+ }
480
+ header(width, title, meta) {
481
+ const left = theme.fg("accent", theme.bold(title));
482
+ const right = theme.fg("dim", meta);
483
+ return truncateToWidth(`${left} ${right}`, width);
484
+ }
485
+ renderList(width, height) {
486
+ const out = [
487
+ this.header(width, "Profiles", `${this.entries.length} profile${this.entries.length === 1 ? "" : "s"}`),
488
+ truncateToWidth(theme.fg("dim", `Identities your sessions run under. Here: ${tildify(this.cwd)}`), width),
489
+ "",
490
+ ];
491
+ // Prompts first: the very first profile is created from the empty list, so
492
+ // an empty-state message that returned before them would hide the field the
493
+ // user is typing into.
494
+ if (this.mode === "new-name")
495
+ return [...out, ...this.field(width, "New profile name", this.nameInput)];
496
+ if (this.mode === "confirm-delete")
497
+ return [...out, ...this.deletePrompt(width)];
498
+ if (this.entries.length === 0) {
499
+ out.push(truncateToWidth(theme.fg("dim", " No profiles yet — press n to create one here."), width));
500
+ return out;
501
+ }
502
+ const pinned = this.pinnedHere();
503
+ const nameWidth = Math.min(22, Math.max(...this.entries.map((e) => e.manifest.name.length)));
504
+ const capacity = Math.max(1, height - 8);
505
+ const range = visibleRange(this.entries.length, this.listIndex, capacity);
506
+ for (let index = range.start; index < range.end; index += 1) {
507
+ const entry = this.entries[index];
508
+ const count = entry.manifest.projects.length;
509
+ const dirs = count === 0 ? "—" : `${count} dir${count === 1 ? "" : "s"}`;
510
+ const badges = [];
511
+ if (profileCoversCwd(entry, this.cwd))
512
+ badges.push("covers here");
513
+ if (pinned === entry.profileId)
514
+ badges.push("pinned");
515
+ if (entry.manifest.paused_at !== null)
516
+ badges.push("paused");
517
+ const body = `${padAnsi(entry.manifest.name, nameWidth)} ${padAnsi(dirs, 8)} ${padAnsi(relativeUsed(entry.manifest.last_used_at), 14)} ${badges.join(" · ")}`;
518
+ if (index === this.listIndex)
519
+ out.push(theme.bg("selectedBg", padAnsi(`\u25b8 ${body}`, width)));
520
+ else
521
+ out.push(truncateToWidth(` ${padAnsi(entry.manifest.name, nameWidth)} ${theme.fg("dim", `${padAnsi(dirs, 8)} ${padAnsi(relativeUsed(entry.manifest.last_used_at), 14)}`)} ${theme.fg("muted", badges.join(" · "))}`, width));
522
+ }
523
+ if (range.start > 0 || range.end < this.entries.length)
524
+ out.push(truncateToWidth(theme.fg("dim", ` ${this.listIndex + 1}/${this.entries.length}`), width));
525
+ return out;
526
+ }
527
+ renderDetail(width, height) {
528
+ const open = this.open();
529
+ if (open === null)
530
+ return this.renderList(width, height);
531
+ const manifest = open.manifest;
532
+ const facts = [
533
+ manifest.home !== null ? `home ${tildify(manifest.home)}` : "no home",
534
+ `kind ${manifest.default_kind ?? "general"}`,
535
+ relativeUsed(manifest.last_used_at),
536
+ ...(manifest.paused_at !== null ? ["paused"] : []),
537
+ ];
538
+ const out = [
539
+ this.header(width, manifest.name, open.profileId),
540
+ truncateToWidth(theme.fg("dim", facts.join(" \u00b7 ")), width),
541
+ "",
542
+ ];
543
+ if (this.mode === "rename")
544
+ return [...out, ...this.field(width, "Rename profile", this.nameInput)];
545
+ if (this.mode === "add-dir")
546
+ return [
547
+ ...out,
548
+ ...this.field(width, "Directory to add to this profile", this.dirInput),
549
+ ];
550
+ const projects = manifest.projects;
551
+ if (projects.length === 0) {
552
+ out.push(truncateToWidth(theme.fg("dim", " Owns no directories — press a to add one."), width));
553
+ return out;
554
+ }
555
+ const pins = new Set(defaultProfileDirs(open.profileId));
556
+ const pathWidth = Math.min(Math.max(20, width - 26), Math.max(...projects.map((p) => tildify(p.path).length)));
557
+ const capacity = Math.max(1, height - 8);
558
+ const range = visibleRange(projects.length, this.dirIndex, capacity);
559
+ for (let index = range.start; index < range.end; index += 1) {
560
+ const project = projects[index];
561
+ const badges = [];
562
+ if (project.path === manifest.home)
563
+ badges.push("home");
564
+ if (pins.has(project.path))
565
+ badges.push("pinned");
566
+ if (project.path === this.cwd)
567
+ badges.push("\u2190 here");
568
+ const path = padAnsi(tildify(project.path), pathWidth);
569
+ const body = `${path} ${padAnsi(project.memory, 8)} ${badges.join(" \u00b7 ")}`;
570
+ if (index === this.dirIndex)
571
+ out.push(theme.bg("selectedBg", padAnsi(`\u25b8 ${body}`, width)));
572
+ else
573
+ out.push(truncateToWidth(` ${path} ${theme.fg("success", padAnsi(project.memory, 8))} ${theme.fg("muted", badges.join(" \u00b7 "))}`, width));
574
+ }
575
+ if (this.mode === "confirm-remove-dir") {
576
+ const dir = this.currentDir();
577
+ out.push("");
578
+ out.push(truncateToWidth(theme.fg("warning", `Remove ${dir !== null ? tildify(dir.path) : "this directory"} from "${manifest.name}"? Its files are untouched. y / n`), width));
579
+ }
580
+ return out;
581
+ }
582
+ /** A labelled single-line text field, used by every prompt in the panel. */
583
+ field(width, label, input) {
584
+ return [
585
+ truncateToWidth(theme.fg("accent", label), width),
586
+ truncateToWidth(` ${input.render(Math.max(8, width - 2))[0] ?? ""}`, width),
587
+ ];
588
+ }
589
+ deletePrompt(width) {
590
+ const open = this.open();
591
+ const name = open?.manifest.name ?? "";
592
+ const out = [];
593
+ for (const line of wrapText(`Delete "${name}" and everything it owns — every node, cron, inbox ticket and review under it, plus its memory store and directory pins? This cannot be undone.`, width))
594
+ out.push(truncateToWidth(theme.fg("warning", line), width));
595
+ out.push("");
596
+ out.push(truncateToWidth(theme.fg("dim", " y delete n cancel"), width));
597
+ return out;
598
+ }
599
+ }
@@ -1,6 +1,7 @@
1
1
  import { ModelRegistry, ModelRuntime } from "@earendil-works/pi-coding-agent";
2
2
  import { TUI, type Component, type Focusable } from "@earendil-works/pi-tui";
3
3
  import { type BindingId, type BindingResolution } from "../../core/keybindings/index.js";
4
+ export type DestinationId = "providers" | "models" | "keybindings" | "display" | "profiles" | "panes" | "broker-limits" | "updates";
4
5
  export declare class SettingsShell implements Component, Focusable {
5
6
  private readonly tui;
6
7
  private readonly bindings;
@@ -9,6 +10,7 @@ export declare class SettingsShell implements Component, Focusable {
9
10
  private readonly models;
10
11
  private readonly keybindings;
11
12
  private readonly brokerLimits;
13
+ private readonly profiles;
12
14
  private readonly destinations;
13
15
  private index;
14
16
  /** The rail owns the arrow keys until you step into a panel. */
@@ -18,7 +20,7 @@ export declare class SettingsShell implements Component, Focusable {
18
20
  private cachedHeight;
19
21
  private cachedLines;
20
22
  onCancel?: () => void;
21
- constructor(tui: TUI, agentDir: string, runtime: ModelRuntime, registry: ModelRegistry, bindings: BindingResolution<BindingId>, rawKeybindings: unknown, terminalRows: () => number, rawTmuxPassthrough?: unknown);
23
+ constructor(tui: TUI, agentDir: string, runtime: ModelRuntime, registry: ModelRegistry, bindings: BindingResolution<BindingId>, rawKeybindings: unknown, terminalRows: () => number, rawTmuxPassthrough?: unknown, initial?: DestinationId);
22
24
  set focused(value: boolean);
23
25
  get focused(): boolean;
24
26
  private get current();
@@ -49,4 +51,4 @@ export declare class SettingsShell implements Component, Focusable {
49
51
  private panelHint;
50
52
  render(width: number): string[];
51
53
  }
52
- export declare function runSettings(): Promise<void>;
54
+ export declare function runSettings(initial?: DestinationId): Promise<void>;