agent-sh 0.12.25 → 0.12.27
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/dist/agent/agent-loop.js +2 -2
- package/dist/agent/conversation-state.js +22 -1
- package/dist/index.js +3 -1
- package/dist/install.js +84 -4
- package/dist/shell/index.d.ts +5 -0
- package/dist/shell/index.js +13 -8
- package/dist/shell/input-handler.js +75 -27
- package/dist/shell/tui-input-view.d.ts +5 -0
- package/dist/shell/tui-input-view.js +137 -96
- package/dist/utils/floating-panel.d.ts +16 -4
- package/dist/utils/floating-panel.js +209 -66
- package/dist/utils/terminal-buffer.d.ts +6 -9
- package/dist/utils/terminal-buffer.js +21 -53
- package/examples/extensions/emacs-buffer.ts +364 -0
- package/examples/extensions/opencode-bridge/index.ts +255 -37
- package/examples/extensions/overlay-agent.ts +28 -5
- package/examples/extensions/terminal-buffer.ts +174 -33
- package/examples/extensions/tunnel-vision.ts +405 -0
- package/examples/extensions/web-access.ts +3 -108
- package/package.json +1 -1
package/dist/agent/agent-loop.js
CHANGED
|
@@ -1105,7 +1105,7 @@ export class AgentLoop {
|
|
|
1105
1105
|
// Compact deeply — shallow targets buy only 1–2 turns of runway on
|
|
1106
1106
|
// tool-heavy workloads.
|
|
1107
1107
|
const target = Math.floor(threshold * 0.25);
|
|
1108
|
-
const result = this.compactWithHooks(target,
|
|
1108
|
+
const result = this.compactWithHooks(target, 1);
|
|
1109
1109
|
if (!result) {
|
|
1110
1110
|
// Auto-compact fired but nothing was evictable. This can happen
|
|
1111
1111
|
// in short conversations with heavy tool output where the pin
|
|
@@ -1488,7 +1488,7 @@ export class AgentLoop {
|
|
|
1488
1488
|
if (this.isContextOverflow(e)) {
|
|
1489
1489
|
const contextWindow = this.currentMode.contextWindow ?? DEFAULT_CONTEXT_WINDOW;
|
|
1490
1490
|
const target = Math.floor((contextWindow - RESPONSE_RESERVE) * 0.6);
|
|
1491
|
-
const stats = this.compactWithHooks(target,
|
|
1491
|
+
const stats = this.compactWithHooks(target, 1);
|
|
1492
1492
|
// If compaction freed nothing, retrying will hit the same error.
|
|
1493
1493
|
// Surface the real failure instead of looping until exhaustion.
|
|
1494
1494
|
if (!stats || stats.after >= stats.before) {
|
|
@@ -29,6 +29,19 @@ function firstMatchExcerpt(text, regex) {
|
|
|
29
29
|
function recencyWeight(idx, total) {
|
|
30
30
|
return Math.max(0.1, 1 - idx / total);
|
|
31
31
|
}
|
|
32
|
+
// Head+tail because the start (command, opening lines) and end (final
|
|
33
|
+
// result, exit code) are the informative parts of shell/file output.
|
|
34
|
+
function slimToolContent(content, maxLen) {
|
|
35
|
+
const exitMatch = content.match(/exit code:?\s*(\d+)/i);
|
|
36
|
+
const exitSuffix = exitMatch ? ` (exit ${exitMatch[1]})` : "";
|
|
37
|
+
const lines = content.split("\n");
|
|
38
|
+
if (lines.length > 6) {
|
|
39
|
+
const head = lines.slice(0, 3).join("\n");
|
|
40
|
+
const tail = lines.slice(-2).join("\n");
|
|
41
|
+
return `${head}\n... [${lines.length - 5} lines trimmed by compact]\n${tail}${exitSuffix}`;
|
|
42
|
+
}
|
|
43
|
+
return `${content.slice(0, maxLen)}\n... [${content.length - maxLen} chars trimmed by compact]${exitSuffix}`;
|
|
44
|
+
}
|
|
32
45
|
/**
|
|
33
46
|
* Conversation state with eager nucleation — shell-history shaped.
|
|
34
47
|
*
|
|
@@ -611,6 +624,7 @@ export class ConversationState {
|
|
|
611
624
|
// ── Internal: Two-tier pin for recent turns ────────────────────
|
|
612
625
|
slimTurn(messages) {
|
|
613
626
|
const MAX_RESULT_LEN = 1500;
|
|
627
|
+
const MAX_ASSISTANT_LEN = 1500;
|
|
614
628
|
const result = [];
|
|
615
629
|
const droppedToolIds = new Set();
|
|
616
630
|
for (const msg of messages) {
|
|
@@ -642,13 +656,20 @@ export class ConversationState {
|
|
|
642
656
|
continue;
|
|
643
657
|
const content = typeof msg.content === "string" ? msg.content : "";
|
|
644
658
|
if (content.length > MAX_RESULT_LEN) {
|
|
645
|
-
result.push({ ...msg, content: content
|
|
659
|
+
result.push({ ...msg, content: slimToolContent(content, MAX_RESULT_LEN) });
|
|
646
660
|
}
|
|
647
661
|
else {
|
|
648
662
|
result.push(msg);
|
|
649
663
|
}
|
|
650
664
|
continue;
|
|
651
665
|
}
|
|
666
|
+
if (msg.role === "assistant" && typeof msg.content === "string" && msg.content.length > MAX_ASSISTANT_LEN) {
|
|
667
|
+
const head = msg.content.slice(0, Math.floor(MAX_ASSISTANT_LEN * 0.6));
|
|
668
|
+
const tail = msg.content.slice(-Math.floor(MAX_ASSISTANT_LEN * 0.2));
|
|
669
|
+
const trimmed = msg.content.length - head.length - tail.length;
|
|
670
|
+
result.push({ ...msg, content: `${head}\n... [${trimmed} chars trimmed by compact]\n${tail}` });
|
|
671
|
+
continue;
|
|
672
|
+
}
|
|
652
673
|
result.push(msg);
|
|
653
674
|
}
|
|
654
675
|
return result;
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawn } from "node:child_process";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
-
import { activateShell } from "./shell/index.js";
|
|
4
|
+
import { activateShell, registerShellHandlers } from "./shell/index.js";
|
|
5
5
|
import { createCore } from "./core.js";
|
|
6
6
|
import { palette as p } from "./utils/palette.js";
|
|
7
7
|
import { loadBuiltinExtensions } from "./extensions/index.js";
|
|
@@ -237,6 +237,8 @@ async function main() {
|
|
|
237
237
|
process.exit(0);
|
|
238
238
|
};
|
|
239
239
|
const extCtx = core.extensionContext({ quit: cleanup });
|
|
240
|
+
// Before loadExtensions: extensions look up shell handlers at activation.
|
|
241
|
+
registerShellHandlers(extCtx);
|
|
240
242
|
// Load before spawning the shell so PS1 lands below the banner.
|
|
241
243
|
await loadBuiltinExtensions(extCtx, getSettings().disabledBuiltins);
|
|
242
244
|
const loadExtensionsTimeoutMs = 10000;
|
package/dist/install.js
CHANGED
|
@@ -69,11 +69,13 @@ function pickResolver(spec) {
|
|
|
69
69
|
return r;
|
|
70
70
|
return bundledResolver;
|
|
71
71
|
}
|
|
72
|
-
function
|
|
72
|
+
function readPackageJson(target) {
|
|
73
73
|
const pkgJson = path.join(target, "package.json");
|
|
74
74
|
if (!fs.existsSync(pkgJson))
|
|
75
|
-
return;
|
|
76
|
-
|
|
75
|
+
return null;
|
|
76
|
+
return JSON.parse(fs.readFileSync(pkgJson, "utf-8"));
|
|
77
|
+
}
|
|
78
|
+
function maybeNpmInstall(target, pkg) {
|
|
77
79
|
const deps = { ...(pkg.dependencies ?? {}), ...(pkg.peerDependencies ?? {}) };
|
|
78
80
|
if (Object.keys(deps).length === 0)
|
|
79
81
|
return;
|
|
@@ -88,6 +90,56 @@ function maybeNpmInstall(target) {
|
|
|
88
90
|
throw new Error(`npm install failed in ${target}; run it manually.`);
|
|
89
91
|
}
|
|
90
92
|
}
|
|
93
|
+
function normalizeBin(pkg) {
|
|
94
|
+
if (!pkg.bin)
|
|
95
|
+
return {};
|
|
96
|
+
if (typeof pkg.bin === "string") {
|
|
97
|
+
const name = pkg.name?.startsWith("@") ? pkg.name.split("/")[1] : pkg.name;
|
|
98
|
+
return name ? { [name]: pkg.bin } : {};
|
|
99
|
+
}
|
|
100
|
+
return pkg.bin;
|
|
101
|
+
}
|
|
102
|
+
function maybeNpmBuild(target, pkg) {
|
|
103
|
+
if (!pkg.scripts?.build)
|
|
104
|
+
return;
|
|
105
|
+
const binPaths = Object.values(normalizeBin(pkg)).map((p) => path.join(target, p));
|
|
106
|
+
if (binPaths.length === 0)
|
|
107
|
+
return;
|
|
108
|
+
if (binPaths.every((p) => fs.existsSync(p)))
|
|
109
|
+
return;
|
|
110
|
+
console.log(`Running npm run build in ${target}...`);
|
|
111
|
+
const result = spawnSync("npm", ["run", "build"], { cwd: target, stdio: "inherit" });
|
|
112
|
+
if (result.status !== 0) {
|
|
113
|
+
throw new Error(`npm run build failed in ${target}; run it manually.`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function linkBins(target, pkg) {
|
|
117
|
+
const bins = normalizeBin(pkg);
|
|
118
|
+
if (Object.keys(bins).length === 0)
|
|
119
|
+
return [];
|
|
120
|
+
const binDir = path.join(CONFIG_DIR, "bin");
|
|
121
|
+
fs.mkdirSync(binDir, { recursive: true });
|
|
122
|
+
const linked = [];
|
|
123
|
+
for (const [name, relPath] of Object.entries(bins)) {
|
|
124
|
+
const src = path.resolve(target, relPath);
|
|
125
|
+
if (!fs.existsSync(src)) {
|
|
126
|
+
console.error(`agent-sh: skipping bin "${name}" — ${src} not found`);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
try {
|
|
130
|
+
fs.chmodSync(src, 0o755);
|
|
131
|
+
}
|
|
132
|
+
catch { /* ignore */ }
|
|
133
|
+
const linkPath = path.join(binDir, name);
|
|
134
|
+
try {
|
|
135
|
+
fs.unlinkSync(linkPath);
|
|
136
|
+
}
|
|
137
|
+
catch { /* ignore */ }
|
|
138
|
+
fs.symlinkSync(src, linkPath);
|
|
139
|
+
linked.push(name);
|
|
140
|
+
}
|
|
141
|
+
return linked;
|
|
142
|
+
}
|
|
91
143
|
export async function runInstall(spec, opts = {}) {
|
|
92
144
|
if (!spec) {
|
|
93
145
|
console.error("Usage: agent-sh install <name|file:|npm:|github:> [--force]\n\n" +
|
|
@@ -114,10 +166,16 @@ export async function runInstall(spec, opts = {}) {
|
|
|
114
166
|
}
|
|
115
167
|
fs.rmSync(target, { recursive: true, force: true });
|
|
116
168
|
}
|
|
169
|
+
let linkedBins = [];
|
|
117
170
|
if (resolved.isDirectory) {
|
|
118
171
|
fs.cpSync(resolved.sourcePath, target, { recursive: true });
|
|
119
172
|
try {
|
|
120
|
-
|
|
173
|
+
const pkg = readPackageJson(target);
|
|
174
|
+
if (pkg) {
|
|
175
|
+
maybeNpmInstall(target, pkg);
|
|
176
|
+
maybeNpmBuild(target, pkg);
|
|
177
|
+
linkedBins = linkBins(target, pkg);
|
|
178
|
+
}
|
|
121
179
|
}
|
|
122
180
|
catch (err) {
|
|
123
181
|
console.error(`agent-sh: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -128,6 +186,11 @@ export async function runInstall(spec, opts = {}) {
|
|
|
128
186
|
fs.copyFileSync(resolved.sourcePath, target);
|
|
129
187
|
}
|
|
130
188
|
console.log(`Installed: ${resolved.name} -> ${target}`);
|
|
189
|
+
if (linkedBins.length > 0) {
|
|
190
|
+
const binDir = path.join(CONFIG_DIR, "bin");
|
|
191
|
+
console.log(`Linked bins: ${linkedBins.join(", ")} -> ${binDir}`);
|
|
192
|
+
console.log(`Add to PATH: export PATH="${binDir}:$PATH"`);
|
|
193
|
+
}
|
|
131
194
|
}
|
|
132
195
|
export async function runUninstall(name) {
|
|
133
196
|
if (!name) {
|
|
@@ -146,6 +209,23 @@ export async function runUninstall(name) {
|
|
|
146
209
|
console.error(`agent-sh: not installed: ${name}`);
|
|
147
210
|
process.exit(1);
|
|
148
211
|
}
|
|
212
|
+
const pkg = readPackageJson(target);
|
|
213
|
+
if (pkg) {
|
|
214
|
+
const binDir = path.join(CONFIG_DIR, "bin");
|
|
215
|
+
const targetPrefix = path.resolve(target) + path.sep;
|
|
216
|
+
for (const binName of Object.keys(normalizeBin(pkg))) {
|
|
217
|
+
const linkPath = path.join(binDir, binName);
|
|
218
|
+
try {
|
|
219
|
+
const stat = fs.lstatSync(linkPath, { throwIfNoEntry: false });
|
|
220
|
+
if (!stat?.isSymbolicLink())
|
|
221
|
+
continue;
|
|
222
|
+
const dest = path.resolve(binDir, fs.readlinkSync(linkPath));
|
|
223
|
+
if (dest.startsWith(targetPrefix))
|
|
224
|
+
fs.unlinkSync(linkPath);
|
|
225
|
+
}
|
|
226
|
+
catch { /* ignore */ }
|
|
227
|
+
}
|
|
228
|
+
}
|
|
149
229
|
fs.rmSync(target, { recursive: true, force: true });
|
|
150
230
|
console.log(`Uninstalled: ${name}`);
|
|
151
231
|
}
|
package/dist/shell/index.d.ts
CHANGED
|
@@ -27,6 +27,11 @@ export interface ShellHandle {
|
|
|
27
27
|
/** Forward terminal size changes to the PTY. */
|
|
28
28
|
resize(cols: number, rows: number): void;
|
|
29
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Register shell-owned handlers extensions can `ctx.call`. Must run before
|
|
32
|
+
* `loadExtensions`; the handlers only need the bus, not the PTY.
|
|
33
|
+
*/
|
|
34
|
+
export declare function registerShellHandlers(ctx: ExtensionContext): void;
|
|
30
35
|
/**
|
|
31
36
|
* Construct the Shell, wire resize forwarding, and register cleanup with the
|
|
32
37
|
* provided ExtensionContext. Returns a handle the caller (typically
|
package/dist/shell/index.js
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import { Shell } from "./shell.js";
|
|
2
2
|
import { StdoutSurface } from "../utils/compositor.js";
|
|
3
3
|
import { TerminalBuffer } from "../utils/terminal-buffer.js";
|
|
4
|
+
/**
|
|
5
|
+
* Register shell-owned handlers extensions can `ctx.call`. Must run before
|
|
6
|
+
* `loadExtensions`; the handlers only need the bus, not the PTY.
|
|
7
|
+
*/
|
|
8
|
+
export function registerShellHandlers(ctx) {
|
|
9
|
+
let terminalBufferSingleton;
|
|
10
|
+
ctx.define("terminal-buffer", () => {
|
|
11
|
+
if (terminalBufferSingleton !== undefined)
|
|
12
|
+
return terminalBufferSingleton;
|
|
13
|
+
terminalBufferSingleton = TerminalBuffer.createWired(ctx.bus);
|
|
14
|
+
return terminalBufferSingleton;
|
|
15
|
+
});
|
|
16
|
+
}
|
|
4
17
|
/**
|
|
5
18
|
* Construct the Shell, wire resize forwarding, and register cleanup with the
|
|
6
19
|
* provided ExtensionContext. Returns a handle the caller (typically
|
|
@@ -13,14 +26,6 @@ export function activateShell(ctx, opts) {
|
|
|
13
26
|
ctx.compositor.setDefault("agent", stdoutSurface);
|
|
14
27
|
ctx.compositor.setDefault("query", stdoutSurface);
|
|
15
28
|
ctx.compositor.setDefault("status", stdoutSurface);
|
|
16
|
-
// Lazy because @xterm/headless is optional; null when not installed.
|
|
17
|
-
let terminalBufferSingleton;
|
|
18
|
-
ctx.define("terminal-buffer", () => {
|
|
19
|
-
if (terminalBufferSingleton !== undefined)
|
|
20
|
-
return terminalBufferSingleton;
|
|
21
|
-
terminalBufferSingleton = TerminalBuffer.createWired(ctx.bus);
|
|
22
|
-
return terminalBufferSingleton;
|
|
23
|
-
});
|
|
24
29
|
const shell = new Shell({
|
|
25
30
|
bus: ctx.bus,
|
|
26
31
|
handlers: { define: ctx.define, call: ctx.call },
|
|
@@ -229,9 +229,15 @@ export class InputHandler {
|
|
|
229
229
|
return false;
|
|
230
230
|
}
|
|
231
231
|
renderModeInput() {
|
|
232
|
-
this.view.
|
|
233
|
-
|
|
234
|
-
|
|
232
|
+
this.view.beginFrame();
|
|
233
|
+
try {
|
|
234
|
+
this.view.clearAutocomplete();
|
|
235
|
+
this.drawPrompt();
|
|
236
|
+
this.updateAutocomplete();
|
|
237
|
+
}
|
|
238
|
+
finally {
|
|
239
|
+
this.view.endFrame();
|
|
240
|
+
}
|
|
235
241
|
}
|
|
236
242
|
updateAutocomplete() {
|
|
237
243
|
const buf = this.editor.text;
|
|
@@ -278,13 +284,19 @@ export class InputHandler {
|
|
|
278
284
|
else {
|
|
279
285
|
this.editor.setText(selected.name);
|
|
280
286
|
}
|
|
281
|
-
this.view.
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
this.
|
|
287
|
+
this.view.beginFrame();
|
|
288
|
+
try {
|
|
289
|
+
this.view.clearAutocomplete();
|
|
290
|
+
this.autocompleteActive = false;
|
|
291
|
+
this.autocompleteItems = [];
|
|
292
|
+
this.autocompleteIndex = 0;
|
|
293
|
+
this.drawPrompt();
|
|
294
|
+
if (isFileAc)
|
|
295
|
+
this.updateAutocomplete();
|
|
296
|
+
}
|
|
297
|
+
finally {
|
|
298
|
+
this.view.endFrame();
|
|
299
|
+
}
|
|
288
300
|
}
|
|
289
301
|
dismissAutocomplete() {
|
|
290
302
|
this.view.clearAutocomplete();
|
|
@@ -314,11 +326,17 @@ export class InputHandler {
|
|
|
314
326
|
case "changed": {
|
|
315
327
|
const switchMode = this.modes.get(this.editor.text);
|
|
316
328
|
if (this.editor.text.length === 1 && switchMode && switchMode !== this.activeMode) {
|
|
317
|
-
this.
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
329
|
+
this.view.beginFrame();
|
|
330
|
+
try {
|
|
331
|
+
this.dismissAutocomplete();
|
|
332
|
+
this.view.clearPromptArea();
|
|
333
|
+
this.activeMode = switchMode;
|
|
334
|
+
this.editor.clear();
|
|
335
|
+
this.drawPrompt(false);
|
|
336
|
+
}
|
|
337
|
+
finally {
|
|
338
|
+
this.view.endFrame();
|
|
339
|
+
}
|
|
322
340
|
break;
|
|
323
341
|
}
|
|
324
342
|
this.historyIndex = -1;
|
|
@@ -371,8 +389,14 @@ export class InputHandler {
|
|
|
371
389
|
}
|
|
372
390
|
case "cancel":
|
|
373
391
|
if (this.autocompleteActive) {
|
|
374
|
-
this.
|
|
375
|
-
|
|
392
|
+
this.view.beginFrame();
|
|
393
|
+
try {
|
|
394
|
+
this.dismissAutocomplete();
|
|
395
|
+
this.drawPrompt();
|
|
396
|
+
}
|
|
397
|
+
finally {
|
|
398
|
+
this.view.endFrame();
|
|
399
|
+
}
|
|
376
400
|
}
|
|
377
401
|
else {
|
|
378
402
|
this.exitMode();
|
|
@@ -393,9 +417,15 @@ export class InputHandler {
|
|
|
393
417
|
this.autocompleteIndex === 0
|
|
394
418
|
? this.autocompleteItems.length - 1
|
|
395
419
|
: this.autocompleteIndex - 1;
|
|
396
|
-
this.view.
|
|
397
|
-
|
|
398
|
-
|
|
420
|
+
this.view.beginFrame();
|
|
421
|
+
try {
|
|
422
|
+
this.view.clearAutocomplete();
|
|
423
|
+
this.drawPrompt();
|
|
424
|
+
this.view.drawAutocomplete({ items: this.autocompleteItems, selected: this.autocompleteIndex });
|
|
425
|
+
}
|
|
426
|
+
finally {
|
|
427
|
+
this.view.endFrame();
|
|
428
|
+
}
|
|
399
429
|
}
|
|
400
430
|
else if (this.history.length > 0) {
|
|
401
431
|
if (this.historyIndex === -1) {
|
|
@@ -406,8 +436,14 @@ export class InputHandler {
|
|
|
406
436
|
this.historyIndex--;
|
|
407
437
|
}
|
|
408
438
|
this.editor.setText(this.history[this.historyIndex]);
|
|
409
|
-
this.view.
|
|
410
|
-
|
|
439
|
+
this.view.beginFrame();
|
|
440
|
+
try {
|
|
441
|
+
this.view.clearAutocomplete();
|
|
442
|
+
this.drawPrompt();
|
|
443
|
+
}
|
|
444
|
+
finally {
|
|
445
|
+
this.view.endFrame();
|
|
446
|
+
}
|
|
411
447
|
}
|
|
412
448
|
break;
|
|
413
449
|
case "arrow-down":
|
|
@@ -416,9 +452,15 @@ export class InputHandler {
|
|
|
416
452
|
this.autocompleteIndex === this.autocompleteItems.length - 1
|
|
417
453
|
? 0
|
|
418
454
|
: this.autocompleteIndex + 1;
|
|
419
|
-
this.view.
|
|
420
|
-
|
|
421
|
-
|
|
455
|
+
this.view.beginFrame();
|
|
456
|
+
try {
|
|
457
|
+
this.view.clearAutocomplete();
|
|
458
|
+
this.drawPrompt();
|
|
459
|
+
this.view.drawAutocomplete({ items: this.autocompleteItems, selected: this.autocompleteIndex });
|
|
460
|
+
}
|
|
461
|
+
finally {
|
|
462
|
+
this.view.endFrame();
|
|
463
|
+
}
|
|
422
464
|
}
|
|
423
465
|
else if (this.historyIndex !== -1) {
|
|
424
466
|
if (this.historyIndex < this.history.length - 1) {
|
|
@@ -429,8 +471,14 @@ export class InputHandler {
|
|
|
429
471
|
this.historyIndex = -1;
|
|
430
472
|
this.editor.setText(this.savedBuffer);
|
|
431
473
|
}
|
|
432
|
-
this.view.
|
|
433
|
-
|
|
474
|
+
this.view.beginFrame();
|
|
475
|
+
try {
|
|
476
|
+
this.view.clearAutocomplete();
|
|
477
|
+
this.drawPrompt();
|
|
478
|
+
}
|
|
479
|
+
finally {
|
|
480
|
+
this.view.endFrame();
|
|
481
|
+
}
|
|
434
482
|
}
|
|
435
483
|
break;
|
|
436
484
|
}
|
|
@@ -26,7 +26,12 @@ export declare class TuiInputView {
|
|
|
26
26
|
private cursorTermCol;
|
|
27
27
|
private autocompleteLines;
|
|
28
28
|
private readonly surface;
|
|
29
|
+
private frameBuf;
|
|
29
30
|
constructor(surface?: RenderSurface);
|
|
31
|
+
beginFrame(): void;
|
|
32
|
+
endFrame(): void;
|
|
33
|
+
private emit;
|
|
34
|
+
private autoFrame;
|
|
30
35
|
resetCursor(): void;
|
|
31
36
|
enableModeKeys(): void;
|
|
32
37
|
disableModeKeys(): void;
|