Zum Artikel springen
PlanToCodeDocsApp herunterladen

HandbuchArchitektur

Befehlsausgabe, Dokumente und Vorschauen

Wie Befehlsausgabe erfasst und in Bereichen gelesen wird, wie HTML-Dokumente auf drei Plattformen in einem abgeschotteten Ursprung laufen, wie Webseiten zu Markdown werden und wie Dateien in Blöcken übertragen werden.

Gegen den Quellcode geprüft am 17. September 2026

Auf dieser Seite

Befehlsausgabe als Artefakt

Befehlsausgabe wird vom Desktop abgeholt, solange der Befehl läuft, und von Codex, sobald er abgeschlossen ist
Befehlsausgabe wird vom Desktop abgeholt, solange der Befehl läuft, und von Codex, sobald er abgeschlossen istEin Befehl im Zeitverlauf. Codex streamt Ausgabe-Deltas und schreibt eine eigene Mitschnittdatei, der Desktop hängt jedes Delta an sein Artefakt an, und die Timeline-Zeile erhält nur Größe und Generation. Ein offener Betrachter liest bis zu 256 KiB auf einmal aus dem Artefakt. Bei item/completed ersetzen Bytes, die von der gesammelten Ausgabe von Codex abweichen, das Artefakt als Generation 2, sodass ein Lesezugriff für Generation 1 einen Konflikt erhält und der Betrachter die Zeile aktualisiert. Sobald die Zeile abgeschlossen ist, zeigt sie auf die Mitschnittdatei von Codex, und Lesezugriffe gehen über den Desktop an thread/commandOutput/read.
Codexführt den Befehl aus
Desktop-Artefakt
Mitschnittdatei
Ausgabe-Deltas mit Bytes
abgeschlossen, Ausgabe bis 1 MiB
Generation 1, jedes Delta angehängt
Generation 2
gleiche Bytes behalten Generation 1, abweichende Bytes werden Generation 2
Timeline-Zeile
Größe und Generation, keine Bytes
abgeschlossen, zeigt jetzt auf Codex
Betrachter
geschlossen, kein Lesen
liest bis 256 KiB
Generation 1 ist weg: Konflikt, Zeile aktualisieren
nicht mehr gelesen
liest den Mitschnitt von Codex über den Desktop
item/started
item/completed
Zeile steht fest
  • Live-ZeilecommandOutput.artifact

    Der Desktop hängt jedes Ausgabe-Delta an sein Artefakt an, bevor sich die Zeile ändert, und sendet dann runId, byteLength, generation, complete und sourceIncomplete höchstens alle 100 ms pro Befehl. Kein Ausgabe-Byte gelangt in die Timeline.

  • Bereichslesenrun.codexChatCommandOutputRead

    Nur ein offener Betrachter liest, 1 Byte bis 256 KiB pro Anfrage, und appSessionId bindet den Lesezugriff an die besitzende Basis-Session. Eine Generation, die das Artefakt nicht mehr hält, wird mit einem Konflikt beantwortet, und der Betrachter aktualisiert die Zeile, bevor er erneut liest. Telefone rufen ihn über das Relay auf, der Betrachter auf dem Desktop ruft denselben Lesezugriff direkt auf.

  • Abschlussitem/completed

    Der Desktop vergleicht seine Bytes mit dem aggregatedOutput von Codex, den Codex auf 1 MiB begrenzt. Identische Bytes markieren das Artefakt nur als vollständig. Abweichende Bytes ersetzen es als nächste Generation, und eine bekannte Kürzungsmarke in diesem Text setzt sourceIncomplete.

  • Abgeschlossene ZeileprotocolOutput

    Sobald thread/items/list den Befehl liefert, zeigt die Zeile auf die Mitschnittdatei, die Codex während des Laufs geschrieben hat, und ein offener Betrachter auf dem Desktop folgt ihr über die unveränderte Block-ID. Der Desktop leitet Lesezugriffe als thread/commandOutput/read weiter und prüft die zurückgegebene Identität. capturedComplete ist false, wenn Codex keinen vollständigen Mitschnitt behalten hat.

