Skip to content
Merged
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
23 changes: 23 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
name: Bug report
about: Report something broken
labels: bug
---

## Description

<!-- What happened? What did you expect to happen? -->

## Steps to reproduce

1.
2.
3.

## Environment

<!-- OS/app version/browser/device — whatever is relevant. -->

## Evidence

<!-- Screenshots or a short video if applicable. Upload directly to GitHub. -->
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
blank_issues_enabled: false
17 changes: 17 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
name: Feature request
about: Suggest an idea or improvement
labels: enhancement
---

## Problem

<!-- What are you trying to do that's hard or impossible today? -->

## Proposed solution

<!-- What should happen? Keep scope small. -->

## Alternatives considered

<!-- Other approaches, and why they're worse for now. -->
26 changes: 26 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
## What Changed

<!-- Describe the change clearly and keep scope tight. One concern per PR — if this says "also", split it. -->

## Why

<!-- Explain the problem being solved and why this approach is right. -->

## Evidence

<!-- UI changes: clear before/after screenshots. Motion/timing: short video.
Upload directly to GitHub — do not commit PR-only assets. Delete if not applicable. -->

## Touched Areas

<!-- Bullet list of files/directories/areas affected. -->

## Testing

<!-- How this was verified; tick before merge. -->

- [ ] Build passes
- [ ] Tests/lint pass (or CI covers it)
- [ ] Verified the change works as described

Built with {model} in the {agent} harness.
49 changes: 49 additions & 0 deletions .github/workflows/pr-size.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Auto-labels pull requests with a size label based on changed lines.
# Labels: size:S (<10), size:M (<100), size:L (<500), size:XL (<1000), size:XXL (>=1000)
name: PR Size

on:
pull_request_target:
types: [opened, reopened, synchronize, ready_for_review]

permissions:
pull-requests: write

jobs:
label:
name: Add size label
runs-on: ubuntu-latest
steps:
- name: Compute diff and label
uses: actions/github-script@v8
with:
script: |
const pr = context.payload.pull_request;

const files = await github.paginate(github.rest.pulls.listFiles, {
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr.number,
per_page: 100,
});

const changed = files.reduce(
(sum, f) => sum + f.additions + f.deletions,
0,
);

const sizes = [
{ max: 10, label: "size:S" },
{ max: 100, label: "size:M" },
{ max: 500, label: "size:L" },
{ max: 1000, label: "size:XL" },
{ max: Infinity, label: "size:XXL" },
];
const label = sizes.find((s) => changed < s.max).label;

await github.rest.issues.setLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
labels: [label],
});
136 changes: 136 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
# AGENTS.md

Guidance for AI coding agents (OpenCode, Claude Code, etc.) working in this repository.

## Project Overview

WebShell is an Android WebView wrapper kit: a minimal Kotlin app that hosts a plain HTML/CSS/JS
web app in a full-screen WebView with a JavaScript-to-native bridge.

