raw fetch (#120) lädt nur ohne Login: kein Cookie, kein JavaScript. Für Paywall-Seiten bringt #120 die Option --html mit - der Mensch speichert die Seite aus seinem eingeloggten Browser, und raw fetch leitet daraus ab. Das reicht für den Einzelfall, verlangt aber pro Artikel Handarbeit am Desktop.
Ein Auth-Dienst, der Sessions hält und "URL rein, HTML raus" beantwortet, soll außerhalb dieses Stacks entstehen (Notizen dazu: #87). wikitool selbst bekommt keine Zugangsdaten, keine Login-Adapter und keine Headless-Browser-Abhängigkeit: Das Tool geht an jede Instanz, und Zugangsdaten haben im Arbeitsbaum nichts zu suchen (raw/CONTRACT.md § What does not belong here). Was fehlt, ist die Stelle, an der eine Instanz einen solchen Dienst einhängt.
Entwurf
Konfiguration .wikitool-fetch.json im Instanz-Root, gitignored, optional - gleiches Muster wie .wikitool-upload.json (Konstante in tools/chemenu/config.py, Eintrag in .gitignore, Ignore-Kanarie in docs verify, Zeile in doctor):
Ohne Datei verhält sich raw fetch exakt wie nach #120.
Auswahl: Der erste Eintrag, dessen hosts auf den Host der URL passt (exakt oder *.-Suffix), wird benutzt; sonst der eingebaute urllib-Abruf. Keine Kaskade: Schlägt der externe Befehl fehl, fällt raw fetchnicht auf den eingebauten Abruf zurück - der lieferte genau den Teaser, den der Fetcher vermeiden soll.
Protokoll mit dem Befehl: Aufruf als command + [url], ohne Shell (subprocess.run(list)). Exit 0 und HTML-Bytes auf stdout = Erfolg; alles andere = exit 1 von raw fetch, stderr des Befehls wird mit ausgegeben, nichts wird nach incoming/ geschrieben. Timeout und Größenlimit aus #120 gelten unverändert.
Ergebnis wie bei #120: dasselbe Bundle <stem>.html (stdout-Bytes unverändert) + <stem>.md. Im Header fetched_by: wikitool raw fetch (fetcher: <name>); http_status/final_url entfallen, weil der Befehl sie nicht liefert.
Wer die Datei schreibt: nur der Nutzer, nie ein Agent - sie benennt ein Programm, das wikitool ausführt. Dieselbe Haltung wie bei .wikitool-remotes.json; steht in raw/CONTRACT.md und im ON FAILURE-Text.
Nicht blockierend, beim Bau zu prüfen: Soll der Befehl optional einen Content-Type zurückgeben können (z. B. PDF hinter Login)? Wenn ein echter Dienst das braucht, als zweite Ausgabezeile auf stderr oder per JSON-Modus nachziehen; sonst nur HTML.
Betroffene Dateien
tools/chemenu/config.py, tools/chemenu/commands/raw_cmd.py bzw. das Modul aus #120 (web_capture.py), Kommando-Record von raw fetch
tools/chemenu/tests/test_raw_fetch.py - Fetcher als kleines Python-Skript im Testverzeichnis
raw/CONTRACT.md, tools/README.md
Akzeptanzkriterien
Ohne .wikitool-fetch.json erzeugt raw fetch byte-identische Ausgaben wie vorher (#120-Tests unverändert grün).
Mit einem passenden Eintrag ist incoming/<stem>.html byte-identisch mit dem stdout des Befehls, und der eingebaute Abruf wird nicht ausgeführt (Testserver erhält keinen Request).
Ein Befehl mit exit ≠ 0 führt zu exit 1, gibt dessen stderr aus und hinterlässt keine Datei in incoming/; der eingebaute Abruf wird nicht als Ersatz versucht.
Eine URL, deren Host auf keinen Eintrag passt, geht über den eingebauten Abruf.
.wikitool-fetch.json ist gitignored (docs verify-Kanarie), doctor meldet vorhanden/fehlt/fehlerhaft, ohne zu FAILen.
pytest, docs verify, instructions verify grün; CI grün.
Versionsteil
--minor - neue optionale Datei, die eine ältere Version ignoriert; ohne sie keine Verhaltensänderung. Drop-in in beide Richtungen.
Auslöser (prio/waiting)
Beides muss erfüllt sein:
#120 ist gebaut (dieses Issue erweitert dessen Kommando).
Ein Auth-Dienst nach #87 existiert und kann als Befehl aufgerufen werden. Vorher fehlt der Gegenpol zum Testen des Protokolls an einem echten Fall; das Protokoll (Punkt 3) wird dann gegen ihn geprüft und hier korrigiert, falls nötig.
## Problem
`raw fetch` (#120) lädt nur ohne Login: kein Cookie, kein JavaScript. Für Paywall-Seiten bringt #120 die Option `--html` mit - der Mensch speichert die Seite aus seinem eingeloggten Browser, und `raw fetch` leitet daraus ab. Das reicht für den Einzelfall, verlangt aber pro Artikel Handarbeit am Desktop.
Ein Auth-Dienst, der Sessions hält und "URL rein, HTML raus" beantwortet, soll außerhalb dieses Stacks entstehen (Notizen dazu: #87). `wikitool` selbst bekommt **keine** Zugangsdaten, keine Login-Adapter und keine Headless-Browser-Abhängigkeit: Das Tool geht an jede Instanz, und Zugangsdaten haben im Arbeitsbaum nichts zu suchen (`raw/CONTRACT.md` § What does not belong here). Was fehlt, ist die Stelle, an der eine Instanz einen solchen Dienst einhängt.
## Entwurf
1. **Konfiguration `.wikitool-fetch.json`** im Instanz-Root, gitignored, optional - gleiches Muster wie `.wikitool-upload.json` (Konstante in `tools/chemenu/config.py`, Eintrag in `.gitignore`, Ignore-Kanarie in `docs verify`, Zeile in `doctor`):
```json
{
"fetchers": [
{"name": "auth-proxy", "hosts": ["heise.de", "*.heise.de"], "command": ["/usr/local/bin/auth-fetch"]}
]
}
```
Ohne Datei verhält sich `raw fetch` exakt wie nach #120.
2. **Auswahl:** Der erste Eintrag, dessen `hosts` auf den Host der URL passt (exakt oder `*.`-Suffix), wird benutzt; sonst der eingebaute `urllib`-Abruf. Keine Kaskade: Schlägt der externe Befehl fehl, fällt `raw fetch` **nicht** auf den eingebauten Abruf zurück - der lieferte genau den Teaser, den der Fetcher vermeiden soll.
3. **Protokoll mit dem Befehl:** Aufruf als `command + [url]`, ohne Shell (`subprocess.run(list)`). Exit 0 und HTML-Bytes auf stdout = Erfolg; alles andere = exit 1 von `raw fetch`, stderr des Befehls wird mit ausgegeben, nichts wird nach `incoming/` geschrieben. Timeout und Größenlimit aus #120 gelten unverändert.
4. **Ergebnis wie bei #120:** dasselbe Bundle `<stem>.html` (stdout-Bytes unverändert) + `<stem>.md`. Im Header `fetched_by: wikitool raw fetch (fetcher: <name>)`; `http_status`/`final_url` entfallen, weil der Befehl sie nicht liefert.
5. **Wer die Datei schreibt:** nur der Nutzer, nie ein Agent - sie benennt ein Programm, das `wikitool` ausführt. Dieselbe Haltung wie bei `.wikitool-remotes.json`; steht in `raw/CONTRACT.md` und im ON FAILURE-Text.
6. **MCP bleibt außen vor** (wie #120 Entscheidung 12).
Nicht blockierend, beim Bau zu prüfen: Soll der Befehl optional einen Content-Type zurückgeben können (z. B. PDF hinter Login)? Wenn ein echter Dienst das braucht, als zweite Ausgabezeile auf stderr oder per JSON-Modus nachziehen; sonst nur HTML.
## Betroffene Dateien
- `tools/chemenu/config.py`, `tools/chemenu/commands/raw_cmd.py` bzw. das Modul aus #120 (`web_capture.py`), Kommando-Record von `raw fetch`
- `.gitignore`, `tools/chemenu/commands/docs_verify.py` (Ignore-Kanarie), `tools/chemenu/commands/doctor.py` (vorhanden/fehlt/kaputt)
- `tools/chemenu/tests/test_raw_fetch.py` - Fetcher als kleines Python-Skript im Testverzeichnis
- `raw/CONTRACT.md`, `tools/README.md`
## Akzeptanzkriterien
- [ ] Ohne `.wikitool-fetch.json` erzeugt `raw fetch` byte-identische Ausgaben wie vorher (#120-Tests unverändert grün).
- [ ] Mit einem passenden Eintrag ist `incoming/<stem>.html` byte-identisch mit dem stdout des Befehls, und der eingebaute Abruf wird nicht ausgeführt (Testserver erhält keinen Request).
- [ ] Ein Befehl mit exit ≠ 0 führt zu exit 1, gibt dessen stderr aus und hinterlässt keine Datei in `incoming/`; der eingebaute Abruf wird nicht als Ersatz versucht.
- [ ] Eine URL, deren Host auf keinen Eintrag passt, geht über den eingebauten Abruf.
- [ ] `.wikitool-fetch.json` ist gitignored (`docs verify`-Kanarie), `doctor` meldet vorhanden/fehlt/fehlerhaft, ohne zu FAILen.
- [ ] `pytest`, `docs verify`, `instructions verify` grün; CI grün.
## Versionsteil
**`--minor`** - neue optionale Datei, die eine ältere Version ignoriert; ohne sie keine Verhaltensänderung. Drop-in in beide Richtungen.
## Auslöser (`prio/waiting`)
Beides muss erfüllt sein:
1. #120 ist gebaut (dieses Issue erweitert dessen Kommando).
2. Ein Auth-Dienst nach #87 existiert und kann als Befehl aufgerufen werden. Vorher fehlt der Gegenpol zum Testen des Protokolls an einem echten Fall; das Protokoll (Punkt 3) wird dann gegen ihn geprüft und hier korrigiert, falls nötig.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
raw fetch(#120) lädt nur ohne Login: kein Cookie, kein JavaScript. Für Paywall-Seiten bringt #120 die Option--htmlmit - der Mensch speichert die Seite aus seinem eingeloggten Browser, undraw fetchleitet daraus ab. Das reicht für den Einzelfall, verlangt aber pro Artikel Handarbeit am Desktop.Ein Auth-Dienst, der Sessions hält und "URL rein, HTML raus" beantwortet, soll außerhalb dieses Stacks entstehen (Notizen dazu: #87).
wikitoolselbst bekommt keine Zugangsdaten, keine Login-Adapter und keine Headless-Browser-Abhängigkeit: Das Tool geht an jede Instanz, und Zugangsdaten haben im Arbeitsbaum nichts zu suchen (raw/CONTRACT.md§ What does not belong here). Was fehlt, ist die Stelle, an der eine Instanz einen solchen Dienst einhängt.Entwurf
.wikitool-fetch.jsonim Instanz-Root, gitignored, optional - gleiches Muster wie.wikitool-upload.json(Konstante intools/chemenu/config.py, Eintrag in.gitignore, Ignore-Kanarie indocs verify, Zeile indoctor):raw fetchexakt wie nach #120.hostsauf den Host der URL passt (exakt oder*.-Suffix), wird benutzt; sonst der eingebauteurllib-Abruf. Keine Kaskade: Schlägt der externe Befehl fehl, fälltraw fetchnicht auf den eingebauten Abruf zurück - der lieferte genau den Teaser, den der Fetcher vermeiden soll.command + [url], ohne Shell (subprocess.run(list)). Exit 0 und HTML-Bytes auf stdout = Erfolg; alles andere = exit 1 vonraw fetch, stderr des Befehls wird mit ausgegeben, nichts wird nachincoming/geschrieben. Timeout und Größenlimit aus #120 gelten unverändert.<stem>.html(stdout-Bytes unverändert) +<stem>.md. Im Headerfetched_by: wikitool raw fetch (fetcher: <name>);http_status/final_urlentfallen, weil der Befehl sie nicht liefert.wikitoolausführt. Dieselbe Haltung wie bei.wikitool-remotes.json; steht inraw/CONTRACT.mdund im ON FAILURE-Text.Nicht blockierend, beim Bau zu prüfen: Soll der Befehl optional einen Content-Type zurückgeben können (z. B. PDF hinter Login)? Wenn ein echter Dienst das braucht, als zweite Ausgabezeile auf stderr oder per JSON-Modus nachziehen; sonst nur HTML.
Betroffene Dateien
tools/chemenu/config.py,tools/chemenu/commands/raw_cmd.pybzw. das Modul aus #120 (web_capture.py), Kommando-Record vonraw fetch.gitignore,tools/chemenu/commands/docs_verify.py(Ignore-Kanarie),tools/chemenu/commands/doctor.py(vorhanden/fehlt/kaputt)tools/chemenu/tests/test_raw_fetch.py- Fetcher als kleines Python-Skript im Testverzeichnisraw/CONTRACT.md,tools/README.mdAkzeptanzkriterien
.wikitool-fetch.jsonerzeugtraw fetchbyte-identische Ausgaben wie vorher (#120-Tests unverändert grün).incoming/<stem>.htmlbyte-identisch mit dem stdout des Befehls, und der eingebaute Abruf wird nicht ausgeführt (Testserver erhält keinen Request).incoming/; der eingebaute Abruf wird nicht als Ersatz versucht..wikitool-fetch.jsonist gitignored (docs verify-Kanarie),doctormeldet vorhanden/fehlt/fehlerhaft, ohne zu FAILen.pytest,docs verify,instructions verifygrün; CI grün.Versionsteil
--minor- neue optionale Datei, die eine ältere Version ignoriert; ohne sie keine Verhaltensänderung. Drop-in in beide Richtungen.Auslöser (
prio/waiting)Beides muss erfüllt sein: