@pellux/goodvibes-agent 1.4.4 → 1.5.1

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 (230) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +52 -7
  3. package/dist/package/main.js +7491 -12253
  4. package/docs/README.md +2 -2
  5. package/docs/channels-remote-and-api.md +1 -1
  6. package/docs/getting-started.md +2 -2
  7. package/docs/release-and-publishing.md +1 -1
  8. package/docs/tools-and-commands.md +5 -5
  9. package/package.json +4 -2
  10. package/release/live-verification/live-verification.json +13 -13
  11. package/release/live-verification/live-verification.md +15 -15
  12. package/release/performance-snapshot.json +2 -2
  13. package/release/release-notes.md +5 -7
  14. package/release/release-readiness.json +6 -6
  15. package/src/agent/behavior-discovery-summary.ts +4 -18
  16. package/src/agent/calendar-registry.ts +322 -0
  17. package/src/agent/competitive-feature-inventory.ts +268 -130
  18. package/src/agent/document-registry.ts +5 -1
  19. package/src/agent/email/email-service.ts +350 -0
  20. package/src/agent/email/imap-client.ts +596 -0
  21. package/src/agent/email/smtp-client.ts +453 -0
  22. package/src/agent/ics-calendar.ts +662 -0
  23. package/src/agent/ics-timezone.ts +172 -0
  24. package/src/agent/markdown-frontmatter.ts +31 -0
  25. package/src/agent/memory-safety.ts +1 -1
  26. package/src/agent/note-registry.ts +3 -9
  27. package/src/agent/persona-discovery.ts +3 -15
  28. package/src/agent/persona-registry.ts +1 -10
  29. package/src/agent/research-source-registry.ts +5 -1
  30. package/src/agent/routine-discovery.ts +3 -15
  31. package/src/agent/runtime-profile.ts +3 -0
  32. package/src/agent/skill-discovery.ts +3 -15
  33. package/src/agent/skill-draft-proposer.ts +203 -0
  34. package/src/agent/skill-draft-runner.ts +201 -0
  35. package/src/agent/skill-registry.ts +36 -1
  36. package/src/agent/skill-standard.ts +99 -0
  37. package/src/agent/vibe-file.ts +7 -22
  38. package/src/cli/completion.ts +1 -1
  39. package/src/cli/config-overrides.ts +10 -1
  40. package/src/cli/redaction.ts +17 -5
  41. package/src/config/provider-model.ts +2 -1
  42. package/src/config/secret-config.ts +13 -6
  43. package/src/core/activity-feed.ts +97 -0
  44. package/src/core/away-digest.ts +161 -0
  45. package/src/core/conversation-rendering.ts +7 -3
  46. package/src/core/conversation.ts +22 -15
  47. package/src/core/hardware-profile.ts +362 -0
  48. package/src/core/last-seen-store.ts +78 -0
  49. package/src/core/plain-language.ts +52 -0
  50. package/src/core/setup-incomplete-hint.ts +90 -0
  51. package/src/core/system-message-router.ts +38 -87
  52. package/src/input/agent-workspace-basic-command-editor-submission.ts +60 -220
  53. package/src/input/agent-workspace-basic-command-editors.ts +39 -141
  54. package/src/input/agent-workspace-categories.ts +40 -125
  55. package/src/input/agent-workspace-command-editor.ts +4 -0
  56. package/src/input/agent-workspace-host-category.ts +0 -5
  57. package/src/input/agent-workspace-local-editor-submission.ts +3 -1
  58. package/src/input/agent-workspace-navigation.ts +10 -3
  59. package/src/input/agent-workspace-onboarding-actions.ts +132 -0
  60. package/src/input/agent-workspace-onboarding-categories.ts +29 -26
  61. package/src/input/agent-workspace-onboarding-finish.ts +11 -4
  62. package/src/input/agent-workspace-onboarding-state.ts +111 -0
  63. package/src/input/agent-workspace-profile-editor-submission.ts +260 -0
  64. package/src/input/agent-workspace-profile-editors.ts +155 -0
  65. package/src/input/agent-workspace-subscription-editor.ts +7 -0
  66. package/src/input/agent-workspace-types.ts +5 -1
  67. package/src/input/agent-workspace.ts +65 -39
  68. package/src/input/command-registry.ts +18 -5
  69. package/src/input/commands/agent-runtime-profile-runtime.ts +2 -1
  70. package/src/input/commands/agent-skills-runtime.ts +60 -3
  71. package/src/input/commands/calendar-runtime.ts +209 -0
  72. package/src/input/commands/channels-runtime.ts +1 -0
  73. package/src/input/commands/command-error.ts +9 -0
  74. package/src/input/commands/compat-runtime.ts +1 -0
  75. package/src/input/commands/config.ts +1 -0
  76. package/src/input/commands/conversation-runtime.ts +1 -1
  77. package/src/input/commands/delegation-runtime.ts +5 -6
  78. package/src/input/commands/email-runtime.ts +387 -0
  79. package/src/input/commands/experience-runtime.ts +17 -4
  80. package/src/input/commands/guidance-runtime.ts +1 -1
  81. package/src/input/commands/health-runtime.ts +6 -1
  82. package/src/input/commands/knowledge-format.ts +73 -0
  83. package/src/input/commands/knowledge.ts +9 -74
  84. package/src/input/commands/local-provider-runtime.ts +2 -1
  85. package/src/input/commands/local-runtime.ts +10 -4
  86. package/src/input/commands/mcp-runtime.ts +7 -0
  87. package/src/input/commands/notify-runtime.ts +17 -1
  88. package/src/input/commands/onboarding-runtime.ts +1 -0
  89. package/src/input/commands/operator-actions-runtime.ts +1 -0
  90. package/src/input/commands/operator-runtime.ts +3 -0
  91. package/src/input/commands/personas-runtime.ts +1 -0
  92. package/src/input/commands/platform-access-runtime.ts +40 -17
  93. package/src/input/commands/product-runtime.ts +6 -1
  94. package/src/input/commands/provider-accounts-runtime.ts +3 -2
  95. package/src/input/commands/qrcode-runtime.ts +1 -0
  96. package/src/input/commands/routines-runtime.ts +1 -0
  97. package/src/input/commands/runtime-services.ts +0 -13
  98. package/src/input/commands/security-runtime.ts +1 -0
  99. package/src/input/commands/session-content.ts +1 -0
  100. package/src/input/commands/shell-core.ts +5 -2
  101. package/src/input/commands/subscription-runtime.ts +33 -9
  102. package/src/input/commands/support-bundle-runtime.ts +8 -1
  103. package/src/input/commands/tasks-runtime.ts +1 -0
  104. package/src/input/commands/tts-runtime.ts +1 -0
  105. package/src/input/commands/vibe-runtime.ts +1 -0
  106. package/src/input/commands.ts +4 -0
  107. package/src/input/feed-context-factory.ts +3 -12
  108. package/src/input/handler-command-route.ts +7 -60
  109. package/src/input/handler-feed-routes.ts +0 -194
  110. package/src/input/handler-feed.ts +2 -54
  111. package/src/input/handler-interactions.ts +0 -2
  112. package/src/input/handler-modal-stack.ts +0 -9
  113. package/src/input/handler-picker-routes.ts +24 -1
  114. package/src/input/handler-shortcuts.ts +11 -40
  115. package/src/input/handler-ui-state.ts +13 -0
  116. package/src/input/handler.ts +8 -35
  117. package/src/input/keybindings.ts +40 -17
  118. package/src/input/model-picker-local-fit.ts +130 -0
  119. package/src/input/shell-passthrough.ts +58 -0
  120. package/src/input/submission-router.ts +0 -5
  121. package/src/main.ts +129 -90
  122. package/src/renderer/activity-sidebar.ts +186 -0
  123. package/src/renderer/agent-workspace-context-lines.ts +5 -48
  124. package/src/renderer/agent-workspace-style.ts +1 -1
  125. package/src/renderer/agent-workspace.ts +14 -2
  126. package/src/renderer/compositor.ts +37 -125
  127. package/src/renderer/conversation-overlays.ts +3 -3
  128. package/src/renderer/help-overlay.ts +7 -5
  129. package/src/renderer/model-workspace.ts +101 -86
  130. package/src/{panels → renderer}/polish.ts +3 -3
  131. package/src/renderer/shell-surface.ts +4 -5
  132. package/src/renderer/status-token.ts +31 -11
  133. package/src/renderer/tab-strip.ts +1 -1
  134. package/src/renderer/tool-call.ts +7 -8
  135. package/src/renderer/tool-labels.ts +92 -0
  136. package/src/renderer/ui-factory.ts +48 -96
  137. package/src/runtime/bootstrap-command-context.ts +0 -5
  138. package/src/runtime/bootstrap-command-parts.ts +6 -15
  139. package/src/runtime/bootstrap-core.ts +34 -13
  140. package/src/runtime/bootstrap-hook-bridge.ts +3 -1
  141. package/src/runtime/bootstrap-shell.ts +3 -50
  142. package/src/runtime/bootstrap.ts +3 -4
  143. package/src/runtime/context.ts +1 -1
  144. package/src/runtime/diagnostics/panels/index.ts +0 -1
  145. package/src/runtime/diagnostics/panels/policy.ts +1 -1
  146. package/src/runtime/execution-ledger.ts +16 -1
  147. package/src/runtime/index.ts +6 -1
  148. package/src/runtime/onboarding/index.ts +1 -0
  149. package/src/runtime/onboarding/onboarding-state.ts +200 -0
  150. package/src/{panels → runtime}/provider-account-snapshot.ts +5 -2
  151. package/src/runtime/services.ts +16 -4
  152. package/src/runtime/terminal-output-guard.ts +7 -0
  153. package/src/runtime/tool-permission-safety.ts +1 -1
  154. package/src/runtime/ui/model-picker/data-provider.ts +1 -1
  155. package/src/runtime/ui/model-picker/health-enrichment.ts +2 -2
  156. package/src/runtime/ui/model-picker/types.ts +2 -2
  157. package/src/runtime/ui/provider-health/data-provider.ts +3 -3
  158. package/src/runtime/ui/provider-health/types.ts +2 -2
  159. package/src/runtime/ui-services.ts +0 -2
  160. package/src/shell/agent-workspace-fullscreen.ts +0 -1
  161. package/src/shell/autonomy-surfacing.ts +272 -0
  162. package/src/shell/session-continuity-hints.ts +0 -6
  163. package/src/shell/startup-wiring.ts +221 -0
  164. package/src/shell/ui-openers.ts +18 -29
  165. package/src/tools/agent-context-policy.ts +1 -1
  166. package/src/tools/agent-harness-background-processes.ts +4 -4
  167. package/src/tools/agent-harness-browser-cockpit-route.ts +3 -3
  168. package/src/tools/agent-harness-command-runner.ts +6 -1
  169. package/src/tools/agent-harness-document-ops.ts +26 -53
  170. package/src/tools/agent-harness-execution-history.ts +1 -13
  171. package/src/tools/agent-harness-execution-posture.ts +0 -15
  172. package/src/tools/agent-harness-keybinding-metadata.ts +28 -29
  173. package/src/tools/agent-harness-local-model-cookbook.ts +24 -1
  174. package/src/tools/agent-harness-metadata.ts +16 -0
  175. package/src/tools/agent-harness-mode-catalog.ts +2 -9
  176. package/src/tools/agent-harness-provider-account-metadata.ts +2 -2
  177. package/src/tools/agent-harness-setup-posture-utils.ts +1 -1
  178. package/src/tools/agent-harness-tool-schema.ts +13 -14
  179. package/src/tools/agent-harness-tool.ts +27 -23
  180. package/src/tools/agent-harness-ui-surface-metadata.ts +10 -20
  181. package/src/tools/agent-harness-workspace-action-runner.ts +3 -4
  182. package/src/tools/agent-workspace-tool.ts +2 -33
  183. package/src/utils/terminal-width.ts +9 -3
  184. package/src/version.ts +1 -1
  185. package/src/input/agent-workspace-panel-route.ts +0 -44
  186. package/src/input/panel-integration-actions.ts +0 -26
  187. package/src/panels/approval-panel.ts +0 -149
  188. package/src/panels/automation-control-panel.ts +0 -212
  189. package/src/panels/base-panel.ts +0 -254
  190. package/src/panels/builtin/agent.ts +0 -58
  191. package/src/panels/builtin/knowledge.ts +0 -26
  192. package/src/panels/builtin/operations.ts +0 -121
  193. package/src/panels/builtin/session.ts +0 -138
  194. package/src/panels/builtin/shared.ts +0 -275
  195. package/src/panels/builtin/usage.ts +0 -21
  196. package/src/panels/builtin-panels.ts +0 -23
  197. package/src/panels/confirm-state.ts +0 -61
  198. package/src/panels/context-visualizer-panel.ts +0 -204
  199. package/src/panels/cost-tracker-panel.ts +0 -444
  200. package/src/panels/docs-panel.ts +0 -285
  201. package/src/panels/index.ts +0 -25
  202. package/src/panels/knowledge-panel.ts +0 -417
  203. package/src/panels/memory-panel.ts +0 -226
  204. package/src/panels/panel-list-panel.ts +0 -464
  205. package/src/panels/panel-manager.ts +0 -570
  206. package/src/panels/provider-accounts-panel.ts +0 -233
  207. package/src/panels/provider-health-domains.ts +0 -208
  208. package/src/panels/provider-health-panel.ts +0 -720
  209. package/src/panels/provider-health-tracker.ts +0 -115
  210. package/src/panels/provider-stats-panel.ts +0 -366
  211. package/src/panels/qr-panel.ts +0 -207
  212. package/src/panels/schedule-panel.ts +0 -321
  213. package/src/panels/scrollable-list-panel.ts +0 -491
  214. package/src/panels/search-focus.ts +0 -32
  215. package/src/panels/security-panel.ts +0 -295
  216. package/src/panels/session-browser-panel.ts +0 -395
  217. package/src/panels/session-maintenance.ts +0 -125
  218. package/src/panels/subscription-panel.ts +0 -263
  219. package/src/panels/system-messages-panel.ts +0 -230
  220. package/src/panels/tasks-panel.ts +0 -344
  221. package/src/panels/thinking-panel.ts +0 -304
  222. package/src/panels/token-budget-panel.ts +0 -475
  223. package/src/panels/tool-inspector-panel.ts +0 -436
  224. package/src/panels/types.ts +0 -54
  225. package/src/renderer/panel-composite.ts +0 -158
  226. package/src/renderer/panel-tab-bar.ts +0 -69
  227. package/src/renderer/panel-workspace-bar.ts +0 -42
  228. package/src/runtime/diagnostics/panels/panel-resources.ts +0 -118
  229. package/src/tools/agent-harness-panel-metadata.ts +0 -211
  230. /package/src/runtime/perf/{panel-health-monitor.ts → component-health.ts} +0 -0
