termux-dev 1.8.0 → 1.8.1
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/assets/banner.svg +1 -1
- package/assets/preview.svg +14 -5
- package/dist/cli/banner.js +2 -3
- package/dist/cli/finder.js +241 -0
- package/dist/cli/index.js +236 -320
- package/dist/cli/logo.js +30 -0
- package/dist/cli/markdown.js +17 -2
- package/dist/cli/picker.js +11 -3
- package/dist/cli/transcript.js +21 -1
- package/dist/cli/ui.js +6 -5
- package/dist/cli/welcome.js +56 -0
- package/dist/core/i18n.js +2 -2
- package/dist/core/locales/de.js +55 -0
- package/dist/core/locales/en.js +55 -0
- package/dist/core/locales/es.js +55 -0
- package/dist/core/locales/fr.js +55 -0
- package/dist/core/locales/ja.js +55 -0
- package/dist/core/locales/pt.js +55 -0
- package/dist/core/locales/ru.js +55 -0
- package/dist/core/locales/uk.js +55 -0
- package/dist/core/locales/zh.js +55 -0
- package/dist/core/types.js +1 -1
- package/package.json +1 -1
package/dist/cli/logo.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The devx wordmark, drawn from a small pixel font: every letter is 5 pixels wide and 6 tall, and two
|
|
3
|
+
* pixel rows share one terminal row with half blocks, so the pixels are square and the shapes stay clean.
|
|
4
|
+
*/
|
|
5
|
+
const FONT = {
|
|
6
|
+
D: ['████ ', '█ █', '█ █', '█ █', '█ █', '████ '],
|
|
7
|
+
E: ['█████', '█ ', '████ ', '█ ', '█ ', '█████'],
|
|
8
|
+
V: ['█ █', '█ █', '█ █', '█ █', ' █ █ ', ' █ '],
|
|
9
|
+
X: ['█ █', ' █ █ ', ' █ ', ' █ ', ' █ █ ', '█ █'],
|
|
10
|
+
};
|
|
11
|
+
export function wordmark(text = 'DEVX', gap = 1) {
|
|
12
|
+
const letters = Array.from(text).map((c) => FONT[c]);
|
|
13
|
+
const rows = letters[0].length;
|
|
14
|
+
const out = [];
|
|
15
|
+
for (let r = 0; r < rows; r += 2) {
|
|
16
|
+
let line = '';
|
|
17
|
+
letters.forEach((glyph, i) => {
|
|
18
|
+
if (i > 0)
|
|
19
|
+
line += ' '.repeat(gap);
|
|
20
|
+
for (let x = 0; x < glyph[r].length; x++) {
|
|
21
|
+
const top = glyph[r][x] !== ' ';
|
|
22
|
+
const bottom = glyph[r + 1][x] !== ' ';
|
|
23
|
+
line += top && bottom ? '█' : top ? '▀' : bottom ? '▄' : ' ';
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
out.push(line);
|
|
27
|
+
}
|
|
28
|
+
return out;
|
|
29
|
+
}
|
|
30
|
+
export const DEVX_LOGO = wordmark();
|
package/dist/cli/markdown.js
CHANGED
|
@@ -8,6 +8,18 @@ marked.use(markedTerminal({
|
|
|
8
8
|
showSectionPrefix: false,
|
|
9
9
|
tab: 2
|
|
10
10
|
}));
|
|
11
|
+
// marked-terminal prints the text of a list item as it was written (`code` and **bold** with their
|
|
12
|
+
// marks); the inline tokens of the item have to be rendered.
|
|
13
|
+
marked.use({
|
|
14
|
+
renderer: {
|
|
15
|
+
text(token) {
|
|
16
|
+
if (token && typeof token === 'object' && Array.isArray(token.tokens) && token.tokens.length > 0) {
|
|
17
|
+
return this.parser.parseInline(token.tokens);
|
|
18
|
+
}
|
|
19
|
+
return false;
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
});
|
|
11
23
|
/**
|
|
12
24
|
* Inline markdown (`code`, **bold**, *italic*) for text that arrives in pieces. The state of an open
|
|
13
25
|
* marker is kept between pieces, so a span that runs over several words (`**seven words in bold**`)
|
|
@@ -104,7 +116,9 @@ export function renderMarkdown(content) {
|
|
|
104
116
|
if (!content)
|
|
105
117
|
return '';
|
|
106
118
|
try {
|
|
107
|
-
|
|
119
|
+
const text = marked.parse(unfenceMarkdown(content)).trim();
|
|
120
|
+
// The list marker of marked-terminal is `*`: draw a bullet instead.
|
|
121
|
+
return text.replace(/^((?:\s|\x1b\[[0-9;]*m)*)\* /gm, '$1• ');
|
|
108
122
|
}
|
|
109
123
|
catch {
|
|
110
124
|
return content;
|
|
@@ -167,7 +181,8 @@ export class MarkdownStreamer {
|
|
|
167
181
|
trimmed === '***');
|
|
168
182
|
if (!isSpecialLine) {
|
|
169
183
|
const lastSpaceIdx = Math.max(this.buffer.lastIndexOf(' '), this.buffer.lastIndexOf('\t'));
|
|
170
|
-
|
|
184
|
+
// At the start of a line, a first word that is not finished yet (` *`, the marker of an indented item) waits.
|
|
185
|
+
if (lastSpaceIdx > 0 && (!this.atLineStart || /\S\s/.test(this.buffer))) {
|
|
171
186
|
const wordsToFlush = this.buffer.slice(0, lastSpaceIdx + 1);
|
|
172
187
|
this.buffer = this.buffer.slice(lastSpaceIdx + 1);
|
|
173
188
|
this.sink(this.formatInline(wordsToFlush));
|
package/dist/cli/picker.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { LiveBlock } from './liveblock.js';
|
|
2
2
|
import { splitKeys } from './keys.js';
|
|
3
3
|
import { palette } from './ui.js';
|
|
4
|
+
import { t } from '../core/i18n.js';
|
|
4
5
|
import { displayWidth, padEndWidth, truncateWidth, wrapWords } from './width.js';
|
|
5
6
|
function hints(width) {
|
|
6
7
|
const variants = [
|
|
7
|
-
[['↑↓', 'move'], ['enter', 'select'], ['esc', 'cancel']],
|
|
8
|
+
[['↑↓', t('picker.hint.move')], ['enter', t('picker.hint.select')], ['esc', t('picker.hint.cancel')]],
|
|
8
9
|
[['↑↓', ''], ['enter', ''], ['esc', '']],
|
|
9
10
|
[['enter', ''], ['esc', '']],
|
|
10
11
|
];
|
|
@@ -16,7 +17,7 @@ function hints(width) {
|
|
|
16
17
|
return '';
|
|
17
18
|
}
|
|
18
19
|
/** Of a long list only the rows around the focus are shown, with "↑ N more" / "↓ N more" at the cut edges. */
|
|
19
|
-
function windowItems(rows, focus, max, width) {
|
|
20
|
+
export function windowItems(rows, focus, max, width) {
|
|
20
21
|
if (rows.length <= max)
|
|
21
22
|
return rows;
|
|
22
23
|
const start = Math.max(0, Math.min(rows.length - max, focus - Math.floor(max / 2)));
|
|
@@ -87,7 +88,14 @@ export function runPicker(options, io = { input: process.stdin, output: process.
|
|
|
87
88
|
const count = options.items.length;
|
|
88
89
|
let focus = Math.max(0, options.items.findIndex((i) => options.current !== undefined && i.value === options.current));
|
|
89
90
|
let done = false;
|
|
90
|
-
|
|
91
|
+
let reported = -1;
|
|
92
|
+
const draw = () => {
|
|
93
|
+
if (options.onFocus && focus !== reported) {
|
|
94
|
+
reported = focus;
|
|
95
|
+
options.onFocus(options.items[focus].value);
|
|
96
|
+
}
|
|
97
|
+
block.draw(renderPicker(options, focus, output.columns || 80, output.rows || 40));
|
|
98
|
+
};
|
|
91
99
|
const wasRaw = !!input.isRaw;
|
|
92
100
|
input.setRawMode?.(true);
|
|
93
101
|
input.resume();
|
package/dist/cli/transcript.js
CHANGED
|
@@ -5,6 +5,8 @@ import { palette, renderPlanCard, renderResultLine, renderTaskCard, renderToolLi
|
|
|
5
5
|
import { displayWidth, truncateWidth, wrapText } from './width.js';
|
|
6
6
|
import { t } from '../core/i18n.js';
|
|
7
7
|
const MAX_ECHO_LINES = 300;
|
|
8
|
+
/** What /compact puts in front of the summary it keeps as the first message. */
|
|
9
|
+
export const COMPACT_MARK = '[CONVERSATION COMPACTED]';
|
|
8
10
|
/** The rows under a tool line: a plan card, a diff, or the output (one row folded, all of it unfolded). */
|
|
9
11
|
export function toolResultRows(name, result, opts) {
|
|
10
12
|
const { cols } = opts;
|
|
@@ -49,6 +51,20 @@ function thoughtRows(item, opts) {
|
|
|
49
51
|
const body = item.text.trim().split('\n').flatMap((line) => (line.trim() === '' ? [''] : wrapText(line, Math.max(20, opts.cols - 8))));
|
|
50
52
|
return [palette.muted(` ∴ ${t('status.thinkingLine')}`), ...body.map((l) => bar + palette.muted(l)), palette.faint(` ╰ ${summary}`)];
|
|
51
53
|
}
|
|
54
|
+
/** The line that follows /compact: folded it says the summary can be opened, unfolded it shows what the model wrote. */
|
|
55
|
+
export function compactRows(summary, opts) {
|
|
56
|
+
const done = t('compact.done');
|
|
57
|
+
if (!opts.outputExpanded) {
|
|
58
|
+
const room = Math.max(10, opts.cols - 1 - 4);
|
|
59
|
+
const hint = ` (${t('view.expandOutput')})`;
|
|
60
|
+
const text = displayWidth(done + hint) <= room ? palette.text(done) + palette.faint(hint) : palette.text(truncateWidth(done, room));
|
|
61
|
+
return [' ' + palette.ok('✓') + ' ' + text];
|
|
62
|
+
}
|
|
63
|
+
const bar = palette.faint(' │ ');
|
|
64
|
+
const body = summary.trim().split('\n').flatMap((line) => (line.trim() === '' ? [''] : wrapText(line, Math.max(20, opts.cols - 8))));
|
|
65
|
+
const head = ' ' + palette.ok('✓') + ' ' + palette.text(truncateWidth(done, Math.max(10, opts.cols - 5)));
|
|
66
|
+
return [head, palette.muted(` ∴ ${truncateWidth(t('compact.summary'), Math.max(10, opts.cols - 6))}`), ...body.map((l) => bar + palette.muted(l)), palette.faint(' ╰')];
|
|
67
|
+
}
|
|
52
68
|
/** One item as terminal rows (without the blank row that separates it from its neighbour). */
|
|
53
69
|
export function renderItem(item, opts) {
|
|
54
70
|
switch (item.kind) {
|
|
@@ -67,6 +83,8 @@ export function renderItem(item, opts) {
|
|
|
67
83
|
rows.push(...toolResultRows(item.name, item.result, { cols: opts.cols, expanded: opts.outputExpanded, diffColors: opts.diffColors }));
|
|
68
84
|
return rows;
|
|
69
85
|
}
|
|
86
|
+
case 'compact':
|
|
87
|
+
return compactRows(item.summary, opts);
|
|
70
88
|
default:
|
|
71
89
|
return item.rows;
|
|
72
90
|
}
|
|
@@ -98,7 +116,9 @@ export function messagesToItems(messages) {
|
|
|
98
116
|
results.set(m.tool_call_id, m);
|
|
99
117
|
const items = [];
|
|
100
118
|
for (const m of messages) {
|
|
101
|
-
if (m.role === 'user')
|
|
119
|
+
if (m.role === 'user' && m.content.startsWith(COMPACT_MARK))
|
|
120
|
+
items.push({ kind: 'compact', summary: m.content.slice(m.content.indexOf('\n') + 1) });
|
|
121
|
+
else if (m.role === 'user')
|
|
102
122
|
items.push({ kind: 'user', text: m.content.split('\n\n--- Attached Files ---')[0] });
|
|
103
123
|
else if (m.role === 'assistant') {
|
|
104
124
|
if (m.reasoning && m.reasoning.text.trim())
|
package/dist/cli/ui.js
CHANGED
|
@@ -74,12 +74,13 @@ export function formatDuration(ms) {
|
|
|
74
74
|
}
|
|
75
75
|
/** `/home/me/projects/app` → `~/projects/app`, shortened from the left to fit `max` cells. */
|
|
76
76
|
export function shortenPath(p, max, home = os.homedir()) {
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
const slashed = (v) => v.split(path.sep).join('/').replace(/\\/g, '/');
|
|
78
|
+
let s = slashed(p);
|
|
79
|
+
const h = slashed(home).replace(/\/+$/, '');
|
|
80
|
+
if (s === h)
|
|
79
81
|
s = '~';
|
|
80
|
-
else if (s.startsWith(
|
|
81
|
-
s = '~' + s.slice(
|
|
82
|
-
s = s.split(path.sep).join('/');
|
|
82
|
+
else if (h && s.startsWith(h + '/'))
|
|
83
|
+
s = '~' + s.slice(h.length);
|
|
83
84
|
if (displayWidth(s) <= max)
|
|
84
85
|
return s;
|
|
85
86
|
const parts = s.split('/');
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { DEVX_LOGO } from './logo.js';
|
|
2
|
+
import { palette } from './ui.js';
|
|
3
|
+
import { displayWidth, padEndWidth, truncateWidth, wrapWords } from './width.js';
|
|
4
|
+
import { t } from '../core/i18n.js';
|
|
5
|
+
const LOGO = DEVX_LOGO;
|
|
6
|
+
/** The steps of the first run, in the order they are asked. */
|
|
7
|
+
export const SETUP_STEPS = ['welcome.step.language', 'welcome.step.theme', 'welcome.step.provider', 'welcome.step.key', 'welcome.step.model'];
|
|
8
|
+
/** The card shown when devx is opened for the first time. `done` steps are ticked, the next one is highlighted. */
|
|
9
|
+
export function renderWelcome(version, cols, done = 0) {
|
|
10
|
+
const steps = SETUP_STEPS.map((key, i) => {
|
|
11
|
+
const label = t(key);
|
|
12
|
+
if (i < done)
|
|
13
|
+
return palette.ok('✓') + ' ' + palette.muted(label);
|
|
14
|
+
if (i === done)
|
|
15
|
+
return palette.accent(String(i + 1)) + ' ' + palette.bold(palette.text(label));
|
|
16
|
+
return palette.faint(String(i + 1)) + ' ' + palette.faint(label);
|
|
17
|
+
});
|
|
18
|
+
if (cols < 60) {
|
|
19
|
+
const width = Math.max(20, cols - 2);
|
|
20
|
+
const lines = ['', ...LOGO.map((l) => ' ' + palette.bold(palette.accent(l))), ' ' + palette.faint(`v${version}`), ''];
|
|
21
|
+
for (const line of wrapWords(t('welcome.tagline'), width))
|
|
22
|
+
lines.push(' ' + palette.text(line));
|
|
23
|
+
lines.push('');
|
|
24
|
+
for (const s of steps)
|
|
25
|
+
lines.push(' ' + s);
|
|
26
|
+
lines.push('');
|
|
27
|
+
return lines;
|
|
28
|
+
}
|
|
29
|
+
const W = Math.min(cols - 1, 76);
|
|
30
|
+
const iw = W - 4;
|
|
31
|
+
const rule = palette.rule;
|
|
32
|
+
const box = (content) => rule('│') + ' ' + padEndWidth(content, iw) + ' ' + rule('│');
|
|
33
|
+
const head = ' ' + palette.bold(palette.accent('devx')) + ' ';
|
|
34
|
+
const ver = ' ' + palette.faint(`v${version}`) + ' ';
|
|
35
|
+
const lines = [rule('╭─') + head + rule('─'.repeat(Math.max(0, W - 4 - displayWidth(head) - displayWidth(ver)))) + ver + rule('─╮'), box('')];
|
|
36
|
+
for (const l of LOGO)
|
|
37
|
+
lines.push(box(' ' + palette.bold(palette.accent(l))));
|
|
38
|
+
lines.push(box(''));
|
|
39
|
+
for (const line of wrapWords(t('welcome.tagline'), iw - 4))
|
|
40
|
+
lines.push(box(' ' + palette.bold(palette.text(line))));
|
|
41
|
+
for (const line of wrapWords(t('welcome.intro'), iw - 4))
|
|
42
|
+
lines.push(box(' ' + palette.muted(line)));
|
|
43
|
+
lines.push(box(''));
|
|
44
|
+
const row = (sep) => ' ' + steps.join(palette.faint(sep));
|
|
45
|
+
const sep = [row(' · '), row(' · ')].find((r) => displayWidth(r) <= iw);
|
|
46
|
+
if (sep)
|
|
47
|
+
lines.push(box(sep));
|
|
48
|
+
else
|
|
49
|
+
for (const step of steps)
|
|
50
|
+
lines.push(box(' ' + step));
|
|
51
|
+
lines.push(box(''));
|
|
52
|
+
for (const line of wrapWords(t('welcome.keyNote'), iw - 4))
|
|
53
|
+
lines.push(box(' ' + palette.faint(truncateWidth(line, iw - 4))));
|
|
54
|
+
lines.push(rule('╰' + '─'.repeat(W - 2) + '╯'));
|
|
55
|
+
return lines;
|
|
56
|
+
}
|
package/dist/core/i18n.js
CHANGED
|
@@ -15,8 +15,8 @@ export const LANGUAGES = [
|
|
|
15
15
|
{ id: 'es', name: 'Español' },
|
|
16
16
|
{ id: 'fr', name: 'Français' },
|
|
17
17
|
{ id: 'pt', name: 'Português' },
|
|
18
|
-
{ id: 'zh', name: '
|
|
19
|
-
{ id: 'ja', name: '
|
|
18
|
+
{ id: 'zh', name: 'Chinese' },
|
|
19
|
+
{ id: 'ja', name: 'Japanese' },
|
|
20
20
|
];
|
|
21
21
|
export const LANGUAGE_IDS = LANGUAGES.map((l) => l.id);
|
|
22
22
|
export const DEFAULT_LANGUAGE = 'en';
|
package/dist/core/locales/de.js
CHANGED
|
@@ -207,4 +207,59 @@ export const de = {
|
|
|
207
207
|
'rewind.filesNo': 'Nein, nur das Gespräch',
|
|
208
208
|
'rewind.done': 'Zurück bei deiner Nachricht. Was danach kam, ist weg, auch für das Modell. Ändere die Nachricht und sende sie.',
|
|
209
209
|
'rewind.doneImages': 'Zurück bei deiner Nachricht (ihre Bilder blieben nicht erhalten, hänge sie erneut an). Was danach kam, ist weg, auch für das Modell.',
|
|
210
|
+
// ── first run and the prompts around it
|
|
211
|
+
'welcome.tagline': 'Ein KI-Coding-Agent für das Terminal',
|
|
212
|
+
'welcome.intro': 'Richten wir alles ein. Das dauert etwa eine Minute.',
|
|
213
|
+
'welcome.step.language': 'Sprache',
|
|
214
|
+
'welcome.step.provider': 'Anbieter',
|
|
215
|
+
'welcome.step.key': 'API-Schlüssel',
|
|
216
|
+
'welcome.step.model': 'Modell',
|
|
217
|
+
'welcome.keyNote': 'Dein Schlüssel bleibt auf diesem Computer, in ~/.devxrc.json.',
|
|
218
|
+
'onboard.language.title': 'sprache',
|
|
219
|
+
'onboard.language.note': 'Du kannst sie später in /settings ändern.',
|
|
220
|
+
'onboard.provider.title': 'anbieter',
|
|
221
|
+
'onboard.provider.placeholder': 'tippen, um einen Anbieter zu finden',
|
|
222
|
+
'onboard.provider.note': 'Der Dienst, der dir die Modelle liefert. Nicht in der Liste? Wähle eigene Adresse.',
|
|
223
|
+
'onboard.custom': 'Eigene Adresse',
|
|
224
|
+
'onboard.customDetail': 'Jede OpenAI-kompatible Adresse',
|
|
225
|
+
'onboard.baseUrl.title': 'adresse',
|
|
226
|
+
'onboard.baseUrl.label': 'Basis-URL der API',
|
|
227
|
+
'onboard.baseUrl.placeholder': 'https://api.example.com/v1',
|
|
228
|
+
'onboard.key.title': 'api-schlüssel',
|
|
229
|
+
'onboard.key.label': 'Füge deinen API-Schlüssel für {provider} ein',
|
|
230
|
+
'onboard.key.note': 'Die Eingabe bleibt verborgen. Esc geht zurück.',
|
|
231
|
+
'onboard.key.useSaved': 'Gespeicherten Schlüssel verwenden',
|
|
232
|
+
'onboard.key.enterNew': 'Neuen Schlüssel eingeben',
|
|
233
|
+
'onboard.key.savedTitle': 'für {provider} ist ein Schlüssel gespeichert',
|
|
234
|
+
'onboard.model.title': 'modell',
|
|
235
|
+
'onboard.model.placeholder': 'tippen, um ein Modell zu finden',
|
|
236
|
+
'onboard.model.custom': 'Modellnamen eingeben',
|
|
237
|
+
'onboard.model.customDetail': 'Jede Modell-ID',
|
|
238
|
+
'onboard.model.label': 'Name des Modells (zum Beispiel gpt-4o)',
|
|
239
|
+
'onboard.model.fetching': 'Modellliste wird geladen...',
|
|
240
|
+
'onboard.model.manual': 'Die Modellliste konnte nicht geladen werden, gib den Modellnamen ein.',
|
|
241
|
+
'onboard.model.context': '{n} Kontext',
|
|
242
|
+
'onboard.model.anthropic': 'Anthropic-Format',
|
|
243
|
+
'onboard.back': 'Zurück',
|
|
244
|
+
'onboard.back.detail': 'Aktuelle Einstellung behalten',
|
|
245
|
+
'onboard.done': 'Fertig. Deine Auswahl ist in ~/.devxrc.json gespeichert.',
|
|
246
|
+
'finder.placeholder': 'tippen zum Filtern',
|
|
247
|
+
'finder.empty': 'Keine Treffer',
|
|
248
|
+
'finder.hint.filter': 'filtern',
|
|
249
|
+
'picker.hint.move': 'bewegen',
|
|
250
|
+
'picker.hint.select': 'wählen',
|
|
251
|
+
'picker.hint.cancel': 'abbrechen',
|
|
252
|
+
'picker.hint.confirm': 'bestätigen',
|
|
253
|
+
'welcome.step.theme': 'Design',
|
|
254
|
+
'onboard.theme.title': 'design',
|
|
255
|
+
'onboard.theme.note': 'Die Farben der Oberfläche. Mit /theme jederzeit änderbar.',
|
|
256
|
+
'resume.title': 'fortsetzen',
|
|
257
|
+
'resume.placeholder': 'tippen, um Sitzungen zu filtern',
|
|
258
|
+
'resume.msgs': '{n} Nachr.',
|
|
259
|
+
'sessions.deleteTitle': 'Sitzungen löschen',
|
|
260
|
+
'sessions.deleteAll': 'Alle {n} Sitzungen löschen',
|
|
261
|
+
'commands.title': 'Befehle',
|
|
262
|
+
'commands.placeholder': 'tippen, um einen Befehl zu finden',
|
|
263
|
+
'compact.done': 'Kontext verdichtet, Zusammenfassung behalten',
|
|
264
|
+
'compact.summary': 'was das Modell geschrieben hat',
|
|
210
265
|
};
|
package/dist/core/locales/en.js
CHANGED
|
@@ -218,4 +218,59 @@ export const en = {
|
|
|
218
218
|
'rewind.filesNo': 'No, only the conversation',
|
|
219
219
|
'rewind.done': 'Back at your message. What came after it is gone, for the model too. Edit the message and send it.',
|
|
220
220
|
'rewind.doneImages': 'Back at your message (its images were not kept, attach them again). What came after it is gone, for the model too.',
|
|
221
|
+
// ── first run and the prompts around it
|
|
222
|
+
'welcome.tagline': 'A terminal AI coding agent',
|
|
223
|
+
'welcome.intro': 'Let us set things up. It takes about a minute.',
|
|
224
|
+
'welcome.step.language': 'Language',
|
|
225
|
+
'welcome.step.provider': 'Provider',
|
|
226
|
+
'welcome.step.key': 'API key',
|
|
227
|
+
'welcome.step.model': 'Model',
|
|
228
|
+
'welcome.keyNote': 'Your key stays on this computer, in ~/.devxrc.json.',
|
|
229
|
+
'onboard.language.title': 'language',
|
|
230
|
+
'onboard.language.note': 'You can change it later in /settings.',
|
|
231
|
+
'onboard.provider.title': 'provider',
|
|
232
|
+
'onboard.provider.placeholder': 'type to find a provider',
|
|
233
|
+
'onboard.provider.note': 'The service that gives you the models. Not in the list? Choose Custom endpoint.',
|
|
234
|
+
'onboard.custom': 'Custom endpoint',
|
|
235
|
+
'onboard.customDetail': 'Any OpenAI-compatible address',
|
|
236
|
+
'onboard.baseUrl.title': 'address',
|
|
237
|
+
'onboard.baseUrl.label': 'Base URL of the API',
|
|
238
|
+
'onboard.baseUrl.placeholder': 'https://api.example.com/v1',
|
|
239
|
+
'onboard.key.title': 'api key',
|
|
240
|
+
'onboard.key.label': 'Paste your API key for {provider}',
|
|
241
|
+
'onboard.key.note': 'What you type is hidden. Esc goes back.',
|
|
242
|
+
'onboard.key.useSaved': 'Use the saved key',
|
|
243
|
+
'onboard.key.enterNew': 'Enter a new key',
|
|
244
|
+
'onboard.key.savedTitle': 'a key is saved for {provider}',
|
|
245
|
+
'onboard.model.title': 'model',
|
|
246
|
+
'onboard.model.placeholder': 'type to find a model',
|
|
247
|
+
'onboard.model.custom': 'Type a model name',
|
|
248
|
+
'onboard.model.customDetail': 'Any model id',
|
|
249
|
+
'onboard.model.label': 'Name of the model (for example gpt-4o)',
|
|
250
|
+
'onboard.model.fetching': 'Fetching the list of models...',
|
|
251
|
+
'onboard.model.manual': 'The list of models could not be fetched, so type the name of the model.',
|
|
252
|
+
'onboard.model.context': '{n} context',
|
|
253
|
+
'onboard.model.anthropic': 'Anthropic format',
|
|
254
|
+
'onboard.back': 'Back',
|
|
255
|
+
'onboard.back.detail': 'Keep what is set now',
|
|
256
|
+
'onboard.done': 'All set. Your choices are saved in ~/.devxrc.json.',
|
|
257
|
+
'finder.placeholder': 'type to filter',
|
|
258
|
+
'finder.empty': 'Nothing matches',
|
|
259
|
+
'finder.hint.filter': 'filter',
|
|
260
|
+
'picker.hint.move': 'move',
|
|
261
|
+
'picker.hint.select': 'select',
|
|
262
|
+
'picker.hint.cancel': 'cancel',
|
|
263
|
+
'picker.hint.confirm': 'confirm',
|
|
264
|
+
'welcome.step.theme': 'Theme',
|
|
265
|
+
'onboard.theme.title': 'theme',
|
|
266
|
+
'onboard.theme.note': 'The colours of the interface. Change them any time with /theme.',
|
|
267
|
+
'resume.title': 'resume',
|
|
268
|
+
'resume.placeholder': 'type to filter sessions',
|
|
269
|
+
'resume.msgs': '{n} msgs',
|
|
270
|
+
'sessions.deleteTitle': 'delete sessions',
|
|
271
|
+
'sessions.deleteAll': 'Delete all {n} sessions',
|
|
272
|
+
'commands.title': 'commands',
|
|
273
|
+
'commands.placeholder': 'type to find a command',
|
|
274
|
+
'compact.done': 'Context compacted, summary kept',
|
|
275
|
+
'compact.summary': 'what the model wrote',
|
|
221
276
|
};
|
package/dist/core/locales/es.js
CHANGED
|
@@ -207,4 +207,59 @@ export const es = {
|
|
|
207
207
|
'rewind.filesNo': 'No, solo la conversación',
|
|
208
208
|
'rewind.done': 'De vuelta en tu mensaje. Lo que vino después desapareció, también para el modelo. Edita el mensaje y envíalo.',
|
|
209
209
|
'rewind.doneImages': 'De vuelta en tu mensaje (sus imágenes no se conservaron, adjúntalas de nuevo). Lo que vino después desapareció, también para el modelo.',
|
|
210
|
+
// ── first run and the prompts around it
|
|
211
|
+
'welcome.tagline': 'Un agente de programación con IA para la terminal',
|
|
212
|
+
'welcome.intro': 'Vamos a configurarlo todo. Lleva cerca de un minuto.',
|
|
213
|
+
'welcome.step.language': 'Idioma',
|
|
214
|
+
'welcome.step.provider': 'Proveedor',
|
|
215
|
+
'welcome.step.key': 'Clave de API',
|
|
216
|
+
'welcome.step.model': 'Modelo',
|
|
217
|
+
'welcome.keyNote': 'Tu clave se queda en este equipo, en ~/.devxrc.json.',
|
|
218
|
+
'onboard.language.title': 'idioma',
|
|
219
|
+
'onboard.language.note': 'Puedes cambiarlo más tarde en /settings.',
|
|
220
|
+
'onboard.provider.title': 'proveedor',
|
|
221
|
+
'onboard.provider.placeholder': 'escribe para buscar un proveedor',
|
|
222
|
+
'onboard.provider.note': 'El servicio que te da los modelos. ¿No está en la lista? Elige Dirección propia.',
|
|
223
|
+
'onboard.custom': 'Dirección propia',
|
|
224
|
+
'onboard.customDetail': 'Cualquier dirección compatible con OpenAI',
|
|
225
|
+
'onboard.baseUrl.title': 'dirección',
|
|
226
|
+
'onboard.baseUrl.label': 'URL base de la API',
|
|
227
|
+
'onboard.baseUrl.placeholder': 'https://api.example.com/v1',
|
|
228
|
+
'onboard.key.title': 'clave de api',
|
|
229
|
+
'onboard.key.label': 'Pega tu clave de API para {provider}',
|
|
230
|
+
'onboard.key.note': 'Lo que escribes está oculto. Esc vuelve atrás.',
|
|
231
|
+
'onboard.key.useSaved': 'Usar la clave guardada',
|
|
232
|
+
'onboard.key.enterNew': 'Introducir una clave nueva',
|
|
233
|
+
'onboard.key.savedTitle': 'hay una clave guardada para {provider}',
|
|
234
|
+
'onboard.model.title': 'modelo',
|
|
235
|
+
'onboard.model.placeholder': 'escribe para buscar un modelo',
|
|
236
|
+
'onboard.model.custom': 'Escribir el nombre de un modelo',
|
|
237
|
+
'onboard.model.customDetail': 'Cualquier id de modelo',
|
|
238
|
+
'onboard.model.label': 'Nombre del modelo (por ejemplo gpt-4o)',
|
|
239
|
+
'onboard.model.fetching': 'Obteniendo la lista de modelos...',
|
|
240
|
+
'onboard.model.manual': 'No se pudo obtener la lista de modelos, escribe el nombre del modelo.',
|
|
241
|
+
'onboard.model.context': 'contexto de {n}',
|
|
242
|
+
'onboard.model.anthropic': 'formato Anthropic',
|
|
243
|
+
'onboard.back': 'Atrás',
|
|
244
|
+
'onboard.back.detail': 'Mantener lo actual',
|
|
245
|
+
'onboard.done': 'Listo. Tu elección está guardada en ~/.devxrc.json.',
|
|
246
|
+
'finder.placeholder': 'escribe para filtrar',
|
|
247
|
+
'finder.empty': 'Nada coincide',
|
|
248
|
+
'finder.hint.filter': 'filtrar',
|
|
249
|
+
'picker.hint.move': 'mover',
|
|
250
|
+
'picker.hint.select': 'elegir',
|
|
251
|
+
'picker.hint.cancel': 'cancelar',
|
|
252
|
+
'picker.hint.confirm': 'confirmar',
|
|
253
|
+
'welcome.step.theme': 'Tema',
|
|
254
|
+
'onboard.theme.title': 'tema',
|
|
255
|
+
'onboard.theme.note': 'Los colores de la interfaz. Puedes cambiarlos cuando quieras con /theme.',
|
|
256
|
+
'resume.title': 'reanudar',
|
|
257
|
+
'resume.placeholder': 'escribe para filtrar sesiones',
|
|
258
|
+
'resume.msgs': '{n} msjs',
|
|
259
|
+
'sessions.deleteTitle': 'borrar sesiones',
|
|
260
|
+
'sessions.deleteAll': 'Borrar las {n} sesiones',
|
|
261
|
+
'commands.title': 'comandos',
|
|
262
|
+
'commands.placeholder': 'escribe para buscar un comando',
|
|
263
|
+
'compact.done': 'Contexto compactado, resumen guardado',
|
|
264
|
+
'compact.summary': 'lo que escribió el modelo',
|
|
210
265
|
};
|
package/dist/core/locales/fr.js
CHANGED
|
@@ -207,4 +207,59 @@ export const fr = {
|
|
|
207
207
|
'rewind.filesNo': 'Non, seulement la conversation',
|
|
208
208
|
'rewind.done': 'De retour à votre message. Ce qui a suivi a disparu, pour le modèle aussi. Modifiez le message et envoyez-le.',
|
|
209
209
|
'rewind.doneImages': 'De retour à votre message (ses images n’ont pas été gardées, joignez-les de nouveau). Ce qui a suivi a disparu, pour le modèle aussi.',
|
|
210
|
+
// ── first run and the prompts around it
|
|
211
|
+
'welcome.tagline': 'Un agent de programmation IA pour le terminal',
|
|
212
|
+
'welcome.intro': 'Configurons tout. Cela prend environ une minute.',
|
|
213
|
+
'welcome.step.language': 'Langue',
|
|
214
|
+
'welcome.step.provider': 'Fournisseur',
|
|
215
|
+
'welcome.step.key': 'Clé API',
|
|
216
|
+
'welcome.step.model': 'Modèle',
|
|
217
|
+
'welcome.keyNote': 'Ta clé reste sur cet ordinateur, dans ~/.devxrc.json.',
|
|
218
|
+
'onboard.language.title': 'langue',
|
|
219
|
+
'onboard.language.note': 'Tu pourras la changer plus tard dans /settings.',
|
|
220
|
+
'onboard.provider.title': 'fournisseur',
|
|
221
|
+
'onboard.provider.placeholder': 'tape pour trouver un fournisseur',
|
|
222
|
+
'onboard.provider.note': 'Le service qui te donne les modèles. Pas dans la liste ? Choisis Adresse personnalisée.',
|
|
223
|
+
'onboard.custom': 'Adresse personnalisée',
|
|
224
|
+
'onboard.customDetail': 'Toute adresse compatible OpenAI',
|
|
225
|
+
'onboard.baseUrl.title': 'adresse',
|
|
226
|
+
'onboard.baseUrl.label': 'URL de base de l’API',
|
|
227
|
+
'onboard.baseUrl.placeholder': 'https://api.example.com/v1',
|
|
228
|
+
'onboard.key.title': 'clé api',
|
|
229
|
+
'onboard.key.label': 'Colle ta clé API pour {provider}',
|
|
230
|
+
'onboard.key.note': 'Ce que tu tapes est masqué. Échap revient en arrière.',
|
|
231
|
+
'onboard.key.useSaved': 'Utiliser la clé enregistrée',
|
|
232
|
+
'onboard.key.enterNew': 'Saisir une nouvelle clé',
|
|
233
|
+
'onboard.key.savedTitle': 'une clé est enregistrée pour {provider}',
|
|
234
|
+
'onboard.model.title': 'modèle',
|
|
235
|
+
'onboard.model.placeholder': 'tape pour trouver un modèle',
|
|
236
|
+
'onboard.model.custom': 'Saisir un nom de modèle',
|
|
237
|
+
'onboard.model.customDetail': 'Tout identifiant de modèle',
|
|
238
|
+
'onboard.model.label': 'Nom du modèle (par exemple gpt-4o)',
|
|
239
|
+
'onboard.model.fetching': 'Récupération de la liste des modèles...',
|
|
240
|
+
'onboard.model.manual': 'La liste des modèles n’a pas pu être récupérée, saisis le nom du modèle.',
|
|
241
|
+
'onboard.model.context': 'contexte de {n}',
|
|
242
|
+
'onboard.model.anthropic': 'format Anthropic',
|
|
243
|
+
'onboard.back': 'Retour',
|
|
244
|
+
'onboard.back.detail': 'Garder le réglage actuel',
|
|
245
|
+
'onboard.done': 'Terminé. Tes choix sont enregistrés dans ~/.devxrc.json.',
|
|
246
|
+
'finder.placeholder': 'tape pour filtrer',
|
|
247
|
+
'finder.empty': 'Aucun résultat',
|
|
248
|
+
'finder.hint.filter': 'filtrer',
|
|
249
|
+
'picker.hint.move': 'déplacer',
|
|
250
|
+
'picker.hint.select': 'choisir',
|
|
251
|
+
'picker.hint.cancel': 'annuler',
|
|
252
|
+
'picker.hint.confirm': 'confirmer',
|
|
253
|
+
'welcome.step.theme': 'Thème',
|
|
254
|
+
'onboard.theme.title': 'thème',
|
|
255
|
+
'onboard.theme.note': 'Les couleurs de l’interface. Tu peux les changer à tout moment avec /theme.',
|
|
256
|
+
'resume.title': 'reprendre',
|
|
257
|
+
'resume.placeholder': 'tape pour filtrer les sessions',
|
|
258
|
+
'resume.msgs': '{n} msgs',
|
|
259
|
+
'sessions.deleteTitle': 'supprimer des sessions',
|
|
260
|
+
'sessions.deleteAll': 'Supprimer les {n} sessions',
|
|
261
|
+
'commands.title': 'commandes',
|
|
262
|
+
'commands.placeholder': 'tape pour trouver une commande',
|
|
263
|
+
'compact.done': 'Contexte compacté, résumé conservé',
|
|
264
|
+
'compact.summary': 'ce que le modèle a écrit',
|
|
210
265
|
};
|
package/dist/core/locales/ja.js
CHANGED
|
@@ -207,4 +207,59 @@ export const ja = {
|
|
|
207
207
|
'rewind.filesNo': 'いいえ、会話だけ',
|
|
208
208
|
'rewind.done': 'あなたのメッセージに戻りました。以降の内容はモデルからも消えています。メッセージを編集して送信してください。',
|
|
209
209
|
'rewind.doneImages': 'あなたのメッセージに戻りました(画像は保持されません。再度添付してください)。以降の内容はモデルからも消えています。',
|
|
210
|
+
// ── first run and the prompts around it
|
|
211
|
+
'welcome.tagline': 'ターミナルで使える AI コーディングエージェント',
|
|
212
|
+
'welcome.intro': '設定を済ませましょう。1 分ほどで終わります。',
|
|
213
|
+
'welcome.step.language': '言語',
|
|
214
|
+
'welcome.step.provider': 'プロバイダー',
|
|
215
|
+
'welcome.step.key': 'API キー',
|
|
216
|
+
'welcome.step.model': 'モデル',
|
|
217
|
+
'welcome.keyNote': 'キーはこのコンピューターの ~/.devxrc.json にだけ保存されます。',
|
|
218
|
+
'onboard.language.title': '言語',
|
|
219
|
+
'onboard.language.note': 'あとで /settings から変更できます。',
|
|
220
|
+
'onboard.provider.title': 'プロバイダー',
|
|
221
|
+
'onboard.provider.placeholder': '入力してプロバイダーを探す',
|
|
222
|
+
'onboard.provider.note': 'モデルを提供するサービスです。一覧にない場合は「独自のアドレス」を選んでください。',
|
|
223
|
+
'onboard.custom': '独自のアドレス',
|
|
224
|
+
'onboard.customDetail': 'OpenAI 互換の任意のアドレス',
|
|
225
|
+
'onboard.baseUrl.title': 'アドレス',
|
|
226
|
+
'onboard.baseUrl.label': 'API のベース URL',
|
|
227
|
+
'onboard.baseUrl.placeholder': 'https://api.example.com/v1',
|
|
228
|
+
'onboard.key.title': 'api キー',
|
|
229
|
+
'onboard.key.label': '{provider} の API キーを貼り付けてください',
|
|
230
|
+
'onboard.key.note': '入力内容は表示されません。Esc で戻ります。',
|
|
231
|
+
'onboard.key.useSaved': '保存済みのキーを使う',
|
|
232
|
+
'onboard.key.enterNew': '新しいキーを入力',
|
|
233
|
+
'onboard.key.savedTitle': '{provider} のキーは保存済みです',
|
|
234
|
+
'onboard.model.title': 'モデル',
|
|
235
|
+
'onboard.model.placeholder': '入力してモデルを探す',
|
|
236
|
+
'onboard.model.custom': 'モデル名を入力',
|
|
237
|
+
'onboard.model.customDetail': '任意のモデル ID',
|
|
238
|
+
'onboard.model.label': 'モデル名(例: gpt-4o)',
|
|
239
|
+
'onboard.model.fetching': 'モデル一覧を取得しています...',
|
|
240
|
+
'onboard.model.manual': 'モデル一覧を取得できませんでした。モデル名を入力してください。',
|
|
241
|
+
'onboard.model.context': '{n} コンテキスト',
|
|
242
|
+
'onboard.model.anthropic': 'Anthropic 形式',
|
|
243
|
+
'onboard.back': '戻る',
|
|
244
|
+
'onboard.back.detail': '現在の設定を維持',
|
|
245
|
+
'onboard.done': '完了です。選択内容は ~/.devxrc.json に保存されました。',
|
|
246
|
+
'finder.placeholder': '入力して絞り込み',
|
|
247
|
+
'finder.empty': '一致なし',
|
|
248
|
+
'finder.hint.filter': '絞り込み',
|
|
249
|
+
'picker.hint.move': '移動',
|
|
250
|
+
'picker.hint.select': '選択',
|
|
251
|
+
'picker.hint.cancel': 'キャンセル',
|
|
252
|
+
'picker.hint.confirm': '確認',
|
|
253
|
+
'welcome.step.theme': 'テーマ',
|
|
254
|
+
'onboard.theme.title': 'テーマ',
|
|
255
|
+
'onboard.theme.note': 'インターフェースの配色です。/theme でいつでも変更できます。',
|
|
256
|
+
'resume.title': '再開',
|
|
257
|
+
'resume.placeholder': '入力してセッションを絞り込み',
|
|
258
|
+
'resume.msgs': '{n} 件',
|
|
259
|
+
'sessions.deleteTitle': 'セッションの削除',
|
|
260
|
+
'sessions.deleteAll': '{n} 件すべてのセッションを削除',
|
|
261
|
+
'commands.title': 'コマンド',
|
|
262
|
+
'commands.placeholder': '入力してコマンドを探す',
|
|
263
|
+
'compact.done': 'コンテキスト圧縮済み、要約を保持',
|
|
264
|
+
'compact.summary': 'モデルが書いた内容',
|
|
210
265
|
};
|
package/dist/core/locales/pt.js
CHANGED
|
@@ -207,4 +207,59 @@ export const pt = {
|
|
|
207
207
|
'rewind.filesNo': 'Não, só a conversa',
|
|
208
208
|
'rewind.done': 'De volta à sua mensagem. O que veio depois sumiu, para o modelo também. Edite a mensagem e envie.',
|
|
209
209
|
'rewind.doneImages': 'De volta à sua mensagem (as imagens dela não foram mantidas, anexe de novo). O que veio depois sumiu, para o modelo também.',
|
|
210
|
+
// ── first run and the prompts around it
|
|
211
|
+
'welcome.tagline': 'Um agente de programação com IA para o terminal',
|
|
212
|
+
'welcome.intro': 'Vamos configurar tudo. Leva cerca de um minuto.',
|
|
213
|
+
'welcome.step.language': 'Idioma',
|
|
214
|
+
'welcome.step.provider': 'Provedor',
|
|
215
|
+
'welcome.step.key': 'Chave de API',
|
|
216
|
+
'welcome.step.model': 'Modelo',
|
|
217
|
+
'welcome.keyNote': 'Sua chave fica neste computador, em ~/.devxrc.json.',
|
|
218
|
+
'onboard.language.title': 'idioma',
|
|
219
|
+
'onboard.language.note': 'Você pode mudar depois em /settings.',
|
|
220
|
+
'onboard.provider.title': 'provedor',
|
|
221
|
+
'onboard.provider.placeholder': 'digite para encontrar um provedor',
|
|
222
|
+
'onboard.provider.note': 'O serviço que fornece os modelos. Não está na lista? Escolha Endereço próprio.',
|
|
223
|
+
'onboard.custom': 'Endereço próprio',
|
|
224
|
+
'onboard.customDetail': 'Qualquer endereço compatível com OpenAI',
|
|
225
|
+
'onboard.baseUrl.title': 'endereço',
|
|
226
|
+
'onboard.baseUrl.label': 'URL base da API',
|
|
227
|
+
'onboard.baseUrl.placeholder': 'https://api.example.com/v1',
|
|
228
|
+
'onboard.key.title': 'chave de api',
|
|
229
|
+
'onboard.key.label': 'Cole sua chave de API para {provider}',
|
|
230
|
+
'onboard.key.note': 'O que você digita fica oculto. Esc volta.',
|
|
231
|
+
'onboard.key.useSaved': 'Usar a chave salva',
|
|
232
|
+
'onboard.key.enterNew': 'Inserir uma nova chave',
|
|
233
|
+
'onboard.key.savedTitle': 'há uma chave salva para {provider}',
|
|
234
|
+
'onboard.model.title': 'modelo',
|
|
235
|
+
'onboard.model.placeholder': 'digite para encontrar um modelo',
|
|
236
|
+
'onboard.model.custom': 'Digitar o nome de um modelo',
|
|
237
|
+
'onboard.model.customDetail': 'Qualquer id de modelo',
|
|
238
|
+
'onboard.model.label': 'Nome do modelo (por exemplo gpt-4o)',
|
|
239
|
+
'onboard.model.fetching': 'Buscando a lista de modelos...',
|
|
240
|
+
'onboard.model.manual': 'Não foi possível obter a lista de modelos, digite o nome do modelo.',
|
|
241
|
+
'onboard.model.context': 'contexto de {n}',
|
|
242
|
+
'onboard.model.anthropic': 'formato Anthropic',
|
|
243
|
+
'onboard.back': 'Voltar',
|
|
244
|
+
'onboard.back.detail': 'Manter o que está definido',
|
|
245
|
+
'onboard.done': 'Pronto. Suas escolhas estão salvas em ~/.devxrc.json.',
|
|
246
|
+
'finder.placeholder': 'digite para filtrar',
|
|
247
|
+
'finder.empty': 'Nada encontrado',
|
|
248
|
+
'finder.hint.filter': 'filtrar',
|
|
249
|
+
'picker.hint.move': 'mover',
|
|
250
|
+
'picker.hint.select': 'escolher',
|
|
251
|
+
'picker.hint.cancel': 'cancelar',
|
|
252
|
+
'picker.hint.confirm': 'confirmar',
|
|
253
|
+
'welcome.step.theme': 'Tema',
|
|
254
|
+
'onboard.theme.title': 'tema',
|
|
255
|
+
'onboard.theme.note': 'As cores da interface. Você pode mudá-las a qualquer momento com /theme.',
|
|
256
|
+
'resume.title': 'retomar',
|
|
257
|
+
'resume.placeholder': 'digite para filtrar sessões',
|
|
258
|
+
'resume.msgs': '{n} msgs',
|
|
259
|
+
'sessions.deleteTitle': 'excluir sessões',
|
|
260
|
+
'sessions.deleteAll': 'Excluir todas as {n} sessões',
|
|
261
|
+
'commands.title': 'comandos',
|
|
262
|
+
'commands.placeholder': 'digite para encontrar um comando',
|
|
263
|
+
'compact.done': 'Contexto compactado, resumo mantido',
|
|
264
|
+
'compact.summary': 'o que o modelo escreveu',
|
|
210
265
|
};
|