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 + + } + > +
+
+ (input = r)} data-component="input" name="name" type="text" placeholder="Enter email" /> + + {(err) =>
{err()}
} +
+
+ +
+ + +
+
+
+ ) +} + +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

+
+ } + > + + + + + + + + + + + + {(member) => { + const [copied, setCopied] = createSignal(false) + // const submission = useSubmission(removeKey, ([fd]) => fd.get("id")?.toString() === key.id) + return ( + + + + + + + ) + }} + + +
EmailRoleJoined
{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",