mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
build: share root config with pi-private
Everything outside apps/ is the same in pi and pi-private; apps/ exists only in pi-private, and these files now tolerate its absence: - workspaces include apps/* - biome.json leaves apps/ to its own config - the pre-commit hook runs the apps/mobile check only when it exists - the Android APK workflow runs only in earendil-works/pi-private - scripts/biome-check.mjs runs native Biome, or Biome WASM on Android (@biomejs/wasm-nodejs 2.3.5), for npm run check From pi-private bac58de97, c2a8629da, 106714ebc.
This commit is contained in:
parent
0f4b1465a4
commit
97195ec3c4
6 changed files with 251 additions and 2 deletions
96
.github/workflows/android-apk.yml
vendored
Normal file
96
.github/workflows/android-apk.yml
vendored
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
name: Android APK
|
||||
|
||||
# Builds the standalone Pi Mobile APK (apps/mobile/platforms/android). The bundled runtime keeps the monorepo layout
|
||||
# and runs the workspace packages from source, so it needs their generated model data and the pi-env daemons too.
|
||||
# apps/ exists only in pi-private; the jobs do nothing elsewhere.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [private]
|
||||
paths:
|
||||
- 'apps/mobile/**'
|
||||
- 'packages/ai/**'
|
||||
- 'packages/chord/**'
|
||||
- 'packages/durable/**'
|
||||
- 'packages/env/**'
|
||||
- 'packages/telemetry/**'
|
||||
- 'packages/coding-agent/src/experimental/source-resolver.ts'
|
||||
- 'package.json'
|
||||
- 'package-lock.json'
|
||||
- 'tsconfig.json'
|
||||
- 'tsconfig.base.json'
|
||||
- '.github/workflows/android-apk.yml'
|
||||
- '.github/workflows/env-daemons.yml'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
# The daemon for the phone runs terminals; the others serve remote environments.
|
||||
env-daemons:
|
||||
if: github.repository == 'earendil-works/pi-private'
|
||||
uses: ./.github/workflows/env-daemons.yml
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
apk:
|
||||
needs: env-daemons
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 40
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: '26.4.0'
|
||||
cache: npm
|
||||
- name: Install host check dependencies without lifecycle scripts
|
||||
run: npm ci --ignore-scripts
|
||||
- name: Generate the model data of pi-ai
|
||||
run: npm run hydrate:model-data
|
||||
- name: Check the app (host dependencies)
|
||||
working-directory: apps/mobile
|
||||
run: npm run check
|
||||
- name: Fetch the pi-env daemons
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: pi-env-*
|
||||
path: packages/env/bin
|
||||
- name: Check the pi-env daemons
|
||||
run: |
|
||||
test -s packages/env/bin/pi-env-android-arm64/pi-env
|
||||
chmod +x packages/env/bin/*/pi-env*
|
||||
ls -lR packages/env/bin
|
||||
- uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: '21'
|
||||
- uses: android-actions/setup-android@v3
|
||||
with:
|
||||
packages: platform-tools
|
||||
- uses: gradle/actions/setup-gradle@v4
|
||||
- name: Install SDK 35
|
||||
run: sdkmanager 'platforms;android-35' 'build-tools;35.0.0'
|
||||
- name: Test Android archive validation
|
||||
working-directory: apps/mobile
|
||||
run: node --test test/android-installer.test.ts
|
||||
- name: Package Termux ARM64 tools and TLS certificates
|
||||
run: python3 apps/mobile/platforms/android/scripts/package-rootfs.py
|
||||
- name: Stage Android runtime separately and verify native bindings
|
||||
run: python3 apps/mobile/platforms/android/scripts/package-runtime.py
|
||||
- name: Preserve the debug signing key for installable updates
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.android/debug.keystore
|
||||
key: pi-mobile-debug-signing-v1
|
||||
- name: Assemble debug APK
|
||||
working-directory: apps/mobile/platforms/android
|
||||
run: bash ./gradlew --no-daemon assembleDebug
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pi-mobile-debug-arm64
|
||||
path: |
|
||||
apps/mobile/platforms/android/app/build/outputs/apk/debug/*.apk
|
||||
apps/mobile/platforms/android/app/src/main/assets/termux-packages.json
|
||||
apps/mobile/platforms/android/app/src/main/assets/runtime-version
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
|
|
@ -16,6 +16,24 @@ if [ $? -ne 0 ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
# Pi Mobile has its own check (own biome.json, TypeScript 5.9; apps/ is outside the root Biome and tsc configs).
|
||||
# apps/ exists only in pi-private.
|
||||
if [ -d apps/mobile ]; then
|
||||
for file in $STAGED_FILES; do
|
||||
case "$file" in
|
||||
apps/mobile/*|packages/*|package.json|package-lock.json|tsconfig.json|tsconfig.base.json)
|
||||
echo "Checking apps/mobile..."
|
||||
npm --prefix apps/mobile run check
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "❌ apps/mobile checks failed."
|
||||
exit 1
|
||||
fi
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
RUN_BROWSER_SMOKE=0
|
||||
for file in $STAGED_FILES; do
|
||||
case "$file" in
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@
|
|||
"!**/models.generated.ts",
|
||||
"!**/*.models.ts",
|
||||
"!packages/mom/data/**/*",
|
||||
"!!**/node_modules"
|
||||
"!!**/node_modules",
|
||||
"!!apps"
|
||||
]
|
||||
},
|
||||
"plugins": ["./scripts/biome/model-type-comparison.grit"]
|
||||
|
|
|
|||
9
package-lock.json
generated
9
package-lock.json
generated
|
|
@ -9,6 +9,7 @@
|
|||
"version": "0.0.3",
|
||||
"workspaces": [
|
||||
"packages/*",
|
||||
"apps/*",
|
||||
"packages/coding-agent/examples/extensions/with-deps",
|
||||
"packages/coding-agent/examples/extensions/custom-provider-anthropic",
|
||||
"packages/coding-agent/examples/extensions/custom-provider-gitlab-duo",
|
||||
|
|
@ -18,6 +19,7 @@
|
|||
"devDependencies": {
|
||||
"@anthropic-ai/sandbox-runtime": "0.0.26",
|
||||
"@biomejs/biome": "2.3.5",
|
||||
"@biomejs/wasm-nodejs": "2.3.5",
|
||||
"@types/node": "22.19.19",
|
||||
"esbuild": "0.28.2",
|
||||
"husky": "9.1.7",
|
||||
|
|
@ -584,6 +586,13 @@
|
|||
"node": ">=14.21.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/wasm-nodejs": {
|
||||
"version": "2.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/wasm-nodejs/-/wasm-nodejs-2.3.5.tgz",
|
||||
"integrity": "sha512-oEryO1M/vq0iUPxgDMPIJIqGmcLcwn/en9DYLBAaBMSzm1pu0ArnJ3nWpBUjoh977oelyZHKILzNiu0dCNCi0g==",
|
||||
"dev": true,
|
||||
"license": "MIT OR Apache-2.0"
|
||||
},
|
||||
"node_modules/@cto.af/wtf8": {
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@cto.af/wtf8/-/wtf8-0.0.5.tgz",
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
"type": "module",
|
||||
"workspaces": [
|
||||
"packages/*",
|
||||
"apps/*",
|
||||
"packages/coding-agent/examples/extensions/with-deps",
|
||||
"packages/coding-agent/examples/extensions/custom-provider-anthropic",
|
||||
"packages/coding-agent/examples/extensions/custom-provider-gitlab-duo",
|
||||
|
|
@ -17,7 +18,7 @@
|
|||
"build:native:darwin": "npm --prefix packages/tui run build:native:darwin",
|
||||
"build:native:linux": "npm --prefix packages/tui run build:native:linux",
|
||||
"build:native:win32": "npm --prefix packages/tui run build:native:win32",
|
||||
"check": "biome check --write --error-on-warnings . && npm run check:pinned-deps && npm run check:runtime-deps && npm run check:ts-imports && npm run check:entry-graphs && npm run check:install-lock:coding-agent && tsc --noEmit && npm run check:browser-smoke",
|
||||
"check": "node scripts/biome-check.mjs --write && npm run check:pinned-deps && npm run check:runtime-deps && npm run check:ts-imports && npm run check:entry-graphs && npm run check:install-lock:coding-agent && tsc --noEmit && npm run check:browser-smoke",
|
||||
"check:browser-smoke": "node scripts/check-browser-smoke.mjs",
|
||||
"check:pinned-deps": "node scripts/check-pinned-deps.mjs",
|
||||
"check:runtime-deps": "node scripts/check-runtime-deps.mjs",
|
||||
|
|
@ -57,6 +58,7 @@
|
|||
"devDependencies": {
|
||||
"@anthropic-ai/sandbox-runtime": "0.0.26",
|
||||
"@biomejs/biome": "2.3.5",
|
||||
"@biomejs/wasm-nodejs": "2.3.5",
|
||||
"@types/node": "22.19.19",
|
||||
"esbuild": "0.28.2",
|
||||
"husky": "9.1.7",
|
||||
|
|
|
|||
123
scripts/biome-check.mjs
Normal file
123
scripts/biome-check.mjs
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
// Runs `biome check --error-on-warnings` for the biome.json in the current directory.
|
||||
// Native Biome has no Android (Termux) binary. There, fall back to Biome's
|
||||
// Node WASM bindings, which check one file at a time.
|
||||
// Usage: node scripts/biome-check.mjs [--write]
|
||||
import { execFileSync, spawnSync } from "node:child_process";
|
||||
import { readFileSync, writeFileSync } from "node:fs";
|
||||
import { createRequire } from "node:module";
|
||||
import { matchesGlob, posix } from "node:path";
|
||||
import { MemoryFileSystem, main, Workspace } from "@biomejs/wasm-nodejs";
|
||||
|
||||
const write = process.argv.includes("--write");
|
||||
|
||||
// Same platform table as @biomejs/biome/bin/biome.
|
||||
const hasNativeBinary = ["win32", "darwin", "linux"].includes(process.platform) && ["x64", "arm64"].includes(process.arch);
|
||||
|
||||
if (hasNativeBinary) {
|
||||
const biomeBin = createRequire(import.meta.url).resolve("@biomejs/biome/bin/biome");
|
||||
const args = ["check", "--error-on-warnings", ...(write ? ["--write"] : []), "."];
|
||||
const result = spawnSync(process.execPath, [biomeBin, ...args], { stdio: "inherit" });
|
||||
if (result.error) throw result.error;
|
||||
process.exit(result.status ?? 1);
|
||||
}
|
||||
|
||||
// The WASM API has no CLI file scanner. Git supplies tracked and untracked
|
||||
// files while respecting .gitignore; biome.json supplies the include patterns.
|
||||
// A negated pattern also excludes everything below a matching directory.
|
||||
const configuration = JSON.parse(readFileSync("biome.json", "utf8"));
|
||||
const patterns = configuration.files?.includes ?? ["**"];
|
||||
const files = execFileSync("git", ["ls-files", "--cached", "--others", "--exclude-standard", "-z"], {
|
||||
encoding: "utf8",
|
||||
})
|
||||
.split("\0")
|
||||
.filter(Boolean)
|
||||
.filter((path) => {
|
||||
let included = false;
|
||||
for (const pattern of patterns) {
|
||||
if (pattern.startsWith("!")) {
|
||||
const glob = pattern.replace(/^!+/, "");
|
||||
if (matchesGlob(path, glob) || matchesGlob(path, `${glob}/**`)) included = false;
|
||||
} else if (matchesGlob(path, pattern)) {
|
||||
included = true;
|
||||
}
|
||||
}
|
||||
return included;
|
||||
});
|
||||
|
||||
// The WASM workspace cannot read the disk. GritQL plugins referenced by
|
||||
// biome.json must be preloaded into its in-memory file system, keyed by the
|
||||
// configured path relative to the project ("./a.grit" becomes "a.grit").
|
||||
main();
|
||||
const fileSystem = new MemoryFileSystem();
|
||||
for (const plugin of configuration.plugins ?? []) {
|
||||
fileSystem.insert(posix.normalize(plugin), readFileSync(plugin));
|
||||
}
|
||||
const workspace = Workspace.withFileSystem(fileSystem);
|
||||
const { projectKey } = workspace.openProject({ path: process.cwd(), openUninitialized: true });
|
||||
workspace.updateSettings({ projectKey, configuration, workspaceDirectory: "./" });
|
||||
|
||||
function withFile(path, content, run) {
|
||||
workspace.openFile({ projectKey, path, content: { type: "fromClient", content, version: 0 } });
|
||||
try {
|
||||
return run();
|
||||
} finally {
|
||||
workspace.closeFile({ projectKey, path });
|
||||
}
|
||||
}
|
||||
|
||||
let failures = 0;
|
||||
let checked = 0;
|
||||
try {
|
||||
for (const path of files) {
|
||||
const original = readFileSync(path, "utf8");
|
||||
const fixed = write
|
||||
? withFile(
|
||||
path,
|
||||
original,
|
||||
() =>
|
||||
workspace.fixFile({
|
||||
projectKey,
|
||||
path,
|
||||
fixFileMode: "safeFixes",
|
||||
shouldFormat: false,
|
||||
ruleCategories: ["syntax", "lint", "action"],
|
||||
}).code,
|
||||
)
|
||||
: original;
|
||||
const { diagnostics, formatted } = withFile(path, fixed, () => {
|
||||
const { diagnostics } = workspace.pullDiagnostics({
|
||||
projectKey,
|
||||
path,
|
||||
categories: ["syntax", "lint", "action"],
|
||||
pullCodeActions: false,
|
||||
});
|
||||
// Like the CLI with formatWithErrors: false, skip formatting files with syntax errors.
|
||||
const syntax = workspace.pullDiagnostics({ projectKey, path, categories: ["syntax"], pullCodeActions: false });
|
||||
const formatted = syntax.errors === 0 ? workspace.formatFile({ projectKey, path }).code : fixed;
|
||||
return { diagnostics, formatted };
|
||||
});
|
||||
if (write && formatted !== original) writeFileSync(path, formatted);
|
||||
for (const diagnostic of diagnostics) {
|
||||
if (diagnostic.severity === "hint") continue;
|
||||
// Biome's WASM build reports its version as 0.0.0. Keep the real
|
||||
// schema URL for editors, but ignore only this spurious mismatch.
|
||||
if (
|
||||
path === "biome.json" &&
|
||||
diagnostic.category === "deserialize" &&
|
||||
diagnostic.description === "The configuration schema version does not match the CLI version 0.0.0"
|
||||
)
|
||||
continue;
|
||||
console.error(`${path}: ${diagnostic.severity} ${diagnostic.category ?? ""}: ${diagnostic.description}`);
|
||||
failures++;
|
||||
}
|
||||
if (!write && formatted !== original) {
|
||||
console.error(`${path}: formatting differs (run with --write)`);
|
||||
failures++;
|
||||
}
|
||||
checked++;
|
||||
}
|
||||
} finally {
|
||||
workspace.free();
|
||||
}
|
||||
console.log(`Biome WASM: checked ${checked} files; ${failures} diagnostics.`);
|
||||
if (failures > 0) process.exitCode = 1;
|
||||
Loading…
Add table
Add a link
Reference in a new issue