zames_pro 2.3.0 → 2.4.0
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/index.js +33 -1
- package/dist/input.js +69 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -183,6 +183,7 @@ ${theme.bold('Пока агент работает:')}
|
|
|
183
183
|
печать + Enter поставить сообщение в очередь (уйдёт после текущей задачи)
|
|
184
184
|
↑ / ↓ история введённых сообщений
|
|
185
185
|
Ctrl+← / Ctrl+→ перемещение по словам
|
|
186
|
+
/ + Tab подсказка и автодополнение slash-команд
|
|
186
187
|
Ctrl+J новая строка (Shift+Enter в терминалах с поддержкой)
|
|
187
188
|
Esc, Ctrl+C прервать текущую генерацию
|
|
188
189
|
|
|
@@ -229,6 +230,34 @@ ${theme.bold('Файлы:')}
|
|
|
229
230
|
function dirLabel(p) {
|
|
230
231
|
return path.basename(p) || p;
|
|
231
232
|
}
|
|
233
|
+
// Список slash-команд для автодополнения при вводе «/» (Tab — дополнить).
|
|
234
|
+
const SLASH_COMMANDS = [
|
|
235
|
+
{ name: '/help', description: 'справка по командам и опциям' },
|
|
236
|
+
{ name: '/new', description: 'новый чат (сброс контекста)' },
|
|
237
|
+
{ name: '/clear', description: 'то же, что /new' },
|
|
238
|
+
{ name: '/sessions', description: 'список сохранённых сессий' },
|
|
239
|
+
{ name: '/chats', description: 'последние чаты DeepSeek' },
|
|
240
|
+
{ name: '/resume', description: 'открыть чат №n из /chats' },
|
|
241
|
+
{ name: '/resume-id', description: 'восстановить сессию по полному id' },
|
|
242
|
+
{ name: '/chat', description: 'показать текущий chat id' },
|
|
243
|
+
{ name: '/cd', description: 'сменить рабочую директорию' },
|
|
244
|
+
{ name: '/pwd', description: 'текущая рабочая директория' },
|
|
245
|
+
{ name: '/status', description: 'состояние сессии' },
|
|
246
|
+
{ name: '/reload', description: 'перечитать модули логики без перезапуска' },
|
|
247
|
+
{ name: '/undo', description: 'откатить последнюю запись/правку' },
|
|
248
|
+
{ name: '/undo-list', description: 'список того, что можно откатить' },
|
|
249
|
+
{ name: '/transcript', description: 'путь к файлу транскрипта' },
|
|
250
|
+
{ name: '/config', description: 'показать текущий конфиг' },
|
|
251
|
+
{ name: '/debug-dom', description: 'сохранить HTML страницы (отладка)' },
|
|
252
|
+
{ name: '/self-review', description: 'снапшот src/ и запуск ревью' },
|
|
253
|
+
{ name: '/self-fix', description: 'продолжить в существующем снапшоте' },
|
|
254
|
+
{ name: '/self-done', description: 'выйти из режима ревью' },
|
|
255
|
+
{ name: '/self-list', description: 'список снапшотов' },
|
|
256
|
+
{ name: '/self-diff', description: 'различия текущего src/ и снапшота' },
|
|
257
|
+
{ name: '/self-apply', description: 'применить снапшот к src/ (с бэкапом)' },
|
|
258
|
+
{ name: '/exit', description: 'выход' },
|
|
259
|
+
{ name: '/quit', description: 'выход' },
|
|
260
|
+
];
|
|
232
261
|
// Временные файлы агента (одноразовые скрипты и т.п.) складываем в
|
|
233
262
|
// <проект>/tmp — эта папка в .gitignore и очищается при каждом запуске.
|
|
234
263
|
const TMP_DIR = path.join(__dirname, '..', 'tmp');
|
|
@@ -842,7 +871,10 @@ async function main() {
|
|
|
842
871
|
return theme.prompt('❯ ') + tail + theme.dim(' › ');
|
|
843
872
|
};
|
|
844
873
|
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
845
|
-
const ed = new LineEditor({
|
|
874
|
+
const ed = new LineEditor({
|
|
875
|
+
prompt: buildPrompt(),
|
|
876
|
+
commands: SLASH_COMMANDS,
|
|
877
|
+
});
|
|
846
878
|
editor = ed;
|
|
847
879
|
ed.onSubmit = (text) => {
|
|
848
880
|
pendingQueue.push(text);
|
package/dist/input.js
CHANGED
|
@@ -14,7 +14,9 @@ import { randomThinkingPhrase, stripEllipsis } from './spinner.js';
|
|
|
14
14
|
// * перемещение по словам: Ctrl+←/→ (и Alt+B/Alt+F), удаление слова
|
|
15
15
|
// Ctrl+W; Ctrl+K — удалить до конца строки;
|
|
16
16
|
// * история введённых сообщений: ↑/↓ на краях ввода (внутри многострочного
|
|
17
|
-
// ввода стрелки двигают по строкам, как в обычном терминале)
|
|
17
|
+
// ввода стрелки двигают по строкам, как в обычном терминале);
|
|
18
|
+
// * подсказки slash-команд: при вводе «/» под строкой показываются
|
|
19
|
+
// подходящие команды с описанием, Tab — дополнить.
|
|
18
20
|
//
|
|
19
21
|
// Все управляющие символы собираются из кодов, чтобы в файле не было
|
|
20
22
|
// «сырых» ESC/CR/LF в строковых литералах (см. AGENTS.md).
|
|
@@ -141,7 +143,10 @@ export class LineEditor {
|
|
|
141
143
|
history;
|
|
142
144
|
_histIndex;
|
|
143
145
|
_histDraft;
|
|
144
|
-
|
|
146
|
+
// Подсказки slash-команд (показываются при вводе «/»).
|
|
147
|
+
slashCommands;
|
|
148
|
+
_suggestCount;
|
|
149
|
+
constructor({ prompt = '> ', commands = [] } = {}) {
|
|
145
150
|
this.promptStr = prompt;
|
|
146
151
|
this.buf = '';
|
|
147
152
|
this.cursor = 0;
|
|
@@ -162,6 +167,42 @@ export class LineEditor {
|
|
|
162
167
|
this.history = [];
|
|
163
168
|
this._histIndex = 0;
|
|
164
169
|
this._histDraft = '';
|
|
170
|
+
this.slashCommands = commands;
|
|
171
|
+
this._suggestCount = 0;
|
|
172
|
+
}
|
|
173
|
+
// Список подсказок для текущего ввода. Показываем, только когда строка
|
|
174
|
+
// начинается с «/» и это одно слово (без пробелов/переводов строк) — как
|
|
175
|
+
// автодополнение команд в Claude Code.
|
|
176
|
+
_suggestions() {
|
|
177
|
+
const b = this.buf;
|
|
178
|
+
if (!b.startsWith('/'))
|
|
179
|
+
return [];
|
|
180
|
+
if (b.includes(NL) || b.includes(' '))
|
|
181
|
+
return [];
|
|
182
|
+
const q = b.toLowerCase();
|
|
183
|
+
return this.slashCommands.filter((c) => c.name.toLowerCase().startsWith(q));
|
|
184
|
+
}
|
|
185
|
+
// Tab: дополнить команду до общего префикса; если совпадение одно —
|
|
186
|
+
// подставить его целиком и добавить пробел.
|
|
187
|
+
_completeCommand() {
|
|
188
|
+
const sugg = this._suggestions();
|
|
189
|
+
if (!sugg.length)
|
|
190
|
+
return;
|
|
191
|
+
if (sugg.length === 1) {
|
|
192
|
+
this.buf = sugg[0].name + ' ';
|
|
193
|
+
this.cursor = Array.from(this.buf).length;
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
let prefix = sugg[0].name;
|
|
197
|
+
for (const c of sugg) {
|
|
198
|
+
while (!c.name.toLowerCase().startsWith(prefix.toLowerCase())) {
|
|
199
|
+
prefix = prefix.slice(0, -1);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (prefix.length > this.buf.length) {
|
|
203
|
+
this.buf = prefix;
|
|
204
|
+
this.cursor = Array.from(this.buf).length;
|
|
205
|
+
}
|
|
165
206
|
}
|
|
166
207
|
start() {
|
|
167
208
|
const stdin = process.stdin;
|
|
@@ -214,9 +255,29 @@ export class LineEditor {
|
|
|
214
255
|
}
|
|
215
256
|
const lay = layoutInput(this.promptStr, this.buf, this.cursor, cols);
|
|
216
257
|
out += lay.rows.map((r) => r.prefix + r.text).join(NL);
|
|
258
|
+
// Подсказки slash-команд рисуем НИЖЕ строки ввода. Курсор потом
|
|
259
|
+
// возвращаем вверх, на строку ввода, поэтому cursorRowFromTop не меняется.
|
|
260
|
+
const sugg = this._suggestions();
|
|
261
|
+
const shown = sugg.slice(0, 8);
|
|
262
|
+
this._suggestCount = shown.length;
|
|
263
|
+
if (shown.length) {
|
|
264
|
+
const maxName = Math.max(...shown.map((c) => c.name.length));
|
|
265
|
+
const lines = shown.map((c) => {
|
|
266
|
+
const name = theme.prompt(c.name.padEnd(maxName));
|
|
267
|
+
const desc = theme.dim(' ' + c.description);
|
|
268
|
+
return ' ' + name + desc;
|
|
269
|
+
});
|
|
270
|
+
out += NL + lines.join(NL);
|
|
271
|
+
const hidden = sugg.length - shown.length;
|
|
272
|
+
if (hidden > 0)
|
|
273
|
+
out += NL + theme.dim(' …ещё ' + hidden);
|
|
274
|
+
}
|
|
217
275
|
process.stdout.write(out);
|
|
218
276
|
const lastRow = lay.rows.length - 1;
|
|
219
|
-
|
|
277
|
+
// Курсор вверх: сначала на строку ввода внутри lay, затем ещё на
|
|
278
|
+
// строки подсказок (если они есть) — курсор должен стоять на вводе.
|
|
279
|
+
const linesBelow = shown.length ? shown.length + (sugg.length > shown.length ? 1 : 0) : 0;
|
|
280
|
+
const up = lastRow - lay.cursorRow + linesBelow;
|
|
220
281
|
if (up > 0)
|
|
221
282
|
process.stdout.write(ESC + '[' + up + 'A');
|
|
222
283
|
process.stdout.write(CR);
|
|
@@ -550,6 +611,11 @@ export class LineEditor {
|
|
|
550
611
|
this._render();
|
|
551
612
|
continue;
|
|
552
613
|
}
|
|
614
|
+
if (code === 9) {
|
|
615
|
+
this._completeCommand();
|
|
616
|
+
this._render();
|
|
617
|
+
continue;
|
|
618
|
+
}
|
|
553
619
|
if (code === 21) {
|
|
554
620
|
this.buf = '';
|
|
555
621
|
this.cursor = 0;
|