@pellux/goodvibes-agent 1.1.3 → 1.1.5
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.
- package/CHANGELOG.md +13 -0
- package/dist/package/main.js +1780 -939
- package/package.json +1 -1
- package/src/input/agent-workspace-activation.ts +21 -1
- package/src/input/agent-workspace-basic-command-editors.ts +8 -9
- package/src/input/agent-workspace-categories.ts +263 -115
- package/src/input/agent-workspace-category-actions.ts +25 -0
- package/src/input/agent-workspace-host-category.ts +57 -0
- package/src/input/agent-workspace-local-editor-submission.ts +193 -0
- package/src/input/agent-workspace-search.ts +6 -0
- package/src/input/agent-workspace-settings.ts +314 -0
- package/src/input/agent-workspace-setup.ts +20 -0
- package/src/input/agent-workspace-snapshot.ts +89 -0
- package/src/input/agent-workspace-subscription-editor.ts +214 -0
- package/src/input/agent-workspace-types.ts +56 -1
- package/src/input/agent-workspace.ts +139 -164
- package/src/input/handler-modal-token-routes.ts +12 -12
- package/src/input/handler.ts +2 -1
- package/src/main.ts +11 -7
- package/src/renderer/agent-workspace.ts +80 -14
- package/src/shell/agent-workspace-fullscreen.ts +11 -3
- package/src/tools/agent-harness-ui-surface-metadata.ts +1 -1
- package/src/tools/agent-harness-workspace-actions.ts +2 -2
- package/src/version.ts +1 -1
|
@@ -1,24 +1,26 @@
|
|
|
1
1
|
import type { MemoryApi } from '@pellux/goodvibes-sdk/platform/knowledge';
|
|
2
2
|
import type { MemoryRecord } from '@pellux/goodvibes-sdk/platform/state';
|
|
3
|
+
import type { ConfigSetting } from '@pellux/goodvibes-sdk/platform/config';
|
|
3
4
|
import type { ShellPathService } from '@/runtime/index.ts';
|
|
4
5
|
import type { CommandContext } from './command-registry.ts';
|
|
5
6
|
import { AgentNoteRegistry } from '../agent/note-registry.ts';
|
|
6
7
|
import { AgentPersonaRegistry } from '../agent/persona-registry.ts';
|
|
7
8
|
import { AgentRoutineRegistry } from '../agent/routine-registry.ts';
|
|
8
|
-
import {
|
|
9
|
+
import type { AgentRuntimeProfileInfo } from '../agent/runtime-profile.ts';
|
|
9
10
|
import { AgentSkillRegistry } from '../agent/skill-registry.ts';
|
|
10
11
|
import { activateAgentWorkspaceSelection } from './agent-workspace-activation.ts';
|
|
11
12
|
import { AGENT_WORKSPACE_CATEGORIES } from './agent-workspace-categories.ts';
|
|
12
13
|
import { buildAgentWorkspaceCommandEditorSubmission, isAgentWorkspaceCommandEditorKind } from './agent-workspace-command-editor.ts';
|
|
13
|
-
import { createDeleteEditor, editorCategoryId
|
|
14
|
-
import {
|
|
14
|
+
import { createDeleteEditor, editorCategoryId } from './agent-workspace-editors.ts';
|
|
15
|
+
import { submitAgentWorkspaceLocalRegistryEditor } from './agent-workspace-local-editor-submission.ts';
|
|
15
16
|
import { clampAgentWorkspaceLocalLibrarySelection, moveAgentWorkspaceLocalLibraryItemSelection, selectedAgentWorkspaceLocalLibraryItem, type AgentWorkspaceLocalSelectionIndexes } from './agent-workspace-local-selection.ts';
|
|
16
17
|
import { applyAgentWorkspaceLocalLibraryOperation } from './agent-workspace-local-operations.ts';
|
|
17
18
|
import { deleteAgentWorkspaceMemoryEditor, submitAgentWorkspaceMemoryEditor } from './agent-workspace-memory-editor.ts';
|
|
18
19
|
import { jumpAgentWorkspaceSelection, moveAgentWorkspaceSelection, selectAgentWorkspaceCategory } from './agent-workspace-navigation.ts';
|
|
19
|
-
import { buildAgentWorkspaceRequirements } from './agent-workspace-requirements.ts';
|
|
20
20
|
import { appendAgentWorkspaceActionSearchText, backspaceAgentWorkspaceActionSearch, beginAgentWorkspaceActionSearch, clearAgentWorkspaceActionSearch, commitAgentWorkspaceActionSearchSelection, searchAgentWorkspaceActions } from './agent-workspace-search.ts';
|
|
21
|
+
import { agentWorkspaceSettingSchema, applyAgentWorkspaceSettingValue, buildAgentWorkspaceSettingActionEffect, importAgentWorkspaceTuiSettings, isAgentWorkspaceActionVisible } from './agent-workspace-settings.ts';
|
|
21
22
|
import { buildAgentWorkspaceRuntimeSnapshot } from './agent-workspace-snapshot.ts';
|
|
23
|
+
import { submitAgentWorkspaceSubscriptionLoginFinishEditor, submitAgentWorkspaceSubscriptionLoginStartEditor, submitAgentWorkspaceSubscriptionLogoutEditor } from './agent-workspace-subscription-editor.ts';
|
|
22
24
|
import type { AgentWorkspaceAction, AgentWorkspaceActionResult, AgentWorkspaceActionSearchResult, AgentWorkspaceCategory, AgentWorkspaceCommandDispatcher, AgentWorkspaceEditorField, AgentWorkspaceFocusPane, AgentWorkspaceLocalEditor, AgentWorkspaceLocalEditorKind, AgentWorkspaceLocalLibraryItem, AgentWorkspaceLocalOperation, AgentWorkspacePromptDispatcher, AgentWorkspaceRuntimeSnapshot } from './agent-workspace-types.ts';
|
|
23
25
|
import { writeOnboardingCheckMarker, writeOnboardingCompletionMarker } from '../runtime/onboarding/index.ts';
|
|
24
26
|
|
|
@@ -39,14 +41,7 @@ export class AgentWorkspace {
|
|
|
39
41
|
public localEditor: AgentWorkspaceLocalEditor | null = null;
|
|
40
42
|
public actionSearchActive = false;
|
|
41
43
|
public actionSearchQuery = '';
|
|
42
|
-
public readonly selectedLibraryItemIndexes: AgentWorkspaceLocalSelectionIndexes = {
|
|
43
|
-
memory: 0,
|
|
44
|
-
note: 0,
|
|
45
|
-
persona: 0,
|
|
46
|
-
skill: 0,
|
|
47
|
-
routine: 0,
|
|
48
|
-
profile: 0,
|
|
49
|
-
};
|
|
44
|
+
public readonly selectedLibraryItemIndexes: AgentWorkspaceLocalSelectionIndexes = { memory: 0, note: 0, persona: 0, skill: 0, routine: 0, profile: 0 };
|
|
50
45
|
private context: CommandContext | null = null;
|
|
51
46
|
private dispatchCommand: AgentWorkspaceCommandDispatcher | null = null;
|
|
52
47
|
private dispatchPrompt: AgentWorkspacePromptDispatcher | null = null;
|
|
@@ -63,7 +58,10 @@ export class AgentWorkspace {
|
|
|
63
58
|
this.localEditor = null;
|
|
64
59
|
this.actionSearchActive = false;
|
|
65
60
|
this.actionSearchQuery = '';
|
|
66
|
-
if (
|
|
61
|
+
if (!categoryId) {
|
|
62
|
+
this.selectedCategoryIndex = 0;
|
|
63
|
+
this.selectedActionIndex = 0;
|
|
64
|
+
} else if (!this.selectCategory(categoryId)) {
|
|
67
65
|
const normalized = categoryId.trim();
|
|
68
66
|
this.status = `Unknown Agent workspace area: ${normalized}`;
|
|
69
67
|
this.lastActionResult = {
|
|
@@ -98,7 +96,7 @@ export class AgentWorkspace {
|
|
|
98
96
|
|
|
99
97
|
get actions(): readonly AgentWorkspaceAction[] {
|
|
100
98
|
if (this.actionSearchActive) return this.actionSearchResults.map((result) => result.action);
|
|
101
|
-
return this.selectedCategory.actions;
|
|
99
|
+
return this.selectedCategory.actions.filter((action) => isAgentWorkspaceActionVisible(this.context, action));
|
|
102
100
|
}
|
|
103
101
|
|
|
104
102
|
get selectedAction(): AgentWorkspaceAction | null {
|
|
@@ -111,7 +109,12 @@ export class AgentWorkspace {
|
|
|
111
109
|
}
|
|
112
110
|
|
|
113
111
|
get actionSearchResults(): readonly AgentWorkspaceActionSearchResult[] {
|
|
114
|
-
|
|
112
|
+
if (!this.actionSearchActive) return [];
|
|
113
|
+
const categories = this.categories.map((category) => ({
|
|
114
|
+
...category,
|
|
115
|
+
actions: category.actions.filter((action) => isAgentWorkspaceActionVisible(this.context, action)),
|
|
116
|
+
}));
|
|
117
|
+
return searchAgentWorkspaceActions(categories, this.actionSearchQuery);
|
|
115
118
|
}
|
|
116
119
|
|
|
117
120
|
get selectedActionSearchResult(): AgentWorkspaceActionSearchResult | null {
|
|
@@ -178,11 +181,7 @@ export class AgentWorkspace {
|
|
|
178
181
|
}
|
|
179
182
|
this.runtimeSnapshot = buildAgentWorkspaceRuntimeSnapshot(this.context);
|
|
180
183
|
this.status = 'Runtime context refreshed.';
|
|
181
|
-
this.lastActionResult = {
|
|
182
|
-
kind: 'refreshed',
|
|
183
|
-
title: 'Runtime context refreshed',
|
|
184
|
-
detail: 'Provider, model, session, local memory, runtime endpoint, and Agent knowledge route posture were re-read from the live command context.',
|
|
185
|
-
};
|
|
184
|
+
this.lastActionResult = { kind: 'refreshed', title: 'Runtime context refreshed', detail: 'Provider, model, session, local memory, runtime endpoint, and Agent knowledge route posture were re-read from the live command context.' };
|
|
186
185
|
}
|
|
187
186
|
|
|
188
187
|
cancelLocalEditor(): void {
|
|
@@ -321,32 +320,86 @@ export class AgentWorkspace {
|
|
|
321
320
|
}
|
|
322
321
|
|
|
323
322
|
try {
|
|
324
|
-
const marker = {
|
|
325
|
-
scope: 'user',
|
|
326
|
-
source: 'wizard',
|
|
327
|
-
mode: 'new',
|
|
328
|
-
workspaceRoot: shellPaths.workingDirectory,
|
|
329
|
-
} as const;
|
|
323
|
+
const marker = { scope: 'user', source: 'wizard', mode: 'new', workspaceRoot: shellPaths.workingDirectory } as const;
|
|
330
324
|
writeOnboardingCheckMarker(shellPaths, marker);
|
|
331
325
|
writeOnboardingCompletionMarker(shellPaths, marker);
|
|
332
326
|
this.status = 'Onboarding applied and closed.';
|
|
333
|
-
this.lastActionResult = {
|
|
334
|
-
kind: 'refreshed',
|
|
335
|
-
title: 'Onboarding complete',
|
|
336
|
-
detail: 'Saved the user onboarding completion marker. Future normal launches start in the main conversation.',
|
|
337
|
-
safety: 'safe',
|
|
338
|
-
};
|
|
327
|
+
this.lastActionResult = { kind: 'refreshed', title: 'Onboarding complete', detail: 'Saved the user onboarding completion marker. Future normal launches start in the main conversation.', safety: 'safe' };
|
|
339
328
|
if (!this.context?.dismissAgentWorkspace?.()) this.close();
|
|
340
329
|
} catch (error) {
|
|
341
330
|
const detail = error instanceof Error ? error.message : String(error);
|
|
342
331
|
this.status = 'Onboarding completion failed.';
|
|
332
|
+
this.lastActionResult = { kind: 'error', title: 'Onboarding completion failed', detail, safety: 'safe' };
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
openModelPickerAction(action: AgentWorkspaceAction, requestRender?: () => void): void {
|
|
337
|
+
const target = action.modelPickerTarget ?? 'main';
|
|
338
|
+
const opened = action.modelPickerFlow === 'model'
|
|
339
|
+
? this.context?.openModelPickerWithTarget?.(target)
|
|
340
|
+
: this.context?.openProviderModelPickerWithTarget?.(target);
|
|
341
|
+
if (!opened) {
|
|
342
|
+
this.status = 'Model picker is unavailable.';
|
|
343
343
|
this.lastActionResult = {
|
|
344
344
|
kind: 'error',
|
|
345
|
-
title: '
|
|
346
|
-
detail,
|
|
347
|
-
safety:
|
|
345
|
+
title: 'Model picker unavailable',
|
|
346
|
+
detail: 'This runtime cannot open the model picker from Agent workspace.',
|
|
347
|
+
safety: action.safety,
|
|
348
348
|
};
|
|
349
|
+
requestRender?.();
|
|
350
|
+
return;
|
|
349
351
|
}
|
|
352
|
+
this.status = `Opening ${action.label}.`;
|
|
353
|
+
this.lastActionResult = {
|
|
354
|
+
kind: 'dispatched',
|
|
355
|
+
title: `Opening ${action.label}`,
|
|
356
|
+
detail: 'Opened the shared provider/model picker for this setup target.',
|
|
357
|
+
safety: action.safety,
|
|
358
|
+
};
|
|
359
|
+
requestRender?.();
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
openSettingsModalAction(action: AgentWorkspaceAction, requestRender?: () => void): void {
|
|
363
|
+
if (!this.context?.openSettingsModal) {
|
|
364
|
+
this.status = 'Settings are unavailable.';
|
|
365
|
+
this.lastActionResult = {
|
|
366
|
+
kind: 'error',
|
|
367
|
+
title: 'Settings unavailable',
|
|
368
|
+
detail: 'This runtime cannot open settings from Agent workspace.',
|
|
369
|
+
safety: action.safety,
|
|
370
|
+
};
|
|
371
|
+
requestRender?.();
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
this.context.openSettingsModal(action.settingsTarget);
|
|
375
|
+
this.status = `Opening ${action.label}.`;
|
|
376
|
+
this.lastActionResult = {
|
|
377
|
+
kind: 'dispatched',
|
|
378
|
+
title: `Opening ${action.label}`,
|
|
379
|
+
detail: 'Opened the shared settings surface for this setup area.',
|
|
380
|
+
safety: action.safety,
|
|
381
|
+
};
|
|
382
|
+
requestRender?.();
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
applySettingAction(action: AgentWorkspaceAction, requestRender?: () => void): void {
|
|
386
|
+
const effect = buildAgentWorkspaceSettingActionEffect(this.context, action);
|
|
387
|
+
if (effect.kind === 'result') {
|
|
388
|
+
this.status = effect.status;
|
|
389
|
+
this.lastActionResult = effect.result;
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
if (effect.kind === 'editor') {
|
|
393
|
+
this.localEditor = effect.editor;
|
|
394
|
+
this.status = effect.status;
|
|
395
|
+
this.lastActionResult = effect.result;
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
void this.applySettingValue(effect.setting, effect.value, requestRender);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
importTuiSettings(requestRender?: () => void): void {
|
|
402
|
+
void this.importTuiSettingsAsync(requestRender);
|
|
350
403
|
}
|
|
351
404
|
|
|
352
405
|
private selectedItemForOperation(operation: AgentWorkspaceLocalOperation): AgentWorkspaceLocalLibraryItem | null {
|
|
@@ -357,6 +410,24 @@ export class AgentWorkspace {
|
|
|
357
410
|
return this.selectedLocalLibraryItem('routine');
|
|
358
411
|
}
|
|
359
412
|
|
|
413
|
+
private async applySettingValue(setting: ConfigSetting, value: unknown, requestRender?: () => void): Promise<void> {
|
|
414
|
+
const outcome = await applyAgentWorkspaceSettingValue(this.context, setting, value);
|
|
415
|
+
this.runtimeSnapshot = this.context ? buildAgentWorkspaceRuntimeSnapshot(this.context) : this.runtimeSnapshot;
|
|
416
|
+
this.clampSelection();
|
|
417
|
+
this.status = outcome.status;
|
|
418
|
+
this.lastActionResult = outcome.result;
|
|
419
|
+
requestRender?.();
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
private async importTuiSettingsAsync(requestRender?: () => void): Promise<void> {
|
|
423
|
+
const outcome = await importAgentWorkspaceTuiSettings(this.context);
|
|
424
|
+
this.runtimeSnapshot = outcome.runtimeSnapshot ?? this.runtimeSnapshot;
|
|
425
|
+
this.clampSelection();
|
|
426
|
+
this.status = outcome.status;
|
|
427
|
+
this.lastActionResult = outcome.result;
|
|
428
|
+
requestRender?.();
|
|
429
|
+
}
|
|
430
|
+
|
|
360
431
|
private memoryApi(): MemoryApi {
|
|
361
432
|
const memory = this.context?.clients?.agentKnowledgeApi?.memory;
|
|
362
433
|
if (!memory) throw new Error('Agent Memory API is unavailable; refusing default knowledge or non-Agent fallback.');
|
|
@@ -424,11 +495,37 @@ export class AgentWorkspace {
|
|
|
424
495
|
this.status = `${missing.label} is required.`;
|
|
425
496
|
return;
|
|
426
497
|
}
|
|
498
|
+
if (editor.kind === 'subscription-login-start') {
|
|
499
|
+
void submitAgentWorkspaceSubscriptionLoginStartEditor(this, editor, this.context, (id) => this.editorField(id)).finally(() => requestRender?.());
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
if (editor.kind === 'subscription-login-finish') {
|
|
503
|
+
void submitAgentWorkspaceSubscriptionLoginFinishEditor(this, editor, this.context, (id) => this.editorField(id)).finally(() => requestRender?.());
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
if (editor.kind === 'subscription-logout') {
|
|
507
|
+
submitAgentWorkspaceSubscriptionLogoutEditor(this, editor, this.context, (id) => this.editorField(id));
|
|
508
|
+
requestRender?.();
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
427
511
|
if (isAgentWorkspaceCommandEditorKind(editor.kind)) {
|
|
428
512
|
this.submitCommandEditor(editor);
|
|
429
513
|
requestRender?.();
|
|
430
514
|
return;
|
|
431
515
|
}
|
|
516
|
+
if (editor.kind === 'setting-set') {
|
|
517
|
+
const setting = editor.recordId ? agentWorkspaceSettingSchema(this.context, editor.recordId) : null;
|
|
518
|
+
if (!setting) {
|
|
519
|
+
this.localEditor = { ...editor, message: 'Unknown setting; cannot save.' };
|
|
520
|
+
this.status = 'Unknown setting; cannot save.';
|
|
521
|
+
requestRender?.();
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
const value = this.editorField('value');
|
|
525
|
+
this.localEditor = null;
|
|
526
|
+
void this.applySettingValue(setting, value, requestRender);
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
432
529
|
if (editor.kind === 'memory') {
|
|
433
530
|
if (editor.mode === 'delete') {
|
|
434
531
|
try {
|
|
@@ -461,135 +558,13 @@ export class AgentWorkspace {
|
|
|
461
558
|
return;
|
|
462
559
|
}
|
|
463
560
|
try {
|
|
464
|
-
|
|
465
|
-
this.
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
name: this.editorField('name'),
|
|
472
|
-
description: this.editorField('description'),
|
|
473
|
-
notes: this.editorField('notes'),
|
|
474
|
-
tags: splitList(this.editorField('tags')),
|
|
475
|
-
triggers: splitList(this.editorField('triggers')),
|
|
476
|
-
enable: isAffirmative(this.editorField('enable')),
|
|
477
|
-
});
|
|
478
|
-
this.finishLocalEditor(created.kind, created.id, created.name, 'Created');
|
|
479
|
-
} else if (editor.kind === 'profile') {
|
|
480
|
-
const template = this.editorField('template');
|
|
481
|
-
const templateId = template && template.toLowerCase() !== 'none' ? template : undefined;
|
|
482
|
-
const profile = createAgentRuntimeProfile(shellPaths.homeDirectory, this.editorField('name'), {
|
|
483
|
-
...(templateId ? { templateId } : {}),
|
|
484
|
-
});
|
|
485
|
-
this.finishProfileEditor(profile);
|
|
486
|
-
} else if (editor.kind === 'note') {
|
|
487
|
-
const registry = AgentNoteRegistry.fromShellPaths(shellPaths);
|
|
488
|
-
if (editor.mode === 'update' && editor.recordId) {
|
|
489
|
-
const updated = registry.update(editor.recordId, {
|
|
490
|
-
title: this.editorField('title'),
|
|
491
|
-
body: this.editorField('body'),
|
|
492
|
-
sourceUrl: this.editorField('sourceUrl'),
|
|
493
|
-
tags: splitList(this.editorField('tags')),
|
|
494
|
-
provenance: 'Workspace',
|
|
495
|
-
});
|
|
496
|
-
this.finishLocalEditor(editor.kind, updated.id, updated.title, 'Updated');
|
|
497
|
-
return;
|
|
498
|
-
}
|
|
499
|
-
const created = registry.create({
|
|
500
|
-
title: this.editorField('title'),
|
|
501
|
-
body: this.editorField('body'),
|
|
502
|
-
sourceUrl: this.editorField('sourceUrl'),
|
|
503
|
-
tags: splitList(this.editorField('tags')),
|
|
504
|
-
source: 'user',
|
|
505
|
-
provenance: 'Workspace',
|
|
506
|
-
});
|
|
507
|
-
this.finishLocalEditor(editor.kind, created.id, created.title, 'Created');
|
|
508
|
-
} else if (editor.kind === 'persona') {
|
|
509
|
-
const registry = AgentPersonaRegistry.fromShellPaths(shellPaths);
|
|
510
|
-
if (editor.mode === 'update' && editor.recordId) {
|
|
511
|
-
const wasActive = registry.snapshot().activePersonaId === editor.recordId;
|
|
512
|
-
const updated = registry.update(editor.recordId, {
|
|
513
|
-
name: this.editorField('name'),
|
|
514
|
-
description: this.editorField('description'),
|
|
515
|
-
body: this.editorField('body'),
|
|
516
|
-
tags: splitList(this.editorField('tags')),
|
|
517
|
-
triggers: splitList(this.editorField('triggers')),
|
|
518
|
-
provenance: 'Workspace',
|
|
519
|
-
});
|
|
520
|
-
if (isAffirmative(this.editorField('activate'))) registry.setActive(updated.id);
|
|
521
|
-
else if (wasActive) registry.clearActive();
|
|
522
|
-
this.finishLocalEditor(editor.kind, updated.id, updated.name, 'Updated');
|
|
523
|
-
return;
|
|
524
|
-
}
|
|
525
|
-
const created = registry.create({
|
|
526
|
-
name: this.editorField('name'),
|
|
527
|
-
description: this.editorField('description'),
|
|
528
|
-
body: this.editorField('body'),
|
|
529
|
-
tags: splitList(this.editorField('tags')),
|
|
530
|
-
triggers: splitList(this.editorField('triggers')),
|
|
531
|
-
source: 'user',
|
|
532
|
-
provenance: 'Workspace',
|
|
533
|
-
});
|
|
534
|
-
if (isAffirmative(this.editorField('activate'))) registry.setActive(created.id);
|
|
535
|
-
this.finishLocalEditor(editor.kind, created.id, created.name, 'Created');
|
|
536
|
-
} else if (editor.kind === 'skill') {
|
|
537
|
-
const registry = AgentSkillRegistry.fromShellPaths(shellPaths);
|
|
538
|
-
if (editor.mode === 'update' && editor.recordId) {
|
|
539
|
-
const updated = registry.update(editor.recordId, {
|
|
540
|
-
name: this.editorField('name'),
|
|
541
|
-
description: this.editorField('description'),
|
|
542
|
-
procedure: this.editorField('procedure'),
|
|
543
|
-
triggers: splitList(this.editorField('triggers')),
|
|
544
|
-
tags: splitList(this.editorField('tags')),
|
|
545
|
-
requirements: buildAgentWorkspaceRequirements((id) => this.editorField(id)),
|
|
546
|
-
provenance: 'Workspace',
|
|
547
|
-
});
|
|
548
|
-
registry.setEnabled(updated.id, isAffirmative(this.editorField('enabled')));
|
|
549
|
-
this.finishLocalEditor(editor.kind, updated.id, updated.name, 'Updated');
|
|
550
|
-
return;
|
|
551
|
-
}
|
|
552
|
-
const created = registry.create({
|
|
553
|
-
name: this.editorField('name'),
|
|
554
|
-
description: this.editorField('description'),
|
|
555
|
-
procedure: this.editorField('procedure'),
|
|
556
|
-
triggers: splitList(this.editorField('triggers')),
|
|
557
|
-
tags: splitList(this.editorField('tags')),
|
|
558
|
-
requirements: buildAgentWorkspaceRequirements((id) => this.editorField(id)),
|
|
559
|
-
enabled: isAffirmative(this.editorField('enabled')),
|
|
560
|
-
source: 'user',
|
|
561
|
-
provenance: 'Workspace',
|
|
562
|
-
});
|
|
563
|
-
this.finishLocalEditor(editor.kind, created.id, created.name, 'Created');
|
|
564
|
-
} else {
|
|
565
|
-
const registry = AgentRoutineRegistry.fromShellPaths(shellPaths);
|
|
566
|
-
if (editor.mode === 'update' && editor.recordId) {
|
|
567
|
-
const updated = registry.update(editor.recordId, {
|
|
568
|
-
name: this.editorField('name'),
|
|
569
|
-
description: this.editorField('description'),
|
|
570
|
-
steps: this.editorField('steps'),
|
|
571
|
-
triggers: splitList(this.editorField('triggers')),
|
|
572
|
-
tags: splitList(this.editorField('tags')),
|
|
573
|
-
requirements: buildAgentWorkspaceRequirements((id) => this.editorField(id)),
|
|
574
|
-
provenance: 'Workspace',
|
|
575
|
-
});
|
|
576
|
-
registry.setEnabled(updated.id, isAffirmative(this.editorField('enabled')));
|
|
577
|
-
this.finishLocalEditor(editor.kind, updated.id, updated.name, 'Updated');
|
|
578
|
-
return;
|
|
579
|
-
}
|
|
580
|
-
const created = registry.create({
|
|
581
|
-
name: this.editorField('name'),
|
|
582
|
-
description: this.editorField('description'),
|
|
583
|
-
steps: this.editorField('steps'),
|
|
584
|
-
triggers: splitList(this.editorField('triggers')),
|
|
585
|
-
tags: splitList(this.editorField('tags')),
|
|
586
|
-
requirements: buildAgentWorkspaceRequirements((id) => this.editorField(id)),
|
|
587
|
-
enabled: isAffirmative(this.editorField('enabled')),
|
|
588
|
-
source: 'user',
|
|
589
|
-
provenance: 'Workspace',
|
|
590
|
-
});
|
|
591
|
-
this.finishLocalEditor(editor.kind, created.id, created.name, 'Created');
|
|
592
|
-
}
|
|
561
|
+
submitAgentWorkspaceLocalRegistryEditor(shellPaths, editor, {
|
|
562
|
+
readField: (id) => this.editorField(id),
|
|
563
|
+
learnedBehaviorTarget: () => this.learnedBehaviorTarget(),
|
|
564
|
+
submitDeleteEditor: () => this.submitLocalDeleteEditor(shellPaths, editor),
|
|
565
|
+
finishLocalEditor: (kind, id, name, verb) => this.finishLocalEditor(kind, id, name, verb),
|
|
566
|
+
finishProfileEditor: (profile) => this.finishProfileEditor(profile),
|
|
567
|
+
});
|
|
593
568
|
} catch (error) {
|
|
594
569
|
const detail = error instanceof Error ? error.message : String(error);
|
|
595
570
|
this.localEditor = { ...editor, message: detail };
|
|
@@ -131,6 +131,18 @@ export function handleModalTokenRoutes(state: ModalTokenRouteState, token: Input
|
|
|
131
131
|
return withState(state, true);
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
if (handleModelPickerToken({
|
|
135
|
+
modelPicker: state.modelPicker,
|
|
136
|
+
modalStack: state.modalStack,
|
|
137
|
+
commandContext: state.commandContext,
|
|
138
|
+
getViewportHeight: state.getViewportHeight,
|
|
139
|
+
requestRender: state.requestRender,
|
|
140
|
+
handleEscape: state.handleEscape,
|
|
141
|
+
onModelPickerCommit: state.onModelPickerCommit,
|
|
142
|
+
}, token)) {
|
|
143
|
+
return withState(state, true);
|
|
144
|
+
}
|
|
145
|
+
|
|
134
146
|
if (handleSettingsModalToken({
|
|
135
147
|
settingsModal: state.settingsModal,
|
|
136
148
|
commandContext: state.commandContext,
|
|
@@ -200,18 +212,6 @@ export function handleModalTokenRoutes(state: ModalTokenRouteState, token: Input
|
|
|
200
212
|
return withState(state, true, historyState);
|
|
201
213
|
}
|
|
202
214
|
|
|
203
|
-
if (handleModelPickerToken({
|
|
204
|
-
modelPicker: state.modelPicker,
|
|
205
|
-
modalStack: state.modalStack,
|
|
206
|
-
commandContext: state.commandContext,
|
|
207
|
-
getViewportHeight: state.getViewportHeight,
|
|
208
|
-
requestRender: state.requestRender,
|
|
209
|
-
handleEscape: state.handleEscape,
|
|
210
|
-
onModelPickerCommit: state.onModelPickerCommit,
|
|
211
|
-
}, token)) {
|
|
212
|
-
return withState(state, true);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
215
|
if (handleLiveTailToken({
|
|
216
216
|
liveTailModal: state.liveTailModal,
|
|
217
217
|
processModal: state.processModal,
|
package/src/input/handler.ts
CHANGED
|
@@ -336,7 +336,8 @@ export class InputHandler {
|
|
|
336
336
|
public handleBlockToggle(): void { handleBlockToggleForHandler(this); }
|
|
337
337
|
public handleCtrlC(): void { handleCtrlCForHandler(this); }
|
|
338
338
|
public modalOpened(name: string): void {
|
|
339
|
-
|
|
339
|
+
const keepAgentWorkspaceUnderlay = name === 'modelPicker' || name === 'settings';
|
|
340
|
+
if (name !== 'agentWorkspace' && !keepAgentWorkspaceUnderlay && this.agentWorkspace.active) {
|
|
340
341
|
this.closeAgentWorkspaceModal();
|
|
341
342
|
}
|
|
342
343
|
modalOpenedForHandler(this, name);
|
package/src/main.ts
CHANGED
|
@@ -15,6 +15,8 @@ import { PermissionPromptUI } from './permissions/prompt.ts';
|
|
|
15
15
|
import { CommandRegistry } from './input/command-registry.ts';
|
|
16
16
|
import type { CommandContext } from './input/command-registry.ts';
|
|
17
17
|
import { renderProcessIndicator } from './renderer/process-indicator.ts';
|
|
18
|
+
import { renderModelWorkspace } from './renderer/model-workspace.ts';
|
|
19
|
+
import { renderSettingsModal } from './renderer/settings-modal.ts';
|
|
18
20
|
import { registerBuiltinCommands } from './input/commands.ts';
|
|
19
21
|
import { ScheduleManager } from '@pellux/goodvibes-sdk/platform/tools';
|
|
20
22
|
import { InputHistory } from './input/input-history.ts';
|
|
@@ -40,7 +42,7 @@ import {
|
|
|
40
42
|
} from '@/runtime/index.ts';
|
|
41
43
|
import type { SessionSnapshot } from '@/runtime/index.ts';
|
|
42
44
|
import { handleBlockingShellInput, type PendingPermissionState } from './shell/blocking-input.ts';
|
|
43
|
-
import { createAgentWorkspaceFullscreenComposite } from './shell/agent-workspace-fullscreen.ts';
|
|
45
|
+
import { createAgentWorkspaceFullscreenComposite, createFullscreenCompositeFromLines } from './shell/agent-workspace-fullscreen.ts';
|
|
44
46
|
import { getTerminalSize } from './shell/terminal-size.ts';
|
|
45
47
|
import { wireShellUiOpeners } from './shell/ui-openers.ts';
|
|
46
48
|
import { deriveComposerState } from './core/composer-state.ts';
|
|
@@ -477,6 +479,14 @@ async function main() {
|
|
|
477
479
|
input.setPanelMouseLayout(null);
|
|
478
480
|
activeConversationWidth = width;
|
|
479
481
|
conversation.setSplashSuppressed(true);
|
|
482
|
+
if (input.modelPicker.active) {
|
|
483
|
+
compositor.composite(createFullscreenCompositeFromLines(renderModelWorkspace(input.modelPicker, width, height), width, height));
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
if (input.settingsModal.active) {
|
|
487
|
+
compositor.composite(createFullscreenCompositeFromLines(renderSettingsModal(input.settingsModal, width, height), width, height));
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
480
490
|
compositor.composite(createAgentWorkspaceFullscreenComposite(input.agentWorkspace, width, height));
|
|
481
491
|
return;
|
|
482
492
|
}
|
|
@@ -709,7 +719,6 @@ async function main() {
|
|
|
709
719
|
streamTokenSpeed = elapsed > 0 ? streamDeltaCount / elapsed : 0;
|
|
710
720
|
}));
|
|
711
721
|
|
|
712
|
-
// --- Terminal setup ---
|
|
713
722
|
stdin.setRawMode(true);
|
|
714
723
|
stdin.resume();
|
|
715
724
|
stdin.setEncoding('utf8');
|
|
@@ -748,11 +757,9 @@ async function main() {
|
|
|
748
757
|
process.on('unhandledRejection', unhandledRejectionHandler);
|
|
749
758
|
stdout.on('resize', resizeHandler);
|
|
750
759
|
|
|
751
|
-
// Initial render
|
|
752
760
|
conversation.rebuildHistory();
|
|
753
761
|
render();
|
|
754
762
|
|
|
755
|
-
// --- Crash recovery check ---
|
|
756
763
|
const recoveryInfo = checkRecoveryFile({ workingDirectory: workingDir, homeDirectory });
|
|
757
764
|
if (recoveryInfo) {
|
|
758
765
|
systemMessageRouter.high(`[Recovery] Found unsaved session from ${new Date(recoveryInfo.timestamp).toLocaleString()}. Title: "${recoveryInfo.title}". Press Ctrl+R to restore, Esc to discard, or start typing to ignore it.`);
|
|
@@ -763,7 +770,6 @@ async function main() {
|
|
|
763
770
|
recoveryPending = true;
|
|
764
771
|
}
|
|
765
772
|
|
|
766
|
-
// --- Auto-save to recovery file every 60s ---
|
|
767
773
|
recoveryInterval = setInterval(() => {
|
|
768
774
|
const snapshot = buildCurrentSessionSnapshot();
|
|
769
775
|
writeRecoveryFile(
|
|
@@ -773,9 +779,7 @@ async function main() {
|
|
|
773
779
|
{ workingDirectory: workingDir, homeDirectory },
|
|
774
780
|
);
|
|
775
781
|
}, 60_000);
|
|
776
|
-
|
|
777
782
|
}
|
|
778
|
-
|
|
779
783
|
main().catch((err: unknown) => {
|
|
780
784
|
const detail = formatFatalStartupErrorForLog(err);
|
|
781
785
|
try {
|