@pellux/goodvibes-agent 0.1.116 → 1.0.0

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 (285) hide show
  1. package/CHANGELOG.md +48 -661
  2. package/README.md +64 -57
  3. package/bin/goodvibes-agent.ts +16 -2
  4. package/dist/package/main.js +199180 -192185
  5. package/docs/README.md +15 -8
  6. package/docs/channels-remote-and-api.md +50 -0
  7. package/docs/connected-host.md +59 -0
  8. package/docs/getting-started.md +61 -50
  9. package/docs/knowledge-artifacts-and-multimodal.md +91 -0
  10. package/docs/project-planning.md +79 -0
  11. package/docs/providers-and-routing.md +46 -0
  12. package/docs/release-and-publishing.md +48 -11
  13. package/docs/tools-and-commands.md +123 -0
  14. package/docs/voice-and-live-tts.md +51 -0
  15. package/package.json +3 -6
  16. package/src/agent/behavior-discovery-summary.ts +1 -3
  17. package/src/agent/channel-delivery.ts +201 -0
  18. package/src/agent/media-generation.ts +159 -0
  19. package/src/agent/memory-prompt.ts +0 -1
  20. package/src/agent/note-registry.ts +329 -0
  21. package/src/agent/operator-actions.ts +343 -0
  22. package/src/agent/persona-discovery.ts +1 -3
  23. package/src/agent/persona-registry.ts +19 -16
  24. package/src/agent/record-labels.ts +107 -0
  25. package/src/agent/reminder-schedule-format.ts +33 -24
  26. package/src/agent/reminder-schedule.ts +27 -26
  27. package/src/agent/routine-registry.ts +54 -14
  28. package/src/agent/routine-schedule-args.ts +2 -1
  29. package/src/agent/routine-schedule-format.ts +77 -53
  30. package/src/agent/routine-schedule-promotion.ts +35 -33
  31. package/src/agent/routine-schedule-receipts.ts +29 -27
  32. package/src/agent/runtime-profile-starters.ts +5 -5
  33. package/src/agent/runtime-profile.ts +91 -12
  34. package/src/agent/skill-registry.ts +210 -32
  35. package/src/cli/agent-knowledge-args.ts +5 -1
  36. package/src/cli/agent-knowledge-command.ts +40 -34
  37. package/src/cli/agent-knowledge-format.ts +80 -67
  38. package/src/cli/agent-knowledge-methods.ts +1 -1
  39. package/src/cli/agent-knowledge-runtime.ts +32 -26
  40. package/src/cli/bundle-command.ts +14 -9
  41. package/src/cli/config-overrides.ts +37 -36
  42. package/src/cli/entrypoint.ts +16 -7
  43. package/src/cli/external-runtime.ts +10 -4
  44. package/src/cli/help.ts +54 -29
  45. package/src/cli/local-library-command.ts +203 -83
  46. package/src/cli/management-commands.ts +105 -68
  47. package/src/cli/management.ts +55 -74
  48. package/src/cli/memory-command.ts +66 -32
  49. package/src/cli/parser.ts +37 -3
  50. package/src/cli/profiles-command.ts +166 -31
  51. package/src/cli/provider-auth-routes.ts +2 -1
  52. package/src/cli/routines-command.ts +176 -40
  53. package/src/cli/service-posture.ts +16 -16
  54. package/src/cli/status.ts +56 -135
  55. package/src/core/conversation-message-snapshot.ts +131 -0
  56. package/src/input/agent-workspace-access-command-editor-submission.ts +149 -0
  57. package/src/input/agent-workspace-access-command-editors.ts +170 -0
  58. package/src/input/agent-workspace-activation.ts +35 -8
  59. package/src/input/agent-workspace-basic-command-editor-submission.ts +351 -94
  60. package/src/input/agent-workspace-basic-command-editors.ts +502 -9
  61. package/src/input/agent-workspace-categories.ts +423 -51
  62. package/src/input/agent-workspace-channel-command-editor-submission.ts +83 -0
  63. package/src/input/agent-workspace-channel-command-editors.ts +65 -0
  64. package/src/input/agent-workspace-channels.ts +35 -2
  65. package/src/input/agent-workspace-command-editor.ts +41 -3
  66. package/src/input/agent-workspace-config-reader.ts +16 -0
  67. package/src/input/agent-workspace-delegation-editor-submission.ts +55 -0
  68. package/src/input/agent-workspace-editors.ts +166 -1
  69. package/src/input/agent-workspace-knowledge-command-editor-submission.ts +132 -0
  70. package/src/input/agent-workspace-knowledge-command-editors.ts +110 -0
  71. package/src/input/agent-workspace-knowledge-query-editor.ts +1 -1
  72. package/src/input/agent-workspace-learned-behavior.ts +67 -0
  73. package/src/input/agent-workspace-library-command-editor-submission.ts +50 -0
  74. package/src/input/agent-workspace-library-command-editors.ts +35 -0
  75. package/src/input/agent-workspace-local-operations.ts +218 -0
  76. package/src/input/agent-workspace-local-selection.ts +75 -0
  77. package/src/input/agent-workspace-mcp-command-editor-submission.ts +95 -0
  78. package/src/input/agent-workspace-media-command-editor-submission.ts +62 -0
  79. package/src/input/agent-workspace-media-command-editors.ts +27 -0
  80. package/src/input/agent-workspace-memory-command-editor-submission.ts +232 -0
  81. package/src/input/agent-workspace-memory-command-editors.ts +180 -0
  82. package/src/input/agent-workspace-memory-editor.ts +2 -2
  83. package/src/input/agent-workspace-navigation.ts +81 -0
  84. package/src/input/agent-workspace-notify-editor-submission.ts +121 -0
  85. package/src/input/agent-workspace-operations-command-editor-submission.ts +208 -0
  86. package/src/input/agent-workspace-operations-command-editors.ts +196 -0
  87. package/src/input/agent-workspace-panel-route.ts +43 -0
  88. package/src/input/agent-workspace-provider-command-editor-submission.ts +155 -0
  89. package/src/input/agent-workspace-provider-command-editors.ts +93 -0
  90. package/src/input/agent-workspace-reminder-schedule-editor.ts +1 -1
  91. package/src/input/agent-workspace-requirements.ts +11 -0
  92. package/src/input/agent-workspace-routine-schedule-editor.ts +2 -2
  93. package/src/input/agent-workspace-search.ts +169 -0
  94. package/src/input/agent-workspace-secret-editor-submission.ts +153 -0
  95. package/src/input/agent-workspace-session-command-editor-submission.ts +199 -0
  96. package/src/input/agent-workspace-session-command-editors.ts +249 -0
  97. package/src/input/agent-workspace-setup.ts +37 -16
  98. package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +101 -0
  99. package/src/input/agent-workspace-skill-bundle-command-editors.ts +110 -0
  100. package/src/input/agent-workspace-snapshot.ts +162 -21
  101. package/src/input/agent-workspace-task-command-editor-submission.ts +61 -0
  102. package/src/input/agent-workspace-task-command-editors.ts +47 -0
  103. package/src/input/agent-workspace-token.ts +18 -2
  104. package/src/input/agent-workspace-types.ts +212 -4
  105. package/src/input/agent-workspace-voice-media.ts +4 -7
  106. package/src/input/agent-workspace-web-research-editor.ts +104 -0
  107. package/src/input/agent-workspace-workplan-editor-submission.ts +153 -0
  108. package/src/input/agent-workspace.ts +178 -240
  109. package/src/input/command-registry.ts +5 -2
  110. package/src/input/commands/agent-runtime-profile-runtime.ts +126 -37
  111. package/src/input/commands/agent-skills-runtime.ts +149 -72
  112. package/src/input/commands/agent-workspace-runtime.ts +23 -6
  113. package/src/input/commands/brief-runtime.ts +55 -25
  114. package/src/input/commands/channels-runtime.ts +147 -33
  115. package/src/input/commands/compat-runtime.ts +32 -0
  116. package/src/input/commands/delegation-runtime.ts +29 -23
  117. package/src/input/commands/experience-runtime.ts +6 -4
  118. package/src/input/commands/guidance-runtime.ts +4 -4
  119. package/src/input/commands/health-runtime.ts +149 -126
  120. package/src/input/commands/knowledge.ts +82 -60
  121. package/src/input/commands/local-provider-runtime.ts +43 -21
  122. package/src/input/commands/local-runtime.ts +138 -16
  123. package/src/input/commands/local-setup-review.ts +10 -20
  124. package/src/input/commands/mcp-runtime.ts +63 -46
  125. package/src/input/commands/notify-runtime.ts +38 -9
  126. package/src/input/commands/operator-actions-runtime.ts +138 -0
  127. package/src/input/commands/operator-runtime.ts +6 -76
  128. package/src/input/commands/personas-runtime.ts +46 -31
  129. package/src/input/commands/planning-runtime.ts +1 -1
  130. package/src/input/commands/platform-access-runtime.ts +35 -98
  131. package/src/input/commands/product-runtime.ts +2 -2
  132. package/src/input/commands/provider-accounts-runtime.ts +60 -39
  133. package/src/input/commands/qrcode-runtime.ts +50 -9
  134. package/src/input/commands/recall-bundle.ts +11 -11
  135. package/src/input/commands/recall-capture.ts +13 -11
  136. package/src/input/commands/recall-query.ts +29 -21
  137. package/src/input/commands/recall-review.ts +2 -1
  138. package/src/input/commands/routines-runtime.ts +99 -45
  139. package/src/input/commands/runtime-services.ts +1 -14
  140. package/src/input/commands/schedule-runtime.ts +33 -20
  141. package/src/input/commands/security-runtime.ts +6 -11
  142. package/src/input/commands/session-content.ts +80 -78
  143. package/src/input/commands/session-workflow.ts +134 -104
  144. package/src/input/commands/session.ts +3 -174
  145. package/src/input/commands/shell-core.ts +38 -17
  146. package/src/input/commands/subscription-runtime.ts +54 -185
  147. package/src/input/commands/support-bundle-runtime.ts +53 -0
  148. package/src/input/commands/tasks-runtime.ts +21 -21
  149. package/src/input/commands/work-plan-runtime.ts +33 -8
  150. package/src/input/commands.ts +6 -2
  151. package/src/input/feed-context-factory.ts +2 -2
  152. package/src/input/file-picker.ts +3 -2
  153. package/src/input/handler-command-route.ts +4 -7
  154. package/src/input/handler-content-actions.ts +89 -26
  155. package/src/input/handler-feed-routes.ts +19 -12
  156. package/src/input/handler-feed.ts +6 -5
  157. package/src/input/handler-interactions.ts +9 -36
  158. package/src/input/handler-modal-stack.ts +3 -3
  159. package/src/input/handler-onboarding.ts +52 -91
  160. package/src/input/handler-shortcuts.ts +16 -7
  161. package/src/input/handler.ts +50 -23
  162. package/src/input/input-history.ts +5 -6
  163. package/src/input/keybindings.ts +27 -16
  164. package/src/input/mcp-workspace.ts +90 -26
  165. package/src/input/onboarding/handler-onboarding-routes.ts +3 -1
  166. package/src/input/onboarding/onboarding-wizard-apply.ts +62 -0
  167. package/src/input/onboarding/onboarding-wizard-constants.ts +1 -0
  168. package/src/input/onboarding/onboarding-wizard-helpers.ts +1 -1
  169. package/src/input/onboarding/onboarding-wizard-operator-steps.ts +223 -55
  170. package/src/input/onboarding/onboarding-wizard-steps.ts +59 -35
  171. package/src/input/onboarding/onboarding-wizard-types.ts +4 -1
  172. package/src/input/onboarding/onboarding-wizard.ts +87 -2
  173. package/src/input/profile-picker-modal.ts +31 -12
  174. package/src/input/session-picker-modal.ts +21 -4
  175. package/src/input/settings-modal-agent-policy.ts +6 -6
  176. package/src/input/settings-modal-behavior.ts +0 -3
  177. package/src/input/settings-modal-subscriptions.ts +3 -3
  178. package/src/input/settings-modal-types.ts +2 -13
  179. package/src/input/settings-modal.ts +20 -66
  180. package/src/input/submission-intent.ts +0 -1
  181. package/src/input/submission-router.ts +3 -3
  182. package/src/main.ts +18 -10
  183. package/src/panels/approval-panel.ts +8 -8
  184. package/src/panels/automation-control-panel.ts +4 -4
  185. package/src/panels/base-panel.ts +1 -1
  186. package/src/panels/builtin/agent.ts +1 -1
  187. package/src/panels/builtin/operations.ts +3 -12
  188. package/src/panels/builtin/session.ts +32 -24
  189. package/src/panels/builtin/shared.ts +7 -7
  190. package/src/panels/cost-tracker-panel.ts +1 -1
  191. package/src/panels/docs-panel.ts +5 -3
  192. package/src/panels/index.ts +0 -1
  193. package/src/panels/knowledge-panel.ts +6 -5
  194. package/src/panels/memory-panel.ts +7 -6
  195. package/src/panels/panel-list-panel.ts +36 -80
  196. package/src/panels/project-planning-panel.ts +19 -12
  197. package/src/panels/provider-account-snapshot.ts +51 -25
  198. package/src/panels/provider-accounts-panel.ts +33 -18
  199. package/src/panels/provider-health-domains.ts +48 -7
  200. package/src/panels/provider-health-panel.ts +5 -4
  201. package/src/panels/qr-panel.ts +44 -20
  202. package/src/panels/schedule-panel.ts +9 -17
  203. package/src/panels/security-panel.ts +8 -8
  204. package/src/panels/session-browser-panel.ts +10 -10
  205. package/src/panels/subscription-panel.ts +6 -6
  206. package/src/panels/system-messages-panel.ts +3 -3
  207. package/src/panels/tasks-panel.ts +21 -14
  208. package/src/panels/tool-inspector-panel.ts +19 -12
  209. package/src/panels/work-plan-panel.ts +5 -5
  210. package/src/planning/project-planning-coordinator.ts +3 -3
  211. package/src/provider-auth-route-display.ts +9 -0
  212. package/src/renderer/agent-workspace-style.ts +34 -0
  213. package/src/renderer/agent-workspace.ts +254 -57
  214. package/src/renderer/autocomplete-overlay.ts +25 -6
  215. package/src/renderer/block-actions.ts +1 -3
  216. package/src/renderer/bookmark-modal.ts +19 -4
  217. package/src/renderer/buffer.ts +4 -2
  218. package/src/renderer/context-inspector.ts +50 -13
  219. package/src/renderer/diff.ts +1 -1
  220. package/src/renderer/file-picker-overlay.ts +19 -6
  221. package/src/renderer/help-overlay.ts +112 -34
  222. package/src/renderer/history-search-overlay.ts +19 -4
  223. package/src/renderer/live-tail-modal.ts +27 -5
  224. package/src/renderer/mcp-workspace.ts +176 -43
  225. package/src/renderer/model-picker-overlay.ts +58 -3
  226. package/src/renderer/model-workspace.ts +104 -22
  227. package/src/renderer/onboarding/onboarding-wizard.ts +20 -4
  228. package/src/renderer/process-modal.ts +27 -6
  229. package/src/renderer/profile-picker-modal.ts +21 -5
  230. package/src/renderer/search-overlay.ts +25 -5
  231. package/src/renderer/selection-modal-overlay.ts +46 -14
  232. package/src/renderer/session-picker-modal.ts +18 -1
  233. package/src/renderer/settings-modal-helpers.ts +2 -40
  234. package/src/renderer/settings-modal.ts +88 -55
  235. package/src/renderer/system-message.ts +1 -1
  236. package/src/renderer/tool-call.ts +20 -11
  237. package/src/runtime/agent-runtime-events.ts +129 -0
  238. package/src/runtime/bootstrap-command-context.ts +7 -1
  239. package/src/runtime/bootstrap-command-parts.ts +11 -8
  240. package/src/runtime/bootstrap-core.ts +23 -65
  241. package/src/runtime/bootstrap-hook-bridge.ts +7 -18
  242. package/src/runtime/bootstrap-shell.ts +46 -8
  243. package/src/runtime/bootstrap.ts +36 -46
  244. package/src/runtime/connected-host-auth.ts +47 -0
  245. package/src/runtime/diagnostics/panels/index.ts +2 -2
  246. package/src/runtime/diagnostics/panels/panel-resources.ts +1 -1
  247. package/src/runtime/diagnostics/panels/policy.ts +7 -7
  248. package/src/runtime/index.ts +2 -5
  249. package/src/runtime/onboarding/apply-file-helpers.ts +66 -0
  250. package/src/runtime/onboarding/apply.ts +288 -74
  251. package/src/runtime/onboarding/derivation.ts +10 -13
  252. package/src/runtime/onboarding/snapshot.ts +2 -17
  253. package/src/runtime/onboarding/types.ts +34 -20
  254. package/src/runtime/onboarding/verify.ts +105 -4
  255. package/src/runtime/operator-token-cleanup.ts +3 -3
  256. package/src/runtime/services.ts +95 -11
  257. package/src/runtime/store/selectors/index.ts +3 -3
  258. package/src/runtime/store/state.ts +1 -4
  259. package/src/runtime/surface-feature-flags.ts +41 -6
  260. package/src/runtime/ui-read-models.ts +3 -4
  261. package/src/runtime/ui-services.ts +6 -6
  262. package/src/shell/blocking-input.ts +2 -1
  263. package/src/shell/service-settings-sync.ts +7 -7
  264. package/src/shell/ui-openers.ts +17 -38
  265. package/src/tools/agent-analysis-registry-policy.ts +0 -1
  266. package/src/tools/agent-channel-send-tool.ts +133 -0
  267. package/src/tools/agent-context-policy.ts +1 -1
  268. package/src/tools/agent-knowledge-ingest-tool.ts +405 -0
  269. package/src/tools/agent-knowledge-tool.ts +170 -0
  270. package/src/tools/agent-local-registry-tool.ts +279 -73
  271. package/src/tools/agent-media-generate-tool.ts +133 -0
  272. package/src/tools/agent-notify-tool.ts +143 -0
  273. package/src/tools/agent-operator-action-tool.ts +137 -0
  274. package/src/tools/agent-operator-briefing-tool.ts +217 -0
  275. package/src/tools/agent-reminder-schedule-tool.ts +237 -0
  276. package/src/tools/agent-tool-policy-guard.ts +13 -15
  277. package/src/tools/agent-work-plan-tool.ts +256 -0
  278. package/src/version.ts +1 -1
  279. package/docs/connected-services.md +0 -51
  280. package/src/cli/package-verification.ts +0 -274
  281. package/src/input/commands/policy-dispatch.ts +0 -339
  282. package/src/input/commands/policy.ts +0 -17
  283. package/src/panels/panel-picker.ts +0 -105
  284. package/src/panels/policy-panel.ts +0 -308
  285. package/src/renderer/panel-picker-overlay.ts +0 -202
