feat: création de projet (nouveau dossier + session) & en-tête de session enrichi

- POST /api/v1/projects : crée <root>/<name> (mkdir non récursif, 409 si existant),
  git init optionnel, puis lance une session dedans. Anti-traversal sur le nom (core/project.ts).
- Web : NewProjectModal (racine préremplie scanRoots[0], case git init) + bouton dans SessionsListView.
- SessionContextBar : badge du groupe (cliquable) + repos couverts avec leur branche dans l'en-tête
  de session ; session simple = repo+branche déduits du cwd.
- 14 tests (unitaires + route).
This commit is contained in:
2026-06-23 18:52:22 +02:00
parent 06a400acc7
commit 8b9060e0c0
14 changed files with 571 additions and 2 deletions

View File

@@ -1,6 +1,6 @@
import { defineStore } from 'pinia';
import { ref } from 'vue';
import type { CreateSessionRequest, HideDiscoveredResponse, SessionResponse, SessionSummary, SessionsListResponse } from '@arboretum/shared';
import type { CreateProjectRequest, CreateProjectResponse, CreateSessionRequest, HideDiscoveredResponse, SessionResponse, SessionSummary, SessionsListResponse } from '@arboretum/shared';
import { api } from '../lib/api';
import { wsClient, type SessionEvent } from '../lib/ws-client';
@@ -106,6 +106,13 @@ export const useSessionsStore = defineStore('sessions', () => {
return res.session;
}
// Crée un nouveau dossier de projet `<root>/<name>` côté serveur puis y lance une session.
async function createProject(req: CreateProjectRequest): Promise<CreateProjectResponse> {
const res = await api.post<CreateProjectResponse>('/api/v1/projects', req);
upsert(res.session);
return res;
}
async function killSession(id: string): Promise<void> {
await api.delete<{ ok: true }>(`/api/v1/sessions/${id}`);
}
@@ -134,6 +141,7 @@ export const useSessionsStore = defineStore('sessions', () => {
startRealtime,
stopRealtime,
createSession,
createProject,
killSession,
resumeSession,
forkSession,