hmgr 0.0.28 → 0.0.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter/claude-code.js +4 -4
- package/dist/adapter/git.js +36 -1
- package/dist/adapter/wsl.js +4 -2
- package/dist/adapter/zeitlimit.js +14 -0
- package/dist/gui/hmgr-cli.js +3 -3
- package/package.json +1 -1
|
@@ -9,6 +9,7 @@ import { LokalerZugriff } from "./dateisystem.js";
|
|
|
9
9
|
import { gitignoreEintragen, istGitRepo } from "./gitignore.js";
|
|
10
10
|
import { arbeitsverzeichnisVerbinden, heimVerbinden, nurHome } from "./heime.js";
|
|
11
11
|
import { tiefGleich } from "./vergleich.js";
|
|
12
|
+
import { mitZeitlimit } from "./zeitlimit.js";
|
|
12
13
|
const CLAUDE_VERZEICHNIS = '.claude';
|
|
13
14
|
const SKILLS_ORDNER = 'skills';
|
|
14
15
|
/**
|
|
@@ -34,8 +35,8 @@ const GITIGNORE_ZEILE = '.claude/';
|
|
|
34
35
|
/**
|
|
35
36
|
* Standard-Ausführer: `claude` vom PATH. Ein Fehlschlag wird zum Code, nicht zur Ausnahme.
|
|
36
37
|
* stdin ist zu, sonst hängt eine CLI, die auf Eingabe wartet, den ganzen Ablauf; der Timeout
|
|
37
|
-
* fängt alles Übrige (beobachtet: 13 Minuten ohne Rückkehr in der GUI)
|
|
38
|
-
*
|
|
38
|
+
* fängt alles Übrige (beobachtet: 13 Minuten ohne Rückkehr in der GUI), selbst gesetzt statt
|
|
39
|
+
* über die spawn-Option (E98, siehe `mitZeitlimit`).
|
|
39
40
|
*
|
|
40
41
|
* `spawn` kommt von cross-spawn, nicht aus node:child_process (E65/B7): unter Windows ist die
|
|
41
42
|
* npm-installierte `claude` ein `.cmd`-Shim, und Node startet `.cmd`/`.bat` seit dem Fix zu
|
|
@@ -48,9 +49,8 @@ export const claudeAusfuehrer = (args, cwd) => new Promise((aufloesen) => {
|
|
|
48
49
|
const kind = spawn('claude', args, {
|
|
49
50
|
...(cwd === undefined ? {} : { cwd }),
|
|
50
51
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
51
|
-
timeout: 120_000,
|
|
52
|
-
killSignal: 'SIGKILL',
|
|
53
52
|
});
|
|
53
|
+
mitZeitlimit(kind, 120_000);
|
|
54
54
|
let stdout = '';
|
|
55
55
|
let stderr = '';
|
|
56
56
|
// `!`, weil cross-spawn nur den allgemeinen ChildProcess-Typ mit nullbaren Strömen kennt;
|
package/dist/adapter/git.js
CHANGED
|
@@ -121,10 +121,39 @@ async function dateienAufPlatte(wurzel, unter = '') {
|
|
|
121
121
|
}
|
|
122
122
|
return dateien;
|
|
123
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* Wartezeiten zwischen den Versuchen bei belegter git-Sperre (E99): 5 Versuche, zusammen rund 3 s.
|
|
126
|
+
* Tests übergeben kürzere über den Konstruktor.
|
|
127
|
+
*/
|
|
128
|
+
export const SPERRE_WARTEZEITEN_MS = [200, 400, 800, 1600];
|
|
129
|
+
/** Meldung, mit der git eine belegte Sperrdatei anzeigt (E99). */
|
|
130
|
+
const SPERRE_BELEGT = /Unable to create '[^']+\.lock': File exists/;
|
|
124
131
|
export class GitQuellen {
|
|
125
132
|
wurzel;
|
|
126
|
-
|
|
133
|
+
sperreWartezeitenMs;
|
|
134
|
+
constructor(wurzel, optionen = {}) {
|
|
127
135
|
this.wurzel = wurzel;
|
|
136
|
+
this.sperreWartezeitenMs = optionen.sperreWartezeitenMs ?? SPERRE_WARTEZEITEN_MS;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Wiederholt einen git-Aufruf, wenn eine fremde Sperre ihn blockiert (E99): GUI-Aktionen und der
|
|
140
|
+
* Start-Lauf rufen git parallel auf, und git bricht bei `….lock: File exists` sofort ab. Nur
|
|
141
|
+
* diese Meldung wird wiederholt, jeder andere Fehler gilt sofort. Nach dem letzten Versuch bleibt
|
|
142
|
+
* die bisherige Fehlermeldung. hmgr löscht fremde Sperren nie, auch keine verwaisten.
|
|
143
|
+
*/
|
|
144
|
+
async mitSperrWiederholung(aufruf) {
|
|
145
|
+
for (let versuch = 0;; versuch++) {
|
|
146
|
+
try {
|
|
147
|
+
return await aufruf();
|
|
148
|
+
}
|
|
149
|
+
catch (fehler) {
|
|
150
|
+
const wartezeit = this.sperreWartezeitenMs[versuch];
|
|
151
|
+
const meldung = fehler instanceof Error ? fehler.message : String(fehler);
|
|
152
|
+
if (wartezeit === undefined || !SPERRE_BELEGT.test(meldung))
|
|
153
|
+
throw fehler;
|
|
154
|
+
await new Promise((fertig) => setTimeout(fertig, wartezeit));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
128
157
|
}
|
|
129
158
|
/**
|
|
130
159
|
* stdin ist zu und git darf nicht nach Zugangsdaten fragen, sonst hängt ein wartender Aufruf
|
|
@@ -132,6 +161,9 @@ export class GitQuellen {
|
|
|
132
161
|
* als dort, ein erster Clone über ein langsames Netz braucht Zeit.
|
|
133
162
|
*/
|
|
134
163
|
async git(args, cwd) {
|
|
164
|
+
return await this.mitSperrWiederholung(() => this.gitEinmal(args, cwd));
|
|
165
|
+
}
|
|
166
|
+
async gitEinmal(args, cwd) {
|
|
135
167
|
return await new Promise((erfuellen, ablehnen) => {
|
|
136
168
|
const kind = spawn('git', args, {
|
|
137
169
|
cwd,
|
|
@@ -155,6 +187,9 @@ export class GitQuellen {
|
|
|
155
187
|
}
|
|
156
188
|
/** Wie `git`, aber mit Text auf stdin und Bytes als Ergebnis: `execFile` kennt keine Eingabe. */
|
|
157
189
|
async gitMitEingabe(args, cwd, eingabe) {
|
|
190
|
+
return await this.mitSperrWiederholung(() => this.gitMitEingabeEinmal(args, cwd, eingabe));
|
|
191
|
+
}
|
|
192
|
+
async gitMitEingabeEinmal(args, cwd, eingabe) {
|
|
158
193
|
return await new Promise((erfuellen, ablehnen) => {
|
|
159
194
|
const kind = spawn('git', args, { cwd, timeout: 300_000, killSignal: 'SIGKILL' });
|
|
160
195
|
const stuecke = [];
|
package/dist/adapter/wsl.js
CHANGED
|
@@ -4,13 +4,15 @@
|
|
|
4
4
|
import spawn from 'cross-spawn';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { WslBrueckeFehlgeschlagen } from "../kern/modell.js";
|
|
7
|
+
import { mitZeitlimit } from "./zeitlimit.js";
|
|
7
8
|
/**
|
|
8
9
|
* Standard-Ausführer: `wsl.exe` vom PATH, über cross-spawn wie die claude-CLI (E65/B7). stdin ist
|
|
9
|
-
* zu, sonst hängt eine Distro, die auf Eingabe wartet; der Timeout fängt alles Übrige. Ein
|
|
10
|
+
* zu, sonst hängt eine Distro, die auf Eingabe wartet; der Timeout (E98, `mitZeitlimit`) fängt alles Übrige. Ein
|
|
10
11
|
* Fehlschlag wird zum Code, nicht zur Ausnahme.
|
|
11
12
|
*/
|
|
12
13
|
export const wslAusfuehrer = (args) => new Promise((aufloesen) => {
|
|
13
|
-
const kind = spawn('wsl.exe', args, { stdio: ['ignore', 'pipe', 'pipe']
|
|
14
|
+
const kind = spawn('wsl.exe', args, { stdio: ['ignore', 'pipe', 'pipe'] });
|
|
15
|
+
mitZeitlimit(kind, 60_000);
|
|
14
16
|
const teile = [];
|
|
15
17
|
const fehlerTeile = [];
|
|
16
18
|
kind.stdout.on('data', (d) => teile.push(d));
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zeitlimit für einen mit cross-spawn gestarteten Prozess (E98). Statt der spawn-Option `timeout`
|
|
3
|
+
* setzen wir den Wecker selbst: Node räumt dessen Timer im `exit`-Handler ab, cross-spawn ersetzt
|
|
4
|
+
* unter Windows aber das `exit` eines nicht gefundenen Programms durch ein `error`. Der Timer
|
|
5
|
+
* bliebe stehen und hielte den Prozess bis zum Ablauf am Leben (gemessen: 120 s ohne `claude`).
|
|
6
|
+
* Abgeräumt wird deshalb bei `close` und bei `error`. Bei Ablauf SIGKILL, weil CLIs SIGTERM
|
|
7
|
+
* überleben können; der Aufrufer sieht dann wie bisher `close` mit Code `null`.
|
|
8
|
+
*/
|
|
9
|
+
export function mitZeitlimit(kind, ms) {
|
|
10
|
+
const wecker = setTimeout(() => kind.kill('SIGKILL'), ms);
|
|
11
|
+
const abraeumen = () => clearTimeout(wecker);
|
|
12
|
+
kind.once('close', abraeumen);
|
|
13
|
+
kind.once('error', abraeumen);
|
|
14
|
+
}
|
package/dist/gui/hmgr-cli.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import spawn from 'cross-spawn';
|
|
7
|
+
import { mitZeitlimit } from "../adapter/zeitlimit.js";
|
|
7
8
|
import { versionLesen } from "../kern/version.js";
|
|
8
9
|
/**
|
|
9
10
|
* Zeigt der aufgelöste Treffer auf die laufende GUI selbst (E97)? Deren Electron-exe heißt ebenfalls
|
|
@@ -25,8 +26,6 @@ export function istEigeneGui(aufgeloest, execPath, plattform) {
|
|
|
25
26
|
export function cliSpawnOptionen(heim = homedir()) {
|
|
26
27
|
return {
|
|
27
28
|
stdio: ['ignore', 'pipe', 'ignore'],
|
|
28
|
-
timeout: 10_000,
|
|
29
|
-
killSignal: 'SIGKILL',
|
|
30
29
|
cwd: heim,
|
|
31
30
|
};
|
|
32
31
|
}
|
|
@@ -45,7 +44,7 @@ function aufgeloesterPfad(optionen) {
|
|
|
45
44
|
*
|
|
46
45
|
* `spawn` von cross-spawn wie im claude-Adapter (E65/B7): unter Windows ist die npm-installierte
|
|
47
46
|
* `hmgr` ein `.cmd`-Shim, das Node seit dem Fix zu CVE-2024-27980 ohne Umweg über cmd.exe nicht
|
|
48
|
-
* mehr startet. stdin zu und ein Timeout, damit nichts hängen bleibt — ein Timeout liefert `fehlt`
|
|
47
|
+
* mehr startet. stdin zu und ein Timeout (E98, `mitZeitlimit`), damit nichts hängen bleibt — ein Timeout liefert `fehlt`
|
|
49
48
|
* (cross-spawn beendet den Prozess dann mit `close` und `null`-Code samt Signal, kein `error`).
|
|
50
49
|
*/
|
|
51
50
|
export function hmgrCliVersion() {
|
|
@@ -63,6 +62,7 @@ export function hmgrCliVersion() {
|
|
|
63
62
|
return melden({ art: 'fehlt' });
|
|
64
63
|
}
|
|
65
64
|
const kind = spawn('hmgr', ['--version'], optionen);
|
|
65
|
+
mitZeitlimit(kind, 10_000);
|
|
66
66
|
let stdout = '';
|
|
67
67
|
kind.stdout.on('data', (stueck) => (stdout += stueck));
|
|
68
68
|
kind.on('error', () => melden({ art: 'fehlt' }));
|