- Accueil
- Documentation
- Extensions
- Chargement des extensions (Modules TypeScript/JavaScript)
Chargement des extensions (Modules TypeScript/JavaScript)
Ce document explique comment l’agent de codage découvre et charge les modules d’extension (.ts/.js) au démarrage.
Il ne couvre pas les extensions de manifeste gemini-extension.json (documentées séparément).
Rôle de ce sous-système
Section intitulée « Rôle de ce sous-système »Le chargement des extensions construit une liste de fichiers d’entrée de modules, importe chaque module avec Bun, exécute sa fabrique et retourne :
- les définitions d’extensions chargées
- les erreurs de chargement par chemin (sans interrompre l’ensemble du chargement)
- un objet de runtime d’extension partagé, utilisé ultérieurement par
ExtensionRunner
Fichiers d’implémentation principaux
Section intitulée « Fichiers d’implémentation principaux »src/extensibility/extensions/loader.ts— découverte des chemins + import/exécutionsrc/extensibility/extensions/index.ts— exports publicssrc/extensibility/extensions/runner.ts— exécution du runtime/des événements après le chargementsrc/discovery/builtin.ts— fournisseur de découverte automatique natif pour les modules d’extensionsrc/config/settings.ts— charge les paramètres fusionnésextensions/disabledExtensions
Entrées du chargement des extensions
Section intitulée « Entrées du chargement des extensions »1) Modules d’extension natifs découverts automatiquement
Section intitulée « 1) Modules d’extension natifs découverts automatiquement »discoverAndLoadExtensions() interroge d’abord les fournisseurs de découverte pour les éléments de capacité extension-module, puis ne conserve que les éléments du fournisseur native.
Emplacements natifs effectifs :
- Projet :
<cwd>/.xcsh/extensions - Utilisateur :
~/.xcsh/agent/extensions
Les racines de chemins proviennent du fournisseur natif (SOURCE_PATHS.native).
Remarques :
- La découverte automatique native est actuellement basée sur
.xcsh. - Le format
.pihérité est toujours accepté dans les clés de manifestepackage.json(pi.extensions), mais pas en tant que racine native ici.
2) Chemins configurés explicitement
Section intitulée « 2) Chemins configurés explicitement »Après la découverte automatique, les chemins configurés sont ajoutés et résolus.
Sources de chemins configurés dans le chemin de démarrage de session principale (sdk.ts) :
- Chemins fournis par la CLI (
--extension/-e, et--hookest également traité comme un chemin d’extension) - Tableau
extensionsdes paramètres (paramètres globaux + projet fusionnés)
Fichier de paramètres global :
~/.xcsh/agent/config.yml(ou répertoire d’agent personnalisé viaPI_CODING_AGENT_DIR)
Fichier de paramètres du projet :
<cwd>/.xcsh/settings.json
Exemples :
extensions: - ~/my-exts/safety.ts - ./local/ext-pack{ "extensions": ["./.xcsh/extensions/my-extra"]}Contrôles d’activation/désactivation
Section intitulée « Contrôles d’activation/désactivation »Désactiver la découverte
Section intitulée « Désactiver la découverte »- CLI :
--no-extensions - Option SDK :
disableExtensionDiscovery
Comportement selon le contexte :
- SDK : lorsque
disableExtensionDiscovery=true, il charge tout de même lesadditionalExtensionPathsvialoadExtensions(). - La construction des chemins CLI (
main.ts) efface actuellement les chemins d’extension CLI lorsque--no-extensionsest défini, de sorte que les options explicites-e/--hookne sont pas transmises dans ce mode.
Désactiver des modules d’extension spécifiques
Section intitulée « Désactiver des modules d’extension spécifiques »Le paramètre disabledExtensions filtre selon le format d’identifiant d’extension :
extension-module:<derivedName>
derivedName est basé sur le chemin d’entrée (getExtensionNameFromPath), par exemple :
/x/foo.ts->foo/x/bar/index.ts->bar
Exemple :
disabledExtensions: - extension-module:fooRésolution des chemins et des entrées
Section intitulée « Résolution des chemins et des entrées »Normalisation des chemins
Section intitulée « Normalisation des chemins »Pour les chemins configurés :
- Normalisation des espaces unicode
- Expansion de
~ - Si relatif, résolution par rapport au
cwdcourant
Si le chemin configuré est un fichier
Section intitulée « Si le chemin configuré est un fichier »Il est utilisé directement comme candidat d’entrée de module.
Si le chemin configuré est un répertoire
Section intitulée « Si le chemin configuré est un répertoire »Ordre de résolution :
package.jsondans ce répertoire avecxcsh.extensions(oupi.extensionshérité) -> utilise les entrées déclaréesindex.tsindex.js- Sinon, analyse d’un niveau pour les entrées d’extension :
*.ts/*.jsdirectsindex.ts/index.jsdans un sous-répertoirepackage.jsondans un sous-répertoire avecxcsh.extensions/pi.extensions
Règles et contraintes :
- pas de découverte récursive au-delà d’un niveau de sous-répertoire
- les entrées de manifeste
extensionsdéclarées sont résolues par rapport à ce répertoire de paquet - les entrées déclarées ne sont incluses que si le fichier existe et si l’accès est autorisé
- dans les paires
*/index.{ts,js}, TypeScript est préféré à JavaScript - les liens symboliques sont traités comme des fichiers/répertoires éligibles
Le comportement d’ignorance diffère selon la source
Section intitulée « Le comportement d’ignorance diffère selon la source »- La découverte automatique native (
discoverExtensionModulePathsdans les assistants de découverte) utilise un glob natif avecgitignore: trueethidden: false. - L’analyse de répertoire configuré explicitement dans
loader.tsutilise les règlesreaddiret n’applique pas le filtrage gitignore.
Ordre de chargement et priorité
Section intitulée « Ordre de chargement et priorité »discoverAndLoadExtensions() construit une liste ordonnée unique, puis appelle loadExtensions().
Ordre :
- Modules découverts automatiquement en mode natif
- Chemins configurés explicitement (dans l’ordre fourni)
Dans sdk.ts, l’ordre configuré est :
- Chemins supplémentaires de la CLI
extensionsdes paramètres
Déduplication :
- basée sur le chemin absolu
- le premier chemin rencontré est conservé
- les doublons ultérieurs sont ignorés
Implication : si le même chemin de module est à la fois découvert automatiquement et configuré explicitement, il est chargé une seule fois à la première position (étape de découverte automatique).
Import du module et contrat de fabrique
Section intitulée « Import du module et contrat de fabrique »Chaque chemin candidat est chargé avec un import dynamique :
await import(resolvedPath)- la fabrique est
module.default ?? module - la fabrique doit être une fonction (
ExtensionFactory)
Si l’export n’est pas une fonction, ce chemin échoue avec une erreur structurée et le chargement continue.
Gestion des échecs et isolation
Section intitulée « Gestion des échecs et isolation »Pendant le chargement
Section intitulée « Pendant le chargement »Par chemin d’extension, les échecs sont capturés sous la forme { path, error } et n’empêchent pas le chargement des autres chemins.
Cas courants :
- échec d’import / fichier manquant
- export de fabrique invalide (non-fonction)
- exception levée lors de l’exécution de la fabrique
Modèle d’isolation du runtime
Section intitulée « Modèle d’isolation du runtime »- Les extensions ne sont pas isolées (même processus/runtime).
- Elles partagent un
EventBuset une instanceExtensionRuntime. - Pendant le chargement, les méthodes d’action du runtime lèvent intentionnellement
ExtensionRuntimeNotInitializedError; le câblage des actions intervient ultérieurement dansExtensionRunner.initialize().
Après le chargement
Section intitulée « Après le chargement »Lorsque les événements transitent par ExtensionRunner, les exceptions des gestionnaires sont interceptées et émises en tant qu’erreurs d’extension plutôt que de faire planter la boucle du runner.
Exemples de structures minimales utilisateur/projet
Section intitulée « Exemples de structures minimales utilisateur/projet »Au niveau utilisateur
Section intitulée « Au niveau utilisateur »~/.xcsh/agent/ config.yml extensions/ guardrails.ts audit/ index.tsAu niveau projet
Section intitulée « Au niveau projet »<repo>/ .xcsh/ settings.json extensions/ checks/ package.json lint-gates.tschecks/package.json :
{ "xcsh": { "extensions": ["./src/check-a.ts", "./src/check-b.js"] }}Clé de manifeste héritée toujours acceptée :
{ "pi": { "extensions": ["./index.ts"] }}