@pellux/goodvibes-agent 0.1.102 → 0.1.104

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 (47) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +10 -0
  3. package/docs/README.md +1 -1
  4. package/docs/getting-started.md +17 -3
  5. package/package.json +1 -1
  6. package/src/agent/memory-safety.ts +16 -0
  7. package/src/cli/help.ts +86 -0
  8. package/src/cli/local-library-command.ts +516 -0
  9. package/src/cli/management.ts +17 -0
  10. package/src/cli/memory-command.ts +630 -0
  11. package/src/cli/package-verification.ts +10 -0
  12. package/src/cli/parser.ts +8 -0
  13. package/src/cli/types.ts +3 -0
  14. package/src/input/agent-workspace-activation.ts +170 -0
  15. package/src/input/agent-workspace-categories.ts +8 -1
  16. package/src/input/agent-workspace-editors.ts +36 -0
  17. package/src/input/agent-workspace-memory-editor.ts +88 -0
  18. package/src/input/agent-workspace-setup.ts +7 -5
  19. package/src/input/agent-workspace-snapshot.ts +40 -4
  20. package/src/input/agent-workspace-token.ts +51 -0
  21. package/src/input/agent-workspace-types.ts +13 -3
  22. package/src/input/agent-workspace.ts +130 -185
  23. package/src/input/feed-context-factory.ts +1 -3
  24. package/src/input/handler-feed.ts +1 -4
  25. package/src/input/handler-interactions.ts +0 -1
  26. package/src/input/handler-modal-stack.ts +0 -1
  27. package/src/input/handler-modal-token-routes.ts +0 -11
  28. package/src/input/handler-picker-routes.ts +11 -20
  29. package/src/input/handler-ui-state.ts +0 -6
  30. package/src/input/handler.ts +1 -17
  31. package/src/main.ts +0 -6
  32. package/src/panels/builtin/agent.ts +0 -17
  33. package/src/panels/index.ts +0 -2
  34. package/src/renderer/agent-workspace.ts +8 -3
  35. package/src/renderer/conversation-overlays.ts +0 -6
  36. package/src/renderer/live-tail-modal.ts +10 -69
  37. package/src/renderer/process-modal.ts +28 -530
  38. package/src/runtime/bootstrap-core.ts +1 -1
  39. package/src/runtime/services.ts +3 -4
  40. package/src/tools/{wrfc-agent-guard.ts → agent-tool-policy-guard.ts} +0 -6
  41. package/src/version.ts +1 -1
  42. package/src/panels/agent-inspector-panel.ts +0 -521
  43. package/src/panels/agent-inspector-shared.ts +0 -94
  44. package/src/panels/agent-logs-panel.ts +0 -559
  45. package/src/panels/agent-logs-shared.ts +0 -129
  46. package/src/renderer/agent-detail-modal.ts +0 -331
  47. package/src/renderer/process-summary.ts +0 -67
@@ -1,12 +1,15 @@
1
- import type { InputToken } from '@pellux/goodvibes-sdk/platform/core';
1
+ import type { MemoryApi } from '@pellux/goodvibes-sdk/platform/knowledge';
2
+ import type { MemoryRecord } from '@pellux/goodvibes-sdk/platform/state';
2
3
  import type { ShellPathService } from '@/runtime/index.ts';
3
4
  import type { CommandContext } from './command-registry.ts';
4
5
  import { AgentPersonaRegistry } from '../agent/persona-registry.ts';
5
6
  import { AgentRoutineRegistry } from '../agent/routine-registry.ts';
6
7
  import { createAgentRuntimeProfile, type AgentRuntimeProfileInfo } from '../agent/runtime-profile.ts';
7
8
  import { AgentSkillRegistry } from '../agent/skill-registry.ts';
9
+ import { activateAgentWorkspaceSelection } from './agent-workspace-activation.ts';
8
10
  import { AGENT_WORKSPACE_CATEGORIES } from './agent-workspace-categories.ts';
9
- import { createDeleteEditor, createLocalEditor, createPersonaUpdateEditor, createProfileEditor, createRoutineUpdateEditor, createSkillUpdateEditor, editorCategoryId, isAffirmative, splitList } from './agent-workspace-editors.ts';
11
+ import { createDeleteEditor, createMemoryUpdateEditor, createPersonaUpdateEditor, createRoutineUpdateEditor, createSkillUpdateEditor, editorCategoryId, isAffirmative, splitList } from './agent-workspace-editors.ts';
12
+ import { deleteAgentWorkspaceMemoryEditor, submitAgentWorkspaceMemoryEditor } from './agent-workspace-memory-editor.ts';
10
13
  import { buildAgentWorkspaceRuntimeSnapshot } from './agent-workspace-snapshot.ts';