HTML-Dokumente in einer Sandbox

Jede HTML-Vorschau ist eine eigene Website, und die Ressourcenwurzel ist ihr oberster Ordner
Jede HTML-Vorschau ist eine eigene Website, und die Ressourcenwurzel ist ihr oberster OrdnerLinks der Datenträger des Desktops, rechts die Anfragen einer Vorschauseite unter /docs/report.html. Jede Anfrage landet auf demselben Pfad unter der Ressourcenwurzel, daher laden relative Importe und fetch-Aufrufe, ein Pfad kann nicht über die Wurzel steigen, und ein Symlink, der hinausführt, wird abgewiesen. Darunter gibt die Sandbox der Seite keinen Zugriff auf die App, und eine Navigationsnachricht ist das Einzige, worauf die App reagiert.
Sandbox
kein Zugriff auf Seite oder Speicher der App
plantocode.html.open
Die Appöffnet eine Datei unter der Wurzel oder eine Webseite
Desktop-Datenträger
~/Pictures/logo.png
~/.ssh/id_ed25519
~/work/shop
Ressourcenwurzel
docs/report.html
src/chart.js
data/sales.json
assets → ~/Pictures
.ssh/id_ed25519
verlässt die Wurzel
fehlt, 404
Vorschauseite
ptc-document://<preview-id>.localhost
keine URL reicht über die Wurzel
/
/docs/report.html
die Seite selbst
/src/chart.js
import "../src/chart.js"
/data/sales.json
fetch("../data/sales.json")
/assets/logo.png
<img src="../assets/logo.png">
/.ssh/id_ed25519
fetch("../../../.ssh/id_ed25519")
  • Ressourcenwurzelopen_html_preview_command

    Der Projektordner, wenn er das Dokument enthält, sonst der eigene Ordner des Dokuments. Der Aufrufer erzeugt die Vorschau-UUID, und der Desktop weigert sich, diese ID an ein zweites Dokument zu binden.

  • Pfadprüfungptc-document://<preview-id>.localhost/<path>

    Der Handler weist einen dekodierten Pfad mit .., einem Backslash, einem Doppelpunkt oder NUL ab, liefert für einen Ordner index.html und antwortet mit 404, wenn der kanonische Pfad fehlt oder die Wurzel verlässt.

  • Sandboxsandbox allow-scripts

    Skripte, Module und fetch laufen in einem opaken Ursprung ohne Zugriff auf die Seite oder den Speicher der App. Eine Nachricht plantocode.html.open oder plantocode.html.ready aus diesem Frame ist das Einzige, worauf die App reagiert, und nur für eine Datei unter der Wurzel oder eine http(s)-Seite.

  • Telefonefiles.readHtmlPreviewResource

    Die iPhone-App unter ptc-document://<preview-id>.localhost und die Android-App unter https://ptc-<preview-id>.invalid lösen dieselben Pfade über den Desktop auf, in geprüften Blöcken von bis zu 4 MiB und ohne Skriptbrücke in die App.

Das Protokoll antwortet auf OPTIONS mit 204, bedient nur GET und HEAD, setzt Cache-Control no-store und X-Content-Type-Options nosniff und hängt navigation.js nach dem Dokumentende an, ohne die Datei zu berühren; dieses Skript sendet plantocode.html.open an den Elternteil und blockiert jedes Schema außer ptc-document und http(s). Lokale Links in einem Dokument gehen deshalb in den Vorschauverlauf ein, Weblinks öffnen sich in der Webvorschau, und Neu laden oder eine Dateiänderung aktualisiert die Darstellung.

Webseiten als Markdown