- Language/stack: Kotlin + AndroidX AppCompat/Core-KTX; web layer is plain HTML/CSS/JS in `assets/www/`
- Package/module: `com.yourapp` (intentional placeholder — forks stamp their own id here)
- Toolchain: minSdk 26, compile/target SDK 35, JVM 11, AGP 8.7.3 / Kotlin 2.0.21 via `gradle/libs.versions.toml`
- Author/maintainer: yungsamd17 (https://github.com/yungsamd17)

## Build & Verify

```bash
./gradlew assembleDebug # build debug APK (the only CI gate)
./gradlew lintDebug # Android lint (available via AGP, not run by CI)
```

- There is no unit or instrumented test suite yet — verification is `assembleDebug` plus manual
testing of the bridge methods on a device/emulator.
- CI (`.github/workflows/ci.yml`) runs on every push to `main`, PRs, and manual dispatch:
validates the Gradle wrapper, sets up JDK 17 (temurin) + the Android SDK, runs
`./gradlew assembleDebug --stacktrace`, and uploads `app-debug.apk` as the `app-debug-apk` artifact.
- Local sandboxes often lack the Android SDK/JDK — if builds can't run locally, rely on careful
code review and let CI verify.

## Architecture

```
app/src/main/
kotlin/com/yourapp/
MainActivity.kt # single Activity hosting a full-screen, edge-to-edge WebView
NativeBridge.kt # @JavascriptInterface methods callable from JS as window.Native.*
assets/www/
index.html # sample entry page
bridge.js # JS wrapper around the native bridge
app.js / style.css # sample web app code
res/ # themes.xml, strings.xml, adaptive launcher icons
AndroidManifest.xml # permissions + activity config (see gotchas)
docs/ # getting-started, bridge-api, java-reference, project-structure, gotchas-and-tips
gradle/libs.versions.toml # version catalog (AGP/Kotlin/androidx versions)
```

Key patterns:

- Bridge contract is two-sided: every new `@JavascriptInterface` method in `NativeBridge.kt`
must get a matching wrapper in `assets/www/bridge.js`. Document it in `docs/bridge-api.md`.
- `@JavascriptInterface` methods run on a background thread — any UI work must be wrapped in
`activity.runOnUiThread { ... }`; pushing data back to JS goes through
`activity.webView.post { webView.evaluateJavascript(...) }`.
- The web app lives entirely in `app/src/main/assets/www/` and loads via
`file:///android_asset/www/index.html`; no server, no build step for the web side.
- Version bumps happen in `app/build.gradle.kts` (`versionCode`/`versionName`) plus a
Keep-a-Changelog style entry in `CHANGELOG.md`.

## Commit Messages

Format: `type(scope): short imperative summary` — lowercase after type, no trailing period.
Keep commits atomic — one logical change per commit.

| Type | Use for |
|---|---|
| `feat` | new user-facing feature |
| `fix` | bug fix |
| `refactor` | code change that neither fixes nor adds behavior |
| `style` | formatting/UI polish without logic change |
| `test` | adding or fixing tests |
| `docs` | documentation only |
| `chore` | build, deps, CI, tooling |
| `release` | version bump / release tagging |

Scope is a short area name for this project (e.g. `app`, `bridge`, `www`, `docs`, `ci`).
Use plain `type:` only when a change genuinely spans everything (rare).

Examples:

```
feat(bridge): add clipboard read method
fix(app): keep keyboard from covering input fields
chore(ci): cache gradle wrapper in workflow
docs(readme): document commit message types
```

## Agent Guardrails

- Never commit or push directly to `main`; all changes land through pull requests.
- Never open a PR unless the developer explicitly asks for it.
- One concern per change. If the description says "also", split it into another branch/PR.
- Do not commit secrets, keystores, local-only files (`local.properties`, `.gradle/`,
`build/`) or APK/AAB outputs (`*.apk`, `*.aab` are gitignored).
- When watching CI/bot feedback on your PRs: poll checks and comments newer than the last push,
verify each bot finding against the source before "fixing" it, dismiss false positives with a
written reason, and stop when checks are green on the latest commit.

## Pull Requests

All changes land on `main` through pull requests.

1. Create a branch off `main`: `<type>/<short-description>` (e.g. `feat/clipboard-bridge-method`).
2. Commit there using the format from **Commit Messages**; keep commits atomic.
3. Push the branch and open a PR against `main`.

PR rules:

- One feature/fix per PR — small and focused beats large and thorough.
- Title follows the commit message format: `type(scope): short imperative summary` —
it becomes the squash-merge commit message.
- Body stays concise, following the PR template: what changed and why, bullet list of touched
areas, evidence if applicable, testing checklist (tick before merge).
- End the body with an AI attribution line stating exactly which model and agent made the changes,
in this exact format:

```
Built with {model} in the {agent} harness.
```

Example: `Built with ox-alpha in the OpenCode harness.`

- Do **not** put AI attribution in GitHub Release notes — releases stay clean.
- CI must pass before merging.

## Gotchas

- `android:hardwareAccelerated="true"` must stay set — WebView rendering breaks without it.
- `allowFileAccess = false` in `MainActivity.kt` is intentional hardening; asset loading uses
`file:///android_asset` which is unaffected. Do not flip it back on.
- `configChanges` on the Activity prevents recreation on rotation/keyboard so the web app never
reloads; removing it changes core behavior. `windowSoftInputMode="adjustResize"` keeps inputs
visible above the keyboard.
- Edge-to-edge is enabled (`WindowCompat.setDecorFitsSystemWindows(window, false)`) — content
should pad with `env(safe-area-inset-*)` in CSS.
- `com.yourapp` namespace/applicationId is a deliberate template placeholder; don't "fix" it.
- Keep the Gradle wrapper executable (`gradlew`); CI validates it on every build.
Loading