@@ -11,6 +11,16 @@
11
11
  * }
12
12
  *
13
13
  * Each value is a KeyCombo or an array of KeyCombos for multi-binding support.
14
+ *
15
+ * Action ID backward-compatibility aliases (accepted in keybindings.json):
16
+ * "panel-picker" → "workspace-picker"
17
+ * "panel-close" → "workspace-close"
18
+ * "panel-close-all" → "workspace-close-all"
19
+ * "panel-tab-next" → "workspace-tab-next"
20
+ * "panel-tab-prev" → "workspace-tab-prev"
21
+ *
22
+ * These aliases are accepted when loading user-provided keybindings.json
23
+ * override files so existing user configs continue to work without changes.
14
24
  */
15
25
 
16
26
  import { readFileSync, existsSync } from 'node:fs';
@@ -34,11 +44,12 @@ export type KeyAction =
34
44
  | 'copy-selection'
35
45
  | 'clear-cancel'
36
46
  | 'screen-clear'
37
- | 'panel-picker'
38
- | 'panel-close'
39
- | 'panel-close-all'
40
- | 'panel-tab-next'
41
- | 'panel-tab-prev'
47
+ | 'workspace-picker'
48
+ | 'workspace-close'
49
+ | 'workspace-close-all'
50
+ | 'workspace-tab-next'
51
+ | 'workspace-tab-prev'
52
+ | 'sidebar-toggle'
42
53
  | 'history-search'
