Eigenes dsh-Plugin für DeepSeek Harness erstellen
Erstellen Sie ein dsh-Plugin aus einem leeren Ordner: wichtige package.json-Felder, Patch-Datei zum Einbinden, echtes Tool und die zwei nötigen Hooks.
Was ein dsh-Plugin tatsächlich ist
Ein dsh-Plugin ist ein npm-Paket, das eine apply-Funktion exportiert und eine kleine YAML-Datei mitliefert, in der DeepSeek Harness angewiesen wird, das Plugin zu laden. Sie müssen nicht zuerst ein separates Plugin-SDK lernen. dsh ist eine Cordis-Anwendung, und „everything is a plugin“ ist wörtlich gemeint: Die Tool-Registry, die Agent-Schleife, der Session-Speicher und der Webserver sind allesamt Einträge im selben Plugin-Baum, dem sich Ihr Paket anschließt.
Cordis ist ein allgemeines Framework zur Komposition von Anwendungen. Es wurde unabhängig entwickelt und dient seit Jahren als Grundlage des Koishi-Chatbot-Frameworks. Es übernimmt das Laden und Entladen und löst die Abhängigkeiten zwischen Plugins auf. Von Agents weiß es nichts. Alles, was mit Agents zu tun hat, kommt aus den darauf aufbauenden Harness-Paketen. Deshalb ist die unten beschriebene Plugin-Struktur so klein. Der größte Teil der Funktionalität wird geerbt.
Ein Plugin besteht aus zwei Teilen. Der Host-Teil läuft in Node, registriert Tools und Event-Listener und kann eigene Dienste bereitstellen. Der Browser-Teil läuft innerhalb der Weboberfläche und registriert UI-Slots. Ein erstes Plugin ist fast immer auf den Host beschränkt. Behandeln Sie den Browser-Teil daher als optional, bis Sie ihn benötigen.
Diese Anleitung wurde für @deepseek-ai/dsh Version 0.1.0-rc.7, den npm-latest-Tag vom 19. August 2026, geschrieben. dsh befindet sich in einer Developer Preview, und die eigene README weist auf mögliche inkompatible Änderungen hin. Jeder unten verwendete Schlüsselname wurde am selben Datum aus der Upstream-Dokumentation und dem Repository übernommen. Bei einer erneuten Prüfung dieser Anleitung am 12. Oktober 2026 war der npm-latest-Tag 0.2.0-rc.2. In den folgenden Abschnitten wird auf Unterschiede in diesem Release hingewiesen. Prüfen Sie die Schlüsselnamen erneut, bevor Sie sich darauf verlassen, da eine Preview-API Felder zwischen Release Candidates umbenennen kann. Wenn der Harness noch nicht läuft, richten Sie ihn zunächst mit DeepSeek Harness auf einem VPS und API-Key und Modellkonfiguration für dsh ein. Kehren Sie danach hierher zurück.
Eine einzelne Testdatei laden, bevor Sie etwas paketieren
Zuerst zu paketieren, ist der langsamste Weg, dies zu lernen. Laden Sie eine einzelne Datei, prüfen Sie, ob die Laufzeit Ihren Code aufruft, und paketieren Sie ihn erst danach.
Erstellen Sie einen Ordner außerhalb des Checkout-Verzeichnisses des Harness und legen Sie eine Datei darin ab.
import type { Context } from '@deepseek-ai/cordis'
export const name = 'hello-plugin'
export function apply(ctx: Context) {
console.log('[hello-plugin] plugin loaded')
}export const name sind Metadaten zur Kennzeichnung des Plugins in Diagnosen. apply ist der vollständige Vertrag: Cordis ruft ihn einmal auf und übergibt einen auf Ihr Plugin beschränkten Kontext. Alles, was Sie in diesem Kontext registrieren, wird beim Freigeben des Plugins automatisch entfernt.
Legen Sie daneben cordis.yml an.
- insert:
- id: hello
name: '/absolute/path/to/scratch-plugin/hello.ts'Starten Sie jetzt ein Profil, über dem diese Datei eingebunden wird.
dsh web --patch ./scratch-plugin/cordis.ymlWenn dsh nicht in Ihrem PATH enthalten ist, erledigt npx @deepseek-ai/dsh web --patch ./scratch-plugin/cordis.yml dieselbe Aufgabe. Über diesen npx-Weg kann jedoch ein älterer Release Candidate aus dem Cache verwendet werden und nicht die Version, die in dieser Anleitung beschrieben wird. Wenn das Harness ein dokumentiertes Flag direkt ablehnt, arbeiten Sie zunächst die Fehlerbehebungen für Installations- und Versionsfehler von dsh durch, bevor Sie an Ihrer eigenen Datei zweifeln. Im Terminal, in dem dsh gestartet wurde, sollte [hello-plugin] plugin loaded erscheinen. Wenn nichts angezeigt wird, wurde die Zeile nicht aufgelöst.
Das Feld name akzeptiert einen npm-Paketnamen oder einen Dateisystempfad. In der Dokumentation des Upstream-Projekts steht, dass der Pfad absolut sein muss. Ein relativer Wert für ./hello.ts ist die erste Ursache, die Sie prüfen sollten, wenn ein Testplugin keine Ausgabe erzeugt. Die zweite Ursache ist die Dateierweiterung. Der dokumentierte Ablauf wird als pnpm dsh web --patch ... aus einem Clone des Harness-Repositorys ausgeführt. Dort werden TypeScript-Einträge über tsx geladen. Wenn Sie dsh über npm installiert haben, verweisen Sie in der Zeile auf reines JavaScript oder erstellen Sie die Datei zuerst.
--patch ist ein Launcher-Flag. Seine Overlay-Konfiguration wird zuletzt angewendet, nach jedem Bundle und nach Ihrem eigenen Profil-Patch. Eine Test-Overlay-Konfiguration hat daher immer Vorrang. Genau das benötigen Sie während der Entwicklung.
Das kleinste nützliche Tool schreiben
Eine Logzeile belegt, dass das Plugin geladen wird. Ein Tool belegt, dass das Plugin Bestandteil des Agents ist.
import type { Context } from '@deepseek-ai/cordis'
import { defineTool } from '@deepseek-ai/dsh-tools'
export const name = 'greet-tool'
export const inject = ['tools']
export function apply(ctx: Context) {
ctx.tools.register(defineTool({
name: 'greet',
description: 'Greet someone by name.',
parameters: {
name: { type: 'string', required: true, description: 'The name to greet' },
},
output: {
schema: { type: 'string' },
render: (_args, value) => [{ type: 'text', text: value }],
},
async execute(args) {
return `Hello, ${args.name}!`
},
}))
}export const inject = ['tools'] ist die Zeile, die häufig fehlt. Einträge in einer Cordis-Konfiguration werden gleichzeitig gestartet. Die Position einer Zeile in der Datei sagt daher nichts über die Ladereihenfolge aus. Die Reihenfolge ergibt sich aus den deklarierten Abhängigkeiten. inject weist Cordis an, zu warten, bis ctx.tools vorhanden ist, bevor es apply aufruft. Ohne diese Angabe kann Ihr Code zu einem Zeitpunkt ausgeführt werden, zu dem die Registry noch nicht vorhanden ist und keine Registrierung möglich ist.
Der restliche Teil des Objekts definiert den Vertrag, den das Modell sieht. parameters ist das Argument-Schema, und execute erhält Argumente, die bereits anhand dieses Schemas geparst wurden. output.schema beschreibt den Wert, den execute zurückgibt, während render diesen Wert in die Inhaltsblöcke umwandelt, die das Modell liest. Die Trennung dieser beiden Aspekte ermöglicht es der Schnittstelle, etwas anderes anzuzeigen, als das Modell liest.
Starten Sie das Profil und bitten Sie den Assistenten, jemanden mit Namen zu begrüßen. Die Antwort wird über Ihr execute zurückgegeben. Die Registrierung über ctx ist reversibel. Beim Freigeben des Plugins wird das Tool daher automatisch ausgetragen. Für Ressourcen, die Cordis nicht kennen kann, etwa einen Socket oder einen Dateideskriptor, rufen Sie ctx.effect() auf und übergeben Sie ihm eine Freigabefunktion.
Die beiden Erweiterungspunkte, die ein erstes Plugin tatsächlich verwendet
Die vollständige Liste der Erweiterungspunkte ist lang. Zwei davon decken fast jedes erste Plugin ab.
Konversationsereignisse bilden den dauerhaften, protokollierten Datenstrom. In 0.1.0-rc.7 lauteten die Namen session/event, turn/start, turn/end, step/start, step/end, user/message, assistant/message, assistant/chunk, tool/call und tool/result. Die Version 0.2.0-rc.2 enthält kein assistant/chunk. Live-Streaming wurde nach agent/assistant-stream verlagert. Dessen Frames verbleiben im Prozess und werden nie protokolliert. Ein neues dauerhaftes assistant/attempt-Ereignis erfasst fehlgeschlagene, wiederholte und abgebrochene Versuche. Sie hängen dafür einen normalen Listener ein.
ctx.on('tool/call', (payload) => {
console.log('[my-plugin] tool/call', JSON.stringify(payload))
})Geben Sie die Payload einmal aus und lesen Sie sie. Übernehmen Sie keine Feldnamen der Payload aus einer Dokumentation, auch nicht aus dieser, weil sich die Struktur der Payload bei einer Preview-API am häufigsten ändert.
Der zweite Erweiterungspunkt ist die Waterfall-Kette. agent/pre-step, agent/request, agent/request-error, llm/stream und die tools/*-Ereignisse sind Waterfalls. Ein Waterfall-Listener hat eine andere Signatur. Er erhält einen next-Callback. Die Kette wird nur fortgesetzt, wenn er diesen aufruft.
ctx.on('agent/request', async (payload, next) => {
const startedAt = Date.now()
const downstream = await next()
console.log('[my-plugin] model request took', Date.now() - startedAt, 'ms')
return downstream
})Wenn Sie await next() vergessen, haben Sie keinen Hook hinzugefügt. Sie haben den Modellaufruf durch nichts ersetzt. Der Agent stoppt an dieser Stelle, weil das vorzeitige Beenden das vorgesehene Verhalten eines Gateway-Plugins ist, das eine Anfrage absichtlich ablehnt. Dieser eine Unterschied verursacht die meisten Missverständnisse beim ersten Plugin. Schreiben Sie den next()-Aufruf, bevor Sie irgendetwas darum herum schreiben.
agent/request umschließt den Modellaufruf selbst. Seine Payload enthält den Agenten, der den Aufruf ausführt, die Nummer des offenen Turns, den Schritt, zu dem die Anfrage gehört, und das Abbruchsignal dieses Turns. Dadurch eignet sich dieser Erweiterungspunkt für einen Request-Logger oder einen Rate Limiter. Die tools/*-Waterfalls haben eine Ebene darunter dieselbe Struktur. tools/pre-execute lässt eine Anfrage vor dem Dispatch zu, lehnt sie ab oder fordert eine Genehmigung an. tools/execute umschließt den Dispatch. tools/post-execute kann das normalisierte Ergebnis ersetzen oder blockieren. tools/result beobachtet ausschließlich das eingefrorene Ergebnis.
Als Bundle paketieren, das andere installieren können
Ein Bundle ist ein npm-Paket, dessen package.json ein dsh.bundle-Feld mit einem Verweis auf seine Patchdatei deklariert. Diese Deklaration ist der gesamte Unterschied zwischen einer temporären Datei und etwas, das installiert werden kann.
{
"name": "dsh-plugin-hello",
"version": "0.1.0",
"type": "module",
"main": "lib/index.js",
"files": ["lib", "cordis.patch.yml", "README.md", "LICENSE"],
"engines": { "node": "^22.19 || >=24", "dsh": ">=0.1.0-rc.6" },
"dsh": { "bundle": { "patch": "./cordis.patch.yml" } },
"keywords": ["dsh-plugin", "deepseek-harness"],
"scripts": { "build": "tsdown", "prepare": "pnpm run build" },
"exports": {
".": { "types": "./lib/index.d.ts", "default": "./lib/index.js" },
"./cordis.patch.yml": "./cordis.patch.yml",
"./package.json": "./package.json"
}
}Das danebenstehende cordis.patch.yml ist kurz.
- insert:
- id: dsh-plugin-hello
name: dsh-plugin-helloDie Zeile name enthält den Paketnamen. Daher müssen diese beiden Zeichenfolgen übereinstimmen. Die Zeile id ist das Ziel, auf das eine spätere Ebene verweist, wenn ein Benutzer Ihre Konfiguration überschreibt. Wählen Sie dafür einen stabilen Namen und verwenden Sie ihn nie für ein anderes Plugin.
files muss cordis.patch.yml auflisten. Lassen Sie diesen Eintrag weg, enthält das veröffentlichte Tarball einen dsh.bundle.patch, der auf eine Datei verweist, die nie gepackt wurde. Das Paket wird dann zwar installiert, trägt aber nichts zum Baum bei.
Installieren Sie es aus dem Verzeichnis, das Ihren Plugin-Ordner enthält, in ein Profil.
dsh plugin --profile demo add ./dsh-plugin-hello
dsh --profile demo --dump-config
dsh --profile demodsh plugin --profile <name> leitet die übrigen Argumente im Profilverzeichnis an pnpm weiter. Daher verhalten sich add und remove wie bei pnpm. Deinstallieren Sie das Paket mit dsh plugin --profile demo remove dsh-plugin-hello. Die mitgelieferten Profile web, headless, sdk, sdk-minimal und acp werden bei der ersten Verwendung anhand von Vorlagen erstellt. In 0.2.0-rc.2 wird jeder andere Name auf eine von zwei Arten erstellt. dsh plugin startet das Profil nur mit dem Basis-Bundle. dsh --profile <name> --from-default-profile <template> kopiert die Bundle-Liste einer mitgelieferten Vorlage. Der Start eines noch nicht vorhandenen benutzerdefinierten Profils schlägt mit einem Hinweis fehl, dsh plugin auszuführen.
Warum Ihre Zeile im zusammengesetzten Baum fehlt
Die Zusammensetzung beginnt mit einer leeren Eintragsliste und fügt die Layer in einer festen Reihenfolge hinzu. Zuerst kommt jedes im Profil unter dsh.profile.bundles aufgeführte Bundle, und zwar in der angegebenen Reihenfolge. Danach folgt das eigene cordis.patch.yml des Profils. Anschließend kommt $DSH_HOME/cordis.patch.yml. Danach wird ein gegebenenfalls über die Befehlszeile angegebenes --patch-Overlay hinzugefügt. Spätere Layer ersetzen frühere Zeilen anhand ihrer ID.
Profile liegen unter $DSH_HOME/profiles/<name>. Ein Profilverzeichnis enthält ein package.json mit dem dsh.profile-Manifest und seiner geordneten bundles-Liste sowie die eigene Patch-Datei des Benutzers. Bundle-Namen werden zuerst aus der dsh-Installation und anschließend aus dem node_modules des Profils aufgelöst. Dort legt pnpm ein Plugin außerhalb des Verzeichnisbaums ab.
dsh --profile demo --dump-config gibt den vollständig zusammengesetzten Baum aus, ohne etwas zu starten. Diese Ausgabe bildet die Trennlinie bei der Fehlersuche. Fehlt Ihre Zeilen-ID, liegt das Problem in der Zusammensetzung: Ein Name lässt sich nicht auflösen oder eine Patch-Datei wurde nie gepackt. Ist die Zeile vorhanden und passiert trotzdem nichts, liegt das Problem in Ihrem Code. Beantworten Sie zuerst diese Frage. Dadurch entfällt der größte Teil des Rätselns.
Wo Ladefehler tatsächlich sichtbar werden
Ein Fehler innerhalb von apply ist deutlich sichtbar. Der Prozess beendet sich mit dieser Ausnahme, und Sie erhalten einen Stacktrace, der auf Ihre eigene Zeile verweist.
Fehler bei der Auflösung bleiben dagegen unauffällig. Der Loader meldet ein Modul, das er nicht auflösen kann, über den Cordis-Logger, statt den Prozess zu beenden. Im vorgelagerten Tutorial wird darauf hingewiesen, dass diese Meldungen beim Start verloren gehen können, weil sie ausgegeben werden, bevor Konsolen-Exporter eingebunden sind. Ein Tippfehler im Pfad sieht daher genau wie ein Plugin aus, das geladen wurde, aber nichts tut. Deshalb lohnt es sich, die Prüfung --dump-config oben auszuführen, bevor Sie den Code untersuchen.
Fügen Sie während der Entwicklung einen console.log als erste Anweisung in apply ein. Wenn er fehlt, erkennen Sie, welche Hälfte des Problems vorliegt. Später können Sie ihn ohne weitere Auswirkungen löschen. Führen Sie das Harness auf einem Server während der Entwicklung im Vordergrund aus, statt es unter einem Service-Manager zu starten. So gelangt die Ausgabe des Loaders direkt in Ihr Terminal und nicht in ein Journal, das Sie erst aufrufen und lesen müssen.
Iteration ohne Neustart des gesamten Systems
In 0.1.0-rc.7 war die Antwort für die Host-Seite einfach: Sie starten neu. Das Webanwendungspaket dieser Version wurde mit deaktivierter gemeinsam genutzter Hot-Module-Reaktivierung ausgeliefert. In der Datei stand außerdem, dass sie wieder aktiviert werde, sobald der Lebenszyklus des Neuladens getestet worden sei. In 0.2.0-rc.2 ist diese Überschreibung entfernt. Das Basispaket bindet @deepseek-ai/dsh-hmr in jedem Profil mit root: [] ein. Daneben steht der Kommentar "Profile configuration reloads by default; module roots are opt-in." Gültige Änderungen an den Profil- und Home-Patchdateien werden jetzt ohne Neustart erneut angewendet. Der Quellcode Ihres Plugins wird weiterhin nicht überwacht, sofern Sie sein Verzeichnis nicht zu root dieser Zeile hinzufügen. Das Hinzufügen, Entfernen oder Aktualisieren eines Pakets erfordert weiterhin einen Neustart. Die Reload-Kette für die Client-Seite wird immer eingebunden, bleibt aber inaktiv, bis ein Build-Watcher die Client-Pakete neu schreibt. Daher hat sie auch auf Ihre Node-Seite keine Auswirkung.
Machen Sie den Neustart schnell, statt sich auf einen Reload zu verlassen, den Sie erst aktivieren müssen. Halten Sie das Plugin in einer Datei. Laden Sie es mit --patch, statt es in einem Profil zu installieren. Dadurch liegen zwischen einer Änderung und der Ausführung weder ein Build-Schritt noch ein pnpm-Schritt. Registrieren Sie alles über ctx, damit ein Neustart kein doppeltes Tool und keinen veralteten Listener zurücklässt. Umschließen Sie alles, was Sie selbst in ctx.effect() reservieren, mit einem echten Disposer. Das typische Symptom eines fehlenden Disposers ist, dass der zweite Lauf fehlschlägt, weil ein Port noch vom ersten Lauf belegt ist.
Wenn Sie gegen ein Harness entwickeln, das auf einem Server statt auf Ihrem Laptop läuft, ändert sich daran nichts. Die Bindung der Web UI ist jedoch relevant. Ein lokaler Start stellt die Web UI unter http://127.0.0.1:3080 bereit und öffnet sie im Standardbrowser. Mit --no-open wird der Browser nicht geöffnet. Ein Start über SSH gibt nur die Host-URL aus. Auf Ihrem Rechner wird daher nichts geöffnet. Die Loopback-Bindung an Port 3080 erklärt, warum die Seite in diesem Fall nicht geöffnet wird und wie Sie das beheben.
Die Browser-Seite und wie sehr Sie ihr vertrauen sollten
Fügen Sie dies nur hinzu, wenn Ihr Plugin eine eigene Benutzeroberfläche benötigt. Es wird im selben Feld dsh wie das Bundle deklariert.
{
"dsh": {
"client": {
"platform": "web",
"inject": [],
"external": [],
"immediately": false
}
},
"exports": {
".": "./src/index.ts",
"./client": "./src/client/apply.ts",
"./package.json": "./package.json"
}
}"platform": "web" ist erforderlich. Der Scanner bricht ab, wenn das Paket keinen ./client-Export besitzt. Deshalb ist die Exportzuordnung Bestandteil des Manifests und keine optionale Ergänzung. Der Client-Einstiegspunkt erhält den Cordis-Context-Typ, erweitert um den Typ der Client-Laufzeit. Jede Registrierung erfolgt innerhalb von apply über ctx.slots.register. Seiteneffekte auf Modulebene sind dort nicht zulässig.
import type { Context } from 'cordis'
import type { DshClientContext } from '@deepseek-ai/dsh-client-runtime'
export async function apply(ctx: Context & DshClientContext) {
ctx.slots.register({ name: 'domain.entry.slot' }, MyComponent)
}Vor dem Start sollten Sie zwei Details kennen. inject im Client-Manifest dient der Dokumentation und nicht der Ablaufsteuerung: Es erfasst Abhängigkeiten zwischen Paketen und steuert nicht die Aktivierungsreihenfolge. external deklariert Modulanforderungen außerhalb der Basiskonfiguration. Die aktuellen Client-Hinweise besagen jedoch, dass es kein Abhängigkeitsmechanismus für ein Feature-Plugin ist und für Infrastruktur, Transport sowie generierten Assemblercode reserviert bleibt. Lassen Sie es in einem Feature-Plugin leer. Dieser Bereich der Vorschau ändert sich am schnellsten. Lesen Sie daher am Tag, an dem Sie den Code schreiben, packages/client/AGENTS.md im Harness-Repository und nicht an dem Tag, an dem Sie einen Leitfaden dazu lesen.
Veröffentlichen Sie das Plugin und geben Sie an, worauf es zugreift
Wenn Sie das Thema dsh-plugin zu einem GitHub-Repository hinzufügen, erscheint es in der Liste, die Nutzer bei der Suche nach Plugins durchsuchen. Damit beanspruchen Sie das Vertrauen anderer und übernehmen entsprechende Pflichten. Diese Pflichten entsprechen genau den Prüfpunkten aus unserem Leitfaden zur Prüfung eines dsh-Plugins vor der Installation. Deshalb lässt sich das Plugin am einfachsten veröffentlichen, wenn Sie diese Checkliste direkt abarbeiten.
- Fixieren Sie Ihre Abhängigkeiten. Ein Caret-Bereich bei einer transitiven Abhängigkeit kann dazu führen, dass ein Paket, das letzte Woche noch sicher war, diese Woche anderen Code ausführt. Genau auf diesem Mechanismus beruhen npm-Lieferkettenangriffe auf einen Server.
- Geben Sie im Manifest an, worauf Sie zugreifen. Ihre
inject-Liste ist eine ehrliche, maschinenlesbare Zusammenfassung der Harness-Dienste, die Sie verwenden. Ein Reviewer kann sie in wenigen Sekunden prüfen und sich daraus ein Urteil bilden. - Keine stillen Netzwerkaufrufe. Wenn ein Tool eine API aufruft, nennen Sie den Host in der README und machen Sie den Endpunkt konfigurierbar. Ein Plugin, das einen nicht erwähnten Server kontaktiert, wird von den zuständigen Prüfern aus der Liste entfernt.
- Halten Sie
filesknapp. Wenn Sie einen vollständigen Arbeitsordner veröffentlichen, kann versehentlich eine Datei mit Zugangsdaten in die Registry gelangen. - Stellen Sie Git-Installern ein
prepare-Skript bereit, das ohne Annahmen über reine Entwicklungsabhängigkeiten erstellt werden kann. Geben Sie in der README an, dass sie diesen Build in derpnpm-workspace.yamlihres Profils auf die Allowlist setzen müssen. - Versehen Sie die README mit dem Datum des Release Candidates, gegen den Sie das Plugin erstellt und getestet haben. Nutzer einer Vorschau-API müssen wissen, welche Version Sie verwendet haben.
Um zu sehen, wie ein fertiges Plugin von außen aussieht, lesen Sie die empfehlenswerten dsh-Plugins und achten Sie darauf, welche Informationen die jeweilige README vor der Installation liefert. Wenn Sie Erweiterungen für einen anderen Agenten geschrieben haben, ist der Aufbau von Claude-Code-Plugins ein nützlicher Vergleich. Der Harness stellt Ihnen einen Live-Objektgraphen und eine reversible Registrierung bereit. Das bietet mehr Möglichkeiten als ein Manifest mit Dateien, bringt aber auch mehr Verantwortung mit sich.
FAQ
Muss ich ein dsh-Plugin bei npm veröffentlichen, um es zu schreiben?
Nein. Ein Dateisystempfad in einem cordis.yml-Overlay, der mit dsh web --patch ./scratch-plugin/cordis.yml geladen wird, reicht aus, um eigenen Code innerhalb des Harness auszuführen. Der Pfad muss absolut sein. Die Paketierung ist nur relevant, wenn jemand anderes das Plugin installiert. Auch dann können Sie mit dsh plugin --profile demo add ./my-plugin einen lokalen Ordner installieren, um die paketierte Form zu testen, ohne eine Registry zu verwenden.
Warum wird mein Plugin geladen, aber das Tool erscheint nie?
Führen Sie zuerst dsh --profile demo --dump-config aus. Fehlt Ihre Zeilen-ID in dieser Ausgabe, wurde das Plugin nie eingebunden. Die Ursache liegt dann in der Zusammensetzung und nicht im Code. Ist die Zeile vorhanden, prüfen Sie export const inject = ['tools']. Einträge in einer Cordis-Konfiguration werden gleichzeitig gestartet. Die Reihenfolge der Dateien bestimmt daher nicht die Ladereihenfolge. Ohne diese Deklaration wartet Cordis nicht auf die Tool-Registry. Ihr apply kann dann zu einem Zeitpunkt ausgeführt werden, zu dem ctx.tools für die Registrierung noch nicht verfügbar ist.
Was ist der Unterschied zwischen cordis.yml und cordis.patch.yml?
cordis.yml ist eine vollständige Liste von Einträgen. cordis.patch.yml ist eine Ebene, die auf eine solche Liste angewendet wird. Sie adressiert Zeilen anhand ihrer ID, um neue Zeilen einzufügen oder eine vorhandene Konfiguration zu ersetzen. Ein Bundle verweist in package.json über dsh.bundle.patch auf seine eigene Patch-Datei. Die Ebenen werden in einer festen Reihenfolge angewendet: zuerst jedes Bundle in der im Profil angegebenen Reihenfolge, danach die Patch-Datei des Profils, dann $DSH_HOME/cordis.patch.yml und anschließend jedes --patch-Overlay. Spätere Ebenen haben Vorrang.
Kann ich ein dsh-Plugin hot-reloaden, während der Agent läuft?
Nicht in 0.1.0-rc.7. Das Web-Bundle enthielt die deaktivierte gemeinsame Zeile für das Hot Module Reloading. In 0.2.0-rc.2 wird diese Zeile in jedem Profil eingebunden, lädt standardmäßig jedoch nur die Profilkonfiguration neu. Modulwurzeln müssen über die root-Liste ausdrücklich aktiviert werden. Ihr Plugin-Code erfordert daher weiterhin einen Neustart, sofern Sie keine Modulwurzel hinzufügen. Planen Sie in jedem Fall einen schnellen Neustart ein: eine Datei, die ohne Build-Schritt über --patch geladen wird, und jede Registrierung über ctx, damit keine Zustände von einem Lauf in den nächsten übergreifen. Verwenden Sie ctx.effect() mit einem Disposer für Ressourcen, die Cordis nicht selbst bereinigen kann.