@north-light/crouter 0.3.192 → 0.3.194

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 (190) hide show
  1. package/dist/api/client.d.ts +31 -10
  2. package/dist/api/client.js +83 -24
  3. package/dist/api/dto/bash-jobs.d.ts +24 -0
  4. package/dist/api/dto/bash-jobs.js +9 -0
  5. package/dist/api/dto/human.d.ts +3 -4
  6. package/dist/api/dto/inbox.d.ts +106 -65
  7. package/dist/api/dto/inbox.js +2 -8
  8. package/dist/api/index.d.ts +1 -0
  9. package/dist/api/index.js +1 -0
  10. package/dist/api/routes.d.ts +7 -0
  11. package/dist/api/routes.js +7 -0
  12. package/dist/builtin-memory/02-lifecycle/01-resident.md +1 -1
  13. package/dist/builtin-memory/internal/examples/imessage-assistant.md +1 -1
  14. package/dist/builtin-memory/internal/nodes-and-canvas.md +2 -2
  15. package/dist/builtin-memory/internal/storage-tiers.md +1 -1
  16. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/serial/provider-rotation.test.ts +101 -3
  17. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +6 -2
  18. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +68 -14
  19. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +87 -13
  20. package/dist/clients/attach/__tests__/chat-view-snapshot-ordering.test.js +2 -2
  21. package/dist/clients/attach/__tests__/group-activity.test.js +2 -2
  22. package/dist/clients/attach/chrome/canvas-panels.d.ts +1 -1
  23. package/dist/clients/attach/chrome/canvas-panels.js +1 -1
  24. package/dist/clients/attach/input/overlay-owner.js +1 -1
  25. package/dist/clients/attach/overlays/auth.js +34 -8
  26. package/dist/clients/attach/overlays/pickers.d.ts +5 -8
  27. package/dist/clients/attach/overlays/pickers.js +37 -43
  28. package/dist/clients/attach/viewer.js +643 -620
  29. package/dist/clients/inbox/__tests__/serial/inbox-controller.test.js +38 -128
  30. package/dist/clients/inbox/__tests__/serial/mount-panel.test.js +72 -148
  31. package/dist/clients/inbox/controller.d.ts +2 -3
  32. package/dist/clients/inbox/controller.js +41 -42
  33. package/dist/clients/inbox/page-adapter.d.ts +33 -0
  34. package/dist/clients/inbox/page-adapter.js +54 -0
  35. package/dist/clients/inbox/resolve.d.ts +2 -2
  36. package/dist/clients/inbox/resolve.js +1 -1
  37. package/dist/clients/inbox/review-visibility.d.ts +1 -1
  38. package/dist/clients/inbox/review-visibility.js +1 -1
  39. package/dist/clients/inbox/tui/ansi.d.ts +1 -1
  40. package/dist/clients/inbox/tui/ansi.js +2 -2
  41. package/dist/clients/inbox/tui/input.d.ts +1 -3
  42. package/dist/clients/inbox/tui/input.js +242 -553
  43. package/dist/clients/inbox/tui/panel.d.ts +3 -1
  44. package/dist/clients/inbox/tui/panel.js +59 -187
  45. package/dist/clients/inbox/tui/render.d.ts +0 -25
  46. package/dist/clients/inbox/tui/render.js +165 -416
  47. package/dist/clients/inbox/tui/slots.d.ts +32 -0
  48. package/dist/clients/inbox/tui/slots.js +156 -0
  49. package/dist/clients/inbox/tui/types.d.ts +25 -13
  50. package/dist/clients/inbox/tui.js +5 -3
  51. package/dist/commands/attention.js +2 -2
  52. package/dist/commands/human/doc.js +66 -20
  53. package/dist/commands/human/prompts.d.ts +3 -3
  54. package/dist/commands/human/prompts.js +158 -112
  55. package/dist/commands/human/queue.d.ts +0 -1
  56. package/dist/commands/human/queue.js +34 -94
  57. package/dist/commands/human/shared.d.ts +10 -4
  58. package/dist/commands/human/shared.js +62 -13
  59. package/dist/commands/human.js +8 -4
  60. package/dist/commands/memory/read.js +13 -5
  61. package/dist/commands/node/bash.js +18 -30
  62. package/dist/commands/node/lifecycle.js +2 -2
  63. package/dist/commands/surface/node/focus.js +1 -1
  64. package/dist/core/__tests__/human-deliver.test.js +40 -46
  65. package/dist/core/__tests__/seam/broker-attach-stream.test.js +7 -1
  66. package/dist/core/__tests__/seam/dormancy-release.test.js +64 -10
  67. package/dist/core/__tests__/serial/human-deliver-e2e.test.js +40 -31
  68. package/dist/core/__tests__/serial/spawn-root.test.js +3 -1
  69. package/dist/core/__tests__/spawn-worktree-id-conflict.test.js +3 -1
  70. package/dist/core/auth-interaction.d.ts +2 -2
  71. package/dist/core/bash-jobs.d.ts +43 -0
  72. package/dist/core/bash-jobs.js +96 -2
  73. package/dist/core/canvas/__tests__/attention.test.js +16 -10
  74. package/dist/core/canvas/__tests__/render-remote.test.js +9 -3
  75. package/dist/core/canvas/attention.js +1 -1
  76. package/dist/core/canvas/browse/app.js +1 -1
  77. package/dist/core/canvas/nav-model.d.ts +1 -1
  78. package/dist/core/canvas/nav-model.js +1 -1
  79. package/dist/core/canvas/remote-canvas-source.js +1 -1
  80. package/dist/core/canvas/types.d.ts +2 -1
  81. package/dist/core/config.js +4 -1
  82. package/dist/core/human/__tests__/page-render.test.d.ts +1 -0
  83. package/dist/core/human/__tests__/page-render.test.js +49 -0
  84. package/dist/core/human/__tests__/page-tickets.test.d.ts +1 -0
  85. package/dist/core/human/__tests__/page-tickets.test.js +112 -0
  86. package/dist/core/human/__tests__/page.test.d.ts +1 -0
  87. package/dist/core/human/__tests__/page.test.js +139 -0
  88. package/dist/core/human/__tests__/serial/inbox-core.test.js +42 -32
  89. package/dist/core/human/claim.js +2 -2
  90. package/dist/core/human/convention.d.ts +4 -4
  91. package/dist/core/human/convention.js +6 -13
  92. package/dist/core/human/markdown-html.d.ts +8 -0
  93. package/dist/core/human/markdown-html.js +581 -0
  94. package/dist/core/human/page-catalog.d.ts +6 -0
  95. package/dist/core/human/page-catalog.js +43 -0
  96. package/dist/core/human/page-render.d.ts +3 -0
  97. package/dist/core/human/page-render.js +131 -0
  98. package/dist/core/human/page-schema.d.ts +312 -0
  99. package/dist/core/human/page-schema.js +291 -0
  100. package/dist/core/human/page-synth.d.ts +9 -0
  101. package/dist/core/human/page-synth.js +17 -0
  102. package/dist/core/human/page.d.ts +22 -0
  103. package/dist/core/human/page.js +427 -0
  104. package/dist/core/human/review-schema.d.ts +19 -0
  105. package/dist/core/human/review-schema.js +34 -0
  106. package/dist/core/human/scan.d.ts +12 -3
  107. package/dist/core/human/scan.js +69 -26
  108. package/dist/core/human/summary.d.ts +5 -6
  109. package/dist/core/human/summary.js +54 -37
  110. package/dist/core/human/tickets.d.ts +61 -11
  111. package/dist/core/human/tickets.js +100 -57
  112. package/dist/core/human/types.d.ts +21 -66
  113. package/dist/core/human/types.js +1 -5
  114. package/dist/core/inspector/model.d.ts +5 -0
  115. package/dist/core/inspector/model.js +5 -0
  116. package/dist/core/inspector/text.js +2 -2
  117. package/dist/core/inspector/tui.js +10 -3
  118. package/dist/core/keybindings/catalog.d.ts +1 -1
  119. package/dist/core/keybindings/catalog.js +4 -2
  120. package/dist/core/preview-registry.js +0 -1
  121. package/dist/core/review/ticket-filter.d.ts +1 -1
  122. package/dist/core/review/ticket-filter.js +2 -8
  123. package/dist/core/runtime/broker/read-ops.js +3 -0
  124. package/dist/core/runtime/broker.js +19 -10
  125. package/dist/core/runtime/package-health.js +1 -1
  126. package/dist/core/runtime/persona.js +2 -1
  127. package/dist/core/runtime/tmux-bindings.js +8 -1
  128. package/dist/core/termrender/termrender.d.ts +1 -1
  129. package/dist/core/termrender/termrender.js +2 -2
  130. package/dist/core/termrender/version.d.ts +1 -1
  131. package/dist/core/termrender/version.js +1 -1
  132. package/dist/core/tui/page-host.d.ts +1 -1
  133. package/dist/core/tui/page-host.js +2 -2
  134. package/dist/core/user-settings.d.ts +19 -0
  135. package/dist/core/user-settings.js +22 -0
  136. package/dist/daemon/api/handlers/bash-jobs.d.ts +2 -0
  137. package/dist/daemon/api/handlers/bash-jobs.js +90 -0
  138. package/dist/daemon/api/handlers/human.js +16 -14
  139. package/dist/daemon/api/handlers/inbox.js +311 -227
  140. package/dist/daemon/api/router.d.ts +5 -1
  141. package/dist/daemon/api/router.js +5 -0
  142. package/dist/daemon/api/server.js +2 -0
  143. package/dist/daemon/cron-run.js +23 -10
  144. package/dist/daemon/human/finish.d.ts +8 -3
  145. package/dist/daemon/human/finish.js +35 -15
  146. package/dist/daemon/reconcilers/broker-supervision.js +7 -1
  147. package/dist/daemon/reconcilers/dormant-inbox.js +8 -0
  148. package/dist/daemon/reconcilers/live-obligation.d.ts +2 -0
  149. package/dist/daemon/reconcilers/live-obligation.js +11 -0
  150. package/dist/pages/bundle.css +1 -0
  151. package/dist/pages/bundle.js +1347 -0
  152. package/dist/pages/comments.d.ts +34 -0
  153. package/dist/pages/comments.js +72 -0
  154. package/dist/pages/elements/cards.d.ts +17 -0
  155. package/dist/pages/elements/cards.js +785 -0
  156. package/dist/pages/elements/chart.d.ts +1 -0
  157. package/dist/pages/elements/chart.js +648 -0
  158. package/dist/pages/elements/options.d.ts +21 -0
  159. package/dist/pages/elements/options.js +604 -0
  160. package/dist/pages/elements/pages.d.ts +24 -0
  161. package/dist/pages/elements/pages.js +355 -0
  162. package/dist/pages/elements/slot.d.ts +21 -0
  163. package/dist/pages/elements/slot.js +105 -0
  164. package/dist/pages/elements/table.d.ts +19 -0
  165. package/dist/pages/elements/table.js +906 -0
  166. package/dist/pages/elements/text.d.ts +25 -0
  167. package/dist/pages/elements/text.js +951 -0
  168. package/dist/pages/entry.d.ts +8 -0
  169. package/dist/pages/entry.js +8 -0
  170. package/dist/pages/host.d.ts +132 -0
  171. package/dist/pages/host.js +149 -0
  172. package/dist/pages/register.d.ts +2 -0
  173. package/dist/pages/register.js +3 -0
  174. package/dist/pages/slot-config.d.ts +36 -0
  175. package/dist/pages/slot-config.js +50 -0
  176. package/dist/pages/types.d.ts +98 -0
  177. package/dist/pages/types.js +23 -0
  178. package/dist/pi-extensions/canvas-bash-valve.d.ts +4 -2
  179. package/dist/pi-extensions/canvas-bash-valve.js +25 -7
  180. package/dist/types.d.ts +4 -0
  181. package/dist/types.js +2 -0
  182. package/package.json +8 -8
  183. package/runtime.lock.json +156 -101
  184. package/scripts/install-runtime.mjs +172 -5
  185. package/dist/clients/inbox/deck-adapter.d.ts +0 -29
  186. package/dist/clients/inbox/deck-adapter.js +0 -63
  187. package/dist/core/human/deck-factories.d.ts +0 -8
  188. package/dist/core/human/deck-factories.js +0 -15
  189. package/dist/core/human/deck-schema.d.ts +0 -70
  190. package/dist/core/human/deck-schema.js +0 -92
