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
4 changes: 2 additions & 2 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ jobs:
- language: go
build-mode: autobuild
- language: javascript-typescript
build-mode: autobuild
build-mode: none
- language: rust
build-mode: autobuild
build-mode: none
# No Swift project in repo — remove entry. Re-add when Swift files need analysis.
# - language: swift
# build-mode: autobuild
Expand Down
17 changes: 15 additions & 2 deletions .github/workflows/osv-scanner.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@ on:
branches: ["develop"]

permissions:
security-events: write
contents: read

jobs:
scan-scheduled:
if: ${{ github.event_name == 'push' || github.event_name == 'schedule' }}
runs-on: ubuntu-latest
permissions:
actions: read
security-events: write
contents: read
steps:
- name: Checkout
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
Expand All @@ -31,10 +34,20 @@ jobs:
-r
--skip-git
./
--output=osv-scanner-results.sarif

- name: Upload SARIF
uses: github/codeql-action/upload-sarif@adfda868f108ac4222129de456ea554034a27db7 # v4
with:
sarif_file: osv-scanner-results.sarif

scan-pr:
if: ${{ github.event_name == 'pull_request' || github.event_name == 'merge_group' }}
uses: "google/osv-scanner-action/.github/workflows/osv-scanner-reusable-pr.yml@v2.3.8"
permissions:
actions: read
contents: read
security-events: write
uses: "google/osv-scanner-action/.github/workflows/osv-scanner-reusable-pr.yml@9a498708959aeaef5ef730655706c5a1df1edbc2" # v2.3.8
Comment thread
coderabbitai[bot] marked this conversation as resolved.
with:
scan-args: |-
-r
Expand Down
63 changes: 47 additions & 16 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ cargo clippy --all-targets --all-features -- -D warnings
## Pre-commit Hooks (ACTUAL BEHAVIOR)

<!-- fallow:setup-hooks:start -->

## Fallow local gate

Before any `git commit` or `git push`, run `fallow audit --format json --quiet --explain --gate-marker agent`. If the verdict is `fail`, fix the reported findings before retrying. Treat JSON runtime errors like `{ "error": true, ... }` as non-blocking.
Expand All @@ -109,20 +110,21 @@ For non-skill agents, treat the task map below as the local onboarding source: r

## Fallow task map

| When the agent is about to... | Run |
|---|---|
| delete an "unused" export or file | `fallow dead-code --trace <file>:<export>` |
| delete an "unused" dependency | `fallow dead-code --trace-dependency <name>` |
| commit or open a PR | `fallow audit --base <ref>` |
| prioritize refactoring | `fallow health --hotspots --targets` |
| ask who owns code | `fallow health --ownership` |
| check untested-but-reachable code | `fallow health --coverage-gaps` |
| consolidate duplication | `fallow dupes --trace dup:<fingerprint>` |
| find feature flags | `fallow flags` |
| check which architecture rules apply to a file before changing it | `fallow guard <files>` |
| surface security candidates | `fallow security` |
| understand a finding | `fallow explain <issue-type>` |
| scope a monorepo | `--workspace <glob> / --changed-workspaces <ref>` (global flags, prefix any command) |
| When the agent is about to... | Run |
| ----------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| delete an "unused" export or file | `fallow dead-code --trace <file>:<export>` |
| delete an "unused" dependency | `fallow dead-code --trace-dependency <name>` |
| commit or open a PR | `fallow audit --base <ref>` |
| prioritize refactoring | `fallow health --hotspots --targets` |
| ask who owns code | `fallow health --ownership` |
| check untested-but-reachable code | `fallow health --coverage-gaps` |
| consolidate duplication | `fallow dupes --trace dup:<fingerprint>` |
| find feature flags | `fallow flags` |
| check which architecture rules apply to a file before changing it | `fallow guard <files>` |
| surface security candidates | `fallow security` |
| understand a finding | `fallow explain <issue-type>` |
| scope a monorepo | `--workspace <glob> / --changed-workspaces <ref>` (global flags, prefix any command) |

<!-- fallow:setup-hooks:end -->

