mirror of
https://github.com/aphrody-labs/terminal.git
synced 2026-10-13 22:05:20 +00:00
fix(aphrody): MSBuild appelé par son chemin dans l'instance VS, fragment livré avec les schémas Aphrody M3 générés, CI qui installe les composants UWP, README de l'outillage
This commit is contained in:
1 parent
459f92bd43
commit
65ac295794
6 files changed
+80
-21
No files matched your search
@@ -22,8 +22,9 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: aphrody-labs/bun/.github/actions/setup-bun@main
|
||||
# L'image ne porte pas les composants UWP de .vsconfig : setup les ajoute (le runner est administrateur).
|
||||
- name: setup
|
||||
run: bun run setup --no-vs-install
|
||||
run: bun run setup
|
||||
- name: build
|
||||
run: bun run build
|
||||
- uses: actions/upload-artifact@v4
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
# Terminal Aphrody
|
||||
|
||||
Terminal de la distribution Aphrody, construit depuis `aphrody-labs/terminal`, branche `aphrody`.
|
||||
La branche suit `microsoft/terminal` `main`, la source du canal Canary (build nocturne `build/pipelines/ob-nightly.yml`, branding `Canary`).
|
||||
Le paquet local porte le branding `Dev` : identité `WindowsTerminalDev`, alias `wtd.exe`. Il coexiste avec le Windows Terminal stable (`Microsoft.WindowsTerminal`).
|
||||
|
||||
## Prérequis
|
||||
|
||||
- Windows 11 avec le mode développeur activé (`AllowDevelopmentWithoutDevLicense=1`), requis pour `Add-AppxPackage -Register`.
|
||||
- Visual Studio 2026 : un IDE ou Build Tools. `bun run setup` installe les composants manquants.
|
||||
- Bun (le runtime de la distribution), `gsudo` ou le `sudo` de Windows pour l'élévation, `pwsh`.
|
||||
|
||||
## Commandes
|
||||
|
||||
| Commande | Effet |
|
||||
| --- | --- |
|
||||
| `bun run setup` | Détecte VS (vswhere) et ajoute les composants de `.vsconfig` (`setup.exe modify --config … --quiet --norestart`, élevé par gsudo ou sudo). Sur Build Tools, les workloads IDE sont remplacés par leurs équivalents Build Tools (`VCTools`, `UniversalBuildTools`, `ManagedDesktopBuildTools`…). Vérifie ensuite le Windows SDK de `src/common.build.pre.props`, le SDK .NET et vcpkg, puis restaure NuGet (`dep/nuget/packages.config`, `build/packages.config`, `msbuild /t:Restore`). Idempotent. `--no-vs-install` signale les composants manquants sans les installer. |
|
||||
| `bun run build [Release\|Debug] [x64\|ARM64]` | `msbuild OpenConsole.slnx /t:Terminal\CascadiaPackage` dans l'environnement `VsDevCmd` (même chemin qu'`Invoke-OpenConsoleBuild`). Release x64 par défaut, `WT_BRANDING` change le branding. |
|
||||
| `bun run deploy` | Décompresse le dernier `.msix` (`makeappx unpack`) dans `%LOCALAPPDATA%\aphrody\terminal\layout\<id>`, l'enregistre (`Add-AppxPackage -Register`), copie la config de profils canonique dans le `LocalState` du paquet, installe le fragment de profils puis lance `wtd.exe`. `--no-launch` saute le lancement. |
|
||||
| `bun run check:profiles [settings.json]` | Ouvre la commandline de chaque profil visible dans un PTY headless (`aphrody.exe shell term`) et vérifie qu'un écran s'affiche. |
|
||||
| `bun run bench [--runs N] [--label nom]` | Mesure le temps entre le lancement de `wt`/`wtd` et le démarrage du shell dans le nouvel onglet. |
|
||||
| `bun run sync [--push]` | `git fetch upstream main` puis rebase de `aphrody`. `--push` pousse `aphrody` et aligne `main` du dépôt sur upstream. |
|
||||
| `bun run clean [--all]` | Supprime `bin`, `obj`, `AppPackages` et les `Generated Files`. `--all` désinstalle aussi le paquet, son layout et le fragment. |
|
||||
|
||||
## Chemins
|
||||
|
||||
| Chemin | Contenu |
|
||||
| --- | --- |
|
||||
| `obj\aphrody\` | Journaux (`build-x64-Release.log`, `.binlog`, `restore*.log`, `vs-installer.log`), `vsconfig.json` généré, mesures `bench-*.json`. |
|
||||
| `src\cascadia\CascadiaPackage\AppPackages\` | `.msix` produit par le build. |
|
||||
| `%LOCALAPPDATA%\aphrody\terminal\layout\` | Layout enregistré du paquet. |
|
||||
| `%LOCALAPPDATA%\Packages\WindowsTerminalDev_8wekyb3d8bbwe\LocalState\settings.json` | Config appliquée, copie de `C:\aphrody\tools\config\host\windows\terminal\settings.json` plus `tools/aphrody/settings.overrides.json` s'il existe. |
|
||||
| `%LOCALAPPDATA%\Microsoft\Windows Terminal\Fragments\Aphrody\aphrody-terminal.json` | Fragment `tools/aphrody/fragment.json` : profils Aphrody Shell (Nushell, `aphrody.exe shell start`) et Bun Shell. |
|
||||
|
||||
## Profils et thème
|
||||
|
||||
Aphrody Shell et Bun Shell sont des profils dynamiques livrés par fragment, sans patch C++. Leurs GUID sont ceux de la config canonique, qui se superpose donc au fragment.
|
||||
Le fragment est lu par toutes les éditions de Terminal installées, stable comprise.
|
||||
Le schéma de couleurs `Aphrody M3` est généré depuis les tokens M3 par la crate `aphrody-identity`, dans `C:\aphrody\tools\config\host\windows\terminal\aphrody-m3.wt-scheme.json`. `fragment.json` le référence par son nom. `deploy` joint au fragment installé les schémas référencés tels que ce fichier les définit, ce qui les rend visibles par toutes les éditions installées. Si le fichier est absent, et qu'aucun autre fragment ne déclare le schéma, la référence est omise, car un schéma inconnu provoque un avertissement au démarrage.
|
||||
|
||||
## CI
|
||||
|
||||
`.github/workflows/aphrody-build.yml` exécute `bun run setup` (l'image n'a pas les composants UWP de `.vsconfig`) puis `bun run build` sur `windows-2025` à chaque push sur `aphrody`, et publie le `.msix` et les journaux. Le workflow upstream `spelling2` (Spell checking) est désactivé sur ce dépôt. `addToProject` (issues) et `winget` (releases publiées) ne se déclenchent pas : le dépôt n'a ni issues ni releases.
|
||||
@@ -1,7 +1,7 @@
|
||||
// bun run build [Debug|Release] [x64|ARM64] : paquet Terminal (CascadiaPackage) via msbuild,
|
||||
// même chemin qu'Invoke-OpenConsoleBuild (tools/OpenConsole.psm1) dans un environnement VsDevCmd.
|
||||
import { join } from "node:path";
|
||||
import { OUT, ensureDir, log, runLogged, vsDevEnv, vsInstance } from "./lib.ts";
|
||||
import { OUT, ensureDir, log, msbuildExe, runLogged, vsDevEnv, vsInstance } from "./lib.ts";
|
||||
|
||||
const configuration = process.argv.find(a => /^(debug|release)$/i.test(a)) ?? "Release";
|
||||
const platform = process.argv.find(a => /^(x64|arm64)$/i.test(a)) ?? "x64";
|
||||
@@ -14,7 +14,7 @@ ensureDir(OUT);
|
||||
|
||||
const logFile = join(OUT, `build-${platform}-${configuration}.log`);
|
||||
const args = [
|
||||
"msbuild.exe",
|
||||
msbuildExe(vs),
|
||||
"OpenConsole.slnx",
|
||||
`/p:Configuration=${configuration}`,
|
||||
`/p:Platform=${platform}`,
|
||||
|
||||
+23
-17
@@ -7,6 +7,7 @@ import {
|
||||
FRAGMENT_DIR,
|
||||
LAYOUT_DIR,
|
||||
LOCALAPPDATA,
|
||||
M3_SCHEMES,
|
||||
OUT,
|
||||
PACKAGE_NAME,
|
||||
ROOT,
|
||||
@@ -78,15 +79,13 @@ async function register(): Promise<AppxPackage> {
|
||||
return pkg;
|
||||
}
|
||||
|
||||
/** Schemes declared by any installed fragment or by the given settings files. */
|
||||
async function knownSchemes(settingsFiles: string[]): Promise<Set<string>> {
|
||||
/** Schemes declared by the other installed fragments. */
|
||||
async function fragmentSchemes(exclude: string): Promise<Set<string>> {
|
||||
const names = new Set<string>();
|
||||
const fragments = join(LOCALAPPDATA, "Microsoft", "Windows Terminal", "Fragments");
|
||||
const files = existsSync(fragments)
|
||||
? [...new Bun.Glob("**/*.json").scanSync({ cwd: fragments, absolute: true })]
|
||||
: [];
|
||||
for (const file of [...files, ...settingsFiles]) {
|
||||
if (!existsSync(file)) continue;
|
||||
if (!existsSync(fragments)) return names;
|
||||
for (const file of new Bun.Glob("**/*.json").scanSync({ cwd: fragments, absolute: true })) {
|
||||
if (file.toLowerCase() === exclude.toLowerCase()) continue;
|
||||
try {
|
||||
const json = (await Bun.file(file).json()) as { schemes?: { name: string }[] };
|
||||
for (const s of json.schemes ?? []) names.add(s.name);
|
||||
@@ -116,18 +115,25 @@ async function applySettings(pkg: AppxPackage): Promise<string> {
|
||||
return target;
|
||||
}
|
||||
|
||||
async function installFragment(settingsFile: string): Promise<void> {
|
||||
async function installFragment(): Promise<void> {
|
||||
const source = (await Bun.file(join(import.meta.dir, "fragment.json")).json()) as {
|
||||
profiles: Record<string, unknown>[];
|
||||
schemes?: { name: string }[];
|
||||
};
|
||||
const scheme = "Aphrody M3";
|
||||
const schemes = await knownSchemes([settingsFile, CANONICAL_SETTINGS]);
|
||||
// An unknown colorScheme raises a settings warning in every Terminal that reads the shared fragments.
|
||||
if (!schemes.has(scheme)) {
|
||||
for (const p of source.profiles) delete p.colorScheme;
|
||||
log("fragment", `schéma « ${scheme} » pas encore installé : référence omise jusqu'au prochain deploy`);
|
||||
}
|
||||
const target = join(ensureDir(FRAGMENT_DIR), "aphrody-terminal.json");
|
||||
const wanted = new Set(source.profiles.map(p => p.colorScheme).filter((s): s is string => typeof s === "string"));
|
||||
// Fragments are read by every installed Terminal edition, so the generated M3 schemes ship with the profiles.
|
||||
if (existsSync(M3_SCHEMES)) {
|
||||
source.schemes = ((await Bun.file(M3_SCHEMES).json()) as { name: string }[]).filter(s => wanted.has(s.name));
|
||||
}
|
||||
const known = await fragmentSchemes(target);
|
||||
for (const s of source.schemes ?? []) known.add(s.name);
|
||||
for (const name of wanted) {
|
||||
if (known.has(name)) continue;
|
||||
// An unknown colorScheme raises a settings warning at every Terminal startup.
|
||||
for (const p of source.profiles) if (p.colorScheme === name) delete p.colorScheme;
|
||||
log("fragment", `schéma « ${name} » absent de ${M3_SCHEMES} : référence omise`);
|
||||
}
|
||||
const content = JSON.stringify(source, null, 2) + "\n";
|
||||
if (existsSync(target) && (await Bun.file(target).text()) === content) {
|
||||
log("fragment", `${target} à jour`);
|
||||
@@ -172,6 +178,6 @@ async function launchCheck(pkg: AppxPackage): Promise<void> {
|
||||
ensureDir(OUT);
|
||||
const pkg = await register();
|
||||
log("deploy", `${pkg.Name} ${pkg.Version} (${pkg.PackageFamilyName})`);
|
||||
const settings = await applySettings(pkg);
|
||||
await installFragment(settings);
|
||||
await applySettings(pkg);
|
||||
await installFragment();
|
||||
if (!process.argv.includes("--no-launch")) await launchCheck(pkg);
|
||||
@@ -11,6 +11,8 @@ export const LOCALAPPDATA =
|
||||
export const PACKAGE_NAME = "WindowsTerminalDev";
|
||||
export const LAYOUT_DIR = join(LOCALAPPDATA, "aphrody", "terminal", "layout");
|
||||
export const CANONICAL_SETTINGS = "C:\\aphrody\\tools\\config\\host\\windows\\terminal\\settings.json";
|
||||
/** Generated by aphrody-identity (crates/ui/identity/src/terminal_theme.rs). */
|
||||
export const M3_SCHEMES = "C:\\aphrody\\tools\\config\\host\\windows\\terminal\\aphrody-m3.wt-scheme.json";
|
||||
export const FRAGMENT_DIR = join(LOCALAPPDATA, "Microsoft", "Windows Terminal", "Fragments", "Aphrody");
|
||||
|
||||
export function ensureDir(path: string): string {
|
||||
@@ -54,6 +56,12 @@ export function elevator(): string[] | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function msbuildExe(vs: VsInstance): string {
|
||||
const exe = join(vs.installationPath, "MSBuild", "Current", "Bin", "amd64", "MSBuild.exe");
|
||||
if (!existsSync(exe)) throw new Error(`MSBuild introuvable (${exe})`);
|
||||
return exe;
|
||||
}
|
||||
|
||||
let vsEnvCache: Record<string, string> | undefined;
|
||||
|
||||
/** Environment of a VS Developer prompt (amd64), equivalent to Set-MsBuildDevEnvironment. */
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
ensureDir,
|
||||
isAdmin,
|
||||
log,
|
||||
msbuildExe,
|
||||
runLogged,
|
||||
vsDevEnv,
|
||||
vsInstance,
|
||||
@@ -169,7 +170,7 @@ async function restore(vs: VsInstance): Promise<void> {
|
||||
const logFile = join(OUT, "restore.log");
|
||||
const code = await runLogged(
|
||||
[
|
||||
"msbuild.exe",
|
||||
msbuildExe(vs),
|
||||
"OpenConsole.slnx",
|
||||
"/t:Restore",
|
||||
"/p:Configuration=Release",
|
||||
|
||||
Reference in new issue
Block a user