Aussi en: English, Español, Português, 日本語, Deutsch, 한국어, 简体中文, Italiano, हिन्दी · Tous les guides en français
Transparence : nous développons Carbon Forge chez 100monkeys.ai, lisez donc ceci comme le récit de son fabricant. Ce guide a été rédigé par l'un de nos agents d'IA à partir de la documentation publique, principalement Working in lanes et Code and files on the substrate, puis relu par l'entreprise ; cette édition française est une traduction du guide original en anglais. Chaque appel ci-dessous est l'exemple de la documentation elle-même, et les citations sont en anglais avec la traduction à côté. Là où la documentation laisse une question ouverte, la dernière section le dit.
Pourquoi un seul changeset
L'accueil de la documentation définit l'unité : "A changeset is many writes landed as one: every page, atom, code tree and library entry it names is written in one transaction under one intent, the changeset's intent, or nothing is written" (Welcome to Carbon). (Un changeset, ce sont plusieurs écritures intégrées comme une seule : chaque page, atome, arbre de code et entrée de bibliothèque qu'il nomme est écrit dans une seule transaction sous une seule intention, celle du changeset, ou rien n'est écrit.) Code et prose sont des entités d'un même registre : personne ne croise le nouveau code à côté de l'ancienne page, et un revert ramène les deux ensemble.
Il vous faut un jeton qui peut écrire des lanes et des arbres ; le préréglage SCM agent est celui que la documentation désigne pour ce travail.
Étape 1. Savoir si le trunk est protégé
workspaces.get_settings {}
→ { "workspaceId": "…", "trunkProtected": true, "trunkProtectedEntities": false } "With trunkProtected, code trees, library entries and changesets go through a lane; with trunkProtectedEntities as well, page and atom edits do too." (Avec trunkProtected, les arbres de code, les entrées de bibliothèque et les changesets passent par une lane ; avec aussi trunkProtectedEntities, les modifications de pages et d'atomes aussi.) Dans les deux cas, une lane est la bonne forme ici : la documentation y recourt quand "a change should be seen whole before it lands." (une modification doit être vue en entier avant d'être intégrée.)
Étape 2. Ouvrir une lane pour la modification
lanes.create { "label": "agent/7/fix-login" } Une étiquette est faite de segments en minuscules séparés par des barres obliques, unique parmi les lanes ouvertes. "A lane costs nothing to open and holds no copy, so one per task, or one per agent, is the expected use." (Ouvrir une lane ne coûte rien et elle ne contient aucune copie : une par tâche, ou une par agent, est l'usage prévu.) Passez owner pour être seul à pouvoir écrire, résoudre et intégrer la lane.
Étape 3. Modifier le code sur la lane
trees.apply_patch { "path": "app", "operations": [ { "op": "patch", "entry_path": "src/login.ts", "old_string": "password", "new_string": "magicLink" } ], "intent": "fix: accept magic links", "lane": "agent/7/fix-login" } Passez l'étiquette comme lane et "the write is held on the lane as a patch against the trunk" (l'écriture est gardée sur la lane comme un patch par rapport au trunk) : "the trunk is not written." (le trunk n'est pas écrit.) trees.apply_patch n'envoie que ses opérations (une substitution dans un fichier, une écriture, une suppression ou un déplacement) ; trees.put envoie la liste complète des entrées de l'arbre. Dans les deux cas, "the lane keeps only what differs." (la lane ne garde que ce qui diffère.)
Étape 4. Modifier la page qui le documente, sur la même lane
pages.apply_patch { "pathOrId": "guides/login", "old_string": "Sign in with a password.", "new_string": "Sign in with a magic link.", "lane": "agent/7/fix-login" } Même étiquette : la modification de la page attend à côté du code. Si la modification renomme aussi une page, pages.move accepte aussi lane, et "a rename belongs to the change that needs it." (un renommage appartient à la modification qui en a besoin.) Une capture d'écran entre de la même façon avec library.put_at_path et l'étiquette.
Étape 5. Lire ce que produirait la lane
Passez la même lane à une lecture et "the answer is the trunk as it stands now with the lane's patches applied, composed on the call" (la réponse est le trunk tel qu'il est maintenant avec les patchs de la lane appliqués, composé au moment de l'appel) : pages.read pour la page, trees.get, trees.diff ou trees.grep pour le code. Puis relisez l'ensemble :
lanes.diff { "label": "agent/7/fix-login" }
lanes.get { "label": "agent/7/fix-login" } lanes.diff répond "entity by entity, the trunk's section and the lane's" (entité par entité, la section du trunk et celle de la lane) ; lanes.get répond avec les patchs, les conflits et landable : "open, at least one live patch, no conflict." (ouverte, au moins un patch vivant, aucun conflit.) Dans l'application, /<workspace>/lanes/<label> montre la même chose, chaque fichier texte modifié sous forme de diff unifié. Une personne qui lit lanes.export et approuve à son hash de composition "has approved exactly that change." (a approuvé exactement cette modification.)
Étape 6. Répondre aux conflits
Si quelqu'un a entre-temps modifié sur le trunk les mêmes lignes de la page ou du fichier, le patch est en conflit, et "nothing merges by itself." (rien ne fusionne tout seul.) lanes.conflicts donne le patch, la section telle qu'elle était, la section actuelle du trunk et les changesets qui l'ont déplacée. Répondez avec lanes.resolve ou abandonnez le patch avec lanes.drop_patch. Une substitution dans un fichier "replays on the trunk's current file, so two agents changing different parts of one file both land." (se rejoue sur le fichier actuel du trunk, donc deux agents qui modifient des parties différentes d'un même fichier sont intégrés tous les deux.)
Étape 7. Intégrer une seule fois, avec une intention
lanes.land { "label": "agent/7/fix-login", "intent": "fix: accept magic links", "dry_run": true }
lanes.land { "label": "agent/7/fix-login", "intent": "fix: accept magic links" } Lancez d'abord l'essai à blanc, puis l'intégration. "Every live patch is replayed as one changeset whose intent is lane agent/7/fix-login: fix: accept magic links" (Chaque patch vivant est rejoué comme un seul changeset portant cette intention), revérifié dans sa propre transaction et "refused whole, with every conflict named, if anything moved." (refusé en bloc, chaque conflit nommé, si quoi que ce soit a bougé.) Commencez l'intention par feat, fix, docs, chore ou revert et les notes de version la regroupent sous ce mot. Envoyez une idempotency_key et une nouvelle tentative après un délai dépassé "answers the first landing's result instead of landing twice." (renvoie le résultat de la première intégration au lieu d'intégrer deux fois.)
Étape 8. Relire l'intégration
Ouvrez /<workspace>/changes/<id> : on y voit l'intention complète, l'acteur, la lane d'origine, son sceau et ses entrées, le fichier de code et la page ensemble. Le blame sur la ligne modifiée répond maintenant avec l'intention que vous avez écrite : trees.blame donne "each line's revision, changeset, intent, actor and landing lane" (pour chaque ligne la révision, le changeset, l'intention, l'acteur et la lane d'intégration) (Code and files). Pour annuler les deux à la fois, changesets.revert écrit un nouveau changeset qui restaure chaque entité écrite par l'intégration.
Ce que la documentation laisse sans réponse
- Un chemin en un seul appel sans lane. Le guide des lanes montre
changesets.applyavec"targets": [ … ]mais n'y détaille pas la forme d'une cible ; ce guide utilise donc une lane. - Quelle page documente quel code. Rien ici ne crée le lien ; le déclarer est le rôle des governed seams (voir le guide lié ci-dessous).