- `.husky/pre-commit` (root, ACTIVE): runs `pnpm --filter drop lint-staged && pnpm --filter drop typecheck`
Expand Down Expand Up @@ -169,16 +171,43 @@ Coverage 1.17% lines / 2.09% funcs (server, no gates). See `docs/coverage-baseli

Bugs caught during this sequence: `prioritylist.ts:34` (`a.priority == a.priority`); `database/Cargo.toml` missing `serde/derive` (53 errs); `cli/` binary-only, no `lib.rs`.

## GitHub Issues & SonarCloud

**Repo**: `BillyOutlast/drop` (fork). Upstream is `Drop-OSS/drop`. Always use `--repo BillyOutlast/drop` for issues/PRs.

**Checking SonarCloud issues:**

```bash
gh issue list --repo BillyOutlast/drop --label sonarcloud --state open
```

**SonarCloud project key**: `BillyOutlast_drop`. Use MCP sonarqube tools to query issues directly:

```text
search_sonar_issues_in_projects(projects=["BillyOutlast_drop"], issueStatuses=["OPEN"])
```

**Issue labels**: `sonarcloud`, `critical`, `major`, `minor`, `a11y`, `security`, `vue`, `react`, `readability`, `performance`, `code-quality`, `refactoring`

**Working SonarCloud issues:**

1. List issues: `gh issue list --repo BillyOutlast/drop --label sonarcloud --state open`
2. Fix issues in code, referencing the SonarCloud rule and file:line
3. Link fixed issues in PR body with `Closes #N` syntax
4. One PR can close multiple related issues (e.g., all `:key` binding fixes in one PR)

**Creating issues**: Use `gh issue create --repo BillyOutlast/drop --label sonarcloud` for new findings.

## Deferred Work Backlog (2026-07-24)

Captured at PR #22 (https://github.com/BillyOutlast/drop/pull/22) close-out. Repo issues disabled — document here instead of filing GitHub issues. **Re-evaluate when coverage >30% or as bandwidth allows.**
Captured at PR #22 (https://github.com/BillyOutlast/drop/pull/22) close-out. **Re-evaluate when coverage >30% or as bandwidth allows.**

| Item | Trigger | Why deferred |
| ---------------------------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Codecov test-results reporting | Coverage >30% | JUnit analytics produce zero signal at 32 tests. Use `codecov-action@v5` with `report_type: test_results` (NOT `codecov/test-results-action@v1` which is DEPRECATED). |
| `.codecov.yml` with `target: auto` | Coverage >30% | At 1.17% baseline, ANY new uncovered code drops percentage and blocks every PR. Contradicts current "no gates" policy. |
| gitleaks-action v2→v3 migration | Pre-Sept 2026 | v2 uses Node 20; GitHub deprecates Node 20 default in Sept 2026. Also unlocks v3's native fork-PR base-SHA resolution. |
| SonarCloud C rating fix | Needs SonarCloud auth | Cannot view findings via GitHub API. Likely test-only noise (90% of PR #22 is test code). |
| SonarCloud C rating fix | Ongoing | 130 open issues tracked via GitHub labels. Use `gh issue list --repo BillyOutlast/drop --label sonarcloud` to query. Fix batches by category (a11y, vue, react, code-quality). |
| `noUncheckedIndexedAccess` enable | After latent-error fixup | 30+ latent TS errors in `server/api/v1/{admin/import/massversion, auth/mfa/webauthn, auth/passkey}/`, `server/internal/{auth/totp, clients/event-handler, metadata/pcgamingwiki, system-data/index, utils/prioritylist}.ts`. Each requires explicit `if (!arr[i]) return` guard. |
| CLI integration tests refactor | Post lib.rs unblock | `cli/tests/*.rs` now compile (commit 35b63960), but real coverage of `commands/upload/` and `commands/connect/` flows needs fixture data setup. |
| E2E user-flow data fixtures | Post test DB infra | 5 page-flow E2E tests were added then removed in PR #22: they return 500 in CI because the app needs DB + auth setup to render pages. The tailwindcss v4 vite plugin recursion is fixed (`E2E=true` guard in `server/nuxt.config.ts`), but the application itself can't render without services. Re-add page tests when test DB + auth fixtures are available. |
Expand All @@ -203,12 +232,14 @@ This file is a cache. Before trusting any fact, verify with a direct command:
When users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.

How to use skills:

- Invoke: `npx openskills read <skill-name>` (run in your shell)
- For multiple: `npx openskills read skill-one,skill-two`
- The skill content will load with detailed instructions on how to complete the task
- Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)

