diff --git a/apps/web/.gitignore 2 b/apps/web/.gitignore 2
new file mode 100644
index 0000000..5ef6a52
--- /dev/null
+++ b/apps/web/.gitignore 2
@@ -0,0 +1,41 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.*
+.yarn/*
+!.yarn/patches
+!.yarn/plugins
+!.yarn/releases
+!.yarn/versions
+
+# testing
+/coverage
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+# misc
+.DS_Store
+*.pem
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+.pnpm-debug.log*
+
+# env files (can opt-in for committing if needed)
+.env*
+
+# vercel
+.vercel
+
+# typescript
+*.tsbuildinfo
+next-env.d.ts
diff --git a/apps/web/AGENTS 2.md b/apps/web/AGENTS 2.md
new file mode 100644
index 0000000..af3b7c8
--- /dev/null
+++ b/apps/web/AGENTS 2.md
@@ -0,0 +1,9 @@
+
+
+## This is NOT the Next.js you know
+
+This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices.
+
+This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.
+
+
diff --git a/apps/web/README 2.md b/apps/web/README 2.md
new file mode 100644
index 0000000..e215bc4
--- /dev/null
+++ b/apps/web/README 2.md
@@ -0,0 +1,36 @@
+This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
+
+## Getting Started
+
+First, run the development server:
+
+```bash
+npm run dev
+# or
+yarn dev
+# or
+pnpm dev
+# or
+bun dev
+```
+
+Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
+
+You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
+
+This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
+
+## Learn More
+
+To learn more about Next.js, take a look at the following resources:
+
+- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
+- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
+
+You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
+
+## Deploy on Vercel
+
+The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
+
+Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
diff --git a/apps/web/eslint.config 2.mjs b/apps/web/eslint.config 2.mjs
new file mode 100644
index 0000000..df69b1a
--- /dev/null
+++ b/apps/web/eslint.config 2.mjs
@@ -0,0 +1,22 @@
+import { defineConfig, globalIgnores } from "eslint/config";
+import nextVitals from "eslint-config-next/core-web-vitals";
+import nextTs from "eslint-config-next/typescript";
+
+const eslintConfig = defineConfig([
+ ...nextVitals,
+ ...nextTs,
+ // Override default ignores of eslint-config-next.
+ globalIgnores([
+ // Default ignores of eslint-config-next:
+ ".next/**",
+ "out/**",
+ "build/**",
+ "next-env.d.ts",
+ // OpenNext and Wrangler output:
+ ".open-next/**",
+ ".wrangler/**",
+ "cloudflare-env.d.ts",
+ ]),
+]);
+
+export default eslintConfig;
diff --git a/apps/web/next.config 2.ts b/apps/web/next.config 2.ts
new file mode 100644
index 0000000..8bf865d
--- /dev/null
+++ b/apps/web/next.config 2.ts
@@ -0,0 +1,18 @@
+import type { NextConfig } from "next";
+
+const nextConfig: NextConfig = {
+ /* config options here */
+ cacheComponents: true,
+ partialPrefetching: true,
+ reactCompiler: true,
+ turbopack: {
+ rules: {
+ "*.css": {
+ loaders: ["@tailwindcss/turbopack"],
+ as: "*.css",
+ },
+ },
+ },
+};
+
+export default nextConfig;
diff --git a/apps/web/package 2.json b/apps/web/package 2.json
new file mode 100644
index 0000000..4975914
--- /dev/null
+++ b/apps/web/package 2.json
@@ -0,0 +1,31 @@
+{
+ "name": "@gitwork/web",
+ "version": "0.1.0",
+ "private": true,
+ "scripts": {
+ "dev": "next dev",
+ "build": "next build",
+ "start": "next start",
+ "lint": "eslint",
+ "typecheck": "next typegen && tsc --noEmit",
+ "cf:build": "opennextjs-cloudflare build",
+ "preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview"
+ },
+ "dependencies": {
+ "next": "16.4.2",
+ "react": "19.3.0",
+ "react-dom": "19.3.0"
+ },
+ "devDependencies": {
+ "@tailwindcss/turbopack": "^4",
+ "@types/node": "^20",
+ "@types/react": "^19",
+ "@types/react-dom": "^19",
+ "babel-plugin-react-compiler": "1.0.0",
+ "eslint": "^9",
+ "eslint-config-next": "16.4.2",
+ "tailwindcss": "^4",
+ "typescript": "^5"
+ },
+ "license": "AGPL-3.0-only"
+}
diff --git a/apps/web/public/file 2.svg b/apps/web/public/file 2.svg
new file mode 100644
index 0000000..004145c
--- /dev/null
+++ b/apps/web/public/file 2.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/apps/web/public/globe 2.svg b/apps/web/public/globe 2.svg
new file mode 100644
index 0000000..567f17b
--- /dev/null
+++ b/apps/web/public/globe 2.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/apps/web/public/next 2.svg b/apps/web/public/next 2.svg
new file mode 100644
index 0000000..5174b28
--- /dev/null
+++ b/apps/web/public/next 2.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/apps/web/public/vercel 2.svg b/apps/web/public/vercel 2.svg
new file mode 100644
index 0000000..7705396
--- /dev/null
+++ b/apps/web/public/vercel 2.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/apps/web/public/window 2.svg b/apps/web/public/window 2.svg
new file mode 100644
index 0000000..b2b2a44
--- /dev/null
+++ b/apps/web/public/window 2.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/apps/web/src/app/favicon 2.ico b/apps/web/src/app/favicon 2.ico
new file mode 100644
index 0000000..af98450
Binary files /dev/null and b/apps/web/src/app/favicon 2.ico differ
diff --git a/apps/web/src/app/globals 2.css b/apps/web/src/app/globals 2.css
new file mode 100644
index 0000000..a2dc41e
--- /dev/null
+++ b/apps/web/src/app/globals 2.css
@@ -0,0 +1,26 @@
+@import "tailwindcss";
+
+:root {
+ --background: #ffffff;
+ --foreground: #171717;
+}
+
+@theme inline {
+ --color-background: var(--background);
+ --color-foreground: var(--foreground);
+ --font-sans: var(--font-geist-sans);
+ --font-mono: var(--font-geist-mono);
+}
+
+@media (prefers-color-scheme: dark) {
+ :root {
+ --background: #0a0a0a;
+ --foreground: #ededed;
+ }
+}
+
+body {
+ background: var(--background);
+ color: var(--foreground);
+ font-family: Arial, Helvetica, sans-serif;
+}
diff --git a/apps/web/src/app/layout 2.tsx b/apps/web/src/app/layout 2.tsx
new file mode 100644
index 0000000..00ce7b2
--- /dev/null
+++ b/apps/web/src/app/layout 2.tsx
@@ -0,0 +1,30 @@
+import { APP_NAME } from "@gitwork/core";
+import type { Metadata } from "next";
+import { Geist, Geist_Mono } from "next/font/google";
+import "./globals.css";
+
+const geistSans = Geist({
+ variable: "--font-geist-sans",
+ subsets: ["latin"],
+});
+
+const geistMono = Geist_Mono({
+ variable: "--font-geist-mono",
+ subsets: ["latin"],
+});
+
+export const metadata: Metadata = {
+ title: APP_NAME,
+ description: "Project management on top of GitHub.",
+};
+
+export default function RootLayout({ children }: LayoutProps<"/">) {
+ return (
+
+
{children}
+
+ );
+}
diff --git a/apps/web/src/app/page 2.tsx b/apps/web/src/app/page 2.tsx
new file mode 100644
index 0000000..f6e51de
--- /dev/null
+++ b/apps/web/src/app/page 2.tsx
@@ -0,0 +1,10 @@
+import { APP_NAME } from "@gitwork/core";
+
+export default function Home() {
+ return (
+
+ {APP_NAME}
+ GitHub is the source of truth.
+
+ );
+}
diff --git a/apps/web/tsconfig 2.json b/apps/web/tsconfig 2.json
new file mode 100644
index 0000000..cf9c65d
--- /dev/null
+++ b/apps/web/tsconfig 2.json
@@ -0,0 +1,34 @@
+{
+ "compilerOptions": {
+ "target": "ES2017",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "noEmit": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "bundler",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "react-jsx",
+ "incremental": true,
+ "plugins": [
+ {
+ "name": "next"
+ }
+ ],
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ },
+ "include": [
+ "next-env.d.ts",
+ "**/*.ts",
+ "**/*.tsx",
+ ".next/types/**/*.ts",
+ ".next/dev/types/**/*.ts",
+ "**/*.mts"
+ ],
+ "exclude": ["node_modules"]
+}
diff --git a/apps/web/worker 2.ts b/apps/web/worker 2.ts
new file mode 100644
index 0000000..6e3e019
--- /dev/null
+++ b/apps/web/worker 2.ts
@@ -0,0 +1,25 @@
+// Custom Worker entry (decision 004): OpenNext's fetch handler plus the reconcile Cron Trigger.
+// OpenNext builds .open-next/worker.js; wrangler bundles this file around it.
+import { openD1 } from "@gitwork/db/d1";
+import { runScheduledReconcile } from "@gitwork/server/sync";
+// Generated by `opennextjs-cloudflare build`; absent before the first build, so @ts-ignore.
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore
+import { default as handler } from "./.open-next/worker.js";
+
+export default {
+ fetch: handler.fetch,
+
+ async scheduled(_controller, env, ctx) {
+ ctx.waitUntil(
+ runScheduledReconcile(openD1(env.DB), env as unknown as Record, crypto.randomUUID()).then((run) =>
+ console.log(`[reconcile] ${JSON.stringify(run)}`),
+ ),
+ );
+ },
+} satisfies ExportedHandler;
+
+// Generated by `opennextjs-cloudflare build`; absent before the first build, so @ts-ignore.
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore
+export { DOQueueHandler, DOShardedTagCache, BucketCachePurge } from "./.open-next/worker.js";
diff --git a/docs/INDEX.md b/docs/INDEX.md
index 780e065..92c3ae6 100644
--- a/docs/INDEX.md
+++ b/docs/INDEX.md
@@ -30,6 +30,7 @@
| 019 | [Instance admins and email from the environment; wizard creates the GitHub App](decisions/019-instance-setup.md) |
| 020 | [Linking a workspace is checked with the user's own GitHub token](decisions/020-workspace-link-boundary.md) |
| 021 | [Task writes: user token first, App on refusal, synchronous](decisions/021-task-writes.md) |
+| 022 | [Cloudflare hosting requires the Workers Paid plan](decisions/022-cloudflare-paid-plan.md) |
## Features
diff --git a/docs/STATE.md b/docs/STATE.md
index bd9bdc3..b495e1e 100644
--- a/docs/STATE.md
+++ b/docs/STATE.md
@@ -1,11 +1,10 @@
# State
-Last updated: 2026-10-15
+Last updated: 2026-10-16
## Resume here
-- **Phase 3 (tasks on web) is in review** on branch `feature/tasks` (PR pending owner merge).
- PRs #1–#3 (Phases 0–2) are merged.
+- PRs #1–#4 (Phases 0–3) are merged. Next: Phase 4 — Docs on web.
- **Live GitHub check: still not done.** It needs a person (or a connected browser) to click
"Create GitHub App" on github.com, and a public webhook URL. See Chores.
- **Before any work:** `git fetch origin && git status -sb`.
@@ -24,7 +23,7 @@ None. Next step: Phase 4 — Docs on web.
| Phase 0 — Scaffold | 2026-10-15 | [features/scaffold.md](features/scaffold.md) |
| Phase 1 — Identity | 2026-10-15 | [features/identity.md](features/identity.md) |
| Phase 2 — GitHub App (PR #3) | 2026-10-15 | [features/github-app.md](features/github-app.md) |
-| Phase 3 — Tasks on web (in review) | 2026-10-15 | [features/tasks.md](features/tasks.md) |
+| Phase 3 — Tasks on web (PR #4) | 2026-10-16 | [features/tasks.md](features/tasks.md) |
## Backlog
@@ -42,10 +41,7 @@ Chores:
(`GET /app/hook/deliveries/{id}`) and replay them to the local webhook route, re-signed with the
stored secret (the API returns parsed JSON, not the signed bytes). Diff real payloads against
`test/fake-github.ts`; exercise linking and a task write with a real user token.
-- Workers bundle is 3.40 MiB gzipped, over the Free plan's 3 MiB (main was already 3.23 MiB).
- Decide: require the Paid plan for Cloudflare, or cut the bundle.
-- Owner question (decision 020): should a workspace unlink when the Admin who linked it loses
- GitHub access?
+- `pnpm smoke`: fail when the gzipped Worker bundle passes 10 MiB (decision 022).
- Before a hosted launch: `/github/installed` should show org names only to users whose GitHub
token can see the installation (now it shows none).
- Upgrade Next 16.3.8 → 16.4.x with OpenNext ≥1.20.12 once it passes the pnpm age policy.
diff --git a/docs/decisions/009-tasks-projects-v2.md b/docs/decisions/009-tasks-projects-v2.md
index b5a0868..9b63ef0 100644
--- a/docs/decisions/009-tasks-projects-v2.md
+++ b/docs/decisions/009-tasks-projects-v2.md
@@ -21,3 +21,5 @@ Projects v2 as the task source.
## Consequences
- Requires the org Projects permission, so org-owned boards only (006).
- Projects v2 webhooks are in public preview; reconcile covers gaps (010).
+- Field mapping has "Auto-detect" (by GitHub's usual field names) but no "none": a mapped field can
+ be overridden, not switched off. (Owner confirmed 2026-10-16.)
diff --git a/docs/decisions/017-identity 2.md b/docs/decisions/017-identity 2.md
new file mode 100644
index 0000000..21d3339
--- /dev/null
+++ b/docs/decisions/017-identity 2.md
@@ -0,0 +1,34 @@
+# 017 — Identity model, GitHub gate, sign-up policy
+
+Date: 2026-10-15 · Status: Accepted · Narrows 007 · Supersedes part of 005
+
+## Context
+Phase 1 builds sign-in, accounts, workspaces, roles, and invites. Three questions came up: what
+Better Auth should own, which Owner/Admin capabilities need a linked GitHub account, and who may
+create a new Account.
+
+## Decision
+- **Better Auth owns identity only:** users, sessions, verification codes, linked GitHub identities.
+ Gitwork owns accounts, account owners, workspaces, memberships, and invites in its own tables.
+ Better Auth's `organization` plugin is not used. Better Auth's "account" model is stored as
+ `auth_identities` so it never collides with Gitwork's Account.
+- **GitHub gate (owner decision):** a linked GitHub account is needed only for GitHub tasks —
+ installing the App and setting a workspace's repos, board, and fields. Owners and Admins can
+ invite, manage members, and change other settings without GitHub. The gated set is one constant,
+ `GITHUB_CAPABILITIES`, in `packages/core`.
+- **Sign-up policy (owner decision):** an instance setting, `open` or `invite-only`. Default `open`
+ until the Phase 2 setup wizard exists; then self-host defaults to `invite-only` and the hosted
+ version stays `open`. A person with a valid pending invite can always sign up. Joining a
+ workspace always needs an invite.
+
+## Alternatives considered
+- **Better Auth `organization` plugin:** has roles and invites, but no Account level above
+ workspaces and no GitHub gate.
+- **Gate all Owner/Admin power on GitHub:** a new Owner could not invite anyone before linking.
+- **Always open / always invite-only sign-up:** the first suits hosting but not private installs;
+ the second leaves the hosted version no way to onboard customers.
+
+## Consequences
+- Every permission check calls `packages/core`; the matrix tests cover the gate.
+- The sign-up check is a hook before user creation, not Better Auth's global `disableSignUp`, which
+ would lock out invitees.
diff --git a/docs/decisions/020-workspace-link-boundary.md b/docs/decisions/020-workspace-link-boundary.md
index 97ab9f7..d154026 100644
--- a/docs/decisions/020-workspace-link-boundary.md
+++ b/docs/decisions/020-workspace-link-boundary.md
@@ -1,6 +1,6 @@
# 020 — Linking a workspace is checked with the user's own GitHub token
-Date: 2026-10-15 · Status: Accepted · Builds on 006, 017
+Date: 2026-10-15 · Status: Accepted (owner confirmed 2026-10-16) · Builds on 006, 017
## Context
A workspace links one board and a list of repos (006). The App's installation token can read every
@@ -32,5 +32,5 @@ pull in. Without a check, an Admin of one workspace could link another customer'
## Consequences
- The link reflects what the linking Admin could see **when they saved it**. If they later lose
access, the workspace keeps its repos (the org's installation still covers them). Re-linking
- re-checks. Open question for the owner: should losing access unlink?
+ re-checks. (Owner confirmed 2026-10-16: keep the link.)
- Pull requests on the board are not tasks in v1; they are filtered out like any unknown type.
diff --git a/docs/decisions/021-task-writes.md b/docs/decisions/021-task-writes.md
index 9e7f884..e4b5dc2 100644
--- a/docs/decisions/021-task-writes.md
+++ b/docs/decisions/021-task-writes.md
@@ -1,6 +1,6 @@
# 021 — Task writes: user token first, App on refusal, synchronous
-Date: 2026-10-15 · Status: Accepted · Builds on 007, 008, 009
+Date: 2026-10-15 · Status: Accepted (owner confirmed the defaults 2026-10-16) · Builds on 007, 008, 009
## Context
Decision 008 says linked users act as themselves and everyone else writes through the App. Two
diff --git a/docs/decisions/022-cloudflare-paid-plan.md b/docs/decisions/022-cloudflare-paid-plan.md
new file mode 100644
index 0000000..3fa00f1
--- /dev/null
+++ b/docs/decisions/022-cloudflare-paid-plan.md
@@ -0,0 +1,22 @@
+# 022 — Cloudflare hosting requires the Workers Paid plan
+
+Date: 2026-10-16 · Status: Accepted (owner) · Builds on 001, 002
+
+## Context
+The Worker bundle is 3.40 MiB gzipped after Phase 3 (3.23 MiB after Phase 2). The Workers Free
+plan allows 3 MiB per Worker; the Paid plan allows 10 MiB. Free also caps subrequests at 50 per
+invocation, which the reconcile defaults already exceed.
+
+## Decision
+Deploying Gitwork to Cloudflare requires the Workers Paid plan. We do not cut the bundle to fit
+the Free plan. Node hosts (decision 001) have no such limit.
+
+## Alternatives considered
+- **Cut the bundle under 3 MiB:** drop or lazy-load dependencies (Better Auth plugins, Radix,
+ drizzle). Costly, and every phase adds code; the limit would bind again soon.
+- **Support Free with reduced features:** two configurations to test for a small saving.
+
+## Consequences
+- The self-host guide (Phase 7) and the Deploy-to-Cloudflare button state the Paid plan.
+- `pnpm smoke` should fail when the gzipped bundle passes 10 MiB (follow-up).
+- Reconcile defaults (`RECONCILE_MAX_PAGES`) stay sized for the Paid plan.
diff --git a/docs/features/tasks.md b/docs/features/tasks.md
index 1f8fcfe..36f520a 100644
--- a/docs/features/tasks.md
+++ b/docs/features/tasks.md
@@ -62,7 +62,7 @@ content, so board syncs and `projects_v2_item` refetches keep `gh_issue_links` c
payload (`IssueLinks` query) instead of trusting it.
**Field mapping.** Stored ids win when they still fit the field type. A stored null means
-**auto-detect** (the settings form labels it so); there is no "none" yet. Auto-detect: kanban = a
+**auto-detect** (the settings form labels it so); there is no "none" (decision 009). Auto-detect: kanban = a
single-select named "Status", else the first one; start = "Start date"/"Start"; end = "Target
date"/"End date"/"Due date"/"Due"; iteration = the first iteration field.
@@ -108,8 +108,8 @@ Add components with `pnpm exec shadcn add ` from `apps/web`.
- **D1 test reset** drops tables in foreign-key order, read from the `CREATE` statements (D1 refuses
`pragma_foreign_key_list`). drizzle-kit creates tables alphabetically, so neither name nor
creation order is a dependency order.
-- **Worker bundle:** 3.40 MiB gzipped (main was 3.23 MiB before this phase). Both exceed the Workers
- Free plan's 3 MiB; the Paid plan allows 10 MiB. Self-hosters on Free cannot deploy as is.
+- **Worker bundle:** 3.40 MiB gzipped (3.23 MiB before this phase), over the Workers Free plan's
+ 3 MiB. Cloudflare hosting requires the Paid plan (decision 022).
- **Not tested against real GitHub.** `/user/installations/{id}/repositories`, the Projects v2
mutations, and the `sub_issues` / `issue_dependencies` payload keys follow GitHub's docs and the
live GraphQL schema (introspected 2026-10-15), not real calls. See STATE → live check.
diff --git a/docs/spec.md b/docs/spec.md
index f960965..8dd74e8 100644
--- a/docs/spec.md
+++ b/docs/spec.md
@@ -52,6 +52,7 @@ Each has a record in `docs/decisions/`.
| 019 | Instance admins (`INSTANCE_ADMIN_EMAILS`) and email come from env; `/setup` creates the GitHub App. |
| 020 | Linking a board and repos is checked with the linking user's own GitHub token; one installation per workspace. |
| 021 | Task writes: user token first, the App when GitHub refuses; synchronous; audit row per write. |
+| 022 | Cloudflare hosting requires the Workers Paid plan (bundle over 3 MiB). |
## Roles
diff --git a/eslint.config 2.mjs b/eslint.config 2.mjs
new file mode 100644
index 0000000..df5f30c
--- /dev/null
+++ b/eslint.config 2.mjs
@@ -0,0 +1,8 @@
+// Lint config for packages/*. apps/web has its own (eslint-config-next).
+import { defineConfig, globalIgnores } from "eslint/config";
+import tseslint from "typescript-eslint";
+
+export default defineConfig([
+ globalIgnores(["**/node_modules/**", "apps/**", "packages/db/migrations/**"]),
+ ...tseslint.configs.recommended,
+]);
diff --git a/package 2.json b/package 2.json
new file mode 100644
index 0000000..21bc790
--- /dev/null
+++ b/package 2.json
@@ -0,0 +1,16 @@
+{
+ "name": "gitwork",
+ "private": true,
+ "license": "AGPL-3.0-only",
+ "packageManager": "pnpm@12.11.2",
+ "engines": {
+ "node": ">=22"
+ },
+ "scripts": {
+ "dev": "pnpm --filter @gitwork/web dev",
+ "build": "pnpm -r build",
+ "test": "vitest run",
+ "lint": "pnpm -r lint",
+ "typecheck": "pnpm -r typecheck"
+ }
+}
diff --git a/packages/db/migrations/0003_resumable_sweep 2.sql b/packages/db/migrations/0003_resumable_sweep 2.sql
new file mode 100644
index 0000000..e43c461
--- /dev/null
+++ b/packages/db/migrations/0003_resumable_sweep 2.sql
@@ -0,0 +1,2 @@
+ALTER TABLE `gh_sync_targets` ADD `sweep_started_at` integer;--> statement-breakpoint
+ALTER TABLE `gh_sync_targets` ADD `sweep_cursor` text;
\ No newline at end of file
diff --git a/packages/db/migrations/meta/0003_snapshot 2.json b/packages/db/migrations/meta/0003_snapshot 2.json
new file mode 100644
index 0000000..b687cf2
--- /dev/null
+++ b/packages/db/migrations/meta/0003_snapshot 2.json
@@ -0,0 +1,1777 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "62143336-6275-4b95-9cab-dc2f238bb5dd",
+ "prevId": "b1f08e6d-32b5-4e16-b855-0d076c3c89b3",
+ "tables": {
+ "account_owners": {
+ "name": "account_owners",
+ "columns": {
+ "account_id": {
+ "name": "account_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(unixepoch() * 1000)"
+ }
+ },
+ "indexes": {
+ "account_owners_user_id_idx": {
+ "name": "account_owners_user_id_idx",
+ "columns": [
+ "user_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "account_owners_account_id_accounts_id_fk": {
+ "name": "account_owners_account_id_accounts_id_fk",
+ "tableFrom": "account_owners",
+ "tableTo": "accounts",
+ "columnsFrom": [
+ "account_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "account_owners_user_id_users_id_fk": {
+ "name": "account_owners_user_id_users_id_fk",
+ "tableFrom": "account_owners",
+ "tableTo": "users",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {
+ "account_owners_account_id_user_id_pk": {
+ "columns": [
+ "account_id",
+ "user_id"
+ ],
+ "name": "account_owners_account_id_user_id_pk"
+ }
+ },
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "accounts": {
+ "name": "accounts",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(unixepoch() * 1000)"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "auth_identities": {
+ "name": "auth_identities",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "account_id": {
+ "name": "account_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "provider_id": {
+ "name": "provider_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "access_token": {
+ "name": "access_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "refresh_token": {
+ "name": "refresh_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "id_token": {
+ "name": "id_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "access_token_expires_at": {
+ "name": "access_token_expires_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "refresh_token_expires_at": {
+ "name": "refresh_token_expires_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "scope": {
+ "name": "scope",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "password": {
+ "name": "password",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(unixepoch() * 1000)"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(unixepoch() * 1000)"
+ }
+ },
+ "indexes": {
+ "auth_identities_user_id_idx": {
+ "name": "auth_identities_user_id_idx",
+ "columns": [
+ "user_id"
+ ],
+ "isUnique": false
+ },
+ "auth_identities_provider_account_uq": {
+ "name": "auth_identities_provider_account_uq",
+ "columns": [
+ "provider_id",
+ "account_id"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {
+ "auth_identities_user_id_users_id_fk": {
+ "name": "auth_identities_user_id_users_id_fk",
+ "tableFrom": "auth_identities",
+ "tableTo": "users",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "gh_issues": {
+ "name": "gh_issues",
+ "columns": {
+ "node_id": {
+ "name": "node_id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "repo_node_id": {
+ "name": "repo_node_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "number": {
+ "name": "number",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "title": {
+ "name": "title",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "body": {
+ "name": "body",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "state": {
+ "name": "state",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "state_reason": {
+ "name": "state_reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "labels": {
+ "name": "labels",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "assignees": {
+ "name": "assignees",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "author_login": {
+ "name": "author_login",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "issue_type": {
+ "name": "issue_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "html_url": {
+ "name": "html_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at_gh": {
+ "name": "created_at_gh",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "closed_at_gh": {
+ "name": "closed_at_gh",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "github_updated_at": {
+ "name": "github_updated_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "deleted": {
+ "name": "deleted",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "synced_at": {
+ "name": "synced_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "gh_issues_repo_number_uq": {
+ "name": "gh_issues_repo_number_uq",
+ "columns": [
+ "repo_node_id",
+ "number"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "gh_project_fields": {
+ "name": "gh_project_fields",
+ "columns": {
+ "node_id": {
+ "name": "node_id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "project_node_id": {
+ "name": "project_node_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "data_type": {
+ "name": "data_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "config": {
+ "name": "config",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "synced_at": {
+ "name": "synced_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "gh_project_fields_project_idx": {
+ "name": "gh_project_fields_project_idx",
+ "columns": [
+ "project_node_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "gh_project_items": {
+ "name": "gh_project_items",
+ "columns": {
+ "node_id": {
+ "name": "node_id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "project_node_id": {
+ "name": "project_node_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "content_type": {
+ "name": "content_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "content_node_id": {
+ "name": "content_node_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "draft_title": {
+ "name": "draft_title",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "draft_body": {
+ "name": "draft_body",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "field_values": {
+ "name": "field_values",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "archived": {
+ "name": "archived",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "github_updated_at": {
+ "name": "github_updated_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "deleted": {
+ "name": "deleted",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "synced_at": {
+ "name": "synced_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "gh_project_items_project_idx": {
+ "name": "gh_project_items_project_idx",
+ "columns": [
+ "project_node_id"
+ ],
+ "isUnique": false
+ },
+ "gh_project_items_content_idx": {
+ "name": "gh_project_items_content_idx",
+ "columns": [
+ "content_node_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "gh_projects": {
+ "name": "gh_projects",
+ "columns": {
+ "node_id": {
+ "name": "node_id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "installation_id": {
+ "name": "installation_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "owner_login": {
+ "name": "owner_login",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "number": {
+ "name": "number",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "title": {
+ "name": "title",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "closed": {
+ "name": "closed",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "url": {
+ "name": "url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "available": {
+ "name": "available",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": true
+ },
+ "synced_at": {
+ "name": "synced_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "gh_repos": {
+ "name": "gh_repos",
+ "columns": {
+ "node_id": {
+ "name": "node_id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "github_id": {
+ "name": "github_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "installation_id": {
+ "name": "installation_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "owner": {
+ "name": "owner",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "full_name": {
+ "name": "full_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "private": {
+ "name": "private",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "default_branch": {
+ "name": "default_branch",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "archived": {
+ "name": "archived",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "html_url": {
+ "name": "html_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "available": {
+ "name": "available",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": true
+ },
+ "synced_at": {
+ "name": "synced_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "gh_repos_github_id_unique": {
+ "name": "gh_repos_github_id_unique",
+ "columns": [
+ "github_id"
+ ],
+ "isUnique": true
+ },
+ "gh_repos_installation_idx": {
+ "name": "gh_repos_installation_idx",
+ "columns": [
+ "installation_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "gh_sync_targets": {
+ "name": "gh_sync_targets",
+ "columns": {
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "node_id": {
+ "name": "node_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "installation_id": {
+ "name": "installation_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "locator": {
+ "name": "locator",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "last_synced_at": {
+ "name": "last_synced_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "last_full_sync_at": {
+ "name": "last_full_sync_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "sweep_started_at": {
+ "name": "sweep_started_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "sweep_cursor": {
+ "name": "sweep_cursor",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {
+ "gh_sync_targets_kind_node_id_pk": {
+ "columns": [
+ "kind",
+ "node_id"
+ ],
+ "name": "gh_sync_targets_kind_node_id_pk"
+ }
+ },
+ "uniqueConstraints": {},
+ "checkConstraints": {
+ "gh_sync_targets_kind_ck": {
+ "name": "gh_sync_targets_kind_ck",
+ "value": "\"gh_sync_targets\".\"kind\" IN ('repo', 'project')"
+ }
+ }
+ },
+ "github_app": {
+ "name": "github_app",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "integer",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "app_id": {
+ "name": "app_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "slug": {
+ "name": "slug",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "client_id": {
+ "name": "client_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "client_secret": {
+ "name": "client_secret",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "webhook_secret": {
+ "name": "webhook_secret",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "private_key": {
+ "name": "private_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "html_url": {
+ "name": "html_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "owner_login": {
+ "name": "owner_login",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(unixepoch() * 1000)"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {
+ "github_app_singleton_ck": {
+ "name": "github_app_singleton_ck",
+ "value": "\"github_app\".\"id\" = 1"
+ }
+ }
+ },
+ "github_installation_tokens": {
+ "name": "github_installation_tokens",
+ "columns": {
+ "installation_id": {
+ "name": "installation_id",
+ "type": "integer",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "token": {
+ "name": "token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "github_installations": {
+ "name": "github_installations",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "integer",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "account_login": {
+ "name": "account_login",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "account_id": {
+ "name": "account_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "account_type": {
+ "name": "account_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "repository_selection": {
+ "name": "repository_selection",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "suspended_at": {
+ "name": "suspended_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "deleted_at": {
+ "name": "deleted_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(unixepoch() * 1000)"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(unixepoch() * 1000)"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "github_manifest_states": {
+ "name": "github_manifest_states",
+ "columns": {
+ "state_hash": {
+ "name": "state_hash",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "used_at": {
+ "name": "used_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "github_manifest_states_user_id_users_id_fk": {
+ "name": "github_manifest_states_user_id_users_id_fk",
+ "tableFrom": "github_manifest_states",
+ "tableTo": "users",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "github_webhook_deliveries": {
+ "name": "github_webhook_deliveries",
+ "columns": {
+ "delivery_id": {
+ "name": "delivery_id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "event": {
+ "name": "event",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "installation_id": {
+ "name": "installation_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(unixepoch() * 1000)"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "instance_settings": {
+ "name": "instance_settings",
+ "columns": {
+ "key": {
+ "name": "key",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "value": {
+ "name": "value",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(unixepoch() * 1000)"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "invites": {
+ "name": "invites",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "email": {
+ "name": "email",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "role": {
+ "name": "role",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "token_hash": {
+ "name": "token_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "invited_by": {
+ "name": "invited_by",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "accepted_at": {
+ "name": "accepted_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "accepted_by": {
+ "name": "accepted_by",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "revoked_at": {
+ "name": "revoked_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(unixepoch() * 1000)"
+ }
+ },
+ "indexes": {
+ "invites_token_hash_unique": {
+ "name": "invites_token_hash_unique",
+ "columns": [
+ "token_hash"
+ ],
+ "isUnique": true
+ },
+ "invites_workspace_id_idx": {
+ "name": "invites_workspace_id_idx",
+ "columns": [
+ "workspace_id"
+ ],
+ "isUnique": false
+ },
+ "invites_email_idx": {
+ "name": "invites_email_idx",
+ "columns": [
+ "email"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "invites_workspace_id_workspaces_id_fk": {
+ "name": "invites_workspace_id_workspaces_id_fk",
+ "tableFrom": "invites",
+ "tableTo": "workspaces",
+ "columnsFrom": [
+ "workspace_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "invites_invited_by_users_id_fk": {
+ "name": "invites_invited_by_users_id_fk",
+ "tableFrom": "invites",
+ "tableTo": "users",
+ "columnsFrom": [
+ "invited_by"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "invites_accepted_by_users_id_fk": {
+ "name": "invites_accepted_by_users_id_fk",
+ "tableFrom": "invites",
+ "tableTo": "users",
+ "columnsFrom": [
+ "accepted_by"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {
+ "invites_role_ck": {
+ "name": "invites_role_ck",
+ "value": "\"invites\".\"role\" IN ('owner', 'admin', 'member', 'read_only')"
+ },
+ "invites_email_lower_ck": {
+ "name": "invites_email_lower_ck",
+ "value": "\"invites\".\"email\" = lower(\"invites\".\"email\")"
+ }
+ }
+ },
+ "rate_limits": {
+ "name": "rate_limits",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "key": {
+ "name": "key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "count": {
+ "name": "count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "last_request": {
+ "name": "last_request",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "rate_limits_key_unique": {
+ "name": "rate_limits_key_unique",
+ "columns": [
+ "key"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "sessions": {
+ "name": "sessions",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "token": {
+ "name": "token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(unixepoch() * 1000)"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(unixepoch() * 1000)"
+ },
+ "ip_address": {
+ "name": "ip_address",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "user_agent": {
+ "name": "user_agent",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "sessions_token_unique": {
+ "name": "sessions_token_unique",
+ "columns": [
+ "token"
+ ],
+ "isUnique": true
+ },
+ "sessions_user_id_idx": {
+ "name": "sessions_user_id_idx",
+ "columns": [
+ "user_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "sessions_user_id_users_id_fk": {
+ "name": "sessions_user_id_users_id_fk",
+ "tableFrom": "sessions",
+ "tableTo": "users",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "sync_leases": {
+ "name": "sync_leases",
+ "columns": {
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "holder": {
+ "name": "holder",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "users": {
+ "name": "users",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "email": {
+ "name": "email",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "email_verified": {
+ "name": "email_verified",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "image": {
+ "name": "image",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(unixepoch() * 1000)"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(unixepoch() * 1000)"
+ }
+ },
+ "indexes": {
+ "users_email_unique": {
+ "name": "users_email_unique",
+ "columns": [
+ "email"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "verifications": {
+ "name": "verifications",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "identifier": {
+ "name": "identifier",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "value": {
+ "name": "value",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(unixepoch() * 1000)"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(unixepoch() * 1000)"
+ }
+ },
+ "indexes": {
+ "verifications_identifier_idx": {
+ "name": "verifications_identifier_idx",
+ "columns": [
+ "identifier"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "workspace_members": {
+ "name": "workspace_members",
+ "columns": {
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "role": {
+ "name": "role",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(unixepoch() * 1000)"
+ }
+ },
+ "indexes": {
+ "workspace_members_user_id_idx": {
+ "name": "workspace_members_user_id_idx",
+ "columns": [
+ "user_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "workspace_members_workspace_id_workspaces_id_fk": {
+ "name": "workspace_members_workspace_id_workspaces_id_fk",
+ "tableFrom": "workspace_members",
+ "tableTo": "workspaces",
+ "columnsFrom": [
+ "workspace_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "workspace_members_user_id_users_id_fk": {
+ "name": "workspace_members_user_id_users_id_fk",
+ "tableFrom": "workspace_members",
+ "tableTo": "users",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {
+ "workspace_members_workspace_id_user_id_pk": {
+ "columns": [
+ "workspace_id",
+ "user_id"
+ ],
+ "name": "workspace_members_workspace_id_user_id_pk"
+ }
+ },
+ "uniqueConstraints": {},
+ "checkConstraints": {
+ "workspace_members_role_ck": {
+ "name": "workspace_members_role_ck",
+ "value": "\"workspace_members\".\"role\" IN ('owner', 'admin', 'member', 'read_only')"
+ }
+ }
+ },
+ "workspaces": {
+ "name": "workspaces",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "account_id": {
+ "name": "account_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "read_only_can_comment": {
+ "name": "read_only_can_comment",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "show_drafts_to_read_only": {
+ "name": "show_drafts_to_read_only",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(unixepoch() * 1000)"
+ }
+ },
+ "indexes": {
+ "workspaces_account_id_idx": {
+ "name": "workspaces_account_id_idx",
+ "columns": [
+ "account_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "workspaces_account_id_accounts_id_fk": {
+ "name": "workspaces_account_id_accounts_id_fk",
+ "tableFrom": "workspaces",
+ "tableTo": "accounts",
+ "columnsFrom": [
+ "account_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ }
+ },
+ "views": {},
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "internal": {
+ "indexes": {}
+ }
+}
\ No newline at end of file
diff --git a/pnpm-lock 2.yaml b/pnpm-lock 2.yaml
new file mode 100644
index 0000000..fb156bc
--- /dev/null
+++ b/pnpm-lock 2.yaml
@@ -0,0 +1,167 @@
+---
+lockfileVersion: '9.0'
+
+importers:
+
+ .:
+ configDependencies: {}
+ packageManagerDependencies:
+ pnpm:
+ specifier: 12.11.2
+ version: 12.11.2
+
+packages:
+
+ '@pnpm/exe.android-arm64@12.11.2':
+ resolution: {integrity: sha512-owLw13OfPkEoY+hLBNeeG+dCFhywr7q2d/EHPz4mNL2RhKnv8gNwMARkjkiDQu234aItVwFNDeGnmQXm+ikkAg==}
+ cpu: [arm64]
+ os: [android]
+
+ '@pnpm/exe.android-x64@12.11.2':
+ resolution: {integrity: sha512-GYPkVebl4iokOA/4MPSpGoUVfFlsth7uqOCe1XiaiM23LAdvUOMJBObqHJijr89ZqjwHm9pO6vO45GRwJ2U2qA==}
+ cpu: [x64]
+ os: [android]
+
+ '@pnpm/exe.darwin-arm64@12.11.2':
+ resolution: {integrity: sha512-n9M4On66y8FDxUAKgMO1FXt0qihyG4e+56p3/F0uo8Bx9KplW8BwKVnXigzCJ8aNM6sVVPkOE6M9XXbeVIxnZA==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@pnpm/exe.darwin-x64@12.11.2':
+ resolution: {integrity: sha512-oSW7n3sBT0c0cyk4kj10T2Y6Mpm+OFEiCAWozgX039tdoI6yqJF1uaFD3sw7ugLdu6VV3+uY0pa1TUZIPdxDWA==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@pnpm/exe.freebsd-x64@12.11.2':
+ resolution: {integrity: sha512-qbzc3KoDpa/Lkf8vs3jnDe6dUUbso+6eLIyssYFMiliLpYNxn8dirk11YoNnOQcdHVB50v5RFls1Yid6ttT5pg==}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@pnpm/exe.linux-arm64-musl@12.11.2':
+ resolution: {integrity: sha512-uMEYDwKRktGwANubQ+kYCwmhNwg3Ik6qK89ahsbQ5cP30R/5FVJb/T99vr9XRUBC/A7mZI6eeT92oyVas9ACyg==}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@pnpm/exe.linux-arm64@12.11.2':
+ resolution: {integrity: sha512-6e8ZAQUwFXAWHHHv5FesWqf/kEK04wuitBv5f/gxzkC0DiBfaixr+f+6JQede8SF4Ji5LcMwVFJbzAtffpWxEg==}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@pnpm/exe.linux-ppc64@12.11.2':
+ resolution: {integrity: sha512-Ui8A4nepkVupx2VpuFfysEluMvWK6gTB5rgVts7Ss/+8dj0RD28x3F/seNeH/zSypgC6yKdV6qsKVQh/uffTuQ==}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [glibc]
+
+ '@pnpm/exe.linux-riscv64@12.11.2':
+ resolution: {integrity: sha512-i1yLdQ5bu+wjQ+srtFoJAaY2gN/+oXHFdjul4llCeoDxHE0rTIG3R41NhHfCjyFPW4+CpbBT58933CL9sMOCnA==}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [glibc]
+
+ '@pnpm/exe.linux-s390x@12.11.2':
+ resolution: {integrity: sha512-YS1/lhPjjTsN4QL50VaFZKRa3Uc/bDnhE8eKbJMFvuX06UuFS5YaiDg04APoZdfVSGqTfX27QAg7rfLMSWaqxA==}
+ cpu: [s390x]
+ os: [linux]
+ libc: [glibc]
+
+ '@pnpm/exe.linux-x64-musl@12.11.2':
+ resolution: {integrity: sha512-7eIxQR05fvJxCujUSKp5KTtehJ7QqrgqP/HD1+BcB/SaV2Be4XI1PEHiOgA1zxsiMIeMvTF6E4G4dYHrFjeXRg==}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@pnpm/exe.linux-x64@12.11.2':
+ resolution: {integrity: sha512-FK7QKe24AYgppJwO3mpooYptduuvIGqKJPi5ac7MdnWkjUy46JBfYhCW0grnkWKC8YOf0x+vGviuQqJEj3SpQQ==}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@pnpm/exe.win32-arm64@12.11.2':
+ resolution: {integrity: sha512-PCTjVDdJb6VvraZxrEeFv6EqEA0hhIsAySx28e95J2Tqpi88hLpgOXgNqV0vpxq9A+b8GLQfyk/D+1UlJPv/YQ==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@pnpm/exe.win32-x64@12.11.2':
+ resolution: {integrity: sha512-8sgX86OvRjJ3yZs/TvGR2L31wH9ScPZ+f+geKI3ikuB0RRiK3i4LlTRO8OXN6pdRqj8epMde4312MCjj7JsJdA==}
+ cpu: [x64]
+ os: [win32]
+
+ pnpm@12.11.2:
+ resolution: {integrity: sha512-JaUWUqGWeFr18ovabf6NxYLr76SsHRgCIc4TkCMcX7dmN4IupLbkYzznSs3LCnf3Ja8RutOBd/3t2u6BipVcuQ==}
+ engines: {node: '>=18.*'}
+ hasBin: true
+
+snapshots:
+
+ '@pnpm/exe.android-arm64@12.11.2':
+ optional: true
+
+ '@pnpm/exe.android-x64@12.11.2':
+ optional: true
+
+ '@pnpm/exe.darwin-arm64@12.11.2':
+ optional: true
+
+ '@pnpm/exe.darwin-x64@12.11.2':
+ optional: true
+
+ '@pnpm/exe.freebsd-x64@12.11.2':
+ optional: true
+
+ '@pnpm/exe.linux-arm64-musl@12.11.2':
+ optional: true
+
+ '@pnpm/exe.linux-arm64@12.11.2':
+ optional: true
+
+ '@pnpm/exe.linux-ppc64@12.11.2':
+ optional: true
+
+ '@pnpm/exe.linux-riscv64@12.11.2':
+ optional: true
+
+ '@pnpm/exe.linux-s390x@12.11.2':
+ optional: true
+
+ '@pnpm/exe.linux-x64-musl@12.11.2':
+ optional: true
+
+ '@pnpm/exe.linux-x64@12.11.2':
+ optional: true
+
+ '@pnpm/exe.win32-arm64@12.11.2':
+ optional: true
+
+ '@pnpm/exe.win32-x64@12.11.2':
+ optional: true
+
+ pnpm@12.11.2:
+ optionalDependencies:
+ '@pnpm/exe.android-arm64': 12.11.2
+ '@pnpm/exe.android-x64': 12.11.2
+ '@pnpm/exe.darwin-arm64': 12.11.2
+ '@pnpm/exe.darwin-x64': 12.11.2
+ '@pnpm/exe.freebsd-x64': 12.11.2
+ '@pnpm/exe.linux-arm64': 12.11.2
+ '@pnpm/exe.linux-arm64-musl': 12.11.2
+ '@pnpm/exe.linux-ppc64': 12.11.2
+ '@pnpm/exe.linux-riscv64': 12.11.2
+ '@pnpm/exe.linux-s390x': 12.11.2
+ '@pnpm/exe.linux-x64': 12.11.2
+ '@pnpm/exe.linux-x64-musl': 12.11.2
+ '@pnpm/exe.win32-arm64': 12.11.2
+ '@pnpm/exe.win32-x64': 12.11.2
+
+---
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .: {}
diff --git a/pnpm-workspace 2.yaml b/pnpm-workspace 2.yaml
new file mode 100644
index 0000000..df7cc6e
--- /dev/null
+++ b/pnpm-workspace 2.yaml
@@ -0,0 +1,9 @@
+packages:
+ - "apps/*"
+ - "packages/*"
+
+allowBuilds:
+ esbuild: true
+ workerd: true
+ sharp: false
+ unrs-resolver: false