43
54
  | 'search'
44
55
  | 'block-copy'
@@ -59,11 +70,12 @@ export const ACTION_DESCRIPTIONS: Record<KeyAction, string> = {
59
70
  'copy-selection': 'Copy selected text to clipboard',
60
71
  'clear-cancel': 'Clear input / cancel generation / exit (double)',
61
72
  'screen-clear': 'Repaint the screen',
62
- 'panel-picker': 'Open the Agent operator workspace',
63
- 'panel-close': 'Dismiss Agent workspace',
64
- 'panel-close-all': 'Dismiss Agent workspace focus',
65
- 'panel-tab-next': 'Cycle Agent workspace category forward',
66
- 'panel-tab-prev': 'Cycle Agent workspace category backward',
73
+ 'workspace-picker': 'Open the Agent operator workspace',
74
+ 'workspace-close': 'Close the Agent workspace',
75
+ 'workspace-close-all': 'Close the Agent workspace (alias: also bound to Ctrl+Shift+X)',
76
+ 'workspace-tab-next': 'Cycle Agent workspace category forward',
77
+ 'workspace-tab-prev': 'Cycle Agent workspace category backward',
78
+ 'sidebar-toggle': 'Show or hide the activity sidebar',
67
79
  'history-search': 'Reverse input history search',
68
80
  'search': 'Toggle conversation search',
69
81
  'block-copy': 'Copy nearest block to clipboard',
@@ -98,11 +110,12 @@ export const DEFAULT_KEYBINDINGS: Record<KeyAction, KeyCombo[]> = {
98
110
  'copy-selection': [{ key: 'c', ctrl: true, shift: true }],
99
111
  'clear-cancel': [{ key: 'c', ctrl: true }],
100
112
  'screen-clear': [{ key: 'l', ctrl: true }],
101
- 'panel-picker': [{ key: 'p', ctrl: true }],
102
- 'panel-close': [{ key: 'x', ctrl: true }],
103
- 'panel-close-all': [{ key: 'x', ctrl: true, shift: true }],
104
- 'panel-tab-next': [{ key: ']', ctrl: true }],
105
- 'panel-tab-prev': [{ key: '[', ctrl: true }],
113
+ 'workspace-picker': [{ key: 'p', ctrl: true }],
114
+ 'workspace-close': [{ key: 'x', ctrl: true }],
115
+ 'workspace-close-all': [{ key: 'x', ctrl: true, shift: true }],
116
+ 'workspace-tab-next': [{ key: ']', ctrl: true }],
117
+ 'workspace-tab-prev': [{ key: '[', ctrl: true }],
118
+ 'sidebar-toggle': [{ key: 'o', ctrl: true }],
106
119
  'history-search': [{ key: 'r', ctrl: true }],
107
120
  'search': [{ key: 'f', ctrl: true }],
108
121
  'block-copy': [{ key: 'y', ctrl: true }],
@@ -116,7 +129,7 @@ export const DEFAULT_KEYBINDINGS: Record<KeyAction, KeyCombo[]> = {
116
129
  'undo': [{ key: 'z', ctrl: true }],
117
130
  'redo': [{ key: 'z', ctrl: true, shift: true }],
118
131
  'paste': [{ key: 'v', ctrl: true }],
119
- 'replay-panel': [{ key: 'r', ctrl: true, shift: true }],
132
+ 'replay-panel': [], // intentionally unbound until replay-panel is implemented
120
133
  };
121
134
 
122
135
  /** Resolved overrides type: each key can be a single combo or array. */
@@ -185,7 +198,17 @@ export class KeybindingsManager {
185
198
  // Reset to defaults before applying overrides
186
199
  this.bindings = this.cloneDefaults();
187
200
 
188
- for (const [action, combo] of Object.entries(parsed)) {
201
+ // Backward-compatibility aliases: map old panel-* action ids to workspace-* equivalents.
202
+ const ALIASES: Readonly<Record<string, KeyAction>> = {
203
+ 'panel-picker': 'workspace-picker',
204
+ 'panel-close': 'workspace-close',
205
+ 'panel-close-all': 'workspace-close-all',
206
+ 'panel-tab-next': 'workspace-tab-next',
207
+ 'panel-tab-prev': 'workspace-tab-prev',
208
+ };
209
+
210
+ for (const [rawAction, combo] of Object.entries(parsed)) {
211
+ const action: string = Object.hasOwn(ALIASES, rawAction) ? ALIASES[rawAction as keyof typeof ALIASES] : rawAction;
189
212
  if (!validActions.has(action as KeyAction)) {
190
213
  logger.debug('keybindings: unknown action, skipping', { action });
191
214
  continue;
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Local-fit recommendation builder.
3
+ *
4
+ * When no provider credentials are configured, the model picker would show an
5
+ * empty list. This module builds a small set of synthetic model entries that
6
+ * represent common local model sizes so the picker opens with useful content.
7
+ *
8
+ * Rules:
9
+ * - These entries are purely informational — they are NOT installed models.
10
+ * - They must never appear when any real provider is configured.
11
+ * - Selecting one routes through the local-provider install/confirm path,
12
+ * never a silent model switch.
13
+ * - The provider sentinel 'local' is distinct from 'ollama', 'lm-studio',
14
+ * etc. so cloud-provider fit checks are never triggered.
15
+ */
16
+
17
+ import type { ModelDefinition } from '@pellux/goodvibes-sdk/platform/providers';
18
+ import {
19
+ estimateModelBytes,
20
+ fitAssessment,
21
+ fitVerdictLabel,
22
+ readHardwareProfileSync,
23
+ } from '../core/hardware-profile.ts';
24
+ import type { HardwareProfile } from '../core/hardware-profile.ts';
25
+
26
+ /**
27
+ * Sentinel provider ID used on synthetic local recommendation entries.
28
+ * Must not collide with any real provider (ollama, lm-studio, etc.).
29
+ */
30
+ export const LOCAL_REC_PROVIDER = 'local';
31
+
32
+ /**
33
+ * Representative local model sizes to recommend.
34
+ * Each entry: { id, displayName, params, sizeLabel }
35
+ */
36
+ const LOCAL_REC_SIZES = [
37
+ { id: 'local:3b', displayName: '3B model (small, fast)', params: 3_000_000_000, sizeLabel: '3B' },
38
+ { id: 'local:7b', displayName: '7B model (balanced)', params: 7_000_000_000, sizeLabel: '7B' },
39
+ { id: 'local:13b', displayName: '13B model (more capable)', params: 13_000_000_000, sizeLabel: '13B' },
40
+ ] as const;
41
+
42
+ /**
43
+ * Sentinel id used on the synthetic "Sign in to a provider" row that is
44
+ * appended to the local-only list when no credentials are configured.
45
+ */
46
+ export const SIGN_IN_ROW_ID = 'local:sign-in';
47
+
48
+ /**
49
+ * Return true when a model entry is the synthetic sign-in affordance row.
50
+ * This row must never be committed as an active model.
51
+ */
52
+ export function isProviderSignInRow(model: ModelDefinition): boolean {
53
+ return model.id === SIGN_IN_ROW_ID && model.provider === LOCAL_REC_PROVIDER;
54
+ }
55
+
56
+ /**
57
+ * Return true when a model entry is a synthetic local fit recommendation
58
+ * (i.e. not a real installed model).
59
+ */
60
+ export function isLocalFitRecommendation(model: ModelDefinition): boolean {
61
+ return (
62
+ model.provider === LOCAL_REC_PROVIDER &&
63
+ (model.description ?? '').includes('not yet installed')
64
+ );
65
+ }
66
+
67
+ /**
68
+ * Build the synthetic "Sign in to a provider" row for the local-only list.
69
+ * Selecting this row routes to the provider picker; it must never be committed
70
+ * as an active model.
71
+ */
72
+ export function buildSignInRow(): ModelDefinition {
73
+ return {
74
+ id: SIGN_IN_ROW_ID,
75
+ provider: LOCAL_REC_PROVIDER,
76
+ registryKey: SIGN_IN_ROW_ID,
77
+ displayName: 'Sign in to a provider →',
78
+ description: 'Open the provider sign-in flow to connect a cloud or local provider.',
79
+ capabilities: {
80
+ toolCalling: false,
81
+ codeEditing: false,
82
+ reasoning: false,
83
+ multimodal: false,
84
+ },
85
+ contextWindow: 0,
86
+ selectable: true,
87
+ tier: 'free',
88
+ };
89
+ }
90
+
91
+ /**
92
+ * Build synthetic local recommendation entries annotated with hardware fit
93
+ * labels for the current machine.
94
+ *
95
+ * Pass a `profile` override for deterministic tests; omit to use the
96
+ * process-level hardware probe (`readHardwareProfileSync`).
97
+ */
98
+ export function buildLocalFitRecommendations(
99
+ profileOverride?: HardwareProfile,
100
+ ): ModelDefinition[] {
101
+ const profile = profileOverride ?? readHardwareProfileSync();
102
+
103
+ return LOCAL_REC_SIZES.map((spec) => {
104
+ const sizeBytes = estimateModelBytes(spec.params);
105
+ const verdict = fitAssessment(sizeBytes, profile);
106
+ const fitHint = fitVerdictLabel(verdict, spec.sizeLabel);
107
+ // Plain-language detail: never imply the model is ready to use.
108
+ const detail = fitHint
109
+ ? `recommended for your hardware — not yet installed (${fitHint})`
110
+ : 'recommended for your hardware — not yet installed';
111
+
112
+ const model: ModelDefinition = {
113
+ id: spec.id,
114
+ provider: LOCAL_REC_PROVIDER,
115
+ registryKey: spec.id,
116
+ displayName: spec.displayName,
117
+ description: detail,
118
+ capabilities: {
119
+ toolCalling: true,
120
+ codeEditing: false,
121
+ reasoning: false,
122
+ multimodal: false,
123
+ },
124
+ contextWindow: 8192,
125
+ selectable: true,
126
+ tier: 'free',
127
+ };
128
+ return model;
129
+ });
130
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * ShellPassthrough — runs user-typed `!<command>` shell escapes.
3
+ *
4
+ * The composer routes a leading `!` to "shell" mode; this runs the command
5
+ * directly (a user-initiated terminal escape, not an agent tool call), shows
6
+ * its output, and buffers a context block that is prepended to the user's next
7
+ * real message — making the result visible to the model on the next turn
8
+ * without triggering a turn of its own.
9
+ *
10
+ * A buffer is used rather than appending a conversation message because the
11
+ * SDK drops `system` messages from the LLM view and does not merge consecutive
12
+ * `user` messages (which would trip a consecutive-user-message API error).
13
+ */
14
+
15
+ const MAX_SHELL_OUTPUT = 16_000;
16
+
17
+ export const SHELL_USAGE_HINT =
18
+ '[Shell] Usage: !<command> — runs a shell command; its output is shown and added as context for your next message.';
19
+
20
+ export interface ShellRunResult {
21
+ /** Formatted output for the conversation/activity feed. */
22
+ readonly display: string;
23
+ /** Context block buffered for the user's next turn. */
24
+ readonly context: string;
25
+ }
26
+
27
+ export class ShellPassthrough {
28
+ private pending: string[] = [];
29
+
30
+ /** Run `command` in `cwd`, returning display + model-context renderings. */
31
+ async run(command: string, cwd: string): Promise<ShellRunResult> {
32
+ const proc = Bun.spawn(['bash', '-c', command], { cwd, stdout: 'pipe', stderr: 'pipe' });
33
+ const [out, err] = await Promise.all([
34
+ new Response(proc.stdout).text(),
35
+ new Response(proc.stderr).text(),
36
+ ]);
37
+ const exitCode = await proc.exited;
38
+ const combined = [out, err].filter((s) => s.trim().length > 0).join('\n').trimEnd();
39
+ const truncated = combined.length > MAX_SHELL_OUTPUT
40
+ ? `${combined.slice(0, MAX_SHELL_OUTPUT)}\n… [truncated ${combined.length - MAX_SHELL_OUTPUT} chars]`
41
+ : combined;
42
+ const body = truncated.length > 0 ? truncated : '(no output)';
43
+ const result: ShellRunResult = {
44
+ display: `[Shell] ${body}\n(exit ${exitCode})`,
45
+ context: `The user ran a shell command via the \`!\` prefix:\n$ ${command}\n--- output (exit ${exitCode}) ---\n${body}`,
46
+ };
47
+ this.pending.push(result.context);
48
+ return result;
49
+ }
50
+
51
+ /** Prepend (and clear) any buffered shell context onto an outgoing message. */
52
+ consumeContext(text: string): string {
53
+ if (this.pending.length === 0) return text;
54
+ const context = this.pending.join('\n\n');
55
+ this.pending = [];
56
+ return text ? `${context}\n\n${text}` : context;
57
+ }
58
+ }
@@ -3,13 +3,11 @@ import type { SubmissionIntent } from './submission-intent.ts';
3
3
  export interface SubmissionRouterInput {
4
4
  readonly text: string;
5
5
  readonly commandMode?: boolean;
6
- readonly panelFocused?: boolean;
7
6
  readonly hasAttachments?: boolean;
8
7
  }
9
8
 
10
9
  const PLAN_COMMANDS = new Set(['plan']);
11
10
  const DELEGATION_COMMANDS = new Set(['delegate', 'build', 'review', 'wrfc', 'agents', 'remote']);
12
- const PANEL_COMMANDS = new Set(['panel']);
13
11
  const ORCHESTRATION_COMMANDS = new Set([
14
12
  'orchestration',
15
13
  'tasks',
@@ -45,9 +43,6 @@ export function routeSubmissionIntent(input: SubmissionRouterInput): SubmissionI
45
43
  if (DELEGATION_COMMANDS.has(commandName)) {
46
44
  return { kind: 'delegation', label: 'delegation', commandName, hasAttachments };
47
45
  }
48
- if (PANEL_COMMANDS.has(commandName)) {
49
- return { kind: 'slash-command', label: 'Agent workspace', commandName, hasAttachments };
50
- }
51
46
  if (ORCHESTRATION_COMMANDS.has(commandName)) {
52
47
  return { kind: 'orchestration', label: 'orchestration', commandName, hasAttachments };
53
48
  }