diff --git a/bun.lock b/bun.lock
index af1979ece..6599b8420 100644
--- a/bun.lock
+++ b/bun.lock
@@ -12,7 +12,7 @@
},
"packages/app": {
"name": "@opencode/app",
- "version": "0.12.1",
+ "version": "0.13.2",
"dependencies": {
"@kobalte/core": "0.13.11",
"@opencode-ai/sdk": "workspace:*",
@@ -60,7 +60,7 @@
},
"packages/console/core": {
"name": "@opencode/console-core",
- "version": "0.12.1",
+ "version": "0.13.2",
"dependencies": {
"@aws-sdk/client-sts": "3.782.0",
"@opencode/console-resource": "workspace:*",
@@ -77,7 +77,7 @@
},
"packages/console/function": {
"name": "@opencode/console-function",
- "version": "0.12.1",
+ "version": "0.13.2",
"dependencies": {
"@ai-sdk/anthropic": "2.0.0",
"@ai-sdk/openai": "2.0.2",
@@ -103,7 +103,7 @@
},
"packages/console/scripts": {
"name": "@opencode/console-scripts",
- "version": "0.12.1",
+ "version": "0.13.2",
"dependencies": {
"@opencode/console-core": "workspace:*",
"tsx": "4.20.5",
@@ -115,7 +115,7 @@
},
"packages/function": {
"name": "@opencode/function",
- "version": "0.12.1",
+ "version": "0.13.2",
"dependencies": {
"@octokit/auth-app": "8.0.1",
"@octokit/rest": "22.0.0",
@@ -130,7 +130,7 @@
},
"packages/opencode": {
"name": "opencode",
- "version": "0.12.1",
+ "version": "0.13.2",
"bin": {
"opencode": "./bin/opencode",
},
@@ -189,7 +189,7 @@
},
"packages/plugin": {
"name": "@opencode-ai/plugin",
- "version": "0.12.1",
+ "version": "0.13.2",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"zod": "catalog:",
@@ -201,7 +201,7 @@
},
"packages/sdk/js": {
"name": "@opencode-ai/sdk",
- "version": "0.12.1",
+ "version": "0.13.2",
"dependencies": {
"@hey-api/openapi-ts": "0.82.5",
},
@@ -212,7 +212,7 @@
},
"packages/web": {
"name": "@opencode/web",
- "version": "0.12.1",
+ "version": "0.13.2",
"dependencies": {
"@astrojs/cloudflare": "12.6.3",
"@astrojs/markdown-remark": "6.3.1",
diff --git a/packages/app/package.json b/packages/app/package.json
index cb0c6ed98..ededee45d 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -1,6 +1,6 @@
{
"name": "@opencode/app",
- "version": "0.12.1",
+ "version": "0.13.2",
"description": "",
"type": "module",
"scripts": {
diff --git a/packages/console/app/package.json b/packages/console/app/package.json
index ce14bb6db..fd9d579e0 100644
--- a/packages/console/app/package.json
+++ b/packages/console/app/package.json
@@ -7,7 +7,7 @@
"dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev",
"build": "vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json",
"start": "vinxi start",
- "version": "0.12.1"
+ "version": "0.13.2"
},
"dependencies": {
"@ibm/plex": "6.4.1",
diff --git a/packages/console/app/src/routes/workspace/[id].tsx b/packages/console/app/src/routes/workspace/[id].tsx
index af8a0dd63..5257a8e97 100644
--- a/packages/console/app/src/routes/workspace/[id].tsx
+++ b/packages/console/app/src/routes/workspace/[id].tsx
@@ -1,12 +1,16 @@
import "./[id].css"
-import { MonthlyLimitSection } from "~/component/workspace/monthly-limit-section"
-import { NewUserSection } from "~/component/workspace/new-user-section"
-import { BillingSection } from "~/component/workspace/billing-section"
-import { PaymentSection } from "~/component/workspace/payment-section"
-import { UsageSection } from "~/component/workspace/usage-section"
-import { KeySection } from "~/component/workspace/key-section"
+import { MonthlyLimitSection } from "./monthly-limit-section"
+import { NewUserSection } from "./new-user-section"
+import { BillingSection } from "./billing-section"
+import { PaymentSection } from "./payment-section"
+import { UsageSection } from "./usage-section"
+import { KeySection } from "./key-section"
+import { MemberSection } from "./member-section"
+import { Show } from "solid-js"
+import { useParams } from "@solidjs/router"
export default function () {
+ const params = useParams()
return (
@@ -23,6 +27,9 @@ export default function () {
+
+
+
@@ -36,6 +43,6 @@ export function isBeta(workspaceID: string) {
return [
"wrk_01K46JDFR0E75SG2Q8K172KF3Y", // production
"wrk_01K4NFRR5P7FSYWH88307B4DDS", // dev
- "wrk_01K4PJRKJ2WPQZN3FFYRV4673F", // frank
+ "wrk_01K68M8J1KK0PJ39H59B1EGHP6", // frank
].includes(workspaceID)
}
diff --git a/packages/console/app/src/component/workspace/billing-section.module.css b/packages/console/app/src/routes/workspace/billing-section.module.css
similarity index 100%
rename from packages/console/app/src/component/workspace/billing-section.module.css
rename to packages/console/app/src/routes/workspace/billing-section.module.css
diff --git a/packages/console/app/src/component/workspace/billing-section.tsx b/packages/console/app/src/routes/workspace/billing-section.tsx
similarity index 100%
rename from packages/console/app/src/component/workspace/billing-section.tsx
rename to packages/console/app/src/routes/workspace/billing-section.tsx
diff --git a/packages/console/app/src/component/workspace/common.tsx b/packages/console/app/src/routes/workspace/common.tsx
similarity index 100%
rename from packages/console/app/src/component/workspace/common.tsx
rename to packages/console/app/src/routes/workspace/common.tsx
diff --git a/packages/console/app/src/component/workspace/key-section.module.css b/packages/console/app/src/routes/workspace/key-section.module.css
similarity index 100%
rename from packages/console/app/src/component/workspace/key-section.module.css
rename to packages/console/app/src/routes/workspace/key-section.module.css
diff --git a/packages/console/app/src/component/workspace/key-section.tsx b/packages/console/app/src/routes/workspace/key-section.tsx
similarity index 100%
rename from packages/console/app/src/component/workspace/key-section.tsx
rename to packages/console/app/src/routes/workspace/key-section.tsx
diff --git a/packages/console/app/src/routes/workspace/member-section.module.css b/packages/console/app/src/routes/workspace/member-section.module.css
new file mode 100644
index 000000000..16b6ff8d2
--- /dev/null
+++ b/packages/console/app/src/routes/workspace/member-section.module.css
@@ -0,0 +1,179 @@
+.root {
+ [data-component="empty-state"] {
+ padding: var(--space-20) var(--space-6);
+ text-align: center;
+ border: 1px dashed var(--color-border);
+ border-radius: var(--border-radius-sm);
+ display: flex;
+ flex-direction: column;
+ gap: var(--space-2);
+
+ p {
+ line-height: 1.5;
+ font-size: var(--font-size-sm);
+ color: var(--color-text-muted);
+ }
+ }
+
+ [data-slot="create-form"] {
+ display: flex;
+ flex-direction: column;
+ gap: var(--space-3);
+ padding: var(--space-4);
+ border: 1px solid var(--color-border);
+ border-radius: var(--border-radius-sm);
+
+ [data-slot="input-container"] {
+ display: flex;
+ flex-direction: column;
+ gap: var(--space-1);
+ }
+
+ @media (max-width: 30rem) {
+ gap: var(--space-2);
+ }
+
+ input {
+ flex: 1;
+ padding: var(--space-2) var(--space-3);
+ border: 1px solid var(--color-border);
+ border-radius: var(--border-radius-sm);
+ background-color: var(--color-bg);
+ color: var(--color-text);
+ font-size: var(--font-size-sm);
+ font-family: var(--font-mono);
+
+ &:focus {
+ outline: none;
+ border-color: var(--color-accent);
+ }
+
+ &::placeholder {
+ color: var(--color-text-disabled);
+ }
+ }
+
+ [data-slot="form-actions"] {
+ display: flex;
+ gap: var(--space-2);
+ }
+
+ [data-slot="form-error"] {
+ color: var(--color-danger);
+ font-size: var(--font-size-sm);
+ margin-top: var(--space-1);
+ line-height: 1.4;
+ }
+ }
+
+ [data-slot="members-table"] {
+ overflow-x: auto;
+ }
+
+ [data-slot="members-table-element"] {
+ width: 100%;
+ border-collapse: collapse;
+ font-size: var(--font-size-sm);
+
+ thead {
+ border-bottom: 1px solid var(--color-border);
+ }
+
+ th {
+ padding: var(--space-3) var(--space-4);
+ text-align: left;
+ font-weight: normal;
+ color: var(--color-text-muted);
+ text-transform: uppercase;
+ }
+
+ td {
+ padding: var(--space-3) var(--space-4);
+ border-bottom: 1px solid var(--color-border-muted);
+ color: var(--color-text-muted);
+ font-family: var(--font-mono);
+
+ &[data-slot="member-email"] {
+ color: var(--color-text);
+ font-family: var(--font-sans);
+ font-weight: 500;
+ }
+
+ &[data-slot="member-role"] {
+ font-family: var(--font-mono);
+
+ button {
+ display: flex;
+ align-items: center;
+ gap: var(--space-2);
+ padding: var(--space-2) var(--space-3);
+ font-size: var(--font-size-sm);
+ font-weight: 400;
+ border: none;
+ background-color: transparent;
+ color: var(--color-text-muted);
+ font-family: var(--font-mono);
+ border-radius: var(--border-radius-sm);
+ cursor: pointer;
+ transition: all 0.15s ease;
+ text-transform: none;
+
+ &:hover:not(:disabled) {
+ background-color: var(--color-bg-surface);
+ color: var(--color-text);
+ }
+
+ &:disabled {
+ cursor: default;
+ color: var(--color-text);
+ }
+
+ span {
+ font-family: inherit;
+ }
+ }
+ }
+
+ &[data-slot="member-date"] {
+ color: var(--color-text);
+ }
+
+ &[data-slot="member-actions"] {
+ font-family: var(--font-sans);
+ }
+ }
+
+ tbody tr {
+ &:last-child td {
+ border-bottom: none;
+ }
+ }
+
+ @media (max-width: 40rem) {
+
+ th,
+ td {
+ padding: var(--space-2) var(--space-3);
+ font-size: var(--font-size-xs);
+ }
+
+ th {
+ &:nth-child(3)
+
+ /* Date */
+ {
+ display: none;
+ }
+ }
+
+ td {
+ &:nth-child(3)
+
+ /* Date */
+ {
+ display: none;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/console/app/src/routes/workspace/member-section.tsx b/packages/console/app/src/routes/workspace/member-section.tsx
new file mode 100644
index 000000000..602c29efc
--- /dev/null
+++ b/packages/console/app/src/routes/workspace/member-section.tsx
@@ -0,0 +1,189 @@
+import { json, query, action, useParams, createAsync, useSubmission } from "@solidjs/router"
+import { createEffect, createSignal, For, Show } from "solid-js"
+import { withActor } from "~/context/auth.withActor"
+import { createStore } from "solid-js/store"
+import { formatDateUTC, formatDateForTable } from "./common"
+import styles from "./member-section.module.css"
+import { and, Database, eq, sql } from "@opencode/console-core/drizzle/index.js"
+import { UserTable } from "@opencode/console-core/schema/user.sql.js"
+import { Identifier } from "@opencode/console-core/identifier.js"
+
+const removeMember = action(async (form: FormData) => {
+ "use server"
+ const id = form.get("id")?.toString()
+ if (!id) return { error: "ID is required" }
+ const workspaceID = form.get("workspaceID")?.toString()
+ if (!workspaceID) return { error: "Workspace ID is required" }
+ return json(
+ await withActor(
+ () =>
+ Database.use((tx) =>
+ tx
+ .update(UserTable)
+ .set({ timeDeleted: sql`now()` })
+ .where(and(eq(UserTable.id, id), eq(UserTable.workspaceID, workspaceID))),
+ ),
+ workspaceID,
+ ),
+ { revalidate: listMembers.key },
+ )
+}, "member.remove")
+
+const inviteMember = action(async (form: FormData) => {
+ "use server"
+ const name = form.get("name")?.toString().trim()
+ if (!name) return { error: "Name is required" }
+ const workspaceID = form.get("workspaceID")?.toString()
+ if (!workspaceID) return { error: "Workspace ID is required" }
+ return json(
+ await withActor(
+ () =>
+ Database.use((tx) =>
+ tx
+ .insert(UserTable)
+ .values({
+ id: Identifier.create("user"),
+ name: "",
+ email: name,
+ workspaceID,
+ role: "member",
+ timeJoined: sql`now()`,
+ })
+ .onDuplicateKeyUpdate({ set: { timeJoined: sql`now()` } })
+ .then((data) => ({ error: undefined, data }))
+ .catch((e) => ({ error: e.message as string })),
+ ),
+ workspaceID,
+ ),
+ { revalidate: listMembers.key },
+ )
+}, "member.create")
+
+const listMembers = query(async (workspaceID: string) => {
+ "use server"
+ return withActor(
+ () => Database.use((tx) => tx.select().from(UserTable).where(eq(UserTable.workspaceID, workspaceID))),
+ workspaceID,
+ )
+}, "member.list")
+
+export function MemberCreateForm() {
+ const params = useParams()
+ const submission = useSubmission(inviteMember)
+ const [store, setStore] = createStore({ show: false })
+
+ let input: HTMLInputElement
+
+ createEffect(() => {
+ if (!submission.pending && submission.result && !submission.result.error) {
+ hide()
+ }
+ })
+
+ function show() {
+ // submission.clear() does not clear the result in some cases, ie.
+ // 1. Create key with empty name => error shows
+ // 2. Put in a key name and creates the key => form hides
+ // 3. Click add key button again => form shows with the same error if
+ // submission.clear() is called only once
+ while (true) {
+ submission.clear()
+ if (!submission.result) break
+ }
+ setStore("show", true)
+ input.focus()
+ }
+
+ function hide() {
+ setStore("show", false)
+ }
+
+ return (
+
show()}>
+ Invite Member
+
+ }
+ >
+
+
+ )
+}
+
+export function MemberSection() {
+ const params = useParams()
+ const members = createAsync(() => listMembers(params.id))
+
+ return (
+
+
+
Members
+
Manage your members for accessing opencode services.
+
+
+
+
+ Invite a member to your workspace
+
+ }
+ >
+
+
+
+ | Email |
+ Role |
+ Joined |
+ |
+
+
+
+
+ {(member) => {
+ const [copied, setCopied] = createSignal(false)
+ // const submission = useSubmission(removeKey, ([fd]) => fd.get("id")?.toString() === key.id)
+ return (
+
+ | {member.email} |
+ {member.role} |
+
+ {formatDateForTable(member.timeJoined!)}
+ |
+
+
+ |
+
+ )
+ }}
+
+
+
+
+
+
+ )
+}
diff --git a/packages/console/app/src/component/workspace/monthly-limit-section.module.css b/packages/console/app/src/routes/workspace/monthly-limit-section.module.css
similarity index 100%
rename from packages/console/app/src/component/workspace/monthly-limit-section.module.css
rename to packages/console/app/src/routes/workspace/monthly-limit-section.module.css
diff --git a/packages/console/app/src/component/workspace/monthly-limit-section.tsx b/packages/console/app/src/routes/workspace/monthly-limit-section.tsx
similarity index 100%
rename from packages/console/app/src/component/workspace/monthly-limit-section.tsx
rename to packages/console/app/src/routes/workspace/monthly-limit-section.tsx
diff --git a/packages/console/app/src/component/workspace/new-user-section.module.css b/packages/console/app/src/routes/workspace/new-user-section.module.css
similarity index 100%
rename from packages/console/app/src/component/workspace/new-user-section.module.css
rename to packages/console/app/src/routes/workspace/new-user-section.module.css
diff --git a/packages/console/app/src/component/workspace/new-user-section.tsx b/packages/console/app/src/routes/workspace/new-user-section.tsx
similarity index 100%
rename from packages/console/app/src/component/workspace/new-user-section.tsx
rename to packages/console/app/src/routes/workspace/new-user-section.tsx
diff --git a/packages/console/app/src/component/workspace/payment-section.module.css b/packages/console/app/src/routes/workspace/payment-section.module.css
similarity index 100%
rename from packages/console/app/src/component/workspace/payment-section.module.css
rename to packages/console/app/src/routes/workspace/payment-section.module.css
diff --git a/packages/console/app/src/component/workspace/payment-section.tsx b/packages/console/app/src/routes/workspace/payment-section.tsx
similarity index 100%
rename from packages/console/app/src/component/workspace/payment-section.tsx
rename to packages/console/app/src/routes/workspace/payment-section.tsx
diff --git a/packages/console/app/src/component/workspace/usage-section.module.css b/packages/console/app/src/routes/workspace/usage-section.module.css
similarity index 100%
rename from packages/console/app/src/component/workspace/usage-section.module.css
rename to packages/console/app/src/routes/workspace/usage-section.module.css
diff --git a/packages/console/app/src/component/workspace/usage-section.tsx b/packages/console/app/src/routes/workspace/usage-section.tsx
similarity index 100%
rename from packages/console/app/src/component/workspace/usage-section.tsx
rename to packages/console/app/src/routes/workspace/usage-section.tsx
diff --git a/packages/console/core/migrations/0019_dazzling_cable.sql b/packages/console/core/migrations/0019_dazzling_cable.sql
new file mode 100644
index 000000000..ab0a22238
--- /dev/null
+++ b/packages/console/core/migrations/0019_dazzling_cable.sql
@@ -0,0 +1 @@
+ALTER TABLE `user` MODIFY COLUMN `role` enum('admin','member') NOT NULL;
\ No newline at end of file
diff --git a/packages/console/core/migrations/meta/0019_snapshot.json b/packages/console/core/migrations/meta/0019_snapshot.json
new file mode 100644
index 000000000..8f1afeb51
--- /dev/null
+++ b/packages/console/core/migrations/meta/0019_snapshot.json
@@ -0,0 +1,702 @@
+{
+ "version": "5",
+ "dialect": "mysql",
+ "id": "a2bb7222-561c-45f0-8939-8ef9b8e57bb3",
+ "prevId": "e9c91c2d-787d-4234-b98d-1620e4ce80e1",
+ "tables": {
+ "account": {
+ "name": "account",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "varchar(30)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "time_created": {
+ "name": "time_created",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(now())"
+ },
+ "time_updated": {
+ "name": "time_updated",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+ },
+ "time_deleted": {
+ "name": "time_deleted",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "email": {
+ "name": "email",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "email": {
+ "name": "email",
+ "columns": [
+ "email"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraint": {}
+ },
+ "billing": {
+ "name": "billing",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "varchar(30)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "varchar(30)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "time_created": {
+ "name": "time_created",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(now())"
+ },
+ "time_updated": {
+ "name": "time_updated",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+ },
+ "time_deleted": {
+ "name": "time_deleted",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "customer_id": {
+ "name": "customer_id",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payment_method_id": {
+ "name": "payment_method_id",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payment_method_last4": {
+ "name": "payment_method_last4",
+ "type": "varchar(4)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "balance": {
+ "name": "balance",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "monthly_limit": {
+ "name": "monthly_limit",
+ "type": "int",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "monthly_usage": {
+ "name": "monthly_usage",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "time_monthly_usage_updated": {
+ "name": "time_monthly_usage_updated",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "reload": {
+ "name": "reload",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "reload_error": {
+ "name": "reload_error",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "time_reload_error": {
+ "name": "time_reload_error",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "time_reload_locked_till": {
+ "name": "time_reload_locked_till",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "global_customer_id": {
+ "name": "global_customer_id",
+ "columns": [
+ "customer_id"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {
+ "billing_workspace_id_id_pk": {
+ "name": "billing_workspace_id_id_pk",
+ "columns": [
+ "workspace_id",
+ "id"
+ ]
+ }
+ },
+ "uniqueConstraints": {},
+ "checkConstraint": {}
+ },
+ "payment": {
+ "name": "payment",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "varchar(30)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "varchar(30)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "time_created": {
+ "name": "time_created",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(now())"
+ },
+ "time_updated": {
+ "name": "time_updated",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+ },
+ "time_deleted": {
+ "name": "time_deleted",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "customer_id": {
+ "name": "customer_id",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "invoice_id": {
+ "name": "invoice_id",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "payment_id": {
+ "name": "payment_id",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "amount": {
+ "name": "amount",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "time_refunded": {
+ "name": "time_refunded",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {
+ "payment_workspace_id_id_pk": {
+ "name": "payment_workspace_id_id_pk",
+ "columns": [
+ "workspace_id",
+ "id"
+ ]
+ }
+ },
+ "uniqueConstraints": {},
+ "checkConstraint": {}
+ },
+ "usage": {
+ "name": "usage",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "varchar(30)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "varchar(30)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "time_created": {
+ "name": "time_created",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(now())"
+ },
+ "time_updated": {
+ "name": "time_updated",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+ },
+ "time_deleted": {
+ "name": "time_deleted",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "model": {
+ "name": "model",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "provider": {
+ "name": "provider",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "input_tokens": {
+ "name": "input_tokens",
+ "type": "int",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "output_tokens": {
+ "name": "output_tokens",
+ "type": "int",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "reasoning_tokens": {
+ "name": "reasoning_tokens",
+ "type": "int",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "cache_read_tokens": {
+ "name": "cache_read_tokens",
+ "type": "int",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "cache_write_5m_tokens": {
+ "name": "cache_write_5m_tokens",
+ "type": "int",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "cache_write_1h_tokens": {
+ "name": "cache_write_1h_tokens",
+ "type": "int",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "cost": {
+ "name": "cost",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {
+ "usage_workspace_id_id_pk": {
+ "name": "usage_workspace_id_id_pk",
+ "columns": [
+ "workspace_id",
+ "id"
+ ]
+ }
+ },
+ "uniqueConstraints": {},
+ "checkConstraint": {}
+ },
+ "key": {
+ "name": "key",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "varchar(30)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "varchar(30)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "time_created": {
+ "name": "time_created",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(now())"
+ },
+ "time_updated": {
+ "name": "time_updated",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+ },
+ "time_deleted": {
+ "name": "time_deleted",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "actor": {
+ "name": "actor",
+ "type": "json",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "old_name": {
+ "name": "old_name",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "key": {
+ "name": "key",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "time_used": {
+ "name": "time_used",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "global_key": {
+ "name": "global_key",
+ "columns": [
+ "key"
+ ],
+ "isUnique": true
+ },
+ "name": {
+ "name": "name",
+ "columns": [
+ "workspace_id",
+ "name"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {
+ "key_workspace_id_id_pk": {
+ "name": "key_workspace_id_id_pk",
+ "columns": [
+ "workspace_id",
+ "id"
+ ]
+ }
+ },
+ "uniqueConstraints": {},
+ "checkConstraint": {}
+ },
+ "user": {
+ "name": "user",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "varchar(30)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "varchar(30)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "time_created": {
+ "name": "time_created",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(now())"
+ },
+ "time_updated": {
+ "name": "time_updated",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+ },
+ "time_deleted": {
+ "name": "time_deleted",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "email": {
+ "name": "email",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "time_seen": {
+ "name": "time_seen",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "time_joined": {
+ "name": "time_joined",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "color": {
+ "name": "color",
+ "type": "int",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "role": {
+ "name": "role",
+ "type": "enum('admin','member')",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "user_email": {
+ "name": "user_email",
+ "columns": [
+ "workspace_id",
+ "email"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {
+ "user_workspace_id_id_pk": {
+ "name": "user_workspace_id_id_pk",
+ "columns": [
+ "workspace_id",
+ "id"
+ ]
+ }
+ },
+ "uniqueConstraints": {},
+ "checkConstraint": {}
+ },
+ "workspace": {
+ "name": "workspace",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "varchar(30)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "slug": {
+ "name": "slug",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "time_created": {
+ "name": "time_created",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(now())"
+ },
+ "time_updated": {
+ "name": "time_updated",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+ },
+ "time_deleted": {
+ "name": "time_deleted",
+ "type": "timestamp(3)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "slug": {
+ "name": "slug",
+ "columns": [
+ "slug"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {
+ "workspace_id": {
+ "name": "workspace_id",
+ "columns": [
+ "id"
+ ]
+ }
+ },
+ "uniqueConstraints": {},
+ "checkConstraint": {}
+ }
+ },
+ "views": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "internal": {
+ "tables": {},
+ "indexes": {}
+ }
+}
\ No newline at end of file
diff --git a/packages/console/core/migrations/meta/_journal.json b/packages/console/core/migrations/meta/_journal.json
index 06fe047fd..d19c9a11a 100644
--- a/packages/console/core/migrations/meta/_journal.json
+++ b/packages/console/core/migrations/meta/_journal.json
@@ -134,6 +134,13 @@
"when": 1759077265040,
"tag": "0018_nervous_iron_lad",
"breakpoints": true
+ },
+ {
+ "idx": 19,
+ "version": "5",
+ "when": 1759103696975,
+ "tag": "0019_dazzling_cable",
+ "breakpoints": true
}
]
}
\ No newline at end of file
diff --git a/packages/console/core/package.json b/packages/console/core/package.json
index 92b25b3ab..a87c74bd2 100644
--- a/packages/console/core/package.json
+++ b/packages/console/core/package.json
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode/console-core",
- "version": "0.12.1",
+ "version": "0.13.2",
"private": true,
"type": "module",
"dependencies": {
diff --git a/packages/console/core/src/schema/user.sql.ts b/packages/console/core/src/schema/user.sql.ts
index 7f051a614..0c2bba947 100644
--- a/packages/console/core/src/schema/user.sql.ts
+++ b/packages/console/core/src/schema/user.sql.ts
@@ -15,7 +15,7 @@ export const UserTable = mysqlTable(
timeSeen: utc("time_seen"),
timeJoined: utc("time_joined"),
color: int("color"),
- role: mysqlEnum("role", ["admin", "member"]),
+ role: mysqlEnum("role", ["admin", "member"]).notNull(),
},
(table) => [...workspaceIndexes(table), uniqueIndex("user_email").on(table.workspaceID, table.email)],
)
diff --git a/packages/console/function/package.json b/packages/console/function/package.json
index 067adb19e..6fa31a936 100644
--- a/packages/console/function/package.json
+++ b/packages/console/function/package.json
@@ -1,6 +1,6 @@
{
"name": "@opencode/console-function",
- "version": "0.12.1",
+ "version": "0.13.2",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
diff --git a/packages/console/scripts/package.json b/packages/console/scripts/package.json
index ac772e4eb..e02ed041f 100644
--- a/packages/console/scripts/package.json
+++ b/packages/console/scripts/package.json
@@ -1,6 +1,6 @@
{
"name": "@opencode/console-scripts",
- "version": "0.12.1",
+ "version": "0.13.2",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
diff --git a/packages/console/scripts/src/reset.ts b/packages/console/scripts/src/reset.ts
new file mode 100644
index 000000000..c84bd6936
--- /dev/null
+++ b/packages/console/scripts/src/reset.ts
@@ -0,0 +1,13 @@
+import { Resource } from "@opencode/console-resource"
+import { Database } from "@opencode/console-core/drizzle/index.js"
+import { UserTable } from "@opencode/console-core/schema/user.sql.js"
+import { AccountTable } from "@opencode/console-core/schema/account.sql.js"
+import { WorkspaceTable } from "@opencode/console-core/schema/workspace.sql.js"
+import { BillingTable, PaymentTable, UsageTable } from "@opencode/console-core/schema/billing.sql.js"
+import { KeyTable } from "@opencode/console-core/schema/key.sql.js"
+
+if (Resource.App.stage !== "frank") throw new Error("This script is only for frank")
+
+for (const table of [AccountTable, BillingTable, KeyTable, PaymentTable, UsageTable, UserTable, WorkspaceTable]) {
+ await Database.use((tx) => tx.delete(table))
+}
diff --git a/packages/function/package.json b/packages/function/package.json
index bdca452c7..4f09e6be3 100644
--- a/packages/function/package.json
+++ b/packages/function/package.json
@@ -1,6 +1,6 @@
{
"name": "@opencode/function",
- "version": "0.12.1",
+ "version": "0.13.2",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
diff --git a/packages/opencode/package.json b/packages/opencode/package.json
index 802f56a54..436528062 100644
--- a/packages/opencode/package.json
+++ b/packages/opencode/package.json
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
- "version": "0.12.1",
+ "version": "0.13.2",
"name": "opencode",
"type": "module",
"private": true,
diff --git a/packages/plugin/package.json b/packages/plugin/package.json
index 1fad1726a..1774ae882 100644
--- a/packages/plugin/package.json
+++ b/packages/plugin/package.json
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/plugin",
- "version": "0.12.1",
+ "version": "0.13.2",
"type": "module",
"scripts": {
"typecheck": "tsc --noEmit",
@@ -22,4 +22,4 @@
"@tsconfig/node22": "catalog:",
"typescript": "catalog:"
}
-}
+}
\ No newline at end of file
diff --git a/packages/plugin/script/publish.ts b/packages/plugin/script/publish.ts
old mode 100644
new mode 100755
index 37bd0a7d5..e0bdd98f2
--- a/packages/plugin/script/publish.ts
+++ b/packages/plugin/script/publish.ts
@@ -8,22 +8,22 @@ import { $ } from "bun"
await $`bun tsc`
const pkg = await import("../package.json").then((m) => m.default)
-// @ts-expect-error
-delete pkg.devDependencies
+const original = JSON.parse(JSON.stringify(pkg))
for (const [key, value] of Object.entries(pkg.exports)) {
- const file = value.replace("./src/", "./").replace(".ts", "")
+ const file = value.replace("./src/", "./dist/").replace(".ts", "")
pkg.exports[key] = {
import: file + ".js",
types: file + ".d.ts",
}
}
-await Bun.write("./dist/package.json", JSON.stringify(pkg, null, 2))
+await Bun.write("package.json", JSON.stringify(pkg, null, 2))
const snapshot = process.env["OPENCODE_SNAPSHOT"] === "true"
if (snapshot) {
- await $`bun publish --tag snapshot --access public`.cwd("./dist")
+ await $`bun publish --tag snapshot --access public`
}
if (!snapshot) {
- await $`bun publish --access public`.cwd("./dist")
+ await $`bun publish --access public`
}
+await Bun.write("package.json", JSON.stringify(original, null, 2))
diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json
index 23d9f0037..bf4a7b38f 100644
--- a/packages/sdk/js/package.json
+++ b/packages/sdk/js/package.json
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/sdk",
- "version": "0.12.1",
+ "version": "0.13.2",
"type": "module",
"scripts": {
"typecheck": "tsc --noEmit",
@@ -22,4 +22,4 @@
"dependencies": {
"@hey-api/openapi-ts": "0.82.5"
}
-}
+}
\ No newline at end of file
diff --git a/packages/sdk/js/script/publish.ts b/packages/sdk/js/script/publish.ts
index ffc044b62..8c403df47 100755
--- a/packages/sdk/js/script/publish.ts
+++ b/packages/sdk/js/script/publish.ts
@@ -8,21 +8,23 @@ import { $ } from "bun"
await import("./build")
const pkg = await import("../package.json").then((m) => m.default)
-// @ts-expect-error
-delete pkg["devDependencies"]
+const original = JSON.parse(JSON.stringify(pkg))
for (const [key, value] of Object.entries(pkg.exports)) {
- const file = value.replace("./src/", "./").replace(".ts", "")
+ const file = value.replace("./src/", "./dist/").replace(".ts", "")
+ /// @ts-expect-error
pkg.exports[key] = {
import: file + ".js",
types: file + ".d.ts",
}
}
-await Bun.write("./dist/package.json", JSON.stringify(pkg, null, 2))
+await Bun.write("package.json", JSON.stringify(pkg, null, 2))
+
const snapshot = process.env["OPENCODE_SNAPSHOT"] === "true"
if (snapshot) {
- await $`bun publish --tag snapshot`.cwd("./dist")
+ await $`bun publish --tag snapshot --access public`
}
if (!snapshot) {
- await $`bun publish`.cwd("./dist")
+ await $`bun publish --access public`
}
+await Bun.write("package.json", JSON.stringify(original, null, 2))
diff --git a/packages/tui/go.mod b/packages/tui/go.mod
index 6dff3e7eb..6ee7c1b76 100644
--- a/packages/tui/go.mod
+++ b/packages/tui/go.mod
@@ -86,7 +86,7 @@ require (
github.com/yuin/goldmark v1.7.8 // indirect
github.com/yuin/goldmark-emoji v1.0.5 // indirect
golang.org/x/net v0.41.0 // indirect
- golang.org/x/sync v0.15.0 // indirect
+ golang.org/x/sync v0.15.0
golang.org/x/sys v0.33.0 // indirect
golang.org/x/term v0.32.0 // indirect
golang.org/x/text v0.26.0
diff --git a/packages/web/package.json b/packages/web/package.json
index cf9d9cbf7..1608bff2f 100644
--- a/packages/web/package.json
+++ b/packages/web/package.json
@@ -1,7 +1,7 @@
{
"name": "@opencode/web",
"type": "module",
- "version": "0.12.1",
+ "version": "0.13.2",
"scripts": {
"dev": "astro dev",
"dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev",
diff --git a/script/publish.ts b/script/publish.ts
index 53ad3583f..d02aa2757 100755
--- a/script/publish.ts
+++ b/script/publish.ts
@@ -11,6 +11,7 @@ console.log("=== publishing ===\n")
const snapshot = process.env["OPENCODE_SNAPSHOT"] === "true"
const version = await (async () => {
if (snapshot) return `0.0.0-${new Date().toISOString().slice(0, 16).replace(/[-:T]/g, "")}`
+ if (process.env["OPENCODE_VERSION"]) return process.env["OPENCODE_VERSION"]
const [major, minor, patch] = (await $`gh release list --limit 1 --json tagName --jq '.[0].tagName'`.text())
.trim()
.replace(/^v/, "")
diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json
index c7c393085..4835d9f52 100644
--- a/sdks/vscode/package.json
+++ b/sdks/vscode/package.json
@@ -2,7 +2,7 @@
"name": "opencode",
"displayName": "opencode",
"description": "opencode for VS Code",
- "version": "0.12.1",
+ "version": "0.13.2",
"publisher": "sst-dev",
"repository": {
"type": "git",