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 @@
From 457cef801c92890b64e9d21c7766f732c760e552 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:12:15 +0800 Subject: [PATCH 4/5] fix: expose PowerShell install command --- src/lib/site.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/lib/site.ts b/src/lib/site.ts index e578f26..d4fb805 100644 --- a/src/lib/site.ts +++ b/src/lib/site.ts @@ -135,11 +135,9 @@ export const install = { id: 'windows', label: 'Windows', badge: 'x86_64', - method: 'GitHub Release archive', - command: 'https://github.com/wrightkit/wright/releases', - altMethod: 'See release documentation', - altCommand: 'docs/release.md', - note: 'Use the currently published Windows distribution path from the release documentation.' + method: 'PowerShell installer', + command: 'irm https://wrightkit.dev/install.ps1 | iex', + note: 'Downloads the matching Windows release and verifies its checksum.' }, { id: 'ci', From 3a4dd05676de9bbdccda4b7b8b5809416c731c0a 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:14:04 +0800 Subject: [PATCH 5/5] fix: keep Windows install target shape consistent --- src/lib/site.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/site.ts b/src/lib/site.ts index d4fb805..aef00a2 100644 --- a/src/lib/site.ts +++ b/src/lib/site.ts @@ -137,6 +137,8 @@ export const install = { badge: 'x86_64', method: 'PowerShell installer', command: 'irm https://wrightkit.dev/install.ps1 | iex', + altMethod: 'Custom install directory', + altCommand: '$script = irm https://wrightkit.dev/install.ps1; & ([scriptblock]::Create($script)) -InstallDir "$HOME\\bin"', note: 'Downloads the matching Windows release and verifies its checksum.' }, {