Ein Weblink öffnet sich als Markdown-Darstellung statt als Live-Seite. Die WebView extrahiert den Artikelinhalt und wandelt ihn mit einer GFM-fähigen Turndown-Pipeline um, die Rust-Seite wandelt mit quick_html2md für Inhalte um, die die WebView nie erreichen, und die Browser Bridge hat einen dritten, handgeschriebenen DOM-zu-Markdown-Renderer, dessen Ausgabe der Desktop als capturedBrowserMarkdown speichert und mit derselben Titelkopfzeile umschließt. Drei Konverter, ein Zielformat.

Dateizugriffe und Übertragungen

files.readContent liefert ein Textdokument von höchstens 2 MiB; eine größere Datei scheitert mit „Text preview is too large“. Die Anfrage trägt projectDirectory, path sowie optional encoding und allowExternalFile, wobei encoding akzeptiert, aber ignoriert wird; sie hat keine Block-Offset- oder Medienfelder, weil Text- und Binäranfragen getrennt bleiben. files.readBinary und files.readMediaRendition lesen sequenzielle Blöcke ab Offset null. Jede Antwort trägt offset, nextOffset (null am Dateiende), dataBase64, byteCount, contentVersion, modifiedAt und mimeType, und Renditionen ergänzen originalByteCount. Benachbarte Grenzen: Medienrenditionsquellen bis 1 GiB, Stream-Transkodierungen bis 256 MiB mit 40-Sekunden-Timeouts, Medienbereichslesezugriffe von 1 MiB und Chat-Anhang-Uploads in 1-MiB-Blöcken, höchstens 2.048 davon.

Eine Datei jeder Größe wird in unabhängigen Lesezugriffen von je 4 MiB übertragen, gebunden an eine Version
Eine Datei jeder Größe wird in unabhängigen Lesezugriffen von je 4 MiB übertragen, gebunden an eine VersionEine maßstabsgetreu gezeichnete Datei mit 9.961.472 Bytes wird in drei Anfragen an den Offsets 0, 4.194.304 und 8.388.608 gelesen. Der Desktop öffnet die Datei für jede Anfrage und behält dazwischen nichts, während das Telefon Version und Größe aus der ersten Antwort festhält. Wird die Datei während der Übertragung gespeichert, trägt die nächste Antwort eine neue Version, und das Telefon verwirft den ganzen Lesevorgang.
report.pdf9.961.472 Bytes
4 MiB
4 MiB
1,5 MiB
0
4.194.304
8.388.608
Desktopöffnet, liest, antwortet
behält zwischen Anfragen nichts
TelefonDatei unverändert
hält Version A und 9.961.472 Bytes fest
wieder Version A
nextOffset null
Telefonmittendrin gespeichert
Version A
Datei gespeichert
Version B
File changed while loading. Open it again.
  • Blocklesenfiles.readBinary

    Jede Anfrage nennt den Pfad und einen Offset. Der Desktop öffnet die Datei, liest dort bis zu 4 MiB und antwortet mit dem nächsten Offset, dem gesamten byteCount und einer contentVersion. Ressourcen der HTML-Vorschau und Medienrenditionen nutzen denselben Leser.

  • Festgehaltene VersioncontentVersion

    Bei files.readBinary ist sie ein Hash aus Pfad, Größe und Änderungszeit, gebildet bei jedem Öffnen der Datei. Beide Telefone behalten Version und Größe der ersten Antwort und verwerfen den ganzen Lesevorgang, wenn eine spätere Antwort abweicht. Eine Datei, die unter den Offset geschrumpft ist, erhält dieselbe Meldung vom Desktop.

  • Relay-FrameDEVICE_LINK_MAX_FRAME_BYTES

    Ein Block von 4 MiB ergibt etwa 5,3 MiB base64, daher bleibt jede Antwort weit unter der Frame-Grenze des Relays von 32 MiB, und die Datei selbst hat keine Größengrenze.

Syntaxhervorhebung

Quellvorschauen auf dem Desktop nutzen Shiki-Grammatiken, und jede Telefon-App hebt mit ihrer eigenen Engine hervor.