From 21b93cfe03b53cf595dd9b44c07261bd73087689 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=F0=9D=90=93=F0=9D=90=9E=F0=9D=90=9A=F0=9D=90=A4?=
=?UTF-8?q?=F0=9D=90=A8=F0=9D=90=B0=F0=9D=90=9A?=
<27560638+Teakowa@users.noreply.github.com>
Date: Mon, 14 Sep 2026 17:11:00 +0800
Subject: [PATCH 1/5] fix: publish Windows installer from site
---
scripts/sync-installer.mjs | 69 +++++++++++++++++++++++++-------------
1 file changed, 45 insertions(+), 24 deletions(-)
diff --git a/scripts/sync-installer.mjs b/scripts/sync-installer.mjs
index 5174b5e..560d239 100644
--- a/scripts/sync-installer.mjs
+++ b/scripts/sync-installer.mjs
@@ -6,56 +6,77 @@ import { fileURLToPath } from 'node:url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT_DIR = resolve(__dirname, '..');
const STATIC_DIR = resolve(ROOT_DIR, 'static');
-const TARGET_FILE = resolve(STATIC_DIR, 'install.sh');
-const LOCAL_CANONICAL_PATH = resolve(ROOT_DIR, '../wright/install.sh');
-const REMOTE_CANONICAL_URL =
- process.env.WRIGHT_INSTALLER_URL ||
- 'https://raw.githubusercontent.com/wrightkit/wright/main/install.sh';
+const installers = [
+ {
+ name: 'install.sh',
+ targetFile: resolve(STATIC_DIR, 'install.sh'),
+ localPath: resolve(ROOT_DIR, '../wright/install.sh'),
+ pathEnv: 'WRIGHT_INSTALLER_PATH',
+ urlEnv: 'WRIGHT_INSTALLER_URL',
+ remoteUrl: 'https://raw.githubusercontent.com/wrightkit/wright/main/install.sh',
+ validate(content) {
+ if (!content.startsWith('#!/usr/bin/env bash') && !content.startsWith('#!/bin/bash')) {
+ throw new Error('install.sh must start with a bash shebang.');
+ }
+ }
+ },
+ {
+ name: 'install.ps1',
+ targetFile: resolve(STATIC_DIR, 'install.ps1'),
+ localPath: resolve(ROOT_DIR, '../wright/install.ps1'),
+ pathEnv: 'WRIGHT_WINDOWS_INSTALLER_PATH',
+ urlEnv: 'WRIGHT_WINDOWS_INSTALLER_URL',
+ remoteUrl: 'https://raw.githubusercontent.com/wrightkit/wright/main/install.ps1',
+ validate(content) {
+ if (!content.includes('[CmdletBinding()]') || !content.includes('x86_64-pc-windows-msvc')) {
+ throw new Error('install.ps1 is missing the expected PowerShell installer contract.');
+ }
+ }
+ }
+];
-async function getInstallerContent() {
- const envPath = process.env.WRIGHT_INSTALLER_PATH;
+async function getInstallerContent(installer) {
+ const envPath = process.env[installer.pathEnv];
if (envPath && existsSync(envPath)) {
return readFileSync(envPath, 'utf8');
}
- if (existsSync(LOCAL_CANONICAL_PATH)) {
- return readFileSync(LOCAL_CANONICAL_PATH, 'utf8');
+ if (existsSync(installer.localPath)) {
+ return readFileSync(installer.localPath, 'utf8');
}
- const response = await fetch(REMOTE_CANONICAL_URL);
+ const remoteUrl = process.env[installer.urlEnv] || installer.remoteUrl;
+ const response = await fetch(remoteUrl);
if (!response.ok) {
- throw new Error(
- `Failed to fetch installer from ${REMOTE_CANONICAL_URL}: ${response.status} ${response.statusText}`
- );
+ throw new Error(`Failed to fetch ${installer.name} from ${remoteUrl}: ${response.status} ${response.statusText}`);
}
return await response.text();
}
-function validateInstaller(content) {
+function validateInstaller(installer, content) {
if (!content || typeof content !== 'string') {
- throw new Error('Installer content is empty or invalid.');
- }
- if (!content.startsWith('#!/usr/bin/env bash') && !content.startsWith('#!/bin/bash')) {
- throw new Error('Installer must start with bash shebang.');
+ throw new Error(`${installer.name} content is empty or invalid.`);
}
+ installer.validate(content);
if (!content.includes('wright') || !content.includes('wright-lsp')) {
- throw new Error('Installer content missing expected binary definitions (wright / wright-lsp).');
+ throw new Error(`${installer.name} is missing expected binary definitions (wright / wright-lsp).`);
}
if (content.length < 500) {
- throw new Error(`Installer content is suspiciously short (${content.length} bytes).`);
+ throw new Error(`${installer.name} is suspiciously short (${content.length} bytes).`);
}
}
async function main() {
- const content = await getInstallerContent();
- validateInstaller(content);
-
if (!existsSync(STATIC_DIR)) {
mkdirSync(STATIC_DIR, { recursive: true });
}
- writeFileSync(TARGET_FILE, content, 'utf8');
+ for (const installer of installers) {
+ const content = await getInstallerContent(installer);
+ validateInstaller(installer, content);
+ writeFileSync(installer.targetFile, content, 'utf8');
+ }
}
main().catch((err) => {
From 815ff18eb0162702a90362d74f302f3bbcf4c876 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=F0=9D=90=93=F0=9D=90=9E=F0=9D=90=9A=F0=9D=90=A4?=
=?UTF-8?q?=F0=9D=90=A8=F0=9D=90=B0=F0=9D=90=9A?=
<27560638+Teakowa@users.noreply.github.com>
Date: Mon, 14 Sep 2026 17:11:08 +0800
Subject: [PATCH 2/5] test: verify both hosted installers
---
scripts/verify-build.mjs | 46 ++++++++++++++++++++++++++++------------
1 file changed, 33 insertions(+), 13 deletions(-)
diff --git a/scripts/verify-build.mjs b/scripts/verify-build.mjs
index ca2d27b..d9e503b 100644
--- a/scripts/verify-build.mjs
+++ b/scripts/verify-build.mjs
@@ -5,19 +5,39 @@ import { fileURLToPath } from 'node:url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT_DIR = resolve(__dirname, '..');
-const BUILD_INSTALLER = resolve(ROOT_DIR, 'build/install.sh');
-if (!existsSync(BUILD_INSTALLER)) {
- console.error('[verify-build] Error: build/install.sh does not exist.');
- process.exit(1);
-}
+const installers = [
+ {
+ name: 'install.sh',
+ path: resolve(ROOT_DIR, 'build/install.sh'),
+ validate(content) {
+ return content.startsWith('#!/usr/bin/env bash') || content.startsWith('#!/bin/bash');
+ },
+ error: 'build/install.sh has an invalid shebang.'
+ },
+ {
+ name: 'install.ps1',
+ path: resolve(ROOT_DIR, 'build/install.ps1'),
+ validate(content) {
+ return content.includes('[CmdletBinding()]') && content.includes('x86_64-pc-windows-msvc');
+ },
+ error: 'build/install.ps1 is missing the expected PowerShell installer contract.'
+ }
+];
-const content = readFileSync(BUILD_INSTALLER, 'utf8');
-if (!content.startsWith('#!/usr/bin/env bash') && !content.startsWith('#!/bin/bash')) {
- console.error('[verify-build] Error: build/install.sh has invalid shebang.');
- process.exit(1);
-}
-if (!content.includes('wright') || !content.includes('wright-lsp')) {
- console.error('[verify-build] Error: build/install.sh is missing wright binary references.');
- process.exit(1);
+for (const installer of installers) {
+ if (!existsSync(installer.path)) {
+ console.error(`[verify-build] Error: build/${installer.name} does not exist.`);
+ process.exit(1);
+ }
+
+ const content = readFileSync(installer.path, 'utf8');
+ if (!installer.validate(content)) {
+ console.error(`[verify-build] Error: ${installer.error}`);
+ process.exit(1);
+ }
+ if (!content.includes('wright') || !content.includes('wright-lsp')) {
+ console.error(`[verify-build] Error: build/${installer.name} is missing wright binary references.`);
+ process.exit(1);
+ }
}
From 4f9820891c0658786f4219ef3d779a6beecf64ff Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=F0=9D=90=93=F0=9D=90=9E=F0=9D=90=9A=F0=9D=90=A4?=
=?UTF-8?q?=F0=9D=90=A8=F0=9D=90=B0=F0=9D=90=9A?=
<27560638+Teakowa@users.noreply.github.com>
Date: Mon, 14 Sep 2026 17:11:31 +0800
Subject: [PATCH 3/5] feat: select install target from visitor platform
---
src/lib/components/InstallSection.svelte | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/src/lib/components/InstallSection.svelte b/src/lib/components/InstallSection.svelte
index 47db8b4..2a81dad 100644
--- a/src/lib/components/InstallSection.svelte
+++ b/src/lib/components/InstallSection.svelte
@@ -1,11 +1,26 @@