Usage notes:

- Only use skills listed in <available_skills> below
- Do not invoke a skill that is already loaded in your context
- Each skill invocation is stateless
Expand Down
15 changes: 5 additions & 10 deletions desktop/main/components/Header.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<ol class="inline-flex items-center gap-x-6">
<NuxtLink
v-for="(nav, navIdx) in navigation"
:key="nav.route"
:class="[
'transition uppercase font-display font-semibold text-md',
navIdx === currentNavigation
Expand All @@ -22,19 +23,13 @@
</ol>
</nav>
</div>
<div
@mousedown="() => window.startDragging()"
class="flex cursor-pointer grow h-full"
/>
<div @mousedown="() => window.startDragging()" class="flex cursor-pointer grow h-full" />
<div class="inline-flex items-center">
<ol class="inline-flex gap-3">
<HeaderProtonSupportWidget />
<HeaderQueueWidget :object="currentQueueObject" />
<li v-for="(item, itemIdx) in quickActions">
<HeaderWidget
@click="item.action"
:notifications="item.notifications"
>
<li v-for="(item, itemIdx) in quickActions" :key="itemIdx">
<HeaderWidget @click="item.action" :notifications="item.notifications">
<component class="h-5" :is="item.icon" />
</HeaderWidget>
</li>
Expand All @@ -43,7 +38,7 @@
</ol>
</div>
</div>
<WindowControl />
<WindowControl />
</div>
</template>

Expand Down
2 changes: 1 addition & 1 deletion desktop/main/components/HeaderUserWidget.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
Admin Dashboard
</a>
</MenuItem>
<MenuItem v-for="(nav, navIdx) in navigation" v-slot="{ active, close }">
<MenuItem v-for="(nav, navIdx) in navigation" :key="navIdx" v-slot="{ active, close }">
<button
type="button"
@click="() => navigate(close, nav)"
Expand Down
6 changes: 3 additions & 3 deletions desktop/main/components/LibrarySearch.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
<DisclosurePanel as="dd" class="mt-2 flex flex-col gap-y-1.5">
<NuxtLink
v-for="item in nav.items"
:key="nav.id"
:key="item.id"
:class="[
'transition-all duration-300 rounded-lg flex items-center px-1 py-0.5 hover:scale-105 active:scale-95 hover:shadow-lg hover:shadow-zinc-950/50',
currentNavigation == item.id
Expand Down Expand Up @@ -93,7 +93,7 @@
</Disclosure>
</TransitionGroup>
<div v-if="loading" class="h-full grow flex p-8 justify-center text-zinc-100">
<div role="status" aria-live="polite">
<output aria-live="polite">
<svg
aria-hidden="true"
class="w-6 h-6 text-transparent animate-spin fill-zinc-600"
Expand All @@ -111,7 +111,7 @@
/>
</svg>
<span class="sr-only">Loading...</span>
</div>
</output>
</div>
</div>
</template>
Expand Down
6 changes: 3 additions & 3 deletions desktop/main/pages/auth/code.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
</h1>
<div class="mt-4">
<p class="text-sm text-zinc-400 max-w-md mx-auto">
Open Drop on another one of your devices, and use your account
dropdown to "Authorize client", and enter the code below.
Open Drop on another one of your devices, and use your account dropdown to "Authorize
client", and enter the code below.
</p>
<div
class="mt-8 flex items-center justify-center gap-x-5 text-8xl font-bold text-zinc-100"
>
<span v-for="letter in code.split('')">{{ letter }}</span>
<span v-for="(letter, letterIdx) in code.split('')" :key="letterIdx">{{ letter }}</span>
</div>
</div>
<div class="mt-10 flex items-center justify-center gap-x-6">
Expand Down
6 changes: 3 additions & 3 deletions desktop/main/pages/library/[id]/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@
</div>
</div>
<div v-else class="w-full flex items-center justify-center p-4">
<div role="status" aria-live="polite">
<output aria-live="polite">
<svg
aria-hidden="true"
class="w-7 h-7 text-transparent animate-spin fill-white"
Expand All @@ -363,7 +363,7 @@
/>
</svg>
<span class="sr-only">Loading...</span>
</div>
</output>
</div>
<div v-if="installDirs">
<InstallDirectorySelector :install-dirs="installDirs" v-model="installDir" />
Expand Down Expand Up @@ -478,7 +478,7 @@
</div>

