From 7afb094f815fd07f6251e23f445ff99e58d51aa9 Mon Sep 17 00:00:00 2001 From: clawbot Date: Tue, 3 Feb 2026 07:14:50 -0800 Subject: [PATCH 01/24] ci: add project-wide typecheck workflow for main and PRs --- .github/workflows/typecheck.yml | 33 +++++++++++++++++++++++++++++++ application/package.json | 4 ++++ package.json | 9 ++++++++- packages/ogi-addon/package.json | 3 ++- packages/real-debrid/package.json | 3 ++- test-addon/package.json | 3 +++ web/package.json | 3 ++- 7 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/typecheck.yml diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml new file mode 100644 index 00000000..1f6a9202 --- /dev/null +++ b/.github/workflows/typecheck.yml @@ -0,0 +1,33 @@ +name: Typecheck + +on: + push: + branches: [main] + pull_request: + branches: [main] + +concurrency: + group: typecheck-${{ github.ref }} + cancel-in-progress: true + +jobs: + typecheck: + runs-on: ubuntu-latest + steps: + - name: Check out Git repository + uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: 1.3.8 + + - name: Install dependencies + run: | + bun install --frozen-lockfile + cp -r ./node_modules/electron ./application/node_modules/electron + mkdir -p ./updater/node_modules + cp -r ./node_modules/electron ./updater/node_modules/electron + + - name: Run project-wide typecheck + run: bun run typecheck diff --git a/application/package.json b/application/package.json index 1bc1f30b..e3677827 100644 --- a/application/package.json +++ b/application/package.json @@ -36,6 +36,10 @@ "electron-pack": "electron-builder", "electron-pack:linux": "electron-builder -l", "check": "svelte-check --tsconfig ./tsconfig.svelte.json", + "typecheck": "bun run typecheck:svelte && bun run typecheck:electron && bun run typecheck:addonserver", + "typecheck:svelte": "svelte-check --tsconfig ./tsconfig.svelte.json", + "typecheck:electron": "tsc -p tsconfig.electron.json --noEmit", + "typecheck:addonserver": "tsc -p tsconfig.addonserver.json --noEmit", "rebuild": "npm rebuild" }, "dependencies": { diff --git a/package.json b/package.json index 20696dda..a5cbaaaf 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,14 @@ "private": true, "scripts": { "release": "cd packages/ogi-addon && bun run release && cd ../real-debrid && bun run release", - "dev": "cd application && bun run electron-dev" + "dev": "cd application && bun run electron-dev", + "typecheck": "bun run build:typecheck-deps && bun run typecheck:ogi-addon && bun run typecheck:real-debrid && bun run typecheck:application && bun run typecheck:web && bun run typecheck:test-addon", + "build:typecheck-deps": "cd packages/ogi-addon && bun run build && cd ../real-debrid && bun run build", + "typecheck:application": "cd application && bun run typecheck", + "typecheck:web": "cd web && bun run typecheck", + "typecheck:ogi-addon": "cd packages/ogi-addon && bun run typecheck", + "typecheck:real-debrid": "cd packages/real-debrid && bun run typecheck", + "typecheck:test-addon": "cd test-addon && bun run typecheck" }, "workspaces": [ "packages/*", diff --git a/packages/ogi-addon/package.json b/packages/ogi-addon/package.json index b9469f89..f3d14ed4 100644 --- a/packages/ogi-addon/package.json +++ b/packages/ogi-addon/package.json @@ -46,7 +46,8 @@ "auto-build": "tsc -w", "build": "tsdown --config tsdown.config.js", "release": "bun run build && npm publish", - "release-beta": "bun run build && npm publish --tag future" + "release-beta": "bun run build && npm publish --tag future", + "typecheck": "tsc --noEmit" }, "devDependencies": { "@types/minimatch": "^6.0.0", diff --git a/packages/real-debrid/package.json b/packages/real-debrid/package.json index ad37c4da..0e624ec1 100644 --- a/packages/real-debrid/package.json +++ b/packages/real-debrid/package.json @@ -29,7 +29,8 @@ "auto-build": "tsc -w", "build": "tsdown --config tsdown.config.js", "test": "bun test ./tests/**/*.test.ts", - "release": "bun run build && npm publish" + "release": "bun run build && npm publish", + "typecheck": "tsc --noEmit" }, "devDependencies": { "@types/node": "^20.14.12", diff --git a/test-addon/package.json b/test-addon/package.json index 8271e87c..99bea3f7 100644 --- a/test-addon/package.json +++ b/test-addon/package.json @@ -2,6 +2,9 @@ "name": "test-addon", "module": "main.ts", "type": "module", + "scripts": { + "typecheck": "tsc --noEmit" + }, "dependencies": { "ogi-addon": "workspace:*" }, diff --git a/web/package.json b/web/package.json index afbc8d1b..cfda7eff 100644 --- a/web/package.json +++ b/web/package.json @@ -7,7 +7,8 @@ "start": "astro dev", "build": "astro check && astro build", "preview": "astro preview", - "astro": "astro" + "astro": "astro", + "typecheck": "astro check" }, "dependencies": { "@astrojs/check": "^0.9.2", From 087bb2646ed0ef911e96999cacb5c43e4bc8812c Mon Sep 17 00:00:00 2001 From: Nat3z <66748576+Nat3z@users.noreply.github.com> Date: Tue, 3 Feb 2026 11:19:12 -0800 Subject: [PATCH 02/24] Remove duplicate 'typecheck' script from package.json --- packages/ogi-addon/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/ogi-addon/package.json b/packages/ogi-addon/package.json index 97b4031c..33ae3204 100644 --- a/packages/ogi-addon/package.json +++ b/packages/ogi-addon/package.json @@ -48,7 +48,6 @@ "typecheck": "tsc --noEmit", "release": "bun run build && npm publish", "release-beta": "bun run build && npm publish --tag future", - "typecheck": "tsc --noEmit" }, "devDependencies": { "@types/minimatch": "^6.0.0", From f4454f8a3e80cba228b7b32a3f85fbebb354171d Mon Sep 17 00:00:00 2001 From: Nat3z <66748576+Nat3z@users.noreply.github.com> Date: Tue, 3 Feb 2026 11:20:28 -0800 Subject: [PATCH 03/24] Fix formatting in package.json for release-beta script --- packages/ogi-addon/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ogi-addon/package.json b/packages/ogi-addon/package.json index 33ae3204..621854a1 100644 --- a/packages/ogi-addon/package.json +++ b/packages/ogi-addon/package.json @@ -47,7 +47,7 @@ "build": "tsdown --config tsdown.config.js", "typecheck": "tsc --noEmit", "release": "bun run build && npm publish", - "release-beta": "bun run build && npm publish --tag future", + "release-beta": "bun run build && npm publish --tag future" }, "devDependencies": { "@types/minimatch": "^6.0.0", From 56a4b5ffc2d32718857a447658887ea3a15a812f Mon Sep 17 00:00:00 2001 From: clawbot Date: Tue, 3 Feb 2026 11:30:45 -0800 Subject: [PATCH 04/24] fix(typecheck): resolve CI typecheck failures --- packages/real-debrid/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/real-debrid/tsconfig.json b/packages/real-debrid/tsconfig.json index 6191a813..1890d57f 100644 --- a/packages/real-debrid/tsconfig.json +++ b/packages/real-debrid/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { // project options - "lib": ["ESNext"], // specifies which default set of type definitions to use ("DOM", "ES6", etc) + "lib": ["ESNext", "DOM"], // specifies which default set of type definitions to use ("DOM", "ES6", etc) "removeComments": true, // Strips all comments from TypeScript files when converting into JavaScript- you rarely read compiled code so this saves space "target": "ESNext", // Target environment. Most modern browsers support ES6, but you may want to set it to newer or older. (defaults to ES3) "module": "ESNext", From 74615d63c8ae9e3354e148d6601807865f04467b Mon Sep 17 00:00:00 2001 From: Fix Bot Date: Tue, 3 Feb 2026 11:37:00 -0800 Subject: [PATCH 05/24] fix(typecheck): fix addonName field mapping in RequestService --- .../src/frontend/lib/downloads/services/RequestService.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/application/src/frontend/lib/downloads/services/RequestService.ts b/application/src/frontend/lib/downloads/services/RequestService.ts index d2765c82..35ced801 100644 --- a/application/src/frontend/lib/downloads/services/RequestService.ts +++ b/application/src/frontend/lib/downloads/services/RequestService.ts @@ -77,6 +77,7 @@ export class RequestService extends BaseService { const updatedResult = { ...response, addonSource: result.addonSource, + addonName: result.addonName, capsuleImage: result.capsuleImage, coverImage: result.coverImage, storefront: result.storefront, From 2f05adc64e8e09dd1d5671fbc16cdb8345065e9e Mon Sep 17 00:00:00 2001 From: clawbot Date: Tue, 3 Feb 2026 11:55:05 -0800 Subject: [PATCH 06/24] fix(typecheck): resolve Svelte type errors --- .../src/electron/handlers/handler.ddl.ts | 2 +- .../electron/handlers/helpers.app/library.ts | 2 +- .../src/electron/handlers/library-handlers.ts | 2 +- .../handlers/redistributable-handlers.ts | 2 +- .../src/electron/manager/manager.addon.ts | 3 +- .../src/electron/server/AddonConnection.ts | 35 ++++++++++--------- .../src/electron/server/DeferrableTask.ts | 4 +-- .../src/electron/server/addon-server.ts | 12 ++++--- application/src/electron/server/api/addons.ts | 31 ++++++++-------- application/src/electron/startup.ts | 2 +- application/src/electron/tsconfig.json | 6 ++-- .../src/frontend/managers/GamepadManager.ts | 14 -------- .../frontend/views/FocusedAddonView.svelte | 1 + 13 files changed, 56 insertions(+), 60 deletions(-) diff --git a/application/src/electron/handlers/handler.ddl.ts b/application/src/electron/handlers/handler.ddl.ts index df16d4af..3c8bead6 100644 --- a/application/src/electron/handlers/handler.ddl.ts +++ b/application/src/electron/handlers/handler.ddl.ts @@ -2,7 +2,7 @@ import { ipcMain, BrowserWindow } from 'electron'; import * as fs from 'fs'; import { rm as rmAsync } from 'fs/promises'; import { sendNotification } from '../main.js'; -import axios, { AxiosError, AxiosResponse } from 'axios'; +import axios, { AxiosError, type AxiosResponse } from 'axios'; import { dirname } from 'path'; import { DOWNLOAD_QUEUE } from '../manager/manager.queue.js'; import { Readable } from 'stream'; diff --git a/application/src/electron/handlers/helpers.app/library.ts b/application/src/electron/handlers/helpers.app/library.ts index be49f880..48baaf7a 100644 --- a/application/src/electron/handlers/helpers.app/library.ts +++ b/application/src/electron/handlers/helpers.app/library.ts @@ -3,7 +3,7 @@ */ import { join } from 'path'; import * as fs from 'fs'; -import { LibraryInfo } from 'ogi-addon'; +import type { LibraryInfo } from 'ogi-addon'; import { __dirname } from '../../manager/manager.paths.js'; export function getLibraryPath(appID: number): string { diff --git a/application/src/electron/handlers/library-handlers.ts b/application/src/electron/handlers/library-handlers.ts index ccb1743d..4b1eaf61 100644 --- a/application/src/electron/handlers/library-handlers.ts +++ b/application/src/electron/handlers/library-handlers.ts @@ -3,7 +3,7 @@ */ import { ipcMain } from 'electron'; import { exec } from 'child_process'; -import { LibraryInfo } from 'ogi-addon'; +import type { LibraryInfo } from 'ogi-addon'; import { isLinux } from './helpers.app/platform.js'; import { getSteamAppIdWithFallback, diff --git a/application/src/electron/handlers/redistributable-handlers.ts b/application/src/electron/handlers/redistributable-handlers.ts index ff2db4bc..1b0158e3 100644 --- a/application/src/electron/handlers/redistributable-handlers.ts +++ b/application/src/electron/handlers/redistributable-handlers.ts @@ -6,7 +6,7 @@ import { spawn } from 'child_process'; import axios from 'axios'; import { join, dirname, basename } from 'path'; import * as fs from 'fs'; -import { LibraryInfo } from 'ogi-addon'; +import type { LibraryInfo } from 'ogi-addon'; import { isLinux, getProtonPrefixPath } from './helpers.app/platform.js'; import { getSteamAppIdWithFallback } from './helpers.app/steam.js'; import { loadLibraryInfo, saveLibraryInfo } from './helpers.app/library.js'; diff --git a/application/src/electron/manager/manager.addon.ts b/application/src/electron/manager/manager.addon.ts index 616d3554..bbde36fe 100644 --- a/application/src/electron/manager/manager.addon.ts +++ b/application/src/electron/manager/manager.addon.ts @@ -183,9 +183,10 @@ export async function startAddon( console.error(e); // write to the run-crash.log file + const errorMessage = e instanceof Error ? e.message : String(e); await writeFile( join(addonPath, 'run-crash.log'), - stripAnsiCodes(e.message) + stripAnsiCodes(errorMessage) ); sendNotification({ diff --git a/application/src/electron/server/AddonConnection.ts b/application/src/electron/server/AddonConnection.ts index e70cef89..582d2999 100644 --- a/application/src/electron/server/AddonConnection.ts +++ b/application/src/electron/server/AddonConnection.ts @@ -1,5 +1,5 @@ import wsLib from 'ws'; -import { +import type { ClientSentEventTypes, OGIAddonConfiguration, OGIAddonEvent, @@ -20,13 +20,13 @@ import { import { DeferrableTask, DeferredTasks } from './DeferrableTask.js'; export class AddonConnection { - public addonInfo: OGIAddonConfiguration; - public ws: wsLib.WebSocket; - public configTemplate: ConfigurationFile; + public addonInfo: OGIAddonConfiguration | undefined; + public ws: InstanceType; + public configTemplate: ConfigurationFile | undefined; public filePath: string | undefined; public addonLink: string | undefined; public eventsAvailable: OGIAddonEvent[] = []; - constructor(ws: wsLib.WebSocket) { + constructor(ws: InstanceType) { this.ws = ws; } @@ -38,7 +38,7 @@ export class AddonConnection { resolve(false); }, 1000); - this.ws.on('message', async (message) => { + this.ws.on('message', async (message: string | Buffer) => { const data: WebsocketMessageClient = JSON.parse(message.toString()); switch (data.event) { case 'notification': { @@ -49,7 +49,7 @@ export class AddonConnection { clearTimeout(authenticationTimeout); // authentication - this.addonInfo = data.args; + this.addonInfo = data.args as OGIAddonConfiguration; if ( isSecurityCheckEnabled && (!data.args.secret || data.args.secret !== addonSecret) @@ -76,7 +76,7 @@ export class AddonConnection { // resolve(false) // break; // } - if (clients.has(this.addonInfo.id)) { + if (clients.has(this.addonInfo!.id)) { console.error( 'Client attempted to authenticate with an ID that is already in use' ); @@ -88,7 +88,7 @@ export class AddonConnection { break; } console.log('Client authenticated:', data.args.name); - sendIPCMessage('addon-connected', this.addonInfo.id); + sendIPCMessage('addon-connected', this.addonInfo!.id); resolve(true); break; } @@ -140,7 +140,7 @@ export class AddonConnection { ); return; } - if (deferredTask.addonOwner !== this.addonInfo.id) { + if (deferredTask.addonOwner !== this.addonInfo!.id) { console.error( 'Client attempted to send defer-update with an ID that does not belong to them' ); @@ -253,7 +253,7 @@ export class AddonConnection { if (!task) { task = new DeferrableTask(async () => { return null; - }, this.addonInfo.id); + }, this.addonInfo!.id); DeferredTasks.getTasks()[data.args.id] = task; // sendNotification({ // type: 'info', @@ -305,7 +305,7 @@ export class AddonConnection { // query all of the clients for the app details const clientsWithStorefront = Array.from(clients.values()).filter( (client) => - client.addonInfo.storefronts.includes(storefront) && + client.addonInfo?.storefronts.includes(storefront) && client.eventsAvailable.includes('game-details') ); // find a storefront that gives app details that isn't undefined @@ -363,7 +363,7 @@ export class AddonConnection { }: ClientSentEventTypes['search-app-name'] = data.args; const clientsWithStorefront = Array.from(clients.values()).filter( (client) => - client.addonInfo.storefronts.includes(storefront) && + client.addonInfo?.storefronts.includes(storefront) && client.eventsAvailable.includes('library-search') ); const searchResult: StoreData[] = []; @@ -398,7 +398,7 @@ export class AddonConnection { 'Setting events-available to', data.args.value, 'for addon', - this.addonInfo.id + this.addonInfo!.id ); this.eventsAvailable = data.args.value as OGIAddonEvent[]; } @@ -416,18 +416,19 @@ export class AddonConnection { message.id = Math.random().toString(36).substring(7); } return new Promise((resolve, reject) => { - this.ws.send(JSON.stringify(message), (err) => { + this.ws.send(JSON.stringify(message), (err: Error | null | undefined) => { if (err) { reject(err); } }); if (expectResponse) { const waitResponse = () => { - if (this.ws.readyState === wsLib.CLOSED) { + // CLOSED state is 3 + if (this.ws.readyState === 3) { reject('Websocket closed'); return; } - this.ws.once('message', (messageRaw) => { + this.ws.once('message', (messageRaw: string | Buffer) => { const messageFromClient: WebsocketMessageClient = JSON.parse( '' + messageRaw.toString() ); diff --git a/application/src/electron/server/DeferrableTask.ts b/application/src/electron/server/DeferrableTask.ts index b6111268..c651db6b 100644 --- a/application/src/electron/server/DeferrableTask.ts +++ b/application/src/electron/server/DeferrableTask.ts @@ -16,7 +16,7 @@ export class DeferrableTask { private task: () => Promise; public finished: boolean = false; - public data: T | null; + public data: T | null = null; public id: string = Math.random().toString(36).substring(7); public addonOwner = ''; public logs: string[] = []; @@ -35,7 +35,7 @@ export class DeferrableTask { this.data = safeSerialize(result); console.log('task finished', this.id); } catch (error) { - this.failed = error; + this.failed = error instanceof Error ? error.message : String(error); this.data = null; this.finished = true; } diff --git a/application/src/electron/server/addon-server.ts b/application/src/electron/server/addon-server.ts index be55ed80..66fb26bd 100644 --- a/application/src/electron/server/addon-server.ts +++ b/application/src/electron/server/addon-server.ts @@ -20,12 +20,16 @@ wss.on('connection', async (ws) => { if (!connected) return; ws.on('close', () => { - console.log('Client disconnected', connection.addonInfo.id); - clients.delete(connection.addonInfo.id); + console.log('Client disconnected', connection.addonInfo?.id); + if (connection.addonInfo) { + clients.delete(connection.addonInfo.id); + } }); - clients.set(connection.addonInfo.id, connection); - await sendIPCMessage('addon-connected', connection.addonInfo.id); + if (connection.addonInfo) { + clients.set(connection.addonInfo.id, connection); + await sendIPCMessage('addon-connected', connection.addonInfo.id); + } }); app.all('*', (_, res, next) => { diff --git a/application/src/electron/server/api/addons.ts b/application/src/electron/server/api/addons.ts index 8ec6c664..890c714b 100644 --- a/application/src/electron/server/api/addons.ts +++ b/application/src/electron/server/api/addons.ts @@ -13,7 +13,8 @@ import * as fs from 'fs/promises'; import { join } from 'path'; import { restartAddonServer } from '../../handlers/handler.addon.js'; import { __dirname } from '../../manager/manager.paths.js'; -import { StoreData, ZodLibraryInfo } from 'ogi-addon'; +import type { StoreData } from 'ogi-addon'; +import { ZodLibraryInfo } from 'ogi-addon'; const procedures: Record> = { // Get all addon info @@ -22,10 +23,12 @@ const procedures: Record> = { .handler(async () => { let info = []; for (const client of clients.values()) { - info.push({ - ...client.addonInfo, - configTemplate: client.configTemplate, - }); + if (client.addonInfo) { + info.push({ + ...client.addonInfo, + configTemplate: client.configTemplate, + }); + } } return new ProcedureJSON(200, info); }), @@ -87,7 +90,7 @@ const procedures: Record> = { }); console.log('searchComplete', event.args); return event.args; - }, client.addonInfo.id); + }, client.addonInfo!.id); return new ProcedureDeferTask(200, deferrableTask); }), @@ -117,7 +120,7 @@ const procedures: Record> = { args: input.query, }); return event.args; - }, client.addonInfo.id); + }, client.addonInfo!.id); return new ProcedureDeferTask(200, deferrableTask); }), @@ -145,7 +148,7 @@ const procedures: Record> = { args: { appID: input.appID, info: input.info }, }); return data.args; - }, client.addonInfo.id); + }, client.addonInfo!.id); return new ProcedureDeferTask(200, deferrableTask); }), @@ -171,7 +174,7 @@ const procedures: Record> = { args: {}, }); return data.args; - }, client.addonInfo.id); + }, client.addonInfo!.id); return new ProcedureDeferTask(200, deferrableTask); }), @@ -231,7 +234,7 @@ const procedures: Record> = { }, }); return data.args; - }, client.addonInfo.id); + }, client.addonInfo!.id); return new ProcedureDeferTask(200, deferrableTask); }), @@ -247,7 +250,7 @@ const procedures: Record> = { .handler(async (input) => { const clientsWithStorefront = Array.from(clients.values()).filter( (client) => - client.addonInfo.storefronts.includes(input.storefront) && + client.addonInfo?.storefronts.includes(input.storefront) && client.eventsAvailable.includes('game-details') ); if (clientsWithStorefront.length === 0) @@ -392,7 +395,7 @@ const procedures: Record> = { }, }); return data.args; - }, client.addonInfo.id); + }, client.addonInfo!.id); return new ProcedureDeferTask(200, deferrableTask); }), @@ -408,7 +411,7 @@ const procedures: Record> = { .handler(async (input) => { const clientsWithStorefront = Array.from(clients.values()).filter( (client) => - client.addonInfo.storefronts.includes(input.storefront) && + client.addonInfo?.storefronts.includes(input.storefront) && client.eventsAvailable.includes('check-for-updates') ); if (clientsWithStorefront.length === 0) @@ -435,7 +438,7 @@ const procedures: Record> = { }, }); return data.args; - }, client.addonInfo.id); + }, client.addonInfo!.id); return new ProcedureDeferTask(200, deferrableTask); }), }; diff --git a/application/src/electron/startup.ts b/application/src/electron/startup.ts index 3b3133ae..851c1b25 100644 --- a/application/src/electron/startup.ts +++ b/application/src/electron/startup.ts @@ -11,7 +11,7 @@ import { mkdirSync, rmSync, } from 'original-fs'; -import { LibraryInfo } from 'ogi-addon'; +import type { LibraryInfo } from 'ogi-addon'; import { app, BrowserWindow } from 'electron'; import { sendNotification } from './main.js'; import semver from 'semver'; diff --git a/application/src/electron/tsconfig.json b/application/src/electron/tsconfig.json index 138eea6a..5e216d86 100644 --- a/application/src/electron/tsconfig.json +++ b/application/src/electron/tsconfig.json @@ -3,13 +3,13 @@ "compilerOptions": { "outDir": "../../build", "typeRoots": ["node_modules/@types"], - "target": "ESNext", + "target": "ES2020", "allowJs": true, "module": "ESNext", "sourceMap": true, "stripInternal": true, - "lib": ["ESNext", "dom"], - "moduleResolution": "Bundler", + "lib": ["ES2020", "dom"], + "moduleResolution": "bundler", "noImplicitAny": true, "strictNullChecks": true, "strictFunctionTypes": true, diff --git a/application/src/frontend/managers/GamepadManager.ts b/application/src/frontend/managers/GamepadManager.ts index 01d6bd61..22d98f33 100644 --- a/application/src/frontend/managers/GamepadManager.ts +++ b/application/src/frontend/managers/GamepadManager.ts @@ -539,20 +539,6 @@ export class GamepadNavigator { // Focus the element first - Steam keyboard will inject text here element.focus(); - // Get input properties for the keyboard - const previousText = element.value || ''; - const title = - element.placeholder || - element.getAttribute('aria-label') || - element.name || - 'Enter text'; - const maxChars = - element instanceof HTMLInputElement - ? element.maxLength > 0 - ? element.maxLength - : 500 - : 2000; - try { // Try to open Steam keyboard overlay // The keyboard injects text directly into the focused input diff --git a/application/src/frontend/views/FocusedAddonView.svelte b/application/src/frontend/views/FocusedAddonView.svelte index 5e48524a..e74ace5f 100644 --- a/application/src/frontend/views/FocusedAddonView.svelte +++ b/application/src/frontend/views/FocusedAddonView.svelte @@ -369,6 +369,7 @@ await runTask( { addonSource: selectedAddon.id, + addonName: selectedAddon.name, manifest: manifest, name: actionOption.displayName, downloadType: 'task' as const, From 1c5c243ba50ac1e61567534baf4685a6771c52c5 Mon Sep 17 00:00:00 2001 From: clawbot Date: Tue, 3 Feb 2026 12:03:43 -0800 Subject: [PATCH 07/24] fix(typecheck): resolve Svelte type errors and improve tsconfig module resolution --- application/src/electron/tsconfig.json | 11 +++++++---- application/src/frontend/global.d.ts | 1 + application/typings/ogi-addon.d.ts | 5 +++++ 3 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 application/typings/ogi-addon.d.ts diff --git a/application/src/electron/tsconfig.json b/application/src/electron/tsconfig.json index 5e216d86..7ba2a0ac 100644 --- a/application/src/electron/tsconfig.json +++ b/application/src/electron/tsconfig.json @@ -3,13 +3,16 @@ "compilerOptions": { "outDir": "../../build", "typeRoots": ["node_modules/@types"], - "target": "ES2020", + "target": "ES2022", "allowJs": true, - "module": "ESNext", + "module": "Node16", "sourceMap": true, "stripInternal": true, - "lib": ["ES2020", "dom"], - "moduleResolution": "bundler", + "lib": ["ES2022", "dom"], + "moduleResolution": "node16", + "paths": { + "ogi-addon/config": ["../../node_modules/ogi-addon/build/config/Configuration.d.mts"] + }, "noImplicitAny": true, "strictNullChecks": true, "strictFunctionTypes": true, diff --git a/application/src/frontend/global.d.ts b/application/src/frontend/global.d.ts index 2b06c3a3..0b1c7e16 100644 --- a/application/src/frontend/global.d.ts +++ b/application/src/frontend/global.d.ts @@ -3,6 +3,7 @@ type AxiosResponse = import('axios').AxiosResponse; type AxiosRequestConfig = import('axios').AxiosRequestConfig; type LibraryInfo = import('ogi-addon').LibraryInfo; +type ConfigurationFile = Record; type $AddTorrentOrMagnet = import('real-debrid-js').$AddTorrentOrMagnet; type $Hosts = import('real-debrid-js').$Hosts; type $UnrestrictLink = import('real-debrid-js').$UnrestrictLink; diff --git a/application/typings/ogi-addon.d.ts b/application/typings/ogi-addon.d.ts new file mode 100644 index 00000000..c9ee4683 --- /dev/null +++ b/application/typings/ogi-addon.d.ts @@ -0,0 +1,5 @@ +declare module 'ogi-addon/config' { + export interface ConfigurationFile { + [key: string]: any; + } +} From 40c21bacecd23cdebf77b256ab5066d2e913c83b Mon Sep 17 00:00:00 2001 From: clawbot Date: Tue, 3 Feb 2026 12:15:34 -0800 Subject: [PATCH 08/24] fix(typecheck): resolve all TypeScript module resolution and top-level await errors --- application/src/electron/tsconfig.json | 8 +++++--- application/tsconfig.addonserver.json | 13 +++++++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/application/src/electron/tsconfig.json b/application/src/electron/tsconfig.json index 7ba2a0ac..951b6a58 100644 --- a/application/src/electron/tsconfig.json +++ b/application/src/electron/tsconfig.json @@ -2,16 +2,18 @@ "compileOnSave": true, "compilerOptions": { "outDir": "../../build", + "baseUrl": ".", "typeRoots": ["node_modules/@types"], "target": "ES2022", "allowJs": true, - "module": "Node16", + "module": "ESNext", "sourceMap": true, "stripInternal": true, "lib": ["ES2022", "dom"], - "moduleResolution": "node16", + "moduleResolution": "bundler", "paths": { - "ogi-addon/config": ["../../node_modules/ogi-addon/build/config/Configuration.d.mts"] + "ogi-addon/config": ["../../node_modules/ogi-addon/build/config/Configuration.d.mts"], + "ogi-addon": ["../../node_modules/ogi-addon/build/main.d.mts"] }, "noImplicitAny": true, "strictNullChecks": true, diff --git a/application/tsconfig.addonserver.json b/application/tsconfig.addonserver.json index 4c83d808..e53620c3 100644 --- a/application/tsconfig.addonserver.json +++ b/application/tsconfig.addonserver.json @@ -2,12 +2,17 @@ "compileOnSave": true, "compilerOptions": { "outDir": "./build-addons", - "target": "ES2015", - "module": "commonjs", + "baseUrl": ".", + "target": "ES2022", + "module": "ESNext", "sourceMap": true, "stripInternal": true, - "lib": ["es2015", "esnext", "dom"], - "moduleResolution": "node", + "lib": ["es2022", "esnext", "dom"], + "moduleResolution": "bundler", + "paths": { + "ogi-addon/config": ["./node_modules/ogi-addon/build/config/Configuration.d.mts"], + "ogi-addon": ["./node_modules/ogi-addon/build/main.d.mts"] + }, "noImplicitAny": true, "strictNullChecks": true, "strictFunctionTypes": true, From 1a1b7d816f956b5cec99c7f8f778fa656c157f2e Mon Sep 17 00:00:00 2001 From: clawbot Date: Tue, 3 Feb 2026 12:23:55 -0800 Subject: [PATCH 09/24] ci: add typecheck comment posting script and GitHub Actions workflow --- .github/workflows/typecheck-comment.yml | 38 +++++++ post-typecheck-comment.sh | 73 ++++++++++++++ scripts/typecheck-with-comment.sh | 129 ++++++++++++++++++++++++ 3 files changed, 240 insertions(+) create mode 100644 .github/workflows/typecheck-comment.yml create mode 100755 post-typecheck-comment.sh create mode 100755 scripts/typecheck-with-comment.sh diff --git a/.github/workflows/typecheck-comment.yml b/.github/workflows/typecheck-comment.yml new file mode 100644 index 00000000..89844349 --- /dev/null +++ b/.github/workflows/typecheck-comment.yml @@ -0,0 +1,38 @@ +name: Typecheck with Comment + +on: + pull_request: + paths: + - '**.ts' + - '**.svelte' + - '**.json' + - '.github/workflows/typecheck-comment.yml' + workflow_dispatch: + +jobs: + typecheck: + runs-on: ubuntu-latest + permissions: + pull-requests: write + contents: read + + steps: + - uses: actions/checkout@v4 + + - uses: oven-sh/setup-bun@v1 + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Run typecheck with GitHub comment + id: typecheck + run: | + bash scripts/typecheck-with-comment.sh \ + --post-comment \ + --pr-number ${{ github.event.pull_request.number }} \ + --token ${{ secrets.GITHUB_TOKEN }} + continue-on-error: true + + - name: Check typecheck status + if: steps.typecheck.outcome == 'failure' + run: echo "⚠️ Typecheck failed but comment was posted" && exit 1 diff --git a/post-typecheck-comment.sh b/post-typecheck-comment.sh new file mode 100755 index 00000000..c8588cac --- /dev/null +++ b/post-typecheck-comment.sh @@ -0,0 +1,73 @@ +#!/bin/bash + +# Post typecheck results to GitHub PR comment +# Usage: ./post-typecheck-comment.sh + +set -e + +OWNER="${1:-Nat3z}" +REPO="${2:-OpenGameInstaller}" +PR_NUMBER="${3}" +GITHUB_TOKEN="${4}" + +if [ -z "$PR_NUMBER" ] || [ -z "$GITHUB_TOKEN" ]; then + echo "Usage: $0 " + exit 1 +fi + +# Run typecheck and capture output +echo "Running typecheck..." +TYPECHECK_OUTPUT=$(bun run typecheck 2>&1 || true) + +# Parse results +SVELTE_ERRORS=$(echo "$TYPECHECK_OUTPUT" | grep "svelte-check found" | grep -oP '\d+(?= errors)' || echo "0") +SVELTE_WARNINGS=$(echo "$TYPECHECK_OUTPUT" | grep "svelte-check found" | grep -oP '\d+(?= warnings)' || echo "0") + +# Check for TypeScript errors +TS_ERRORS=$(echo "$TYPECHECK_OUTPUT" | grep -c "error TS" || echo "0") + +# Extract error details +ERROR_DETAILS=$(echo "$TYPECHECK_OUTPUT" | grep -A1 "error TS" | head -20 || echo "") + +# Determine status +if [ "$SVELTE_ERRORS" -eq 0 ] && [ "$TS_ERRORS" -eq 0 ]; then + STATUS="✅ PASSED" + COLOR="green" +else + STATUS="❌ FAILED" + COLOR="red" +fi + +# Create GitHub comment +COMMENT="## Typecheck Results $STATUS + +### Summary +- **Svelte:** $SVELTE_ERRORS errors, $SVELTE_WARNINGS warnings +- **TypeScript:** $TS_ERRORS errors + +### Details +\`\`\` +$TYPECHECK_OUTPUT +\`\`\` +" + +# If there are errors, add error details +if [ "$TS_ERRORS" -gt 0 ]; then + COMMENT+=" + +### Errors Found +\`\`\` +$ERROR_DETAILS +\`\`\` +" +fi + +# Post to GitHub +echo "Posting comment to GitHub PR #$PR_NUMBER..." +curl -X POST \ + -H "Authorization: token $GITHUB_TOKEN" \ + -H "Content-Type: application/json" \ + -d "{\"body\": $(echo "$COMMENT" | jq -R -s '.')}" \ + "https://api.github.com/repos/$OWNER/$REPO/issues/$PR_NUMBER/comments" + +echo "Comment posted!" diff --git a/scripts/typecheck-with-comment.sh b/scripts/typecheck-with-comment.sh new file mode 100755 index 00000000..90536b97 --- /dev/null +++ b/scripts/typecheck-with-comment.sh @@ -0,0 +1,129 @@ +#!/bin/bash + +# Typecheck runner with GitHub comment posting +# Usage: ./scripts/typecheck-with-comment.sh [--post-comment] [--pr-number 123] [--token xxx] + +set -e + +POST_COMMENT=false +PR_NUMBER="" +GITHUB_TOKEN="" +OWNER="Nat3z" +REPO="OpenGameInstaller" + +# Parse arguments +while [[ $# -gt 0 ]]; do + case $1 in + --post-comment) + POST_COMMENT=true + shift + ;; + --pr-number) + PR_NUMBER="$2" + shift 2 + ;; + --token) + GITHUB_TOKEN="$2" + shift 2 + ;; + *) + shift + ;; + esac +done + +# Run typecheck +echo "▶️ Running typecheck..." +TYPECHECK_OUTPUT=$(bun run typecheck 2>&1 || true) +TYPECHECK_EXIT_CODE=$? + +# Parse results +SVELTE_LINE=$(echo "$TYPECHECK_OUTPUT" | grep "svelte-check found" || echo "") +SVELTE_ERRORS=$(echo "$SVELTE_LINE" | grep -oP '\d+(?= errors)' | head -1 || echo "0") +SVELTE_WARNINGS=$(echo "$SVELTE_LINE" | grep -oP '\d+(?= warnings)' | head -1 || echo "0") + +# Clean up any newlines +SVELTE_ERRORS=$(echo "$SVELTE_ERRORS" | tr -d '\n' | tr -d ' ') +SVELTE_WARNINGS=$(echo "$SVELTE_WARNINGS" | tr -d '\n' | tr -d ' ') + +# Count TypeScript errors +TS_ERROR_COUNT=$(echo "$TYPECHECK_OUTPUT" | grep -c "error TS" || true) +TS_ERRORS=$((TS_ERROR_COUNT)) + +# Extract error lines +ERROR_LINES=$(echo "$TYPECHECK_OUTPUT" | grep "error TS" | head -10 || echo "") + +# Determine status +if [ "${SVELTE_ERRORS:-0}" = "0" ] && [ "$TS_ERRORS" -eq 0 ]; then + STATUS="✅ PASSED" + EMOJI="✅" + EXIT_CODE=0 +else + STATUS="❌ FAILED" + EMOJI="❌" + EXIT_CODE=1 +fi + +# Display results locally +echo "" +echo "================================================" +echo "Typecheck Results: $STATUS" +echo "================================================" +echo "Svelte: ${SVELTE_ERRORS:-0} errors, ${SVELTE_WARNINGS:-0} warnings" +echo "TypeScript: $TS_ERRORS errors" +echo "================================================" +echo "" + +# Post to GitHub if requested and we have credentials +if [ "$POST_COMMENT" = true ] && [ -n "$PR_NUMBER" ] && [ -n "$GITHUB_TOKEN" ]; then + echo "📝 Posting comment to GitHub PR #$PR_NUMBER..." + + # Create the comment body + read -r -d '' COMMENT_BODY << EOF || true +## $EMOJI Typecheck Results: $STATUS + +### Summary +| Check | Status | +|-------|--------| +| Svelte Check | ${SVELTE_ERRORS:-0} errors, ${SVELTE_WARNINGS:-0} warnings | +| TypeScript | $TS_ERRORS errors | + +EOF + + # Add error details if there are any + if [ -n "$ERROR_LINES" ]; then + COMMENT_BODY+="### Errors Found +\`\`\` +$ERROR_LINES +\`\`\` +" + fi + + # Add link to workflow if running in GitHub Actions + if [ -n "$GITHUB_RUN_ID" ]; then + COMMENT_BODY+=" +[View full workflow run](https://github.com/$OWNER/$REPO/actions/runs/$GITHUB_RUN_ID) +" + fi + + # Post to GitHub + PAYLOAD=$(jq -n --arg body "$COMMENT_BODY" '{body: $body}') + + RESPONSE=$(curl -s -X POST \ + -H "Authorization: token $GITHUB_TOKEN" \ + -H "Content-Type: application/json" \ + -d "$PAYLOAD" \ + "https://api.github.com/repos/$OWNER/$REPO/issues/$PR_NUMBER/comments") + + if echo "$RESPONSE" | jq . > /dev/null 2>&1; then + echo "✅ Comment posted successfully!" + else + echo "⚠️ Failed to post comment:" + echo "$RESPONSE" + fi +elif [ "$POST_COMMENT" = true ]; then + echo "⚠️ Cannot post comment: missing PR_NUMBER and/or GITHUB_TOKEN" + echo " Usage: $0 --post-comment --pr-number --token " +fi + +exit $EXIT_CODE From 5e56d03d1fecbf7a6d076408bb5aca5be4291d9d Mon Sep 17 00:00:00 2001 From: clawbot Date: Tue, 3 Feb 2026 12:24:14 -0800 Subject: [PATCH 10/24] docs: add typecheck script documentation --- scripts/TYPECHECK_README.md | 97 +++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 scripts/TYPECHECK_README.md diff --git a/scripts/TYPECHECK_README.md b/scripts/TYPECHECK_README.md new file mode 100644 index 00000000..25ffcb8e --- /dev/null +++ b/scripts/TYPECHECK_README.md @@ -0,0 +1,97 @@ +# Typecheck with GitHub Comments + +This directory contains tools for running typecheck and automatically posting results to GitHub PRs. + +## Scripts + +### `typecheck-with-comment.sh` + +Runs the typecheck suite and optionally posts a comment to a GitHub PR with the results. + +**Usage:** + +```bash +# Just run typecheck locally +bash scripts/typecheck-with-comment.sh + +# Run and post results to a GitHub PR +bash scripts/typecheck-with-comment.sh \ + --post-comment \ + --pr-number 57 \ + --token $GITHUB_TOKEN +``` + +**Output:** +- Displays a formatted table with typecheck results +- Counts Svelte errors/warnings +- Counts TypeScript errors +- Posts to GitHub PR comments if requested +- Returns exit code 0 if all checks pass, 1 if any fail + +### `post-typecheck-comment.sh` + +Standalone script for posting typecheck results to GitHub. Less featured than the above. + +```bash +./post-typecheck-comment.sh +``` + +## GitHub Actions Workflow + +`.github/workflows/typecheck-comment.yml` - Automatically runs on every PR that touches TypeScript/Svelte files. + +**Features:** +- ✅ Runs on PR with relevant file changes +- ✅ Auto-posts comment with results +- ✅ Links to workflow run +- ✅ Extracts error details +- ✅ Works with GitHub secrets + +**Configuration:** + +The workflow uses `secrets.GITHUB_TOKEN` which is automatically provided by GitHub Actions. + +## Example Comment Output + +``` +✅ Typecheck Results: ✅ PASSED + +Summary +Check Status +Svelte Check 0 errors, 371 warnings +TypeScript 0 errors + +[View full workflow run](https://github.com/Nat3z/OpenGameInstaller/actions/runs/12345) +``` + +## Error Example + +``` +❌ Typecheck Results: ❌ FAILED + +Summary +Check Status +Svelte Check 0 errors, 371 warnings +TypeScript 2 errors + +Errors Found +src/electron/main.ts(8,40): error TS2307: Cannot find module 'ogi-addon/config' +src/electron/startup.ts(67,15): error TS1378: Top-level 'await' expressions... + +[View full workflow run](...) +``` + +## Integration with CI/CD + +To use in your CI pipeline: + +```yaml +- name: Typecheck + run: bash scripts/typecheck-with-comment.sh \ + --post-comment \ + --pr-number ${{ github.event.pull_request.number }} \ + --token ${{ secrets.GITHUB_TOKEN }} + continue-on-error: true +``` + +The `continue-on-error: true` allows the job to report even if checks fail. From 5bcdfdef4b4e3451fee7869119ab1229963ef3ca Mon Sep 17 00:00:00 2001 From: Nat3z <66748576+Nat3z@users.noreply.github.com> Date: Tue, 3 Feb 2026 12:52:53 -0800 Subject: [PATCH 11/24] Delete .github/workflows/typecheck.yml --- .github/workflows/typecheck.yml | 33 --------------------------------- 1 file changed, 33 deletions(-) delete mode 100644 .github/workflows/typecheck.yml diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml deleted file mode 100644 index 1f6a9202..00000000 --- a/.github/workflows/typecheck.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Typecheck - -on: - push: - branches: [main] - pull_request: - branches: [main] - -concurrency: - group: typecheck-${{ github.ref }} - cancel-in-progress: true - -jobs: - typecheck: - runs-on: ubuntu-latest - steps: - - name: Check out Git repository - uses: actions/checkout@v4 - - - name: Setup Bun - uses: oven-sh/setup-bun@v2 - with: - bun-version: 1.3.8 - - - name: Install dependencies - run: | - bun install --frozen-lockfile - cp -r ./node_modules/electron ./application/node_modules/electron - mkdir -p ./updater/node_modules - cp -r ./node_modules/electron ./updater/node_modules/electron - - - name: Run project-wide typecheck - run: bun run typecheck From 9d91eebc3f74e8bf1729a21c912b4a0b35a3d2b6 Mon Sep 17 00:00:00 2001 From: Nat3z <66748576+Nat3z@users.noreply.github.com> Date: Tue, 3 Feb 2026 13:11:48 -0800 Subject: [PATCH 12/24] Ci/typecheck comment (#58) * ci: add typecheck and comment automation for PR request-changes review * ci: improve typecheck-comment workflow with better error handling and permissions --------- Co-authored-by: ClawBot --- .github/workflows/typecheck-comment.yml | 98 +++++++++++++++++-------- .github/workflows/typecheck.yml | 54 ++++++++++++++ 2 files changed, 121 insertions(+), 31 deletions(-) create mode 100644 .github/workflows/typecheck.yml diff --git a/.github/workflows/typecheck-comment.yml b/.github/workflows/typecheck-comment.yml index 89844349..cf5736ac 100644 --- a/.github/workflows/typecheck-comment.yml +++ b/.github/workflows/typecheck-comment.yml @@ -1,38 +1,74 @@ -name: Typecheck with Comment +name: Typecheck Comment on: - pull_request: - paths: - - '**.ts' - - '**.svelte' - - '**.json' - - '.github/workflows/typecheck-comment.yml' - workflow_dispatch: + workflow_run: + workflows: ["Typecheck"] + types: [completed] + +permissions: + actions: read + pull-requests: write jobs: - typecheck: + comment: runs-on: ubuntu-latest - permissions: - pull-requests: write - contents: read - + if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'failure' steps: - - uses: actions/checkout@v4 - - - uses: oven-sh/setup-bun@v1 - - - name: Install dependencies - run: bun install --frozen-lockfile - - - name: Run typecheck with GitHub comment - id: typecheck + - name: Download artifact + id: download + uses: actions/github-script@v7 + with: + script: | + let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.payload.workflow_run.id, + }); + let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => { + return artifact.name == "typecheck-results" + })[0]; + if (!matchArtifact) { + console.log("No typecheck-results artifact found"); + core.setOutput('artifact_found', 'false'); + return; + } + core.setOutput('artifact_found', 'true'); + let download = await github.rest.actions.downloadArtifact({ + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: matchArtifact.id, + archive_format: 'zip', + }); + let fs = require('fs'); + fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/typecheck-results.zip`, Buffer.from(download.data)); + + - name: Unzip artifact + if: steps.download.outputs.artifact_found == 'true' + run: unzip -o typecheck-results.zip -d typecheck-results + + - name: Check typecheck results + if: steps.download.outputs.artifact_found == 'true' + id: check run: | - bash scripts/typecheck-with-comment.sh \ - --post-comment \ - --pr-number ${{ github.event.pull_request.number }} \ - --token ${{ secrets.GITHUB_TOKEN }} - continue-on-error: true - - - name: Check typecheck status - if: steps.typecheck.outcome == 'failure' - run: echo "⚠️ Typecheck failed but comment was posted" && exit 1 + if [ -f typecheck-results/errors.txt ]; then + echo "has_errors=true" >> $GITHUB_OUTPUT + cat typecheck-results/errors.txt + else + echo "has_errors=false" >> $GITHUB_OUTPUT + fi + + - name: Post comment on PR + if: steps.download.outputs.artifact_found == 'true' && steps.check.outputs.has_errors == 'true' + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const errors = fs.readFileSync('typecheck-results/errors.txt', 'utf8'); + + github.rest.pulls.createReview({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.payload.workflow_run.pull_requests[0].number, + event: 'REQUEST_CHANGES', + body: `❌ **Typecheck Failed**\n\nPlease fix the following type errors:\n\n\`\`\`\n${errors}\n\`\`\`` + }); diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml new file mode 100644 index 00000000..41e3435b --- /dev/null +++ b/.github/workflows/typecheck.yml @@ -0,0 +1,54 @@ +name: Typecheck + +on: + push: + branches: ["**"] + pull_request: + branches: ["**"] + +jobs: + typecheck: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: "1" + + - name: Cache dependencies + uses: actions/cache@v4 + with: + path: | + ~/.bun/install/cache + node_modules + application/node_modules + packages/*/node_modules + key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lockb', '**/bun.lock') }} + restore-keys: | + ${{ runner.os }}-bun- + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Run typecheck + run: cd application && bun run check 2>&1 | tee typecheck-output.txt + continue-on-error: true + + - name: Extract errors + if: always() + run: | + mkdir -p typecheck-results + if grep -q "error" application/typecheck-output.txt; then + grep "error" application/typecheck-output.txt > typecheck-results/errors.txt || true + fi + + - name: Upload typecheck results + if: always() + uses: actions/upload-artifact@v4 + with: + name: typecheck-results + path: typecheck-results/ + retention-days: 1 From 1e6d8476a26d75f40f1a51db55ca9e83978fb930 Mon Sep 17 00:00:00 2001 From: Nat3z <66748576+Nat3z@users.noreply.github.com> Date: Tue, 3 Feb 2026 13:13:32 -0800 Subject: [PATCH 13/24] Enable concurrency for typecheck workflow Add concurrency settings to typecheck workflow --- .github/workflows/typecheck.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml index 41e3435b..cd94b915 100644 --- a/.github/workflows/typecheck.yml +++ b/.github/workflows/typecheck.yml @@ -6,6 +6,10 @@ on: pull_request: branches: ["**"] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: typecheck: runs-on: ubuntu-latest From 653b1df9f7c93e1500c503e9768c18c3ee733bbd Mon Sep 17 00:00:00 2001 From: Nat3z <66748576+Nat3z@users.noreply.github.com> Date: Tue, 3 Feb 2026 13:24:37 -0800 Subject: [PATCH 14/24] Ci/typecheck comment fix (#59) * ci: add typecheck and comment automation for PR request-changes review * ci: improve typecheck-comment workflow with better error handling and permissions * ci: simplify typecheck workflow - combine comment logic inline and run only on PRs --------- Co-authored-by: ClawBot --- .github/workflows/typecheck.yml | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml index cd94b915..870c3d0a 100644 --- a/.github/workflows/typecheck.yml +++ b/.github/workflows/typecheck.yml @@ -1,8 +1,6 @@ name: Typecheck on: - push: - branches: ["**"] pull_request: branches: ["**"] @@ -13,6 +11,9 @@ concurrency: jobs: typecheck: runs-on: ubuntu-latest + permissions: + pull-requests: write + steps: - name: Checkout uses: actions/checkout@v4 @@ -43,16 +44,27 @@ jobs: - name: Extract errors if: always() + id: errors run: | - mkdir -p typecheck-results if grep -q "error" application/typecheck-output.txt; then - grep "error" application/typecheck-output.txt > typecheck-results/errors.txt || true + echo "has_errors=true" >> $GITHUB_OUTPUT + grep "error" application/typecheck-output.txt > errors.txt || true + else + echo "has_errors=false" >> $GITHUB_OUTPUT fi - - name: Upload typecheck results - if: always() - uses: actions/upload-artifact@v4 + - name: Post review on errors + if: steps.errors.outputs.has_errors == 'true' + uses: actions/github-script@v7 with: - name: typecheck-results - path: typecheck-results/ - retention-days: 1 + script: | + const fs = require('fs'); + const errors = fs.readFileSync('errors.txt', 'utf8'); + + github.rest.pulls.createReview({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number, + event: 'REQUEST_CHANGES', + body: `❌ **Typecheck Failed**\n\nPlease fix the following type errors:\n\n\`\`\`\n${errors}\n\`\`\`` + }); From 1f08fc41ccb759c5ac18de547e501f626a674381 Mon Sep 17 00:00:00 2001 From: Clawd Date: Wed, 4 Feb 2026 06:21:15 -0800 Subject: [PATCH 15/24] fix(ci): address CodeRabbit review - improve typecheck workflow and fix type issues - Fix duplicate key in Debug.svelte (t -> t2) and remove obsolete @ts-expect-error - Improve typecheck.yml: add contents:read permission, restrict to main branch - Fix typecheck-comment.yml condition for non-success runs - Fix real-debrid tsconfig: remove DOM lib, add types:[node] - Clean up unused CSS in CommunityAddonsList.svelte --- .github/workflows/typecheck-comment.yml | 2 +- .github/workflows/typecheck.yml | 28 ++++++++++++++----- .../src/frontend/managers/Debug.svelte | 5 +--- .../frontend/views/CommunityAddonsList.svelte | 8 +----- packages/real-debrid/tsconfig.json | 3 +- 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/.github/workflows/typecheck-comment.yml b/.github/workflows/typecheck-comment.yml index cf5736ac..4d0742df 100644 --- a/.github/workflows/typecheck-comment.yml +++ b/.github/workflows/typecheck-comment.yml @@ -12,7 +12,7 @@ permissions: jobs: comment: runs-on: ubuntu-latest - if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'failure' + if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion != 'success' steps: - name: Download artifact id: download diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml index 870c3d0a..cfea114a 100644 --- a/.github/workflows/typecheck.yml +++ b/.github/workflows/typecheck.yml @@ -1,8 +1,10 @@ name: Typecheck on: + push: + branches: ["main"] pull_request: - branches: ["**"] + branches: ["main"] concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -12,6 +14,7 @@ jobs: typecheck: runs-on: ubuntu-latest permissions: + contents: read pull-requests: write steps: @@ -39,27 +42,38 @@ jobs: run: bun install --frozen-lockfile - name: Run typecheck - run: cd application && bun run check 2>&1 | tee typecheck-output.txt - continue-on-error: true + run: | + set -o pipefail + bun run typecheck 2>&1 | tee typecheck-output.txt - name: Extract errors if: always() id: errors run: | - if grep -q "error" application/typecheck-output.txt; then + if grep -qiE '\berrors?\b' typecheck-output.txt; then echo "has_errors=true" >> $GITHUB_OUTPUT - grep "error" application/typecheck-output.txt > errors.txt || true + grep -iE '\berrors?\b' typecheck-output.txt > errors.txt || true else echo "has_errors=false" >> $GITHUB_OUTPUT fi + - name: Upload typecheck results + if: always() + uses: actions/upload-artifact@v4 + with: + name: typecheck-results + path: errors.txt + - name: Post review on errors - if: steps.errors.outputs.has_errors == 'true' + if: steps.errors.outputs.has_errors == 'true' && github.event_name == 'pull_request' uses: actions/github-script@v7 with: script: | const fs = require('fs'); - const errors = fs.readFileSync('errors.txt', 'utf8'); + let errors = ''; + if (fs.existsSync('errors.txt')) { + errors = fs.readFileSync('errors.txt', 'utf8'); + } github.rest.pulls.createReview({ owner: context.repo.owner, diff --git a/application/src/frontend/managers/Debug.svelte b/application/src/frontend/managers/Debug.svelte index 98b14e36..09215787 100644 --- a/application/src/frontend/managers/Debug.svelte +++ b/application/src/frontend/managers/Debug.svelte @@ -27,7 +27,6 @@ description: string; } = { config: { - // @ts-expect-error - options is a valid property for a string option if a choice. t: { name: 'test-options', displayName: 'Test Options', @@ -35,12 +34,10 @@ defaultValue: '', type: 'string', }, - // @ts-expect-error - options is a valid property for a string option if a choice. - t: { + t2: { name: 'test-option-2', displayName: 'Test Options', description: 'This is a test options modal', - // @ts-expect-error - options is a valid property for a string option if a choice. allowedValues: ['test-option-1', 'test-option-2', 'test-option-3'], type: 'string', }, diff --git a/application/src/frontend/views/CommunityAddonsList.svelte b/application/src/frontend/views/CommunityAddonsList.svelte index b562c165..c9a98f45 100644 --- a/application/src/frontend/views/CommunityAddonsList.svelte +++ b/application/src/frontend/views/CommunityAddonsList.svelte @@ -226,16 +226,10 @@ @apply flex flex-col w-full h-full; } - .loading-container, - .error-container { + .loading-container { @apply flex items-center justify-center w-full h-full; } - .loading-text, - .error-text { - @apply text-lg text-gray-600; - } - .addon-grid { @apply flex flex-col w-full gap-4 py-6 px-0 overflow-y-auto; max-height: calc(100vh - 200px); diff --git a/packages/real-debrid/tsconfig.json b/packages/real-debrid/tsconfig.json index 1890d57f..c62fef6c 100644 --- a/packages/real-debrid/tsconfig.json +++ b/packages/real-debrid/tsconfig.json @@ -1,7 +1,8 @@ { "compilerOptions": { // project options - "lib": ["ESNext", "DOM"], // specifies which default set of type definitions to use ("DOM", "ES6", etc) + "lib": ["ESNext"], // specifies which default set of type definitions to use ("DOM", "ES6", etc) + "types": ["node"], "removeComments": true, // Strips all comments from TypeScript files when converting into JavaScript- you rarely read compiled code so this saves space "target": "ESNext", // Target environment. Most modern browsers support ES6, but you may want to set it to newer or older. (defaults to ES3) "module": "ESNext", From cd5a47f89b5c1581b2f0414fd9aa622718dfb3ce Mon Sep 17 00:00:00 2001 From: Clawd Date: Wed, 4 Feb 2026 06:33:23 -0800 Subject: [PATCH 16/24] ci: combine typecheck and comment workflows - Combine typecheck logic and PR commenting into a single workflow (typecheck.yml) - Set PR branch filter to "**" as a reference to the flex repo configuration - Remove redundant typecheck-comment.yml workflow --- .github/workflows/typecheck-comment.yml | 74 ------------------------- .github/workflows/typecheck.yml | 2 +- 2 files changed, 1 insertion(+), 75 deletions(-) delete mode 100644 .github/workflows/typecheck-comment.yml diff --git a/.github/workflows/typecheck-comment.yml b/.github/workflows/typecheck-comment.yml deleted file mode 100644 index 4d0742df..00000000 --- a/.github/workflows/typecheck-comment.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: Typecheck Comment - -on: - workflow_run: - workflows: ["Typecheck"] - types: [completed] - -permissions: - actions: read - pull-requests: write - -jobs: - comment: - runs-on: ubuntu-latest - if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion != 'success' - steps: - - name: Download artifact - id: download - uses: actions/github-script@v7 - with: - script: | - let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({ - owner: context.repo.owner, - repo: context.repo.repo, - run_id: context.payload.workflow_run.id, - }); - let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => { - return artifact.name == "typecheck-results" - })[0]; - if (!matchArtifact) { - console.log("No typecheck-results artifact found"); - core.setOutput('artifact_found', 'false'); - return; - } - core.setOutput('artifact_found', 'true'); - let download = await github.rest.actions.downloadArtifact({ - owner: context.repo.owner, - repo: context.repo.repo, - artifact_id: matchArtifact.id, - archive_format: 'zip', - }); - let fs = require('fs'); - fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/typecheck-results.zip`, Buffer.from(download.data)); - - - name: Unzip artifact - if: steps.download.outputs.artifact_found == 'true' - run: unzip -o typecheck-results.zip -d typecheck-results - - - name: Check typecheck results - if: steps.download.outputs.artifact_found == 'true' - id: check - run: | - if [ -f typecheck-results/errors.txt ]; then - echo "has_errors=true" >> $GITHUB_OUTPUT - cat typecheck-results/errors.txt - else - echo "has_errors=false" >> $GITHUB_OUTPUT - fi - - - name: Post comment on PR - if: steps.download.outputs.artifact_found == 'true' && steps.check.outputs.has_errors == 'true' - uses: actions/github-script@v7 - with: - script: | - const fs = require('fs'); - const errors = fs.readFileSync('typecheck-results/errors.txt', 'utf8'); - - github.rest.pulls.createReview({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: context.payload.workflow_run.pull_requests[0].number, - event: 'REQUEST_CHANGES', - body: `❌ **Typecheck Failed**\n\nPlease fix the following type errors:\n\n\`\`\`\n${errors}\n\`\`\`` - }); diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml index cfea114a..68450582 100644 --- a/.github/workflows/typecheck.yml +++ b/.github/workflows/typecheck.yml @@ -4,7 +4,7 @@ on: push: branches: ["main"] pull_request: - branches: ["main"] + branches: ["**"] concurrency: group: ${{ github.workflow }}-${{ github.ref }} From ae8e62297cce42a23c8997408083a43bb7aa073b Mon Sep 17 00:00:00 2001 From: nat-openclaw Date: Wed, 4 Feb 2026 06:42:17 -0800 Subject: [PATCH 17/24] ci: fix typecheck reporting logic and match flex pattern --- .github/workflows/typecheck.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml index 68450582..7f06000d 100644 --- a/.github/workflows/typecheck.yml +++ b/.github/workflows/typecheck.yml @@ -42,17 +42,17 @@ jobs: run: bun install --frozen-lockfile - name: Run typecheck - run: | - set -o pipefail - bun run typecheck 2>&1 | tee typecheck-output.txt + id: typecheck + run: bun run typecheck 2>&1 | tee typecheck-output.txt + continue-on-error: true - name: Extract errors if: always() id: errors run: | - if grep -qiE '\berrors?\b' typecheck-output.txt; then + if [ -f typecheck-output.txt ] && grep -qiE 'error' typecheck-output.txt; then echo "has_errors=true" >> $GITHUB_OUTPUT - grep -iE '\berrors?\b' typecheck-output.txt > errors.txt || true + grep -iE 'error' typecheck-output.txt > errors.txt || true else echo "has_errors=false" >> $GITHUB_OUTPUT fi From 784f6a62171b493c1ef34f35cecef4270d9cd6bb Mon Sep 17 00:00:00 2001 From: nat-openclaw Date: Wed, 4 Feb 2026 06:42:32 -0800 Subject: [PATCH 18/24] ci: verify gpg signing with new key --- .github/workflows/typecheck.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml index 7f06000d..57f64ed2 100644 --- a/.github/workflows/typecheck.yml +++ b/.github/workflows/typecheck.yml @@ -1,3 +1,4 @@ +# Unified typecheck workflow matching Flex pattern name: Typecheck on: From 653dbff2b0ed8598d4ceea177ab3acc93b40b3c1 Mon Sep 17 00:00:00 2001 From: nat-openclaw Date: Wed, 4 Feb 2026 06:48:27 -0800 Subject: [PATCH 19/24] ci: strip ansi codes from typecheck results --- .github/workflows/typecheck.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml index 57f64ed2..dce2efb5 100644 --- a/.github/workflows/typecheck.yml +++ b/.github/workflows/typecheck.yml @@ -53,7 +53,8 @@ jobs: run: | if [ -f typecheck-output.txt ] && grep -qiE 'error' typecheck-output.txt; then echo "has_errors=true" >> $GITHUB_OUTPUT - grep -iE 'error' typecheck-output.txt > errors.txt || true + # Strip ANSI escape codes + sed -r "s/\x1B\[([0-9]{1,3}(;[0-9]{1,2})?)?[mGK]//g" typecheck-output.txt | grep -iE 'error' > errors.txt || true else echo "has_errors=false" >> $GITHUB_OUTPUT fi From 17290c4b89d14fc5602ef3da71e5a4c20dd2a57b Mon Sep 17 00:00:00 2001 From: Nat3z <66748576+Nat3z@users.noreply.github.com> Date: Wed, 4 Feb 2026 08:36:55 -0800 Subject: [PATCH 20/24] Delete TYPECHECK_README.md --- scripts/TYPECHECK_README.md | 97 ------------------------------------- 1 file changed, 97 deletions(-) delete mode 100644 scripts/TYPECHECK_README.md diff --git a/scripts/TYPECHECK_README.md b/scripts/TYPECHECK_README.md deleted file mode 100644 index 25ffcb8e..00000000 --- a/scripts/TYPECHECK_README.md +++ /dev/null @@ -1,97 +0,0 @@ -# Typecheck with GitHub Comments - -This directory contains tools for running typecheck and automatically posting results to GitHub PRs. - -## Scripts - -### `typecheck-with-comment.sh` - -Runs the typecheck suite and optionally posts a comment to a GitHub PR with the results. - -**Usage:** - -```bash -# Just run typecheck locally -bash scripts/typecheck-with-comment.sh - -# Run and post results to a GitHub PR -bash scripts/typecheck-with-comment.sh \ - --post-comment \ - --pr-number 57 \ - --token $GITHUB_TOKEN -``` - -**Output:** -- Displays a formatted table with typecheck results -- Counts Svelte errors/warnings -- Counts TypeScript errors -- Posts to GitHub PR comments if requested -- Returns exit code 0 if all checks pass, 1 if any fail - -### `post-typecheck-comment.sh` - -Standalone script for posting typecheck results to GitHub. Less featured than the above. - -```bash -./post-typecheck-comment.sh -``` - -## GitHub Actions Workflow - -`.github/workflows/typecheck-comment.yml` - Automatically runs on every PR that touches TypeScript/Svelte files. - -**Features:** -- ✅ Runs on PR with relevant file changes -- ✅ Auto-posts comment with results -- ✅ Links to workflow run -- ✅ Extracts error details -- ✅ Works with GitHub secrets - -**Configuration:** - -The workflow uses `secrets.GITHUB_TOKEN` which is automatically provided by GitHub Actions. - -## Example Comment Output - -``` -✅ Typecheck Results: ✅ PASSED - -Summary -Check Status -Svelte Check 0 errors, 371 warnings -TypeScript 0 errors - -[View full workflow run](https://github.com/Nat3z/OpenGameInstaller/actions/runs/12345) -``` - -## Error Example - -``` -❌ Typecheck Results: ❌ FAILED - -Summary -Check Status -Svelte Check 0 errors, 371 warnings -TypeScript 2 errors - -Errors Found -src/electron/main.ts(8,40): error TS2307: Cannot find module 'ogi-addon/config' -src/electron/startup.ts(67,15): error TS1378: Top-level 'await' expressions... - -[View full workflow run](...) -``` - -## Integration with CI/CD - -To use in your CI pipeline: - -```yaml -- name: Typecheck - run: bash scripts/typecheck-with-comment.sh \ - --post-comment \ - --pr-number ${{ github.event.pull_request.number }} \ - --token ${{ secrets.GITHUB_TOKEN }} - continue-on-error: true -``` - -The `continue-on-error: true` allows the job to report even if checks fail. From 163be7374df065f24bb68d71c6ec4bb9eb82db7e Mon Sep 17 00:00:00 2001 From: Nat3z <66748576+Nat3z@users.noreply.github.com> Date: Wed, 4 Feb 2026 08:38:13 -0800 Subject: [PATCH 21/24] Delete post-typecheck-comment.sh --- post-typecheck-comment.sh | 73 --------------------------------------- 1 file changed, 73 deletions(-) delete mode 100755 post-typecheck-comment.sh diff --git a/post-typecheck-comment.sh b/post-typecheck-comment.sh deleted file mode 100755 index c8588cac..00000000 --- a/post-typecheck-comment.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/bin/bash - -# Post typecheck results to GitHub PR comment -# Usage: ./post-typecheck-comment.sh - -set -e - -OWNER="${1:-Nat3z}" -REPO="${2:-OpenGameInstaller}" -PR_NUMBER="${3}" -GITHUB_TOKEN="${4}" - -if [ -z "$PR_NUMBER" ] || [ -z "$GITHUB_TOKEN" ]; then - echo "Usage: $0 " - exit 1 -fi - -# Run typecheck and capture output -echo "Running typecheck..." -TYPECHECK_OUTPUT=$(bun run typecheck 2>&1 || true) - -# Parse results -SVELTE_ERRORS=$(echo "$TYPECHECK_OUTPUT" | grep "svelte-check found" | grep -oP '\d+(?= errors)' || echo "0") -SVELTE_WARNINGS=$(echo "$TYPECHECK_OUTPUT" | grep "svelte-check found" | grep -oP '\d+(?= warnings)' || echo "0") - -# Check for TypeScript errors -TS_ERRORS=$(echo "$TYPECHECK_OUTPUT" | grep -c "error TS" || echo "0") - -# Extract error details -ERROR_DETAILS=$(echo "$TYPECHECK_OUTPUT" | grep -A1 "error TS" | head -20 || echo "") - -# Determine status -if [ "$SVELTE_ERRORS" -eq 0 ] && [ "$TS_ERRORS" -eq 0 ]; then - STATUS="✅ PASSED" - COLOR="green" -else - STATUS="❌ FAILED" - COLOR="red" -fi - -# Create GitHub comment -COMMENT="## Typecheck Results $STATUS - -### Summary -- **Svelte:** $SVELTE_ERRORS errors, $SVELTE_WARNINGS warnings -- **TypeScript:** $TS_ERRORS errors - -### Details -\`\`\` -$TYPECHECK_OUTPUT -\`\`\` -" - -# If there are errors, add error details -if [ "$TS_ERRORS" -gt 0 ]; then - COMMENT+=" - -### Errors Found -\`\`\` -$ERROR_DETAILS -\`\`\` -" -fi - -# Post to GitHub -echo "Posting comment to GitHub PR #$PR_NUMBER..." -curl -X POST \ - -H "Authorization: token $GITHUB_TOKEN" \ - -H "Content-Type: application/json" \ - -d "{\"body\": $(echo "$COMMENT" | jq -R -s '.')}" \ - "https://api.github.com/repos/$OWNER/$REPO/issues/$PR_NUMBER/comments" - -echo "Comment posted!" From 4fc07f10824de0591ff321fe8154acc27d338a76 Mon Sep 17 00:00:00 2001 From: nat-openclaw Date: Wed, 4 Feb 2026 09:19:30 -0800 Subject: [PATCH 22/24] chore: improve typecheck workflow (main-only, pipefail, error regex, review truncation) --- .github/workflows/typecheck.yml | 32 ++++++++++---- .../src/electron/server/AddonConnection.ts | 10 +++-- .../src/electron/server/addon-server.ts | 6 +-- application/src/electron/server/api/addons.ts | 26 ++++++++---- .../src/frontend/managers/Debug.svelte | 42 +++++++++++-------- scripts/typecheck-with-comment.sh | 25 ++++++----- 6 files changed, 88 insertions(+), 53 deletions(-) diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml index dce2efb5..4f7eae9f 100644 --- a/.github/workflows/typecheck.yml +++ b/.github/workflows/typecheck.yml @@ -5,7 +5,7 @@ on: push: branches: ["main"] pull_request: - branches: ["**"] + branches: ["main"] concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -44,17 +44,18 @@ jobs: - name: Run typecheck id: typecheck - run: bun run typecheck 2>&1 | tee typecheck-output.txt - continue-on-error: true + run: | + set -o pipefail + bun run typecheck 2>&1 | tee typecheck-output.txt - name: Extract errors if: always() id: errors run: | - if [ -f typecheck-output.txt ] && grep -qiE 'error' typecheck-output.txt; then + if [ -f typecheck-output.txt ] && grep -qE 'error TS|Error:' typecheck-output.txt; then echo "has_errors=true" >> $GITHUB_OUTPUT - # Strip ANSI escape codes - sed -r "s/\x1B\[([0-9]{1,3}(;[0-9]{1,2})?)?[mGK]//g" typecheck-output.txt | grep -iE 'error' > errors.txt || true + # Strip ANSI escape codes; capture lines with real errors (not e.g. "0 errors") + sed -r "s/\x1B\[([0-9]{1,3}(;[0-9]{1,2})?)?[mGK]//g" typecheck-output.txt | grep -E 'error TS|Error:' > errors.txt || true else echo "has_errors=false" >> $GITHUB_OUTPUT fi @@ -65,6 +66,7 @@ jobs: with: name: typecheck-results path: errors.txt + if-no-files-found: ignore - name: Post review on errors if: steps.errors.outputs.has_errors == 'true' && github.event_name == 'pull_request' @@ -72,15 +74,27 @@ jobs: with: script: | const fs = require('fs'); + const MAX_BODY = 60000; let errors = ''; if (fs.existsSync('errors.txt')) { errors = fs.readFileSync('errors.txt', 'utf8'); } - - github.rest.pulls.createReview({ + if (errors.length > MAX_BODY) { + errors = errors.slice(0, MAX_BODY) + '\n...truncated'; + } + const pullNumber = context.eventName === 'workflow_run' + ? (context.payload.workflow_run?.pull_requests?.length > 0 + ? context.payload.workflow_run.pull_requests[0].number + : null) + : context.issue.number; + if (pullNumber == null) { + console.log('Skipping review: no PR number available'); + return; + } + await github.rest.pulls.createReview({ owner: context.repo.owner, repo: context.repo.repo, - pull_number: context.issue.number, + pull_number: pullNumber, event: 'REQUEST_CHANGES', body: `❌ **Typecheck Failed**\n\nPlease fix the following type errors:\n\n\`\`\`\n${errors}\n\`\`\`` }); diff --git a/application/src/electron/server/AddonConnection.ts b/application/src/electron/server/AddonConnection.ts index 582d2999..ebd8f837 100644 --- a/application/src/electron/server/AddonConnection.ts +++ b/application/src/electron/server/AddonConnection.ts @@ -49,7 +49,8 @@ export class AddonConnection { clearTimeout(authenticationTimeout); // authentication - this.addonInfo = data.args as OGIAddonConfiguration; + const addonInfo = data.args as OGIAddonConfiguration; + this.addonInfo = addonInfo; if ( isSecurityCheckEnabled && (!data.args.secret || data.args.secret !== addonSecret) @@ -65,7 +66,7 @@ export class AddonConnection { break; } - // if (this.addonInfo.version !== ogiAddonVERSION) { + // if (addonInfo.version !== ogiAddonVERSION) { // sendNotification({ // type: 'error', // message: 'Client attempted to authenticate with an addon version that is not compatible with the OGI Addon Server', @@ -76,7 +77,7 @@ export class AddonConnection { // resolve(false) // break; // } - if (clients.has(this.addonInfo!.id)) { + if (clients.has(addonInfo.id)) { console.error( 'Client attempted to authenticate with an ID that is already in use' ); @@ -88,7 +89,8 @@ export class AddonConnection { break; } console.log('Client authenticated:', data.args.name); - sendIPCMessage('addon-connected', this.addonInfo!.id); + clients.set(addonInfo.id, this); + sendIPCMessage('addon-connected', addonInfo.id); resolve(true); break; } diff --git a/application/src/electron/server/addon-server.ts b/application/src/electron/server/addon-server.ts index 66fb26bd..37d2d15b 100644 --- a/application/src/electron/server/addon-server.ts +++ b/application/src/electron/server/addon-server.ts @@ -7,7 +7,6 @@ import addonProcedures from './api/addons.js'; import deferProcedures from './api/defer.js'; import { AddonConnection } from './AddonConnection.js'; import { AddonServer } from './serve.js'; -import { sendIPCMessage } from '../main.js'; const app = express(); const server = http.createServer(app); const wss = new WebSocketServer({ server }); @@ -26,10 +25,7 @@ wss.on('connection', async (ws) => { } }); - if (connection.addonInfo) { - clients.set(connection.addonInfo.id, connection); - await sendIPCMessage('addon-connected', connection.addonInfo.id); - } + // Client is registered in AddonConnection.authenticate (clients.set + sendIPCMessage) }); app.all('*', (_, res, next) => { diff --git a/application/src/electron/server/api/addons.ts b/application/src/electron/server/api/addons.ts index 890c714b..b6297d5b 100644 --- a/application/src/electron/server/api/addons.ts +++ b/application/src/electron/server/api/addons.ts @@ -1,6 +1,9 @@ import { z } from 'zod'; import { clients } from '../addon-server.js'; import { DeferrableTask } from '../DeferrableTask.js'; + +// Invariant: clients only contains connections with addonInfo set (added in AddonConnection.authenticate). +// We still guard below for robustness in case the map is accessed before auth or after disconnect. import sanitize from 'sanitize-html'; import { type Procedure, @@ -44,6 +47,7 @@ const procedures: Record> = { .handler(async (input) => { const client = clients.get(input.addonID); if (!client) return new ProcedureError(404, 'Client not found'); + if (!client.addonInfo) return new ProcedureError(400, 'Client has no addon info'); const response = await client.sendEventMessage({ event: 'config-update', @@ -74,6 +78,7 @@ const procedures: Record> = { .handler(async (input) => { const client = clients.get(input.addonID); if (!client) return new ProcedureError(404, 'Client not found'); + if (!client.addonInfo) return new ProcedureError(400, 'Client has no addon info'); if (!client.eventsAvailable.includes('search')) { return new ProcedureError(400, 'Client does not support search'); } @@ -90,7 +95,7 @@ const procedures: Record> = { }); console.log('searchComplete', event.args); return event.args; - }, client.addonInfo!.id); + }, client.addonInfo.id); return new ProcedureDeferTask(200, deferrableTask); }), @@ -106,6 +111,7 @@ const procedures: Record> = { .handler(async (input) => { const client = clients.get(input.addonID); if (!client) return new ProcedureError(404, 'Client not found'); + if (!client.addonInfo) return new ProcedureError(400, 'Client has no addon info'); if (!client.eventsAvailable.includes('library-search')) { return new ProcedureError( @@ -120,7 +126,7 @@ const procedures: Record> = { args: input.query, }); return event.args; - }, client.addonInfo!.id); + }, client.addonInfo.id); return new ProcedureDeferTask(200, deferrableTask); }), @@ -137,6 +143,7 @@ const procedures: Record> = { .handler(async (input) => { const client = clients.get(input.addonID); if (!client) return new ProcedureError(404, 'Client not found'); + if (!client.addonInfo) return new ProcedureError(400, 'Client has no addon info'); if (!client.eventsAvailable.includes('request-dl')) { return new ProcedureError(400, 'Client does not support request-dl'); @@ -148,7 +155,7 @@ const procedures: Record> = { args: { appID: input.appID, info: input.info }, }); return data.args; - }, client.addonInfo!.id); + }, client.addonInfo.id); return new ProcedureDeferTask(200, deferrableTask); }), @@ -163,6 +170,7 @@ const procedures: Record> = { .handler(async (input) => { const client = clients.get(input.addonID); if (!client) return new ProcedureError(404, 'Client not found'); + if (!client.addonInfo) return new ProcedureError(400, 'Client has no addon info'); if (!client.eventsAvailable.includes('catalog')) { return new ProcedureError(400, 'Client does not support catalog'); @@ -174,7 +182,7 @@ const procedures: Record> = { args: {}, }); return data.args; - }, client.addonInfo!.id); + }, client.addonInfo.id); return new ProcedureDeferTask(200, deferrableTask); }), @@ -210,6 +218,7 @@ const procedures: Record> = { console.error('Client not found'); return new ProcedureError(404, 'Client not found'); } + if (!client.addonInfo) return new ProcedureError(400, 'Client has no addon info'); if (!client.eventsAvailable.includes('setup')) { console.error('Client does not support setup'); @@ -234,7 +243,7 @@ const procedures: Record> = { }, }); return data.args; - }, client.addonInfo!.id); + }, client.addonInfo.id); return new ProcedureDeferTask(200, deferrableTask); }), @@ -311,6 +320,7 @@ const procedures: Record> = { .handler(async (input) => { const client = clients.get(input.addonID); if (!client) return new ProcedureError(404, 'Client not found'); + if (!client.addonInfo) return new ProcedureError(400, 'Client has no addon info'); if (!client.addonLink || client.addonLink.startsWith('local:')) { return new ProcedureError( 400, @@ -381,6 +391,7 @@ const procedures: Record> = { .handler(async (input) => { const client = clients.get(input.addonID); if (!client) return new ProcedureError(404, 'Client not found'); + if (!client.addonInfo) return new ProcedureError(400, 'Client has no addon info'); const deferrableTask = new DeferrableTask(async () => { const data = await client.sendEventMessage({ @@ -395,7 +406,7 @@ const procedures: Record> = { }, }); return data.args; - }, client.addonInfo!.id); + }, client.addonInfo.id); return new ProcedureDeferTask(200, deferrableTask); }), @@ -428,6 +439,7 @@ const procedures: Record> = { } const client = clientsWithStorefront[0]; + if (!client.addonInfo) return new ProcedureError(400, 'Client has no addon info'); const deferrableTask = new DeferrableTask(async () => { const data = await client.sendEventMessage({ event: 'check-for-updates', @@ -438,7 +450,7 @@ const procedures: Record> = { }, }); return data.args; - }, client.addonInfo!.id); + }, client.addonInfo.id); return new ProcedureDeferTask(200, deferrableTask); }), }; diff --git a/application/src/frontend/managers/Debug.svelte b/application/src/frontend/managers/Debug.svelte index 09215787..378cf242 100644 --- a/application/src/frontend/managers/Debug.svelte +++ b/application/src/frontend/managers/Debug.svelte @@ -8,7 +8,10 @@ import ButtonModal from '../components/modal/ButtonModal.svelte'; import { createNotification, notificationHistory } from '../store'; import CheckboxModal from '../components/modal/CheckboxModal.svelte'; - import type { ConfigurationFile } from 'ogi-addon/config'; + import { + ConfigurationBuilder, + type ConfigurationFile, + } from 'ogi-addon/config'; import HeaderModal from '../components/modal/HeaderModal.svelte'; let showDebugModal = $state(false); @@ -20,28 +23,33 @@ let showEventsPerSec = $state(false); let showNotificationSideView = $state(false); let showInsertAppModal = $state(false); + // Build test config with real StringOption instances (matches production shape) const optionConfig: { config: ConfigurationFile; id: string; name: string; description: string; } = { - config: { - t: { - name: 'test-options', - displayName: 'Test Options', - description: 'This is a test options modal', - defaultValue: '', - type: 'string', - }, - t2: { - name: 'test-option-2', - displayName: 'Test Options', - description: 'This is a test options modal', - allowedValues: ['test-option-1', 'test-option-2', 'test-option-3'], - type: 'string', - }, - }, + config: new ConfigurationBuilder() + .addStringOption((option) => + option + .setName('test-options') + .setDisplayName('Test Options') + .setDescription('This is a test options modal') + .setDefaultValue('') + ) + .addStringOption((option) => + option + .setName('test-option-2') + .setDisplayName('Test Options') + .setDescription('This is a test options modal') + .setAllowedValues([ + 'test-option-1', + 'test-option-2', + 'test-option-3', + ]) + ) + .build(false), id: 'test-options', name: 'Test Options', description: 'This is a test options modal', diff --git a/scripts/typecheck-with-comment.sh b/scripts/typecheck-with-comment.sh index 90536b97..7bfc2cbc 100755 --- a/scripts/typecheck-with-comment.sh +++ b/scripts/typecheck-with-comment.sh @@ -32,9 +32,9 @@ while [[ $# -gt 0 ]]; do esac done -# Run typecheck +# Run typecheck (do not mask failures) echo "▶️ Running typecheck..." -TYPECHECK_OUTPUT=$(bun run typecheck 2>&1 || true) +TYPECHECK_OUTPUT=$(bun run typecheck 2>&1) TYPECHECK_EXIT_CODE=$? # Parse results @@ -48,13 +48,13 @@ SVELTE_WARNINGS=$(echo "$SVELTE_WARNINGS" | tr -d '\n' | tr -d ' ') # Count TypeScript errors TS_ERROR_COUNT=$(echo "$TYPECHECK_OUTPUT" | grep -c "error TS" || true) -TS_ERRORS=$((TS_ERROR_COUNT)) +TS_ERRORS=$((TS_ERROR_COUNT + 0)) # Extract error lines ERROR_LINES=$(echo "$TYPECHECK_OUTPUT" | grep "error TS" | head -10 || echo "") -# Determine status -if [ "${SVELTE_ERRORS:-0}" = "0" ] && [ "$TS_ERRORS" -eq 0 ]; then +# Determine status (use real typecheck exit code) +if [ "$TYPECHECK_EXIT_CODE" -eq 0 ] && [ "${SVELTE_ERRORS:-0}" = "0" ] && [ "$TS_ERRORS" -eq 0 ]; then STATUS="✅ PASSED" EMOJI="✅" EXIT_CODE=0 @@ -106,20 +106,23 @@ $ERROR_LINES " fi - # Post to GitHub + # Post to GitHub (capture HTTP status and body) PAYLOAD=$(jq -n --arg body "$COMMENT_BODY" '{body: $body}') - - RESPONSE=$(curl -s -X POST \ + RESPONSE_FILE=$(mktemp) + HTTP_CODE=$(curl -s -w "%{http_code}" -o "$RESPONSE_FILE" -X POST \ -H "Authorization: token $GITHUB_TOKEN" \ -H "Content-Type: application/json" \ -d "$PAYLOAD" \ "https://api.github.com/repos/$OWNER/$REPO/issues/$PR_NUMBER/comments") - - if echo "$RESPONSE" | jq . > /dev/null 2>&1; then + RESPONSE=$(cat "$RESPONSE_FILE") + rm -f "$RESPONSE_FILE" + + if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then echo "✅ Comment posted successfully!" else - echo "⚠️ Failed to post comment:" + echo "⚠️ Failed to post comment (HTTP $HTTP_CODE):" echo "$RESPONSE" + exit 1 fi elif [ "$POST_COMMENT" = true ]; then echo "⚠️ Cannot post comment: missing PR_NUMBER and/or GITHUB_TOKEN" From bf31d0458ede81b2e09cb9a135eb0c970e4ce1ea Mon Sep 17 00:00:00 2001 From: nat-openclaw Date: Wed, 4 Feb 2026 09:35:05 -0800 Subject: [PATCH 23/24] Update typecheck.yml --- .github/workflows/typecheck.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml index 4f7eae9f..0e330045 100644 --- a/.github/workflows/typecheck.yml +++ b/.github/workflows/typecheck.yml @@ -5,7 +5,7 @@ on: push: branches: ["main"] pull_request: - branches: ["main"] + branches: ["**"] concurrency: group: ${{ github.workflow }}-${{ github.ref }} From e2d2bc03b62c46d2d00c33ad5950811c300d5641 Mon Sep 17 00:00:00 2001 From: Nat3z <66748576+Nat3z@users.noreply.github.com> Date: Wed, 4 Feb 2026 10:44:37 -0800 Subject: [PATCH 24/24] Delete scripts/typecheck-with-comment.sh --- scripts/typecheck-with-comment.sh | 132 ------------------------------ 1 file changed, 132 deletions(-) delete mode 100755 scripts/typecheck-with-comment.sh diff --git a/scripts/typecheck-with-comment.sh b/scripts/typecheck-with-comment.sh deleted file mode 100755 index 7bfc2cbc..00000000 --- a/scripts/typecheck-with-comment.sh +++ /dev/null @@ -1,132 +0,0 @@ -#!/bin/bash - -# Typecheck runner with GitHub comment posting -# Usage: ./scripts/typecheck-with-comment.sh [--post-comment] [--pr-number 123] [--token xxx] - -set -e - -POST_COMMENT=false -PR_NUMBER="" -GITHUB_TOKEN="" -OWNER="Nat3z" -REPO="OpenGameInstaller" - -# Parse arguments -while [[ $# -gt 0 ]]; do - case $1 in - --post-comment) - POST_COMMENT=true - shift - ;; - --pr-number) - PR_NUMBER="$2" - shift 2 - ;; - --token) - GITHUB_TOKEN="$2" - shift 2 - ;; - *) - shift - ;; - esac -done - -# Run typecheck (do not mask failures) -echo "▶️ Running typecheck..." -TYPECHECK_OUTPUT=$(bun run typecheck 2>&1) -TYPECHECK_EXIT_CODE=$? - -# Parse results -SVELTE_LINE=$(echo "$TYPECHECK_OUTPUT" | grep "svelte-check found" || echo "") -SVELTE_ERRORS=$(echo "$SVELTE_LINE" | grep -oP '\d+(?= errors)' | head -1 || echo "0") -SVELTE_WARNINGS=$(echo "$SVELTE_LINE" | grep -oP '\d+(?= warnings)' | head -1 || echo "0") - -# Clean up any newlines -SVELTE_ERRORS=$(echo "$SVELTE_ERRORS" | tr -d '\n' | tr -d ' ') -SVELTE_WARNINGS=$(echo "$SVELTE_WARNINGS" | tr -d '\n' | tr -d ' ') - -# Count TypeScript errors -TS_ERROR_COUNT=$(echo "$TYPECHECK_OUTPUT" | grep -c "error TS" || true) -TS_ERRORS=$((TS_ERROR_COUNT + 0)) - -# Extract error lines -ERROR_LINES=$(echo "$TYPECHECK_OUTPUT" | grep "error TS" | head -10 || echo "") - -# Determine status (use real typecheck exit code) -if [ "$TYPECHECK_EXIT_CODE" -eq 0 ] && [ "${SVELTE_ERRORS:-0}" = "0" ] && [ "$TS_ERRORS" -eq 0 ]; then - STATUS="✅ PASSED" - EMOJI="✅" - EXIT_CODE=0 -else - STATUS="❌ FAILED" - EMOJI="❌" - EXIT_CODE=1 -fi - -# Display results locally -echo "" -echo "================================================" -echo "Typecheck Results: $STATUS" -echo "================================================" -echo "Svelte: ${SVELTE_ERRORS:-0} errors, ${SVELTE_WARNINGS:-0} warnings" -echo "TypeScript: $TS_ERRORS errors" -echo "================================================" -echo "" - -# Post to GitHub if requested and we have credentials -if [ "$POST_COMMENT" = true ] && [ -n "$PR_NUMBER" ] && [ -n "$GITHUB_TOKEN" ]; then - echo "📝 Posting comment to GitHub PR #$PR_NUMBER..." - - # Create the comment body - read -r -d '' COMMENT_BODY << EOF || true -## $EMOJI Typecheck Results: $STATUS - -### Summary -| Check | Status | -|-------|--------| -| Svelte Check | ${SVELTE_ERRORS:-0} errors, ${SVELTE_WARNINGS:-0} warnings | -| TypeScript | $TS_ERRORS errors | - -EOF - - # Add error details if there are any - if [ -n "$ERROR_LINES" ]; then - COMMENT_BODY+="### Errors Found -\`\`\` -$ERROR_LINES -\`\`\` -" - fi - - # Add link to workflow if running in GitHub Actions - if [ -n "$GITHUB_RUN_ID" ]; then - COMMENT_BODY+=" -[View full workflow run](https://github.com/$OWNER/$REPO/actions/runs/$GITHUB_RUN_ID) -" - fi - - # Post to GitHub (capture HTTP status and body) - PAYLOAD=$(jq -n --arg body "$COMMENT_BODY" '{body: $body}') - RESPONSE_FILE=$(mktemp) - HTTP_CODE=$(curl -s -w "%{http_code}" -o "$RESPONSE_FILE" -X POST \ - -H "Authorization: token $GITHUB_TOKEN" \ - -H "Content-Type: application/json" \ - -d "$PAYLOAD" \ - "https://api.github.com/repos/$OWNER/$REPO/issues/$PR_NUMBER/comments") - RESPONSE=$(cat "$RESPONSE_FILE") - rm -f "$RESPONSE_FILE" - - if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then - echo "✅ Comment posted successfully!" - else - echo "⚠️ Failed to post comment (HTTP $HTTP_CODE):" - echo "$RESPONSE" - exit 1 - fi -elif [ "$POST_COMMENT" = true ]; then - echo "⚠️ Cannot post comment: missing PR_NUMBER and/or GITHUB_TOKEN" - echo " Usage: $0 --post-comment --pr-number --token " -fi - -exit $EXIT_CODE