// New Repository… (spec §8.5): a repository on a hub under you or one of // your organisations, optionally with an assistant's starting files (#347), // then cloned into a folder you choose. import * as vscode from "vscode"; import type * as api from "./hubapi"; import { HubAuth } from "./auth"; const NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/; export async function newRepository(auth: HubAuth): Promise { const hubs = auth.all().map((s) => s.base); const base = hubs.length === 1 ? hubs[0] : await vscode.window.showQuickPick(hubs, { placeHolder: "Create the repository on" }); if (!base) { if (!hubs.length) { void vscode.window.showWarningMessage("OxygenHub: sign in to a hub first."); } return; } const client = auth.clientFor(base); const [me, orgs] = await Promise.all([client.me(), client.orgs().catch(() => [] as api.Organisation[])]); const owner = orgs.length ? (await vscode.window.showQuickPick([{ label: me.username, description: "you" }, ...orgs.map((o) => ({ label: o.name, description: o.display_name }))], { placeHolder: "Owner" }))?.label : me.username; if (!owner) { return; } const name = await vscode.window.showInputBox({ prompt: `Repository name under ${owner}`, validateInput: (v) => (NAME.test(v) ? undefined : "Letters, digits, '.', '_' and '-', starting with a letter or digit") }); if (!name) { return; } const description = (await vscode.window.showInputBox({ prompt: "What is it for? (optional; an assistant can draft its starting files from this)" })) ?? ""; const vis = await vscode.window.showQuickPick( [ { label: "$(lock) Private", value: "private" as const }, { label: "$(organization) Internal", description: "everyone signed in to the hub", value: "internal" as const }, { label: "$(globe) Public", value: "public" as const }, ], { placeHolder: "Visibility" }, ); if (!vis) { return; } try { const repo = await client.createRepository({ owner, name, description, visibility: vis.value }); if (description.trim()) { await offerStarter(client, repo, description.trim()); } const pick = await vscode.window.showInformationMessage(`OxygenHub: created ${owner}/${name}.`, "Clone", "Open on Hub"); if (pick === "Open on Hub") { void vscode.env.openExternal(vscode.Uri.parse(`${base}/${owner}/${name}`)); } else if (pick === "Clone") { const parent = await vscode.window.showOpenDialog({ canSelectFolders: true, canSelectFiles: false, openLabel: "Clone Here" }); if (parent?.[0]) { const t = vscode.window.createTerminal({ name: "OxygenHub", cwd: parent[0].fsPath }); t.show(); t.sendText(`oxy clone ${repo.clone_url} ${name}`); } } } catch (e) { void vscode.window.showErrorMessage(`OxygenHub: ${(e as Error).message}`); } } /** When the owner has an assistant, offer its starting files, and wait for them. */ async function offerStarter(client: ReturnType, repo: api.Repository, description: string): Promise { const { assistants } = await client.starterAssistants(repo.owner).catch(() => ({ assistants: [] as api.StarterAssistant[] })); if (!assistants.length) { return; } const pick = await vscode.window.showQuickPick( [{ label: "$(close) No, start empty" }, ...assistants.map((a) => ({ label: `$(sparkle) Ask ${a.name}`, description: `${a.model}, from ${a.from}`, assistant: a.name }))], { placeHolder: "Ask an assistant for its starting files (a README, build files, a first test)?" }, ); if (!pick || !("assistant" in pick)) { return; } await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, title: `OxygenHub: ${pick.assistant} is drafting the starting files…`, cancellable: true }, async (_p, token) => { let s = await client.startStarter(repo.owner, repo.name, { description, assistant: pick.assistant }); // A model may take a few minutes; the hub commits the files when it is done. for (let i = 0; i < 120 && s.status === "running" && !token.isCancellationRequested; i++) { await new Promise((r) => setTimeout(r, 3000)); s = await client.starterStatus(repo.owner, repo.name); } if (s.status === "done") { void vscode.window.showInformationMessage(`OxygenHub: ${s.assistant} committed ${s.files?.length ?? 0} starting file(s).`); } else if (s.status === "failed") { void vscode.window.showWarningMessage(`OxygenHub: the starter failed: ${s.error}`); } else if (s.status === "running") { void vscode.window.showInformationMessage("OxygenHub: the starter is still being drafted; the hub commits it when done."); } }); }