From 2c36bf9490ef346d48680bc31fce51e90c52f47c Mon Sep 17 00:00:00 2001 From: Brendan Allan Date: Wed, 15 Apr 2026 08:24:52 +0800 Subject: fix(app): avoid bootstrap error popups during global sync init (#22426) --- packages/app/src/context/global-sync/bootstrap.ts | 27 ++++++++++++----------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'packages/app/src/context/global-sync') diff --git a/packages/app/src/context/global-sync/bootstrap.ts b/packages/app/src/context/global-sync/bootstrap.ts index 7edd5a1ce..c4deb431a 100644 --- a/packages/app/src/context/global-sync/bootstrap.ts +++ b/packages/app/src/context/global-sync/bootstrap.ts @@ -122,20 +122,21 @@ export async function bootstrapGlobal(input: { }), ), ] - - showErrors({ - errors: errors(await runAll(fast)), - title: input.requestFailedTitle, - translate: input.translate, - formatMoreCount: input.formatMoreCount, - }) + await runAll(fast) + // showErrors({ + // errors: errors(await runAll(fast)), + // title: input.requestFailedTitle, + // translate: input.translate, + // formatMoreCount: input.formatMoreCount, + // }) await waitForPaint() - showErrors({ - errors: errors(await runAll(slow)), - title: input.requestFailedTitle, - translate: input.translate, - formatMoreCount: input.formatMoreCount, - }) + await runAll(slow) + // showErrors({ + // errors: errors(), + // title: input.requestFailedTitle, + // translate: input.translate, + // formatMoreCount: input.formatMoreCount, + // }) input.setGlobalStore("ready", true) } -- cgit v1.2.3 From be9432a893dd1662c10ff41c7ab552bcba8f3e1b Mon Sep 17 00:00:00 2001 From: Dax Date: Wed, 15 Apr 2026 10:26:20 -0400 Subject: shared package (#22626) --- bun.lock | 80 ++++--- package.json | 2 + packages/app/package.json | 2 +- .../app/src/components/dialog-edit-project.tsx | 2 +- packages/app/src/components/dialog-fork.tsx | 2 +- .../app/src/components/dialog-select-directory.tsx | 2 +- packages/app/src/components/dialog-select-file.tsx | 4 +- .../components/prompt-input/build-request-parts.ts | 2 +- .../src/components/prompt-input/context-items.tsx | 2 +- .../src/components/prompt-input/slash-popover.tsx | 2 +- .../app/src/components/prompt-input/submit.test.ts | 2 +- packages/app/src/components/prompt-input/submit.ts | 4 +- .../src/components/session/session-context-tab.tsx | 4 +- .../app/src/components/session/session-header.tsx | 2 +- .../src/components/session/session-new-view.tsx | 2 +- .../components/session/session-sortable-tab.tsx | 2 +- packages/app/src/context/file.tsx | 2 +- packages/app/src/context/global-sync.tsx | 2 +- packages/app/src/context/global-sync/bootstrap.ts | 4 +- .../app/src/context/global-sync/event-reducer.ts | 2 +- packages/app/src/context/local.tsx | 2 +- packages/app/src/context/notification.tsx | 4 +- .../src/context/permission-auto-respond.test.ts | 2 +- .../app/src/context/permission-auto-respond.ts | 2 +- packages/app/src/context/prompt.tsx | 2 +- packages/app/src/context/sync.tsx | 4 +- packages/app/src/pages/directory-layout.tsx | 2 +- packages/app/src/pages/home.tsx | 2 +- packages/app/src/pages/layout.tsx | 8 +- packages/app/src/pages/layout/helpers.ts | 2 +- packages/app/src/pages/layout/sidebar-items.tsx | 2 +- packages/app/src/pages/layout/sidebar-project.tsx | 2 +- .../app/src/pages/layout/sidebar-workspace.tsx | 4 +- packages/app/src/pages/session.tsx | 2 +- packages/app/src/pages/session/file-tabs.tsx | 2 +- .../app/src/pages/session/message-timeline.tsx | 4 +- .../app/src/pages/session/use-session-commands.tsx | 2 +- packages/app/src/utils/base64.ts | 2 +- packages/app/src/utils/persist.ts | 2 +- packages/enterprise/package.json | 2 +- packages/enterprise/src/core/share.ts | 4 +- packages/enterprise/src/core/storage.ts | 2 +- packages/enterprise/src/routes/share/[shareID].tsx | 6 +- packages/enterprise/test/core/share.test.ts | 2 +- packages/opencode/package.json | 2 +- packages/opencode/src/auth/index.ts | 2 +- packages/opencode/src/cli/cmd/tui/context/sync.tsx | 2 +- .../opencode/src/cli/cmd/tui/context/theme.tsx | 2 +- packages/opencode/src/cli/ui.ts | 2 +- packages/opencode/src/config/config.ts | 8 +- packages/opencode/src/config/markdown.ts | 2 +- packages/opencode/src/config/paths.ts | 2 +- packages/opencode/src/config/tui.ts | 2 +- packages/opencode/src/control-plane/workspace.ts | 2 +- packages/opencode/src/effect/app-runtime.ts | 2 +- packages/opencode/src/file/ignore.ts | 2 +- packages/opencode/src/file/index.ts | 2 +- packages/opencode/src/file/time.ts | 2 +- packages/opencode/src/filesystem/index.ts | 236 --------------------- packages/opencode/src/format/formatter.ts | 2 +- packages/opencode/src/ide/index.ts | 2 +- packages/opencode/src/index.ts | 2 +- packages/opencode/src/lsp/client.ts | 2 +- packages/opencode/src/lsp/server.ts | 4 +- packages/opencode/src/mcp/auth.ts | 2 +- packages/opencode/src/mcp/index.ts | 4 +- packages/opencode/src/npm/index.ts | 2 +- packages/opencode/src/plugin/index.ts | 2 +- packages/opencode/src/plugin/shared.ts | 2 +- packages/opencode/src/project/project.ts | 2 +- packages/opencode/src/project/vcs.ts | 2 +- packages/opencode/src/provider/auth.ts | 2 +- packages/opencode/src/provider/provider.ts | 4 +- packages/opencode/src/pty/index.ts | 2 +- packages/opencode/src/server/instance/session.ts | 2 +- packages/opencode/src/server/middleware.ts | 2 +- packages/opencode/src/session/index.ts | 2 +- packages/opencode/src/session/instruction.ts | 2 +- packages/opencode/src/session/message-v2.ts | 2 +- packages/opencode/src/session/message.ts | 2 +- packages/opencode/src/session/prompt.ts | 4 +- packages/opencode/src/session/retry.ts | 2 +- packages/opencode/src/skill/discovery.ts | 2 +- packages/opencode/src/skill/index.ts | 6 +- packages/opencode/src/snapshot/index.ts | 2 +- packages/opencode/src/storage/db.ts | 2 +- packages/opencode/src/storage/json-migration.ts | 2 +- packages/opencode/src/storage/storage.ts | 4 +- packages/opencode/src/tool/apply_patch.ts | 2 +- packages/opencode/src/tool/bash.ts | 2 +- packages/opencode/src/tool/edit.ts | 2 +- packages/opencode/src/tool/external-directory.ts | 2 +- packages/opencode/src/tool/glob.ts | 2 +- packages/opencode/src/tool/grep.ts | 2 +- packages/opencode/src/tool/lsp.ts | 2 +- packages/opencode/src/tool/read.ts | 2 +- packages/opencode/src/tool/registry.ts | 4 +- packages/opencode/src/tool/truncate.ts | 2 +- packages/opencode/src/tool/write.ts | 2 +- packages/opencode/src/util/filesystem.ts | 2 +- packages/opencode/src/util/glob.ts | 34 --- packages/opencode/src/util/log.ts | 2 +- packages/opencode/src/worktree/index.ts | 6 +- packages/opencode/test/config/config.test.ts | 2 +- .../opencode/test/filesystem/filesystem.test.ts | 2 +- packages/opencode/test/project/project.test.ts | 2 +- .../opencode/test/session/prompt-effect.test.ts | 2 +- packages/opencode/test/session/prompt.test.ts | 2 +- packages/opencode/test/session/retry.test.ts | 2 +- .../test/session/snapshot-tool-race.test.ts | 2 +- packages/opencode/test/storage/storage.test.ts | 2 +- packages/opencode/test/tool/apply_patch.test.ts | 2 +- packages/opencode/test/tool/bash.test.ts | 2 +- packages/opencode/test/tool/edit.test.ts | 2 +- packages/opencode/test/tool/glob.test.ts | 2 +- packages/opencode/test/tool/grep.test.ts | 2 +- packages/opencode/test/tool/read.test.ts | 2 +- packages/opencode/test/tool/write.test.ts | 2 +- packages/opencode/test/util/glob.test.ts | 2 +- packages/opencode/test/util/module.test.ts | 2 +- packages/shared/package.json | 31 +++ packages/shared/src/filesystem.ts | 236 +++++++++++++++++++++ packages/shared/src/util/array.ts | 10 + packages/shared/src/util/binary.ts | 41 ++++ packages/shared/src/util/encode.ts | 51 +++++ packages/shared/src/util/error.ts | 54 +++++ packages/shared/src/util/fn.ts | 11 + packages/shared/src/util/glob.ts | 34 +++ packages/shared/src/util/identifier.ts | 48 +++++ packages/shared/src/util/iife.ts | 3 + packages/shared/src/util/lazy.ts | 11 + packages/shared/src/util/module.ts | 10 + packages/shared/src/util/path.ts | 37 ++++ packages/shared/src/util/retry.ts | 41 ++++ packages/shared/src/util/slug.ts | 74 +++++++ packages/shared/tsconfig.json | 23 ++ packages/ui/package.json | 2 +- packages/ui/src/components/file.tsx | 2 +- packages/ui/src/components/line-comment.tsx | 2 +- packages/ui/src/components/markdown.tsx | 2 +- packages/ui/src/components/message-part.tsx | 4 +- packages/ui/src/components/session-review.tsx | 4 +- packages/ui/src/components/session-turn.tsx | 4 +- packages/util/package.json | 20 -- packages/util/src/array.ts | 10 - packages/util/src/binary.ts | 41 ---- packages/util/src/encode.ts | 51 ----- packages/util/src/error.ts | 54 ----- packages/util/src/fn.ts | 11 - packages/util/src/identifier.ts | 48 ----- packages/util/src/iife.ts | 3 - packages/util/src/lazy.ts | 11 - packages/util/src/module.ts | 10 - packages/util/src/path.ts | 37 ---- packages/util/src/retry.ts | 41 ---- packages/util/src/slug.ts | 74 ------- packages/util/sst-env.d.ts | 10 - packages/util/tsconfig.json | 14 -- 158 files changed, 906 insertions(+), 902 deletions(-) delete mode 100644 packages/opencode/src/filesystem/index.ts delete mode 100644 packages/opencode/src/util/glob.ts create mode 100644 packages/shared/package.json create mode 100644 packages/shared/src/filesystem.ts create mode 100644 packages/shared/src/util/array.ts create mode 100644 packages/shared/src/util/binary.ts create mode 100644 packages/shared/src/util/encode.ts create mode 100644 packages/shared/src/util/error.ts create mode 100644 packages/shared/src/util/fn.ts create mode 100644 packages/shared/src/util/glob.ts create mode 100644 packages/shared/src/util/identifier.ts create mode 100644 packages/shared/src/util/iife.ts create mode 100644 packages/shared/src/util/lazy.ts create mode 100644 packages/shared/src/util/module.ts create mode 100644 packages/shared/src/util/path.ts create mode 100644 packages/shared/src/util/retry.ts create mode 100644 packages/shared/src/util/slug.ts create mode 100644 packages/shared/tsconfig.json delete mode 100644 packages/util/package.json delete mode 100644 packages/util/src/array.ts delete mode 100644 packages/util/src/binary.ts delete mode 100644 packages/util/src/encode.ts delete mode 100644 packages/util/src/error.ts delete mode 100644 packages/util/src/fn.ts delete mode 100644 packages/util/src/identifier.ts delete mode 100644 packages/util/src/iife.ts delete mode 100644 packages/util/src/lazy.ts delete mode 100644 packages/util/src/module.ts delete mode 100644 packages/util/src/path.ts delete mode 100644 packages/util/src/retry.ts delete mode 100644 packages/util/src/slug.ts delete mode 100644 packages/util/sst-env.d.ts delete mode 100644 packages/util/tsconfig.json (limited to 'packages/app/src/context/global-sync') diff --git a/bun.lock b/bun.lock index e7085b31d..01966b826 100644 --- a/bun.lock +++ b/bun.lock @@ -31,8 +31,8 @@ "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", + "@opencode-ai/shared": "workspace:*", "@opencode-ai/ui": "workspace:*", - "@opencode-ai/util": "workspace:*", "@shikijs/transformers": "3.9.2", "@solid-primitives/active-element": "2.1.3", "@solid-primitives/audio": "1.4.2", @@ -268,8 +268,8 @@ "name": "@opencode-ai/enterprise", "version": "1.4.6", "dependencies": { + "@opencode-ai/shared": "workspace:*", "@opencode-ai/ui": "workspace:*", - "@opencode-ai/util": "workspace:*", "@pierre/diffs": "catalog:", "@solidjs/meta": "catalog:", "@solidjs/router": "catalog:", @@ -358,7 +358,6 @@ "@opencode-ai/script": "workspace:*", "@opencode-ai/sdk": "workspace:*", "@opencode-ai/server": "workspace:*", - "@opencode-ai/util": "workspace:*", "@openrouter/ai-sdk-provider": "2.5.1", "@opentelemetry/exporter-trace-otlp-http": "0.214.0", "@opentelemetry/sdk-trace-base": "2.6.1", @@ -424,6 +423,7 @@ "@effect/language-service": "0.84.2", "@octokit/webhooks-types": "7.6.1", "@opencode-ai/script": "workspace:*", + "@opencode-ai/shared": "workspace:*", "@parcel/watcher-darwin-arm64": "2.5.1", "@parcel/watcher-darwin-x64": "2.5.1", "@parcel/watcher-linux-arm64-glibc": "2.5.1", @@ -513,6 +513,25 @@ "typescript": "catalog:", }, }, + "packages/shared": { + "name": "@opencode-ai/shared", + "version": "1.4.6", + "bin": { + "opencode": "./bin/opencode", + }, + "dependencies": { + "@effect/platform-node": "catalog:", + "@npmcli/arborist": "catalog:", + "effect": "catalog:", + "mime-types": "3.0.2", + "minimatch": "10.2.5", + "semver": "catalog:", + "zod": "catalog:", + }, + "devDependencies": { + "@types/semver": "catalog:", + }, + }, "packages/slack": { "name": "@opencode-ai/slack", "version": "1.4.6", @@ -554,7 +573,7 @@ "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", - "@opencode-ai/util": "workspace:*", + "@opencode-ai/shared": "workspace:*", "@pierre/diffs": "catalog:", "@shikijs/transformers": "3.9.2", "@solid-primitives/bounds": "0.1.3", @@ -597,17 +616,6 @@ "vite-plugin-solid": "catalog:", }, }, - "packages/util": { - "name": "@opencode-ai/util", - "version": "1.4.6", - "dependencies": { - "zod": "catalog:", - }, - "devDependencies": { - "@types/bun": "catalog:", - "typescript": "catalog:", - }, - }, "packages/web": { "name": "@opencode-ai/web", "version": "1.4.6", @@ -666,6 +674,7 @@ "@hono/zod-validator": "0.4.2", "@kobalte/core": "0.13.11", "@lydell/node-pty": "1.2.0-beta.10", + "@npmcli/arborist": "9.4.0", "@octokit/rest": "22.0.0", "@openauthjs/openauth": "0.0.0-20250322224806", "@pierre/diffs": "1.1.0-beta.18", @@ -698,6 +707,7 @@ "marked-shiki": "1.2.1", "remeda": "2.26.0", "remend": "1.3.0", + "semver": "7.7.4", "shiki": "3.20.0", "solid-js": "1.9.10", "solid-list": "0.3.0", @@ -1554,14 +1564,14 @@ "@opencode-ai/server": ["@opencode-ai/server@workspace:packages/server"], + "@opencode-ai/shared": ["@opencode-ai/shared@workspace:packages/shared"], + "@opencode-ai/slack": ["@opencode-ai/slack@workspace:packages/slack"], "@opencode-ai/storybook": ["@opencode-ai/storybook@workspace:packages/storybook"], "@opencode-ai/ui": ["@opencode-ai/ui@workspace:packages/ui"], - "@opencode-ai/util": ["@opencode-ai/util@workspace:packages/util"], - "@opencode-ai/web": ["@opencode-ai/web@workspace:packages/web"], "@openrouter/ai-sdk-provider": ["@openrouter/ai-sdk-provider@2.5.1", "", { "peerDependencies": { "ai": "^6.0.0", "zod": "^3.25.0 || ^4.0.0" } }, "sha512-r1fJL1Cb3gQDa2MpWH/sfx1BsEW0uzlRriJM6eihaKqbtKDmZoBisF32VcVaQYassighX7NGCkF68EsrZA43uQ=="], @@ -2780,7 +2790,7 @@ "commander": ["commander@14.0.2", "", {}, "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ=="], - "common-ancestor-path": ["common-ancestor-path@1.0.1", "", {}, "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w=="], + "common-ancestor-path": ["common-ancestor-path@2.0.0", "", {}, "sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng=="], "compare-version": ["compare-version@0.1.2", "", {}, "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A=="], @@ -3880,7 +3890,7 @@ "miniflare": ["miniflare@4.20251118.1", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "sharp": "^0.33.5", "stoppable": "1.1.0", "undici": "7.14.0", "workerd": "1.20251118.0", "ws": "8.18.0", "youch": "4.1.0-beta.10", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-uLSAE/DvOm392fiaig4LOaatxLjM7xzIniFRG5Y3yF9IduOYLLK/pkCPQNCgKQH3ou0YJRHnTN+09LPfqYNTQQ=="], - "minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="], + "minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], @@ -3938,7 +3948,7 @@ "native-duplexpair": ["native-duplexpair@1.0.0", "", {}, "sha512-E7QQoM+3jvNtlmyfqRZ0/U75VFgCls+fSkbml2MpgWkWyz3ox8Y58gNhfuziuQYGNNQAbFZJQck55LHCnCK6CA=="], - "negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], + "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], "neotraverse": ["neotraverse@0.6.18", "", {}, "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA=="], @@ -5440,12 +5450,6 @@ "@modelcontextprotocol/sdk/zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="], - "@npmcli/arborist/common-ancestor-path": ["common-ancestor-path@2.0.0", "", {}, "sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng=="], - - "@npmcli/arborist/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], - - "@npmcli/map-workspaces/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], - "@npmcli/query/postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="], "@octokit/auth-app/@octokit/request": ["@octokit/request@10.0.8", "", { "dependencies": { "@octokit/endpoint": "^11.0.3", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "json-with-bigint": "^3.5.3", "universal-user-agent": "^7.0.2" } }, "sha512-SJZNwY9pur9Agf7l87ywFi14W+Hd9Jg6Ifivsd33+/bGUQIjNujdFiXII2/qSlN2ybqUHfp5xpekMEjIBTjlSw=="], @@ -5614,8 +5618,6 @@ "@testing-library/dom/dom-accessibility-api": ["dom-accessibility-api@0.5.16", "", {}, "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg=="], - "@tufjs/models/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], - "@types/plist/xmlbuilder": ["xmlbuilder@15.1.1", "", {}, "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg=="], "@vitest/expect/@vitest/utils": ["@vitest/utils@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" } }, "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA=="], @@ -5628,6 +5630,8 @@ "accepts/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + "accepts/negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], + "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=="], @@ -5650,8 +5654,6 @@ "app-builder-lib/hosted-git-info": ["hosted-git-info@4.1.0", "", { "dependencies": { "lru-cache": "^6.0.0" } }, "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA=="], - "app-builder-lib/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], - "app-builder-lib/which": ["which@5.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ=="], "archiver-utils/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], @@ -5660,6 +5662,8 @@ "astro/@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.6.1", "", {}, "sha512-l5Pqf6uZu31aG+3Lv8nl/3s4DbUzdlxTWDof4pEpto6GUJNhhCbelVi9dEyurOVyqaelwmS9oSyOWOENSfgo9A=="], + "astro/common-ancestor-path": ["common-ancestor-path@1.0.1", "", {}, "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w=="], + "astro/diff": ["diff@5.2.2", "", {}, "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A=="], "astro/unstorage": ["unstorage@1.17.5", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^5.0.0", "destr": "^2.0.5", "h3": "^1.15.10", "lru-cache": "^11.2.7", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.1", "ufo": "^1.6.3" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6 || ^7 || ^8", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1 || ^2 || ^3", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg=="], @@ -5784,8 +5788,6 @@ "gitlab-ai-provider/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "glob/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], - "globby/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], "gray-matter/js-yaml": ["js-yaml@3.14.2", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg=="], @@ -5802,8 +5804,6 @@ "iconv-corefoundation/node-addon-api": ["node-addon-api@1.7.2", "", {}, "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg=="], - "ignore-walk/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], - "js-beautify/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], "js-beautify/nopt": ["nopt@7.2.1", "", { "dependencies": { "abbrev": "^2.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w=="], @@ -5818,8 +5818,6 @@ "log-symbols/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], - "make-fetch-happen/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], - "matcher/escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], "md-to-react-email/marked": ["marked@7.0.4", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-t8eP0dXRJMtMvBojtkcsA7n48BkauktUKzfkPSCq85ZMTJ0v76Rke4DYz01omYpPTUh4p/f7HePgRo3ebG8+QQ=="], @@ -5858,6 +5856,8 @@ "opencode/@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=="], + "opencode/minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="], + "opencode-gitlab-auth/open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="], "opencode-poe-auth/open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="], @@ -6668,8 +6668,6 @@ "type-is/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], - "vite-plugin-icons-spritesheet/glob/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], - "vitest/@vitest/expect/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], "vitest/@vitest/expect/chai": ["chai@6.2.2", "", {}, "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg=="], @@ -6806,8 +6804,6 @@ "@electron/rebuild/node-gyp/make-fetch-happen/minipass-fetch": ["minipass-fetch@4.0.1", "", { "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^1.0.3", "minizlib": "^3.0.1" }, "optionalDependencies": { "encoding": "^0.1.13" } }, "sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ=="], - "@electron/rebuild/node-gyp/make-fetch-happen/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], - "@electron/rebuild/node-gyp/make-fetch-happen/ssri": ["ssri@12.0.0", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ=="], "@electron/rebuild/node-gyp/nopt/abbrev": ["abbrev@3.0.1", "", {}, "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg=="], @@ -6872,8 +6868,6 @@ "@jsx-email/cli/vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="], - "@modelcontextprotocol/sdk/express/accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], - "@modelcontextprotocol/sdk/express/type-is/media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], "@octokit/auth-app/@octokit/request-error/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], @@ -7072,8 +7066,6 @@ "js-beautify/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - "opencontrol/@modelcontextprotocol/sdk/express/accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], - "opencontrol/@modelcontextprotocol/sdk/express/type-is/media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], "pkg-up/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], diff --git a/package.json b/package.json index 282506206..abe1b5d36 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "catalog": { "@effect/opentelemetry": "4.0.0-beta.48", "@effect/platform-node": "4.0.0-beta.48", + "@npmcli/arborist": "9.4.0", "@types/bun": "1.3.11", "@types/cross-spawn": "6.0.6", "@octokit/rest": "22.0.0", @@ -59,6 +60,7 @@ "marked-shiki": "1.2.1", "remend": "1.3.0", "@playwright/test": "1.59.1", + "semver": "7.7.4", "typescript": "5.8.2", "@typescript/native-preview": "7.0.0-dev.20251207.1", "zod": "4.1.8", diff --git a/packages/app/package.json b/packages/app/package.json index 9aadb774b..483c71dc5 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -42,7 +42,7 @@ "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", "@opencode-ai/ui": "workspace:*", - "@opencode-ai/util": "workspace:*", + "@opencode-ai/shared": "workspace:*", "@shikijs/transformers": "3.9.2", "@solid-primitives/active-element": "2.1.3", "@solid-primitives/audio": "1.4.2", diff --git a/packages/app/src/components/dialog-edit-project.tsx b/packages/app/src/components/dialog-edit-project.tsx index eb962f47e..ea5d70065 100644 --- a/packages/app/src/components/dialog-edit-project.tsx +++ b/packages/app/src/components/dialog-edit-project.tsx @@ -9,7 +9,7 @@ import { createStore } from "solid-js/store" import { useGlobalSDK } from "@/context/global-sdk" import { useGlobalSync } from "@/context/global-sync" import { type LocalProject, getAvatarColors } from "@/context/layout" -import { getFilename } from "@opencode-ai/util/path" +import { getFilename } from "@opencode-ai/shared/util/path" import { Avatar } from "@opencode-ai/ui/avatar" import { useLanguage } from "@/context/language" diff --git a/packages/app/src/components/dialog-fork.tsx b/packages/app/src/components/dialog-fork.tsx index 9e1b896fa..710618c30 100644 --- a/packages/app/src/components/dialog-fork.tsx +++ b/packages/app/src/components/dialog-fork.tsx @@ -9,7 +9,7 @@ import { List } from "@opencode-ai/ui/list" import { showToast } from "@opencode-ai/ui/toast" import { extractPromptFromParts } from "@/utils/prompt" import type { TextPart as SDKTextPart } from "@opencode-ai/sdk/v2/client" -import { base64Encode } from "@opencode-ai/util/encode" +import { base64Encode } from "@opencode-ai/shared/util/encode" import { useLanguage } from "@/context/language" interface ForkableMessage { diff --git a/packages/app/src/components/dialog-select-directory.tsx b/packages/app/src/components/dialog-select-directory.tsx index 91e23f8ff..903cb1915 100644 --- a/packages/app/src/components/dialog-select-directory.tsx +++ b/packages/app/src/components/dialog-select-directory.tsx @@ -3,7 +3,7 @@ import { Dialog } from "@opencode-ai/ui/dialog" import { FileIcon } from "@opencode-ai/ui/file-icon" import { List } from "@opencode-ai/ui/list" import type { ListRef } from "@opencode-ai/ui/list" -import { getDirectory, getFilename } from "@opencode-ai/util/path" +import { getDirectory, getFilename } from "@opencode-ai/shared/util/path" import fuzzysort from "fuzzysort" import { createMemo, createResource, createSignal } from "solid-js" import { useGlobalSDK } from "@/context/global-sdk" diff --git a/packages/app/src/components/dialog-select-file.tsx b/packages/app/src/components/dialog-select-file.tsx index e21be77fb..a0347a039 100644 --- a/packages/app/src/components/dialog-select-file.tsx +++ b/packages/app/src/components/dialog-select-file.tsx @@ -4,8 +4,8 @@ import { FileIcon } from "@opencode-ai/ui/file-icon" import { Icon } from "@opencode-ai/ui/icon" import { Keybind } from "@opencode-ai/ui/keybind" import { List } from "@opencode-ai/ui/list" -import { base64Encode } from "@opencode-ai/util/encode" -import { getDirectory, getFilename } from "@opencode-ai/util/path" +import { base64Encode } from "@opencode-ai/shared/util/encode" +import { getDirectory, getFilename } from "@opencode-ai/shared/util/path" import { useNavigate } from "@solidjs/router" import { createMemo, createSignal, Match, onCleanup, Show, Switch } from "solid-js" import { formatKeybind, useCommand, type CommandOption } from "@/context/command" diff --git a/packages/app/src/components/prompt-input/build-request-parts.ts b/packages/app/src/components/prompt-input/build-request-parts.ts index a1076e60c..c268af35e 100644 --- a/packages/app/src/components/prompt-input/build-request-parts.ts +++ b/packages/app/src/components/prompt-input/build-request-parts.ts @@ -1,4 +1,4 @@ -import { getFilename } from "@opencode-ai/util/path" +import { getFilename } from "@opencode-ai/shared/util/path" import { type AgentPartInput, type FilePartInput, type Part, type TextPartInput } from "@opencode-ai/sdk/v2/client" import type { FileSelection } from "@/context/file" import { encodeFilePath } from "@/context/file/path" diff --git a/packages/app/src/components/prompt-input/context-items.tsx b/packages/app/src/components/prompt-input/context-items.tsx index b138fe3ef..9f20f1c04 100644 --- a/packages/app/src/components/prompt-input/context-items.tsx +++ b/packages/app/src/components/prompt-input/context-items.tsx @@ -2,7 +2,7 @@ import { Component, For, Show } from "solid-js" import { FileIcon } from "@opencode-ai/ui/file-icon" import { IconButton } from "@opencode-ai/ui/icon-button" import { Tooltip } from "@opencode-ai/ui/tooltip" -import { getDirectory, getFilename, getFilenameTruncated } from "@opencode-ai/util/path" +import { getDirectory, getFilename, getFilenameTruncated } from "@opencode-ai/shared/util/path" import type { ContextItem } from "@/context/prompt" type PromptContextItem = ContextItem & { key: string } diff --git a/packages/app/src/components/prompt-input/slash-popover.tsx b/packages/app/src/components/prompt-input/slash-popover.tsx index 65eb01c79..0c8c95923 100644 --- a/packages/app/src/components/prompt-input/slash-popover.tsx +++ b/packages/app/src/components/prompt-input/slash-popover.tsx @@ -1,7 +1,7 @@ import { Component, For, Match, Show, Switch } from "solid-js" import { FileIcon } from "@opencode-ai/ui/file-icon" import { Icon } from "@opencode-ai/ui/icon" -import { getDirectory, getFilename } from "@opencode-ai/util/path" +import { getDirectory, getFilename } from "@opencode-ai/shared/util/path" export type AtOption = | { type: "agent"; name: string; display: string } diff --git a/packages/app/src/components/prompt-input/submit.test.ts b/packages/app/src/components/prompt-input/submit.test.ts index 03bece2e3..cf9949723 100644 --- a/packages/app/src/components/prompt-input/submit.test.ts +++ b/packages/app/src/components/prompt-input/submit.test.ts @@ -74,7 +74,7 @@ beforeAll(async () => { showToast: () => 0, })) - mock.module("@opencode-ai/util/encode", () => ({ + mock.module("@opencode-ai/shared/util/encode", () => ({ base64Encode: (value: string) => value, })) diff --git a/packages/app/src/components/prompt-input/submit.ts b/packages/app/src/components/prompt-input/submit.ts index d147d7b50..27e898043 100644 --- a/packages/app/src/components/prompt-input/submit.ts +++ b/packages/app/src/components/prompt-input/submit.ts @@ -1,7 +1,7 @@ import type { Message, Session } from "@opencode-ai/sdk/v2/client" import { showToast } from "@opencode-ai/ui/toast" -import { base64Encode } from "@opencode-ai/util/encode" -import { Binary } from "@opencode-ai/util/binary" +import { base64Encode } from "@opencode-ai/shared/util/encode" +import { Binary } from "@opencode-ai/shared/util/binary" import { useNavigate, useParams } from "@solidjs/router" import { batch, type Accessor } from "solid-js" import type { FileSelection } from "@/context/file" diff --git a/packages/app/src/components/session/session-context-tab.tsx b/packages/app/src/components/session/session-context-tab.tsx index 4e7dc8e78..abf4c9334 100644 --- a/packages/app/src/components/session/session-context-tab.tsx +++ b/packages/app/src/components/session/session-context-tab.tsx @@ -1,8 +1,8 @@ import { createMemo, createEffect, on, onCleanup, For, Show } from "solid-js" import type { JSX } from "solid-js" import { useSync } from "@/context/sync" -import { checksum } from "@opencode-ai/util/encode" -import { findLast } from "@opencode-ai/util/array" +import { checksum } from "@opencode-ai/shared/util/encode" +import { findLast } from "@opencode-ai/shared/util/array" import { same } from "@/utils/same" import { Icon } from "@opencode-ai/ui/icon" import { Accordion } from "@opencode-ai/ui/accordion" diff --git a/packages/app/src/components/session/session-header.tsx b/packages/app/src/components/session/session-header.tsx index 495b32340..e65b575ac 100644 --- a/packages/app/src/components/session/session-header.tsx +++ b/packages/app/src/components/session/session-header.tsx @@ -7,7 +7,7 @@ import { Keybind } from "@opencode-ai/ui/keybind" import { Spinner } from "@opencode-ai/ui/spinner" import { showToast } from "@opencode-ai/ui/toast" import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip" -import { getFilename } from "@opencode-ai/util/path" +import { getFilename } from "@opencode-ai/shared/util/path" import { createEffect, createMemo, For, onCleanup, Show } from "solid-js" import { createStore } from "solid-js/store" import { Portal } from "solid-js/web" diff --git a/packages/app/src/components/session/session-new-view.tsx b/packages/app/src/components/session/session-new-view.tsx index e4ef36393..d2cac28fc 100644 --- a/packages/app/src/components/session/session-new-view.tsx +++ b/packages/app/src/components/session/session-new-view.tsx @@ -5,7 +5,7 @@ import { useSDK } from "@/context/sdk" import { useLanguage } from "@/context/language" import { Icon } from "@opencode-ai/ui/icon" import { Mark } from "@opencode-ai/ui/logo" -import { getDirectory, getFilename } from "@opencode-ai/util/path" +import { getDirectory, getFilename } from "@opencode-ai/shared/util/path" const MAIN_WORKTREE = "main" const CREATE_WORKTREE = "create" diff --git a/packages/app/src/components/session/session-sortable-tab.tsx b/packages/app/src/components/session/session-sortable-tab.tsx index dfda91c16..fb2275c44 100644 --- a/packages/app/src/components/session/session-sortable-tab.tsx +++ b/packages/app/src/components/session/session-sortable-tab.tsx @@ -5,7 +5,7 @@ import { FileIcon } from "@opencode-ai/ui/file-icon" import { IconButton } from "@opencode-ai/ui/icon-button" import { TooltipKeybind } from "@opencode-ai/ui/tooltip" import { Tabs } from "@opencode-ai/ui/tabs" -import { getFilename } from "@opencode-ai/util/path" +import { getFilename } from "@opencode-ai/shared/util/path" import { useFile } from "@/context/file" import { useLanguage } from "@/context/language" import { useCommand } from "@/context/command" diff --git a/packages/app/src/context/file.tsx b/packages/app/src/context/file.tsx index f8fec7142..8998731a6 100644 --- a/packages/app/src/context/file.tsx +++ b/packages/app/src/context/file.tsx @@ -3,7 +3,7 @@ import { createStore, produce, reconcile } from "solid-js/store" import { createSimpleContext } from "@opencode-ai/ui/context" import { showToast } from "@opencode-ai/ui/toast" import { useParams } from "@solidjs/router" -import { getFilename } from "@opencode-ai/util/path" +import { getFilename } from "@opencode-ai/shared/util/path" import { useSDK } from "./sdk" import { useSync } from "./sync" import { useLanguage } from "@/context/language" diff --git a/packages/app/src/context/global-sync.tsx b/packages/app/src/context/global-sync.tsx index 0cf3570a8..fe5f2f130 100644 --- a/packages/app/src/context/global-sync.tsx +++ b/packages/app/src/context/global-sync.tsx @@ -8,7 +8,7 @@ import type { Todo, } from "@opencode-ai/sdk/v2/client" import { showToast } from "@opencode-ai/ui/toast" -import { getFilename } from "@opencode-ai/util/path" +import { getFilename } from "@opencode-ai/shared/util/path" import { createContext, getOwner, onCleanup, onMount, type ParentProps, untrack, useContext } from "solid-js" import { createStore, produce, reconcile } from "solid-js/store" import { useLanguage } from "@/context/language" diff --git a/packages/app/src/context/global-sync/bootstrap.ts b/packages/app/src/context/global-sync/bootstrap.ts index c4deb431a..ad987efa6 100644 --- a/packages/app/src/context/global-sync/bootstrap.ts +++ b/packages/app/src/context/global-sync/bootstrap.ts @@ -11,8 +11,8 @@ import type { Todo, } from "@opencode-ai/sdk/v2/client" import { showToast } from "@opencode-ai/ui/toast" -import { getFilename } from "@opencode-ai/util/path" -import { retry } from "@opencode-ai/util/retry" +import { getFilename } from "@opencode-ai/shared/util/path" +import { retry } from "@opencode-ai/shared/util/retry" import { batch } from "solid-js" import { reconcile, type SetStoreFunction, type Store } from "solid-js/store" import type { State, VcsCache } from "./types" diff --git a/packages/app/src/context/global-sync/event-reducer.ts b/packages/app/src/context/global-sync/event-reducer.ts index 500013c1d..11a0cf83f 100644 --- a/packages/app/src/context/global-sync/event-reducer.ts +++ b/packages/app/src/context/global-sync/event-reducer.ts @@ -1,4 +1,4 @@ -import { Binary } from "@opencode-ai/util/binary" +import { Binary } from "@opencode-ai/shared/util/binary" import { produce, reconcile, type SetStoreFunction, type Store } from "solid-js/store" import type { Message, diff --git a/packages/app/src/context/local.tsx b/packages/app/src/context/local.tsx index 28ce2770d..0b0972ee6 100644 --- a/packages/app/src/context/local.tsx +++ b/packages/app/src/context/local.tsx @@ -1,5 +1,5 @@ import { createSimpleContext } from "@opencode-ai/ui/context" -import { base64Encode } from "@opencode-ai/util/encode" +import { base64Encode } from "@opencode-ai/shared/util/encode" import { useParams } from "@solidjs/router" import { batch, createEffect, createMemo } from "solid-js" import { createStore } from "solid-js/store" diff --git a/packages/app/src/context/notification.tsx b/packages/app/src/context/notification.tsx index 281a1ef33..251b67b06 100644 --- a/packages/app/src/context/notification.tsx +++ b/packages/app/src/context/notification.tsx @@ -7,8 +7,8 @@ import { useGlobalSync } from "./global-sync" import { usePlatform } from "@/context/platform" import { useLanguage } from "@/context/language" import { useSettings } from "@/context/settings" -import { Binary } from "@opencode-ai/util/binary" -import { base64Encode } from "@opencode-ai/util/encode" +import { Binary } from "@opencode-ai/shared/util/binary" +import { base64Encode } from "@opencode-ai/shared/util/encode" import { decode64 } from "@/utils/base64" import { EventSessionError } from "@opencode-ai/sdk/v2" import { Persist, persisted } from "@/utils/persist" diff --git a/packages/app/src/context/permission-auto-respond.test.ts b/packages/app/src/context/permission-auto-respond.test.ts index 755611300..2f8ca6265 100644 --- a/packages/app/src/context/permission-auto-respond.test.ts +++ b/packages/app/src/context/permission-auto-respond.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test" import type { PermissionRequest, Session } from "@opencode-ai/sdk/v2/client" -import { base64Encode } from "@opencode-ai/util/encode" +import { base64Encode } from "@opencode-ai/shared/util/encode" import { autoRespondsPermission, isDirectoryAutoAccepting } from "./permission-auto-respond" const session = (input: { id: string; parentID?: string }) => diff --git a/packages/app/src/context/permission-auto-respond.ts b/packages/app/src/context/permission-auto-respond.ts index b206deedf..2ebca3434 100644 --- a/packages/app/src/context/permission-auto-respond.ts +++ b/packages/app/src/context/permission-auto-respond.ts @@ -1,4 +1,4 @@ -import { base64Encode } from "@opencode-ai/util/encode" +import { base64Encode } from "@opencode-ai/shared/util/encode" export function acceptKey(sessionID: string, directory?: string) { if (!directory) return sessionID diff --git a/packages/app/src/context/prompt.tsx b/packages/app/src/context/prompt.tsx index 831fdbca8..9b666e5e7 100644 --- a/packages/app/src/context/prompt.tsx +++ b/packages/app/src/context/prompt.tsx @@ -1,5 +1,5 @@ import { createSimpleContext } from "@opencode-ai/ui/context" -import { checksum } from "@opencode-ai/util/encode" +import { checksum } from "@opencode-ai/shared/util/encode" import { useParams } from "@solidjs/router" import { batch, createMemo, createRoot, getOwner, onCleanup } from "solid-js" import { createStore, type SetStoreFunction } from "solid-js/store" diff --git a/packages/app/src/context/sync.tsx b/packages/app/src/context/sync.tsx index fb02a2d2d..29b7fe68c 100644 --- a/packages/app/src/context/sync.tsx +++ b/packages/app/src/context/sync.tsx @@ -1,7 +1,7 @@ import { batch, createMemo } from "solid-js" import { createStore, produce, reconcile } from "solid-js/store" -import { Binary } from "@opencode-ai/util/binary" -import { retry } from "@opencode-ai/util/retry" +import { Binary } from "@opencode-ai/shared/util/binary" +import { retry } from "@opencode-ai/shared/util/retry" import { createSimpleContext } from "@opencode-ai/ui/context" import { clearSessionPrefetch, diff --git a/packages/app/src/pages/directory-layout.tsx b/packages/app/src/pages/directory-layout.tsx index 427b4823b..f604dd6c5 100644 --- a/packages/app/src/pages/directory-layout.tsx +++ b/packages/app/src/pages/directory-layout.tsx @@ -1,6 +1,6 @@ import { DataProvider } from "@opencode-ai/ui/context" import { showToast } from "@opencode-ai/ui/toast" -import { base64Encode } from "@opencode-ai/util/encode" +import { base64Encode } from "@opencode-ai/shared/util/encode" import { useLocation, useNavigate, useParams } from "@solidjs/router" import { createEffect, createMemo, type ParentProps, Show } from "solid-js" import { useLanguage } from "@/context/language" diff --git a/packages/app/src/pages/home.tsx b/packages/app/src/pages/home.tsx index 4c795b968..46cacdf62 100644 --- a/packages/app/src/pages/home.tsx +++ b/packages/app/src/pages/home.tsx @@ -3,7 +3,7 @@ import { Button } from "@opencode-ai/ui/button" import { Logo } from "@opencode-ai/ui/logo" import { useLayout } from "@/context/layout" import { useNavigate } from "@solidjs/router" -import { base64Encode } from "@opencode-ai/util/encode" +import { base64Encode } from "@opencode-ai/shared/util/encode" import { Icon } from "@opencode-ai/ui/icon" import { usePlatform } from "@/context/platform" import { DateTime } from "luxon" diff --git a/packages/app/src/pages/layout.tsx b/packages/app/src/pages/layout.tsx index f402f4bc0..62d5cba61 100644 --- a/packages/app/src/pages/layout.tsx +++ b/packages/app/src/pages/layout.tsx @@ -17,7 +17,7 @@ import { useNavigate, useParams } from "@solidjs/router" import { useLayout, LocalProject } from "@/context/layout" import { useGlobalSync } from "@/context/global-sync" import { Persist, persisted } from "@/utils/persist" -import { base64Encode } from "@opencode-ai/util/encode" +import { base64Encode } from "@opencode-ai/shared/util/encode" import { decode64 } from "@/utils/base64" import { ResizeHandle } from "@opencode-ai/ui/resize-handle" import { Button } from "@opencode-ai/ui/button" @@ -25,7 +25,7 @@ import { IconButton } from "@opencode-ai/ui/icon-button" import { Tooltip } from "@opencode-ai/ui/tooltip" import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu" import { Dialog } from "@opencode-ai/ui/dialog" -import { getFilename } from "@opencode-ai/util/path" +import { getFilename } from "@opencode-ai/shared/util/path" import { Session, type Message } from "@opencode-ai/sdk/v2/client" import { usePlatform } from "@/context/platform" import { useSettings } from "@/context/settings" @@ -48,8 +48,8 @@ import { } from "@/context/global-sync/session-prefetch" import { useNotification } from "@/context/notification" import { usePermission } from "@/context/permission" -import { Binary } from "@opencode-ai/util/binary" -import { retry } from "@opencode-ai/util/retry" +import { Binary } from "@opencode-ai/shared/util/binary" +import { retry } from "@opencode-ai/shared/util/retry" import { playSoundById } from "@/utils/sound" import { createAim } from "@/utils/aim" import { setNavigate } from "@/utils/notification-click" diff --git a/packages/app/src/pages/layout/helpers.ts b/packages/app/src/pages/layout/helpers.ts index 48158debb..26b66d166 100644 --- a/packages/app/src/pages/layout/helpers.ts +++ b/packages/app/src/pages/layout/helpers.ts @@ -1,4 +1,4 @@ -import { getFilename } from "@opencode-ai/util/path" +import { getFilename } from "@opencode-ai/shared/util/path" import { type Session } from "@opencode-ai/sdk/v2/client" type SessionStore = { diff --git a/packages/app/src/pages/layout/sidebar-items.tsx b/packages/app/src/pages/layout/sidebar-items.tsx index e56accfc8..b0f45859a 100644 --- a/packages/app/src/pages/layout/sidebar-items.tsx +++ b/packages/app/src/pages/layout/sidebar-items.tsx @@ -4,7 +4,7 @@ import { Icon } from "@opencode-ai/ui/icon" import { IconButton } from "@opencode-ai/ui/icon-button" import { Spinner } from "@opencode-ai/ui/spinner" import { Tooltip } from "@opencode-ai/ui/tooltip" -import { getFilename } from "@opencode-ai/util/path" +import { getFilename } from "@opencode-ai/shared/util/path" import { A, useParams } from "@solidjs/router" import { type Accessor, createMemo, For, type JSX, Match, Show, Switch } from "solid-js" import { useGlobalSync } from "@/context/global-sync" diff --git a/packages/app/src/pages/layout/sidebar-project.tsx b/packages/app/src/pages/layout/sidebar-project.tsx index 7c9ae1aaf..076e1ef88 100644 --- a/packages/app/src/pages/layout/sidebar-project.tsx +++ b/packages/app/src/pages/layout/sidebar-project.tsx @@ -1,6 +1,6 @@ import { createMemo, For, Show, type Accessor, type JSX } from "solid-js" import { createStore } from "solid-js/store" -import { base64Encode } from "@opencode-ai/util/encode" +import { base64Encode } from "@opencode-ai/shared/util/encode" import { Button } from "@opencode-ai/ui/button" import { ContextMenu } from "@opencode-ai/ui/context-menu" import { HoverCard } from "@opencode-ai/ui/hover-card" diff --git a/packages/app/src/pages/layout/sidebar-workspace.tsx b/packages/app/src/pages/layout/sidebar-workspace.tsx index 878b6e5fa..9e0069147 100644 --- a/packages/app/src/pages/layout/sidebar-workspace.tsx +++ b/packages/app/src/pages/layout/sidebar-workspace.tsx @@ -3,8 +3,8 @@ import { createEffect, createMemo, For, Show, type Accessor, type JSX } from "so import { createStore } from "solid-js/store" import { createSortable } from "@thisbeyond/solid-dnd" import { createMediaQuery } from "@solid-primitives/media" -import { base64Encode } from "@opencode-ai/util/encode" -import { getFilename } from "@opencode-ai/util/path" +import { base64Encode } from "@opencode-ai/shared/util/encode" +import { getFilename } from "@opencode-ai/shared/util/path" import { Button } from "@opencode-ai/ui/button" import { Collapsible } from "@opencode-ai/ui/collapsible" import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu" diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx index eb6a49411..e328e3f0c 100644 --- a/packages/app/src/pages/session.tsx +++ b/packages/app/src/pages/session.tsx @@ -27,7 +27,7 @@ import { createAutoScroll } from "@opencode-ai/ui/hooks" import { previewSelectedLines } from "@opencode-ai/ui/pierre/selection-bridge" import { Button } from "@opencode-ai/ui/button" import { showToast } from "@opencode-ai/ui/toast" -import { checksum } from "@opencode-ai/util/encode" +import { checksum } from "@opencode-ai/shared/util/encode" import { useSearchParams } from "@solidjs/router" import { NewSessionView, SessionHeader } from "@/components/session" import { useComments } from "@/context/comments" diff --git a/packages/app/src/pages/session/file-tabs.tsx b/packages/app/src/pages/session/file-tabs.tsx index cb7617523..a64dff64e 100644 --- a/packages/app/src/pages/session/file-tabs.tsx +++ b/packages/app/src/pages/session/file-tabs.tsx @@ -6,7 +6,7 @@ import type { FileSearchHandle } from "@opencode-ai/ui/file" import { useFileComponent } from "@opencode-ai/ui/context/file" import { cloneSelectedLineRange, previewSelectedLines } from "@opencode-ai/ui/pierre/selection-bridge" import { createLineCommentController } from "@opencode-ai/ui/line-comment-annotations" -import { sampledChecksum } from "@opencode-ai/util/encode" +import { sampledChecksum } from "@opencode-ai/shared/util/encode" import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu" import { IconButton } from "@opencode-ai/ui/icon-button" import { Tabs } from "@opencode-ai/ui/tabs" diff --git a/packages/app/src/pages/session/message-timeline.tsx b/packages/app/src/pages/session/message-timeline.tsx index 838016395..978f188b6 100644 --- a/packages/app/src/pages/session/message-timeline.tsx +++ b/packages/app/src/pages/session/message-timeline.tsx @@ -15,8 +15,8 @@ import { ScrollView } from "@opencode-ai/ui/scroll-view" import { TextField } from "@opencode-ai/ui/text-field" import type { AssistantMessage, Message as MessageType, Part, TextPart, UserMessage } from "@opencode-ai/sdk/v2" import { showToast } from "@opencode-ai/ui/toast" -import { Binary } from "@opencode-ai/util/binary" -import { getFilename } from "@opencode-ai/util/path" +import { Binary } from "@opencode-ai/shared/util/binary" +import { getFilename } from "@opencode-ai/shared/util/path" import { Popover as KobaltePopover } from "@kobalte/core/popover" import { shouldMarkBoundaryGesture, normalizeWheelDelta } from "@/pages/session/message-gesture" import { SessionContextUsage } from "@/components/session-context-usage" diff --git a/packages/app/src/pages/session/use-session-commands.tsx b/packages/app/src/pages/session/use-session-commands.tsx index 239795373..b5d254463 100644 --- a/packages/app/src/pages/session/use-session-commands.tsx +++ b/packages/app/src/pages/session/use-session-commands.tsx @@ -12,7 +12,7 @@ import { useSDK } from "@/context/sdk" import { useSync } from "@/context/sync" import { useTerminal } from "@/context/terminal" import { showToast } from "@opencode-ai/ui/toast" -import { findLast } from "@opencode-ai/util/array" +import { findLast } from "@opencode-ai/shared/util/array" import { createSessionTabs } from "@/pages/session/helpers" import { extractPromptFromParts } from "@/utils/prompt" import { UserMessage } from "@opencode-ai/sdk/v2" diff --git a/packages/app/src/utils/base64.ts b/packages/app/src/utils/base64.ts index c1f9d88c6..f60dff2b6 100644 --- a/packages/app/src/utils/base64.ts +++ b/packages/app/src/utils/base64.ts @@ -1,4 +1,4 @@ -import { base64Decode } from "@opencode-ai/util/encode" +import { base64Decode } from "@opencode-ai/shared/util/encode" export function decode64(value: string | undefined) { if (value === undefined) return diff --git a/packages/app/src/utils/persist.ts b/packages/app/src/utils/persist.ts index 3dcbeb7d3..dce0e94c3 100644 --- a/packages/app/src/utils/persist.ts +++ b/packages/app/src/utils/persist.ts @@ -1,6 +1,6 @@ import { Platform, usePlatform } from "@/context/platform" import { makePersisted, type AsyncStorage, type SyncStorage } from "@solid-primitives/storage" -import { checksum } from "@opencode-ai/util/encode" +import { checksum } from "@opencode-ai/shared/util/encode" import { createResource, type Accessor } from "solid-js" import type { SetStoreFunction, Store } from "solid-js/store" diff --git a/packages/enterprise/package.json b/packages/enterprise/package.json index 0d165e95f..3c4a835f3 100644 --- a/packages/enterprise/package.json +++ b/packages/enterprise/package.json @@ -13,7 +13,7 @@ "shell-prod": "sst shell --target Teams --stage production" }, "dependencies": { - "@opencode-ai/util": "workspace:*", + "@opencode-ai/shared": "workspace:*", "@opencode-ai/ui": "workspace:*", "aws4fetch": "^1.0.20", "@pierre/diffs": "catalog:", diff --git a/packages/enterprise/src/core/share.ts b/packages/enterprise/src/core/share.ts index 18fcd7a07..1a343272f 100644 --- a/packages/enterprise/src/core/share.ts +++ b/packages/enterprise/src/core/share.ts @@ -1,6 +1,6 @@ import { Message, Model, Part, Session, SnapshotFileDiff } from "@opencode-ai/sdk/v2" -import { fn } from "@opencode-ai/util/fn" -import { iife } from "@opencode-ai/util/iife" +import { fn } from "@opencode-ai/shared/util/fn" +import { iife } from "@opencode-ai/shared/util/iife" import z from "zod" import { Storage } from "./storage" diff --git a/packages/enterprise/src/core/storage.ts b/packages/enterprise/src/core/storage.ts index b8030b4f9..a6222e415 100644 --- a/packages/enterprise/src/core/storage.ts +++ b/packages/enterprise/src/core/storage.ts @@ -1,5 +1,5 @@ import { AwsClient } from "aws4fetch" -import { lazy } from "@opencode-ai/util/lazy" +import { lazy } from "@opencode-ai/shared/util/lazy" export namespace Storage { export interface Adapter { diff --git a/packages/enterprise/src/routes/share/[shareID].tsx b/packages/enterprise/src/routes/share/[shareID].tsx index edeeaf1ad..f3be14e39 100644 --- a/packages/enterprise/src/routes/share/[shareID].tsx +++ b/packages/enterprise/src/routes/share/[shareID].tsx @@ -10,9 +10,9 @@ import { Share } from "~/core/share" import { Logo, Mark } from "@opencode-ai/ui/logo" import { IconButton } from "@opencode-ai/ui/icon-button" import { ProviderIcon } from "@opencode-ai/ui/provider-icon" -import { iife } from "@opencode-ai/util/iife" -import { Binary } from "@opencode-ai/util/binary" -import { NamedError } from "@opencode-ai/util/error" +import { iife } from "@opencode-ai/shared/util/iife" +import { Binary } from "@opencode-ai/shared/util/binary" +import { NamedError } from "@opencode-ai/shared/util/error" import { DateTime } from "luxon" import { createStore } from "solid-js/store" import z from "zod" diff --git a/packages/enterprise/test/core/share.test.ts b/packages/enterprise/test/core/share.test.ts index d49d4b763..34f3b17a3 100644 --- a/packages/enterprise/test/core/share.test.ts +++ b/packages/enterprise/test/core/share.test.ts @@ -1,7 +1,7 @@ import { describe, expect, test, afterAll } from "bun:test" import { Share } from "../../src/core/share" import { Storage } from "../../src/core/storage" -import { Identifier } from "@opencode-ai/util/identifier" +import { Identifier } from "@opencode-ai/shared/util/identifier" describe.concurrent("core.share", () => { test("should create a share", async () => { diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 0f0c26ed9..9ddf1fa9f 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -44,6 +44,7 @@ "@effect/language-service": "0.84.2", "@octokit/webhooks-types": "7.6.1", "@opencode-ai/script": "workspace:*", + "@opencode-ai/shared": "workspace:*", "@parcel/watcher-darwin-arm64": "2.5.1", "@parcel/watcher-darwin-x64": "2.5.1", "@parcel/watcher-linux-arm64-glibc": "2.5.1", @@ -115,7 +116,6 @@ "@opencode-ai/server": "workspace:*", "@opencode-ai/script": "workspace:*", "@opencode-ai/sdk": "workspace:*", - "@opencode-ai/util": "workspace:*", "@opentelemetry/exporter-trace-otlp-http": "0.214.0", "@opentelemetry/sdk-trace-base": "2.6.1", "@opentelemetry/sdk-trace-node": "2.6.1", diff --git a/packages/opencode/src/auth/index.ts b/packages/opencode/src/auth/index.ts index b1502da78..b287ce551 100644 --- a/packages/opencode/src/auth/index.ts +++ b/packages/opencode/src/auth/index.ts @@ -2,7 +2,7 @@ import path from "path" import { Effect, Layer, Record, Result, Schema, Context } from "effect" import { zod } from "@/util/effect-zod" import { Global } from "../global" -import { AppFileSystem } from "../filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" export const OAUTH_DUMMY_KEY = "opencode-oauth-dummy-key" diff --git a/packages/opencode/src/cli/cmd/tui/context/sync.tsx b/packages/opencode/src/cli/cmd/tui/context/sync.tsx index 772b5d9a0..cab162f8f 100644 --- a/packages/opencode/src/cli/cmd/tui/context/sync.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/sync.tsx @@ -22,7 +22,7 @@ import { createStore, produce, reconcile } from "solid-js/store" import { useProject } from "@tui/context/project" import { useEvent } from "@tui/context/event" import { useSDK } from "@tui/context/sdk" -import { Binary } from "@opencode-ai/util/binary" +import { Binary } from "@opencode-ai/shared/util/binary" import { createSimpleContext } from "./helper" import type { Snapshot } from "@/snapshot" import { useExit } from "./exit" diff --git a/packages/opencode/src/cli/cmd/tui/context/theme.tsx b/packages/opencode/src/cli/cmd/tui/context/theme.tsx index de8152996..0c0658e74 100644 --- a/packages/opencode/src/cli/cmd/tui/context/theme.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/theme.tsx @@ -2,7 +2,7 @@ import { CliRenderEvents, SyntaxStyle, RGBA, type TerminalColors } from "@opentu import path from "path" import { createEffect, createMemo, onCleanup, onMount } from "solid-js" import { createSimpleContext } from "./helper" -import { Glob } from "../../../../util/glob" +import { Glob } from "@opencode-ai/shared/util/glob" import aura from "./theme/aura.json" with { type: "json" } import ayu from "./theme/ayu.json" with { type: "json" } import catppuccin from "./theme/catppuccin.json" with { type: "json" } diff --git a/packages/opencode/src/cli/ui.ts b/packages/opencode/src/cli/ui.ts index b24a2a2f4..d735a5541 100644 --- a/packages/opencode/src/cli/ui.ts +++ b/packages/opencode/src/cli/ui.ts @@ -1,6 +1,6 @@ import z from "zod" import { EOL } from "os" -import { NamedError } from "@opencode-ai/util/error" +import { NamedError } from "@opencode-ai/shared/util/error" import { logo as glyphs } from "./logo" export namespace UI { diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index f9ca88341..f8205bac2 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -7,7 +7,7 @@ import z from "zod" import { mergeDeep, pipe, unique } from "remeda" import { Global } from "../global" import fsNode from "fs/promises" -import { NamedError } from "@opencode-ai/util/error" +import { NamedError } from "@opencode-ai/shared/util/error" import { Flag } from "../flag/flag" import { Auth } from "../auth" import { Env } from "../env" @@ -26,17 +26,17 @@ import { existsSync } from "fs" import { Bus } from "@/bus" import { GlobalBus } from "@/bus/global" import { Event } from "../server/event" -import { Glob } from "../util/glob" +import { Glob } from "@opencode-ai/shared/util/glob" import { Account } from "@/account" import { isRecord } from "@/util/record" import { ConfigPaths } from "./paths" import type { ConsoleState } from "./console-state" -import { AppFileSystem } from "@/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { InstanceState } from "@/effect/instance-state" import { Context, Duration, Effect, Exit, Fiber, Layer, Option } from "effect" import { Flock } from "@/util/flock" import { isPathPluginSpec, parsePluginSpecifier, resolvePathPluginTarget } from "@/plugin/shared" -import { Npm } from "@/npm" +import { Npm } from "../npm" import { InstanceRef } from "@/effect/instance-ref" export namespace Config { diff --git a/packages/opencode/src/config/markdown.ts b/packages/opencode/src/config/markdown.ts index 3c9709b5b..2f1483dca 100644 --- a/packages/opencode/src/config/markdown.ts +++ b/packages/opencode/src/config/markdown.ts @@ -1,4 +1,4 @@ -import { NamedError } from "@opencode-ai/util/error" +import { NamedError } from "@opencode-ai/shared/util/error" import matter from "gray-matter" import { z } from "zod" import { Filesystem } from "../util/filesystem" diff --git a/packages/opencode/src/config/paths.ts b/packages/opencode/src/config/paths.ts index 82ccf3945..884a77449 100644 --- a/packages/opencode/src/config/paths.ts +++ b/packages/opencode/src/config/paths.ts @@ -2,7 +2,7 @@ import path from "path" import os from "os" import z from "zod" import { type ParseError as JsoncParseError, parse as parseJsonc, printParseErrorCode } from "jsonc-parser" -import { NamedError } from "@opencode-ai/util/error" +import { NamedError } from "@opencode-ai/shared/util/error" import { Filesystem } from "@/util/filesystem" import { Flag } from "@/flag/flag" import { Global } from "@/global" diff --git a/packages/opencode/src/config/tui.ts b/packages/opencode/src/config/tui.ts index 9347a8cc4..87c39e700 100644 --- a/packages/opencode/src/config/tui.ts +++ b/packages/opencode/src/config/tui.ts @@ -13,7 +13,7 @@ import { Global } from "@/global" import { Filesystem } from "@/util/filesystem" import { InstanceState } from "@/effect/instance-state" import { makeRuntime } from "@/effect/run-service" -import { AppFileSystem } from "@/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" export namespace TuiConfig { const log = Log.create({ service: "tui.config" }) diff --git a/packages/opencode/src/control-plane/workspace.ts b/packages/opencode/src/control-plane/workspace.ts index 78f3d770e..b9ac0a6b4 100644 --- a/packages/opencode/src/control-plane/workspace.ts +++ b/packages/opencode/src/control-plane/workspace.ts @@ -11,7 +11,7 @@ import { Flag } from "@/flag/flag" import { Log } from "@/util/log" import { Filesystem } from "@/util/filesystem" import { ProjectID } from "@/project/schema" -import { Slug } from "@opencode-ai/util/slug" +import { Slug } from "@opencode-ai/shared/util/slug" import { WorkspaceTable } from "./workspace.sql" import { getAdaptor } from "./adaptors" import { WorkspaceInfo } from "./types" diff --git a/packages/opencode/src/effect/app-runtime.ts b/packages/opencode/src/effect/app-runtime.ts index b13396615..5948bd25e 100644 --- a/packages/opencode/src/effect/app-runtime.ts +++ b/packages/opencode/src/effect/app-runtime.ts @@ -2,7 +2,7 @@ import { Layer, ManagedRuntime } from "effect" import { attach, memoMap } from "./run-service" import { Observability } from "./observability" -import { AppFileSystem } from "@/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { Bus } from "@/bus" import { Auth } from "@/auth" import { Account } from "@/account" diff --git a/packages/opencode/src/file/ignore.ts b/packages/opencode/src/file/ignore.ts index b9731040c..a102e7d17 100644 --- a/packages/opencode/src/file/ignore.ts +++ b/packages/opencode/src/file/ignore.ts @@ -1,5 +1,5 @@ import { sep } from "node:path" -import { Glob } from "../util/glob" +import { Glob } from "@opencode-ai/shared/util/glob" export namespace FileIgnore { const FOLDERS = new Set([ diff --git a/packages/opencode/src/file/index.ts b/packages/opencode/src/file/index.ts index 6730957f2..113dc5909 100644 --- a/packages/opencode/src/file/index.ts +++ b/packages/opencode/src/file/index.ts @@ -1,7 +1,7 @@ import { BusEvent } from "@/bus/bus-event" import { InstanceState } from "@/effect/instance-state" import { makeRuntime } from "@/effect/run-service" -import { AppFileSystem } from "@/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { Git } from "@/git" import { Effect, Layer, Context } from "effect" import * as Stream from "effect/Stream" diff --git a/packages/opencode/src/file/time.ts b/packages/opencode/src/file/time.ts index e5055b671..553752673 100644 --- a/packages/opencode/src/file/time.ts +++ b/packages/opencode/src/file/time.ts @@ -1,6 +1,6 @@ import { DateTime, Effect, Layer, Option, Semaphore, Context } from "effect" import { InstanceState } from "@/effect/instance-state" -import { AppFileSystem } from "@/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { Flag } from "@/flag/flag" import type { SessionID } from "@/session/schema" import { Filesystem } from "@/util/filesystem" diff --git a/packages/opencode/src/filesystem/index.ts b/packages/opencode/src/filesystem/index.ts deleted file mode 100644 index 2c3964ec2..000000000 --- a/packages/opencode/src/filesystem/index.ts +++ /dev/null @@ -1,236 +0,0 @@ -import { NodeFileSystem } from "@effect/platform-node" -import { dirname, join, relative, resolve as pathResolve } from "path" -import { realpathSync } from "fs" -import * as NFS from "fs/promises" -import { lookup } from "mime-types" -import { Effect, FileSystem, Layer, Schema, Context } from "effect" -import type { PlatformError } from "effect/PlatformError" -import { Glob } from "../util/glob" - -export namespace AppFileSystem { - export class FileSystemError extends Schema.TaggedErrorClass()("FileSystemError", { - method: Schema.String, - cause: Schema.optional(Schema.Defect), - }) {} - - export type Error = PlatformError | FileSystemError - - export interface DirEntry { - readonly name: string - readonly type: "file" | "directory" | "symlink" | "other" - } - - export interface Interface extends FileSystem.FileSystem { - readonly isDir: (path: string) => Effect.Effect - readonly isFile: (path: string) => Effect.Effect - readonly existsSafe: (path: string) => Effect.Effect - readonly readJson: (path: string) => Effect.Effect - readonly writeJson: (path: string, data: unknown, mode?: number) => Effect.Effect - readonly ensureDir: (path: string) => Effect.Effect - readonly writeWithDirs: (path: string, content: string | Uint8Array, mode?: number) => Effect.Effect - readonly readDirectoryEntries: (path: string) => Effect.Effect - readonly findUp: (target: string, start: string, stop?: string) => Effect.Effect - readonly up: (options: { targets: string[]; start: string; stop?: string }) => Effect.Effect - readonly globUp: (pattern: string, start: string, stop?: string) => Effect.Effect - readonly glob: (pattern: string, options?: Glob.Options) => Effect.Effect - readonly globMatch: (pattern: string, filepath: string) => boolean - } - - export class Service extends Context.Service()("@opencode/FileSystem") {} - - export const layer = Layer.effect( - Service, - Effect.gen(function* () { - const fs = yield* FileSystem.FileSystem - - const existsSafe = Effect.fn("FileSystem.existsSafe")(function* (path: string) { - return yield* fs.exists(path).pipe(Effect.orElseSucceed(() => false)) - }) - - const isDir = Effect.fn("FileSystem.isDir")(function* (path: string) { - const info = yield* fs.stat(path).pipe(Effect.catch(() => Effect.void)) - return info?.type === "Directory" - }) - - const isFile = Effect.fn("FileSystem.isFile")(function* (path: string) { - const info = yield* fs.stat(path).pipe(Effect.catch(() => Effect.void)) - return info?.type === "File" - }) - - const readDirectoryEntries = Effect.fn("FileSystem.readDirectoryEntries")(function* (dirPath: string) { - return yield* Effect.tryPromise({ - try: async () => { - const entries = await NFS.readdir(dirPath, { withFileTypes: true }) - return entries.map( - (e): DirEntry => ({ - name: e.name, - type: e.isDirectory() ? "directory" : e.isSymbolicLink() ? "symlink" : e.isFile() ? "file" : "other", - }), - ) - }, - catch: (cause) => new FileSystemError({ method: "readDirectoryEntries", cause }), - }) - }) - - const readJson = Effect.fn("FileSystem.readJson")(function* (path: string) { - const text = yield* fs.readFileString(path) - return JSON.parse(text) - }) - - const writeJson = Effect.fn("FileSystem.writeJson")(function* (path: string, data: unknown, mode?: number) { - const content = JSON.stringify(data, null, 2) - yield* fs.writeFileString(path, content) - if (mode) yield* fs.chmod(path, mode) - }) - - const ensureDir = Effect.fn("FileSystem.ensureDir")(function* (path: string) { - yield* fs.makeDirectory(path, { recursive: true }) - }) - - const writeWithDirs = Effect.fn("FileSystem.writeWithDirs")(function* ( - path: string, - content: string | Uint8Array, - mode?: number, - ) { - const write = typeof content === "string" ? fs.writeFileString(path, content) : fs.writeFile(path, content) - - yield* write.pipe( - Effect.catchIf( - (e) => e.reason._tag === "NotFound", - () => - Effect.gen(function* () { - yield* fs.makeDirectory(dirname(path), { recursive: true }) - yield* write - }), - ), - ) - if (mode) yield* fs.chmod(path, mode) - }) - - const glob = Effect.fn("FileSystem.glob")(function* (pattern: string, options?: Glob.Options) { - return yield* Effect.tryPromise({ - try: () => Glob.scan(pattern, options), - catch: (cause) => new FileSystemError({ method: "glob", cause }), - }) - }) - - const findUp = Effect.fn("FileSystem.findUp")(function* (target: string, start: string, stop?: string) { - const result: string[] = [] - let current = start - while (true) { - const search = join(current, target) - if (yield* fs.exists(search)) result.push(search) - if (stop === current) break - const parent = dirname(current) - if (parent === current) break - current = parent - } - return result - }) - - const up = Effect.fn("FileSystem.up")(function* (options: { targets: string[]; start: string; stop?: string }) { - const result: string[] = [] - let current = options.start - while (true) { - for (const target of options.targets) { - const search = join(current, target) - if (yield* fs.exists(search)) result.push(search) - } - if (options.stop === current) break - const parent = dirname(current) - if (parent === current) break - current = parent - } - return result - }) - - const globUp = Effect.fn("FileSystem.globUp")(function* (pattern: string, start: string, stop?: string) { - const result: string[] = [] - let current = start - while (true) { - const matches = yield* glob(pattern, { cwd: current, absolute: true, include: "file", dot: true }).pipe( - Effect.catch(() => Effect.succeed([] as string[])), - ) - result.push(...matches) - if (stop === current) break - const parent = dirname(current) - if (parent === current) break - current = parent - } - return result - }) - - return Service.of({ - ...fs, - existsSafe, - isDir, - isFile, - readDirectoryEntries, - readJson, - writeJson, - ensureDir, - writeWithDirs, - findUp, - up, - globUp, - glob, - globMatch: Glob.match, - }) - }), - ) - - export const defaultLayer = layer.pipe(Layer.provide(NodeFileSystem.layer)) - - // Pure helpers that don't need Effect (path manipulation, sync operations) - export function mimeType(p: string): string { - return lookup(p) || "application/octet-stream" - } - - export function normalizePath(p: string): string { - if (process.platform !== "win32") return p - const resolved = pathResolve(windowsPath(p)) - try { - return realpathSync.native(resolved) - } catch { - return resolved - } - } - - export function normalizePathPattern(p: string): string { - if (process.platform !== "win32") return p - if (p === "*") return p - const match = p.match(/^(.*)[\\/]\*$/) - if (!match) return normalizePath(p) - const dir = /^[A-Za-z]:$/.test(match[1]) ? match[1] + "\\" : match[1] - return join(normalizePath(dir), "*") - } - - export function resolve(p: string): string { - const resolved = pathResolve(windowsPath(p)) - try { - return normalizePath(realpathSync(resolved)) - } catch (e: any) { - if (e?.code === "ENOENT") return normalizePath(resolved) - throw e - } - } - - export function windowsPath(p: string): string { - if (process.platform !== "win32") return p - return p - .replace(/^\/([a-zA-Z]):(?:[\\/]|$)/, (_, drive) => `${drive.toUpperCase()}:/`) - .replace(/^\/([a-zA-Z])(?:\/|$)/, (_, drive) => `${drive.toUpperCase()}:/`) - .replace(/^\/cygdrive\/([a-zA-Z])(?:\/|$)/, (_, drive) => `${drive.toUpperCase()}:/`) - .replace(/^\/mnt\/([a-zA-Z])(?:\/|$)/, (_, drive) => `${drive.toUpperCase()}:/`) - } - - export function overlaps(a: string, b: string) { - const relA = relative(a, b) - const relB = relative(b, a) - return !relA || !relA.startsWith("..") || !relB || !relB.startsWith("..") - } - - export function contains(parent: string, child: string) { - return !relative(parent, child).startsWith("..") - } -} diff --git a/packages/opencode/src/format/formatter.ts b/packages/opencode/src/format/formatter.ts index ada661eba..6c17310ff 100644 --- a/packages/opencode/src/format/formatter.ts +++ b/packages/opencode/src/format/formatter.ts @@ -1,4 +1,4 @@ -import { Npm } from "@/npm" +import { Npm } from "../npm" import { Instance } from "../project/instance" import { Filesystem } from "../util/filesystem" import { Process } from "../util/process" diff --git a/packages/opencode/src/ide/index.ts b/packages/opencode/src/ide/index.ts index ce4128b90..46efea2cc 100644 --- a/packages/opencode/src/ide/index.ts +++ b/packages/opencode/src/ide/index.ts @@ -1,7 +1,7 @@ import { BusEvent } from "@/bus/bus-event" import { Bus } from "@/bus" import z from "zod" -import { NamedError } from "@opencode-ai/util/error" +import { NamedError } from "@opencode-ai/shared/util/error" import { Log } from "../util/log" import { Process } from "@/util/process" diff --git a/packages/opencode/src/index.ts b/packages/opencode/src/index.ts index 753becc26..641411461 100644 --- a/packages/opencode/src/index.ts +++ b/packages/opencode/src/index.ts @@ -11,7 +11,7 @@ import { UninstallCommand } from "./cli/cmd/uninstall" import { ModelsCommand } from "./cli/cmd/models" import { UI } from "./cli/ui" import { Installation } from "./installation" -import { NamedError } from "@opencode-ai/util/error" +import { NamedError } from "@opencode-ai/shared/util/error" import { FormatError } from "./cli/error" import { ServeCommand } from "./cli/cmd/serve" import { Filesystem } from "./util/filesystem" diff --git a/packages/opencode/src/lsp/client.ts b/packages/opencode/src/lsp/client.ts index de0c43862..fe5a9ab18 100644 --- a/packages/opencode/src/lsp/client.ts +++ b/packages/opencode/src/lsp/client.ts @@ -9,7 +9,7 @@ import { Process } from "../util/process" import { LANGUAGE_EXTENSIONS } from "./language" import z from "zod" import type { LSPServer } from "./server" -import { NamedError } from "@opencode-ai/util/error" +import { NamedError } from "@opencode-ai/shared/util/error" import { withTimeout } from "../util/timeout" import { Instance } from "../project/instance" import { Filesystem } from "../util/filesystem" diff --git a/packages/opencode/src/lsp/server.ts b/packages/opencode/src/lsp/server.ts index abfb31ead..9ffef7a42 100644 --- a/packages/opencode/src/lsp/server.ts +++ b/packages/opencode/src/lsp/server.ts @@ -11,9 +11,9 @@ import { Flag } from "../flag/flag" import { Archive } from "../util/archive" import { Process } from "../util/process" import { which } from "../util/which" -import { Module } from "@opencode-ai/util/module" +import { Module } from "@opencode-ai/shared/util/module" import { spawn } from "./launch" -import { Npm } from "@/npm" +import { Npm } from "../npm" export namespace LSPServer { const log = Log.create({ service: "lsp.server" }) diff --git a/packages/opencode/src/mcp/auth.ts b/packages/opencode/src/mcp/auth.ts index 6eefc107d..85f9e1d8c 100644 --- a/packages/opencode/src/mcp/auth.ts +++ b/packages/opencode/src/mcp/auth.ts @@ -2,7 +2,7 @@ import path from "path" import z from "zod" import { Global } from "../global" import { Effect, Layer, Context } from "effect" -import { AppFileSystem } from "@/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" export namespace McpAuth { export const Tokens = z.object({ diff --git a/packages/opencode/src/mcp/index.ts b/packages/opencode/src/mcp/index.ts index 3de427d7e..3b6690934 100644 --- a/packages/opencode/src/mcp/index.ts +++ b/packages/opencode/src/mcp/index.ts @@ -11,12 +11,12 @@ import { } from "@modelcontextprotocol/sdk/types.js" import { Config } from "../config/config" import { Log } from "../util/log" -import { NamedError } from "@opencode-ai/util/error" +import { NamedError } from "@opencode-ai/shared/util/error" import z from "zod/v4" import { Instance } from "../project/instance" import { Installation } from "../installation" import { withTimeout } from "@/util/timeout" -import { AppFileSystem } from "@/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { McpOAuthProvider } from "./oauth-provider" import { McpOAuthCallback } from "./oauth-callback" import { McpAuth } from "./auth" diff --git a/packages/opencode/src/npm/index.ts b/packages/opencode/src/npm/index.ts index 3568ff20e..5b708431c 100644 --- a/packages/opencode/src/npm/index.ts +++ b/packages/opencode/src/npm/index.ts @@ -1,6 +1,6 @@ import semver from "semver" import z from "zod" -import { NamedError } from "@opencode-ai/util/error" +import { NamedError } from "@opencode-ai/shared/util/error" import { Global } from "../global" import { Log } from "../util/log" import path from "path" diff --git a/packages/opencode/src/plugin/index.ts b/packages/opencode/src/plugin/index.ts index 0dc53d997..c716ffdf8 100644 --- a/packages/opencode/src/plugin/index.ts +++ b/packages/opencode/src/plugin/index.ts @@ -12,7 +12,7 @@ import { createOpencodeClient } from "@opencode-ai/sdk" import { Flag } from "../flag/flag" import { CodexAuthPlugin } from "./codex" import { Session } from "../session" -import { NamedError } from "@opencode-ai/util/error" +import { NamedError } from "@opencode-ai/shared/util/error" import { CopilotAuthPlugin } from "./github-copilot/copilot" import { gitlabAuthPlugin as GitlabAuthPlugin } from "opencode-gitlab-auth" import { PoeAuthPlugin } from "opencode-poe-auth" diff --git a/packages/opencode/src/plugin/shared.ts b/packages/opencode/src/plugin/shared.ts index 6cda49786..54cc32af5 100644 --- a/packages/opencode/src/plugin/shared.ts +++ b/packages/opencode/src/plugin/shared.ts @@ -2,7 +2,7 @@ import path from "path" import { fileURLToPath, pathToFileURL } from "url" import npa from "npm-package-arg" import semver from "semver" -import { Npm } from "@/npm" +import { Npm } from "../npm" import { Filesystem } from "@/util/filesystem" import { isRecord } from "@/util/record" diff --git a/packages/opencode/src/project/project.ts b/packages/opencode/src/project/project.ts index f9d634a1c..d20bf4249 100644 --- a/packages/opencode/src/project/project.ts +++ b/packages/opencode/src/project/project.ts @@ -11,7 +11,7 @@ import { ProjectID } from "./schema" import { Effect, Layer, Path, Scope, Context, Stream } from "effect" import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" import { NodePath } from "@effect/platform-node" -import { AppFileSystem } from "@/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner" export namespace Project { diff --git a/packages/opencode/src/project/vcs.ts b/packages/opencode/src/project/vcs.ts index aede980d6..e4093fd45 100644 --- a/packages/opencode/src/project/vcs.ts +++ b/packages/opencode/src/project/vcs.ts @@ -4,7 +4,7 @@ import path from "path" import { Bus } from "@/bus" import { BusEvent } from "@/bus/bus-event" import { InstanceState } from "@/effect/instance-state" -import { AppFileSystem } from "@/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { FileWatcher } from "@/file/watcher" import { Git } from "@/git" import { Log } from "@/util/log" diff --git a/packages/opencode/src/provider/auth.ts b/packages/opencode/src/provider/auth.ts index e410b8636..c66ccffc1 100644 --- a/packages/opencode/src/provider/auth.ts +++ b/packages/opencode/src/provider/auth.ts @@ -1,5 +1,5 @@ import type { AuthOAuthResult, Hooks } from "@opencode-ai/plugin" -import { NamedError } from "@opencode-ai/util/error" +import { NamedError } from "@opencode-ai/shared/util/error" import { Auth } from "@/auth" import { InstanceState } from "@/effect/instance-state" import { Plugin } from "../plugin" diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index 84f074d42..d34721f1d 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -8,7 +8,7 @@ import { Log } from "../util/log" import { Npm } from "../npm" import { Hash } from "../util/hash" import { Plugin } from "../plugin" -import { NamedError } from "@opencode-ai/util/error" +import { NamedError } from "@opencode-ai/shared/util/error" import { type LanguageModelV3 } from "@ai-sdk/provider" import { ModelsDev } from "./models" import { Auth } from "../auth" @@ -21,7 +21,7 @@ import path from "path" import { Effect, Layer, Context } from "effect" import { EffectLogger } from "@/effect/logger" import { InstanceState } from "@/effect/instance-state" -import { AppFileSystem } from "@/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { isRecord } from "@/util/record" // Direct imports for bundled providers diff --git a/packages/opencode/src/pty/index.ts b/packages/opencode/src/pty/index.ts index 189172185..9c79eb2d4 100644 --- a/packages/opencode/src/pty/index.ts +++ b/packages/opencode/src/pty/index.ts @@ -5,7 +5,7 @@ import { Instance } from "@/project/instance" import type { Proc } from "#pty" import z from "zod" import { Log } from "../util/log" -import { lazy } from "@opencode-ai/util/lazy" +import { lazy } from "@opencode-ai/shared/util/lazy" import { Shell } from "@/shell/shell" import { Plugin } from "@/plugin" import { PtyID } from "./schema" diff --git a/packages/opencode/src/server/instance/session.ts b/packages/opencode/src/server/instance/session.ts index e443a6ddd..a011c32f9 100644 --- a/packages/opencode/src/server/instance/session.ts +++ b/packages/opencode/src/server/instance/session.ts @@ -25,7 +25,7 @@ import { ModelID, ProviderID } from "@/provider/schema" import { errors } from "../error" import { lazy } from "../../util/lazy" import { Bus } from "../../bus" -import { NamedError } from "@opencode-ai/util/error" +import { NamedError } from "@opencode-ai/shared/util/error" const log = Log.create({ service: "server" }) diff --git a/packages/opencode/src/server/middleware.ts b/packages/opencode/src/server/middleware.ts index d0539eb24..6e9165186 100644 --- a/packages/opencode/src/server/middleware.ts +++ b/packages/opencode/src/server/middleware.ts @@ -1,5 +1,5 @@ import { Provider } from "../provider/provider" -import { NamedError } from "@opencode-ai/util/error" +import { NamedError } from "@opencode-ai/shared/util/error" import { NotFoundError } from "../storage/db" import { Session } from "../session" import type { ContentfulStatusCode } from "hono/utils/http-status" diff --git a/packages/opencode/src/session/index.ts b/packages/opencode/src/session/index.ts index aa3404ad7..d8ab81234 100644 --- a/packages/opencode/src/session/index.ts +++ b/packages/opencode/src/session/index.ts @@ -1,4 +1,4 @@ -import { Slug } from "@opencode-ai/util/slug" +import { Slug } from "@opencode-ai/shared/util/slug" import path from "path" import { BusEvent } from "@/bus/bus-event" import { Bus } from "@/bus" diff --git a/packages/opencode/src/session/instruction.ts b/packages/opencode/src/session/instruction.ts index 04f2610df..b4794ba5b 100644 --- a/packages/opencode/src/session/instruction.ts +++ b/packages/opencode/src/session/instruction.ts @@ -5,7 +5,7 @@ import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/unstable/ import { Config } from "@/config/config" import { InstanceState } from "@/effect/instance-state" import { Flag } from "@/flag/flag" -import { AppFileSystem } from "@/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { withTransientReadRetry } from "@/util/effect-http-client" import { Global } from "../global" import { Instance } from "../project/instance" diff --git a/packages/opencode/src/session/message-v2.ts b/packages/opencode/src/session/message-v2.ts index 4c18d1f7e..8c82d4d73 100644 --- a/packages/opencode/src/session/message-v2.ts +++ b/packages/opencode/src/session/message-v2.ts @@ -1,7 +1,7 @@ import { BusEvent } from "@/bus/bus-event" import { SessionID, MessageID, PartID } from "./schema" import z from "zod" -import { NamedError } from "@opencode-ai/util/error" +import { NamedError } from "@opencode-ai/shared/util/error" import { APICallError, convertToModelMessages, LoadAPIKeyError, type ModelMessage, type UIMessage } from "ai" import { LSP } from "../lsp" import { Snapshot } from "@/snapshot" diff --git a/packages/opencode/src/session/message.ts b/packages/opencode/src/session/message.ts index ee5eac08b..396034825 100644 --- a/packages/opencode/src/session/message.ts +++ b/packages/opencode/src/session/message.ts @@ -1,7 +1,7 @@ import z from "zod" import { SessionID } from "./schema" import { ModelID, ProviderID } from "../provider/schema" -import { NamedError } from "@opencode-ai/util/error" +import { NamedError } from "@opencode-ai/shared/util/error" export namespace Message { export const OutputLengthError = NamedError.create("MessageOutputLengthError", z.object({})) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 3efcc0365..f8c794505 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -32,14 +32,14 @@ import { Command } from "../command" import { pathToFileURL, fileURLToPath } from "url" import { ConfigMarkdown } from "../config/markdown" import { SessionSummary } from "./summary" -import { NamedError } from "@opencode-ai/util/error" +import { NamedError } from "@opencode-ai/shared/util/error" import { SessionProcessor } from "./processor" import { Tool } from "@/tool/tool" import { Permission } from "@/permission" import { SessionStatus } from "./status" import { LLM } from "./llm" import { Shell } from "@/shell/shell" -import { AppFileSystem } from "@/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { Truncate } from "@/tool/truncate" import { decodeDataUrl } from "@/util/data-url" import { Process } from "@/util/process" diff --git a/packages/opencode/src/session/retry.ts b/packages/opencode/src/session/retry.ts index 5ec9a585b..39eb8cfb7 100644 --- a/packages/opencode/src/session/retry.ts +++ b/packages/opencode/src/session/retry.ts @@ -1,4 +1,4 @@ -import type { NamedError } from "@opencode-ai/util/error" +import type { NamedError } from "@opencode-ai/shared/util/error" import { Cause, Clock, Duration, Effect, Schedule } from "effect" import { MessageV2 } from "./message-v2" import { iife } from "@/util/iife" diff --git a/packages/opencode/src/skill/discovery.ts b/packages/opencode/src/skill/discovery.ts index 0bc3ee629..0323f250f 100644 --- a/packages/opencode/src/skill/discovery.ts +++ b/packages/opencode/src/skill/discovery.ts @@ -2,7 +2,7 @@ import { NodePath } from "@effect/platform-node" import { Effect, Layer, Path, Schema, Context } from "effect" import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" import { withTransientReadRetry } from "@/util/effect-http-client" -import { AppFileSystem } from "@/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { Global } from "../global" import { Log } from "../util/log" diff --git a/packages/opencode/src/skill/index.ts b/packages/opencode/src/skill/index.ts index 6c4f290a0..79b426c69 100644 --- a/packages/opencode/src/skill/index.ts +++ b/packages/opencode/src/skill/index.ts @@ -3,17 +3,17 @@ import path from "path" import { pathToFileURL } from "url" import z from "zod" import { Effect, Layer, Context } from "effect" -import { NamedError } from "@opencode-ai/util/error" +import { NamedError } from "@opencode-ai/shared/util/error" import type { Agent } from "@/agent/agent" import { Bus } from "@/bus" import { InstanceState } from "@/effect/instance-state" import { Flag } from "@/flag/flag" import { Global } from "@/global" import { Permission } from "@/permission" -import { AppFileSystem } from "@/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { Config } from "../config/config" import { ConfigMarkdown } from "../config/markdown" -import { Glob } from "../util/glob" +import { Glob } from "@opencode-ai/shared/util/glob" import { Log } from "../util/log" import { Discovery } from "./discovery" diff --git a/packages/opencode/src/snapshot/index.ts b/packages/opencode/src/snapshot/index.ts index 06c91442a..2b21f7e89 100644 --- a/packages/opencode/src/snapshot/index.ts +++ b/packages/opencode/src/snapshot/index.ts @@ -5,7 +5,7 @@ import path from "path" import z from "zod" import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner" import { InstanceState } from "@/effect/instance-state" -import { AppFileSystem } from "@/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { Hash } from "@/util/hash" import { Config } from "../config/config" import { Global } from "../global" diff --git a/packages/opencode/src/storage/db.ts b/packages/opencode/src/storage/db.ts index a7dbf9380..68a41e471 100644 --- a/packages/opencode/src/storage/db.ts +++ b/packages/opencode/src/storage/db.ts @@ -6,7 +6,7 @@ import { LocalContext } from "../util/local-context" import { lazy } from "../util/lazy" import { Global } from "../global" import { Log } from "../util/log" -import { NamedError } from "@opencode-ai/util/error" +import { NamedError } from "@opencode-ai/shared/util/error" import z from "zod" import path from "path" import { readFileSync, readdirSync, existsSync } from "fs" diff --git a/packages/opencode/src/storage/json-migration.ts b/packages/opencode/src/storage/json-migration.ts index 400e3dc9e..89d27b9a7 100644 --- a/packages/opencode/src/storage/json-migration.ts +++ b/packages/opencode/src/storage/json-migration.ts @@ -8,7 +8,7 @@ import { SessionShareTable } from "../share/share.sql" import path from "path" import { existsSync } from "fs" import { Filesystem } from "../util/filesystem" -import { Glob } from "../util/glob" +import { Glob } from "@opencode-ai/shared/util/glob" export namespace JsonMigration { const log = Log.create({ service: "json-migration" }) diff --git a/packages/opencode/src/storage/storage.ts b/packages/opencode/src/storage/storage.ts index a123cd664..359c750ce 100644 --- a/packages/opencode/src/storage/storage.ts +++ b/packages/opencode/src/storage/storage.ts @@ -1,9 +1,9 @@ import { Log } from "../util/log" import path from "path" import { Global } from "../global" -import { NamedError } from "@opencode-ai/util/error" +import { NamedError } from "@opencode-ai/shared/util/error" import z from "zod" -import { AppFileSystem } from "@/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { Effect, Exit, Layer, Option, RcMap, Schema, Context, TxReentrantLock } from "effect" import { Git } from "@/git" diff --git a/packages/opencode/src/tool/apply_patch.ts b/packages/opencode/src/tool/apply_patch.ts index fd38a9b22..b9877d8fe 100644 --- a/packages/opencode/src/tool/apply_patch.ts +++ b/packages/opencode/src/tool/apply_patch.ts @@ -10,7 +10,7 @@ import { createTwoFilesPatch, diffLines } from "diff" import { assertExternalDirectoryEffect } from "./external-directory" import { trimDiff } from "./edit" import { LSP } from "../lsp" -import { AppFileSystem } from "../filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import DESCRIPTION from "./apply_patch.txt" import { File } from "../file" import { Format } from "../format" diff --git a/packages/opencode/src/tool/bash.ts b/packages/opencode/src/tool/bash.ts index ad6739b9a..3bb936944 100644 --- a/packages/opencode/src/tool/bash.ts +++ b/packages/opencode/src/tool/bash.ts @@ -8,7 +8,7 @@ import { Instance } from "../project/instance" import { lazy } from "@/util/lazy" import { Language, type Node } from "web-tree-sitter" -import { AppFileSystem } from "@/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { fileURLToPath } from "url" import { Flag } from "@/flag/flag" import { Shell } from "@/shell/shell" diff --git a/packages/opencode/src/tool/edit.ts b/packages/opencode/src/tool/edit.ts index a835714c6..bc8478e39 100644 --- a/packages/opencode/src/tool/edit.ts +++ b/packages/opencode/src/tool/edit.ts @@ -19,7 +19,7 @@ import { Filesystem } from "../util/filesystem" import { Instance } from "../project/instance" import { Snapshot } from "@/snapshot" import { assertExternalDirectoryEffect } from "./external-directory" -import { AppFileSystem } from "../filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" function normalizeLineEndings(text: string): string { return text.replaceAll("\r\n", "\n") diff --git a/packages/opencode/src/tool/external-directory.ts b/packages/opencode/src/tool/external-directory.ts index 9df3e0aaf..352cc0739 100644 --- a/packages/opencode/src/tool/external-directory.ts +++ b/packages/opencode/src/tool/external-directory.ts @@ -4,7 +4,7 @@ import { EffectLogger } from "@/effect/logger" import { InstanceState } from "@/effect/instance-state" import type { Tool } from "./tool" import { Instance } from "../project/instance" -import { AppFileSystem } from "../filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" type Kind = "file" | "directory" diff --git a/packages/opencode/src/tool/glob.ts b/packages/opencode/src/tool/glob.ts index c1577bc7d..778a74ddc 100644 --- a/packages/opencode/src/tool/glob.ts +++ b/packages/opencode/src/tool/glob.ts @@ -3,7 +3,7 @@ import z from "zod" import { Effect, Option } from "effect" import * as Stream from "effect/Stream" import { InstanceState } from "@/effect/instance-state" -import { AppFileSystem } from "../filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { Ripgrep } from "../file/ripgrep" import { assertExternalDirectoryEffect } from "./external-directory" import DESCRIPTION from "./glob.txt" diff --git a/packages/opencode/src/tool/grep.ts b/packages/opencode/src/tool/grep.ts index 0d717ba37..9a2bab5b2 100644 --- a/packages/opencode/src/tool/grep.ts +++ b/packages/opencode/src/tool/grep.ts @@ -2,7 +2,7 @@ import path from "path" import z from "zod" import { Effect, Option } from "effect" import { InstanceState } from "@/effect/instance-state" -import { AppFileSystem } from "../filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { Ripgrep } from "../file/ripgrep" import { assertExternalDirectoryEffect } from "./external-directory" import DESCRIPTION from "./grep.txt" diff --git a/packages/opencode/src/tool/lsp.ts b/packages/opencode/src/tool/lsp.ts index c5a5d6f81..36cab3c1c 100644 --- a/packages/opencode/src/tool/lsp.ts +++ b/packages/opencode/src/tool/lsp.ts @@ -7,7 +7,7 @@ import DESCRIPTION from "./lsp.txt" import { Instance } from "../project/instance" import { pathToFileURL } from "url" import { assertExternalDirectoryEffect } from "./external-directory" -import { AppFileSystem } from "../filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" const operations = [ "goToDefinition", diff --git a/packages/opencode/src/tool/read.ts b/packages/opencode/src/tool/read.ts index 501a8c97e..701bfc4b9 100644 --- a/packages/opencode/src/tool/read.ts +++ b/packages/opencode/src/tool/read.ts @@ -5,7 +5,7 @@ import { open } from "fs/promises" import * as path from "path" import { createInterface } from "readline" import { Tool } from "./tool" -import { AppFileSystem } from "../filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { LSP } from "../lsp" import { FileTime } from "../file/time" import DESCRIPTION from "./read.txt" diff --git a/packages/opencode/src/tool/registry.ts b/packages/opencode/src/tool/registry.ts index 2e7da5b50..6900feecc 100644 --- a/packages/opencode/src/tool/registry.ts +++ b/packages/opencode/src/tool/registry.ts @@ -26,7 +26,7 @@ import { Log } from "@/util/log" import { LspTool } from "./lsp" import { Truncate } from "./truncate" import { ApplyPatchTool } from "./apply_patch" -import { Glob } from "../util/glob" +import { Glob } from "@opencode-ai/shared/util/glob" import path from "path" import { pathToFileURL } from "url" import { Effect, Layer, Context } from "effect" @@ -41,7 +41,7 @@ import { Todo } from "../session/todo" import { LSP } from "../lsp" import { FileTime } from "../file/time" import { Instruction } from "../session/instruction" -import { AppFileSystem } from "../filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { Bus } from "../bus" import { Agent } from "../agent/agent" import { Skill } from "../skill" diff --git a/packages/opencode/src/tool/truncate.ts b/packages/opencode/src/tool/truncate.ts index e6bab1a16..a7bd8a4b1 100644 --- a/packages/opencode/src/tool/truncate.ts +++ b/packages/opencode/src/tool/truncate.ts @@ -2,7 +2,7 @@ import { NodePath } from "@effect/platform-node" import { Cause, Duration, Effect, Layer, Schedule, Context } from "effect" import path from "path" import type { Agent } from "../agent/agent" -import { AppFileSystem } from "@/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { evaluate } from "@/permission/evaluate" import { Identifier } from "../id/id" import { Log } from "../util/log" diff --git a/packages/opencode/src/tool/write.ts b/packages/opencode/src/tool/write.ts index 7a9d82cf8..337c2708c 100644 --- a/packages/opencode/src/tool/write.ts +++ b/packages/opencode/src/tool/write.ts @@ -10,7 +10,7 @@ import { File } from "../file" import { FileWatcher } from "../file/watcher" import { Format } from "../format" import { FileTime } from "../file/time" -import { AppFileSystem } from "../filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { Instance } from "../project/instance" import { trimDiff } from "./edit" import { assertExternalDirectoryEffect } from "./external-directory" diff --git a/packages/opencode/src/util/filesystem.ts b/packages/opencode/src/util/filesystem.ts index 5f50231b0..b4aef0545 100644 --- a/packages/opencode/src/util/filesystem.ts +++ b/packages/opencode/src/util/filesystem.ts @@ -5,7 +5,7 @@ import { realpathSync } from "fs" import { dirname, join, relative, resolve as pathResolve, win32 } from "path" import { Readable } from "stream" import { pipeline } from "stream/promises" -import { Glob } from "./glob" +import { Glob } from "@opencode-ai/shared/util/glob" export namespace Filesystem { // Fast sync version for metadata checks diff --git a/packages/opencode/src/util/glob.ts b/packages/opencode/src/util/glob.ts deleted file mode 100644 index febf062da..000000000 --- a/packages/opencode/src/util/glob.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { glob, globSync, type GlobOptions } from "glob" -import { minimatch } from "minimatch" - -export namespace Glob { - export interface Options { - cwd?: string - absolute?: boolean - include?: "file" | "all" - dot?: boolean - symlink?: boolean - } - - function toGlobOptions(options: Options): GlobOptions { - return { - cwd: options.cwd, - absolute: options.absolute, - dot: options.dot, - follow: options.symlink ?? false, - nodir: options.include !== "all", - } - } - - export async function scan(pattern: string, options: Options = {}): Promise { - return glob(pattern, toGlobOptions(options)) as Promise - } - - export function scanSync(pattern: string, options: Options = {}): string[] { - return globSync(pattern, toGlobOptions(options)) as string[] - } - - export function match(pattern: string, filepath: string): boolean { - return minimatch(filepath, pattern, { dot: true }) - } -} diff --git a/packages/opencode/src/util/log.ts b/packages/opencode/src/util/log.ts index f94e9866f..781263276 100644 --- a/packages/opencode/src/util/log.ts +++ b/packages/opencode/src/util/log.ts @@ -3,7 +3,7 @@ import fs from "fs/promises" import { createWriteStream } from "fs" import { Global } from "../global" import z from "zod" -import { Glob } from "./glob" +import { Glob } from "@opencode-ai/shared/util/glob" export namespace Log { export const Level = z.enum(["DEBUG", "INFO", "WARN", "ERROR"]).meta({ ref: "LogLevel", description: "Log level" }) diff --git a/packages/opencode/src/worktree/index.ts b/packages/opencode/src/worktree/index.ts index 18240524a..14a3a0dc9 100644 --- a/packages/opencode/src/worktree/index.ts +++ b/packages/opencode/src/worktree/index.ts @@ -1,5 +1,5 @@ import z from "zod" -import { NamedError } from "@opencode-ai/util/error" +import { NamedError } from "@opencode-ai/shared/util/error" import { Global } from "../global" import { Instance } from "../project/instance" import { InstanceBootstrap } from "../project/bootstrap" @@ -8,7 +8,7 @@ import { Database, eq } from "../storage/db" import { ProjectTable } from "../project/project.sql" import type { ProjectID } from "../project/schema" import { Log } from "../util/log" -import { Slug } from "@opencode-ai/util/slug" +import { Slug } from "@opencode-ai/shared/util/slug" import { errorMessage } from "../util/error" import { BusEvent } from "@/bus/bus-event" import { GlobalBus } from "@/bus/global" @@ -16,7 +16,7 @@ import { Git } from "@/git" import { Effect, Layer, Path, Scope, Context, Stream } from "effect" import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" import { NodePath } from "@effect/platform-node" -import { AppFileSystem } from "@/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { BootstrapRuntime } from "@/effect/bootstrap-runtime" import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner" import { InstanceState } from "@/effect/instance-state" diff --git a/packages/opencode/test/config/config.test.ts b/packages/opencode/test/config/config.test.ts index e759985fe..ed7e689da 100644 --- a/packages/opencode/test/config/config.test.ts +++ b/packages/opencode/test/config/config.test.ts @@ -5,7 +5,7 @@ import { Config } from "../../src/config/config" import { Instance } from "../../src/project/instance" import { Auth } from "../../src/auth" import { AccessToken, Account, AccountID, OrgID } from "../../src/account" -import { AppFileSystem } from "../../src/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { Env } from "../../src/env" import { provideTmpdirInstance } from "../fixture/fixture" import { tmpdir, tmpdirScoped } from "../fixture/fixture" diff --git a/packages/opencode/test/filesystem/filesystem.test.ts b/packages/opencode/test/filesystem/filesystem.test.ts index ca73b3336..0bb4ba583 100644 --- a/packages/opencode/test/filesystem/filesystem.test.ts +++ b/packages/opencode/test/filesystem/filesystem.test.ts @@ -1,7 +1,7 @@ import { describe, test, expect } from "bun:test" import { Effect, Layer } from "effect" import { NodeFileSystem } from "@effect/platform-node" -import { AppFileSystem } from "../../src/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { testEffect } from "../lib/effect" import path from "path" diff --git a/packages/opencode/test/project/project.test.ts b/packages/opencode/test/project/project.test.ts index eddd79bc6..ba253a920 100644 --- a/packages/opencode/test/project/project.test.ts +++ b/packages/opencode/test/project/project.test.ts @@ -9,7 +9,7 @@ import { ProjectID } from "../../src/project/schema" import { Effect, Layer, Stream } from "effect" import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" import { NodePath } from "@effect/platform-node" -import { AppFileSystem } from "../../src/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner" Log.init({ print: false }) diff --git a/packages/opencode/test/session/prompt-effect.test.ts b/packages/opencode/test/session/prompt-effect.test.ts index 244f778ca..94561206e 100644 --- a/packages/opencode/test/session/prompt-effect.test.ts +++ b/packages/opencode/test/session/prompt-effect.test.ts @@ -22,7 +22,7 @@ import { Todo } from "../../src/session/todo" import { Session } from "../../src/session" import { LLM } from "../../src/session/llm" import { MessageV2 } from "../../src/session/message-v2" -import { AppFileSystem } from "../../src/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { SessionCompaction } from "../../src/session/compaction" import { SessionSummary } from "../../src/session/summary" import { Instruction } from "../../src/session/instruction" diff --git a/packages/opencode/test/session/prompt.test.ts b/packages/opencode/test/session/prompt.test.ts index c1d6f1da9..1290570b8 100644 --- a/packages/opencode/test/session/prompt.test.ts +++ b/packages/opencode/test/session/prompt.test.ts @@ -1,6 +1,6 @@ import path from "path" import { describe, expect, test } from "bun:test" -import { NamedError } from "@opencode-ai/util/error" +import { NamedError } from "@opencode-ai/shared/util/error" import { fileURLToPath } from "url" import { Effect, Layer } from "effect" import { Instance } from "../../src/project/instance" diff --git a/packages/opencode/test/session/retry.test.ts b/packages/opencode/test/session/retry.test.ts index a598c37fc..314306ba6 100644 --- a/packages/opencode/test/session/retry.test.ts +++ b/packages/opencode/test/session/retry.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test" -import type { NamedError } from "@opencode-ai/util/error" +import type { NamedError } from "@opencode-ai/shared/util/error" import { APICallError } from "ai" import { setTimeout as sleep } from "node:timers/promises" import { Effect, Schedule } from "effect" diff --git a/packages/opencode/test/session/snapshot-tool-race.test.ts b/packages/opencode/test/session/snapshot-tool-race.test.ts index 464182395..80d74c756 100644 --- a/packages/opencode/test/session/snapshot-tool-race.test.ts +++ b/packages/opencode/test/session/snapshot-tool-race.test.ts @@ -53,7 +53,7 @@ import { Shell } from "../../src/shell/shell" import { Snapshot } from "../../src/snapshot" import { ToolRegistry } from "../../src/tool/registry" import { Truncate } from "../../src/tool/truncate" -import { AppFileSystem } from "../../src/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner" import { Ripgrep } from "../../src/file/ripgrep" import { Format } from "../../src/format" diff --git a/packages/opencode/test/storage/storage.test.ts b/packages/opencode/test/storage/storage.test.ts index ea8f1feb4..60b458bb3 100644 --- a/packages/opencode/test/storage/storage.test.ts +++ b/packages/opencode/test/storage/storage.test.ts @@ -1,7 +1,7 @@ import { describe, expect } from "bun:test" import path from "path" import { Effect, Exit, Layer } from "effect" -import { AppFileSystem } from "../../src/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner" import { Git } from "../../src/git" import { Global } from "../../src/global" diff --git a/packages/opencode/test/tool/apply_patch.test.ts b/packages/opencode/test/tool/apply_patch.test.ts index 03220ea3b..c0448c78c 100644 --- a/packages/opencode/test/tool/apply_patch.test.ts +++ b/packages/opencode/test/tool/apply_patch.test.ts @@ -5,7 +5,7 @@ import { Effect, ManagedRuntime, Layer } from "effect" import { ApplyPatchTool } from "../../src/tool/apply_patch" import { Instance } from "../../src/project/instance" import { LSP } from "../../src/lsp" -import { AppFileSystem } from "../../src/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { Format } from "../../src/format" import { Agent } from "../../src/agent/agent" import { Bus } from "../../src/bus" diff --git a/packages/opencode/test/tool/bash.test.ts b/packages/opencode/test/tool/bash.test.ts index fc7a9e73e..3b03da57e 100644 --- a/packages/opencode/test/tool/bash.test.ts +++ b/packages/opencode/test/tool/bash.test.ts @@ -12,7 +12,7 @@ import { Agent } from "../../src/agent/agent" import { Truncate } from "../../src/tool/truncate" import { SessionID, MessageID } from "../../src/session/schema" import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner" -import { AppFileSystem } from "../../src/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { Plugin } from "../../src/plugin" const runtime = ManagedRuntime.make( diff --git a/packages/opencode/test/tool/edit.test.ts b/packages/opencode/test/tool/edit.test.ts index 9fe24b49b..37a19a5fd 100644 --- a/packages/opencode/test/tool/edit.test.ts +++ b/packages/opencode/test/tool/edit.test.ts @@ -7,7 +7,7 @@ import { Instance } from "../../src/project/instance" import { tmpdir } from "../fixture/fixture" import { FileTime } from "../../src/file/time" import { LSP } from "../../src/lsp" -import { AppFileSystem } from "../../src/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { Format } from "../../src/format" import { Agent } from "../../src/agent/agent" import { Bus } from "../../src/bus" diff --git a/packages/opencode/test/tool/glob.test.ts b/packages/opencode/test/tool/glob.test.ts index 092885ed1..20e761fc1 100644 --- a/packages/opencode/test/tool/glob.test.ts +++ b/packages/opencode/test/tool/glob.test.ts @@ -5,7 +5,7 @@ import { GlobTool } from "../../src/tool/glob" import { SessionID, MessageID } from "../../src/session/schema" import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner" import { Ripgrep } from "../../src/file/ripgrep" -import { AppFileSystem } from "../../src/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { Truncate } from "../../src/tool/truncate" import { Agent } from "../../src/agent/agent" import { provideTmpdirInstance } from "../fixture/fixture" diff --git a/packages/opencode/test/tool/grep.test.ts b/packages/opencode/test/tool/grep.test.ts index 7cdf6a0aa..35467aeab 100644 --- a/packages/opencode/test/tool/grep.test.ts +++ b/packages/opencode/test/tool/grep.test.ts @@ -8,7 +8,7 @@ import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner" import { Truncate } from "../../src/tool/truncate" import { Agent } from "../../src/agent/agent" import { Ripgrep } from "../../src/file/ripgrep" -import { AppFileSystem } from "../../src/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { testEffect } from "../lib/effect" const it = testEffect( diff --git a/packages/opencode/test/tool/read.test.ts b/packages/opencode/test/tool/read.test.ts index 2064193d5..f14ec3310 100644 --- a/packages/opencode/test/tool/read.test.ts +++ b/packages/opencode/test/tool/read.test.ts @@ -3,7 +3,7 @@ import { Cause, Effect, Exit, Layer } from "effect" import path from "path" import { Agent } from "../../src/agent/agent" import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner" -import { AppFileSystem } from "../../src/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { FileTime } from "../../src/file/time" import { LSP } from "../../src/lsp" import { Permission } from "../../src/permission" diff --git a/packages/opencode/test/tool/write.test.ts b/packages/opencode/test/tool/write.test.ts index f7daa1e97..e83ec2efd 100644 --- a/packages/opencode/test/tool/write.test.ts +++ b/packages/opencode/test/tool/write.test.ts @@ -5,7 +5,7 @@ import fs from "fs/promises" import { WriteTool } from "../../src/tool/write" import { Instance } from "../../src/project/instance" import { LSP } from "../../src/lsp" -import { AppFileSystem } from "../../src/filesystem" +import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { FileTime } from "../../src/file/time" import { Bus } from "../../src/bus" import { Format } from "../../src/format" diff --git a/packages/opencode/test/util/glob.test.ts b/packages/opencode/test/util/glob.test.ts index e58d92c85..e982d5194 100644 --- a/packages/opencode/test/util/glob.test.ts +++ b/packages/opencode/test/util/glob.test.ts @@ -1,7 +1,7 @@ import { describe, test, expect } from "bun:test" import path from "path" import fs from "fs/promises" -import { Glob } from "../../src/util/glob" +import { Glob } from "@opencode-ai/shared/util/glob" import { tmpdir } from "../fixture/fixture" describe("Glob", () => { diff --git a/packages/opencode/test/util/module.test.ts b/packages/opencode/test/util/module.test.ts index 738b4a785..6f8539bfb 100644 --- a/packages/opencode/test/util/module.test.ts +++ b/packages/opencode/test/util/module.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test" import path from "path" -import { Module } from "@opencode-ai/util/module" +import { Module } from "@opencode-ai/shared/util/module" import { Filesystem } from "../../src/util/filesystem" import { tmpdir } from "../fixture/fixture" diff --git a/packages/shared/package.json b/packages/shared/package.json new file mode 100644 index 000000000..1bb1ca47e --- /dev/null +++ b/packages/shared/package.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://json.schemastore.org/package.json", + "version": "1.4.6", + "name": "@opencode-ai/shared", + "type": "module", + "license": "MIT", + "private": true, + "scripts": {}, + "bin": { + "opencode": "./bin/opencode" + }, + "exports": { + "./*": "./src/*.ts" + }, + "imports": {}, + "devDependencies": { + "@types/semver": "catalog:" + }, + "dependencies": { + "@effect/platform-node": "catalog:", + "@npmcli/arborist": "catalog:", + "effect": "catalog:", + "mime-types": "3.0.2", + "minimatch": "10.2.5", + "semver": "catalog:", + "zod": "catalog:" + }, + "overrides": { + "drizzle-orm": "catalog:" + } +} diff --git a/packages/shared/src/filesystem.ts b/packages/shared/src/filesystem.ts new file mode 100644 index 000000000..44346be8f --- /dev/null +++ b/packages/shared/src/filesystem.ts @@ -0,0 +1,236 @@ +import { NodeFileSystem } from "@effect/platform-node" +import { dirname, join, relative, resolve as pathResolve } from "path" +import { realpathSync } from "fs" +import * as NFS from "fs/promises" +import { lookup } from "mime-types" +import { Effect, FileSystem, Layer, Schema, Context } from "effect" +import type { PlatformError } from "effect/PlatformError" +import { Glob } from "./util/glob" + +export namespace AppFileSystem { + export class FileSystemError extends Schema.TaggedErrorClass()("FileSystemError", { + method: Schema.String, + cause: Schema.optional(Schema.Defect), + }) {} + + export type Error = PlatformError | FileSystemError + + export interface DirEntry { + readonly name: string + readonly type: "file" | "directory" | "symlink" | "other" + } + + export interface Interface extends FileSystem.FileSystem { + readonly isDir: (path: string) => Effect.Effect + readonly isFile: (path: string) => Effect.Effect + readonly existsSafe: (path: string) => Effect.Effect + readonly readJson: (path: string) => Effect.Effect + readonly writeJson: (path: string, data: unknown, mode?: number) => Effect.Effect + readonly ensureDir: (path: string) => Effect.Effect + readonly writeWithDirs: (path: string, content: string | Uint8Array, mode?: number) => Effect.Effect + readonly readDirectoryEntries: (path: string) => Effect.Effect + readonly findUp: (target: string, start: string, stop?: string) => Effect.Effect + readonly up: (options: { targets: string[]; start: string; stop?: string }) => Effect.Effect + readonly globUp: (pattern: string, start: string, stop?: string) => Effect.Effect + readonly glob: (pattern: string, options?: Glob.Options) => Effect.Effect + readonly globMatch: (pattern: string, filepath: string) => boolean + } + + export class Service extends Context.Service()("@opencode/FileSystem") {} + + export const layer = Layer.effect( + Service, + Effect.gen(function* () { + const fs = yield* FileSystem.FileSystem + + const existsSafe = Effect.fn("FileSystem.existsSafe")(function* (path: string) { + return yield* fs.exists(path).pipe(Effect.orElseSucceed(() => false)) + }) + + const isDir = Effect.fn("FileSystem.isDir")(function* (path: string) { + const info = yield* fs.stat(path).pipe(Effect.catch(() => Effect.void)) + return info?.type === "Directory" + }) + + const isFile = Effect.fn("FileSystem.isFile")(function* (path: string) { + const info = yield* fs.stat(path).pipe(Effect.catch(() => Effect.void)) + return info?.type === "File" + }) + + const readDirectoryEntries = Effect.fn("FileSystem.readDirectoryEntries")(function* (dirPath: string) { + return yield* Effect.tryPromise({ + try: async () => { + const entries = await NFS.readdir(dirPath, { withFileTypes: true }) + return entries.map( + (e): DirEntry => ({ + name: e.name, + type: e.isDirectory() ? "directory" : e.isSymbolicLink() ? "symlink" : e.isFile() ? "file" : "other", + }), + ) + }, + catch: (cause) => new FileSystemError({ method: "readDirectoryEntries", cause }), + }) + }) + + const readJson = Effect.fn("FileSystem.readJson")(function* (path: string) { + const text = yield* fs.readFileString(path) + return JSON.parse(text) + }) + + const writeJson = Effect.fn("FileSystem.writeJson")(function* (path: string, data: unknown, mode?: number) { + const content = JSON.stringify(data, null, 2) + yield* fs.writeFileString(path, content) + if (mode) yield* fs.chmod(path, mode) + }) + + const ensureDir = Effect.fn("FileSystem.ensureDir")(function* (path: string) { + yield* fs.makeDirectory(path, { recursive: true }) + }) + + const writeWithDirs = Effect.fn("FileSystem.writeWithDirs")(function* ( + path: string, + content: string | Uint8Array, + mode?: number, + ) { + const write = typeof content === "string" ? fs.writeFileString(path, content) : fs.writeFile(path, content) + + yield* write.pipe( + Effect.catchIf( + (e) => e.reason._tag === "NotFound", + () => + Effect.gen(function* () { + yield* fs.makeDirectory(dirname(path), { recursive: true }) + yield* write + }), + ), + ) + if (mode) yield* fs.chmod(path, mode) + }) + + const glob = Effect.fn("FileSystem.glob")(function* (pattern: string, options?: Glob.Options) { + return yield* Effect.tryPromise({ + try: () => Glob.scan(pattern, options), + catch: (cause) => new FileSystemError({ method: "glob", cause }), + }) + }) + + const findUp = Effect.fn("FileSystem.findUp")(function* (target: string, start: string, stop?: string) { + const result: string[] = [] + let current = start + while (true) { + const search = join(current, target) + if (yield* fs.exists(search)) result.push(search) + if (stop === current) break + const parent = dirname(current) + if (parent === current) break + current = parent + } + return result + }) + + const up = Effect.fn("FileSystem.up")(function* (options: { targets: string[]; start: string; stop?: string }) { + const result: string[] = [] + let current = options.start + while (true) { + for (const target of options.targets) { + const search = join(current, target) + if (yield* fs.exists(search)) result.push(search) + } + if (options.stop === current) break + const parent = dirname(current) + if (parent === current) break + current = parent + } + return result + }) + + const globUp = Effect.fn("FileSystem.globUp")(function* (pattern: string, start: string, stop?: string) { + const result: string[] = [] + let current = start + while (true) { + const matches = yield* glob(pattern, { cwd: current, absolute: true, include: "file", dot: true }).pipe( + Effect.catch(() => Effect.succeed([] as string[])), + ) + result.push(...matches) + if (stop === current) break + const parent = dirname(current) + if (parent === current) break + current = parent + } + return result + }) + + return Service.of({ + ...fs, + existsSafe, + isDir, + isFile, + readDirectoryEntries, + readJson, + writeJson, + ensureDir, + writeWithDirs, + findUp, + up, + globUp, + glob, + globMatch: Glob.match, + }) + }), + ) + + export const defaultLayer = layer.pipe(Layer.provide(NodeFileSystem.layer)) + + // Pure helpers that don't need Effect (path manipulation, sync operations) + export function mimeType(p: string): string { + return lookup(p) || "application/octet-stream" + } + + export function normalizePath(p: string): string { + if (process.platform !== "win32") return p + const resolved = pathResolve(windowsPath(p)) + try { + return realpathSync.native(resolved) + } catch { + return resolved + } + } + + export function normalizePathPattern(p: string): string { + if (process.platform !== "win32") return p + if (p === "*") return p + const match = p.match(/^(.*)[\\/]\*$/) + if (!match) return normalizePath(p) + const dir = /^[A-Za-z]:$/.test(match[1]) ? match[1] + "\\" : match[1] + return join(normalizePath(dir), "*") + } + + export function resolve(p: string): string { + const resolved = pathResolve(windowsPath(p)) + try { + return normalizePath(realpathSync(resolved)) + } catch (e: any) { + if (e?.code === "ENOENT") return normalizePath(resolved) + throw e + } + } + + export function windowsPath(p: string): string { + if (process.platform !== "win32") return p + return p + .replace(/^\/([a-zA-Z]):(?:[\\/]|$)/, (_, drive) => `${drive.toUpperCase()}:/`) + .replace(/^\/([a-zA-Z])(?:\/|$)/, (_, drive) => `${drive.toUpperCase()}:/`) + .replace(/^\/cygdrive\/([a-zA-Z])(?:\/|$)/, (_, drive) => `${drive.toUpperCase()}:/`) + .replace(/^\/mnt\/([a-zA-Z])(?:\/|$)/, (_, drive) => `${drive.toUpperCase()}:/`) + } + + export function overlaps(a: string, b: string) { + const relA = relative(a, b) + const relB = relative(b, a) + return !relA || !relA.startsWith("..") || !relB || !relB.startsWith("..") + } + + export function contains(parent: string, child: string) { + return !relative(parent, child).startsWith("..") + } +} diff --git a/packages/shared/src/util/array.ts b/packages/shared/src/util/array.ts new file mode 100644 index 000000000..1fb8ac69e --- /dev/null +++ b/packages/shared/src/util/array.ts @@ -0,0 +1,10 @@ +export function findLast( + items: readonly T[], + predicate: (item: T, index: number, items: readonly T[]) => boolean, +): T | undefined { + for (let i = items.length - 1; i >= 0; i -= 1) { + const item = items[i] + if (predicate(item, i, items)) return item + } + return undefined +} diff --git a/packages/shared/src/util/binary.ts b/packages/shared/src/util/binary.ts new file mode 100644 index 000000000..3d8f61851 --- /dev/null +++ b/packages/shared/src/util/binary.ts @@ -0,0 +1,41 @@ +export namespace Binary { + export function search(array: T[], id: string, compare: (item: T) => string): { found: boolean; index: number } { + let left = 0 + let right = array.length - 1 + + while (left <= right) { + const mid = Math.floor((left + right) / 2) + const midId = compare(array[mid]) + + if (midId === id) { + return { found: true, index: mid } + } else if (midId < id) { + left = mid + 1 + } else { + right = mid - 1 + } + } + + return { found: false, index: left } + } + + export function insert(array: T[], item: T, compare: (item: T) => string): T[] { + const id = compare(item) + let left = 0 + let right = array.length + + while (left < right) { + const mid = Math.floor((left + right) / 2) + const midId = compare(array[mid]) + + if (midId < id) { + left = mid + 1 + } else { + right = mid + } + } + + array.splice(left, 0, item) + return array + } +} diff --git a/packages/shared/src/util/encode.ts b/packages/shared/src/util/encode.ts new file mode 100644 index 000000000..e4c6e70ac --- /dev/null +++ b/packages/shared/src/util/encode.ts @@ -0,0 +1,51 @@ +export function base64Encode(value: string) { + const bytes = new TextEncoder().encode(value) + const binary = Array.from(bytes, (b) => String.fromCharCode(b)).join("") + return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "") +} + +export function base64Decode(value: string) { + const binary = atob(value.replace(/-/g, "+").replace(/_/g, "/")) + const bytes = Uint8Array.from(binary, (c) => c.charCodeAt(0)) + return new TextDecoder().decode(bytes) +} + +export async function hash(content: string, algorithm = "SHA-256"): Promise { + const encoder = new TextEncoder() + const data = encoder.encode(content) + const hashBuffer = await crypto.subtle.digest(algorithm, data) + const hashArray = Array.from(new Uint8Array(hashBuffer)) + const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("") + return hashHex +} + +export function checksum(content: string): string | undefined { + if (!content) return undefined + let hash = 0x811c9dc5 + for (let i = 0; i < content.length; i++) { + hash ^= content.charCodeAt(i) + hash = Math.imul(hash, 0x01000193) + } + return (hash >>> 0).toString(36) +} + +export function sampledChecksum(content: string, limit = 500_000): string | undefined { + if (!content) return undefined + if (content.length <= limit) return checksum(content) + + const size = 4096 + const points = [ + 0, + Math.floor(content.length * 0.25), + Math.floor(content.length * 0.5), + Math.floor(content.length * 0.75), + content.length - size, + ] + const hashes = points + .map((point) => { + const start = Math.max(0, Math.min(content.length - size, point - Math.floor(size / 2))) + return checksum(content.slice(start, start + size)) ?? "" + }) + .join(":") + return `${content.length}:${hashes}` +} diff --git a/packages/shared/src/util/error.ts b/packages/shared/src/util/error.ts new file mode 100644 index 000000000..12c27a0a7 --- /dev/null +++ b/packages/shared/src/util/error.ts @@ -0,0 +1,54 @@ +import z from "zod" + +export abstract class NamedError extends Error { + abstract schema(): z.core.$ZodType + abstract toObject(): { name: string; data: any } + + static create(name: Name, data: Data) { + const schema = z + .object({ + name: z.literal(name), + data, + }) + .meta({ + ref: name, + }) + const result = class extends NamedError { + public static readonly Schema = schema + + public override readonly name = name as Name + + constructor( + public readonly data: z.input, + options?: ErrorOptions, + ) { + super(name, options) + this.name = name + } + + static isInstance(input: any): input is InstanceType { + return typeof input === "object" && "name" in input && input.name === name + } + + schema() { + return schema + } + + toObject() { + return { + name: name, + data: this.data, + } + } + } + Object.defineProperty(result, "name", { value: name }) + return result + } + + public static readonly Unknown = NamedError.create( + "UnknownError", + z.object({ + message: z.string(), + }), + ) +} diff --git a/packages/shared/src/util/fn.ts b/packages/shared/src/util/fn.ts new file mode 100644 index 000000000..9efe4622f --- /dev/null +++ b/packages/shared/src/util/fn.ts @@ -0,0 +1,11 @@ +import { z } from "zod" + +export function fn(schema: T, cb: (input: z.infer) => Result) { + const result = (input: z.infer) => { + const parsed = schema.parse(input) + return cb(parsed) + } + result.force = (input: z.infer) => cb(input) + result.schema = schema + return result +} diff --git a/packages/shared/src/util/glob.ts b/packages/shared/src/util/glob.ts new file mode 100644 index 000000000..febf062da --- /dev/null +++ b/packages/shared/src/util/glob.ts @@ -0,0 +1,34 @@ +import { glob, globSync, type GlobOptions } from "glob" +import { minimatch } from "minimatch" + +export namespace Glob { + export interface Options { + cwd?: string + absolute?: boolean + include?: "file" | "all" + dot?: boolean + symlink?: boolean + } + + function toGlobOptions(options: Options): GlobOptions { + return { + cwd: options.cwd, + absolute: options.absolute, + dot: options.dot, + follow: options.symlink ?? false, + nodir: options.include !== "all", + } + } + + export async function scan(pattern: string, options: Options = {}): Promise { + return glob(pattern, toGlobOptions(options)) as Promise + } + + export function scanSync(pattern: string, options: Options = {}): string[] { + return globSync(pattern, toGlobOptions(options)) as string[] + } + + export function match(pattern: string, filepath: string): boolean { + return minimatch(filepath, pattern, { dot: true }) + } +} diff --git a/packages/shared/src/util/identifier.ts b/packages/shared/src/util/identifier.ts new file mode 100644 index 000000000..ba28a351b --- /dev/null +++ b/packages/shared/src/util/identifier.ts @@ -0,0 +1,48 @@ +import { randomBytes } from "crypto" + +export namespace Identifier { + const LENGTH = 26 + + // State for monotonic ID generation + let lastTimestamp = 0 + let counter = 0 + + export function ascending() { + return create(false) + } + + export function descending() { + return create(true) + } + + function randomBase62(length: number): string { + const chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + let result = "" + const bytes = randomBytes(length) + for (let i = 0; i < length; i++) { + result += chars[bytes[i] % 62] + } + return result + } + + export function create(descending: boolean, timestamp?: number): string { + const currentTimestamp = timestamp ?? Date.now() + + if (currentTimestamp !== lastTimestamp) { + lastTimestamp = currentTimestamp + counter = 0 + } + counter++ + + let now = BigInt(currentTimestamp) * BigInt(0x1000) + BigInt(counter) + + now = descending ? ~now : now + + const timeBytes = Buffer.alloc(6) + for (let i = 0; i < 6; i++) { + timeBytes[i] = Number((now >> BigInt(40 - 8 * i)) & BigInt(0xff)) + } + + return timeBytes.toString("hex") + randomBase62(LENGTH - 12) + } +} diff --git a/packages/shared/src/util/iife.ts b/packages/shared/src/util/iife.ts new file mode 100644 index 000000000..ca9ae6c10 --- /dev/null +++ b/packages/shared/src/util/iife.ts @@ -0,0 +1,3 @@ +export function iife(fn: () => T) { + return fn() +} diff --git a/packages/shared/src/util/lazy.ts b/packages/shared/src/util/lazy.ts new file mode 100644 index 000000000..935ebe0f9 --- /dev/null +++ b/packages/shared/src/util/lazy.ts @@ -0,0 +1,11 @@ +export function lazy(fn: () => T) { + let value: T | undefined + let loaded = false + + return (): T => { + if (loaded) return value as T + loaded = true + value = fn() + return value as T + } +} diff --git a/packages/shared/src/util/module.ts b/packages/shared/src/util/module.ts new file mode 100644 index 000000000..6ed3b23d7 --- /dev/null +++ b/packages/shared/src/util/module.ts @@ -0,0 +1,10 @@ +import { createRequire } from "node:module" +import path from "node:path" + +export namespace Module { + export function resolve(id: string, dir: string) { + try { + return createRequire(path.join(dir, "package.json")).resolve(id) + } catch {} + } +} diff --git a/packages/shared/src/util/path.ts b/packages/shared/src/util/path.ts new file mode 100644 index 000000000..bb191f512 --- /dev/null +++ b/packages/shared/src/util/path.ts @@ -0,0 +1,37 @@ +export function getFilename(path: string | undefined) { + if (!path) return "" + const trimmed = path.replace(/[\/\\]+$/, "") + const parts = trimmed.split(/[\/\\]/) + return parts[parts.length - 1] ?? "" +} + +export function getDirectory(path: string | undefined) { + if (!path) return "" + const trimmed = path.replace(/[\/\\]+$/, "") + const parts = trimmed.split(/[\/\\]/) + return parts.slice(0, parts.length - 1).join("/") + "/" +} + +export function getFileExtension(path: string | undefined) { + if (!path) return "" + const parts = path.split(".") + return parts[parts.length - 1] +} + +export function getFilenameTruncated(path: string | undefined, maxLength: number = 20) { + const filename = getFilename(path) + if (filename.length <= maxLength) return filename + const lastDot = filename.lastIndexOf(".") + const ext = lastDot <= 0 ? "" : filename.slice(lastDot) + const available = maxLength - ext.length - 1 // -1 for ellipsis + if (available <= 0) return filename.slice(0, maxLength - 1) + "…" + return filename.slice(0, available) + "…" + ext +} + +export function truncateMiddle(text: string, maxLength: number = 20) { + if (text.length <= maxLength) return text + const available = maxLength - 1 // -1 for ellipsis + const start = Math.ceil(available / 2) + const end = Math.floor(available / 2) + return text.slice(0, start) + "…" + text.slice(-end) +} diff --git a/packages/shared/src/util/retry.ts b/packages/shared/src/util/retry.ts new file mode 100644 index 000000000..0014a604c --- /dev/null +++ b/packages/shared/src/util/retry.ts @@ -0,0 +1,41 @@ +export interface RetryOptions { + attempts?: number + delay?: number + factor?: number + maxDelay?: number + retryIf?: (error: unknown) => boolean +} + +const TRANSIENT_MESSAGES = [ + "load failed", + "network connection was lost", + "network request failed", + "failed to fetch", + "econnreset", + "econnrefused", + "etimedout", + "socket hang up", +] + +function isTransientError(error: unknown): boolean { + if (!error) return false + const message = String(error instanceof Error ? error.message : error).toLowerCase() + return TRANSIENT_MESSAGES.some((m) => message.includes(m)) +} + +export async function retry(fn: () => Promise, options: RetryOptions = {}): Promise { + const { attempts = 3, delay = 500, factor = 2, maxDelay = 10000, retryIf = isTransientError } = options + + let lastError: unknown + for (let attempt = 0; attempt < attempts; attempt++) { + try { + return await fn() + } catch (error) { + lastError = error + if (attempt === attempts - 1 || !retryIf(error)) throw error + const wait = Math.min(delay * Math.pow(factor, attempt), maxDelay) + await new Promise((resolve) => setTimeout(resolve, wait)) + } + } + throw lastError +} diff --git a/packages/shared/src/util/slug.ts b/packages/shared/src/util/slug.ts new file mode 100644 index 000000000..62cf0e57b --- /dev/null +++ b/packages/shared/src/util/slug.ts @@ -0,0 +1,74 @@ +export namespace Slug { + const ADJECTIVES = [ + "brave", + "calm", + "clever", + "cosmic", + "crisp", + "curious", + "eager", + "gentle", + "glowing", + "happy", + "hidden", + "jolly", + "kind", + "lucky", + "mighty", + "misty", + "neon", + "nimble", + "playful", + "proud", + "quick", + "quiet", + "shiny", + "silent", + "stellar", + "sunny", + "swift", + "tidy", + "witty", + ] as const + + const NOUNS = [ + "cabin", + "cactus", + "canyon", + "circuit", + "comet", + "eagle", + "engine", + "falcon", + "forest", + "garden", + "harbor", + "island", + "knight", + "lagoon", + "meadow", + "moon", + "mountain", + "nebula", + "orchid", + "otter", + "panda", + "pixel", + "planet", + "river", + "rocket", + "sailor", + "squid", + "star", + "tiger", + "wizard", + "wolf", + ] as const + + export function create() { + return [ + ADJECTIVES[Math.floor(Math.random() * ADJECTIVES.length)], + NOUNS[Math.floor(Math.random() * NOUNS.length)], + ].join("-") + } +} diff --git a/packages/shared/tsconfig.json b/packages/shared/tsconfig.json new file mode 100644 index 000000000..ff9886313 --- /dev/null +++ b/packages/shared/tsconfig.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@tsconfig/bun/tsconfig.json", + "compilerOptions": { + "jsx": "preserve", + "jsxImportSource": "@opentui/solid", + "lib": ["ESNext", "DOM", "DOM.Iterable"], + "types": [], + "noUncheckedIndexedAccess": false, + "customConditions": ["browser"], + "paths": { + "@/*": ["./src/*"], + "@tui/*": ["./src/cli/cmd/tui/*"] + }, + "plugins": [ + { + "name": "@effect/language-service", + "transform": "@effect/language-service/transform", + "namespaceImportPackages": ["effect", "@effect/*"] + } + ] + } +} diff --git a/packages/ui/package.json b/packages/ui/package.json index e406ecf16..21974e3ec 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -44,7 +44,7 @@ "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", - "@opencode-ai/util": "workspace:*", + "@opencode-ai/shared": "workspace:*", "@pierre/diffs": "catalog:", "@shikijs/transformers": "3.9.2", "@solid-primitives/bounds": "0.1.3", diff --git a/packages/ui/src/components/file.tsx b/packages/ui/src/components/file.tsx index b78f0bae4..51c289273 100644 --- a/packages/ui/src/components/file.tsx +++ b/packages/ui/src/components/file.tsx @@ -1,4 +1,4 @@ -import { sampledChecksum } from "@opencode-ai/util/encode" +import { sampledChecksum } from "@opencode-ai/shared/util/encode" import { DEFAULT_VIRTUAL_FILE_METRICS, type DiffLineAnnotation, diff --git a/packages/ui/src/components/line-comment.tsx b/packages/ui/src/components/line-comment.tsx index 26e763bb3..e20da5a8d 100644 --- a/packages/ui/src/components/line-comment.tsx +++ b/packages/ui/src/components/line-comment.tsx @@ -1,5 +1,5 @@ import { useFilteredList } from "@opencode-ai/ui/hooks" -import { getDirectory, getFilename } from "@opencode-ai/util/path" +import { getDirectory, getFilename } from "@opencode-ai/shared/util/path" import { createSignal, For, onMount, Show, splitProps, type JSX } from "solid-js" import { Button } from "./button" import { FileIcon } from "./file-icon" diff --git a/packages/ui/src/components/markdown.tsx b/packages/ui/src/components/markdown.tsx index ceab10df9..f3037da8b 100644 --- a/packages/ui/src/components/markdown.tsx +++ b/packages/ui/src/components/markdown.tsx @@ -2,7 +2,7 @@ import { useMarked } from "../context/marked" import { useI18n } from "../context/i18n" import DOMPurify from "dompurify" import morphdom from "morphdom" -import { checksum } from "@opencode-ai/util/encode" +import { checksum } from "@opencode-ai/shared/util/encode" import { ComponentProps, createEffect, createResource, createSignal, onCleanup, splitProps } from "solid-js" import { isServer } from "solid-js/web" import { stream } from "./markdown-stream" diff --git a/packages/ui/src/components/message-part.tsx b/packages/ui/src/components/message-part.tsx index 02bd80ac9..48444cd01 100644 --- a/packages/ui/src/components/message-part.tsx +++ b/packages/ui/src/components/message-part.tsx @@ -46,8 +46,8 @@ import { Checkbox } from "./checkbox" import { DiffChanges } from "./diff-changes" import { Markdown } from "./markdown" import { ImagePreview } from "./image-preview" -import { getDirectory as _getDirectory, getFilename } from "@opencode-ai/util/path" -import { checksum } from "@opencode-ai/util/encode" +import { getDirectory as _getDirectory, getFilename } from "@opencode-ai/shared/util/path" +import { checksum } from "@opencode-ai/shared/util/encode" import { Tooltip } from "./tooltip" import { IconButton } from "./icon-button" import { Spinner } from "./spinner" diff --git a/packages/ui/src/components/session-review.tsx b/packages/ui/src/components/session-review.tsx index 3223f5d08..bb19d099e 100644 --- a/packages/ui/src/components/session-review.tsx +++ b/packages/ui/src/components/session-review.tsx @@ -11,8 +11,8 @@ import { Tooltip } from "./tooltip" import { ScrollView } from "./scroll-view" import { useFileComponent } from "../context/file" import { useI18n } from "../context/i18n" -import { getDirectory, getFilename } from "@opencode-ai/util/path" -import { checksum } from "@opencode-ai/util/encode" +import { getDirectory, getFilename } from "@opencode-ai/shared/util/path" +import { checksum } from "@opencode-ai/shared/util/encode" import { createEffect, createMemo, For, Match, onCleanup, Show, Switch, untrack, type JSX } from "solid-js" import { createStore } from "solid-js/store" import { type FileContent, type SnapshotFileDiff, type VcsFileDiff } from "@opencode-ai/sdk/v2" diff --git a/packages/ui/src/components/session-turn.tsx b/packages/ui/src/components/session-turn.tsx index e891a6feb..6d43a575a 100644 --- a/packages/ui/src/components/session-turn.tsx +++ b/packages/ui/src/components/session-turn.tsx @@ -8,8 +8,8 @@ import type { SessionStatus } from "@opencode-ai/sdk/v2" import { useData } from "../context" import { useFileComponent } from "../context/file" -import { Binary } from "@opencode-ai/util/binary" -import { getDirectory, getFilename } from "@opencode-ai/util/path" +import { Binary } from "@opencode-ai/shared/util/binary" +import { getDirectory, getFilename } from "@opencode-ai/shared/util/path" import { createEffect, createMemo, createSignal, For, on, ParentProps, Show } from "solid-js" import { createStore } from "solid-js/store" import { Dynamic } from "solid-js/web" diff --git a/packages/util/package.json b/packages/util/package.json deleted file mode 100644 index 35aaa9b7c..000000000 --- a/packages/util/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "@opencode-ai/util", - "version": "1.4.6", - "private": true, - "type": "module", - "license": "MIT", - "exports": { - "./*": "./src/*.ts" - }, - "scripts": { - "typecheck": "tsc --noEmit" - }, - "dependencies": { - "zod": "catalog:" - }, - "devDependencies": { - "typescript": "catalog:", - "@types/bun": "catalog:" - } -} diff --git a/packages/util/src/array.ts b/packages/util/src/array.ts deleted file mode 100644 index 1fb8ac69e..000000000 --- a/packages/util/src/array.ts +++ /dev/null @@ -1,10 +0,0 @@ -export function findLast( - items: readonly T[], - predicate: (item: T, index: number, items: readonly T[]) => boolean, -): T | undefined { - for (let i = items.length - 1; i >= 0; i -= 1) { - const item = items[i] - if (predicate(item, i, items)) return item - } - return undefined -} diff --git a/packages/util/src/binary.ts b/packages/util/src/binary.ts deleted file mode 100644 index 3d8f61851..000000000 --- a/packages/util/src/binary.ts +++ /dev/null @@ -1,41 +0,0 @@ -export namespace Binary { - export function search(array: T[], id: string, compare: (item: T) => string): { found: boolean; index: number } { - let left = 0 - let right = array.length - 1 - - while (left <= right) { - const mid = Math.floor((left + right) / 2) - const midId = compare(array[mid]) - - if (midId === id) { - return { found: true, index: mid } - } else if (midId < id) { - left = mid + 1 - } else { - right = mid - 1 - } - } - - return { found: false, index: left } - } - - export function insert(array: T[], item: T, compare: (item: T) => string): T[] { - const id = compare(item) - let left = 0 - let right = array.length - - while (left < right) { - const mid = Math.floor((left + right) / 2) - const midId = compare(array[mid]) - - if (midId < id) { - left = mid + 1 - } else { - right = mid - } - } - - array.splice(left, 0, item) - return array - } -} diff --git a/packages/util/src/encode.ts b/packages/util/src/encode.ts deleted file mode 100644 index e4c6e70ac..000000000 --- a/packages/util/src/encode.ts +++ /dev/null @@ -1,51 +0,0 @@ -export function base64Encode(value: string) { - const bytes = new TextEncoder().encode(value) - const binary = Array.from(bytes, (b) => String.fromCharCode(b)).join("") - return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "") -} - -export function base64Decode(value: string) { - const binary = atob(value.replace(/-/g, "+").replace(/_/g, "/")) - const bytes = Uint8Array.from(binary, (c) => c.charCodeAt(0)) - return new TextDecoder().decode(bytes) -} - -export async function hash(content: string, algorithm = "SHA-256"): Promise { - const encoder = new TextEncoder() - const data = encoder.encode(content) - const hashBuffer = await crypto.subtle.digest(algorithm, data) - const hashArray = Array.from(new Uint8Array(hashBuffer)) - const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("") - return hashHex -} - -export function checksum(content: string): string | undefined { - if (!content) return undefined - let hash = 0x811c9dc5 - for (let i = 0; i < content.length; i++) { - hash ^= content.charCodeAt(i) - hash = Math.imul(hash, 0x01000193) - } - return (hash >>> 0).toString(36) -} - -export function sampledChecksum(content: string, limit = 500_000): string | undefined { - if (!content) return undefined - if (content.length <= limit) return checksum(content) - - const size = 4096 - const points = [ - 0, - Math.floor(content.length * 0.25), - Math.floor(content.length * 0.5), - Math.floor(content.length * 0.75), - content.length - size, - ] - const hashes = points - .map((point) => { - const start = Math.max(0, Math.min(content.length - size, point - Math.floor(size / 2))) - return checksum(content.slice(start, start + size)) ?? "" - }) - .join(":") - return `${content.length}:${hashes}` -} diff --git a/packages/util/src/error.ts b/packages/util/src/error.ts deleted file mode 100644 index 12c27a0a7..000000000 --- a/packages/util/src/error.ts +++ /dev/null @@ -1,54 +0,0 @@ -import z from "zod" - -export abstract class NamedError extends Error { - abstract schema(): z.core.$ZodType - abstract toObject(): { name: string; data: any } - - static create(name: Name, data: Data) { - const schema = z - .object({ - name: z.literal(name), - data, - }) - .meta({ - ref: name, - }) - const result = class extends NamedError { - public static readonly Schema = schema - - public override readonly name = name as Name - - constructor( - public readonly data: z.input, - options?: ErrorOptions, - ) { - super(name, options) - this.name = name - } - - static isInstance(input: any): input is InstanceType { - return typeof input === "object" && "name" in input && input.name === name - } - - schema() { - return schema - } - - toObject() { - return { - name: name, - data: this.data, - } - } - } - Object.defineProperty(result, "name", { value: name }) - return result - } - - public static readonly Unknown = NamedError.create( - "UnknownError", - z.object({ - message: z.string(), - }), - ) -} diff --git a/packages/util/src/fn.ts b/packages/util/src/fn.ts deleted file mode 100644 index 9efe4622f..000000000 --- a/packages/util/src/fn.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { z } from "zod" - -export function fn(schema: T, cb: (input: z.infer) => Result) { - const result = (input: z.infer) => { - const parsed = schema.parse(input) - return cb(parsed) - } - result.force = (input: z.infer) => cb(input) - result.schema = schema - return result -} diff --git a/packages/util/src/identifier.ts b/packages/util/src/identifier.ts deleted file mode 100644 index ba28a351b..000000000 --- a/packages/util/src/identifier.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { randomBytes } from "crypto" - -export namespace Identifier { - const LENGTH = 26 - - // State for monotonic ID generation - let lastTimestamp = 0 - let counter = 0 - - export function ascending() { - return create(false) - } - - export function descending() { - return create(true) - } - - function randomBase62(length: number): string { - const chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" - let result = "" - const bytes = randomBytes(length) - for (let i = 0; i < length; i++) { - result += chars[bytes[i] % 62] - } - return result - } - - export function create(descending: boolean, timestamp?: number): string { - const currentTimestamp = timestamp ?? Date.now() - - if (currentTimestamp !== lastTimestamp) { - lastTimestamp = currentTimestamp - counter = 0 - } - counter++ - - let now = BigInt(currentTimestamp) * BigInt(0x1000) + BigInt(counter) - - now = descending ? ~now : now - - const timeBytes = Buffer.alloc(6) - for (let i = 0; i < 6; i++) { - timeBytes[i] = Number((now >> BigInt(40 - 8 * i)) & BigInt(0xff)) - } - - return timeBytes.toString("hex") + randomBase62(LENGTH - 12) - } -} diff --git a/packages/util/src/iife.ts b/packages/util/src/iife.ts deleted file mode 100644 index ca9ae6c10..000000000 --- a/packages/util/src/iife.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function iife(fn: () => T) { - return fn() -} diff --git a/packages/util/src/lazy.ts b/packages/util/src/lazy.ts deleted file mode 100644 index 935ebe0f9..000000000 --- a/packages/util/src/lazy.ts +++ /dev/null @@ -1,11 +0,0 @@ -export function lazy(fn: () => T) { - let value: T | undefined - let loaded = false - - return (): T => { - if (loaded) return value as T - loaded = true - value = fn() - return value as T - } -} diff --git a/packages/util/src/module.ts b/packages/util/src/module.ts deleted file mode 100644 index 6ed3b23d7..000000000 --- a/packages/util/src/module.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { createRequire } from "node:module" -import path from "node:path" - -export namespace Module { - export function resolve(id: string, dir: string) { - try { - return createRequire(path.join(dir, "package.json")).resolve(id) - } catch {} - } -} diff --git a/packages/util/src/path.ts b/packages/util/src/path.ts deleted file mode 100644 index bb191f512..000000000 --- a/packages/util/src/path.ts +++ /dev/null @@ -1,37 +0,0 @@ -export function getFilename(path: string | undefined) { - if (!path) return "" - const trimmed = path.replace(/[\/\\]+$/, "") - const parts = trimmed.split(/[\/\\]/) - return parts[parts.length - 1] ?? "" -} - -export function getDirectory(path: string | undefined) { - if (!path) return "" - const trimmed = path.replace(/[\/\\]+$/, "") - const parts = trimmed.split(/[\/\\]/) - return parts.slice(0, parts.length - 1).join("/") + "/" -} - -export function getFileExtension(path: string | undefined) { - if (!path) return "" - const parts = path.split(".") - return parts[parts.length - 1] -} - -export function getFilenameTruncated(path: string | undefined, maxLength: number = 20) { - const filename = getFilename(path) - if (filename.length <= maxLength) return filename - const lastDot = filename.lastIndexOf(".") - const ext = lastDot <= 0 ? "" : filename.slice(lastDot) - const available = maxLength - ext.length - 1 // -1 for ellipsis - if (available <= 0) return filename.slice(0, maxLength - 1) + "…" - return filename.slice(0, available) + "…" + ext -} - -export function truncateMiddle(text: string, maxLength: number = 20) { - if (text.length <= maxLength) return text - const available = maxLength - 1 // -1 for ellipsis - const start = Math.ceil(available / 2) - const end = Math.floor(available / 2) - return text.slice(0, start) + "…" + text.slice(-end) -} diff --git a/packages/util/src/retry.ts b/packages/util/src/retry.ts deleted file mode 100644 index 0014a604c..000000000 --- a/packages/util/src/retry.ts +++ /dev/null @@ -1,41 +0,0 @@ -export interface RetryOptions { - attempts?: number - delay?: number - factor?: number - maxDelay?: number - retryIf?: (error: unknown) => boolean -} - -const TRANSIENT_MESSAGES = [ - "load failed", - "network connection was lost", - "network request failed", - "failed to fetch", - "econnreset", - "econnrefused", - "etimedout", - "socket hang up", -] - -function isTransientError(error: unknown): boolean { - if (!error) return false - const message = String(error instanceof Error ? error.message : error).toLowerCase() - return TRANSIENT_MESSAGES.some((m) => message.includes(m)) -} - -export async function retry(fn: () => Promise, options: RetryOptions = {}): Promise { - const { attempts = 3, delay = 500, factor = 2, maxDelay = 10000, retryIf = isTransientError } = options - - let lastError: unknown - for (let attempt = 0; attempt < attempts; attempt++) { - try { - return await fn() - } catch (error) { - lastError = error - if (attempt === attempts - 1 || !retryIf(error)) throw error - const wait = Math.min(delay * Math.pow(factor, attempt), maxDelay) - await new Promise((resolve) => setTimeout(resolve, wait)) - } - } - throw lastError -} diff --git a/packages/util/src/slug.ts b/packages/util/src/slug.ts deleted file mode 100644 index 62cf0e57b..000000000 --- a/packages/util/src/slug.ts +++ /dev/null @@ -1,74 +0,0 @@ -export namespace Slug { - const ADJECTIVES = [ - "brave", - "calm", - "clever", - "cosmic", - "crisp", - "curious", - "eager", - "gentle", - "glowing", - "happy", - "hidden", - "jolly", - "kind", - "lucky", - "mighty", - "misty", - "neon", - "nimble", - "playful", - "proud", - "quick", - "quiet", - "shiny", - "silent", - "stellar", - "sunny", - "swift", - "tidy", - "witty", - ] as const - - const NOUNS = [ - "cabin", - "cactus", - "canyon", - "circuit", - "comet", - "eagle", - "engine", - "falcon", - "forest", - "garden", - "harbor", - "island", - "knight", - "lagoon", - "meadow", - "moon", - "mountain", - "nebula", - "orchid", - "otter", - "panda", - "pixel", - "planet", - "river", - "rocket", - "sailor", - "squid", - "star", - "tiger", - "wizard", - "wolf", - ] as const - - export function create() { - return [ - ADJECTIVES[Math.floor(Math.random() * ADJECTIVES.length)], - NOUNS[Math.floor(Math.random() * NOUNS.length)], - ].join("-") - } -} diff --git a/packages/util/sst-env.d.ts b/packages/util/sst-env.d.ts deleted file mode 100644 index 64441936d..000000000 --- a/packages/util/sst-env.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* This file is auto-generated by SST. Do not edit. */ -/* tslint:disable */ -/* eslint-disable */ -/* deno-fmt-ignore-file */ -/* biome-ignore-all lint: auto-generated */ - -/// - -import "sst" -export {} \ No newline at end of file diff --git a/packages/util/tsconfig.json b/packages/util/tsconfig.json deleted file mode 100644 index 528dcd91d..000000000 --- a/packages/util/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "module": "ESNext", - "moduleResolution": "bundler", - "skipLibCheck": true, - "allowSyntheticDefaultImports": true, - "esModuleInterop": true, - "allowJs": true, - "noEmit": true, - "strict": true, - "isolatedModules": true - } -} -- cgit v1.2.3 From 3d6f90cb536ec30ff5091e1cbe3b1e619a93e1b0 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Wed, 15 Apr 2026 20:45:19 -0400 Subject: feat: add oxlint with correctness defaults (#22682) --- .oxlintrc.json | 10 ++++++ bun.lock | 41 ++++++++++++++++++++++ package.json | 2 ++ packages/app/src/components/file-tree.tsx | 2 +- packages/app/src/components/terminal.tsx | 2 +- .../app/src/context/global-sync/child-store.ts | 4 +-- packages/app/src/context/layout.tsx | 4 +-- .../console/app/src/routes/zen/util/handler.ts | 2 +- packages/console/core/src/key.ts | 8 ++--- packages/desktop-electron/src/main/apps.ts | 2 +- packages/desktop-electron/src/main/shell-env.ts | 2 +- packages/opencode/script/build.ts | 4 +-- packages/opencode/src/agent/agent.ts | 2 +- packages/opencode/src/cli/cmd/providers.ts | 4 +-- packages/opencode/src/config/tui.ts | 2 +- packages/opencode/src/lsp/launch.ts | 2 +- packages/opencode/src/plugin/cloudflare.ts | 6 ++-- packages/opencode/src/plugin/meta.ts | 2 +- packages/opencode/src/provider/provider.ts | 4 +-- packages/opencode/src/server/instance/session.ts | 2 +- packages/opencode/src/session/prompt.ts | 2 +- packages/opencode/src/tool/bash.ts | 2 +- packages/opencode/test/cli/tui/theme-store.test.ts | 2 +- .../opencode/test/plugin/loader-shared.test.ts | 10 +++--- .../opencode/test/plugin/workspace-adaptor.test.ts | 2 +- packages/shared/src/util/path.ts | 8 ++--- packages/ui/src/components/accordion.tsx | 10 +++--- packages/ui/src/components/app-icon.tsx | 2 +- packages/ui/src/components/avatar.tsx | 2 +- packages/ui/src/components/button.tsx | 2 +- packages/ui/src/components/card.tsx | 8 ++--- packages/ui/src/components/collapsible.tsx | 2 +- packages/ui/src/components/context-menu.tsx | 32 ++++++++--------- packages/ui/src/components/dialog.tsx | 2 +- packages/ui/src/components/dock-surface.tsx | 6 ++-- packages/ui/src/components/dropdown-menu.tsx | 32 ++++++++--------- packages/ui/src/components/file-icon.tsx | 2 +- packages/ui/src/components/file-ssr.tsx | 4 +-- packages/ui/src/components/file.tsx | 2 +- packages/ui/src/components/hover-card.tsx | 2 +- packages/ui/src/components/icon-button.tsx | 2 +- packages/ui/src/components/icon.tsx | 2 +- packages/ui/src/components/keybind.tsx | 2 +- packages/ui/src/components/markdown.tsx | 4 +-- packages/ui/src/components/popover.tsx | 2 +- packages/ui/src/components/progress-circle.tsx | 2 +- packages/ui/src/components/progress.tsx | 2 +- packages/ui/src/components/provider-icon.tsx | 2 +- packages/ui/src/components/radio-group.tsx | 2 +- packages/ui/src/components/resize-handle.tsx | 2 +- packages/ui/src/components/select.tsx | 6 ++-- packages/ui/src/components/session-turn.tsx | 2 +- packages/ui/src/components/spinner.tsx | 2 +- .../ui/src/components/sticky-accordion-header.tsx | 2 +- packages/ui/src/components/tabs.tsx | 8 ++--- packages/ui/src/components/tag.tsx | 2 +- packages/ui/src/components/toast.tsx | 2 +- 57 files changed, 165 insertions(+), 122 deletions(-) create mode 100644 .oxlintrc.json (limited to 'packages/app/src/context/global-sync') diff --git a/.oxlintrc.json b/.oxlintrc.json new file mode 100644 index 000000000..0875f3832 --- /dev/null +++ b/.oxlintrc.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://raw.githubusercontent.com/nicolo-ribaudo/oxc-project.github.io/refs/heads/json-schema/src/public/.oxlintrc.schema.json", + "rules": { + // Effect uses `function*` with Effect.gen/Effect.fnUntraced that don't always yield + "require-yield": "off", + // SolidJS uses `let ref: T | undefined` for JSX ref bindings assigned at runtime + "no-unassigned-vars": "off" + }, + "ignorePatterns": ["**/node_modules", "**/dist", "**/.build", "**/.sst", "**/*.d.ts"] +} diff --git a/bun.lock b/bun.lock index aeab042cf..48243e652 100644 --- a/bun.lock +++ b/bun.lock @@ -19,6 +19,7 @@ "@typescript/native-preview": "catalog:", "glob": "13.0.5", "husky": "9.1.7", + "oxlint": "1.60.0", "prettier": "3.6.2", "semver": "^7.6.0", "sst": "3.18.10", @@ -1693,6 +1694,44 @@ "@oxc-transform/binding-win32-x64-msvc": ["@oxc-transform/binding-win32-x64-msvc@0.96.0", "", { "os": "win32", "cpu": "x64" }, "sha512-0fI0P0W7bSO/GCP/N5dkmtB9vBqCA4ggo1WmXTnxNJVmFFOtcA1vYm1I9jl8fxo+sucW2WnlpnI4fjKdo3JKxA=="], + "@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.60.0", "", { "os": "android", "cpu": "arm" }, "sha512-YdeJKaZckDQL1qa62a1aKq/goyq48aX3yOxaaWqWb4sau4Ee4IiLbamftNLU3zbePky6QsDj6thnSSzHRBjDfA=="], + + "@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.60.0", "", { "os": "android", "cpu": "arm64" }, "sha512-7ANS7PpXCfq84xZQ8E5WPs14gwcuPcl+/8TFNXfpSu0CQBXz3cUo2fDpHT8v8HJN+Ut02eacvMAzTnc9s6X4tw=="], + + "@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.60.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-pJsgd9AfplLGBm1fIr25V6V14vMrayhx4uIQvlfH7jWs2SZwSrvi3TfgfJySB8T+hvyEH8K2zXljQiUnkgUnfQ=="], + + "@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.60.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-Ue1aXHX49ivwflKqGJc7zcd/LeLgbhaTcDCQStgx5x06AXgjEAZmvrlMuIkWd4AL4FHQe6QJ9f33z04Cg448VQ=="], + + "@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.60.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-YCyQzsQtusQw+gNRW9rRTifSO+Dt/+dtCl2NHoDMZqJlRTEZ/Oht9YnuporI9yiTx7+cB+eqzX3MtHHVHGIWhg=="], + + "@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.60.0", "", { "os": "linux", "cpu": "arm" }, "sha512-c7dxM2Zksa45Qw16i2iGY3Fti2NirJ38FrsBsKw+qcJ0OtqTsBgKJLF0xV+yLG56UH01Z8WRPgsw31e0MoRoGQ=="], + + "@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.60.0", "", { "os": "linux", "cpu": "arm" }, "sha512-ZWALoA42UYqBEP1Tbw9OWURgFGS1nWj2AAvLdY6ZcGx/Gj93qVCBKjcvwXMupZibYwFbi9s/rzqkZseb/6gVtQ=="], + + "@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.60.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-tpy+1w4p9hN5CicMCxqNy6ymfRtV5ayE573vFNjp1k1TN/qhLFgflveZoE/0++RlkHikBz2vY545NWm/hp7big=="], + + "@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.60.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-eDYDXZGhQAXyn6GwtwiX/qcLS0HlOLPJ/+iiIY8RYr+3P8oKBmgKxADLlniL6FtWfE7pPk7IGN9/xvDEvDvFeg=="], + + "@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.60.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-nxehly5XYBHUWI9VJX1bqCf9j/B43DaK/aS/T1fcxCpX3PA4Rm9BB54nPD1CKayT8xg6REN1ao+01hSRNgy8OA=="], + + "@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.60.0", "", { "os": "linux", "cpu": "none" }, "sha512-j1qf/NaUfOWQutjeoooNG1Q0zsK0XGmSu1uDLq3cctquRF3j7t9Hxqf/76ehCc5GEUAanth2W4Fa+XT1RFg/nw=="], + + "@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.60.0", "", { "os": "linux", "cpu": "none" }, "sha512-YELKPRefQ/q/h3RUmeRfPCUhh2wBvgV1RyZ/F9M9u8cDyXsQW2ojv1DeWQTt466yczDITjZnIOg/s05pk7Ve2A=="], + + "@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.60.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-JkO3C6Gki7Y6h/MiIkFKvHFOz98/YWvQ4WYbK9DLXACMP2rjULzkeGyAzorJE5S1dzLQGFgeqvN779kSFwoV1g=="], + + "@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.60.0", "", { "os": "linux", "cpu": "x64" }, "sha512-XjKHdFVCpZZZSWBCKyyqCq65s2AKXykMXkjLoKYODrD+f5toLhlwsMESscu8FbgnJQ4Y/dpR/zdazsahmgBJIA=="], + + "@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.60.0", "", { "os": "linux", "cpu": "x64" }, "sha512-js29ZWIuPhNWzY8NC7KoffEMEeWG105vbmm+8EOJsC+T/jHBiKIJEUF78+F/IrgEWMMP9N0kRND4Pp75+xAhKg=="], + + "@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.60.0", "", { "os": "none", "cpu": "arm64" }, "sha512-H+PUITKHk04stFpWj3x3Kg08Afp/bcXSBi0EhasR5a0Vw7StXHTzdl655PUI0fB4qdh2Wsu6Dsi+3ACxPoyQnA=="], + + "@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.60.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-WA/yc7f7ZfCefBXVzNHn1Ztulb1EFwNBb4jMZ6pjML0zz6pHujlF3Q3jySluz3XHl/GNeMTntG1seUBWVMlMag=="], + + "@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.60.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-33YxL1sqwYNZXtn3MD/4dno6s0xeedXOJlT1WohkVD565WvohClZUr7vwKdAk954n4xiEWJkewiCr+zLeq7AeA=="], + + "@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.60.0", "", { "os": "win32", "cpu": "x64" }, "sha512-JOro4ZcfBLamJCyfURQmOQByoorgOdx3ZjAkSqnb/CyG/i+lN3KoV5LAgk5ZAW6DPq7/Cx7n23f8DuTWXTWgyQ=="], + "@pagefind/darwin-arm64": ["@pagefind/darwin-arm64@1.5.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-MXpI+7HsAdPkvJ0gk9xj9g541BCqBZOBbdwj9g6lB5LCj6kSV6nqDSjzcAJwvOsfu0fjwvC8hQU+ecfhp+MpiQ=="], "@pagefind/darwin-x64": ["@pagefind/darwin-x64@1.5.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-IojxFWMEJe0RQ7PQ3KXQsPIImNsbpPYpoZ+QUDrL8fAl/O27IX+LVLs74/UzEZy5uA2LD8Nz1AiwKr72vrkZQw=="], @@ -4073,6 +4112,8 @@ "oxc-transform": ["oxc-transform@0.96.0", "", { "optionalDependencies": { "@oxc-transform/binding-android-arm64": "0.96.0", "@oxc-transform/binding-darwin-arm64": "0.96.0", "@oxc-transform/binding-darwin-x64": "0.96.0", "@oxc-transform/binding-freebsd-x64": "0.96.0", "@oxc-transform/binding-linux-arm-gnueabihf": "0.96.0", "@oxc-transform/binding-linux-arm-musleabihf": "0.96.0", "@oxc-transform/binding-linux-arm64-gnu": "0.96.0", "@oxc-transform/binding-linux-arm64-musl": "0.96.0", "@oxc-transform/binding-linux-riscv64-gnu": "0.96.0", "@oxc-transform/binding-linux-s390x-gnu": "0.96.0", "@oxc-transform/binding-linux-x64-gnu": "0.96.0", "@oxc-transform/binding-linux-x64-musl": "0.96.0", "@oxc-transform/binding-wasm32-wasi": "0.96.0", "@oxc-transform/binding-win32-arm64-msvc": "0.96.0", "@oxc-transform/binding-win32-x64-msvc": "0.96.0" } }, "sha512-dQPNIF+gHpSkmC0+Vg9IktNyhcn28Y8R3eTLyzn52UNymkasLicl3sFAtz7oEVuFmCpgGjaUTKkwk+jW2cHpDQ=="], + "oxlint": ["oxlint@1.60.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.60.0", "@oxlint/binding-android-arm64": "1.60.0", "@oxlint/binding-darwin-arm64": "1.60.0", "@oxlint/binding-darwin-x64": "1.60.0", "@oxlint/binding-freebsd-x64": "1.60.0", "@oxlint/binding-linux-arm-gnueabihf": "1.60.0", "@oxlint/binding-linux-arm-musleabihf": "1.60.0", "@oxlint/binding-linux-arm64-gnu": "1.60.0", "@oxlint/binding-linux-arm64-musl": "1.60.0", "@oxlint/binding-linux-ppc64-gnu": "1.60.0", "@oxlint/binding-linux-riscv64-gnu": "1.60.0", "@oxlint/binding-linux-riscv64-musl": "1.60.0", "@oxlint/binding-linux-s390x-gnu": "1.60.0", "@oxlint/binding-linux-x64-gnu": "1.60.0", "@oxlint/binding-linux-x64-musl": "1.60.0", "@oxlint/binding-openharmony-arm64": "1.60.0", "@oxlint/binding-win32-arm64-msvc": "1.60.0", "@oxlint/binding-win32-ia32-msvc": "1.60.0", "@oxlint/binding-win32-x64-msvc": "1.60.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.18.0" }, "optionalPeers": ["oxlint-tsgolint"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-tnRzTWiWJ9pg3ftRWnD0+Oqh78L6ZSwcEudvCZaER0PIqiAnNyXj5N1dPwjmNpDalkKS9m/WMLN1CTPUBPmsgw=="], + "p-cancelable": ["p-cancelable@2.1.1", "", {}, "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg=="], "p-defer": ["p-defer@3.0.0", "", {}, "sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw=="], diff --git a/package.json b/package.json index abe1b5d36..8c5ae9195 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "dev:web": "bun --cwd packages/app dev", "dev:console": "ulimit -n 10240 2>/dev/null; bun run --cwd packages/console/app dev", "dev:storybook": "bun --cwd packages/storybook storybook", + "lint": "oxlint", "typecheck": "bun turbo typecheck", "postinstall": "bun run --cwd packages/opencode fix-node-pty", "prepare": "husky", @@ -85,6 +86,7 @@ "@typescript/native-preview": "catalog:", "glob": "13.0.5", "husky": "9.1.7", + "oxlint": "1.60.0", "prettier": "3.6.2", "semver": "^7.6.0", "sst": "3.18.10", diff --git a/packages/app/src/components/file-tree.tsx b/packages/app/src/components/file-tree.tsx index 930832fb6..8fbecf671 100644 --- a/packages/app/src/components/file-tree.tsx +++ b/packages/app/src/components/file-tree.tsx @@ -149,7 +149,7 @@ const FileTreeNode = ( classList={{ "w-full min-w-0 h-6 flex items-center justify-start gap-x-1.5 rounded-md px-1.5 py-0 text-left hover:bg-surface-raised-base-hover active:bg-surface-base-active transition-colors cursor-pointer": true, "bg-surface-base-active": local.node.path === local.active, - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, [local.nodeClass ?? ""]: !!local.nodeClass, }} diff --git a/packages/app/src/components/terminal.tsx b/packages/app/src/components/terminal.tsx index 96a865b9e..9b7ef83b2 100644 --- a/packages/app/src/components/terminal.tsx +++ b/packages/app/src/components/terminal.tsx @@ -634,7 +634,7 @@ export const Terminal = (props: TerminalProps) => { tabIndex={-1} style={{ "background-color": terminalColors().background }} classList={{ - ...(local.classList ?? {}), + ...local.classList, "select-text": true, "size-full px-6 py-3 font-mono relative overflow-hidden": true, [local.class ?? ""]: !!local.class, diff --git a/packages/app/src/context/global-sync/child-store.ts b/packages/app/src/context/global-sync/child-store.ts index 5678491f8..3fe67e4fb 100644 --- a/packages/app/src/context/global-sync/child-store.ts +++ b/packages/app/src/context/global-sync/child-store.ts @@ -243,8 +243,8 @@ export function createChildStoreManager(input: { const cached = metaCache.get(directory) if (!cached) return const previous = store.projectMeta ?? {} - const icon = patch.icon ? { ...(previous.icon ?? {}), ...patch.icon } : previous.icon - const commands = patch.commands ? { ...(previous.commands ?? {}), ...patch.commands } : previous.commands + const icon = patch.icon ? { ...previous.icon, ...patch.icon } : previous.icon + const commands = patch.commands ? { ...previous.commands, ...patch.commands } : previous.commands const next = { ...previous, ...patch, diff --git a/packages/app/src/context/layout.tsx b/packages/app/src/context/layout.tsx index bab3d39f3..87f11d2b6 100644 --- a/packages/app/src/context/layout.tsx +++ b/packages/app/src/context/layout.tsx @@ -344,7 +344,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext( return } - setStore("sessionView", sessionKey, "scroll", (prev) => ({ ...(prev ?? {}), ...next })) + setStore("sessionView", sessionKey, "scroll", (prev) => ({ ...prev, ...next })) prune(keep) }, }) @@ -399,7 +399,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext( local?.icon?.color !== undefined const base = { - ...(metadata ?? {}), + ...metadata, ...project, icon: { url: metadata?.icon?.url, diff --git a/packages/console/app/src/routes/zen/util/handler.ts b/packages/console/app/src/routes/zen/util/handler.ts index 58df61809..358d8736c 100644 --- a/packages/console/app/src/routes/zen/util/handler.ts +++ b/packages/console/app/src/routes/zen/util/handler.ts @@ -144,7 +144,7 @@ export async function handler( providerInfo.modifyBody({ ...createBodyConverter(opts.format, providerInfo.format)(body), model: providerInfo.model, - ...(providerInfo.payloadModifier ?? {}), + ...providerInfo.payloadModifier, ...Object.fromEntries( Object.entries(providerInfo.payloadMappings ?? {}) .map(([k, v]) => [k, input.request.headers.get(v)]) diff --git a/packages/console/core/src/key.ts b/packages/console/core/src/key.ts index 688f19b3d..d1aae1524 100644 --- a/packages/console/core/src/key.ts +++ b/packages/console/core/src/key.ts @@ -24,11 +24,9 @@ export namespace Key { .innerJoin(AuthTable, and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email"))) .where( and( - ...[ - eq(KeyTable.workspaceID, Actor.workspace()), + eq(KeyTable.workspaceID, Actor.workspace()), isNull(KeyTable.timeDeleted), ...(Actor.userRole() === "admin" ? [] : [eq(KeyTable.userID, Actor.userID())]), - ], ), ) .orderBy(sql`${KeyTable.name} DESC`), @@ -84,11 +82,9 @@ export namespace Key { }) .where( and( - ...[ - eq(KeyTable.id, input.id), + eq(KeyTable.id, input.id), eq(KeyTable.workspaceID, Actor.workspace()), ...(Actor.userRole() === "admin" ? [] : [eq(KeyTable.userID, Actor.userID())]), - ], ), ), ) diff --git a/packages/desktop-electron/src/main/apps.ts b/packages/desktop-electron/src/main/apps.ts index 2b4603789..d21b6cc9e 100644 --- a/packages/desktop-electron/src/main/apps.ts +++ b/packages/desktop-electron/src/main/apps.ts @@ -20,7 +20,7 @@ export function wslPath(path: string, mode: "windows" | "linux" | null): string try { if (path.startsWith("~")) { const suffix = path.slice(1) - const cmd = `wslpath ${flag} \"$HOME${suffix.replace(/\"/g, '\\"')}\"` + const cmd = `wslpath ${flag} "$HOME${suffix.replace(/"/g, '\\"')}"` const output = execFileSync("wsl", ["-e", "sh", "-lc", cmd]) return output.toString().trim() } diff --git a/packages/desktop-electron/src/main/shell-env.ts b/packages/desktop-electron/src/main/shell-env.ts index 8453a5730..f57677323 100644 --- a/packages/desktop-electron/src/main/shell-env.ts +++ b/packages/desktop-electron/src/main/shell-env.ts @@ -82,7 +82,7 @@ export function loadShellEnv(shell: string) { export function mergeShellEnv(shell: Record | null, env: Record) { return { - ...(shell || {}), + ...shell, ...env, } } diff --git a/packages/opencode/script/build.ts b/packages/opencode/script/build.ts index 6d1087f28..d2628974f 100755 --- a/packages/opencode/script/build.ts +++ b/packages/opencode/script/build.ts @@ -211,9 +211,7 @@ for (const item of targets) { execArgv: [`--user-agent=opencode/${Script.version}`, "--use-system-ca", "--"], windows: {}, }, - files: { - ...(embeddedFileMap ? { "opencode-web-ui.gen.ts": embeddedFileMap } : {}), - }, + files: (embeddedFileMap ? { "opencode-web-ui.gen.ts": embeddedFileMap } : {}), entrypoints: [ "./src/index.ts", parserWorker, diff --git a/packages/opencode/src/agent/agent.ts b/packages/opencode/src/agent/agent.ts index 8857696b0..ba38c8efe 100644 --- a/packages/opencode/src/agent/agent.ts +++ b/packages/opencode/src/agent/agent.ts @@ -368,7 +368,7 @@ export namespace Agent { )), { role: "user", - content: `Create an agent configuration based on this request: \"${input.description}\".\n\nIMPORTANT: The following identifiers already exist and must NOT be used: ${existing.map((i) => i.name).join(", ")}\n Return ONLY the JSON object, no other text, do not wrap in backticks`, + content: `Create an agent configuration based on this request: "${input.description}".\n\nIMPORTANT: The following identifiers already exist and must NOT be used: ${existing.map((i) => i.name).join(", ")}\n Return ONLY the JSON object, no other text, do not wrap in backticks`, }, ], model: language, diff --git a/packages/opencode/src/cli/cmd/providers.ts b/packages/opencode/src/cli/cmd/providers.ts index d2afbabfb..06f9fdf1d 100644 --- a/packages/opencode/src/cli/cmd/providers.ts +++ b/packages/opencode/src/cli/cmd/providers.ts @@ -40,12 +40,10 @@ async function handlePluginAuth(plugin: { auth: PluginAuth }, provider: string, } else if (plugin.auth.methods.length > 1) { const method = await prompts.select({ message: "Login method", - options: [ - ...plugin.auth.methods.map((x, index) => ({ + options: plugin.auth.methods.map((x, index) => ({ label: x.label, value: index.toString(), })), - ], }) if (prompts.isCancel(method)) throw new UI.CancelledError() index = parseInt(method) diff --git a/packages/opencode/src/config/tui.ts b/packages/opencode/src/config/tui.ts index 12bd7e0da..e64b226c1 100644 --- a/packages/opencode/src/config/tui.ts +++ b/packages/opencode/src/config/tui.ts @@ -125,7 +125,7 @@ export namespace TuiConfig { } } - const keybinds = { ...(acc.result.keybinds ?? {}) } + const keybinds = { ...acc.result.keybinds } if (process.platform === "win32") { // Native Windows terminals do not support POSIX suspend, so prefer prompt undo. keybinds.terminal_suspend = "none" diff --git a/packages/opencode/src/lsp/launch.ts b/packages/opencode/src/lsp/launch.ts index b7dca446f..51a7c209b 100644 --- a/packages/opencode/src/lsp/launch.ts +++ b/packages/opencode/src/lsp/launch.ts @@ -9,7 +9,7 @@ export function spawn(cmd: string, argsOrOpts?: string[] | Process.Options, opts const args = Array.isArray(argsOrOpts) ? [...argsOrOpts] : [] const cfg = Array.isArray(argsOrOpts) ? opts : argsOrOpts const proc = Process.spawn([cmd, ...args], { - ...(cfg ?? {}), + ...cfg, stdin: "pipe", stdout: "pipe", stderr: "pipe", diff --git a/packages/opencode/src/plugin/cloudflare.ts b/packages/opencode/src/plugin/cloudflare.ts index e20a488a3..267d1ed2f 100644 --- a/packages/opencode/src/plugin/cloudflare.ts +++ b/packages/opencode/src/plugin/cloudflare.ts @@ -1,8 +1,7 @@ import type { Hooks, PluginInput } from "@opencode-ai/plugin" export async function CloudflareWorkersAuthPlugin(_input: PluginInput): Promise { - const prompts = [ - ...(!process.env.CLOUDFLARE_ACCOUNT_ID + const prompts = (!process.env.CLOUDFLARE_ACCOUNT_ID ? [ { type: "text" as const, @@ -11,8 +10,7 @@ export async function CloudflareWorkersAuthPlugin(_input: PluginInput): Promise< placeholder: "e.g. 1234567890abcdef1234567890abcdef", }, ] - : []), - ] + : []) return { auth: { diff --git a/packages/opencode/src/plugin/meta.ts b/packages/opencode/src/plugin/meta.ts index f40895469..3f02f543e 100644 --- a/packages/opencode/src/plugin/meta.ts +++ b/packages/opencode/src/plugin/meta.ts @@ -174,7 +174,7 @@ export namespace PluginMeta { const entry = store[id] if (!entry) return entry.themes = { - ...(entry.themes ?? {}), + ...entry.themes, [name]: theme, } await Filesystem.writeJson(file, store) diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index 9ec5dfc6b..c029e5c5c 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -551,13 +551,13 @@ export namespace Provider { const aiGatewayHeaders = { "User-Agent": `opencode/${Installation.VERSION} gitlab-ai-provider/${GITLAB_PROVIDER_VERSION} (${os.platform()} ${os.release()}; ${os.arch()})`, "anthropic-beta": "context-1m-2025-08-07", - ...(providerConfig?.options?.aiGatewayHeaders || {}), + ...providerConfig?.options?.aiGatewayHeaders, } const featureFlags = { duo_agent_platform_agentic_chat: true, duo_agent_platform: true, - ...(providerConfig?.options?.featureFlags || {}), + ...providerConfig?.options?.featureFlags, } return { diff --git a/packages/opencode/src/server/instance/session.ts b/packages/opencode/src/server/instance/session.ts index 0bce3085e..c606af854 100644 --- a/packages/opencode/src/server/instance/session.ts +++ b/packages/opencode/src/server/instance/session.ts @@ -695,7 +695,7 @@ export const SessionRoutes = lazy(() => url.searchParams.set("limit", query.limit.toString()) url.searchParams.set("before", page.cursor) c.header("Access-Control-Expose-Headers", "Link, X-Next-Cursor") - c.header("Link", `<${url.toString()}>; rel=\"next\"`) + c.header("Link", `<${url.toString()}>; rel="next"`) c.header("X-Next-Cursor", page.cursor) } return c.json(page.items) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index ffd074d3f..f2a160e26 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -497,7 +497,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the const truncated = yield* truncate.output(textParts.join("\n\n"), {}, input.agent) const metadata = { - ...(result.metadata ?? {}), + ...result.metadata, truncated: truncated.truncated, ...(truncated.truncated && { outputPath: truncated.outputPath }), } diff --git a/packages/opencode/src/tool/bash.ts b/packages/opencode/src/tool/bash.ts index 3bb936944..7a124dada 100644 --- a/packages/opencode/src/tool/bash.ts +++ b/packages/opencode/src/tool/bash.ts @@ -176,7 +176,7 @@ function dynamic(text: string, ps: boolean) { } function prefix(text: string) { - const match = /[?*\[]/.exec(text) + const match = /[?*[]/.exec(text) if (!match) return text if (match.index === 0) return return text.slice(0, match.index) diff --git a/packages/opencode/test/cli/tui/theme-store.test.ts b/packages/opencode/test/cli/tui/theme-store.test.ts index 936e3e6f7..9ebfc4320 100644 --- a/packages/opencode/test/cli/tui/theme-store.test.ts +++ b/packages/opencode/test/cli/tui/theme-store.test.ts @@ -41,7 +41,7 @@ test("hasTheme checks theme presence", () => { test("resolveTheme rejects circular color refs", () => { const item = structuredClone(DEFAULT_THEMES.opencode) item.defs = { - ...(item.defs ?? {}), + ...item.defs, one: "two", two: "one", } diff --git a/packages/opencode/test/plugin/loader-shared.test.ts b/packages/opencode/test/plugin/loader-shared.test.ts index 5f1e2b168..4265e83c5 100644 --- a/packages/opencode/test/plugin/loader-shared.test.ts +++ b/packages/opencode/test/plugin/loader-shared.test.ts @@ -48,7 +48,7 @@ describe("plugin.loader.shared", () => { file, [ "export default async () => {", - ` await Bun.write(${JSON.stringify(mark)}, \"called\")`, + ` await Bun.write(${JSON.stringify(mark)}, "called")`, " return {}", "}", "", @@ -78,8 +78,8 @@ describe("plugin.loader.shared", () => { file, [ "const run = async () => {", - ` const text = await Bun.file(${JSON.stringify(mark)}).text().catch(() => \"\")`, - ` await Bun.write(${JSON.stringify(mark)}, text + \"1\")`, + ` const text = await Bun.file(${JSON.stringify(mark)}).text().catch(() => "")`, + ` await Bun.write(${JSON.stringify(mark)}, text + "1")`, " return {}", "}", "export default run", @@ -715,7 +715,7 @@ describe("plugin.loader.shared", () => { "const plugin = {", ' id: "demo.object",', " server: async () => {", - ` await Bun.write(${JSON.stringify(mark)}, \"called\")`, + ` await Bun.write(${JSON.stringify(mark)}, "called")`, " return {}", " },", "}", @@ -833,7 +833,7 @@ export default { "export default {", ' id: "demo.pure",', " server: async () => {", - ` await Bun.write(${JSON.stringify(mark)}, \"called\")`, + ` await Bun.write(${JSON.stringify(mark)}, "called")`, " return {}", " },", "}", diff --git a/packages/opencode/test/plugin/workspace-adaptor.test.ts b/packages/opencode/test/plugin/workspace-adaptor.test.ts index a5f56df5e..669a822a2 100644 --- a/packages/opencode/test/plugin/workspace-adaptor.test.ts +++ b/packages/opencode/test/plugin/workspace-adaptor.test.ts @@ -39,7 +39,7 @@ describe("plugin.workspace", () => { ' name: "plug",', ' description: "plugin workspace adaptor",', " configure(input) {", - ` return { ...input, name: \"plug\", branch: \"plug/main\", directory: ${JSON.stringify(space)} }`, + ` return { ...input, name: "plug", branch: "plug/main", directory: ${JSON.stringify(space)} }`, " },", " async create(input) {", ` await Bun.write(${JSON.stringify(mark)}, JSON.stringify(input))`, diff --git a/packages/shared/src/util/path.ts b/packages/shared/src/util/path.ts index bb191f512..b87316358 100644 --- a/packages/shared/src/util/path.ts +++ b/packages/shared/src/util/path.ts @@ -1,14 +1,14 @@ export function getFilename(path: string | undefined) { if (!path) return "" - const trimmed = path.replace(/[\/\\]+$/, "") - const parts = trimmed.split(/[\/\\]/) + const trimmed = path.replace(/[/\\]+$/, "") + const parts = trimmed.split(/[/\\]/) return parts[parts.length - 1] ?? "" } export function getDirectory(path: string | undefined) { if (!path) return "" - const trimmed = path.replace(/[\/\\]+$/, "") - const parts = trimmed.split(/[\/\\]/) + const trimmed = path.replace(/[/\\]+$/, "") + const parts = trimmed.split(/[/\\]/) return parts.slice(0, parts.length - 1).join("/") + "/" } diff --git a/packages/ui/src/components/accordion.tsx b/packages/ui/src/components/accordion.tsx index 535d38e3d..3179b8a15 100644 --- a/packages/ui/src/components/accordion.tsx +++ b/packages/ui/src/components/accordion.tsx @@ -15,7 +15,7 @@ function AccordionRoot(props: AccordionProps) { {...rest} data-component="accordion" classList={{ - ...(split.classList ?? {}), + ...split.classList, [split.class ?? ""]: !!split.class, }} /> @@ -29,7 +29,7 @@ function AccordionItem(props: AccordionItemProps) { {...rest} data-slot="accordion-item" classList={{ - ...(split.classList ?? {}), + ...split.classList, [split.class ?? ""]: !!split.class, }} /> @@ -43,7 +43,7 @@ function AccordionHeader(props: ParentProps) { {...rest} data-slot="accordion-header" classList={{ - ...(split.classList ?? {}), + ...split.classList, [split.class ?? ""]: !!split.class, }} > @@ -59,7 +59,7 @@ function AccordionTrigger(props: ParentProps) { {...rest} data-slot="accordion-trigger" classList={{ - ...(split.classList ?? {}), + ...split.classList, [split.class ?? ""]: !!split.class, }} > @@ -75,7 +75,7 @@ function AccordionContent(props: ParentProps) { {...rest} data-slot="accordion-content" classList={{ - ...(split.classList ?? {}), + ...split.classList, [split.class ?? ""]: !!split.class, }} > diff --git a/packages/ui/src/components/app-icon.tsx b/packages/ui/src/components/app-icon.tsx index f8b587ff2..541dfc570 100644 --- a/packages/ui/src/components/app-icon.tsx +++ b/packages/ui/src/components/app-icon.tsx @@ -77,7 +77,7 @@ export const AppIcon: Component = (props) => { alt={local.alt ?? ""} draggable={local.draggable ?? false} classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} /> diff --git a/packages/ui/src/components/avatar.tsx b/packages/ui/src/components/avatar.tsx index c1617b265..035c2d304 100644 --- a/packages/ui/src/components/avatar.tsx +++ b/packages/ui/src/components/avatar.tsx @@ -38,7 +38,7 @@ export function Avatar(props: AvatarProps) { data-size={split.size || "normal"} data-has-image={src ? "" : undefined} classList={{ - ...(split.classList ?? {}), + ...split.classList, [split.class ?? ""]: !!split.class, }} style={{ diff --git a/packages/ui/src/components/button.tsx b/packages/ui/src/components/button.tsx index 7f974b2f7..d1652145f 100644 --- a/packages/ui/src/components/button.tsx +++ b/packages/ui/src/components/button.tsx @@ -20,7 +20,7 @@ export function Button(props: ButtonProps) { data-variant={split.variant || "secondary"} data-icon={split.icon} classList={{ - ...(split.classList ?? {}), + ...split.classList, [split.class ?? ""]: !!split.class, }} > diff --git a/packages/ui/src/components/card.tsx b/packages/ui/src/components/card.tsx index 7a1bd5e45..320aba718 100644 --- a/packages/ui/src/components/card.tsx +++ b/packages/ui/src/components/card.tsx @@ -53,7 +53,7 @@ export function Card(props: CardProps) { data-variant={variant()} style={mix(split.style, accent())} classList={{ - ...(split.classList ?? {}), + ...split.classList, [split.class ?? ""]: !!split.class, }} > @@ -76,7 +76,7 @@ export function CardTitle(props: CardTitleProps) { {...rest} data-slot="card-title" classList={{ - ...(split.classList ?? {}), + ...split.classList, [split.class ?? ""]: !!split.class, }} > @@ -97,7 +97,7 @@ export function CardDescription(props: ComponentProps<"div">) { {...rest} data-slot="card-description" classList={{ - ...(split.classList ?? {}), + ...split.classList, [split.class ?? ""]: !!split.class, }} > @@ -113,7 +113,7 @@ export function CardActions(props: ComponentProps<"div">) { {...rest} data-slot="card-actions" classList={{ - ...(split.classList ?? {}), + ...split.classList, [split.class ?? ""]: !!split.class, }} > diff --git a/packages/ui/src/components/collapsible.tsx b/packages/ui/src/components/collapsible.tsx index 8b5cd825c..b2a603264 100644 --- a/packages/ui/src/components/collapsible.tsx +++ b/packages/ui/src/components/collapsible.tsx @@ -15,7 +15,7 @@ function CollapsibleRoot(props: CollapsibleProps) { data-component="collapsible" data-variant={local.variant || "normal"} classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} {...others} diff --git a/packages/ui/src/components/context-menu.tsx b/packages/ui/src/components/context-menu.tsx index afdaff7b8..f4566a17a 100644 --- a/packages/ui/src/components/context-menu.tsx +++ b/packages/ui/src/components/context-menu.tsx @@ -33,7 +33,7 @@ function ContextMenuTrigger(props: ParentProps) { {...rest} data-slot="context-menu-trigger" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > @@ -49,7 +49,7 @@ function ContextMenuIcon(props: ParentProps) { {...rest} data-slot="context-menu-icon" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > @@ -69,7 +69,7 @@ function ContextMenuContent(props: ParentProps) { {...rest} data-component="context-menu-content" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > @@ -85,7 +85,7 @@ function ContextMenuArrow(props: ContextMenuArrowProps) { {...rest} data-slot="context-menu-arrow" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} /> @@ -99,7 +99,7 @@ function ContextMenuSeparator(props: ContextMenuSeparatorProps) { {...rest} data-slot="context-menu-separator" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} /> @@ -113,7 +113,7 @@ function ContextMenuGroup(props: ParentProps) { {...rest} data-slot="context-menu-group" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > @@ -129,7 +129,7 @@ function ContextMenuGroupLabel(props: ParentProps) { {...rest} data-slot="context-menu-group-label" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > @@ -145,7 +145,7 @@ function ContextMenuItem(props: ParentProps) { {...rest} data-slot="context-menu-item" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > @@ -161,7 +161,7 @@ function ContextMenuItemLabel(props: ParentProps) { {...rest} data-slot="context-menu-item-label" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > @@ -177,7 +177,7 @@ function ContextMenuItemDescription(props: ParentProps @@ -193,7 +193,7 @@ function ContextMenuItemIndicator(props: ParentProps @@ -209,7 +209,7 @@ function ContextMenuRadioGroup(props: ParentProps) { {...rest} data-slot="context-menu-radio-group" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > @@ -225,7 +225,7 @@ function ContextMenuRadioItem(props: ParentProps) { {...rest} data-slot="context-menu-radio-item" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > @@ -241,7 +241,7 @@ function ContextMenuCheckboxItem(props: ParentProps @@ -261,7 +261,7 @@ function ContextMenuSubTrigger(props: ParentProps) { {...rest} data-slot="context-menu-sub-trigger" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > @@ -277,7 +277,7 @@ function ContextMenuSubContent(props: ParentProps) { {...rest} data-component="context-menu-sub-content" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > diff --git a/packages/ui/src/components/dialog.tsx b/packages/ui/src/components/dialog.tsx index ce7704f37..981e3f45d 100644 --- a/packages/ui/src/components/dialog.tsx +++ b/packages/ui/src/components/dialog.tsx @@ -28,7 +28,7 @@ export function Dialog(props: DialogProps) { data-slot="dialog-content" data-no-header={!props.title && !props.action ? "" : undefined} classList={{ - ...(props.classList ?? {}), + ...props.classList, [props.class ?? ""]: !!props.class, }} onOpenAutoFocus={(e) => { diff --git a/packages/ui/src/components/dock-surface.tsx b/packages/ui/src/components/dock-surface.tsx index 1c4af2ed5..06cf2a5eb 100644 --- a/packages/ui/src/components/dock-surface.tsx +++ b/packages/ui/src/components/dock-surface.tsx @@ -11,7 +11,7 @@ export function DockShell(props: ComponentProps<"div">) { {...rest} data-dock-surface="shell" classList={{ - ...(split.classList ?? {}), + ...split.classList, [split.class ?? ""]: !!split.class, }} > @@ -27,7 +27,7 @@ export function DockShellForm(props: ComponentProps<"form">) { {...rest} data-dock-surface="shell" classList={{ - ...(split.classList ?? {}), + ...split.classList, [split.class ?? ""]: !!split.class, }} > @@ -44,7 +44,7 @@ export function DockTray(props: DockTrayProps) { data-dock-surface="tray" data-dock-attach={split.attach || "none"} classList={{ - ...(split.classList ?? {}), + ...split.classList, [split.class ?? ""]: !!split.class, }} > diff --git a/packages/ui/src/components/dropdown-menu.tsx b/packages/ui/src/components/dropdown-menu.tsx index efb2b45ca..259cb791a 100644 --- a/packages/ui/src/components/dropdown-menu.tsx +++ b/packages/ui/src/components/dropdown-menu.tsx @@ -33,7 +33,7 @@ function DropdownMenuTrigger(props: ParentProps) { {...rest} data-slot="dropdown-menu-trigger" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > @@ -49,7 +49,7 @@ function DropdownMenuIcon(props: ParentProps) { {...rest} data-slot="dropdown-menu-icon" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > @@ -69,7 +69,7 @@ function DropdownMenuContent(props: ParentProps) { {...rest} data-component="dropdown-menu-content" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > @@ -85,7 +85,7 @@ function DropdownMenuArrow(props: DropdownMenuArrowProps) { {...rest} data-slot="dropdown-menu-arrow" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} /> @@ -99,7 +99,7 @@ function DropdownMenuSeparator(props: DropdownMenuSeparatorProps) { {...rest} data-slot="dropdown-menu-separator" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} /> @@ -113,7 +113,7 @@ function DropdownMenuGroup(props: ParentProps) { {...rest} data-slot="dropdown-menu-group" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > @@ -129,7 +129,7 @@ function DropdownMenuGroupLabel(props: ParentProps) {...rest} data-slot="dropdown-menu-group-label" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > @@ -145,7 +145,7 @@ function DropdownMenuItem(props: ParentProps) { {...rest} data-slot="dropdown-menu-item" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > @@ -161,7 +161,7 @@ function DropdownMenuItemLabel(props: ParentProps) { {...rest} data-slot="dropdown-menu-item-label" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > @@ -177,7 +177,7 @@ function DropdownMenuItemDescription(props: ParentProps @@ -193,7 +193,7 @@ function DropdownMenuItemIndicator(props: ParentProps @@ -209,7 +209,7 @@ function DropdownMenuRadioGroup(props: ParentProps) {...rest} data-slot="dropdown-menu-radio-group" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > @@ -225,7 +225,7 @@ function DropdownMenuRadioItem(props: ParentProps) { {...rest} data-slot="dropdown-menu-radio-item" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > @@ -241,7 +241,7 @@ function DropdownMenuCheckboxItem(props: ParentProps @@ -261,7 +261,7 @@ function DropdownMenuSubTrigger(props: ParentProps) {...rest} data-slot="dropdown-menu-sub-trigger" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > @@ -277,7 +277,7 @@ function DropdownMenuSubContent(props: ParentProps) {...rest} data-component="dropdown-menu-sub-content" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > diff --git a/packages/ui/src/components/file-icon.tsx b/packages/ui/src/components/file-icon.tsx index 133cb169c..d66ee1c25 100644 --- a/packages/ui/src/components/file-icon.tsx +++ b/packages/ui/src/components/file-icon.tsx @@ -18,7 +18,7 @@ export const FileIcon: Component = (props) => { data-component="file-icon" {...rest} classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > diff --git a/packages/ui/src/components/file-ssr.tsx b/packages/ui/src/components/file-ssr.tsx index fed5c8931..ad05555bd 100644 --- a/packages/ui/src/components/file-ssr.tsx +++ b/packages/ui/src/components/file-ssr.tsx @@ -99,7 +99,7 @@ function DiffSSRViewer(props: SSRDiffFileProps) { { ...createDefaultOptions(props.diffStyle), ...others, - ...(local.preloadedDiff.options ?? {}), + ...local.preloadedDiff.options, }, virtualizer, virtualMetrics, @@ -109,7 +109,7 @@ function DiffSSRViewer(props: SSRDiffFileProps) { { ...createDefaultOptions(props.diffStyle), ...others, - ...(local.preloadedDiff.options ?? {}), + ...local.preloadedDiff.options, }, workerPool, ) diff --git a/packages/ui/src/components/file.tsx b/packages/ui/src/components/file.tsx index 51c289273..fd902b2e0 100644 --- a/packages/ui/src/components/file.tsx +++ b/packages/ui/src/components/file.tsx @@ -655,7 +655,7 @@ function ViewerShell(props: { style={styleVariables} class="relative outline-none" classList={{ - ...(props.classList || {}), + ...props.classList, [props.class ?? ""]: !!props.class, }} ref={(el) => (props.viewer.wrapper = el)} diff --git a/packages/ui/src/components/hover-card.tsx b/packages/ui/src/components/hover-card.tsx index 8330375aa..4e6647313 100644 --- a/packages/ui/src/components/hover-card.tsx +++ b/packages/ui/src/components/hover-card.tsx @@ -20,7 +20,7 @@ export function HoverCard(props: HoverCardProps) { diff --git a/packages/ui/src/components/icon-button.tsx b/packages/ui/src/components/icon-button.tsx index 89ab00fcd..457283aa0 100644 --- a/packages/ui/src/components/icon-button.tsx +++ b/packages/ui/src/components/icon-button.tsx @@ -19,7 +19,7 @@ export function IconButton(props: ComponentProps<"button"> & IconButtonProps) { data-size={split.size || "normal"} data-variant={split.variant || "secondary"} classList={{ - ...(split.classList ?? {}), + ...split.classList, [split.class ?? ""]: !!split.class, }} > diff --git a/packages/ui/src/components/icon.tsx b/packages/ui/src/components/icon.tsx index e2eaf107a..08726d0ff 100644 --- a/packages/ui/src/components/icon.tsx +++ b/packages/ui/src/components/icon.tsx @@ -117,7 +117,7 @@ export function Icon(props: IconProps) { diff --git a/packages/ui/src/components/markdown.tsx b/packages/ui/src/components/markdown.tsx index f3037da8b..28653512e 100644 --- a/packages/ui/src/components/markdown.tsx +++ b/packages/ui/src/components/markdown.tsx @@ -50,7 +50,7 @@ function escape(text: string) { .replace(/&/g, "&") .replace(//g, ">") - .replace(/\"/g, """) + .replace(/"/g, """) .replace(/'/g, "'") } @@ -338,7 +338,7 @@ export function Markdown(
(props: PopoverProps ref={(el: HTMLElement | undefined) => setState("contentRef", el)} data-component="popover-content" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} style={local.style} diff --git a/packages/ui/src/components/progress-circle.tsx b/packages/ui/src/components/progress-circle.tsx index 02bd36bb7..992fb62e8 100644 --- a/packages/ui/src/components/progress-circle.tsx +++ b/packages/ui/src/components/progress-circle.tsx @@ -32,7 +32,7 @@ export function ProgressCircle(props: ProgressCircleProps) { fill="none" data-component="progress-circle" classList={{ - ...(split.classList ?? {}), + ...split.classList, [split.class ?? ""]: !!split.class, }} > diff --git a/packages/ui/src/components/progress.tsx b/packages/ui/src/components/progress.tsx index bfe10a1d1..7cbe5d6bc 100644 --- a/packages/ui/src/components/progress.tsx +++ b/packages/ui/src/components/progress.tsx @@ -15,7 +15,7 @@ export function Progress(props: ProgressProps) { {...others} data-component="progress" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > diff --git a/packages/ui/src/components/provider-icon.tsx b/packages/ui/src/components/provider-icon.tsx index edfdd0357..7c0eb3d04 100644 --- a/packages/ui/src/components/provider-icon.tsx +++ b/packages/ui/src/components/provider-icon.tsx @@ -15,7 +15,7 @@ export const ProviderIcon: Component = (props) => { data-component="provider-icon" {...rest} classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > diff --git a/packages/ui/src/components/radio-group.tsx b/packages/ui/src/components/radio-group.tsx index 544e852e4..9151a24b0 100644 --- a/packages/ui/src/components/radio-group.tsx +++ b/packages/ui/src/components/radio-group.tsx @@ -56,7 +56,7 @@ export function RadioGroup(props: RadioGroupProps) { data-fill={local.fill ? "" : undefined} data-pad={local.pad ?? "normal"} classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} value={local.current ? getValue(local.current) : undefined} diff --git a/packages/ui/src/components/resize-handle.tsx b/packages/ui/src/components/resize-handle.tsx index e2eed1bb7..d7774a684 100644 --- a/packages/ui/src/components/resize-handle.tsx +++ b/packages/ui/src/components/resize-handle.tsx @@ -73,7 +73,7 @@ export function ResizeHandle(props: ResizeHandleProps) { data-direction={local.direction} data-edge={local.edge ?? (local.direction === "vertical" ? "start" : "end")} classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} onMouseDown={handleMouseDown} diff --git a/packages/ui/src/components/select.tsx b/packages/ui/src/components/select.tsx index 61804a951..67becf2d9 100644 --- a/packages/ui/src/components/select.tsx +++ b/packages/ui/src/components/select.tsx @@ -104,7 +104,7 @@ export function Select(props: SelectProps & Omit) {...itemProps} data-slot="select-select-item" classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} onPointerEnter={() => move(itemProps.item.rawValue)} @@ -141,7 +141,7 @@ export function Select(props: SelectProps & Omit) variant={props.variant} style={local.triggerStyle} classList={{ - ...(local.classList ?? {}), + ...local.classList, [local.class ?? ""]: !!local.class, }} > @@ -160,7 +160,7 @@ export function Select(props: SelectProps & Omit) diff --git a/packages/ui/src/components/tabs.tsx b/packages/ui/src/components/tabs.tsx index 396504dd7..f46e9bfb3 100644 --- a/packages/ui/src/components/tabs.tsx +++ b/packages/ui/src/components/tabs.tsx @@ -27,7 +27,7 @@ function TabsRoot(props: TabsProps) { data-variant={split.variant || "normal"} data-orientation={split.orientation || "horizontal"} classList={{ - ...(split.classList ?? {}), + ...split.classList, [split.class ?? ""]: !!split.class, }} /> @@ -41,7 +41,7 @@ function TabsList(props: TabsListProps) { {...rest} data-slot="tabs-list" classList={{ - ...(split.classList ?? {}), + ...split.classList, [split.class ?? ""]: !!split.class, }} /> @@ -63,7 +63,7 @@ function TabsTrigger(props: ParentProps) { data-slot="tabs-trigger-wrapper" data-value={props.value} classList={{ - ...(split.classList ?? {}), + ...split.classList, [split.class ?? ""]: !!split.class, }} onMouseDown={(e) => { @@ -104,7 +104,7 @@ function TabsContent(props: ParentProps) { {...rest} data-slot="tabs-content" classList={{ - ...(split.classList ?? {}), + ...split.classList, [split.class ?? ""]: !!split.class, }} > diff --git a/packages/ui/src/components/tag.tsx b/packages/ui/src/components/tag.tsx index 428eedd0f..c54e4d474 100644 --- a/packages/ui/src/components/tag.tsx +++ b/packages/ui/src/components/tag.tsx @@ -12,7 +12,7 @@ export function Tag(props: TagProps) { data-component="tag" data-size={split.size || "normal"} classList={{ - ...(split.classList ?? {}), + ...split.classList, [split.class ?? ""]: !!split.class, }} > diff --git a/packages/ui/src/components/toast.tsx b/packages/ui/src/components/toast.tsx index e8062a2a8..599cf2a9e 100644 --- a/packages/ui/src/components/toast.tsx +++ b/packages/ui/src/components/toast.tsx @@ -30,7 +30,7 @@ function ToastRoot(props: ToastRootComponentProps) { Date: Wed, 15 Apr 2026 21:33:54 -0400 Subject: fix: resolve oxlint warnings — suppress false positives, remove unused imports (#22687) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .oxlintrc.json | 8 +++++++- github/index.ts | 6 +++--- infra/enterprise.ts | 2 +- packages/app/src/addons/serialize.ts | 4 ++-- packages/app/src/components/session/session-header.tsx | 2 +- packages/app/src/components/titlebar.tsx | 2 +- packages/app/src/context/global-sync/queue.ts | 1 + packages/app/src/pages/layout.tsx | 2 +- packages/app/src/pages/session/review-tab.tsx | 2 +- packages/console/app/src/component/email-signup.tsx | 1 - packages/console/app/src/component/header.tsx | 2 +- packages/console/app/src/context/auth.session.ts | 1 + packages/console/app/src/routes/bench/[id].tsx | 2 +- packages/console/app/src/routes/go/index.tsx | 2 +- packages/console/app/src/routes/workspace-picker.tsx | 2 +- packages/console/app/src/routes/zen/index.tsx | 2 +- packages/console/app/src/routes/zen/util/handler.ts | 2 +- .../console/app/src/routes/zen/util/provider/anthropic.ts | 2 +- packages/console/app/src/routes/zen/util/provider/google.ts | 2 +- .../app/src/routes/zen/util/provider/openai-compatible.ts | 6 +++--- packages/console/app/src/routes/zen/util/provider/openai.ts | 2 +- packages/console/core/script/black-cancel-waitlist.ts | 6 ++---- packages/console/core/script/black-gift.ts | 6 ++---- packages/console/core/script/black-onboard-waitlist.ts | 6 ++---- packages/console/core/script/black-select-workspaces.ts | 2 +- packages/console/core/src/util/env.cloudflare.ts | 1 + packages/console/core/src/util/log.ts | 2 +- packages/enterprise/test/core/share.test.ts | 2 +- packages/opencode/script/publish.ts | 2 +- packages/opencode/src/cli/cmd/debug/lsp.ts | 1 - packages/opencode/src/cli/cmd/export.ts | 2 +- packages/opencode/src/cli/cmd/github.ts | 4 ++-- packages/opencode/src/cli/cmd/serve.ts | 3 --- packages/opencode/src/cli/cmd/tui/app.tsx | 3 ++- .../opencode/src/cli/cmd/tui/component/dialog-theme-list.tsx | 2 +- packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx | 2 +- packages/opencode/src/cli/cmd/tui/event.ts | 1 - packages/opencode/src/cli/cmd/tui/routes/session/index.tsx | 6 +++--- packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx | 2 +- packages/opencode/src/control-plane/workspace-context.ts | 2 +- packages/opencode/src/file/ignore.ts | 1 - packages/opencode/src/file/watcher.ts | 2 +- packages/opencode/src/format/index.ts | 1 - packages/opencode/src/global/index.ts | 2 +- packages/opencode/src/ide/index.ts | 1 - packages/opencode/src/lsp/server.ts | 2 +- packages/opencode/src/patch/index.ts | 2 +- packages/opencode/src/permission/index.ts | 1 - packages/opencode/src/plugin/codex.ts | 4 +--- .../sdk/copilot/responses/openai-responses-language-model.ts | 1 + packages/opencode/src/server/instance/config.ts | 1 - packages/opencode/src/server/instance/event.ts | 1 - packages/opencode/src/server/instance/pty.ts | 2 +- packages/opencode/src/session/compaction.ts | 1 - packages/opencode/src/session/processor.ts | 2 ++ packages/opencode/src/session/projectors.ts | 6 ++---- packages/opencode/src/session/revert.ts | 1 - packages/opencode/src/storage/json-migration.ts | 4 ++++ packages/opencode/src/sync/index.ts | 1 - packages/opencode/src/tool/edit.ts | 2 +- packages/opencode/src/tool/task.ts | 1 - packages/opencode/src/tool/webfetch.ts | 2 +- packages/opencode/src/util/lazy.ts | 11 +++-------- packages/opencode/src/v2/session.ts | 2 -- packages/opencode/test/cli/tui/plugin-lifecycle.test.ts | 1 - packages/opencode/test/effect/cross-spawn-spawner.test.ts | 3 +-- packages/opencode/test/effect/instance-state.test.ts | 2 +- packages/opencode/test/permission/next.test.ts | 2 +- packages/opencode/test/provider/gitlab-duo.test.ts | 1 + packages/opencode/test/server/project-init-git.test.ts | 1 - packages/opencode/test/session/compaction.test.ts | 1 - packages/opencode/test/session/prompt-effect.test.ts | 1 - packages/opencode/test/session/snapshot-tool-race.test.ts | 1 - packages/opencode/test/share/share-next.test.ts | 1 - packages/opencode/test/tool/question.test.ts | 1 - packages/slack/src/index.ts | 2 +- packages/ui/src/components/message-part.tsx | 1 - packages/ui/src/components/timeline-playground.stories.tsx | 2 +- packages/ui/src/pierre/commented-lines.ts | 2 +- sdks/vscode/src/extension.ts | 2 +- 80 files changed, 82 insertions(+), 106 deletions(-) (limited to 'packages/app/src/context/global-sync') diff --git a/.oxlintrc.json b/.oxlintrc.json index 0875f3832..c366084ee 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -4,7 +4,13 @@ // Effect uses `function*` with Effect.gen/Effect.fnUntraced that don't always yield "require-yield": "off", // SolidJS uses `let ref: T | undefined` for JSX ref bindings assigned at runtime - "no-unassigned-vars": "off" + "no-unassigned-vars": "off", + // SolidJS tracks reactive deps by reading properties inside createEffect + "no-unused-expressions": "off", + // Intentional control char matching (ANSI escapes, null byte sanitization) + "no-control-regex": "off", + // SST and plugin tools require triple-slash references + "triple-slash-reference": "off" }, "ignorePatterns": ["**/node_modules", "**/dist", "**/.build", "**/.sst", "**/*.d.ts"] } diff --git a/github/index.ts b/github/index.ts index 6bfa96462..be8e5aafc 100644 --- a/github/index.ts +++ b/github/index.ts @@ -281,7 +281,7 @@ async function assertOpencodeConnected() { }) connected = true break - } catch (e) {} + } catch {} await sleep(300) } while (retry++ < 30) @@ -561,7 +561,7 @@ async function subscribeSessionEvents() { if (evt.properties.info.id !== session.id) continue session = evt.properties.info } - } catch (e) { + } catch { // Ignore parse errors } } @@ -576,7 +576,7 @@ async function subscribeSessionEvents() { async function summarize(response: string) { try { return await chat(`Summarize the following in less than 40 characters:\n\n${response}`) - } catch (e) { + } catch { if (isScheduleEvent()) { return "Scheduled task changes" } diff --git a/infra/enterprise.ts b/infra/enterprise.ts index 22b4c6f44..38f0c3c8f 100644 --- a/infra/enterprise.ts +++ b/infra/enterprise.ts @@ -1,5 +1,5 @@ import { SECRET } from "./secret" -import { domain, shortDomain } from "./stage" +import { shortDomain } from "./stage" const storage = new sst.cloudflare.Bucket("EnterpriseStorage") diff --git a/packages/app/src/addons/serialize.ts b/packages/app/src/addons/serialize.ts index 4cab55b3f..3823fb443 100644 --- a/packages/app/src/addons/serialize.ts +++ b/packages/app/src/addons/serialize.ts @@ -258,8 +258,8 @@ class StringSerializeHandler extends BaseSerializeHandler { } protected _beforeSerialize(rows: number, start: number, _end: number): void { - this._allRows = new Array(rows) - this._allRowSeparators = new Array(rows) + this._allRows = Array.from({ length: rows }) + this._allRowSeparators = Array.from({ length: rows }) this._rowIndex = 0 this._currentRow = "" diff --git a/packages/app/src/components/session/session-header.tsx b/packages/app/src/components/session/session-header.tsx index e65b575ac..7acfdfc37 100644 --- a/packages/app/src/components/session/session-header.tsx +++ b/packages/app/src/components/session/session-header.tsx @@ -8,7 +8,7 @@ import { Spinner } from "@opencode-ai/ui/spinner" import { showToast } from "@opencode-ai/ui/toast" import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip" import { getFilename } from "@opencode-ai/shared/util/path" -import { createEffect, createMemo, For, onCleanup, Show } from "solid-js" +import { createEffect, createMemo, For, Show } from "solid-js" import { createStore } from "solid-js/store" import { Portal } from "solid-js/web" import { useCommand } from "@/context/command" diff --git a/packages/app/src/components/titlebar.tsx b/packages/app/src/components/titlebar.tsx index 0a41f3119..a90178abd 100644 --- a/packages/app/src/components/titlebar.tsx +++ b/packages/app/src/components/titlebar.tsx @@ -1,4 +1,4 @@ -import { createEffect, createMemo, onCleanup, Show, untrack } from "solid-js" +import { createEffect, createMemo, Show, untrack } from "solid-js" import { createStore } from "solid-js/store" import { useLocation, useNavigate, useParams } from "@solidjs/router" import { IconButton } from "@opencode-ai/ui/icon-button" diff --git a/packages/app/src/context/global-sync/queue.ts b/packages/app/src/context/global-sync/queue.ts index c3468583b..5c228dac0 100644 --- a/packages/app/src/context/global-sync/queue.ts +++ b/packages/app/src/context/global-sync/queue.ts @@ -63,6 +63,7 @@ export function createRefreshQueue(input: QueueInput) { } } finally { running = false + // oxlint-disable-next-line no-unsafe-finally -- intentional: early return skips schedule() when paused if (input.paused()) return if (root || queued.size) schedule() } diff --git a/packages/app/src/pages/layout.tsx b/packages/app/src/pages/layout.tsx index 62d5cba61..3ba2659a3 100644 --- a/packages/app/src/pages/layout.tsx +++ b/packages/app/src/pages/layout.tsx @@ -704,7 +704,7 @@ export default function Layout(props: ParentProps) { createEffect(() => { const active = new Set(visibleSessionDirs()) - for (const directory of [...prefetchedByDir.keys()]) { + for (const directory of prefetchedByDir.keys()) { if (active.has(directory)) continue prefetchedByDir.delete(directory) } diff --git a/packages/app/src/pages/session/review-tab.tsx b/packages/app/src/pages/session/review-tab.tsx index 71dfe375e..5719fce31 100644 --- a/packages/app/src/pages/session/review-tab.tsx +++ b/packages/app/src/pages/session/review-tab.tsx @@ -1,4 +1,4 @@ -import { createEffect, createSignal, onCleanup, type JSX } from "solid-js" +import { createEffect, onCleanup, type JSX } from "solid-js" import { makeEventListener } from "@solid-primitives/event-listener" import type { SnapshotFileDiff, VcsFileDiff } from "@opencode-ai/sdk/v2" import { SessionReview } from "@opencode-ai/ui/session-review" diff --git a/packages/console/app/src/component/email-signup.tsx b/packages/console/app/src/component/email-signup.tsx index bd33e9200..caedaf0f2 100644 --- a/packages/console/app/src/component/email-signup.tsx +++ b/packages/console/app/src/component/email-signup.tsx @@ -1,5 +1,4 @@ import { action, useSubmission } from "@solidjs/router" -import dock from "../asset/lander/dock.png" import { Resource } from "@opencode-ai/console-resource" import { Show } from "solid-js" import { useI18n } from "~/context/i18n" diff --git a/packages/console/app/src/component/header.tsx b/packages/console/app/src/component/header.tsx index 1e129d590..cc45ed534 100644 --- a/packages/console/app/src/component/header.tsx +++ b/packages/console/app/src/component/header.tsx @@ -47,7 +47,7 @@ export function Header(props: { zen?: boolean; go?: boolean; hideGetStarted?: bo notation: "compact", compactDisplay: "short", maximumFractionDigits: 0, - }).format(githubData()?.stars!) + }).format(githubData()?.stars) : config.github.starsFormatted.compact, ) diff --git a/packages/console/app/src/context/auth.session.ts b/packages/console/app/src/context/auth.session.ts index e69de29bb..336ce12bb 100644 --- a/packages/console/app/src/context/auth.session.ts +++ b/packages/console/app/src/context/auth.session.ts @@ -0,0 +1 @@ +export {} diff --git a/packages/console/app/src/routes/bench/[id].tsx b/packages/console/app/src/routes/bench/[id].tsx index dd96bcbbc..c6d10826b 100644 --- a/packages/console/app/src/routes/bench/[id].tsx +++ b/packages/console/app/src/routes/bench/[id].tsx @@ -1,7 +1,7 @@ import { Title } from "@solidjs/meta" import { createAsync, query, useParams } from "@solidjs/router" import { createSignal, For, Show } from "solid-js" -import { Database, desc, eq } from "@opencode-ai/console-core/drizzle/index.js" +import { Database, eq } from "@opencode-ai/console-core/drizzle/index.js" import { BenchmarkTable } from "@opencode-ai/console-core/schema/benchmark.sql.js" import { useI18n } from "~/context/i18n" diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index 0ac85a957..82b3caf66 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -1,5 +1,5 @@ import "./index.css" -import { createAsync, query, redirect } from "@solidjs/router" +import { createAsync, query } from "@solidjs/router" import { Title, Meta } from "@solidjs/meta" import { For, createMemo, createSignal, onCleanup, onMount } from "solid-js" //import { HttpHeader } from "@solidjs/start" diff --git a/packages/console/app/src/routes/workspace-picker.tsx b/packages/console/app/src/routes/workspace-picker.tsx index ffec2f3be..8778abefd 100644 --- a/packages/console/app/src/routes/workspace-picker.tsx +++ b/packages/console/app/src/routes/workspace-picker.tsx @@ -1,5 +1,5 @@ import { query, useParams, action, createAsync, redirect, useSubmission } from "@solidjs/router" -import { For, Show, createEffect } from "solid-js" +import { For, createEffect } from "solid-js" import { createStore } from "solid-js/store" import { withActor } from "~/context/auth.withActor" import { Actor } from "@opencode-ai/console-core/actor.js" diff --git a/packages/console/app/src/routes/zen/index.tsx b/packages/console/app/src/routes/zen/index.tsx index 62e8f5d37..6285a0bd8 100644 --- a/packages/console/app/src/routes/zen/index.tsx +++ b/packages/console/app/src/routes/zen/index.tsx @@ -1,5 +1,5 @@ import "./index.css" -import { createAsync, query, redirect } from "@solidjs/router" +import { createAsync, query } from "@solidjs/router" import { Title, Meta } from "@solidjs/meta" //import { HttpHeader } from "@solidjs/start" import zenLogoLight from "../../asset/zen-ornate-light.svg" diff --git a/packages/console/app/src/routes/zen/util/handler.ts b/packages/console/app/src/routes/zen/util/handler.ts index 358d8736c..d1c5985a8 100644 --- a/packages/console/app/src/routes/zen/util/handler.ts +++ b/packages/console/app/src/routes/zen/util/handler.ts @@ -345,7 +345,7 @@ export async function handler( logger.metric({ "error.cause2": JSON.stringify(error.cause), }) - } catch (e) {} + } catch {} } // Note: both top level "type" and "error.type" fields are used by the @ai-sdk/anthropic client to render the error message. diff --git a/packages/console/app/src/routes/zen/util/provider/anthropic.ts b/packages/console/app/src/routes/zen/util/provider/anthropic.ts index b63be8688..0f6f11da7 100644 --- a/packages/console/app/src/routes/zen/util/provider/anthropic.ts +++ b/packages/console/app/src/routes/zen/util/provider/anthropic.ts @@ -153,7 +153,7 @@ export const anthropicHelper: ProviderHelper = ({ reqModel, providerModel }) => let json try { json = JSON.parse(data.slice(6)) - } catch (e) { + } catch { return } diff --git a/packages/console/app/src/routes/zen/util/provider/google.ts b/packages/console/app/src/routes/zen/util/provider/google.ts index f6f7d6e19..ef7937c35 100644 --- a/packages/console/app/src/routes/zen/util/provider/google.ts +++ b/packages/console/app/src/routes/zen/util/provider/google.ts @@ -48,7 +48,7 @@ export const googleHelper: ProviderHelper = ({ providerModel }) => ({ let json try { json = JSON.parse(chunk.slice(6)) as { usageMetadata?: Usage } - } catch (e) { + } catch { return } diff --git a/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts b/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts index cf9ee287c..e05f0d6c0 100644 --- a/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts +++ b/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts @@ -49,7 +49,7 @@ export const oaCompatHelper: ProviderHelper = ({ adjustCacheUsage, safetyIdentif let json try { json = JSON.parse(chunk.slice(6)) as { usage?: Usage } - } catch (e) { + } catch { return } @@ -289,7 +289,7 @@ export function fromOaCompatibleResponse(resp: any): CommonResponse { index: 0, message: { role: "assistant" as const, - ...(content.length > 0 && content.some((c) => c.type === "text") + ...(content.some((c) => c.type === "text") ? { content: content .filter((c) => c.type === "text") @@ -297,7 +297,7 @@ export function fromOaCompatibleResponse(resp: any): CommonResponse { .join(""), } : {}), - ...(content.length > 0 && content.some((c) => c.type === "tool_use") + ...(content.some((c) => c.type === "tool_use") ? { tool_calls: content .filter((c) => c.type === "tool_use") diff --git a/packages/console/app/src/routes/zen/util/provider/openai.ts b/packages/console/app/src/routes/zen/util/provider/openai.ts index 3c5831a9a..bee1e01ec 100644 --- a/packages/console/app/src/routes/zen/util/provider/openai.ts +++ b/packages/console/app/src/routes/zen/util/provider/openai.ts @@ -36,7 +36,7 @@ export const openaiHelper: ProviderHelper = ({ workspaceID }) => ({ let json try { json = JSON.parse(data.slice(6)) as { response?: { usage?: Usage } } - } catch (e) { + } catch { return } diff --git a/packages/console/core/script/black-cancel-waitlist.ts b/packages/console/core/script/black-cancel-waitlist.ts index ab2aa16d5..7c3584e00 100644 --- a/packages/console/core/script/black-cancel-waitlist.ts +++ b/packages/console/core/script/black-cancel-waitlist.ts @@ -1,7 +1,5 @@ -import { subscribe } from "diagnostics_channel" -import { Billing } from "../src/billing.js" -import { and, Database, eq } from "../src/drizzle/index.js" -import { BillingTable, PaymentTable, SubscriptionTable } from "../src/schema/billing.sql.js" +import { Database, eq } from "../src/drizzle/index.js" +import { BillingTable } from "../src/schema/billing.sql.js" const workspaceID = process.argv[2] diff --git a/packages/console/core/script/black-gift.ts b/packages/console/core/script/black-gift.ts index c666a1ab6..e57ec9775 100644 --- a/packages/console/core/script/black-gift.ts +++ b/packages/console/core/script/black-gift.ts @@ -1,12 +1,10 @@ import { Billing } from "../src/billing.js" -import { and, Database, eq, isNull, sql } from "../src/drizzle/index.js" +import { and, Database, eq, isNull } from "../src/drizzle/index.js" import { UserTable } from "../src/schema/user.sql.js" -import { BillingTable, PaymentTable, SubscriptionTable } from "../src/schema/billing.sql.js" +import { BillingTable, SubscriptionTable } from "../src/schema/billing.sql.js" import { Identifier } from "../src/identifier.js" -import { centsToMicroCents } from "../src/util/price.js" import { AuthTable } from "../src/schema/auth.sql.js" import { BlackData } from "../src/black.js" -import { Actor } from "../src/actor.js" const plan = "200" const couponID = "JAIr0Pe1" diff --git a/packages/console/core/script/black-onboard-waitlist.ts b/packages/console/core/script/black-onboard-waitlist.ts index 96d0f8f91..9e7d9e935 100644 --- a/packages/console/core/script/black-onboard-waitlist.ts +++ b/packages/console/core/script/black-onboard-waitlist.ts @@ -1,7 +1,5 @@ -import { subscribe } from "diagnostics_channel" -import { Billing } from "../src/billing.js" -import { and, Database, eq } from "../src/drizzle/index.js" -import { BillingTable, PaymentTable, SubscriptionTable } from "../src/schema/billing.sql.js" +import { Database, eq } from "../src/drizzle/index.js" +import { BillingTable } from "../src/schema/billing.sql.js" const workspaceID = process.argv[2] diff --git a/packages/console/core/script/black-select-workspaces.ts b/packages/console/core/script/black-select-workspaces.ts index 63bfab887..0772bd212 100644 --- a/packages/console/core/script/black-select-workspaces.ts +++ b/packages/console/core/script/black-select-workspaces.ts @@ -1,4 +1,4 @@ -import { Database, eq, and, sql, inArray, isNull, count } from "../src/drizzle/index.js" +import { Database, eq, and, sql, inArray, isNull } from "../src/drizzle/index.js" import { BillingTable, BlackPlans } from "../src/schema/billing.sql.js" import { UserTable } from "../src/schema/user.sql.js" import { AuthTable } from "../src/schema/auth.sql.js" diff --git a/packages/console/core/src/util/env.cloudflare.ts b/packages/console/core/src/util/env.cloudflare.ts index e69de29bb..336ce12bb 100644 --- a/packages/console/core/src/util/env.cloudflare.ts +++ b/packages/console/core/src/util/env.cloudflare.ts @@ -0,0 +1 @@ +export {} diff --git a/packages/console/core/src/util/log.ts b/packages/console/core/src/util/log.ts index 4f2d25c13..ef3ad85c6 100644 --- a/packages/console/core/src/util/log.ts +++ b/packages/console/core/src/util/log.ts @@ -48,7 +48,7 @@ export namespace Log { function use() { try { return ctx.use() - } catch (e) { + } catch { return { tags: {} } } } diff --git a/packages/enterprise/test/core/share.test.ts b/packages/enterprise/test/core/share.test.ts index 34f3b17a3..2877f8e0e 100644 --- a/packages/enterprise/test/core/share.test.ts +++ b/packages/enterprise/test/core/share.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, test, afterAll } from "bun:test" +import { describe, expect, test } from "bun:test" import { Share } from "../../src/core/share" import { Storage } from "../../src/core/storage" import { Identifier } from "@opencode-ai/shared/util/identifier" diff --git a/packages/opencode/script/publish.ts b/packages/opencode/script/publish.ts index fbc1c83ba..9c4b8f187 100755 --- a/packages/opencode/script/publish.ts +++ b/packages/opencode/script/publish.ts @@ -107,7 +107,7 @@ if (!Script.preview) { await $`cd ./dist/aur-${pkg} && git commit -m "Update to v${Script.version}"` await $`cd ./dist/aur-${pkg} && git push` break - } catch (e) { + } catch { continue } } diff --git a/packages/opencode/src/cli/cmd/debug/lsp.ts b/packages/opencode/src/cli/cmd/debug/lsp.ts index 5f0a1807d..18f67b391 100644 --- a/packages/opencode/src/cli/cmd/debug/lsp.ts +++ b/packages/opencode/src/cli/cmd/debug/lsp.ts @@ -5,7 +5,6 @@ import { bootstrap } from "../../bootstrap" import { cmd } from "../cmd" import { Log } from "../../../util/log" import { EOL } from "os" -import { setTimeout as sleep } from "node:timers/promises" export const LSPCommand = cmd({ command: "lsp", diff --git a/packages/opencode/src/cli/cmd/export.ts b/packages/opencode/src/cli/cmd/export.ts index 9a1a51adc..06b361c6d 100644 --- a/packages/opencode/src/cli/cmd/export.ts +++ b/packages/opencode/src/cli/cmd/export.ts @@ -297,7 +297,7 @@ export const ExportCommand = cmd({ process.stdout.write(JSON.stringify(args.sanitize ? sanitize(exportData) : exportData, null, 2)) process.stdout.write(EOL) - } catch (error) { + } catch { UI.error(`Session not found: ${sessionID!}`) process.exit(1) } diff --git a/packages/opencode/src/cli/cmd/github.ts b/packages/opencode/src/cli/cmd/github.ts index 074d9e518..b6781d085 100644 --- a/packages/opencode/src/cli/cmd/github.ts +++ b/packages/opencode/src/cli/cmd/github.ts @@ -362,7 +362,7 @@ export const GithubInstallCommand = cmd({ retries++ await sleep(1000) - } while (true) + } while (true) // oxlint-disable-line no-constant-condition s.stop("Installed GitHub app") @@ -931,7 +931,7 @@ export const GithubRunCommand = cmd({ async function summarize(response: string) { try { return await chat(`Summarize the following in less than 40 characters:\n\n${response}`) - } catch (e) { + } catch { const title = issueEvent ? issueEvent.issue.title : (payload as PullRequestReviewCommentEvent).pull_request.title diff --git a/packages/opencode/src/cli/cmd/serve.ts b/packages/opencode/src/cli/cmd/serve.ts index 73e7a18a7..d5eee75dd 100644 --- a/packages/opencode/src/cli/cmd/serve.ts +++ b/packages/opencode/src/cli/cmd/serve.ts @@ -2,9 +2,6 @@ import { Server } from "../../server/server" import { cmd } from "./cmd" import { withNetworkOptions, resolveNetworkOptions } from "../network" import { Flag } from "../../flag/flag" -import { Workspace } from "../../control-plane/workspace" -import { Project } from "../../project/project" -import { Installation } from "../../installation" export const ServeCommand = cmd({ command: "serve", diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index acf007197..4c6c74ff3 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -23,7 +23,7 @@ import { DialogProvider, useDialog } from "@tui/ui/dialog" import { DialogProvider as DialogProviderList } from "@tui/component/dialog-provider" import { ErrorComponent } from "@tui/component/error-component" import { PluginRouteMissing } from "@tui/component/plugin-route-missing" -import { ProjectProvider, useProject } from "@tui/context/project" +import { ProjectProvider } from "@tui/context/project" import { useEvent } from "@tui/context/event" import { SDKProvider, useSDK } from "@tui/context/sdk" import { StartupLoading } from "@tui/component/startup-loading" @@ -115,6 +115,7 @@ export function tui(input: { events?: EventSource }) { // promise to prevent immediate exit + // oxlint-disable-next-line no-async-promise-executor -- intentional: async executor used for sequential setup before resolve return new Promise(async (resolve) => { const unguard = win32InstallCtrlCGuard() win32DisableProcessedInput() diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-theme-list.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-theme-list.tsx index f4072c978..6cf3539ad 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-theme-list.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-theme-list.tsx @@ -1,7 +1,7 @@ import { DialogSelect, type DialogSelectRef } from "../ui/dialog-select" import { useTheme } from "../context/theme" import { useDialog } from "../ui/dialog" -import { onCleanup, onMount } from "solid-js" +import { onCleanup } from "solid-js" export function DialogThemeList() { const theme = useTheme() diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index d0f5b481c..87440d0e2 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -1,4 +1,4 @@ -import { BoxRenderable, TextareaRenderable, MouseEvent, PasteEvent, decodePasteBytes, t, dim, fg } from "@opentui/core" +import { BoxRenderable, TextareaRenderable, MouseEvent, PasteEvent, decodePasteBytes } from "@opentui/core" import { createEffect, createMemo, onMount, createSignal, onCleanup, on, Show, Switch, Match } from "solid-js" import "opentui-spinner/solid" import path from "path" diff --git a/packages/opencode/src/cli/cmd/tui/event.ts b/packages/opencode/src/cli/cmd/tui/event.ts index b2e4b92c5..fa164d53e 100644 --- a/packages/opencode/src/cli/cmd/tui/event.ts +++ b/packages/opencode/src/cli/cmd/tui/event.ts @@ -1,5 +1,4 @@ import { BusEvent } from "@/bus/bus-event" -import { Bus } from "@/bus" import { SessionID } from "@/session/schema" import z from "zod" diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 2b95cd5ae..f9fd5a9b9 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -863,7 +863,7 @@ export function Session() { ) await Clipboard.copy(transcript) toast.show({ message: "Session transcript copied to clipboard!", variant: "success" }) - } catch (error) { + } catch { toast.show({ message: "Failed to copy session transcript", variant: "error" }) } dialog.clear() @@ -925,7 +925,7 @@ export function Session() { toast.show({ message: `Session exported to ${filename}`, variant: "success" }) } - } catch (error) { + } catch { toast.show({ message: "Failed to export session", variant: "error" }) } dialog.clear() @@ -1010,7 +1010,7 @@ export function Session() { ), } }) - } catch (error) { + } catch { return [] } }) diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx index 109b5f2f1..b6c937f41 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx @@ -1,6 +1,6 @@ import { InputRenderable, RGBA, ScrollBoxRenderable, TextAttributes } from "@opentui/core" import { useTheme, selectedForeground } from "@tui/context/theme" -import { entries, filter, flatMap, groupBy, pipe, take } from "remeda" +import { entries, filter, flatMap, groupBy, pipe } from "remeda" import { batch, createEffect, createMemo, For, Show, type JSX, on } from "solid-js" import { createStore } from "solid-js/store" import { useKeyboard, useTerminalDimensions } from "@opentui/solid" diff --git a/packages/opencode/src/control-plane/workspace-context.ts b/packages/opencode/src/control-plane/workspace-context.ts index 541657b88..273adbb24 100644 --- a/packages/opencode/src/control-plane/workspace-context.ts +++ b/packages/opencode/src/control-plane/workspace-context.ts @@ -19,7 +19,7 @@ export const WorkspaceContext = { get workspaceID() { try { return context.use().workspaceID - } catch (err) { + } catch { return undefined } }, diff --git a/packages/opencode/src/file/ignore.ts b/packages/opencode/src/file/ignore.ts index a102e7d17..63f2f594e 100644 --- a/packages/opencode/src/file/ignore.ts +++ b/packages/opencode/src/file/ignore.ts @@ -1,4 +1,3 @@ -import { sep } from "node:path" import { Glob } from "@opencode-ai/shared/util/glob" export namespace FileIgnore { diff --git a/packages/opencode/src/file/watcher.ts b/packages/opencode/src/file/watcher.ts index 74966fd47..4dcec5094 100644 --- a/packages/opencode/src/file/watcher.ts +++ b/packages/opencode/src/file/watcher.ts @@ -1,4 +1,4 @@ -import { Cause, Effect, Layer, Scope, Context } from "effect" +import { Cause, Effect, Layer, Context } from "effect" // @ts-ignore import { createWrapper } from "@parcel/watcher/wrapper" import type ParcelWatcher from "@parcel/watcher" diff --git a/packages/opencode/src/format/index.ts b/packages/opencode/src/format/index.ts index 595bb7a60..d65ed2944 100644 --- a/packages/opencode/src/format/index.ts +++ b/packages/opencode/src/format/index.ts @@ -6,7 +6,6 @@ import path from "path" import { mergeDeep } from "remeda" import z from "zod" import { Config } from "../config" -import { Instance } from "../project/instance" import { Log } from "../util/log" import * as Formatter from "./formatter" diff --git a/packages/opencode/src/global/index.ts b/packages/opencode/src/global/index.ts index 32d515321..df4639781 100644 --- a/packages/opencode/src/global/index.ts +++ b/packages/opencode/src/global/index.ts @@ -53,6 +53,6 @@ if (version !== CACHE_VERSION) { }), ), ) - } catch (e) {} + } catch {} await Filesystem.write(path.join(Global.Path.cache, "version"), CACHE_VERSION) } diff --git a/packages/opencode/src/ide/index.ts b/packages/opencode/src/ide/index.ts index 46efea2cc..24ba53f82 100644 --- a/packages/opencode/src/ide/index.ts +++ b/packages/opencode/src/ide/index.ts @@ -1,5 +1,4 @@ import { BusEvent } from "@/bus/bus-event" -import { Bus } from "@/bus" import z from "zod" import { NamedError } from "@opencode-ai/shared/util/error" import { Log } from "../util/log" diff --git a/packages/opencode/src/lsp/server.ts b/packages/opencode/src/lsp/server.ts index 9ffef7a42..f4554ae3e 100644 --- a/packages/opencode/src/lsp/server.ts +++ b/packages/opencode/src/lsp/server.ts @@ -826,7 +826,7 @@ export namespace LSPServer { if (cargoTomlContent.includes("[workspace]")) { return currentDir } - } catch (err) { + } catch { // File doesn't exist or can't be read, continue searching up } diff --git a/packages/opencode/src/patch/index.ts b/packages/opencode/src/patch/index.ts index b87ad5552..f003606c4 100644 --- a/packages/opencode/src/patch/index.ts +++ b/packages/opencode/src/patch/index.ts @@ -630,7 +630,7 @@ export namespace Patch { type: "delete", content, }) - } catch (error) { + } catch { return { type: MaybeApplyPatchVerified.CorrectnessError, error: new Error(`Failed to read file for deletion: ${deletePath}`), diff --git a/packages/opencode/src/permission/index.ts b/packages/opencode/src/permission/index.ts index 71d321080..010048549 100644 --- a/packages/opencode/src/permission/index.ts +++ b/packages/opencode/src/permission/index.ts @@ -3,7 +3,6 @@ import { BusEvent } from "@/bus/bus-event" import { Config } from "@/config" import { InstanceState } from "@/effect/instance-state" import { ProjectID } from "@/project/schema" -import { Instance } from "@/project/instance" import { MessageID, SessionID } from "@/session/schema" import { PermissionTable } from "@/session/session.sql" import { Database, eq } from "@/storage/db" diff --git a/packages/opencode/src/plugin/codex.ts b/packages/opencode/src/plugin/codex.ts index 1e127fae5..ea356d55d 100644 --- a/packages/opencode/src/plugin/codex.ts +++ b/packages/opencode/src/plugin/codex.ts @@ -1,10 +1,8 @@ import type { Hooks, PluginInput } from "@opencode-ai/plugin" import { Log } from "../util/log" import { Installation } from "../installation" -import { Auth, OAUTH_DUMMY_KEY } from "../auth" +import { OAUTH_DUMMY_KEY } from "../auth" import os from "os" -import { ProviderTransform } from "@/provider/transform" -import { ModelID, ProviderID } from "@/provider/schema" import { setTimeout as sleep } from "node:timers/promises" import { createServer } from "http" diff --git a/packages/opencode/src/provider/sdk/copilot/responses/openai-responses-language-model.ts b/packages/opencode/src/provider/sdk/copilot/responses/openai-responses-language-model.ts index 4606af7a1..92c8fd857 100644 --- a/packages/opencode/src/provider/sdk/copilot/responses/openai-responses-language-model.ts +++ b/packages/opencode/src/provider/sdk/copilot/responses/openai-responses-language-model.ts @@ -793,6 +793,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 { fetch: this.config.fetch, }) + // oxlint-disable-next-line no-this-alias -- needed for closure scope inside generator const self = this let finishReason: { diff --git a/packages/opencode/src/server/instance/config.ts b/packages/opencode/src/server/instance/config.ts index 11845c69c..68a6b5076 100644 --- a/packages/opencode/src/server/instance/config.ts +++ b/packages/opencode/src/server/instance/config.ts @@ -7,7 +7,6 @@ import { mapValues } from "remeda" import { errors } from "../error" import { lazy } from "../../util/lazy" import { AppRuntime } from "../../effect/app-runtime" -import { Effect } from "effect" import { jsonRequest } from "./trace" export const ConfigRoutes = lazy(() => diff --git a/packages/opencode/src/server/instance/event.ts b/packages/opencode/src/server/instance/event.ts index 5d631d954..f13ed035e 100644 --- a/packages/opencode/src/server/instance/event.ts +++ b/packages/opencode/src/server/instance/event.ts @@ -4,7 +4,6 @@ import { describeRoute, resolver } from "hono-openapi" import { streamSSE } from "hono/streaming" import { Log } from "@/util/log" import { BusEvent } from "@/bus/bus-event" -import { SyncEvent } from "@/sync" import { Bus } from "@/bus" import { AsyncQueue } from "../../util/queue" diff --git a/packages/opencode/src/server/instance/pty.ts b/packages/opencode/src/server/instance/pty.ts index 576cbe5de..3cb8dbfe2 100644 --- a/packages/opencode/src/server/instance/pty.ts +++ b/packages/opencode/src/server/instance/pty.ts @@ -1,4 +1,4 @@ -import { Hono, type MiddlewareHandler } from "hono" +import { Hono } from "hono" import { describeRoute, validator, resolver } from "hono-openapi" import type { UpgradeWebSocket } from "hono/ws" import { Effect } from "effect" diff --git a/packages/opencode/src/session/compaction.ts b/packages/opencode/src/session/compaction.ts index 810b94974..03f972311 100644 --- a/packages/opencode/src/session/compaction.ts +++ b/packages/opencode/src/session/compaction.ts @@ -2,7 +2,6 @@ import { BusEvent } from "@/bus/bus-event" import { Bus } from "@/bus" import { Session } from "." import { SessionID, MessageID, PartID } from "./schema" -import { Instance } from "../project/instance" import { Provider } from "../provider/provider" import { MessageV2 } from "./message-v2" import z from "zod" diff --git a/packages/opencode/src/session/processor.ts b/packages/opencode/src/session/processor.ts index d91b1427b..0f8cd41b3 100644 --- a/packages/opencode/src/session/processor.ts +++ b/packages/opencode/src/session/processor.ts @@ -249,6 +249,7 @@ export namespace SessionProcessor { case "reasoning-end": if (!(value.id in ctx.reasoningMap)) return + // oxlint-disable-next-line no-self-assign -- reactivity trigger ctx.reasoningMap[value.id].text = ctx.reasoningMap[value.id].text ctx.reasoningMap[value.id].time = { ...ctx.reasoningMap[value.id].time, end: Date.now() } if (value.providerMetadata) ctx.reasoningMap[value.id].metadata = value.providerMetadata @@ -431,6 +432,7 @@ export namespace SessionProcessor { case "text-end": if (!ctx.currentText) return + // oxlint-disable-next-line no-self-assign -- reactivity trigger ctx.currentText.text = ctx.currentText.text ctx.currentText.text = (yield* plugin.trigger( "experimental.text.complete", diff --git a/packages/opencode/src/session/projectors.ts b/packages/opencode/src/session/projectors.ts index 460f0a41c..a1b2e401d 100644 --- a/packages/opencode/src/session/projectors.ts +++ b/packages/opencode/src/session/projectors.ts @@ -1,11 +1,9 @@ -import { NotFoundError, eq, and, sql } from "../storage/db" +import { NotFoundError, eq, and } from "../storage/db" import { SyncEvent } from "@/sync" import { Session } from "./index" import { MessageV2 } from "./message-v2" -import { SessionTable, MessageTable, PartTable, SessionEntryTable } from "./session.sql" +import { SessionTable, MessageTable, PartTable } from "./session.sql" import { Log } from "../util/log" -import { DateTime } from "effect" -import { SessionEntry } from "@/v2/session-entry" const log = Log.create({ service: "session.projector" }) diff --git a/packages/opencode/src/session/revert.ts b/packages/opencode/src/session/revert.ts index a4a7a27d6..7a7f847ad 100644 --- a/packages/opencode/src/session/revert.ts +++ b/packages/opencode/src/session/revert.ts @@ -10,7 +10,6 @@ import { MessageV2 } from "./message-v2" import { SessionID, MessageID, PartID } from "./schema" import { SessionRunState } from "./run-state" import { SessionSummary } from "./summary" -import { SessionStatus } from "./status" export namespace SessionRevert { const log = Log.create({ service: "session.revert" }) diff --git a/packages/opencode/src/storage/json-migration.ts b/packages/opencode/src/storage/json-migration.ts index 89d27b9a7..c13a005ca 100644 --- a/packages/opencode/src/storage/json-migration.ts +++ b/packages/opencode/src/storage/json-migration.ts @@ -77,11 +77,13 @@ export namespace JsonMigration { async function read(files: string[], start: number, end: number) { const count = end - start + // oxlint-disable-next-line unicorn/no-new-array -- pre-allocated for index-based batch fill const tasks = new Array(count) for (let i = 0; i < count; i++) { tasks[i] = Filesystem.readJson(files[start + i]) } const results = await Promise.allSettled(tasks) + // oxlint-disable-next-line unicorn/no-new-array -- pre-allocated for index-based batch fill const items = new Array(count) for (let i = 0; i < results.length; i++) { const result = results[i] @@ -243,6 +245,7 @@ export namespace JsonMigration { for (let i = 0; i < allMessageFiles.length; i += batchSize) { const end = Math.min(i + batchSize, allMessageFiles.length) const batch = await read(allMessageFiles, i, end) + // oxlint-disable-next-line unicorn/no-new-array -- pre-allocated for index-based batch fill const values = new Array(batch.length) let count = 0 for (let j = 0; j < batch.length; j++) { @@ -273,6 +276,7 @@ export namespace JsonMigration { for (let i = 0; i < partFiles.length; i += batchSize) { const end = Math.min(i + batchSize, partFiles.length) const batch = await read(partFiles, i, end) + // oxlint-disable-next-line unicorn/no-new-array -- pre-allocated for index-based batch fill const values = new Array(batch.length) let count = 0 for (let j = 0; j < batch.length; j++) { diff --git a/packages/opencode/src/sync/index.ts b/packages/opencode/src/sync/index.ts index ce598dae6..e89d57e18 100644 --- a/packages/opencode/src/sync/index.ts +++ b/packages/opencode/src/sync/index.ts @@ -1,6 +1,5 @@ import z from "zod" import type { ZodObject } from "zod" -import { EventEmitter } from "events" import { Database, eq } from "@/storage/db" import { GlobalBus } from "@/bus/global" import { Bus as ProjectBus } from "@/bus" diff --git a/packages/opencode/src/tool/edit.ts b/packages/opencode/src/tool/edit.ts index 5c8246394..2303618a0 100644 --- a/packages/opencode/src/tool/edit.ts +++ b/packages/opencode/src/tool/edit.ts @@ -416,7 +416,7 @@ export const WhitespaceNormalizedReplacer: Replacer = function* (content, find) if (match) { yield match[0] } - } catch (e) { + } catch { // Invalid regex pattern, skip } } diff --git a/packages/opencode/src/tool/task.ts b/packages/opencode/src/tool/task.ts index bbb07caa4..8f7104e80 100644 --- a/packages/opencode/src/tool/task.ts +++ b/packages/opencode/src/tool/task.ts @@ -8,7 +8,6 @@ import { Agent } from "../agent/agent" import type { SessionPrompt } from "../session/prompt" import { Config } from "../config" import { Effect } from "effect" -import { Log } from "@/util/log" export interface TaskPromptOps { cancel(sessionID: SessionID): void diff --git a/packages/opencode/src/tool/webfetch.ts b/packages/opencode/src/tool/webfetch.ts index 9339038b0..14d546584 100644 --- a/packages/opencode/src/tool/webfetch.ts +++ b/packages/opencode/src/tool/webfetch.ts @@ -1,6 +1,6 @@ import z from "zod" import { Effect } from "effect" -import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, HttpClientRequest } from "effect/unstable/http" import { Tool } from "./tool" import TurndownService from "turndown" import DESCRIPTION from "./webfetch.txt" diff --git a/packages/opencode/src/util/lazy.ts b/packages/opencode/src/util/lazy.ts index 55643dc6a..86967e11a 100644 --- a/packages/opencode/src/util/lazy.ts +++ b/packages/opencode/src/util/lazy.ts @@ -4,14 +4,9 @@ export function lazy(fn: () => T) { const result = (): T => { if (loaded) return value as T - try { - value = fn() - loaded = true - return value as T - } catch (e) { - // Don't mark as loaded if initialization failed - throw e - } + value = fn() + loaded = true + return value as T } result.reset = () => { diff --git a/packages/opencode/src/v2/session.ts b/packages/opencode/src/v2/session.ts index b7191a4c9..97df0a220 100644 --- a/packages/opencode/src/v2/session.ts +++ b/packages/opencode/src/v2/session.ts @@ -1,8 +1,6 @@ import { Context, Layer, Schema, Effect } from "effect" import { SessionEntry } from "./session-entry" import { Struct } from "effect" -import { Identifier } from "@/id/id" -import { withStatics } from "@/util/schema" import { Session } from "@/session" import { SessionID } from "@/session/schema" diff --git a/packages/opencode/test/cli/tui/plugin-lifecycle.test.ts b/packages/opencode/test/cli/tui/plugin-lifecycle.test.ts index 9c868a4c9..b22180ef3 100644 --- a/packages/opencode/test/cli/tui/plugin-lifecycle.test.ts +++ b/packages/opencode/test/cli/tui/plugin-lifecycle.test.ts @@ -5,7 +5,6 @@ import { pathToFileURL } from "url" import { tmpdir } from "../../fixture/fixture" import { createTuiPluginApi } from "../../fixture/tui-plugin" import { mockTuiRuntime } from "../../fixture/tui-runtime" -import { TuiConfig } from "../../../src/config/tui" const { TuiPluginRuntime } = await import("../../../src/cli/cmd/tui/plugin/runtime") diff --git a/packages/opencode/test/effect/cross-spawn-spawner.test.ts b/packages/opencode/test/effect/cross-spawn-spawner.test.ts index 2cc509202..5990635aa 100644 --- a/packages/opencode/test/effect/cross-spawn-spawner.test.ts +++ b/packages/opencode/test/effect/cross-spawn-spawner.test.ts @@ -1,8 +1,7 @@ -import { NodeFileSystem, NodePath } from "@effect/platform-node" import { describe, expect } from "bun:test" import fs from "node:fs/promises" import path from "node:path" -import { Effect, Exit, Layer, Stream } from "effect" +import { Effect, Exit, Stream } from "effect" import type * as PlatformError from "effect/PlatformError" import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner" diff --git a/packages/opencode/test/effect/instance-state.test.ts b/packages/opencode/test/effect/instance-state.test.ts index 813ca344a..ca74c915b 100644 --- a/packages/opencode/test/effect/instance-state.test.ts +++ b/packages/opencode/test/effect/instance-state.test.ts @@ -1,5 +1,5 @@ import { afterEach, expect, test } from "bun:test" -import { Cause, Deferred, Duration, Effect, Exit, Fiber, Layer, ManagedRuntime, Context } from "effect" +import { Deferred, Duration, Effect, Exit, Fiber, Layer, ManagedRuntime, Context } from "effect" import { InstanceState } from "../../src/effect/instance-state" import { InstanceRef } from "../../src/effect/instance-ref" import { Instance } from "../../src/project/instance" diff --git a/packages/opencode/test/permission/next.test.ts b/packages/opencode/test/permission/next.test.ts index 9e3007f6d..805c230f3 100644 --- a/packages/opencode/test/permission/next.test.ts +++ b/packages/opencode/test/permission/next.test.ts @@ -6,7 +6,7 @@ import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner" import { Permission } from "../../src/permission" import { PermissionID } from "../../src/permission/schema" import { Instance } from "../../src/project/instance" -import { provideInstance, provideTmpdirInstance, tmpdir, tmpdirScoped } from "../fixture/fixture" +import { provideInstance, provideTmpdirInstance, tmpdirScoped } from "../fixture/fixture" import { testEffect } from "../lib/effect" import { MessageID, SessionID } from "../../src/session/schema" diff --git a/packages/opencode/test/provider/gitlab-duo.test.ts b/packages/opencode/test/provider/gitlab-duo.test.ts index 9b5441fe2..a80ecf5ae 100644 --- a/packages/opencode/test/provider/gitlab-duo.test.ts +++ b/packages/opencode/test/provider/gitlab-duo.test.ts @@ -1,3 +1,4 @@ +export {} // TODO: UNCOMMENT WHEN GITLAB SUPPORT IS COMPLETED // // diff --git a/packages/opencode/test/server/project-init-git.test.ts b/packages/opencode/test/server/project-init-git.test.ts index 25d706643..406b3d6d8 100644 --- a/packages/opencode/test/server/project-init-git.test.ts +++ b/packages/opencode/test/server/project-init-git.test.ts @@ -3,7 +3,6 @@ import { Effect } from "effect" import path from "path" import { GlobalBus } from "../../src/bus/global" import { Snapshot } from "../../src/snapshot" -import { InstanceBootstrap } from "../../src/project/bootstrap" import { Instance } from "../../src/project/instance" import { Server } from "../../src/server/server" import { Filesystem } from "../../src/util/filesystem" diff --git a/packages/opencode/test/session/compaction.test.ts b/packages/opencode/test/session/compaction.test.ts index 1174cdf6a..aaf34348b 100644 --- a/packages/opencode/test/session/compaction.test.ts +++ b/packages/opencode/test/session/compaction.test.ts @@ -2,7 +2,6 @@ import { afterEach, describe, expect, mock, test } from "bun:test" import { APICallError } from "ai" import { Cause, Effect, Exit, Layer, ManagedRuntime } from "effect" import * as Stream from "effect/Stream" -import path from "path" import z from "zod" import { Bus } from "../../src/bus" import { Config } from "../../src/config" diff --git a/packages/opencode/test/session/prompt-effect.test.ts b/packages/opencode/test/session/prompt-effect.test.ts index ec1a87e96..3963c815d 100644 --- a/packages/opencode/test/session/prompt-effect.test.ts +++ b/packages/opencode/test/session/prompt-effect.test.ts @@ -3,7 +3,6 @@ import { FetchHttpClient } from "effect/unstable/http" import { expect } from "bun:test" import { Cause, Effect, Exit, Fiber, Layer } from "effect" import path from "path" -import z from "zod" import { Agent as AgentSvc } from "../../src/agent/agent" import { Bus } from "../../src/bus" import { Command } from "../../src/command" diff --git a/packages/opencode/test/session/snapshot-tool-race.test.ts b/packages/opencode/test/session/snapshot-tool-race.test.ts index a0ea47c89..e32919aed 100644 --- a/packages/opencode/test/session/snapshot-tool-race.test.ts +++ b/packages/opencode/test/session/snapshot-tool-race.test.ts @@ -49,7 +49,6 @@ import { Instruction } from "../../src/session/instruction" import { SessionProcessor } from "../../src/session/processor" import { SessionRunState } from "../../src/session/run-state" import { SessionStatus } from "../../src/session/status" -import { Shell } from "../../src/shell/shell" import { Snapshot } from "../../src/snapshot" import { ToolRegistry } from "../../src/tool/registry" import { Truncate } from "../../src/tool/truncate" diff --git a/packages/opencode/test/share/share-next.test.ts b/packages/opencode/test/share/share-next.test.ts index 135d44db0..747541195 100644 --- a/packages/opencode/test/share/share-next.test.ts +++ b/packages/opencode/test/share/share-next.test.ts @@ -13,7 +13,6 @@ import { Provider } from "../../src/provider/provider" import { Session } from "../../src/session" import type { SessionID } from "../../src/session/schema" import { ShareNext } from "../../src/share/share-next" -import { Storage } from "../../src/storage/storage" import { SessionShareTable } from "../../src/share/share.sql" import { Database, eq } from "../../src/storage/db" import { provideTmpdirInstance } from "../fixture/fixture" diff --git a/packages/opencode/test/tool/question.test.ts b/packages/opencode/test/tool/question.test.ts index eb69f1d96..629e5d2d2 100644 --- a/packages/opencode/test/tool/question.test.ts +++ b/packages/opencode/test/tool/question.test.ts @@ -1,6 +1,5 @@ import { describe, expect } from "bun:test" import { Effect, Fiber, Layer } from "effect" -import { Tool } from "../../src/tool/tool" import { QuestionTool } from "../../src/tool/question" import { Question } from "../../src/question" import { SessionID, MessageID } from "../../src/session/schema" diff --git a/packages/slack/src/index.ts b/packages/slack/src/index.ts index d07e3dfb4..123710aa4 100644 --- a/packages/slack/src/index.ts +++ b/packages/slack/src/index.ts @@ -95,7 +95,7 @@ app.message(async ({ message, say }) => { const shareResult = await client.session.share({ path: { id: createResult.data.id } }) if (!shareResult.error && shareResult.data) { - const sessionUrl = shareResult.data.share?.url! + const sessionUrl = shareResult.data.share?.url console.log("🔗 Session shared:", sessionUrl) await app.client.chat.postMessage({ channel, thread_ts: thread, text: sessionUrl }) } diff --git a/packages/ui/src/components/message-part.tsx b/packages/ui/src/components/message-part.tsx index 48444cd01..81e6a52a2 100644 --- a/packages/ui/src/components/message-part.tsx +++ b/packages/ui/src/components/message-part.tsx @@ -37,7 +37,6 @@ import { type UiI18n, useI18n } from "../context/i18n" import { BasicTool, GenericTool } from "./basic-tool" import { Accordion } from "./accordion" import { StickyAccordionHeader } from "./sticky-accordion-header" -import { Card } from "./card" import { Collapsible } from "./collapsible" import { FileIcon } from "./file-icon" import { Icon } from "./icon" diff --git a/packages/ui/src/components/timeline-playground.stories.tsx b/packages/ui/src/components/timeline-playground.stories.tsx index 98cdf8500..282592ff6 100644 --- a/packages/ui/src/components/timeline-playground.stories.tsx +++ b/packages/ui/src/components/timeline-playground.stories.tsx @@ -1,5 +1,5 @@ // @ts-nocheck -import { createSignal, createMemo, createEffect, on, For, Show, Index, batch } from "solid-js" +import { createSignal, createMemo, createEffect, on, For, Show, batch } from "solid-js" import { createStore, produce } from "solid-js/store" import type { Message, diff --git a/packages/ui/src/pierre/commented-lines.ts b/packages/ui/src/pierre/commented-lines.ts index d2fa64866..e970b7841 100644 --- a/packages/ui/src/pierre/commented-lines.ts +++ b/packages/ui/src/pierre/commented-lines.ts @@ -1,5 +1,5 @@ import { type SelectedLineRange } from "@pierre/diffs" -import { diffLineIndex, diffRowIndex, findDiffSide } from "./diff-selection" +import { diffLineIndex, diffRowIndex } from "./diff-selection" export type CommentSide = "additions" | "deletions" diff --git a/sdks/vscode/src/extension.ts b/sdks/vscode/src/extension.ts index 105ab0293..772da9cc2 100644 --- a/sdks/vscode/src/extension.ts +++ b/sdks/vscode/src/extension.ts @@ -78,7 +78,7 @@ export function activate(context: vscode.ExtensionContext) { await fetch(`http://localhost:${port}/app`) connected = true break - } catch (e) {} + } catch {} tries-- } while (tries > 0) -- cgit v1.2.3 From 34213d444681a8953c5693bd01dd754c4e79a30b Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Wed, 15 Apr 2026 22:01:02 -0400 Subject: fix: delete 9 dead functions with zero callers (#22697) --- packages/app/src/context/global-sync/bootstrap.ts | 16 --------------- packages/function/src/api.ts | 14 ------------- packages/opencode/script/postinstall.mjs | 12 ----------- .../opencode/src/server/instance/httpapi/server.ts | 4 ---- packages/opencode/test/lib/llm-server.ts | 24 ---------------------- packages/opencode/test/session/compaction.test.ts | 19 ----------------- packages/ui/src/components/session-diff.ts | 14 ------------- .../src/components/timeline-playground.stories.tsx | 4 ---- 8 files changed, 107 deletions(-) (limited to 'packages/app/src/context/global-sync') diff --git a/packages/app/src/context/global-sync/bootstrap.ts b/packages/app/src/context/global-sync/bootstrap.ts index ad987efa6..2f9147498 100644 --- a/packages/app/src/context/global-sync/bootstrap.ts +++ b/packages/app/src/context/global-sync/bootstrap.ts @@ -65,22 +65,6 @@ function runAll(list: Array<() => Promise>) { return Promise.allSettled(list.map((item) => item())) } -function showErrors(input: { - errors: unknown[] - title: string - translate: (key: string, vars?: Record) => string - formatMoreCount: (count: number) => string -}) { - if (input.errors.length === 0) return - const message = formatServerError(input.errors[0], input.translate) - const more = input.errors.length > 1 ? input.formatMoreCount(input.errors.length - 1) : "" - showToast({ - variant: "error", - title: input.title, - description: message + more, - }) -} - export async function bootstrapGlobal(input: { globalSDK: OpencodeClient requestFailedTitle: string diff --git a/packages/function/src/api.ts b/packages/function/src/api.ts index d6565b287..4d8b295ec 100644 --- a/packages/function/src/api.ts +++ b/packages/function/src/api.ts @@ -12,20 +12,6 @@ type Env = { WEB_DOMAIN: string } -async function getFeishuTenantToken(): Promise { - const response = await fetch("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - app_id: Resource.FEISHU_APP_ID.value, - app_secret: Resource.FEISHU_APP_SECRET.value, - }), - }) - const data = (await response.json()) as { tenant_access_token?: string } - if (!data.tenant_access_token) throw new Error("Failed to get Feishu tenant token") - return data.tenant_access_token -} - export class SyncServer extends DurableObject { constructor(ctx: DurableObjectState, env: Env) { super(ctx, env) diff --git a/packages/opencode/script/postinstall.mjs b/packages/opencode/script/postinstall.mjs index 98f23e16f..2b990251c 100644 --- a/packages/opencode/script/postinstall.mjs +++ b/packages/opencode/script/postinstall.mjs @@ -85,18 +85,6 @@ function prepareBinDirectory(binaryName) { return { binDir, targetPath } } -function symlinkBinary(sourcePath, binaryName) { - const { targetPath } = prepareBinDirectory(binaryName) - - fs.symlinkSync(sourcePath, targetPath) - console.log(`opencode binary symlinked: ${targetPath} -> ${sourcePath}`) - - // Verify the file exists after operation - if (!fs.existsSync(targetPath)) { - throw new Error(`Failed to symlink binary to ${targetPath}`) - } -} - async function main() { try { if (os.platform() === "win32") { diff --git a/packages/opencode/src/server/instance/httpapi/server.ts b/packages/opencode/src/server/instance/httpapi/server.ts index 363e93a24..54c3c57ff 100644 --- a/packages/opencode/src/server/instance/httpapi/server.ts +++ b/packages/opencode/src/server/instance/httpapi/server.ts @@ -26,10 +26,6 @@ const Headers = Schema.Struct({ }) export namespace ExperimentalHttpApiServer { - function text(input: string, status: number, headers?: Record) { - return HttpServerResponse.text(input, { status, headers }) - } - function decode(input: string) { try { return decodeURIComponent(input) diff --git a/packages/opencode/test/lib/llm-server.ts b/packages/opencode/test/lib/llm-server.ts index 2e2a2ea89..1f873a9fb 100644 --- a/packages/opencode/test/lib/llm-server.ts +++ b/packages/opencode/test/lib/llm-server.ts @@ -596,35 +596,11 @@ function hit(url: string, body: unknown) { } satisfies Hit } -/** Auto-acknowledging tool-result follow-ups avoids requiring tests to queue two responses per tool call. */ -function isToolResultFollowUp(body: unknown): boolean { - if (!body || typeof body !== "object") return false - // OpenAI chat format: last message has role "tool" - if ("messages" in body && Array.isArray(body.messages)) { - const last = body.messages[body.messages.length - 1] - return last?.role === "tool" - } - // Responses API: input contains function_call_output - if ("input" in body && Array.isArray(body.input)) { - return body.input.some((item: Record) => item?.type === "function_call_output") - } - return false -} - function isTitleRequest(body: unknown): boolean { if (!body || typeof body !== "object") return false return JSON.stringify(body).includes("Generate a title for this conversation") } -function requestSummary(body: unknown): string { - if (!body || typeof body !== "object") return "empty body" - if ("messages" in body && Array.isArray(body.messages)) { - const roles = body.messages.map((m: Record) => m.role).join(",") - return `messages=[${roles}]` - } - return `keys=[${Object.keys(body).join(",")}]` -} - namespace TestLLMServer { export interface Service { readonly url: string diff --git a/packages/opencode/test/session/compaction.test.ts b/packages/opencode/test/session/compaction.test.ts index d658f48bd..7711d3193 100644 --- a/packages/opencode/test/session/compaction.test.ts +++ b/packages/opencode/test/session/compaction.test.ts @@ -143,25 +143,6 @@ async function assistant(sessionID: SessionID, parentID: MessageID, root: string return msg } -async function tool(sessionID: SessionID, messageID: MessageID, tool: string, output: string) { - return svc.updatePart({ - id: PartID.ascending(), - messageID, - sessionID, - type: "tool", - callID: crypto.randomUUID(), - tool, - state: { - status: "completed", - input: {}, - output, - title: "done", - metadata: {}, - time: { start: Date.now(), end: Date.now() }, - }, - }) -} - function fake( input: Parameters[0], result: "continue" | "compact", diff --git a/packages/ui/src/components/session-diff.ts b/packages/ui/src/components/session-diff.ts index d791c7fc1..a5fbdbc5c 100644 --- a/packages/ui/src/components/session-diff.ts +++ b/packages/ui/src/components/session-diff.ts @@ -25,20 +25,6 @@ export type ViewDiff = { const cache = new Map() -function empty(file: string, key: string) { - return { - name: file, - type: "change", - hunks: [], - splitLineCount: 0, - unifiedLineCount: 0, - isPartial: true, - deletionLines: [], - additionLines: [], - cacheKey: key, - } satisfies FileDiffMetadata -} - function patch(diff: ReviewDiff) { if (typeof diff.patch === "string") { const [patch] = parsePatch(diff.patch) diff --git a/packages/ui/src/components/timeline-playground.stories.tsx b/packages/ui/src/components/timeline-playground.stories.tsx index 282592ff6..fa3e7ff79 100644 --- a/packages/ui/src/components/timeline-playground.stories.tsx +++ b/packages/ui/src/components/timeline-playground.stories.tsx @@ -555,10 +555,6 @@ function toolPart(sample: (typeof TOOL_SAMPLES)[keyof typeof TOOL_SAMPLES], stat } as ToolPart } -function compactionPart(): CompactionPart { - return { id: uid(), type: "compaction", auto: true } as CompactionPart -} - // --------------------------------------------------------------------------- // CSS Controls definition // --------------------------------------------------------------------------- -- cgit v1.2.3 From cf423d27693ab5718eb836bdba7ba3ed357204b0 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Wed, 15 Apr 2026 22:17:59 -0400 Subject: fix: remove 10 unused type-only imports and declarations (#22696) --- packages/app/src/components/file-tree.tsx | 1 - packages/app/src/context/global-sync/types.ts | 1 - packages/app/src/i18n/ko.ts | 2 -- packages/opencode/src/cli/cmd/tui/context/sdk.tsx | 2 +- packages/opencode/src/cli/cmd/tui/plugin/api.tsx | 1 - packages/opencode/src/cli/cmd/tui/ui/dialog-export-options.tsx | 2 +- packages/opencode/test/fixture/plugin-meta-worker.ts | 7 ------- packages/opencode/test/mcp/oauth-auto-connect.test.ts | 1 - packages/opencode/test/session/prompt-effect.test.ts | 1 - packages/plugin/src/tui.ts | 1 - 10 files changed, 2 insertions(+), 17 deletions(-) (limited to 'packages/app/src/context/global-sync') diff --git a/packages/app/src/components/file-tree.tsx b/packages/app/src/components/file-tree.tsx index 8fbecf671..211ce05ef 100644 --- a/packages/app/src/components/file-tree.tsx +++ b/packages/app/src/components/file-tree.tsx @@ -14,7 +14,6 @@ import { Switch, untrack, type ComponentProps, - type JSXElement, type ParentProps, } from "solid-js" import { Dynamic } from "solid-js/web" diff --git a/packages/app/src/context/global-sync/types.ts b/packages/app/src/context/global-sync/types.ts index b0f340a90..e3ec83c5e 100644 --- a/packages/app/src/context/global-sync/types.ts +++ b/packages/app/src/context/global-sync/types.ts @@ -8,7 +8,6 @@ import type { Part, Path, PermissionRequest, - Project, ProviderListResponse, QuestionRequest, Session, diff --git a/packages/app/src/i18n/ko.ts b/packages/app/src/i18n/ko.ts index 0f2f7647a..1c1572009 100644 --- a/packages/app/src/i18n/ko.ts +++ b/packages/app/src/i18n/ko.ts @@ -1,7 +1,5 @@ import { dict as en } from "./en" -type Keys = keyof typeof en - export const dict = { "command.category.suggested": "추천", "command.category.view": "보기", diff --git a/packages/opencode/src/cli/cmd/tui/context/sdk.tsx b/packages/opencode/src/cli/cmd/tui/context/sdk.tsx index ad35aa45c..14d306288 100644 --- a/packages/opencode/src/cli/cmd/tui/context/sdk.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/sdk.tsx @@ -1,5 +1,5 @@ import { createOpencodeClient } from "@opencode-ai/sdk/v2" -import type { GlobalEvent, Event } from "@opencode-ai/sdk/v2" +import type { GlobalEvent } from "@opencode-ai/sdk/v2" import { createSimpleContext } from "./helper" import { createGlobalEmitter } from "@solid-primitives/event-bus" import { batch, onCleanup, onMount } from "solid-js" diff --git a/packages/opencode/src/cli/cmd/tui/plugin/api.tsx b/packages/opencode/src/cli/cmd/tui/plugin/api.tsx index 42bf78adb..3af70d8c2 100644 --- a/packages/opencode/src/cli/cmd/tui/plugin/api.tsx +++ b/packages/opencode/src/cli/cmd/tui/plugin/api.tsx @@ -19,7 +19,6 @@ import { Prompt } from "../component/prompt" import { Slot as HostSlot } from "./slots" import type { useToast } from "../ui/toast" import { Installation } from "@/installation" -import { type OpencodeClient } from "@opencode-ai/sdk/v2" type RouteEntry = { key: symbol diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog-export-options.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog-export-options.tsx index 4442eb9e6..513d34910 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog-export-options.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog-export-options.tsx @@ -2,7 +2,7 @@ import { TextareaRenderable, TextAttributes } from "@opentui/core" import { useTheme } from "../context/theme" import { useDialog, type DialogContext } from "./dialog" import { createStore } from "solid-js/store" -import { onMount, Show, type JSX } from "solid-js" +import { onMount, Show } from "solid-js" import { useKeyboard } from "@opentui/solid" export type DialogExportOptionsProps = { diff --git a/packages/opencode/test/fixture/plugin-meta-worker.ts b/packages/opencode/test/fixture/plugin-meta-worker.ts index 86284b4c7..c02b448ae 100644 --- a/packages/opencode/test/fixture/plugin-meta-worker.ts +++ b/packages/opencode/test/fixture/plugin-meta-worker.ts @@ -1,10 +1,3 @@ -type Msg = { - file: string - spec: string - target: string - id: string -} - const raw = process.argv[2] if (!raw) throw new Error("Missing worker payload") diff --git a/packages/opencode/test/mcp/oauth-auto-connect.test.ts b/packages/opencode/test/mcp/oauth-auto-connect.test.ts index 13ae0bb34..89edd0908 100644 --- a/packages/opencode/test/mcp/oauth-auto-connect.test.ts +++ b/packages/opencode/test/mcp/oauth-auto-connect.test.ts @@ -1,6 +1,5 @@ import { test, expect, mock, beforeEach } from "bun:test" import { Effect } from "effect" -import type { MCP as MCPNS } from "../../src/mcp/index" // Mock UnauthorizedError to match the SDK's class class MockUnauthorizedError extends Error { diff --git a/packages/opencode/test/session/prompt-effect.test.ts b/packages/opencode/test/session/prompt-effect.test.ts index 7a118cb05..5ff8bf342 100644 --- a/packages/opencode/test/session/prompt-effect.test.ts +++ b/packages/opencode/test/session/prompt-effect.test.ts @@ -14,7 +14,6 @@ import { Permission } from "../../src/permission" import { Plugin } from "../../src/plugin" import { Provider as ProviderSvc } from "../../src/provider" import { Env } from "../../src/env" -import type { Provider } from "../../src/provider" import { ModelID, ProviderID } from "../../src/provider/schema" import { Question } from "../../src/question" import { Todo } from "../../src/session/todo" diff --git a/packages/plugin/src/tui.ts b/packages/plugin/src/tui.ts index e6f832f7e..099cf2758 100644 --- a/packages/plugin/src/tui.ts +++ b/packages/plugin/src/tui.ts @@ -13,7 +13,6 @@ import type { QuestionRequest, SessionStatus, TextPart, - Workspace, Config as SdkConfig, } from "@opencode-ai/sdk/v2" import type { CliRenderer, ParsedKey, RGBA, SlotMode } from "@opentui/core" -- cgit v1.2.3 From 97918500d4020a7b44f3636f23daabc8c477008b Mon Sep 17 00:00:00 2001 From: Brendan Allan Date: Thu, 16 Apr 2026 14:10:23 +0800 Subject: app: start migrating bootstrap data fetching to TanStack Query (#22756) --- bun.lock | 4 + packages/app/src/app.tsx | 23 +- packages/app/src/components/prompt-input.tsx | 203 +++++++++------- packages/app/src/context/global-sync.tsx | 91 ++++--- packages/app/src/context/global-sync/bootstrap.ts | 269 ++++++++++++--------- .../app/src/context/global-sync/child-store.ts | 1 + packages/app/src/context/global-sync/types.ts | 1 + packages/app/src/pages/layout.tsx | 10 +- .../app/src/pages/layout/sidebar-workspace.tsx | 8 +- packages/app/src/pages/session.tsx | 16 +- 10 files changed, 355 insertions(+), 271 deletions(-) (limited to 'packages/app/src/context/global-sync') diff --git a/bun.lock b/bun.lock index 644de37f2..c15653379 100644 --- a/bun.lock +++ b/bun.lock @@ -75,6 +75,7 @@ "@types/luxon": "catalog:", "@types/node": "catalog:", "@typescript/native-preview": "catalog:", + "tw-animate-css": "1.4.0", "typescript": "catalog:", "vite": "catalog:", "vite-plugin-icons-spritesheet": "3.0.1", @@ -597,6 +598,7 @@ "solid-js": "catalog:", "solid-list": "catalog:", "strip-ansi": "7.1.2", + "tw-animate-css": "1.4.0", "virtua": "catalog:", }, "devDependencies": { @@ -4859,6 +4861,8 @@ "turndown": ["turndown@7.2.0", "", { "dependencies": { "@mixmark-io/domino": "^2.2.0" } }, "sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A=="], + "tw-animate-css": ["tw-animate-css@1.4.0", "", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="], + "tw-to-css": ["tw-to-css@0.0.12", "", { "dependencies": { "postcss": "8.4.31", "postcss-css-variables": "0.18.0", "tailwindcss": "3.3.2" } }, "sha512-rQAsQvOtV1lBkyCw+iypMygNHrShYAItES5r8fMsrhhaj5qrV2LkZyXc8ccEH+u5bFjHjQ9iuxe90I7Kykf6pw=="], "type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], diff --git a/packages/app/src/app.tsx b/packages/app/src/app.tsx index a2a746c05..dbe107448 100644 --- a/packages/app/src/app.tsx +++ b/packages/app/src/app.tsx @@ -121,10 +121,10 @@ function SessionProviders(props: ParentProps) { function RouterRoot(props: ParentProps<{ appChildren?: JSX.Element }>) { return ( - }> - {props.appChildren} - {props.children} - + {/*}>*/} + {props.appChildren} + {props.children} + {/**/} ) } @@ -184,14 +184,22 @@ function ConnectionGate(props: ParentProps<{ disableHealthCheck?: boolean }>) { ) return ( -
} > + {/* + + + } + >*/} + {checkMode() === "blocking" ? startupHealthCheck() : startupHealthCheck.latest} ) { > {props.children} - + {/**/} + ) } diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx index 534215022..156b0b3a4 100644 --- a/packages/app/src/components/prompt-input.tsx +++ b/packages/app/src/components/prompt-input.tsx @@ -54,6 +54,8 @@ import { PromptImageAttachments } from "./prompt-input/image-attachments" import { PromptDragOverlay } from "./prompt-input/drag-overlay" import { promptPlaceholder } from "./prompt-input/placeholder" import { ImagePreview } from "@opencode-ai/ui/image-preview" +import { useQuery } from "@tanstack/solid-query" +import { loadAgentsQuery, loadProvidersQuery } from "@/context/global-sync/bootstrap" interface PromptInputProps { class?: string @@ -100,6 +102,7 @@ const NON_EMPTY_TEXT = /[^\s\u200B]/ export const PromptInput: Component = (props) => { const sdk = useSDK() + const sync = useSync() const local = useLocal() const files = useFile() @@ -1249,6 +1252,14 @@ export const PromptInput: Component = (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 (
= (props) => { {language.t("prompt.mode.shell")}
-
-
- - { + local.agent.set(value) + restoreFocus() + }} + class="capitalize max-w-[160px] text-text-base" + valueClass="truncate text-13-regular text-text-base" + triggerStyle={control()} + triggerProps={{ "data-action": "prompt-agent" }} + variant="ghost" + /> + +
+ + + +
+ 0} + fallback={ + + + + } + > - + - } - > + +
+
- (x === "default" ? language.t("common.default") : x)} + onSelect={(value) => { + local.model.variant.set(value === "default" ? undefined : value) + restoreFocus() }} - onClose={restoreFocus} - > - - - - - {local.model.current()?.name ?? language.t("dialog.model.select.title")} - - - + 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" + /> - -
-
- -