@pellux/goodvibes-tui 2.0.8 → 2.0.9
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 +18 -0
- package/README.md +1 -1
- package/docs/foundation-artifacts/operator-contract.json +439 -269
- package/package.json +3 -3
- package/src/input/handler-interactions.ts +39 -0
- package/src/input/handler-types.ts +7 -0
- package/src/input/handler.ts +10 -21
- package/src/version.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pellux/goodvibes-tui",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.9",
|
|
4
4
|
"description": "Terminal-native GoodVibes client for coding, operations, knowledge and channel workflows — a pure client of the GoodVibes daemon.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/main.ts",
|
|
@@ -95,8 +95,8 @@
|
|
|
95
95
|
"@anthropic-ai/bedrock-sdk": "^0.29.1",
|
|
96
96
|
"@anthropic-ai/sdk": "^0.92.0",
|
|
97
97
|
"@ast-grep/napi": "^0.42.0",
|
|
98
|
-
"@pellux/goodvibes-sdk": "2.0.
|
|
99
|
-
"@pellux/goodvibes-terminal-shell": "2.0.
|
|
98
|
+
"@pellux/goodvibes-sdk": "2.0.9",
|
|
99
|
+
"@pellux/goodvibes-terminal-shell": "2.0.9",
|
|
100
100
|
"bash-language-server": "^5.6.0",
|
|
101
101
|
"fuse.js": "^7.1.0",
|
|
102
102
|
"@pellux/goodvibes-daemon": "1.28.7",
|
|
@@ -58,6 +58,45 @@ export async function hydrateOnboardingWizardFromRuntimeForHandler(handler: Inpu
|
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
/**
|
|
62
|
+
* handlePasteForHandler - Shared paste path for Ctrl+V and middle-click.
|
|
63
|
+
*
|
|
64
|
+
* Tries the clipboard's image first, then its text. The clipboard itself comes
|
|
65
|
+
* from `handler.clipboardSource`, so tests can hand in a clipboard without
|
|
66
|
+
* touching the real one.
|
|
67
|
+
*
|
|
68
|
+
* The prompt is edited on the HANDLER here, not on the shortcut route state
|
|
69
|
+
* that dispatched the key. feedInputTokens snapshots the prompt before
|
|
70
|
+
* dispatching and would write that snapshot back over this edit, erasing the
|
|
71
|
+
* paste — it does not, because it only restores a field the action left
|
|
72
|
+
* untouched (see the promptBefore guard in handler-feed.ts). That guard is the
|
|
73
|
+
* only reason Ctrl+V works, so it is pinned by test.
|
|
74
|
+
*/
|
|
75
|
+
export function handlePasteForHandler(handler: InputHandler): ReturnType<typeof handleClipboardPaste> {
|
|
76
|
+
const result = handleClipboardPaste({
|
|
77
|
+
prompt: handler.prompt,
|
|
78
|
+
cursorPos: handler.cursorPos,
|
|
79
|
+
pasteRegistry: handler.pasteRegistry,
|
|
80
|
+
nextPasteId: handler.nextPasteId,
|
|
81
|
+
imageRegistry: handler.imageRegistry,
|
|
82
|
+
nextImageId: handler.nextImageId,
|
|
83
|
+
saveUndoState: () => handler.saveUndoState(),
|
|
84
|
+
ensureInputCursorVisible: () => handler.ensureInputCursorVisible(),
|
|
85
|
+
requestRender: handler.requestRender,
|
|
86
|
+
}, handler.uiServices.environment.shellPaths.workingDirectory, handler.clipboardSource);
|
|
87
|
+
|
|
88
|
+
handler.prompt = result.prompt;
|
|
89
|
+
handler.cursorPos = result.cursorPos;
|
|
90
|
+
handler.nextImageId = result.nextImageId;
|
|
91
|
+
handler.nextPasteId = result.nextPasteId;
|
|
92
|
+
|
|
93
|
+
if (!result.pasted) {
|
|
94
|
+
handler.conversationManager?.log('[Paste: clipboard does not contain supported text or image data]', { fg: '240' });
|
|
95
|
+
handler.requestRender();
|
|
96
|
+
}
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
|
|
61
100
|
export function registerPasteForHandler(handler: InputHandler, content: string): string {
|
|
62
101
|
const result = registerPaste({
|
|
63
102
|
pasteRegistry: handler.pasteRegistry,
|
|
@@ -19,6 +19,7 @@ import type { UiRuntimeServices } from '../runtime/ui-services.ts';
|
|
|
19
19
|
import type { CommandContext } from './command-registry.ts';
|
|
20
20
|
import type { ConversationManager } from '../core/conversation';
|
|
21
21
|
import type { ModelPickerModal, ModelPickerTarget } from './model-picker.ts';
|
|
22
|
+
import type { ClipboardPasteSource } from './handler-content-actions.ts';
|
|
22
23
|
import type { SelectionManager } from '@pellux/goodvibes-terminal-shell';
|
|
23
24
|
import type { InfiniteBuffer } from '@pellux/goodvibes-terminal-shell';
|
|
24
25
|
import type { AutocompleteEngine } from './autocomplete.ts';
|
|
@@ -81,6 +82,11 @@ export interface InputHandlerLike {
|
|
|
81
82
|
nextPasteId: number;
|
|
82
83
|
imageRegistry: Map<string, { data: string; mediaType: string }>;
|
|
83
84
|
nextImageId: number;
|
|
85
|
+
/**
|
|
86
|
+
* The clipboard this composer pastes from. Swappable so tests can supply a
|
|
87
|
+
* clipboard instead of reaching for the machine's real one.
|
|
88
|
+
*/
|
|
89
|
+
clipboardSource: ClipboardPasteSource;
|
|
84
90
|
|
|
85
91
|
// ── Timing ───────────────────────────────────────────────────────────────
|
|
86
92
|
lastCopyTime: number;
|
|
@@ -124,6 +130,7 @@ export interface InputHandlerLike {
|
|
|
124
130
|
// ── Methods: modal lifecycle ──────────────────────────────────────────────
|
|
125
131
|
modalOpened(name: string): void;
|
|
126
132
|
saveUndoState(): void;
|
|
133
|
+
ensureInputCursorVisible(contentWidth?: number): void;
|
|
127
134
|
|
|
128
135
|
// ── Methods: block actions (dispatched in executeBlockAction) ────────────
|
|
129
136
|
handleBlockCopy(): void;
|
package/src/input/handler.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node
|
|
|
2
2
|
import { dirname } from 'node:path';
|
|
3
3
|
import { InputTokenizer } from '@pellux/goodvibes-sdk/platform/core';
|
|
4
4
|
import { createOAuthLocalListener } from '@pellux/goodvibes-sdk/platform/config';
|
|
5
|
-
import { clearModalStackForHandler, cleanupMarkerRegistryForHandler, executeBlockActionForHandler, expandPromptForHandler, findMarkerAtPosForHandler, getImageAttachmentsForHandler, handleBlockCopyForHandler, handleBlockSaveForHandler, handleBlockToggleForHandler, handleBookmarkForHandler, handleCopyForHandler, handleCtrlCForHandler, handleDiffApplyForHandler, handleEscapeForHandler, hydrateOnboardingWizardFromRuntimeForHandler, modalOpenedForHandler, openOnboardingWizardForHandler, registerPasteForHandler } from './handler-interactions.ts';
|
|
5
|
+
import { clearModalStackForHandler, cleanupMarkerRegistryForHandler, executeBlockActionForHandler, expandPromptForHandler, findMarkerAtPosForHandler, getImageAttachmentsForHandler, handleBlockCopyForHandler, handleBlockSaveForHandler, handleBlockToggleForHandler, handleBookmarkForHandler, handleCopyForHandler, handleCtrlCForHandler, handleDiffApplyForHandler, handleEscapeForHandler, handlePasteForHandler, hydrateOnboardingWizardFromRuntimeForHandler, modalOpenedForHandler, openOnboardingWizardForHandler, registerPasteForHandler } from './handler-interactions.ts';
|
|
6
6
|
import { getViewportBottomLine } from '../renderer/conversation-layout.ts';
|
|
7
7
|
import { clearOnboardingModelPickerCancelStateForHandler, clearOnboardingPendingModelPickerTargetForHandler, completeOpenAiSubscriptionFromListenerForHandler, getOnboardingConfigValueForHandler, getOnboardingRuntimePostureForHandler, handleModelPickerCommitForHandler, handleOnboardingActionForHandler, handleOpenAiSubscriptionFinishForHandler, handleOpenAiSubscriptionStartForHandler, openModelPickerWithTargetForHandler, openProviderModelPickerWithTargetForHandler, refreshOnboardingHydrationForHandler, restartOnboardingExternalServicesIfNeededForHandler, restoreOnboardingModelPickerCancelStateForHandler, saveWizardProgressForHandler, syncRuntimeFromOnboardingRequestForHandler, verifyOnboardingRuntimePostureForHandler, } from './handler-onboarding.ts';
|
|
8
8
|
import type { OnboardingRuntimePosture } from './handler-types.ts';
|
|
@@ -53,12 +53,14 @@ import {
|
|
|
53
53
|
handleBlockToggle,
|
|
54
54
|
handleBookmark,
|
|
55
55
|
handleClipboardPaste,
|
|
56
|
+
type ClipboardPasteSource,
|
|
56
57
|
handleCopy,
|
|
57
58
|
handleCtrlC,
|
|
58
59
|
handleDiffApply,
|
|
59
60
|
mediaTypeFromExt,
|
|
60
61
|
registerPaste,
|
|
61
62
|
} from './handler-content-actions.ts';
|
|
63
|
+
import { pasteFromClipboard, pasteImageFromClipboard } from '../utils/clipboard.ts';
|
|
62
64
|
import {
|
|
63
65
|
handleIndicatorFocusToken,
|
|
64
66
|
handleMouseToken,
|
|
@@ -574,28 +576,15 @@ export class InputHandler implements InputHandlerLike {
|
|
|
574
576
|
* Tries image clipboard first, falls back to text paste.
|
|
575
577
|
*/
|
|
576
578
|
public handlePaste(): ReturnType<typeof handleClipboardPaste> {
|
|
577
|
-
|
|
578
|
-
prompt: this.prompt,
|
|
579
|
-
cursorPos: this.cursorPos,
|
|
580
|
-
pasteRegistry: this.pasteRegistry,
|
|
581
|
-
nextPasteId: this.nextPasteId,
|
|
582
|
-
imageRegistry: this.imageRegistry,
|
|
583
|
-
nextImageId: this.nextImageId,
|
|
584
|
-
saveUndoState: () => this.saveUndoState(),
|
|
585
|
-
ensureInputCursorVisible: () => this.ensureInputCursorVisible(),
|
|
586
|
-
requestRender: this.requestRender,
|
|
587
|
-
}, this.uiServices.environment.shellPaths.workingDirectory);
|
|
588
|
-
this.prompt = result.prompt;
|
|
589
|
-
this.cursorPos = result.cursorPos;
|
|
590
|
-
this.nextImageId = result.nextImageId;
|
|
591
|
-
this.nextPasteId = result.nextPasteId;
|
|
592
|
-
if (!result.pasted) {
|
|
593
|
-
this.conversationManager?.log('[Paste: clipboard does not contain supported text or image data]', { fg: '240' });
|
|
594
|
-
this.requestRender();
|
|
595
|
-
}
|
|
596
|
-
return result;
|
|
579
|
+
return handlePasteForHandler(this);
|
|
597
580
|
}
|
|
598
581
|
|
|
582
|
+
/**
|
|
583
|
+
* The clipboard this composer pastes from. Swappable so tests can supply a
|
|
584
|
+
* clipboard instead of reaching for the machine's real one.
|
|
585
|
+
*/
|
|
586
|
+
public clipboardSource: ClipboardPasteSource = { pasteImageFromClipboard, pasteFromClipboard };
|
|
587
|
+
|
|
599
588
|
/** Content width for wrapping — set by main.ts via setContentWidth(). */
|
|
600
589
|
public contentWidth = 76;
|
|
601
590
|
public panelMouseLayout: PanelMouseLayout | null = null;
|
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 = '2.0.
|
|
9
|
+
let _version = '2.0.9';
|
|
10
10
|
try {
|
|
11
11
|
const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8'));
|
|
12
12
|
// Only trust a version read from OUR OWN package.json. A Bun single-file
|