agen-vektor 0.3.6 → 0.3.7
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/cli/index.js +19 -4
- package/dist/tui/app.js +56 -5
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -247,7 +247,10 @@ async function runTui(opts) {
|
|
|
247
247
|
const out = app.render();
|
|
248
248
|
process.stdout.write(terminal_1.ANSI.hideCursor + out);
|
|
249
249
|
};
|
|
250
|
-
const onResize = () =>
|
|
250
|
+
const onResize = () => {
|
|
251
|
+
app.markDirty();
|
|
252
|
+
doRender();
|
|
253
|
+
};
|
|
251
254
|
process.stdout.on('resize', onResize);
|
|
252
255
|
process.on('SIGINT', () => {
|
|
253
256
|
// In raw mode Ctrl+C arrives as a key event (0x03), but some terminals
|
|
@@ -258,6 +261,12 @@ async function runTui(opts) {
|
|
|
258
261
|
else
|
|
259
262
|
process.exit(0);
|
|
260
263
|
});
|
|
264
|
+
process.on('SIGTERM', () => {
|
|
265
|
+
if (app)
|
|
266
|
+
app.requestExit();
|
|
267
|
+
else
|
|
268
|
+
process.exit(0);
|
|
269
|
+
});
|
|
261
270
|
process.on('SIGWINCH', onResize);
|
|
262
271
|
const keyHandler = (ev) => {
|
|
263
272
|
void app.handleKey(ev);
|
|
@@ -269,11 +278,17 @@ async function runTui(opts) {
|
|
|
269
278
|
(0, keyboard_1.keyStream)(keyHandler);
|
|
270
279
|
app.start();
|
|
271
280
|
doRender();
|
|
272
|
-
|
|
281
|
+
app.consumeRender();
|
|
282
|
+
// Main tick loop — repaint only when something changed. Repainting the
|
|
283
|
+
// whole frame every tick caused constant flicker and made keystrokes
|
|
284
|
+
// (Enter, Ctrl+C) feel laggy on slow/mobile connections.
|
|
273
285
|
while (!exit) {
|
|
274
286
|
await app.tick();
|
|
275
|
-
|
|
276
|
-
|
|
287
|
+
if (app.needsRender()) {
|
|
288
|
+
doRender();
|
|
289
|
+
app.consumeRender();
|
|
290
|
+
}
|
|
291
|
+
await sleep(80);
|
|
277
292
|
}
|
|
278
293
|
}
|
|
279
294
|
finally {
|
package/dist/tui/app.js
CHANGED
|
@@ -79,6 +79,8 @@ class App {
|
|
|
79
79
|
abortController = null;
|
|
80
80
|
spinner = new theme_1.Spinner();
|
|
81
81
|
runStart = null;
|
|
82
|
+
/** set on every mutation so the render loop only repaints when needed */
|
|
83
|
+
dirty = true;
|
|
82
84
|
constructor(agent, opts) {
|
|
83
85
|
this.agent = agent;
|
|
84
86
|
this.opts = opts;
|
|
@@ -88,7 +90,20 @@ class App {
|
|
|
88
90
|
}
|
|
89
91
|
}
|
|
90
92
|
// ─── Public API ───────────────────────────────────────────────
|
|
93
|
+
/** Mark the screen as needing a repaint. */
|
|
94
|
+
markDirty() {
|
|
95
|
+
this.dirty = true;
|
|
96
|
+
}
|
|
97
|
+
/** True when the screen must be repainted (dirty, or streaming). */
|
|
98
|
+
needsRender() {
|
|
99
|
+
return this.dirty || this.running;
|
|
100
|
+
}
|
|
101
|
+
/** Clear the dirty flag after a repaint. */
|
|
102
|
+
consumeRender() {
|
|
103
|
+
this.dirty = false;
|
|
104
|
+
}
|
|
91
105
|
start() {
|
|
106
|
+
this.markDirty();
|
|
92
107
|
this.connected = true;
|
|
93
108
|
this.status = 'Ready';
|
|
94
109
|
if (this.opts.continueSession && this.sessionName) {
|
|
@@ -106,6 +121,7 @@ class App {
|
|
|
106
121
|
}
|
|
107
122
|
}
|
|
108
123
|
async handleKey(ev) {
|
|
124
|
+
this.markDirty();
|
|
109
125
|
if (this.modal.type !== 'none') {
|
|
110
126
|
await this.handleModalKey(ev);
|
|
111
127
|
return;
|
|
@@ -119,6 +135,10 @@ class App {
|
|
|
119
135
|
this.running = false;
|
|
120
136
|
this.addSystem('⏹ Stopped. Press Ctrl+C again to quit.');
|
|
121
137
|
}
|
|
138
|
+
else if (ev.name === 'ctrl_d') {
|
|
139
|
+
// Ctrl+D stops and quits in one go (handy on mobile)
|
|
140
|
+
this.requestExit();
|
|
141
|
+
}
|
|
122
142
|
return;
|
|
123
143
|
}
|
|
124
144
|
switch (ev.name) {
|
|
@@ -204,11 +224,13 @@ class App {
|
|
|
204
224
|
}
|
|
205
225
|
async tick() {
|
|
206
226
|
if (this.pendingPrompt) {
|
|
227
|
+
this.markDirty();
|
|
207
228
|
const p = this.pendingPrompt;
|
|
208
229
|
this.pendingPrompt = '';
|
|
209
230
|
await this.submit(p);
|
|
210
231
|
}
|
|
211
232
|
if (this.planToExecute) {
|
|
233
|
+
this.markDirty();
|
|
212
234
|
const plan = this.planToExecute;
|
|
213
235
|
this.planToExecute = null;
|
|
214
236
|
await this.executeWithPlan(plan);
|
|
@@ -222,6 +244,7 @@ class App {
|
|
|
222
244
|
* Used by Ctrl+C and SIGINT so the TUI never needs to be killed.
|
|
223
245
|
*/
|
|
224
246
|
requestExit() {
|
|
247
|
+
this.markDirty();
|
|
225
248
|
if (this.running) {
|
|
226
249
|
this.abortController?.abort();
|
|
227
250
|
this.running = false;
|
|
@@ -230,6 +253,7 @@ class App {
|
|
|
230
253
|
}
|
|
231
254
|
// ─── Submission ───────────────────────────────────────────────
|
|
232
255
|
async submit(text) {
|
|
256
|
+
this.markDirty();
|
|
233
257
|
if (text.startsWith('/')) {
|
|
234
258
|
await this.handleCommand(text);
|
|
235
259
|
return;
|
|
@@ -284,15 +308,18 @@ class App {
|
|
|
284
308
|
}) - 1;
|
|
285
309
|
this.agent.setCallbacks({
|
|
286
310
|
onDelta: (delta) => {
|
|
311
|
+
this.markDirty();
|
|
287
312
|
const m = this.messages[msgIndex];
|
|
288
313
|
if (m)
|
|
289
314
|
m.content += delta;
|
|
290
315
|
},
|
|
291
316
|
onStatus: (status) => {
|
|
317
|
+
this.markDirty();
|
|
292
318
|
this.status = status;
|
|
293
319
|
this.statusColor = (0, theme_1.statusColor)(status);
|
|
294
320
|
},
|
|
295
321
|
onToolCall: (tool, args) => {
|
|
322
|
+
this.markDirty();
|
|
296
323
|
let preview = '';
|
|
297
324
|
try {
|
|
298
325
|
const parsed = JSON.parse(args);
|
|
@@ -306,6 +333,7 @@ class App {
|
|
|
306
333
|
this.messages.push({ kind: 'tool', tool, content: `→ ${preview}` });
|
|
307
334
|
},
|
|
308
335
|
onToolResult: (tool, result) => {
|
|
336
|
+
this.markDirty();
|
|
309
337
|
const last = this.messages[this.messages.length - 1];
|
|
310
338
|
if (last && last.kind === 'tool' && last.tool === tool) {
|
|
311
339
|
last.content = result.split('\n').slice(0, 12).join('\n');
|
|
@@ -314,6 +342,7 @@ class App {
|
|
|
314
342
|
}
|
|
315
343
|
},
|
|
316
344
|
onError: (err) => {
|
|
345
|
+
this.markDirty();
|
|
317
346
|
const m = this.messages[msgIndex];
|
|
318
347
|
if (m) {
|
|
319
348
|
m.kind = 'error';
|
|
@@ -322,6 +351,7 @@ class App {
|
|
|
322
351
|
}
|
|
323
352
|
},
|
|
324
353
|
onFinal: (result) => {
|
|
354
|
+
this.markDirty();
|
|
325
355
|
const m = this.messages[msgIndex];
|
|
326
356
|
if (m) {
|
|
327
357
|
m.content = result.content || m.content;
|
|
@@ -386,6 +416,7 @@ class App {
|
|
|
386
416
|
}));
|
|
387
417
|
}
|
|
388
418
|
async executeWithPlan(plan) {
|
|
419
|
+
this.markDirty();
|
|
389
420
|
this.running = true;
|
|
390
421
|
this.status = 'Executing plan';
|
|
391
422
|
this.statusColor = terminal_1.ANSI.yellow;
|
|
@@ -478,6 +509,21 @@ class App {
|
|
|
478
509
|
this.addSystem(`Current session: ${this.sessionName || '(none)'}`);
|
|
479
510
|
}
|
|
480
511
|
break;
|
|
512
|
+
case '/connect':
|
|
513
|
+
// Wizard for a custom OpenAI-compatible API: base URL + token
|
|
514
|
+
this.agent.config.provider = 'custom';
|
|
515
|
+
this.agent.rebuildProvider();
|
|
516
|
+
(0, config_1.saveConfig)(this.agent.config);
|
|
517
|
+
this.addSystem('Custom provider — masukkan base URL API (mis. https://…/v1), lalu token.');
|
|
518
|
+
this.modal = { type: 'custom-url', value: this.agent.config.apiUrl || '' };
|
|
519
|
+
break;
|
|
520
|
+
case '/agent':
|
|
521
|
+
this.agent.setMode(this.agent.config.permissionMode === 'yolo' ? 'ask' : 'yolo');
|
|
522
|
+
(0, config_1.saveConfig)(this.agent.config);
|
|
523
|
+
this.addSystem(this.agent.config.permissionMode === 'yolo'
|
|
524
|
+
? 'Agent mode: YOLO — prompt permission untuk aksi ask-level dilewati.'
|
|
525
|
+
: 'Agent mode: ask — prompt permission aktif.');
|
|
526
|
+
break;
|
|
481
527
|
default:
|
|
482
528
|
this.addSystem(`Unknown command: ${name} (type /help for commands)`);
|
|
483
529
|
break;
|
|
@@ -689,10 +735,12 @@ class App {
|
|
|
689
735
|
}
|
|
690
736
|
// ─── Message helpers ──────────────────────────────────────────
|
|
691
737
|
addSystem(text) {
|
|
738
|
+
this.markDirty();
|
|
692
739
|
this.messages.push({ kind: 'system', content: text });
|
|
693
740
|
}
|
|
694
741
|
/** Show a permission modal (called by the permission callback). */
|
|
695
742
|
setPermissionModal(req) {
|
|
743
|
+
this.markDirty();
|
|
696
744
|
this.modal = {
|
|
697
745
|
type: 'permission',
|
|
698
746
|
req,
|
|
@@ -706,6 +754,7 @@ class App {
|
|
|
706
754
|
this.permissionResolver = fn;
|
|
707
755
|
}
|
|
708
756
|
addTool(tool, content) {
|
|
757
|
+
this.markDirty();
|
|
709
758
|
this.messages.push({ kind: 'tool', tool, content });
|
|
710
759
|
}
|
|
711
760
|
// ─── Rendering ────────────────────────────────────────────────
|
|
@@ -799,11 +848,12 @@ class App {
|
|
|
799
848
|
' PgUp/Dn scroll chat',
|
|
800
849
|
' ? this help',
|
|
801
850
|
' Ctrl+C stop agent / quit',
|
|
851
|
+
' Ctrl+D stop + quit (mobile)',
|
|
802
852
|
' Ctrl+L clear conversation',
|
|
803
853
|
'',
|
|
804
|
-
'Commands: /setup /model /provider
|
|
805
|
-
'/settings /status /clear /continue
|
|
806
|
-
'/git /compact /
|
|
854
|
+
'Commands: /connect /setup /model /provider',
|
|
855
|
+
'/session /settings /status /clear /continue',
|
|
856
|
+
'/diff /git /compact /agent /exit',
|
|
807
857
|
],
|
|
808
858
|
}, rows, cols);
|
|
809
859
|
case 'commands':
|
|
@@ -811,7 +861,8 @@ class App {
|
|
|
811
861
|
title: 'Commands',
|
|
812
862
|
body: [
|
|
813
863
|
'/help show help',
|
|
814
|
-
'/
|
|
864
|
+
'/connect set custom API base URL + token',
|
|
865
|
+
'/setup setup provider',
|
|
815
866
|
'/model select model',
|
|
816
867
|
'/provider select provider',
|
|
817
868
|
'/session manage sessions',
|
|
@@ -822,7 +873,7 @@ class App {
|
|
|
822
873
|
'/diff show diff',
|
|
823
874
|
'/git git status',
|
|
824
875
|
'/compact compact context',
|
|
825
|
-
'/
|
|
876
|
+
'/agent toggle permission mode (ask/yolo)',
|
|
826
877
|
'/exit quit',
|
|
827
878
|
],
|
|
828
879
|
}, rows, cols);
|
package/package.json
CHANGED