@arkvenai/cli 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -242
- package/dist/befehle.js +138 -77
- package/dist/index.js +63 -334
- package/dist/projekt.js +121 -0
- package/dist/ruf.js +45 -0
- package/dist/uebertragen.js +185 -0
- package/dist/zugang.js +114 -0
- package/package.json +7 -39
- package/CHANGELOG.md +0 -105
- package/dist/agents.d.ts +0 -11
- package/dist/agents.d.ts.map +0 -1
- package/dist/agents.js +0 -76
- package/dist/agents.js.map +0 -1
- package/dist/auftrag.d.ts +0 -3
- package/dist/auftrag.d.ts.map +0 -1
- package/dist/auftrag.js +0 -45
- package/dist/auftrag.js.map +0 -1
- package/dist/bauplan.d.ts +0 -15
- package/dist/bauplan.d.ts.map +0 -1
- package/dist/bauplan.js +0 -219
- package/dist/bauplan.js.map +0 -1
- package/dist/befehle.d.ts +0 -12
- package/dist/befehle.d.ts.map +0 -1
- package/dist/befehle.js.map +0 -1
- package/dist/befund.d.ts +0 -21
- package/dist/befund.d.ts.map +0 -1
- package/dist/befund.js +0 -107
- package/dist/befund.js.map +0 -1
- package/dist/codeAblage.d.ts +0 -31
- package/dist/codeAblage.d.ts.map +0 -1
- package/dist/codeAblage.js +0 -80
- package/dist/codeAblage.js.map +0 -1
- package/dist/deklaration.d.ts +0 -3
- package/dist/deklaration.d.ts.map +0 -1
- package/dist/deklaration.js +0 -14
- package/dist/deklaration.js.map +0 -1
- package/dist/diff.d.ts +0 -10
- package/dist/diff.d.ts.map +0 -1
- package/dist/diff.js +0 -72
- package/dist/diff.js.map +0 -1
- package/dist/erkennung.d.ts +0 -26
- package/dist/erkennung.d.ts.map +0 -1
- package/dist/erkennung.js +0 -174
- package/dist/erkennung.js.map +0 -1
- package/dist/fix.d.ts +0 -26
- package/dist/fix.d.ts.map +0 -1
- package/dist/fix.js +0 -101
- package/dist/fix.js.map +0 -1
- package/dist/geteilt/bauplan/form.d.ts +0 -100
- package/dist/geteilt/bauplan/form.d.ts.map +0 -1
- package/dist/geteilt/bauplan/form.js +0 -21
- package/dist/geteilt/bauplan/form.js.map +0 -1
- package/dist/geteilt/bauplan/index.d.ts +0 -4
- package/dist/geteilt/bauplan/index.d.ts.map +0 -1
- package/dist/geteilt/bauplan/index.js +0 -4
- package/dist/geteilt/bauplan/index.js.map +0 -1
- package/dist/geteilt/bauplan/lesen.d.ts +0 -6
- package/dist/geteilt/bauplan/lesen.d.ts.map +0 -1
- package/dist/geteilt/bauplan/lesen.js +0 -344
- package/dist/geteilt/bauplan/lesen.js.map +0 -1
- package/dist/geteilt/bauplan/schreiben.d.ts +0 -3
- package/dist/geteilt/bauplan/schreiben.d.ts.map +0 -1
- package/dist/geteilt/bauplan/schreiben.js +0 -80
- package/dist/geteilt/bauplan/schreiben.js.map +0 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/init.d.ts +0 -28
- package/dist/init.d.ts.map +0 -1
- package/dist/init.js +0 -324
- package/dist/init.js.map +0 -1
- package/dist/login.d.ts +0 -45
- package/dist/login.d.ts.map +0 -1
- package/dist/login.js +0 -162
- package/dist/login.js.map +0 -1
- package/dist/mcp.d.ts +0 -18
- package/dist/mcp.d.ts.map +0 -1
- package/dist/mcp.js +0 -115
- package/dist/mcp.js.map +0 -1
- package/dist/neu.d.ts +0 -17
- package/dist/neu.d.ts.map +0 -1
- package/dist/neu.js +0 -118
- package/dist/neu.js.map +0 -1
- package/dist/npmrc.d.ts +0 -9
- package/dist/npmrc.d.ts.map +0 -1
- package/dist/npmrc.js +0 -49
- package/dist/npmrc.js.map +0 -1
- package/dist/projekte.d.ts +0 -23
- package/dist/projekte.d.ts.map +0 -1
- package/dist/projekte.js +0 -82
- package/dist/projekte.js.map +0 -1
- package/dist/pull.d.ts +0 -15
- package/dist/pull.d.ts.map +0 -1
- package/dist/pull.js +0 -301
- package/dist/pull.js.map +0 -1
- package/dist/push/bericht.d.ts +0 -8
- package/dist/push/bericht.d.ts.map +0 -1
- package/dist/push/bericht.js +0 -85
- package/dist/push/bericht.js.map +0 -1
- package/dist/push/form.d.ts +0 -67
- package/dist/push/form.d.ts.map +0 -1
- package/dist/push/form.js +0 -6
- package/dist/push/form.js.map +0 -1
- package/dist/push/medien.d.ts +0 -7
- package/dist/push/medien.d.ts.map +0 -1
- package/dist/push/medien.js +0 -154
- package/dist/push/medien.js.map +0 -1
- package/dist/push/sammeln.d.ts +0 -34
- package/dist/push/sammeln.d.ts.map +0 -1
- package/dist/push/sammeln.js +0 -112
- package/dist/push/sammeln.js.map +0 -1
- package/dist/push/verzeichnisse.d.ts +0 -40
- package/dist/push/verzeichnisse.d.ts.map +0 -1
- package/dist/push/verzeichnisse.js +0 -158
- package/dist/push/verzeichnisse.js.map +0 -1
- package/dist/push.d.ts +0 -8
- package/dist/push.d.ts.map +0 -1
- package/dist/push.js +0 -306
- package/dist/push.js.map +0 -1
- package/dist/starter.d.ts +0 -4
- package/dist/starter.d.ts.map +0 -1
- package/dist/starter.js +0 -587
- package/dist/starter.js.map +0 -1
- package/dist/tiefpruefung.d.ts +0 -39
- package/dist/tiefpruefung.d.ts.map +0 -1
- package/dist/tiefpruefung.js +0 -56
- package/dist/tiefpruefung.js.map +0 -1
- package/dist/vertrag.d.ts +0 -6
- package/dist/vertrag.d.ts.map +0 -1
- package/dist/vertrag.js +0 -267
- package/dist/vertrag.js.map +0 -1
- package/dist/vertragSpaet.d.ts +0 -4
- package/dist/vertragSpaet.d.ts.map +0 -1
- package/dist/vertragSpaet.js +0 -158
- package/dist/vertragSpaet.js.map +0 -1
- package/dist/vorlagen.d.ts +0 -7
- package/dist/vorlagen.d.ts.map +0 -1
- package/dist/vorlagen.js +0 -83
- package/dist/vorlagen.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,352 +1,81 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
import { fahreNeu } from './neu.js';
|
|
11
|
-
import { richteBezugEin } from './npmrc.js';
|
|
12
|
-
import { fahrePush, leseArkvenDatei, sammleTeile } from './push.js';
|
|
13
|
-
import { alsBefunde, tiefPruefen } from './tiefpruefung.js';
|
|
14
|
-
const DEKLARATION = 'arkven.json';
|
|
15
|
-
import { fahrePull } from './pull.js';
|
|
16
|
-
import { deklarationsBefunde } from './deklaration.js';
|
|
17
|
-
import { pruefeAnker, pruefeMailArten } from './bauplan.js';
|
|
18
|
-
import { pruefeVertrag } from './vertrag.js';
|
|
19
|
-
import { BEFEHLE } from './befehle.js';
|
|
20
|
-
const VERSION = '0.5.1';
|
|
21
|
-
function gib(e, flags) {
|
|
22
|
-
if (flags.has('--sarif'))
|
|
23
|
-
return alsSarif(e, VERSION);
|
|
24
|
-
if (flags.has('--json'))
|
|
25
|
-
return alsJson(e);
|
|
26
|
-
return alsText(e);
|
|
27
|
-
}
|
|
28
|
-
function umbrich(einzug, text, breite = 98) {
|
|
29
|
-
const folgeEinzug = ' '.repeat(einzug.length);
|
|
30
|
-
const zeilen = [];
|
|
31
|
-
let laufend = einzug;
|
|
32
|
-
for (const wort of text.split(' ')) {
|
|
33
|
-
if (laufend.trimEnd().length > einzug.length && laufend.length + 1 + wort.length > breite) {
|
|
34
|
-
zeilen.push(laufend);
|
|
35
|
-
laufend = folgeEinzug + wort;
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
laufend = laufend.trimEnd().length === einzug.trimEnd().length && laufend.endsWith(' ')
|
|
39
|
-
? laufend + wort
|
|
40
|
-
: laufend + ' ' + wort;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
zeilen.push(laufend);
|
|
44
|
-
return zeilen;
|
|
45
|
-
}
|
|
46
|
-
function befehlsZeilen(namen) {
|
|
47
|
-
const zeilen = [];
|
|
48
|
-
for (const name of namen) {
|
|
49
|
-
const b = BEFEHLE.find((x) => x.name === name);
|
|
50
|
-
if (!b)
|
|
51
|
-
continue;
|
|
52
|
-
const kopf = ` arkven ${b.name}${b.stelle ? ' ' + b.stelle : ''}`;
|
|
53
|
-
zeilen.push(...umbrich(kopf.padEnd(30), b.wirkung));
|
|
54
|
-
for (const s of b.schalter)
|
|
55
|
-
zeilen.push(...umbrich(` ${s.flagge.padEnd(26)}`, s.wirkung));
|
|
56
|
-
}
|
|
57
|
-
return zeilen.join(String.fromCharCode(10));
|
|
58
|
-
}
|
|
59
|
-
const HILFE = `arkven ${VERSION} - eigene Projekte auf Arkven
|
|
2
|
+
import { login, status, umgebung } from './befehle.js';
|
|
3
|
+
import { live, pull, push } from './uebertragen.js';
|
|
4
|
+
/**
|
|
5
|
+
* Die Befehlsverteilung. Sie tut selbst nichts, ausser Argumente zu lesen und den
|
|
6
|
+
* richtigen Befehl zu rufen: was hier an Logik stuende, waere an einem Ort, an dem sie
|
|
7
|
+
* niemand vermutet.
|
|
8
|
+
*/
|
|
9
|
+
const HILFE = `arkven -- dein Arkven auf diesem Rechner
|
|
60
10
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
2. arkven pull zeigt deine Projekte, du wählst die Nummer
|
|
64
|
-
3. Änderungen machen
|
|
65
|
-
4. arkven push Vorschau ansehen und bestätigen
|
|
66
|
-
5. arkven push --deploy online stellen
|
|
11
|
+
arkven login [--server=<adresse>] [--umgebung=<name>]
|
|
12
|
+
Diesen Rechner anmelden. Du bestaetigst im Browser.
|
|
67
13
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
2. arkven init schreibt arkven.json
|
|
71
|
-
3. arkven push --name="Mein Tool" legt das Projekt in Arkven an
|
|
72
|
-
4. arkven push --deploy online stellen
|
|
14
|
+
arkven status [--umgebung=<name>]
|
|
15
|
+
Wer du bist, welche Umgebung gilt, welche Apps es gibt.
|
|
73
16
|
|
|
74
|
-
|
|
17
|
+
arkven umgebung [<name>] [--weg=<name>]
|
|
18
|
+
Ohne Namen: alle angemeldeten Umgebungen, die aktive mit einem Stern.
|
|
19
|
+
Mit Namen: diese wird aktiv.
|
|
75
20
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
${befehlsZeilen(['push'])}
|
|
21
|
+
arkven pull [--app=<kennung>] [--ja]
|
|
22
|
+
Den Quelltext einer App in diesen Ordner holen. Ohne --ja nur die Vorschau.
|
|
79
23
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
Dann sammelt push beide Teile und schickt sie getrennt: das Frontend wird die Vorschau, der Server
|
|
83
|
-
geht in den Container. Ohne diese Angabe bleibt alles wie bisher.
|
|
84
|
-
${befehlsZeilen(['version', 'help'])}
|
|
24
|
+
arkven push [--betreff="..."] [--ja]
|
|
25
|
+
Den Quelltext von hier nach Arkven. Ohne --ja nur die Vorschau.
|
|
85
26
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
Rückgabewerte von new: 0 angelegt und nachgemessen - 1 abgebrochen, nichts angelegt.
|
|
89
|
-
Rückgabewerte von push: 0 übernommen - 1 etwas blockiert (Befund oder Konflikt) - 2 nichts messbar.
|
|
27
|
+
arkven live [--ja]
|
|
28
|
+
Die App live schalten. Ohne --ja nur der Hinweis, was passieren wuerde.
|
|
90
29
|
|
|
91
|
-
|
|
92
|
-
automatische Wahl würde eine der beiden Fassungen still verlieren.
|
|
93
|
-
|
|
94
|
-
${befehlsZeilen(['mcp'])}
|
|
30
|
+
Ueberall moeglich: --umgebung=<name>, wenn nicht die aktive gemeint ist.
|
|
95
31
|
`;
|
|
96
|
-
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
return vorschlag;
|
|
102
|
-
return antwort === 'j' || antwort === 'ja' || antwort === 'y' || antwort === 'yes';
|
|
103
|
-
}
|
|
104
|
-
finally {
|
|
105
|
-
rl.close();
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
async function frageTextImTerminal(text) {
|
|
109
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
110
|
-
try {
|
|
111
|
-
return (await rl.question(`\n${text}\n> `)).trim();
|
|
112
|
-
}
|
|
113
|
-
finally {
|
|
114
|
-
rl.close();
|
|
115
|
-
}
|
|
32
|
+
function flagge(argv, name) {
|
|
33
|
+
const mit = argv.find((a) => a.startsWith(`--${name}=`));
|
|
34
|
+
if (mit)
|
|
35
|
+
return mit.slice(name.length + 3);
|
|
36
|
+
return undefined;
|
|
116
37
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
const
|
|
120
|
-
const
|
|
121
|
-
const
|
|
122
|
-
const
|
|
123
|
-
...(typeof verz.server === 'string' ? { server: verz.server } : {}),
|
|
124
|
-
...(typeof verz.frontend === 'string' ? { frontend: verz.frontend } : {}),
|
|
125
|
-
});
|
|
126
|
-
const tief = await tiefPruefen(teile.app.sammlung.dateien, (teile.server ?? teile.app).sammlung.dateien);
|
|
127
|
-
if (!tief.erreichbar)
|
|
128
|
-
return befunde;
|
|
129
|
-
befunde.push(...alsBefunde(tief.ergebnis));
|
|
130
|
-
befunde.push(...pruefeMailArten(wurzel, tief.ergebnis.mailArten ?? []));
|
|
131
|
-
befunde.push(...pruefeAnker(teile.app.sammlung.dateien, tief.ergebnis.screens ?? []));
|
|
132
|
-
return befunde;
|
|
133
|
-
}
|
|
134
|
-
async function main(argv) {
|
|
135
|
-
const [befehl, ...rest] = argv;
|
|
136
|
-
const flags = new Set(rest.filter((a) => a.startsWith('--')));
|
|
137
|
-
const stellen = rest.filter((a) => !a.startsWith('--'));
|
|
38
|
+
const hat = (argv, name) => argv.includes(`--${name}`);
|
|
39
|
+
export async function fahre(argv, sage) {
|
|
40
|
+
const befehl = argv.find((a) => !a.startsWith('-')) ?? '';
|
|
41
|
+
const gemeinsam = { umgebung: flagge(argv, 'umgebung'), sage };
|
|
42
|
+
const bestaetigt = hat(argv, 'ja');
|
|
43
|
+
const wurzel = process.cwd();
|
|
138
44
|
switch (befehl) {
|
|
139
|
-
case '
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
case '
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
return e.code;
|
|
157
|
-
}
|
|
158
|
-
case 'check': {
|
|
159
|
-
const wurzel = path.resolve(stellen[0] ?? process.cwd());
|
|
160
|
-
const ergebnis = pruefeVertrag(wurzel);
|
|
161
|
-
ergebnis.befunde.push(...deklarationsBefunde(wurzel));
|
|
162
|
-
if (flags.has('--tief')) {
|
|
163
|
-
const datei = leseArkvenDatei(wurzel);
|
|
164
|
-
const v = datei['verzeichnisse'];
|
|
165
|
-
const verz = v && typeof v === 'object' && !Array.isArray(v) ? v : {};
|
|
166
|
-
const teile = sammleTeile(wurzel, {
|
|
167
|
-
...(typeof verz.server === 'string' ? { server: verz.server } : {}),
|
|
168
|
-
...(typeof verz.frontend === 'string' ? { frontend: verz.frontend } : {}),
|
|
169
|
-
});
|
|
170
|
-
const serverBaum = (teile.server ?? teile.app).sammlung.dateien;
|
|
171
|
-
const appBaum = teile.app.sammlung.dateien;
|
|
172
|
-
if (!appBaum.some((d) => d.pfad === DEKLARATION)) {
|
|
173
|
-
let ordner = wurzel;
|
|
174
|
-
for (let i = 0; i < 3; i++) {
|
|
175
|
-
try {
|
|
176
|
-
const inhalt = fs.readFileSync(path.join(ordner, DEKLARATION), 'utf8');
|
|
177
|
-
appBaum.push({ pfad: DEKLARATION, inhalt });
|
|
178
|
-
if (ordner !== wurzel)
|
|
179
|
-
console.log(`Deklaration aus ${ordner} gelesen (sie beschreibt das ganze Projekt).`);
|
|
180
|
-
break;
|
|
181
|
-
}
|
|
182
|
-
catch {
|
|
183
|
-
const oben = path.dirname(ordner);
|
|
184
|
-
if (oben === ordner)
|
|
185
|
-
break;
|
|
186
|
-
ordner = oben;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
console.log('Die Gates der Plattform laufen mit (dieselbe Prüfung wie beim Ausrollen) …');
|
|
191
|
-
const tief = await tiefPruefen(appBaum, serverBaum);
|
|
192
|
-
if (tief.erreichbar) {
|
|
193
|
-
ergebnis.befunde.push(...alsBefunde(tief.ergebnis));
|
|
194
|
-
ergebnis.befunde.push(...pruefeMailArten(wurzel, tief.ergebnis.mailArten ?? []));
|
|
195
|
-
ergebnis.befunde.push(...pruefeAnker(appBaum, tief.ergebnis.screens ?? []));
|
|
196
|
-
for (const c of tief.ergebnis.checks)
|
|
197
|
-
if (c.ok)
|
|
198
|
-
ergebnis.gehalten.push(c.regel ?? c.name);
|
|
199
|
-
console.log(gib(ergebnis, flags));
|
|
200
|
-
for (const u of tief.ergebnis.ungeprueft)
|
|
201
|
-
console.log(`? nicht geprüft: ${u}`);
|
|
202
|
-
return exitCode(ergebnis);
|
|
203
|
-
}
|
|
204
|
-
ergebnis.befunde.push({
|
|
205
|
-
regel: 'arkven/plattform-gates',
|
|
206
|
-
schwere: 'ungeprueft',
|
|
207
|
-
titel: 'Die Gates der Plattform sind in diesem Lauf nicht mitgelaufen.',
|
|
208
|
-
ausweg: tief.grund,
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
console.log(gib(ergebnis, flags));
|
|
212
|
-
return exitCode(ergebnis);
|
|
213
|
-
}
|
|
214
|
-
case 'auftrag': {
|
|
215
|
-
const wurzel = path.resolve(stellen[0] ?? process.cwd());
|
|
216
|
-
const mitBauplan = pruefeVertrag(wurzel);
|
|
217
|
-
mitBauplan.befunde.push(...(await alleZusatzBefunde(wurzel)));
|
|
218
|
-
const auftrag = baueAuftrag(mitBauplan);
|
|
219
|
-
if (!auftrag) {
|
|
220
|
-
console.log('Es blockiert nichts, deshalb gibt es keinen Auftrag.');
|
|
221
|
-
return 0;
|
|
222
|
-
}
|
|
223
|
-
console.log(auftrag);
|
|
224
|
-
return 0;
|
|
225
|
-
}
|
|
226
|
-
case 'fix': {
|
|
227
|
-
const wurzel = path.resolve(stellen[0] ?? process.cwd());
|
|
228
|
-
const rundenArg = rest.find((a) => a.startsWith('--runden'));
|
|
229
|
-
const runden = Number(rundenArg?.split('=')[1] ?? rest[rest.indexOf('--runden') + 1] ?? 3);
|
|
230
|
-
if (!Number.isFinite(runden) || runden < 1 || runden > 10) {
|
|
231
|
-
console.error('`--runden` braucht eine Zahl zwischen 1 und 10.');
|
|
232
|
-
return 1;
|
|
233
|
-
}
|
|
234
|
-
console.log(`Claude Code bearbeitet gleich Dateien in ${wurzel}.`);
|
|
235
|
-
console.log('Datei-Änderungen werden dabei ohne Rückfrage übernommen - dafür hast du diesen Befehl aufgerufen.');
|
|
236
|
-
console.log('Alles andere bleibt hinter Claudes eigener Rückfrage. Es wird nichts committet und nichts gepusht.');
|
|
237
|
-
console.log('Sieh dir hinterher `git diff` an. Abbrechen mit Strg-C.\n');
|
|
238
|
-
const e = await fahreFix(wurzel, {
|
|
239
|
-
runden,
|
|
240
|
-
sage: (z) => console.log(z),
|
|
241
|
-
zusatzBefunde: () => alleZusatzBefunde(wurzel),
|
|
242
|
-
});
|
|
243
|
-
console.log('');
|
|
244
|
-
if (e.behoben.length > 0)
|
|
245
|
-
console.log(`Behoben und nachgemessen (${e.behoben.length}): ${e.behoben.join(', ')}`);
|
|
246
|
-
if (e.offen.length > 0)
|
|
247
|
-
console.log(`Weiterhin offen (${e.offen.length}): ${e.offen.join(', ')}`);
|
|
248
|
-
if (e.grund)
|
|
249
|
-
console.log(e.grund);
|
|
250
|
-
console.log(e.offen.length > 0
|
|
251
|
-
? '\nSieh dir die Änderungen an (`git diff`) und rufe danach `arkven check` erneut auf.'
|
|
252
|
-
: '\nSieh dir die Änderungen an (`git diff`). Nächster Schritt: `arkven push --deploy`.');
|
|
253
|
-
return e.offen.length > 0 ? 1 : 0;
|
|
254
|
-
}
|
|
255
|
-
case 'version':
|
|
256
|
-
case '--version':
|
|
257
|
-
case '-v':
|
|
258
|
-
console.log(VERSION);
|
|
259
|
-
return 0;
|
|
260
|
-
case undefined:
|
|
45
|
+
case 'login':
|
|
46
|
+
return (await login({ server: flagge(argv, 'server'), umgebung: flagge(argv, 'umgebung'), sage })).code;
|
|
47
|
+
case 'status':
|
|
48
|
+
return (await status(gemeinsam)).code;
|
|
49
|
+
case 'umgebung':
|
|
50
|
+
return umgebung({
|
|
51
|
+
name: argv.filter((a) => !a.startsWith('-'))[1],
|
|
52
|
+
weg: flagge(argv, 'weg'),
|
|
53
|
+
sage,
|
|
54
|
+
}).code;
|
|
55
|
+
case 'pull':
|
|
56
|
+
return (await pull(wurzel, { ...gemeinsam, app: flagge(argv, 'app'), bestaetigt })).code;
|
|
57
|
+
case 'push':
|
|
58
|
+
return (await push(wurzel, { ...gemeinsam, app: flagge(argv, 'app'), betreff: flagge(argv, 'betreff'), bestaetigt })).code;
|
|
59
|
+
case 'live':
|
|
60
|
+
return (await live(wurzel, { ...gemeinsam, app: flagge(argv, 'app'), bestaetigt })).code;
|
|
61
|
+
case '':
|
|
261
62
|
case 'help':
|
|
262
63
|
case '--help':
|
|
263
|
-
|
|
264
|
-
console.log(HILFE);
|
|
265
|
-
return 0;
|
|
266
|
-
case 'login': {
|
|
267
|
-
const serverArg = rest.find((a) => a.startsWith('--server='))?.split('=')[1];
|
|
268
|
-
let e;
|
|
269
|
-
if (flags.has('--einfuegen')) {
|
|
270
|
-
if (!process.stdin.isTTY) {
|
|
271
|
-
console.error('`--einfuegen` braucht ein Terminal, in das du den Wert einfügen kannst.');
|
|
272
|
-
console.error('So kommst du weiter: den Befehl direkt in einer Eingabeaufforderung ausführen.');
|
|
273
|
-
return 1;
|
|
274
|
-
}
|
|
275
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
276
|
-
const wert = await rl.question('\nWert von der Bestätigungsseite einfügen (beginnt mit arkv1_):\n> ');
|
|
277
|
-
rl.close();
|
|
278
|
-
e = nimmEinfuegeWert(wert);
|
|
279
|
-
}
|
|
280
|
-
else {
|
|
281
|
-
e = await fahreLogin({ server: serverArg, sage: (z) => console.log(z) });
|
|
282
|
-
}
|
|
283
|
-
if (e.code !== 0 || !e.zugang) {
|
|
284
|
-
console.error('');
|
|
285
|
-
console.error(e.grund ?? 'Die Anmeldung ist fehlgeschlagen.');
|
|
286
|
-
return e.code;
|
|
287
|
-
}
|
|
288
|
-
const bezug = richteBezugEin(e.zugang.server, e.zugang.registryToken, path.resolve(stellen[0] ?? process.cwd()));
|
|
289
|
-
const teams = e.zugang.teams ?? [];
|
|
290
|
-
console.log('');
|
|
291
|
-
console.log(` Angemeldet. Der Zugang gilt für ${teams.length} Team(s)${teams.length ? `: ${teams.map((t) => t.name).join(', ')}` : ''}.`);
|
|
292
|
-
console.log(` Er läuft in ${tageBis(e.zugang.laeuftAbAm.registry)} Tagen ab und ist jederzeit in den Konto-Einstellungen entziehbar.`);
|
|
293
|
-
console.log(` Gespeichert in ${zugangsDatei()}`);
|
|
294
|
-
console.log(` Paketbezug eingerichtet: ${bezug.projektDatei} (Zuordnung) und ${bezug.benutzerDatei} (Token)`);
|
|
295
|
-
console.log('');
|
|
296
|
-
console.log(' `npm install @arkvenai/base` funktioniert jetzt in diesem Projekt.');
|
|
297
|
-
console.log(' Nächster Schritt: `arkven check` prüft dein Projekt.');
|
|
64
|
+
sage(HILFE);
|
|
298
65
|
return 0;
|
|
299
|
-
}
|
|
300
|
-
case 'pull': {
|
|
301
|
-
const wurzel = path.resolve(stellen[0] ?? process.cwd());
|
|
302
|
-
const e = await fahrePull(wurzel, {
|
|
303
|
-
sage: (z) => console.log(z),
|
|
304
|
-
frage: process.stdin.isTTY ? (text) => frageImTerminal(text, false) : undefined,
|
|
305
|
-
ja: flags.has('--yes') || flags.has('--ja'),
|
|
306
|
-
server: rest.find((a) => a.startsWith('--server='))?.split('=')[1],
|
|
307
|
-
nurDeklaration: flags.has('--nur-deklaration'),
|
|
308
|
-
projektId: rest.find((a) => a.startsWith('--projekt='))?.split('=')[1],
|
|
309
|
-
frageText: process.stdin.isTTY ? (text) => frageTextImTerminal(text) : undefined,
|
|
310
|
-
});
|
|
311
|
-
if (e.grund) {
|
|
312
|
-
console.log('');
|
|
313
|
-
if (e.code === 0)
|
|
314
|
-
console.log(e.grund);
|
|
315
|
-
else
|
|
316
|
-
console.error(e.grund);
|
|
317
|
-
}
|
|
318
|
-
return e.code;
|
|
319
|
-
}
|
|
320
|
-
case 'push': {
|
|
321
|
-
const wurzel = path.resolve(stellen[0] ?? process.cwd());
|
|
322
|
-
const e = await fahrePush(wurzel, {
|
|
323
|
-
sage: (z) => console.log(z),
|
|
324
|
-
frage: process.stdin.isTTY ? (text) => frageImTerminal(text, false) : undefined,
|
|
325
|
-
frageText: process.stdin.isTTY ? (text) => frageTextImTerminal(text) : undefined,
|
|
326
|
-
ja: flags.has('--yes') || flags.has('--ja'),
|
|
327
|
-
deploy: flags.has('--deploy'),
|
|
328
|
-
server: rest.find((a) => a.startsWith('--server='))?.split('=')[1],
|
|
329
|
-
name: rest.find((a) => a.startsWith('--name='))?.split('=')[1],
|
|
330
|
-
team: rest.find((a) => a.startsWith('--team='))?.split('=')[1],
|
|
331
|
-
});
|
|
332
|
-
if (e.grund) {
|
|
333
|
-
console.log('');
|
|
334
|
-
if (e.code === 0)
|
|
335
|
-
console.log(e.grund);
|
|
336
|
-
else
|
|
337
|
-
console.error(e.grund);
|
|
338
|
-
}
|
|
339
|
-
return e.code;
|
|
340
|
-
}
|
|
341
|
-
case 'mcp': {
|
|
342
|
-
const { fahreMcp } = await import('./mcp.js');
|
|
343
|
-
return await fahreMcp();
|
|
344
|
-
}
|
|
345
66
|
default:
|
|
346
|
-
|
|
347
|
-
|
|
67
|
+
sage(`"${befehl}" kennt arkven nicht.`);
|
|
68
|
+
sage('');
|
|
69
|
+
sage(HILFE);
|
|
348
70
|
return 1;
|
|
349
71
|
}
|
|
350
72
|
}
|
|
351
|
-
|
|
352
|
-
|
|
73
|
+
// Nur ausfuehren, wenn dieses Modul der Einstieg ist -- die Probe importiert es.
|
|
74
|
+
if (process.argv[1] && import.meta.url.endsWith(process.argv[1].replace(/\\/g, '/').split('/').pop() ?? '')) {
|
|
75
|
+
fahre(process.argv.slice(2), (z) => console.log(z))
|
|
76
|
+
.then((code) => process.exit(code))
|
|
77
|
+
.catch((f) => {
|
|
78
|
+
console.error(f instanceof Error ? f.message : String(f));
|
|
79
|
+
process.exit(1);
|
|
80
|
+
});
|
|
81
|
+
}
|
package/dist/projekt.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
export const DATEI = 'arkven.json';
|
|
4
|
+
export function lesen(wurzel) {
|
|
5
|
+
try {
|
|
6
|
+
const j = JSON.parse(fs.readFileSync(path.join(wurzel, DATEI), 'utf8'));
|
|
7
|
+
return j.app ? { app: j.app, umgebung: j.umgebung, name: j.name } : null;
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function schreiben(wurzel, v) {
|
|
14
|
+
fs.writeFileSync(path.join(wurzel, DATEI), JSON.stringify(v, null, 2) + '\n', 'utf8');
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Was NICHT mitgeschickt wird.
|
|
18
|
+
*
|
|
19
|
+
* Auf dem Server entscheidet das git; hier gibt es kein git, auf das man sich verlassen
|
|
20
|
+
* koennte -- ein frisch gezogener Ordner hat keins. Diese Liste ist deshalb bewusst
|
|
21
|
+
* kurz und nennt nur, was ueberall dasselbe bedeutet. Alles andere geht mit: eine
|
|
22
|
+
* Datei, die jemand angelegt hat, gehoert ihm, und wir raten nicht, ob er sie meint.
|
|
23
|
+
*/
|
|
24
|
+
const NICHT_MIT = new Set([
|
|
25
|
+
'node_modules',
|
|
26
|
+
'.git',
|
|
27
|
+
'dist',
|
|
28
|
+
'build',
|
|
29
|
+
'.next',
|
|
30
|
+
'.turbo',
|
|
31
|
+
'.cache',
|
|
32
|
+
'coverage',
|
|
33
|
+
'.arkven',
|
|
34
|
+
]);
|
|
35
|
+
/**
|
|
36
|
+
* Dateien ohne Endung, die trotzdem Quelltext sind. Sie stehen in EINER Liste mit denen,
|
|
37
|
+
* die den Versteckt-Filter passieren duerfen: zwei Listen fuer dieselbe Frage waren der
|
|
38
|
+
* Fehler, den die Gegenprobe gefunden hat. Die .gitignore kam durch den einen Filter
|
|
39
|
+
* und blieb am anderen haengen, weil sie keine Endung hat.
|
|
40
|
+
*/
|
|
41
|
+
const BEKANNT_ALS_TEXT = new Set(['.gitignore', '.env.example', '.npmrc', 'Dockerfile', 'Procfile']);
|
|
42
|
+
/**
|
|
43
|
+
* Was sonst als Text lesbar ist. Bilder, Schriften und Videos gehen diesen Weg nicht:
|
|
44
|
+
* sie wuerden als kaputter Text ankommen, und das waere schlimmer als sie wegzulassen.
|
|
45
|
+
*/
|
|
46
|
+
const TEXT = /\.(tsx?|jsx?|mjs|cjs|css|scss|json|md|sql|html?|ya?ml|txt|svg)$/i;
|
|
47
|
+
function istText(name) {
|
|
48
|
+
return BEKANNT_ALS_TEXT.has(name) || TEXT.test(name);
|
|
49
|
+
}
|
|
50
|
+
/** Wieviel eine einzelne Datei hoechstens wiegt. Darueber ist es kein Quelltext mehr. */
|
|
51
|
+
const ZEICHEN_JE_DATEI = 400_000;
|
|
52
|
+
export function sammeln(wurzel) {
|
|
53
|
+
const dateien = [];
|
|
54
|
+
const uebersprungen = [];
|
|
55
|
+
const gehen = (ordner, praefix) => {
|
|
56
|
+
let eintraege;
|
|
57
|
+
try {
|
|
58
|
+
eintraege = fs.readdirSync(ordner, { withFileTypes: true });
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
for (const e of eintraege) {
|
|
64
|
+
if (NICHT_MIT.has(e.name))
|
|
65
|
+
continue;
|
|
66
|
+
// Versteckte Dateien bleiben draussen, bis auf die, die zum Projekt gehoeren -
|
|
67
|
+
// dieselbe Liste, die auch "ist das Text" beantwortet. Eine .env steht bewusst
|
|
68
|
+
// NICHT darin: dort liegen Geheimnisse, und die gehen keinen Push mit.
|
|
69
|
+
if (e.name.startsWith('.') && !BEKANNT_ALS_TEXT.has(e.name))
|
|
70
|
+
continue;
|
|
71
|
+
const relativ = praefix ? `${praefix}/${e.name}` : e.name;
|
|
72
|
+
const voll = path.join(ordner, e.name);
|
|
73
|
+
if (e.isDirectory()) {
|
|
74
|
+
gehen(voll, relativ);
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (!e.isFile())
|
|
78
|
+
continue;
|
|
79
|
+
if (relativ === DATEI)
|
|
80
|
+
continue;
|
|
81
|
+
if (!istText(e.name)) {
|
|
82
|
+
uebersprungen.push(relativ);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
let inhalt;
|
|
86
|
+
try {
|
|
87
|
+
inhalt = fs.readFileSync(voll, 'utf8');
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
uebersprungen.push(relativ);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (inhalt.length > ZEICHEN_JE_DATEI) {
|
|
94
|
+
uebersprungen.push(relativ);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
dateien.push({ pfad: relativ, inhalt });
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
gehen(wurzel, '');
|
|
101
|
+
return { dateien: dateien.sort((a, b) => a.pfad.localeCompare(b.pfad)), uebersprungen };
|
|
102
|
+
}
|
|
103
|
+
/** Die Grenze zwischen Oberflaeche und Server, dieselbe wie auf dem Server. */
|
|
104
|
+
export function istServerDatei(pfad) {
|
|
105
|
+
return pfad === 'server' || pfad.startsWith('server/');
|
|
106
|
+
}
|
|
107
|
+
export function schreibenAufPlatte(wurzel, dateien) {
|
|
108
|
+
let n = 0;
|
|
109
|
+
for (const d of dateien) {
|
|
110
|
+
// Derselbe Riegel wie auf dem Server, und aus demselben Grund: nachrechnen statt
|
|
111
|
+
// ein Muster gegen ".." legen. Was von aussen kommt, darf nicht ausserhalb des
|
|
112
|
+
// Ordners landen -- auch dann nicht, wenn es vom eigenen Server kommt.
|
|
113
|
+
const ziel = path.resolve(wurzel, d.pfad);
|
|
114
|
+
if (ziel !== wurzel && !ziel.startsWith(wurzel + path.sep))
|
|
115
|
+
continue;
|
|
116
|
+
fs.mkdirSync(path.dirname(ziel), { recursive: true });
|
|
117
|
+
fs.writeFileSync(ziel, d.inhalt, 'utf8');
|
|
118
|
+
n++;
|
|
119
|
+
}
|
|
120
|
+
return n;
|
|
121
|
+
}
|
package/dist/ruf.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
export async function ruf(server, weg, opts = {}) {
|
|
3
|
+
const adresse = `${server.replace(/\/+$/, '')}${weg}`;
|
|
4
|
+
try {
|
|
5
|
+
const res = await fetch(adresse, {
|
|
6
|
+
method: opts.methode ?? (opts.koerper ? 'POST' : 'GET'),
|
|
7
|
+
headers: {
|
|
8
|
+
...(opts.koerper ? { 'content-type': 'application/json' } : {}),
|
|
9
|
+
...(opts.token ? { authorization: `Bearer ${opts.token}` } : {}),
|
|
10
|
+
},
|
|
11
|
+
body: opts.koerper ? JSON.stringify(opts.koerper) : undefined,
|
|
12
|
+
});
|
|
13
|
+
const daten = (await res.json().catch(() => ({})));
|
|
14
|
+
if (!res.ok)
|
|
15
|
+
return { ok: false, status: res.status, daten };
|
|
16
|
+
return { ok: true, status: res.status, daten: daten };
|
|
17
|
+
}
|
|
18
|
+
catch (e) {
|
|
19
|
+
// Kein Netz ist kein HTTP-Fehler: Status 0 sagt dem Aufrufer, dass die Anfrage nie
|
|
20
|
+
// angekommen ist. Der Unterschied zaehlt - bei einem Push heisst das "es wurde
|
|
21
|
+
// nichts geaendert", bei einem 500 weiss man das nicht.
|
|
22
|
+
return { ok: false, status: 0, daten: {}, netz: String(e?.message ?? e) };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Der Satz, den ein Mensch aus einer Absage liest.
|
|
27
|
+
*
|
|
28
|
+
* Der Server schickt "fehler" und oft "ausweg". Beide gehoeren zusammen: ein Grund
|
|
29
|
+
* ohne Weg hinaus ist eine Sackgasse, und wer in einer Sackgasse steht, probiert
|
|
30
|
+
* dasselbe noch einmal.
|
|
31
|
+
*/
|
|
32
|
+
export function absage(a) {
|
|
33
|
+
if (a.ok)
|
|
34
|
+
return '';
|
|
35
|
+
if (a.netz)
|
|
36
|
+
return `Arkven war nicht erreichbar: ${a.netz}`;
|
|
37
|
+
const grund = String(a.daten.fehler ?? a.daten.error ?? `Arkven antwortete mit ${a.status}.`);
|
|
38
|
+
const ausweg = a.daten.ausweg ? `\n${String(a.daten.ausweg)}` : '';
|
|
39
|
+
return grund + ausweg;
|
|
40
|
+
}
|
|
41
|
+
export function neuesGeheimnis() {
|
|
42
|
+
const verifier = randomBytes(32).toString('base64url');
|
|
43
|
+
return { verifier, challenge: createHash('sha256').update(verifier).digest('base64url') };
|
|
44
|
+
}
|
|
45
|
+
export const schlafe = (ms) => new Promise((f) => setTimeout(f, ms));
|