@@ -1,3 +1,4 @@
1
+ import type { Dirent } from 'node:fs';
1
2
  import { readdir } from 'node:fs/promises';
2
3
  import { join, relative } from 'node:path';
3
4
  import type { ShellPathService } from '@/runtime/index.ts';
@@ -160,9 +161,9 @@ export class FilePickerModal {
160
161
  if (depth > 8) return; // Limit depth
161
162
  if (files.length > 5000) return; // Limit total files
162
163
 
163
- let entries: import('node:fs').Dirent[];
164
+ let entries: Dirent[];
164
165
  try {
165
- entries = (await readdir(dir, { withFileTypes: true })) as unknown as import('node:fs').Dirent[];
166
+ entries = await readdir(dir, { withFileTypes: true });
166
167
  } catch {
167
168
  return;
168
169
  }
@@ -106,7 +106,7 @@ export function handleCommandModeToken(state: CommandModeRouteState, token: Inpu
106
106
  if (skillContent) {
107
107
  state.commandContext?.submitInput?.(skillContent);
108
108
  } else {
109
- state.conversationManager?.log(`Unknown command: /${name}. Type /help for available commands.`, { fg: '#ef4444' });
109
+ state.conversationManager?.log(`Unknown command /${name}. Type /help for available commands.`, { fg: '#ef4444' });
110
110
  state.requestRender();
111
111
  }
112
112
  }
@@ -121,27 +121,24 @@ export function handleCommandModeToken(state: CommandModeRouteState, token: Inpu
121
121
  }
122
122
 
123
123
  function withPanelFocusSync(context: CommandContext, state: CommandModeRouteState): CommandContext {
124
- const panelIsFocusable = (): boolean =>
125
- state.panelManager.isVisible() && state.panelManager.getAllOpen().length > 0;
126
-
127
124
  return {
128
125
  ...context,
129
126
  openPanelPicker: context.openPanelPicker
130
127
  ? () => {
131
128
  context.openPanelPicker?.();
132
- state.panelFocused = panelIsFocusable();
129
+ state.panelFocused = false;
133
130
  }
134
131
  : undefined,
135
132
  showPanel: context.showPanel
136
133
  ? (panelId, pane) => {
137
134
  context.showPanel?.(panelId, pane);
138
- state.panelFocused = true;
135
+ state.panelFocused = false;
139
136
  }
140
137
  : undefined,
141
138
  focusPanels: context.focusPanels
142
139
  ? () => {
143
140
  context.focusPanels?.();
144
- state.panelFocused = panelIsFocusable();
141
+ state.panelFocused = false;
145
142
  }
146
143
  : undefined,
147
144
  focusPrompt: context.focusPrompt
@@ -1,10 +1,9 @@
1
- import { readFileSync, existsSync } from 'node:fs';
1
+ import { existsSync, lstatSync, readFileSync, readdirSync } from 'node:fs';
2
+ import { basename, relative } from 'node:path';
2
3
  import { copyToClipboard, pasteFromClipboard, pasteImageFromClipboard } from '../utils/clipboard.ts';
3
4
  import type { InfiniteBuffer } from '../core/history.ts';
4
5
  import type { ConversationManager } from '../core/conversation';
5
- import type { PermissionCategory } from '@pellux/goodvibes-sdk/platform/permissions';
6
6
  import type { ContentPart } from '@pellux/goodvibes-sdk/platform/providers';
7
- import type { CommandContext } from './command-registry.ts';
8
7
  import type { BookmarkManager } from '@pellux/goodvibes-sdk/platform/bookmarks';
9
8
  import { resolveAndValidatePath } from '@pellux/goodvibes-sdk/platform/utils';
10
9
  import { logger } from '@pellux/goodvibes-sdk/platform/utils';
@@ -32,6 +31,11 @@ export const BINARY_IMAGE_MAGIC: {
32
31
  ];
33
32
 
34
33
  export const IMAGE_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.webp', '.gif'];
34
+ const MAX_CONTEXT_FILE_BYTES = 64 * 1024;
35
+ const MAX_CONTEXT_DIRECTORY_ENTRIES = 200;
36
+ const URL_REFERENCE_REGEX = /^https?:\/\/[^\s]+$/i;
37
+ const CONTEXT_REFERENCE_REGEX = /(^|\s)@([^\s]+)/g;
38
+ const CONTEXT_REFERENCE_TRAILING_PUNCTUATION = /[),.;:!?]+$/;
35
39
 
36
40
  export function formatFileSize(bytes: number): string {
37
41
  if (bytes < 1024) return `${bytes}B`;
@@ -48,6 +52,86 @@ export function mediaTypeFromExt(ext: string): string {
48
52
  }
49
53
  }
50
54
 
55
+ function stripTrailingReferencePunctuation(value: string): { readonly core: string; readonly suffix: string } {
56
+ const match = CONTEXT_REFERENCE_TRAILING_PUNCTUATION.exec(value);
57
+ if (!match) return { core: value, suffix: '' };
58
+ return {
59
+ core: value.slice(0, -match[0].length),
60
+ suffix: match[0],
61
+ };
62
+ }
63
+
64
+ function escapeContextAttribute(value: string): string {
65
+ return value
66
+ .replace(/&/g, '&amp;')
67
+ .replace(/"/g, '&quot;')
68
+ .replace(/</g, '&lt;')
69
+ .replace(/>/g, '&gt;');
70
+ }
71
+
72
+ function readContextFileBlock(reference: string, projectRoot: string): string | null {
73
+ let resolvedPath: string;
74
+ try {
75
+ resolvedPath = resolveAndValidatePath(reference, projectRoot);
76
+ } catch (error) {
77
+ logger.debug('expandPrompt: context reference rejected', { reference, error: summarizeError(error) });
78
+ return null;
79
+ }
80
+ if (!existsSync(resolvedPath)) return null;
81
+
82
+ const stat = lstatSync(resolvedPath);
83
+ const label = escapeContextAttribute(relative(projectRoot, resolvedPath) || basename(resolvedPath));
84
+ if (stat.isDirectory()) {
85
+ const entries = readdirSync(resolvedPath, { withFileTypes: true })
86
+ .slice(0, MAX_CONTEXT_DIRECTORY_ENTRIES)
87
+ .map((entry) => `${entry.isDirectory() ? 'dir ' : 'file'} ${entry.name}`)
88
+ .join('\n');
89
+ return [
90
+ `<context-folder path="${label}">`,
91
+ entries || '(empty directory)',
92
+ stat.isDirectory() ? `</context-folder>` : '',
93
+ ].filter(Boolean).join('\n');
94
+ }
95
+
96
+ if (!stat.isFile()) return null;
97
+ if (stat.size > MAX_CONTEXT_FILE_BYTES) {
98
+ return [
99
+ `<context-file path="${label}" truncated="true" bytes="${stat.size}">`,
100
+ readFileSync(resolvedPath, 'utf-8').slice(0, MAX_CONTEXT_FILE_BYTES),
101
+ '</context-file>',
102
+ ].join('\n');
103
+ }
104
+
105
+ return [
106
+ `<context-file path="${label}" bytes="${stat.size}">`,
107
+ readFileSync(resolvedPath, 'utf-8'),
108
+ '</context-file>',
109
+ ].join('\n');
110
+ }
111
+
112
+ function buildContextUrlBlock(reference: string): string {
113
+ const href = escapeContextAttribute(reference);
114
+ return [
115
+ `<context-url href="${href}">`,
116
+ 'The user referenced this URL in the prompt. Use connected tools only if content retrieval is needed; do not ingest it into Agent Knowledge unless the user explicitly asks.',
117
+ '</context-url>',
118
+ ].join('\n');
119
+ }
120
+
121
+ function expandContextReferences(text: string, projectRoot: string): string {
122
+ return text.replace(CONTEXT_REFERENCE_REGEX, (full: string, prefix: string, rawReference: string): string => {
123
+ if (rawReference.startsWith('model:')) return full;
124
+ const { core, suffix } = stripTrailingReferencePunctuation(rawReference);
125
+ if (!core || core.startsWith('@')) return full;
126
+ if (URL_REFERENCE_REGEX.test(core)) {
127
+ return `${prefix}${buildContextUrlBlock(core)}${suffix}`;
128
+ }
129
+ const fileBlock = readContextFileBlock(core, projectRoot);
130
+ if (!fileBlock) return full;
131
+ return `${prefix}${fileBlock}${suffix}`;
132
+ });
133
+ }
134
+
51
135
  export type PasteRegistryState = {
52
136
  pasteRegistry: Map<string, string>;
53
137
  nextPasteId: number;
@@ -173,6 +257,8 @@ export function expandPrompt(
173
257
  }
174
258
  }
175
259
 
260
+ expanded = expandContextReferences(expanded, projectRoot);
261
+
176
262
  const imageMarkerRegex = /\[IMAGE: (img\d+), [^\]]+\]/g;
177
263
  const imageMarkers: { marker: string; index: number; id: string }[] = [];
178
264
  let imgMatch;
@@ -337,29 +423,6 @@ export function handleBlockToggle(
337
423
  }
338
424
  }
339
425
 
340
- export function handleDiffApply(
341
- conversationManager: ConversationManager | null,
342
- getScrollTop: () => number,
343
- commandContext: CommandContext | undefined,
344
- requestRender: () => void,
345
- getCallId: () => string,
346
- category: PermissionCategory,
347
- ): boolean {
348
- void commandContext;
349
- void getCallId;
350
- void category;
351
- if (!conversationManager) return false;
352
- const lineIndex = getScrollTop();
353
- const diff = conversationManager.getDiffAtLine(lineIndex);
354
- if (!diff || !diff.filePath) return false;
355
- conversationManager.log(
356
- `[Diff apply blocked in GoodVibes Agent: ${diff.filePath}. Delegate build/fix work to GoodVibes TUI with /delegate <task>.]`,
357
- { fg: '#f59e0b' },
358
- );
359
- requestRender();
360
- return true;
361
- }
362
-
363
426
  export function handleCtrlC(
364
427
  prompt: string,
365
428
  saveUndoState: () => void,
@@ -25,7 +25,8 @@ export type PanelFocusRouteState = {
25
25
  autocompleteActive: boolean;
26
26
  requestRender: () => void;
27
27
  handlePathCompletion: () => boolean;
28
- cyclePanelTab: (direction: 'next' | 'prev') => void;
28
+ cycleAgentWorkspaceCategory: (direction: 'next' | 'prev') => void;
29
+ dismissAgentWorkspace: () => boolean;
29
30
  onPanelInputConsumed?: (activePanel: import('../panels/types.ts').Panel | null, key: string) => void;
30
31
  };
31
32
 
@@ -42,16 +43,16 @@ export function handlePanelFocusToken(state: PanelFocusRouteState, token: InputT
42
43
  !state.searchActive &&
43
44
  !state.autocompleteActive
44
45
  ) {
45
- const pm = state.panelManager;
46
- if (pm.isVisible() && pm.getAllOpen().length > 0) {
47
- if (panelFocused) {
48
- panelFocused = false;
49
- } else if (!state.handlePathCompletion()) {
50
- panelFocused = true;
51
- }
46
+ if (panelFocused) {
47
+ panelFocused = false;
48
+ state.requestRender();
49
+ return { handled: true, panelFocused };
50
+ }
51
+ if (state.handlePathCompletion()) {
52
52
  state.requestRender();
53
53
  return { handled: true, panelFocused };
54
54
  }
55
+ return { handled: false, panelFocused };
55
56
  }
56
57
 
57
58
  if (!panelFocused) {
@@ -76,14 +77,17 @@ export function handlePanelFocusToken(state: PanelFocusRouteState, token: InputT
76
77
  }
77
78
  const kb = state.keybindingsManager;
78
79
  if (kb.matches('panel-tab-next', token)) {
79
- state.cyclePanelTab('next');
80
- return { handled: true, panelFocused };
80
+ state.cycleAgentWorkspaceCategory('next');
81
+ return { handled: true, panelFocused: false };
81
82
  }
82
83
  if (kb.matches('panel-tab-prev', token)) {
83
- state.cyclePanelTab('prev');
84
- return { handled: true, panelFocused };
84
+ state.cycleAgentWorkspaceCategory('prev');
85
+ return { handled: true, panelFocused: false };
85
86
  }
86
87
  if (kb.matches('panel-close-all', token)) {
88
+ if (state.dismissAgentWorkspace()) {
89
+ return { handled: true, panelFocused: false };
90
+ }
87
91
  const pm = state.panelManager;
88
92
  for (const p of pm.getAllOpen()) pm.close(p.id);
89
93
  panelFocused = false;
@@ -91,6 +95,9 @@ export function handlePanelFocusToken(state: PanelFocusRouteState, token: InputT
91
95
  return { handled: true, panelFocused };
92
96
  }
93
97
  if (kb.matches('panel-close', token)) {
98
+ if (state.dismissAgentWorkspace()) {
99
+ return { handled: true, panelFocused: false };
100
+ }
94
101
  const pm = state.panelManager;
95
102
  const active = pm.getActivePanel();
96
103
  if (active) {
@@ -141,7 +141,6 @@ export interface InputFeedContext {
141
141
  readonly handleBlockCopy: () => void;
142
142
  readonly handleBookmark: () => void;
143
143
  readonly handleBlockSave: () => void;
144
- readonly handleDiffApply: () => boolean;
145
144
  readonly handleUndo: () => void;
146
145
  readonly handleRedo: () => void;
147
146
  readonly handlePaste: () => void;
@@ -149,7 +148,8 @@ export interface InputFeedContext {
149
148
  readonly ensureInputCursorVisible: (contentWidth?: number) => void;
150
149
  readonly registerPaste: (content: string) => string;
151
150
  readonly executeBlockAction: (id: string) => void;
152
- readonly cyclePanelTab: (direction: 'next' | 'prev') => void;
151
+ readonly cycleAgentWorkspaceCategory: (direction: 'next' | 'prev') => void;
152
+ readonly dismissAgentWorkspace: () => boolean;
153
153
  readonly onPanelInputConsumed: (activePanel: Panel | null, key: string) => void;
154
154
  readonly getWrappedPromptInfo: (contentWidth: number) => WrappedPromptInfo;
155
155
  readonly moveCursorVertical: (direction: -1 | 1) => boolean;
@@ -272,12 +272,12 @@ export function feedInputTokens(context: InputFeedContext, tokens: readonly Inpu
272
272
  handleBlockCopy: context.handleBlockCopy,
273
273
  handleBookmark: context.handleBookmark,
274
274
  handleBlockSave: context.handleBlockSave,
275
- handleDiffApply: context.handleDiffApply,
276
275
  handleUndo: context.handleUndo,
277
276
  handleRedo: context.handleRedo,
278
277
  handlePaste: context.handlePaste,
279
278
  handleEscape: context.handleEscape,
280
- cyclePanelTab: context.cyclePanelTab,
279
+ cycleAgentWorkspaceCategory: context.cycleAgentWorkspaceCategory,
280
+ dismissAgentWorkspace: context.dismissAgentWorkspace,
281
281
  panelManager: context.panelManager,
282
282
  keybindingsManager: context.keybindingsManager,
283
283
  };
@@ -297,7 +297,8 @@ export function feedInputTokens(context: InputFeedContext, tokens: readonly Inpu
297
297
  autocompleteActive: !!context.autocomplete?.isActive,
298
298
  requestRender: context.requestRender,
299
299
  handlePathCompletion: context.handlePathCompletion,
300
- cyclePanelTab: context.cyclePanelTab,
300
+ cycleAgentWorkspaceCategory: context.cycleAgentWorkspaceCategory,
301
+ dismissAgentWorkspace: context.dismissAgentWorkspace,
301
302
  panelManager: context.panelManager,
302
303
  keybindingsManager: context.keybindingsManager,
303
304
  onPanelInputConsumed: context.onPanelInputConsumed,
@@ -1,7 +1,7 @@
1
- import { buildProviderAccountSnapshot } from '@/runtime/index.ts';
1
+ import { buildProviderAccountSnapshot } from '../panels/provider-account-snapshot.ts';
2
2
  import type { OnboardingWizardMode } from './onboarding/onboarding-wizard.ts';
3
- import { collectOnboardingSnapshot, readOnboardingCheckMarker, writeOnboardingCheckMarker } from '../runtime/onboarding/index.ts';
4
- import { cleanupMarkerRegistry, expandPrompt, findMarkerAtPos, handleBlockCopy, handleBlockRerun, handleBlockSave, handleBlockToggle, handleBookmark, handleClipboardPaste, handleCopy, handleCtrlC, handleDiffApply, registerPaste } from './handler-content-actions.ts';
3
+ import { collectOnboardingSnapshot } from '../runtime/onboarding/index.ts';
4
+ import { cleanupMarkerRegistry, expandPrompt, findMarkerAtPos, handleBlockCopy, handleBlockRerun, handleBlockSave, handleBlockToggle, handleBookmark, handleClipboardPaste, handleCopy, handleCtrlC, registerPaste } from './handler-content-actions.ts';
5
5
  import { clearModalStack, handleEscape, modalOpened } from './handler-modal-stack.ts';
6
6
  import { openOnboardingWizardState, type OpenOnboardingWizardOptions } from './handler-ui-state.ts';
7
7
  import type { InputHandler } from './handler.ts';
@@ -11,19 +11,6 @@ export function openOnboardingWizardForHandler(
11
11
  modeOrOptions: OnboardingWizardMode | OpenOnboardingWizardOptions = 'new',
12
12
  ): void {
13
13
  const options = typeof modeOrOptions === 'string' ? { mode: modeOrOptions } : modeOrOptions;
14
- const userMarker = readOnboardingCheckMarker(handler.uiServices.environment.shellPaths, 'user');
15
- if (!userMarker.payload) {
16
- try {
17
- writeOnboardingCheckMarker(handler.uiServices.environment.shellPaths, {
18
- scope: 'user',
19
- source: 'wizard',
20
- mode: options.mode ?? 'new',
21
- });
22
- } catch (error) {
23
- const message = error instanceof Error ? error.message : String(error);
24
- handler.commandContext?.print?.(`Onboarding check marker could not be written: ${message}`);
25
- }
26
- }
27
14
  if (!handler.modalStack.includes('onboarding')) handler.modalOpened('onboarding');
28
15
  handler.clearOnboardingModelPickerCancelState();
29
16
  openOnboardingWizardState(handler.onboardingWizard, options);
@@ -50,10 +37,12 @@ export async function hydrateOnboardingWizardFromRuntimeForHandler(handler: Inpu
50
37
  },
51
38
  providerAccounts: {
52
39
  loadSnapshot: () => buildProviderAccountSnapshot({
53
- providerRegistry: handler.uiServices.providers.providerRegistry,
54
- serviceRegistry: handler.uiServices.platform.serviceRegistry,
55
- subscriptionManager: handler.uiServices.platform.subscriptionManager,
56
- secretsManager: handler.uiServices.platform.secretsManager,
40
+ providerModels: handler.uiServices.providers.providerRegistry,
41
+ services: handler.uiServices.platform.serviceRegistry,
42
+ subscriptions: handler.uiServices.platform.subscriptionManager,
43
+ environment: {
44
+ hasEnvironmentVariable: (name: string) => Boolean(process.env[name]),
45
+ },
57
46
  }),
58
47
  },
59
48
  });
@@ -152,7 +141,6 @@ export function executeBlockActionForHandler(handler: InputHandler, actionId: st
152
141
  case 'copy': handler.handleBlockCopy(); break;
153
142
  case 'bookmark': handler.handleBookmark(); break;
154
143
  case 'toggle': handler.handleBlockToggle(); break;
155
- case 'apply': handler.handleDiffApply(); break;
156
144
  case 'rerun': handler.handleBlockRerun(); break;
157
145
  }
158
146
  }
@@ -172,21 +160,6 @@ export function handleBlockToggleForHandler(handler: InputHandler): void {
172
160
  handleBlockToggle(handler.conversationManager, handler.getScrollTop, handler.requestRender);
173
161
  }
174
162
 
175
- /**
176
- * handleDiffApply - Ctrl+A when a diff block is nearest: request approval and apply the diff.
177
- * Returns true if a diff was found and applied (so caller can skip default Ctrl+A).
178
- */
179
- export function handleDiffApplyForHandler(handler: InputHandler): boolean {
180
- return handleDiffApply(
181
- handler.conversationManager,
182
- handler.getScrollTop,
183
- handler.commandContext,
184
- handler.requestRender,
185
- () => `diff-apply-${Date.now()}`,
186
- 'write',
187
- );
188
- }
189
-
190
163
  /**
191
164
  * Handle Ctrl+C:
192
165
  * - If prompt has text: clear it
@@ -8,7 +8,7 @@ import type { SelectionResult } from './selection-modal.ts';
8
8
 
9
9
  export type ModalStackState = ActiveModalState & {
10
10
  modalStack: string[];
11
- modalReturnFocus?: 'prompt' | 'panel' | 'indicator';
11
+ modalReturnFocus?: 'prompt' | 'indicator';
12
12
  panelFocused: boolean;
13
13
  indicatorFocused: boolean;
14
14
  };
@@ -20,7 +20,7 @@ export function modalOpened(state: ModalStackState, name: string): void {
20
20
  if (state.modalStack[state.modalStack.length - 1] === name) return;
21
21
  if (state.modalStack.includes(name)) return;
22
22
  if (state.modalStack.length === 0) {
23
- state.modalReturnFocus = state.indicatorFocused ? 'indicator' : state.panelFocused ? 'panel' : 'prompt';
23
+ state.modalReturnFocus = state.indicatorFocused ? 'indicator' : 'prompt';
24
24
  }
25
25
  state.modalStack.push(name);
26
26
  }
@@ -86,7 +86,7 @@ export function handleEscape(state: EscapeState): {
86
86
  shortcutsOverlayActive,
87
87
  commandMode,
88
88
  }) !== null) return;
89
- panelFocused = modalReturnFocus === 'panel';
89
+ panelFocused = false;
90
90
  indicatorFocused = modalReturnFocus === 'indicator';
91
91
  modalReturnFocus = 'prompt';
92
92
  state.modalReturnFocus = 'prompt';