Aller au contenu
English

Travailler sur plusieurs dépôts

Confiez chaque dépôt à sa propre tâche d’agent et reliez les tâches par leurs dépendances.

Confiez chaque dépôt à une tâche defineIsolatedTask() et reliez ces tâches dans un workflow. Une sandbox gère un seul dépôt : chaque tâche possède donc sa copie de travail et son historique Git.

import { defineIsolatedTask } from "@elie-laloum/outpost";
import { resolve } from "node:path";
import { sandboxProvider, coder } from "./outpost.config.ts";

export function upgrade(key: string, path: string) {
  return defineIsolatedTask({
    key,
    request: () => ({
      repository: resolve(import.meta.dirname, path),
      sandboxProvider,
      agent: coder,
      branch: { mode: "named", name: "outpost/node-24" },
      brief: {
        text: "Move CI and package.json to Node.js 24, run the tests and commit.",
      },
    }),
  });
}
import { reportValue } from "./reporter.ts";
import { upgrade } from "./upgrade.ts";
import { defineWorkflow } from "@elie-laloum/outpost";

export const api = upgrade("api", "../api");
export const web = upgrade("web", "../web");
export const result = await defineWorkflow("node-24", [api, web]).start({
  concurrency: 2,
});
result.unwrap();
reportValue(result.value(api).commits.length, result.value(web).commits.length);
// Example output: 1 1

Le script affiche le nombre de commits sur outpost/node-24 dans chaque checkout. Chaque tâche ouvre son propre worktree et sa propre sandbox, puis les ferme en fin de tâche.

Les chemins sont résolus depuis import.meta.dirname, ce qui permet de lancer ce script depuis n’importe quel dossier. Pour régler le nombre de tâches exécutées en parallèle, consultez WorkflowOptions.

Transmettre le résultat d’un dépôt à un autre

Section intitulée « Transmettre le résultat d’un dépôt à un autre »

Ajoutez la première tâche à after, puis lisez son résultat avec context.value() dans request. Le client démarre dès que la tâche de l’API réussit.

import { defineIsolatedTask } from "@elie-laloum/outpost";
import { resolve } from "node:path";
import { sandboxProvider, coder } from "./outpost.config.ts";

export const branch = { mode: "named", name: "outpost/rename-field" } as const;
export const api = defineIsolatedTask({
  key: "api",
  request: () => ({
    repository: resolve(import.meta.dirname, "../api"),
    sandboxProvider,
    agent: coder,
    branch,
    brief: {
      text: "Rename user_name to username in GET /users, commit, and describe the change.",
    },
  }),
});
import { defineIsolatedTask } from "@elie-laloum/outpost";
import { api, branch } from "./api-change.ts";
import { resolve } from "node:path";
import { sandboxProvider, coder } from "./outpost.config.ts";

export const web = defineIsolatedTask({
  key: "web",
  after: [api],
  request: (context) => ({
    repository: resolve(import.meta.dirname, "../web"),
    sandboxProvider,
    agent: coder,
    branch,
    brief: {
      text: `The API changed:\n${context.value(api).text}\nUpdate this client and commit.`,
    },
  }),
});
import { defineWorkflow } from "@elie-laloum/outpost";
import { api } from "./api-change.ts";
import { web } from "./web-change.ts";

export const result = await defineWorkflow("rename-field", [api, web]).start();
result.unwrap();

La dépendance ordonne les tâches. Chaque dépôt garde sa propre branche et son propre historique.

L’échec d’une tâche n’annule pas les autres. Par défaut, le premier échec arrête l’exécution ; stopOnError: false laisse les dépôts indépendants aller au bout.

Ce qui s’est passéCe que vous faites
Une tâche est failedLisez task.error dans result.tasks. Son worktree reste sous .outpost/workspaces/ dans ce checkout, avec le travail de l’agent.
D’autres tâches sont cancelledElles tournaient ou attendaient quand le premier échec a arrêté l’exécution. Leurs worktrees restent aussi. Passez stopOnError: false pour les laisser finir.
Une tâche dépendante est skippedElle n’a pas tourné, car une tâche de son after n’a pas réussi.
Certains dépôts sont done, un autre nonLeurs branches restent telles quelles. Gardez-les, ou supprimez-les vous-même.
Vous relancez le script après une correctionToutes les tâches repartent, y compris celles déjà done. Une branche named reprend son worktree conservé tel quel.

Pour ne relancer que les tâches inachevées, ajoutez un checkpoint : Exécutions durables. Récupérer du travail inspecte les worktrees conservés.

Outpost ne pousse rien. Placez le push ou le merge dans une tâche située après une étape d’approbation defineApprovalTask() dont le after liste chaque tâche de dépôt.

Une étape d’approbation exige un checkpoint, et les checkpoints ne contiennent que du JSON. Enveloppez chaque tâche isolée dans un defineTask() qui garde repository, branch et commits. Modifier plusieurs dépôts en donne l’exemple complet, avec l’approbation.

  • Aucune opération Git ne couvre plusieurs dépôts : ni commit commun, ni rollback, ni push.
  • Le résultat d’une tâche isolée n’est pas du JSON : il ne peut être ni mis en cache ni placé dans un checkpoint sans tâche d’enveloppe.

API : defineIsolatedTask · defineWorkflow · WorkflowOptions · TaskContext · WorkflowResult.