11
14
  import type { AgentWorkspaceAction, AgentWorkspaceActionResult, AgentWorkspaceCategory, AgentWorkspaceCommandDispatcher, AgentWorkspaceEditorField, AgentWorkspaceFocusPane, AgentWorkspaceLocalEditor, AgentWorkspaceLocalEditorKind, AgentWorkspaceLocalLibraryItem, AgentWorkspaceLocalOperation, AgentWorkspaceRuntimeSnapshot } from './agent-workspace-types.ts';
12
15
 
@@ -26,12 +29,7 @@ export type {
26
29
  } from './agent-workspace-types.ts';
27
30
  export { AGENT_WORKSPACE_MODAL_NAME } from './agent-workspace-types.ts';
28
31
  export { buildAgentWorkspaceRuntimeSnapshot } from './agent-workspace-snapshot.ts';
29
- function parseCommand(command: string): { readonly name: string; readonly args: readonly string[] } {
30
- const trimmed = command.trim().replace(/^\//, '');
31
- if (!trimmed) return { name: '', args: [] };
32
- const parts = trimmed.split(/\s+/);
33
- return { name: parts[0] ?? '', args: parts.slice(1) };
34
- }
32
+ export { handleAgentWorkspaceToken } from './agent-workspace-token.ts';
35
33
 
36
34
  export class AgentWorkspace {
37
35
  public active = false;
@@ -43,6 +41,7 @@ export class AgentWorkspace {
43
41
  public lastActionResult: AgentWorkspaceActionResult | null = null;
44
42
  public localEditor: AgentWorkspaceLocalEditor | null = null;
45
43
  private readonly selectedLibraryItemIndexes: Record<AgentWorkspaceLocalEditorKind, number> = {
44
+ memory: 0,
46
45
  persona: 0,
47
46
  skill: 0,
48
47
  routine: 0,
@@ -207,147 +206,39 @@ export class AgentWorkspace {
207
206
  this.replaceEditorField(editor.selectedFieldIndex, characters.join(''), editor.message);
208
207
  }
209
208
 
210
- submitEditorFieldOrForm(): void {
209
+ submitEditorFieldOrForm(requestRender?: () => void): void {
211
210
  const editor = this.localEditor;
212
211
  if (!editor) return;
213
212
  if (editor.selectedFieldIndex < editor.fields.length - 1) {
214
213
  this.moveEditorField(1);
215
214
  return;
216
215
  }
217
- this.submitLocalEditor();
216
+ this.submitLocalEditor(requestRender);
218
217
  }
219
218
 
220
- activateSelected(): void {
221
- if (this.localEditor) {
222
- this.submitEditorFieldOrForm();
223
- return;
224
- }
225
- if (this.focusPane === 'categories') {
226
- this.focusActions();
227
- return;
228
- }
229
- const action = this.selectedAction;
230
- if (!action) return;
231
- if (action.kind === 'editor' && action.editorKind) {
232
- this.localEditor = action.editorKind === 'profile'
233
- ? createProfileEditor(this.runtimeSnapshot?.runtimeStarterTemplates ?? [])
234
- : createLocalEditor(action.editorKind);
235
- this.status = `Editing ${this.localEditor.title}.`;
236
- this.lastActionResult = {
237
- kind: 'guidance',
238
- title: this.localEditor.title,
239
- detail: this.localEditor.message,
240
- safety: action.safety,
241
- };
242
- return;
243
- }
244
- if (action.kind === 'local-selection' && action.localKind) {
245
- this.moveLocalLibraryItemSelection(action.localKind, action.selectionDelta ?? 0);
246
- return;
247
- }
248
- if (action.kind === 'local-operation' && action.localOperation) {
249
- this.applyLocalLibraryOperation(action.localOperation);
250
- return;
251
- }
252
- if (action.kind === 'guidance' || !action.command) {
253
- if (action.kind === 'workspace' && action.targetCategoryId) {
254
- const targetIndex = this.categories.findIndex((category) => category.id === action.targetCategoryId);
255
- if (targetIndex >= 0) {
256
- this.selectedCategoryIndex = targetIndex;
257
- this.selectedActionIndex = 0;
258
- this.focusActions();
259
- this.status = `Opened ${this.selectedCategory.label}.`;
260
- this.lastActionResult = {
261
- kind: 'refreshed',
262
- title: `Opened ${this.selectedCategory.label}`,
263
- detail: action.detail,
264
- safety: action.safety,
265
- };
266
- this.clampSelection();
267
- return;
268
- }
269
- this.status = `Workspace area unavailable: ${action.targetCategoryId}.`;
270
- this.lastActionResult = {
271
- kind: 'error',
272
- title: 'Workspace area unavailable',
273
- detail: `No Agent workspace category exists for ${action.targetCategoryId}.`,
274
- safety: action.safety,
275
- };
276
- return;
277
- }
278
- this.status = action.detail;
279
- this.lastActionResult = {
280
- kind: 'guidance',
281
- title: action.label,
282
- detail: action.detail,
283
- safety: action.safety,
284
- };
285
- return;
286
- }
287
- if (action.safety === 'blocked') {
288
- this.status = `Blocked here: ${action.label}.`;
289
- this.lastActionResult = {
290
- kind: 'blocked',
291
- title: `${action.label} is blocked in Agent`,
292
- detail: action.detail,
293
- command: action.command,
294
- safety: action.safety,
295
- };
296
- return;
297
- }
298
- const parsed = parseCommand(action.command);
299
- if (!parsed.name) {
300
- this.status = `No command is configured for ${action.label}.`;
301
- this.lastActionResult = {
302
- kind: 'error',
303
- title: 'Command unavailable',
304
- detail: `No command is configured for ${action.label}.`,
305
- safety: action.safety,
306
- };
307
- return;
308
- }
309
- if (/<[^>\s]+(?:\s+[^>]*)?>/.test(action.command)) {
310
- this.status = `Placeholder command not dispatched: ${action.command}.`;
311
- this.lastActionResult = {
312
- kind: 'guidance',
313
- title: `${action.label} needs details`,
314
- detail: 'This action is a command template. Close the workspace and run it with real task text instead of placeholder values.',
315
- command: action.command,
316
- safety: action.safety,
317
- };
318
- return;
319
- }
320
- if (!this.context?.executeCommand || !this.dispatchCommand) {
321
- this.status = `Command dispatch is not available for ${action.command}.`;
322
- this.lastActionResult = {
323
- kind: 'error',
324
- title: 'Command dispatch unavailable',
325
- detail: `The command ${action.command} cannot be opened from this runtime.`,
326
- command: action.command,
327
- safety: action.safety,
328
- };
329
- return;
330
- }
331
- this.status = `Opening ${action.command}.`;
332
- this.lastActionResult = {
333
- kind: 'dispatched',
334
- title: `Opening ${action.label}`,
335
- detail: 'The workspace handed this safe or read-only command to the shell-owned command router.',
336
- command: action.command,
337
- safety: action.safety,
338
- };
339
- this.dispatchCommand(action.command);
219
+ activateSelected(requestRender?: () => void): void {
220
+ activateAgentWorkspaceSelection(this, requestRender);
340
221
  }
341
222
 
342
- private clampSelection(): void {
223
+ hasCommandDispatch(): boolean {
224
+ return Boolean(this.context?.executeCommand && this.dispatchCommand);
225
+ }
226
+
227
+ dispatchWorkspaceCommand(command: string): void {
228
+ this.dispatchCommand?.(command);
229
+ }
230
+
231
+ clampSelection(): void {
343
232
  this.selectedCategoryIndex = Math.max(0, Math.min(this.selectedCategoryIndex, this.categories.length - 1));
344
233
  this.selectedActionIndex = Math.max(0, Math.min(this.selectedActionIndex, this.actions.length - 1));
234
+ this.clampLocalLibrarySelection('memory');
345
235
  this.clampLocalLibrarySelection('persona');
346
236
  this.clampLocalLibrarySelection('skill');
347
237
  this.clampLocalLibrarySelection('routine');
348
238
  }
349
239
 
350
240
  private localLibraryItems(kind: AgentWorkspaceLocalEditorKind): readonly AgentWorkspaceLocalLibraryItem[] {
241
+ if (kind === 'memory') return this.runtimeSnapshot?.localMemories ?? [];
351
242
  if (kind === 'persona') return this.runtimeSnapshot?.localPersonas ?? [];
352
243
  if (kind === 'skill') return this.runtimeSnapshot?.localSkills ?? [];
353
244
  if (kind === 'profile') return [];
@@ -361,7 +252,7 @@ export class AgentWorkspace {
361
252
  : Math.max(0, Math.min(this.selectedLibraryItemIndexes[kind], length - 1));
362
253
  }
363
254
 
364
- private moveLocalLibraryItemSelection(kind: AgentWorkspaceLocalEditorKind, delta: number): void {
255
+ moveLocalLibraryItemSelection(kind: AgentWorkspaceLocalEditorKind, delta: number): void {
365
256
  const items = this.localLibraryItems(kind);
366
257
  if (items.length === 0) {
367
258
  this.status = `No local ${kind} records to select.`;
@@ -384,7 +275,7 @@ export class AgentWorkspace {
384
275
  };
385
276
  }
386
277
 
387
- private applyLocalLibraryOperation(operation: AgentWorkspaceLocalOperation): void {
278
+ applyLocalLibraryOperation(operation: AgentWorkspaceLocalOperation): void {
388
279
  const shellPaths = this.context?.workspace?.shellPaths;
389
280
  if (!shellPaths) {
390
281
  this.status = 'Local Agent registry files are unavailable.';
@@ -412,7 +303,29 @@ export class AgentWorkspace {
412
303
  };
413
304
  return;
414
305
  }
415
- if (operation === 'persona-edit') {
306
+ if (operation === 'memory-edit') {
307
+ const memory = this.memoryApi();
308
+ const record = memory.get(selected.id);
309
+ if (!record) throw new Error(`Unknown Agent memory: ${selected.id}`);
310
+ this.localEditor = createMemoryUpdateEditor(record);
311
+ this.status = `Editing memory: ${record.id}.`;
312
+ this.lastActionResult = {
313
+ kind: 'guidance',
314
+ title: this.localEditor.title,
315
+ detail: this.localEditor.message,
316
+ safety: 'safe',
317
+ };
318
+ } else if (operation === 'memory-review') {
319
+ const record = this.memoryApi().review(selected.id, { state: 'reviewed', confidence: selected.confidence ?? 100, reviewedBy: 'operator' });
320
+ if (!record) throw new Error(`Unknown Agent memory: ${selected.id}`);
321
+ this.finishLocalOperation('memory', `Reviewed memory ${record.id}`, `${record.summary} is marked reviewed.`);
322
+ } else if (operation === 'memory-stale') {
323
+ const record = this.memoryApi().review(selected.id, { state: 'stale', staleReason: 'Marked stale from Agent workspace', reviewedBy: 'operator' });
324
+ if (!record) throw new Error(`Unknown Agent memory: ${selected.id}`);
325
+ this.finishLocalOperation('memory', `Marked memory stale ${record.id}`, `${record.summary} needs review before reuse.`);
326
+ } else if (operation === 'memory-delete') {
327
+ this.openDeleteEditor('memory', selected);
328
+ } else if (operation === 'persona-edit') {
416
329
  const registry = AgentPersonaRegistry.fromShellPaths(shellPaths);
417
330
  const persona = registry.get(selected.id);
418
331
  if (!persona) throw new Error(`Unknown persona: ${selected.id}`);
@@ -492,11 +405,18 @@ export class AgentWorkspace {
492
405
  }
493
406
 
494
407
  private selectedItemForOperation(operation: AgentWorkspaceLocalOperation): AgentWorkspaceLocalLibraryItem | null {
408
+ if (operation.startsWith('memory-')) return this.selectedLocalLibraryItem('memory');
495
409
  if (operation.startsWith('persona-')) return this.selectedLocalLibraryItem('persona');
496
410
  if (operation.startsWith('skill-')) return this.selectedLocalLibraryItem('skill');
497
411
  return this.selectedLocalLibraryItem('routine');
498
412
  }
499
413
 
414
+ private memoryApi(): MemoryApi {
415
+ const memory = this.context?.clients?.agentKnowledgeApi?.memory;
416
+ if (!memory) throw new Error('Agent Memory API is unavailable; refusing default Knowledge/Wiki or non-Agent fallback.');
417
+ return memory;
418
+ }
419
+
500
420
  private finishLocalOperation(kind: AgentWorkspaceLocalEditorKind, title: string, detail: string): void {
501
421
  this.runtimeSnapshot = this.context ? buildAgentWorkspaceRuntimeSnapshot(this.context) : this.runtimeSnapshot;
502
422
  this.clampLocalLibrarySelection(kind);
@@ -538,7 +458,7 @@ export class AgentWorkspace {
538
458
  return editor.fields.find((field) => field.required && field.value.trim().length === 0) ?? null;
539
459
  }
540
460
 
541
- private submitLocalEditor(): void {
461
+ private submitLocalEditor(requestRender?: () => void): void {
542
462
  const editor = this.localEditor;
543
463
  if (!editor) return;
544
464
  const missing = this.missingEditorField();
@@ -552,6 +472,26 @@ export class AgentWorkspace {
552
472
  this.status = `${missing.label} is required.`;
553
473
  return;
554
474
  }
475
+ if (editor.kind === 'memory') {
476
+ if (editor.mode === 'delete') {
477
+ try {
478
+ this.submitMemoryDeleteEditor(editor);
479
+ } catch (error) {
480
+ const detail = error instanceof Error ? error.message : String(error);
481
+ this.localEditor = { ...editor, message: detail };
482
+ this.status = detail;
483
+ this.lastActionResult = {
484
+ kind: 'error',
485
+ title: `${editor.title} failed`,
486
+ detail,
487
+ };
488
+ }
489
+ requestRender?.();
490
+ return;
491
+ }
492
+ void this.submitMemoryEditor(editor).finally(() => requestRender?.());
493
+ return;
494
+ }
555
495
  const shellPaths = this.context?.workspace?.shellPaths;
556
496
  if (!shellPaths) {
557
497
  this.localEditor = { ...editor, message: 'Cannot save because Agent shell paths are unavailable.' };
@@ -679,7 +619,11 @@ export class AgentWorkspace {
679
619
  this.status = 'Deletion not confirmed.';
680
620
  return;
681
621
  }
682
- if (editor.kind === 'persona') {
622
+ if (editor.kind === 'memory') {
623
+ const removed = this.memoryApi().delete(expectedId);
624
+ if (!removed) throw new Error(`Unknown Agent memory: ${expectedId}`);
625
+ this.finishLocalDelete(editor.kind, expectedId, expectedId);
626
+ } else if (editor.kind === 'persona') {
683
627
  const removed = AgentPersonaRegistry.fromShellPaths(shellPaths).deletePersona(expectedId);
684
628
  this.finishLocalDelete(editor.kind, removed.id, removed.name);
685
629
  } else if (editor.kind === 'skill') {
@@ -691,6 +635,56 @@ export class AgentWorkspace {
691
635
  }
692
636
  }
693
637
 
638
+ private submitMemoryDeleteEditor(editor: AgentWorkspaceLocalEditor): void {
639
+ const expectedId = editor.recordId ?? '';
640
+ const confirmedId = this.editorField('confirm');
641
+ const removed = deleteAgentWorkspaceMemoryEditor(editor, confirmedId, this.memoryApi());
642
+ if (!removed) {
643
+ this.localEditor = {
644
+ ...editor,
645
+ message: `Deletion not confirmed. Type ${expectedId} exactly, then press Enter.`,
646
+ };
647
+ this.status = 'Deletion not confirmed.';
648
+ return;
649
+ }
650
+ this.finishLocalDelete(editor.kind, removed.id, removed.name);
651
+ }
652
+
653
+ private async submitMemoryEditor(editor: AgentWorkspaceLocalEditor): Promise<void> {
654
+ try {
655
+ this.status = 'Saving Agent memory...';
656
+ const result = await submitAgentWorkspaceMemoryEditor(editor, this.memoryApi(), (id) => this.editorField(id));
657
+ this.finishMemoryEditor(result.record, result.verb);
658
+ } catch (error) {
659
+ const detail = error instanceof Error ? error.message : String(error);
660
+ this.localEditor = { ...editor, message: detail };
661
+ this.status = detail;
662
+ this.lastActionResult = {
663
+ kind: 'error',
664
+ title: `${editor.title} failed`,
665
+ detail,
666
+ };
667
+ }
668
+ }
669
+
670
+ private finishMemoryEditor(record: MemoryRecord, verb: 'Created' | 'Updated'): void {
671
+ this.localEditor = null;
672
+ this.runtimeSnapshot = this.context ? buildAgentWorkspaceRuntimeSnapshot(this.context) : this.runtimeSnapshot;
673
+ const categoryIndex = this.categories.findIndex((category) => category.id === 'memory');
674
+ if (categoryIndex >= 0) {
675
+ this.selectedCategoryIndex = categoryIndex;
676
+ this.selectedActionIndex = 0;
677
+ }
678
+ this.status = `${verb} memory: ${record.summary}.`;
679
+ this.lastActionResult = {
680
+ kind: 'refreshed',
681
+ title: `${verb} memory`,
682
+ detail: `${record.summary} (${record.id}) was saved to Agent-owned memory only.`,
683
+ safety: 'safe',
684
+ };
685
+ this.clampSelection();
686
+ }
687
+
694
688
  private finishLocalEditor(kind: AgentWorkspaceLocalEditorKind, id: string, name: string, verb: 'Created' | 'Updated'): void {
695
689
  this.localEditor = null;
696
690
  const categoryId = editorCategoryId(kind);
@@ -749,52 +743,3 @@ export class AgentWorkspace {
749
743
  this.clampSelection();
750
744
  }
751
745
  }
752
-
753
- export function handleAgentWorkspaceToken(
754
- workspace: AgentWorkspace,
755
- token: InputToken,
756
- handleEscape: () => void,
757
- requestRender: () => void,
758
- ): boolean {
759
- if (!workspace.active) return false;
760
-
761
- if (workspace.localEditor) {
762
- if (token.type === 'text') {
763
- workspace.appendEditorText(token.value);
764
- } else if (token.type === 'key') {
765
- if (token.logicalName === 'escape') workspace.cancelLocalEditor();
766
- else if (token.logicalName === 'enter') workspace.submitEditorFieldOrForm();
767
- else if (token.logicalName === 'tab' || token.logicalName === 'down') workspace.moveEditorField(1);
768
- else if (token.logicalName === 'up') workspace.moveEditorField(-1);
769
- else if (token.logicalName === 'backspace' || token.logicalName === 'delete') workspace.editorBackspace();
770
- else if (token.logicalName === 'j' && token.ctrl === true) workspace.appendEditorNewline();
771
- }
772
- requestRender();
773
- return true;
774
- }
775
-
776
- if (token.type === 'key') {
777
- if (token.logicalName === 'escape') {
778
- handleEscape();
779
- return true;
780
- }
781
- if (token.logicalName === 'enter' || token.logicalName === 'space') workspace.activateSelected();
782
- else if (token.logicalName === 'left') workspace.focusCategories();
783
- else if (token.logicalName === 'right') workspace.focusActions();
784
- else if (token.logicalName === 'up') workspace.moveUp();
785
- else if (token.logicalName === 'down') workspace.moveDown();
786
- else if (token.logicalName === 'tab') workspace.toggleFocusPane();
787
- else if (token.logicalName === 'home') workspace.jumpHome();
788
- else if (token.logicalName === 'end') workspace.jumpEnd();
789
- } else if (token.type === 'text') {
790
- if (token.value === 'h') workspace.focusCategories();
791
- else if (token.value === 'l') workspace.focusActions();
792
- else if (token.value === 'j') workspace.moveDown();
793
- else if (token.value === 'k') workspace.moveUp();
794
- else if (token.value === 'r' || token.value === 'R') workspace.refreshRuntimeSnapshot();
795
- else if (token.value === ' ') workspace.activateSelected();
796
- }
797
-
798
- requestRender();
799
- return true;
800
- }
@@ -25,7 +25,6 @@ import type { ConversationManager } from '../core/conversation';
25
25
  import type { ProcessModal } from '../renderer/process-modal.ts';
26
26
  import type { LiveTailModal } from '../renderer/live-tail-modal.ts';
27
27
  import type { BlockActionsMenu } from '../renderer/block-actions.ts';
28
- import type { AgentDetailModal } from '../renderer/agent-detail-modal.ts';
29
28
  import type { ContextInspectorModal } from '../renderer/context-inspector.ts';
30
29
  import type { BookmarkModal } from './bookmark-modal.ts';
31
30
  import type { SettingsModal } from './settings-modal.ts';
@@ -83,7 +82,7 @@ export interface FeedContextMutableInit {
83
82
  * - `selectionModal`, `bookmarkModal`, `settingsModal`, `sessionPickerModal`,
84
83
  * `profilePickerModal` — modal objects constructed once
85
84
  * - `filePicker`, `modelPicker`, `processModal`, `liveTailModal`,
86
- * `agentDetailModal`, `contextInspectorModal`, `blockActionsMenu`,
85
+ * `contextInspectorModal`, `blockActionsMenu`,
87
86
  * `searchManager`, `historySearch`, `onboardingWizard` — service objects constructed once
88
87
  * - `panelManager`, `keybindingsManager` — from uiServices, stable
89
88
  * - `modalStack` — reference to the handler's shared array
@@ -117,7 +116,6 @@ export interface FeedContextStableRefs {
117
116
  onboardingWizard: OnboardingWizardController;
118
117
  processModal: ProcessModal;
119
118
  liveTailModal: LiveTailModal;
120
- agentDetailModal: AgentDetailModal;
121
119
  contextInspectorModal: ContextInspectorModal;
122
120
  blockActionsMenu: BlockActionsMenu;
123
121
  searchManager: SearchManager;
@@ -12,7 +12,6 @@ import type { BlockMeta, ConversationManager } from '../core/conversation';
12
12
  import { ProcessModal } from '../renderer/process-modal.ts';
13
13
  import { LiveTailModal } from '../renderer/live-tail-modal.ts';
14
14
  import { BlockActionsMenu } from '../renderer/block-actions.ts';
15
- import { AgentDetailModal } from '../renderer/agent-detail-modal.ts';
16
15
  import { ContextInspectorModal } from '../renderer/context-inspector.ts';
17
16
  import { BookmarkModal } from './bookmark-modal.ts';
18
17
  import { SettingsModal } from './settings-modal.ts';
@@ -73,7 +72,7 @@ import type { ModelPickerTarget } from './model-picker.ts';
73
72
  * - `selectionModal`, `bookmarkModal`, `settingsModal`, `sessionPickerModal`,
74
73
  * `profilePickerModal` — modal objects constructed once in InputHandler constructor
75
74
  * - `filePicker`, `modelPicker`, `onboardingWizard`, `processModal`, `liveTailModal`,
76
- * `agentDetailModal`, `contextInspectorModal`, `blockActionsMenu`, `searchManager`, `historySearch` —
75
+ * `contextInspectorModal`, `blockActionsMenu`, `searchManager`, `historySearch` —
77
76
  * service objects constructed once
78
77
  * - `panelManager`, `keybindingsManager` — from uiServices, stable for app lifetime
79
78
  * - `modalStack` — reference to the handler's shared array (mutated in place)
@@ -121,7 +120,6 @@ export interface InputFeedContext {
121
120
  readonly onboardingWizard: OnboardingWizardController;
122
121
  readonly processModal: ProcessModal;
123
122
  readonly liveTailModal: LiveTailModal;
124
- readonly agentDetailModal: AgentDetailModal;
125
123
  readonly contextInspectorModal: ContextInspectorModal;
126
124
  readonly blockActionsMenu: BlockActionsMenu;
127
125
  readonly searchManager: SearchManager;
@@ -211,7 +209,6 @@ export function feedInputTokens(context: InputFeedContext, tokens: readonly Inpu
211
209
  handleEscape: context.handleEscape,
212
210
  liveTailModal: context.liveTailModal,
213
211
  processModal: context.processModal,
214
- agentDetailModal: context.agentDetailModal,
215
212
  contextInspectorModal: context.contextInspectorModal,
216
213
  modalOpened: context.modalOpened,
217
214
  filePicker: context.filePicker,
@@ -235,7 +235,6 @@ export function handleEscapeForHandler(handler: InputHandler): void {
235
235
  helpOverlayActive: handler.helpOverlayActive,
236
236
  shortcutsOverlayActive: handler.shortcutsOverlayActive,
237
237
  bookmarkModal: handler.bookmarkModal,
238
- agentDetailModal: handler.agentDetailModal,
239
238
  liveTailModal: handler.liveTailModal,
240
239
  settingsModal: handler.settingsModal,
241
240
  mcpWorkspace: handler.mcpWorkspace,
@@ -121,7 +121,6 @@ export function handleEscape(state: EscapeState): {
121
121
  shortcutsScrollOffset = 0;
122
122
  },
123
123
  closeBookmark: () => state.bookmarkModal.close(),
124
- closeAgentDetail: () => state.agentDetailModal.close(),
125
124
  closeLiveTail: () => state.liveTailModal.close(),
126
125
  closeSettings: () => state.settingsModal.close(),
127
126
  closeMcpWorkspace: () => state.mcpWorkspace?.close(),
@@ -12,7 +12,6 @@ import { handleMcpWorkspaceToken, type McpWorkspace } from './mcp-workspace.ts';
12
12
  import type { CommandContext } from './command-registry.ts';
13
13
  import type { LiveTailModal } from '../renderer/live-tail-modal.ts';
14
14
  import type { ProcessModal } from '../renderer/process-modal.ts';
15
- import type { AgentDetailModal } from '../renderer/agent-detail-modal.ts';
16
15
  import type { ContextInspectorModal } from '../renderer/context-inspector.ts';
17
16
  import type { FilePickerModal } from './file-picker.ts';
18
17
  import type { BlockActionsMenu, BlockActionId } from '../renderer/block-actions.ts';
@@ -65,7 +64,6 @@ export type ModalTokenRouteState = {
65
64
  handleEscape: () => void;
66
65
  liveTailModal: LiveTailModal;
67
66
  processModal: ProcessModal;
68
- agentDetailModal: AgentDetailModal;
69
67
  contextInspectorModal: ContextInspectorModal;
70
68
  modalOpened: (name: string) => void;
71
69
  filePicker: FilePickerModal;
@@ -240,14 +238,6 @@ export function handleModalTokenRoutes(state: ModalTokenRouteState, token: Input
240
238
  return withState(state, true);
241
239
  }
242
240
 
243
- if (handleEscapeOnlyModalToken({
244
- active: state.agentDetailModal.active,
245
- requestRender: state.requestRender,
246
- handleEscape: state.handleEscape,
247
- }, token)) {
248
- return withState(state, true);
249
- }
250
-
251
241
  if (handleEscapeOnlyModalToken({
252
242
  active: state.contextInspectorModal.active,
253
243
  requestRender: state.requestRender,
@@ -259,7 +249,6 @@ export function handleModalTokenRoutes(state: ModalTokenRouteState, token: Input
259
249
  if (handleProcessModalToken({
260
250
  processModal: state.processModal,
261
251
  liveTailModal: state.liveTailModal,
262
- agentDetailModal: state.agentDetailModal,
263
252
  modalOpened: state.modalOpened,
264
253
  requestRender: state.requestRender,
265
254
  handleEscape: state.handleEscape,
@@ -204,15 +204,12 @@ type ProcessRouteState = {
204
204
  getSelected: () => ProcessEntry | undefined;
205
205
  close: () => void;
206
206
  open: () => void;
207
- killSelected: () => boolean;
207
+ stopSelected: () => boolean;
208
208
  refresh: () => void;
209
209
  };
210
210
  liveTailModal: {
211
211
  open: (entry: ProcessEntry) => void;
212
212
  };
213
- agentDetailModal: {
214
- open: (id: string) => void;
215
- };
216
213
  modalOpened: (name: string) => void;
217
214
  requestRender: () => void;
218
215
  handleEscape: () => void;
@@ -231,20 +228,14 @@ export function handleProcessModalToken(state: ProcessRouteState, token: InputTo
231
228
  else if (token.logicalName === 'enter') {
232
229
  const entry = state.processModal.getSelected();
233
230
  if (entry) {
234
- if (entry.type === 'agent') {
235
- state.modalOpened('agentDetail');
236
- state.processModal.close();
237
- state.agentDetailModal.open(entry.id);
238
- } else {
239
- state.modalOpened('liveTail');
240
- state.processModal.close();
241
- state.liveTailModal.open(entry);
242
- }
231
+ state.modalOpened('liveTail');
232
+ state.processModal.close();
233
+ state.liveTailModal.open(entry);
243
234
  }
244
235
  }
245
236
  } else if (token.type === 'text' && token.value === 'k') {
246
- const killed = state.processModal.killSelected();
247
- if (killed) state.processModal.refresh();
237
+ const stopped = state.processModal.stopSelected();
238
+ if (stopped) state.processModal.refresh();
248
239
  }
249
240
 
250
241
  state.requestRender();
@@ -256,7 +247,7 @@ type LiveTailRouteState = {
256
247
  active: boolean;
257
248
  scrollUp: () => void;
258
249
  scrollDown: () => void;
259
- killProcess: () => boolean;
250
+ stopProcess: () => boolean;
260
251
  close: () => void;
261
252
  };
262
253
  processModal: {
@@ -269,8 +260,8 @@ type LiveTailRouteState = {
269
260
  export function handleLiveTailToken(state: LiveTailRouteState, token: InputToken): boolean {
270
261
  if (!state.liveTailModal.active) return false;
271
262
 
272
- const killAndReturn = (): void => {
273
- if (state.liveTailModal.killProcess()) state.handleEscape();
263
+ const stopAndReturn = (): void => {
264
+ if (state.liveTailModal.stopProcess()) state.handleEscape();
274
265
  };
275
266
 
276
267
  if (token.type === 'key') {
@@ -280,9 +271,9 @@ export function handleLiveTailToken(state: LiveTailRouteState, token: InputToken
280
271
  }
281
272
  if (token.logicalName === 'up') state.liveTailModal.scrollUp();
282
273
  else if (token.logicalName === 'down') state.liveTailModal.scrollDown();
283
- else if (token.logicalName === 'k') killAndReturn();
274
+ else if (token.logicalName === 'k') stopAndReturn();
284
275
  } else if (token.type === 'text' && token.value === 'k') {
285
- killAndReturn();
276
+ stopAndReturn();
286
277
  }
287
278
 
288
279
  state.requestRender();
@@ -55,7 +55,6 @@ export type ActiveModalState = {
55
55
  helpOverlayActive: boolean;
56
56
  shortcutsOverlayActive: boolean;
57
57
  bookmarkModal: { active: boolean; close: () => void };
58
- agentDetailModal: { active: boolean; close: () => void };
59
58
  liveTailModal: { active: boolean; close: () => void };
60
59
  settingsModal: { active: boolean; close: () => void };
61
60
  mcpWorkspace?: { active: boolean; close: () => void; reopen: () => void };
@@ -76,7 +75,6 @@ export function getActiveModalName(state: ActiveModalState): string | null {
76
75
  if (state.helpOverlayActive) return 'help';
77
76
  if (state.shortcutsOverlayActive) return 'shortcuts';
78
77
  if (state.bookmarkModal.active) return 'bookmark';
79
- if (state.agentDetailModal.active) return 'agentDetail';
80
78
  if (state.liveTailModal.active) return 'liveTail';
81
79
  if (state.settingsModal.active) return 'settings';
82
80
  if (state.mcpWorkspace?.active) return 'mcpWorkspace';
@@ -98,7 +96,6 @@ export type ModalCloseOps = {
98
96
  resetHelp: () => void;
99
97
  resetShortcuts: () => void;
100
98
  closeBookmark: () => void;
101
- closeAgentDetail: () => void;
102
99
  closeLiveTail: () => void;
103
100
  closeSettings: () => void;
104
101
  closeMcpWorkspace: () => void;
@@ -126,9 +123,6 @@ export function closeModalByName(name: string, ops: ModalCloseOps): void {
126
123
  case 'bookmark':
127
124
  ops.closeBookmark();
128
125
  break;
129
- case 'agentDetail':
130
- ops.closeAgentDetail();
131
- break;
132
126
  case 'liveTail':
133
127
  ops.closeLiveTail();
134
128
  break;