<ol class="space-y-2">
<li v-for="(launchData, launchIdx) in launchOptions!">
<li v-for="(launchData, launchIdx) in launchOptions!" :key="launchIdx">
<button
type="button"
class="transition w-full rounded-sm bg-zinc-800 inline-flex items-center text-sm py-2 px-3 gap-x-2 text-zinc-100 hover:text-zinc-300 hover:bg-zinc-700"
Expand Down
3 changes: 2 additions & 1 deletion desktop/main/pages/queue.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
</div>
<div class="absolute inset-0 h-full flex flex-row items-end justify-end space-x-[1px]">
<div
v-for="bar in speedHistory"
v-for="(bar, barIdx) in speedHistory"
:key="barIdx"
:style="{ height: `${(bar / speedMax) * 100}%` }"
class="w-[3px] bg-blue-600 rounded-t-full"
/>
Expand Down
4 changes: 2 additions & 2 deletions libraries/base/components/LoadingButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
:class="[styles[style].base, props.disabled ? styles[style].disabled : styles[style].dft]"
:disabled="props.disabled"
>
<div v-if="props.loading" role="status" aria-live="polite">
<output v-if="props.loading" aria-live="polite">
<svg
aria-hidden="true"
class="w-5 h-5 text-transparent animate-spin fill-white"
Expand All @@ -22,7 +22,7 @@
/>
</svg>
<span class="sr-only">Loading...</span>
</div>
</output>
<slot v-else />
</button>
</template>
Expand Down
2 changes: 1 addition & 1 deletion server/components/CodeInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ function input(index: number) {
codeElements.value[index + 1].focus();
}

if (!(index - 1 < 0) && !v) {
if (index >= 1 && !v) {
codeElements.value[index - 1].focus();
}

Expand Down
8 changes: 7 additions & 1 deletion server/components/GameEditor/Metadata.vue
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@
</div>
</div>
<div class="flex flex-col">
<label class="text-sm/6 font-medium text-zinc-100">
<label
for="ageRatingOrg"
class="text-sm/6 font-medium text-zinc-100"
>
{{ $t("library.admin.game.ageRatings") }}
</label>
<div class="mt-2 space-y-2">
Expand Down Expand Up @@ -88,6 +91,7 @@
</p>
<div v-if="showAddAgeRating" class="flex items-center gap-2">
<select
id="ageRatingOrg"
v-model="newAgeRatingOrg"
class="rounded-md bg-zinc-800 px-2 py-1 text-sm text-zinc-100 outline outline-1 -outline-offset-1 outline-zinc-700 focus:outline-blue-600"
>
Expand All @@ -100,8 +104,10 @@
</option>
</select>
<select
id="ageRatingValue"
v-model="newAgeRatingValue"
:disabled="!newAgeRatingOrg"
aria-label="Age rating value"
class="rounded-md bg-zinc-800 px-2 py-1 text-sm text-zinc-100 outline outline-1 -outline-offset-1 outline-zinc-700 focus:outline-blue-600"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
>
<option
Expand Down
2 changes: 1 addition & 1 deletion server/components/GameEditor/VersionConfig.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,6 @@ const props = defineProps<{
function isSetup(
v: typeof props.config,
): v is AdminFetchGameType["versions"][number]["setups"][number] {
return Object.prototype.hasOwnProperty.call(v, "setupId");
return Object.hasOwn(v, "setupId");
}
</script>
4 changes: 2 additions & 2 deletions server/components/Selector/MultiItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
v-if="createLoading"
class="absolute inset-0 bg-zinc-950 flex items-center justify-center"
>
<div role="status" aria-live="polite">
<output aria-live="polite">
<svg
aria-hidden="true"
class="size-8 text-transparent animate-spin fill-white"
Expand All @@ -111,7 +111,7 @@
/>
</svg>
<span class="sr-only">{{ $t("common.srLoading") }}</span>
</div>
</output>
</div>
</div>
</Combobox>
Expand Down
Loading
Loading