mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-16 01:19:19 -04:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| df7e2fe63a |
@@ -594,6 +594,7 @@ OPENCODE_DISABLE_CLAUDE_CODE
|
|||||||
OPENCODE_DISABLE_CLAUDE_CODE_PROMPT
|
OPENCODE_DISABLE_CLAUDE_CODE_PROMPT
|
||||||
OPENCODE_DISABLE_CLAUDE_CODE_SKILLS
|
OPENCODE_DISABLE_CLAUDE_CODE_SKILLS
|
||||||
OPENCODE_DISABLE_DEFAULT_PLUGINS
|
OPENCODE_DISABLE_DEFAULT_PLUGINS
|
||||||
|
OPENCODE_DISABLE_FILETIME_CHECK
|
||||||
OPENCODE_DISABLE_LSP_DOWNLOAD
|
OPENCODE_DISABLE_LSP_DOWNLOAD
|
||||||
OPENCODE_DISABLE_MODELS_FETCH
|
OPENCODE_DISABLE_MODELS_FETCH
|
||||||
OPENCODE_DISABLE_PRUNE
|
OPENCODE_DISABLE_PRUNE
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://opencode.ai/config.json",
|
"$schema": "https://opencode.ai/config.json",
|
||||||
"provider": {},
|
"provider": {
|
||||||
|
"opencode": {
|
||||||
|
"options": {},
|
||||||
|
},
|
||||||
|
},
|
||||||
"permission": {
|
"permission": {
|
||||||
"edit": {
|
"edit": {
|
||||||
"packages/opencode/migration/*": "deny",
|
"packages/opencode/migration/*": "deny",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ async function githubFetch(endpoint: string, options: RequestInit = {}) {
|
|||||||
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
|
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
|
||||||
Accept: "application/vnd.github+json",
|
Accept: "application/vnd.github+json",
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
...(options.headers instanceof Headers ? Object.fromEntries(options.headers.entries()) : options.headers),
|
...options.headers,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ async function githubFetch(endpoint: string, options: RequestInit = {}) {
|
|||||||
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
|
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
|
||||||
Accept: "application/vnd.github+json",
|
Accept: "application/vnd.github+json",
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
...(options.headers instanceof Headers ? Object.fromEntries(options.headers.entries()) : options.headers),
|
...options.headers,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
|||||||
+2
-11
@@ -1,13 +1,9 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://raw.githubusercontent.com/nicolo-ribaudo/oxc-project.github.io/refs/heads/json-schema/src/public/.oxlintrc.schema.json",
|
"$schema": "https://raw.githubusercontent.com/nicolo-ribaudo/oxc-project.github.io/refs/heads/json-schema/src/public/.oxlintrc.schema.json",
|
||||||
"options": {
|
|
||||||
"typeAware": true
|
|
||||||
},
|
|
||||||
"categories": {
|
"categories": {
|
||||||
"suspicious": "warn"
|
"suspicious": "warn"
|
||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
"typescript/no-base-to-string": "warn",
|
|
||||||
// Effect uses `function*` with Effect.gen/Effect.fnUntraced that don't always yield
|
// Effect uses `function*` with Effect.gen/Effect.fnUntraced that don't always yield
|
||||||
"require-yield": "off",
|
"require-yield": "off",
|
||||||
// SolidJS uses `let ref: T | undefined` for JSX ref bindings assigned at runtime
|
// SolidJS uses `let ref: T | undefined` for JSX ref bindings assigned at runtime
|
||||||
@@ -37,15 +33,10 @@
|
|||||||
"no-new": "off",
|
"no-new": "off",
|
||||||
|
|
||||||
// Type-aware: catch unhandled promises
|
// Type-aware: catch unhandled promises
|
||||||
"typescript/no-floating-promises": "warn",
|
"typescript/no-floating-promises": "warn"
|
||||||
// Warn when spreading non-plain objects (Headers, class instances, etc.)
|
|
||||||
"typescript/no-misused-spread": "warn"
|
|
||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"typeAware": true
|
"typeAware": true
|
||||||
},
|
},
|
||||||
"options": {
|
"ignorePatterns": ["**/node_modules", "**/dist", "**/.build", "**/.sst", "**/*.d.ts"]
|
||||||
"typeAware": true
|
|
||||||
},
|
|
||||||
"ignorePatterns": ["**/node_modules", "**/dist", "**/.build", "**/.sst", "**/*.d.ts", "**/sdk.gen.ts"]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
- Use Bun APIs when possible, like `Bun.file()`
|
- Use Bun APIs when possible, like `Bun.file()`
|
||||||
- Rely on type inference when possible; avoid explicit type annotations or interfaces unless necessary for exports or clarity
|
- Rely on type inference when possible; avoid explicit type annotations or interfaces unless necessary for exports or clarity
|
||||||
- Prefer functional array methods (flatMap, filter, map) over for loops; use type guards on filter to maintain type inference downstream
|
- Prefer functional array methods (flatMap, filter, map) over for loops; use type guards on filter to maintain type inference downstream
|
||||||
- In `src/config`, follow the existing self-export pattern at the top of the file (for example `export * as ConfigAgent from "./agent"`) when adding a new config module.
|
|
||||||
|
|
||||||
Reduce total variable count by inlining when a value is only used once.
|
Reduce total variable count by inlining when a value is only used once.
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
},
|
},
|
||||||
"packages/app": {
|
"packages/app": {
|
||||||
"name": "@opencode-ai/app",
|
"name": "@opencode-ai/app",
|
||||||
"version": "1.14.18",
|
"version": "1.4.6",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kobalte/core": "catalog:",
|
"@kobalte/core": "catalog:",
|
||||||
"@opencode-ai/sdk": "workspace:*",
|
"@opencode-ai/sdk": "workspace:*",
|
||||||
@@ -83,7 +83,7 @@
|
|||||||
},
|
},
|
||||||
"packages/console/app": {
|
"packages/console/app": {
|
||||||
"name": "@opencode-ai/console-app",
|
"name": "@opencode-ai/console-app",
|
||||||
"version": "1.14.18",
|
"version": "1.4.6",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cloudflare/vite-plugin": "1.15.2",
|
"@cloudflare/vite-plugin": "1.15.2",
|
||||||
"@ibm/plex": "6.4.1",
|
"@ibm/plex": "6.4.1",
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
},
|
},
|
||||||
"packages/console/core": {
|
"packages/console/core": {
|
||||||
"name": "@opencode-ai/console-core",
|
"name": "@opencode-ai/console-core",
|
||||||
"version": "1.14.18",
|
"version": "1.4.6",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-sts": "3.782.0",
|
"@aws-sdk/client-sts": "3.782.0",
|
||||||
"@jsx-email/render": "1.1.1",
|
"@jsx-email/render": "1.1.1",
|
||||||
@@ -144,7 +144,7 @@
|
|||||||
},
|
},
|
||||||
"packages/console/function": {
|
"packages/console/function": {
|
||||||
"name": "@opencode-ai/console-function",
|
"name": "@opencode-ai/console-function",
|
||||||
"version": "1.14.18",
|
"version": "1.4.6",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ai-sdk/anthropic": "3.0.64",
|
"@ai-sdk/anthropic": "3.0.64",
|
||||||
"@ai-sdk/openai": "3.0.48",
|
"@ai-sdk/openai": "3.0.48",
|
||||||
@@ -168,7 +168,7 @@
|
|||||||
},
|
},
|
||||||
"packages/console/mail": {
|
"packages/console/mail": {
|
||||||
"name": "@opencode-ai/console-mail",
|
"name": "@opencode-ai/console-mail",
|
||||||
"version": "1.14.18",
|
"version": "1.4.6",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jsx-email/all": "2.2.3",
|
"@jsx-email/all": "2.2.3",
|
||||||
"@jsx-email/cli": "1.4.3",
|
"@jsx-email/cli": "1.4.3",
|
||||||
@@ -190,35 +190,9 @@
|
|||||||
"cloudflare": "5.2.0",
|
"cloudflare": "5.2.0",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"packages/core": {
|
|
||||||
"name": "@opencode-ai/core",
|
|
||||||
"version": "1.4.11",
|
|
||||||
"bin": {
|
|
||||||
"opencode": "./bin/opencode",
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@effect/platform-node": "catalog:",
|
|
||||||
"@npmcli/arborist": "catalog:",
|
|
||||||
"effect": "catalog:",
|
|
||||||
"glob": "13.0.5",
|
|
||||||
"mime-types": "3.0.2",
|
|
||||||
"minimatch": "10.2.5",
|
|
||||||
"npm-package-arg": "13.0.2",
|
|
||||||
"semver": "catalog:",
|
|
||||||
"xdg-basedir": "5.1.0",
|
|
||||||
"zod": "catalog:",
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@tsconfig/bun": "catalog:",
|
|
||||||
"@types/bun": "catalog:",
|
|
||||||
"@types/npm-package-arg": "6.1.4",
|
|
||||||
"@types/npmcli__arborist": "6.3.3",
|
|
||||||
"@types/semver": "catalog:",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"packages/desktop": {
|
"packages/desktop": {
|
||||||
"name": "@opencode-ai/desktop",
|
"name": "@opencode-ai/desktop",
|
||||||
"version": "1.14.18",
|
"version": "1.4.6",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@opencode-ai/app": "workspace:*",
|
"@opencode-ai/app": "workspace:*",
|
||||||
"@opencode-ai/ui": "workspace:*",
|
"@opencode-ai/ui": "workspace:*",
|
||||||
@@ -251,9 +225,8 @@
|
|||||||
},
|
},
|
||||||
"packages/desktop-electron": {
|
"packages/desktop-electron": {
|
||||||
"name": "@opencode-ai/desktop-electron",
|
"name": "@opencode-ai/desktop-electron",
|
||||||
"version": "1.14.18",
|
"version": "1.4.6",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"drizzle-orm": "catalog:",
|
|
||||||
"effect": "catalog:",
|
"effect": "catalog:",
|
||||||
"electron-context-menu": "4.1.2",
|
"electron-context-menu": "4.1.2",
|
||||||
"electron-log": "^5",
|
"electron-log": "^5",
|
||||||
@@ -275,7 +248,7 @@
|
|||||||
"@types/node": "catalog:",
|
"@types/node": "catalog:",
|
||||||
"@typescript/native-preview": "catalog:",
|
"@typescript/native-preview": "catalog:",
|
||||||
"@valibot/to-json-schema": "1.6.0",
|
"@valibot/to-json-schema": "1.6.0",
|
||||||
"electron": "41.2.1",
|
"electron": "40.4.1",
|
||||||
"electron-builder": "^26",
|
"electron-builder": "^26",
|
||||||
"electron-vite": "^5",
|
"electron-vite": "^5",
|
||||||
"solid-js": "catalog:",
|
"solid-js": "catalog:",
|
||||||
@@ -295,7 +268,7 @@
|
|||||||
},
|
},
|
||||||
"packages/enterprise": {
|
"packages/enterprise": {
|
||||||
"name": "@opencode-ai/enterprise",
|
"name": "@opencode-ai/enterprise",
|
||||||
"version": "1.14.18",
|
"version": "1.4.6",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@opencode-ai/shared": "workspace:*",
|
"@opencode-ai/shared": "workspace:*",
|
||||||
"@opencode-ai/ui": "workspace:*",
|
"@opencode-ai/ui": "workspace:*",
|
||||||
@@ -324,7 +297,7 @@
|
|||||||
},
|
},
|
||||||
"packages/function": {
|
"packages/function": {
|
||||||
"name": "@opencode-ai/function",
|
"name": "@opencode-ai/function",
|
||||||
"version": "1.14.18",
|
"version": "1.4.6",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@octokit/auth-app": "8.0.1",
|
"@octokit/auth-app": "8.0.1",
|
||||||
"@octokit/rest": "catalog:",
|
"@octokit/rest": "catalog:",
|
||||||
@@ -340,7 +313,7 @@
|
|||||||
},
|
},
|
||||||
"packages/opencode": {
|
"packages/opencode": {
|
||||||
"name": "opencode",
|
"name": "opencode",
|
||||||
"version": "1.14.18",
|
"version": "1.4.6",
|
||||||
"bin": {
|
"bin": {
|
||||||
"opencode": "./bin/opencode",
|
"opencode": "./bin/opencode",
|
||||||
},
|
},
|
||||||
@@ -349,15 +322,15 @@
|
|||||||
"@actions/github": "6.0.1",
|
"@actions/github": "6.0.1",
|
||||||
"@agentclientprotocol/sdk": "0.16.1",
|
"@agentclientprotocol/sdk": "0.16.1",
|
||||||
"@ai-sdk/alibaba": "1.0.17",
|
"@ai-sdk/alibaba": "1.0.17",
|
||||||
"@ai-sdk/amazon-bedrock": "4.0.96",
|
"@ai-sdk/amazon-bedrock": "4.0.93",
|
||||||
"@ai-sdk/anthropic": "3.0.71",
|
"@ai-sdk/anthropic": "3.0.67",
|
||||||
"@ai-sdk/azure": "3.0.49",
|
"@ai-sdk/azure": "3.0.49",
|
||||||
"@ai-sdk/cerebras": "2.0.41",
|
"@ai-sdk/cerebras": "2.0.41",
|
||||||
"@ai-sdk/cohere": "3.0.27",
|
"@ai-sdk/cohere": "3.0.27",
|
||||||
"@ai-sdk/deepinfra": "2.0.41",
|
"@ai-sdk/deepinfra": "2.0.41",
|
||||||
"@ai-sdk/gateway": "3.0.104",
|
"@ai-sdk/gateway": "3.0.97",
|
||||||
"@ai-sdk/google": "3.0.63",
|
"@ai-sdk/google": "3.0.63",
|
||||||
"@ai-sdk/google-vertex": "4.0.112",
|
"@ai-sdk/google-vertex": "4.0.109",
|
||||||
"@ai-sdk/groq": "3.0.31",
|
"@ai-sdk/groq": "3.0.31",
|
||||||
"@ai-sdk/mistral": "3.0.27",
|
"@ai-sdk/mistral": "3.0.27",
|
||||||
"@ai-sdk/openai": "3.0.53",
|
"@ai-sdk/openai": "3.0.53",
|
||||||
@@ -392,8 +365,8 @@
|
|||||||
"@opentelemetry/exporter-trace-otlp-http": "0.214.0",
|
"@opentelemetry/exporter-trace-otlp-http": "0.214.0",
|
||||||
"@opentelemetry/sdk-trace-base": "2.6.1",
|
"@opentelemetry/sdk-trace-base": "2.6.1",
|
||||||
"@opentelemetry/sdk-trace-node": "2.6.1",
|
"@opentelemetry/sdk-trace-node": "2.6.1",
|
||||||
"@opentui/core": "0.1.101",
|
"@opentui/core": "0.1.99",
|
||||||
"@opentui/solid": "0.1.101",
|
"@opentui/solid": "0.1.99",
|
||||||
"@parcel/watcher": "2.5.1",
|
"@parcel/watcher": "2.5.1",
|
||||||
"@pierre/diffs": "catalog:",
|
"@pierre/diffs": "catalog:",
|
||||||
"@solid-primitives/event-bus": "1.1.2",
|
"@solid-primitives/event-bus": "1.1.2",
|
||||||
@@ -413,7 +386,7 @@
|
|||||||
"drizzle-orm": "catalog:",
|
"drizzle-orm": "catalog:",
|
||||||
"effect": "catalog:",
|
"effect": "catalog:",
|
||||||
"fuzzysort": "3.1.0",
|
"fuzzysort": "3.1.0",
|
||||||
"gitlab-ai-provider": "6.6.0",
|
"gitlab-ai-provider": "6.4.2",
|
||||||
"glob": "13.0.5",
|
"glob": "13.0.5",
|
||||||
"google-auth-library": "10.5.0",
|
"google-auth-library": "10.5.0",
|
||||||
"gray-matter": "4.0.3",
|
"gray-matter": "4.0.3",
|
||||||
@@ -431,6 +404,7 @@
|
|||||||
"opentui-spinner": "0.0.6",
|
"opentui-spinner": "0.0.6",
|
||||||
"partial-json": "0.1.7",
|
"partial-json": "0.1.7",
|
||||||
"remeda": "catalog:",
|
"remeda": "catalog:",
|
||||||
|
"ripgrep": "0.3.1",
|
||||||
"semver": "^7.6.3",
|
"semver": "^7.6.3",
|
||||||
"solid-js": "catalog:",
|
"solid-js": "catalog:",
|
||||||
"strip-ansi": "7.1.2",
|
"strip-ansi": "7.1.2",
|
||||||
@@ -484,23 +458,23 @@
|
|||||||
},
|
},
|
||||||
"packages/plugin": {
|
"packages/plugin": {
|
||||||
"name": "@opencode-ai/plugin",
|
"name": "@opencode-ai/plugin",
|
||||||
"version": "1.14.18",
|
"version": "1.4.6",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@opencode-ai/sdk": "workspace:*",
|
"@opencode-ai/sdk": "workspace:*",
|
||||||
"effect": "catalog:",
|
"effect": "catalog:",
|
||||||
"zod": "catalog:",
|
"zod": "catalog:",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@opentui/core": "0.1.101",
|
"@opentui/core": "0.1.99",
|
||||||
"@opentui/solid": "0.1.101",
|
"@opentui/solid": "0.1.99",
|
||||||
"@tsconfig/node22": "catalog:",
|
"@tsconfig/node22": "catalog:",
|
||||||
"@types/node": "catalog:",
|
"@types/node": "catalog:",
|
||||||
"@typescript/native-preview": "catalog:",
|
"@typescript/native-preview": "catalog:",
|
||||||
"typescript": "catalog:",
|
"typescript": "catalog:",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@opentui/core": ">=0.1.101",
|
"@opentui/core": ">=0.1.99",
|
||||||
"@opentui/solid": ">=0.1.101",
|
"@opentui/solid": ">=0.1.99",
|
||||||
},
|
},
|
||||||
"optionalPeers": [
|
"optionalPeers": [
|
||||||
"@opentui/core",
|
"@opentui/core",
|
||||||
@@ -519,7 +493,7 @@
|
|||||||
},
|
},
|
||||||
"packages/sdk/js": {
|
"packages/sdk/js": {
|
||||||
"name": "@opencode-ai/sdk",
|
"name": "@opencode-ai/sdk",
|
||||||
"version": "1.14.18",
|
"version": "1.4.6",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cross-spawn": "catalog:",
|
"cross-spawn": "catalog:",
|
||||||
},
|
},
|
||||||
@@ -534,7 +508,7 @@
|
|||||||
},
|
},
|
||||||
"packages/shared": {
|
"packages/shared": {
|
||||||
"name": "@opencode-ai/shared",
|
"name": "@opencode-ai/shared",
|
||||||
"version": "1.14.18",
|
"version": "1.4.6",
|
||||||
"bin": {
|
"bin": {
|
||||||
"opencode": "./bin/opencode",
|
"opencode": "./bin/opencode",
|
||||||
},
|
},
|
||||||
@@ -542,7 +516,6 @@
|
|||||||
"@effect/platform-node": "catalog:",
|
"@effect/platform-node": "catalog:",
|
||||||
"@npmcli/arborist": "catalog:",
|
"@npmcli/arborist": "catalog:",
|
||||||
"effect": "catalog:",
|
"effect": "catalog:",
|
||||||
"glob": "13.0.5",
|
|
||||||
"mime-types": "3.0.2",
|
"mime-types": "3.0.2",
|
||||||
"minimatch": "10.2.5",
|
"minimatch": "10.2.5",
|
||||||
"semver": "catalog:",
|
"semver": "catalog:",
|
||||||
@@ -550,15 +523,13 @@
|
|||||||
"zod": "catalog:",
|
"zod": "catalog:",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tsconfig/bun": "catalog:",
|
|
||||||
"@types/bun": "catalog:",
|
"@types/bun": "catalog:",
|
||||||
"@types/npmcli__arborist": "6.3.3",
|
|
||||||
"@types/semver": "catalog:",
|
"@types/semver": "catalog:",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"packages/slack": {
|
"packages/slack": {
|
||||||
"name": "@opencode-ai/slack",
|
"name": "@opencode-ai/slack",
|
||||||
"version": "1.14.18",
|
"version": "1.4.6",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@opencode-ai/sdk": "workspace:*",
|
"@opencode-ai/sdk": "workspace:*",
|
||||||
"@slack/bolt": "^3.17.1",
|
"@slack/bolt": "^3.17.1",
|
||||||
@@ -593,7 +564,7 @@
|
|||||||
},
|
},
|
||||||
"packages/ui": {
|
"packages/ui": {
|
||||||
"name": "@opencode-ai/ui",
|
"name": "@opencode-ai/ui",
|
||||||
"version": "1.14.18",
|
"version": "1.4.6",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kobalte/core": "catalog:",
|
"@kobalte/core": "catalog:",
|
||||||
"@opencode-ai/sdk": "workspace:*",
|
"@opencode-ai/sdk": "workspace:*",
|
||||||
@@ -642,7 +613,7 @@
|
|||||||
},
|
},
|
||||||
"packages/web": {
|
"packages/web": {
|
||||||
"name": "@opencode-ai/web",
|
"name": "@opencode-ai/web",
|
||||||
"version": "1.14.18",
|
"version": "1.4.6",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/cloudflare": "12.6.3",
|
"@astrojs/cloudflare": "12.6.3",
|
||||||
"@astrojs/markdown-remark": "6.3.1",
|
"@astrojs/markdown-remark": "6.3.1",
|
||||||
@@ -701,8 +672,6 @@
|
|||||||
"@npmcli/arborist": "9.4.0",
|
"@npmcli/arborist": "9.4.0",
|
||||||
"@octokit/rest": "22.0.0",
|
"@octokit/rest": "22.0.0",
|
||||||
"@openauthjs/openauth": "0.0.0-20250322224806",
|
"@openauthjs/openauth": "0.0.0-20250322224806",
|
||||||
"@opentui/core": "0.1.99",
|
|
||||||
"@opentui/solid": "0.1.99",
|
|
||||||
"@pierre/diffs": "1.1.0-beta.18",
|
"@pierre/diffs": "1.1.0-beta.18",
|
||||||
"@playwright/test": "1.59.1",
|
"@playwright/test": "1.59.1",
|
||||||
"@solid-primitives/storage": "4.3.3",
|
"@solid-primitives/storage": "4.3.3",
|
||||||
@@ -718,7 +687,7 @@
|
|||||||
"@types/node": "22.13.9",
|
"@types/node": "22.13.9",
|
||||||
"@types/semver": "7.7.1",
|
"@types/semver": "7.7.1",
|
||||||
"@typescript/native-preview": "7.0.0-dev.20251207.1",
|
"@typescript/native-preview": "7.0.0-dev.20251207.1",
|
||||||
"ai": "6.0.168",
|
"ai": "6.0.158",
|
||||||
"cross-spawn": "7.0.6",
|
"cross-spawn": "7.0.6",
|
||||||
"diff": "8.0.2",
|
"diff": "8.0.2",
|
||||||
"dompurify": "3.3.1",
|
"dompurify": "3.3.1",
|
||||||
@@ -766,7 +735,7 @@
|
|||||||
|
|
||||||
"@ai-sdk/alibaba": ["@ai-sdk/alibaba@1.0.17", "", { "dependencies": { "@ai-sdk/openai-compatible": "2.0.41", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ZbE+U5bWz2JBc5DERLowx5+TKbjGBE93LqKZAWvuEn7HOSQMraxFMZuc0ST335QZJAyfBOzh7m1mPQ+y7EaaoA=="],
|
"@ai-sdk/alibaba": ["@ai-sdk/alibaba@1.0.17", "", { "dependencies": { "@ai-sdk/openai-compatible": "2.0.41", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ZbE+U5bWz2JBc5DERLowx5+TKbjGBE93LqKZAWvuEn7HOSQMraxFMZuc0ST335QZJAyfBOzh7m1mPQ+y7EaaoA=="],
|
||||||
|
|
||||||
"@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@4.0.96", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.71", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Mc4Ias2jRMD1jOB6xWtKNPdhECeuCZyIlbr9EAGfBnyBt++sS13ziZh9qv9TdyMCAZJ7xoQcpbchoRJcKwPdpA=="],
|
"@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@4.0.93", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.69", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-hcXDU8QDwpAzLVTuY932TQVlIij9+iaVTxc5mPGY6yb//JMAAC5hMVhg93IrxlrxWLvMgjezNgoZGwquR+SGnw=="],
|
||||||
|
|
||||||
"@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.64", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.21" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-rwLi/Rsuj2pYniQXIrvClHvXDzgM4UQHHnvHTWEF14efnlKclG/1ghpNC+adsRujAbCTr6gRsSbDE2vEqriV7g=="],
|
"@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.64", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.21" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-rwLi/Rsuj2pYniQXIrvClHvXDzgM4UQHHnvHTWEF14efnlKclG/1ghpNC+adsRujAbCTr6gRsSbDE2vEqriV7g=="],
|
||||||
|
|
||||||
@@ -786,11 +755,11 @@
|
|||||||
|
|
||||||
"@ai-sdk/fireworks": ["@ai-sdk/fireworks@2.0.46", "", { "dependencies": { "@ai-sdk/openai-compatible": "2.0.41", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-XRKR0zgRyegdmtK5CDUEjlyRp0Fo+XVCdoG+301U1SGtgRIAYG3ObVtgzVJBVpJdHFSLHuYeLTnNiQoUxD7+FQ=="],
|
"@ai-sdk/fireworks": ["@ai-sdk/fireworks@2.0.46", "", { "dependencies": { "@ai-sdk/openai-compatible": "2.0.41", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-XRKR0zgRyegdmtK5CDUEjlyRp0Fo+XVCdoG+301U1SGtgRIAYG3ObVtgzVJBVpJdHFSLHuYeLTnNiQoUxD7+FQ=="],
|
||||||
|
|
||||||
"@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.104", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@vercel/oidc": "3.2.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ZKX5n74io8VIRlhIMSLWVlvT3sXC8Z7cZ9GHuWBWZDVi96+62AIsWuLGvMfcBA1STYuSoDrp6rIziZmvrTq0TA=="],
|
"@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.97", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@vercel/oidc": "3.1.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ERHmVGX30YKTwxObuHQzNqoOf8Nb5WwYMDBn34e3TGGVn0vLEXwMimo7uRVTbhhi4gfu9WtwYTE4x1+csZok1w=="],
|
||||||
|
|
||||||
"@ai-sdk/google": ["@ai-sdk/google@3.0.63", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-RfOZWVMYSPu2sPRfGajrauWAZ9BSaRopSn+AszkKWQ1MFj8nhaXvCqRHB5pBQUaHTfZKagvOmMpNfa/s3gPLgQ=="],
|
"@ai-sdk/google": ["@ai-sdk/google@3.0.63", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-RfOZWVMYSPu2sPRfGajrauWAZ9BSaRopSn+AszkKWQ1MFj8nhaXvCqRHB5pBQUaHTfZKagvOmMpNfa/s3gPLgQ=="],
|
||||||
|
|
||||||
"@ai-sdk/google-vertex": ["@ai-sdk/google-vertex@4.0.112", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.71", "@ai-sdk/google": "3.0.64", "@ai-sdk/openai-compatible": "2.0.41", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "google-auth-library": "^10.5.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-cSfHCkM+9ZrFtQWIN1WlV93JPD+isGSdFxKj7u1L9m2aLVZajlXdcE41GL9hMt7ld7bZYE4NnZ+4VLxBAHE+Eg=="],
|
"@ai-sdk/google-vertex": ["@ai-sdk/google-vertex@4.0.109", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.69", "@ai-sdk/google": "3.0.63", "@ai-sdk/openai-compatible": "2.0.41", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "google-auth-library": "^10.5.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-QzQ+DgOoSYlkU4mK0H+iaCaW1bl5zOimH9X2E2oylcVyUtAdCuduQ959Uw1ygW3l09J2K/ceEDtK8OUPHyOA7g=="],
|
||||||
|
|
||||||
"@ai-sdk/groq": ["@ai-sdk/groq@3.0.31", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.21" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-XbbugpnFmXGu2TlXiq8KUJskP6/VVbuFcnFIGDzDIB/Chg6XHsNnqrTF80Zxkh0Pd3+NvbM+2Uqrtsndk6bDAg=="],
|
"@ai-sdk/groq": ["@ai-sdk/groq@3.0.31", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.21" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-XbbugpnFmXGu2TlXiq8KUJskP6/VVbuFcnFIGDzDIB/Chg6XHsNnqrTF80Zxkh0Pd3+NvbM+2Uqrtsndk6bDAg=="],
|
||||||
|
|
||||||
@@ -1574,8 +1543,6 @@
|
|||||||
|
|
||||||
"@opencode-ai/console-resource": ["@opencode-ai/console-resource@workspace:packages/console/resource"],
|
"@opencode-ai/console-resource": ["@opencode-ai/console-resource@workspace:packages/console/resource"],
|
||||||
|
|
||||||
"@opencode-ai/core": ["@opencode-ai/core@workspace:packages/core"],
|
|
||||||
|
|
||||||
"@opencode-ai/desktop": ["@opencode-ai/desktop@workspace:packages/desktop"],
|
"@opencode-ai/desktop": ["@opencode-ai/desktop@workspace:packages/desktop"],
|
||||||
|
|
||||||
"@opencode-ai/desktop-electron": ["@opencode-ai/desktop-electron@workspace:packages/desktop-electron"],
|
"@opencode-ai/desktop-electron": ["@opencode-ai/desktop-electron@workspace:packages/desktop-electron"],
|
||||||
@@ -1616,7 +1583,7 @@
|
|||||||
|
|
||||||
"@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.214.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.214.0", "@opentelemetry/core": "2.6.1", "@opentelemetry/resources": "2.6.1", "@opentelemetry/sdk-logs": "0.214.0", "@opentelemetry/sdk-metrics": "2.6.1", "@opentelemetry/sdk-trace-base": "2.6.1", "protobufjs": "^7.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-DSaYcuBRh6uozfsWN3R8HsN0yDhCuWP7tOFdkUOVaWD1KVJg8m4qiLUsg/tNhTLS9HUYUcwNpwL2eroLtsZZ/w=="],
|
"@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.214.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.214.0", "@opentelemetry/core": "2.6.1", "@opentelemetry/resources": "2.6.1", "@opentelemetry/sdk-logs": "0.214.0", "@opentelemetry/sdk-metrics": "2.6.1", "@opentelemetry/sdk-trace-base": "2.6.1", "protobufjs": "^7.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-DSaYcuBRh6uozfsWN3R8HsN0yDhCuWP7tOFdkUOVaWD1KVJg8m4qiLUsg/tNhTLS9HUYUcwNpwL2eroLtsZZ/w=="],
|
||||||
|
|
||||||
"@opentelemetry/resources": ["@opentelemetry/resources@2.2.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A=="],
|
"@opentelemetry/resources": ["@opentelemetry/resources@2.6.1", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA=="],
|
||||||
|
|
||||||
"@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.214.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.214.0", "@opentelemetry/core": "2.6.1", "@opentelemetry/resources": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-zf6acnScjhsaBUU22zXZ/sLWim1dfhUAbGXdMmHmNG3LfBnQ3DKsOCITb2IZwoUsNNMTogqFKBnlIPPftUgGwA=="],
|
"@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.214.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.214.0", "@opentelemetry/core": "2.6.1", "@opentelemetry/resources": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-zf6acnScjhsaBUU22zXZ/sLWim1dfhUAbGXdMmHmNG3LfBnQ3DKsOCITb2IZwoUsNNMTogqFKBnlIPPftUgGwA=="],
|
||||||
|
|
||||||
@@ -1628,21 +1595,21 @@
|
|||||||
|
|
||||||
"@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.40.0", "", {}, "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw=="],
|
"@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.40.0", "", {}, "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw=="],
|
||||||
|
|
||||||
"@opentui/core": ["@opentui/core@0.1.101", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "marked": "17.0.1", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.101", "@opentui/core-darwin-x64": "0.1.101", "@opentui/core-linux-arm64": "0.1.101", "@opentui/core-linux-x64": "0.1.101", "@opentui/core-win32-arm64": "0.1.101", "@opentui/core-win32-x64": "0.1.101", "bun-webgpu": "0.1.5", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-8jUhNKnwCDO3Y2iiEmagoQLjgX5l1WbddQiwky8B5JU4FW0/WRHairBmU1kRAQBmhdeg57dVinSG4iu2PAtKEA=="],
|
"@opentui/core": ["@opentui/core@0.1.99", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "marked": "17.0.1", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.99", "@opentui/core-darwin-x64": "0.1.99", "@opentui/core-linux-arm64": "0.1.99", "@opentui/core-linux-x64": "0.1.99", "@opentui/core-win32-arm64": "0.1.99", "@opentui/core-win32-x64": "0.1.99", "bun-webgpu": "0.1.5", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-I3+AEgGzqNWIpWX9g2WOscSPwtQDNOm4KlBjxBWCZjLxkF07u77heWXF7OiAdhKLtNUW6TFiyt6yznqAZPdG3A=="],
|
||||||
|
|
||||||
"@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.101", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HtqZh8TIKCH1Nge5J0etBCpzYfPY4fVcq110uJm2As6D/dTTPv8r4J+KkrqoSphkpj/Y2b4t7KpqNHthXA0EVw=="],
|
"@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.99", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bzVrqeX2vb5iWrc/ftOUOqeUY8XO+qSgoTwj5TXHuwagavgwD3Hpeyjx8+icnTTeM4pao0som1WR9xfye6/X5Q=="],
|
||||||
|
|
||||||
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.101", "", { "os": "darwin", "cpu": "x64" }, "sha512-o5ClQWnGG1inRE2YZAatPw1jPEAJni00amcoIfKBj8e1WS+fQA+iQTq1xFunNcyNPObLDCVuW1X+NrbK9xmPvQ=="],
|
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.99", "", { "os": "darwin", "cpu": "x64" }, "sha512-VE4FrXBYpkxnvkqcCV1a8aN9jyyMJMihVW+V2NLCtp+4yQsj0AapG5TiUSN76XnmSZRptxDy5rBmEempeoIZbg=="],
|
||||||
|
|
||||||
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.101", "", { "os": "linux", "cpu": "arm64" }, "sha512-E/weY7DQpaPWGYDPD0CROHowUotqnVlk7Kb6l9+iZCrxm9s7HPRHkcMDVmcWDqHEqa/J879EJcqaUDzDArqC+w=="],
|
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.99", "", { "os": "linux", "cpu": "arm64" }, "sha512-viXQsbpS7yHjYkl7+am32JdvG96QU9lvHh1UiZtpOxcNUUqiYmA2ZwZFPD2Bi54jNyj5l2hjH6YkD3DzE2FEWA=="],
|
||||||
|
|
||||||
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.101", "", { "os": "linux", "cpu": "x64" }, "sha512-+Bfr8jLbbR1WREUMCCvSZ44G1+WU2lPqJx7x1StTa9iFNEdicxCdd0QQsO6cnKn5yW+2Pr/FdrqHbxSQw3ejbA=="],
|
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.99", "", { "os": "linux", "cpu": "x64" }, "sha512-WLoEFINOSp0tZSR9y4LUuGc7n4Y7H1wcpjUPzQ9vChkYDXrfZltEanzoDWbDcQ4kZQW5tHVC7LrZHpAsRLwFZg=="],
|
||||||
|
|
||||||
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.101", "", { "os": "win32", "cpu": "arm64" }, "sha512-LTMIHJzJrVqS8mgpp+tuyVHuqYlicQTvFi/sTsJ6Xswf1asatsvZYsbQByhBLpFT80j10G7uvDa361S5gjCUDA=="],
|
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.99", "", { "os": "win32", "cpu": "arm64" }, "sha512-yWMOLWCEO8HdrctU1dMkgZC8qGkiO4Dwr4/e11tTvVpRmYhDsP/IR89ZjEEtOwnKwFOFuB/MxvflqaEWVQ2g5Q=="],
|
||||||
|
|
||||||
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.101", "", { "os": "win32", "cpu": "x64" }, "sha512-VaMs5bg6y0tYKptaEK8Hy5wTp4m//wJRKUdW8uvrS9cFgxyovZGuw0+TfK3NgbdeX+8jWm8LEAiak4jle5BABg=="],
|
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.99", "", { "os": "win32", "cpu": "x64" }, "sha512-aYRlsL2w8YRL6vPd7/hrqlNVkXU3QowWb01TOvAcHS8UAsXaGFUr47kSDyjxDi1wg1MzmVduCfsC7T3NoThV1w=="],
|
||||||
|
|
||||||
"@opentui/solid": ["@opentui/solid@0.1.101", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.101", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.10", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.11" } }, "sha512-STY2FQYtVS2rhUgpslG6mM0EAkgobBDF91+B+SNmvXIkJwP+ydP6UVgcuIo5McIbb9GIbAODx5X2Q48PSR7hgw=="],
|
"@opentui/solid": ["@opentui/solid@0.1.99", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.99", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.10", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.11" } }, "sha512-DrqqO4h2V88FmeIP2cErYkMU0ZK5MrUsZw3w6IzZpoXyyiL4/9qpWzUq+CXx+r16VP2iGxDJwGKUmtFAzUch2Q=="],
|
||||||
|
|
||||||
"@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="],
|
"@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="],
|
||||||
|
|
||||||
@@ -2484,7 +2451,7 @@
|
|||||||
|
|
||||||
"@valibot/to-json-schema": ["@valibot/to-json-schema@1.6.0", "", { "peerDependencies": { "valibot": "^1.3.0" } }, "sha512-d6rYyK5KVa2XdqamWgZ4/Nr+cXhxjy7lmpe6Iajw15J/jmU+gyxl2IEd1Otg1d7Rl3gOQL5reulnSypzBtYy1A=="],
|
"@valibot/to-json-schema": ["@valibot/to-json-schema@1.6.0", "", { "peerDependencies": { "valibot": "^1.3.0" } }, "sha512-d6rYyK5KVa2XdqamWgZ4/Nr+cXhxjy7lmpe6Iajw15J/jmU+gyxl2IEd1Otg1d7Rl3gOQL5reulnSypzBtYy1A=="],
|
||||||
|
|
||||||
"@vercel/oidc": ["@vercel/oidc@3.2.0", "", {}, "sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug=="],
|
"@vercel/oidc": ["@vercel/oidc@3.1.0", "", {}, "sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w=="],
|
||||||
|
|
||||||
"@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="],
|
"@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="],
|
||||||
|
|
||||||
@@ -2544,7 +2511,7 @@
|
|||||||
|
|
||||||
"agentkeepalive": ["agentkeepalive@4.6.0", "", { "dependencies": { "humanize-ms": "^1.2.1" } }, "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ=="],
|
"agentkeepalive": ["agentkeepalive@4.6.0", "", { "dependencies": { "humanize-ms": "^1.2.1" } }, "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ=="],
|
||||||
|
|
||||||
"ai": ["ai@6.0.168", "", { "dependencies": { "@ai-sdk/gateway": "3.0.104", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-2HqCJuO+1V2aV7vfYs5LFEUfxbkGX+5oa54q/gCCTL7KLTdbxcCu5D7TdLA5kwsrs3Szgjah9q6D9tpjHM3hUQ=="],
|
"ai": ["ai@6.0.158", "", { "dependencies": { "@ai-sdk/gateway": "3.0.95", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-gLTp1UXFtMqKUi3XHs33K7UFglbvojkxF/aq337TxnLGOhHIW9+GyP2jwW4hYX87f1es+wId3VQoPRRu9zEStQ=="],
|
||||||
|
|
||||||
"ai-gateway-provider": ["ai-gateway-provider@3.1.2", "", { "optionalDependencies": { "@ai-sdk/amazon-bedrock": "^4.0.62", "@ai-sdk/anthropic": "^3.0.46", "@ai-sdk/azure": "^3.0.31", "@ai-sdk/cerebras": "^2.0.34", "@ai-sdk/cohere": "^3.0.21", "@ai-sdk/deepgram": "^2.0.20", "@ai-sdk/deepseek": "^2.0.20", "@ai-sdk/elevenlabs": "^2.0.20", "@ai-sdk/fireworks": "^2.0.34", "@ai-sdk/google": "^3.0.30", "@ai-sdk/google-vertex": "^4.0.61", "@ai-sdk/groq": "^3.0.24", "@ai-sdk/mistral": "^3.0.20", "@ai-sdk/openai": "^3.0.30", "@ai-sdk/perplexity": "^3.0.19", "@ai-sdk/xai": "^3.0.57", "@openrouter/ai-sdk-provider": "^2.2.3" }, "peerDependencies": { "@ai-sdk/openai-compatible": "^2.0.0", "@ai-sdk/provider": "^3.0.0", "@ai-sdk/provider-utils": "^4.0.0", "ai": "^6.0.0" } }, "sha512-krGNnJSoO/gJ7Hbe5nQDlsBpDUGIBGtMQTRUaW7s1MylsfvLduba0TLWzQaGtOmNRkP0pGhtGlwsnS6FNQMlyw=="],
|
"ai-gateway-provider": ["ai-gateway-provider@3.1.2", "", { "optionalDependencies": { "@ai-sdk/amazon-bedrock": "^4.0.62", "@ai-sdk/anthropic": "^3.0.46", "@ai-sdk/azure": "^3.0.31", "@ai-sdk/cerebras": "^2.0.34", "@ai-sdk/cohere": "^3.0.21", "@ai-sdk/deepgram": "^2.0.20", "@ai-sdk/deepseek": "^2.0.20", "@ai-sdk/elevenlabs": "^2.0.20", "@ai-sdk/fireworks": "^2.0.34", "@ai-sdk/google": "^3.0.30", "@ai-sdk/google-vertex": "^4.0.61", "@ai-sdk/groq": "^3.0.24", "@ai-sdk/mistral": "^3.0.20", "@ai-sdk/openai": "^3.0.30", "@ai-sdk/perplexity": "^3.0.19", "@ai-sdk/xai": "^3.0.57", "@openrouter/ai-sdk-provider": "^2.2.3" }, "peerDependencies": { "@ai-sdk/openai-compatible": "^2.0.0", "@ai-sdk/provider": "^3.0.0", "@ai-sdk/provider-utils": "^4.0.0", "ai": "^6.0.0" } }, "sha512-krGNnJSoO/gJ7Hbe5nQDlsBpDUGIBGtMQTRUaW7s1MylsfvLduba0TLWzQaGtOmNRkP0pGhtGlwsnS6FNQMlyw=="],
|
||||||
|
|
||||||
@@ -3054,7 +3021,7 @@
|
|||||||
|
|
||||||
"ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
|
"ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
|
||||||
|
|
||||||
"electron": ["electron@41.2.1", "", { "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^24.9.0", "extract-zip": "^2.0.1" }, "bin": { "electron": "cli.js" } }, "sha512-teeRThiYGTPKf/2yOW7zZA1bhb91KEQ4yLBPOg7GxpmnkLFLugKgQaAKOrCgdzwsXh/5mFIfmkm+4+wACJKwaA=="],
|
"electron": ["electron@40.4.1", "", { "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^24.9.0", "extract-zip": "^2.0.1" }, "bin": { "electron": "cli.js" } }, "sha512-N1ZXybQZL8kYemO8vAeh9nrk4mSvqlAO8xs0QCHkXIvRnuB/7VGwEehjvQbsU5/f4bmTKpG+2GQERe/zmKpudQ=="],
|
||||||
|
|
||||||
"electron-builder": ["electron-builder@26.8.1", "", { "dependencies": { "app-builder-lib": "26.8.1", "builder-util": "26.8.1", "builder-util-runtime": "9.5.1", "chalk": "^4.1.2", "ci-info": "^4.2.0", "dmg-builder": "26.8.1", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "simple-update-notifier": "2.0.0", "yargs": "^17.6.2" }, "bin": { "electron-builder": "cli.js", "install-app-deps": "install-app-deps.js" } }, "sha512-uWhx1r74NGpCagG0ULs/P9Nqv2nsoo+7eo4fLUOB8L8MdWltq9odW/uuLXMFCDGnPafknYLZgjNX0ZIFRzOQAw=="],
|
"electron-builder": ["electron-builder@26.8.1", "", { "dependencies": { "app-builder-lib": "26.8.1", "builder-util": "26.8.1", "builder-util-runtime": "9.5.1", "chalk": "^4.1.2", "ci-info": "^4.2.0", "dmg-builder": "26.8.1", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "simple-update-notifier": "2.0.0", "yargs": "^17.6.2" }, "bin": { "electron-builder": "cli.js", "install-app-deps": "install-app-deps.js" } }, "sha512-uWhx1r74NGpCagG0ULs/P9Nqv2nsoo+7eo4fLUOB8L8MdWltq9odW/uuLXMFCDGnPafknYLZgjNX0ZIFRzOQAw=="],
|
||||||
|
|
||||||
@@ -3334,7 +3301,7 @@
|
|||||||
|
|
||||||
"get-tsconfig": ["get-tsconfig@4.13.8", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-J87BxkLXykmisLQ+KA4x2+O6rVf+PJrtFUO8lGyiRg4lyxJLJ8/v0sRAKdVZQOy6tR6lMRAF1NqzCf9BQijm0w=="],
|
"get-tsconfig": ["get-tsconfig@4.13.8", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-J87BxkLXykmisLQ+KA4x2+O6rVf+PJrtFUO8lGyiRg4lyxJLJ8/v0sRAKdVZQOy6tR6lMRAF1NqzCf9BQijm0w=="],
|
||||||
|
|
||||||
"ghostty-web": ["ghostty-web@github:anomalyco/ghostty-web#20bd361", {}, "anomalyco-ghostty-web-20bd361", "sha512-dW0nwaiBBcun9y5WJSvm3HxDLe5o9V0xLCndQvWonRVubU8CS1PHxZpLffyPt1YujPWC13ez03aWxcuKBPYYGQ=="],
|
"ghostty-web": ["ghostty-web@github:anomalyco/ghostty-web#4af877d", {}, "anomalyco-ghostty-web-4af877d", "sha512-fbEK8mtr7ar4ySsF+JUGjhaZrane7dKphanN+SxHt5XXI6yLMAh/Hpf6sNCOyyVa2UlGCd7YpXG/T2v2RUAX+A=="],
|
||||||
|
|
||||||
"gifwrap": ["gifwrap@0.10.1", "", { "dependencies": { "image-q": "^4.0.0", "omggif": "^1.0.10" } }, "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw=="],
|
"gifwrap": ["gifwrap@0.10.1", "", { "dependencies": { "image-q": "^4.0.0", "omggif": "^1.0.10" } }, "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw=="],
|
||||||
|
|
||||||
@@ -3342,7 +3309,7 @@
|
|||||||
|
|
||||||
"github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="],
|
"github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="],
|
||||||
|
|
||||||
"gitlab-ai-provider": ["gitlab-ai-provider@6.6.0", "", { "dependencies": { "@anthropic-ai/sdk": "^0.71.0", "@anycable/core": "^0.9.2", "graphql-request": "^6.1.0", "isomorphic-ws": "^5.0.0", "openai": "^6.16.0", "socket.io-client": "^4.8.1", "vscode-jsonrpc": "^8.2.1", "zod": "^3.25.76" }, "peerDependencies": { "@ai-sdk/provider": ">=3.0.0", "@ai-sdk/provider-utils": ">=4.0.0" } }, "sha512-jUxYnKA4XQaPc3wxACDZ8bPDXO0Mzx7cZaBDxbT2uGgLqtGZmSi+9tVNIg7louSS+s/ioVra3SoUz3iOFVhKPA=="],
|
"gitlab-ai-provider": ["gitlab-ai-provider@6.4.2", "", { "dependencies": { "@anthropic-ai/sdk": "^0.71.0", "@anycable/core": "^0.9.2", "graphql-request": "^6.1.0", "isomorphic-ws": "^5.0.0", "openai": "^6.16.0", "socket.io-client": "^4.8.1", "vscode-jsonrpc": "^8.2.1", "zod": "^3.25.76" }, "peerDependencies": { "@ai-sdk/provider": ">=3.0.0", "@ai-sdk/provider-utils": ">=4.0.0" } }, "sha512-Wyw6uslCuipBOr/NYwAtpgXEUJj68iJY5aekad2DjePN99JetKVQBqkLgAy9PZp2EA4OuscfRQu9qKIBN/evNw=="],
|
||||||
|
|
||||||
"glob": ["glob@13.0.5", "", { "dependencies": { "minimatch": "^10.2.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-BzXxZg24Ibra1pbQ/zE7Kys4Ua1ks7Bn6pKLkVPZ9FZe4JQS6/Q7ef3LG1H+k7lUf5l4T3PLSyYyYJVYUvfgTw=="],
|
"glob": ["glob@13.0.5", "", { "dependencies": { "minimatch": "^10.2.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-BzXxZg24Ibra1pbQ/zE7Kys4Ua1ks7Bn6pKLkVPZ9FZe4JQS6/Q7ef3LG1H+k7lUf5l4T3PLSyYyYJVYUvfgTw=="],
|
||||||
|
|
||||||
@@ -4510,6 +4477,8 @@
|
|||||||
|
|
||||||
"rimraf": ["rimraf@2.6.3", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "./bin.js" } }, "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA=="],
|
"rimraf": ["rimraf@2.6.3", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "./bin.js" } }, "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA=="],
|
||||||
|
|
||||||
|
"ripgrep": ["ripgrep@0.3.1", "", { "bin": { "rg": "lib/rg.mjs", "ripgrep": "lib/rg.mjs" } }, "sha512-6bDtNIBh1qPviVIU685/4uv0Ap5t8eS4wiJhy/tR2LdIeIey9CVasENlGS+ul3HnTmGANIp7AjnfsztsRmALfQ=="],
|
||||||
|
|
||||||
"roarr": ["roarr@2.15.4", "", { "dependencies": { "boolean": "^3.0.1", "detect-node": "^2.0.4", "globalthis": "^1.0.1", "json-stringify-safe": "^5.0.1", "semver-compare": "^1.0.0", "sprintf-js": "^1.1.2" } }, "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A=="],
|
"roarr": ["roarr@2.15.4", "", { "dependencies": { "boolean": "^3.0.1", "detect-node": "^2.0.4", "globalthis": "^1.0.1", "json-stringify-safe": "^5.0.1", "semver-compare": "^1.0.0", "sprintf-js": "^1.1.2" } }, "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A=="],
|
||||||
|
|
||||||
"rollup": ["rollup@4.60.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.60.1", "@rollup/rollup-android-arm64": "4.60.1", "@rollup/rollup-darwin-arm64": "4.60.1", "@rollup/rollup-darwin-x64": "4.60.1", "@rollup/rollup-freebsd-arm64": "4.60.1", "@rollup/rollup-freebsd-x64": "4.60.1", "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", "@rollup/rollup-linux-arm-musleabihf": "4.60.1", "@rollup/rollup-linux-arm64-gnu": "4.60.1", "@rollup/rollup-linux-arm64-musl": "4.60.1", "@rollup/rollup-linux-loong64-gnu": "4.60.1", "@rollup/rollup-linux-loong64-musl": "4.60.1", "@rollup/rollup-linux-ppc64-gnu": "4.60.1", "@rollup/rollup-linux-ppc64-musl": "4.60.1", "@rollup/rollup-linux-riscv64-gnu": "4.60.1", "@rollup/rollup-linux-riscv64-musl": "4.60.1", "@rollup/rollup-linux-s390x-gnu": "4.60.1", "@rollup/rollup-linux-x64-gnu": "4.60.1", "@rollup/rollup-linux-x64-musl": "4.60.1", "@rollup/rollup-openbsd-x64": "4.60.1", "@rollup/rollup-openharmony-arm64": "4.60.1", "@rollup/rollup-win32-arm64-msvc": "4.60.1", "@rollup/rollup-win32-ia32-msvc": "4.60.1", "@rollup/rollup-win32-x64-gnu": "4.60.1", "@rollup/rollup-win32-x64-msvc": "4.60.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w=="],
|
"rollup": ["rollup@4.60.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.60.1", "@rollup/rollup-android-arm64": "4.60.1", "@rollup/rollup-darwin-arm64": "4.60.1", "@rollup/rollup-darwin-x64": "4.60.1", "@rollup/rollup-freebsd-arm64": "4.60.1", "@rollup/rollup-freebsd-x64": "4.60.1", "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", "@rollup/rollup-linux-arm-musleabihf": "4.60.1", "@rollup/rollup-linux-arm64-gnu": "4.60.1", "@rollup/rollup-linux-arm64-musl": "4.60.1", "@rollup/rollup-linux-loong64-gnu": "4.60.1", "@rollup/rollup-linux-loong64-musl": "4.60.1", "@rollup/rollup-linux-ppc64-gnu": "4.60.1", "@rollup/rollup-linux-ppc64-musl": "4.60.1", "@rollup/rollup-linux-riscv64-gnu": "4.60.1", "@rollup/rollup-linux-riscv64-musl": "4.60.1", "@rollup/rollup-linux-s390x-gnu": "4.60.1", "@rollup/rollup-linux-x64-gnu": "4.60.1", "@rollup/rollup-linux-x64-musl": "4.60.1", "@rollup/rollup-openbsd-x64": "4.60.1", "@rollup/rollup-openharmony-arm64": "4.60.1", "@rollup/rollup-win32-arm64-msvc": "4.60.1", "@rollup/rollup-win32-ia32-msvc": "4.60.1", "@rollup/rollup-win32-x64-gnu": "4.60.1", "@rollup/rollup-win32-x64-msvc": "4.60.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w=="],
|
||||||
@@ -5180,11 +5149,7 @@
|
|||||||
|
|
||||||
"@ai-sdk/alibaba/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.41", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g=="],
|
"@ai-sdk/alibaba/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.41", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g=="],
|
||||||
|
|
||||||
"@ai-sdk/amazon-bedrock/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.71", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-bUWOzrzR0gJKJO/PLGMR4uH2dqEgqGhrsCV+sSpk4KtOEnUQlfjZI/F7BFlqSvVpFbjdgYRRLysAeEZpJ6S1lg=="],
|
"@ai-sdk/amazon-bedrock/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.69", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-LshR7X3pFugY0o41G2VKTmg1XoGpSl7uoYWfzk6zjVZLhCfeFiwgpOga+eTV4XY1VVpZwKVqRnkDbIL7K2eH5g=="],
|
||||||
|
|
||||||
"@ai-sdk/amazon-bedrock/@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.13", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.14.0", "@smithy/util-hex-encoding": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-vYahwBAtRaAcFbOmE9aLr12z7RiHYDSLcnogSdxfm7kKfsNa3wH+NU5r7vTeB5rKvLsWyPjVX8iH94brP7umiQ=="],
|
|
||||||
|
|
||||||
"@ai-sdk/amazon-bedrock/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
|
|
||||||
|
|
||||||
"@ai-sdk/anthropic/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.21", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw=="],
|
"@ai-sdk/anthropic/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.21", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw=="],
|
||||||
|
|
||||||
@@ -5198,9 +5163,7 @@
|
|||||||
|
|
||||||
"@ai-sdk/fireworks/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.41", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g=="],
|
"@ai-sdk/fireworks/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.41", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g=="],
|
||||||
|
|
||||||
"@ai-sdk/google-vertex/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.71", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-bUWOzrzR0gJKJO/PLGMR4uH2dqEgqGhrsCV+sSpk4KtOEnUQlfjZI/F7BFlqSvVpFbjdgYRRLysAeEZpJ6S1lg=="],
|
"@ai-sdk/google-vertex/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.69", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-LshR7X3pFugY0o41G2VKTmg1XoGpSl7uoYWfzk6zjVZLhCfeFiwgpOga+eTV4XY1VVpZwKVqRnkDbIL7K2eH5g=="],
|
||||||
|
|
||||||
"@ai-sdk/google-vertex/@ai-sdk/google": ["@ai-sdk/google@3.0.64", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-CbR82EgGPNrj/6q0HtclwuCqe0/pDShyv3nWDP/A9DroujzWXnLMlUJVrgPOsg4b40zQCwwVs2XSKCxvt/4QaA=="],
|
|
||||||
|
|
||||||
"@ai-sdk/google-vertex/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.41", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g=="],
|
"@ai-sdk/google-vertex/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.41", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g=="],
|
||||||
|
|
||||||
@@ -5610,18 +5573,6 @@
|
|||||||
|
|
||||||
"@opencode-ai/web/@shikijs/transformers": ["@shikijs/transformers@3.20.0", "", { "dependencies": { "@shikijs/core": "3.20.0", "@shikijs/types": "3.20.0" } }, "sha512-PrHHMRr3Q5W1qB/42kJW6laqFyWdhrPF2hNR9qjOm1xcSiAO3hAHo7HaVyHE6pMyevmy3i51O8kuGGXC78uK3g=="],
|
"@opencode-ai/web/@shikijs/transformers": ["@shikijs/transformers@3.20.0", "", { "dependencies": { "@shikijs/core": "3.20.0", "@shikijs/types": "3.20.0" } }, "sha512-PrHHMRr3Q5W1qB/42kJW6laqFyWdhrPF2hNR9qjOm1xcSiAO3hAHo7HaVyHE6pMyevmy3i51O8kuGGXC78uK3g=="],
|
||||||
|
|
||||||
"@opentelemetry/exporter-trace-otlp-http/@opentelemetry/resources": ["@opentelemetry/resources@2.6.1", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA=="],
|
|
||||||
|
|
||||||
"@opentelemetry/otlp-transformer/@opentelemetry/resources": ["@opentelemetry/resources@2.6.1", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA=="],
|
|
||||||
|
|
||||||
"@opentelemetry/resources/@opentelemetry/core": ["@opentelemetry/core@2.2.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw=="],
|
|
||||||
|
|
||||||
"@opentelemetry/sdk-logs/@opentelemetry/resources": ["@opentelemetry/resources@2.6.1", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA=="],
|
|
||||||
|
|
||||||
"@opentelemetry/sdk-metrics/@opentelemetry/resources": ["@opentelemetry/resources@2.6.1", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA=="],
|
|
||||||
|
|
||||||
"@opentelemetry/sdk-trace-base/@opentelemetry/resources": ["@opentelemetry/resources@2.6.1", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA=="],
|
|
||||||
|
|
||||||
"@opentui/solid/@babel/core": ["@babel/core@7.28.0", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", "@babel/helpers": "^7.27.6", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.0", "@babel/types": "^7.28.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ=="],
|
"@opentui/solid/@babel/core": ["@babel/core@7.28.0", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", "@babel/helpers": "^7.27.6", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.0", "@babel/types": "^7.28.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ=="],
|
||||||
|
|
||||||
"@opentui/solid/babel-preset-solid": ["babel-preset-solid@1.9.10", "", { "dependencies": { "babel-plugin-jsx-dom-expressions": "^0.40.3" }, "peerDependencies": { "@babel/core": "^7.0.0", "solid-js": "^1.9.10" }, "optionalPeers": ["solid-js"] }, "sha512-HCelrgua/Y+kqO8RyL04JBWS/cVdrtUv/h45GntgQY+cJl4eBcKkCDV3TdMjtKx1nXwRaR9QXslM/Npm1dxdZQ=="],
|
"@opentui/solid/babel-preset-solid": ["babel-preset-solid@1.9.10", "", { "dependencies": { "babel-plugin-jsx-dom-expressions": "^0.40.3" }, "peerDependencies": { "@babel/core": "^7.0.0", "solid-js": "^1.9.10" }, "optionalPeers": ["solid-js"] }, "sha512-HCelrgua/Y+kqO8RyL04JBWS/cVdrtUv/h45GntgQY+cJl4eBcKkCDV3TdMjtKx1nXwRaR9QXslM/Npm1dxdZQ=="],
|
||||||
@@ -5728,7 +5679,7 @@
|
|||||||
|
|
||||||
"accepts/negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="],
|
"accepts/negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="],
|
||||||
|
|
||||||
"ai-gateway-provider/@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@4.0.93", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.69", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-hcXDU8QDwpAzLVTuY932TQVlIij9+iaVTxc5mPGY6yb//JMAAC5hMVhg93IrxlrxWLvMgjezNgoZGwquR+SGnw=="],
|
"ai/@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.95", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@vercel/oidc": "3.1.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ZmUNNbZl3V42xwQzPaNUi+s8eqR2lnrxf0bvB6YbLXpLjHYv0k2Y78t12cNOfY0bxGeuVVTLyk856uLuQIuXEQ=="],
|
||||||
|
|
||||||
"ai-gateway-provider/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.69", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-LshR7X3pFugY0o41G2VKTmg1XoGpSl7uoYWfzk6zjVZLhCfeFiwgpOga+eTV4XY1VVpZwKVqRnkDbIL7K2eH5g=="],
|
"ai-gateway-provider/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.69", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-LshR7X3pFugY0o41G2VKTmg1XoGpSl7uoYWfzk6zjVZLhCfeFiwgpOga+eTV4XY1VVpZwKVqRnkDbIL7K2eH5g=="],
|
||||||
|
|
||||||
@@ -5946,7 +5897,7 @@
|
|||||||
|
|
||||||
"nypm/tinyexec": ["tinyexec@1.1.1", "", {}, "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg=="],
|
"nypm/tinyexec": ["tinyexec@1.1.1", "", {}, "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg=="],
|
||||||
|
|
||||||
"opencode/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.71", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-bUWOzrzR0gJKJO/PLGMR4uH2dqEgqGhrsCV+sSpk4KtOEnUQlfjZI/F7BFlqSvVpFbjdgYRRLysAeEZpJ6S1lg=="],
|
"opencode/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.67", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-FFX4P5Fd6lcQJc2OLngZQkbbJHa0IDDZi087Edb8qRZx6h90krtM61ArbMUL8us/7ZUwojCXnyJ/wQ2Eflx2jQ=="],
|
||||||
|
|
||||||
"opencode/@ai-sdk/openai": ["@ai-sdk/openai@3.0.53", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Wld+Rbc05KaUn08uBt06eEuwcgalcIFtIl32Yp+GxuZXUQwOb6YeAuq+C6da4ch6BurFoqEaLemJVwjBb7x+PQ=="],
|
"opencode/@ai-sdk/openai": ["@ai-sdk/openai@3.0.53", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Wld+Rbc05KaUn08uBt06eEuwcgalcIFtIl32Yp+GxuZXUQwOb6YeAuq+C6da4ch6BurFoqEaLemJVwjBb7x+PQ=="],
|
||||||
|
|
||||||
|
|||||||
@@ -236,6 +236,7 @@ new sst.cloudflare.x.SolidStart("Console", {
|
|||||||
SALESFORCE_INSTANCE_URL,
|
SALESFORCE_INSTANCE_URL,
|
||||||
ZEN_BLACK_PRICE,
|
ZEN_BLACK_PRICE,
|
||||||
ZEN_LITE_PRICE,
|
ZEN_LITE_PRICE,
|
||||||
|
new sst.Secret("ZEN_LITE_COUPON_FIRST_MONTH_100_INVITEES"),
|
||||||
new sst.Secret("ZEN_LIMITS"),
|
new sst.Secret("ZEN_LIMITS"),
|
||||||
new sst.Secret("ZEN_SESSION_SECRET"),
|
new sst.Secret("ZEN_SESSION_SECRET"),
|
||||||
...ZEN_MODELS,
|
...ZEN_MODELS,
|
||||||
|
|||||||
+4
-4
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"nodeModules": {
|
"nodeModules": {
|
||||||
"x86_64-linux": "sha256-YcVW8AGN3TP34CoBoCw+Fx30RL1aveNvxr5eoeOgYeg=",
|
"x86_64-linux": "sha256-VIgTxIjmZ4Bfwwdj/YFmRJdBpPHYhJSY31kh06EXX+0=",
|
||||||
"aarch64-linux": "sha256-G/J3YFfrpEwXSHa25kNyUhYpwPhzNIZf/4v+RCfuslk=",
|
"aarch64-linux": "sha256-9118AS1ED0nrliURgZYBRuF/18RqXpUouhYJRlZ6jeA=",
|
||||||
"aarch64-darwin": "sha256-dNPYrGWKoafk4rHqc34U34TtiJGk87yUv5tKnliQcWs=",
|
"aarch64-darwin": "sha256-ppo3MfSIGKQHJCdYEZiLFRc61PtcJ9J0kAXH1pNIonA=",
|
||||||
"x86_64-darwin": "sha256-1LStvefCajGkbdXobMpk0IQyw9SQcQgGKE+U3Fc0Osw="
|
"x86_64-darwin": "sha256-m+CZSOglBCTfNzbdBX6hXdDqqOzHNMzAddVp6BZVDtU="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,6 @@ stdenvNoCC.mkDerivation {
|
|||||||
--filter './packages/opencode' \
|
--filter './packages/opencode' \
|
||||||
--filter './packages/desktop' \
|
--filter './packages/desktop' \
|
||||||
--filter './packages/app' \
|
--filter './packages/app' \
|
||||||
--filter './packages/shared' \
|
|
||||||
--frozen-lockfile \
|
--frozen-lockfile \
|
||||||
--ignore-scripts \
|
--ignore-scripts \
|
||||||
--no-progress
|
--no-progress
|
||||||
|
|||||||
+17
-18
@@ -7,7 +7,6 @@
|
|||||||
sysctl,
|
sysctl,
|
||||||
makeBinaryWrapper,
|
makeBinaryWrapper,
|
||||||
models-dev,
|
models-dev,
|
||||||
ripgrep,
|
|
||||||
installShellFiles,
|
installShellFiles,
|
||||||
versionCheckHook,
|
versionCheckHook,
|
||||||
writableTmpDirAsHomeHook,
|
writableTmpDirAsHomeHook,
|
||||||
@@ -52,25 +51,25 @@ stdenvNoCC.mkDerivation (finalAttrs: {
|
|||||||
runHook postBuild
|
runHook postBuild
|
||||||
'';
|
'';
|
||||||
|
|
||||||
installPhase = ''
|
installPhase =
|
||||||
runHook preInstall
|
''
|
||||||
|
runHook preInstall
|
||||||
|
|
||||||
install -Dm755 dist/opencode-*/bin/opencode $out/bin/opencode
|
install -Dm755 dist/opencode-*/bin/opencode $out/bin/opencode
|
||||||
install -Dm644 schema.json $out/share/opencode/schema.json
|
install -Dm644 schema.json $out/share/opencode/schema.json
|
||||||
|
''
|
||||||
wrapProgram $out/bin/opencode \
|
# bun runs sysctl to detect if dunning on rosetta2
|
||||||
--prefix PATH : ${
|
+ lib.optionalString stdenvNoCC.hostPlatform.isDarwin ''
|
||||||
lib.makeBinPath (
|
wrapProgram $out/bin/opencode \
|
||||||
[
|
--prefix PATH : ${
|
||||||
ripgrep
|
lib.makeBinPath [
|
||||||
|
sysctl
|
||||||
]
|
]
|
||||||
# bun runs sysctl to detect if dunning on rosetta2
|
}
|
||||||
++ lib.optional stdenvNoCC.hostPlatform.isDarwin sysctl
|
''
|
||||||
)
|
+ ''
|
||||||
}
|
runHook postInstall
|
||||||
|
'';
|
||||||
runHook postInstall
|
|
||||||
'';
|
|
||||||
|
|
||||||
postInstall = lib.optionalString (stdenvNoCC.buildPlatform.canExecute stdenvNoCC.hostPlatform) ''
|
postInstall = lib.optionalString (stdenvNoCC.buildPlatform.canExecute stdenvNoCC.hostPlatform) ''
|
||||||
# trick yargs into also generating zsh completions
|
# trick yargs into also generating zsh completions
|
||||||
|
|||||||
+2
-4
@@ -7,7 +7,7 @@
|
|||||||
"packageManager": "bun@1.3.11",
|
"packageManager": "bun@1.3.11",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "bun run --cwd packages/opencode --conditions=browser src/index.ts",
|
"dev": "bun run --cwd packages/opencode --conditions=browser src/index.ts",
|
||||||
"dev:desktop": "bun --cwd packages/desktop-electron dev",
|
"dev:desktop": "bun --cwd packages/desktop tauri dev",
|
||||||
"dev:web": "bun --cwd packages/app dev",
|
"dev:web": "bun --cwd packages/app dev",
|
||||||
"dev:console": "ulimit -n 10240 2>/dev/null; bun run --cwd packages/console/app dev",
|
"dev:console": "ulimit -n 10240 2>/dev/null; bun run --cwd packages/console/app dev",
|
||||||
"dev:storybook": "bun --cwd packages/storybook storybook",
|
"dev:storybook": "bun --cwd packages/storybook storybook",
|
||||||
@@ -34,8 +34,6 @@
|
|||||||
"@types/cross-spawn": "6.0.6",
|
"@types/cross-spawn": "6.0.6",
|
||||||
"@octokit/rest": "22.0.0",
|
"@octokit/rest": "22.0.0",
|
||||||
"@hono/zod-validator": "0.4.2",
|
"@hono/zod-validator": "0.4.2",
|
||||||
"@opentui/core": "0.1.99",
|
|
||||||
"@opentui/solid": "0.1.99",
|
|
||||||
"ulid": "3.0.1",
|
"ulid": "3.0.1",
|
||||||
"@kobalte/core": "0.13.11",
|
"@kobalte/core": "0.13.11",
|
||||||
"@types/luxon": "3.7.1",
|
"@types/luxon": "3.7.1",
|
||||||
@@ -53,7 +51,7 @@
|
|||||||
"drizzle-kit": "1.0.0-beta.19-d95b7a4",
|
"drizzle-kit": "1.0.0-beta.19-d95b7a4",
|
||||||
"drizzle-orm": "1.0.0-beta.19-d95b7a4",
|
"drizzle-orm": "1.0.0-beta.19-d95b7a4",
|
||||||
"effect": "4.0.0-beta.48",
|
"effect": "4.0.0-beta.48",
|
||||||
"ai": "6.0.168",
|
"ai": "6.0.158",
|
||||||
"cross-spawn": "7.0.6",
|
"cross-spawn": "7.0.6",
|
||||||
"hono": "4.10.7",
|
"hono": "4.10.7",
|
||||||
"hono-openapi": "1.1.2",
|
"hono-openapi": "1.1.2",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@opencode-ai/app",
|
"name": "@opencode-ai/app",
|
||||||
"version": "1.14.18",
|
"version": "1.4.6",
|
||||||
"description": "",
|
"description": "",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
Binary file not shown.
@@ -121,10 +121,10 @@ function SessionProviders(props: ParentProps) {
|
|||||||
function RouterRoot(props: ParentProps<{ appChildren?: JSX.Element }>) {
|
function RouterRoot(props: ParentProps<{ appChildren?: JSX.Element }>) {
|
||||||
return (
|
return (
|
||||||
<AppShellProviders>
|
<AppShellProviders>
|
||||||
{/*<Suspense fallback={<Loading />}>*/}
|
<Suspense fallback={<Loading />}>
|
||||||
{props.appChildren}
|
{props.appChildren}
|
||||||
{props.children}
|
{props.children}
|
||||||
{/*</Suspense>*/}
|
</Suspense>
|
||||||
</AppShellProviders>
|
</AppShellProviders>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -184,22 +184,14 @@ function ConnectionGate(props: ParentProps<{ disableHealthCheck?: boolean }>) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Suspense
|
<Show
|
||||||
|
when={checkMode() === "blocking" ? !startupHealthCheck.loading : startupHealthCheck.state !== "pending"}
|
||||||
fallback={
|
fallback={
|
||||||
<div class="h-dvh w-screen flex flex-col items-center justify-center bg-background-base">
|
<div class="h-dvh w-screen flex flex-col items-center justify-center bg-background-base">
|
||||||
<Splash class="w-16 h-20 opacity-50 animate-pulse" />
|
<Splash class="w-16 h-20 opacity-50 animate-pulse" />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{/*<Show
|
|
||||||
when={checkMode() === "blocking" ? !startupHealthCheck.loading : startupHealthCheck.state !== "pending"}
|
|
||||||
fallback={
|
|
||||||
<div class="h-dvh w-screen flex flex-col items-center justify-center bg-background-base">
|
|
||||||
<Splash class="w-16 h-20 opacity-50 animate-pulse" />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>*/}
|
|
||||||
{checkMode() === "blocking" ? startupHealthCheck() : startupHealthCheck.latest}
|
|
||||||
<Show
|
<Show
|
||||||
when={startupHealthCheck()}
|
when={startupHealthCheck()}
|
||||||
fallback={
|
fallback={
|
||||||
@@ -217,8 +209,7 @@ function ConnectionGate(props: ParentProps<{ disableHealthCheck?: boolean }>) {
|
|||||||
>
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
</Show>
|
</Show>
|
||||||
{/*</Show>*/}
|
</Show>
|
||||||
</Suspense>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,8 +54,6 @@ import { PromptImageAttachments } from "./prompt-input/image-attachments"
|
|||||||
import { PromptDragOverlay } from "./prompt-input/drag-overlay"
|
import { PromptDragOverlay } from "./prompt-input/drag-overlay"
|
||||||
import { promptPlaceholder } from "./prompt-input/placeholder"
|
import { promptPlaceholder } from "./prompt-input/placeholder"
|
||||||
import { ImagePreview } from "@opencode-ai/ui/image-preview"
|
import { ImagePreview } from "@opencode-ai/ui/image-preview"
|
||||||
import { useQuery } from "@tanstack/solid-query"
|
|
||||||
import { loadAgentsQuery, loadProvidersQuery } from "@/context/global-sync/bootstrap"
|
|
||||||
|
|
||||||
interface PromptInputProps {
|
interface PromptInputProps {
|
||||||
class?: string
|
class?: string
|
||||||
@@ -102,7 +100,6 @@ const NON_EMPTY_TEXT = /[^\s\u200B]/
|
|||||||
|
|
||||||
export const PromptInput: Component<PromptInputProps> = (props) => {
|
export const PromptInput: Component<PromptInputProps> = (props) => {
|
||||||
const sdk = useSDK()
|
const sdk = useSDK()
|
||||||
|
|
||||||
const sync = useSync()
|
const sync = useSync()
|
||||||
const local = useLocal()
|
const local = useLocal()
|
||||||
const files = useFile()
|
const files = useFile()
|
||||||
@@ -1252,14 +1249,6 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const agentsQuery = useQuery(() => loadAgentsQuery(sdk.directory))
|
|
||||||
const agentsLoading = () => agentsQuery.isLoading
|
|
||||||
|
|
||||||
const globalProvidersQuery = useQuery(() => loadProvidersQuery(null))
|
|
||||||
const providersQuery = useQuery(() => loadProvidersQuery(sdk.directory))
|
|
||||||
|
|
||||||
const providersLoading = () => agentsLoading() || providersQuery.isLoading || globalProvidersQuery.isLoading
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="relative size-full _max-h-[320px] flex flex-col gap-0">
|
<div class="relative size-full _max-h-[320px] flex flex-col gap-0">
|
||||||
<PromptPopover
|
<PromptPopover
|
||||||
@@ -1455,89 +1444,53 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
|||||||
<span class="truncate text-13-medium text-text-strong">{language.t("prompt.mode.shell")}</span>
|
<span class="truncate text-13-medium text-text-strong">{language.t("prompt.mode.shell")}</span>
|
||||||
<div class="size-4 shrink-0" />
|
<div class="size-4 shrink-0" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-1.5 min-w-0 flex-1 h-7">
|
<div class="flex items-center gap-1.5 min-w-0 flex-1">
|
||||||
<Show when={!agentsLoading()}>
|
<div data-component="prompt-agent-control">
|
||||||
<div data-component="prompt-agent-control">
|
<TooltipKeybind
|
||||||
<TooltipKeybind
|
placement="top"
|
||||||
placement="top"
|
gutter={4}
|
||||||
gutter={4}
|
title={language.t("command.agent.cycle")}
|
||||||
title={language.t("command.agent.cycle")}
|
keybind={command.keybind("agent.cycle")}
|
||||||
keybind={command.keybind("agent.cycle")}
|
>
|
||||||
>
|
<Select
|
||||||
<Select
|
size="normal"
|
||||||
size="normal"
|
options={agentNames()}
|
||||||
options={agentNames()}
|
current={local.agent.current()?.name ?? ""}
|
||||||
current={local.agent.current()?.name ?? ""}
|
onSelect={(value) => {
|
||||||
onSelect={(value) => {
|
local.agent.set(value)
|
||||||
local.agent.set(value)
|
restoreFocus()
|
||||||
restoreFocus()
|
}}
|
||||||
}}
|
class="capitalize max-w-[160px] text-text-base"
|
||||||
class="capitalize max-w-[160px] text-text-base"
|
valueClass="truncate text-13-regular text-text-base"
|
||||||
valueClass="truncate text-13-regular text-text-base"
|
triggerStyle={control()}
|
||||||
triggerStyle={control()}
|
triggerProps={{ "data-action": "prompt-agent" }}
|
||||||
triggerProps={{ "data-action": "prompt-agent" }}
|
variant="ghost"
|
||||||
variant="ghost"
|
/>
|
||||||
/>
|
</TooltipKeybind>
|
||||||
</TooltipKeybind>
|
</div>
|
||||||
</div>
|
<Show when={store.mode !== "shell"}>
|
||||||
</Show>
|
<div data-component="prompt-model-control">
|
||||||
<Show when={!providersLoading()}>
|
<Show
|
||||||
<Show when={store.mode !== "shell"}>
|
when={providers.paid().length > 0}
|
||||||
<div data-component="prompt-model-control">
|
fallback={
|
||||||
<Show
|
|
||||||
when={providers.paid().length > 0}
|
|
||||||
fallback={
|
|
||||||
<TooltipKeybind
|
|
||||||
placement="top"
|
|
||||||
gutter={4}
|
|
||||||
title={language.t("command.model.choose")}
|
|
||||||
keybind={command.keybind("model.choose")}
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
data-action="prompt-model"
|
|
||||||
as="div"
|
|
||||||
variant="ghost"
|
|
||||||
size="normal"
|
|
||||||
class="min-w-0 max-w-[320px] text-13-regular text-text-base group"
|
|
||||||
style={control()}
|
|
||||||
onClick={() => {
|
|
||||||
void import("@/components/dialog-select-model-unpaid").then((x) => {
|
|
||||||
dialog.show(() => <x.DialogSelectModelUnpaid model={local.model} />)
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Show when={local.model.current()?.provider?.id}>
|
|
||||||
<ProviderIcon
|
|
||||||
id={local.model.current()?.provider?.id ?? ""}
|
|
||||||
class="size-4 shrink-0 opacity-40 group-hover:opacity-100 transition-opacity duration-150"
|
|
||||||
style={{ "will-change": "opacity", transform: "translateZ(0)" }}
|
|
||||||
/>
|
|
||||||
</Show>
|
|
||||||
<span class="truncate">
|
|
||||||
{local.model.current()?.name ?? language.t("dialog.model.select.title")}
|
|
||||||
</span>
|
|
||||||
<Icon name="chevron-down" size="small" class="shrink-0" />
|
|
||||||
</Button>
|
|
||||||
</TooltipKeybind>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<TooltipKeybind
|
<TooltipKeybind
|
||||||
placement="top"
|
placement="top"
|
||||||
gutter={4}
|
gutter={4}
|
||||||
title={language.t("command.model.choose")}
|
title={language.t("command.model.choose")}
|
||||||
keybind={command.keybind("model.choose")}
|
keybind={command.keybind("model.choose")}
|
||||||
>
|
>
|
||||||
<ModelSelectorPopover
|
<Button
|
||||||
model={local.model}
|
data-action="prompt-model"
|
||||||
triggerAs={Button}
|
as="div"
|
||||||
triggerProps={{
|
variant="ghost"
|
||||||
variant: "ghost",
|
size="normal"
|
||||||
size: "normal",
|
class="min-w-0 max-w-[320px] text-13-regular text-text-base group"
|
||||||
style: control(),
|
style={control()}
|
||||||
class: "min-w-0 max-w-[320px] text-13-regular text-text-base group",
|
onClick={() => {
|
||||||
"data-action": "prompt-model",
|
void import("@/components/dialog-select-model-unpaid").then((x) => {
|
||||||
|
dialog.show(() => <x.DialogSelectModelUnpaid model={local.model} />)
|
||||||
|
})
|
||||||
}}
|
}}
|
||||||
onClose={restoreFocus}
|
|
||||||
>
|
>
|
||||||
<Show when={local.model.current()?.provider?.id}>
|
<Show when={local.model.current()?.provider?.id}>
|
||||||
<ProviderIcon
|
<ProviderIcon
|
||||||
@@ -1550,35 +1503,67 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
|||||||
{local.model.current()?.name ?? language.t("dialog.model.select.title")}
|
{local.model.current()?.name ?? language.t("dialog.model.select.title")}
|
||||||
</span>
|
</span>
|
||||||
<Icon name="chevron-down" size="small" class="shrink-0" />
|
<Icon name="chevron-down" size="small" class="shrink-0" />
|
||||||
</ModelSelectorPopover>
|
</Button>
|
||||||
</TooltipKeybind>
|
</TooltipKeybind>
|
||||||
</Show>
|
}
|
||||||
</div>
|
>
|
||||||
<div data-component="prompt-variant-control">
|
|
||||||
<TooltipKeybind
|
<TooltipKeybind
|
||||||
placement="top"
|
placement="top"
|
||||||
gutter={4}
|
gutter={4}
|
||||||
title={language.t("command.model.variant.cycle")}
|
title={language.t("command.model.choose")}
|
||||||
keybind={command.keybind("model.variant.cycle")}
|
keybind={command.keybind("model.choose")}
|
||||||
>
|
>
|
||||||
<Select
|
<ModelSelectorPopover
|
||||||
size="normal"
|
model={local.model}
|
||||||
options={variants()}
|
triggerAs={Button}
|
||||||
current={local.model.variant.current() ?? "default"}
|
triggerProps={{
|
||||||
label={(x) => (x === "default" ? language.t("common.default") : x)}
|
variant: "ghost",
|
||||||
onSelect={(value) => {
|
size: "normal",
|
||||||
local.model.variant.set(value === "default" ? undefined : value)
|
style: control(),
|
||||||
restoreFocus()
|
class: "min-w-0 max-w-[320px] text-13-regular text-text-base group",
|
||||||
|
"data-action": "prompt-model",
|
||||||
}}
|
}}
|
||||||
class="capitalize max-w-[160px] text-text-base"
|
onClose={restoreFocus}
|
||||||
valueClass="truncate text-13-regular text-text-base"
|
>
|
||||||
triggerStyle={control()}
|
<Show when={local.model.current()?.provider?.id}>
|
||||||
triggerProps={{ "data-action": "prompt-model-variant" }}
|
<ProviderIcon
|
||||||
variant="ghost"
|
id={local.model.current()?.provider?.id ?? ""}
|
||||||
/>
|
class="size-4 shrink-0 opacity-40 group-hover:opacity-100 transition-opacity duration-150"
|
||||||
|
style={{ "will-change": "opacity", transform: "translateZ(0)" }}
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
<span class="truncate">
|
||||||
|
{local.model.current()?.name ?? language.t("dialog.model.select.title")}
|
||||||
|
</span>
|
||||||
|
<Icon name="chevron-down" size="small" class="shrink-0" />
|
||||||
|
</ModelSelectorPopover>
|
||||||
</TooltipKeybind>
|
</TooltipKeybind>
|
||||||
</div>
|
</Show>
|
||||||
</Show>
|
</div>
|
||||||
|
<div data-component="prompt-variant-control">
|
||||||
|
<TooltipKeybind
|
||||||
|
placement="top"
|
||||||
|
gutter={4}
|
||||||
|
title={language.t("command.model.variant.cycle")}
|
||||||
|
keybind={command.keybind("model.variant.cycle")}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
size="normal"
|
||||||
|
options={variants()}
|
||||||
|
current={local.model.variant.current() ?? "default"}
|
||||||
|
label={(x) => (x === "default" ? language.t("common.default") : x)}
|
||||||
|
onSelect={(value) => {
|
||||||
|
local.model.variant.set(value === "default" ? undefined : value)
|
||||||
|
restoreFocus()
|
||||||
|
}}
|
||||||
|
class="capitalize max-w-[160px] text-text-base"
|
||||||
|
valueClass="truncate text-13-regular text-text-base"
|
||||||
|
triggerStyle={control()}
|
||||||
|
triggerProps={{ "data-action": "prompt-model-variant" }}
|
||||||
|
variant="ghost"
|
||||||
|
/>
|
||||||
|
</TooltipKeybind>
|
||||||
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { Spinner } from "@opencode-ai/ui/spinner"
|
|||||||
import { showToast } from "@opencode-ai/ui/toast"
|
import { showToast } from "@opencode-ai/ui/toast"
|
||||||
import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip"
|
import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip"
|
||||||
import { getFilename } from "@opencode-ai/shared/util/path"
|
import { getFilename } from "@opencode-ai/shared/util/path"
|
||||||
import { createEffect, createMemo, createSignal, For, onMount, Show } from "solid-js"
|
import { createEffect, createMemo, For, Show } from "solid-js"
|
||||||
import { createStore } from "solid-js/store"
|
import { createStore } from "solid-js/store"
|
||||||
import { Portal } from "solid-js/web"
|
import { Portal } from "solid-js/web"
|
||||||
import { useCommand } from "@/context/command"
|
import { useCommand } from "@/context/command"
|
||||||
@@ -16,7 +16,6 @@ import { useLanguage } from "@/context/language"
|
|||||||
import { useLayout } from "@/context/layout"
|
import { useLayout } from "@/context/layout"
|
||||||
import { usePlatform } from "@/context/platform"
|
import { usePlatform } from "@/context/platform"
|
||||||
import { useServer } from "@/context/server"
|
import { useServer } from "@/context/server"
|
||||||
import { useSettings } from "@/context/settings"
|
|
||||||
import { useSync } from "@/context/sync"
|
import { useSync } from "@/context/sync"
|
||||||
import { useTerminal } from "@/context/terminal"
|
import { useTerminal } from "@/context/terminal"
|
||||||
import { focusTerminalById } from "@/pages/session/helpers"
|
import { focusTerminalById } from "@/pages/session/helpers"
|
||||||
@@ -135,7 +134,6 @@ export function SessionHeader() {
|
|||||||
const server = useServer()
|
const server = useServer()
|
||||||
const platform = usePlatform()
|
const platform = usePlatform()
|
||||||
const language = useLanguage()
|
const language = useLanguage()
|
||||||
const settings = useSettings()
|
|
||||||
const sync = useSync()
|
const sync = useSync()
|
||||||
const terminal = useTerminal()
|
const terminal = useTerminal()
|
||||||
const { params, view } = useSessionLayout()
|
const { params, view } = useSessionLayout()
|
||||||
@@ -153,11 +151,6 @@ export function SessionHeader() {
|
|||||||
})
|
})
|
||||||
const hotkey = createMemo(() => command.keybind("file.open"))
|
const hotkey = createMemo(() => command.keybind("file.open"))
|
||||||
const os = createMemo(() => detectOS(platform))
|
const os = createMemo(() => detectOS(platform))
|
||||||
const isDesktopBeta = platform.platform === "desktop" && import.meta.env.VITE_OPENCODE_CHANNEL === "beta"
|
|
||||||
const search = createMemo(() => !isDesktopBeta || settings.general.showSearch())
|
|
||||||
const tree = createMemo(() => !isDesktopBeta || settings.general.showFileTree())
|
|
||||||
const term = createMemo(() => !isDesktopBeta || settings.general.showTerminal())
|
|
||||||
const status = createMemo(() => !isDesktopBeta || settings.general.showStatus())
|
|
||||||
|
|
||||||
const [exists, setExists] = createStore<Partial<Record<OpenApp, boolean>>>({
|
const [exists, setExists] = createStore<Partial<Record<OpenApp, boolean>>>({
|
||||||
finder: true,
|
finder: true,
|
||||||
@@ -269,16 +262,12 @@ export function SessionHeader() {
|
|||||||
.catch((err: unknown) => showRequestError(language, err))
|
.catch((err: unknown) => showRequestError(language, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
const [centerMount, setCenterMount] = createSignal<HTMLElement | null>(null)
|
const centerMount = createMemo(() => document.getElementById("opencode-titlebar-center"))
|
||||||
const [rightMount, setRightMount] = createSignal<HTMLElement | null>(null)
|
const rightMount = createMemo(() => document.getElementById("opencode-titlebar-right"))
|
||||||
onMount(() => {
|
|
||||||
setCenterMount(document.getElementById("opencode-titlebar-center"))
|
|
||||||
setRightMount(document.getElementById("opencode-titlebar-right"))
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Show when={search() && centerMount()}>
|
<Show when={centerMount()}>
|
||||||
{(mount) => (
|
{(mount) => (
|
||||||
<Portal mount={mount()}>
|
<Portal mount={mount()}>
|
||||||
<Button
|
<Button
|
||||||
@@ -426,28 +415,24 @@ export function SessionHeader() {
|
|||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
<div class="flex items-center gap-1">
|
<div class="flex items-center gap-1">
|
||||||
<Show when={status()}>
|
<Tooltip placement="bottom" value={language.t("status.popover.trigger")}>
|
||||||
<Tooltip placement="bottom" value={language.t("status.popover.trigger")}>
|
<StatusPopover />
|
||||||
<StatusPopover />
|
</Tooltip>
|
||||||
</Tooltip>
|
<TooltipKeybind
|
||||||
</Show>
|
title={language.t("command.terminal.toggle")}
|
||||||
<Show when={term()}>
|
keybind={command.keybind("terminal.toggle")}
|
||||||
<TooltipKeybind
|
>
|
||||||
title={language.t("command.terminal.toggle")}
|
<Button
|
||||||
keybind={command.keybind("terminal.toggle")}
|
variant="ghost"
|
||||||
|
class="group/terminal-toggle titlebar-icon w-8 h-6 p-0 box-border shrink-0"
|
||||||
|
onClick={toggleTerminal}
|
||||||
|
aria-label={language.t("command.terminal.toggle")}
|
||||||
|
aria-expanded={view().terminal.opened()}
|
||||||
|
aria-controls="terminal-panel"
|
||||||
>
|
>
|
||||||
<Button
|
<Icon size="small" name={view().terminal.opened() ? "terminal-active" : "terminal"} />
|
||||||
variant="ghost"
|
</Button>
|
||||||
class="group/terminal-toggle titlebar-icon w-8 h-6 p-0 box-border shrink-0"
|
</TooltipKeybind>
|
||||||
onClick={toggleTerminal}
|
|
||||||
aria-label={language.t("command.terminal.toggle")}
|
|
||||||
aria-expanded={view().terminal.opened()}
|
|
||||||
aria-controls="terminal-panel"
|
|
||||||
>
|
|
||||||
<Icon size="small" name={view().terminal.opened() ? "terminal-active" : "terminal"} />
|
|
||||||
</Button>
|
|
||||||
</TooltipKeybind>
|
|
||||||
</Show>
|
|
||||||
|
|
||||||
<div class="hidden md:flex items-center gap-1 shrink-0">
|
<div class="hidden md:flex items-center gap-1 shrink-0">
|
||||||
<TooltipKeybind
|
<TooltipKeybind
|
||||||
@@ -466,32 +451,30 @@ export function SessionHeader() {
|
|||||||
</Button>
|
</Button>
|
||||||
</TooltipKeybind>
|
</TooltipKeybind>
|
||||||
|
|
||||||
<Show when={tree()}>
|
<TooltipKeybind
|
||||||
<TooltipKeybind
|
title={language.t("command.fileTree.toggle")}
|
||||||
title={language.t("command.fileTree.toggle")}
|
keybind={command.keybind("fileTree.toggle")}
|
||||||
keybind={command.keybind("fileTree.toggle")}
|
>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
class="titlebar-icon w-8 h-6 p-0 box-border"
|
||||||
|
onClick={() => layout.fileTree.toggle()}
|
||||||
|
aria-label={language.t("command.fileTree.toggle")}
|
||||||
|
aria-expanded={layout.fileTree.opened()}
|
||||||
|
aria-controls="file-tree-panel"
|
||||||
>
|
>
|
||||||
<Button
|
<div class="relative flex items-center justify-center size-4">
|
||||||
variant="ghost"
|
<Icon
|
||||||
class="titlebar-icon w-8 h-6 p-0 box-border"
|
size="small"
|
||||||
onClick={() => layout.fileTree.toggle()}
|
name={layout.fileTree.opened() ? "file-tree-active" : "file-tree"}
|
||||||
aria-label={language.t("command.fileTree.toggle")}
|
classList={{
|
||||||
aria-expanded={layout.fileTree.opened()}
|
"text-icon-strong": layout.fileTree.opened(),
|
||||||
aria-controls="file-tree-panel"
|
"text-icon-weak": !layout.fileTree.opened(),
|
||||||
>
|
}}
|
||||||
<div class="relative flex items-center justify-center size-4">
|
/>
|
||||||
<Icon
|
</div>
|
||||||
size="small"
|
</Button>
|
||||||
name={layout.fileTree.opened() ? "file-tree-active" : "file-tree"}
|
</TooltipKeybind>
|
||||||
classList={{
|
|
||||||
"text-icon-strong": layout.fileTree.opened(),
|
|
||||||
"text-icon-weak": !layout.fileTree.opened(),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Button>
|
|
||||||
</TooltipKeybind>
|
|
||||||
</Show>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -19,9 +19,6 @@ import {
|
|||||||
sansDefault,
|
sansDefault,
|
||||||
sansFontFamily,
|
sansFontFamily,
|
||||||
sansInput,
|
sansInput,
|
||||||
terminalDefault,
|
|
||||||
terminalFontFamily,
|
|
||||||
terminalInput,
|
|
||||||
useSettings,
|
useSettings,
|
||||||
} from "@/context/settings"
|
} from "@/context/settings"
|
||||||
import { decode64 } from "@/utils/base64"
|
import { decode64 } from "@/utils/base64"
|
||||||
@@ -109,7 +106,6 @@ export const SettingsGeneral: Component = () => {
|
|||||||
|
|
||||||
permission.disableAutoAccept(params.id, value)
|
permission.disableAutoAccept(params.id, value)
|
||||||
}
|
}
|
||||||
const desktop = createMemo(() => platform.platform === "desktop")
|
|
||||||
|
|
||||||
const check = () => {
|
const check = () => {
|
||||||
if (!platform.checkUpdate) return
|
if (!platform.checkUpdate) return
|
||||||
@@ -184,7 +180,6 @@ export const SettingsGeneral: Component = () => {
|
|||||||
const soundOptions = [noneSound, ...SOUND_OPTIONS]
|
const soundOptions = [noneSound, ...SOUND_OPTIONS]
|
||||||
const mono = () => monoInput(settings.appearance.font())
|
const mono = () => monoInput(settings.appearance.font())
|
||||||
const sans = () => sansInput(settings.appearance.uiFont())
|
const sans = () => sansInput(settings.appearance.uiFont())
|
||||||
const terminal = () => terminalInput(settings.appearance.terminalFont())
|
|
||||||
|
|
||||||
const soundSelectProps = (
|
const soundSelectProps = (
|
||||||
enabled: () => boolean,
|
enabled: () => boolean,
|
||||||
@@ -284,74 +279,6 @@ export const SettingsGeneral: Component = () => {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const AdvancedSection = () => (
|
|
||||||
<div class="flex flex-col gap-1">
|
|
||||||
<h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.advanced")}</h3>
|
|
||||||
|
|
||||||
<SettingsList>
|
|
||||||
<SettingsRow
|
|
||||||
title={language.t("settings.general.row.showFileTree.title")}
|
|
||||||
description={language.t("settings.general.row.showFileTree.description")}
|
|
||||||
>
|
|
||||||
<div data-action="settings-show-file-tree">
|
|
||||||
<Switch
|
|
||||||
checked={settings.general.showFileTree()}
|
|
||||||
onChange={(checked) => settings.general.setShowFileTree(checked)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</SettingsRow>
|
|
||||||
|
|
||||||
<SettingsRow
|
|
||||||
title={language.t("settings.general.row.showNavigation.title")}
|
|
||||||
description={language.t("settings.general.row.showNavigation.description")}
|
|
||||||
>
|
|
||||||
<div data-action="settings-show-navigation">
|
|
||||||
<Switch
|
|
||||||
checked={settings.general.showNavigation()}
|
|
||||||
onChange={(checked) => settings.general.setShowNavigation(checked)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</SettingsRow>
|
|
||||||
|
|
||||||
<SettingsRow
|
|
||||||
title={language.t("settings.general.row.showSearch.title")}
|
|
||||||
description={language.t("settings.general.row.showSearch.description")}
|
|
||||||
>
|
|
||||||
<div data-action="settings-show-search">
|
|
||||||
<Switch
|
|
||||||
checked={settings.general.showSearch()}
|
|
||||||
onChange={(checked) => settings.general.setShowSearch(checked)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</SettingsRow>
|
|
||||||
|
|
||||||
<SettingsRow
|
|
||||||
title={language.t("settings.general.row.showTerminal.title")}
|
|
||||||
description={language.t("settings.general.row.showTerminal.description")}
|
|
||||||
>
|
|
||||||
<div data-action="settings-show-terminal">
|
|
||||||
<Switch
|
|
||||||
checked={settings.general.showTerminal()}
|
|
||||||
onChange={(checked) => settings.general.setShowTerminal(checked)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</SettingsRow>
|
|
||||||
|
|
||||||
<SettingsRow
|
|
||||||
title={language.t("settings.general.row.showStatus.title")}
|
|
||||||
description={language.t("settings.general.row.showStatus.description")}
|
|
||||||
>
|
|
||||||
<div data-action="settings-show-status">
|
|
||||||
<Switch
|
|
||||||
checked={settings.general.showStatus()}
|
|
||||||
onChange={(checked) => settings.general.setShowStatus(checked)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</SettingsRow>
|
|
||||||
</SettingsList>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
const AppearanceSection = () => (
|
const AppearanceSection = () => (
|
||||||
<div class="flex flex-col gap-1">
|
<div class="flex flex-col gap-1">
|
||||||
<h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.appearance")}</h3>
|
<h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.appearance")}</h3>
|
||||||
@@ -455,29 +382,6 @@ export const SettingsGeneral: Component = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</SettingsRow>
|
</SettingsRow>
|
||||||
|
|
||||||
<SettingsRow
|
|
||||||
title={language.t("settings.general.row.terminalFont.title")}
|
|
||||||
description={language.t("settings.general.row.terminalFont.description")}
|
|
||||||
>
|
|
||||||
<div class="w-full sm:w-[220px]">
|
|
||||||
<TextField
|
|
||||||
data-action="settings-terminal-font"
|
|
||||||
label={language.t("settings.general.row.terminalFont.title")}
|
|
||||||
hideLabel
|
|
||||||
type="text"
|
|
||||||
value={terminal()}
|
|
||||||
onChange={(value) => settings.appearance.setTerminalFont(value)}
|
|
||||||
placeholder={terminalDefault}
|
|
||||||
spellcheck={false}
|
|
||||||
autocorrect="off"
|
|
||||||
autocomplete="off"
|
|
||||||
autocapitalize="off"
|
|
||||||
class="text-12-regular"
|
|
||||||
style={{ "font-family": terminalFontFamily(settings.appearance.terminalFont()) }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</SettingsRow>
|
|
||||||
</SettingsList>
|
</SettingsList>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@@ -623,7 +527,6 @@ export const SettingsGeneral: Component = () => {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
console.log(import.meta.env)
|
|
||||||
return (
|
return (
|
||||||
<div class="flex flex-col h-full overflow-y-auto no-scrollbar px-4 pb-10 sm:px-10 sm:pb-10">
|
<div class="flex flex-col h-full overflow-y-auto no-scrollbar px-4 pb-10 sm:px-10 sm:pb-10">
|
||||||
<div class="sticky top-0 z-10 bg-[linear-gradient(to_bottom,var(--surface-stronger-non-alpha)_calc(100%_-_24px),transparent)]">
|
<div class="sticky top-0 z-10 bg-[linear-gradient(to_bottom,var(--surface-stronger-non-alpha)_calc(100%_-_24px),transparent)]">
|
||||||
@@ -706,10 +609,6 @@ export const SettingsGeneral: Component = () => {
|
|||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<Show when={desktop() && import.meta.env.VITE_OPENCODE_CHANNEL === "beta"}>
|
|
||||||
<AdvancedSection />
|
|
||||||
</Show>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { useLanguage } from "@/context/language"
|
|||||||
import { usePlatform } from "@/context/platform"
|
import { usePlatform } from "@/context/platform"
|
||||||
import { useSDK } from "@/context/sdk"
|
import { useSDK } from "@/context/sdk"
|
||||||
import { useServer } from "@/context/server"
|
import { useServer } from "@/context/server"
|
||||||
import { terminalFontFamily, useSettings } from "@/context/settings"
|
import { monoFontFamily, useSettings } from "@/context/settings"
|
||||||
import type { LocalPTY } from "@/context/terminal"
|
import type { LocalPTY } from "@/context/terminal"
|
||||||
import { disposeIfDisposable, getHoveredLinkText, setOptionIfSupported } from "@/utils/runtime-adapters"
|
import { disposeIfDisposable, getHoveredLinkText, setOptionIfSupported } from "@/utils/runtime-adapters"
|
||||||
import { terminalWriter } from "@/utils/terminal-writer"
|
import { terminalWriter } from "@/utils/terminal-writer"
|
||||||
@@ -191,7 +191,7 @@ export const Terminal = (props: TerminalProps) => {
|
|||||||
const scrollY = typeof local.pty.scrollY === "number" ? local.pty.scrollY : undefined
|
const scrollY = typeof local.pty.scrollY === "number" ? local.pty.scrollY : undefined
|
||||||
let ws: WebSocket | undefined
|
let ws: WebSocket | undefined
|
||||||
let term: Term | undefined
|
let term: Term | undefined
|
||||||
let _ghostty: Ghostty
|
let ghostty: Ghostty
|
||||||
let serializeAddon: SerializeAddon
|
let serializeAddon: SerializeAddon
|
||||||
let fitAddon: FitAddon
|
let fitAddon: FitAddon
|
||||||
let handleResize: () => void
|
let handleResize: () => void
|
||||||
@@ -300,7 +300,7 @@ export const Terminal = (props: TerminalProps) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
const font = terminalFontFamily(settings.appearance.terminalFont())
|
const font = monoFontFamily(settings.appearance.font())
|
||||||
if (!term) return
|
if (!term) return
|
||||||
setOptionIfSupported(term, "fontFamily", font)
|
setOptionIfSupported(term, "fontFamily", font)
|
||||||
scheduleFit()
|
scheduleFit()
|
||||||
@@ -360,7 +360,7 @@ export const Terminal = (props: TerminalProps) => {
|
|||||||
cols: restoreSize?.cols,
|
cols: restoreSize?.cols,
|
||||||
rows: restoreSize?.rows,
|
rows: restoreSize?.rows,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontFamily: terminalFontFamily(settings.appearance.terminalFont()),
|
fontFamily: monoFontFamily(settings.appearance.font()),
|
||||||
allowTransparency: false,
|
allowTransparency: false,
|
||||||
convertEol: false,
|
convertEol: false,
|
||||||
theme: terminalColors(),
|
theme: terminalColors(),
|
||||||
@@ -372,7 +372,7 @@ export const Terminal = (props: TerminalProps) => {
|
|||||||
cleanup()
|
cleanup()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_ghostty = g
|
ghostty = g
|
||||||
term = t
|
term = t
|
||||||
output = terminalWriter((data, done) =>
|
output = terminalWriter((data, done) =>
|
||||||
t.write(data, () => {
|
t.write(data, () => {
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import { useLayout } from "@/context/layout"
|
|||||||
import { usePlatform } from "@/context/platform"
|
import { usePlatform } from "@/context/platform"
|
||||||
import { useCommand } from "@/context/command"
|
import { useCommand } from "@/context/command"
|
||||||
import { useLanguage } from "@/context/language"
|
import { useLanguage } from "@/context/language"
|
||||||
import { useSettings } from "@/context/settings"
|
|
||||||
import { applyPath, backPath, forwardPath } from "./titlebar-history"
|
import { applyPath, backPath, forwardPath } from "./titlebar-history"
|
||||||
|
|
||||||
type TauriDesktopWindow = {
|
type TauriDesktopWindow = {
|
||||||
@@ -41,7 +40,6 @@ export function Titlebar() {
|
|||||||
const platform = usePlatform()
|
const platform = usePlatform()
|
||||||
const command = useCommand()
|
const command = useCommand()
|
||||||
const language = useLanguage()
|
const language = useLanguage()
|
||||||
const settings = useSettings()
|
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
@@ -80,7 +78,6 @@ export function Titlebar() {
|
|||||||
const canBack = createMemo(() => history.index > 0)
|
const canBack = createMemo(() => history.index > 0)
|
||||||
const canForward = createMemo(() => history.index < history.stack.length - 1)
|
const canForward = createMemo(() => history.index < history.stack.length - 1)
|
||||||
const hasProjects = createMemo(() => layout.projects.list().length > 0)
|
const hasProjects = createMemo(() => layout.projects.list().length > 0)
|
||||||
const nav = createMemo(() => import.meta.env.VITE_OPENCODE_CHANNEL !== "beta" || settings.general.showNavigation())
|
|
||||||
|
|
||||||
const back = () => {
|
const back = () => {
|
||||||
const next = backPath(history)
|
const next = backPath(history)
|
||||||
@@ -255,47 +252,41 @@ export function Titlebar() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
<div
|
<Show when={hasProjects()}>
|
||||||
class="flex items-center shrink-0"
|
<div
|
||||||
classList={{
|
class="flex items-center gap-0 transition-transform"
|
||||||
"-translate-x-[36px]": layout.sidebar.opened() && !!params.dir,
|
classList={{
|
||||||
"duration-180 ease-out": !layout.sidebar.opened(),
|
"translate-x-0": !layout.sidebar.opened(),
|
||||||
"duration-180 ease-in": layout.sidebar.opened(),
|
"-translate-x-[36px]": layout.sidebar.opened(),
|
||||||
}}
|
"duration-180 ease-out": !layout.sidebar.opened(),
|
||||||
>
|
"duration-180 ease-in": layout.sidebar.opened(),
|
||||||
<Show when={hasProjects() && nav()}>
|
}}
|
||||||
<div class="flex items-center gap-0 transition-transform">
|
>
|
||||||
<Tooltip placement="bottom" value={language.t("common.goBack")} openDelay={2000}>
|
<Tooltip placement="bottom" value={language.t("common.goBack")} openDelay={2000}>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
icon="chevron-left"
|
icon="chevron-left"
|
||||||
class="titlebar-icon w-6 h-6 p-0 box-border"
|
class="titlebar-icon w-6 h-6 p-0 box-border"
|
||||||
disabled={!canBack()}
|
disabled={!canBack()}
|
||||||
onClick={back}
|
onClick={back}
|
||||||
aria-label={language.t("common.goBack")}
|
aria-label={language.t("common.goBack")}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip placement="bottom" value={language.t("common.goForward")} openDelay={2000}>
|
<Tooltip placement="bottom" value={language.t("common.goForward")} openDelay={2000}>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
icon="chevron-right"
|
icon="chevron-right"
|
||||||
class="titlebar-icon w-6 h-6 p-0 box-border"
|
class="titlebar-icon w-6 h-6 p-0 box-border"
|
||||||
disabled={!canForward()}
|
disabled={!canForward()}
|
||||||
onClick={forward}
|
onClick={forward}
|
||||||
aria-label={language.t("common.goForward")}
|
aria-label={language.t("common.goForward")}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
<div id="opencode-titlebar-left" class="flex items-center gap-3 min-w-0 px-2" />
|
|
||||||
{["beta", "dev"].includes(import.meta.env.VITE_OPENCODE_CHANNEL) && (
|
|
||||||
<div class="bg-icon-interactive-base text-[#FFF] font-medium px-2 rounded-sm uppercase font-mono">
|
|
||||||
{import.meta.env.VITE_OPENCODE_CHANNEL.toUpperCase()}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="opencode-titlebar-left" class="flex items-center gap-3 min-w-0 px-2" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="min-w-0 flex items-center justify-center pointer-events-none">
|
<div class="min-w-0 flex items-center justify-center pointer-events-none">
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import type { ProjectMeta } from "./global-sync/types"
|
|||||||
import { SESSION_RECENT_LIMIT } from "./global-sync/types"
|
import { SESSION_RECENT_LIMIT } from "./global-sync/types"
|
||||||
import { sanitizeProject } from "./global-sync/utils"
|
import { sanitizeProject } from "./global-sync/utils"
|
||||||
import { formatServerError } from "@/utils/server-errors"
|
import { formatServerError } from "@/utils/server-errors"
|
||||||
import { queryOptions, skipToken, useQueryClient } from "@tanstack/solid-query"
|
|
||||||
|
|
||||||
type GlobalStore = {
|
type GlobalStore = {
|
||||||
ready: boolean
|
ready: boolean
|
||||||
@@ -42,9 +41,6 @@ type GlobalStore = {
|
|||||||
reload: undefined | "pending" | "complete"
|
reload: undefined | "pending" | "complete"
|
||||||
}
|
}
|
||||||
|
|
||||||
export const loadSessionsQuery = (directory: string) =>
|
|
||||||
queryOptions<null>({ queryKey: [directory, "loadSessions"], queryFn: skipToken })
|
|
||||||
|
|
||||||
function createGlobalSync() {
|
function createGlobalSync() {
|
||||||
const globalSDK = useGlobalSDK()
|
const globalSDK = useGlobalSDK()
|
||||||
const language = useLanguage()
|
const language = useLanguage()
|
||||||
@@ -71,7 +67,6 @@ function createGlobalSync() {
|
|||||||
config: {},
|
config: {},
|
||||||
reload: undefined,
|
reload: undefined,
|
||||||
})
|
})
|
||||||
const queryClient = useQueryClient()
|
|
||||||
|
|
||||||
let active = true
|
let active = true
|
||||||
let projectWritten = false
|
let projectWritten = false
|
||||||
@@ -203,50 +198,43 @@ function createGlobalSync() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const limit = Math.max(store.limit + SESSION_RECENT_LIMIT, SESSION_RECENT_LIMIT)
|
const limit = Math.max(store.limit + SESSION_RECENT_LIMIT, SESSION_RECENT_LIMIT)
|
||||||
const promise = queryClient
|
const promise = loadRootSessionsWithFallback({
|
||||||
.fetchQuery({
|
directory,
|
||||||
...loadSessionsQuery(directory),
|
limit,
|
||||||
queryFn: () =>
|
list: (query) => globalSDK.client.session.list(query),
|
||||||
loadRootSessionsWithFallback({
|
})
|
||||||
directory,
|
.then((x) => {
|
||||||
limit,
|
const nonArchived = (x.data ?? [])
|
||||||
list: (query) => globalSDK.client.session.list(query),
|
.filter((s) => !!s?.id)
|
||||||
})
|
.filter((s) => !s.time?.archived)
|
||||||
.then((x) => {
|
.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0))
|
||||||
const nonArchived = (x.data ?? [])
|
const limit = store.limit
|
||||||
.filter((s) => !!s?.id)
|
const childSessions = store.session.filter((s) => !!s.parentID)
|
||||||
.filter((s) => !s.time?.archived)
|
const sessions = trimSessions([...nonArchived, ...childSessions], {
|
||||||
.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0))
|
limit,
|
||||||
const limit = store.limit
|
permission: store.permission,
|
||||||
const childSessions = store.session.filter((s) => !!s.parentID)
|
})
|
||||||
const sessions = trimSessions([...nonArchived, ...childSessions], {
|
setStore(
|
||||||
limit,
|
"sessionTotal",
|
||||||
permission: store.permission,
|
estimateRootSessionTotal({
|
||||||
})
|
count: nonArchived.length,
|
||||||
setStore(
|
limit: x.limit,
|
||||||
"sessionTotal",
|
limited: x.limited,
|
||||||
estimateRootSessionTotal({
|
}),
|
||||||
count: nonArchived.length,
|
)
|
||||||
limit: x.limit,
|
setStore("session", reconcile(sessions, { key: "id" }))
|
||||||
limited: x.limited,
|
cleanupDroppedSessionCaches(store, setStore, sessions, setSessionTodo)
|
||||||
}),
|
sessionMeta.set(directory, { limit })
|
||||||
)
|
})
|
||||||
setStore("session", reconcile(sessions, { key: "id" }))
|
.catch((err) => {
|
||||||
cleanupDroppedSessionCaches(store, setStore, sessions, setSessionTodo)
|
console.error("Failed to load sessions", err)
|
||||||
sessionMeta.set(directory, { limit })
|
const project = getFilename(directory)
|
||||||
})
|
showToast({
|
||||||
.catch((err) => {
|
variant: "error",
|
||||||
console.error("Failed to load sessions", err)
|
title: language.t("toast.session.listFailed.title", { project }),
|
||||||
const project = getFilename(directory)
|
description: formatServerError(err, language.t),
|
||||||
showToast({
|
})
|
||||||
variant: "error",
|
|
||||||
title: language.t("toast.session.listFailed.title", { project }),
|
|
||||||
description: formatServerError(err, language.t),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.then(() => null),
|
|
||||||
})
|
})
|
||||||
.then(() => {})
|
|
||||||
|
|
||||||
sessionLoads.set(directory, promise)
|
sessionLoads.set(directory, promise)
|
||||||
void promise.finally(() => {
|
void promise.finally(() => {
|
||||||
@@ -262,7 +250,7 @@ function createGlobalSync() {
|
|||||||
if (pending) return pending
|
if (pending) return pending
|
||||||
|
|
||||||
children.pin(directory)
|
children.pin(directory)
|
||||||
const promise = Promise.resolve().then(async () => {
|
const promise = (async () => {
|
||||||
const child = children.ensureChild(directory)
|
const child = children.ensureChild(directory)
|
||||||
const cache = children.vcsCache.get(directory)
|
const cache = children.vcsCache.get(directory)
|
||||||
if (!cache) return
|
if (!cache) return
|
||||||
@@ -281,9 +269,8 @@ function createGlobalSync() {
|
|||||||
vcsCache: cache,
|
vcsCache: cache,
|
||||||
loadSessions,
|
loadSessions,
|
||||||
translate: language.t,
|
translate: language.t,
|
||||||
queryClient,
|
|
||||||
})
|
})
|
||||||
})
|
})()
|
||||||
|
|
||||||
booting.set(directory, promise)
|
booting.set(directory, promise)
|
||||||
void promise.finally(() => {
|
void promise.finally(() => {
|
||||||
@@ -359,7 +346,6 @@ function createGlobalSync() {
|
|||||||
translate: language.t,
|
translate: language.t,
|
||||||
formatMoreCount: (count) => language.t("common.moreCountSuffix", { count }),
|
formatMoreCount: (count) => language.t("common.moreCountSuffix", { count }),
|
||||||
setGlobalStore: setBootStore,
|
setGlobalStore: setBootStore,
|
||||||
queryClient,
|
|
||||||
})
|
})
|
||||||
bootedAt = Date.now()
|
bootedAt = Date.now()
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ import { reconcile, type SetStoreFunction, type Store } from "solid-js/store"
|
|||||||
import type { State, VcsCache } from "./types"
|
import type { State, VcsCache } from "./types"
|
||||||
import { cmp, normalizeAgentList, normalizeProviderList } from "./utils"
|
import { cmp, normalizeAgentList, normalizeProviderList } from "./utils"
|
||||||
import { formatServerError } from "@/utils/server-errors"
|
import { formatServerError } from "@/utils/server-errors"
|
||||||
import { QueryClient, queryOptions, skipToken } from "@tanstack/solid-query"
|
|
||||||
import { loadSessionsQuery } from "../global-sync"
|
|
||||||
|
|
||||||
type GlobalStore = {
|
type GlobalStore = {
|
||||||
ready: boolean
|
ready: boolean
|
||||||
@@ -73,7 +71,6 @@ export async function bootstrapGlobal(input: {
|
|||||||
translate: (key: string, vars?: Record<string, string | number>) => string
|
translate: (key: string, vars?: Record<string, string | number>) => string
|
||||||
formatMoreCount: (count: number) => string
|
formatMoreCount: (count: number) => string
|
||||||
setGlobalStore: SetStoreFunction<GlobalStore>
|
setGlobalStore: SetStoreFunction<GlobalStore>
|
||||||
queryClient: QueryClient
|
|
||||||
}) {
|
}) {
|
||||||
const fast = [
|
const fast = [
|
||||||
() =>
|
() =>
|
||||||
@@ -83,16 +80,11 @@ export async function bootstrapGlobal(input: {
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
() =>
|
() =>
|
||||||
input.queryClient.fetchQuery({
|
retry(() =>
|
||||||
...loadProvidersQuery(null),
|
input.globalSDK.provider.list().then((x) => {
|
||||||
queryFn: () =>
|
input.setGlobalStore("provider", normalizeProviderList(x.data!))
|
||||||
retry(() =>
|
}),
|
||||||
input.globalSDK.provider.list().then((x) => {
|
),
|
||||||
input.setGlobalStore("provider", normalizeProviderList(x.data!))
|
|
||||||
return null
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const slow = [
|
const slow = [
|
||||||
@@ -180,12 +172,6 @@ function warmSessions(input: {
|
|||||||
).then(() => undefined)
|
).then(() => undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const loadProvidersQuery = (directory: string | null) =>
|
|
||||||
queryOptions<null>({ queryKey: [directory, "providers"], queryFn: skipToken })
|
|
||||||
|
|
||||||
export const loadAgentsQuery = (directory: string | null) =>
|
|
||||||
queryOptions<null>({ queryKey: [directory, "agents"], queryFn: skipToken })
|
|
||||||
|
|
||||||
export async function bootstrapDirectory(input: {
|
export async function bootstrapDirectory(input: {
|
||||||
directory: string
|
directory: string
|
||||||
sdk: OpencodeClient
|
sdk: OpencodeClient
|
||||||
@@ -200,7 +186,6 @@ export async function bootstrapDirectory(input: {
|
|||||||
project: Project[]
|
project: Project[]
|
||||||
provider: ProviderListResponse
|
provider: ProviderListResponse
|
||||||
}
|
}
|
||||||
queryClient: QueryClient
|
|
||||||
}) {
|
}) {
|
||||||
const loading = input.store.status !== "complete"
|
const loading = input.store.status !== "complete"
|
||||||
const seededProject = projectID(input.directory, input.global.project)
|
const seededProject = projectID(input.directory, input.global.project)
|
||||||
@@ -222,7 +207,97 @@ export async function bootstrapDirectory(input: {
|
|||||||
input.setStore("lsp", [])
|
input.setStore("lsp", [])
|
||||||
if (loading) input.setStore("status", "partial")
|
if (loading) input.setStore("status", "partial")
|
||||||
|
|
||||||
const fast = [() => Promise.resolve(input.loadSessions(input.directory))]
|
const fast = [
|
||||||
|
() => retry(() => input.sdk.app.agents().then((x) => input.setStore("agent", normalizeAgentList(x.data)))),
|
||||||
|
() => retry(() => input.sdk.config.get().then((x) => input.setStore("config", x.data!))),
|
||||||
|
() => retry(() => input.sdk.session.status().then((x) => input.setStore("session_status", x.data!))),
|
||||||
|
]
|
||||||
|
|
||||||
|
const slow = [
|
||||||
|
() =>
|
||||||
|
seededProject
|
||||||
|
? Promise.resolve()
|
||||||
|
: retry(() => input.sdk.project.current()).then((x) => input.setStore("project", x.data!.id)),
|
||||||
|
() =>
|
||||||
|
seededPath
|
||||||
|
? Promise.resolve()
|
||||||
|
: retry(() =>
|
||||||
|
input.sdk.path.get().then((x) => {
|
||||||
|
input.setStore("path", x.data!)
|
||||||
|
const next = projectID(x.data?.directory ?? input.directory, input.global.project)
|
||||||
|
if (next) input.setStore("project", next)
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
() =>
|
||||||
|
retry(() =>
|
||||||
|
input.sdk.vcs.get().then((x) => {
|
||||||
|
const next = x.data ?? input.store.vcs
|
||||||
|
input.setStore("vcs", next)
|
||||||
|
if (next) input.vcsCache.setStore("value", next)
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
() => retry(() => input.sdk.command.list().then((x) => input.setStore("command", x.data ?? []))),
|
||||||
|
() =>
|
||||||
|
retry(() =>
|
||||||
|
input.sdk.permission.list().then((x) => {
|
||||||
|
const ids = (x.data ?? []).map((perm) => perm?.sessionID).filter((id): id is string => !!id)
|
||||||
|
const grouped = groupBySession(
|
||||||
|
(x.data ?? []).filter((perm): perm is PermissionRequest => !!perm?.id && !!perm.sessionID),
|
||||||
|
)
|
||||||
|
return warmSessions({ ids, store: input.store, setStore: input.setStore, sdk: input.sdk }).then(() =>
|
||||||
|
batch(() => {
|
||||||
|
for (const sessionID of Object.keys(input.store.permission)) {
|
||||||
|
if (grouped[sessionID]) continue
|
||||||
|
input.setStore("permission", sessionID, [])
|
||||||
|
}
|
||||||
|
for (const [sessionID, permissions] of Object.entries(grouped)) {
|
||||||
|
input.setStore(
|
||||||
|
"permission",
|
||||||
|
sessionID,
|
||||||
|
reconcile(
|
||||||
|
permissions.filter((p) => !!p?.id).sort((a, b) => cmp(a.id, b.id)),
|
||||||
|
{ key: "id" },
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
() =>
|
||||||
|
retry(() =>
|
||||||
|
input.sdk.question.list().then((x) => {
|
||||||
|
const ids = (x.data ?? []).map((question) => question?.sessionID).filter((id): id is string => !!id)
|
||||||
|
const grouped = groupBySession((x.data ?? []).filter((q): q is QuestionRequest => !!q?.id && !!q.sessionID))
|
||||||
|
return warmSessions({ ids, store: input.store, setStore: input.setStore, sdk: input.sdk }).then(() =>
|
||||||
|
batch(() => {
|
||||||
|
for (const sessionID of Object.keys(input.store.question)) {
|
||||||
|
if (grouped[sessionID]) continue
|
||||||
|
input.setStore("question", sessionID, [])
|
||||||
|
}
|
||||||
|
for (const [sessionID, questions] of Object.entries(grouped)) {
|
||||||
|
input.setStore(
|
||||||
|
"question",
|
||||||
|
sessionID,
|
||||||
|
reconcile(
|
||||||
|
questions.filter((q) => !!q?.id).sort((a, b) => cmp(a.id, b.id)),
|
||||||
|
{ key: "id" },
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
() => Promise.resolve(input.loadSessions(input.directory)),
|
||||||
|
() =>
|
||||||
|
retry(() =>
|
||||||
|
input.sdk.mcp.status().then((x) => {
|
||||||
|
input.setStore("mcp", x.data!)
|
||||||
|
input.setStore("mcp_ready", true)
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
const errs = errors(await runAll(fast))
|
const errs = errors(await runAll(fast))
|
||||||
if (errs.length > 0) {
|
if (errs.length > 0) {
|
||||||
@@ -235,138 +310,36 @@ export async function bootstrapDirectory(input: {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
;(async () => {
|
await waitForPaint()
|
||||||
const slow = [
|
const slowErrs = errors(await runAll(slow))
|
||||||
() =>
|
if (slowErrs.length > 0) {
|
||||||
input.queryClient.ensureQueryData({
|
console.error("Failed to finish bootstrap instance", slowErrs[0])
|
||||||
...loadAgentsQuery(input.directory),
|
const project = getFilename(input.directory)
|
||||||
queryFn: () =>
|
showToast({
|
||||||
retry(() => input.sdk.app.agents().then((x) => input.setStore("agent", normalizeAgentList(x.data)))).then(
|
variant: "error",
|
||||||
() => null,
|
title: input.translate("toast.project.reloadFailed.title", { project }),
|
||||||
),
|
description: formatServerError(slowErrs[0], input.translate),
|
||||||
}),
|
})
|
||||||
() => retry(() => input.sdk.config.get().then((x) => input.setStore("config", x.data!))),
|
}
|
||||||
() => retry(() => input.sdk.session.status().then((x) => input.setStore("session_status", x.data!))),
|
|
||||||
() =>
|
|
||||||
seededProject
|
|
||||||
? Promise.resolve()
|
|
||||||
: retry(() => input.sdk.project.current()).then((x) => input.setStore("project", x.data!.id)),
|
|
||||||
() =>
|
|
||||||
seededPath
|
|
||||||
? Promise.resolve()
|
|
||||||
: retry(() =>
|
|
||||||
input.sdk.path.get().then((x) => {
|
|
||||||
input.setStore("path", x.data!)
|
|
||||||
const next = projectID(x.data?.directory ?? input.directory, input.global.project)
|
|
||||||
if (next) input.setStore("project", next)
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
() =>
|
|
||||||
retry(() =>
|
|
||||||
input.sdk.vcs.get().then((x) => {
|
|
||||||
const next = x.data ?? input.store.vcs
|
|
||||||
input.setStore("vcs", next)
|
|
||||||
if (next) input.vcsCache.setStore("value", next)
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
() => retry(() => input.sdk.command.list().then((x) => input.setStore("command", x.data ?? []))),
|
|
||||||
() =>
|
|
||||||
retry(() =>
|
|
||||||
input.sdk.permission.list().then((x) => {
|
|
||||||
const ids = (x.data ?? []).map((perm) => perm?.sessionID).filter((id): id is string => !!id)
|
|
||||||
const grouped = groupBySession(
|
|
||||||
(x.data ?? []).filter((perm): perm is PermissionRequest => !!perm?.id && !!perm.sessionID),
|
|
||||||
)
|
|
||||||
return warmSessions({ ids, store: input.store, setStore: input.setStore, sdk: input.sdk }).then(() =>
|
|
||||||
batch(() => {
|
|
||||||
for (const sessionID of Object.keys(input.store.permission)) {
|
|
||||||
if (grouped[sessionID]) continue
|
|
||||||
input.setStore("permission", sessionID, [])
|
|
||||||
}
|
|
||||||
for (const [sessionID, permissions] of Object.entries(grouped)) {
|
|
||||||
input.setStore(
|
|
||||||
"permission",
|
|
||||||
sessionID,
|
|
||||||
reconcile(
|
|
||||||
permissions.filter((p) => !!p?.id).sort((a, b) => cmp(a.id, b.id)),
|
|
||||||
{ key: "id" },
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
() =>
|
|
||||||
retry(() =>
|
|
||||||
input.sdk.question.list().then((x) => {
|
|
||||||
const ids = (x.data ?? []).map((question) => question?.sessionID).filter((id): id is string => !!id)
|
|
||||||
const grouped = groupBySession((x.data ?? []).filter((q): q is QuestionRequest => !!q?.id && !!q.sessionID))
|
|
||||||
return warmSessions({ ids, store: input.store, setStore: input.setStore, sdk: input.sdk }).then(() =>
|
|
||||||
batch(() => {
|
|
||||||
for (const sessionID of Object.keys(input.store.question)) {
|
|
||||||
if (grouped[sessionID]) continue
|
|
||||||
input.setStore("question", sessionID, [])
|
|
||||||
}
|
|
||||||
for (const [sessionID, questions] of Object.entries(grouped)) {
|
|
||||||
input.setStore(
|
|
||||||
"question",
|
|
||||||
sessionID,
|
|
||||||
reconcile(
|
|
||||||
questions.filter((q) => !!q?.id).sort((a, b) => cmp(a.id, b.id)),
|
|
||||||
{ key: "id" },
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
() => Promise.resolve(input.loadSessions(input.directory)),
|
|
||||||
() =>
|
|
||||||
retry(() =>
|
|
||||||
input.sdk.mcp.status().then((x) => {
|
|
||||||
input.setStore("mcp", x.data!)
|
|
||||||
input.setStore("mcp_ready", true)
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
await waitForPaint()
|
if (loading && errs.length === 0 && slowErrs.length === 0) input.setStore("status", "complete")
|
||||||
const slowErrs = errors(await runAll(slow))
|
|
||||||
if (slowErrs.length > 0) {
|
const rev = (providerRev.get(input.directory) ?? 0) + 1
|
||||||
console.error("Failed to finish bootstrap instance", slowErrs[0])
|
providerRev.set(input.directory, rev)
|
||||||
|
void retry(() => input.sdk.provider.list())
|
||||||
|
.then((x) => {
|
||||||
|
if (providerRev.get(input.directory) !== rev) return
|
||||||
|
input.setStore("provider", normalizeProviderList(x.data!))
|
||||||
|
input.setStore("provider_ready", true)
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
if (providerRev.get(input.directory) !== rev) return
|
||||||
|
console.error("Failed to refresh provider list", err)
|
||||||
const project = getFilename(input.directory)
|
const project = getFilename(input.directory)
|
||||||
showToast({
|
showToast({
|
||||||
variant: "error",
|
variant: "error",
|
||||||
title: input.translate("toast.project.reloadFailed.title", { project }),
|
title: input.translate("toast.project.reloadFailed.title", { project }),
|
||||||
description: formatServerError(slowErrs[0], input.translate),
|
description: formatServerError(err, input.translate),
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
if (loading && errs.length === 0 && slowErrs.length === 0) input.setStore("status", "complete")
|
|
||||||
|
|
||||||
const rev = (providerRev.get(input.directory) ?? 0) + 1
|
|
||||||
providerRev.set(input.directory, rev)
|
|
||||||
void input.queryClient.ensureQueryData({
|
|
||||||
...loadSessionsQuery(input.directory),
|
|
||||||
queryFn: () =>
|
|
||||||
retry(() => input.sdk.provider.list())
|
|
||||||
.then((x) => {
|
|
||||||
if (providerRev.get(input.directory) !== rev) return
|
|
||||||
input.setStore("provider", normalizeProviderList(x.data!))
|
|
||||||
input.setStore("provider_ready", true)
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
if (providerRev.get(input.directory) !== rev) console.error("Failed to refresh provider list", err)
|
|
||||||
const project = getFilename(input.directory)
|
|
||||||
showToast({
|
|
||||||
variant: "error",
|
|
||||||
title: input.translate("toast.project.reloadFailed.title", { project }),
|
|
||||||
description: formatServerError(err, input.translate),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.then(() => null),
|
|
||||||
})
|
})
|
||||||
})()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,11 +23,6 @@ export interface Settings {
|
|||||||
autoSave: boolean
|
autoSave: boolean
|
||||||
releaseNotes: boolean
|
releaseNotes: boolean
|
||||||
followup: "queue" | "steer"
|
followup: "queue" | "steer"
|
||||||
showFileTree: boolean
|
|
||||||
showNavigation: boolean
|
|
||||||
showSearch: boolean
|
|
||||||
showStatus: boolean
|
|
||||||
showTerminal: boolean
|
|
||||||
showReasoningSummaries: boolean
|
showReasoningSummaries: boolean
|
||||||
shellToolPartsExpanded: boolean
|
shellToolPartsExpanded: boolean
|
||||||
editToolPartsExpanded: boolean
|
editToolPartsExpanded: boolean
|
||||||
@@ -39,7 +34,6 @@ export interface Settings {
|
|||||||
fontSize: number
|
fontSize: number
|
||||||
mono: string
|
mono: string
|
||||||
sans: string
|
sans: string
|
||||||
terminal: string
|
|
||||||
}
|
}
|
||||||
keybinds: Record<string, string>
|
keybinds: Record<string, string>
|
||||||
permissions: {
|
permissions: {
|
||||||
@@ -51,17 +45,13 @@ export interface Settings {
|
|||||||
|
|
||||||
export const monoDefault = "System Mono"
|
export const monoDefault = "System Mono"
|
||||||
export const sansDefault = "System Sans"
|
export const sansDefault = "System Sans"
|
||||||
export const terminalDefault = "JetBrainsMono Nerd Font Mono"
|
|
||||||
|
|
||||||
const monoFallback =
|
const monoFallback =
|
||||||
'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace'
|
'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace'
|
||||||
const sansFallback = 'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif'
|
const sansFallback = 'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif'
|
||||||
const terminalFallback =
|
|
||||||
'"JetBrainsMono Nerd Font Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace'
|
|
||||||
|
|
||||||
const monoBase = monoFallback
|
const monoBase = monoFallback
|
||||||
const sansBase = sansFallback
|
const sansBase = sansFallback
|
||||||
const terminalBase = terminalFallback
|
|
||||||
|
|
||||||
function input(font: string | undefined) {
|
function input(font: string | undefined) {
|
||||||
return font ?? ""
|
return font ?? ""
|
||||||
@@ -94,24 +84,11 @@ export function sansFontFamily(font: string | undefined) {
|
|||||||
return stack(font, sansBase)
|
return stack(font, sansBase)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function terminalInput(font: string | undefined) {
|
|
||||||
return input(font)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function terminalFontFamily(font: string | undefined) {
|
|
||||||
return stack(font, terminalBase)
|
|
||||||
}
|
|
||||||
|
|
||||||
const defaultSettings: Settings = {
|
const defaultSettings: Settings = {
|
||||||
general: {
|
general: {
|
||||||
autoSave: true,
|
autoSave: true,
|
||||||
releaseNotes: true,
|
releaseNotes: true,
|
||||||
followup: "steer",
|
followup: "steer",
|
||||||
showFileTree: false,
|
|
||||||
showNavigation: false,
|
|
||||||
showSearch: false,
|
|
||||||
showStatus: false,
|
|
||||||
showTerminal: false,
|
|
||||||
showReasoningSummaries: false,
|
showReasoningSummaries: false,
|
||||||
shellToolPartsExpanded: false,
|
shellToolPartsExpanded: false,
|
||||||
editToolPartsExpanded: false,
|
editToolPartsExpanded: false,
|
||||||
@@ -123,7 +100,6 @@ const defaultSettings: Settings = {
|
|||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
mono: "",
|
mono: "",
|
||||||
sans: "",
|
sans: "",
|
||||||
terminal: "",
|
|
||||||
},
|
},
|
||||||
keybinds: {},
|
keybinds: {},
|
||||||
permissions: {
|
permissions: {
|
||||||
@@ -186,26 +162,6 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont
|
|||||||
setFollowup(value: "queue" | "steer") {
|
setFollowup(value: "queue" | "steer") {
|
||||||
setStore("general", "followup", value === "queue" ? "steer" : value)
|
setStore("general", "followup", value === "queue" ? "steer" : value)
|
||||||
},
|
},
|
||||||
showFileTree: withFallback(() => store.general?.showFileTree, defaultSettings.general.showFileTree),
|
|
||||||
setShowFileTree(value: boolean) {
|
|
||||||
setStore("general", "showFileTree", value)
|
|
||||||
},
|
|
||||||
showNavigation: withFallback(() => store.general?.showNavigation, defaultSettings.general.showNavigation),
|
|
||||||
setShowNavigation(value: boolean) {
|
|
||||||
setStore("general", "showNavigation", value)
|
|
||||||
},
|
|
||||||
showSearch: withFallback(() => store.general?.showSearch, defaultSettings.general.showSearch),
|
|
||||||
setShowSearch(value: boolean) {
|
|
||||||
setStore("general", "showSearch", value)
|
|
||||||
},
|
|
||||||
showStatus: withFallback(() => store.general?.showStatus, defaultSettings.general.showStatus),
|
|
||||||
setShowStatus(value: boolean) {
|
|
||||||
setStore("general", "showStatus", value)
|
|
||||||
},
|
|
||||||
showTerminal: withFallback(() => store.general?.showTerminal, defaultSettings.general.showTerminal),
|
|
||||||
setShowTerminal(value: boolean) {
|
|
||||||
setStore("general", "showTerminal", value)
|
|
||||||
},
|
|
||||||
showReasoningSummaries: withFallback(
|
showReasoningSummaries: withFallback(
|
||||||
() => store.general?.showReasoningSummaries,
|
() => store.general?.showReasoningSummaries,
|
||||||
defaultSettings.general.showReasoningSummaries,
|
defaultSettings.general.showReasoningSummaries,
|
||||||
@@ -247,10 +203,6 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont
|
|||||||
setUIFont(value: string) {
|
setUIFont(value: string) {
|
||||||
setStore("appearance", "sans", value.trim() ? value : "")
|
setStore("appearance", "sans", value.trim() ? value : "")
|
||||||
},
|
},
|
||||||
terminalFont: withFallback(() => store.appearance?.terminal, defaultSettings.appearance.terminal),
|
|
||||||
setTerminalFont(value: string) {
|
|
||||||
setStore("appearance", "terminal", value.trim() ? value : "")
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
keybinds: {
|
keybinds: {
|
||||||
get: (action: string) => store.keybinds?.[action],
|
get: (action: string) => store.keybinds?.[action],
|
||||||
|
|||||||
Vendored
+3
-2
@@ -1,14 +1,15 @@
|
|||||||
|
import "solid-js"
|
||||||
|
|
||||||
interface ImportMetaEnv {
|
interface ImportMetaEnv {
|
||||||
readonly VITE_OPENCODE_SERVER_HOST: string
|
readonly VITE_OPENCODE_SERVER_HOST: string
|
||||||
readonly VITE_OPENCODE_SERVER_PORT: string
|
readonly VITE_OPENCODE_SERVER_PORT: string
|
||||||
readonly VITE_OPENCODE_CHANNEL?: "dev" | "beta" | "prod"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ImportMeta {
|
interface ImportMeta {
|
||||||
readonly env: ImportMetaEnv
|
readonly env: ImportMetaEnv
|
||||||
}
|
}
|
||||||
|
|
||||||
export declare module "solid-js" {
|
declare module "solid-js" {
|
||||||
namespace JSX {
|
namespace JSX {
|
||||||
interface Directives {
|
interface Directives {
|
||||||
sortable: true
|
sortable: true
|
||||||
|
|||||||
@@ -565,9 +565,7 @@ export const dict = {
|
|||||||
"settings.general.row.theme.title": "السمة",
|
"settings.general.row.theme.title": "السمة",
|
||||||
"settings.general.row.theme.description": "تخصيص سمة OpenCode.",
|
"settings.general.row.theme.description": "تخصيص سمة OpenCode.",
|
||||||
"settings.general.row.font.title": "خط الكود",
|
"settings.general.row.font.title": "خط الكود",
|
||||||
"settings.general.row.font.description": "خصّص الخط المستخدم في كتل التعليمات البرمجية",
|
"settings.general.row.font.description": "خصّص الخط المستخدم في كتل التعليمات البرمجية والطرفيات",
|
||||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
|
||||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
|
||||||
"settings.general.row.uiFont.title": "خط الواجهة",
|
"settings.general.row.uiFont.title": "خط الواجهة",
|
||||||
"settings.general.row.uiFont.description": "خصّص الخط المستخدم في الواجهة بأكملها",
|
"settings.general.row.uiFont.description": "خصّص الخط المستخدم في الواجهة بأكملها",
|
||||||
"settings.general.row.followup.title": "سلوك المتابعة",
|
"settings.general.row.followup.title": "سلوك المتابعة",
|
||||||
|
|||||||
@@ -572,9 +572,7 @@ export const dict = {
|
|||||||
"settings.general.row.theme.title": "Tema",
|
"settings.general.row.theme.title": "Tema",
|
||||||
"settings.general.row.theme.description": "Personalize como o OpenCode é tematizado.",
|
"settings.general.row.theme.description": "Personalize como o OpenCode é tematizado.",
|
||||||
"settings.general.row.font.title": "Fonte de código",
|
"settings.general.row.font.title": "Fonte de código",
|
||||||
"settings.general.row.font.description": "Personalize a fonte usada em blocos de código",
|
"settings.general.row.font.description": "Personalize a fonte usada em blocos de código e terminais",
|
||||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
|
||||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
|
||||||
"settings.general.row.uiFont.title": "Fonte da interface",
|
"settings.general.row.uiFont.title": "Fonte da interface",
|
||||||
"settings.general.row.uiFont.description": "Personalize a fonte usada em toda a interface",
|
"settings.general.row.uiFont.description": "Personalize a fonte usada em toda a interface",
|
||||||
"settings.general.row.followup.title": "Comportamento de acompanhamento",
|
"settings.general.row.followup.title": "Comportamento de acompanhamento",
|
||||||
|
|||||||
@@ -637,9 +637,7 @@ export const dict = {
|
|||||||
"settings.general.row.theme.title": "Tema",
|
"settings.general.row.theme.title": "Tema",
|
||||||
"settings.general.row.theme.description": "Prilagodi temu OpenCode-a.",
|
"settings.general.row.theme.description": "Prilagodi temu OpenCode-a.",
|
||||||
"settings.general.row.font.title": "Font za kod",
|
"settings.general.row.font.title": "Font za kod",
|
||||||
"settings.general.row.font.description": "Prilagodi font koji se koristi u blokovima koda",
|
"settings.general.row.font.description": "Prilagodi font koji se koristi u blokovima koda i terminalima",
|
||||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
|
||||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
|
||||||
"settings.general.row.uiFont.title": "UI font",
|
"settings.general.row.uiFont.title": "UI font",
|
||||||
"settings.general.row.uiFont.description": "Prilagodi font koji se koristi u cijelom interfejsu",
|
"settings.general.row.uiFont.description": "Prilagodi font koji se koristi u cijelom interfejsu",
|
||||||
"settings.general.row.followup.title": "Ponašanje nadovezivanja",
|
"settings.general.row.followup.title": "Ponašanje nadovezivanja",
|
||||||
|
|||||||
@@ -632,9 +632,7 @@ export const dict = {
|
|||||||
"settings.general.row.theme.title": "Tema",
|
"settings.general.row.theme.title": "Tema",
|
||||||
"settings.general.row.theme.description": "Tilpas hvordan OpenCode er temabestemt.",
|
"settings.general.row.theme.description": "Tilpas hvordan OpenCode er temabestemt.",
|
||||||
"settings.general.row.font.title": "Kode-skrifttype",
|
"settings.general.row.font.title": "Kode-skrifttype",
|
||||||
"settings.general.row.font.description": "Tilpas skrifttypen, der bruges i kodeblokke",
|
"settings.general.row.font.description": "Tilpas skrifttypen, der bruges i kodeblokke og terminaler",
|
||||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
|
||||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
|
||||||
"settings.general.row.uiFont.title": "UI-skrifttype",
|
"settings.general.row.uiFont.title": "UI-skrifttype",
|
||||||
"settings.general.row.uiFont.description": "Tilpas skrifttypen, der bruges i hele brugerfladen",
|
"settings.general.row.uiFont.description": "Tilpas skrifttypen, der bruges i hele brugerfladen",
|
||||||
"settings.general.row.followup.title": "Opfølgningsadfærd",
|
"settings.general.row.followup.title": "Opfølgningsadfærd",
|
||||||
|
|||||||
@@ -582,9 +582,7 @@ export const dict = {
|
|||||||
"settings.general.row.theme.title": "Thema",
|
"settings.general.row.theme.title": "Thema",
|
||||||
"settings.general.row.theme.description": "Das Thema von OpenCode anpassen.",
|
"settings.general.row.theme.description": "Das Thema von OpenCode anpassen.",
|
||||||
"settings.general.row.font.title": "Code-Schriftart",
|
"settings.general.row.font.title": "Code-Schriftart",
|
||||||
"settings.general.row.font.description": "Die in Codeblöcken verwendete Schriftart anpassen",
|
"settings.general.row.font.description": "Die in Codeblöcken und Terminals verwendete Schriftart anpassen",
|
||||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
|
||||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
|
||||||
"settings.general.row.uiFont.title": "UI-Schriftart",
|
"settings.general.row.uiFont.title": "UI-Schriftart",
|
||||||
"settings.general.row.uiFont.description": "Die im gesamten Interface verwendete Schriftart anpassen",
|
"settings.general.row.uiFont.description": "Die im gesamten Interface verwendete Schriftart anpassen",
|
||||||
"settings.general.row.followup.title": "Verhalten bei Folgefragen",
|
"settings.general.row.followup.title": "Verhalten bei Folgefragen",
|
||||||
|
|||||||
@@ -719,7 +719,6 @@ export const dict = {
|
|||||||
"settings.desktop.wsl.description": "Run the OpenCode server inside WSL on Windows.",
|
"settings.desktop.wsl.description": "Run the OpenCode server inside WSL on Windows.",
|
||||||
|
|
||||||
"settings.general.section.appearance": "Appearance",
|
"settings.general.section.appearance": "Appearance",
|
||||||
"settings.general.section.advanced": "Advanced",
|
|
||||||
"settings.general.section.notifications": "System notifications",
|
"settings.general.section.notifications": "System notifications",
|
||||||
"settings.general.section.updates": "Updates",
|
"settings.general.section.updates": "Updates",
|
||||||
"settings.general.section.sounds": "Sound effects",
|
"settings.general.section.sounds": "Sound effects",
|
||||||
@@ -735,25 +734,13 @@ export const dict = {
|
|||||||
"settings.general.row.theme.title": "Theme",
|
"settings.general.row.theme.title": "Theme",
|
||||||
"settings.general.row.theme.description": "Customise how OpenCode is themed.",
|
"settings.general.row.theme.description": "Customise how OpenCode is themed.",
|
||||||
"settings.general.row.font.title": "Code Font",
|
"settings.general.row.font.title": "Code Font",
|
||||||
"settings.general.row.font.description": "Customise the font used in code blocks",
|
"settings.general.row.font.description": "Customise the font used in code blocks and terminals",
|
||||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
|
||||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
|
||||||
"settings.general.row.uiFont.title": "UI Font",
|
"settings.general.row.uiFont.title": "UI Font",
|
||||||
"settings.general.row.uiFont.description": "Customise the font used throughout the interface",
|
"settings.general.row.uiFont.description": "Customise the font used throughout the interface",
|
||||||
"settings.general.row.followup.title": "Follow-up behavior",
|
"settings.general.row.followup.title": "Follow-up behavior",
|
||||||
"settings.general.row.followup.description": "Choose whether follow-up prompts steer immediately or wait in a queue",
|
"settings.general.row.followup.description": "Choose whether follow-up prompts steer immediately or wait in a queue",
|
||||||
"settings.general.row.followup.option.queue": "Queue",
|
"settings.general.row.followup.option.queue": "Queue",
|
||||||
"settings.general.row.followup.option.steer": "Steer",
|
"settings.general.row.followup.option.steer": "Steer",
|
||||||
"settings.general.row.showFileTree.title": "File tree",
|
|
||||||
"settings.general.row.showFileTree.description": "Show the file tree toggle and panel in desktop sessions",
|
|
||||||
"settings.general.row.showNavigation.title": "Navigation controls",
|
|
||||||
"settings.general.row.showNavigation.description": "Show the back and forward buttons in the desktop title bar",
|
|
||||||
"settings.general.row.showSearch.title": "Command palette",
|
|
||||||
"settings.general.row.showSearch.description": "Show the search and command palette button in the desktop title bar",
|
|
||||||
"settings.general.row.showTerminal.title": "Terminal",
|
|
||||||
"settings.general.row.showTerminal.description": "Show the terminal button in the desktop title bar",
|
|
||||||
"settings.general.row.showStatus.title": "Server status",
|
|
||||||
"settings.general.row.showStatus.description": "Show the server status button in the desktop title bar",
|
|
||||||
"settings.general.row.reasoningSummaries.title": "Show reasoning summaries",
|
"settings.general.row.reasoningSummaries.title": "Show reasoning summaries",
|
||||||
"settings.general.row.reasoningSummaries.description": "Display model reasoning summaries in the timeline",
|
"settings.general.row.reasoningSummaries.description": "Display model reasoning summaries in the timeline",
|
||||||
"settings.general.row.shellToolPartsExpanded.title": "Expand shell tool parts",
|
"settings.general.row.shellToolPartsExpanded.title": "Expand shell tool parts",
|
||||||
|
|||||||
@@ -640,9 +640,7 @@ export const dict = {
|
|||||||
"settings.general.row.theme.title": "Tema",
|
"settings.general.row.theme.title": "Tema",
|
||||||
"settings.general.row.theme.description": "Personaliza el tema de OpenCode.",
|
"settings.general.row.theme.description": "Personaliza el tema de OpenCode.",
|
||||||
"settings.general.row.font.title": "Fuente de código",
|
"settings.general.row.font.title": "Fuente de código",
|
||||||
"settings.general.row.font.description": "Personaliza la fuente usada en bloques de código",
|
"settings.general.row.font.description": "Personaliza la fuente usada en bloques de código y terminales",
|
||||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
|
||||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
|
||||||
"settings.general.row.uiFont.title": "Fuente de la interfaz",
|
"settings.general.row.uiFont.title": "Fuente de la interfaz",
|
||||||
"settings.general.row.uiFont.description": "Personaliza la fuente usada en toda la interfaz",
|
"settings.general.row.uiFont.description": "Personaliza la fuente usada en toda la interfaz",
|
||||||
"settings.general.row.followup.title": "Comportamiento de seguimiento",
|
"settings.general.row.followup.title": "Comportamiento de seguimiento",
|
||||||
|
|||||||
@@ -579,9 +579,7 @@ export const dict = {
|
|||||||
"settings.general.row.theme.title": "Thème",
|
"settings.general.row.theme.title": "Thème",
|
||||||
"settings.general.row.theme.description": "Personnaliser le thème d'OpenCode.",
|
"settings.general.row.theme.description": "Personnaliser le thème d'OpenCode.",
|
||||||
"settings.general.row.font.title": "Police de code",
|
"settings.general.row.font.title": "Police de code",
|
||||||
"settings.general.row.font.description": "Personnaliser la police utilisée dans les blocs de code",
|
"settings.general.row.font.description": "Personnaliser la police utilisée dans les blocs de code et les terminaux",
|
||||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
|
||||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
|
||||||
"settings.general.row.uiFont.title": "Police de l'interface",
|
"settings.general.row.uiFont.title": "Police de l'interface",
|
||||||
"settings.general.row.uiFont.description": "Personnaliser la police utilisée dans toute l'interface",
|
"settings.general.row.uiFont.description": "Personnaliser la police utilisée dans toute l'interface",
|
||||||
"settings.general.row.followup.title": "Comportement de suivi",
|
"settings.general.row.followup.title": "Comportement de suivi",
|
||||||
|
|||||||
@@ -569,9 +569,7 @@ export const dict = {
|
|||||||
"settings.general.row.theme.title": "テーマ",
|
"settings.general.row.theme.title": "テーマ",
|
||||||
"settings.general.row.theme.description": "OpenCodeのテーマをカスタマイズします。",
|
"settings.general.row.theme.description": "OpenCodeのテーマをカスタマイズします。",
|
||||||
"settings.general.row.font.title": "コードフォント",
|
"settings.general.row.font.title": "コードフォント",
|
||||||
"settings.general.row.font.description": "コードブロックで使用するフォントをカスタマイズします",
|
"settings.general.row.font.description": "コードブロックとターミナルで使用するフォントをカスタマイズします",
|
||||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
|
||||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
|
||||||
"settings.general.row.uiFont.title": "UIフォント",
|
"settings.general.row.uiFont.title": "UIフォント",
|
||||||
"settings.general.row.uiFont.description": "インターフェース全体で使用するフォントをカスタマイズします",
|
"settings.general.row.uiFont.description": "インターフェース全体で使用するフォントをカスタマイズします",
|
||||||
"settings.general.row.followup.title": "フォローアップの動作",
|
"settings.general.row.followup.title": "フォローアップの動作",
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { dict as en } from "./en"
|
||||||
|
|
||||||
export const dict = {
|
export const dict = {
|
||||||
"command.category.suggested": "추천",
|
"command.category.suggested": "추천",
|
||||||
"command.category.view": "보기",
|
"command.category.view": "보기",
|
||||||
@@ -566,9 +568,7 @@ export const dict = {
|
|||||||
"settings.general.row.theme.title": "테마",
|
"settings.general.row.theme.title": "테마",
|
||||||
"settings.general.row.theme.description": "OpenCode 테마 사용자 지정",
|
"settings.general.row.theme.description": "OpenCode 테마 사용자 지정",
|
||||||
"settings.general.row.font.title": "코드 글꼴",
|
"settings.general.row.font.title": "코드 글꼴",
|
||||||
"settings.general.row.font.description": "코드 블록에 사용되는 글꼴을 사용자 지정",
|
"settings.general.row.font.description": "코드 블록과 터미널에 사용되는 글꼴을 사용자 지정",
|
||||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
|
||||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
|
||||||
"settings.general.row.uiFont.title": "UI 글꼴",
|
"settings.general.row.uiFont.title": "UI 글꼴",
|
||||||
"settings.general.row.uiFont.description": "인터페이스 전반에 사용되는 글꼴을 사용자 지정",
|
"settings.general.row.uiFont.description": "인터페이스 전반에 사용되는 글꼴을 사용자 지정",
|
||||||
"settings.general.row.followup.title": "후속 조치 동작",
|
"settings.general.row.followup.title": "후속 조치 동작",
|
||||||
|
|||||||
@@ -640,9 +640,7 @@ export const dict = {
|
|||||||
"settings.general.row.theme.title": "Tema",
|
"settings.general.row.theme.title": "Tema",
|
||||||
"settings.general.row.theme.description": "Tilpass hvordan OpenCode er tematisert.",
|
"settings.general.row.theme.description": "Tilpass hvordan OpenCode er tematisert.",
|
||||||
"settings.general.row.font.title": "Kodefont",
|
"settings.general.row.font.title": "Kodefont",
|
||||||
"settings.general.row.font.description": "Tilpass skrifttypen som brukes i kodeblokker",
|
"settings.general.row.font.description": "Tilpass skrifttypen som brukes i kodeblokker og terminaler",
|
||||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
|
||||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
|
||||||
"settings.general.row.uiFont.title": "UI-skrift",
|
"settings.general.row.uiFont.title": "UI-skrift",
|
||||||
"settings.general.row.uiFont.description": "Tilpass skrifttypen som brukes i hele grensesnittet",
|
"settings.general.row.uiFont.description": "Tilpass skrifttypen som brukes i hele grensesnittet",
|
||||||
"settings.general.row.followup.title": "Oppfølgingsadferd",
|
"settings.general.row.followup.title": "Oppfølgingsadferd",
|
||||||
|
|||||||
@@ -571,9 +571,7 @@ export const dict = {
|
|||||||
"settings.general.row.theme.title": "Motyw",
|
"settings.general.row.theme.title": "Motyw",
|
||||||
"settings.general.row.theme.description": "Dostosuj motyw OpenCode.",
|
"settings.general.row.theme.description": "Dostosuj motyw OpenCode.",
|
||||||
"settings.general.row.font.title": "Czcionka kodu",
|
"settings.general.row.font.title": "Czcionka kodu",
|
||||||
"settings.general.row.font.description": "Dostosuj czcionkę używaną w blokach kodu",
|
"settings.general.row.font.description": "Dostosuj czcionkę używaną w blokach kodu i terminalach",
|
||||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
|
||||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
|
||||||
"settings.general.row.uiFont.title": "Czcionka interfejsu",
|
"settings.general.row.uiFont.title": "Czcionka interfejsu",
|
||||||
"settings.general.row.uiFont.description": "Dostosuj czcionkę używaną w całym interfejsie",
|
"settings.general.row.uiFont.description": "Dostosuj czcionkę używaną w całym interfejsie",
|
||||||
"settings.general.row.followup.title": "Zachowanie kontynuacji",
|
"settings.general.row.followup.title": "Zachowanie kontynuacji",
|
||||||
|
|||||||
@@ -637,9 +637,7 @@ export const dict = {
|
|||||||
"settings.general.row.theme.title": "Тема",
|
"settings.general.row.theme.title": "Тема",
|
||||||
"settings.general.row.theme.description": "Настройте оформление OpenCode.",
|
"settings.general.row.theme.description": "Настройте оформление OpenCode.",
|
||||||
"settings.general.row.font.title": "Шрифт кода",
|
"settings.general.row.font.title": "Шрифт кода",
|
||||||
"settings.general.row.font.description": "Настройте шрифт, используемый в блоках кода",
|
"settings.general.row.font.description": "Настройте шрифт, используемый в блоках кода и терминалах",
|
||||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
|
||||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
|
||||||
"settings.general.row.uiFont.title": "Шрифт интерфейса",
|
"settings.general.row.uiFont.title": "Шрифт интерфейса",
|
||||||
"settings.general.row.uiFont.description": "Настройте шрифт, используемый во всем интерфейсе",
|
"settings.general.row.uiFont.description": "Настройте шрифт, используемый во всем интерфейсе",
|
||||||
"settings.general.row.followup.title": "Поведение уточняющих вопросов",
|
"settings.general.row.followup.title": "Поведение уточняющих вопросов",
|
||||||
|
|||||||
@@ -631,9 +631,7 @@ export const dict = {
|
|||||||
"settings.general.row.theme.title": "ธีม",
|
"settings.general.row.theme.title": "ธีม",
|
||||||
"settings.general.row.theme.description": "ปรับแต่งวิธีการที่ OpenCode มีธีม",
|
"settings.general.row.theme.description": "ปรับแต่งวิธีการที่ OpenCode มีธีม",
|
||||||
"settings.general.row.font.title": "ฟอนต์โค้ด",
|
"settings.general.row.font.title": "ฟอนต์โค้ด",
|
||||||
"settings.general.row.font.description": "ปรับแต่งฟอนต์ที่ใช้ในบล็อกโค้ด",
|
"settings.general.row.font.description": "ปรับแต่งฟอนต์ที่ใช้ในบล็อกโค้ดและเทอร์มินัล",
|
||||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
|
||||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
|
||||||
"settings.general.row.uiFont.title": "ฟอนต์ UI",
|
"settings.general.row.uiFont.title": "ฟอนต์ UI",
|
||||||
"settings.general.row.uiFont.description": "ปรับแต่งฟอนต์ที่ใช้ทั่วทั้งอินเทอร์เฟซ",
|
"settings.general.row.uiFont.description": "ปรับแต่งฟอนต์ที่ใช้ทั่วทั้งอินเทอร์เฟซ",
|
||||||
"settings.general.row.followup.title": "พฤติกรรมการติดตามผล",
|
"settings.general.row.followup.title": "พฤติกรรมการติดตามผล",
|
||||||
|
|||||||
@@ -644,9 +644,7 @@ export const dict = {
|
|||||||
"settings.general.row.theme.title": "Tema",
|
"settings.general.row.theme.title": "Tema",
|
||||||
"settings.general.row.theme.description": "OpenCode'un temasını özelleştirin.",
|
"settings.general.row.theme.description": "OpenCode'un temasını özelleştirin.",
|
||||||
"settings.general.row.font.title": "Kod Yazı Tipi",
|
"settings.general.row.font.title": "Kod Yazı Tipi",
|
||||||
"settings.general.row.font.description": "Kod bloklarında kullanılan yazı tipini özelleştirin",
|
"settings.general.row.font.description": "Kod bloklarında ve terminallerde kullanılan yazı tipini özelleştirin",
|
||||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
|
||||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
|
||||||
"settings.general.row.uiFont.title": "Arayüz Yazı Tipi",
|
"settings.general.row.uiFont.title": "Arayüz Yazı Tipi",
|
||||||
"settings.general.row.uiFont.description": "Arayüz genelinde kullanılan yazı tipini özelleştirin",
|
"settings.general.row.uiFont.description": "Arayüz genelinde kullanılan yazı tipini özelleştirin",
|
||||||
"settings.general.row.followup.title": "Takip davranışı",
|
"settings.general.row.followup.title": "Takip davranışı",
|
||||||
|
|||||||
@@ -631,9 +631,7 @@ export const dict = {
|
|||||||
"settings.general.row.theme.title": "主题",
|
"settings.general.row.theme.title": "主题",
|
||||||
"settings.general.row.theme.description": "自定义 OpenCode 的主题。",
|
"settings.general.row.theme.description": "自定义 OpenCode 的主题。",
|
||||||
"settings.general.row.font.title": "代码字体",
|
"settings.general.row.font.title": "代码字体",
|
||||||
"settings.general.row.font.description": "自定义代码块使用的字体",
|
"settings.general.row.font.description": "自定义代码块和终端使用的字体",
|
||||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
|
||||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
|
||||||
"settings.general.row.uiFont.title": "界面字体",
|
"settings.general.row.uiFont.title": "界面字体",
|
||||||
"settings.general.row.uiFont.description": "自定义整个界面使用的字体",
|
"settings.general.row.uiFont.description": "自定义整个界面使用的字体",
|
||||||
"settings.general.row.followup.title": "跟进消息行为",
|
"settings.general.row.followup.title": "跟进消息行为",
|
||||||
|
|||||||
@@ -626,9 +626,7 @@ export const dict = {
|
|||||||
"settings.general.row.theme.title": "主題",
|
"settings.general.row.theme.title": "主題",
|
||||||
"settings.general.row.theme.description": "自訂 OpenCode 的主題。",
|
"settings.general.row.theme.description": "自訂 OpenCode 的主題。",
|
||||||
"settings.general.row.font.title": "程式碼字型",
|
"settings.general.row.font.title": "程式碼字型",
|
||||||
"settings.general.row.font.description": "自訂程式碼區塊使用的字型",
|
"settings.general.row.font.description": "自訂程式碼區塊和終端機使用的字型",
|
||||||
"settings.general.row.terminalFont.title": "Terminal Font",
|
|
||||||
"settings.general.row.terminalFont.description": "Customise the font used in the terminal",
|
|
||||||
"settings.general.row.uiFont.title": "介面字型",
|
"settings.general.row.uiFont.title": "介面字型",
|
||||||
"settings.general.row.uiFont.description": "自訂整個介面使用的字型",
|
"settings.general.row.uiFont.description": "自訂整個介面使用的字型",
|
||||||
"settings.general.row.followup.title": "後續追問行為",
|
"settings.general.row.followup.title": "後續追問行為",
|
||||||
|
|||||||
@@ -1,12 +1,5 @@
|
|||||||
@import "@opencode-ai/ui/styles/tailwind";
|
@import "@opencode-ai/ui/styles/tailwind";
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "JetBrainsMono Nerd Font Mono";
|
|
||||||
src: url("/assets/JetBrainsMonoNerdFontMono-Regular.woff2") format("woff2");
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@layer components {
|
@layer components {
|
||||||
@keyframes session-progress-whip {
|
@keyframes session-progress-whip {
|
||||||
0% {
|
0% {
|
||||||
|
|||||||
+177
-183
@@ -13,7 +13,7 @@ import {
|
|||||||
type Accessor,
|
type Accessor,
|
||||||
} from "solid-js"
|
} from "solid-js"
|
||||||
import { makeEventListener } from "@solid-primitives/event-listener"
|
import { makeEventListener } from "@solid-primitives/event-listener"
|
||||||
import { useLocation, useNavigate, useParams } from "@solidjs/router"
|
import { useNavigate, useParams } from "@solidjs/router"
|
||||||
import { useLayout, LocalProject } from "@/context/layout"
|
import { useLayout, LocalProject } from "@/context/layout"
|
||||||
import { useGlobalSync } from "@/context/global-sync"
|
import { useGlobalSync } from "@/context/global-sync"
|
||||||
import { Persist, persisted } from "@/utils/persist"
|
import { Persist, persisted } from "@/utils/persist"
|
||||||
@@ -127,17 +127,14 @@ export default function Layout(props: ParentProps) {
|
|||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const language = useLanguage()
|
const language = useLanguage()
|
||||||
const initialDirectory = decode64(params.dir)
|
const initialDirectory = decode64(params.dir)
|
||||||
const location = useLocation()
|
|
||||||
const route = createMemo(() => {
|
const route = createMemo(() => {
|
||||||
const slug = params.dir
|
const slug = params.dir
|
||||||
if (!slug) return { slug, dir: "" }
|
if (!slug) return { slug, dir: "" }
|
||||||
const dir = decode64(slug)
|
const dir = decode64(slug)
|
||||||
if (!dir) return { slug, dir: "" }
|
if (!dir) return { slug, dir: "" }
|
||||||
const store = globalSync.peek(dir, { bootstrap: false })
|
|
||||||
return {
|
return {
|
||||||
slug,
|
slug,
|
||||||
store,
|
dir: globalSync.peek(dir, { bootstrap: false })[0].path.directory || dir,
|
||||||
dir: store[0].path.directory || dir,
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const availableThemeEntries = createMemo(() => theme.ids().map((id) => [id, theme.themes()[id]] as const))
|
const availableThemeEntries = createMemo(() => theme.ids().map((id) => [id, theme.themes()[id]] as const))
|
||||||
@@ -2103,198 +2100,196 @@ export default function Layout(props: ParentProps) {
|
|||||||
</Show>
|
</Show>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{(project) => (
|
<>
|
||||||
<>
|
<div class="shrink-0 pl-1 py-1">
|
||||||
<div class="shrink-0 pl-1 py-1">
|
<div class="group/project flex items-start justify-between gap-2 py-2 pl-2 pr-0">
|
||||||
<div class="group/project flex items-start justify-between gap-2 py-2 pl-2 pr-0">
|
<div class="flex flex-col min-w-0">
|
||||||
<div class="flex flex-col min-w-0">
|
<InlineEditor
|
||||||
<InlineEditor
|
id={`project:${projectId()}`}
|
||||||
id={`project:${projectId()}`}
|
value={projectName}
|
||||||
value={projectName}
|
onSave={(next) => {
|
||||||
onSave={(next) => {
|
const item = project()
|
||||||
const item = project()
|
if (!item) return
|
||||||
if (!item) return
|
void renameProject(item, next)
|
||||||
void renameProject(item, next)
|
}}
|
||||||
}}
|
class="text-14-medium text-text-strong truncate"
|
||||||
class="text-14-medium text-text-strong truncate"
|
displayClass="text-14-medium text-text-strong truncate"
|
||||||
displayClass="text-14-medium text-text-strong truncate"
|
stopPropagation
|
||||||
stopPropagation
|
/>
|
||||||
/>
|
|
||||||
|
|
||||||
<Tooltip
|
<Tooltip
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
gutter={2}
|
gutter={2}
|
||||||
value={worktree()}
|
value={worktree()}
|
||||||
class="shrink-0"
|
class="shrink-0"
|
||||||
contentStyle={{
|
contentStyle={{
|
||||||
"max-width": "640px",
|
"max-width": "640px",
|
||||||
transform: "translate3d(52px, 0, 0)",
|
transform: "translate3d(52px, 0, 0)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span class="text-12-regular text-text-base truncate select-text">
|
<span class="text-12-regular text-text-base truncate select-text">
|
||||||
{worktree().replace(homedir(), "~")}
|
{worktree().replace(homedir(), "~")}
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
|
||||||
|
|
||||||
<DropdownMenu modal={!sidebarHovering()}>
|
|
||||||
<DropdownMenu.Trigger
|
|
||||||
as={IconButton}
|
|
||||||
icon="dot-grid"
|
|
||||||
variant="ghost"
|
|
||||||
data-action="project-menu"
|
|
||||||
data-project={slug()}
|
|
||||||
class="shrink-0 size-6 rounded-md transition-opacity data-[expanded]:bg-surface-base-active"
|
|
||||||
classList={{
|
|
||||||
"opacity-100": panelProps.mobile || merged(),
|
|
||||||
"opacity-0 group-hover/project:opacity-100 group-focus-within/project:opacity-100 data-[expanded]:opacity-100":
|
|
||||||
!panelProps.mobile && !merged(),
|
|
||||||
}}
|
|
||||||
aria-label={language.t("common.moreOptions")}
|
|
||||||
/>
|
|
||||||
<DropdownMenu.Portal>
|
|
||||||
<DropdownMenu.Content class="mt-1">
|
|
||||||
<DropdownMenu.Item
|
|
||||||
onSelect={() => {
|
|
||||||
const item = project()
|
|
||||||
if (!item) return
|
|
||||||
showEditProjectDialog(item)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<DropdownMenu.ItemLabel>{language.t("common.edit")}</DropdownMenu.ItemLabel>
|
|
||||||
</DropdownMenu.Item>
|
|
||||||
<DropdownMenu.Item
|
|
||||||
data-action="project-workspaces-toggle"
|
|
||||||
data-project={slug()}
|
|
||||||
disabled={!canToggle()}
|
|
||||||
onSelect={() => {
|
|
||||||
const item = project()
|
|
||||||
if (!item) return
|
|
||||||
toggleProjectWorkspaces(item)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<DropdownMenu.ItemLabel>
|
|
||||||
{workspacesEnabled()
|
|
||||||
? language.t("sidebar.workspaces.disable")
|
|
||||||
: language.t("sidebar.workspaces.enable")}
|
|
||||||
</DropdownMenu.ItemLabel>
|
|
||||||
</DropdownMenu.Item>
|
|
||||||
<DropdownMenu.Item
|
|
||||||
data-action="project-clear-notifications"
|
|
||||||
data-project={slug()}
|
|
||||||
disabled={unseenCount() === 0}
|
|
||||||
onSelect={clearNotifications}
|
|
||||||
>
|
|
||||||
<DropdownMenu.ItemLabel>
|
|
||||||
{language.t("sidebar.project.clearNotifications")}
|
|
||||||
</DropdownMenu.ItemLabel>
|
|
||||||
</DropdownMenu.Item>
|
|
||||||
<DropdownMenu.Separator />
|
|
||||||
<DropdownMenu.Item
|
|
||||||
data-action="project-close-menu"
|
|
||||||
data-project={slug()}
|
|
||||||
onSelect={() => {
|
|
||||||
const dir = worktree()
|
|
||||||
if (!dir) return
|
|
||||||
closeProject(dir)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<DropdownMenu.ItemLabel>{language.t("common.close")}</DropdownMenu.ItemLabel>
|
|
||||||
</DropdownMenu.Item>
|
|
||||||
</DropdownMenu.Content>
|
|
||||||
</DropdownMenu.Portal>
|
|
||||||
</DropdownMenu>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex-1 min-h-0 flex flex-col">
|
<DropdownMenu modal={!sidebarHovering()}>
|
||||||
<Show
|
<DropdownMenu.Trigger
|
||||||
when={workspacesEnabled()}
|
as={IconButton}
|
||||||
fallback={
|
icon="dot-grid"
|
||||||
<>
|
variant="ghost"
|
||||||
<div class="shrink-0 py-4">
|
data-action="project-menu"
|
||||||
<Button
|
data-project={slug()}
|
||||||
size="large"
|
class="shrink-0 size-6 rounded-md transition-opacity data-[expanded]:bg-surface-base-active"
|
||||||
icon="new-session"
|
classList={{
|
||||||
class="w-full"
|
"opacity-100": panelProps.mobile || merged(),
|
||||||
onClick={() => {
|
"opacity-0 group-hover/project:opacity-100 group-focus-within/project:opacity-100 data-[expanded]:opacity-100":
|
||||||
const dir = worktree()
|
!panelProps.mobile && !merged(),
|
||||||
if (!dir) return
|
}}
|
||||||
navigateWithSidebarReset(`/${base64Encode(dir)}/session`)
|
aria-label={language.t("common.moreOptions")}
|
||||||
}}
|
/>
|
||||||
>
|
<DropdownMenu.Portal>
|
||||||
{language.t("command.session.new")}
|
<DropdownMenu.Content class="mt-1">
|
||||||
</Button>
|
<DropdownMenu.Item
|
||||||
</div>
|
onSelect={() => {
|
||||||
<div class="flex-1 min-h-0">
|
const item = project()
|
||||||
<LocalWorkspace
|
if (!item) return
|
||||||
ctx={workspaceSidebarCtx}
|
showEditProjectDialog(item)
|
||||||
project={project()}
|
}}
|
||||||
sortNow={sortNow}
|
>
|
||||||
mobile={panelProps.mobile}
|
<DropdownMenu.ItemLabel>{language.t("common.edit")}</DropdownMenu.ItemLabel>
|
||||||
/>
|
</DropdownMenu.Item>
|
||||||
</div>
|
<DropdownMenu.Item
|
||||||
</>
|
data-action="project-workspaces-toggle"
|
||||||
}
|
data-project={slug()}
|
||||||
>
|
disabled={!canToggle()}
|
||||||
|
onSelect={() => {
|
||||||
|
const item = project()
|
||||||
|
if (!item) return
|
||||||
|
toggleProjectWorkspaces(item)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DropdownMenu.ItemLabel>
|
||||||
|
{workspacesEnabled()
|
||||||
|
? language.t("sidebar.workspaces.disable")
|
||||||
|
: language.t("sidebar.workspaces.enable")}
|
||||||
|
</DropdownMenu.ItemLabel>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
<DropdownMenu.Item
|
||||||
|
data-action="project-clear-notifications"
|
||||||
|
data-project={slug()}
|
||||||
|
disabled={unseenCount() === 0}
|
||||||
|
onSelect={clearNotifications}
|
||||||
|
>
|
||||||
|
<DropdownMenu.ItemLabel>
|
||||||
|
{language.t("sidebar.project.clearNotifications")}
|
||||||
|
</DropdownMenu.ItemLabel>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
<DropdownMenu.Separator />
|
||||||
|
<DropdownMenu.Item
|
||||||
|
data-action="project-close-menu"
|
||||||
|
data-project={slug()}
|
||||||
|
onSelect={() => {
|
||||||
|
const dir = worktree()
|
||||||
|
if (!dir) return
|
||||||
|
closeProject(dir)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DropdownMenu.ItemLabel>{language.t("common.close")}</DropdownMenu.ItemLabel>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
</DropdownMenu.Content>
|
||||||
|
</DropdownMenu.Portal>
|
||||||
|
</DropdownMenu>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1 min-h-0 flex flex-col">
|
||||||
|
<Show
|
||||||
|
when={workspacesEnabled()}
|
||||||
|
fallback={
|
||||||
<>
|
<>
|
||||||
<div class="shrink-0 py-4">
|
<div class="shrink-0 py-4">
|
||||||
<Button
|
<Button
|
||||||
size="large"
|
size="large"
|
||||||
icon="plus-small"
|
icon="new-session"
|
||||||
class="w-full"
|
class="w-full"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const item = project()
|
const dir = worktree()
|
||||||
if (!item) return
|
if (!dir) return
|
||||||
void createWorkspace(item)
|
navigateWithSidebarReset(`/${base64Encode(dir)}/session`)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{language.t("workspace.new")}
|
{language.t("command.session.new")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div class="relative flex-1 min-h-0">
|
<div class="flex-1 min-h-0">
|
||||||
<DragDropProvider
|
<LocalWorkspace
|
||||||
onDragStart={handleWorkspaceDragStart}
|
ctx={workspaceSidebarCtx}
|
||||||
onDragEnd={handleWorkspaceDragEnd}
|
project={project()!}
|
||||||
onDragOver={handleWorkspaceDragOver}
|
sortNow={sortNow}
|
||||||
collisionDetector={closestCenter}
|
mobile={panelProps.mobile}
|
||||||
>
|
/>
|
||||||
<DragDropSensors />
|
|
||||||
<ConstrainDragXAxis />
|
|
||||||
<div
|
|
||||||
ref={(el) => {
|
|
||||||
if (!panelProps.mobile) scrollContainerRef = el
|
|
||||||
}}
|
|
||||||
class="size-full flex flex-col py-2 gap-4 overflow-y-auto no-scrollbar [overflow-anchor:none]"
|
|
||||||
>
|
|
||||||
<SortableProvider ids={workspaces()}>
|
|
||||||
<For each={workspaces()}>
|
|
||||||
{(directory) => (
|
|
||||||
<SortableWorkspace
|
|
||||||
ctx={workspaceSidebarCtx}
|
|
||||||
directory={directory}
|
|
||||||
project={project()}
|
|
||||||
sortNow={sortNow}
|
|
||||||
mobile={panelProps.mobile}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
</SortableProvider>
|
|
||||||
</div>
|
|
||||||
<DragOverlay>
|
|
||||||
<WorkspaceDragOverlay
|
|
||||||
sidebarProject={sidebarProject}
|
|
||||||
activeWorkspace={() => store.activeWorkspace}
|
|
||||||
workspaceLabel={workspaceLabel}
|
|
||||||
/>
|
|
||||||
</DragOverlay>
|
|
||||||
</DragDropProvider>
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
</Show>
|
}
|
||||||
</div>
|
>
|
||||||
</>
|
<>
|
||||||
)}
|
<div class="shrink-0 py-4">
|
||||||
|
<Button
|
||||||
|
size="large"
|
||||||
|
icon="plus-small"
|
||||||
|
class="w-full"
|
||||||
|
onClick={() => {
|
||||||
|
const item = project()
|
||||||
|
if (!item) return
|
||||||
|
void createWorkspace(item)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{language.t("workspace.new")}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div class="relative flex-1 min-h-0">
|
||||||
|
<DragDropProvider
|
||||||
|
onDragStart={handleWorkspaceDragStart}
|
||||||
|
onDragEnd={handleWorkspaceDragEnd}
|
||||||
|
onDragOver={handleWorkspaceDragOver}
|
||||||
|
collisionDetector={closestCenter}
|
||||||
|
>
|
||||||
|
<DragDropSensors />
|
||||||
|
<ConstrainDragXAxis />
|
||||||
|
<div
|
||||||
|
ref={(el) => {
|
||||||
|
if (!panelProps.mobile) scrollContainerRef = el
|
||||||
|
}}
|
||||||
|
class="size-full flex flex-col py-2 gap-4 overflow-y-auto no-scrollbar [overflow-anchor:none]"
|
||||||
|
>
|
||||||
|
<SortableProvider ids={workspaces()}>
|
||||||
|
<For each={workspaces()}>
|
||||||
|
{(directory) => (
|
||||||
|
<SortableWorkspace
|
||||||
|
ctx={workspaceSidebarCtx}
|
||||||
|
directory={directory}
|
||||||
|
project={project()!}
|
||||||
|
sortNow={sortNow}
|
||||||
|
mobile={panelProps.mobile}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</SortableProvider>
|
||||||
|
</div>
|
||||||
|
<DragOverlay>
|
||||||
|
<WorkspaceDragOverlay
|
||||||
|
sidebarProject={sidebarProject}
|
||||||
|
activeWorkspace={() => store.activeWorkspace}
|
||||||
|
workspaceLabel={workspaceLabel}
|
||||||
|
/>
|
||||||
|
</DragOverlay>
|
||||||
|
</DragDropProvider>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@@ -2360,7 +2355,6 @@ export default function Layout(props: ParentProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="relative bg-background-base flex-1 min-h-0 min-w-0 flex flex-col select-none [&_input]:select-text [&_textarea]:select-text [&_[contenteditable]]:select-text">
|
<div class="relative bg-background-base flex-1 min-h-0 min-w-0 flex flex-col select-none [&_input]:select-text [&_textarea]:select-text [&_[contenteditable]]:select-text">
|
||||||
{autoselecting() ?? ""}
|
|
||||||
<Titlebar />
|
<Titlebar />
|
||||||
<div class="flex-1 min-h-0 min-w-0 flex">
|
<div class="flex-1 min-h-0 min-w-0 flex">
|
||||||
<div class="flex-1 min-h-0 relative">
|
<div class="flex-1 min-h-0 relative">
|
||||||
|
|||||||
@@ -14,11 +14,10 @@ import { Spinner } from "@opencode-ai/ui/spinner"
|
|||||||
import { Tooltip } from "@opencode-ai/ui/tooltip"
|
import { Tooltip } from "@opencode-ai/ui/tooltip"
|
||||||
import { type Session } from "@opencode-ai/sdk/v2/client"
|
import { type Session } from "@opencode-ai/sdk/v2/client"
|
||||||
import { type LocalProject } from "@/context/layout"
|
import { type LocalProject } from "@/context/layout"
|
||||||
import { loadSessionsQuery, useGlobalSync } from "@/context/global-sync"
|
import { useGlobalSync } from "@/context/global-sync"
|
||||||
import { useLanguage } from "@/context/language"
|
import { useLanguage } from "@/context/language"
|
||||||
import { NewSessionItem, SessionItem, SessionSkeleton } from "./sidebar-items"
|
import { NewSessionItem, SessionItem, SessionSkeleton } from "./sidebar-items"
|
||||||
import { sortedRootSessions, workspaceKey } from "./helpers"
|
import { sortedRootSessions, workspaceKey } from "./helpers"
|
||||||
import { useQuery } from "@tanstack/solid-query"
|
|
||||||
|
|
||||||
type InlineEditorComponent = (props: {
|
type InlineEditorComponent = (props: {
|
||||||
id: string
|
id: string
|
||||||
@@ -317,11 +316,12 @@ export const SortableWorkspace = (props: {
|
|||||||
})
|
})
|
||||||
const open = createMemo(() => props.ctx.workspaceExpanded(props.directory, local()))
|
const open = createMemo(() => props.ctx.workspaceExpanded(props.directory, local()))
|
||||||
const boot = createMemo(() => open() || active())
|
const boot = createMemo(() => open() || active())
|
||||||
|
const booted = createMemo((prev) => prev || workspaceStore.status === "complete", false)
|
||||||
const count = createMemo(() => sessions()?.length ?? 0)
|
const count = createMemo(() => sessions()?.length ?? 0)
|
||||||
const hasMore = createMemo(() => workspaceStore.sessionTotal > count())
|
const hasMore = createMemo(() => workspaceStore.sessionTotal > count())
|
||||||
const query = useQuery(() => ({ ...loadSessionsQuery(props.project.worktree) }))
|
|
||||||
const busy = createMemo(() => props.ctx.isBusy(props.directory))
|
const busy = createMemo(() => props.ctx.isBusy(props.directory))
|
||||||
const loading = () => query.isLoading
|
const wasBusy = createMemo((prev) => prev || busy(), false)
|
||||||
|
const loading = createMemo(() => open() && !booted() && count() === 0 && !wasBusy())
|
||||||
const touch = createMediaQuery("(hover: none)")
|
const touch = createMediaQuery("(hover: none)")
|
||||||
const showNew = createMemo(() => !loading() && (touch() || count() === 0 || (active() && !params.id)))
|
const showNew = createMemo(() => !loading() && (touch() || count() === 0 || (active() && !params.id)))
|
||||||
const loadMore = async () => {
|
const loadMore = async () => {
|
||||||
@@ -426,7 +426,7 @@ export const SortableWorkspace = (props: {
|
|||||||
mobile={props.mobile}
|
mobile={props.mobile}
|
||||||
ctx={props.ctx}
|
ctx={props.ctx}
|
||||||
showNew={showNew}
|
showNew={showNew}
|
||||||
loading={() => query.isLoading && count() === 0}
|
loading={loading}
|
||||||
sessions={sessions}
|
sessions={sessions}
|
||||||
hasMore={hasMore}
|
hasMore={hasMore}
|
||||||
loadMore={loadMore}
|
loadMore={loadMore}
|
||||||
@@ -452,10 +452,10 @@ export const LocalWorkspace = (props: {
|
|||||||
})
|
})
|
||||||
const slug = createMemo(() => base64Encode(props.project.worktree))
|
const slug = createMemo(() => base64Encode(props.project.worktree))
|
||||||
const sessions = createMemo(() => sortedRootSessions(workspace().store, props.sortNow()))
|
const sessions = createMemo(() => sortedRootSessions(workspace().store, props.sortNow()))
|
||||||
|
const booted = createMemo((prev) => prev || workspace().store.status === "complete", false)
|
||||||
const count = createMemo(() => sessions()?.length ?? 0)
|
const count = createMemo(() => sessions()?.length ?? 0)
|
||||||
const query = useQuery(() => ({ ...loadSessionsQuery(props.project.worktree) }))
|
const loading = createMemo(() => !booted() && count() === 0)
|
||||||
const hasMore = createMemo(() => workspace().store.sessionTotal > count())
|
const hasMore = createMemo(() => workspace().store.sessionTotal > count())
|
||||||
const loading = () => query.isLoading && count() === 0
|
|
||||||
const loadMore = async () => {
|
const loadMore = async () => {
|
||||||
workspace().setStore("limit", (limit) => (limit ?? 0) + 5)
|
workspace().setStore("limit", (limit) => (limit ?? 0) + 5)
|
||||||
await globalSync.project.loadSessions(props.project.worktree)
|
await globalSync.project.loadSessions(props.project.worktree)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { Project, UserMessage } from "@opencode-ai/sdk/v2"
|
import type { Project, UserMessage, VcsFileDiff } from "@opencode-ai/sdk/v2"
|
||||||
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
||||||
import { createQuery, skipToken, useMutation, useQueryClient } from "@tanstack/solid-query"
|
import { useMutation } from "@tanstack/solid-query"
|
||||||
import {
|
import {
|
||||||
batch,
|
batch,
|
||||||
onCleanup,
|
onCleanup,
|
||||||
@@ -13,7 +13,6 @@ import {
|
|||||||
on,
|
on,
|
||||||
onMount,
|
onMount,
|
||||||
untrack,
|
untrack,
|
||||||
createResource,
|
|
||||||
} from "solid-js"
|
} from "solid-js"
|
||||||
import { makeEventListener } from "@solid-primitives/event-listener"
|
import { makeEventListener } from "@solid-primitives/event-listener"
|
||||||
import { createMediaQuery } from "@solid-primitives/media"
|
import { createMediaQuery } from "@solid-primitives/media"
|
||||||
@@ -324,7 +323,6 @@ export default function Page() {
|
|||||||
const local = useLocal()
|
const local = useLocal()
|
||||||
const file = useFile()
|
const file = useFile()
|
||||||
const sync = useSync()
|
const sync = useSync()
|
||||||
const queryClient = useQueryClient()
|
|
||||||
const dialog = useDialog()
|
const dialog = useDialog()
|
||||||
const language = useLanguage()
|
const language = useLanguage()
|
||||||
const sdk = useSDK()
|
const sdk = useSDK()
|
||||||
@@ -434,6 +432,7 @@ export default function Page() {
|
|||||||
const info = createMemo(() => (params.id ? sync.session.get(params.id) : undefined))
|
const info = createMemo(() => (params.id ? sync.session.get(params.id) : undefined))
|
||||||
const isChildSession = createMemo(() => !!info()?.parentID)
|
const isChildSession = createMemo(() => !!info()?.parentID)
|
||||||
const diffs = createMemo(() => (params.id ? list(sync.data.session_diff[params.id]) : []))
|
const diffs = createMemo(() => (params.id ? list(sync.data.session_diff[params.id]) : []))
|
||||||
|
const sessionCount = createMemo(() => Math.max(info()?.summary?.files ?? 0, diffs().length))
|
||||||
const canReview = createMemo(() => !!sync.project)
|
const canReview = createMemo(() => !!sync.project)
|
||||||
const reviewTab = createMemo(() => isDesktop())
|
const reviewTab = createMemo(() => isDesktop())
|
||||||
const tabState = createSessionTabs({
|
const tabState = createSessionTabs({
|
||||||
@@ -519,6 +518,26 @@ export default function Page() {
|
|||||||
deferRender: false,
|
deferRender: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const [vcs, setVcs] = createStore<{
|
||||||
|
diff: {
|
||||||
|
git: VcsFileDiff[]
|
||||||
|
branch: VcsFileDiff[]
|
||||||
|
}
|
||||||
|
ready: {
|
||||||
|
git: boolean
|
||||||
|
branch: boolean
|
||||||
|
}
|
||||||
|
}>({
|
||||||
|
diff: {
|
||||||
|
git: [] as VcsFileDiff[],
|
||||||
|
branch: [] as VcsFileDiff[],
|
||||||
|
},
|
||||||
|
ready: {
|
||||||
|
git: false,
|
||||||
|
branch: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
const [followup, setFollowup] = persisted(
|
const [followup, setFollowup] = persisted(
|
||||||
Persist.workspace(sdk.directory, "followup", ["followup.v1"]),
|
Persist.workspace(sdk.directory, "followup", ["followup.v1"]),
|
||||||
createStore<{
|
createStore<{
|
||||||
@@ -552,6 +571,68 @@ export default function Page() {
|
|||||||
let todoTimer: number | undefined
|
let todoTimer: number | undefined
|
||||||
let diffFrame: number | undefined
|
let diffFrame: number | undefined
|
||||||
let diffTimer: number | undefined
|
let diffTimer: number | undefined
|
||||||
|
const vcsTask = new Map<VcsMode, Promise<void>>()
|
||||||
|
const vcsRun = new Map<VcsMode, number>()
|
||||||
|
|
||||||
|
const bumpVcs = (mode: VcsMode) => {
|
||||||
|
const next = (vcsRun.get(mode) ?? 0) + 1
|
||||||
|
vcsRun.set(mode, next)
|
||||||
|
return next
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetVcs = (mode?: VcsMode) => {
|
||||||
|
const list = mode ? [mode] : (["git", "branch"] as const)
|
||||||
|
list.forEach((item) => {
|
||||||
|
bumpVcs(item)
|
||||||
|
vcsTask.delete(item)
|
||||||
|
setVcs("diff", item, [])
|
||||||
|
setVcs("ready", item, false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadVcs = (mode: VcsMode, force = false) => {
|
||||||
|
if (sync.project?.vcs !== "git") return Promise.resolve()
|
||||||
|
if (!force && vcs.ready[mode]) return Promise.resolve()
|
||||||
|
|
||||||
|
if (force) {
|
||||||
|
if (vcsTask.has(mode)) bumpVcs(mode)
|
||||||
|
vcsTask.delete(mode)
|
||||||
|
setVcs("ready", mode, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
const current = vcsTask.get(mode)
|
||||||
|
if (current) return current
|
||||||
|
|
||||||
|
const run = bumpVcs(mode)
|
||||||
|
|
||||||
|
const task = sdk.client.vcs
|
||||||
|
.diff({ mode })
|
||||||
|
.then((result) => {
|
||||||
|
if (vcsRun.get(mode) !== run) return
|
||||||
|
setVcs("diff", mode, list(result.data))
|
||||||
|
setVcs("ready", mode, true)
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
if (vcsRun.get(mode) !== run) return
|
||||||
|
console.debug("[session-review] failed to load vcs diff", { mode, error })
|
||||||
|
setVcs("diff", mode, [])
|
||||||
|
setVcs("ready", mode, true)
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
if (vcsTask.get(mode) === task) vcsTask.delete(mode)
|
||||||
|
})
|
||||||
|
|
||||||
|
vcsTask.set(mode, task)
|
||||||
|
return task
|
||||||
|
}
|
||||||
|
|
||||||
|
const refreshVcs = () => {
|
||||||
|
resetVcs()
|
||||||
|
const mode = untrack(vcsMode)
|
||||||
|
if (!mode) return
|
||||||
|
if (!untrack(wantsReview)) return
|
||||||
|
void loadVcs(mode, true)
|
||||||
|
}
|
||||||
|
|
||||||
createComputed((prev) => {
|
createComputed((prev) => {
|
||||||
const open = desktopReviewOpen()
|
const open = desktopReviewOpen()
|
||||||
@@ -582,52 +663,21 @@ export default function Page() {
|
|||||||
list.push("turn")
|
list.push("turn")
|
||||||
return list
|
return list
|
||||||
})
|
})
|
||||||
const mobileChanges = createMemo(() => !isDesktop() && store.mobileTab === "changes")
|
|
||||||
const wantsReview = createMemo(() =>
|
|
||||||
isDesktop()
|
|
||||||
? desktopFileTreeOpen() || (desktopReviewOpen() && activeTab() === "review")
|
|
||||||
: store.mobileTab === "changes",
|
|
||||||
)
|
|
||||||
const vcsMode = createMemo<VcsMode | undefined>(() => {
|
const vcsMode = createMemo<VcsMode | undefined>(() => {
|
||||||
if (store.changes === "git" || store.changes === "branch") return store.changes
|
if (store.changes === "git" || store.changes === "branch") return store.changes
|
||||||
})
|
})
|
||||||
const vcsKey = createMemo(
|
const reviewDiffs = createMemo(() => {
|
||||||
() => ["session-vcs", sdk.directory, sync.data.vcs?.branch ?? "", sync.data.vcs?.default_branch ?? ""] as const,
|
if (store.changes === "git") return list(vcs.diff.git)
|
||||||
)
|
if (store.changes === "branch") return list(vcs.diff.branch)
|
||||||
const vcsQuery = createQuery(() => {
|
|
||||||
const mode = vcsMode()
|
|
||||||
const enabled = wantsReview() && sync.project?.vcs === "git"
|
|
||||||
|
|
||||||
return {
|
|
||||||
queryKey: [...vcsKey(), mode] as const,
|
|
||||||
enabled,
|
|
||||||
staleTime: Number.POSITIVE_INFINITY,
|
|
||||||
gcTime: 60 * 1000,
|
|
||||||
queryFn: mode
|
|
||||||
? () =>
|
|
||||||
sdk.client.vcs
|
|
||||||
.diff({ mode })
|
|
||||||
.then((result) => list(result.data))
|
|
||||||
.catch((error) => {
|
|
||||||
console.debug("[session-review] failed to load vcs diff", { mode, error })
|
|
||||||
return []
|
|
||||||
})
|
|
||||||
: skipToken,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const refreshVcs = () => void queryClient.invalidateQueries({ queryKey: vcsKey() })
|
|
||||||
const reviewDiffs = () => {
|
|
||||||
if (store.changes === "git" || store.changes === "branch")
|
|
||||||
// avoids suspense
|
|
||||||
return vcsQuery.isFetched ? (vcsQuery.data ?? []) : []
|
|
||||||
return turnDiffs()
|
return turnDiffs()
|
||||||
}
|
})
|
||||||
const reviewCount = () => reviewDiffs().length
|
const reviewCount = createMemo(() => reviewDiffs().length)
|
||||||
const hasReview = () => reviewCount() > 0
|
const hasReview = createMemo(() => reviewCount() > 0)
|
||||||
const reviewReady = () => {
|
const reviewReady = createMemo(() => {
|
||||||
if (store.changes === "git" || store.changes === "branch") return !vcsQuery.isPending
|
if (store.changes === "git") return vcs.ready.git
|
||||||
|
if (store.changes === "branch") return vcs.ready.branch
|
||||||
return true
|
return true
|
||||||
}
|
})
|
||||||
|
|
||||||
const newSessionWorktree = createMemo(() => {
|
const newSessionWorktree = createMemo(() => {
|
||||||
if (store.newSessionWorktree === "create") return "create"
|
if (store.newSessionWorktree === "create") return "create"
|
||||||
@@ -755,9 +805,8 @@ export default function Page() {
|
|||||||
|
|
||||||
const hasScrollGesture = () => Date.now() - ui.scrollGesture < scrollGestureWindowMs
|
const hasScrollGesture = () => Date.now() - ui.scrollGesture < scrollGestureWindowMs
|
||||||
|
|
||||||
const [sessionSync] = createResource(
|
createEffect(
|
||||||
() => [sdk.directory, params.id] as const,
|
on([() => sdk.directory, () => params.id] as const, ([, id]) => {
|
||||||
([directory, id]) => {
|
|
||||||
if (refreshFrame !== undefined) cancelAnimationFrame(refreshFrame)
|
if (refreshFrame !== undefined) cancelAnimationFrame(refreshFrame)
|
||||||
if (refreshTimer !== undefined) window.clearTimeout(refreshTimer)
|
if (refreshTimer !== undefined) window.clearTimeout(refreshTimer)
|
||||||
refreshFrame = undefined
|
refreshFrame = undefined
|
||||||
@@ -768,10 +817,13 @@ export default function Page() {
|
|||||||
const stale = !cached
|
const stale = !cached
|
||||||
? false
|
? false
|
||||||
: (() => {
|
: (() => {
|
||||||
const info = getSessionPrefetch(directory, id)
|
const info = getSessionPrefetch(sdk.directory, id)
|
||||||
if (!info) return true
|
if (!info) return true
|
||||||
return Date.now() - info.at > SESSION_PREFETCH_TTL
|
return Date.now() - info.at > SESSION_PREFETCH_TTL
|
||||||
})()
|
})()
|
||||||
|
untrack(() => {
|
||||||
|
void sync.session.sync(id)
|
||||||
|
})
|
||||||
|
|
||||||
refreshFrame = requestAnimationFrame(() => {
|
refreshFrame = requestAnimationFrame(() => {
|
||||||
refreshFrame = undefined
|
refreshFrame = undefined
|
||||||
@@ -783,9 +835,7 @@ export default function Page() {
|
|||||||
})
|
})
|
||||||
}, 0)
|
}, 0)
|
||||||
})
|
})
|
||||||
|
}),
|
||||||
return sync.session.sync(id)
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
createEffect(
|
createEffect(
|
||||||
@@ -847,6 +897,27 @@ export default function Page() {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
createEffect(
|
||||||
|
on(
|
||||||
|
() => sdk.directory,
|
||||||
|
() => {
|
||||||
|
resetVcs()
|
||||||
|
},
|
||||||
|
{ defer: true },
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
createEffect(
|
||||||
|
on(
|
||||||
|
() => [sync.data.vcs?.branch, sync.data.vcs?.default_branch] as const,
|
||||||
|
(next, prev) => {
|
||||||
|
if (prev === undefined || same(next, prev)) return
|
||||||
|
refreshVcs()
|
||||||
|
},
|
||||||
|
{ defer: true },
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
const stopVcs = sdk.event.listen((evt) => {
|
const stopVcs = sdk.event.listen((evt) => {
|
||||||
if (evt.details.type !== "file.watcher.updated") return
|
if (evt.details.type !== "file.watcher.updated") return
|
||||||
const props =
|
const props =
|
||||||
@@ -980,6 +1051,13 @@ export default function Page() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const mobileChanges = createMemo(() => !isDesktop() && store.mobileTab === "changes")
|
||||||
|
const wantsReview = createMemo(() =>
|
||||||
|
isDesktop()
|
||||||
|
? desktopFileTreeOpen() || (desktopReviewOpen() && activeTab() === "review")
|
||||||
|
: store.mobileTab === "changes",
|
||||||
|
)
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
const list = changesOptions()
|
const list = changesOptions()
|
||||||
if (list.includes(store.changes)) return
|
if (list.includes(store.changes)) return
|
||||||
@@ -988,12 +1066,22 @@ export default function Page() {
|
|||||||
setStore("changes", next)
|
setStore("changes", next)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
const mode = vcsMode()
|
||||||
|
if (!mode) return
|
||||||
|
if (!wantsReview()) return
|
||||||
|
void loadVcs(mode)
|
||||||
|
})
|
||||||
|
|
||||||
createEffect(
|
createEffect(
|
||||||
on(
|
on(
|
||||||
() => sync.data.session_status[params.id ?? ""]?.type,
|
() => sync.data.session_status[params.id ?? ""]?.type,
|
||||||
(next, prev) => {
|
(next, prev) => {
|
||||||
|
const mode = vcsMode()
|
||||||
|
if (!mode) return
|
||||||
|
if (!wantsReview()) return
|
||||||
if (next !== "idle" || prev === undefined || prev === "idle") return
|
if (next !== "idle" || prev === undefined || prev === "idle") return
|
||||||
refreshVcs()
|
void loadVcs(mode, true)
|
||||||
},
|
},
|
||||||
{ defer: true },
|
{ defer: true },
|
||||||
),
|
),
|
||||||
@@ -1794,7 +1882,6 @@ export default function Page() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="relative bg-background-base size-full overflow-hidden flex flex-col">
|
<div class="relative bg-background-base size-full overflow-hidden flex flex-col">
|
||||||
{sessionSync() ?? ""}
|
|
||||||
<SessionHeader />
|
<SessionHeader />
|
||||||
<div class="flex-1 min-h-0 flex flex-col md:flex-row">
|
<div class="flex-1 min-h-0 flex flex-col md:flex-row">
|
||||||
<Show when={!isDesktop() && !!params.id}>
|
<Show when={!isDesktop() && !!params.id}>
|
||||||
|
|||||||
@@ -19,9 +19,6 @@ import { useCommand } from "@/context/command"
|
|||||||
import { useFile, type SelectedLineRange } from "@/context/file"
|
import { useFile, type SelectedLineRange } from "@/context/file"
|
||||||
import { useLanguage } from "@/context/language"
|
import { useLanguage } from "@/context/language"
|
||||||
import { useLayout } from "@/context/layout"
|
import { useLayout } from "@/context/layout"
|
||||||
import { usePlatform } from "@/context/platform"
|
|
||||||
import { useSettings } from "@/context/settings"
|
|
||||||
import { useSync } from "@/context/sync"
|
|
||||||
import { createFileTabListSync } from "@/pages/session/file-tab-scroll"
|
import { createFileTabListSync } from "@/pages/session/file-tab-scroll"
|
||||||
import { FileTabContent } from "@/pages/session/file-tabs"
|
import { FileTabContent } from "@/pages/session/file-tabs"
|
||||||
import { createOpenSessionFileTab, createSessionTabs, getTabReorderIndex, type Sizing } from "@/pages/session/helpers"
|
import { createOpenSessionFileTab, createSessionTabs, getTabReorderIndex, type Sizing } from "@/pages/session/helpers"
|
||||||
@@ -42,9 +39,6 @@ export function SessionSidePanel(props: {
|
|||||||
size: Sizing
|
size: Sizing
|
||||||
}) {
|
}) {
|
||||||
const layout = useLayout()
|
const layout = useLayout()
|
||||||
const platform = usePlatform()
|
|
||||||
const settings = useSettings()
|
|
||||||
const sync = useSync()
|
|
||||||
const file = useFile()
|
const file = useFile()
|
||||||
const language = useLanguage()
|
const language = useLanguage()
|
||||||
const command = useCommand()
|
const command = useCommand()
|
||||||
@@ -52,15 +46,9 @@ export function SessionSidePanel(props: {
|
|||||||
const { sessionKey, tabs, view } = useSessionLayout()
|
const { sessionKey, tabs, view } = useSessionLayout()
|
||||||
|
|
||||||
const isDesktop = createMediaQuery("(min-width: 768px)")
|
const isDesktop = createMediaQuery("(min-width: 768px)")
|
||||||
const shown = createMemo(
|
|
||||||
() =>
|
|
||||||
platform.platform !== "desktop" ||
|
|
||||||
import.meta.env.VITE_OPENCODE_CHANNEL !== "beta" ||
|
|
||||||
settings.general.showFileTree(),
|
|
||||||
)
|
|
||||||
|
|
||||||
const reviewOpen = createMemo(() => isDesktop() && view().reviewPanel.opened())
|
const reviewOpen = createMemo(() => isDesktop() && view().reviewPanel.opened())
|
||||||
const fileOpen = createMemo(() => isDesktop() && shown() && layout.fileTree.opened())
|
const fileOpen = createMemo(() => isDesktop() && layout.fileTree.opened())
|
||||||
const open = createMemo(() => reviewOpen() || fileOpen())
|
const open = createMemo(() => reviewOpen() || fileOpen())
|
||||||
const reviewTab = createMemo(() => isDesktop())
|
const reviewTab = createMemo(() => isDesktop())
|
||||||
const panelWidth = createMemo(() => {
|
const panelWidth = createMemo(() => {
|
||||||
@@ -353,99 +341,98 @@ export function SessionSidePanel(props: {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Show when={shown()}>
|
<div
|
||||||
|
id="file-tree-panel"
|
||||||
|
aria-hidden={!fileOpen()}
|
||||||
|
inert={!fileOpen()}
|
||||||
|
class="relative min-w-0 h-full shrink-0 overflow-hidden"
|
||||||
|
classList={{
|
||||||
|
"pointer-events-none": !fileOpen(),
|
||||||
|
"transition-[width] duration-200 ease-[cubic-bezier(0.22,1,0.36,1)] will-change-[width] motion-reduce:transition-none":
|
||||||
|
!props.size.active(),
|
||||||
|
}}
|
||||||
|
style={{ width: treeWidth() }}
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
id="file-tree-panel"
|
class="h-full flex flex-col overflow-hidden group/filetree"
|
||||||
aria-hidden={!fileOpen()}
|
classList={{ "border-l border-border-weaker-base": reviewOpen() }}
|
||||||
inert={!fileOpen()}
|
|
||||||
class="relative min-w-0 h-full shrink-0 overflow-hidden"
|
|
||||||
classList={{
|
|
||||||
"pointer-events-none": !fileOpen(),
|
|
||||||
"transition-[width] duration-200 ease-[cubic-bezier(0.22,1,0.36,1)] will-change-[width] motion-reduce:transition-none":
|
|
||||||
!props.size.active(),
|
|
||||||
}}
|
|
||||||
style={{ width: treeWidth() }}
|
|
||||||
>
|
>
|
||||||
<div
|
<Tabs
|
||||||
class="h-full flex flex-col overflow-hidden group/filetree"
|
variant="pill"
|
||||||
classList={{ "border-l border-border-weaker-base": reviewOpen() }}
|
value={fileTreeTab()}
|
||||||
|
onChange={setFileTreeTabValue}
|
||||||
|
class="h-full"
|
||||||
|
data-scope="filetree"
|
||||||
>
|
>
|
||||||
<Tabs
|
<Tabs.List>
|
||||||
variant="pill"
|
<Tabs.Trigger value="changes" class="flex-1" classes={{ button: "w-full" }}>
|
||||||
value={fileTreeTab()}
|
{props.reviewCount()}{" "}
|
||||||
onChange={setFileTreeTabValue}
|
{language.t(
|
||||||
class="h-full"
|
props.reviewCount() === 1 ? "session.review.change.one" : "session.review.change.other",
|
||||||
data-scope="filetree"
|
)}
|
||||||
>
|
</Tabs.Trigger>
|
||||||
<Tabs.List>
|
<Tabs.Trigger value="all" class="flex-1" classes={{ button: "w-full" }}>
|
||||||
<Tabs.Trigger value="changes" class="flex-1" classes={{ button: "w-full" }}>
|
{language.t("session.files.all")}
|
||||||
{props.reviewCount()}{" "}
|
</Tabs.Trigger>
|
||||||
{language.t(
|
</Tabs.List>
|
||||||
props.reviewCount() === 1 ? "session.review.change.one" : "session.review.change.other",
|
<Tabs.Content value="changes" class="bg-background-stronger px-3 py-0">
|
||||||
)}
|
<Switch>
|
||||||
</Tabs.Trigger>
|
<Match when={props.hasReview() || !props.diffsReady()}>
|
||||||
<Tabs.Trigger value="all" class="flex-1" classes={{ button: "w-full" }}>
|
<Show
|
||||||
{language.t("session.files.all")}
|
when={props.diffsReady()}
|
||||||
</Tabs.Trigger>
|
fallback={
|
||||||
</Tabs.List>
|
<div class="px-2 py-2 text-12-regular text-text-weak">
|
||||||
<Tabs.Content value="changes" class="bg-background-stronger px-3 py-0">
|
{language.t("common.loading")}
|
||||||
<Switch>
|
{language.t("common.loading.ellipsis")}
|
||||||
<Match when={props.hasReview() || !props.diffsReady()}>
|
</div>
|
||||||
<Show
|
}
|
||||||
when={props.diffsReady()}
|
>
|
||||||
fallback={
|
|
||||||
<div class="px-2 py-2 text-12-regular text-text-weak">
|
|
||||||
{language.t("common.loading")}
|
|
||||||
{language.t("common.loading.ellipsis")}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<FileTree
|
|
||||||
path=""
|
|
||||||
class="pt-3"
|
|
||||||
allowed={diffFiles()}
|
|
||||||
kinds={kinds()}
|
|
||||||
draggable={false}
|
|
||||||
active={props.activeDiff}
|
|
||||||
onFileClick={(node) => props.focusReviewDiff(node.path)}
|
|
||||||
/>
|
|
||||||
</Show>
|
|
||||||
</Match>
|
|
||||||
</Switch>
|
|
||||||
</Tabs.Content>
|
|
||||||
<Tabs.Content value="all" class="bg-background-stronger px-3 py-0">
|
|
||||||
<Switch>
|
|
||||||
<Match when={nofiles()}>{empty(language.t("session.files.empty"))}</Match>
|
|
||||||
<Match when={true}>
|
|
||||||
<FileTree
|
<FileTree
|
||||||
path=""
|
path=""
|
||||||
class="pt-3"
|
class="pt-3"
|
||||||
modified={diffFiles()}
|
allowed={diffFiles()}
|
||||||
kinds={kinds()}
|
kinds={kinds()}
|
||||||
onFileClick={(node) => openTab(file.tab(node.path))}
|
draggable={false}
|
||||||
|
active={props.activeDiff}
|
||||||
|
onFileClick={(node) => props.focusReviewDiff(node.path)}
|
||||||
/>
|
/>
|
||||||
</Match>
|
</Show>
|
||||||
</Switch>
|
</Match>
|
||||||
</Tabs.Content>
|
<Match when={true}>{empty(props.empty())}</Match>
|
||||||
</Tabs>
|
</Switch>
|
||||||
</div>
|
</Tabs.Content>
|
||||||
<Show when={fileOpen()}>
|
<Tabs.Content value="all" class="bg-background-stronger px-3 py-0">
|
||||||
<div onPointerDown={() => props.size.start()}>
|
<Switch>
|
||||||
<ResizeHandle
|
<Match when={nofiles()}>{empty(language.t("session.files.empty"))}</Match>
|
||||||
direction="horizontal"
|
<Match when={true}>
|
||||||
edge="start"
|
<FileTree
|
||||||
size={layout.fileTree.width()}
|
path=""
|
||||||
min={200}
|
class="pt-3"
|
||||||
max={480}
|
modified={diffFiles()}
|
||||||
onResize={(width) => {
|
kinds={kinds()}
|
||||||
props.size.touch()
|
onFileClick={(node) => openTab(file.tab(node.path))}
|
||||||
layout.fileTree.resize(width)
|
/>
|
||||||
}}
|
</Match>
|
||||||
/>
|
</Switch>
|
||||||
</div>
|
</Tabs.Content>
|
||||||
</Show>
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
<Show when={fileOpen()}>
|
||||||
|
<div onPointerDown={() => props.size.start()}>
|
||||||
|
<ResizeHandle
|
||||||
|
direction="horizontal"
|
||||||
|
edge="start"
|
||||||
|
size={layout.fileTree.width()}
|
||||||
|
min={200}
|
||||||
|
max={480}
|
||||||
|
onResize={(width) => {
|
||||||
|
props.size.touch()
|
||||||
|
layout.fileTree.resize(width)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
</Show>
|
</Show>
|
||||||
|
|||||||
@@ -7,10 +7,8 @@ import { useLanguage } from "@/context/language"
|
|||||||
import { useLayout } from "@/context/layout"
|
import { useLayout } from "@/context/layout"
|
||||||
import { useLocal } from "@/context/local"
|
import { useLocal } from "@/context/local"
|
||||||
import { usePermission } from "@/context/permission"
|
import { usePermission } from "@/context/permission"
|
||||||
import { usePlatform } from "@/context/platform"
|
|
||||||
import { usePrompt } from "@/context/prompt"
|
import { usePrompt } from "@/context/prompt"
|
||||||
import { useSDK } from "@/context/sdk"
|
import { useSDK } from "@/context/sdk"
|
||||||
import { useSettings } from "@/context/settings"
|
|
||||||
import { useSync } from "@/context/sync"
|
import { useSync } from "@/context/sync"
|
||||||
import { useTerminal } from "@/context/terminal"
|
import { useTerminal } from "@/context/terminal"
|
||||||
import { showToast } from "@opencode-ai/ui/toast"
|
import { showToast } from "@opencode-ai/ui/toast"
|
||||||
@@ -41,10 +39,8 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
|
|||||||
const language = useLanguage()
|
const language = useLanguage()
|
||||||
const local = useLocal()
|
const local = useLocal()
|
||||||
const permission = usePermission()
|
const permission = usePermission()
|
||||||
const platform = usePlatform()
|
|
||||||
const prompt = usePrompt()
|
const prompt = usePrompt()
|
||||||
const sdk = useSDK()
|
const sdk = useSDK()
|
||||||
const settings = useSettings()
|
|
||||||
const sync = useSync()
|
const sync = useSync()
|
||||||
const terminal = useTerminal()
|
const terminal = useTerminal()
|
||||||
const layout = useLayout()
|
const layout = useLayout()
|
||||||
@@ -70,10 +66,6 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
|
|||||||
})
|
})
|
||||||
const activeFileTab = tabState.activeFileTab
|
const activeFileTab = tabState.activeFileTab
|
||||||
const closableTab = tabState.closableTab
|
const closableTab = tabState.closableTab
|
||||||
const shown = () =>
|
|
||||||
platform.platform !== "desktop" ||
|
|
||||||
import.meta.env.VITE_OPENCODE_CHANNEL !== "beta" ||
|
|
||||||
settings.general.showFileTree()
|
|
||||||
|
|
||||||
const idle = { type: "idle" as const }
|
const idle = { type: "idle" as const }
|
||||||
const status = () => sync.data.session_status[params.id ?? ""] ?? idle
|
const status = () => sync.data.session_status[params.id ?? ""] ?? idle
|
||||||
@@ -465,16 +457,12 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
|
|||||||
keybind: "mod+shift+r",
|
keybind: "mod+shift+r",
|
||||||
onSelect: () => view().reviewPanel.toggle(),
|
onSelect: () => view().reviewPanel.toggle(),
|
||||||
}),
|
}),
|
||||||
...(shown()
|
viewCommand({
|
||||||
? [
|
id: "fileTree.toggle",
|
||||||
viewCommand({
|
title: language.t("command.fileTree.toggle"),
|
||||||
id: "fileTree.toggle",
|
keybind: "mod+\\",
|
||||||
title: language.t("command.fileTree.toggle"),
|
onSelect: () => layout.fileTree.toggle(),
|
||||||
keybind: "mod+\\",
|
}),
|
||||||
onSelect: () => layout.fileTree.toggle(),
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
viewCommand({
|
viewCommand({
|
||||||
id: "input.focus",
|
id: "input.focus",
|
||||||
title: language.t("command.input.focus"),
|
title: language.t("command.input.focus"),
|
||||||
|
|||||||
@@ -469,7 +469,7 @@ export function persisted<T>(
|
|||||||
state,
|
state,
|
||||||
setState,
|
setState,
|
||||||
init,
|
init,
|
||||||
Object.assign(() => (ready.loading ? false : ready.latest === true), {
|
Object.assign(() => ready() === true, {
|
||||||
promise: init instanceof Promise ? init : undefined,
|
promise: init instanceof Promise ? init : undefined,
|
||||||
}),
|
}),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -16,10 +16,7 @@ export function createSdkForServer({
|
|||||||
|
|
||||||
return createOpencodeClient({
|
return createOpencodeClient({
|
||||||
...config,
|
...config,
|
||||||
headers: {
|
headers: { ...config.headers, ...auth },
|
||||||
...(config.headers instanceof Headers ? Object.fromEntries(config.headers.entries()) : config.headers),
|
|
||||||
...auth,
|
|
||||||
},
|
|
||||||
baseUrl: server.url,
|
baseUrl: server.url,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@opencode-ai/console-app",
|
"name": "@opencode-ai/console-app",
|
||||||
"version": "1.14.18",
|
"version": "1.4.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const dict = {
|
|||||||
"nav.enterprise": "المؤسسات",
|
"nav.enterprise": "المؤسسات",
|
||||||
"nav.zen": "Zen",
|
"nav.zen": "Zen",
|
||||||
"nav.login": "تسجيل الدخول",
|
"nav.login": "تسجيل الدخول",
|
||||||
"nav.free": "تحميل",
|
"nav.free": "مجانا",
|
||||||
"nav.home": "الرئيسية",
|
"nav.home": "الرئيسية",
|
||||||
"nav.openMenu": "فتح القائمة",
|
"nav.openMenu": "فتح القائمة",
|
||||||
"nav.getStartedFree": "ابدأ مجانا",
|
"nav.getStartedFree": "ابدأ مجانا",
|
||||||
@@ -558,13 +558,6 @@ export const dict = {
|
|||||||
"workspace.monthlyLimit.currentUsage.beforeMonth": "الاستخدام الحالي لـ",
|
"workspace.monthlyLimit.currentUsage.beforeMonth": "الاستخدام الحالي لـ",
|
||||||
"workspace.monthlyLimit.currentUsage.beforeAmount": "هو $",
|
"workspace.monthlyLimit.currentUsage.beforeAmount": "هو $",
|
||||||
|
|
||||||
"workspace.redeem.title": "استرداد قسيمة",
|
|
||||||
"workspace.redeem.subtitle": "استرد رمز القسيمة للحصول على رصيد أو مزايا.",
|
|
||||||
"workspace.redeem.placeholder": "أدخل رمز القسيمة",
|
|
||||||
"workspace.redeem.redeem": "استرداد",
|
|
||||||
"workspace.redeem.redeeming": "جارٍ الاسترداد...",
|
|
||||||
"workspace.redeem.success": "تم استرداد القسيمة بنجاح.",
|
|
||||||
|
|
||||||
"workspace.reload.title": "إعادة الشحن التلقائي",
|
"workspace.reload.title": "إعادة الشحن التلقائي",
|
||||||
"workspace.reload.disabled.before": "إعادة الشحن التلقائي",
|
"workspace.reload.disabled.before": "إعادة الشحن التلقائي",
|
||||||
"workspace.reload.disabled.state": "معطّل",
|
"workspace.reload.disabled.state": "معطّل",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const dict = {
|
|||||||
"nav.enterprise": "Enterprise",
|
"nav.enterprise": "Enterprise",
|
||||||
"nav.zen": "Zen",
|
"nav.zen": "Zen",
|
||||||
"nav.login": "Entrar",
|
"nav.login": "Entrar",
|
||||||
"nav.free": "Download",
|
"nav.free": "Grátis",
|
||||||
"nav.home": "Início",
|
"nav.home": "Início",
|
||||||
"nav.openMenu": "Abrir menu",
|
"nav.openMenu": "Abrir menu",
|
||||||
"nav.getStartedFree": "Começar grátis",
|
"nav.getStartedFree": "Começar grátis",
|
||||||
@@ -567,13 +567,6 @@ export const dict = {
|
|||||||
"workspace.monthlyLimit.currentUsage.beforeMonth": "Uso atual para",
|
"workspace.monthlyLimit.currentUsage.beforeMonth": "Uso atual para",
|
||||||
"workspace.monthlyLimit.currentUsage.beforeAmount": "é $",
|
"workspace.monthlyLimit.currentUsage.beforeAmount": "é $",
|
||||||
|
|
||||||
"workspace.redeem.title": "Resgatar Cupom",
|
|
||||||
"workspace.redeem.subtitle": "Resgate um código de cupom para receber créditos ou vantagens.",
|
|
||||||
"workspace.redeem.placeholder": "Digite o código do cupom",
|
|
||||||
"workspace.redeem.redeem": "Resgatar",
|
|
||||||
"workspace.redeem.redeeming": "Resgatando...",
|
|
||||||
"workspace.redeem.success": "Cupom resgatado com sucesso.",
|
|
||||||
|
|
||||||
"workspace.reload.title": "Recarga Automática",
|
"workspace.reload.title": "Recarga Automática",
|
||||||
"workspace.reload.disabled.before": "A recarga automática está",
|
"workspace.reload.disabled.before": "A recarga automática está",
|
||||||
"workspace.reload.disabled.state": "desativada",
|
"workspace.reload.disabled.state": "desativada",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const dict = {
|
|||||||
"nav.enterprise": "Enterprise",
|
"nav.enterprise": "Enterprise",
|
||||||
"nav.zen": "Zen",
|
"nav.zen": "Zen",
|
||||||
"nav.login": "Log ind",
|
"nav.login": "Log ind",
|
||||||
"nav.free": "Download",
|
"nav.free": "Gratis",
|
||||||
"nav.home": "Hjem",
|
"nav.home": "Hjem",
|
||||||
"nav.openMenu": "Åbn menu",
|
"nav.openMenu": "Åbn menu",
|
||||||
"nav.getStartedFree": "Kom i gang gratis",
|
"nav.getStartedFree": "Kom i gang gratis",
|
||||||
@@ -563,13 +563,6 @@ export const dict = {
|
|||||||
"workspace.monthlyLimit.currentUsage.beforeMonth": "Nuværende brug for",
|
"workspace.monthlyLimit.currentUsage.beforeMonth": "Nuværende brug for",
|
||||||
"workspace.monthlyLimit.currentUsage.beforeAmount": "er $",
|
"workspace.monthlyLimit.currentUsage.beforeAmount": "er $",
|
||||||
|
|
||||||
"workspace.redeem.title": "Indløs kupon",
|
|
||||||
"workspace.redeem.subtitle": "Indløs en kuponkode for at få kreditter eller fordele.",
|
|
||||||
"workspace.redeem.placeholder": "Indtast kuponkode",
|
|
||||||
"workspace.redeem.redeem": "Indløs",
|
|
||||||
"workspace.redeem.redeeming": "Indløser...",
|
|
||||||
"workspace.redeem.success": "Kuponen blev indløst.",
|
|
||||||
|
|
||||||
"workspace.reload.title": "Automatisk genopfyldning",
|
"workspace.reload.title": "Automatisk genopfyldning",
|
||||||
"workspace.reload.disabled.before": "Automatisk genopfyldning er",
|
"workspace.reload.disabled.before": "Automatisk genopfyldning er",
|
||||||
"workspace.reload.disabled.state": "deaktiveret",
|
"workspace.reload.disabled.state": "deaktiveret",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const dict = {
|
|||||||
"nav.enterprise": "Enterprise",
|
"nav.enterprise": "Enterprise",
|
||||||
"nav.zen": "Zen",
|
"nav.zen": "Zen",
|
||||||
"nav.login": "Anmelden",
|
"nav.login": "Anmelden",
|
||||||
"nav.free": "Download",
|
"nav.free": "Kostenlos",
|
||||||
"nav.home": "Startseite",
|
"nav.home": "Startseite",
|
||||||
"nav.openMenu": "Menü öffnen",
|
"nav.openMenu": "Menü öffnen",
|
||||||
"nav.getStartedFree": "Kostenlos starten",
|
"nav.getStartedFree": "Kostenlos starten",
|
||||||
@@ -566,13 +566,6 @@ export const dict = {
|
|||||||
"workspace.monthlyLimit.currentUsage.beforeMonth": "Aktuelle Nutzung für",
|
"workspace.monthlyLimit.currentUsage.beforeMonth": "Aktuelle Nutzung für",
|
||||||
"workspace.monthlyLimit.currentUsage.beforeAmount": "ist $",
|
"workspace.monthlyLimit.currentUsage.beforeAmount": "ist $",
|
||||||
|
|
||||||
"workspace.redeem.title": "Gutschein einlösen",
|
|
||||||
"workspace.redeem.subtitle": "Löse einen Gutscheincode ein, um Guthaben oder Vorteile zu erhalten.",
|
|
||||||
"workspace.redeem.placeholder": "Gutscheincode eingeben",
|
|
||||||
"workspace.redeem.redeem": "Einlösen",
|
|
||||||
"workspace.redeem.redeeming": "Wird eingelöst...",
|
|
||||||
"workspace.redeem.success": "Gutschein erfolgreich eingelöst.",
|
|
||||||
|
|
||||||
"workspace.reload.title": "Auto-Reload",
|
"workspace.reload.title": "Auto-Reload",
|
||||||
"workspace.reload.disabled.before": "Auto-Reload ist",
|
"workspace.reload.disabled.before": "Auto-Reload ist",
|
||||||
"workspace.reload.disabled.state": "deaktiviert",
|
"workspace.reload.disabled.state": "deaktiviert",
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export const dict = {
|
|||||||
"nav.zen": "Zen",
|
"nav.zen": "Zen",
|
||||||
"nav.go": "Go",
|
"nav.go": "Go",
|
||||||
"nav.login": "Login",
|
"nav.login": "Login",
|
||||||
"nav.free": "Download",
|
"nav.free": "Free",
|
||||||
"nav.home": "Home",
|
"nav.home": "Home",
|
||||||
"nav.openMenu": "Open menu",
|
"nav.openMenu": "Open menu",
|
||||||
"nav.getStartedFree": "Get started for free",
|
"nav.getStartedFree": "Get started for free",
|
||||||
@@ -559,13 +559,6 @@ export const dict = {
|
|||||||
"workspace.monthlyLimit.currentUsage.beforeMonth": "Current usage for",
|
"workspace.monthlyLimit.currentUsage.beforeMonth": "Current usage for",
|
||||||
"workspace.monthlyLimit.currentUsage.beforeAmount": "is $",
|
"workspace.monthlyLimit.currentUsage.beforeAmount": "is $",
|
||||||
|
|
||||||
"workspace.redeem.title": "Redeem Coupon",
|
|
||||||
"workspace.redeem.subtitle": "Redeem a coupon code to claim credits or perks.",
|
|
||||||
"workspace.redeem.placeholder": "Enter coupon code",
|
|
||||||
"workspace.redeem.redeem": "Redeem",
|
|
||||||
"workspace.redeem.redeeming": "Redeeming...",
|
|
||||||
"workspace.redeem.success": "Coupon redeemed successfully.",
|
|
||||||
|
|
||||||
"workspace.reload.title": "Auto Reload",
|
"workspace.reload.title": "Auto Reload",
|
||||||
"workspace.reload.disabled.before": "Auto reload is",
|
"workspace.reload.disabled.before": "Auto reload is",
|
||||||
"workspace.reload.disabled.state": "disabled",
|
"workspace.reload.disabled.state": "disabled",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const dict = {
|
|||||||
"nav.enterprise": "Enterprise",
|
"nav.enterprise": "Enterprise",
|
||||||
"nav.zen": "Zen",
|
"nav.zen": "Zen",
|
||||||
"nav.login": "Iniciar sesión",
|
"nav.login": "Iniciar sesión",
|
||||||
"nav.free": "Descargar",
|
"nav.free": "Gratis",
|
||||||
"nav.home": "Inicio",
|
"nav.home": "Inicio",
|
||||||
"nav.openMenu": "Abrir menú",
|
"nav.openMenu": "Abrir menú",
|
||||||
"nav.getStartedFree": "Empezar gratis",
|
"nav.getStartedFree": "Empezar gratis",
|
||||||
@@ -567,13 +567,6 @@ export const dict = {
|
|||||||
"workspace.monthlyLimit.currentUsage.beforeMonth": "Uso actual para",
|
"workspace.monthlyLimit.currentUsage.beforeMonth": "Uso actual para",
|
||||||
"workspace.monthlyLimit.currentUsage.beforeAmount": "es $",
|
"workspace.monthlyLimit.currentUsage.beforeAmount": "es $",
|
||||||
|
|
||||||
"workspace.redeem.title": "Canjear cupón",
|
|
||||||
"workspace.redeem.subtitle": "Canjea un código de cupón para obtener crédito o beneficios.",
|
|
||||||
"workspace.redeem.placeholder": "Introduce el código del cupón",
|
|
||||||
"workspace.redeem.redeem": "Canjear",
|
|
||||||
"workspace.redeem.redeeming": "Canjeando...",
|
|
||||||
"workspace.redeem.success": "Cupón canjeado correctamente.",
|
|
||||||
|
|
||||||
"workspace.reload.title": "Auto Recarga",
|
"workspace.reload.title": "Auto Recarga",
|
||||||
"workspace.reload.disabled.before": "La auto recarga está",
|
"workspace.reload.disabled.before": "La auto recarga está",
|
||||||
"workspace.reload.disabled.state": "deshabilitada",
|
"workspace.reload.disabled.state": "deshabilitada",
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export const dict = {
|
|||||||
"nav.enterprise": "Entreprise",
|
"nav.enterprise": "Entreprise",
|
||||||
"nav.zen": "Zen",
|
"nav.zen": "Zen",
|
||||||
"nav.login": "Se connecter",
|
"nav.login": "Se connecter",
|
||||||
"nav.free": "Télécharger",
|
"nav.free": "Gratuit",
|
||||||
"nav.home": "Accueil",
|
"nav.home": "Accueil",
|
||||||
"nav.openMenu": "Ouvrir le menu",
|
"nav.openMenu": "Ouvrir le menu",
|
||||||
"nav.getStartedFree": "Commencer gratuitement",
|
"nav.getStartedFree": "Commencer gratuitement",
|
||||||
@@ -569,13 +569,6 @@ export const dict = {
|
|||||||
"workspace.monthlyLimit.currentUsage.beforeMonth": "L'utilisation actuelle pour",
|
"workspace.monthlyLimit.currentUsage.beforeMonth": "L'utilisation actuelle pour",
|
||||||
"workspace.monthlyLimit.currentUsage.beforeAmount": "est de",
|
"workspace.monthlyLimit.currentUsage.beforeAmount": "est de",
|
||||||
|
|
||||||
"workspace.redeem.title": "Utiliser un coupon",
|
|
||||||
"workspace.redeem.subtitle": "Utilisez un code promo pour obtenir du crédit ou des avantages.",
|
|
||||||
"workspace.redeem.placeholder": "Saisissez le code promo",
|
|
||||||
"workspace.redeem.redeem": "Utiliser",
|
|
||||||
"workspace.redeem.redeeming": "Utilisation...",
|
|
||||||
"workspace.redeem.success": "Coupon utilisé avec succès.",
|
|
||||||
|
|
||||||
"workspace.reload.title": "Rechargement automatique",
|
"workspace.reload.title": "Rechargement automatique",
|
||||||
"workspace.reload.disabled.before": "Le rechargement automatique est",
|
"workspace.reload.disabled.before": "Le rechargement automatique est",
|
||||||
"workspace.reload.disabled.state": "désactivé",
|
"workspace.reload.disabled.state": "désactivé",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const dict = {
|
|||||||
"nav.enterprise": "Enterprise",
|
"nav.enterprise": "Enterprise",
|
||||||
"nav.zen": "Zen",
|
"nav.zen": "Zen",
|
||||||
"nav.login": "Accedi",
|
"nav.login": "Accedi",
|
||||||
"nav.free": "Scarica",
|
"nav.free": "Gratis",
|
||||||
"nav.home": "Home",
|
"nav.home": "Home",
|
||||||
"nav.openMenu": "Apri menu",
|
"nav.openMenu": "Apri menu",
|
||||||
"nav.getStartedFree": "Inizia gratis",
|
"nav.getStartedFree": "Inizia gratis",
|
||||||
@@ -565,13 +565,6 @@ export const dict = {
|
|||||||
"workspace.monthlyLimit.currentUsage.beforeMonth": "Utilizzo attuale per",
|
"workspace.monthlyLimit.currentUsage.beforeMonth": "Utilizzo attuale per",
|
||||||
"workspace.monthlyLimit.currentUsage.beforeAmount": "è $",
|
"workspace.monthlyLimit.currentUsage.beforeAmount": "è $",
|
||||||
|
|
||||||
"workspace.redeem.title": "Riscatta Coupon",
|
|
||||||
"workspace.redeem.subtitle": "Riscatta un codice coupon per ottenere credito o vantaggi.",
|
|
||||||
"workspace.redeem.placeholder": "Inserisci il codice coupon",
|
|
||||||
"workspace.redeem.redeem": "Riscatta",
|
|
||||||
"workspace.redeem.redeeming": "Riscatto in corso...",
|
|
||||||
"workspace.redeem.success": "Coupon riscattato con successo.",
|
|
||||||
|
|
||||||
"workspace.reload.title": "Ricarica Auto",
|
"workspace.reload.title": "Ricarica Auto",
|
||||||
"workspace.reload.disabled.before": "La ricarica auto è",
|
"workspace.reload.disabled.before": "La ricarica auto è",
|
||||||
"workspace.reload.disabled.state": "disabilitata",
|
"workspace.reload.disabled.state": "disabilitata",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const dict = {
|
|||||||
"nav.enterprise": "エンタープライズ",
|
"nav.enterprise": "エンタープライズ",
|
||||||
"nav.zen": "Zen",
|
"nav.zen": "Zen",
|
||||||
"nav.login": "ログイン",
|
"nav.login": "ログイン",
|
||||||
"nav.free": "ダウンロード",
|
"nav.free": "無料",
|
||||||
"nav.home": "ホーム",
|
"nav.home": "ホーム",
|
||||||
"nav.openMenu": "メニューを開く",
|
"nav.openMenu": "メニューを開く",
|
||||||
"nav.getStartedFree": "無料ではじめる",
|
"nav.getStartedFree": "無料ではじめる",
|
||||||
@@ -564,13 +564,6 @@ export const dict = {
|
|||||||
"workspace.monthlyLimit.currentUsage.beforeMonth": "現在の使用状況(",
|
"workspace.monthlyLimit.currentUsage.beforeMonth": "現在の使用状況(",
|
||||||
"workspace.monthlyLimit.currentUsage.beforeAmount": ")は $",
|
"workspace.monthlyLimit.currentUsage.beforeAmount": ")は $",
|
||||||
|
|
||||||
"workspace.redeem.title": "クーポンを利用",
|
|
||||||
"workspace.redeem.subtitle": "クーポンコードを利用して、クレジットや特典を受け取ります。",
|
|
||||||
"workspace.redeem.placeholder": "クーポンコードを入力",
|
|
||||||
"workspace.redeem.redeem": "利用する",
|
|
||||||
"workspace.redeem.redeeming": "利用中...",
|
|
||||||
"workspace.redeem.success": "クーポンを利用しました。",
|
|
||||||
|
|
||||||
"workspace.reload.title": "自動チャージ",
|
"workspace.reload.title": "自動チャージ",
|
||||||
"workspace.reload.disabled.before": "自動チャージは",
|
"workspace.reload.disabled.before": "自動チャージは",
|
||||||
"workspace.reload.disabled.state": "無効",
|
"workspace.reload.disabled.state": "無効",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const dict = {
|
|||||||
"nav.enterprise": "엔터프라이즈",
|
"nav.enterprise": "엔터프라이즈",
|
||||||
"nav.zen": "Zen",
|
"nav.zen": "Zen",
|
||||||
"nav.login": "로그인",
|
"nav.login": "로그인",
|
||||||
"nav.free": "다운로드",
|
"nav.free": "무료",
|
||||||
"nav.home": "홈",
|
"nav.home": "홈",
|
||||||
"nav.openMenu": "메뉴 열기",
|
"nav.openMenu": "메뉴 열기",
|
||||||
"nav.getStartedFree": "무료로 시작하기",
|
"nav.getStartedFree": "무료로 시작하기",
|
||||||
@@ -558,13 +558,6 @@ export const dict = {
|
|||||||
"workspace.monthlyLimit.currentUsage.beforeMonth": "현재",
|
"workspace.monthlyLimit.currentUsage.beforeMonth": "현재",
|
||||||
"workspace.monthlyLimit.currentUsage.beforeAmount": "사용량: $",
|
"workspace.monthlyLimit.currentUsage.beforeAmount": "사용량: $",
|
||||||
|
|
||||||
"workspace.redeem.title": "쿠폰 사용",
|
|
||||||
"workspace.redeem.subtitle": "쿠폰 코드를 사용해 크레딧이나 혜택을 받으세요.",
|
|
||||||
"workspace.redeem.placeholder": "쿠폰 코드를 입력하세요",
|
|
||||||
"workspace.redeem.redeem": "사용",
|
|
||||||
"workspace.redeem.redeeming": "사용 중...",
|
|
||||||
"workspace.redeem.success": "쿠폰을 성공적으로 사용했습니다.",
|
|
||||||
|
|
||||||
"workspace.reload.title": "자동 충전",
|
"workspace.reload.title": "자동 충전",
|
||||||
"workspace.reload.disabled.before": "자동 충전이",
|
"workspace.reload.disabled.before": "자동 충전이",
|
||||||
"workspace.reload.disabled.state": "비활성화",
|
"workspace.reload.disabled.state": "비활성화",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const dict = {
|
|||||||
"nav.enterprise": "Enterprise",
|
"nav.enterprise": "Enterprise",
|
||||||
"nav.zen": "Zen",
|
"nav.zen": "Zen",
|
||||||
"nav.login": "Logg inn",
|
"nav.login": "Logg inn",
|
||||||
"nav.free": "Last ned",
|
"nav.free": "Gratis",
|
||||||
"nav.home": "Hjem",
|
"nav.home": "Hjem",
|
||||||
"nav.openMenu": "Åpne meny",
|
"nav.openMenu": "Åpne meny",
|
||||||
"nav.getStartedFree": "Kom i gang gratis",
|
"nav.getStartedFree": "Kom i gang gratis",
|
||||||
@@ -564,13 +564,6 @@ export const dict = {
|
|||||||
"workspace.monthlyLimit.currentUsage.beforeMonth": "Gjeldende forbruk for",
|
"workspace.monthlyLimit.currentUsage.beforeMonth": "Gjeldende forbruk for",
|
||||||
"workspace.monthlyLimit.currentUsage.beforeAmount": "er $",
|
"workspace.monthlyLimit.currentUsage.beforeAmount": "er $",
|
||||||
|
|
||||||
"workspace.redeem.title": "Løs inn kupong",
|
|
||||||
"workspace.redeem.subtitle": "Løs inn en kupongkode for å få kreditt eller fordeler.",
|
|
||||||
"workspace.redeem.placeholder": "Skriv inn kupongkode",
|
|
||||||
"workspace.redeem.redeem": "Løs inn",
|
|
||||||
"workspace.redeem.redeeming": "Løser inn...",
|
|
||||||
"workspace.redeem.success": "Kupongen ble løst inn.",
|
|
||||||
|
|
||||||
"workspace.reload.title": "Auto-påfyll",
|
"workspace.reload.title": "Auto-påfyll",
|
||||||
"workspace.reload.disabled.before": "Auto-påfyll er",
|
"workspace.reload.disabled.before": "Auto-påfyll er",
|
||||||
"workspace.reload.disabled.state": "deaktivert",
|
"workspace.reload.disabled.state": "deaktivert",
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export const dict = {
|
|||||||
"nav.enterprise": "Enterprise",
|
"nav.enterprise": "Enterprise",
|
||||||
"nav.zen": "Zen",
|
"nav.zen": "Zen",
|
||||||
"nav.login": "Zaloguj się",
|
"nav.login": "Zaloguj się",
|
||||||
"nav.free": "Pobierz",
|
"nav.free": "Darmowe",
|
||||||
"nav.home": "Strona główna",
|
"nav.home": "Strona główna",
|
||||||
"nav.openMenu": "Otwórz menu",
|
"nav.openMenu": "Otwórz menu",
|
||||||
"nav.getStartedFree": "Zacznij za darmo",
|
"nav.getStartedFree": "Zacznij za darmo",
|
||||||
@@ -565,13 +565,6 @@ export const dict = {
|
|||||||
"workspace.monthlyLimit.currentUsage.beforeMonth": "Aktualne użycie za",
|
"workspace.monthlyLimit.currentUsage.beforeMonth": "Aktualne użycie za",
|
||||||
"workspace.monthlyLimit.currentUsage.beforeAmount": "wynosi $",
|
"workspace.monthlyLimit.currentUsage.beforeAmount": "wynosi $",
|
||||||
|
|
||||||
"workspace.redeem.title": "Zrealizuj kupon",
|
|
||||||
"workspace.redeem.subtitle": "Zrealizuj kod kuponu, aby otrzymać środki lub korzyści.",
|
|
||||||
"workspace.redeem.placeholder": "Wpisz kod kuponu",
|
|
||||||
"workspace.redeem.redeem": "Zrealizuj",
|
|
||||||
"workspace.redeem.redeeming": "Realizowanie...",
|
|
||||||
"workspace.redeem.success": "Kupon został zrealizowany.",
|
|
||||||
|
|
||||||
"workspace.reload.title": "Automatyczne doładowanie",
|
"workspace.reload.title": "Automatyczne doładowanie",
|
||||||
"workspace.reload.disabled.before": "Automatyczne doładowanie jest",
|
"workspace.reload.disabled.before": "Automatyczne doładowanie jest",
|
||||||
"workspace.reload.disabled.state": "wyłączone",
|
"workspace.reload.disabled.state": "wyłączone",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const dict = {
|
|||||||
"nav.enterprise": "Enterprise",
|
"nav.enterprise": "Enterprise",
|
||||||
"nav.zen": "Zen",
|
"nav.zen": "Zen",
|
||||||
"nav.login": "Войти",
|
"nav.login": "Войти",
|
||||||
"nav.free": "Скачать",
|
"nav.free": "Бесплатно",
|
||||||
"nav.home": "Главная",
|
"nav.home": "Главная",
|
||||||
"nav.openMenu": "Открыть меню",
|
"nav.openMenu": "Открыть меню",
|
||||||
"nav.getStartedFree": "Начать бесплатно",
|
"nav.getStartedFree": "Начать бесплатно",
|
||||||
@@ -571,13 +571,6 @@ export const dict = {
|
|||||||
"workspace.monthlyLimit.currentUsage.beforeMonth": "Текущее использование за",
|
"workspace.monthlyLimit.currentUsage.beforeMonth": "Текущее использование за",
|
||||||
"workspace.monthlyLimit.currentUsage.beforeAmount": "составляет $",
|
"workspace.monthlyLimit.currentUsage.beforeAmount": "составляет $",
|
||||||
|
|
||||||
"workspace.redeem.title": "Активировать купон",
|
|
||||||
"workspace.redeem.subtitle": "Активируйте код купона, чтобы получить кредит или бонусы.",
|
|
||||||
"workspace.redeem.placeholder": "Введите код купона",
|
|
||||||
"workspace.redeem.redeem": "Активировать",
|
|
||||||
"workspace.redeem.redeeming": "Активация...",
|
|
||||||
"workspace.redeem.success": "Купон успешно активирован.",
|
|
||||||
|
|
||||||
"workspace.reload.title": "Автопополнение",
|
"workspace.reload.title": "Автопополнение",
|
||||||
"workspace.reload.disabled.before": "Автопополнение",
|
"workspace.reload.disabled.before": "Автопополнение",
|
||||||
"workspace.reload.disabled.state": "отключено",
|
"workspace.reload.disabled.state": "отключено",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const dict = {
|
|||||||
"nav.enterprise": "องค์กร",
|
"nav.enterprise": "องค์กร",
|
||||||
"nav.zen": "Zen",
|
"nav.zen": "Zen",
|
||||||
"nav.login": "เข้าสู่ระบบ",
|
"nav.login": "เข้าสู่ระบบ",
|
||||||
"nav.free": "ดาวน์โหลด",
|
"nav.free": "ฟรี",
|
||||||
"nav.home": "หน้าหลัก",
|
"nav.home": "หน้าหลัก",
|
||||||
"nav.openMenu": "เปิดเมนู",
|
"nav.openMenu": "เปิดเมนู",
|
||||||
"nav.getStartedFree": "เริ่มต้นฟรี",
|
"nav.getStartedFree": "เริ่มต้นฟรี",
|
||||||
@@ -560,13 +560,6 @@ export const dict = {
|
|||||||
"workspace.monthlyLimit.currentUsage.beforeMonth": "การใช้งานปัจจุบันสำหรับ",
|
"workspace.monthlyLimit.currentUsage.beforeMonth": "การใช้งานปัจจุบันสำหรับ",
|
||||||
"workspace.monthlyLimit.currentUsage.beforeAmount": "คือ $",
|
"workspace.monthlyLimit.currentUsage.beforeAmount": "คือ $",
|
||||||
|
|
||||||
"workspace.redeem.title": "แลกคูปอง",
|
|
||||||
"workspace.redeem.subtitle": "แลกรหัสคูปองเพื่อรับเครดิตหรือสิทธิพิเศษ",
|
|
||||||
"workspace.redeem.placeholder": "กรอกรหัสคูปอง",
|
|
||||||
"workspace.redeem.redeem": "แลก",
|
|
||||||
"workspace.redeem.redeeming": "กำลังแลก...",
|
|
||||||
"workspace.redeem.success": "แลกคูปองสำเร็จ",
|
|
||||||
|
|
||||||
"workspace.reload.title": "โหลดซ้ำอัตโนมัติ",
|
"workspace.reload.title": "โหลดซ้ำอัตโนมัติ",
|
||||||
"workspace.reload.disabled.before": "การโหลดซ้ำอัตโนมัติ",
|
"workspace.reload.disabled.before": "การโหลดซ้ำอัตโนมัติ",
|
||||||
"workspace.reload.disabled.state": "ปิดใช้งานอยู่",
|
"workspace.reload.disabled.state": "ปิดใช้งานอยู่",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const dict = {
|
|||||||
"nav.enterprise": "Kurumsal",
|
"nav.enterprise": "Kurumsal",
|
||||||
"nav.zen": "Zen",
|
"nav.zen": "Zen",
|
||||||
"nav.login": "Giriş",
|
"nav.login": "Giriş",
|
||||||
"nav.free": "İndir",
|
"nav.free": "Ücretsiz",
|
||||||
"nav.home": "Ana sayfa",
|
"nav.home": "Ana sayfa",
|
||||||
"nav.openMenu": "Menüyü aç",
|
"nav.openMenu": "Menüyü aç",
|
||||||
"nav.getStartedFree": "Ücretsiz başla",
|
"nav.getStartedFree": "Ücretsiz başla",
|
||||||
@@ -567,13 +567,6 @@ export const dict = {
|
|||||||
"workspace.monthlyLimit.currentUsage.beforeMonth": "Şu anki kullanım",
|
"workspace.monthlyLimit.currentUsage.beforeMonth": "Şu anki kullanım",
|
||||||
"workspace.monthlyLimit.currentUsage.beforeAmount": "$",
|
"workspace.monthlyLimit.currentUsage.beforeAmount": "$",
|
||||||
|
|
||||||
"workspace.redeem.title": "Kupon Kullan",
|
|
||||||
"workspace.redeem.subtitle": "Kredi veya avantajlardan yararlanmak için bir kupon kodu kullanın.",
|
|
||||||
"workspace.redeem.placeholder": "Kupon kodunu girin",
|
|
||||||
"workspace.redeem.redeem": "Kullan",
|
|
||||||
"workspace.redeem.redeeming": "Kullanılıyor...",
|
|
||||||
"workspace.redeem.success": "Kupon başarıyla kullanıldı.",
|
|
||||||
|
|
||||||
"workspace.reload.title": "Otomatik Yeniden Yükleme",
|
"workspace.reload.title": "Otomatik Yeniden Yükleme",
|
||||||
"workspace.reload.disabled.before": "Otomatik yeniden yükleme:",
|
"workspace.reload.disabled.before": "Otomatik yeniden yükleme:",
|
||||||
"workspace.reload.disabled.state": "devre dışı",
|
"workspace.reload.disabled.state": "devre dışı",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const dict = {
|
|||||||
"nav.enterprise": "企业版",
|
"nav.enterprise": "企业版",
|
||||||
"nav.zen": "Zen",
|
"nav.zen": "Zen",
|
||||||
"nav.login": "登录",
|
"nav.login": "登录",
|
||||||
"nav.free": "下载",
|
"nav.free": "免费",
|
||||||
"nav.home": "首页",
|
"nav.home": "首页",
|
||||||
"nav.openMenu": "打开菜单",
|
"nav.openMenu": "打开菜单",
|
||||||
"nav.getStartedFree": "免费开始",
|
"nav.getStartedFree": "免费开始",
|
||||||
@@ -542,13 +542,6 @@ export const dict = {
|
|||||||
"workspace.monthlyLimit.currentUsage.beforeMonth": "当前",
|
"workspace.monthlyLimit.currentUsage.beforeMonth": "当前",
|
||||||
"workspace.monthlyLimit.currentUsage.beforeAmount": "的使用量为 $",
|
"workspace.monthlyLimit.currentUsage.beforeAmount": "的使用量为 $",
|
||||||
|
|
||||||
"workspace.redeem.title": "兑换优惠券",
|
|
||||||
"workspace.redeem.subtitle": "兑换优惠码以领取充值额度或权益。",
|
|
||||||
"workspace.redeem.placeholder": "输入优惠码",
|
|
||||||
"workspace.redeem.redeem": "兑换",
|
|
||||||
"workspace.redeem.redeeming": "兑换中...",
|
|
||||||
"workspace.redeem.success": "优惠券兑换成功。",
|
|
||||||
|
|
||||||
"workspace.reload.title": "自动充值",
|
"workspace.reload.title": "自动充值",
|
||||||
"workspace.reload.disabled.before": "自动充值已",
|
"workspace.reload.disabled.before": "自动充值已",
|
||||||
"workspace.reload.disabled.state": "禁用",
|
"workspace.reload.disabled.state": "禁用",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const dict = {
|
|||||||
"nav.enterprise": "企業",
|
"nav.enterprise": "企業",
|
||||||
"nav.zen": "Zen",
|
"nav.zen": "Zen",
|
||||||
"nav.login": "登入",
|
"nav.login": "登入",
|
||||||
"nav.free": "下載",
|
"nav.free": "免費",
|
||||||
"nav.home": "首頁",
|
"nav.home": "首頁",
|
||||||
"nav.openMenu": "開啟選單",
|
"nav.openMenu": "開啟選單",
|
||||||
"nav.getStartedFree": "免費開始使用",
|
"nav.getStartedFree": "免費開始使用",
|
||||||
@@ -542,13 +542,6 @@ export const dict = {
|
|||||||
"workspace.monthlyLimit.currentUsage.beforeMonth": "目前",
|
"workspace.monthlyLimit.currentUsage.beforeMonth": "目前",
|
||||||
"workspace.monthlyLimit.currentUsage.beforeAmount": "的使用量為 $",
|
"workspace.monthlyLimit.currentUsage.beforeAmount": "的使用量為 $",
|
||||||
|
|
||||||
"workspace.redeem.title": "兌換優惠券",
|
|
||||||
"workspace.redeem.subtitle": "兌換優惠碼以領取儲值額度或權益。",
|
|
||||||
"workspace.redeem.placeholder": "輸入優惠碼",
|
|
||||||
"workspace.redeem.redeem": "兌換",
|
|
||||||
"workspace.redeem.redeeming": "兌換中...",
|
|
||||||
"workspace.redeem.success": "優惠券兌換成功。",
|
|
||||||
|
|
||||||
"workspace.reload.title": "自動儲值",
|
"workspace.reload.title": "自動儲值",
|
||||||
"workspace.reload.disabled.before": "自動儲值已",
|
"workspace.reload.disabled.before": "自動儲值已",
|
||||||
"workspace.reload.disabled.state": "停用",
|
"workspace.reload.disabled.state": "停用",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import type { APIEvent } from "@solidjs/start/server"
|
import type { APIEvent } from "@solidjs/start/server"
|
||||||
import { AWS } from "@opencode-ai/console-core/aws.js"
|
import { AWS } from "@opencode-ai/console-core/aws.js"
|
||||||
import { Resource } from "@opencode-ai/console-resource"
|
|
||||||
import { i18n } from "~/i18n"
|
import { i18n } from "~/i18n"
|
||||||
import { localeFromRequest } from "~/lib/language"
|
import { localeFromRequest } from "~/lib/language"
|
||||||
import { createLead } from "~/lib/salesforce"
|
import { createLead } from "~/lib/salesforce"
|
||||||
@@ -15,64 +14,6 @@ interface EnterpriseFormData {
|
|||||||
message: string
|
message: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const EMAIL_OCTOPUS_LIST_ID = "1b381e5e-39bd-11f1-ba4a-cdd4791f0c43"
|
|
||||||
|
|
||||||
function splitFullName(fullName: string) {
|
|
||||||
const parts = fullName
|
|
||||||
.trim()
|
|
||||||
.split(/\s+/)
|
|
||||||
.filter((p) => p.length > 0)
|
|
||||||
if (parts.length === 0) return { firstName: "", lastName: "" }
|
|
||||||
if (parts.length === 1) return { firstName: parts[0], lastName: "" }
|
|
||||||
return { firstName: parts[0], lastName: parts.slice(1).join(" ") }
|
|
||||||
}
|
|
||||||
|
|
||||||
function getEmailOctopusApiKey() {
|
|
||||||
if (process.env.EMAILOCTOPUS_API_KEY) return process.env.EMAILOCTOPUS_API_KEY
|
|
||||||
try {
|
|
||||||
return Resource.EMAILOCTOPUS_API_KEY.value
|
|
||||||
} catch {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function subscribe(email: string, fullName: string) {
|
|
||||||
const apiKey = getEmailOctopusApiKey()
|
|
||||||
if (!apiKey) {
|
|
||||||
console.warn("Skipping EmailOctopus subscribe: missing API key")
|
|
||||||
return Promise.resolve(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
const name = splitFullName(fullName)
|
|
||||||
const fields: Record<string, string> = {}
|
|
||||||
if (name.firstName) fields.FirstName = name.firstName
|
|
||||||
if (name.lastName) fields.LastName = name.lastName
|
|
||||||
|
|
||||||
const payload: { email_address: string; fields?: Record<string, string> } = { email_address: email }
|
|
||||||
if (Object.keys(fields).length) payload.fields = fields
|
|
||||||
|
|
||||||
return fetch(`https://api.emailoctopus.com/lists/${EMAIL_OCTOPUS_LIST_ID}/contacts`, {
|
|
||||||
method: "PUT",
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${apiKey}`,
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify(payload),
|
|
||||||
}).then(
|
|
||||||
(res) => {
|
|
||||||
if (!res.ok) {
|
|
||||||
console.error("EmailOctopus subscribe failed:", res.status, res.statusText)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
(err) => {
|
|
||||||
console.error("Failed to subscribe enterprise email:", err)
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function POST(event: APIEvent) {
|
export async function POST(event: APIEvent) {
|
||||||
const dict = i18n(localeFromRequest(event.request))
|
const dict = i18n(localeFromRequest(event.request))
|
||||||
try {
|
try {
|
||||||
@@ -100,7 +41,7 @@ ${body.role}<br>
|
|||||||
${body.company ? `${body.company}<br>` : ""}${body.email}<br>
|
${body.company ? `${body.company}<br>` : ""}${body.email}<br>
|
||||||
${body.phone ? `${body.phone}<br>` : ""}`.trim()
|
${body.phone ? `${body.phone}<br>` : ""}`.trim()
|
||||||
|
|
||||||
const [lead, mail, octopus] = await Promise.all([
|
const [lead, mail] = await Promise.all([
|
||||||
createLead({
|
createLead({
|
||||||
name: body.name,
|
name: body.name,
|
||||||
role: body.role,
|
role: body.role,
|
||||||
@@ -108,9 +49,6 @@ ${body.phone ? `${body.phone}<br>` : ""}`.trim()
|
|||||||
email: body.email,
|
email: body.email,
|
||||||
phone: body.phone,
|
phone: body.phone,
|
||||||
message: body.message,
|
message: body.message,
|
||||||
}).catch((err) => {
|
|
||||||
console.error("Failed to create Salesforce lead:", err)
|
|
||||||
return false
|
|
||||||
}),
|
}),
|
||||||
AWS.sendEmail({
|
AWS.sendEmail({
|
||||||
to: "contact@anoma.ly",
|
to: "contact@anoma.ly",
|
||||||
@@ -124,14 +62,9 @@ ${body.phone ? `${body.phone}<br>` : ""}`.trim()
|
|||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
subscribe(body.email, body.name),
|
|
||||||
])
|
])
|
||||||
|
|
||||||
if (!lead && !mail && !octopus) {
|
if (!lead && !mail) {
|
||||||
if (import.meta.env.DEV) {
|
|
||||||
console.warn("Enterprise inquiry accepted in dev mode without integrations", { email: body.email })
|
|
||||||
return Response.json({ success: true, message: dict["enterprise.form.success.submitted"] }, { status: 200 })
|
|
||||||
}
|
|
||||||
console.error("Enterprise inquiry delivery failed", { email: body.email })
|
console.error("Enterprise inquiry delivery failed", { email: body.email })
|
||||||
return Response.json({ error: dict["enterprise.form.error.internalServer"] }, { status: 500 })
|
return Response.json({ error: dict["enterprise.form.error.internalServer"] }, { status: 500 })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { APIEvent } from "@solidjs/start"
|
import type { APIEvent } from "@solidjs/start"
|
||||||
import type { DownloadPlatform } from "../types"
|
import type { DownloadPlatform } from "../types"
|
||||||
|
|
||||||
const prodAssetNames: Record<string, string> = {
|
const assetNames: Record<string, string> = {
|
||||||
"darwin-aarch64-dmg": "opencode-desktop-darwin-aarch64.dmg",
|
"darwin-aarch64-dmg": "opencode-desktop-darwin-aarch64.dmg",
|
||||||
"darwin-x64-dmg": "opencode-desktop-darwin-x64.dmg",
|
"darwin-x64-dmg": "opencode-desktop-darwin-x64.dmg",
|
||||||
"windows-x64-nsis": "opencode-desktop-windows-x64.exe",
|
"windows-x64-nsis": "opencode-desktop-windows-x64.exe",
|
||||||
@@ -10,15 +10,6 @@ const prodAssetNames: Record<string, string> = {
|
|||||||
"linux-x64-rpm": "opencode-desktop-linux-x86_64.rpm",
|
"linux-x64-rpm": "opencode-desktop-linux-x86_64.rpm",
|
||||||
} satisfies Record<DownloadPlatform, string>
|
} satisfies Record<DownloadPlatform, string>
|
||||||
|
|
||||||
const betaAssetNames: Record<string, string> = {
|
|
||||||
"darwin-aarch64-dmg": "opencode-electron-mac-arm64.dmg",
|
|
||||||
"darwin-x64-dmg": "opencode-electron-mac-x64.dmg",
|
|
||||||
"windows-x64-nsis": "opencode-electron-win-x64.exe",
|
|
||||||
"linux-x64-deb": "opencode-electron-linux-amd64.deb",
|
|
||||||
"linux-x64-appimage": "opencode-electron-linux-x86_64.AppImage",
|
|
||||||
"linux-x64-rpm": "opencode-electron-linux-x86_64.rpm",
|
|
||||||
} satisfies Record<DownloadPlatform, string>
|
|
||||||
|
|
||||||
// Doing this on the server lets us preserve the original name for platforms we don't care to rename for
|
// Doing this on the server lets us preserve the original name for platforms we don't care to rename for
|
||||||
const downloadNames: Record<string, string> = {
|
const downloadNames: Record<string, string> = {
|
||||||
"darwin-aarch64-dmg": "OpenCode Desktop.dmg",
|
"darwin-aarch64-dmg": "OpenCode Desktop.dmg",
|
||||||
@@ -27,7 +18,7 @@ const downloadNames: Record<string, string> = {
|
|||||||
} satisfies { [K in DownloadPlatform]?: string }
|
} satisfies { [K in DownloadPlatform]?: string }
|
||||||
|
|
||||||
export async function GET({ params: { platform, channel } }: APIEvent) {
|
export async function GET({ params: { platform, channel } }: APIEvent) {
|
||||||
const assetName = channel === "stable" ? prodAssetNames[platform] : betaAssetNames[platform]
|
const assetName = assetNames[platform]
|
||||||
if (!assetName) return new Response(null, { status: 404 })
|
if (!assetName) return new Response(null, { status: 404 })
|
||||||
|
|
||||||
const resp = await fetch(
|
const resp = await fetch(
|
||||||
@@ -46,5 +37,5 @@ export async function GET({ params: { platform, channel } }: APIEvent) {
|
|||||||
const headers = new Headers(resp.headers)
|
const headers = new Headers(resp.headers)
|
||||||
if (downloadName) headers.set("content-disposition", `attachment; filename="${downloadName}"`)
|
if (downloadName) headers.set("content-disposition", `attachment; filename="${downloadName}"`)
|
||||||
|
|
||||||
return new Response(resp.body, { status: resp.status, statusText: resp.statusText, headers })
|
return new Response(resp.body, { ...resp, headers })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { Header } from "~/component/header"
|
|||||||
import { Footer } from "~/component/footer"
|
import { Footer } from "~/component/footer"
|
||||||
import { Legal } from "~/component/legal"
|
import { Legal } from "~/component/legal"
|
||||||
import { github } from "~/lib/github"
|
import { github } from "~/lib/github"
|
||||||
|
import { createMemo } from "solid-js"
|
||||||
import { config } from "~/config"
|
import { config } from "~/config"
|
||||||
import { useI18n } from "~/context/i18n"
|
import { useI18n } from "~/context/i18n"
|
||||||
import { useLanguage } from "~/context/language"
|
import { useLanguage } from "~/context/language"
|
||||||
@@ -29,7 +30,7 @@ function CopyStatus() {
|
|||||||
export default function Home() {
|
export default function Home() {
|
||||||
const i18n = useI18n()
|
const i18n = useI18n()
|
||||||
const language = useLanguage()
|
const language = useLanguage()
|
||||||
const _githubData = createAsync(() => github())
|
const githubData = createAsync(() => github())
|
||||||
const handleCopyClick = (event: Event) => {
|
const handleCopyClick = (event: Event) => {
|
||||||
const button = event.currentTarget as HTMLButtonElement
|
const button = event.currentTarget as HTMLButtonElement
|
||||||
const text = button.textContent
|
const text = button.textContent
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import { Actor } from "@opencode-ai/console-core/actor.js"
|
|||||||
import { Resource } from "@opencode-ai/console-resource"
|
import { Resource } from "@opencode-ai/console-resource"
|
||||||
import { LiteData } from "@opencode-ai/console-core/lite.js"
|
import { LiteData } from "@opencode-ai/console-core/lite.js"
|
||||||
import { BlackData } from "@opencode-ai/console-core/black.js"
|
import { BlackData } from "@opencode-ai/console-core/black.js"
|
||||||
import { User } from "@opencode-ai/console-core/user.js"
|
|
||||||
|
|
||||||
export async function POST(input: APIEvent) {
|
export async function POST(input: APIEvent) {
|
||||||
const body = await Billing.stripe().webhooks.constructEventAsync(
|
const body = await Billing.stripe().webhooks.constructEventAsync(
|
||||||
@@ -110,8 +109,6 @@ export async function POST(input: APIEvent) {
|
|||||||
if (type === "lite") {
|
if (type === "lite") {
|
||||||
const workspaceID = body.data.object.metadata?.workspaceID
|
const workspaceID = body.data.object.metadata?.workspaceID
|
||||||
const userID = body.data.object.metadata?.userID
|
const userID = body.data.object.metadata?.userID
|
||||||
const userEmail = body.data.object.metadata?.userEmail
|
|
||||||
const coupon = body.data.object.metadata?.coupon
|
|
||||||
const customerID = body.data.object.customer as string
|
const customerID = body.data.object.customer as string
|
||||||
const invoiceID = body.data.object.latest_invoice as string
|
const invoiceID = body.data.object.latest_invoice as string
|
||||||
const subscriptionID = body.data.object.id as string
|
const subscriptionID = body.data.object.id as string
|
||||||
@@ -159,10 +156,6 @@ export async function POST(input: APIEvent) {
|
|||||||
id: Identifier.create("lite"),
|
id: Identifier.create("lite"),
|
||||||
userID: userID,
|
userID: userID,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (userEmail && coupon === LiteData.firstMonth100Coupon) {
|
|
||||||
await Billing.redeemCoupon(userEmail, "GOFREEMONTH")
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,9 +116,9 @@ const createSessionUrl = action(async (workspaceID: string, returnUrl: string) =
|
|||||||
|
|
||||||
const setUseBalance = action(async (form: FormData) => {
|
const setUseBalance = action(async (form: FormData) => {
|
||||||
"use server"
|
"use server"
|
||||||
const workspaceID = form.get("workspaceID") as string | null
|
const workspaceID = form.get("workspaceID")?.toString()
|
||||||
if (!workspaceID) return { error: formError.workspaceRequired }
|
if (!workspaceID) return { error: formError.workspaceRequired }
|
||||||
const useBalance = (form.get("useBalance") as string | null) === "true"
|
const useBalance = form.get("useBalance")?.toString() === "true"
|
||||||
|
|
||||||
return json(
|
return json(
|
||||||
await withActor(async () => {
|
await withActor(async () => {
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { BillingSection } from "./billing-section"
|
|||||||
import { ReloadSection } from "./reload-section"
|
import { ReloadSection } from "./reload-section"
|
||||||
import { PaymentSection } from "./payment-section"
|
import { PaymentSection } from "./payment-section"
|
||||||
import { BlackSection } from "./black-section"
|
import { BlackSection } from "./black-section"
|
||||||
import { RedeemSection } from "./redeem-section"
|
|
||||||
import { createMemo, Show } from "solid-js"
|
import { createMemo, Show } from "solid-js"
|
||||||
import { createAsync, useParams } from "@solidjs/router"
|
import { createAsync, useParams } from "@solidjs/router"
|
||||||
import { queryBillingInfo, querySessionInfo } from "../../common"
|
import { queryBillingInfo, querySessionInfo } from "../../common"
|
||||||
@@ -22,7 +21,6 @@ export default function () {
|
|||||||
<BlackSection />
|
<BlackSection />
|
||||||
</Show>
|
</Show>
|
||||||
<BillingSection />
|
<BillingSection />
|
||||||
<RedeemSection />
|
|
||||||
<Show when={billingInfo()?.customerID}>
|
<Show when={billingInfo()?.customerID}>
|
||||||
<ReloadSection />
|
<ReloadSection />
|
||||||
<MonthlyLimitSection />
|
<MonthlyLimitSection />
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ import { formError, localizeError } from "~/lib/form-error"
|
|||||||
|
|
||||||
const setMonthlyLimit = action(async (form: FormData) => {
|
const setMonthlyLimit = action(async (form: FormData) => {
|
||||||
"use server"
|
"use server"
|
||||||
const limit = form.get("limit") as string | null
|
const limit = form.get("limit")?.toString()
|
||||||
if (!limit) return { error: formError.limitRequired }
|
if (!limit) return { error: formError.limitRequired }
|
||||||
const numericLimit = parseInt(limit)
|
const numericLimit = parseInt(limit)
|
||||||
if (numericLimit < 0) return { error: formError.monthlyLimitInvalid }
|
if (numericLimit < 0) return { error: formError.monthlyLimitInvalid }
|
||||||
const workspaceID = form.get("workspaceID") as string | null
|
const workspaceID = form.get("workspaceID")?.toString()
|
||||||
if (!workspaceID) return { error: formError.workspaceRequired }
|
if (!workspaceID) return { error: formError.workspaceRequired }
|
||||||
return json(
|
return json(
|
||||||
await withActor(
|
await withActor(
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
.root {
|
|
||||||
[data-slot="redeem-container"] {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: var(--space-3);
|
|
||||||
min-width: 20rem;
|
|
||||||
width: fit-content;
|
|
||||||
|
|
||||||
@media (max-width: 30rem) {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-slot="redeem-form"] {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: var(--space-2);
|
|
||||||
|
|
||||||
[data-slot="input-row"] {
|
|
||||||
display: flex;
|
|
||||||
gap: var(--space-2);
|
|
||||||
align-items: stretch;
|
|
||||||
|
|
||||||
@media (max-width: 30rem) {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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-error"] {
|
|
||||||
color: var(--color-danger);
|
|
||||||
font-size: var(--font-size-sm);
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-slot="form-success"] {
|
|
||||||
color: var(--color-success, var(--color-accent));
|
|
||||||
font-size: var(--font-size-sm);
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
import { json, action, useParams, useSubmission } from "@solidjs/router"
|
|
||||||
import { Show } from "solid-js"
|
|
||||||
import { withActor } from "~/context/auth.withActor"
|
|
||||||
import { Billing } from "@opencode-ai/console-core/billing.js"
|
|
||||||
import { User } from "@opencode-ai/console-core/user.js"
|
|
||||||
import { Actor } from "@opencode-ai/console-core/actor.js"
|
|
||||||
import { CouponType } from "@opencode-ai/console-core/schema/billing.sql.js"
|
|
||||||
import styles from "./redeem-section.module.css"
|
|
||||||
import { queryBillingInfo } from "../../common"
|
|
||||||
import { useI18n } from "~/context/i18n"
|
|
||||||
import { formError, localizeError } from "~/lib/form-error"
|
|
||||||
|
|
||||||
const redeem = action(async (form: FormData) => {
|
|
||||||
"use server"
|
|
||||||
const workspaceID = form.get("workspaceID") as string | null
|
|
||||||
if (!workspaceID) return { error: formError.workspaceRequired }
|
|
||||||
const code = (form.get("code") as string | null)?.trim().toUpperCase()
|
|
||||||
if (!code) return { error: "Coupon code is required." }
|
|
||||||
if (!(CouponType as readonly string[]).includes(code)) return { error: "Invalid coupon code." }
|
|
||||||
|
|
||||||
return json(
|
|
||||||
await withActor(async () => {
|
|
||||||
const actor = Actor.assert("user")
|
|
||||||
const email = await User.getAuthEmail(actor.properties.userID)
|
|
||||||
if (!email) return { error: "No email on account." }
|
|
||||||
return Billing.redeemCoupon(email, code as (typeof CouponType)[number])
|
|
||||||
.then(() => ({ error: undefined, data: true }))
|
|
||||||
.catch((e) => ({ error: e.message as string }))
|
|
||||||
}, workspaceID),
|
|
||||||
{ revalidate: queryBillingInfo.key },
|
|
||||||
)
|
|
||||||
}, "billing.redeemCoupon")
|
|
||||||
|
|
||||||
export function RedeemSection() {
|
|
||||||
const params = useParams()
|
|
||||||
const i18n = useI18n()
|
|
||||||
const submission = useSubmission(redeem)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<section class={styles.root}>
|
|
||||||
<div data-slot="section-title">
|
|
||||||
<h2>{i18n.t("workspace.redeem.title")}</h2>
|
|
||||||
<p>{i18n.t("workspace.redeem.subtitle")}</p>
|
|
||||||
</div>
|
|
||||||
<div data-slot="redeem-container">
|
|
||||||
<form action={redeem} method="post" data-slot="redeem-form">
|
|
||||||
<div data-slot="input-row">
|
|
||||||
<input
|
|
||||||
required
|
|
||||||
data-component="input"
|
|
||||||
name="code"
|
|
||||||
type="text"
|
|
||||||
autocomplete="off"
|
|
||||||
placeholder={i18n.t("workspace.redeem.placeholder")}
|
|
||||||
/>
|
|
||||||
<button type="submit" data-color="primary" disabled={submission.pending}>
|
|
||||||
{submission.pending ? i18n.t("workspace.redeem.redeeming") : i18n.t("workspace.redeem.redeem")}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<Show when={submission.result && (submission.result as any).error}>
|
|
||||||
{(err: any) => <div data-slot="form-error">{localizeError(i18n.t, err())}</div>}
|
|
||||||
</Show>
|
|
||||||
<Show when={submission.result && !(submission.result as any).error && (submission.result as any).data}>
|
|
||||||
<div data-slot="form-success">{i18n.t("workspace.redeem.success")}</div>
|
|
||||||
</Show>
|
|
||||||
<input type="hidden" name="workspaceID" value={params.id} />
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -12,7 +12,7 @@ import { formError, formErrorReloadAmountMin, formErrorReloadTriggerMin, localiz
|
|||||||
|
|
||||||
const reload = action(async (form: FormData) => {
|
const reload = action(async (form: FormData) => {
|
||||||
"use server"
|
"use server"
|
||||||
const workspaceID = form.get("workspaceID") as string | null
|
const workspaceID = form.get("workspaceID")?.toString()
|
||||||
if (!workspaceID) return { error: formError.workspaceRequired }
|
if (!workspaceID) return { error: formError.workspaceRequired }
|
||||||
return json(await withActor(() => Billing.reload(), workspaceID), {
|
return json(await withActor(() => Billing.reload(), workspaceID), {
|
||||||
revalidate: queryBillingInfo.key,
|
revalidate: queryBillingInfo.key,
|
||||||
@@ -21,11 +21,11 @@ const reload = action(async (form: FormData) => {
|
|||||||
|
|
||||||
const setReload = action(async (form: FormData) => {
|
const setReload = action(async (form: FormData) => {
|
||||||
"use server"
|
"use server"
|
||||||
const workspaceID = form.get("workspaceID") as string | null
|
const workspaceID = form.get("workspaceID")?.toString()
|
||||||
if (!workspaceID) return { error: formError.workspaceRequired }
|
if (!workspaceID) return { error: formError.workspaceRequired }
|
||||||
const reloadValue = (form.get("reload") as string | null) === "true"
|
const reloadValue = form.get("reload")?.toString() === "true"
|
||||||
const amountStr = form.get("reloadAmount") as string | null
|
const amountStr = form.get("reloadAmount")?.toString()
|
||||||
const triggerStr = form.get("reloadTrigger") as string | null
|
const triggerStr = form.get("reloadTrigger")?.toString()
|
||||||
|
|
||||||
const reloadAmount = amountStr && amountStr.trim() !== "" ? parseInt(amountStr) : null
|
const reloadAmount = amountStr && amountStr.trim() !== "" ? parseInt(amountStr) : null
|
||||||
const reloadTrigger = triggerStr && triggerStr.trim() !== "" ? parseInt(triggerStr) : null
|
const reloadTrigger = triggerStr && triggerStr.trim() !== "" ? parseInt(triggerStr) : null
|
||||||
@@ -91,8 +91,8 @@ export function ReloadSection() {
|
|||||||
const info = billingInfo()!
|
const info = billingInfo()!
|
||||||
setStore("show", true)
|
setStore("show", true)
|
||||||
setStore("reload", true)
|
setStore("reload", true)
|
||||||
setStore("reloadAmount", String(info.reloadAmount))
|
setStore("reloadAmount", info.reloadAmount.toString())
|
||||||
setStore("reloadTrigger", String(info.reloadTrigger))
|
setStore("reloadTrigger", info.reloadTrigger.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
function hide() {
|
function hide() {
|
||||||
@@ -152,11 +152,11 @@ export function ReloadSection() {
|
|||||||
data-component="input"
|
data-component="input"
|
||||||
name="reloadAmount"
|
name="reloadAmount"
|
||||||
type="number"
|
type="number"
|
||||||
min={String(billingInfo()?.reloadAmountMin ?? "")}
|
min={billingInfo()?.reloadAmountMin.toString()}
|
||||||
step="1"
|
step="1"
|
||||||
value={store.reloadAmount}
|
value={store.reloadAmount}
|
||||||
onInput={(e) => setStore("reloadAmount", e.currentTarget.value)}
|
onInput={(e) => setStore("reloadAmount", e.currentTarget.value)}
|
||||||
placeholder={String(billingInfo()?.reloadAmount ?? "")}
|
placeholder={billingInfo()?.reloadAmount.toString()}
|
||||||
disabled={!store.reload}
|
disabled={!store.reload}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -166,11 +166,11 @@ export function ReloadSection() {
|
|||||||
data-component="input"
|
data-component="input"
|
||||||
name="reloadTrigger"
|
name="reloadTrigger"
|
||||||
type="number"
|
type="number"
|
||||||
min={String(billingInfo()?.reloadTriggerMin ?? "")}
|
min={billingInfo()?.reloadTriggerMin.toString()}
|
||||||
step="1"
|
step="1"
|
||||||
value={store.reloadTrigger}
|
value={store.reloadTrigger}
|
||||||
onInput={(e) => setStore("reloadTrigger", e.currentTarget.value)}
|
onInput={(e) => setStore("reloadTrigger", e.currentTarget.value)}
|
||||||
placeholder={String(billingInfo()?.reloadTrigger ?? "")}
|
placeholder={billingInfo()?.reloadTrigger.toString()}
|
||||||
disabled={!store.reload}
|
disabled={!store.reload}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -120,9 +120,9 @@ const createSessionUrl = action(async (workspaceID: string, returnUrl: string) =
|
|||||||
|
|
||||||
const setLiteUseBalance = action(async (form: FormData) => {
|
const setLiteUseBalance = action(async (form: FormData) => {
|
||||||
"use server"
|
"use server"
|
||||||
const workspaceID = form.get("workspaceID") as string | null
|
const workspaceID = form.get("workspaceID")?.toString()
|
||||||
if (!workspaceID) return { error: formError.workspaceRequired }
|
if (!workspaceID) return { error: formError.workspaceRequired }
|
||||||
const useBalance = (form.get("useBalance") as string | null) === "true"
|
const useBalance = form.get("useBalance")?.toString() === "true"
|
||||||
|
|
||||||
return json(
|
return json(
|
||||||
await withActor(async () => {
|
await withActor(async () => {
|
||||||
|
|||||||
@@ -12,18 +12,18 @@ import { formError, localizeError } from "~/lib/form-error"
|
|||||||
|
|
||||||
const removeKey = action(async (form: FormData) => {
|
const removeKey = action(async (form: FormData) => {
|
||||||
"use server"
|
"use server"
|
||||||
const id = form.get("id") as string | null
|
const id = form.get("id")?.toString()
|
||||||
if (!id) return { error: formError.idRequired }
|
if (!id) return { error: formError.idRequired }
|
||||||
const workspaceID = form.get("workspaceID") as string | null
|
const workspaceID = form.get("workspaceID")?.toString()
|
||||||
if (!workspaceID) return { error: formError.workspaceRequired }
|
if (!workspaceID) return { error: formError.workspaceRequired }
|
||||||
return json(await withActor(() => Key.remove({ id }), workspaceID), { revalidate: listKeys.key })
|
return json(await withActor(() => Key.remove({ id }), workspaceID), { revalidate: listKeys.key })
|
||||||
}, "key.remove")
|
}, "key.remove")
|
||||||
|
|
||||||
const createKey = action(async (form: FormData) => {
|
const createKey = action(async (form: FormData) => {
|
||||||
"use server"
|
"use server"
|
||||||
const name = (form.get("name") as string | null)?.trim()
|
const name = form.get("name")?.toString().trim()
|
||||||
if (!name) return { error: formError.nameRequired }
|
if (!name) return { error: formError.nameRequired }
|
||||||
const workspaceID = form.get("workspaceID") as string | null
|
const workspaceID = form.get("workspaceID")?.toString()
|
||||||
if (!workspaceID) return { error: formError.workspaceRequired }
|
if (!workspaceID) return { error: formError.workspaceRequired }
|
||||||
return json(
|
return json(
|
||||||
await withActor(
|
await withActor(
|
||||||
|
|||||||
@@ -24,13 +24,13 @@ const listMembers = query(async (workspaceID: string) => {
|
|||||||
|
|
||||||
const inviteMember = action(async (form: FormData) => {
|
const inviteMember = action(async (form: FormData) => {
|
||||||
"use server"
|
"use server"
|
||||||
const email = (form.get("email") as string | null)?.trim()
|
const email = form.get("email")?.toString().trim()
|
||||||
if (!email) return { error: formError.emailRequired }
|
if (!email) return { error: formError.emailRequired }
|
||||||
const workspaceID = form.get("workspaceID") as string | null
|
const workspaceID = form.get("workspaceID")?.toString()
|
||||||
if (!workspaceID) return { error: formError.workspaceRequired }
|
if (!workspaceID) return { error: formError.workspaceRequired }
|
||||||
const role = form.get("role") as (typeof UserRole)[number] | null
|
const role = form.get("role")?.toString() as (typeof UserRole)[number]
|
||||||
if (!role) return { error: formError.roleRequired }
|
if (!role) return { error: formError.roleRequired }
|
||||||
const limit = form.get("limit") as string | null
|
const limit = form.get("limit")?.toString()
|
||||||
const monthlyLimit = limit && limit.trim() !== "" ? parseInt(limit) : null
|
const monthlyLimit = limit && limit.trim() !== "" ? parseInt(limit) : null
|
||||||
if (monthlyLimit !== null && monthlyLimit < 0) return { error: formError.monthlyLimitInvalid }
|
if (monthlyLimit !== null && monthlyLimit < 0) return { error: formError.monthlyLimitInvalid }
|
||||||
return json(
|
return json(
|
||||||
@@ -47,9 +47,9 @@ const inviteMember = action(async (form: FormData) => {
|
|||||||
|
|
||||||
const removeMember = action(async (form: FormData) => {
|
const removeMember = action(async (form: FormData) => {
|
||||||
"use server"
|
"use server"
|
||||||
const id = form.get("id") as string | null
|
const id = form.get("id")?.toString()
|
||||||
if (!id) return { error: formError.idRequired }
|
if (!id) return { error: formError.idRequired }
|
||||||
const workspaceID = form.get("workspaceID") as string | null
|
const workspaceID = form.get("workspaceID")?.toString()
|
||||||
if (!workspaceID) return { error: formError.workspaceRequired }
|
if (!workspaceID) return { error: formError.workspaceRequired }
|
||||||
return json(
|
return json(
|
||||||
await withActor(
|
await withActor(
|
||||||
@@ -66,13 +66,13 @@ const removeMember = action(async (form: FormData) => {
|
|||||||
const updateMember = action(async (form: FormData) => {
|
const updateMember = action(async (form: FormData) => {
|
||||||
"use server"
|
"use server"
|
||||||
|
|
||||||
const id = form.get("id") as string | null
|
const id = form.get("id")?.toString()
|
||||||
if (!id) return { error: formError.idRequired }
|
if (!id) return { error: formError.idRequired }
|
||||||
const workspaceID = form.get("workspaceID") as string | null
|
const workspaceID = form.get("workspaceID")?.toString()
|
||||||
if (!workspaceID) return { error: formError.workspaceRequired }
|
if (!workspaceID) return { error: formError.workspaceRequired }
|
||||||
const role = form.get("role") as (typeof UserRole)[number] | null
|
const role = form.get("role")?.toString() as (typeof UserRole)[number]
|
||||||
if (!role) return { error: formError.roleRequired }
|
if (!role) return { error: formError.roleRequired }
|
||||||
const limit = form.get("limit") as string | null
|
const limit = form.get("limit")?.toString()
|
||||||
const monthlyLimit = limit && limit.trim() !== "" ? parseInt(limit) : null
|
const monthlyLimit = limit && limit.trim() !== "" ? parseInt(limit) : null
|
||||||
if (monthlyLimit !== null && monthlyLimit < 0) return { error: formError.monthlyLimitInvalid }
|
if (monthlyLimit !== null && monthlyLimit < 0) return { error: formError.monthlyLimitInvalid }
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@ function MemberRow(props: {
|
|||||||
}
|
}
|
||||||
setStore("editing", true)
|
setStore("editing", true)
|
||||||
setStore("selectedRole", props.member.role)
|
setStore("selectedRole", props.member.role)
|
||||||
setStore("limit", props.member.monthlyLimit != null ? String(props.member.monthlyLimit) : "")
|
setStore("limit", props.member.monthlyLimit?.toString() ?? "")
|
||||||
}
|
}
|
||||||
|
|
||||||
function hide() {
|
function hide() {
|
||||||
|
|||||||
@@ -67,11 +67,11 @@ const getModelsInfo = query(async (workspaceID: string) => {
|
|||||||
|
|
||||||
const updateModel = action(async (form: FormData) => {
|
const updateModel = action(async (form: FormData) => {
|
||||||
"use server"
|
"use server"
|
||||||
const model = form.get("model") as string | null
|
const model = form.get("model")?.toString()
|
||||||
if (!model) return { error: formError.modelRequired }
|
if (!model) return { error: formError.modelRequired }
|
||||||
const workspaceID = form.get("workspaceID") as string | null
|
const workspaceID = form.get("workspaceID")?.toString()
|
||||||
if (!workspaceID) return { error: formError.workspaceRequired }
|
if (!workspaceID) return { error: formError.workspaceRequired }
|
||||||
const enabled = (form.get("enabled") as string | null) === "true"
|
const enabled = form.get("enabled")?.toString() === "true"
|
||||||
return json(
|
return json(
|
||||||
withActor(async () => {
|
withActor(async () => {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
@@ -163,7 +163,7 @@ export function ModelSection() {
|
|||||||
<form action={updateModel} method="post">
|
<form action={updateModel} method="post">
|
||||||
<input type="hidden" name="model" value={id} />
|
<input type="hidden" name="model" value={id} />
|
||||||
<input type="hidden" name="workspaceID" value={params.id} />
|
<input type="hidden" name="workspaceID" value={params.id} />
|
||||||
<input type="hidden" name="enabled" value={String(isEnabled())} />
|
<input type="hidden" name="enabled" value={isEnabled().toString()} />
|
||||||
<label data-slot="model-toggle-label">
|
<label data-slot="model-toggle-label">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ function maskCredentials(credentials: string) {
|
|||||||
|
|
||||||
const removeProvider = action(async (form: FormData) => {
|
const removeProvider = action(async (form: FormData) => {
|
||||||
"use server"
|
"use server"
|
||||||
const provider = form.get("provider") as string | null
|
const provider = form.get("provider")?.toString()
|
||||||
if (!provider) return { error: formError.providerRequired }
|
if (!provider) return { error: formError.providerRequired }
|
||||||
const workspaceID = form.get("workspaceID") as string | null
|
const workspaceID = form.get("workspaceID")?.toString()
|
||||||
if (!workspaceID) return { error: formError.workspaceRequired }
|
if (!workspaceID) return { error: formError.workspaceRequired }
|
||||||
return json(await withActor(() => Provider.remove({ provider }), workspaceID), {
|
return json(await withActor(() => Provider.remove({ provider }), workspaceID), {
|
||||||
revalidate: listProviders.key,
|
revalidate: listProviders.key,
|
||||||
@@ -32,11 +32,11 @@ const removeProvider = action(async (form: FormData) => {
|
|||||||
|
|
||||||
const saveProvider = action(async (form: FormData) => {
|
const saveProvider = action(async (form: FormData) => {
|
||||||
"use server"
|
"use server"
|
||||||
const provider = form.get("provider") as string | null
|
const provider = form.get("provider")?.toString()
|
||||||
const credentials = form.get("credentials") as string | null
|
const credentials = form.get("credentials")?.toString()
|
||||||
if (!provider) return { error: formError.providerRequired }
|
if (!provider) return { error: formError.providerRequired }
|
||||||
if (!credentials) return { error: formError.apiKeyRequired }
|
if (!credentials) return { error: formError.apiKeyRequired }
|
||||||
const workspaceID = form.get("workspaceID") as string | null
|
const workspaceID = form.get("workspaceID")?.toString()
|
||||||
if (!workspaceID) return { error: formError.workspaceRequired }
|
if (!workspaceID) return { error: formError.workspaceRequired }
|
||||||
return json(
|
return json(
|
||||||
await withActor(
|
await withActor(
|
||||||
@@ -59,13 +59,10 @@ function ProviderRow(props: { provider: Provider }) {
|
|||||||
const params = useParams()
|
const params = useParams()
|
||||||
const i18n = useI18n()
|
const i18n = useI18n()
|
||||||
const providers = createAsync(() => listProviders(params.id!))
|
const providers = createAsync(() => listProviders(params.id!))
|
||||||
const saveSubmission = useSubmission(
|
const saveSubmission = useSubmission(saveProvider, ([fd]) => fd.get("provider")?.toString() === props.provider.key)
|
||||||
saveProvider,
|
|
||||||
([fd]) => (fd.get("provider") as string | null) === props.provider.key,
|
|
||||||
)
|
|
||||||
const removeSubmission = useSubmission(
|
const removeSubmission = useSubmission(
|
||||||
removeProvider,
|
removeProvider,
|
||||||
([fd]) => (fd.get("provider") as string | null) === props.provider.key,
|
([fd]) => fd.get("provider")?.toString() === props.provider.key,
|
||||||
)
|
)
|
||||||
const [store, setStore] = createStore({ editing: false })
|
const [store, setStore] = createStore({ editing: false })
|
||||||
|
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ const getWorkspaceInfo = query(async (workspaceID: string) => {
|
|||||||
|
|
||||||
const updateWorkspace = action(async (form: FormData) => {
|
const updateWorkspace = action(async (form: FormData) => {
|
||||||
"use server"
|
"use server"
|
||||||
const name = (form.get("name") as string | null)?.trim()
|
const name = form.get("name")?.toString().trim()
|
||||||
if (!name) return { error: formError.workspaceNameRequired }
|
if (!name) return { error: formError.workspaceNameRequired }
|
||||||
if (name.length > 255) return { error: formError.nameTooLong }
|
if (name.length > 255) return { error: formError.nameTooLong }
|
||||||
const workspaceID = form.get("workspaceID") as string | null
|
const workspaceID = form.get("workspaceID")?.toString()
|
||||||
if (!workspaceID) return { error: formError.workspaceRequired }
|
if (!workspaceID) return { error: formError.workspaceRequired }
|
||||||
return json(
|
return json(
|
||||||
await withActor(
|
await withActor(
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ import { LiteData } from "@opencode-ai/console-core/lite.js"
|
|||||||
import { Resource } from "@opencode-ai/console-resource"
|
import { Resource } from "@opencode-ai/console-resource"
|
||||||
import { i18n, type Key } from "~/i18n"
|
import { i18n, type Key } from "~/i18n"
|
||||||
import { localeFromRequest } from "~/lib/language"
|
import { localeFromRequest } from "~/lib/language"
|
||||||
import { createModelTpmLimiter } from "./modelTpmLimiter"
|
|
||||||
|
|
||||||
type ZenData = Awaited<ReturnType<typeof ZenData.list>>
|
type ZenData = Awaited<ReturnType<typeof ZenData.list>>
|
||||||
type RetryOptions = {
|
type RetryOptions = {
|
||||||
@@ -122,8 +121,6 @@ export async function handler(
|
|||||||
const authInfo = await authenticate(modelInfo, zenApiKey)
|
const authInfo = await authenticate(modelInfo, zenApiKey)
|
||||||
const billingSource = validateBilling(authInfo, modelInfo)
|
const billingSource = validateBilling(authInfo, modelInfo)
|
||||||
logger.metric({ source: billingSource })
|
logger.metric({ source: billingSource })
|
||||||
const modelTpmLimiter = createModelTpmLimiter(modelInfo.providers)
|
|
||||||
const modelTpmLimits = await modelTpmLimiter?.check()
|
|
||||||
|
|
||||||
const retriableRequest = async (retry: RetryOptions = { excludeProviders: [], retryCount: 0 }) => {
|
const retriableRequest = async (retry: RetryOptions = { excludeProviders: [], retryCount: 0 }) => {
|
||||||
const providerInfo = selectProvider(
|
const providerInfo = selectProvider(
|
||||||
@@ -136,7 +133,6 @@ export async function handler(
|
|||||||
trialProviders,
|
trialProviders,
|
||||||
retry,
|
retry,
|
||||||
stickyProvider,
|
stickyProvider,
|
||||||
modelTpmLimits,
|
|
||||||
)
|
)
|
||||||
validateModelSettings(billingSource, authInfo)
|
validateModelSettings(billingSource, authInfo)
|
||||||
updateProviderKey(authInfo, providerInfo)
|
updateProviderKey(authInfo, providerInfo)
|
||||||
@@ -233,7 +229,6 @@ export async function handler(
|
|||||||
const usageInfo = providerInfo.normalizeUsage(json.usage)
|
const usageInfo = providerInfo.normalizeUsage(json.usage)
|
||||||
const costInfo = calculateCost(modelInfo, usageInfo)
|
const costInfo = calculateCost(modelInfo, usageInfo)
|
||||||
await trialLimiter?.track(usageInfo)
|
await trialLimiter?.track(usageInfo)
|
||||||
await modelTpmLimiter?.track(providerInfo.id, providerInfo.model, usageInfo)
|
|
||||||
await trackUsage(sessionId, billingSource, authInfo, modelInfo, providerInfo, usageInfo, costInfo)
|
await trackUsage(sessionId, billingSource, authInfo, modelInfo, providerInfo, usageInfo, costInfo)
|
||||||
await reload(billingSource, authInfo, costInfo)
|
await reload(billingSource, authInfo, costInfo)
|
||||||
json.cost = calculateOccurredCost(billingSource, costInfo)
|
json.cost = calculateOccurredCost(billingSource, costInfo)
|
||||||
@@ -283,7 +278,6 @@ export async function handler(
|
|||||||
const usageInfo = providerInfo.normalizeUsage(usage)
|
const usageInfo = providerInfo.normalizeUsage(usage)
|
||||||
const costInfo = calculateCost(modelInfo, usageInfo)
|
const costInfo = calculateCost(modelInfo, usageInfo)
|
||||||
await trialLimiter?.track(usageInfo)
|
await trialLimiter?.track(usageInfo)
|
||||||
await modelTpmLimiter?.track(providerInfo.id, providerInfo.model, usageInfo)
|
|
||||||
await trackUsage(sessionId, billingSource, authInfo, modelInfo, providerInfo, usageInfo, costInfo)
|
await trackUsage(sessionId, billingSource, authInfo, modelInfo, providerInfo, usageInfo, costInfo)
|
||||||
await reload(billingSource, authInfo, costInfo)
|
await reload(billingSource, authInfo, costInfo)
|
||||||
const cost = calculateOccurredCost(billingSource, costInfo)
|
const cost = calculateOccurredCost(billingSource, costInfo)
|
||||||
@@ -439,16 +433,12 @@ export async function handler(
|
|||||||
trialProviders: string[] | undefined,
|
trialProviders: string[] | undefined,
|
||||||
retry: RetryOptions,
|
retry: RetryOptions,
|
||||||
stickyProvider: string | undefined,
|
stickyProvider: string | undefined,
|
||||||
modelTpmLimits: Record<string, number> | undefined,
|
|
||||||
) {
|
) {
|
||||||
const modelProvider = (() => {
|
const modelProvider = (() => {
|
||||||
// Byok is top priority b/c if user set their own API key, we should use it
|
|
||||||
// instead of using the sticky provider for the same session
|
|
||||||
if (authInfo?.provider?.credentials) {
|
if (authInfo?.provider?.credentials) {
|
||||||
return modelInfo.providers.find((provider) => provider.id === modelInfo.byokProvider)
|
return modelInfo.providers.find((provider) => provider.id === modelInfo.byokProvider)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always use the same provider for the same session
|
|
||||||
if (stickyProvider) {
|
if (stickyProvider) {
|
||||||
const provider = modelInfo.providers.find((provider) => provider.id === stickyProvider)
|
const provider = modelInfo.providers.find((provider) => provider.id === stickyProvider)
|
||||||
if (provider) return provider
|
if (provider) return provider
|
||||||
@@ -461,20 +451,10 @@ export async function handler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (retry.retryCount !== MAX_FAILOVER_RETRIES) {
|
if (retry.retryCount !== MAX_FAILOVER_RETRIES) {
|
||||||
const allProviders = modelInfo.providers
|
const providers = modelInfo.providers
|
||||||
.filter((provider) => !provider.disabled)
|
.filter((provider) => !provider.disabled)
|
||||||
.filter((provider) => provider.weight !== 0)
|
|
||||||
.filter((provider) => !retry.excludeProviders.includes(provider.id))
|
.filter((provider) => !retry.excludeProviders.includes(provider.id))
|
||||||
.filter((provider) => {
|
.flatMap((provider) => Array<typeof provider>(provider.weight ?? 1).fill(provider))
|
||||||
if (!provider.tpmLimit) return true
|
|
||||||
const usage = modelTpmLimits?.[`${provider.id}/${provider.model}`] ?? 0
|
|
||||||
return usage < provider.tpmLimit * 1_000_000
|
|
||||||
})
|
|
||||||
|
|
||||||
const topPriority = Math.min(...allProviders.map((p) => p.priority))
|
|
||||||
const providers = allProviders
|
|
||||||
.filter((p) => p.priority <= topPriority)
|
|
||||||
.flatMap((provider) => Array<typeof provider>(provider.weight).fill(provider))
|
|
||||||
|
|
||||||
// Use the last 4 characters of session ID to select a provider
|
// Use the last 4 characters of session ID to select a provider
|
||||||
const identifier = sessionId.length ? sessionId : ip
|
const identifier = sessionId.length ? sessionId : ip
|
||||||
@@ -762,8 +742,7 @@ export async function handler(
|
|||||||
const billing = authInfo.billing
|
const billing = authInfo.billing
|
||||||
const billingUrl = `https://opencode.ai/workspace/${authInfo.workspaceID}/billing`
|
const billingUrl = `https://opencode.ai/workspace/${authInfo.workspaceID}/billing`
|
||||||
const membersUrl = `https://opencode.ai/workspace/${authInfo.workspaceID}/members`
|
const membersUrl = `https://opencode.ai/workspace/${authInfo.workspaceID}/members`
|
||||||
if (!billing.paymentMethodID && billing.balance <= 0)
|
if (!billing.paymentMethodID) throw new CreditsError(t("zen.api.error.noPaymentMethod", { billingUrl }))
|
||||||
throw new CreditsError(t("zen.api.error.noPaymentMethod", { billingUrl }))
|
|
||||||
if (billing.balance <= 0) throw new CreditsError(t("zen.api.error.insufficientBalance", { billingUrl }))
|
if (billing.balance <= 0) throw new CreditsError(t("zen.api.error.insufficientBalance", { billingUrl }))
|
||||||
|
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
import { and, Database, eq, inArray, sql } from "@opencode-ai/console-core/drizzle/index.js"
|
|
||||||
import { ModelRateLimitTable } from "@opencode-ai/console-core/schema/ip.sql.js"
|
|
||||||
import { UsageInfo } from "./provider/provider"
|
|
||||||
|
|
||||||
export function createModelTpmLimiter(providers: { id: string; model: string; tpmLimit?: number }[]) {
|
|
||||||
const keys = providers.filter((p) => p.tpmLimit).map((p) => `${p.id}/${p.model}`)
|
|
||||||
if (keys.length === 0) return
|
|
||||||
|
|
||||||
const yyyyMMddHHmm = new Date(Date.now())
|
|
||||||
.toISOString()
|
|
||||||
.replace(/[^0-9]/g, "")
|
|
||||||
.substring(0, 12)
|
|
||||||
|
|
||||||
return {
|
|
||||||
check: async () => {
|
|
||||||
const data = await Database.use((tx) =>
|
|
||||||
tx
|
|
||||||
.select()
|
|
||||||
.from(ModelRateLimitTable)
|
|
||||||
.where(and(inArray(ModelRateLimitTable.key, keys), eq(ModelRateLimitTable.interval, yyyyMMddHHmm))),
|
|
||||||
)
|
|
||||||
|
|
||||||
// convert to map of model to count
|
|
||||||
return data.reduce(
|
|
||||||
(acc, curr) => {
|
|
||||||
acc[curr.key] = curr.count
|
|
||||||
return acc
|
|
||||||
},
|
|
||||||
{} as Record<string, number>,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
track: async (id: string, model: string, usageInfo: UsageInfo) => {
|
|
||||||
const key = `${id}/${model}`
|
|
||||||
if (!keys.includes(key)) return
|
|
||||||
const usage =
|
|
||||||
usageInfo.inputTokens +
|
|
||||||
usageInfo.outputTokens +
|
|
||||||
(usageInfo.reasoningTokens ?? 0) +
|
|
||||||
(usageInfo.cacheReadTokens ?? 0) +
|
|
||||||
(usageInfo.cacheWrite5mTokens ?? 0) +
|
|
||||||
(usageInfo.cacheWrite1hTokens ?? 0)
|
|
||||||
if (usage <= 0) return
|
|
||||||
await Database.use((tx) =>
|
|
||||||
tx
|
|
||||||
.insert(ModelRateLimitTable)
|
|
||||||
.values({ key, interval: yyyyMMddHHmm, count: usage })
|
|
||||||
.onDuplicateKeyUpdate({ set: { count: sql`${ModelRateLimitTable.count} + ${usage}` } }),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
CREATE TABLE `model_rate_limit` (
|
|
||||||
`key` varchar(255) NOT NULL,
|
|
||||||
`interval` varchar(40) NOT NULL,
|
|
||||||
`count` int NOT NULL,
|
|
||||||
CONSTRAINT PRIMARY KEY(`key`,`interval`)
|
|
||||||
);
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +0,0 @@
|
|||||||
CREATE TABLE `coupon` (
|
|
||||||
`email` varchar(255),
|
|
||||||
`type` enum('BUILDATHON','GOFREEMONTH') NOT NULL,
|
|
||||||
`time_redeemed` timestamp(3),
|
|
||||||
CONSTRAINT PRIMARY KEY(`email`,`type`)
|
|
||||||
);
|
|
||||||
-2619
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"name": "@opencode-ai/console-core",
|
"name": "@opencode-ai/console-core",
|
||||||
"version": "1.14.18",
|
"version": "1.4.6",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
import { Database } from "../src/drizzle/index.js"
|
|
||||||
import { CouponTable, CouponType } from "../src/schema/billing.sql.js"
|
|
||||||
|
|
||||||
const email = process.argv[2]
|
|
||||||
const type = process.argv[3] as (typeof CouponType)[number]
|
|
||||||
|
|
||||||
if (!email || !type) {
|
|
||||||
console.error(`Usage: bun create-coupon.ts <email> <${CouponType.join("|")}>`)
|
|
||||||
process.exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(CouponType as readonly string[]).includes(type)) {
|
|
||||||
console.error(`Error: type must be one of ${CouponType.join(", ")}`)
|
|
||||||
process.exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
await Database.use((tx) =>
|
|
||||||
tx.insert(CouponTable).values({
|
|
||||||
email,
|
|
||||||
type,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
console.log(`Created ${type} coupon for ${email}`)
|
|
||||||
@@ -1,14 +1,6 @@
|
|||||||
import { Stripe } from "stripe"
|
import { Stripe } from "stripe"
|
||||||
import { and, Database, eq, isNull, sql } from "./drizzle"
|
import { Database, eq, sql } from "./drizzle"
|
||||||
import {
|
import { BillingTable, LiteTable, PaymentTable, SubscriptionTable, UsageTable } from "./schema/billing.sql"
|
||||||
BillingTable,
|
|
||||||
CouponTable,
|
|
||||||
CouponType,
|
|
||||||
LiteTable,
|
|
||||||
PaymentTable,
|
|
||||||
SubscriptionTable,
|
|
||||||
UsageTable,
|
|
||||||
} from "./schema/billing.sql"
|
|
||||||
import { Actor } from "./actor"
|
import { Actor } from "./actor"
|
||||||
import { fn } from "./util/fn"
|
import { fn } from "./util/fn"
|
||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
@@ -155,37 +147,6 @@ export namespace Billing {
|
|||||||
return amountInMicroCents
|
return amountInMicroCents
|
||||||
}
|
}
|
||||||
|
|
||||||
export const redeemCoupon = async (email: string, type: (typeof CouponType)[number]) => {
|
|
||||||
const coupon = await Database.use((tx) =>
|
|
||||||
tx
|
|
||||||
.select()
|
|
||||||
.from(CouponTable)
|
|
||||||
.where(and(eq(CouponTable.email, email), eq(CouponTable.type, type)))
|
|
||||||
.then((rows) => rows[0]),
|
|
||||||
)
|
|
||||||
if (!coupon) throw new Error("Invalid coupon code")
|
|
||||||
if (coupon.timeRedeemed) throw new Error("Coupon already redeemed")
|
|
||||||
|
|
||||||
if (type === "BUILDATHON") await grantCredit(Actor.workspace(), 500)
|
|
||||||
|
|
||||||
await Database.use((tx) =>
|
|
||||||
tx
|
|
||||||
.update(CouponTable)
|
|
||||||
.set({ timeRedeemed: sql`now()` })
|
|
||||||
.where(and(eq(CouponTable.email, email), eq(CouponTable.type, type))),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const hasCoupon = async (email: string, type: (typeof CouponType)[number]) => {
|
|
||||||
return await Database.use((tx) =>
|
|
||||||
tx
|
|
||||||
.select()
|
|
||||||
.from(CouponTable)
|
|
||||||
.where(and(eq(CouponTable.email, email), eq(CouponTable.type, type), isNull(CouponTable.timeRedeemed)))
|
|
||||||
.then((rows) => rows.length > 0),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const setMonthlyLimit = fn(z.number(), async (input) => {
|
export const setMonthlyLimit = fn(z.number(), async (input) => {
|
||||||
return await Database.use((tx) =>
|
return await Database.use((tx) =>
|
||||||
tx
|
tx
|
||||||
@@ -284,19 +245,16 @@ export namespace Billing {
|
|||||||
const user = Actor.assert("user")
|
const user = Actor.assert("user")
|
||||||
const { successUrl, cancelUrl, method } = input
|
const { successUrl, cancelUrl, method } = input
|
||||||
|
|
||||||
const email = (await User.getAuthEmail(user.properties.userID))!
|
const email = await User.getAuthEmail(user.properties.userID)
|
||||||
const billing = await Billing.get()
|
const billing = await Billing.get()
|
||||||
|
|
||||||
if (billing.subscriptionID) throw new Error("Already subscribed to Black")
|
if (billing.subscriptionID) throw new Error("Already subscribed to Black")
|
||||||
if (billing.liteSubscriptionID) throw new Error("Already subscribed to Lite")
|
if (billing.liteSubscriptionID) throw new Error("Already subscribed to Lite")
|
||||||
|
|
||||||
const coupon = (await Billing.hasCoupon(email, "GOFREEMONTH"))
|
|
||||||
? LiteData.firstMonth100Coupon
|
|
||||||
: LiteData.firstMonth50Coupon
|
|
||||||
const createSession = () =>
|
const createSession = () =>
|
||||||
Billing.stripe().checkout.sessions.create({
|
Billing.stripe().checkout.sessions.create({
|
||||||
mode: "subscription",
|
mode: "subscription",
|
||||||
discounts: [{ coupon }],
|
discounts: [{ coupon: LiteData.firstMonthCoupon(email!) }],
|
||||||
...(billing.customerID
|
...(billing.customerID
|
||||||
? {
|
? {
|
||||||
customer: billing.customerID,
|
customer: billing.customerID,
|
||||||
@@ -306,7 +264,7 @@ export namespace Billing {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
customer_email: email,
|
customer_email: email!,
|
||||||
}),
|
}),
|
||||||
...(() => {
|
...(() => {
|
||||||
if (method === "alipay") {
|
if (method === "alipay") {
|
||||||
@@ -354,8 +312,6 @@ export namespace Billing {
|
|||||||
metadata: {
|
metadata: {
|
||||||
workspaceID: Actor.workspace(),
|
workspaceID: Actor.workspace(),
|
||||||
userID: user.properties.userID,
|
userID: user.properties.userID,
|
||||||
userEmail: email,
|
|
||||||
coupon,
|
|
||||||
type: "lite",
|
type: "lite",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -11,7 +11,11 @@ export namespace LiteData {
|
|||||||
export const productID = fn(z.void(), () => Resource.ZEN_LITE_PRICE.product)
|
export const productID = fn(z.void(), () => Resource.ZEN_LITE_PRICE.product)
|
||||||
export const priceID = fn(z.void(), () => Resource.ZEN_LITE_PRICE.price)
|
export const priceID = fn(z.void(), () => Resource.ZEN_LITE_PRICE.price)
|
||||||
export const priceInr = fn(z.void(), () => Resource.ZEN_LITE_PRICE.priceInr)
|
export const priceInr = fn(z.void(), () => Resource.ZEN_LITE_PRICE.priceInr)
|
||||||
export const firstMonth100Coupon = Resource.ZEN_LITE_PRICE.firstMonth100Coupon
|
export const firstMonthCoupon = fn(z.string(), (email) => {
|
||||||
export const firstMonth50Coupon = Resource.ZEN_LITE_PRICE.firstMonth50Coupon
|
const invitees = Resource.ZEN_LITE_COUPON_FIRST_MONTH_100_INVITEES.value.split(",")
|
||||||
|
return invitees.includes(email)
|
||||||
|
? Resource.ZEN_LITE_PRICE.firstMonth100Coupon
|
||||||
|
: Resource.ZEN_LITE_PRICE.firstMonth50Coupon
|
||||||
|
})
|
||||||
export const planName = fn(z.void(), () => "lite")
|
export const planName = fn(z.void(), () => "lite")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,8 +34,6 @@ export namespace ZenData {
|
|||||||
z.object({
|
z.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
model: z.string(),
|
model: z.string(),
|
||||||
priority: z.number().optional(),
|
|
||||||
tpmLimit: z.number().optional(),
|
|
||||||
weight: z.number().optional(),
|
weight: z.number().optional(),
|
||||||
disabled: z.boolean().optional(),
|
disabled: z.boolean().optional(),
|
||||||
storeModel: z.string().optional(),
|
storeModel: z.string().optional(),
|
||||||
@@ -125,16 +123,10 @@ export namespace ZenData {
|
|||||||
),
|
),
|
||||||
models: (() => {
|
models: (() => {
|
||||||
const normalize = (model: z.infer<typeof ModelSchema>) => {
|
const normalize = (model: z.infer<typeof ModelSchema>) => {
|
||||||
const providers = model.providers.map((p) => ({
|
const composite = model.providers.find((p) => compositeProviders[p.id].length > 1)
|
||||||
...p,
|
|
||||||
priority: p.priority ?? Infinity,
|
|
||||||
weight: p.weight ?? 1,
|
|
||||||
}))
|
|
||||||
const composite = providers.find((p) => compositeProviders[p.id].length > 1)
|
|
||||||
if (!composite)
|
if (!composite)
|
||||||
return {
|
return {
|
||||||
trialProvider: model.trialProvider ? [model.trialProvider] : undefined,
|
trialProvider: model.trialProvider ? [model.trialProvider] : undefined,
|
||||||
providers,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const weightMulti = compositeProviders[composite.id].length
|
const weightMulti = compositeProviders[composite.id].length
|
||||||
@@ -145,16 +137,17 @@ export namespace ZenData {
|
|||||||
if (model.trialProvider === composite.id) return compositeProviders[composite.id].map((p) => p.id)
|
if (model.trialProvider === composite.id) return compositeProviders[composite.id].map((p) => p.id)
|
||||||
return [model.trialProvider]
|
return [model.trialProvider]
|
||||||
})(),
|
})(),
|
||||||
providers: providers.flatMap((p) =>
|
providers: model.providers.flatMap((p) =>
|
||||||
p.id === composite.id
|
p.id === composite.id
|
||||||
? compositeProviders[p.id].map((sub) => ({
|
? compositeProviders[p.id].map((sub) => ({
|
||||||
...p,
|
...p,
|
||||||
id: sub.id,
|
id: sub.id,
|
||||||
|
weight: p.weight ?? 1,
|
||||||
}))
|
}))
|
||||||
: [
|
: [
|
||||||
{
|
{
|
||||||
...p,
|
...p,
|
||||||
weight: p.weight * weightMulti,
|
weight: (p.weight ?? 1) * weightMulti,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,15 +1,4 @@
|
|||||||
import {
|
import { bigint, boolean, index, int, json, mysqlEnum, mysqlTable, uniqueIndex, varchar } from "drizzle-orm/mysql-core"
|
||||||
bigint,
|
|
||||||
boolean,
|
|
||||||
index,
|
|
||||||
int,
|
|
||||||
json,
|
|
||||||
mysqlEnum,
|
|
||||||
mysqlTable,
|
|
||||||
primaryKey,
|
|
||||||
uniqueIndex,
|
|
||||||
varchar,
|
|
||||||
} from "drizzle-orm/mysql-core"
|
|
||||||
import { timestamps, ulid, utc, workspaceColumns } from "../drizzle/types"
|
import { timestamps, ulid, utc, workspaceColumns } from "../drizzle/types"
|
||||||
import { workspaceIndexes } from "./workspace.sql"
|
import { workspaceIndexes } from "./workspace.sql"
|
||||||
|
|
||||||
@@ -132,14 +121,3 @@ export const UsageTable = mysqlTable(
|
|||||||
},
|
},
|
||||||
(table) => [...workspaceIndexes(table), index("usage_time_created").on(table.workspaceID, table.timeCreated)],
|
(table) => [...workspaceIndexes(table), index("usage_time_created").on(table.workspaceID, table.timeCreated)],
|
||||||
)
|
)
|
||||||
|
|
||||||
export const CouponType = ["BUILDATHON", "GOFREEMONTH"] as const
|
|
||||||
export const CouponTable = mysqlTable(
|
|
||||||
"coupon",
|
|
||||||
{
|
|
||||||
email: varchar("email", { length: 255 }),
|
|
||||||
type: mysqlEnum("type", CouponType).notNull(),
|
|
||||||
timeRedeemed: utc("time_redeemed"),
|
|
||||||
},
|
|
||||||
(table) => [primaryKey({ columns: [table.email, table.type] })],
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -30,13 +30,3 @@ export const KeyRateLimitTable = mysqlTable(
|
|||||||
},
|
},
|
||||||
(table) => [primaryKey({ columns: [table.key, table.interval] })],
|
(table) => [primaryKey({ columns: [table.key, table.interval] })],
|
||||||
)
|
)
|
||||||
|
|
||||||
export const ModelRateLimitTable = mysqlTable(
|
|
||||||
"model_rate_limit",
|
|
||||||
{
|
|
||||||
key: varchar("key", { length: 255 }).notNull(),
|
|
||||||
interval: varchar("interval", { length: 40 }).notNull(),
|
|
||||||
count: int("count").notNull(),
|
|
||||||
},
|
|
||||||
(table) => [primaryKey({ columns: [table.key, table.interval] })],
|
|
||||||
)
|
|
||||||
|
|||||||
Vendored
+4
@@ -142,6 +142,10 @@ declare module "sst" {
|
|||||||
"type": "sst.sst.Secret"
|
"type": "sst.sst.Secret"
|
||||||
"value": string
|
"value": string
|
||||||
}
|
}
|
||||||
|
"ZEN_LITE_COUPON_FIRST_MONTH_100_INVITEES": {
|
||||||
|
"type": "sst.sst.Secret"
|
||||||
|
"value": string
|
||||||
|
}
|
||||||
"ZEN_LITE_PRICE": {
|
"ZEN_LITE_PRICE": {
|
||||||
"firstMonth100Coupon": string
|
"firstMonth100Coupon": string
|
||||||
"firstMonth50Coupon": string
|
"firstMonth50Coupon": string
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@opencode-ai/console-function",
|
"name": "@opencode-ai/console-function",
|
||||||
"version": "1.14.18",
|
"version": "1.4.6",
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
+4
@@ -142,6 +142,10 @@ declare module "sst" {
|
|||||||
"type": "sst.sst.Secret"
|
"type": "sst.sst.Secret"
|
||||||
"value": string
|
"value": string
|
||||||
}
|
}
|
||||||
|
"ZEN_LITE_COUPON_FIRST_MONTH_100_INVITEES": {
|
||||||
|
"type": "sst.sst.Secret"
|
||||||
|
"value": string
|
||||||
|
}
|
||||||
"ZEN_LITE_PRICE": {
|
"ZEN_LITE_PRICE": {
|
||||||
"firstMonth100Coupon": string
|
"firstMonth100Coupon": string
|
||||||
"firstMonth50Coupon": string
|
"firstMonth50Coupon": string
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@opencode-ai/console-mail",
|
"name": "@opencode-ai/console-mail",
|
||||||
"version": "1.14.18",
|
"version": "1.4.6",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jsx-email/all": "2.2.3",
|
"@jsx-email/all": "2.2.3",
|
||||||
"@jsx-email/cli": "1.4.3",
|
"@jsx-email/cli": "1.4.3",
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user