@pellux/goodvibes-agent 1.1.4 → 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 +6 -0
- package/dist/package/main.js +1273 -899
- package/package.json +1 -1
- package/src/input/agent-workspace-activation.ts +10 -0
- package/src/input/agent-workspace-basic-command-editors.ts +8 -9
- package/src/input/agent-workspace-categories.ts +109 -117
- 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-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 +44 -2
- package/src/input/agent-workspace.ts +73 -133
- 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 +68 -3
- package/src/shell/agent-workspace-fullscreen.ts +11 -3
- package/src/version.ts +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ModelPickerTarget } from './model-picker.ts';
|
|
1
2
|
import type { AgentWorkspaceChannelStatus } from './agent-workspace-channels.ts';
|
|
2
3
|
import type { AgentWorkspaceSetupChecklistItem } from './agent-workspace-setup.ts';
|
|
3
4
|
import type { AgentWorkspaceVoiceMediaReadiness } from './agent-workspace-voice-media.ts';
|
|
@@ -17,7 +18,7 @@ export const AGENT_WORKSPACE_CATEGORY_IDS = [
|
|
|
17
18
|
'onboarding-channels',
|
|
18
19
|
'onboarding-voice-media',
|
|
19
20
|
'onboarding-context',
|
|
20
|
-
'onboarding-
|
|
21
|
+
'onboarding-automation',
|
|
21
22
|
'research',
|
|
22
23
|
'artifacts',
|
|
23
24
|
'conversation',
|
|
@@ -40,7 +41,7 @@ export const AGENT_WORKSPACE_CATEGORY_IDS = [
|
|
|
40
41
|
|
|
41
42
|
export type AgentWorkspaceCategoryId = (typeof AGENT_WORKSPACE_CATEGORY_IDS)[number];
|
|
42
43
|
|
|
43
|
-
export type AgentWorkspaceActionKind = 'command' | 'guidance' | 'workspace' | 'editor' | 'setting' | 'settings-import' | 'local-selection' | 'local-operation' | 'onboarding-complete';
|
|
44
|
+
export type AgentWorkspaceActionKind = 'command' | 'guidance' | 'workspace' | 'editor' | 'setting' | 'settings-import' | 'model-picker' | 'settings-modal' | 'local-selection' | 'local-operation' | 'onboarding-complete';
|
|
44
45
|
|
|
45
46
|
export type AgentWorkspaceLocalEditorKind = 'memory' | 'note' | 'persona' | 'skill' | 'routine' | 'profile';
|
|
46
47
|
|
|
@@ -258,6 +259,9 @@ export interface AgentWorkspaceAction {
|
|
|
258
259
|
readonly editorKind?: AgentWorkspaceEditorKind;
|
|
259
260
|
readonly settingKey?: string;
|
|
260
261
|
readonly settingValueHint?: string;
|
|
262
|
+
readonly modelPickerTarget?: ModelPickerTarget;
|
|
263
|
+
readonly modelPickerFlow?: 'providerModel' | 'model';
|
|
264
|
+
readonly settingsTarget?: string;
|
|
261
265
|
readonly visibleWhenSettingKey?: string;
|
|
262
266
|
readonly visibleWhenSettingValue?: string | boolean | number;
|
|
263
267
|
readonly localKind?: AgentWorkspaceLocalEditorKind;
|
|
@@ -362,11 +366,49 @@ export interface AgentWorkspaceRuntimeSnapshot {
|
|
|
362
366
|
readonly provider: string;
|
|
363
367
|
readonly model: string;
|
|
364
368
|
readonly modelDisplayName: string;
|
|
369
|
+
readonly embeddingProvider: string;
|
|
370
|
+
readonly reasoningEffort: string;
|
|
371
|
+
readonly helperEnabled: boolean;
|
|
372
|
+
readonly toolLlmEnabled: boolean;
|
|
373
|
+
readonly providerFailureHints: boolean;
|
|
374
|
+
readonly cacheEnabled: boolean;
|
|
375
|
+
readonly cacheStableTtl: string;
|
|
376
|
+
readonly cacheMonitorHitRate: boolean;
|
|
377
|
+
readonly cacheHitRateWarningThreshold: number;
|
|
378
|
+
readonly hitlMode: string;
|
|
379
|
+
readonly guidanceMode: string;
|
|
380
|
+
readonly saveHistory: boolean;
|
|
381
|
+
readonly autoApprove: boolean;
|
|
382
|
+
readonly autoCompactThreshold: number;
|
|
383
|
+
readonly staleContextWarnings: boolean;
|
|
384
|
+
readonly showThinking: boolean;
|
|
385
|
+
readonly showReasoningSummary: boolean;
|
|
386
|
+
readonly theme: string;
|
|
387
|
+
readonly stream: boolean;
|
|
388
|
+
readonly lineNumbers: string;
|
|
389
|
+
readonly operationalMessages: string;
|
|
390
|
+
readonly systemMessages: string;
|
|
391
|
+
readonly releaseChannel: string;
|
|
392
|
+
readonly permissionMode: string;
|
|
393
|
+
readonly toolAutoHeal: boolean;
|
|
394
|
+
readonly toolsDefaultTokenBudget: number;
|
|
395
|
+
readonly artifactMaxBytes: number;
|
|
396
|
+
readonly rawPromptTelemetry: boolean;
|
|
397
|
+
readonly automationEnabled: boolean;
|
|
398
|
+
readonly automationMaxConcurrentRuns: number;
|
|
399
|
+
readonly automationRunHistoryLimit: number;
|
|
400
|
+
readonly automationDefaultTimeoutMs: number;
|
|
401
|
+
readonly automationCatchUpWindowMinutes: number;
|
|
402
|
+
readonly automationFailureCooldownMs: number;
|
|
403
|
+
readonly automationDeleteAfterRun: boolean;
|
|
365
404
|
readonly sessionId: string;
|
|
366
405
|
readonly workingDirectory: string;
|
|
367
406
|
readonly homeDirectory: string;
|
|
368
407
|
readonly runtimeBaseUrl: string;
|
|
369
408
|
readonly runtimeOwnership: 'external';
|
|
409
|
+
readonly activeSubscriptionCount: number;
|
|
410
|
+
readonly pendingSubscriptionCount: number;
|
|
411
|
+
readonly availableSubscriptionProviderCount: number;
|
|
370
412
|
readonly sessionMemoryCount: number;
|
|
371
413
|
readonly localMemoryCount: number;
|
|
372
414
|
readonly localMemoryReviewQueueCount: number;
|
|
@@ -6,21 +6,21 @@ import type { CommandContext } from './command-registry.ts';
|
|
|
6
6
|
import { AgentNoteRegistry } from '../agent/note-registry.ts';
|
|
7
7
|
import { AgentPersonaRegistry } from '../agent/persona-registry.ts';
|
|
8
8
|
import { AgentRoutineRegistry } from '../agent/routine-registry.ts';
|
|
9
|
-
import {
|
|
9
|
+
import type { AgentRuntimeProfileInfo } from '../agent/runtime-profile.ts';
|
|
10
10
|
import { AgentSkillRegistry } from '../agent/skill-registry.ts';
|
|
11
11
|
import { activateAgentWorkspaceSelection } from './agent-workspace-activation.ts';
|
|
12
12
|
import { AGENT_WORKSPACE_CATEGORIES } from './agent-workspace-categories.ts';
|
|
13
13
|
import { buildAgentWorkspaceCommandEditorSubmission, isAgentWorkspaceCommandEditorKind } from './agent-workspace-command-editor.ts';
|
|
14
|
-
import { createDeleteEditor, editorCategoryId
|
|
15
|
-
import {
|
|
14
|
+
import { createDeleteEditor, editorCategoryId } from './agent-workspace-editors.ts';
|
|
15
|
+
import { submitAgentWorkspaceLocalRegistryEditor } from './agent-workspace-local-editor-submission.ts';
|
|
16
16
|
import { clampAgentWorkspaceLocalLibrarySelection, moveAgentWorkspaceLocalLibraryItemSelection, selectedAgentWorkspaceLocalLibraryItem, type AgentWorkspaceLocalSelectionIndexes } from './agent-workspace-local-selection.ts';
|
|
17
17
|
import { applyAgentWorkspaceLocalLibraryOperation } from './agent-workspace-local-operations.ts';
|
|
18
18
|
import { deleteAgentWorkspaceMemoryEditor, submitAgentWorkspaceMemoryEditor } from './agent-workspace-memory-editor.ts';
|
|
19
19
|
import { jumpAgentWorkspaceSelection, moveAgentWorkspaceSelection, selectAgentWorkspaceCategory } from './agent-workspace-navigation.ts';
|
|
20
|
-
import { buildAgentWorkspaceRequirements } from './agent-workspace-requirements.ts';
|
|
21
20
|
import { appendAgentWorkspaceActionSearchText, backspaceAgentWorkspaceActionSearch, beginAgentWorkspaceActionSearch, clearAgentWorkspaceActionSearch, commitAgentWorkspaceActionSearchSelection, searchAgentWorkspaceActions } from './agent-workspace-search.ts';
|
|
22
21
|
import { agentWorkspaceSettingSchema, applyAgentWorkspaceSettingValue, buildAgentWorkspaceSettingActionEffect, importAgentWorkspaceTuiSettings, isAgentWorkspaceActionVisible } from './agent-workspace-settings.ts';
|
|
23
22
|
import { buildAgentWorkspaceRuntimeSnapshot } from './agent-workspace-snapshot.ts';
|
|
23
|
+
import { submitAgentWorkspaceSubscriptionLoginFinishEditor, submitAgentWorkspaceSubscriptionLoginStartEditor, submitAgentWorkspaceSubscriptionLogoutEditor } from './agent-workspace-subscription-editor.ts';
|
|
24
24
|
import type { AgentWorkspaceAction, AgentWorkspaceActionResult, AgentWorkspaceActionSearchResult, AgentWorkspaceCategory, AgentWorkspaceCommandDispatcher, AgentWorkspaceEditorField, AgentWorkspaceFocusPane, AgentWorkspaceLocalEditor, AgentWorkspaceLocalEditorKind, AgentWorkspaceLocalLibraryItem, AgentWorkspaceLocalOperation, AgentWorkspacePromptDispatcher, AgentWorkspaceRuntimeSnapshot } from './agent-workspace-types.ts';
|
|
25
25
|
import { writeOnboardingCheckMarker, writeOnboardingCompletionMarker } from '../runtime/onboarding/index.ts';
|
|
26
26
|
|
|
@@ -333,6 +333,55 @@ export class AgentWorkspace {
|
|
|
333
333
|
}
|
|
334
334
|
}
|
|
335
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
|
+
this.lastActionResult = {
|
|
344
|
+
kind: 'error',
|
|
345
|
+
title: 'Model picker unavailable',
|
|
346
|
+
detail: 'This runtime cannot open the model picker from Agent workspace.',
|
|
347
|
+
safety: action.safety,
|
|
348
|
+
};
|
|
349
|
+
requestRender?.();
|
|
350
|
+
return;
|
|
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
|
+
|
|
336
385
|
applySettingAction(action: AgentWorkspaceAction, requestRender?: () => void): void {
|
|
337
386
|
const effect = buildAgentWorkspaceSettingActionEffect(this.context, action);
|
|
338
387
|
if (effect.kind === 'result') {
|
|
@@ -446,6 +495,19 @@ export class AgentWorkspace {
|
|
|
446
495
|
this.status = `${missing.label} is required.`;
|
|
447
496
|
return;
|
|
448
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
|
+
}
|
|
449
511
|
if (isAgentWorkspaceCommandEditorKind(editor.kind)) {
|
|
450
512
|
this.submitCommandEditor(editor);
|
|
451
513
|
requestRender?.();
|
|
@@ -496,135 +558,13 @@ export class AgentWorkspace {
|
|
|
496
558
|
return;
|
|
497
559
|
}
|
|
498
560
|
try {
|
|
499
|
-
|
|
500
|
-
this.
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
name: this.editorField('name'),
|
|
507
|
-
description: this.editorField('description'),
|
|
508
|
-
notes: this.editorField('notes'),
|
|
509
|
-
tags: splitList(this.editorField('tags')),
|
|
510
|
-
triggers: splitList(this.editorField('triggers')),
|
|
511
|
-
enable: isAffirmative(this.editorField('enable')),
|
|
512
|
-
});
|
|
513
|
-
this.finishLocalEditor(created.kind, created.id, created.name, 'Created');
|
|
514
|
-
} else if (editor.kind === 'profile') {
|
|
515
|
-
const template = this.editorField('template');
|
|
516
|
-
const templateId = template && template.toLowerCase() !== 'none' ? template : undefined;
|
|
517
|
-
const profile = createAgentRuntimeProfile(shellPaths.homeDirectory, this.editorField('name'), {
|
|
518
|
-
...(templateId ? { templateId } : {}),
|
|
519
|
-
});
|
|
520
|
-
this.finishProfileEditor(profile);
|
|
521
|
-
} else if (editor.kind === 'note') {
|
|
522
|
-
const registry = AgentNoteRegistry.fromShellPaths(shellPaths);
|
|
523
|
-
if (editor.mode === 'update' && editor.recordId) {
|
|
524
|
-
const updated = registry.update(editor.recordId, {
|
|
525
|
-
title: this.editorField('title'),
|
|
526
|
-
body: this.editorField('body'),
|
|
527
|
-
sourceUrl: this.editorField('sourceUrl'),
|
|
528
|
-
tags: splitList(this.editorField('tags')),
|
|
529
|
-
provenance: 'Workspace',
|
|
530
|
-
});
|
|
531
|
-
this.finishLocalEditor(editor.kind, updated.id, updated.title, 'Updated');
|
|
532
|
-
return;
|
|
533
|
-
}
|
|
534
|
-
const created = registry.create({
|
|
535
|
-
title: this.editorField('title'),
|
|
536
|
-
body: this.editorField('body'),
|
|
537
|
-
sourceUrl: this.editorField('sourceUrl'),
|
|
538
|
-
tags: splitList(this.editorField('tags')),
|
|
539
|
-
source: 'user',
|
|
540
|
-
provenance: 'Workspace',
|
|
541
|
-
});
|
|
542
|
-
this.finishLocalEditor(editor.kind, created.id, created.title, 'Created');
|
|
543
|
-
} else if (editor.kind === 'persona') {
|
|
544
|
-
const registry = AgentPersonaRegistry.fromShellPaths(shellPaths);
|
|
545
|
-
if (editor.mode === 'update' && editor.recordId) {
|
|
546
|
-
const wasActive = registry.snapshot().activePersonaId === editor.recordId;
|
|
547
|
-
const updated = registry.update(editor.recordId, {
|
|
548
|
-
name: this.editorField('name'),
|
|
549
|
-
description: this.editorField('description'),
|
|
550
|
-
body: this.editorField('body'),
|
|
551
|
-
tags: splitList(this.editorField('tags')),
|
|
552
|
-
triggers: splitList(this.editorField('triggers')),
|
|
553
|
-
provenance: 'Workspace',
|
|
554
|
-
});
|
|
555
|
-
if (isAffirmative(this.editorField('activate'))) registry.setActive(updated.id);
|
|
556
|
-
else if (wasActive) registry.clearActive();
|
|
557
|
-
this.finishLocalEditor(editor.kind, updated.id, updated.name, 'Updated');
|
|
558
|
-
return;
|
|
559
|
-
}
|
|
560
|
-
const created = registry.create({
|
|
561
|
-
name: this.editorField('name'),
|
|
562
|
-
description: this.editorField('description'),
|
|
563
|
-
body: this.editorField('body'),
|
|
564
|
-
tags: splitList(this.editorField('tags')),
|
|
565
|
-
triggers: splitList(this.editorField('triggers')),
|
|
566
|
-
source: 'user',
|
|
567
|
-
provenance: 'Workspace',
|
|
568
|
-
});
|
|
569
|
-
if (isAffirmative(this.editorField('activate'))) registry.setActive(created.id);
|
|
570
|
-
this.finishLocalEditor(editor.kind, created.id, created.name, 'Created');
|
|
571
|
-
} else if (editor.kind === 'skill') {
|
|
572
|
-
const registry = AgentSkillRegistry.fromShellPaths(shellPaths);
|
|
573
|
-
if (editor.mode === 'update' && editor.recordId) {
|
|
574
|
-
const updated = registry.update(editor.recordId, {
|
|
575
|
-
name: this.editorField('name'),
|
|
576
|
-
description: this.editorField('description'),
|
|
577
|
-
procedure: this.editorField('procedure'),
|
|
578
|
-
triggers: splitList(this.editorField('triggers')),
|
|
579
|
-
tags: splitList(this.editorField('tags')),
|
|
580
|
-
requirements: buildAgentWorkspaceRequirements((id) => this.editorField(id)),
|
|
581
|
-
provenance: 'Workspace',
|
|
582
|
-
});
|
|
583
|
-
registry.setEnabled(updated.id, isAffirmative(this.editorField('enabled')));
|
|
584
|
-
this.finishLocalEditor(editor.kind, updated.id, updated.name, 'Updated');
|
|
585
|
-
return;
|
|
586
|
-
}
|
|
587
|
-
const created = registry.create({
|
|
588
|
-
name: this.editorField('name'),
|
|
589
|
-
description: this.editorField('description'),
|
|
590
|
-
procedure: this.editorField('procedure'),
|
|
591
|
-
triggers: splitList(this.editorField('triggers')),
|
|
592
|
-
tags: splitList(this.editorField('tags')),
|
|
593
|
-
requirements: buildAgentWorkspaceRequirements((id) => this.editorField(id)),
|
|
594
|
-
enabled: isAffirmative(this.editorField('enabled')),
|
|
595
|
-
source: 'user',
|
|
596
|
-
provenance: 'Workspace',
|
|
597
|
-
});
|
|
598
|
-
this.finishLocalEditor(editor.kind, created.id, created.name, 'Created');
|
|
599
|
-
} else {
|
|
600
|
-
const registry = AgentRoutineRegistry.fromShellPaths(shellPaths);
|
|
601
|
-
if (editor.mode === 'update' && editor.recordId) {
|
|
602
|
-
const updated = registry.update(editor.recordId, {
|
|
603
|
-
name: this.editorField('name'),
|
|
604
|
-
description: this.editorField('description'),
|
|
605
|
-
steps: this.editorField('steps'),
|
|
606
|
-
triggers: splitList(this.editorField('triggers')),
|
|
607
|
-
tags: splitList(this.editorField('tags')),
|
|
608
|
-
requirements: buildAgentWorkspaceRequirements((id) => this.editorField(id)),
|
|
609
|
-
provenance: 'Workspace',
|
|
610
|
-
});
|
|
611
|
-
registry.setEnabled(updated.id, isAffirmative(this.editorField('enabled')));
|
|
612
|
-
this.finishLocalEditor(editor.kind, updated.id, updated.name, 'Updated');
|
|
613
|
-
return;
|
|
614
|
-
}
|
|
615
|
-
const created = registry.create({
|
|
616
|
-
name: this.editorField('name'),
|
|
617
|
-
description: this.editorField('description'),
|
|
618
|
-
steps: this.editorField('steps'),
|
|
619
|
-
triggers: splitList(this.editorField('triggers')),
|
|
620
|
-
tags: splitList(this.editorField('tags')),
|
|
621
|
-
requirements: buildAgentWorkspaceRequirements((id) => this.editorField(id)),
|
|
622
|
-
enabled: isAffirmative(this.editorField('enabled')),
|
|
623
|
-
source: 'user',
|
|
624
|
-
provenance: 'Workspace',
|
|
625
|
-
});
|
|
626
|
-
this.finishLocalEditor(editor.kind, created.id, created.name, 'Created');
|
|
627
|
-
}
|
|
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
|
+
});
|
|
628
568
|
} catch (error) {
|
|
629
569
|
const detail = error instanceof Error ? error.message : String(error);
|
|
630
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 {
|
|
@@ -55,12 +55,15 @@ function buildLeftRows(workspace: AgentWorkspace, height: number): WorkspaceRow[
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
function actionCommand(action: AgentWorkspaceAction): string {
|
|
58
|
-
if (action.kind === 'workspace') return
|
|
59
|
-
if (action.kind === 'editor') return action.editorKind ? `edit ${action.editorKind}` : '
|
|
60
|
-
if (action.kind === 'setting') return action.settingKey ? `
|
|
58
|
+
if (action.kind === 'workspace') return 'open area';
|
|
59
|
+
if (action.kind === 'editor') return action.editorKind ? `edit ${action.editorKind}` : 'edit form';
|
|
60
|
+
if (action.kind === 'setting') return action.settingKey ? `setting ${action.settingKey}` : 'setting';
|
|
61
61
|
if (action.kind === 'settings-import') return 'import GoodVibes settings';
|
|
62
|
+
if (action.kind === 'model-picker') return action.modelPickerFlow === 'model' ? 'model picker' : 'provider/model picker';
|
|
63
|
+
if (action.kind === 'settings-modal') return action.settingsTarget ? `settings ${action.settingsTarget}` : 'settings';
|
|
62
64
|
if (action.kind === 'local-selection') return action.selectionDelta && action.selectionDelta < 0 ? 'select previous' : 'select next';
|
|
63
65
|
if (action.kind === 'local-operation') return action.localOperation ?? '(local action)';
|
|
66
|
+
if (action.kind === 'onboarding-complete') return 'apply and close';
|
|
64
67
|
return action.command ?? '(guidance)';
|
|
65
68
|
}
|
|
66
69
|
|
|
@@ -83,6 +86,11 @@ function setupStatusLabel(status: AgentWorkspaceRuntimeSnapshot['setupChecklist'
|
|
|
83
86
|
: 'Optional';
|
|
84
87
|
}
|
|
85
88
|
|
|
89
|
+
function formatMegabytes(bytes: number): string {
|
|
90
|
+
if (!Number.isFinite(bytes) || bytes <= 0) return '0 MB';
|
|
91
|
+
return `${Math.round(bytes / (1024 * 1024))} MB`;
|
|
92
|
+
}
|
|
93
|
+
|
|
86
94
|
function compactText(text: string, maxWidth = 104): string {
|
|
87
95
|
const normalized = text.replace(/\s+/g, ' ').trim();
|
|
88
96
|
if (normalized.length === 0) return '';
|
|
@@ -291,6 +299,63 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
|
|
|
291
299
|
base.push(
|
|
292
300
|
...setupOverviewLines(snapshot),
|
|
293
301
|
);
|
|
302
|
+
} else if (category.id === 'account-model') {
|
|
303
|
+
base.push(
|
|
304
|
+
{ text: `Chat route: ${snapshot.provider} / ${snapshot.modelDisplayName}`, fg: PALETTE.info },
|
|
305
|
+
{ text: `Subscriptions: ${snapshot.activeSubscriptionCount} active; ${snapshot.pendingSubscriptionCount} pending; ${snapshot.availableSubscriptionProviderCount} available.`, fg: snapshot.activeSubscriptionCount > 0 ? PALETTE.good : snapshot.pendingSubscriptionCount > 0 ? PALETTE.warn : PALETTE.muted },
|
|
306
|
+
{ text: `Embedding: ${snapshot.embeddingProvider}; reasoning ${snapshot.reasoningEffort}.`, fg: PALETTE.info },
|
|
307
|
+
{ text: `Helper: ${snapshot.helperEnabled ? 'enabled' : 'disabled'}; Tool LLM: ${snapshot.toolLlmEnabled ? 'enabled' : 'disabled'}.`, fg: snapshot.helperEnabled || snapshot.toolLlmEnabled ? PALETTE.good : PALETTE.muted },
|
|
308
|
+
{ text: `Cache: ${snapshot.cacheEnabled ? snapshot.cacheStableTtl : 'off'}; monitor ${snapshot.cacheMonitorHitRate ? snapshot.cacheHitRateWarningThreshold : 'off'}; failure hints ${snapshot.providerFailureHints ? 'on' : 'off'}.`, fg: snapshot.cacheEnabled ? PALETTE.info : PALETTE.muted },
|
|
309
|
+
);
|
|
310
|
+
} else if (category.id === 'assistant-behavior') {
|
|
311
|
+
base.push(
|
|
312
|
+
{ text: `Interaction: ${snapshot.hitlMode}; guidance ${snapshot.guidanceMode}; history ${snapshot.saveHistory ? 'saved' : 'off'}.`, fg: PALETTE.info },
|
|
313
|
+
{ text: `Context: compact at ${snapshot.autoCompactThreshold}; stale warnings ${snapshot.staleContextWarnings ? 'on' : 'off'}.`, fg: PALETTE.info },
|
|
314
|
+
{ text: `Reasoning display: thinking ${snapshot.showThinking ? 'on' : 'off'}; summaries ${snapshot.showReasoningSummary ? 'on' : 'off'}.`, fg: PALETTE.muted },
|
|
315
|
+
);
|
|
316
|
+
} else if (category.id === 'tools-permissions') {
|
|
317
|
+
base.push(
|
|
318
|
+
{ text: `Permission mode: ${snapshot.permissionMode}.`, fg: snapshot.permissionMode === 'allow-all' ? PALETTE.warn : PALETTE.info },
|
|
319
|
+
{ text: `Auto-approve ${snapshot.autoApprove ? 'on' : 'off'}; tool auto-heal ${snapshot.toolAutoHeal ? 'on' : 'off'}; token budget ${snapshot.toolsDefaultTokenBudget}.`, fg: snapshot.autoApprove ? PALETTE.warn : PALETTE.info },
|
|
320
|
+
{ text: `Artifact limit ${formatMegabytes(snapshot.artifactMaxBytes)}; raw prompt telemetry ${snapshot.rawPromptTelemetry ? 'on' : 'off'}.`, fg: snapshot.rawPromptTelemetry ? PALETTE.warn : PALETTE.muted },
|
|
321
|
+
{ text: `MCP servers: ${snapshot.mcpConnectedServerCount}/${snapshot.mcpServerCount} connected; quarantined ${snapshot.mcpQuarantinedServerCount}.`, fg: snapshot.mcpQuarantinedServerCount > 0 ? PALETTE.warn : PALETTE.info },
|
|
322
|
+
{ text: 'MCP and secret setup use forms; selecting a row does not run arbitrary tools.', fg: PALETTE.good },
|
|
323
|
+
);
|
|
324
|
+
} else if (category.id === 'onboarding-display') {
|
|
325
|
+
base.push(
|
|
326
|
+
{ text: `Theme: ${snapshot.theme}; streaming ${snapshot.stream ? 'on' : 'off'}; line numbers ${snapshot.lineNumbers}.`, fg: PALETTE.info },
|
|
327
|
+
{ text: `Messages: operational ${snapshot.operationalMessages}; system ${snapshot.systemMessages}.`, fg: PALETTE.info },
|
|
328
|
+
{ text: `Release channel: ${snapshot.releaseChannel}.`, fg: PALETTE.muted },
|
|
329
|
+
);
|
|
330
|
+
} else if (category.id === 'onboarding-channels') {
|
|
331
|
+
const enabledCount = snapshot.channels.filter((channel) => channel.enabled).length;
|
|
332
|
+
const readyCount = snapshot.channels.filter((channel) => channel.ready).length;
|
|
333
|
+
const needsConfig = snapshot.channels.filter((channel) => channel.setupState === 'needs-config');
|
|
334
|
+
const needsTarget = snapshot.channels.filter((channel) => channel.setupState === 'needs-target');
|
|
335
|
+
base.push(
|
|
336
|
+
{ text: `Channels: ${readyCount}/${snapshot.channels.length} ready; ${enabledCount} enabled.`, fg: enabledCount > 0 ? PALETTE.info : PALETTE.muted },
|
|
337
|
+
{ text: `Needs config: ${needsConfig.length}; needs target: ${needsTarget.length}.`, fg: needsConfig.length > 0 || needsTarget.length > 0 ? PALETTE.warn : PALETTE.good },
|
|
338
|
+
{ text: 'Enable only the channels you want; hidden channel fields appear after the channel is enabled.', fg: PALETTE.good },
|
|
339
|
+
);
|
|
340
|
+
} else if (category.id === 'onboarding-voice-media') {
|
|
341
|
+
const readiness = snapshot.voiceMediaReadiness;
|
|
342
|
+
base.push(
|
|
343
|
+
{ text: `Voice: ${snapshot.voiceSurfaceEnabled ? 'enabled' : 'disabled'}; TTS ${snapshot.ttsProvider}; voice ${snapshot.ttsVoice}.`, fg: snapshot.voiceSurfaceEnabled ? PALETTE.good : PALETTE.info },
|
|
344
|
+
{ text: `Media readiness: ${readiness.readyMediaProviderCount}/${snapshot.mediaProviderCount}; generation providers ${snapshot.mediaGenerationProviderCount}.`, fg: readiness.readyMediaProviderCount > 0 ? PALETTE.good : PALETTE.muted },
|
|
345
|
+
{ text: `Telephony channel: ${snapshot.channels.find((channel) => channel.id === 'telephony')?.setupState ?? 'disabled'}.`, fg: PALETTE.info },
|
|
346
|
+
);
|
|
347
|
+
} else if (category.id === 'onboarding-context') {
|
|
348
|
+
base.push(
|
|
349
|
+
{ text: `Local context: ${snapshot.localMemoryCount} memories, ${snapshot.localNoteCount} notes, ${snapshot.localPersonaCount} personas.`, fg: PALETTE.info },
|
|
350
|
+
{ text: `Skills: ${snapshot.enabledSkillCount}/${snapshot.localSkillCount} enabled; routines ${snapshot.enabledRoutineCount}/${snapshot.localRoutineCount} enabled.`, fg: PALETTE.info },
|
|
351
|
+
{ text: `Discovered files: personas ${snapshot.discoveredBehavior.personas.count}, skills ${snapshot.discoveredBehavior.skills.count}, routines ${snapshot.discoveredBehavior.routines.count}.`, fg: PALETTE.muted },
|
|
352
|
+
);
|
|
353
|
+
} else if (category.id === 'onboarding-automation') {
|
|
354
|
+
base.push(
|
|
355
|
+
{ text: `Automation: ${snapshot.automationEnabled ? 'enabled' : 'disabled'}; max ${snapshot.automationMaxConcurrentRuns} concurrent; history ${snapshot.automationRunHistoryLimit}.`, fg: snapshot.automationEnabled ? PALETTE.good : PALETTE.muted },
|
|
356
|
+
{ text: `Timeout ${snapshot.automationDefaultTimeoutMs} ms; catch-up ${snapshot.automationCatchUpWindowMinutes} min; cooldown ${snapshot.automationFailureCooldownMs} ms.`, fg: PALETTE.info },
|
|
357
|
+
{ text: `Delete one-shot jobs after success: ${snapshot.automationDeleteAfterRun ? 'yes' : 'no'}.`, fg: snapshot.automationDeleteAfterRun ? PALETTE.info : PALETTE.muted },
|
|
358
|
+
);
|
|
294
359
|
} else if (category.id === 'artifacts') {
|
|
295
360
|
const mediaReady = snapshot.voiceMediaReadiness.readyMediaProviderCount;
|
|
296
361
|
base.push(
|
|
@@ -16,8 +16,8 @@ function normalizeFullscreenViewport(lines: readonly Line[], width: number, heig
|
|
|
16
16
|
return viewport;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export function
|
|
20
|
-
|
|
19
|
+
export function createFullscreenCompositeFromLines(
|
|
20
|
+
lines: readonly Line[],
|
|
21
21
|
width: number,
|
|
22
22
|
height: number,
|
|
23
23
|
): CompositeRequest {
|
|
@@ -25,9 +25,17 @@ export function createAgentWorkspaceFullscreenComposite(
|
|
|
25
25
|
width,
|
|
26
26
|
height,
|
|
27
27
|
header: [],
|
|
28
|
-
viewport: normalizeFullscreenViewport(
|
|
28
|
+
viewport: normalizeFullscreenViewport(lines, width, height),
|
|
29
29
|
footer: [],
|
|
30
30
|
forceFullRedraw: true,
|
|
31
31
|
panelWidth: 0,
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
|
+
|
|
35
|
+
export function createAgentWorkspaceFullscreenComposite(
|
|
36
|
+
workspace: AgentWorkspace,
|
|
37
|
+
width: number,
|
|
38
|
+
height: number,
|
|
39
|
+
): CompositeRequest {
|
|
40
|
+
return createFullscreenCompositeFromLines(renderAgentWorkspace(workspace, width, height), width, height);
|
|
41
|
+
}
|
package/src/version.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { join } from 'node:path';
|
|
|
6
6
|
// The prebuild script updates the fallback value before compilation.
|
|
7
7
|
// Uses import.meta.dir (Bun) to locate package.json relative to this file,
|
|
8
8
|
// which is correct regardless of the process working directory.
|
|
9
|
-
let _version = '1.1.
|
|
9
|
+
let _version = '1.1.5';
|
|
10
10
|
try {
|
|
11
11
|
const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8')) as {
|
|
12
12
|
readonly version?: unknown;
|