Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ ELECTROBUN_ENABLE_CODESIGN=false
ELECTROBUN_ENABLE_NOTARIZE=false

# Optional: enable sanitized hook debug logs locally
LOOPNDROLL_ENABLE_HOOK_DEBUG_LOGS=true
LOOPNDROLL_ENABLE_HOOK_DEBUG_LOGS=false
260 changes: 178 additions & 82 deletions README.md

Large diffs are not rendered by default.

14 changes: 10 additions & 4 deletions electrobun.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import { readFileSync } from "node:fs";
const releaseBaseUrl = process.env["RELEASE_BASE_URL"] || "";
const enableCodesign = process.env["ELECTROBUN_ENABLE_CODESIGN"] === "true";
const enableNotarize = process.env["ELECTROBUN_ENABLE_NOTARIZE"] === "true";
const packageVersion = JSON.parse(readFileSync(new URL("./package.json", import.meta.url), "utf8")).version;
const packageVersion = JSON.parse(
readFileSync(new URL("./package.json", import.meta.url), "utf8"),
).version;

export default {
app: {
Expand All @@ -23,21 +25,25 @@ export default {
copy: {
"dist/index.html": "views/app/index.html",
"dist/assets": "views/app/assets",
"dist/fonts": "views/app/fonts",
},
watchIgnore: ["dist/**"],
mac: {
codesign: enableCodesign,
notarize: enableNotarize,
bundleCEF: false,
icons: "build/icon.iconset",
icons: undefined,
},
linux: {
bundleCEF: false,
icon: "build/icon.png",
icon: "src/assets/app-icon.png",
},
win: {
bundleCEF: false,
icon: "build/icon.png",
icon: "src/assets/app-icon.png",
},
},
scripts: {
postBuild: "scripts/copy-macos-app-icon.ts",
},
} satisfies ElectrobunConfig;
11 changes: 9 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@
"private": true,
"type": "module",
"packageManager": "pnpm@10.33.0",
"pnpm": {
"overrides": {
"basic-ftp": "5.3.0",
"hono": "4.12.14",
"@hono/node-server": "1.19.13"
}
},
"description": "Keep Codex running forever",
"scripts": {
"dev": "concurrently -k -n vite,app \"pnpm run hmr\" \"pnpm run dev:app\"",
Expand All @@ -14,13 +21,13 @@
"build:dev": "vite build && electrobun build",
"build:stable": "vite build && electrobun build --env=stable",
"release:macos": "bash scripts/release-macos.sh",
"build": "pnpm run build:dev",
"build": "vite build && electrobun build",
"lint": "oxlint src electrobun.config.ts vite.config.ts --deny-warnings",
"lint:fix": "oxlint src electrobun.config.ts vite.config.ts --fix",
"format": "oxfmt src electrobun.config.ts vite.config.ts",
"format:check": "oxfmt --check src electrobun.config.ts vite.config.ts",
"typecheck": "tsgo --noEmit -p tsconfig.json",
"check": "pnpm run lint && pnpm run format:check && pnpm run typecheck"
"check": "oxlint src electrobun.config.ts vite.config.ts --deny-warnings && oxfmt --check src electrobun.config.ts vite.config.ts && tsgo --noEmit -p tsconfig.json"
},
"dependencies": {
"@base-ui/react": "^1.3.0",
Expand Down
33 changes: 19 additions & 14 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions scripts/copy-macos-app-icon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { copyFileSync, existsSync, mkdirSync } from "node:fs";
import { dirname, join } from "node:path";

const wrapperBundlePath = process.env["ELECTROBUN_WRAPPER_BUNDLE_PATH"];
const buildDir = process.env["ELECTROBUN_BUILD_DIR"];
const appName = process.env["ELECTROBUN_APP_NAME"];
const appBundleName = appName?.endsWith(".app") ? appName : `${appName}.app`;
const bundlePath =
wrapperBundlePath ?? (buildDir && appName ? join(buildDir, appBundleName) : undefined);

if (!bundlePath) {
throw new Error(
"ELECTROBUN_WRAPPER_BUNDLE_PATH or ELECTROBUN_BUILD_DIR/ELECTROBUN_APP_NAME is required",
);
}

const sourcePath = join(process.cwd(), "src/assets/AppIcon.icns");
const destinationPath = join(bundlePath, "Contents/Resources/AppIcon.icns");

if (!existsSync(sourcePath)) {
throw new Error(`Missing app icon asset: ${sourcePath}`);
}

mkdirSync(dirname(destinationPath), { recursive: true });
copyFileSync(sourcePath, destinationPath);
console.log(`Copied macOS app icon to ${destinationPath}`);
63 changes: 63 additions & 0 deletions scripts/extract-installed-app-icon.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import AppKit
import Foundation

let fileManager = FileManager.default
let projectRoot = URL(fileURLWithPath: fileManager.currentDirectoryPath)
let defaultSource = "/Applications/Loopndroll.app/Contents/Resources/AppIcon.icns"
let sourcePath = CommandLine.arguments.dropFirst().first ?? defaultSource
let sourceURL = URL(fileURLWithPath: sourcePath)
let assetsURL = projectRoot.appendingPathComponent("src/assets", isDirectory: true)
let icnsURL = assetsURL.appendingPathComponent("AppIcon.icns")
let pngURL = assetsURL.appendingPathComponent("app-icon.png")

guard let sourceImage = NSImage(contentsOf: sourceURL) else {
FileHandle.standardError.write(
"Could not read installed app icon at \(sourcePath)\n".data(using: .utf8)!,
)
exit(1)
}

try fileManager.createDirectory(at: assetsURL, withIntermediateDirectories: true)
if fileManager.fileExists(atPath: icnsURL.path) {
try fileManager.removeItem(at: icnsURL)
}
try fileManager.copyItem(at: sourceURL, to: icnsURL)

func pngData(from image: NSImage, pixels: Int) -> Data {
guard
let bitmap = NSBitmapImageRep(
bitmapDataPlanes: nil,
pixelsWide: pixels,
pixelsHigh: pixels,
bitsPerSample: 8,
samplesPerPixel: 4,
hasAlpha: true,
isPlanar: false,
colorSpaceName: .deviceRGB,
bytesPerRow: 0,
bitsPerPixel: 0,
)
else {
fatalError("Could not create bitmap for \(pixels)x\(pixels)")
}

bitmap.size = NSSize(width: pixels, height: pixels)
NSGraphicsContext.saveGraphicsState()
NSGraphicsContext.current = NSGraphicsContext(bitmapImageRep: bitmap)
image.draw(
in: NSRect(x: 0, y: 0, width: pixels, height: pixels),
from: .zero,
operation: .copy,
fraction: 1.0,
)
NSGraphicsContext.restoreGraphicsState()

guard let data = bitmap.representation(using: .png, properties: [:]) else {
fatalError("Could not encode PNG for \(pixels)x\(pixels)")
}
return data
}

try pngData(from: sourceImage, pixels: 1024).write(to: pngURL)

print("Extracted installed app icon from \(sourcePath)")
97 changes: 97 additions & 0 deletions scripts/sacrificial_static_check_probe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { buildSacrificialStaticCheckPlan } from "../src/bun/sacrificial-static-check";

type SacrificialStaticCheckProbeArgs = {
mode: string;
cwd: string | null;
sandboxRoot: string | null;
};

function parseArgs(argv: string[]): SacrificialStaticCheckProbeArgs {
let mode = "readiness";
let cwd: string | null = null;
let sandboxRoot: string | null = null;

for (let index = 0; index < argv.length; index += 1) {
const token = argv[index];

if (token === "--mode") {
mode = argv[index + 1] ?? mode;
index += 1;
continue;
}

if (token === "--cwd") {
cwd = argv[index + 1] ?? null;
index += 1;
continue;
}

if (token === "--sandbox-root") {
sandboxRoot = argv[index + 1] ?? null;
index += 1;
}
}

return { mode, cwd, sandboxRoot };
}

function printProbeOutput(payload: Record<string, unknown>) {
console.log(JSON.stringify(payload, null, 2));
}

function getSandboxWorkspaceRoot(sandboxRoot: string) {
return `${sandboxRoot.replace(/\/+$/, "")}/workspace`;
}

function isWithinSandboxWorkspace(cwd: string, sandboxRoot: string) {
const workspaceRoot = getSandboxWorkspaceRoot(sandboxRoot);
return cwd === workspaceRoot || cwd.startsWith(`${workspaceRoot}/`);
}

async function main() {
const args = parseArgs(process.argv.slice(2));

try {
const plan = buildSacrificialStaticCheckPlan({
cwd: args.cwd ?? "",
sandboxRoot: args.sandboxRoot ?? "",
});

if (args.mode === "run-check" && !isWithinSandboxWorkspace(plan.cwd, plan.sandboxRoot)) {
printProbeOutput({
status: "blocked",
mode: "run-check",
cwd: plan.cwd,
sandboxRoot: plan.sandboxRoot,
lane: plan.lane,
command: plan.command,
reason: "repo-outside-sandbox-workspace",
detail:
"The repo cwd is outside the sacrificial sandbox workspace, and this lane forbids install/materialization into the sandbox.",
allowHostGlobalPnpmFallback: plan.allowHostGlobalPnpmFallback,
allowInstallOrMaterialization: plan.allowInstallOrMaterialization,
});
return;
}

printProbeOutput({
status: "ready",
mode: args.mode,
cwd: plan.cwd,
sandboxRoot: plan.sandboxRoot,
lane: plan.lane,
command: plan.command,
allowHostGlobalPnpmFallback: plan.allowHostGlobalPnpmFallback,
allowInstallOrMaterialization: plan.allowInstallOrMaterialization,
});
} catch (error) {
printProbeOutput({
status: "blocked",
cwd: args.cwd,
sandboxRoot: args.sandboxRoot,
error: error instanceof Error ? error.message : String(error),
});
}
}

await main();
Loading