@tensor.chat/companion 0.4.3 → 0.4.4
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/README.md +3 -1
- package/bin/tensor-companion.js +1 -1
- package/package.json +1 -1
- package/src/setup/i18n.js +10 -131
- package/src/setup/lang/de.js +68 -0
- package/src/setup/lang/en.js +68 -0
- package/src/setup/lang/es.js +68 -0
- package/src/setup/lang/fr.js +69 -0
- package/src/setup/lang/hi.js +68 -0
- package/src/setup/lang/pt.js +68 -0
- package/src/setup/lang/ru.js +69 -0
- package/src/setup/lang/zh.js +68 -0
- package/src/setup/layout.js +123 -5
- package/src/setup/term.js +4 -0
- package/src/setup/wizard.js +58 -33
package/README.md
CHANGED
|
@@ -17,7 +17,9 @@ The command prints a code such as `AB3D-7KQ2`. In tensor.chat open
|
|
|
17
17
|
setup asks in the terminal what the AI may use on this computer: folders from a list of
|
|
18
18
|
suggestions or a folder browser, everything (not recommended), or nothing yet, and
|
|
19
19
|
whether it may run commands. Run it again any time with
|
|
20
|
-
`npx @tensor.chat/companion setup`.
|
|
20
|
+
`npx @tensor.chat/companion setup`. It speaks the computer's language (`LANG`) if that is
|
|
21
|
+
one of de, en, es, fr, hi, pt, ru or zh, English otherwise; `--lang` picks another.
|
|
22
|
+
Then keep the daemon running:
|
|
21
23
|
|
|
22
24
|
```
|
|
23
25
|
npx @tensor.chat/companion run
|
package/bin/tensor-companion.js
CHANGED
|
@@ -165,7 +165,7 @@ function help() {
|
|
|
165
165
|
out(`tensor-companion ${VERSION}
|
|
166
166
|
|
|
167
167
|
tensor-companion pair [--server URL] [--name NAME] pair this machine with your account
|
|
168
|
-
tensor-companion setup [--lang
|
|
168
|
+
tensor-companion setup [--lang LANG] choose what the AI may use on this computer
|
|
169
169
|
tensor-companion run stay connected and run tools for the AI
|
|
170
170
|
tensor-companion status show the current pairing
|
|
171
171
|
tensor-companion shell <path|auto> choose the shell Bash commands run in
|
package/package.json
CHANGED
package/src/setup/i18n.js
CHANGED
|
@@ -1,138 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
// The setup's words, in the language the computer is set to (LC_ALL, LC_MESSAGES,
|
|
3
|
-
// LANG - an SSH session usually brings the caller's), English otherwise.
|
|
3
|
+
// LANG - an SSH session usually brings the caller's), English otherwise. The site
|
|
4
|
+
// speaks the same eight.
|
|
4
5
|
|
|
5
6
|
const STRINGS = {
|
|
6
|
-
en:
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
'start.now': 'Approved now:',
|
|
15
|
-
'start.later': 'Change it any time:',
|
|
16
|
-
'places.title': 'Which folders may the AI use?',
|
|
17
|
-
'places.loading': 'Looking for folders…',
|
|
18
|
-
'places.none': 'No suggestions on this computer.',
|
|
19
|
-
'places.browse': 'Browse all folders…', 'places.type': 'Type a path…', 'places.continue': 'Continue',
|
|
20
|
-
selected: '{n} selected',
|
|
21
|
-
'note.git': '{n} Git projects', 'note.git1': '1 Git project', 'note.project': 'Git project',
|
|
22
|
-
'note.web': 'websites', 'note.srv': 'server data', 'note.opt': 'installed programs',
|
|
23
|
-
'note.etc': 'system settings', 'note.log': 'logs', 'note.home': 'your whole home folder',
|
|
24
|
-
'note.readOnly': 'read-only for you', 'note.added': 'added by you', 'note.earlier': 'approved earlier',
|
|
25
|
-
'note.inside': 'inside {path}',
|
|
26
|
-
'help.home': 'Everything in {home}, also hidden settings and keys such as ~/.ssh.',
|
|
27
|
-
'help.etc': 'Settings of the whole system. A wrong change there can stop the server.',
|
|
28
|
-
'help.log': 'Log files of the system and its services. Good for finding errors.',
|
|
29
|
-
'help.web': 'Files of the websites this server delivers.',
|
|
30
|
-
'help.srv': 'Data of the services on this server.',
|
|
31
|
-
'help.opt': 'Programs installed outside the package manager.',
|
|
32
|
-
'help.code': 'Your code projects.',
|
|
33
|
-
'help.readOnly': 'You can read here but not write. The AI can do the same, no more.',
|
|
34
|
-
'help.browse': 'Pick any folder on this computer, like in a file manager.',
|
|
35
|
-
'help.type': 'Enter a full path. Tab completes it.',
|
|
36
|
-
'help.continue': 'Next: commands.',
|
|
37
|
-
'browse.title': 'Browse', 'browse.thisPc': 'This PC',
|
|
38
|
-
'browse.loading': 'loading…', 'browse.empty': 'no folders', 'browse.noAccess': 'no access', 'browse.link': 'link',
|
|
39
|
-
'browse.blocked': '{path} is inside {parent}, which is already selected.',
|
|
40
|
-
'browse.hidden': 'Hidden folders are shown.', 'browse.hiddenOff': 'Hidden folders are hidden.',
|
|
41
|
-
'type.title': 'Type a folder path', 'type.label': 'Path',
|
|
42
|
-
'type.notFound': 'There is no folder {path}.',
|
|
43
|
-
'everything.title': 'Share everything?',
|
|
44
|
-
'everything.body': 'The AI can read, change and delete every file that {user} can reach on this computer.',
|
|
45
|
-
'everything.root': 'You are root: that is every file on the system, the system itself included.',
|
|
46
|
-
'everything.free': 'It lets the AI work freely on this server. Not recommended.',
|
|
47
|
-
'everything.no': 'No, go back', 'everything.yes': 'Yes, share everything',
|
|
48
|
-
'everything.summary': 'Everything on this computer',
|
|
49
|
-
'shell.title': 'May the AI run commands here?',
|
|
50
|
-
'shell.body': 'Commands run as {user}, with full internet access. They are not limited to the shared folders.',
|
|
51
|
-
'shell.keep': 'Keep as it is', 'shell.keepNote': 'until {date}',
|
|
52
|
-
'shell.no': 'Not now', 'shell.noNote': 'a chat asks first when it needs them',
|
|
53
|
-
'shell.off': 'Turn off', 'shell.offNote': 'a chat asks first when it needs them',
|
|
54
|
-
'shell.d7': 'Yes, for 7 days', 'shell.d30': 'Yes, for 30 days', 'shell.d365': 'Yes, for a year',
|
|
55
|
-
'review.title': 'Check and save',
|
|
56
|
-
'review.folders': 'Folders', 'review.commands': 'Commands',
|
|
57
|
-
'review.noFolders': 'none — a chat asks when it needs one',
|
|
58
|
-
'review.removed': 'approval removed',
|
|
59
|
-
'review.cmdNo': 'not approved — a chat asks first',
|
|
60
|
-
'review.cmdUntil': 'approved until {date}',
|
|
61
|
-
'review.save': 'Save', 'review.back': 'Back', 'review.quit': 'Quit without saving',
|
|
62
|
-
'review.where': 'Saved only on this computer, in {file}',
|
|
63
|
-
keyNames: { space: 'space', enter: 'enter', esc: 'esc', tab: 'tab', backspace: 'backspace' },
|
|
64
|
-
keys: { move: 'move', select: 'select', toggle: 'select', back: 'back', quit: 'quit', open: 'open', close: 'close', openClose: 'open/close', up: 'folder up', hidden: 'hidden', done: 'done', tab: 'complete', add: 'add' },
|
|
65
|
-
'done.saved': 'Saved on this computer.',
|
|
66
|
-
'done.unchanged': 'Nothing changed.',
|
|
67
|
-
'done.web': 'When a chat on tensor.chat shares one of these folders, this computer confirms it by itself.',
|
|
68
|
-
'done.run': 'Start the companion with:',
|
|
69
|
-
'done.noTty': 'The setup needs an interactive terminal. Without one, use approve-folder and approve-shell.',
|
|
70
|
-
},
|
|
71
|
-
de: {
|
|
72
|
-
setup: 'Einrichtung',
|
|
73
|
-
steps: ['Was', 'Ordner', 'Befehle', 'Speichern'],
|
|
74
|
-
'start.title': 'Was darf die KI auf diesem Computer nutzen?',
|
|
75
|
-
'start.folders': 'Ordner auswählen', 'start.foldersNote': 'empfohlen',
|
|
76
|
-
'start.nothing': 'Noch nichts', 'start.nothingNote': 'ein Chat fragt, wenn er einen Ordner braucht',
|
|
77
|
-
'start.everything': 'Alles', 'start.everythingNote': 'nicht empfohlen',
|
|
78
|
-
'start.help': 'Die KI liest, ändert und löscht Dateien nur dort, wo du es hier erlaubst.',
|
|
79
|
-
'start.now': 'Jetzt freigegeben:',
|
|
80
|
-
'start.later': 'Jederzeit änderbar:',
|
|
81
|
-
'places.title': 'Welche Ordner darf die KI nutzen?',
|
|
82
|
-
'places.loading': 'Suche Ordner…',
|
|
83
|
-
'places.none': 'Keine Vorschläge auf diesem Computer.',
|
|
84
|
-
'places.browse': 'Alle Ordner durchsuchen…', 'places.type': 'Pfad eingeben…', 'places.continue': 'Weiter',
|
|
85
|
-
selected: '{n} ausgewählt',
|
|
86
|
-
'note.git': '{n} Git-Projekte', 'note.git1': '1 Git-Projekt', 'note.project': 'Git-Projekt',
|
|
87
|
-
'note.web': 'Webseiten', 'note.srv': 'Serverdaten', 'note.opt': 'installierte Programme',
|
|
88
|
-
'note.etc': 'Systemeinstellungen', 'note.log': 'Protokolle', 'note.home': 'dein ganzer Home-Ordner',
|
|
89
|
-
'note.readOnly': 'für dich nur lesbar', 'note.added': 'von dir hinzugefügt', 'note.earlier': 'schon freigegeben',
|
|
90
|
-
'note.inside': 'liegt in {path}',
|
|
91
|
-
'help.home': 'Alles in {home}, auch versteckte Einstellungen und Schlüssel wie ~/.ssh.',
|
|
92
|
-
'help.etc': 'Einstellungen des ganzen Systems. Eine falsche Änderung dort kann den Server lahmlegen.',
|
|
93
|
-
'help.log': 'Protokolle des Systems und seiner Dienste. Gut für die Fehlersuche.',
|
|
94
|
-
'help.web': 'Dateien der Webseiten, die dieser Server ausliefert.',
|
|
95
|
-
'help.srv': 'Daten der Dienste auf diesem Server.',
|
|
96
|
-
'help.opt': 'Programme, die neben der Paketverwaltung installiert sind.',
|
|
97
|
-
'help.code': 'Deine Code-Projekte.',
|
|
98
|
-
'help.readOnly': 'Du kannst hier lesen, aber nicht schreiben. Die KI kann dasselbe, nicht mehr.',
|
|
99
|
-
'help.browse': 'Wähle einen beliebigen Ordner auf diesem Computer, wie in einem Dateimanager.',
|
|
100
|
-
'help.type': 'Gib einen vollständigen Pfad ein. Tab ergänzt ihn.',
|
|
101
|
-
'help.continue': 'Weiter zu den Befehlen.',
|
|
102
|
-
'browse.title': 'Durchsuchen', 'browse.thisPc': 'Dieser PC',
|
|
103
|
-
'browse.loading': 'lädt…', 'browse.empty': 'keine Ordner', 'browse.noAccess': 'kein Zugriff', 'browse.link': 'Verknüpfung',
|
|
104
|
-
'browse.blocked': '{path} liegt in {parent}, und der ist schon ausgewählt.',
|
|
105
|
-
'browse.hidden': 'Versteckte Ordner werden angezeigt.', 'browse.hiddenOff': 'Versteckte Ordner sind ausgeblendet.',
|
|
106
|
-
'type.title': 'Ordnerpfad eingeben', 'type.label': 'Pfad',
|
|
107
|
-
'type.notFound': 'Den Ordner {path} gibt es nicht.',
|
|
108
|
-
'everything.title': 'Alles freigeben?',
|
|
109
|
-
'everything.body': 'Die KI kann jede Datei lesen, ändern und löschen, an die {user} auf diesem Computer herankommt.',
|
|
110
|
-
'everything.root': 'Du bist root: Das ist jede Datei des Systems, das System selbst eingeschlossen.',
|
|
111
|
-
'everything.free': 'So kann die KI frei auf diesem Server arbeiten. Nicht empfohlen.',
|
|
112
|
-
'everything.no': 'Nein, zurück', 'everything.yes': 'Ja, alles freigeben',
|
|
113
|
-
'everything.summary': 'Alles auf diesem Computer',
|
|
114
|
-
'shell.title': 'Darf die KI hier Befehle ausführen?',
|
|
115
|
-
'shell.body': 'Befehle laufen als {user}, mit vollem Internetzugang. Sie sind nicht auf die freigegebenen Ordner beschränkt.',
|
|
116
|
-
'shell.keep': 'So lassen', 'shell.keepNote': 'bis {date}',
|
|
117
|
-
'shell.no': 'Jetzt nicht', 'shell.noNote': 'ein Chat fragt vorher, wenn er sie braucht',
|
|
118
|
-
'shell.off': 'Ausschalten', 'shell.offNote': 'ein Chat fragt vorher, wenn er sie braucht',
|
|
119
|
-
'shell.d7': 'Ja, für 7 Tage', 'shell.d30': 'Ja, für 30 Tage', 'shell.d365': 'Ja, für ein Jahr',
|
|
120
|
-
'review.title': 'Prüfen und speichern',
|
|
121
|
-
'review.folders': 'Ordner', 'review.commands': 'Befehle',
|
|
122
|
-
'review.noFolders': 'keine – ein Chat fragt, wenn er einen braucht',
|
|
123
|
-
'review.removed': 'Freigabe entfernt',
|
|
124
|
-
'review.cmdNo': 'nicht freigegeben – ein Chat fragt vorher',
|
|
125
|
-
'review.cmdUntil': 'freigegeben bis {date}',
|
|
126
|
-
'review.save': 'Speichern', 'review.back': 'Zurück', 'review.quit': 'Beenden ohne zu speichern',
|
|
127
|
-
'review.where': 'Wird nur auf diesem Computer gespeichert, in {file}',
|
|
128
|
-
keyNames: { space: 'Leertaste', enter: 'Enter', esc: 'Esc', tab: 'Tab', backspace: 'Rücktaste' },
|
|
129
|
-
keys: { move: 'wählen', select: 'bestätigen', toggle: 'auswählen', back: 'zurück', quit: 'beenden', open: 'öffnen', close: 'schließen', openClose: 'öffnen/schließen', up: 'Ordner hoch', hidden: 'versteckte', done: 'fertig', tab: 'ergänzen', add: 'hinzufügen' },
|
|
130
|
-
'done.saved': 'Auf diesem Computer gespeichert.',
|
|
131
|
-
'done.unchanged': 'Nichts geändert.',
|
|
132
|
-
'done.web': 'Gibt ein Chat auf tensor.chat einen dieser Ordner frei, bestätigt dieser Computer das selbst.',
|
|
133
|
-
'done.run': 'Den Companion starten mit:',
|
|
134
|
-
'done.noTty': 'Die Einrichtung braucht ein interaktives Terminal. Ohne eines gehen approve-folder und approve-shell.',
|
|
135
|
-
},
|
|
7
|
+
en: require('./lang/en'),
|
|
8
|
+
de: require('./lang/de'),
|
|
9
|
+
es: require('./lang/es'),
|
|
10
|
+
fr: require('./lang/fr'),
|
|
11
|
+
hi: require('./lang/hi'),
|
|
12
|
+
pt: require('./lang/pt'),
|
|
13
|
+
ru: require('./lang/ru'),
|
|
14
|
+
zh: require('./lang/zh'),
|
|
136
15
|
};
|
|
137
16
|
|
|
138
17
|
function pickLanguage(env = process.env, override) {
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// The setup's words in German.
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
setup: 'Einrichtung',
|
|
6
|
+
steps: ['Was', 'Ordner', 'Befehle', 'Speichern'],
|
|
7
|
+
'start.title': 'Was darf die KI auf diesem Computer nutzen?',
|
|
8
|
+
'start.folders': 'Ordner auswählen', 'start.foldersNote': 'empfohlen',
|
|
9
|
+
'start.nothing': 'Noch nichts', 'start.nothingNote': 'ein Chat fragt, wenn er einen Ordner braucht',
|
|
10
|
+
'start.everything': 'Alles', 'start.everythingNote': 'nicht empfohlen',
|
|
11
|
+
'start.help': 'Die KI liest, ändert und löscht Dateien nur dort, wo du es hier erlaubst.',
|
|
12
|
+
'start.now': 'Jetzt freigegeben:',
|
|
13
|
+
'start.later': 'Jederzeit änderbar:',
|
|
14
|
+
'places.title': 'Welche Ordner darf die KI nutzen?',
|
|
15
|
+
'places.loading': 'Suche Ordner…',
|
|
16
|
+
'places.none': 'Keine Vorschläge auf diesem Computer.',
|
|
17
|
+
'places.browse': 'Alle Ordner durchsuchen…', 'places.type': 'Pfad eingeben…', 'places.continue': 'Weiter',
|
|
18
|
+
selected: '{n} ausgewählt',
|
|
19
|
+
'note.git': '{n} Git-Projekte', 'note.git1': '1 Git-Projekt', 'note.project': 'Git-Projekt',
|
|
20
|
+
'note.web': 'Webseiten', 'note.srv': 'Serverdaten', 'note.opt': 'installierte Programme',
|
|
21
|
+
'note.etc': 'Systemeinstellungen', 'note.log': 'Protokolle', 'note.home': 'dein ganzer Home-Ordner',
|
|
22
|
+
'note.readOnly': 'für dich nur lesbar', 'note.added': 'von dir hinzugefügt', 'note.earlier': 'schon freigegeben',
|
|
23
|
+
'note.inside': 'liegt in {path}',
|
|
24
|
+
'help.home': 'Alles in {home}, auch versteckte Einstellungen und Schlüssel wie ~/.ssh.',
|
|
25
|
+
'help.etc': 'Einstellungen des ganzen Systems. Eine falsche Änderung dort kann den Server lahmlegen.',
|
|
26
|
+
'help.log': 'Protokolle des Systems und seiner Dienste. Gut für die Fehlersuche.',
|
|
27
|
+
'help.web': 'Dateien der Webseiten, die dieser Server ausliefert.',
|
|
28
|
+
'help.srv': 'Daten der Dienste auf diesem Server.',
|
|
29
|
+
'help.opt': 'Programme, die neben der Paketverwaltung installiert sind.',
|
|
30
|
+
'help.code': 'Deine Code-Projekte.',
|
|
31
|
+
'help.readOnly': 'Du kannst hier lesen, aber nicht schreiben. Die KI kann dasselbe, nicht mehr.',
|
|
32
|
+
'help.browse': 'Wähle einen beliebigen Ordner auf diesem Computer, wie in einem Dateimanager.',
|
|
33
|
+
'help.type': 'Gib einen vollständigen Pfad ein. Tab ergänzt ihn.',
|
|
34
|
+
'help.continue': 'Weiter zu den Befehlen.',
|
|
35
|
+
'browse.title': 'Durchsuchen', 'browse.thisPc': 'Dieser PC',
|
|
36
|
+
'browse.loading': 'lädt…', 'browse.empty': 'keine Ordner', 'browse.noAccess': 'kein Zugriff', 'browse.link': 'Verknüpfung',
|
|
37
|
+
'browse.blocked': '{path} liegt in {parent}, und der ist schon ausgewählt.',
|
|
38
|
+
'browse.hidden': 'Versteckte Ordner werden angezeigt.', 'browse.hiddenOff': 'Versteckte Ordner sind ausgeblendet.',
|
|
39
|
+
'type.title': 'Ordnerpfad eingeben', 'type.label': 'Pfad',
|
|
40
|
+
'type.notFound': 'Den Ordner {path} gibt es nicht.',
|
|
41
|
+
'everything.title': 'Alles freigeben?',
|
|
42
|
+
'everything.body': 'Die KI kann jede Datei lesen, ändern und löschen, an die {user} auf diesem Computer herankommt.',
|
|
43
|
+
'everything.root': 'Du bist root: Das ist jede Datei des Systems, das System selbst eingeschlossen.',
|
|
44
|
+
'everything.free': 'So kann die KI frei auf diesem Server arbeiten. Nicht empfohlen.',
|
|
45
|
+
'everything.no': 'Nein, zurück', 'everything.yes': 'Ja, alles freigeben',
|
|
46
|
+
'everything.summary': 'Alles auf diesem Computer',
|
|
47
|
+
'shell.title': 'Darf die KI hier Befehle ausführen?',
|
|
48
|
+
'shell.body': 'Befehle laufen als {user}, mit vollem Internetzugang. Sie sind nicht auf die freigegebenen Ordner beschränkt.',
|
|
49
|
+
'shell.keep': 'So lassen', 'shell.keepNote': 'bis {date}',
|
|
50
|
+
'shell.no': 'Jetzt nicht', 'shell.noNote': 'ein Chat fragt vorher, wenn er sie braucht',
|
|
51
|
+
'shell.off': 'Ausschalten', 'shell.offNote': 'ein Chat fragt vorher, wenn er sie braucht',
|
|
52
|
+
'shell.d7': 'Ja, für 7 Tage', 'shell.d30': 'Ja, für 30 Tage', 'shell.d365': 'Ja, für ein Jahr',
|
|
53
|
+
'review.title': 'Prüfen und speichern',
|
|
54
|
+
'review.folders': 'Ordner', 'review.commands': 'Befehle',
|
|
55
|
+
'review.noFolders': 'keine – ein Chat fragt, wenn er einen braucht',
|
|
56
|
+
'review.removed': 'Freigabe entfernt',
|
|
57
|
+
'review.cmdNo': 'nicht freigegeben – ein Chat fragt vorher',
|
|
58
|
+
'review.cmdUntil': 'freigegeben bis {date}',
|
|
59
|
+
'review.save': 'Speichern', 'review.back': 'Zurück', 'review.quit': 'Beenden ohne zu speichern',
|
|
60
|
+
'review.where': 'Wird nur auf diesem Computer gespeichert, in {file}',
|
|
61
|
+
keyNames: { space: 'Leertaste', enter: 'Enter', esc: 'Esc', tab: 'Tab', backspace: 'Rücktaste' },
|
|
62
|
+
keys: { move: 'wählen', select: 'bestätigen', toggle: 'auswählen', back: 'zurück', quit: 'beenden', open: 'öffnen', close: 'schließen', openClose: 'öffnen/schließen', up: 'Ordner hoch', hidden: 'versteckte', done: 'fertig', tab: 'ergänzen', add: 'hinzufügen' },
|
|
63
|
+
'done.saved': 'Auf diesem Computer gespeichert.',
|
|
64
|
+
'done.unchanged': 'Nichts geändert.',
|
|
65
|
+
'done.web': 'Gibt ein Chat auf tensor.chat einen dieser Ordner frei, bestätigt dieser Computer das selbst.',
|
|
66
|
+
'done.run': 'Den Companion starten mit:',
|
|
67
|
+
'done.noTty': 'Die Einrichtung braucht ein interaktives Terminal. Ohne eines gehen approve-folder und approve-shell.',
|
|
68
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// The setup's words in English.
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
setup: 'setup',
|
|
6
|
+
steps: ['What', 'Folders', 'Commands', 'Save'],
|
|
7
|
+
'start.title': 'What may the AI use on this computer?',
|
|
8
|
+
'start.folders': 'Choose folders', 'start.foldersNote': 'recommended',
|
|
9
|
+
'start.nothing': 'Nothing yet', 'start.nothingNote': 'a chat asks when it needs a folder',
|
|
10
|
+
'start.everything': 'Everything', 'start.everythingNote': 'not recommended',
|
|
11
|
+
'start.help': 'The AI reads, changes and deletes files only where you allow it here.',
|
|
12
|
+
'start.now': 'Approved now:',
|
|
13
|
+
'start.later': 'Change it any time:',
|
|
14
|
+
'places.title': 'Which folders may the AI use?',
|
|
15
|
+
'places.loading': 'Looking for folders…',
|
|
16
|
+
'places.none': 'No suggestions on this computer.',
|
|
17
|
+
'places.browse': 'Browse all folders…', 'places.type': 'Type a path…', 'places.continue': 'Continue',
|
|
18
|
+
selected: '{n} selected',
|
|
19
|
+
'note.git': '{n} Git projects', 'note.git1': '1 Git project', 'note.project': 'Git project',
|
|
20
|
+
'note.web': 'websites', 'note.srv': 'server data', 'note.opt': 'installed programs',
|
|
21
|
+
'note.etc': 'system settings', 'note.log': 'logs', 'note.home': 'your whole home folder',
|
|
22
|
+
'note.readOnly': 'read-only for you', 'note.added': 'added by you', 'note.earlier': 'approved earlier',
|
|
23
|
+
'note.inside': 'inside {path}',
|
|
24
|
+
'help.home': 'Everything in {home}, also hidden settings and keys such as ~/.ssh.',
|
|
25
|
+
'help.etc': 'Settings of the whole system. A wrong change there can stop the server.',
|
|
26
|
+
'help.log': 'Log files of the system and its services. Good for finding errors.',
|
|
27
|
+
'help.web': 'Files of the websites this server delivers.',
|
|
28
|
+
'help.srv': 'Data of the services on this server.',
|
|
29
|
+
'help.opt': 'Programs installed outside the package manager.',
|
|
30
|
+
'help.code': 'Your code projects.',
|
|
31
|
+
'help.readOnly': 'You can read here but not write. The AI can do the same, no more.',
|
|
32
|
+
'help.browse': 'Pick any folder on this computer, like in a file manager.',
|
|
33
|
+
'help.type': 'Enter a full path. Tab completes it.',
|
|
34
|
+
'help.continue': 'Next: commands.',
|
|
35
|
+
'browse.title': 'Browse', 'browse.thisPc': 'This PC',
|
|
36
|
+
'browse.loading': 'loading…', 'browse.empty': 'no folders', 'browse.noAccess': 'no access', 'browse.link': 'link',
|
|
37
|
+
'browse.blocked': '{path} is inside {parent}, which is already selected.',
|
|
38
|
+
'browse.hidden': 'Hidden folders are shown.', 'browse.hiddenOff': 'Hidden folders are hidden.',
|
|
39
|
+
'type.title': 'Type a folder path', 'type.label': 'Path',
|
|
40
|
+
'type.notFound': 'There is no folder {path}.',
|
|
41
|
+
'everything.title': 'Share everything?',
|
|
42
|
+
'everything.body': 'The AI can read, change and delete every file that {user} can reach on this computer.',
|
|
43
|
+
'everything.root': 'You are root: that is every file on the system, the system itself included.',
|
|
44
|
+
'everything.free': 'It lets the AI work freely on this server. Not recommended.',
|
|
45
|
+
'everything.no': 'No, go back', 'everything.yes': 'Yes, share everything',
|
|
46
|
+
'everything.summary': 'Everything on this computer',
|
|
47
|
+
'shell.title': 'May the AI run commands here?',
|
|
48
|
+
'shell.body': 'Commands run as {user}, with full internet access. They are not limited to the shared folders.',
|
|
49
|
+
'shell.keep': 'Keep as it is', 'shell.keepNote': 'until {date}',
|
|
50
|
+
'shell.no': 'Not now', 'shell.noNote': 'a chat asks first when it needs them',
|
|
51
|
+
'shell.off': 'Turn off', 'shell.offNote': 'a chat asks first when it needs them',
|
|
52
|
+
'shell.d7': 'Yes, for 7 days', 'shell.d30': 'Yes, for 30 days', 'shell.d365': 'Yes, for a year',
|
|
53
|
+
'review.title': 'Check and save',
|
|
54
|
+
'review.folders': 'Folders', 'review.commands': 'Commands',
|
|
55
|
+
'review.noFolders': 'none — a chat asks when it needs one',
|
|
56
|
+
'review.removed': 'approval removed',
|
|
57
|
+
'review.cmdNo': 'not approved — a chat asks first',
|
|
58
|
+
'review.cmdUntil': 'approved until {date}',
|
|
59
|
+
'review.save': 'Save', 'review.back': 'Back', 'review.quit': 'Quit without saving',
|
|
60
|
+
'review.where': 'Saved only on this computer, in {file}',
|
|
61
|
+
keyNames: { space: 'space', enter: 'enter', esc: 'esc', tab: 'tab', backspace: 'backspace' },
|
|
62
|
+
keys: { move: 'move', select: 'select', toggle: 'select', back: 'back', quit: 'quit', open: 'open', close: 'close', openClose: 'open/close', up: 'folder up', hidden: 'hidden', done: 'done', tab: 'complete', add: 'add' },
|
|
63
|
+
'done.saved': 'Saved on this computer.',
|
|
64
|
+
'done.unchanged': 'Nothing changed.',
|
|
65
|
+
'done.web': 'When a chat on tensor.chat shares one of these folders, this computer confirms it by itself.',
|
|
66
|
+
'done.run': 'Start the companion with:',
|
|
67
|
+
'done.noTty': 'The setup needs an interactive terminal. Without one, use approve-folder and approve-shell.',
|
|
68
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// The setup's words in Spanish.
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
setup: 'configuración',
|
|
6
|
+
steps: ['Qué', 'Carpetas', 'Comandos', 'Guardar'],
|
|
7
|
+
'start.title': '¿Qué puede usar la IA en este ordenador?',
|
|
8
|
+
'start.folders': 'Elegir carpetas', 'start.foldersNote': 'recomendado',
|
|
9
|
+
'start.nothing': 'Nada por ahora', 'start.nothingNote': 'un chat pregunta cuando necesita una carpeta',
|
|
10
|
+
'start.everything': 'Todo', 'start.everythingNote': 'no recomendado',
|
|
11
|
+
'start.help': 'La IA lee, modifica y borra archivos solo donde tú lo permitas aquí.',
|
|
12
|
+
'start.now': 'Aprobado ahora:',
|
|
13
|
+
'start.later': 'Puedes cambiarlo cuando quieras:',
|
|
14
|
+
'places.title': '¿Qué carpetas puede usar la IA?',
|
|
15
|
+
'places.loading': 'Buscando carpetas…',
|
|
16
|
+
'places.none': 'No hay sugerencias en este ordenador.',
|
|
17
|
+
'places.browse': 'Explorar todas las carpetas…', 'places.type': 'Escribir una ruta…', 'places.continue': 'Continuar',
|
|
18
|
+
selected: 'Selección: {n}',
|
|
19
|
+
'note.git': '{n} proyectos Git', 'note.git1': '1 proyecto Git', 'note.project': 'proyecto Git',
|
|
20
|
+
'note.web': 'sitios web', 'note.srv': 'datos del servidor', 'note.opt': 'programas instalados',
|
|
21
|
+
'note.etc': 'ajustes del sistema', 'note.log': 'registros', 'note.home': 'toda tu carpeta personal',
|
|
22
|
+
'note.readOnly': 'solo lectura para ti', 'note.added': 'añadida por ti', 'note.earlier': 'aprobada antes',
|
|
23
|
+
'note.inside': 'dentro de {path}',
|
|
24
|
+
'help.home': 'Todo lo que hay en {home}, también ajustes ocultos y claves como ~/.ssh.',
|
|
25
|
+
'help.etc': 'Ajustes de todo el sistema. Un cambio erróneo ahí puede dejar el servidor sin funcionar.',
|
|
26
|
+
'help.log': 'Registros del sistema y de sus servicios. Útiles para encontrar errores.',
|
|
27
|
+
'help.web': 'Archivos de los sitios web que sirve este servidor.',
|
|
28
|
+
'help.srv': 'Datos de los servicios de este servidor.',
|
|
29
|
+
'help.opt': 'Programas instalados fuera del gestor de paquetes.',
|
|
30
|
+
'help.code': 'Tus proyectos de código.',
|
|
31
|
+
'help.readOnly': 'Aquí puedes leer, pero no escribir. La IA puede hacer lo mismo, nada más.',
|
|
32
|
+
'help.browse': 'Elige cualquier carpeta de este ordenador, como en un explorador de archivos.',
|
|
33
|
+
'help.type': 'Escribe una ruta completa. Tab la completa.',
|
|
34
|
+
'help.continue': 'Siguiente: comandos.',
|
|
35
|
+
'browse.title': 'Explorar', 'browse.thisPc': 'Este equipo',
|
|
36
|
+
'browse.loading': 'cargando…', 'browse.empty': 'sin carpetas', 'browse.noAccess': 'sin acceso', 'browse.link': 'enlace',
|
|
37
|
+
'browse.blocked': '{path} está dentro de {parent}, que ya está seleccionada.',
|
|
38
|
+
'browse.hidden': 'Se muestran las carpetas ocultas.', 'browse.hiddenOff': 'Las carpetas ocultas no se muestran.',
|
|
39
|
+
'type.title': 'Escribe la ruta de una carpeta', 'type.label': 'Ruta',
|
|
40
|
+
'type.notFound': 'No existe la carpeta {path}.',
|
|
41
|
+
'everything.title': '¿Compartir todo?',
|
|
42
|
+
'everything.body': 'La IA puede leer, modificar y borrar cualquier archivo al que {user} tenga acceso en este ordenador.',
|
|
43
|
+
'everything.root': 'Eres root: eso incluye cada archivo del sistema, también el propio sistema.',
|
|
44
|
+
'everything.free': 'Así la IA puede trabajar libremente en este servidor. No recomendado.',
|
|
45
|
+
'everything.no': 'No, volver', 'everything.yes': 'Sí, compartir todo',
|
|
46
|
+
'everything.summary': 'Todo en este ordenador',
|
|
47
|
+
'shell.title': '¿Puede la IA ejecutar comandos aquí?',
|
|
48
|
+
'shell.body': 'Los comandos se ejecutan como {user}, con acceso completo a Internet. No se limitan a las carpetas compartidas.',
|
|
49
|
+
'shell.keep': 'Dejarlo así', 'shell.keepNote': 'hasta el {date}',
|
|
50
|
+
'shell.no': 'Ahora no', 'shell.noNote': 'un chat pregunta antes cuando los necesita',
|
|
51
|
+
'shell.off': 'Desactivar', 'shell.offNote': 'un chat pregunta antes cuando los necesita',
|
|
52
|
+
'shell.d7': 'Sí, durante 7 días', 'shell.d30': 'Sí, durante 30 días', 'shell.d365': 'Sí, durante un año',
|
|
53
|
+
'review.title': 'Revisar y guardar',
|
|
54
|
+
'review.folders': 'Carpetas', 'review.commands': 'Comandos',
|
|
55
|
+
'review.noFolders': 'ninguna — un chat pregunta cuando necesita una',
|
|
56
|
+
'review.removed': 'aprobación retirada',
|
|
57
|
+
'review.cmdNo': 'no aprobados — un chat pregunta antes',
|
|
58
|
+
'review.cmdUntil': 'aprobados hasta el {date}',
|
|
59
|
+
'review.save': 'Guardar', 'review.back': 'Atrás', 'review.quit': 'Salir sin guardar',
|
|
60
|
+
'review.where': 'Se guarda solo en este ordenador, en {file}',
|
|
61
|
+
keyNames: { space: 'espacio', enter: 'enter', esc: 'esc', tab: 'tab', backspace: 'retroceso' },
|
|
62
|
+
keys: { move: 'mover', select: 'elegir', toggle: 'marcar', back: 'atrás', quit: 'salir', open: 'abrir', close: 'cerrar', openClose: 'abrir/cerrar', up: 'carpeta superior', hidden: 'ocultas', done: 'listo', tab: 'completar', add: 'añadir' },
|
|
63
|
+
'done.saved': 'Guardado en este ordenador.',
|
|
64
|
+
'done.unchanged': 'No se ha cambiado nada.',
|
|
65
|
+
'done.web': 'Cuando un chat de tensor.chat comparta una de estas carpetas, este ordenador lo confirmará por sí solo.',
|
|
66
|
+
'done.run': 'Inicia el Companion con:',
|
|
67
|
+
'done.noTty': 'La configuración necesita un terminal interactivo. Sin él, usa approve-folder y approve-shell.',
|
|
68
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// The setup's words in French. is the no-break space French sets before
|
|
3
|
+
// ? : ! and between a number and its word.
|
|
4
|
+
|
|
5
|
+
module.exports = {
|
|
6
|
+
setup: 'configuration',
|
|
7
|
+
steps: ['Quoi', 'Dossiers', 'Commandes', 'Enregistrer'],
|
|
8
|
+
'start.title': 'Que peut utiliser l’IA sur cet ordinateur ?',
|
|
9
|
+
'start.folders': 'Choisir des dossiers', 'start.foldersNote': 'recommandé',
|
|
10
|
+
'start.nothing': 'Rien pour l’instant', 'start.nothingNote': 'une discussion demande quand elle a besoin d’un dossier',
|
|
11
|
+
'start.everything': 'Tout', 'start.everythingNote': 'déconseillé',
|
|
12
|
+
'start.help': 'L’IA lit, modifie et supprime des fichiers uniquement là où vous l’autorisez ici.',
|
|
13
|
+
'start.now': 'Approuvé actuellement :',
|
|
14
|
+
'start.later': 'Modifiable à tout moment :',
|
|
15
|
+
'places.title': 'Quels dossiers l’IA peut-elle utiliser ?',
|
|
16
|
+
'places.loading': 'Recherche de dossiers…',
|
|
17
|
+
'places.none': 'Aucune suggestion sur cet ordinateur.',
|
|
18
|
+
'places.browse': 'Parcourir tous les dossiers…', 'places.type': 'Saisir un chemin…', 'places.continue': 'Continuer',
|
|
19
|
+
selected: 'Sélection : {n}',
|
|
20
|
+
'note.git': '{n} projets Git', 'note.git1': '1 projet Git', 'note.project': 'projet Git',
|
|
21
|
+
'note.web': 'sites web', 'note.srv': 'données du serveur', 'note.opt': 'programmes installés',
|
|
22
|
+
'note.etc': 'réglages du système', 'note.log': 'journaux', 'note.home': 'tout votre dossier personnel',
|
|
23
|
+
'note.readOnly': 'lecture seule pour vous', 'note.added': 'ajouté par vous', 'note.earlier': 'déjà approuvé',
|
|
24
|
+
'note.inside': 'dans {path}',
|
|
25
|
+
'help.home': 'Tout ce qui se trouve dans {home}, y compris les réglages cachés et les clés comme ~/.ssh.',
|
|
26
|
+
'help.etc': 'Réglages de tout le système. Une mauvaise modification peut arrêter le serveur.',
|
|
27
|
+
'help.log': 'Journaux du système et de ses services. Utiles pour trouver des erreurs.',
|
|
28
|
+
'help.web': 'Fichiers des sites web hébergés sur ce serveur.',
|
|
29
|
+
'help.srv': 'Données des services de ce serveur.',
|
|
30
|
+
'help.opt': 'Programmes installés en dehors du gestionnaire de paquets.',
|
|
31
|
+
'help.code': 'Vos projets de code.',
|
|
32
|
+
'help.readOnly': 'Vous pouvez lire ici, mais pas écrire. L’IA peut faire de même, pas plus.',
|
|
33
|
+
'help.browse': 'Choisissez n’importe quel dossier de cet ordinateur, comme dans un gestionnaire de fichiers.',
|
|
34
|
+
'help.type': 'Saisissez un chemin complet. Tab le complète.',
|
|
35
|
+
'help.continue': 'Ensuite : les commandes.',
|
|
36
|
+
'browse.title': 'Parcourir', 'browse.thisPc': 'Ce PC',
|
|
37
|
+
'browse.loading': 'chargement…', 'browse.empty': 'aucun dossier', 'browse.noAccess': 'pas d’accès', 'browse.link': 'lien',
|
|
38
|
+
'browse.blocked': '{path} se trouve dans {parent}, qui est déjà sélectionné.',
|
|
39
|
+
'browse.hidden': 'Les dossiers cachés sont affichés.', 'browse.hiddenOff': 'Les dossiers cachés sont masqués.',
|
|
40
|
+
'type.title': 'Saisir le chemin d’un dossier', 'type.label': 'Chemin',
|
|
41
|
+
'type.notFound': 'Le dossier {path} n’existe pas.',
|
|
42
|
+
'everything.title': 'Tout partager ?',
|
|
43
|
+
'everything.body': 'L’IA peut lire, modifier et supprimer tous les fichiers auxquels {user} a accès sur cet ordinateur.',
|
|
44
|
+
'everything.root': 'Vous êtes root : cela couvre tous les fichiers du système, y compris le système lui-même.',
|
|
45
|
+
'everything.free': 'L’IA peut ainsi travailler librement sur ce serveur. Déconseillé.',
|
|
46
|
+
'everything.no': 'Non, revenir', 'everything.yes': 'Oui, tout partager',
|
|
47
|
+
'everything.summary': 'Tout sur cet ordinateur',
|
|
48
|
+
'shell.title': 'L’IA peut-elle exécuter des commandes ici ?',
|
|
49
|
+
'shell.body': 'Les commandes s’exécutent en tant que {user}, avec un accès Internet complet. Elles ne se limitent pas aux dossiers partagés.',
|
|
50
|
+
'shell.keep': 'Laisser ainsi', 'shell.keepNote': 'jusqu’au {date}',
|
|
51
|
+
'shell.no': 'Pas maintenant', 'shell.noNote': 'une discussion demande d’abord quand elle en a besoin',
|
|
52
|
+
'shell.off': 'Désactiver', 'shell.offNote': 'une discussion demande d’abord quand elle en a besoin',
|
|
53
|
+
'shell.d7': 'Oui, pour 7 jours', 'shell.d30': 'Oui, pour 30 jours', 'shell.d365': 'Oui, pour un an',
|
|
54
|
+
'review.title': 'Vérifier et enregistrer',
|
|
55
|
+
'review.folders': 'Dossiers', 'review.commands': 'Commandes',
|
|
56
|
+
'review.noFolders': 'aucun — une discussion demande quand elle en a besoin',
|
|
57
|
+
'review.removed': 'approbation retirée',
|
|
58
|
+
'review.cmdNo': 'non approuvées — une discussion demande d’abord',
|
|
59
|
+
'review.cmdUntil': 'approuvées jusqu’au {date}',
|
|
60
|
+
'review.save': 'Enregistrer', 'review.back': 'Retour', 'review.quit': 'Quitter sans enregistrer',
|
|
61
|
+
'review.where': 'Enregistré uniquement sur cet ordinateur, dans {file}',
|
|
62
|
+
keyNames: { space: 'espace', enter: 'entrée', esc: 'échap', tab: 'tab', backspace: 'retour arrière' },
|
|
63
|
+
keys: { move: 'déplacer', select: 'valider', toggle: 'cocher', back: 'retour', quit: 'quitter', open: 'ouvrir', close: 'fermer', openClose: 'ouvrir/fermer', up: 'dossier parent', hidden: 'cachés', done: 'terminer', tab: 'compléter', add: 'ajouter' },
|
|
64
|
+
'done.saved': 'Enregistré sur cet ordinateur.',
|
|
65
|
+
'done.unchanged': 'Aucune modification.',
|
|
66
|
+
'done.web': 'Quand une discussion sur tensor.chat partage l’un de ces dossiers, cet ordinateur le confirme de lui-même.',
|
|
67
|
+
'done.run': 'Démarrez le Companion avec :',
|
|
68
|
+
'done.noTty': 'La configuration nécessite un terminal interactif. Sans terminal, utilisez approve-folder et approve-shell.',
|
|
69
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// The setup's words in Hindi.
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
setup: 'सेटअप',
|
|
6
|
+
steps: ['क्या', 'फ़ोल्डर', 'कमांड', 'सहेजें'],
|
|
7
|
+
'start.title': 'AI इस कंप्यूटर पर क्या इस्तेमाल कर सकता है?',
|
|
8
|
+
'start.folders': 'फ़ोल्डर चुनें', 'start.foldersNote': 'अनुशंसित',
|
|
9
|
+
'start.nothing': 'अभी कुछ नहीं', 'start.nothingNote': 'फ़ोल्डर की ज़रूरत होने पर चैट पूछती है',
|
|
10
|
+
'start.everything': 'सब कुछ', 'start.everythingNote': 'अनुशंसित नहीं',
|
|
11
|
+
'start.help': 'AI फ़ाइलें केवल वहीं पढ़ता, बदलता और हटाता है जहाँ आप यहाँ अनुमति देते हैं।',
|
|
12
|
+
'start.now': 'अभी स्वीकृत:',
|
|
13
|
+
'start.later': 'इसे कभी भी बदलें:',
|
|
14
|
+
'places.title': 'AI कौन-से फ़ोल्डर इस्तेमाल कर सकता है?',
|
|
15
|
+
'places.loading': 'फ़ोल्डर खोजे जा रहे हैं…',
|
|
16
|
+
'places.none': 'इस कंप्यूटर पर कोई सुझाव नहीं।',
|
|
17
|
+
'places.browse': 'सभी फ़ोल्डर ब्राउज़ करें…', 'places.type': 'पथ लिखें…', 'places.continue': 'जारी रखें',
|
|
18
|
+
selected: 'चयनित: {n}',
|
|
19
|
+
'note.git': '{n} Git प्रोजेक्ट', 'note.git1': '1 Git प्रोजेक्ट', 'note.project': 'Git प्रोजेक्ट',
|
|
20
|
+
'note.web': 'वेबसाइटें', 'note.srv': 'सर्वर डेटा', 'note.opt': 'इंस्टॉल किए गए प्रोग्राम',
|
|
21
|
+
'note.etc': 'सिस्टम सेटिंग्स', 'note.log': 'लॉग', 'note.home': 'आपका पूरा होम फ़ोल्डर',
|
|
22
|
+
'note.readOnly': 'आपके लिए केवल पढ़ने योग्य', 'note.added': 'आपने जोड़ा', 'note.earlier': 'पहले से स्वीकृत',
|
|
23
|
+
'note.inside': '{path} के अंदर',
|
|
24
|
+
'help.home': '{home} में सब कुछ, छिपी सेटिंग्स और ~/.ssh जैसी कुंजियाँ भी।',
|
|
25
|
+
'help.etc': 'पूरे सिस्टम की सेटिंग्स। वहाँ एक गलत बदलाव सर्वर को रोक सकता है।',
|
|
26
|
+
'help.log': 'सिस्टम और उसकी सेवाओं के लॉग। गड़बड़ी ढूँढने में काम आते हैं।',
|
|
27
|
+
'help.web': 'उन वेबसाइटों की फ़ाइलें जिन्हें यह सर्वर दिखाता है।',
|
|
28
|
+
'help.srv': 'इस सर्वर की सेवाओं का डेटा।',
|
|
29
|
+
'help.opt': 'पैकेज मैनेजर के बाहर इंस्टॉल किए गए प्रोग्राम।',
|
|
30
|
+
'help.code': 'आपके कोड प्रोजेक्ट।',
|
|
31
|
+
'help.readOnly': 'आप यहाँ पढ़ सकते हैं, लिख नहीं सकते। AI भी इतना ही कर सकता है, इससे ज़्यादा नहीं।',
|
|
32
|
+
'help.browse': 'इस कंप्यूटर पर कोई भी फ़ोल्डर चुनें, जैसे किसी फ़ाइल मैनेजर में।',
|
|
33
|
+
'help.type': 'पूरा पथ लिखें। Tab उसे पूरा करता है।',
|
|
34
|
+
'help.continue': 'आगे: कमांड।',
|
|
35
|
+
'browse.title': 'ब्राउज़ करें', 'browse.thisPc': 'यह पीसी',
|
|
36
|
+
'browse.loading': 'लोड हो रहा है…', 'browse.empty': 'कोई फ़ोल्डर नहीं', 'browse.noAccess': 'पहुँच नहीं', 'browse.link': 'लिंक',
|
|
37
|
+
'browse.blocked': '{path}, {parent} के अंदर है, और वह पहले से चुना हुआ है।',
|
|
38
|
+
'browse.hidden': 'छिपे फ़ोल्डर दिखाए जा रहे हैं।', 'browse.hiddenOff': 'छिपे फ़ोल्डर नहीं दिखाए जा रहे।',
|
|
39
|
+
'type.title': 'फ़ोल्डर का पथ लिखें', 'type.label': 'पथ',
|
|
40
|
+
'type.notFound': '{path} नाम का कोई फ़ोल्डर नहीं है।',
|
|
41
|
+
'everything.title': 'सब कुछ साझा करें?',
|
|
42
|
+
'everything.body': 'AI इस कंप्यूटर पर हर वह फ़ाइल पढ़, बदल और हटा सकता है जिस तक {user} पहुँच सकता है।',
|
|
43
|
+
'everything.root': 'आप root हैं: यानी सिस्टम की हर फ़ाइल, खुद सिस्टम भी।',
|
|
44
|
+
'everything.free': 'इससे AI इस सर्वर पर खुलकर काम कर सकता है। अनुशंसित नहीं।',
|
|
45
|
+
'everything.no': 'नहीं, वापस', 'everything.yes': 'हाँ, सब कुछ साझा करें',
|
|
46
|
+
'everything.summary': 'इस कंप्यूटर पर सब कुछ',
|
|
47
|
+
'shell.title': 'क्या AI यहाँ कमांड चला सकता है?',
|
|
48
|
+
'shell.body': 'कमांड {user} के रूप में, पूरी इंटरनेट पहुँच के साथ चलते हैं। वे साझा फ़ोल्डरों तक सीमित नहीं हैं।',
|
|
49
|
+
'shell.keep': 'जैसा है वैसा रखें', 'shell.keepNote': '{date} तक',
|
|
50
|
+
'shell.no': 'अभी नहीं', 'shell.noNote': 'ज़रूरत होने पर चैट पहले पूछती है',
|
|
51
|
+
'shell.off': 'बंद करें', 'shell.offNote': 'ज़रूरत होने पर चैट पहले पूछती है',
|
|
52
|
+
'shell.d7': 'हाँ, 7 दिनों के लिए', 'shell.d30': 'हाँ, 30 दिनों के लिए', 'shell.d365': 'हाँ, एक साल के लिए',
|
|
53
|
+
'review.title': 'जाँचें और सहेजें',
|
|
54
|
+
'review.folders': 'फ़ोल्डर', 'review.commands': 'कमांड',
|
|
55
|
+
'review.noFolders': 'कोई नहीं — ज़रूरत होने पर चैट पूछती है',
|
|
56
|
+
'review.removed': 'स्वीकृति हटाई गई',
|
|
57
|
+
'review.cmdNo': 'स्वीकृत नहीं — चैट पहले पूछती है',
|
|
58
|
+
'review.cmdUntil': '{date} तक स्वीकृत',
|
|
59
|
+
'review.save': 'सहेजें', 'review.back': 'वापस', 'review.quit': 'बिना सहेजे बाहर निकलें',
|
|
60
|
+
'review.where': 'केवल इस कंप्यूटर पर सहेजा जाता है, {file} में',
|
|
61
|
+
keyNames: { space: 'स्पेस', enter: 'Enter', esc: 'Esc', tab: 'Tab', backspace: 'Backspace' },
|
|
62
|
+
keys: { move: 'चलें', select: 'चुनें', toggle: 'टिक करें', back: 'वापस', quit: 'बाहर निकलें', open: 'खोलें', close: 'बंद करें', openClose: 'खोलें/बंद करें', up: 'ऊपर का फ़ोल्डर', hidden: 'छिपे', done: 'हो गया', tab: 'पूरा करें', add: 'जोड़ें' },
|
|
63
|
+
'done.saved': 'इस कंप्यूटर पर सहेजा गया।',
|
|
64
|
+
'done.unchanged': 'कुछ नहीं बदला।',
|
|
65
|
+
'done.web': 'जब tensor.chat पर कोई चैट इनमें से कोई फ़ोल्डर साझा करती है, तो यह कंप्यूटर खुद उसकी पुष्टि कर देता है।',
|
|
66
|
+
'done.run': 'Companion को इससे शुरू करें:',
|
|
67
|
+
'done.noTty': 'सेटअप के लिए इंटरैक्टिव टर्मिनल चाहिए। उसके बिना approve-folder और approve-shell इस्तेमाल करें।',
|
|
68
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// The setup's words in Portuguese (Brazil, as on the site).
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
setup: 'configuração',
|
|
6
|
+
steps: ['O quê', 'Pastas', 'Comandos', 'Salvar'],
|
|
7
|
+
'start.title': 'O que a IA pode usar neste computador?',
|
|
8
|
+
'start.folders': 'Escolher pastas', 'start.foldersNote': 'recomendado',
|
|
9
|
+
'start.nothing': 'Nada por enquanto', 'start.nothingNote': 'uma conversa pergunta quando precisar de uma pasta',
|
|
10
|
+
'start.everything': 'Tudo', 'start.everythingNote': 'não recomendado',
|
|
11
|
+
'start.help': 'A IA lê, altera e exclui arquivos somente onde você permitir aqui.',
|
|
12
|
+
'start.now': 'Aprovado agora:',
|
|
13
|
+
'start.later': 'Altere quando quiser:',
|
|
14
|
+
'places.title': 'Quais pastas a IA pode usar?',
|
|
15
|
+
'places.loading': 'Procurando pastas…',
|
|
16
|
+
'places.none': 'Nenhuma sugestão neste computador.',
|
|
17
|
+
'places.browse': 'Procurar em todas as pastas…', 'places.type': 'Digitar um caminho…', 'places.continue': 'Continuar',
|
|
18
|
+
selected: 'Seleção: {n}',
|
|
19
|
+
'note.git': '{n} projetos Git', 'note.git1': '1 projeto Git', 'note.project': 'projeto Git',
|
|
20
|
+
'note.web': 'sites', 'note.srv': 'dados do servidor', 'note.opt': 'programas instalados',
|
|
21
|
+
'note.etc': 'configurações do sistema', 'note.log': 'logs', 'note.home': 'toda a sua pasta pessoal',
|
|
22
|
+
'note.readOnly': 'somente leitura para você', 'note.added': 'adicionada por você', 'note.earlier': 'aprovada antes',
|
|
23
|
+
'note.inside': 'dentro de {path}',
|
|
24
|
+
'help.home': 'Tudo em {home}, inclusive configurações ocultas e chaves como ~/.ssh.',
|
|
25
|
+
'help.etc': 'Configurações de todo o sistema. Uma alteração errada ali pode derrubar o servidor.',
|
|
26
|
+
'help.log': 'Logs do sistema e de seus serviços. Úteis para encontrar erros.',
|
|
27
|
+
'help.web': 'Arquivos dos sites hospedados neste servidor.',
|
|
28
|
+
'help.srv': 'Dados dos serviços deste servidor.',
|
|
29
|
+
'help.opt': 'Programas instalados fora do gerenciador de pacotes.',
|
|
30
|
+
'help.code': 'Seus projetos de código.',
|
|
31
|
+
'help.readOnly': 'Aqui você pode ler, mas não escrever. A IA pode fazer o mesmo, nada mais.',
|
|
32
|
+
'help.browse': 'Escolha qualquer pasta deste computador, como em um gerenciador de arquivos.',
|
|
33
|
+
'help.type': 'Digite um caminho completo. Tab completa.',
|
|
34
|
+
'help.continue': 'Próximo: comandos.',
|
|
35
|
+
'browse.title': 'Procurar', 'browse.thisPc': 'Este Computador',
|
|
36
|
+
'browse.loading': 'carregando…', 'browse.empty': 'nenhuma pasta', 'browse.noAccess': 'sem acesso', 'browse.link': 'link',
|
|
37
|
+
'browse.blocked': '{path} está dentro de {parent}, que já está selecionada.',
|
|
38
|
+
'browse.hidden': 'As pastas ocultas estão visíveis.', 'browse.hiddenOff': 'As pastas ocultas não são mostradas.',
|
|
39
|
+
'type.title': 'Digite o caminho de uma pasta', 'type.label': 'Caminho',
|
|
40
|
+
'type.notFound': 'A pasta {path} não existe.',
|
|
41
|
+
'everything.title': 'Compartilhar tudo?',
|
|
42
|
+
'everything.body': 'A IA pode ler, alterar e excluir qualquer arquivo que {user} consiga acessar neste computador.',
|
|
43
|
+
'everything.root': 'Você é root: isso inclui cada arquivo do sistema, inclusive o próprio sistema.',
|
|
44
|
+
'everything.free': 'Assim a IA pode trabalhar livremente neste servidor. Não recomendado.',
|
|
45
|
+
'everything.no': 'Não, voltar', 'everything.yes': 'Sim, compartilhar tudo',
|
|
46
|
+
'everything.summary': 'Tudo neste computador',
|
|
47
|
+
'shell.title': 'A IA pode executar comandos aqui?',
|
|
48
|
+
'shell.body': 'Os comandos são executados como {user}, com acesso total à Internet. Eles não se limitam às pastas compartilhadas.',
|
|
49
|
+
'shell.keep': 'Manter como está', 'shell.keepNote': 'até {date}',
|
|
50
|
+
'shell.no': 'Agora não', 'shell.noNote': 'uma conversa pergunta antes quando precisar deles',
|
|
51
|
+
'shell.off': 'Desativar', 'shell.offNote': 'uma conversa pergunta antes quando precisar deles',
|
|
52
|
+
'shell.d7': 'Sim, por 7 dias', 'shell.d30': 'Sim, por 30 dias', 'shell.d365': 'Sim, por um ano',
|
|
53
|
+
'review.title': 'Revisar e salvar',
|
|
54
|
+
'review.folders': 'Pastas', 'review.commands': 'Comandos',
|
|
55
|
+
'review.noFolders': 'nenhuma — uma conversa pergunta quando precisar de uma',
|
|
56
|
+
'review.removed': 'aprovação removida',
|
|
57
|
+
'review.cmdNo': 'não aprovados — uma conversa pergunta antes',
|
|
58
|
+
'review.cmdUntil': 'aprovados até {date}',
|
|
59
|
+
'review.save': 'Salvar', 'review.back': 'Voltar', 'review.quit': 'Sair sem salvar',
|
|
60
|
+
'review.where': 'Salvo somente neste computador, em {file}',
|
|
61
|
+
keyNames: { space: 'espaço', enter: 'enter', esc: 'esc', tab: 'tab', backspace: 'backspace' },
|
|
62
|
+
keys: { move: 'mover', select: 'escolher', toggle: 'marcar', back: 'voltar', quit: 'sair', open: 'abrir', close: 'fechar', openClose: 'abrir/fechar', up: 'pasta acima', hidden: 'ocultas', done: 'concluir', tab: 'completar', add: 'adicionar' },
|
|
63
|
+
'done.saved': 'Salvo neste computador.',
|
|
64
|
+
'done.unchanged': 'Nada foi alterado.',
|
|
65
|
+
'done.web': 'Quando uma conversa no tensor.chat compartilhar uma dessas pastas, este computador confirma isso sozinho.',
|
|
66
|
+
'done.run': 'Inicie o Companion com:',
|
|
67
|
+
'done.noTty': 'A configuração precisa de um terminal interativo. Sem um, use approve-folder e approve-shell.',
|
|
68
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// The setup's words in Russian. A count comes after a colon ("Выбрано: 3"), so no
|
|
3
|
+
// word has to take one of the three plural forms.
|
|
4
|
+
|
|
5
|
+
module.exports = {
|
|
6
|
+
setup: 'настройка',
|
|
7
|
+
steps: ['Что', 'Папки', 'Команды', 'Сохранение'],
|
|
8
|
+
'start.title': 'Что ИИ может использовать на этом компьютере?',
|
|
9
|
+
'start.folders': 'Выбрать папки', 'start.foldersNote': 'рекомендуется',
|
|
10
|
+
'start.nothing': 'Пока ничего', 'start.nothingNote': 'чат спросит, когда ему понадобится папка',
|
|
11
|
+
'start.everything': 'Всё', 'start.everythingNote': 'не рекомендуется',
|
|
12
|
+
'start.help': 'ИИ читает, изменяет и удаляет файлы только там, где вы это здесь разрешите.',
|
|
13
|
+
'start.now': 'Сейчас разрешено:',
|
|
14
|
+
'start.later': 'Изменить можно в любой момент:',
|
|
15
|
+
'places.title': 'Какие папки может использовать ИИ?',
|
|
16
|
+
'places.loading': 'Ищем папки…',
|
|
17
|
+
'places.none': 'На этом компьютере нет предложений.',
|
|
18
|
+
'places.browse': 'Обзор всех папок…', 'places.type': 'Ввести путь…', 'places.continue': 'Продолжить',
|
|
19
|
+
selected: 'Выбрано: {n}',
|
|
20
|
+
'note.git': 'Git-проектов: {n}', 'note.git1': '1 Git-проект', 'note.project': 'Git-проект',
|
|
21
|
+
'note.web': 'сайты', 'note.srv': 'данные сервера', 'note.opt': 'установленные программы',
|
|
22
|
+
'note.etc': 'настройки системы', 'note.log': 'журналы', 'note.home': 'вся ваша домашняя папка',
|
|
23
|
+
'note.readOnly': 'для вас только чтение', 'note.added': 'добавлена вами', 'note.earlier': 'разрешена ранее',
|
|
24
|
+
'note.inside': 'внутри {path}',
|
|
25
|
+
'help.home': 'Всё в {home}, включая скрытые настройки и ключи, например ~/.ssh.',
|
|
26
|
+
'help.etc': 'Настройки всей системы. Неверное изменение здесь может остановить сервер.',
|
|
27
|
+
'help.log': 'Журналы системы и её служб. Помогают находить ошибки.',
|
|
28
|
+
'help.web': 'Файлы сайтов, которые отдаёт этот сервер.',
|
|
29
|
+
'help.srv': 'Данные служб на этом сервере.',
|
|
30
|
+
'help.opt': 'Программы, установленные в обход менеджера пакетов.',
|
|
31
|
+
'help.code': 'Ваши проекты с кодом.',
|
|
32
|
+
'help.readOnly': 'Здесь вы можете читать, но не писать. ИИ может то же самое, не больше.',
|
|
33
|
+
'help.browse': 'Выберите любую папку на этом компьютере, как в файловом менеджере.',
|
|
34
|
+
'help.type': 'Введите полный путь. Tab дополняет его.',
|
|
35
|
+
'help.continue': 'Далее: команды.',
|
|
36
|
+
'browse.title': 'Обзор', 'browse.thisPc': 'Этот компьютер',
|
|
37
|
+
'browse.loading': 'загрузка…', 'browse.empty': 'нет папок', 'browse.noAccess': 'нет доступа', 'browse.link': 'ссылка',
|
|
38
|
+
'browse.blocked': '{path} находится внутри {parent}, а эта папка уже выбрана.',
|
|
39
|
+
'browse.hidden': 'Скрытые папки показаны.', 'browse.hiddenOff': 'Скрытые папки не показываются.',
|
|
40
|
+
'type.title': 'Введите путь к папке', 'type.label': 'Путь',
|
|
41
|
+
'type.notFound': 'Папки {path} не существует.',
|
|
42
|
+
'everything.title': 'Открыть доступ ко всему?',
|
|
43
|
+
'everything.body': 'ИИ сможет читать, изменять и удалять любой файл, доступный пользователю {user} на этом компьютере.',
|
|
44
|
+
'everything.root': 'Вы root: это все файлы системы, включая саму систему.',
|
|
45
|
+
'everything.free': 'Так ИИ сможет свободно работать на этом сервере. Не рекомендуется.',
|
|
46
|
+
'everything.no': 'Нет, назад', 'everything.yes': 'Да, открыть доступ ко всему',
|
|
47
|
+
'everything.summary': 'Всё на этом компьютере',
|
|
48
|
+
'shell.title': 'Может ли ИИ выполнять здесь команды?',
|
|
49
|
+
'shell.body': 'Команды выполняются от имени {user}, с полным доступом в Интернет. Они не ограничены общими папками.',
|
|
50
|
+
'shell.keep': 'Оставить как есть', 'shell.keepNote': 'до {date}',
|
|
51
|
+
'shell.no': 'Не сейчас', 'shell.noNote': 'чат сначала спросит, когда они понадобятся',
|
|
52
|
+
'shell.off': 'Отключить', 'shell.offNote': 'чат сначала спросит, когда они понадобятся',
|
|
53
|
+
'shell.d7': 'Да, на 7 дней', 'shell.d30': 'Да, на 30 дней', 'shell.d365': 'Да, на год',
|
|
54
|
+
'review.title': 'Проверка и сохранение',
|
|
55
|
+
'review.folders': 'Папки', 'review.commands': 'Команды',
|
|
56
|
+
'review.noFolders': 'нет — чат спросит, когда ему понадобится папка',
|
|
57
|
+
'review.removed': 'разрешение отозвано',
|
|
58
|
+
'review.cmdNo': 'не разрешены — чат сначала спросит',
|
|
59
|
+
'review.cmdUntil': 'разрешены до {date}',
|
|
60
|
+
'review.save': 'Сохранить', 'review.back': 'Назад', 'review.quit': 'Выйти без сохранения',
|
|
61
|
+
'review.where': 'Сохраняется только на этом компьютере, в {file}',
|
|
62
|
+
keyNames: { space: 'пробел', enter: 'Enter', esc: 'Esc', tab: 'Tab', backspace: 'Backspace' },
|
|
63
|
+
keys: { move: 'перемещение', select: 'выбор', toggle: 'отметить', back: 'назад', quit: 'выход', open: 'открыть', close: 'закрыть', openClose: 'открыть/закрыть', up: 'папка выше', hidden: 'скрытые', done: 'готово', tab: 'дополнить', add: 'добавить' },
|
|
64
|
+
'done.saved': 'Сохранено на этом компьютере.',
|
|
65
|
+
'done.unchanged': 'Ничего не изменилось.',
|
|
66
|
+
'done.web': 'Когда чат на tensor.chat откроет доступ к одной из этих папок, этот компьютер подтвердит это сам.',
|
|
67
|
+
'done.run': 'Запустите Companion командой:',
|
|
68
|
+
'done.noTty': 'Для настройки нужен интерактивный терминал. Без него используйте approve-folder и approve-shell.',
|
|
69
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// The setup's words in Chinese (Simplified).
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
setup: '设置',
|
|
6
|
+
steps: ['范围', '文件夹', '命令', '保存'],
|
|
7
|
+
'start.title': 'AI 可以使用这台电脑上的哪些内容?',
|
|
8
|
+
'start.folders': '选择文件夹', 'start.foldersNote': '推荐',
|
|
9
|
+
'start.nothing': '暂不共享', 'start.nothingNote': '聊天需要文件夹时会询问',
|
|
10
|
+
'start.everything': '全部', 'start.everythingNote': '不推荐',
|
|
11
|
+
'start.help': 'AI 只会在你在这里允许的位置读取、修改和删除文件。',
|
|
12
|
+
'start.now': '当前已批准:',
|
|
13
|
+
'start.later': '随时可以更改:',
|
|
14
|
+
'places.title': 'AI 可以使用哪些文件夹?',
|
|
15
|
+
'places.loading': '正在查找文件夹…',
|
|
16
|
+
'places.none': '这台电脑上没有建议。',
|
|
17
|
+
'places.browse': '浏览所有文件夹…', 'places.type': '输入路径…', 'places.continue': '继续',
|
|
18
|
+
selected: '已选 {n} 个',
|
|
19
|
+
'note.git': '{n} 个 Git 项目', 'note.git1': '1 个 Git 项目', 'note.project': 'Git 项目',
|
|
20
|
+
'note.web': '网站', 'note.srv': '服务器数据', 'note.opt': '已安装的程序',
|
|
21
|
+
'note.etc': '系统设置', 'note.log': '日志', 'note.home': '你的整个主目录',
|
|
22
|
+
'note.readOnly': '你只能读取', 'note.added': '由你添加', 'note.earlier': '之前已批准',
|
|
23
|
+
'note.inside': '位于 {path} 内',
|
|
24
|
+
'help.home': '{home} 中的所有内容,也包括隐藏的设置和密钥,例如 ~/.ssh。',
|
|
25
|
+
'help.etc': '整个系统的设置。改错一处就可能让服务器停止运行。',
|
|
26
|
+
'help.log': '系统及其服务的日志。便于排查错误。',
|
|
27
|
+
'help.web': '此服务器提供的网站文件。',
|
|
28
|
+
'help.srv': '此服务器上各项服务的数据。',
|
|
29
|
+
'help.opt': '在软件包管理器之外安装的程序。',
|
|
30
|
+
'help.code': '你的代码项目。',
|
|
31
|
+
'help.readOnly': '你在这里只能读取,不能写入。AI 也只有同样的权限。',
|
|
32
|
+
'help.browse': '像在文件管理器中一样,选择这台电脑上的任意文件夹。',
|
|
33
|
+
'help.type': '输入完整路径。按 Tab 自动补全。',
|
|
34
|
+
'help.continue': '下一步:命令。',
|
|
35
|
+
'browse.title': '浏览', 'browse.thisPc': '此电脑',
|
|
36
|
+
'browse.loading': '加载中…', 'browse.empty': '没有文件夹', 'browse.noAccess': '无权访问', 'browse.link': '链接',
|
|
37
|
+
'browse.blocked': '{path} 位于 {parent} 内,而后者已被选择。',
|
|
38
|
+
'browse.hidden': '隐藏文件夹已显示。', 'browse.hiddenOff': '隐藏文件夹未显示。',
|
|
39
|
+
'type.title': '输入文件夹路径', 'type.label': '路径',
|
|
40
|
+
'type.notFound': '文件夹 {path} 不存在。',
|
|
41
|
+
'everything.title': '共享全部内容?',
|
|
42
|
+
'everything.body': 'AI 可以读取、修改和删除 {user} 在这台电脑上能访问的所有文件。',
|
|
43
|
+
'everything.root': '你是 root:这意味着系统中的所有文件,包括系统本身。',
|
|
44
|
+
'everything.free': '这样 AI 可以在这台服务器上自由工作。不推荐。',
|
|
45
|
+
'everything.no': '不,返回', 'everything.yes': '是,共享全部',
|
|
46
|
+
'everything.summary': '这台电脑上的全部内容',
|
|
47
|
+
'shell.title': 'AI 可以在这里运行命令吗?',
|
|
48
|
+
'shell.body': '命令以 {user} 身份运行,并可完全访问互联网。命令不限于共享的文件夹。',
|
|
49
|
+
'shell.keep': '保持不变', 'shell.keepNote': '到 {date} 为止',
|
|
50
|
+
'shell.no': '暂不', 'shell.noNote': '聊天需要时会先询问',
|
|
51
|
+
'shell.off': '关闭', 'shell.offNote': '聊天需要时会先询问',
|
|
52
|
+
'shell.d7': '是,7 天', 'shell.d30': '是,30 天', 'shell.d365': '是,一年',
|
|
53
|
+
'review.title': '检查并保存',
|
|
54
|
+
'review.folders': '文件夹', 'review.commands': '命令',
|
|
55
|
+
'review.noFolders': '无 — 聊天需要时会询问',
|
|
56
|
+
'review.removed': '已撤销批准',
|
|
57
|
+
'review.cmdNo': '未批准 — 聊天会先询问',
|
|
58
|
+
'review.cmdUntil': '已批准,到 {date} 为止',
|
|
59
|
+
'review.save': '保存', 'review.back': '返回', 'review.quit': '退出且不保存',
|
|
60
|
+
'review.where': '仅保存在这台电脑上的 {file} 中',
|
|
61
|
+
keyNames: { space: '空格', enter: 'Enter', esc: 'Esc', tab: 'Tab', backspace: '退格' },
|
|
62
|
+
keys: { move: '移动', select: '选择', toggle: '勾选', back: '返回', quit: '退出', open: '展开', close: '收起', openClose: '展开/收起', up: '上一级', hidden: '隐藏项', done: '完成', tab: '补全', add: '添加' },
|
|
63
|
+
'done.saved': '已保存在这台电脑上。',
|
|
64
|
+
'done.unchanged': '没有更改。',
|
|
65
|
+
'done.web': '当 tensor.chat 上的聊天共享其中某个文件夹时,这台电脑会自动确认。',
|
|
66
|
+
'done.run': '使用以下命令启动 Companion:',
|
|
67
|
+
'done.noTty': '设置需要交互式终端。没有终端时,请使用 approve-folder 和 approve-shell。',
|
|
68
|
+
};
|
package/src/setup/layout.js
CHANGED
|
@@ -2,18 +2,100 @@
|
|
|
2
2
|
// How the setup's lines are laid out: wrapped text, columns, the key hints and framed
|
|
3
3
|
// blocks. Widths count what the terminal shows, not the escape codes.
|
|
4
4
|
|
|
5
|
-
const { width, pad } = require('./term');
|
|
5
|
+
const { width, pad, fit } = require('./term');
|
|
6
6
|
|
|
7
|
+
const ESC_SPLIT = /(\x1b\[[0-9;?]*[A-Za-z])/;
|
|
8
|
+
// Chinese and Japanese break between any two characters, but a line never starts
|
|
9
|
+
// with closing punctuation or ends with opening punctuation
|
|
10
|
+
const NO_START = new Set([...'、。,.:;?!)」』】〕》〉…・ー〜%’”),.:;?!%]}']);
|
|
11
|
+
const NO_END = new Set([...'(「『【〔《〈‘“([{']);
|
|
12
|
+
|
|
13
|
+
// The text's runs that stay together on a line, each knowing whether a space came
|
|
14
|
+
// before it. Only a real space separates words: French keeps its no-break space.
|
|
15
|
+
function runs(text) {
|
|
16
|
+
const out = [];
|
|
17
|
+
let run = null;
|
|
18
|
+
let spaced = false;
|
|
19
|
+
let pending = '';
|
|
20
|
+
let prev = '';
|
|
21
|
+
for (const part of String(text).split(ESC_SPLIT)) {
|
|
22
|
+
if (part.startsWith('\x1b[')) { pending += part; continue; }
|
|
23
|
+
for (const ch of part) {
|
|
24
|
+
// codes right before a space end the word before it
|
|
25
|
+
if (/[ \t\r\n]/.test(ch)) { if (run) { run.s += pending; pending = ''; out.push(run); } run = null; spaced = out.length > 0; prev = ''; continue; }
|
|
26
|
+
const w = width(ch);
|
|
27
|
+
if (run && (w === 2 || width(prev) === 2) && !NO_START.has(ch) && !NO_END.has(prev)) { out.push(run); run = null; }
|
|
28
|
+
if (!run) { run = { s: '', w: 0, spaced }; spaced = false; }
|
|
29
|
+
run.s += pending + ch;
|
|
30
|
+
run.w += w;
|
|
31
|
+
pending = '';
|
|
32
|
+
prev = ch;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (run) out.push(run);
|
|
36
|
+
if (pending && out.length) out[out.length - 1].s += pending;
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// The colours and weights still switched on after `s`, given those before it
|
|
41
|
+
function sgrAfter(active, s) {
|
|
42
|
+
let on = active;
|
|
43
|
+
for (const [, params] of s.matchAll(/\x1b\[([0-9;]*)m/g)) {
|
|
44
|
+
for (const p of params.split(';')) {
|
|
45
|
+
if (p === '' || p === '0') on = [];
|
|
46
|
+
else if (p === '22') on = on.filter((x) => x !== '1' && x !== '2');
|
|
47
|
+
else if (p === '24' || p === '27') on = on.filter((x) => x !== String(p - 20));
|
|
48
|
+
else if (p === '39') on = on.filter((x) => !/^(3[0-7]|9[0-7])$/.test(x));
|
|
49
|
+
else on = [...on, p];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return on;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Lines of at most `cols` cells. A styled text keeps its style on every line.
|
|
7
56
|
function wrap(text, cols) {
|
|
8
57
|
const lines = [];
|
|
9
58
|
let line = '';
|
|
10
|
-
|
|
11
|
-
|
|
59
|
+
let used = 0;
|
|
60
|
+
let on = [];
|
|
61
|
+
const add = (s, w) => { line += s; used += w; on = sgrAfter(on, s); };
|
|
62
|
+
const next = () => {
|
|
63
|
+
lines.push(line + (on.length ? '\x1b[0m' : ''));
|
|
64
|
+
line = on.map((p) => `\x1b[${p}m`).join('');
|
|
65
|
+
used = 0;
|
|
66
|
+
};
|
|
67
|
+
for (const run of runs(text)) {
|
|
68
|
+
const gap = used && run.spaced ? 1 : 0;
|
|
69
|
+
if (used && used + gap + run.w > cols) next();
|
|
70
|
+
else if (gap) add(' ', 1);
|
|
71
|
+
if (used + run.w <= cols) { add(run.s, run.w); continue; }
|
|
72
|
+
// a run longer than a whole line, like a long path, is cut where the line ends
|
|
73
|
+
for (const unit of run.s.match(/(?:\x1b\[[0-9;?]*[A-Za-z])*(?:[^\x1b]|$)/gu)) {
|
|
74
|
+
const w = width(unit);
|
|
75
|
+
if (used && used + w > cols) next();
|
|
76
|
+
add(unit, w);
|
|
77
|
+
}
|
|
12
78
|
}
|
|
13
|
-
if (
|
|
79
|
+
if (used) lines.push(line + (on.length ? '\x1b[0m' : ''));
|
|
14
80
|
return lines;
|
|
15
81
|
}
|
|
16
82
|
|
|
83
|
+
// A path too long for its place loses its middle: the start says where, the end which
|
|
84
|
+
function shorten(text, cols) {
|
|
85
|
+
if (width(text) <= cols) return text;
|
|
86
|
+
const chars = [...text];
|
|
87
|
+
let head = '';
|
|
88
|
+
while (width(head) < Math.floor((cols - 1) / 3)) head += chars.shift();
|
|
89
|
+
// both cuts fall on a separator where there is one
|
|
90
|
+
const sep = Math.max(head.lastIndexOf('/'), head.lastIndexOf('\\'));
|
|
91
|
+
if (sep > 0) { chars.unshift(...head.slice(sep + 1)); head = head.slice(0, sep + 1); }
|
|
92
|
+
let tail = '';
|
|
93
|
+
while (chars.length && width(tail) + width(chars[chars.length - 1]) <= cols - 1 - width(head)) tail = chars.pop() + tail;
|
|
94
|
+
const start = tail.search(/[\\/]/);
|
|
95
|
+
if (start > 0) tail = tail.slice(start);
|
|
96
|
+
return `${head}…${tail}`;
|
|
97
|
+
}
|
|
98
|
+
|
|
17
99
|
// A label in its column, always followed by a gap
|
|
18
100
|
function cell(label, col) {
|
|
19
101
|
return pad(label, col - 2) + ' ';
|
|
@@ -46,4 +128,40 @@ function panel(S, lines, tone, w) {
|
|
|
46
128
|
];
|
|
47
129
|
}
|
|
48
130
|
|
|
49
|
-
|
|
131
|
+
// At most `n` of the lines; a cut note ends in "…"
|
|
132
|
+
function clip(lines, n, cols) {
|
|
133
|
+
if (lines.length <= n) return lines;
|
|
134
|
+
const last = lines[n - 1];
|
|
135
|
+
return [...lines.slice(0, n - 1), width(last) + 2 <= cols ? `${last} …` : fit(last, width(last) - 1)];
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// The frame's top and bottom for a screen of `rows` lines. Before the list gets fewer
|
|
139
|
+
// than three lines, these give way in turn: a third line of the note, the blank lines
|
|
140
|
+
// on top, the gap above the keys, the rule, the steps, a second line of the note.
|
|
141
|
+
function squeeze({ rows, width: cols, brand, steps, heading, note, rule, keys }) {
|
|
142
|
+
const at = (l) => ' ' + l;
|
|
143
|
+
let noteMax = 3;
|
|
144
|
+
let blanks = true;
|
|
145
|
+
let gap = 1;
|
|
146
|
+
let stepped = true;
|
|
147
|
+
let ruled = true;
|
|
148
|
+
const build = () => {
|
|
149
|
+
const blank = blanks ? [''] : [];
|
|
150
|
+
const said = clip(note, noteMax, cols).map(at);
|
|
151
|
+
return {
|
|
152
|
+
top: [...blank, ...brand.map(at), ...(stepped ? [at(steps)] : []), ...blank, ...heading.map(at), ...blank],
|
|
153
|
+
bottom: [...(said.length ? said : ['']), ...(ruled ? [at(rule)] : []), ...keys],
|
|
154
|
+
gap,
|
|
155
|
+
};
|
|
156
|
+
};
|
|
157
|
+
const giveWay = [() => { noteMax = 2; }, () => { blanks = false; }, () => { gap = 0; }, () => { ruled = false; }, () => { stepped = false; }, () => { noteMax = 1; }];
|
|
158
|
+
let parts = build();
|
|
159
|
+
for (const next of giveWay) {
|
|
160
|
+
if (parts.top.length + parts.bottom.length + parts.gap + 3 <= rows) break;
|
|
161
|
+
next();
|
|
162
|
+
parts = build();
|
|
163
|
+
}
|
|
164
|
+
return parts;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
module.exports = { wrap, shorten, cell, spread, keyLines, panel, squeeze };
|
package/src/setup/term.js
CHANGED
|
@@ -17,7 +17,11 @@ function styles(color) {
|
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
// Marks that sit on the letter before them, like most Devanagari vowel signs
|
|
21
|
+
const ZERO_WIDTH = /^[\p{Mn}\p{Me}\p{Cf}]$/u;
|
|
22
|
+
|
|
20
23
|
function charWidth(cp) {
|
|
24
|
+
if (ZERO_WIDTH.test(String.fromCodePoint(cp))) return 0;
|
|
21
25
|
// East Asian wide and fullwidth forms take two cells
|
|
22
26
|
if ((cp >= 0x1100 && cp <= 0x115f) || (cp >= 0x2e80 && cp <= 0xa4cf) || (cp >= 0xac00 && cp <= 0xd7a3)
|
|
23
27
|
|| (cp >= 0xf900 && cp <= 0xfaff) || (cp >= 0xfe30 && cp <= 0xfe4f) || (cp >= 0xff00 && cp <= 0xff60)
|
package/src/setup/wizard.js
CHANGED
|
@@ -70,40 +70,55 @@ function runSetup({
|
|
|
70
70
|
const { rows } = screen.size();
|
|
71
71
|
const w = contentWidth();
|
|
72
72
|
const step = STEP[st.screen];
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
'
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
];
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
...
|
|
88
|
-
|
|
89
|
-
|
|
73
|
+
// A narrow screen names only the current step, and puts what does not fit beside
|
|
74
|
+
// the brand or the title on a line of its own
|
|
75
|
+
const stepLine = (named) => t('steps').map((name, i) => {
|
|
76
|
+
const label = (mark) => (named || i === step ? `${mark} ${name}` : mark);
|
|
77
|
+
return i < step ? S.green(label('✔')) : i === step ? S.bold(S.cyan(label('●'))) : S.dim(label('○'));
|
|
78
|
+
}).join(S.dim(' ─ '));
|
|
79
|
+
const steps = width(stepLine(true)) <= w ? stepLine(true) : stepLine(false);
|
|
80
|
+
const besides = (left, rightPart) => (!rightPart || width(left) + 1 + width(rightPart) <= w ? [spread(left, rightPart, w)] : [left, rightPart]);
|
|
81
|
+
const heading = width(title) <= w ? [S.bold(title)] : wrap(title, w).map((l) => S.bold(l));
|
|
82
|
+
const parts = layout.squeeze({
|
|
83
|
+
rows,
|
|
84
|
+
width: w,
|
|
85
|
+
brand: besides(`${S.cyan('◆')} ${S.bold('Tensor.Chat Companion')} ${S.dim(t('setup'))}`, S.dim([device, user].filter(Boolean).join(' · '))),
|
|
86
|
+
steps,
|
|
87
|
+
heading: [...heading.slice(0, -1), ...besides(heading[heading.length - 1], right)],
|
|
88
|
+
// the status, or the help for the line under the cursor
|
|
89
|
+
note: st.message ? wrap(st.message.text, w).map((l) => S[st.message.tone](l)) : wrap(help, w).map((l) => S.dim(l)),
|
|
90
|
+
rule: S.dim('─'.repeat(w)),
|
|
91
|
+
keys: keyLines(keys, w),
|
|
92
|
+
});
|
|
93
|
+
const { top, bottom, gap } = parts;
|
|
94
|
+
const space = Math.max(3, rows - top.length - bottom.length - gap);
|
|
90
95
|
let start = 0;
|
|
91
96
|
if (body.length > space) start = Math.min(Math.max(0, focus - Math.floor(space / 2)), body.length - space);
|
|
92
97
|
const shown = body.slice(start, start + space);
|
|
93
98
|
if (start > 0) shown[0] = ' ' + S.dim('↑');
|
|
94
99
|
if (start + space < body.length) shown[shown.length - 1] = ' ' + S.dim('↓');
|
|
95
100
|
while (shown.length < space) shown.push('');
|
|
96
|
-
return [...top, ...shown, '', ...bottom];
|
|
101
|
+
return [...top, ...shown, ...(gap ? [''] : []), ...bottom];
|
|
97
102
|
}
|
|
98
103
|
|
|
99
104
|
const pointer = (on) => (on ? S.cyan('❯') : ' ');
|
|
105
|
+
// One line per choice, its note beside it; when one note does not fit there, every
|
|
106
|
+
// note goes under its choice. `at` is the line of the choice under the cursor.
|
|
100
107
|
function radio(options, cursor) {
|
|
108
|
+
const w = contentWidth();
|
|
101
109
|
const col = Math.min(LABEL_MAX, Math.max(...options.map((o) => width(o.label))) + 3);
|
|
102
|
-
|
|
110
|
+
const below = options.some((o) => o.note && 4 + col + width(o.note) > w);
|
|
111
|
+
const lines = [];
|
|
112
|
+
options.forEach((o, i) => {
|
|
103
113
|
const on = i === cursor;
|
|
104
|
-
const
|
|
105
|
-
|
|
114
|
+
const tone = (s) => (o.tone ? S[o.tone](s) : S.dim(s));
|
|
115
|
+
const head = ` ${pointer(on)} ${on ? S.cyan('●') : S.dim('○')} `;
|
|
116
|
+
if (on) lines.at = lines.length;
|
|
117
|
+
if (!o.note) lines.push(head + (on ? S.bold(o.label) : o.label));
|
|
118
|
+
else if (!below) lines.push(head + cell(on ? S.bold(o.label) : o.label, col) + tone(o.note));
|
|
119
|
+
else lines.push(head + (on ? S.bold(o.label) : o.label), ...wrap(o.note, w - 4).map((l) => ' ' + tone(l)));
|
|
106
120
|
});
|
|
121
|
+
return lines;
|
|
107
122
|
}
|
|
108
123
|
|
|
109
124
|
function box(state) {
|
|
@@ -128,11 +143,13 @@ function runSetup({
|
|
|
128
143
|
{ label: t('start.nothing'), note: t('start.nothingNote') },
|
|
129
144
|
{ label: t('start.everything'), note: t('start.everythingNote'), tone: 'yellow' },
|
|
130
145
|
];
|
|
131
|
-
const
|
|
132
|
-
const
|
|
146
|
+
const w = contentWidth();
|
|
147
|
+
const choices = radio(opts, st.cursor.start);
|
|
148
|
+
const body = [...choices, '', ...wrap(t('start.help'), w).map((l) => ' ' + S.dim(l))];
|
|
133
149
|
if (initial.length) body.push('', ' ' + S.dim(t('start.now')), ...initial.slice(0, 4).map((r) => ` ${S.green('◼')} ${show(r)}`), ...(initial.length > 4 ? [' …'] : []));
|
|
134
|
-
|
|
135
|
-
|
|
150
|
+
const again = 'npx @tensor.chat/companion setup';
|
|
151
|
+
body.push('', ...(width(t('start.later')) + 1 + again.length <= w ? [' ' + S.dim(t('start.later')) + ' ' + S.cyan(again)] : [' ' + S.dim(t('start.later')), ' ' + S.cyan(again)]));
|
|
152
|
+
return frame({ title: t('start.title'), body, focus: choices.at, keys: [['↑↓', K.move], [N.enter, K.select], [N.esc, K.quit]] });
|
|
136
153
|
}
|
|
137
154
|
|
|
138
155
|
function placeRows() {
|
|
@@ -168,7 +185,8 @@ function runSetup({
|
|
|
168
185
|
function placesView() {
|
|
169
186
|
const rows = placeRows();
|
|
170
187
|
const cur = Math.min(st.cursor.places, rows.length - 1);
|
|
171
|
-
const
|
|
188
|
+
const name = (r) => layout.shorten(show(r.path), contentWidth() - 4);
|
|
189
|
+
const labels = rows.filter((r) => r.type === 'place').map((r) => width(name(r)));
|
|
172
190
|
const col = Math.min(LABEL_MAX, Math.max(12, ...labels) + 3);
|
|
173
191
|
const body = [];
|
|
174
192
|
let focus = 0;
|
|
@@ -180,8 +198,10 @@ function runSetup({
|
|
|
180
198
|
if (on) focus = body.length;
|
|
181
199
|
if (r.type === 'place') {
|
|
182
200
|
const state = tickState(r.path, st.selected, platform);
|
|
183
|
-
const label = on ? S.bold(
|
|
184
|
-
|
|
201
|
+
const label = on ? S.bold(name(r)) : name(r);
|
|
202
|
+
const note = placeNote(r, state);
|
|
203
|
+
if (4 + Math.max(col, width(label) + 2) + width(note) <= contentWidth()) body.push(` ${pointer(on)} ${box(state)} ${cell(label, col)}${note}`);
|
|
204
|
+
else body.push(` ${pointer(on)} ${box(state)} ${label}`, ...wrap(note, contentWidth() - 4).map((l) => ' ' + l));
|
|
185
205
|
} else if (r.type === 'continue') {
|
|
186
206
|
body.push(` ${pointer(on)} ${on ? S.bold(S.cyan(t('places.continue') + ' →')) : S.cyan(t('places.continue') + ' →')}`);
|
|
187
207
|
} else {
|
|
@@ -240,21 +260,26 @@ function runSetup({
|
|
|
240
260
|
if (isRoot) text.push(S.red(t('everything.root')));
|
|
241
261
|
text.push('', S.yellow(t('everything.free')));
|
|
242
262
|
const body = [...panel(text, 'yellow'), ''];
|
|
243
|
-
|
|
244
|
-
|
|
263
|
+
const choices = radio([{ label: t('everything.no') }, { label: t('everything.yes'), tone: 'yellow' }], st.cursor.everything);
|
|
264
|
+
const focus = body.length + choices.at;
|
|
265
|
+
body.push(...choices);
|
|
266
|
+
return frame({ title: `${S.yellow('▲')} ${t('everything.title')}`, body, focus, keys: [['↑↓', K.move], [N.enter, K.select], [N.esc, K.back]] });
|
|
245
267
|
}
|
|
246
268
|
|
|
247
269
|
function shellOptions() {
|
|
248
270
|
const quiet = t('shell.noNote');
|
|
249
271
|
const list = shellUntil
|
|
250
|
-
? [{ id: 'keep', label: t('shell.keep'), note: t('shell.keepNote', { date: t.date(shellUntil) }) }, { id: 'off', label: t('shell.off'), note:
|
|
272
|
+
? [{ id: 'keep', label: t('shell.keep'), note: t('shell.keepNote', { date: t.date(shellUntil) }) }, { id: 'off', label: t('shell.off'), note: t('shell.offNote') }]
|
|
251
273
|
: [{ id: 'no', label: t('shell.no'), note: quiet }];
|
|
252
274
|
return [...list, { id: 7, label: t('shell.d7') }, { id: 30, label: t('shell.d30') }, { id: 365, label: t('shell.d365'), tone: 'yellow' }];
|
|
253
275
|
}
|
|
254
276
|
|
|
255
277
|
function shellView() {
|
|
256
|
-
const body = [...panel([t('shell.body', { user: user || '?' })]), ''
|
|
257
|
-
|
|
278
|
+
const body = [...panel([t('shell.body', { user: user || '?' })]), ''];
|
|
279
|
+
const choices = radio(shellOptions(), st.cursor.shell);
|
|
280
|
+
const focus = body.length + choices.at;
|
|
281
|
+
body.push(...choices);
|
|
282
|
+
return frame({ title: t('shell.title'), body, focus, keys: [['↑↓', K.move], [N.enter, K.select], [N.esc, K.back]] });
|
|
258
283
|
}
|
|
259
284
|
|
|
260
285
|
function changes() {
|