@imenam/mcp-organizer 1.0.3 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -20
- package/dist/shared/schemas/admin-api.schema.d.ts +101 -0
- package/dist/shared/schemas/admin-api.schema.js +39 -0
- package/dist/shared/schemas/agent-api.schema.d.ts +2 -0
- package/dist/shared/schemas/agent-api.schema.js +4 -0
- package/dist/shared/schemas/agent-tools.schema.d.ts +34 -0
- package/dist/shared/schemas/agent-tools.schema.js +2 -0
- package/dist/shared/schemas/api.schema.d.ts +2 -0
- package/dist/shared/schemas/api.schema.js +2 -0
- package/dist/shared/schemas/entities.schema.d.ts +27 -1
- package/dist/shared/schemas/entities.schema.js +21 -2
- package/dist/shared/schemas/notifications-api.schema.d.ts +31 -0
- package/dist/shared/schemas/notifications-api.schema.js +22 -1
- package/dist/src/agent-api/requests.js +2 -1
- package/dist/src/cli/set-admin.d.ts +1 -0
- package/dist/src/cli/set-admin.js +45 -0
- package/dist/src/core/accounts.js +2 -1
- package/dist/src/core/admin.d.ts +24 -0
- package/dist/src/core/admin.js +85 -0
- package/dist/src/core/agent-tokens.d.ts +9 -1
- package/dist/src/core/agent-tokens.js +25 -2
- package/dist/src/core/agent.d.ts +5 -0
- package/dist/src/core/agent.js +23 -0
- package/dist/src/core/migrations.js +369 -344
- package/dist/src/core/notifications.d.ts +7 -1
- package/dist/src/core/notifications.js +32 -1
- package/dist/src/core/requests.d.ts +1 -1
- package/dist/src/core/requests.js +4 -4
- package/dist/src/core/store.d.ts +38 -2
- package/dist/src/core/store.js +161 -38
- package/dist/src/gui-api.d.ts +6 -0
- package/dist/src/gui-api.js +25 -4
- package/dist/src/index.js +8 -1
- package/dist/src/mcp/start.d.ts +1 -1
- package/dist/src/mcp/start.js +1 -1
- package/dist/src/mcp/tools.js +1 -1
- package/dist/src/server/runner.d.ts +51 -0
- package/dist/src/server/runner.js +222 -0
- package/dist/src/server/start.js +8 -0
- package/gui/dist/assets/index-DuoSNpBr.js +70 -0
- package/gui/dist/assets/index-duxL0fvO.css +1 -0
- package/gui/dist/index.html +2 -2
- package/package.json +3 -2
- package/gui/dist/assets/index-BVN0agCc.css +0 -1
- package/gui/dist/assets/index-DI1_kr81.js +0 -70
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ Un seul paquet, deux modes :
|
|
|
11
11
|
| `mcp-organizer --server` | **Site** : processus web permanent, derrière un reverse proxy (nginx). Il détient la base, sert l'interface, son API et l'API des agents (`/api/agent/*`). |
|
|
12
12
|
| `mcp-organizer` | **MCP** (stdio) : serveur MCP de l'agent, sans base ni logique métier. Configuré par `ORGANIZER_URL` et `ORGANIZER_TOKEN`, il relaie chaque appel d'outil à l'API des agents du site. Il peut tourner sur n'importe quelle machine, notamment dans une gateway de mcp-gateway-manager. |
|
|
13
13
|
|
|
14
|
-
Autres commandes : `--setup` (installation du site : `.env`, unité systemd, bloc nginx, premier compte), `--set-user` (compte), `--backup` (sauvegarde de la base et des pièces jointes), `--claude-setup-mcp` (entrée `.mcp.json` du mode MCP), `--watch` (veilleur de notifications de l'agent, lancé par son outil `Monitor`), `--version`, `--help`. Chaque mode et chaque commande chargent leur code à la demande.
|
|
14
|
+
Autres commandes : `--setup` (installation du site : `.env`, unité systemd, bloc nginx, premier compte), `--set-user` (compte), `--set-admin` (administrateurs du site), `--backup` (sauvegarde de la base et des pièces jointes), `--claude-setup-mcp` (entrée `.mcp.json` du mode MCP), `--watch` (veilleur de notifications de l'agent, lancé par son outil `Monitor`), `--version`, `--help`. Chaque mode et chaque commande chargent leur code à la demande.
|
|
15
15
|
|
|
16
16
|
Prérequis : Node.js 20 ou plus récent.
|
|
17
17
|
|
|
@@ -111,9 +111,20 @@ Les comptes se créent sur invitation uniquement : il n'y a pas d'inscription li
|
|
|
111
111
|
|
|
112
112
|
Tant qu'aucun compte n'existe, le site refuse toute connexion et indique comment en créer un : la commande d'une installation par clonage (`node dist/src/index.js --set-user <email> --name="Prénom Nom"`, dans le dossier du site), celle du paquet npm (`npx -y @imenam/mcp-organizer --set-user …`, qui exige les modules natifs construits, voir « Via une gateway de mcp-gateway-manager ») et les variables `ORGANIZER_ADMIN_*`. Chaque utilisateur change ensuite son nom affiché et son mot de passe dans les Paramètres.
|
|
113
113
|
|
|
114
|
+
### Administrateurs
|
|
115
|
+
|
|
116
|
+
Le **premier compte** créé, par l'une des trois façons ci-dessus, est **administrateur du site** : il voit la page Administration et décide des espaces où le runner travaille. Sur une installation qui avait déjà des comptes, ou pour en désigner d'autres :
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
npm run set-admin -- <email>
|
|
120
|
+
npm run set-admin -- <email> --revoke
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Le compte doit exister et être actif. `--revoke` retire le rôle, sauf au dernier administrateur (« … est le seul administrateur : désignez-en un autre … ») : le site n'en reste jamais dépourvu. Une adresse inconnue est refusée avec la commande qui crée le compte. La commande lit le même `.env` que le site et écrit dans son répertoire de données.
|
|
124
|
+
|
|
114
125
|
## Connecter un agent (mode MCP)
|
|
115
126
|
|
|
116
|
-
Un agent se connecte au site avec un **jeton d'agent** (voir « Jetons d'agent ») : un utilisateur le crée dans
|
|
127
|
+
Un agent se connecte au site avec un **jeton d'agent** (voir « Jetons d'agent ») : un utilisateur le crée dans Mon compte > Agents, pour un espace dont il est membre. L'agent voit alors les demandes de tous les membres de cet espace et agit avec les droits du créateur du jeton.
|
|
117
128
|
|
|
118
129
|
Le mode MCP est un serveur stdio léger : il n'ouvre aucune base, ne charge aucun module natif (`better-sqlite3`, `argon2`) et n'a aucune logique métier. Chaque outil est un appel HTTPS à l'API des agents du site, avec le jeton dans `Authorization: Bearer`. Une instance correspond à un jeton, donc à un utilisateur et un espace.
|
|
119
130
|
|
|
@@ -152,7 +163,7 @@ Elle écrit l'entrée `mcp-organizer` de `<dossier>/.mcp.json`, ou l'ajoute à u
|
|
|
152
163
|
}
|
|
153
164
|
```
|
|
154
165
|
|
|
155
|
-
Le jeton est un secret : `.mcp.json` ne se partage pas et ne se versionne pas. Il se révoque depuis
|
|
166
|
+
Le jeton est un secret : `.mcp.json` ne se partage pas et ne se versionne pas. Il se révoque depuis Mon compte > Agents.
|
|
156
167
|
|
|
157
168
|
### Via une gateway de mcp-gateway-manager
|
|
158
169
|
|
|
@@ -187,7 +198,7 @@ Les outils MCP sont destinés à l'agent ; leurs schémas JSON sont écrits à l
|
|
|
187
198
|
| Outil | Route de l'API des agents | Rôle |
|
|
188
199
|
|---|---|---|
|
|
189
200
|
| `list_requests` | `GET requests` | Demandes de l'espace par statut (`pending` par défaut, ou `all`) : en attente de la plus ancienne à la plus récente, les autres statuts de la plus récente à la plus ancienne ; avec auteur, type, tâche de contexte et, en cours, si ce jeton les a prises |
|
|
190
|
-
| `claim_request` | `POST requests/:id/claim` | Prend une demande pour ce jeton (atomique) et renvoie son contexte : texte, auteur, tâche ou idée de contexte (et, pour une review, les résultats du testeur point par point), arbre de l'espace, membres, idées récentes |
|
|
201
|
+
| `claim_request` | `POST requests/:id/claim` | Prend une demande pour ce jeton (atomique) et renvoie son contexte : texte, auteur, tâche ou idée de contexte (et, pour une review, les résultats du testeur point par point), pour un message les derniers échanges clos de son auteur dans l'espace (demandes et réponses, au nombre fixé dans ses Paramètres), arbre de l'espace, membres, idées récentes |
|
|
191
202
|
| `get_context` | `GET context` | Espace du jeton : nom, préfixe, membres, arbre des tâches, idées récentes |
|
|
192
203
|
| `get_task` | `GET tasks/:ref` | Détail d'une tâche : champs, parents, assignés, tags, description, checklist ou points de vérification (avec leurs identifiants), sous-tâches, commentaires récents, pièces jointes |
|
|
193
204
|
| `search_tasks` | `GET tasks?query=…` | Recherche par mots (titre, description, clé) et filtres (statut, priorité, type, assigné) |
|
|
@@ -244,6 +255,40 @@ Le jeton organizer reste sur la machine de la gateway. Le veilleur de la gateway
|
|
|
244
255
|
|
|
245
256
|
**Présence** : le site tient en mémoire, par jeton, les attentes en cours de son veilleur, avec un délai de grâce de 2 minutes entre deux attentes. `enable_notifications` répond « already live » quand un veilleur est déjà armé (en armer un second doublerait chaque notification), et la page Agent de l'interface affiche « à l'écoute » à côté du jeton. Les attentes du veilleur de la gateway comptent aussi (`watcher: true`).
|
|
246
257
|
|
|
258
|
+
### Runner
|
|
259
|
+
|
|
260
|
+
Le runner rend un agent Claude Code disponible en permanence, sans clé d'API, pour les espaces qu'un administrateur autorise dans la page Administration. Claude Code est installé sur la machine du site, et c'est le site qui lance les sessions : activer l'interrupteur « Runner » d'un espace suffit, sans autre configuration par espace.
|
|
261
|
+
|
|
262
|
+
**Déclenchement.** Le site lance une session `claude -p` pour un espace autorisé quand une demande y passe en attente (création, ou libération par un membre), quand un administrateur autorise un espace où des demandes attendent, et au démarrage pour les espaces autorisés qui ont des demandes. La session traite la file de l'espace jusqu'à ce qu'elle soit vide, puis se termine. Une seule session tourne à la fois ; un espace qui reçoit une demande pendant sa propre session est repris après elle (sans session s'il ne reste rien). Une session qui dépasse 30 minutes est arrêtée. Désautoriser un espace ne coupe pas la session en cours, mais n'en lance plus.
|
|
263
|
+
|
|
264
|
+
**Traitement ponctuel.** Sur la page Agent, un administrateur dispose du bouton « Traiter la file » (`POST /api/spaces/:spaceId/runner/run`) : il lance une session pour les demandes en attente de l'espace ouvert, **même si le runner n'y est pas autorisé**, sans changer l'autorisation. Le bouton est désactivé quand aucune demande n'attend, ou quand le runner du site est désactivé (la raison s'affiche en infobulle).
|
|
265
|
+
|
|
266
|
+
**Session.** Elle tourne sous le compte du site, avec :
|
|
267
|
+
|
|
268
|
+
- une configuration MCP propre (`--mcp-config <fichier> --strict-mcp-config`) : le mode MCP de ce paquet, relié au site local en http (`HOST:PORT`), avec le **jeton du runner** de l'espace. Le fichier, en 0600 sous `<données>/runner/`, est supprimé à la fin de la session ;
|
|
269
|
+
- les seuls outils organizer : `--allowedTools mcp__organizer`, et les outils intégrés de Claude Code refusés (`Bash`, `Read`, `Write`, `Edit`, `Glob`, `Grep`, `WebFetch`, `WebSearch`, `Task`…). Sans shell ni accès aux fichiers, la session ne peut agir qu'à travers l'API des agents, dans l'espace du jeton ;
|
|
270
|
+
- un environnement réduit à `PATH`, `LANG`, les dossiers temporaires, et `HOME` = `CLAUDE_CONFIG_DIR` = `<données>/claude` : les secrets du site (SMTP, Groq…) ne lui parviennent pas ;
|
|
271
|
+
- une consigne qui lui demande de vider la file ; les `instructions` du serveur MCP lui donnent les concepts et la boucle de travail. Sa sortie part dans le journal du site (`[runner]`).
|
|
272
|
+
|
|
273
|
+
**Jeton du runner.** Un par espace, au nom du **propriétaire de l'espace**, nommé « Runner » : il apparaît dans la page Agent (et dans l'historique des actions), jamais dans les jetons de Mon compte. Sa valeur est renouvelée avant chaque session et invalidée après : en dehors d'une session, aucune valeur valide n'existe.
|
|
274
|
+
|
|
275
|
+
**Installation**, une fois, sur la machine du site :
|
|
276
|
+
|
|
277
|
+
1. Installer Claude Code (`npm install -g @anthropic-ai/claude-code`) et le connecter **pour le compte du site**, avec son dossier de configuration sous le répertoire de données :
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
sudo -u mcp-organizer env HOME=/var/lib/mcp-organizer/claude CLAUDE_CONFIG_DIR=/var/lib/mcp-organizer/claude claude
|
|
281
|
+
# puis /login, et quitter
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
2. Indiquer la commande de Claude Code dans le `.env` du site, puis redémarrer le service :
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
ORGANIZER_RUNNER_CLAUDE=/usr/bin/claude
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Sans `ORGANIZER_RUNNER_CLAUDE`, le runner est désactivé : le journal et la page Administration en donnent la raison. Il l'est aussi quand `HOST` n'est pas une adresse locale, la session joignant le site en http sur la machine.
|
|
291
|
+
|
|
247
292
|
### API des agents
|
|
248
293
|
|
|
249
294
|
`/api/agent/*` sert le mode MCP ; n'importe quel client HTTP peut l'appeler avec un jeton.
|
|
@@ -251,7 +296,7 @@ Le jeton organizer reste sur la machine de la gateway. Le veilleur de la gateway
|
|
|
251
296
|
- **Authentification** : `Authorization: Bearer org_…`, revérifiée à chaque requête (jeton non révoqué, non expiré, propriétaire actif et toujours membre de l'espace) ; le dernier usage du jeton est mis à jour. Les cookies sont ignorés et le contrôle d'origine des modifications ne s'applique pas : sans cookie, une page tierce ne peut rien faire au nom d'un utilisateur.
|
|
252
297
|
- **Codes** : 401 pour un jeton absent, inconnu, révoqué (y compris au départ de son propriétaire) ou expiré (avec `WWW-Authenticate: Bearer`) ; 403 pour un propriétaire inactif ou qui n'est plus membre, une tâche ou une idée d'un autre espace, ou une demande prise par un autre jeton ; 404 pour une demande, une tâche ou une route inconnue ; 409 pour un état qui interdit l'action (demande en attente ou close) ; 400 pour des paramètres invalides ; 500 pour une erreur interne, avec un message générique et une référence (voir « Sécurité »). Le corps d'une erreur est `{ "error": "<message qui dit quoi faire>" }`.
|
|
253
298
|
- **Réponses** : `{ "text": "…", "data": { … } }`. `text` est le résultat rédigé pour l'agent (celui que renvoie l'outil) ; `data` porte les mêmes informations structurées, validées par les schémas zod de `shared/schemas/agent-tools.schema.ts`, partagés par le site et le mode MCP.
|
|
254
|
-
- **Attente longue** : `GET requests/wait?timeout_seconds=<1-50>&since=<curseur>&watcher=true` rend les demandes de l'espace passées en attente depuis `since`, sinon attend la prochaine, au plus `timeout_seconds` (30 par défaut) ; `data` porte les demandes, le curseur suivant et `timedOut`. `watcher=true` compte l'attente dans la présence du veilleur du jeton. `GET notifications` donne le jeton, son espace, le nombre de demandes en attente et l'état du veilleur.
|
|
299
|
+
- **Attente longue** : `GET requests/wait?timeout_seconds=<1-50>&since=<curseur>&watcher=true` rend les demandes de l'espace passées en attente depuis `since`, sinon attend la prochaine, au plus `timeout_seconds` (30 par défaut) ; `data` porte les demandes, le curseur suivant et `timedOut`. `watcher=true` compte l'attente dans la présence du veilleur du jeton . `GET notifications` donne le jeton, son espace, le nombre de demandes en attente et l'état du veilleur.
|
|
255
300
|
- **Paramètres** : les noms des arguments des outils (`request_id`, `after_task`…) ; dans le chemin pour la tâche (`:ref`), l'idée et la demande, dans la requête pour un `GET`, dans le corps JSON sinon.
|
|
256
301
|
|
|
257
302
|
## Configuration
|
|
@@ -271,6 +316,7 @@ Le setup écrit cette configuration ; elle se modifie aussi à la main. Le site
|
|
|
271
316
|
| `ORGANIZER_TRANSCRIBE_MODEL` | Modèle de transcription Groq (`whisper-large-v3-turbo`). |
|
|
272
317
|
| `SMTP_URL` | Serveur d'envoi des e-mails : `smtp://utilisateur:motdepasse@hote:587` ou `smtps://…`. |
|
|
273
318
|
| `MAIL_FROM` | Expéditeur des e-mails, par exemple `Organizer <organizer@example.com>`. |
|
|
319
|
+
| `ORGANIZER_RUNNER_CLAUDE` | Commande de Claude Code (par exemple `/usr/bin/claude`), qui active le runner (voir « Runner »). Vide : runner désactivé. |
|
|
274
320
|
| `ORGANIZER_ADMIN_EMAIL`, `ORGANIZER_ADMIN_NAME`, `ORGANIZER_ADMIN_PASSWORD` | Premier compte, créé au démarrage si aucun compte n'existe (voir « Premier compte »). |
|
|
275
321
|
|
|
276
322
|
Exemple de `.env` :
|
|
@@ -397,16 +443,16 @@ Chaque mutation ajoute à la table `changes` une ligne par entité touchée (`se
|
|
|
397
443
|
|
|
398
444
|
```
|
|
399
445
|
src/index.ts ligne de commande : aide, version, .env, choix du mode ou de la commande
|
|
400
|
-
src/server/ mode site : configuration, serveur Hono, protections, limitation des connexions
|
|
446
|
+
src/server/ mode site : configuration, serveur Hono, protections, limitation des connexions, runner (runner.ts)
|
|
401
447
|
src/mcp/ mode MCP (stdio) : instructions, définitions des outils, client HTTP du site,
|
|
402
448
|
enable_notifications et wait_for_requests (notifications.ts), relais du veilleur (watch-handoff.ts)
|
|
403
449
|
src/agent-api/ routes /api/agent/* : logique des outils de l'agent, authentifiée par jeton
|
|
404
450
|
src/gui-api.ts routes /api/* de l'interface
|
|
405
|
-
src/cli/ --setup (setup.ts), --set-user (set-user.ts), --backup (backup.ts),
|
|
451
|
+
src/cli/ --setup (setup.ts), --set-user (set-user.ts), --set-admin (set-admin.ts), --backup (backup.ts),
|
|
406
452
|
--claude-setup-mcp (setup-mcp.ts), --watch (watch.ts), saisies au terminal (prompt.ts)
|
|
407
453
|
src/deploy/ fichiers écrits par --setup : .env fusionné (env-render.ts), unité systemd et bloc nginx (templates.ts)
|
|
408
454
|
src/core/ base SQLite, migrations, store, comptes, espaces, tâches, tests, pièces jointes,
|
|
409
|
-
notifications, e-mail, dictée, file de l'agent, jetons d'agent, historique, .env, journaux, entrée .mcp.json
|
|
455
|
+
notifications, e-mail, dictée, file de l'agent, jetons d'agent, administration, historique, .env, journaux, entrée .mcp.json
|
|
410
456
|
shared/schemas/ schémas zod communs au serveur et à l'interface
|
|
411
457
|
shared/logic/ logique pure commune (préfixes, initiales, rangs fractionnaires, bilan d'un test, création du premier compte)
|
|
412
458
|
gui/ SPA Vite + React 19 + zustand, routage par hash
|
|
@@ -418,7 +464,7 @@ e2e/ parcours Playwright sur le site réel ; captures dans e2e/
|
|
|
418
464
|
|
|
419
465
|
Les tests ne lisent jamais la configuration du développeur : `test/launch.ts`, partagé par les tests node et les parcours e2e, lance chaque processus avec `--dotenv=<fichier vide du répertoire temporaire>` et vide toutes les variables de configuration héritées du shell. Le site de test est lancé en `--server` sur un port libre de `127.0.0.1`, avec `ORGANIZER_PUBLIC_URL=http://127.0.0.1:<port>` ; les outils sont appelés par un client MCP réel sur le mode MCP, relié à ce site par un jeton créé par l'API de l'interface (`ORGANIZER_URL`, `ORGANIZER_TOKEN`). Un test vérifie, sur une copie du package dont le `.env` détourne le répertoire de données, que ce `.env` n'atteint pas un processus lancé par les tests (et qu'il l'atteindrait sans `--dotenv`).
|
|
420
466
|
|
|
421
|
-
**Tests node** : migrations, invariants, versions, journal des changements, connexions concurrentes ; comptes (amorçage avec nom obligatoire, `--set-user` et `--name`, connexion, sessions, liens d'accès, invitations, droits, e-mail) ; profil ; jetons d'agent (affichage unique, configuration du mode MCP, hash seul en base, révocation, expiration, perte d'appartenance, espace hors de portée) ; `--claude-setup-mcp` (entrée du mode MCP, `--url` et `--token` obligatoires, fusion, `--force`, options inconnues ou invalides, fichier illisible laissé intact) ; `--setup` (`.env`, unité systemd et bloc nginx écrits, premier compte créé, `.env` existant fusionné, publication sous un chemin, valeurs incohérentes ou manquantes refusées sans rien écrire, valeurs dotenv citées, site démarré depuis le `.env` écrit) ; `--backup` (copie de la base d'un site en service et de ses pièces jointes, restaurable ; destination existante refusée sans `--force` ; pièce jointe manquante qui ne laisse aucun fichier ; répertoire sans base refusé) ; `.env` et `--dotenv` ; tâches, tâches de test, pièces jointes, notifications, boîte à idées, dictée avec un serveur Groq simulé, historique et annulation ; chaque outil appelé par un client MCP du SDK sur le mode MCP relié à un site de test, jeton inconnu, révoqué ou expiré, site injoignable, espace hors portée, demande prise par un autre jeton, deux jetons de deux membres sur le même espace commun (prise atomique), mode MCP sans `ORGANIZER_URL` / `ORGANIZER_TOKEN`, mode MCP qui ne charge aucun module natif (crochet de résolution qui les bloque), `ORGANIZER_URL` en http refusée hors de la machine locale, redirection du site refusée sans y envoyer le jeton, `.env` du paquet ignoré par le mode MCP (lu avec `--dotenv`) ; commandes du site arrêtées avec la marche à suivre quand better-sqlite3 n'a pas de module natif (crochet de résolution qui simule l'échec) ; `list_requests` sur plus de 100 demandes closes (les plus récentes d'abord) ; jetons révoqués au départ ou au retrait de leur propriétaire, et migration qui révoque ceux des anciens membres ; erreurs internes au message générique ; sauvegarde privée pendant son écriture (droits observés hors Windows, test ignoré sous Windows) ; `--setup` qui refuse `--trust-proxy=oui` avec une écoute hors de la boucle locale, bloc nginx en `listen 443 ssl http2` ; notifications de l'agent (présence et délai de grâce du veilleur, ligne d'une demande, `GET notifications`, attente longue réveillée par une demande créée ou libérée, curseur qui rattrape une demande arrivée entre deux attentes, expiration, jeton inconnu, durée hors limites ; `enable_notifications` puis veilleur `--watch` réel qui écrit une ligne par nouvelle demande, sans le jeton dans la conversation, « already live » une fois armé, arrêt sur jeton révoqué, refus de démarrer sans relais ; convention de mcp-http-gateway : propriété `_gateway_watch`, spécification de veille sans relais local, curseur de départ qui rattrape une demande, lignes et curseur de `wait_for_requests`, présence, arguments invalides) ; API des agents en HTTP direct (401 et 403 explicites, cookies ignorés, écriture sans `Origin`, réponses validées par les schémas partagés) ; site : `--help` (qui cite `--setup` et `--backup`) et `--version`, refus de connexion sans compte avec les commandes d'une installation par clonage et du paquet npm, démarrage refusé sans `ORGANIZER_PUBLIC_URL` ou `PORT` ou avec un chemin de base incohérent, SPA et `<base href>`, cookie (`Path`, `Secure` en https), formulaires multipart et 413 ; protections : modification refusée sans origine ou d'une origine étrangère, en-têtes de sécurité, limitation des connexions par couple (IP, e-mail) et par IP, rafale de tentatives parallèles limitée, compte non bloqué par un tiers, `X-Forwarded-For` ignoré sans `ORGANIZER_TRUST_PROXY` et pris en compte avec.
|
|
467
|
+
**Tests node** : migrations, invariants, versions, journal des changements, connexions concurrentes ; comptes (amorçage avec nom obligatoire, `--set-user` et `--name`, connexion, sessions, liens d'accès, invitations, droits, e-mail) ; profil ; jetons d'agent (affichage unique, configuration du mode MCP, hash seul en base, révocation, expiration, perte d'appartenance, espace hors de portée) ; `--claude-setup-mcp` (entrée du mode MCP, `--url` et `--token` obligatoires, fusion, `--force`, options inconnues ou invalides, fichier illisible laissé intact) ; `--setup` (`.env`, unité systemd et bloc nginx écrits, premier compte créé, `.env` existant fusionné, publication sous un chemin, valeurs incohérentes ou manquantes refusées sans rien écrire, valeurs dotenv citées, site démarré depuis le `.env` écrit) ; `--backup` (copie de la base d'un site en service et de ses pièces jointes, restaurable ; destination existante refusée sans `--force` ; pièce jointe manquante qui ne laisse aucun fichier ; répertoire sans base refusé) ; `.env` et `--dotenv` ; tâches, tâches de test, pièces jointes, notifications, boîte à idées, dictée avec un serveur Groq simulé, historique et annulation ; chaque outil appelé par un client MCP du SDK sur le mode MCP relié à un site de test, jeton inconnu, révoqué ou expiré, site injoignable, espace hors portée, demande prise par un autre jeton, deux jetons de deux membres sur le même espace commun (prise atomique), mode MCP sans `ORGANIZER_URL` / `ORGANIZER_TOKEN`, mode MCP qui ne charge aucun module natif (crochet de résolution qui les bloque), `ORGANIZER_URL` en http refusée hors de la machine locale, redirection du site refusée sans y envoyer le jeton, `.env` du paquet ignoré par le mode MCP (lu avec `--dotenv`) ; commandes du site arrêtées avec la marche à suivre quand better-sqlite3 n'a pas de module natif (crochet de résolution qui simule l'échec) ; `list_requests` sur plus de 100 demandes closes (les plus récentes d'abord) ; jetons révoqués au départ ou au retrait de leur propriétaire, et migration qui révoque ceux des anciens membres ; erreurs internes au message générique ; sauvegarde privée pendant son écriture (droits observés hors Windows, test ignoré sous Windows) ; `--setup` qui refuse `--trust-proxy=oui` avec une écoute hors de la boucle locale, bloc nginx en `listen 443 ssl http2` ; administration et runner (premier compte administrateur, page Administration réservée, autorisation par espace, `--set-admin` et dernier administrateur protégé, session `claude -p` lancée par le site dès qu'une demande attend dans un espace autorisé ou qu'un espace est autorisé, avec les seuls outils organizer, un environnement sans les secrets du site, une configuration MCP supprimée et un jeton invalidé après la session, jeton « Runner » visible dans la page Agent et absent de Mon compte, traitement ponctuel d'une file par un administrateur même sans autorisation, refusé aux membres, sans demande en attente ou runner désactivé, runner désactivé sans `ORGANIZER_RUNNER_CLAUDE`) ; notifications de l'agent (présence et délai de grâce du veilleur, ligne d'une demande, `GET notifications`, attente longue réveillée par une demande créée ou libérée, curseur qui rattrape une demande arrivée entre deux attentes, expiration, jeton inconnu, durée hors limites ; `enable_notifications` puis veilleur `--watch` réel qui écrit une ligne par nouvelle demande, sans le jeton dans la conversation, « already live » une fois armé, arrêt sur jeton révoqué, refus de démarrer sans relais ; convention de mcp-http-gateway : propriété `_gateway_watch`, spécification de veille sans relais local, curseur de départ qui rattrape une demande, lignes et curseur de `wait_for_requests`, présence, arguments invalides) ; API des agents en HTTP direct (401 et 403 explicites, cookies ignorés, écriture sans `Origin`, réponses validées par les schémas partagés) ; site : `--help` (qui cite `--setup` et `--backup`) et `--version`, refus de connexion sans compte avec les commandes d'une installation par clonage et du paquet npm, démarrage refusé sans `ORGANIZER_PUBLIC_URL` ou `PORT` ou avec un chemin de base incohérent, SPA et `<base href>`, cookie (`Path`, `Secure` en https), formulaires multipart et 413 ; protections : modification refusée sans origine ou d'une origine étrangère, en-têtes de sécurité, limitation des connexions par couple (IP, e-mail) et par IP, rafale de tentatives parallèles limitée, compte non bloqué par un tiers, `X-Forwarded-For` ignoré sans `ORGANIZER_TRUST_PROXY` et pris en compte avec.
|
|
422
468
|
|
|
423
469
|
**Parcours e2e** (site compilé en `--server`, port libre, répertoire de données temporaire, premier compte créé par `ORGANIZER_ADMIN_*`). Chaque page est surveillée : une exception ou une erreur de console, dont toute violation de la CSP, fait échouer le parcours.
|
|
424
470
|
|
|
@@ -426,13 +472,13 @@ Les tests ne lisent jamais la configuration du développeur : `test/launch.ts`,
|
|
|
426
472
|
- connexion refusée puis réussie, création d'un espace commun, invitation, activation du compte invité par le lien dans un second navigateur ; invitation d'un second espace rejointe depuis « Invitations reçues », ancien lien refusé ;
|
|
427
473
|
- tâches, sous-tâches et sous-sous-tâches, glisser-déposer entre colonnes et dans une colonne (persisté), assignation notifiée chez l'assignée ;
|
|
428
474
|
- tâche de test à deux testeurs, résultats, review soumise qui crée une demande traitée par l'agent ; testeuse désassignée puis retirée, résultats conservés en lecture seule ;
|
|
429
|
-
- idée saisie dans l'interface → demande en attente → traitement par un client MCP réel sur le mode MCP, avec un jeton créé par l'API de l'interface (tâche créée, statut et priorité changés) → réponse, actions, jeton qui a traité la demande et dernier passage de l'agent visibles → annulation d'une action puis du lot, tâche retirée du tableau de bord ; demande restée en cours libérée depuis la page Agent puis reprise ; jeton dont le veilleur attend affiché « à l'écoute », réveillé par une demande ;
|
|
475
|
+
- idée saisie dans l'interface → demande en attente → traitement par un client MCP réel sur le mode MCP, avec un jeton créé par l'API de l'interface (tâche créée, statut et priorité changés) → réponse, actions, jeton qui a traité la demande et dernier passage de l'agent visibles → annulation d'une action puis du lot, tâche retirée du tableau de bord ; onglets En attente, En cours, Traitées et Annulées de la page Agent avec leurs nombres ; demande restée en cours libérée depuis la page Agent puis reprise ; page Administration réservée au premier compte (bouton « Traiter la file » désactivé avec sa raison sans Claude Code, absent pour un membre ; pastille « Runner désactivé » avec sa raison sur la page Agent, runner autorisé sur un espace, entrée absente et fragment refusé pour un membre) ; jeton dont le veilleur attend affiché « à l'écoute », réveillé par une demande ;
|
|
430
476
|
- portée : les agents de Julie (un jeton sur son espace personnel, un sur l'espace commun) ne voient que les demandes de leur espace et ne lisent ni ne modifient l'espace personnel de Matthieu, sur lequel elle ne peut pas créer de jeton ;
|
|
431
477
|
- panneau assistant, « Modifiée par l'agent · Annuler » et restauration d'une version ;
|
|
432
478
|
- boîte à idées : promotion manuelle et promotion confiée à l'agent ;
|
|
433
479
|
- commentaires notifiés aux assignés et aux commentateurs précédents, préférence désactivée ;
|
|
434
|
-
- deux utilisateurs, deux agents : Matthieu et Julie créent chacun leur jeton dans
|
|
435
|
-
-
|
|
480
|
+
- deux utilisateurs, deux agents : Matthieu et Julie créent chacun leur jeton dans Mon compte > Agents et y relient un client MCP réel sur le mode MCP ; les deux agents de l'espace commun voient les demandes des deux membres ; l'agent de Matthieu traite l'idée de Julie, qui annule ses actions depuis la page Agent ; le jeton personnel de Julie est refusé hors de son espace ; le jeton de Julie, révoqué pendant qu'elle traite une demande, est refusé à l'appel suivant avec un message qui dit quoi faire ; la demande restée en cours est libérée depuis la page Agent et reprise par l'agent de Matthieu ;
|
|
481
|
+
- Mon compte : création d'un jeton montré une seule fois, configuration du mode MCP copiée, jeton absent de la page ensuite, révocation, nom affiché et mot de passe ;
|
|
436
482
|
- dictée : faux micro de Chromium et serveur Groq simulé.
|
|
437
483
|
|
|
438
484
|
Les attentes portent sur l'état de la page ou de l'API, jamais sur un délai fixe. Les captures (1440 px de large, 900 px de haut sauf les détails de tâche, à la hauteur de leur maquette ; données proches des maquettes) sont écrites dans `e2e/screenshots/` : `01-tableau-de-bord`, `02-detail-tache-standard`, `03-detail-tache-de-test`, `04-saisir-une-idee`, `05-panneau-assistant`, `06-agent`, `06-agent-deux-agents`, `08-idees`, `09-menu-espaces`, `09-membres`, `09-invitations-recues`, `10-connexion`, `10-connexion-aucun-compte`, `11-parametres`, `11-parametres-jeton-cree`, `11-parametres-agents`, `12-notifications`, et quelques états intermédiaires.
|
|
@@ -447,18 +493,20 @@ Thème sombre, épuré, une seule action principale par écran. L'interface se r
|
|
|
447
493
|
|---|---|
|
|
448
494
|
| **Connexion** | Carte unique : e-mail, mot de passe, « Se connecter ». |
|
|
449
495
|
| **Activation** (`#/activation/<jeton>`) | Lien d'invitation : nom affiché, mot de passe, confirmation ; l'activation ouvre la session. |
|
|
450
|
-
| **Coquille** | Barre latérale : sélecteur d'espace (menu : espaces, « Invitations reçues » quand il y en a, signalées par un point sur le sélecteur, «
|
|
496
|
+
| **Coquille** | Barre latérale en deux étages. En haut, un cadre réunit ce qui concerne l'espace ouvert : sélecteur d'espace (menu : espaces, « Invitations reçues » quand il y en a, signalées par un point sur le sélecteur, « Nouvel espace commun »), Tableau de bord, Idées, Agent avec le nombre de demandes en attente, Membres (modale), Réglages de l'espace. En bas, hors du cadre : « Site › Administration » pour les administrateurs, puis l'utilisateur, « Mon compte » (menu : Mon compte, Déconnexion). En-tête : titre, recherche, cloche, bouton principal « Saisir une idée ». Bulle de l'assistant en bas à droite. |
|
|
451
497
|
| **Tableau de bord** | Kanban à quatre colonnes figées (À faire, En cours, En revue, Terminé) avec glisser-déposer (statut et ordre, souris ou clavier), « Ajouter une tâche » en bas de colonne, onglet « Liste », menu « Filtrer » (type, priorité, assigné, tag). Une carte montre le titre, la priorité si elle est Haute ou Critique, l'icône d'un test et ses KO, l'avancement des sous-tâches et les avatars ; une tâche terminée se réduit à son titre. |
|
|
452
498
|
| **Détail d'une tâche** (`#/task/<id>`) | Une colonne : fil d'Ariane, titre, ligne statut · priorité · assignés · menu ⋯ (tags, type, tâche testée, historique, suppression) ; « Modifiée par l'agent il y a … · Annuler » ; description markdown ; pièces jointes ; checklist ; Kanban des sous-tâches (avec le nombre de sous-sous-tâches) ; commentaires. |
|
|
453
499
|
| **Détail d'un test** | Même gabarit avec « Test », la ligne « Teste ORG-41 … », la barre de bilan et « 9/12 vérifiés · 2 KO », un onglet par testeur, puis un onglet en lecture seule par ancien testeur (désassigné ou parti de l'espace), un résultat par point (OK, KO, Bloqué, À vérifier, avec commentaire), « Ma review » avec dictée et « Soumettre la review », reviews des autres testeurs repliées avec l'état de leur demande. |
|
|
454
500
|
| **Saisir une idée** | Modale : texte, micro, « Envoyer » ; « L'agent la classera à son prochain passage ». |
|
|
455
|
-
| **Assistant** | Panneau latéral
|
|
456
|
-
| **Agent** (`#/agent`) |
|
|
501
|
+
| **Assistant** | Panneau latéral, élargi ou rétréci par sa poignée gauche (glisser, ou flèches au clavier), largeur retenue dans le stockage local du navigateur ; mention du nombre d'échanges précédents que voit l'agent, avec un lien « Régler » vers les Paramètres ; contexte « À propos de ORG-41 » (tâche ouverte), fil des demandes de l'utilisateur et des réponses de l'agent, statut, « Modifier · Annuler » en attente, « Libérer » en cours, nom du jeton qui traite ou a traité la demande (son propriétaire en infobulle), « N actions · Annuler ». |
|
|
502
|
+
| **Agent** (`#/agent`) | Onglets En attente, En cours, Traitées et Annulées, chacun avec son nombre, suivis du filtre (types, « Mes demandes ») et, pour un administrateur, de « Traiter la file » (voir « Runner »). Sous les onglets, l'état rechargé toutes les 30 s : pastille du runner (« Runner actif », « Runner non activé » avec « Activer le runner » pour un administrateur, ou « Runner désactivé » avec la raison en infobulle), puis chaque jeton actif de l'espace, son propriétaire et son dernier passage (point allumé s'il date de moins de 10 min) ou « à l'écoute » quand son veilleur de notifications est armé, ou « Aucun agent sur cet espace · Ajouter un agent ». En attente : une carte par demande (texte, type, auteur, ancienneté, « Modifier » et « Annuler » visibles) ; En cours : jeton qui l'a prise, « Libérer » ; Traitées : jeton qui l'a traitée, elles se déplient (réponse, actions avec « Annuler », « Tout annuler ») ; Annulées : qui l'a annulée. |
|
|
457
503
|
| **Idées** (`#/idees`) | Liste avec ajout rapide, idées classées par l'agent, « Promouvoir » ; tiroir « Promouvoir en tâche » : « Laisser l'agent la formater », ou « la remplir moi-même » (titre, type, priorité). |
|
|
458
|
-
| **Membres** | Modale : invitation par adresse, membres et rôles, invitations en attente (renvoyer, révoquer, lien à copier quand l'e-mail ne part pas),
|
|
504
|
+
| **Membres** | Modale ouverte par l'entrée Membres de la barre latérale : invitation par adresse, membres et rôles, invitations en attente (renvoyer, révoquer, lien à copier quand l'e-mail ne part pas). Renommer, supprimer ou quitter l'espace se fait dans Réglages de l'espace. |
|
|
459
505
|
| **Invitations reçues** | Modale ouverte depuis le menu du sélecteur d'espace : pour chaque espace qui invite l'utilisateur, l'auteur de l'invitation, « Refuser » et « Rejoindre » (qui ouvre l'espace). |
|
|
460
506
|
| **Notifications** | Menu sous la cloche : non lues d'abord, phrase courte, extrait du commentaire, « Tout marquer comme lu » ; un clic ouvre la tâche. |
|
|
461
|
-
| **
|
|
507
|
+
| **Administration** (`#/administration`) | Administrateurs seulement (entrée « Site › Administration » de la barre latérale, fragment refusé aux autres) : tous les comptes, administrateurs signalés, chacun avec les espaces dont il est propriétaire (type, membres) et un interrupteur « Runner » par espace ; « N espaces autorisés sur M ». |
|
|
508
|
+
| **Réglages de l'espace** (`#/espace`) | Portée de la page (espace ouvert, commun ou personnel) ; Général (nom, renommable par le propriétaire d'un espace commun, préfixe des tâches en lecture seule) ; Notifications dans cet espace (« Personnaliser pour cet espace » : préférences propres à l'espace, parties de celles du compte ; sans personnalisation, celles de Mon compte en lecture seule) ; Agent (état du runner du site dans cet espace, lien vers l'Administration pour un administrateur) ; Zone sensible d'un espace commun (« Supprimer l'espace » avec confirmation pour le propriétaire, « Quitter l'espace » pour un membre). |
|
|
509
|
+
| **Mon compte** (`#/parametres`) | Profil (nom affiché, mot de passe avec l'ancien) ; Agents (jetons : nom, espace, dernier usage, état ; « Créer un jeton », « Révoquer ») ; Assistant (« Mémoire de la conversation » : champ numérique : nombre d'échanges précédents transmis à l'agent avec un message, de 5 à 20, 5 par défaut) ; Notifications (assignation / commentaire × application / e-mail, avec la raison quand les e-mails ne partent pas), valables dans tous les espaces sauf ceux qui ont les leurs. |
|
|
462
510
|
|
|
463
511
|
« Créer un jeton » demande un nom, un espace parmi ceux de l'utilisateur et une expiration facultative (7 jours, 30 jours, 90 jours, 1 an), puis affiche une seule fois le jeton et « Copier la configuration », qui copie l'entrée `.mcp.json` du mode MCP prête à coller (voir « Jetons d'agent »). Le presse-papiers exige HTTPS ou localhost ; sinon la page dit pourquoi la copie échoue.
|
|
464
512
|
|
|
@@ -479,6 +527,7 @@ Thème sombre, épuré, une seule action principale par écran. L'interface se r
|
|
|
479
527
|
| Inviter, révoquer, retirer un membre, renommer, supprimer l'espace | Propriétaire |
|
|
480
528
|
| Accepter ou refuser une invitation | Son destinataire, connecté |
|
|
481
529
|
| Voir une demande, la modifier ou l'annuler en attente, la libérer quand l'agent l'a prise | Membres de l'espace où elle est écrite |
|
|
530
|
+
| Voir tous les comptes et tous les espaces, autoriser le runner sur un espace, faire traiter une file ponctuellement | Administrateurs du site |
|
|
482
531
|
| Voir les actions de l'agent et les annuler | Membres de l'espace de la demande : tous dans un espace commun, le propriétaire seul pour son espace personnel |
|
|
483
532
|
| Agent | Droits du propriétaire du jeton, limités à l'espace du jeton, pour une demande prise par ce jeton |
|
|
484
533
|
|
|
@@ -494,7 +543,7 @@ Un non-membre reçoit la même réponse qu'un espace ou une tâche inexistants (
|
|
|
494
543
|
|
|
495
544
|
### Demandes
|
|
496
545
|
|
|
497
|
-
- **Types** : `idea` (« Saisir une idée »), `message` (panneau assistant, avec la tâche ouverte pour contexte), `remark`, `test_review` et `idea_promotion`.
|
|
546
|
+
- **Types** : `idea` (« Saisir une idée »), `message` (panneau assistant, avec la tâche ouverte pour contexte et les derniers échanges de l'auteur), `remark`, `test_review` et `idea_promotion`.
|
|
498
547
|
- **Cycle** : `pending`, puis `processing` quand l'agent la prend, puis `done` avec sa réponse ou `failed` avec la raison. Une demande en attente se modifie ou s'annule (`cancelled`). Une demande restée `processing` (agent arrêté en cours de route) se **libère** : un membre de son espace la repasse `pending`, et un agent pourra la reprendre ; les actions déjà faites restent dans son lot. Rien ne la libère automatiquement.
|
|
499
548
|
- **Lot** : chaque écriture de l'agent pour une demande est une action numérotée, avec l'état de l'entité avant et après et un résumé (« Statut En cours → En revue », « Assigné à Julie Laurent »).
|
|
500
549
|
|
|
@@ -504,6 +553,7 @@ Un non-membre reçoit la même réponse qu'un espace ou une tâche inexistants (
|
|
|
504
553
|
- **Commentaire** : notifie les assignés de la tâche et ceux qui l'ont déjà commentée, sauf l'auteur.
|
|
505
554
|
- L'auteur d'une notification est un utilisateur ou l'agent (avec la demande pour laquelle il agit).
|
|
506
555
|
- **Préférences** (toutes activées par défaut) : assignation et commentaire, chacun dans l'application et par e-mail. L'e-mail part du site après la validation de la transaction, y compris pour les actions de l'agent (le mode MCP n'envoie rien), avec un lien vers la tâche ; son issue (`emailedAt`, ou `emailError` avec la raison) est enregistrée.
|
|
556
|
+
- **Préférences d'un espace** : un membre peut personnaliser ses préférences dans un espace (Réglages de l'espace). Elles partent de celles du compte et les remplacent dans cet espace seulement ; une notification suit les préférences de l'espace de sa tâche. Revenir à celles du compte, ou quitter l'espace, efface les préférences propres.
|
|
507
557
|
|
|
508
558
|
### Boîte à idées
|
|
509
559
|
|
|
@@ -514,7 +564,7 @@ Un non-membre reçoit la même réponse qu'un espace ou une tâche inexistants (
|
|
|
514
564
|
|
|
515
565
|
### Jetons d'agent
|
|
516
566
|
|
|
517
|
-
- Un **jeton** se crée dans
|
|
567
|
+
- Un **jeton** se crée dans Mon compte > Agents. Il couvre **exactement un espace** : l'espace personnel de son créateur ou un espace commun dont il est membre.
|
|
518
568
|
- Il vaut `org_` suivi de 32 octets aléatoires en base64url. Il n'est affiché qu'une fois, à sa création ; la base n'en garde que le hash sha256 et le début (`org_` et 8 caractères), qui sert à le reconnaître.
|
|
519
569
|
- La création renvoie aussi l'entrée `.mcp.json` du mode MCP : `npx -y @imenam/mcp-organizer` avec `ORGANIZER_URL` (l'URL publique du site) et `ORGANIZER_TOKEN` (le jeton).
|
|
520
570
|
- Un jeton est vérifié à chaque usage : il ne doit être ni révoqué ni expiré, son propriétaire doit avoir un compte actif et être toujours membre de l'espace couvert. Chaque usage accepté met à jour son « dernier usage ».
|
|
@@ -550,7 +600,8 @@ Le navigateur enregistre le micro en webm (MediaRecorder) et envoie l'enregistre
|
|
|
550
600
|
| `POST /api/agent-actions/:id/undo`, `POST /api/requests/:id/undo` | Annulation d'une action ; d'un lot |
|
|
551
601
|
| `GET /api/tasks/:id/versions`, `POST /api/tasks/:id/versions/:version/restore` | Versions d'une tâche ; restauration |
|
|
552
602
|
| `GET /api/notifications`, `GET …/unread-count`, `POST …/:id/read`, `POST …/read-all` | Notifications |
|
|
553
|
-
| `GET` / `PUT /api/settings` | Préférences de notification ; disponibilité de l'e-mail et de la dictée |
|
|
603
|
+
| `GET` / `PUT /api/settings` | Préférences de notification du compte, mémoire de l'assistant ; disponibilité de l'e-mail et de la dictée |
|
|
604
|
+
| `GET` / `PUT /api/spaces/:id/notification-settings` | Notifications de l'utilisateur dans un espace : `custom` (préférences propres à l'espace, sinon celles du compte), les quatre préférences en vigueur ; `PUT` avec `custom: false` revient au compte |
|
|
554
605
|
| `GET` / `POST /api/tokens`, `POST /api/tokens/:id/revoke` | Jetons d'agent de l'utilisateur ; création `{ name, spaceId, expiresInDays }` (renvoie une seule fois `value` et `mcpJson`, l’entrée `.mcp.json` du mode MCP) ; révocation |
|
|
555
606
|
| `POST /api/transcribe` (multipart, champ `file`) | Dictée |
|
|
556
607
|
| `GET /api/changes?since=<seq>` | Changements des espaces de l'utilisateur et de ses notifications |
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* API d'administration (`/api/admin/*`), réservée aux administrateurs du
|
|
4
|
+
* site : tous les comptes avec leurs espaces, et l'autorisation du runner par
|
|
5
|
+
* espace.
|
|
6
|
+
*/
|
|
7
|
+
export declare const AdminSpaceViewSchema: z.ZodObject<{
|
|
8
|
+
id: z.ZodString;
|
|
9
|
+
name: z.ZodString;
|
|
10
|
+
kind: z.ZodEnum<{
|
|
11
|
+
personal: "personal";
|
|
12
|
+
shared: "shared";
|
|
13
|
+
}>;
|
|
14
|
+
keyPrefix: z.ZodString;
|
|
15
|
+
runnerAllowed: z.ZodBoolean;
|
|
16
|
+
members: z.ZodArray<z.ZodObject<{
|
|
17
|
+
id: z.ZodString;
|
|
18
|
+
name: z.ZodString;
|
|
19
|
+
email: z.ZodPipe<z.ZodString, z.ZodEmail>;
|
|
20
|
+
}, z.core.$strip>>;
|
|
21
|
+
}, z.core.$strip>;
|
|
22
|
+
export type AdminSpaceView = z.infer<typeof AdminSpaceViewSchema>;
|
|
23
|
+
export declare const AdminUserViewSchema: z.ZodObject<{
|
|
24
|
+
id: z.ZodString;
|
|
25
|
+
email: z.ZodPipe<z.ZodString, z.ZodEmail>;
|
|
26
|
+
displayName: z.ZodNullable<z.ZodString>;
|
|
27
|
+
status: z.ZodEnum<{
|
|
28
|
+
active: "active";
|
|
29
|
+
disabled: "disabled";
|
|
30
|
+
invited: "invited";
|
|
31
|
+
}>;
|
|
32
|
+
isAdmin: z.ZodBoolean;
|
|
33
|
+
spaces: z.ZodArray<z.ZodObject<{
|
|
34
|
+
id: z.ZodString;
|
|
35
|
+
name: z.ZodString;
|
|
36
|
+
kind: z.ZodEnum<{
|
|
37
|
+
personal: "personal";
|
|
38
|
+
shared: "shared";
|
|
39
|
+
}>;
|
|
40
|
+
keyPrefix: z.ZodString;
|
|
41
|
+
runnerAllowed: z.ZodBoolean;
|
|
42
|
+
members: z.ZodArray<z.ZodObject<{
|
|
43
|
+
id: z.ZodString;
|
|
44
|
+
name: z.ZodString;
|
|
45
|
+
email: z.ZodPipe<z.ZodString, z.ZodEmail>;
|
|
46
|
+
}, z.core.$strip>>;
|
|
47
|
+
}, z.core.$strip>>;
|
|
48
|
+
}, z.core.$strip>;
|
|
49
|
+
export type AdminUserView = z.infer<typeof AdminUserViewSchema>;
|
|
50
|
+
/** État du runner du site : actif, ou désactivé avec la raison (en français). */
|
|
51
|
+
export declare const RunnerStatusSchema: z.ZodObject<{
|
|
52
|
+
enabled: z.ZodBoolean;
|
|
53
|
+
disabledReason: z.ZodNullable<z.ZodString>;
|
|
54
|
+
}, z.core.$strip>;
|
|
55
|
+
export type RunnerStatus = z.infer<typeof RunnerStatusSchema>;
|
|
56
|
+
/** `GET /admin/spaces` : comptes du plus ancien au plus récent, décompte des espaces autorisés et état du runner. */
|
|
57
|
+
export declare const AdminSpacesResponseSchema: z.ZodObject<{
|
|
58
|
+
users: z.ZodArray<z.ZodObject<{
|
|
59
|
+
id: z.ZodString;
|
|
60
|
+
email: z.ZodPipe<z.ZodString, z.ZodEmail>;
|
|
61
|
+
displayName: z.ZodNullable<z.ZodString>;
|
|
62
|
+
status: z.ZodEnum<{
|
|
63
|
+
active: "active";
|
|
64
|
+
disabled: "disabled";
|
|
65
|
+
invited: "invited";
|
|
66
|
+
}>;
|
|
67
|
+
isAdmin: z.ZodBoolean;
|
|
68
|
+
spaces: z.ZodArray<z.ZodObject<{
|
|
69
|
+
id: z.ZodString;
|
|
70
|
+
name: z.ZodString;
|
|
71
|
+
kind: z.ZodEnum<{
|
|
72
|
+
personal: "personal";
|
|
73
|
+
shared: "shared";
|
|
74
|
+
}>;
|
|
75
|
+
keyPrefix: z.ZodString;
|
|
76
|
+
runnerAllowed: z.ZodBoolean;
|
|
77
|
+
members: z.ZodArray<z.ZodObject<{
|
|
78
|
+
id: z.ZodString;
|
|
79
|
+
name: z.ZodString;
|
|
80
|
+
email: z.ZodPipe<z.ZodString, z.ZodEmail>;
|
|
81
|
+
}, z.core.$strip>>;
|
|
82
|
+
}, z.core.$strip>>;
|
|
83
|
+
}, z.core.$strip>>;
|
|
84
|
+
allowedCount: z.ZodNumber;
|
|
85
|
+
spaceCount: z.ZodNumber;
|
|
86
|
+
runner: z.ZodObject<{
|
|
87
|
+
enabled: z.ZodBoolean;
|
|
88
|
+
disabledReason: z.ZodNullable<z.ZodString>;
|
|
89
|
+
}, z.core.$strip>;
|
|
90
|
+
}, z.core.$strip>;
|
|
91
|
+
export type AdminSpacesResponse = z.infer<typeof AdminSpacesResponseSchema>;
|
|
92
|
+
/** `POST /spaces/:spaceId/runner/run` : session lancée pour traiter les demandes en attente. */
|
|
93
|
+
export declare const RunQueueResponseSchema: z.ZodObject<{
|
|
94
|
+
pendingCount: z.ZodNumber;
|
|
95
|
+
}, z.core.$strip>;
|
|
96
|
+
export type RunQueueResponse = z.infer<typeof RunQueueResponseSchema>;
|
|
97
|
+
/** `PUT /admin/spaces/:spaceId/runner` */
|
|
98
|
+
export declare const SetRunnerAllowedRequestSchema: z.ZodObject<{
|
|
99
|
+
allowed: z.ZodBoolean;
|
|
100
|
+
}, z.core.$strict>;
|
|
101
|
+
export type SetRunnerAllowedRequest = z.infer<typeof SetRunnerAllowedRequestSchema>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { SpaceKindSchema, UserStatusSchema } from "./enums.schema.js";
|
|
3
|
+
import { EmailSchema, IdSchema } from "./entities.schema.js";
|
|
4
|
+
/**
|
|
5
|
+
* API d'administration (`/api/admin/*`), réservée aux administrateurs du
|
|
6
|
+
* site : tous les comptes avec leurs espaces, et l'autorisation du runner par
|
|
7
|
+
* espace.
|
|
8
|
+
*/
|
|
9
|
+
export const AdminSpaceViewSchema = z.object({
|
|
10
|
+
id: IdSchema,
|
|
11
|
+
name: z.string(),
|
|
12
|
+
kind: SpaceKindSchema,
|
|
13
|
+
keyPrefix: z.string(),
|
|
14
|
+
runnerAllowed: z.boolean(),
|
|
15
|
+
/** Membres de l'espace, propriétaire compris, dans l'ordre d'arrivée. */
|
|
16
|
+
members: z.array(z.object({ id: IdSchema, name: z.string(), email: EmailSchema })),
|
|
17
|
+
});
|
|
18
|
+
export const AdminUserViewSchema = z.object({
|
|
19
|
+
id: IdSchema,
|
|
20
|
+
email: EmailSchema,
|
|
21
|
+
displayName: z.string().nullable(),
|
|
22
|
+
status: UserStatusSchema,
|
|
23
|
+
isAdmin: z.boolean(),
|
|
24
|
+
/** Espaces dont le compte est propriétaire : son espace personnel d'abord, puis ses espaces communs par nom. */
|
|
25
|
+
spaces: z.array(AdminSpaceViewSchema),
|
|
26
|
+
});
|
|
27
|
+
/** État du runner du site : actif, ou désactivé avec la raison (en français). */
|
|
28
|
+
export const RunnerStatusSchema = z.object({ enabled: z.boolean(), disabledReason: z.string().nullable() });
|
|
29
|
+
/** `GET /admin/spaces` : comptes du plus ancien au plus récent, décompte des espaces autorisés et état du runner. */
|
|
30
|
+
export const AdminSpacesResponseSchema = z.object({
|
|
31
|
+
users: z.array(AdminUserViewSchema),
|
|
32
|
+
allowedCount: z.number().int().min(0),
|
|
33
|
+
spaceCount: z.number().int().min(0),
|
|
34
|
+
runner: RunnerStatusSchema,
|
|
35
|
+
});
|
|
36
|
+
/** `POST /spaces/:spaceId/runner/run` : session lancée pour traiter les demandes en attente. */
|
|
37
|
+
export const RunQueueResponseSchema = z.object({ pendingCount: z.number().int().min(1) });
|
|
38
|
+
/** `PUT /admin/spaces/:spaceId/runner` */
|
|
39
|
+
export const SetRunnerAllowedRequestSchema = z.object({ allowed: z.boolean() }).strict();
|
|
@@ -236,6 +236,8 @@ export declare const RequestListResponseSchema: z.ZodObject<{
|
|
|
236
236
|
lastUsedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
237
237
|
listening: z.ZodBoolean;
|
|
238
238
|
}, z.core.$strip>>;
|
|
239
|
+
runnerAllowed: z.ZodBoolean;
|
|
240
|
+
runnerDisabledReason: z.ZodNullable<z.ZodString>;
|
|
239
241
|
}, z.core.$strip>;
|
|
240
242
|
export type RequestListResponse = z.infer<typeof RequestListResponseSchema>;
|
|
241
243
|
/** Version d'une tâche dans son historique. */
|
|
@@ -80,6 +80,10 @@ export const RequestListResponseSchema = z.object({
|
|
|
80
80
|
* récemment ; `listening` : un veilleur de notifications de ce jeton est armé.
|
|
81
81
|
*/
|
|
82
82
|
agents: z.array(AgentRefSchema.extend({ lastUsedAt: TimestampSchema.nullable(), listening: z.boolean() })),
|
|
83
|
+
/** Le runner traite les demandes de l'espace (décidé par un administrateur). */
|
|
84
|
+
runnerAllowed: z.boolean(),
|
|
85
|
+
/** Raison pour laquelle le runner du site est désactivé (en français), null quand il est actif. */
|
|
86
|
+
runnerDisabledReason: z.string().nullable(),
|
|
83
87
|
});
|
|
84
88
|
/** Version d'une tâche dans son historique. */
|
|
85
89
|
export const TaskVersionViewSchema = z.object({
|
|
@@ -361,6 +361,40 @@ export declare const ClaimRequestDataSchema: z.ZodObject<{
|
|
|
361
361
|
reply: z.ZodNullable<z.ZodString>;
|
|
362
362
|
failureReason: z.ZodNullable<z.ZodString>;
|
|
363
363
|
}, z.core.$strip>;
|
|
364
|
+
history: z.ZodArray<z.ZodObject<{
|
|
365
|
+
id: z.ZodString;
|
|
366
|
+
kind: z.ZodEnum<{
|
|
367
|
+
idea: "idea";
|
|
368
|
+
idea_promotion: "idea_promotion";
|
|
369
|
+
message: "message";
|
|
370
|
+
remark: "remark";
|
|
371
|
+
test_review: "test_review";
|
|
372
|
+
}>;
|
|
373
|
+
status: z.ZodEnum<{
|
|
374
|
+
cancelled: "cancelled";
|
|
375
|
+
done: "done";
|
|
376
|
+
failed: "failed";
|
|
377
|
+
pending: "pending";
|
|
378
|
+
processing: "processing";
|
|
379
|
+
}>;
|
|
380
|
+
text: z.ZodString;
|
|
381
|
+
author: z.ZodObject<{
|
|
382
|
+
id: z.ZodString;
|
|
383
|
+
name: z.ZodString;
|
|
384
|
+
email: z.ZodString;
|
|
385
|
+
}, z.core.$strip>;
|
|
386
|
+
contextTask: z.ZodNullable<z.ZodObject<{
|
|
387
|
+
id: z.ZodString;
|
|
388
|
+
key: z.ZodString;
|
|
389
|
+
title: z.ZodString;
|
|
390
|
+
}, z.core.$strip>>;
|
|
391
|
+
contextIdeaId: z.ZodNullable<z.ZodString>;
|
|
392
|
+
createdAt: z.ZodISODateTime;
|
|
393
|
+
claimedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
394
|
+
claimedByThisToken: z.ZodBoolean;
|
|
395
|
+
reply: z.ZodNullable<z.ZodString>;
|
|
396
|
+
failureReason: z.ZodNullable<z.ZodString>;
|
|
397
|
+
}, z.core.$strip>>;
|
|
364
398
|
space: z.ZodObject<{
|
|
365
399
|
id: z.ZodString;
|
|
366
400
|
name: z.ZodString;
|
|
@@ -145,6 +145,8 @@ export const AgentIdeaSchema = z.object({ id: IdSchema, text: z.string(), archiv
|
|
|
145
145
|
export const ListRequestsDataSchema = z.object({ space: AgentSpaceSchema, requests: z.array(AgentRequestSummarySchema) });
|
|
146
146
|
export const ClaimRequestDataSchema = z.object({
|
|
147
147
|
request: AgentRequestSummarySchema,
|
|
148
|
+
/** Échanges précédents de l'auteur dans l'espace, du plus ancien au plus récent, pour une demande de type message. */
|
|
149
|
+
history: z.array(AgentRequestSummarySchema),
|
|
148
150
|
space: AgentSpaceSchema,
|
|
149
151
|
members: z.array(AgentMemberSchema),
|
|
150
152
|
tasks: z.array(AgentTaskSummarySchema),
|
|
@@ -17,6 +17,7 @@ export declare const PublicUserSchema: z.ZodObject<{
|
|
|
17
17
|
disabled: "disabled";
|
|
18
18
|
invited: "invited";
|
|
19
19
|
}>;
|
|
20
|
+
isAdmin: z.ZodBoolean;
|
|
20
21
|
}, z.core.$strip>;
|
|
21
22
|
export type PublicUser = z.infer<typeof PublicUserSchema>;
|
|
22
23
|
export declare const LoginRequestSchema: z.ZodObject<{
|
|
@@ -34,6 +35,7 @@ export declare const MeResponseSchema: z.ZodObject<{
|
|
|
34
35
|
disabled: "disabled";
|
|
35
36
|
invited: "invited";
|
|
36
37
|
}>;
|
|
38
|
+
isAdmin: z.ZodBoolean;
|
|
37
39
|
}, z.core.$strip>;
|
|
38
40
|
}, z.core.$strip>;
|
|
39
41
|
export type MeResponse = z.infer<typeof MeResponseSchema>;
|
|
@@ -15,6 +15,8 @@ export const PublicUserSchema = z.object({
|
|
|
15
15
|
email: EmailSchema,
|
|
16
16
|
displayName: z.string().nullable(),
|
|
17
17
|
status: UserStatusSchema,
|
|
18
|
+
/** Administrateur du site : voit la page Administration. */
|
|
19
|
+
isAdmin: z.boolean(),
|
|
18
20
|
});
|
|
19
21
|
// --- Authentification ---
|
|
20
22
|
export const LoginRequestSchema = z.object({
|
|
@@ -18,6 +18,7 @@ export declare const UserSchema: z.ZodObject<{
|
|
|
18
18
|
disabled: "disabled";
|
|
19
19
|
invited: "invited";
|
|
20
20
|
}>;
|
|
21
|
+
isAdmin: z.ZodBoolean;
|
|
21
22
|
createdAt: z.ZodISODateTime;
|
|
22
23
|
}, z.core.$strip>;
|
|
23
24
|
export type User = z.infer<typeof UserSchema>;
|
|
@@ -58,16 +59,40 @@ export declare const AgentTokenSchema: z.ZodObject<{
|
|
|
58
59
|
lastUsedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
59
60
|
expiresAt: z.ZodNullable<z.ZodISODateTime>;
|
|
60
61
|
revokedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
62
|
+
isRunner: z.ZodBoolean;
|
|
61
63
|
}, z.core.$strip>;
|
|
62
64
|
export type AgentToken = z.infer<typeof AgentTokenSchema>;
|
|
65
|
+
/** Bornes du nombre d'échanges précédents de l'auteur transmis à l'agent avec un message. */
|
|
66
|
+
export declare const MIN_ASSISTANT_HISTORY = 5;
|
|
67
|
+
export declare const MAX_ASSISTANT_HISTORY = 20;
|
|
68
|
+
export declare const AssistantHistorySchema: z.ZodNumber;
|
|
69
|
+
/** Préférences de notification : assignation et commentaire, dans l'application et par e-mail. */
|
|
70
|
+
export declare const NotificationPreferencesSchema: z.ZodObject<{
|
|
71
|
+
notifyAssignApp: z.ZodBoolean;
|
|
72
|
+
notifyAssignEmail: z.ZodBoolean;
|
|
73
|
+
notifyCommentApp: z.ZodBoolean;
|
|
74
|
+
notifyCommentEmail: z.ZodBoolean;
|
|
75
|
+
}, z.core.$strip>;
|
|
76
|
+
export type NotificationPreferences = z.infer<typeof NotificationPreferencesSchema>;
|
|
63
77
|
export declare const UserSettingsSchema: z.ZodObject<{
|
|
64
|
-
userId: z.ZodString;
|
|
65
78
|
notifyAssignApp: z.ZodBoolean;
|
|
66
79
|
notifyAssignEmail: z.ZodBoolean;
|
|
67
80
|
notifyCommentApp: z.ZodBoolean;
|
|
68
81
|
notifyCommentEmail: z.ZodBoolean;
|
|
82
|
+
userId: z.ZodString;
|
|
83
|
+
assistantHistory: z.ZodNumber;
|
|
69
84
|
}, z.core.$strip>;
|
|
70
85
|
export type UserSettings = z.infer<typeof UserSettingsSchema>;
|
|
86
|
+
/** Préférences de notification d'un utilisateur propres à un espace ; elles remplacent celles du compte dans cet espace. */
|
|
87
|
+
export declare const SpaceNotificationSettingsSchema: z.ZodObject<{
|
|
88
|
+
notifyAssignApp: z.ZodBoolean;
|
|
89
|
+
notifyAssignEmail: z.ZodBoolean;
|
|
90
|
+
notifyCommentApp: z.ZodBoolean;
|
|
91
|
+
notifyCommentEmail: z.ZodBoolean;
|
|
92
|
+
userId: z.ZodString;
|
|
93
|
+
spaceId: z.ZodString;
|
|
94
|
+
}, z.core.$strip>;
|
|
95
|
+
export type SpaceNotificationSettings = z.infer<typeof SpaceNotificationSettingsSchema>;
|
|
71
96
|
export declare const SpaceSchema: z.ZodObject<{
|
|
72
97
|
id: z.ZodString;
|
|
73
98
|
name: z.ZodString;
|
|
@@ -78,6 +103,7 @@ export declare const SpaceSchema: z.ZodObject<{
|
|
|
78
103
|
ownerId: z.ZodString;
|
|
79
104
|
keyPrefix: z.ZodString;
|
|
80
105
|
nextTaskNumber: z.ZodNumber;
|
|
106
|
+
runnerAllowed: z.ZodBoolean;
|
|
81
107
|
createdAt: z.ZodISODateTime;
|
|
82
108
|
}, z.core.$strip>;
|
|
83
109
|
export type Space = z.infer<typeof SpaceSchema>;
|
|
@@ -20,6 +20,8 @@ export const UserSchema = z.object({
|
|
|
20
20
|
displayName: z.string().min(1).nullable(),
|
|
21
21
|
passwordHash: z.string().min(1).nullable(),
|
|
22
22
|
status: UserStatusSchema,
|
|
23
|
+
/** Administrateur du site : accède à la page Administration. */
|
|
24
|
+
isAdmin: z.boolean(),
|
|
23
25
|
createdAt: TimestampSchema,
|
|
24
26
|
});
|
|
25
27
|
export const AccessLinkSchema = z.object({
|
|
@@ -55,14 +57,29 @@ export const AgentTokenSchema = z.object({
|
|
|
55
57
|
lastUsedAt: TimestampSchema.nullable(),
|
|
56
58
|
expiresAt: TimestampSchema.nullable(),
|
|
57
59
|
revokedAt: TimestampSchema.nullable(),
|
|
60
|
+
/** Jeton du runner de l'espace : absent des Paramètres, sa valeur change à chaque session. */
|
|
61
|
+
isRunner: z.boolean(),
|
|
58
62
|
});
|
|
59
|
-
|
|
60
|
-
|
|
63
|
+
/** Bornes du nombre d'échanges précédents de l'auteur transmis à l'agent avec un message. */
|
|
64
|
+
export const MIN_ASSISTANT_HISTORY = 5;
|
|
65
|
+
export const MAX_ASSISTANT_HISTORY = 20;
|
|
66
|
+
export const AssistantHistorySchema = z.number().int().min(MIN_ASSISTANT_HISTORY).max(MAX_ASSISTANT_HISTORY);
|
|
67
|
+
/** Préférences de notification : assignation et commentaire, dans l'application et par e-mail. */
|
|
68
|
+
export const NotificationPreferencesSchema = z.object({
|
|
61
69
|
notifyAssignApp: z.boolean(),
|
|
62
70
|
notifyAssignEmail: z.boolean(),
|
|
63
71
|
notifyCommentApp: z.boolean(),
|
|
64
72
|
notifyCommentEmail: z.boolean(),
|
|
65
73
|
});
|
|
74
|
+
export const UserSettingsSchema = NotificationPreferencesSchema.extend({
|
|
75
|
+
userId: IdSchema,
|
|
76
|
+
assistantHistory: AssistantHistorySchema,
|
|
77
|
+
});
|
|
78
|
+
/** Préférences de notification d'un utilisateur propres à un espace ; elles remplacent celles du compte dans cet espace. */
|
|
79
|
+
export const SpaceNotificationSettingsSchema = NotificationPreferencesSchema.extend({
|
|
80
|
+
userId: IdSchema,
|
|
81
|
+
spaceId: IdSchema,
|
|
82
|
+
});
|
|
66
83
|
export const SpaceSchema = z.object({
|
|
67
84
|
id: IdSchema,
|
|
68
85
|
name: z.string().trim().min(1),
|
|
@@ -70,6 +87,8 @@ export const SpaceSchema = z.object({
|
|
|
70
87
|
ownerId: IdSchema,
|
|
71
88
|
keyPrefix: KeyPrefixSchema,
|
|
72
89
|
nextTaskNumber: z.number().int().min(1),
|
|
90
|
+
/** Le runner traite les demandes de l'espace ; décidé par un administrateur. */
|
|
91
|
+
runnerAllowed: z.boolean(),
|
|
73
92
|
createdAt: TimestampSchema,
|
|
74
93
|
});
|
|
75
94
|
export const MembershipSchema = z.object({
|