@@ -67,7 +67,7 @@ export class InputOverlayOwner {
67
67
  return this.openPicker({ type: 'get_tree' }, 'get_tree', 'fork', (data, close) => buildForkPicker(data, this.hooks.send, close));
68
68
  }
69
69
  openSettingsPicker() {
70
- return this.openPicker({ type: 'get_settings' }, 'get_settings', 'settings', (data, close) => buildSettingsPicker(data, this.hooks.send, close, this.hooks.notify));
70
+ return this.openPicker({ type: 'get_settings' }, 'get_settings', 'settings', (data, close) => buildSettingsPicker(data, this.hooks.send, close));
71
71
  }
72
72
  openScopedModelsPicker() {
73
73
  return this.openPicker({ type: 'list_scoped_models' }, 'list_scoped_models', 'scoped-models', (data, close) => buildScopedModelsPicker(data, close, this.hooks.notify));
@@ -9,7 +9,7 @@
9
9
  // actual login flow UI) are pi's own exported components, used verbatim.
10
10
  import { join } from 'node:path';
11
11
  import { execFile } from 'node:child_process';
12
- import { ModelRuntime, OAuthSelectorComponent, LoginDialogComponent, } from '@earendil-works/pi-coding-agent';
12
+ import { CredentialSynchronizationError, ModelRuntime, OAuthSelectorComponent, LoginDialogComponent, } from '@earendil-works/pi-coding-agent';
13
13
  import { deleteAuthCredential, setAuthCredential } from '../../../core/auth-file.js';
14
14
  import { PoolCredentialStore } from '../../../core/pool-credential-store.js';
15
15
  import { dialogAuthInteraction } from '../../../core/auth-interaction.js';
@@ -20,11 +20,26 @@ import { commitManagedLogin, isManagedProvider, readSubscriptionPool, removeMana
20
20
  async function buildLocalAuth(agentDir) {
21
21
  const authPath = join(agentDir, 'auth.json');
22
22
  const modelsPath = join(agentDir, 'models.json');
23
- const runtime = await ModelRuntime.create({
24
- credentials: new PoolCredentialStore(authPath),
25
- modelsPath,
26
- });
27
- return { runtime, authPath };
23
+ const store = new PoolCredentialStore(authPath);
24
+ let mutationBoundary;
25
+ const credentials = {
26
+ read: (providerId) => store.read(providerId),
27
+ list: () => store.list(),
28
+ modify: (providerId, fn) => {
29
+ const enter = mutationBoundary;
30
+ mutationBoundary = undefined;
31
+ if (enter !== undefined && !enter())
32
+ return Promise.reject(new Error('Login cancelled'));
33
+ return store.modify(providerId, fn);
34
+ },
35
+ delete: (providerId) => store.delete(providerId),
36
+ };
37
+ const runtime = await ModelRuntime.create({ credentials, modelsPath });
38
+ return {
39
+ runtime,
40
+ authPath,
41
+ beforeNextCredentialMutation: (callback) => { mutationBoundary = callback; },
42
+ };
28
43
  }
29
44
  /** Assemble the AuthSelectorProvider list for the OAuth selector: every composed
30
45
  * provider, OAuth ones first, each carrying its current auth status (which the
@@ -57,7 +72,7 @@ function openBrowser(url) {
57
72
  * the controls the overlay host hands out. So this resolves the runtime first and
58
73
  * returns the sync picker factory. */
59
74
  export async function buildLoginPicker(tui, agentDir, onAuthReloaded, notify) {
60
- const { runtime, authPath } = await buildLocalAuth(agentDir);
75
+ const { runtime, authPath, beforeNextCredentialMutation } = await buildLocalAuth(agentDir);
61
76
  const providers = await buildProviderList(runtime);
62
77
  return ({ close, replace }) => {
63
78
  const onSelect = (providerId) => {
@@ -115,6 +130,15 @@ export async function buildLoginPicker(tui, agentDir, onAuthReloaded, notify) {
115
130
  isActive: () => !settled && !dialog.signal.aborted,
116
131
  });
117
132
  const fail = (err) => {
133
+ // ModelRuntime persists the credential before synchronizing its provider
134
+ // state. A synchronization failure is therefore a successful login with
135
+ // a refresh warning, not a failed login.
136
+ if (err instanceof CredentialSynchronizationError) {
137
+ notify(`Logged in to ${provider.name}; provider refresh failed: ${err.message}`);
138
+ onAuthReloaded();
139
+ finish();
140
+ return;
141
+ }
118
142
  // An Esc-cancel aborts the flow; the dialog's onComplete already notified +
119
143
  // finished, so only report a genuine error here.
120
144
  const error = err;
@@ -175,6 +199,7 @@ export async function buildLoginPicker(tui, agentDir, onAuthReloaded, notify) {
175
199
  }
176
200
  // Non-managed OAuth: `runtime.login` persists through crouter's own credential
177
201
  // store, so auth.json lands exactly where the broker reads it.
202
+ beforeNextCredentialMutation(beginCommit);
178
203
  runtime
179
204
  .login(providerId, 'oauth', interaction)
180
205
  .then(() => {
@@ -184,7 +209,8 @@ export async function buildLoginPicker(tui, agentDir, onAuthReloaded, notify) {
184
209
  onAuthReloaded();
185
210
  finish();
186
211
  })
187
- .catch(fail);
212
+ .catch(fail)
213
+ .finally(() => beforeNextCredentialMutation(undefined));
188
214
  }
189
215
  else {
190
216
  // API-key provider: prompt for the key and persist it locally.
@@ -42,14 +42,11 @@ export declare function buildTreePicker(tui: TUI, data: GetTreeData, send: Send,
42
42
  * `get_tree.forkPoints`). Select → `fork`. The outer component has no
43
43
  * `handleInput`; the inner `getMessageList()` does (focus target). */
44
44
  export declare function buildForkPicker(data: GetTreeData, send: Send, close: Close): Picker;
45
- /** `/settings` — the real settings menu (the wire `settings` IS a SettingsConfig
46
- * superset). Only the contract-enumerated mutations are wired: thinking level →
47
- * `set_thinking_level`, auto-compact → `set_auto_compaction`. Every other toggle
48
- * has no command frame (out of scope), so its callback notifies rather than
49
- * silently lying that the change took. The theme submenu is viewer-local (CTO).
50
- * The outer component has no `handleInput`; `getSettingsList()` is the focus
51
- * target. */
52
- export declare function buildSettingsPicker(data: GetSettingsData, send: Send, close: Close, notify: Notify): Picker;
45
+ /** `/settings` exposes only the two settings attach can actually mutate over
46
+ * view.sock. Upstream's selector has no item-omission API and always includes its
47
+ * fullscreen controls, which are not real attach state because attach is fixed to
48
+ * TuiMainScreen's normal buffer. */
49
+ export declare function buildSettingsPicker(data: GetSettingsData, send: Send, close: Close): Picker;
53
50
  /** `/scoped-models` — READ-ONLY via a pi-tui SelectList. CONTRACT GAP: pi (through
54
51
  * 0.79.1) does not re-export `ScopedModelsSelectorComponent`, and the contract
55
52
  * exposes no command frame for its enable/disable/persist mutations, so a
@@ -26,8 +26,8 @@
26
26
  // The duck-typed runtime adapter relies on the component's current 4-method
27
27
  // ModelRuntime surface — a future pi adding a runtime call there would surface at
28
28
  // runtime (caught by live verification).
29
- import { SelectList, } from '@earendil-works/pi-tui';
30
- import { getSelectListTheme, ModelSelectorComponent, SessionSelectorComponent, SettingsSelectorComponent, TreeSelectorComponent, UserMessageSelectorComponent, SettingsManager, } from '@earendil-works/pi-coding-agent';
29
+ import { Container, SelectList, SettingsList, } from '@earendil-works/pi-tui';
30
+ import { DynamicBorder, getSelectListTheme, getSettingsListTheme, ModelSelectorComponent, SessionSelectorComponent, TreeSelectorComponent, UserMessageSelectorComponent, SettingsManager, } from '@earendil-works/pi-coding-agent';
31
31
  /** A minimal `ModelRuntime` for `ModelSelectorComponent`: the component calls
32
32
  * only `getAvailableSnapshot()`, `getModel()`, `getError()`, and `refresh()`
33
33
  * (verified against pi `model-selector.js`). We satisfy exactly those from the
@@ -102,47 +102,41 @@ export function buildForkPicker(data, send, close) {
102
102
  }, () => close());
103
103
  return { component, focus: component.getMessageList() };
104
104
  }
105
- /** `/settings` — the real settings menu (the wire `settings` IS a SettingsConfig
106
- * superset). Only the contract-enumerated mutations are wired: thinking level →
107
- * `set_thinking_level`, auto-compact → `set_auto_compaction`. Every other toggle
108
- * has no command frame (out of scope), so its callback notifies rather than
109
- * silently lying that the change took. The theme submenu is viewer-local (CTO).
110
- * The outer component has no `handleInput`; `getSettingsList()` is the focus
111
- * target. */
112
- export function buildSettingsPicker(data, send, close, notify) {
113
- const out = () => notify('Only thinking level + auto-compaction are adjustable over view.sock');
114
- const callbacks = {
115
- onThinkingLevelChange: (level) => send({ type: 'set_thinking_level', level }),
116
- onAutoCompactChange: (enabled) => send({ type: 'set_auto_compaction', enabled }),
117
- onCancel: () => close(),
118
- onShowImagesChange: out,
119
- onImageWidthCellsChange: out,
120
- onAutoResizeImagesChange: out,
121
- onBlockImagesChange: out,
122
- onEnableSkillCommandsChange: out,
123
- onSteeringModeChange: out,
124
- onFollowUpModeChange: out,
125
- onTransportChange: out,
126
- onHttpIdleTimeoutMsChange: out,
127
- onThemeChange: out,
128
- onHideThinkingBlockChange: out,
129
- onCollapseChangelogChange: out,
130
- onEnableInstallTelemetryChange: out,
131
- onDoubleEscapeActionChange: out,
132
- onTreeFilterModeChange: out,
133
- onShowHardwareCursorChange: out,
134
- onEditorPaddingXChange: out,
135
- onAutocompleteMaxVisibleChange: out,
136
- onQuietStartupChange: out,
137
- onDefaultProjectTrustChange: out,
138
- onClearOnShrinkChange: out,
139
- onShowTerminalProgressChange: out,
140
- onWarningsChange: out,
141
- onShowCacheMissNoticesChange: out,
142
- onOutputPadChange: out,
143
- };
144
- const component = new SettingsSelectorComponent(data.settings, callbacks);
145
- return { component, focus: component.getSettingsList() };
105
+ /** `/settings` exposes only the two settings attach can actually mutate over
106
+ * view.sock. Upstream's selector has no item-omission API and always includes its
107
+ * fullscreen controls, which are not real attach state because attach is fixed to
108
+ * TuiMainScreen's normal buffer. */
109
+ export function buildSettingsPicker(data, send, close) {
110
+ const items = [
111
+ {
112
+ id: 'autocompact',
113
+ label: 'Auto-compact',
114
+ description: 'Automatically compact context when it gets too large',
115
+ currentValue: data.settings.autoCompact ? 'true' : 'false',
116
+ values: ['true', 'false'],
117
+ },
118
+ {
119
+ id: 'thinking',
120
+ label: 'Thinking level',
121
+ description: 'Reasoning depth for thinking-capable models',
122
+ currentValue: data.settings.thinkingLevel,
123
+ values: data.settings.availableThinkingLevels,
124
+ },
125
+ ];
126
+ const list = new SettingsList(items, items.length, getSettingsListTheme(), (id, value) => {
127
+ if (id === 'autocompact')
128
+ send({ type: 'set_auto_compaction', enabled: value === 'true' });
129
+ if (id === 'thinking')
130
+ send({
131
+ type: 'set_thinking_level',
132
+ level: value,
133
+ });
134
+ }, close, { enableSearch: false });
135
+ const component = new Container();
136
+ component.addChild(new DynamicBorder());
137
+ component.addChild(list);
138
+ component.addChild(new DynamicBorder());
139
+ return { component, focus: list };
146
140
  }
147
141
  /** `/scoped-models` — READ-ONLY via a pi-tui SelectList. CONTRACT GAP: pi (through
148
142
  * 0.79.1) does not re-export `ScopedModelsSelectorComponent`, and the contract