Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f81b7c585 | ||
|
|
0a12c617b2 | ||
|
|
ee490f5eaf | ||
|
|
79e032b563 | ||
|
|
d0f52eb7c0 | ||
|
|
38d38d51e3 |
@@ -1,28 +1,30 @@
|
||||
# Gitea Actions : pipeline de release (issue #42).
|
||||
#
|
||||
# Sur chaque tag v* : construit les binaires de toutes les plateformes,
|
||||
# archive + publie la release Gitea avec les artefacts. Les installateurs
|
||||
# (install.sh / install.ps1) et 'am self-update' consomment ces artefacts.
|
||||
# Sur chaque tag v* : construit les binaires de toutes les plateformes.
|
||||
# Le job principal 'release' cross-compile Linux + Windows depuis un seul
|
||||
# runner ubuntu-latest, donc il n'a pas besoin de runners Windows/macOS.
|
||||
# Le job 'macos' est optionnel : s'il y a un runner macos-latest, il ajoute
|
||||
# les archives macOS a la release existante ; sinon l'installateur retombe
|
||||
# sur cargo install --git sur macOS.
|
||||
#
|
||||
# Labels de runners attendus : ubuntu-latest, windows-latest, macos-latest.
|
||||
# Un runner manquant laisse son job en attente ; le job linux couvre la
|
||||
# majorite des cas (les artefacts windows/macos peuvent aussi etre produits
|
||||
# par les scripts locaux documentes dans RELEASING.md).
|
||||
# Les installateurs one-liner (install.sh / install.ps1) et 'am self-update'
|
||||
# consomment les artefacts attaches a la release.
|
||||
#
|
||||
# Prérequis du runner : pouvoir tirer les images docker.io (rust:1.94-alpine,
|
||||
# ~300 Mo) et le secret GITEA_TOKEN (jeton avec droit 'write:release')
|
||||
# positionné sur le dépôt. La release existante est écrasée
|
||||
# (release_overwrite).
|
||||
# Cross-compilation utilisee :
|
||||
# - Linux x86_64 + aarch64 : cargo-zigbuild + musl (binaires statiques)
|
||||
# - Windows x86_64 : mingw-w64 + x86_64-pc-windows-gnu
|
||||
#
|
||||
# Prerequis du runner : pouvoir tirer l'image docker.io (rust:1.94-bookworm,
|
||||
# ~1,2 Go) et le secret GITEA_TOKEN (jeton avec droit 'write:release')
|
||||
# positionne sur le depot.
|
||||
#
|
||||
# Note disque (runner avec espace limite) :
|
||||
# - il faut ~1 Go libres sur / pour tirer l'image (rust:1.94-alpine) ;
|
||||
# - il faut ~2 Go libres sur / pour tirer l'image (rust:1.94-bookworm) ;
|
||||
# en cas de 'no space left on device' : docker system prune -af --volumes
|
||||
# sur l'HOTE du runner (pas une autre machine !) ;
|
||||
# - les builds compilent dans CARGO_TARGET_DIR=/tmp (hors du volume
|
||||
# workspace) avec l'incremental desactive, donc rien ne persiste ;
|
||||
# - le job linux utilise cargo-zigbuild : zig (~50 Mo) fournit le linker
|
||||
# croise pour les DEUX cibles musl statiques dans une seule image legere
|
||||
# (rust:1.94-alpine n'embarque pas de compilateur croise aarch64).
|
||||
# - zig (~50 Mo) fournit le linker croise pour Linux.
|
||||
name: release
|
||||
|
||||
on:
|
||||
@@ -35,41 +37,56 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
container: rust:1.94-alpine
|
||||
container: rust:1.94-bookworm
|
||||
env:
|
||||
CARGO_TARGET_DIR: /tmp/am-target
|
||||
CARGO_INCREMENTAL: "0"
|
||||
steps:
|
||||
# actions/checkout (et son post-step) s'execute via node, absent de
|
||||
# l'image rust:alpine : sans nodejs le job echoue des le checkout.
|
||||
# l'image rust:bookworm par defaut : sans nodejs le job echoue des le checkout.
|
||||
- name: Prepare container (node for checkout action)
|
||||
run: apk add --no-cache nodejs
|
||||
run: apt-get update && apt-get install -y nodejs
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install build tools (zig + cargo-zigbuild)
|
||||
- name: Install build tools (zig + cargo-zigbuild + mingw)
|
||||
run: |
|
||||
apk add --no-cache build-base zip curl
|
||||
rustup target add x86_64-unknown-linux-musl aarch64-unknown-linux-musl
|
||||
apt-get update
|
||||
apt-get install -y build-essential mingw-w64 zip curl
|
||||
rustup target add \
|
||||
x86_64-unknown-linux-musl \
|
||||
aarch64-unknown-linux-musl \
|
||||
x86_64-pc-windows-gnu
|
||||
curl -fsSL https://ziglang.org/download/0.14.1/zig-x86_64-linux-0.14.1.tar.xz -o /tmp/zig.tar.xz
|
||||
tar -xf /tmp/zig.tar.xz -C /opt
|
||||
echo "/opt/zig-x86_64-linux-0.14.1" >> "$GITHUB_PATH"
|
||||
cargo install cargo-zigbuild --locked
|
||||
# Contourne un bug de casse dans certaines crates Windows
|
||||
# (ex. windows-sys peut emettre -lKernel32 au lieu de -lkernel32).
|
||||
# Le linker MinGW sous Linux est sensible a la casse.
|
||||
ln -sf /usr/x86_64-w64-mingw32/lib/libkernel32.a \
|
||||
/usr/x86_64-w64-mingw32/lib/libKernel32.a
|
||||
|
||||
- name: Build linux x86_64 + aarch64 (static musl, zig)
|
||||
run: cargo zigbuild --release --locked --target x86_64-unknown-linux-musl --target aarch64-unknown-linux-musl
|
||||
|
||||
- name: Build windows x86_64 (mingw)
|
||||
run: cargo build --release --locked --target x86_64-pc-windows-gnu
|
||||
|
||||
- name: Stage archives
|
||||
run: |
|
||||
mkdir -p dist
|
||||
cp "$CARGO_TARGET_DIR/x86_64-unknown-linux-musl/release/am" dist/am-linux-x86_64
|
||||
cp "$CARGO_TARGET_DIR/aarch64-unknown-linux-musl/release/am" dist/am-linux-aarch64
|
||||
cp "$CARGO_TARGET_DIR/x86_64-pc-windows-gnu/release/am.exe" dist/am-windows-x86_64.exe
|
||||
cd dist
|
||||
tar -czf am-linux-x86_64.tar.gz am-linux-x86_64
|
||||
tar -czf am-linux-aarch64.tar.gz am-linux-aarch64
|
||||
sha256sum am-linux-*.tar.gz > checksums.txt
|
||||
zip -q am-windows-x86_64.zip am-windows-x86_64.exe
|
||||
rm am-windows-x86_64.exe
|
||||
sha256sum am-linux-*.tar.gz am-windows-*.zip > checksums.txt
|
||||
|
||||
- name: Publish release
|
||||
uses: https://gitea.com/actions/gitea-release-action@v1
|
||||
@@ -80,37 +97,16 @@ jobs:
|
||||
files: |
|
||||
dist/am-linux-x86_64.tar.gz
|
||||
dist/am-linux-aarch64.tar.gz
|
||||
dist/checksums.txt
|
||||
GITHUB_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
release_overwrite: true
|
||||
|
||||
windows:
|
||||
runs-on: windows-latest
|
||||
env:
|
||||
CARGO_TARGET_DIR: C:/am-target
|
||||
CARGO_INCREMENTAL: "0"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build windows x86_64
|
||||
run: cargo build --release --locked
|
||||
|
||||
- name: Stage archive
|
||||
run: |
|
||||
New-Item -ItemType Directory -Force dist | Out-Null
|
||||
Compress-Archive -Path C:/am-target/release/am.exe -DestinationPath dist/am-windows-x86_64.zip -Force
|
||||
(Get-FileHash dist/am-windows-x86_64.zip -Algorithm SHA256).Hash.ToLower() | Out-File dist/checksums.txt
|
||||
|
||||
- name: Publish release
|
||||
uses: https://gitea.com/actions/gitea-release-action@v1
|
||||
with:
|
||||
files: |
|
||||
dist/am-windows-x86_64.zip
|
||||
dist/checksums.txt
|
||||
GITHUB_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
release_overwrite: true
|
||||
|
||||
macos:
|
||||
# Optionnel : ajoute les archives macOS si un runner macos-latest est
|
||||
# disponible. Sinon ce job reste en attente, mais le job release a deja
|
||||
# publie Linux + Windows.
|
||||
needs: release
|
||||
runs-on: macos-latest
|
||||
env:
|
||||
CARGO_TARGET_DIR: /tmp/am-target
|
||||
@@ -132,7 +128,7 @@ jobs:
|
||||
cd dist
|
||||
tar -czf am-macos-x86_64.tar.gz am-macos-x86_64
|
||||
tar -czf am-macos-aarch64.tar.gz am-macos-aarch64
|
||||
shasum -a 256 am-*.tar.gz > checksums.txt
|
||||
shasum -a 256 am-macos-*.tar.gz > checksums-macos.txt
|
||||
|
||||
- name: Publish release
|
||||
uses: https://gitea.com/actions/gitea-release-action@v1
|
||||
@@ -140,6 +136,8 @@ jobs:
|
||||
files: |
|
||||
dist/am-macos-x86_64.tar.gz
|
||||
dist/am-macos-aarch64.tar.gz
|
||||
dist/checksums.txt
|
||||
dist/checksums-macos.txt
|
||||
GITHUB_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
release_overwrite: true
|
||||
# false = ajoute les assets macOS a la release creee par le job
|
||||
# principal, sans ecraser Linux + Windows.
|
||||
release_overwrite: false
|
||||
|
||||
+98
-2
@@ -15,6 +15,7 @@
|
||||
- 🚀 Les démarrer, arrêter, redémarrer en avant-plan ou en arrière-plan
|
||||
- 🔍 Observer leur état, leurs logs, leurs statistiques d'utilisation
|
||||
- 🛠️ Gérer dépendances, alias, groupes, profils, secrets, favoris et annotations
|
||||
- ⚡ Exécuter des actions shell via langage naturel avec un agent léger (`am ai`)
|
||||
|
||||
Le tout sans toucher au système : chaque agent est installé dans un répertoire utilisateur isolé.
|
||||
|
||||
@@ -35,6 +36,7 @@ flowchart TB
|
||||
APP["App<br/>contexte partagé"]
|
||||
CLI_DEF["cli.rs<br/>définition des commandes"]
|
||||
CMD["commands/<br/>dispatch"]
|
||||
SHELL_AI["shell_ai.rs<br/>agent shell léger"]
|
||||
end
|
||||
|
||||
subgraph DATA["💾 Données persistantes"]
|
||||
@@ -62,7 +64,9 @@ flowchart TB
|
||||
CLI --> APP
|
||||
REPL --> APP
|
||||
TUI --> APP
|
||||
WEB --> APP
|
||||
APP --> CLI_DEF
|
||||
APP --> SHELL_AI
|
||||
APP --> CONFIG
|
||||
APP --> CATALOG
|
||||
APP --> STATE
|
||||
@@ -76,6 +80,7 @@ flowchart TB
|
||||
CMD --> DASH
|
||||
CMD --> STATS
|
||||
CMD --> SESSIONS
|
||||
SHELL_AI --> CMD
|
||||
```
|
||||
|
||||
---
|
||||
@@ -131,6 +136,7 @@ src/
|
||||
├── app.rs 🧰 Contexte App (config, state, paths, logger, theme)
|
||||
├── config.rs ⚙️ Schéma YAML, chargement, fusion, validation
|
||||
├── catalog.rs 🔍 Index agents + recherche fuzzy + suggestions
|
||||
├── catalog_remote.rs 🌐 Catalogues distants (fetch, cache, includes)
|
||||
├── state.rs 💾 Base JSON des installations et annotations
|
||||
├── events.rs 📝 Journal d'événements JSONL
|
||||
├── runner.rs 🏃 Trait d'exécution système / mock
|
||||
@@ -149,15 +155,34 @@ src/
|
||||
├── tables.rs 📋 Rendu tabulaire
|
||||
├── theme.rs 🎨 Thèmes de couleur (REPL et tableaux)
|
||||
├── web.rs 🌐 Serveur HTTP local (127.0.0.1) + API JSON + frontend embarqué
|
||||
├── serve.rs 🚀 API HTTP + WebSocket authentifiée (pilotage à distance, issue #80)
|
||||
├── frontend/ 📄 index.html — dashboard web (HTML5 + CSS + JS vanilla, include_str!)
|
||||
├── history.rs ⏪ Historique des commandes
|
||||
├── sessions.rs 📅 Registre des sessions
|
||||
├── projects.rs 🗂️️ Agrégation par projet
|
||||
├── hooks.rs 🪝 Hooks de cycle de vie
|
||||
├── secrets.rs 🔒 Gestion des secrets (keyring OS)
|
||||
├── providers.rs 🏷️ Registre de providers LLM (base_url, modèles, défaut, @secret)
|
||||
├── registry.rs 📦 Registre communautaire de catalogues (manifeste + sha256)
|
||||
├── ask.rs 💬 Langage naturel → commandes am (règles locales + LLM optionnel)
|
||||
├── sandbox.rs 🛡️ Profils sandbox par agent (allowlist, périmètre, réseau)
|
||||
├── telemetry.rs 📈 Télémétrie anonyme opt-in (compteurs agrégés)
|
||||
├── lab.rs 🧪 Benchmark d'agents (tâches YAML versionnables)
|
||||
├── playbook.rs ▶️ Rejeu pas à pas d'une séquence d'historique
|
||||
├── plugins.rs 🔌 Scripts d'extension sur les événements (contrat JSON)
|
||||
├── models.rs 🤖 Inventaire des modèles locaux (ollama, llama.cpp, LM Studio)
|
||||
├── shell_ai.rs ⚡ Agent shell léger : langage naturel → action shell
|
||||
├── sync.rs 🔄 Push git de l'état (journal, sessions, config)
|
||||
├── agent_config.rs ⚙️ Adaptateurs de configuration post-install (TOML/YAML/JSON/key=value)
|
||||
├── costs.rs 💰 Coûts estimés par agent (tokens in/out, modèles de prix)
|
||||
├── automation.rs ⚙️ Services système + tâches planifiées (systemd/launchd/schtasks)
|
||||
├── backup.rs 💾 Sauvegardes (update --rollback, migrate)
|
||||
├── doctor.rs 🩺 Diagnostics environnement + --fix
|
||||
├── nav.rs 🧭 Tables de navigation (ls/dir)
|
||||
├── i18n.rs 🌍 Catalogue de traductions FR/EN (--lang, AM_LANG, LANG)
|
||||
├── version.rs 🏷️ Informations de version
|
||||
├── commands/ 📦 35 modules, un par commande
|
||||
└── installers/ 📦 9 installateurs spécialisés
|
||||
├── commands/ 📦 51 modules, un par commande
|
||||
└── installers/ 📦 8 installateurs spécialisés
|
||||
```
|
||||
|
||||
---
|
||||
@@ -435,6 +460,26 @@ flowchart TB
|
||||
| `am version` | Version et build |
|
||||
| `am` (sans commande) | REPL interactif |
|
||||
|
||||
### 🤖 Copilote & plateforme (v0.7.0 / v1.0)
|
||||
|
||||
| Commande | Description |
|
||||
|----------|-------------|
|
||||
| `am ask "<demande>"` | Langage naturel → commande(s) am : règles locales FR/EN hors-ligne, raffinement LLM optionnel (`settings.ask`), confirmation avant exécution |
|
||||
| `am providers list/add/remove/set-token` | Registre LLM centralisé (base_url, modèles, clé par provider au keyring, résolution `@secret`) |
|
||||
| `am registry publish/search/install` | Registre communautaire de catalogues (Gitea, manifeste + checksum sha256 vérifié) |
|
||||
| `am serve --token [--port]` | API HTTP + WebSocket authentifiée : stats, run, start, stop, ask — rate limiting par IP, TLS derrière reverse proxy |
|
||||
| `am web [--port]` | Dashboard web local en lecture seule (127.0.0.1), contrats `--json` réutilisés |
|
||||
| `am ai "<prompt>" [--exec] [--files <path>]` | **Shell AI** : langage naturel → commande/action shell via agent léger (AIChat) ; `--dry-run` par défaut, confirmation avant exécution |
|
||||
| `am lab --agents a,b --task <f>` | Benchmark comparatif (durée, exit, coût) sur tâches YAML versionnables |
|
||||
| `am sync [--message]` | Sauvegarde git de l'état (journal, sessions, config — secrets exclus) |
|
||||
| `am migrate export/import` | Bundle de transfert machine A → B (config + état + historique) |
|
||||
| `am schedule add/list/remove/run` | Planification de commandes am (cron / Task Scheduler, issue #56) |
|
||||
| `am service install <agent>` | Service système (systemd / launchd / tâche Windows, autostart) |
|
||||
| `am monitor [--json]` | TUI temps réel des processus gérés (CPU/RSS/uptime) + alertes de seuils |
|
||||
| `am models [--prune]` | Inventaire des modèles locaux (ollama, llama.cpp, LM Studio) |
|
||||
| `am audit` | Qui a modifié quoi, quand (checksums config + journal) |
|
||||
| `am plugins [--test <nom>]` | Scripts d'extension sur les événements (contrat JSON stdin/stdout) |
|
||||
|
||||
---
|
||||
|
||||
## 🌐 Options globales
|
||||
@@ -673,6 +718,57 @@ flowchart LR
|
||||
|
||||
---
|
||||
|
||||
## ⚡ Shell AI
|
||||
|
||||
`am ai` (alias `am shell`) est une commande dédiée aux **actions shell via langage naturel**. Elle repose sur un agent léger (par défaut **AIChat**, installé comme n'importe quel autre agent via le catalogue) et réutilise le registre de providers LLM (`providers.rs`) pour choisir le modèle le plus rapide/cheap.
|
||||
|
||||
### Flux d'exécution
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
participant User
|
||||
participant cli as cli.rs
|
||||
participant shell_ai as shell_ai.rs
|
||||
participant catalog as catalog.rs
|
||||
participant providers as providers.rs
|
||||
participant runner as runner.rs
|
||||
participant aichat as aichat (agent)
|
||||
|
||||
User->>cli: am ai "traite les JSON"
|
||||
cli->>shell_ai: parse args (--exec, --files)
|
||||
shell_ai->>catalog: agent "aichat" installé ?
|
||||
catalog-->>shell_ai: Ok / install
|
||||
shell_ai->>providers: provider & modèle par défaut
|
||||
providers-->>shell_ai: config (ollama / cheap cloud)
|
||||
shell_ai->>shell_ai: injecte cwd + fichiers (--files)
|
||||
shell_ai->>runner: exec aichat -f . -e "..."
|
||||
runner->>aichat: lancement processus
|
||||
aichat-->>runner: commande générée / exécutée
|
||||
runner-->>shell_ai: output + exit code
|
||||
shell_ai->>shell_ai: journalise événement shell_ai
|
||||
shell_ai-->>User: résultat ou confirmation
|
||||
```
|
||||
|
||||
### Sécurité
|
||||
|
||||
| Règle | Détail |
|
||||
|---|---|
|
||||
| `--dry-run` par défaut | Aucune commande modifiante n'est exécutée sans confirmation |
|
||||
| Classification risk/certainty | Inspiré d'AI CLI : chaque commande est classée `safe` ou `risky` |
|
||||
| Confirmation utilisateur | Les commandes `risky` demandent une validation explicite |
|
||||
| Mode local possible | Support d'Ollama via `providers.rs` pour ne pas sortir les données |
|
||||
|
||||
### Dépendances
|
||||
|
||||
- `src/shell_ai.rs` : parsing du prompt, gestion des flags, appel à l'agent
|
||||
- `src/providers.rs` : résolution du provider/modèle
|
||||
- `src/runner.rs` : exécution du binaire `aichat`
|
||||
- `src/events.rs` : journalisation `shell_ai` dans le journal JSONL
|
||||
- `config.yaml` : définition de l'agent `aichat` + alias `ai`
|
||||
|
||||
---
|
||||
|
||||
## 📚 Références
|
||||
|
||||
- `src/lib.rs:4` : documentation d'architecture du crate
|
||||
|
||||
Generated
+1
-1
@@ -21,7 +21,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "agent-manager"
|
||||
version = "1.0.1"
|
||||
version = "1.0.4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "agent-manager"
|
||||
version = "1.0.1"
|
||||
version = "1.0.4"
|
||||
edition = "2021"
|
||||
description = "Manage local AI coding agents: list, install, start, stop, update — with automatic dependency handling and a YAML-driven catalog."
|
||||
license = "MIT"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 🚀 agent-manager — vos agents IA, gérés comme des apps
|
||||
|
||||
**am** liste, installe, démarre, met à jour et désinstalle vos agents IA de
|
||||
coding (Claude Code, Codex, Aider, jcode, Prime Agent… **72 agents connus**)
|
||||
coding (Claude Code, Codex, Aider, jcode, Prime Agent… **77 agents connus**)
|
||||
en une ligne de commande — avec la gestion des dépendances (Node.js, Python,
|
||||
Go, Rust…) prise en charge pour vous.
|
||||
|
||||
@@ -11,7 +11,7 @@ Go, Rust…) prise en charge pour vous.
|
||||
|
||||
## ✨ Pourquoi am ?
|
||||
|
||||
- 🗂️ **Catalogue de 72 agents prêts à l'emploi** — descriptions, méthodes
|
||||
- 🗂️ **Catalogue de 77 agents prêts à l'emploi** — descriptions, méthodes
|
||||
d'installation, dépendances et commandes de démarrage déjà configurées.
|
||||
- 📦 **9 méthodes d'installation** — npm, pip, uv, cargo, go, bun, script
|
||||
d'installation, binaire (GitHub Releases/Gitea) et dépôt git — toujours
|
||||
@@ -78,11 +78,14 @@ plateforme, il compile automatiquement depuis les sources.
|
||||
| am list --all | tout le catalogue, avec l'état de chacun |
|
||||
| am search <mot-clé> | recherche fuzzy : tolère les fautes de frappe, classe par pertinence, propose « vouliez-vous dire » |
|
||||
| am suggest <requête> | recommande un agent pour une demande en langage naturel (tags + usage réel) |
|
||||
| am ask "<demande>" | langage naturel → commande(s) am : règles locales hors-ligne, raffinement LLM optionnel (settings.ask), confirmation avant exécution — ex: am ask "installe claude et lance-le" |
|
||||
| am info <agent> | fiche détaillée (installation, dépendances, site…) |
|
||||
| am status [agent] | état, version, PID, logs |
|
||||
| am models | inventaire des modèles locaux (ollama, llama.cpp, LM Studio) |
|
||||
| am models --prune | purge des modèles inutilisés (--dry-run : simulation) |
|
||||
| am providers list / add / set-token | registre LLM centralisé : base_url, modèles par provider, clé dans le trousseau (jamais en clair, résolue via @secret) |
|
||||
| am catalog update / add <url> | catalogue distant : rafraîchit l'officiel ou ajoute un catalogue d'équipe |
|
||||
| am registry publish/search/install | registre communautaire de catalogues (Gitea) : publication, recherche, installation avec checksum sha256 vérifié et décision de confiance explicite |
|
||||
| am audit | qui a modifié quoi, quand (checksums config + journal) |
|
||||
| am sessions --export <id> | export d'une session (métadonnées + commandes + extrait de log) |
|
||||
| am sessions --retention <jours> | purge des sessions terminées au-delà de N jours |
|
||||
@@ -127,7 +130,7 @@ Les variables d'environnement `AGENT_MANAGER_DATA`, `AGENT_MANAGER_STATE` et `AG
|
||||
|
||||
#### Cycle d'installation (`am install <agent>`)
|
||||
|
||||
1. **Résolution du catalogue** — `am` fusionne le catalogue embarqué (72 agents) avec `~/.config/agent-manager/config.yaml` et un éventuel `./agent-manager.yaml`. Vos définitions remplacent les entrées par défaut du même nom.
|
||||
1. **Résolution du catalogue** — `am` fusionne le catalogue embarqué (77 agents) avec `~/.config/agent-manager/config.yaml` et un éventuel `./agent-manager.yaml`. Vos définitions remplacent les entrées par défaut du même nom.
|
||||
2. **Vérification des dépendances** — les outils requis (`node`, `python`, `uv`, `cargo`, `go`, `bun`, `git`...) sont détectés sur le `PATH`. S'il en manque, `am` détecte l'OS et propose la commande d'installation (`scoop`, `winget`, `apt`, `dnf`, `pacman`, `brew`...). Avec `--yes` ou `settings.auto_install_deps: true`, il peut l'exécuter à votre place.
|
||||
3. **Choix de la méthode** — chaque agent déclare une méthode principale et des alternatives. `--method <nom>` force le choix ; sinon `am` prend la première disponible. Pour `am update`, c'est la méthode utilisée lors de l'installation initiale qui est reconstruite.
|
||||
4. **Exécution de l'installateur** — selon le type, les commandes réelles lancées sont :
|
||||
@@ -207,6 +210,7 @@ Les variables d'environnement `AGENT_MANAGER_DATA`, `AGENT_MANAGER_STATE` et `AG
|
||||
| am config show / edit / add / set | gère votre configuration (hooks on_start/on_stop/… dans settings.hooks) |
|
||||
| am open <agent> | ouvre le répertoire d'installation dans l'explorateur |
|
||||
| am completion <shell> [--installed] | script de complétion (bash, zsh, fish, powershell, elvish) ; --installed complète dynamiquement les agents installés, alias et groupes |
|
||||
| am serve --token [--port <p>] | API HTTP + WebSocket authentifiée pour piloter am à distance (stats, run, start, stop, ask…) — rate limiting par IP, TLS via reverse proxy |
|
||||
| am self-update | met à jour am lui-même (si configuré) |
|
||||
| am self-uninstall | désinstalle am et tout ce qu'il a créé (confirmation) |
|
||||
| am | shell interactif : bannière, passerelle système, Tab et historique |
|
||||
@@ -351,7 +355,7 @@ supprimez aussi ces emplacements.)
|
||||
1. --config <fichier>
|
||||
2. ./agent-manager.yaml (répertoire courant)
|
||||
3. ~/.config/agent-manager/config.yaml
|
||||
4. catalogue embarqué (72 agents)
|
||||
4. catalogue embarqué (77 agents)
|
||||
|
||||
Vos définitions **complètent ou surchargent** le catalogue par nom.
|
||||
|
||||
|
||||
+115
-7
@@ -1,6 +1,7 @@
|
||||
# 🗺️ ROADMAP agent-manager — vers le « super outil »
|
||||
|
||||
> **Version du document : 2.2** · Statut : propositions, non engagées
|
||||
> **Version du document : 2.4** · Statut : phases 0 à 3 livrées
|
||||
> (v0.3.0 → v1.0.1), maintenance v1.0.2 → v1.0.4
|
||||
> Base : analyse du code **v0.2.7** (Rust, 45+ tests, zéro dépendance runtime)
|
||||
>
|
||||
> ✅ **Phase 0 livrée en v0.3.0 (2026-08-17)** : issues #2 à #16 clôturées,
|
||||
@@ -18,8 +19,25 @@
|
||||
> (#47–#75), 250+ tests. am web, i18n, services, schedule, lab, sync,
|
||||
> migrate, models, plugins d'événements… Binaires publiés sur Gitea.
|
||||
>
|
||||
> 🔨 **Phase v0.7.0 en cours (priorité P0)** : providers & configuration
|
||||
> automatisée (épique #87) — livrée AVANT la Phase 3 (v1.0), voir section 7 bis.
|
||||
> ✅ **Phase v0.7.0 livrée (2026-08-19)** : 5/5 issues clôturées (#88–#92) —
|
||||
> registre de providers LLM (am providers), secrets partagés par provider,
|
||||
> flags --provider/--model/--no-config à l'install, configuration
|
||||
> post-install (bloc config:).
|
||||
>
|
||||
> ✅ **Phase 3 livrée en v1.0.0 (2026-08-20)** : 5/5 issues clôturées
|
||||
> (#76–#80) — télémétrie opt-in, am registry, am ask, profils sandbox,
|
||||
> am serve (API HTTP + WebSocket). v1.0.1 : self-update décompresse les
|
||||
> archives, prompt REPL avec shell actif.
|
||||
>
|
||||
> 🔧 **Maintenance v1.0.3 (2026-08-20)** : commandes REPL ask/serve/registry
|
||||
> routées vers am (v1.0.2) ; détection externe corrigée — champ `detect`
|
||||
> (sonde PATH explicite) pour les lanceurs interpréteurs (npx/python),
|
||||
> plus de faux « external » ; docs alignées.
|
||||
>
|
||||
> 🔧 **Maintenance v1.0.4 (2026-08-20)** : catalogue enrichi — 5 agents
|
||||
> **shell-ai** ajoutés (issues #94 #95) : AIChat (alias `ai`, binaire GitHub
|
||||
> Release), ShellGPT (pip), Fabric (go), Shell AI (npm/Ollama), AI CLI
|
||||
> (binaire, politique de sécurité risk/certainty). Catalogue : 77 agents.
|
||||
|
||||
---
|
||||
|
||||
@@ -41,7 +59,7 @@
|
||||
|
||||
## 1. 📌 Résumé exécutif
|
||||
|
||||
**am** est aujourd'hui un excellent *gestionnaire* d'agents : 72 agents au
|
||||
**am** est aujourd'hui un excellent *gestionnaire* d'agents : 77 agents au
|
||||
catalogue, 9 méthodes d'installation, dépendances résolues automatiquement,
|
||||
processus pilotés, REPL avec passerelle shell, sauvegarde export/import.
|
||||
|
||||
@@ -103,7 +121,7 @@ quelques jours, à caler avant ou pendant la construction du journal.*
|
||||
|
||||
| Brique actuelle | Fichier | Limite aujourd'hui |
|
||||
|---|---|---|
|
||||
| Catalogue 72 agents, alias, groupes | src/catalog.rs, config.yaml | recherche = sous-chaîne stricte, pas de ranking |
|
||||
| Catalogue 77 agents, alias, groupes | src/catalog.rs, config.yaml | recherche = sous-chaîne stricte, pas de ranking |
|
||||
| Installation (9 méthodes), dépendances OS | src/installers/, src/deps.rs, src/toolchain.rs | solide — rien à redire |
|
||||
| État local | src/state.rs (state.json v1) | installations + PID courant uniquement, **aucun historique** |
|
||||
| Détection externe + cache | src/probe.rs | excellent pattern de cache — à généraliser |
|
||||
@@ -333,6 +351,95 @@ consultable, reprenable, archivable.
|
||||
| i18n : messages EN/FR | L | P2 |
|
||||
| Plugin scripts (hooks avancés, intégration CI) | M | P2 |
|
||||
|
||||
---
|
||||
|
||||
### Axe 13 — ⚡ Shell AI & Action ⭐
|
||||
|
||||
🎯 Transformer une commande en langage naturel en une action shell exécutée par un agent léger, rapide et contextuel, sans démarrer un gros coding agent.
|
||||
|
||||
**Contexte :** `am` gère aujourd'hui ~77 agents IA, principalement des *coding agents*, des assistants et des outils SaaS. Les shell assistants sont maintenant au catalogue (AIChat, ShellGPT, Fabric, Shell AI, AI CLI — v1.0.4) : légers, rapides, conçus pour transformer une phrase en commande ou action sur le système de fichiers local (ex. *"traite les fichiers JSON du dossier courant pour extraire les clés uniques"*).
|
||||
|
||||
---
|
||||
|
||||
#### 13.1 Agents shell AI découverts (✅ tous ajoutés au catalogue — v1.0.4, issues #94 #95)
|
||||
|
||||
| Outil | Repo | Langage | Force | Maturité |
|
||||
|---|---|---|---|---|
|
||||
| ✅ **AIChat** | `sigoden/aichat` | Rust | Shell assistant natif, RAG, agents, fichiers/répertoires, 20+ providers | **10.4k stars**, très actif |
|
||||
| ✅ **ShellGPT** | `TheR1D/shell_gpt` | Python | Génère/exécute commandes shell, code, docs | Très connu, mature |
|
||||
| ✅ **Fabric** | `danielmiessler/fabric` | Go | Patterns AI (summarize, extract wisdom), CLI | Très populaire, orienté contenu/texte |
|
||||
| ✅ **Shell AI** | `nishant9083/shell-ai` | TypeScript | Agent ReAct local via Ollama, MCP, filesystem tools | Plus récent, prometteur mais jeune |
|
||||
| ✅ **AI CLI** | `kriserickson/ai-cli` | Go | Natural language → commandes shell avec safety policy (`risk` / `certainty`) | Petit, simple, moins connu |
|
||||
|
||||
---
|
||||
|
||||
#### 13.2 Recommandation : AIChat (`sigoden/aichat`)
|
||||
|
||||
**Choix privilégié pour la fonction Shell AI.**
|
||||
|
||||
| Avantage | Détails |
|
||||
|---|---|
|
||||
| **Léger & rapide** | Rust, binaire unique, cold start rapide, idéal pour RPi 4 |
|
||||
| **Shell Assistant natif** | Génère et exécute des commandes shell à partir du langage naturel |
|
||||
| **Multi-provider** | OpenAI, Claude, Gemini, DeepSeek, Groq, Ollama, OpenRouter… |
|
||||
| **Passage de contexte** | `aichat -f .` injecte le dossier ou les fichiers dans le prompt |
|
||||
| **Mode exécution** | `aichat -e "..."` exécute directement, mode conversationnel sinon |
|
||||
| **Facilité d'intégration** | Release binaire GitHub, installable via `binary` dans le catalogue |
|
||||
|
||||
Exemples d'usage ciblés :
|
||||
|
||||
```bash
|
||||
# Lister et traiter les fichiers JSON du dossier courant
|
||||
aichat -f . -e "liste tous les fichiers JSON et extrait les clés uniques"
|
||||
|
||||
# Résumer un dossier de fichiers
|
||||
aichat -f . "résume les données de ces fichiers JSON"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 13.3 Fonctionnalités prévues
|
||||
|
||||
| Fonctionnalité | Description | Effort | Phase |
|
||||
|---|---|---|---|
|
||||
| ✅ **Catalogue : ajouter AIChat** | Définition `AgentDef` + alias `ai` → `aichat` — livré en v1.0.4 (issues #94 #95) | S | P1 |
|
||||
| **Commande `am ai <prompt>`** | Lancer AIChat avec le dossier courant comme contexte | S | P3 |
|
||||
| **Flag `--exec` / `-e`** | Active le mode exécution directe (`aichat -e`) | S | P3 |
|
||||
| **Flag `--files <path>`** | Passer fichiers/dossiers spécifiques en contexte | S | P3 |
|
||||
| **Sécurité : `--dry-run` par défaut** | Simuler avant exécution ; confirmation si modification | M | P3 |
|
||||
| **Provider configurable** | Réutiliser le registre `providers.rs` (cheap model par défaut) | M | P3 |
|
||||
| **Alias intégrés** | `am shell`, `am do` comme synonymes | S | P3 |
|
||||
| **Extensions sœurs** | `am summarize`, `am explain`, `am fix` (voir ci-dessous) | M | P3 |
|
||||
|
||||
---
|
||||
|
||||
#### 13.4 Risques & garde-fous
|
||||
|
||||
| Risque | Mitigation |
|
||||
|---|---|
|
||||
| Exécution automatique de commandes dangereuses | `--dry-run` par défaut, confirmation obligatoire avant toute commande `risky` |
|
||||
| Coût API récurrent | Modèle cheap par défaut (`gpt-4.1-mini`, `gemini-flash`) ou Ollama local |
|
||||
| Fuite de données sensibles | Support du mode local Ollama, pas d'envoi hors du provider configuré |
|
||||
| Installation lente sur RPi | Utiliser l'installateur `binary` GitHub Releases plutôt que `cargo` |
|
||||
|
||||
---
|
||||
|
||||
#### 13.5 Idées sœurs (à intégrer ou lier à d'autres axes)
|
||||
|
||||
| Commande | Description | Axe lié |
|
||||
|---|---|---|
|
||||
| `am summarize <fichier/dossier>` | Résume un fichier ou un dossier via AIChat/Fabric | Axe 13 |
|
||||
| `am explain <commande>` | Explique une commande shell avant exécution | Axe 13 |
|
||||
| `am commit` | Génère un message de commit depuis `git diff` | Axe 13 / Axe 3 |
|
||||
| `am review` | Review rapide d'un diff ou d'une PR | Axe 7 |
|
||||
| `am translate <fichier> --to en` | Traduit un fichier markdown/doc | Axe 13 |
|
||||
| `am ask-code "..."` | Pose une question sur le codebase sans lancer un gros agent | Axe 7 |
|
||||
| `am doc <dossier>` | Génère un README/doc à partir du code | Axe 13 / Axe 7 |
|
||||
| `am fix` | Corrige une commande shell qui a échoué | Axe 13 |
|
||||
| `am note` | Extrait des action items d'un texte/réunion | Axe 10 |
|
||||
| `am search-web "..."` | Recherche web rapide et réponse synthétisée | Axe 7 |
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 8. 🚀 Jalons versionnés
|
||||
@@ -509,5 +616,6 @@ configuration manuelle (tokens au keyring, provider/modèle par défaut).
|
||||
---
|
||||
|
||||
*Document généré à partir de l'analyse du code (v0.2.7, commit d886de3).
|
||||
La phase 0 est livrée (v0.3.0) ; les découpages des phases 1 (v0.4.0),
|
||||
2 (v0.5.0) et 3 (v1.0) sont en place sur Gitea (issues #25 à #80).*
|
||||
Phases livrées : 0 (v0.3.0), 1 (v0.4.1), 2 (v0.6.0), v0.7.0 (providers,
|
||||
2026-08-19), 3 (v1.0.0, #76–#80, 2026-08-20) ; maintenance v1.0.1/v1.0.2
|
||||
(self-update décompression, REPL).*
|
||||
|
||||
+72
@@ -108,6 +108,7 @@ aliases:
|
||||
gjc: gajae-code
|
||||
tiny: tiny-agents
|
||||
continue: continue-cli
|
||||
ai: aichat
|
||||
|
||||
# --- Groups (start/stop/restart several agents together) ----------------------
|
||||
groups:
|
||||
@@ -798,6 +799,9 @@ agents:
|
||||
dependencies:
|
||||
- { name: node, min_version: "18.0.0", install_hint: "https://nodejs.org" }
|
||||
run: "npx lazycodex-ai"
|
||||
# Sonde PATH explicite : le premier mot de `run` est npx (interpréteur) —
|
||||
# sans `detect`, npx sur le PATH suffirait à déclarer l'agent « external ».
|
||||
detect: lazycodex-ai
|
||||
note: "s'intègre dans Codex (nécessite @openai/codex)"
|
||||
tags: [harness, codex, plan]
|
||||
|
||||
@@ -870,6 +874,71 @@ agents:
|
||||
note: "étapes de build spécifiques au repo — consultez son README"
|
||||
tags: [simulator, orchestration]
|
||||
|
||||
# ---------------------------------------------------------------- Shell AI
|
||||
- name: aichat
|
||||
display_name: "AIChat"
|
||||
description: "All-in-one LLM CLI avec Shell Assistant, Chat-REPL, RAG, AI Tools & Agents et support fichiers/répertoires (-f). Idéal pour exécuter des micro-tâches shell via langage naturel (issue #94)."
|
||||
category: shell-ai
|
||||
website: https://github.com/sigoden/aichat
|
||||
install:
|
||||
type: binary
|
||||
repo: sigoden/aichat
|
||||
binary: aichat
|
||||
run: aichat
|
||||
tags: [shell, rust, multi-provider, rag, local, fast]
|
||||
|
||||
- name: ai-cli
|
||||
display_name: "AI CLI"
|
||||
description: "Traduit le langage naturel en commandes shell (OpenAI, OpenRouter ou serveur local) avec politique de sécurité (risk / certainty) avant exécution (issue #95)."
|
||||
category: shell-ai
|
||||
website: https://github.com/kriserickson/ai-cli
|
||||
install:
|
||||
type: binary
|
||||
repo: kriserickson/ai-cli
|
||||
binary: ai
|
||||
run: ai
|
||||
tags: [shell, go, safety, multi-provider]
|
||||
|
||||
- name: fabric
|
||||
display_name: "Fabric"
|
||||
description: "Framework open source pour augmenter les humains avec l'IA : patterns réutilisables (summarize, extract wisdom, analyse de contenu), CLI Go 43k+ stars (issue #95)."
|
||||
category: shell-ai
|
||||
website: https://github.com/danielmiessler/fabric
|
||||
install:
|
||||
type: go
|
||||
package: github.com/danielmiessler/fabric/cmd/fabric@latest
|
||||
dependencies:
|
||||
- { name: go, min_version: "1.22.0", install_hint: "https://go.dev/dl" }
|
||||
run: fabric
|
||||
tags: [patterns, go, content]
|
||||
|
||||
- name: shell-ai
|
||||
display_name: "Shell AI"
|
||||
description: "Agent ReAct local-first propulsé par Ollama : zéro réseau, outils filesystem, exécution de commandes shell et intégration MCP (issue #95)."
|
||||
category: shell-ai
|
||||
website: https://github.com/nishant9083/shell-ai
|
||||
install:
|
||||
type: npm
|
||||
package: "@shell-ai/cli"
|
||||
dependencies:
|
||||
- { name: node, min_version: "18.0.0", install_hint: "https://nodejs.org" }
|
||||
run: shell-ai
|
||||
note: "nécessite Ollama et un modèle (ollama pull gpt-oss) — agent jeune (15 stars)"
|
||||
tags: [shell, ollama, local, mcp, typescript]
|
||||
|
||||
- name: shellgpt
|
||||
display_name: "ShellGPT"
|
||||
description: "Outil de productivité CLI propulsé par LLM (GPT-5…) : génère et exécute des commandes shell, écrit du code et des docs, 12k+ stars (issue #95)."
|
||||
category: shell-ai
|
||||
website: https://github.com/TheR1D/shell_gpt
|
||||
install:
|
||||
type: pip
|
||||
package: shell-gpt
|
||||
dependencies:
|
||||
- { name: python, min_version: "3.10.0", install_hint: "https://python.org" }
|
||||
run: sgpt
|
||||
tags: [shell, python, multi-provider]
|
||||
|
||||
# ----------------------------------------------------- Écosystème OpenClaw
|
||||
- name: openclaw
|
||||
display_name: "OpenClaw"
|
||||
@@ -895,6 +964,9 @@ agents:
|
||||
dependencies:
|
||||
- { name: python, min_version: "3.9.0", install_hint: "https://python.org" }
|
||||
run: "python -m nanobot"
|
||||
# Sonde PATH explicite : le premier mot de `run` est python (interpréteur) —
|
||||
# sans `detect`, /usr/bin/python suffirait à déclarer l'agent « external ».
|
||||
detect: nanobot
|
||||
tags: [python, lightweight]
|
||||
|
||||
- name: zeroclaw
|
||||
|
||||
+19
-3
@@ -22,6 +22,13 @@ case "$arch" in
|
||||
*) fail "architecture non supportée: $arch" ;;
|
||||
esac
|
||||
|
||||
os=$(uname -s | tr '[:upper:]' '[:lower:]')
|
||||
case "$os" in
|
||||
linux) platform="linux" ;;
|
||||
darwin) platform="macos" ;;
|
||||
*) fail "système non supporté: $os" ;;
|
||||
esac
|
||||
|
||||
install_from_source() {
|
||||
if ! command -v cargo >/dev/null 2>&1; then
|
||||
fail "pas de binaire précompilé pour $arch et cargo est absent — installez Rust (https://rustup.rs) puis relancez"
|
||||
@@ -45,14 +52,23 @@ fi
|
||||
|
||||
installed=""
|
||||
if [ -n "$tag" ] && command -v curl >/dev/null 2>&1; then
|
||||
asset="am-linux-$arch.tar.gz"
|
||||
asset="am-$platform-$arch.tar.gz"
|
||||
url="$BASE_URL/releases/download/$tag/$asset"
|
||||
echo "Téléchargement de $url …"
|
||||
if curl -fsSL --connect-timeout 20 -o "$tmpdir/am.tar.gz" "$url"; then
|
||||
tar -xzf "$tmpdir/am.tar.gz" -C "$tmpdir" 2>/dev/null || true
|
||||
if [ -f "$tmpdir/am" ]; then
|
||||
# L'entrée de l'archive varie selon le pipeline CI : « am » ou
|
||||
# « am-linux-x86_64 » (nom de la release). Prendre le premier fichier
|
||||
# extrait.
|
||||
bin=""
|
||||
for cand in "$tmpdir/am" "$tmpdir/am-$platform-$arch" "$tmpdir/am-$arch" "$tmpdir"/*; do
|
||||
if [ -f "$cand" ] && [ -z "$bin" ]; then
|
||||
bin="$cand"
|
||||
fi
|
||||
done
|
||||
if [ -n "$bin" ]; then
|
||||
mkdir -p "$INSTALL_DIR"
|
||||
cp "$tmpdir/am" "$INSTALL_DIR/am"
|
||||
cp "$bin" "$INSTALL_DIR/am"
|
||||
chmod +x "$INSTALL_DIR/am"
|
||||
installed=1
|
||||
fi
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.TH am 1 "am 1.0.0"
|
||||
.TH am 1 "am 1.0.3"
|
||||
.SH NAME
|
||||
am \- agent\-manager (am) — manage local AI coding agents
|
||||
.SH SYNOPSIS
|
||||
@@ -244,4 +244,4 @@ Export the configuration and installation state (backup)
|
||||
am\-import(1)
|
||||
Import a previously exported configuration and state
|
||||
.SH VERSION
|
||||
v1.0.0
|
||||
v1.0.3
|
||||
|
||||
@@ -12,9 +12,18 @@ $zip = "dist/am-windows-x86_64.zip"
|
||||
Remove-Item $zip -ErrorAction SilentlyContinue
|
||||
Compress-Archive -Path target/release/am.exe -DestinationPath $zip
|
||||
|
||||
function Get-Sha256Net([string]$path) {
|
||||
$stream = [System.IO.File]::OpenRead($path)
|
||||
try {
|
||||
$sha = [System.Security.Cryptography.SHA256]::Create()
|
||||
$bytes = $sha.ComputeHash($stream)
|
||||
return ([BitConverter]::ToString($bytes) -replace '-', '').ToLower()
|
||||
} finally { $stream.Close() }
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Artefacts:"
|
||||
Get-ChildItem dist | ForEach-Object {
|
||||
$hash = (Get-FileHash $_.FullName -Algorithm SHA256).Hash.ToLower()
|
||||
Get-ChildItem dist -File | ForEach-Object {
|
||||
$hash = Get-Sha256Net $_.FullName
|
||||
Write-Host (" {0,-32} {1} sha256:{2}" -f $_.Name, $_.Length, $hash)
|
||||
}
|
||||
|
||||
@@ -408,6 +408,7 @@ mod tests {
|
||||
install: None,
|
||||
dependencies: vec![],
|
||||
run: Some("x".to_string()),
|
||||
detect: None,
|
||||
args: vec![],
|
||||
env: BTreeMap::new(),
|
||||
version: None,
|
||||
|
||||
@@ -655,6 +655,7 @@ mod tests {
|
||||
install: None,
|
||||
dependencies: vec![],
|
||||
run: Some("demo".to_string()),
|
||||
detect: None,
|
||||
args: vec![],
|
||||
env: BTreeMap::new(),
|
||||
version: None,
|
||||
|
||||
@@ -190,6 +190,7 @@ mod tests {
|
||||
install: None,
|
||||
dependencies: vec![],
|
||||
run: Some(name.to_string()),
|
||||
detect: None,
|
||||
args: vec![],
|
||||
env: BTreeMap::new(),
|
||||
version: None,
|
||||
|
||||
@@ -103,6 +103,12 @@ pub static SECTIONS: &[TipSection] = &[
|
||||
options: &[("--json", "sortie machine-readable")],
|
||||
example: "suggest un agent pour du Python",
|
||||
},
|
||||
TipEntry {
|
||||
usage: "ask <demande>",
|
||||
about: "langage naturel → commande(s) am : règles locales hors-ligne, raffinement LLM optionnel (issue #78)",
|
||||
options: &[("--yes", "exécute la commande sans confirmation")],
|
||||
example: "ask installe claude et lance-le",
|
||||
},
|
||||
TipEntry {
|
||||
usage: "models",
|
||||
about: "inventaire des modèles locaux (ollama, llama.cpp, LM Studio)",
|
||||
@@ -119,6 +125,15 @@ pub static SECTIONS: &[TipSection] = &[
|
||||
options: &[("add <url>", "ajoute un catalogue d'équipe par URL")],
|
||||
example: "catalog add https://git.dracodev.net/team/agents.yaml",
|
||||
},
|
||||
TipEntry {
|
||||
usage: "registry publish <catalogue.yaml> --source <url>",
|
||||
about: "registre communautaire : publie, cherche ou installe un catalogue (manifeste + checksum sha256 vérifié)",
|
||||
options: &[
|
||||
("search <mot>", "cherche dans le registre"),
|
||||
("install <url>", "installe après vérification du checksum et décision de confiance"),
|
||||
],
|
||||
example: "registry search agents python",
|
||||
},
|
||||
TipEntry {
|
||||
usage: "audit",
|
||||
about: "qui a modifié quoi, quand (checksums config + journal d'événements)",
|
||||
@@ -251,6 +266,16 @@ pub static SECTIONS: &[TipSection] = &[
|
||||
],
|
||||
example: "web --port 9090",
|
||||
},
|
||||
TipEntry {
|
||||
usage: "serve --token <tok>",
|
||||
about: "API HTTP + WebSocket authentifiée pour piloter am à distance (stats, run, start, stop, ask) (issue #80)",
|
||||
options: &[
|
||||
("--port <p>", "port d'écoute (défaut 8080)"),
|
||||
("--host <h>", "adresse d'écoute (défaut 127.0.0.1)"),
|
||||
("--rate-limit <n>", "requêtes par IP et par minute (défaut 120)"),
|
||||
],
|
||||
example: "serve --token mon-token --port 9000",
|
||||
},
|
||||
TipEntry {
|
||||
usage: "sync",
|
||||
about: "pousse l'état (state.json, journal, historique) dans le dépôt git configuré (sync_repo)",
|
||||
|
||||
@@ -398,6 +398,13 @@ pub struct AgentDef {
|
||||
/// Command used to start the agent (e.g. "claude", "python -m nanobot").
|
||||
#[serde(default)]
|
||||
pub run: Option<String>,
|
||||
/// Binary name probed on the PATH for external detection. When unset,
|
||||
/// the first token of `run` is used — which is wrong for interpreter
|
||||
/// launchers ("npx pkg", "python -m pkg"): the interpreter itself would
|
||||
/// be matched, reporting the agent as present whenever node/python is
|
||||
/// on the PATH. Set it to the real entry point (e.g. "lazycodex-ai").
|
||||
#[serde(default)]
|
||||
pub detect: Option<String>,
|
||||
/// Default arguments appended to the run command.
|
||||
#[serde(default)]
|
||||
pub args: Vec<String>,
|
||||
@@ -516,6 +523,12 @@ impl AgentDef {
|
||||
})
|
||||
}
|
||||
|
||||
/// Binary probed on the PATH for external detection: the explicit
|
||||
/// `detect` name when set, otherwise the first token of `run`.
|
||||
pub fn detect_token(&self) -> Option<String> {
|
||||
self.detect.clone().or_else(|| self.first_token())
|
||||
}
|
||||
|
||||
/// The run command split into tokens (empty when unset).
|
||||
pub fn run_tokens(&self) -> Vec<String> {
|
||||
self.run
|
||||
@@ -1167,6 +1180,31 @@ mod tests {
|
||||
assert!(validate(&cfg).is_empty(), "embedded config invalid: {:?}", validate(&cfg));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn detect_token_prefers_explicit_binary() {
|
||||
// Interpreter launcher: without `detect`, the interpreter itself
|
||||
// would be probed (false "external" when node/python is on PATH).
|
||||
let a: AgentDef = serde_yaml::from_str(
|
||||
"name: lazycodex\nrun: \"npx lazycodex-ai\"\ndetect: lazycodex-ai\n",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(a.detect_token().as_deref(), Some("lazycodex-ai"));
|
||||
// No `detect`: falls back to the first token of run.
|
||||
let b: AgentDef =
|
||||
serde_yaml::from_str("name: nanobot\nrun: \"python -m nanobot\"\n").unwrap();
|
||||
assert_eq!(b.detect_token().as_deref(), Some("python"));
|
||||
assert_eq!(b.first_token().as_deref(), Some("python"));
|
||||
// Plain binary command is unchanged.
|
||||
let c: AgentDef = serde_yaml::from_str("name: claude\nrun: claude\n").unwrap();
|
||||
assert_eq!(c.detect_token().as_deref(), Some("claude"));
|
||||
// The embedded catalog must stay valid with the new field.
|
||||
let cfg: Config = serde_yaml::from_str(DEFAULT_CONFIG).unwrap();
|
||||
let lazy = cfg.agents.iter().find(|a| a.name == "lazycodex").unwrap();
|
||||
assert_eq!(lazy.detect_token().as_deref(), Some("lazycodex-ai"));
|
||||
let nano = cfg.agents.iter().find(|a| a.name == "nanobot").unwrap();
|
||||
assert_eq!(nano.detect_token().as_deref(), Some("nanobot"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expands_paths() {
|
||||
std::env::set_var("AM_TEST_EXPAND_VAR", "expanded-value");
|
||||
|
||||
+33
-5
@@ -79,6 +79,11 @@ struct ProbeCache {
|
||||
/// FNV-1a hash of the PATH string the token index was built from.
|
||||
#[serde(default)]
|
||||
path_hash: u64,
|
||||
/// FNV-1a hash of the catalog's detect tokens. When the catalog changes
|
||||
/// which binaries it probes (new agent, `detect` added), the token
|
||||
/// index must be rebuilt even if the PATH is unchanged.
|
||||
#[serde(default)]
|
||||
token_hash: u64,
|
||||
/// Catalog run-command first token -> resolved path (null = not found).
|
||||
#[serde(default)]
|
||||
tokens: BTreeMap<String, Option<String>>,
|
||||
@@ -98,6 +103,26 @@ fn path_hash() -> u64 {
|
||||
h
|
||||
}
|
||||
|
||||
/// Hash of the sorted catalog detect tokens: cache invalidation for catalog
|
||||
/// changes (new agent, added `detect` field) without re-scanning the PATH.
|
||||
fn catalog_token_hash(app: &App) -> u64 {
|
||||
let mut h: u64 = 0xcbf2_9ce4_8422_2325;
|
||||
let mut tokens: Vec<String> = app
|
||||
.catalog
|
||||
.agents()
|
||||
.iter()
|
||||
.filter_map(|a| a.detect_token())
|
||||
.collect();
|
||||
tokens.sort();
|
||||
for t in tokens {
|
||||
for b in t.bytes() {
|
||||
h ^= b as u64;
|
||||
h = h.wrapping_mul(0x0000_0100_0000_01b3);
|
||||
}
|
||||
}
|
||||
h
|
||||
}
|
||||
|
||||
/// Build an index of every executable on the PATH in a single pass.
|
||||
/// Much cheaper than one which() call per agent when the catalog is large.
|
||||
fn build_path_index() -> BTreeMap<String, PathBuf> {
|
||||
@@ -163,13 +188,15 @@ pub fn detect_externals(app: &App) -> ExternalInfo {
|
||||
.unwrap_or_default();
|
||||
let mut dirty = false;
|
||||
|
||||
// Resolve the run-command tokens of the catalog (once per PATH change).
|
||||
// Resolve the detect tokens of the catalog (once per PATH change or
|
||||
// catalog change).
|
||||
let current_hash = path_hash();
|
||||
if cache.path_hash != current_hash {
|
||||
let current_tokens = catalog_token_hash(app);
|
||||
if cache.path_hash != current_hash || cache.token_hash != current_tokens {
|
||||
let index = build_path_index();
|
||||
cache.tokens.clear();
|
||||
for agent in app.catalog.agents() {
|
||||
let Some(token) = agent.first_token() else {
|
||||
let Some(token) = agent.detect_token() else {
|
||||
continue;
|
||||
};
|
||||
if !cache.tokens.contains_key(&token) {
|
||||
@@ -180,6 +207,7 @@ pub fn detect_externals(app: &App) -> ExternalInfo {
|
||||
}
|
||||
}
|
||||
cache.path_hash = current_hash;
|
||||
cache.token_hash = current_tokens;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
@@ -195,7 +223,7 @@ pub fn detect_externals(app: &App) -> ExternalInfo {
|
||||
let index = build_path_index();
|
||||
cache.tokens.clear();
|
||||
for agent in app.catalog.agents() {
|
||||
let Some(token) = agent.first_token() else {
|
||||
let Some(token) = agent.detect_token() else {
|
||||
continue;
|
||||
};
|
||||
if !cache.tokens.contains_key(&token) {
|
||||
@@ -211,7 +239,7 @@ pub fn detect_externals(app: &App) -> ExternalInfo {
|
||||
if agent.hidden || !agent.installable || managed.contains_key(&agent.name) {
|
||||
continue;
|
||||
}
|
||||
let Some(token) = agent.first_token() else {
|
||||
let Some(token) = agent.detect_token() else {
|
||||
continue;
|
||||
};
|
||||
if let Some(Some(path)) = cache.tokens.get(&token) {
|
||||
|
||||
+6
-2
@@ -113,6 +113,7 @@ const COMMAND_DESCRIPTIONS: &[(&str, &str)] = &[
|
||||
("registry", "publish, search and install agent catalogs (Gitea)"),
|
||||
("providers", "manage the LLM provider registry (base URLs, models, default)"),
|
||||
("suggest", "recommend an agent for a request"),
|
||||
("ask", "natural language → am commands (local rules first, optional LLM refinement)"),
|
||||
("audit", "who changed what, when (config checksums)"),
|
||||
("service", "register an agent as a system service (autostart)"),
|
||||
("schedule", "plan am commands (daily) and check the fleet health"),
|
||||
@@ -798,7 +799,7 @@ pub fn banner_box(
|
||||
.to_string(),
|
||||
));
|
||||
rows.push(inner(
|
||||
" models models · models --prune · catalog · suggest · audit".to_string(),
|
||||
" models models · models --prune · catalog · suggest · ask · audit".to_string(),
|
||||
));
|
||||
rows.push(inner(
|
||||
" automate service install · schedule add · doctor --watch · monitor · sync · migrate · playbook".to_string(),
|
||||
@@ -2014,13 +2015,16 @@ pub fn is_am_command(word: &str) -> bool {
|
||||
| "tip"
|
||||
| "models"
|
||||
| "catalog"
|
||||
| "registry"
|
||||
| "providers"
|
||||
| "suggest"
|
||||
| "ask"
|
||||
| "audit"
|
||||
| "service"
|
||||
| "schedule"
|
||||
| "monitor"
|
||||
| "web"
|
||||
| "serve"
|
||||
| "sync"
|
||||
| "migrate"
|
||||
| "playbook"
|
||||
@@ -2676,7 +2680,7 @@ mod tests {
|
||||
for cmd in [
|
||||
"list", "status", "search", "info", "install", "uninstall", "update", "start",
|
||||
"stop", "restart", "run", "doctor", "config", "completion", "self-update",
|
||||
"self-uninstall", "export", "import",
|
||||
"self-uninstall", "export", "import", "ask", "serve", "registry",
|
||||
] {
|
||||
assert!(is_am_command(cmd), "{cmd}");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user