From 99f1e7214dcb2373d2d8c0e84c74cc0d258919d8 Mon Sep 17 00:00:00 2001 From: Maksym Diabin Date: Fri, 20 Feb 2026 14:58:05 +0100 Subject: [PATCH 1/2] fix(ci): make CI runner labels configurable via repository variables Replace hardcoded Blacksmith runner labels with repository-variable fallbacks (e.g. vars.RUNNER_UBUNTU, vars.RUNNER_WINDOWS) so forks can use their own runners. Replace Blacksmith stickydisk with actions/cache. Defaults preserve the existing Blacksmith configuration for the upstream repo. Ref: anomalyco/opencode#14305 Co-Authored-By: codemie-ai --- .github/workflows/deploy.yml | 2 +- .github/workflows/generate.yml | 2 +- .github/workflows/nix-eval.yml | 2 +- .github/workflows/nix-hashes.yml | 6 +++--- .github/workflows/pr-management.yml | 2 +- .github/workflows/test.yml | 8 ++++---- .github/workflows/typecheck.yml | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index c08d7edf3b1..c42a4f0733d 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -11,7 +11,7 @@ concurrency: ${{ github.workflow }}-${{ github.ref }} jobs: deploy: - runs-on: blacksmith-4vcpu-ubuntu-2404 + runs-on: ${{ vars.RUNNER_UBUNTU || 'blacksmith-4vcpu-ubuntu-2404' }} steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml index 706ab2989e1..4e71719a1a2 100644 --- a/.github/workflows/generate.yml +++ b/.github/workflows/generate.yml @@ -7,7 +7,7 @@ on: jobs: generate: - runs-on: blacksmith-4vcpu-ubuntu-2404 + runs-on: ${{ vars.RUNNER_UBUNTU || 'blacksmith-4vcpu-ubuntu-2404' }} permissions: contents: write pull-requests: write diff --git a/.github/workflows/nix-eval.yml b/.github/workflows/nix-eval.yml index c76b2c97297..f3f726e4970 100644 --- a/.github/workflows/nix-eval.yml +++ b/.github/workflows/nix-eval.yml @@ -16,7 +16,7 @@ permissions: jobs: nix-eval: - runs-on: blacksmith-4vcpu-ubuntu-2404 + runs-on: ${{ vars.RUNNER_UBUNTU || 'blacksmith-4vcpu-ubuntu-2404' }} timeout-minutes: 15 steps: - name: Checkout repository diff --git a/.github/workflows/nix-hashes.yml b/.github/workflows/nix-hashes.yml index 2529c14c208..6f0c375c9aa 100644 --- a/.github/workflows/nix-hashes.yml +++ b/.github/workflows/nix-hashes.yml @@ -26,9 +26,9 @@ jobs: matrix: include: - system: x86_64-linux - runner: blacksmith-4vcpu-ubuntu-2404 + runner: ${{ vars.RUNNER_UBUNTU || 'blacksmith-4vcpu-ubuntu-2404' }} - system: aarch64-linux - runner: blacksmith-4vcpu-ubuntu-2404-arm + runner: ${{ vars.RUNNER_UBUNTU_ARM || 'blacksmith-4vcpu-ubuntu-2404-arm' }} - system: x86_64-darwin runner: macos-15-intel - system: aarch64-darwin @@ -77,7 +77,7 @@ jobs: update-hashes: needs: compute-hash if: github.event_name != 'pull_request' - runs-on: blacksmith-4vcpu-ubuntu-2404 + runs-on: ${{ vars.RUNNER_UBUNTU || 'blacksmith-4vcpu-ubuntu-2404' }} steps: - name: Checkout repository diff --git a/.github/workflows/pr-management.yml b/.github/workflows/pr-management.yml index 35bd7ae36f2..7c567fa3fe8 100644 --- a/.github/workflows/pr-management.yml +++ b/.github/workflows/pr-management.yml @@ -6,7 +6,7 @@ on: jobs: check-duplicates: - runs-on: blacksmith-4vcpu-ubuntu-2404 + runs-on: ${{ vars.RUNNER_UBUNTU || 'blacksmith-4vcpu-ubuntu-2404' }} permissions: contents: read pull-requests: write diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 647b9e18869..80ccb4273d0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,7 +9,7 @@ on: jobs: unit: name: unit (linux) - runs-on: blacksmith-4vcpu-ubuntu-2404 + runs-on: ${{ vars.RUNNER_UBUNTU || 'blacksmith-4vcpu-ubuntu-2404' }} defaults: run: shell: bash @@ -38,10 +38,10 @@ jobs: matrix: settings: - name: linux - host: blacksmith-4vcpu-ubuntu-2404 + host: ${{ vars.RUNNER_UBUNTU || 'blacksmith-4vcpu-ubuntu-2404' }} playwright: bunx playwright install --with-deps - name: windows - host: blacksmith-4vcpu-windows-2025 + host: ${{ vars.RUNNER_WINDOWS || 'blacksmith-4vcpu-windows-2025' }} playwright: bunx playwright install runs-on: ${{ matrix.settings.host }} env: @@ -81,7 +81,7 @@ jobs: required: name: test (linux) - runs-on: blacksmith-4vcpu-ubuntu-2404 + runs-on: ${{ vars.RUNNER_UBUNTU || 'blacksmith-4vcpu-ubuntu-2404' }} needs: - unit - e2e diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml index b247d24b40d..6021d782eb7 100644 --- a/.github/workflows/typecheck.yml +++ b/.github/workflows/typecheck.yml @@ -9,7 +9,7 @@ on: jobs: typecheck: - runs-on: blacksmith-4vcpu-ubuntu-2404 + runs-on: ${{ vars.RUNNER_UBUNTU || 'blacksmith-4vcpu-ubuntu-2404' }} steps: - name: Checkout repository uses: actions/checkout@v4 From 1049d6bfb7419b81ae1bdb17a725479a8405c531 Mon Sep 17 00:00:00 2001 From: Maksym Diabin Date: Fri, 20 Feb 2026 14:59:44 +0100 Subject: [PATCH 2/2] feat: add codemie whitelabel package and rebrand - Add codemie npm package with platform-specific binary distribution - Add publish CI workflow for codemie packages - Rebrand TUI/CLI from opencode to codemie-code - Remove OpenCode Zen inference provider references and sharing features - Redesign logo with readable M and sweep animation - Add explicit TypeScript type annotations to callback parameters - Disable Cloudflare deployment (local-only sessions) - Remove Stripe and PlanetScale providers from SST config - Add Apache-2.0 license and README to platform packages Co-Authored-By: codemie-ai --- .github/workflows/deploy.yml | 13 +- .github/workflows/publish-codemie.yml | 63 +++++++++ bun.lock | 33 +++-- packages/codemie/.gitignore | 2 + packages/codemie/README.md | 30 +++++ packages/codemie/README.platform.md | 14 ++ packages/codemie/bin/codemie | 93 +++++++++++++ packages/codemie/package.json | 18 +++ packages/codemie/script/build.ts | 105 +++++++++++++++ packages/codemie/script/postinstall.mjs | 125 ++++++++++++++++++ packages/codemie/script/publish.ts | 74 +++++++++++ packages/opencode/script/build.ts | 1 + packages/opencode/src/acp/agent.ts | 22 +-- packages/opencode/src/acp/session.ts | 4 +- packages/opencode/src/cli/cmd/auth.ts | 2 +- packages/opencode/src/cli/cmd/pr.ts | 8 +- packages/opencode/src/cli/cmd/run.ts | 4 +- packages/opencode/src/cli/cmd/serve.ts | 4 +- packages/opencode/src/cli/cmd/tui/app.tsx | 16 +-- packages/opencode/src/cli/cmd/tui/attach.ts | 2 +- .../cmd/tui/component/dialog-session-list.tsx | 6 +- .../cli/cmd/tui/component/dialog-skill.tsx | 4 +- .../src/cli/cmd/tui/component/dialog-tag.tsx | 4 +- .../src/cli/cmd/tui/component/logo.tsx | 109 ++++++++++++--- .../cmd/tui/component/prompt/autocomplete.tsx | 4 +- .../cli/cmd/tui/component/prompt/index.tsx | 2 +- .../src/cli/cmd/tui/component/tips.tsx | 34 ++--- .../opencode/src/cli/cmd/tui/context/sync.tsx | 36 ++--- .../src/cli/cmd/tui/routes/session/index.tsx | 2 +- .../cli/cmd/tui/routes/session/permission.tsx | 8 +- .../cli/cmd/tui/routes/session/sidebar.tsx | 6 +- packages/opencode/src/cli/cmd/tui/thread.ts | 4 +- packages/opencode/src/cli/cmd/uninstall.ts | 6 +- packages/opencode/src/cli/cmd/upgrade.ts | 2 +- packages/opencode/src/cli/cmd/web.ts | 2 +- packages/opencode/src/cli/error.ts | 4 +- packages/opencode/src/cli/logo.ts | 10 +- packages/opencode/src/cli/network.ts | 4 +- packages/opencode/src/cli/ui.ts | 27 ++-- packages/opencode/src/config/config.ts | 12 +- .../opencode/src/session/prompt/anthropic.txt | 10 +- .../opencode/src/session/prompt/beast.txt | 18 +-- packages/opencode/src/session/prompt/qwen.txt | 10 +- .../opencode/src/session/prompt/trinity.txt | 2 +- packages/script/src/index.ts | 5 +- script/version.ts | 2 +- sst.config.ts | 9 +- 47 files changed, 778 insertions(+), 197 deletions(-) create mode 100644 .github/workflows/publish-codemie.yml create mode 100644 packages/codemie/.gitignore create mode 100644 packages/codemie/README.md create mode 100644 packages/codemie/README.platform.md create mode 100644 packages/codemie/bin/codemie create mode 100644 packages/codemie/package.json create mode 100644 packages/codemie/script/build.ts create mode 100644 packages/codemie/script/postinstall.mjs create mode 100644 packages/codemie/script/publish.ts diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index c42a4f0733d..d224bbc7bd8 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,10 +1,9 @@ name: deploy +# Disabled: Cloudflare deployment is not used for local-only codemie. +# Artifacts are produced by the publish-codemie workflow instead. +# To re-enable, restore the push trigger below. on: - push: - branches: - - dev - - production workflow_dispatch: concurrency: ${{ github.workflow }}-${{ github.ref }} @@ -30,9 +29,7 @@ jobs: - name: Fix Pulumi version conflict run: sudo rm -f /usr/local/bin/pulumi-language-nodejs - - run: bun sst deploy --stage=${{ github.ref_name }} + - run: bun sst deploy --stage=${{ github.ref_name }} --print-logs env: CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} - PLANETSCALE_SERVICE_TOKEN_NAME: ${{ secrets.PLANETSCALE_SERVICE_TOKEN_NAME }} - PLANETSCALE_SERVICE_TOKEN: ${{ secrets.PLANETSCALE_SERVICE_TOKEN }} - STRIPE_SECRET_KEY: ${{ github.ref_name == 'production' && secrets.STRIPE_SECRET_KEY_PROD || secrets.STRIPE_SECRET_KEY_DEV }} + CLOUDFLARE_DEFAULT_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_DEFAULT_ACCOUNT_ID }} diff --git a/.github/workflows/publish-codemie.yml b/.github/workflows/publish-codemie.yml new file mode 100644 index 00000000000..7a8b075ef18 --- /dev/null +++ b/.github/workflows/publish-codemie.yml @@ -0,0 +1,63 @@ +name: publish-codemie + +on: + workflow_dispatch: + inputs: + bump: + description: "Bump major, minor, or patch" + required: false + type: choice + options: + - major + - minor + - patch + version: + description: "Override version (optional)" + required: false + type: string + +permissions: + id-token: write + contents: read + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - uses: ./.github/actions/setup-bun + + - uses: actions/setup-node@v4 + with: + node-version: "24" + registry-url: "https://registry.npmjs.org" + + - name: Determine version + id: version + run: ./script/version.ts + env: + GH_TOKEN: ${{ github.token }} + OPENCODE_BUMP: ${{ inputs.bump }} + OPENCODE_VERSION: ${{ inputs.version }} + OPENCODE_NPM_PACKAGE: "@codemieai/codemie-opencode" + OPENCODE_SKIP_RELEASE: "true" + + - name: Build codemie + run: bun run build + working-directory: packages/codemie + env: + OPENCODE_VERSION: ${{ steps.version.outputs.version }} + OPENCODE_RELEASE: ${{ steps.version.outputs.release }} + GH_TOKEN: ${{ github.token }} + + - name: Publish codemie to npm + run: bun run publish:npm + working-directory: packages/codemie + env: + OPENCODE_VERSION: ${{ steps.version.outputs.version }} + OPENCODE_RELEASE: ${{ steps.version.outputs.release }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + NPM_CONFIG_PROVENANCE: false diff --git a/bun.lock b/bun.lock index 04da112cf79..91a77a3c13b 100644 --- a/bun.lock +++ b/bun.lock @@ -73,6 +73,17 @@ "vite-plugin-solid": "catalog:", }, }, + "packages/codemie": { + "name": "codemie", + "version": "1.1.56", + "bin": { + "codemie": "./bin/codemie", + }, + "devDependencies": { + "@opencode-ai/script": "workspace:*", + "@types/bun": "catalog:", + }, + }, "packages/console/app": { "name": "@opencode-ai/console-app", "version": "1.2.10", @@ -1962,7 +1973,7 @@ "@types/scheduler": ["@types/scheduler@0.26.0", "", {}, "sha512-WFHp9YUJQ6CKshqoC37iOlHnQSmxNc795UhB26CyBBttrN9svdIrUjl/NjnNmfcwtncN0h/0PPAFWv9ovP8mLA=="], - "@types/send": ["@types/send@1.2.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ=="], + "@types/send": ["@types/send@0.17.6", "", { "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og=="], "@types/serve-static": ["@types/serve-static@1.15.10", "", { "dependencies": { "@types/http-errors": "*", "@types/node": "*", "@types/send": "<1" } }, "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw=="], @@ -2160,7 +2171,7 @@ "bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="], - "balanced-match": ["balanced-match@4.0.2", "", { "dependencies": { "jackspeak": "^4.2.3" } }, "sha512-x0K50QvKQ97fdEz2kPehIerj+YTeptKF9hyYkKf6egnwmMWAkADiO0QCzSp0R5xN8FTZgYaBfSaue46Ej62nMg=="], + "balanced-match": ["balanced-match@4.0.3", "", {}, "sha512-1pHv8LX9CpKut1Zp4EXey7Z8OfH11ONNH6Dhi2WDUt31VVZFXZzKwXcysBgqSumFCmR+0dqjMK5v5JiFHzi0+g=="], "bare-events": ["bare-events@2.8.2", "", { "peerDependencies": { "bare-abort-controller": "*" }, "optionalPeers": ["bare-abort-controller"] }, "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ=="], @@ -2304,6 +2315,8 @@ "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], + "codemie": ["codemie@workspace:packages/codemie"], + "collapse-white-space": ["collapse-white-space@2.1.0", "", {}, "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw=="], "color": ["color@4.2.3", "", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="], @@ -4144,7 +4157,7 @@ "xml-parse-from-string": ["xml-parse-from-string@1.0.1", "", {}, "sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g=="], - "xml2js": ["xml2js@0.5.0", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA=="], + "xml2js": ["xml2js@0.6.2", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA=="], "xmlbuilder": ["xmlbuilder@11.0.1", "", {}, "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="], @@ -4416,6 +4429,8 @@ "@azure/core-http/uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], + "@azure/core-http/xml2js": ["xml2js@0.5.0", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA=="], + "@azure/core-xml/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], "@azure/msal-node/uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], @@ -4632,8 +4647,6 @@ "@tanstack/server-functions-plugin/@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], - "@types/serve-static/@types/send": ["@types/send@0.17.6", "", { "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og=="], - "@vscode/emmet-helper/jsonc-parser": ["jsonc-parser@2.3.1", "", {}, "sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg=="], "accepts/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], @@ -4672,8 +4685,6 @@ "aws-sdk/events": ["events@1.1.1", "", {}, "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw=="], - "aws-sdk/xml2js": ["xml2js@0.6.2", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA=="], - "babel-plugin-jsx-dom-expressions/@babel/helper-module-imports": ["@babel/helper-module-imports@7.18.6", "", { "dependencies": { "@babel/types": "^7.18.6" } }, "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA=="], "babel-plugin-module-resolver/glob": ["glob@9.3.5", "", { "dependencies": { "fs.realpath": "^1.0.0", "minimatch": "^8.0.2", "minipass": "^4.2.4", "path-scurry": "^1.6.1" } }, "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q=="], @@ -4686,8 +4697,6 @@ "body-parser/qs": ["qs@6.14.2", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q=="], - "buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], - "bun-webgpu/@webgpu/types": ["@webgpu/types@0.1.69", "", {}, "sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ=="], "c12/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], @@ -4800,6 +4809,8 @@ "p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + "parse-bmfont-xml/xml2js": ["xml2js@0.5.0", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA=="], + "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], "parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], @@ -4898,8 +4909,6 @@ "wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "xml2js/sax": ["sax@1.4.4", "", {}, "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw=="], - "yaml-language-server/lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], "yaml-language-server/request-light": ["request-light@0.5.8", "", {}, "sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg=="], @@ -5240,8 +5249,6 @@ "astro/unstorage/ofetch": ["ofetch@1.5.1", "", { "dependencies": { "destr": "^2.0.5", "node-fetch-native": "^1.6.7", "ufo": "^1.6.1" } }, "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA=="], - "aws-sdk/xml2js/sax": ["sax@1.4.4", "", {}, "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw=="], - "babel-plugin-module-resolver/glob/minimatch": ["minimatch@8.0.4", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA=="], "babel-plugin-module-resolver/glob/minipass": ["minipass@4.2.8", "", {}, "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ=="], diff --git a/packages/codemie/.gitignore b/packages/codemie/.gitignore new file mode 100644 index 00000000000..de4d1f007dd --- /dev/null +++ b/packages/codemie/.gitignore @@ -0,0 +1,2 @@ +dist +node_modules diff --git a/packages/codemie/README.md b/packages/codemie/README.md new file mode 100644 index 00000000000..eabb1bcf7e8 --- /dev/null +++ b/packages/codemie/README.md @@ -0,0 +1,30 @@ +# @codemieai/codemie-opencode + +AI coding agent for [Codemie Code](https://github.com/codemie-ai/codemie-opencode). + +## How it works + +This is a wrapper package that automatically installs the correct platform-specific binary for your OS and architecture. You don't need to install platform packages directly. + +## Supported platforms + +| OS | Architecture | +| ------- | ------------ | +| macOS | arm64 | +| macOS | x64 | +| Linux | arm64 | +| Linux | x64 | +| Linux | x64 (musl) | +| Windows | x64 | + +## Part of the @codemieai/code ecosystem + +This package is a component of the [`@codemieai/code`](https://www.npmjs.com/package/@codemieai/code) CLI. It is installed automatically as a dependency — you typically don't need to install it yourself. + +## Links + +- [GitHub](https://github.com/codemie-ai/codemie-opencode) + +## License + +Apache-2.0 diff --git a/packages/codemie/README.platform.md b/packages/codemie/README.platform.md new file mode 100644 index 00000000000..6da3b0d38ad --- /dev/null +++ b/packages/codemie/README.platform.md @@ -0,0 +1,14 @@ +# @codemieai/codemie-opencode platform binary + +This package contains a platform-specific binary for [`@codemieai/codemie-opencode`](https://www.npmjs.com/package/@codemieai/codemie-opencode). + +It is **not meant to be installed directly** — it is installed automatically by the wrapper package when you install `@codemieai/codemie-opencode` or `@codemieai/code`. + +## Links + +- [Wrapper package](https://www.npmjs.com/package/@codemieai/codemie-opencode) +- [GitHub](https://github.com/codemie-ai/codemie-opencode) + +## License + +Apache-2.0 diff --git a/packages/codemie/bin/codemie b/packages/codemie/bin/codemie new file mode 100644 index 00000000000..c719ff4a628 --- /dev/null +++ b/packages/codemie/bin/codemie @@ -0,0 +1,93 @@ +#!/usr/bin/env node + +const childProcess = require("child_process") +const fs = require("fs") +const path = require("path") +const os = require("os") + +function run(target) { + const result = childProcess.spawnSync(target, process.argv.slice(2), { + stdio: "inherit", + }) + if (result.error) { + console.error(result.error.message) + process.exit(1) + } + const code = typeof result.status === "number" ? result.status : 0 + process.exit(code) +} + +const envPath = process.env.CODEMIE_BIN_PATH || process.env.OPENCODE_BIN_PATH +if (envPath) { + run(envPath) +} + +const scriptPath = fs.realpathSync(__filename) +const scriptDir = path.dirname(scriptPath) + +const platformMap = { + darwin: "darwin", + linux: "linux", + win32: "windows", +} +const archMap = { + x64: "x64", + arm64: "arm64", + arm: "arm", +} + +let platform = platformMap[os.platform()] +if (!platform) { + platform = os.platform() +} +let arch = archMap[os.arch()] +if (!arch) { + arch = os.arch() +} +const base = "codemie-opencode-" + platform + "-" + arch +const binary = platform === "windows" ? "codemie.exe" : "codemie" + +const scope = "@codemieai" + +function findBinary(startDir) { + let current = startDir + for (;;) { + const modules = path.join(current, "node_modules") + if (fs.existsSync(modules)) { + // Check scoped location first: node_modules/@codemieai/codemie-{platform}-{arch} + const scopedDir = path.join(modules, scope, base) + const scopedCandidate = path.join(scopedDir, "bin", binary) + if (fs.existsSync(scopedCandidate)) { + return scopedCandidate + } + // Fallback: unscoped (for backward compat) + const entries = fs.readdirSync(modules) + for (const entry of entries) { + if (!entry.startsWith(base)) { + continue + } + const candidate = path.join(modules, entry, "bin", binary) + if (fs.existsSync(candidate)) { + return candidate + } + } + } + const parent = path.dirname(current) + if (parent === current) { + return + } + current = parent + } +} + +const resolved = findBinary(scriptDir) +if (!resolved) { + console.error( + 'It seems that your package manager failed to install the right version of the codemie CLI for your platform. You can try manually installing the "' + + base + + '" package', + ) + process.exit(1) +} + +run(resolved) diff --git a/packages/codemie/package.json b/packages/codemie/package.json new file mode 100644 index 00000000000..28073fbe27a --- /dev/null +++ b/packages/codemie/package.json @@ -0,0 +1,18 @@ +{ + "name": "codemie", + "version": "1.1.56", + "type": "module", + "license": "Apache-2.0", + "private": true, + "scripts": { + "build": "bun run script/build.ts", + "publish:npm": "bun run script/publish.ts" + }, + "bin": { + "codemie": "./bin/codemie" + }, + "devDependencies": { + "@opencode-ai/script": "workspace:*", + "@types/bun": "catalog:" + } +} diff --git a/packages/codemie/script/build.ts b/packages/codemie/script/build.ts new file mode 100644 index 00000000000..160d547d193 --- /dev/null +++ b/packages/codemie/script/build.ts @@ -0,0 +1,105 @@ +#!/usr/bin/env bun + +import path from "path" +import fs from "fs" +import { $ } from "bun" +import { fileURLToPath } from "url" + +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) +const dir = path.resolve(__dirname, "..") +const opencodePkgDir = path.resolve(dir, "../opencode") + +process.chdir(dir) + +// Forward flags to the opencode build +const flags: string[] = [] +if (process.argv.includes("--single")) flags.push("--single") +if (process.argv.includes("--baseline")) flags.push("--baseline") +if (process.argv.includes("--skip-install")) flags.push("--skip-install") + +// Step 1: Run the opencode build as a subprocess +if (!process.argv.includes("--skip-opencode-build")) { + console.log("Running opencode build...") + const buildArgs = ["run", "script/build.ts", ...flags] + const result = Bun.spawnSync(["bun", ...buildArgs], { + cwd: opencodePkgDir, + stdio: ["inherit", "inherit", "inherit"], + env: { ...process.env }, + }) + + if (result.exitCode !== 0) { + console.error(`opencode build failed with exit code ${result.exitCode}`) + process.exit(1) + } +} else { + console.log("Skipping opencode build (--skip-opencode-build)") +} + +// Step 2: Clean our dist +await $`rm -rf dist` +await $`mkdir -p dist` + +// Step 3: Scan opencode dist for platform directories and copy+rename +const opencodeDistDir = path.join(opencodePkgDir, "dist") +if (!fs.existsSync(opencodeDistDir)) { + console.error(`opencode dist directory not found at ${opencodeDistDir}`) + process.exit(1) +} + +const entries = fs.readdirSync(opencodeDistDir) +const platformDirs = entries.filter((entry) => { + return entry.startsWith("opencode-") && fs.statSync(path.join(opencodeDistDir, entry)).isDirectory() +}) + +if (platformDirs.length === 0) { + console.error("No platform directories found in opencode dist") + process.exit(1) +} + +for (const platformDir of platformDirs) { + // Rename: opencode-darwin-arm64 → codemie-darwin-arm64 + const newName = platformDir.replace(/^opencode-/, "codemie-opencode-") + const srcDir = path.join(opencodeDistDir, platformDir) + const destDir = path.join(dir, "dist", newName) + + console.log(`Copying ${platformDir} → ${newName}`) + await $`cp -r ${srcDir} ${destDir}` + + // Rename binaries inside bin/ + const binDir = path.join(destDir, "bin") + if (fs.existsSync(binDir)) { + const oldBin = path.join(binDir, "opencode") + const newBin = path.join(binDir, "codemie") + if (fs.existsSync(oldBin)) { + fs.renameSync(oldBin, newBin) + } + + const oldExe = path.join(binDir, "opencode.exe") + const newExe = path.join(binDir, "codemie.exe") + if (fs.existsSync(oldExe)) { + fs.renameSync(oldExe, newExe) + } + } + + // Rewrite the platform package.json name field + const pkgJsonPath = path.join(destDir, "package.json") + if (fs.existsSync(pkgJsonPath)) { + const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8")) + pkgJson.name = "@codemieai/" + pkgJson.name.replace(/^opencode-/, "codemie-opencode-") + pkgJson.description = "Platform-specific binary for @codemieai/codemie-opencode" + pkgJson.repository = { type: "git", url: "https://github.com/codemie-ai/codemie-opencode" } + pkgJson.homepage = "https://github.com/codemie-ai/codemie-opencode" + pkgJson.license = "Apache-2.0" + fs.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2)) + } + + // Copy platform README + fs.copyFileSync(path.join(dir, "README.platform.md"), path.join(destDir, "README.md")) +} + +console.log("codemie build complete!") +console.log("Platform packages:") +for (const entry of fs.readdirSync(path.join(dir, "dist"))) { + console.log(` ${entry}`) +} diff --git a/packages/codemie/script/postinstall.mjs b/packages/codemie/script/postinstall.mjs new file mode 100644 index 00000000000..236f0017a01 --- /dev/null +++ b/packages/codemie/script/postinstall.mjs @@ -0,0 +1,125 @@ +#!/usr/bin/env node + +import fs from "fs" +import path from "path" +import os from "os" +import { fileURLToPath } from "url" +import { createRequire } from "module" + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) +const require = createRequire(import.meta.url) + +function detectPlatformAndArch() { + // Map platform names + let platform + switch (os.platform()) { + case "darwin": + platform = "darwin" + break + case "linux": + platform = "linux" + break + case "win32": + platform = "windows" + break + default: + platform = os.platform() + break + } + + // Map architecture names + let arch + switch (os.arch()) { + case "x64": + arch = "x64" + break + case "arm64": + arch = "arm64" + break + case "arm": + arch = "arm" + break + default: + arch = os.arch() + break + } + + return { platform, arch } +} + +function findBinary() { + const { platform, arch } = detectPlatformAndArch() + const packageName = `@codemieai/codemie-opencode-${platform}-${arch}` + const binaryName = platform === "windows" ? "codemie.exe" : "codemie" + + try { + // Use require.resolve to find the package + const packageJsonPath = require.resolve(`${packageName}/package.json`) + const packageDir = path.dirname(packageJsonPath) + const binaryPath = path.join(packageDir, "bin", binaryName) + + if (!fs.existsSync(binaryPath)) { + throw new Error(`Binary not found at ${binaryPath}`) + } + + return { binaryPath, binaryName } + } catch (error) { + throw new Error(`Could not find package ${packageName}: ${error.message}`) + } +} + +function prepareBinDirectory(binaryName) { + const binDir = path.join(__dirname, "bin") + const targetPath = path.join(binDir, binaryName) + + // Ensure bin directory exists + if (!fs.existsSync(binDir)) { + fs.mkdirSync(binDir, { recursive: true }) + } + + // Remove existing binary/symlink if it exists + if (fs.existsSync(targetPath)) { + fs.unlinkSync(targetPath) + } + + return { binDir, targetPath } +} + +function symlinkBinary(sourcePath, binaryName) { + const { targetPath } = prepareBinDirectory(binaryName) + + fs.symlinkSync(sourcePath, targetPath) + console.log(`codemie 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") { + // On Windows, the .exe is already included in the package and bin field points to it + // No postinstall setup needed + console.log("Windows detected: binary setup not needed (using packaged .exe)") + return + } + + // On non-Windows platforms, just verify the binary package exists + // Don't replace the wrapper script - it handles binary execution + const { binaryPath } = findBinary() + console.log(`Platform binary verified at: ${binaryPath}`) + console.log("Wrapper script will handle binary execution") + } catch (error) { + console.error("Failed to setup codemie binary:", error.message) + process.exit(1) + } +} + +try { + main() +} catch (error) { + console.error("Postinstall script error:", error.message) + process.exit(0) +} diff --git a/packages/codemie/script/publish.ts b/packages/codemie/script/publish.ts new file mode 100644 index 00000000000..93e3dbd9bbb --- /dev/null +++ b/packages/codemie/script/publish.ts @@ -0,0 +1,74 @@ +#!/usr/bin/env bun +import { $ } from "bun" +import pkg from "../package.json" +import { Script } from "@opencode-ai/script" +import { fileURLToPath } from "url" + +const dir = fileURLToPath(new URL("..", import.meta.url)) +process.chdir(dir) + +const binaries: Record = {} +const distDirs: Record = {} +for (const filepath of new Bun.Glob("*/package.json").scanSync({ cwd: "./dist" })) { + const distPkg = await Bun.file(`./dist/${filepath}`).json() + binaries[distPkg.name] = distPkg.version + distDirs[distPkg.name] = `./dist/${filepath.replace("/package.json", "")}` +} +console.log("binaries", binaries) +const version = Object.values(binaries)[0] + +if (!version) { + console.error("No platform packages found in dist/. Run build first.") + process.exit(1) +} + +// Create the wrapper package directory +const wrapperName = "@codemieai/codemie-opencode" +const wrapperDir = `./dist/${pkg.name}` +await $`mkdir -p ${wrapperDir}` +await $`cp -r ./bin ${wrapperDir}/bin` +await $`cp ./script/postinstall.mjs ${wrapperDir}/postinstall.mjs` + +// Write LICENSE +await Bun.file(`${wrapperDir}/LICENSE`).write("Apache-2.0\n\nSee https://www.apache.org/licenses/LICENSE-2.0\n") + +// Copy wrapper README +await $`cp ./README.md ${wrapperDir}/README.md` + +await Bun.file(`${wrapperDir}/package.json`).write( + JSON.stringify( + { + name: wrapperName, + description: "Codemie Code AI coding agent — platform wrapper", + bin: { + codemie: "./bin/codemie", + }, + scripts: { + postinstall: "bun ./postinstall.mjs || node ./postinstall.mjs", + }, + version: version, + license: "Apache-2.0", + repository: { type: "git", url: "https://github.com/codemie-ai/codemie-opencode" }, + homepage: "https://github.com/codemie-ai/codemie-opencode", + optionalDependencies: binaries, + }, + null, + 2, + ), +) + +// Publish platform packages +const tasks = Object.entries(binaries).map(async ([name]) => { + const pkgDir = distDirs[name] + if (process.platform !== "win32") { + await $`chmod -R 755 .`.cwd(pkgDir) + } + await $`bun pm pack`.cwd(pkgDir) + await $`npm publish *.tgz --access public --tag ${Script.channel}`.cwd(pkgDir) +}) +await Promise.all(tasks) + +// Publish the wrapper package +await $`cd ${wrapperDir} && bun pm pack && npm publish *.tgz --access public --tag ${Script.channel}` + +console.log(`Published ${wrapperName}@${version} with tag ${Script.channel}`) diff --git a/packages/opencode/script/build.ts b/packages/opencode/script/build.ts index ddb4769912d..e19a3b40c7d 100755 --- a/packages/opencode/script/build.ts +++ b/packages/opencode/script/build.ts @@ -198,6 +198,7 @@ for (const item of targets) { version: Script.version, os: [item.os], cpu: [item.arch], + license: "Apache-2.0", }, null, 2, diff --git a/packages/opencode/src/acp/agent.ts b/packages/opencode/src/acp/agent.ts index 765c741c0d6..2cc87eff300 100644 --- a/packages/opencode/src/acp/agent.ts +++ b/packages/opencode/src/acp/agent.ts @@ -60,13 +60,13 @@ export namespace ACP { ): Promise { const providers = await sdk.config .providers({ directory }) - .then((x) => x.data?.providers ?? []) - .catch((error) => { + .then((x: any) => x.data?.providers ?? []) + .catch((error: unknown) => { log.error("failed to get providers for context limit", { error }) return [] }) - const provider = providers.find((p) => p.id === providerID) + const provider = providers.find((p: any) => p.id === providerID) const model = provider?.models[modelID] return model?.limit.context ?? null } @@ -1379,7 +1379,7 @@ export namespace ACP { const command = await this.config.sdk.command .list({ directory }, { throwOnError: true }) - .then((x) => x.data!.find((c) => c.name === cmd.name)) + .then((x: any) => x.data!.find((c: any) => c.name === cmd.name)) if (command) { const response = await this.sdk.session.command({ sessionID, @@ -1490,7 +1490,7 @@ export namespace ACP { const specified = await sdk.config .get({ directory }, { throwOnError: true }) - .then((resp) => { + .then((resp: any) => { const cfg = resp.data if (!cfg || !cfg.model) return undefined const parsed = Provider.parseModel(cfg.model) @@ -1499,27 +1499,27 @@ export namespace ACP { modelID: parsed.modelID, } }) - .catch((error) => { + .catch((error: unknown) => { log.error("failed to load user config for default model", { error }) return undefined }) const providers = await sdk.config .providers({ directory }, { throwOnError: true }) - .then((x) => x.data?.providers ?? []) - .catch((error) => { + .then((x: any) => x.data?.providers ?? []) + .catch((error: unknown) => { log.error("failed to list providers for default model", { error }) return [] }) if (specified && providers.length) { - const provider = providers.find((p) => p.id === specified.providerID) + const provider = providers.find((p: any) => p.id === specified.providerID) if (provider && provider.models[specified.modelID]) return specified } if (specified && !providers.length) return specified - const opencodeProvider = providers.find((p) => p.id === "opencode") + const opencodeProvider = providers.find((p: any) => p.id === "opencode") if (opencodeProvider) { if (opencodeProvider.models["big-pickle"]) { return { providerID: "opencode", modelID: "big-pickle" } @@ -1533,7 +1533,7 @@ export namespace ACP { } } - const models = providers.flatMap((p) => Object.values(p.models)) + const models = providers.flatMap((p: any) => Object.values(p.models)) const [best] = Provider.sort(models) if (best) { return { diff --git a/packages/opencode/src/acp/session.ts b/packages/opencode/src/acp/session.ts index b96ebc1c895..b78983a8110 100644 --- a/packages/opencode/src/acp/session.ts +++ b/packages/opencode/src/acp/session.ts @@ -25,7 +25,7 @@ export class ACPSessionManager { }, { throwOnError: true }, ) - .then((x) => x.data!) + .then((x: any) => x.data!) const sessionId = session.id const resolvedModel = model @@ -57,7 +57,7 @@ export class ACPSessionManager { }, { throwOnError: true }, ) - .then((x) => x.data!) + .then((x: any) => x.data!) const resolvedModel = model diff --git a/packages/opencode/src/cli/cmd/auth.ts b/packages/opencode/src/cli/cmd/auth.ts index e050a0abf80..97de8554912 100644 --- a/packages/opencode/src/cli/cmd/auth.ts +++ b/packages/opencode/src/cli/cmd/auth.ts @@ -251,7 +251,7 @@ export const AuthLoginCommand = cmd({ describe: "log in to a provider", builder: (yargs) => yargs.positional("url", { - describe: "opencode auth provider", + describe: "codemie-code auth provider", type: "string", }), async handler(args) { diff --git a/packages/opencode/src/cli/cmd/pr.ts b/packages/opencode/src/cli/cmd/pr.ts index d6176572002..52015056aa1 100644 --- a/packages/opencode/src/cli/cmd/pr.ts +++ b/packages/opencode/src/cli/cmd/pr.ts @@ -5,7 +5,7 @@ import { $ } from "bun" export const PrCommand = cmd({ command: "pr ", - describe: "fetch and checkout a GitHub PR branch, then run opencode", + describe: "fetch and checkout a GitHub PR branch, then run codemie-code", builder: (yargs) => yargs.positional("number", { type: "number", @@ -88,13 +88,13 @@ export const PrCommand = cmd({ UI.println(`Successfully checked out PR #${prNumber} as branch '${localBranchName}'`) UI.println() - UI.println("Starting opencode...") + UI.println("Starting codemie-code...") UI.println() // Launch opencode TUI with session ID if available const { spawn } = await import("child_process") const opencodeArgs = sessionId ? ["-s", sessionId] : [] - const opencodeProcess = spawn("opencode", opencodeArgs, { + const opencodeProcess = spawn("codemie", opencodeArgs, { stdio: "inherit", cwd: process.cwd(), }) @@ -102,7 +102,7 @@ export const PrCommand = cmd({ await new Promise((resolve, reject) => { opencodeProcess.on("exit", (code) => { if (code === 0) resolve() - else reject(new Error(`opencode exited with code ${code}`)) + else reject(new Error(`codemie exited with code ${code}`)) }) opencodeProcess.on("error", reject) }) diff --git a/packages/opencode/src/cli/cmd/run.ts b/packages/opencode/src/cli/cmd/run.ts index f3781f1abd8..8282244af03 100644 --- a/packages/opencode/src/cli/cmd/run.ts +++ b/packages/opencode/src/cli/cmd/run.ts @@ -220,7 +220,7 @@ function normalizePath(input?: string) { export const RunCommand = cmd({ command: "run [message..]", - describe: "run opencode with a message", + describe: "run codemie-code with a message", builder: (yargs: Argv) => { return yargs .positional("message", { @@ -278,7 +278,7 @@ export const RunCommand = cmd({ }) .option("attach", { type: "string", - describe: "attach to a running opencode server (e.g., http://localhost:4096)", + describe: "attach to a running codemie-code server (e.g., http://localhost:4096)", }) .option("dir", { type: "string", diff --git a/packages/opencode/src/cli/cmd/serve.ts b/packages/opencode/src/cli/cmd/serve.ts index bee2c8f711f..aabb76ce1a9 100644 --- a/packages/opencode/src/cli/cmd/serve.ts +++ b/packages/opencode/src/cli/cmd/serve.ts @@ -6,14 +6,14 @@ import { Flag } from "../../flag/flag" export const ServeCommand = cmd({ command: "serve", builder: (yargs) => withNetworkOptions(yargs), - describe: "starts a headless opencode server", + describe: "starts a headless codemie-code server", handler: async (args) => { if (!Flag.OPENCODE_SERVER_PASSWORD) { console.log("Warning: OPENCODE_SERVER_PASSWORD is not set; server is unsecured.") } const opts = await resolveNetworkOptions(args) const server = Server.listen(opts) - console.log(`opencode server listening on http://${server.hostname}:${server.port}`) + console.log(`codemie-code server listening on http://${server.hostname}:${server.port}`) await new Promise(() => {}) await server.stop() }, diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index ab3d0968925..c1ddb87e626 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -261,20 +261,20 @@ function App() { if (!terminalTitleEnabled() || Flag.OPENCODE_DISABLE_TERMINAL_TITLE) return if (route.data.type === "home") { - renderer.setTerminalTitle("OpenCode") + renderer.setTerminalTitle("Codemie Code") return } if (route.data.type === "session") { const session = sync.session.get(route.data.sessionID) if (!session || SessionApi.isDefaultTitle(session.title)) { - renderer.setTerminalTitle("OpenCode") + renderer.setTerminalTitle("Codemie Code") return } // Truncate title to 40 chars max const title = session.title.length > 40 ? session.title.slice(0, 37) + "..." : session.title - renderer.setTerminalTitle(`OC | ${title}`) + renderer.setTerminalTitle(`CC | ${title}`) } }) @@ -312,7 +312,7 @@ function App() { if (match) { continued = true if (args.fork) { - sdk.client.session.fork({ sessionID: match }).then((result) => { + sdk.client.session.fork({ sessionID: match }).then((result: any) => { if (result.data?.id) { route.navigate({ type: "session", sessionID: result.data.id }) } else { @@ -332,7 +332,7 @@ function App() { createEffect(() => { if (forked || sync.status !== "complete" || !args.sessionID || !args.fork) return forked = true - sdk.client.session.fork({ sessionID: args.sessionID }).then((result) => { + sdk.client.session.fork({ sessionID: args.sessionID }).then((result: any) => { if (result.data?.id) { route.navigate({ type: "session", sessionID: result.data.id }) } else { @@ -555,7 +555,7 @@ function App() { title: "Open docs", value: "docs.open", onSelect: () => { - open("https://opencode.ai/docs").catch(() => {}) + open("https://codemie.ai").catch(() => {}) dialog.clear() }, category: "System", @@ -724,7 +724,7 @@ function App() { toast.show({ variant: "info", title: "Update Available", - message: `OpenCode v${evt.properties.version} is available. Run 'opencode upgrade' to update manually.`, + message: `Codemie Code v${evt.properties.version} is available. Run 'codemie upgrade' to update manually.`, duration: 10000, }) }) @@ -779,7 +779,7 @@ function ErrorComponent(props: { }) const [copied, setCopied] = createSignal(false) - const issueURL = new URL("https://github.com/anomalyco/opencode/issues/new?template=bug-report.yml") + const issueURL = new URL("https://github.com/codemie-ai/codemie-opencode/issues/new?template=bug-report.yml") // Choose safe fallback colors per mode since theme context may not be available const isLight = props.mode === "light" diff --git a/packages/opencode/src/cli/cmd/tui/attach.ts b/packages/opencode/src/cli/cmd/tui/attach.ts index a2559cfce67..23304231d3e 100644 --- a/packages/opencode/src/cli/cmd/tui/attach.ts +++ b/packages/opencode/src/cli/cmd/tui/attach.ts @@ -5,7 +5,7 @@ import { win32DisableProcessedInput, win32InstallCtrlCGuard } from "./win32" export const AttachCommand = cmd({ command: "attach ", - describe: "attach to a running opencode server", + describe: "attach to a running codemie-code server", builder: (yargs) => yargs .positional("url", { diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx index 775969bfcb3..eac34d1c610 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx @@ -37,9 +37,9 @@ export function DialogSessionList() { const options = createMemo(() => { const today = new Date().toDateString() return sessions() - .filter((x) => x.parentID === undefined) - .toSorted((a, b) => b.time.updated - a.time.updated) - .map((x) => { + .filter((x: any) => x.parentID === undefined) + .toSorted((a: any, b: any) => b.time.updated - a.time.updated) + .map((x: any) => { const date = new Date(x.time.updated) let category = date.toDateString() if (category === today) { diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-skill.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-skill.tsx index 4bcd3c7bde4..63b445f5d30 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-skill.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-skill.tsx @@ -19,8 +19,8 @@ export function DialogSkill(props: DialogSkillProps) { const options = createMemo[]>(() => { const list = skills() ?? [] - const maxWidth = Math.max(0, ...list.map((s) => s.name.length)) - return list.map((skill) => ({ + const maxWidth = Math.max(0, ...list.map((s: any) => s.name.length)) + return list.map((skill: any) => ({ title: skill.name.padEnd(maxWidth), description: skill.description?.replace(/\s+/g, " ").trim(), value: skill.name, diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-tag.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-tag.tsx index 6d6c62450ea..e1882bad86c 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-tag.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-tag.tsx @@ -25,7 +25,7 @@ export function DialogTag(props: { onSelect?: (value: string) => void }) { ) const options = createMemo(() => - (files() ?? []).map((file) => ({ + (files() ?? []).map((file: any) => ({ value: file, title: file, })), @@ -35,7 +35,7 @@ export function DialogTag(props: { onSelect?: (value: string) => void }) { { + onSelect={(option: any) => { props.onSelect?.(option.value) dialog.clear() }} diff --git a/packages/opencode/src/cli/cmd/tui/component/logo.tsx b/packages/opencode/src/cli/cmd/tui/component/logo.tsx index 8e6208b140b..82d3268bf3e 100644 --- a/packages/opencode/src/cli/cmd/tui/component/logo.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/logo.tsx @@ -1,20 +1,34 @@ -import { TextAttributes, RGBA } from "@opentui/core" -import { For, type JSX } from "solid-js" +import { TextAttributes } from "@opentui/core" +import { For, Show, createSignal, onCleanup, type JSX } from "solid-js" import { useTheme, tint } from "@tui/context/theme" +import { useKV } from "../context/kv" import { logo, marks } from "@/cli/logo" -// Shadow markers (rendered chars in parens): -// _ = full shadow cell (space with bg=shadow) -// ^ = letter top, shadow bottom (▀ with fg=letter, bg=shadow) -// ~ = shadow top only (▀ with fg=shadow) const SHADOW_MARKER = new RegExp(`[${marks}]`) +const SWEEP_WIDTH = 6 +const PAUSE_FRAMES = 20 +const FRAME_INTERVAL = 70 export function Logo() { const { theme } = useTheme() + const kv = useKV() - const renderLine = (line: string, fg: RGBA, bold: boolean): JSX.Element[] => { - const shadow = tint(theme.background, fg, 0.25) - const attrs = bold ? TextAttributes.BOLD : undefined + const logoWidth = Math.max(...logo.map((l) => l.length)) + const totalFrames = logoWidth + SWEEP_WIDTH + PAUSE_FRAMES + + const [frame, setFrame] = createSignal(0) + + const interval = setInterval(() => { + if (!kv.get("animations_enabled", true)) return + setFrame((f) => (f + 1) % totalFrames) + }, FRAME_INTERVAL) + onCleanup(() => clearInterval(interval)) + + const lineChars = logo.map((line) => Array.from(line).map((char, col) => ({ char, col }))) + + const renderLineStatic = (line: string): JSX.Element[] => { + const shadow = tint(theme.background, theme.text, 0.25) + const attrs = TextAttributes.BOLD const elements: JSX.Element[] = [] let i = 0 @@ -24,7 +38,7 @@ export function Logo() { if (markerIndex === -1) { elements.push( - + {rest} , ) @@ -33,7 +47,7 @@ export function Logo() { if (markerIndex > 0) { elements.push( - + {rest.slice(0, markerIndex)} , ) @@ -43,14 +57,14 @@ export function Logo() { switch (marker) { case "_": elements.push( - + {" "} , ) break case "^": elements.push( - + , ) @@ -72,14 +86,67 @@ export function Logo() { return ( - - {(line, index) => ( - - {renderLine(line, theme.textMuted, false)} - {renderLine(logo.right[index()], theme.text, true)} - - )} - + + {(line) => ( + + {renderLineStatic(line)} + + )} + + } + > + + {(chars) => ( + + + + {(info) => { + const charFg = () => { + const beamPos = frame() + if (beamPos >= logoWidth + SWEEP_WIDTH) return theme.text + const dist = beamPos - info.col + if (dist < 0 || dist > SWEEP_WIDTH) return theme.text + const intensity = (1 - dist / SWEEP_WIDTH) * 0.8 + return tint(theme.text, theme.primary, intensity) + } + const charShadow = () => tint(theme.background, charFg(), 0.25) + + if (info.char === "_") { + return ( + + {" "} + + ) + } + if (info.char === "^") { + return ( + + ▀ + + ) + } + if (info.char === "~") { + return ( + + ▀ + + ) + } + return ( + + {info.char} + + ) + }} + + + + )} + + ) } diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx index 3240afab326..4f2787ce324 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx @@ -234,7 +234,7 @@ export function Autocomplete(props: { // Add file options if (!result.error && result.data) { - const sortedFiles = result.data.sort((a, b) => { + const sortedFiles = result.data.sort((a: any, b: any) => { const aScore = frecency.getFrecency(a) const bScore = frecency.getFrecency(b) if (aScore !== bScore) return bScore - aScore @@ -246,7 +246,7 @@ export function Autocomplete(props: { const width = props.anchor().width - 4 options.push( - ...sortedFiles.map((item): AutocompleteOption => { + ...sortedFiles.map((item: any): AutocompleteOption => { const baseDir = (sync.data.path.directory || process.cwd()).replace(/\/+$/, "") const fullPath = `${baseDir}/${item}` const urlObj = pathToFileURL(fullPath) 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 d63c248fb83..fa295e26e96 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -542,7 +542,7 @@ export function Prompt(props: PromptProps) { const sessionID = props.sessionID ? props.sessionID : await (async () => { - const sessionID = await sdk.client.session.create({}).then((x) => x.data!.id) + const sessionID = await sdk.client.session.create({}).then((x: any) => x.data!.id) return sessionID })() const messageID = Identifier.ascending("message") diff --git a/packages/opencode/src/cli/cmd/tui/component/tips.tsx b/packages/opencode/src/cli/cmd/tui/component/tips.tsx index d0a7e5b44ec..0c75982920b 100644 --- a/packages/opencode/src/cli/cmd/tui/component/tips.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/tips.tsx @@ -54,7 +54,6 @@ const TIPS = [ "Press {highlight}Tab{/highlight} to cycle between Build and Plan agents", "Use {highlight}/undo{/highlight} to revert the last message and file changes", "Use {highlight}/redo{/highlight} to restore previously undone messages and file changes", - "Run {highlight}/share{/highlight} to create a public link to your conversation at opencode.ai", "Drag and drop images into the terminal to add them as context", "Press {highlight}Ctrl+V{/highlight} to paste images from your clipboard into the prompt", "Press {highlight}Ctrl+X E{/highlight} or {highlight}/editor{/highlight} to compose messages in your external editor", @@ -87,7 +86,7 @@ const TIPS = [ "Override any keybind in config via the {highlight}keybinds{/highlight} section", "Set any keybind to {highlight}none{/highlight} to disable it completely", "Configure local or remote MCP servers in the {highlight}mcp{/highlight} config section", - "OpenCode auto-handles OAuth for remote MCP servers requiring auth", + "Codemie Code auto-handles OAuth for remote MCP servers requiring auth", "Add {highlight}.md{/highlight} files to {highlight}.opencode/command/{/highlight} to define reusable custom prompts", "Use {highlight}$ARGUMENTS{/highlight}, {highlight}$1{/highlight}, {highlight}$2{/highlight} in custom commands for dynamic input", "Use backticks in commands to inject shell output (e.g., {highlight}`git status`{/highlight})", @@ -96,28 +95,25 @@ const TIPS = [ 'Use patterns like {highlight}"git *": "allow"{/highlight} for granular bash permissions', 'Set {highlight}"rm -rf *": "deny"{/highlight} to block destructive commands', 'Configure {highlight}"git push": "ask"{/highlight} to require approval before pushing', - "OpenCode auto-formats files using prettier, gofmt, ruff, and more", + "Codemie Code auto-formats files using prettier, gofmt, ruff, and more", 'Set {highlight}"formatter": false{/highlight} in config to disable all auto-formatting', "Define custom formatter commands with file extensions in config", - "OpenCode uses LSP servers for intelligent code analysis", + "Codemie Code uses LSP servers for intelligent code analysis", "Create {highlight}.ts{/highlight} files in {highlight}.opencode/tools/{/highlight} to define new LLM tools", "Tool definitions can invoke scripts written in Python, Go, etc", "Add {highlight}.ts{/highlight} files to {highlight}.opencode/plugin/{/highlight} for event hooks", "Use plugins to send OS notifications when sessions complete", - "Create a plugin to prevent OpenCode from reading sensitive files", - "Use {highlight}opencode run{/highlight} for non-interactive scripting", - "Use {highlight}opencode --continue{/highlight} to resume the last session", - "Use {highlight}opencode run -f file.ts{/highlight} to attach files via CLI", + "Create a plugin to prevent Codemie Code from reading sensitive files", + "Use {highlight}codemie run{/highlight} for non-interactive scripting", + "Use {highlight}codemie --continue{/highlight} to resume the last session", + "Use {highlight}codemie run -f file.ts{/highlight} to attach files via CLI", "Use {highlight}--format json{/highlight} for machine-readable output in scripts", - "Run {highlight}opencode serve{/highlight} for headless API access to OpenCode", - "Use {highlight}opencode run --attach{/highlight} to connect to a running server", - "Run {highlight}opencode upgrade{/highlight} to update to the latest version", - "Run {highlight}opencode auth list{/highlight} to see all configured providers", - "Run {highlight}opencode agent create{/highlight} for guided agent creation", - "Use {highlight}/opencode{/highlight} in GitHub issues/PRs to trigger AI actions", - "Run {highlight}opencode github install{/highlight} to set up the GitHub workflow", - "Comment {highlight}/opencode fix this{/highlight} on issues to auto-create PRs", - "Comment {highlight}/oc{/highlight} on PR code lines for targeted code reviews", + "Run {highlight}codemie serve{/highlight} for headless API access to Codemie Code", + "Use {highlight}codemie run --attach{/highlight} to connect to a running server", + "Run {highlight}codemie upgrade{/highlight} to update to the latest version", + "Run {highlight}codemie auth list{/highlight} to see all configured providers", + "Run {highlight}codemie agent create{/highlight} for guided agent creation", + "Run {highlight}codemie github install{/highlight} to set up the GitHub workflow", 'Use {highlight}"theme": "system"{/highlight} to match your terminal\'s colors', "Create JSON theme files in {highlight}.opencode/themes/{/highlight} directory", "Themes support dark/light variants for both modes", @@ -135,15 +131,13 @@ const TIPS = [ "Run {highlight}/unshare{/highlight} to remove a session from public access", "Permission {highlight}doom_loop{/highlight} prevents infinite tool call loops", "Permission {highlight}external_directory{/highlight} protects files outside project", - "Run {highlight}opencode debug config{/highlight} to troubleshoot configuration", + "Run {highlight}codemie debug config{/highlight} to troubleshoot configuration", "Use {highlight}--print-logs{/highlight} flag to see detailed logs in stderr", "Press {highlight}Ctrl+X G{/highlight} or {highlight}/timeline{/highlight} to jump to specific messages", "Press {highlight}Ctrl+X H{/highlight} to toggle code block visibility in messages", "Press {highlight}Ctrl+X S{/highlight} or {highlight}/status{/highlight} to see system status info", "Enable {highlight}tui.scroll_acceleration{/highlight} for smooth macOS-style scrolling", "Toggle username display in chat via command palette ({highlight}Ctrl+P{/highlight})", - "Run {highlight}docker run -it --rm ghcr.io/anomalyco/opencode{/highlight} for containerized use", - "Use {highlight}/connect{/highlight} with OpenCode Zen for curated, tested models", "Commit your project's {highlight}AGENTS.md{/highlight} file to Git for team sharing", "Use {highlight}/review{/highlight} to review uncommitted changes, branches, or PRs", "Run {highlight}/help{/highlight} or {highlight}Ctrl+X H{/highlight} to show the help dialog", diff --git a/packages/opencode/src/cli/cmd/tui/context/sync.tsx b/packages/opencode/src/cli/cmd/tui/context/sync.tsx index 269ed7ae0bd..32733d1c681 100644 --- a/packages/opencode/src/cli/cmd/tui/context/sync.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/sync.tsx @@ -332,7 +332,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ } case "lsp.updated": { - sdk.client.lsp.status().then((x) => setStore("lsp", x.data!)) + sdk.client.lsp.status().then((x: any) => setStore("lsp", x.data!)) break } @@ -351,7 +351,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ const start = Date.now() - 30 * 24 * 60 * 60 * 1000 const sessionListPromise = sdk.client.session .list({ start: start }) - .then((x) => (x.data ?? []).toSorted((a, b) => a.id.localeCompare(b.id))) + .then((x: any) => (x.data ?? []).toSorted((a: any, b: any) => a.id.localeCompare(b.id))) // blocking - include session.list when continuing a session const providersPromise = sdk.client.config.providers({}, { throwOnError: true }) @@ -368,10 +368,10 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ await Promise.all(blockingRequests) .then(() => { - const providersResponse = providersPromise.then((x) => x.data!) - const providerListResponse = providerListPromise.then((x) => x.data!) - const agentsResponse = agentsPromise.then((x) => x.data ?? []) - const configResponse = configPromise.then((x) => x.data!) + const providersResponse = providersPromise.then((x: any) => x.data!) + const providerListResponse = providerListPromise.then((x: any) => x.data!) + const agentsResponse = agentsPromise.then((x: any) => x.data ?? []) + const configResponse = configPromise.then((x: any) => x.data!) const sessionListResponse = args.continue ? sessionListPromise : undefined return Promise.all([ @@ -401,18 +401,20 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ if (store.status !== "complete") setStore("status", "partial") // non-blocking Promise.all([ - ...(args.continue ? [] : [sessionListPromise.then((sessions) => setStore("session", reconcile(sessions)))]), - sdk.client.command.list().then((x) => setStore("command", reconcile(x.data ?? []))), - sdk.client.lsp.status().then((x) => setStore("lsp", reconcile(x.data!))), - sdk.client.mcp.status().then((x) => setStore("mcp", reconcile(x.data!))), - sdk.client.experimental.resource.list().then((x) => setStore("mcp_resource", reconcile(x.data ?? {}))), - sdk.client.formatter.status().then((x) => setStore("formatter", reconcile(x.data!))), - sdk.client.session.status().then((x) => { + ...(args.continue + ? [] + : [sessionListPromise.then((sessions: any) => setStore("session", reconcile(sessions)))]), + sdk.client.command.list().then((x: any) => setStore("command", reconcile(x.data ?? []))), + sdk.client.lsp.status().then((x: any) => setStore("lsp", reconcile(x.data!))), + sdk.client.mcp.status().then((x: any) => setStore("mcp", reconcile(x.data!))), + sdk.client.experimental.resource.list().then((x: any) => setStore("mcp_resource", reconcile(x.data ?? {}))), + sdk.client.formatter.status().then((x: any) => setStore("formatter", reconcile(x.data!))), + sdk.client.session.status().then((x: any) => { setStore("session_status", reconcile(x.data!)) }), - sdk.client.provider.auth().then((x) => setStore("provider_auth", reconcile(x.data ?? {}))), - sdk.client.vcs.get().then((x) => setStore("vcs", reconcile(x.data))), - sdk.client.path.get().then((x) => setStore("path", reconcile(x.data!))), + sdk.client.provider.auth().then((x: any) => setStore("provider_auth", reconcile(x.data ?? {}))), + sdk.client.vcs.get().then((x: any) => setStore("vcs", reconcile(x.data))), + sdk.client.path.get().then((x: any) => setStore("path", reconcile(x.data!))), ]).then(() => { setStore("status", "complete") }) @@ -471,7 +473,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ if (match.found) draft.session[match.index] = session.data! if (!match.found) draft.session.splice(match.index, 0, session.data!) draft.todo[sessionID] = todo.data ?? [] - draft.message[sessionID] = messages.data!.map((x) => x.info) + draft.message[sessionID] = messages.data!.map((x: any) => x.info) for (const message of messages.data!) { draft.part[message.info.id] = message.parts } 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 f5a7f6f6ca4..aa3fadba619 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -241,7 +241,7 @@ export function Session() { `${logo[3] ?? ""}`, ``, ` ${weak("Session")}${UI.Style.TEXT_NORMAL_BOLD}${title}${UI.Style.TEXT_NORMAL}`, - ` ${weak("Continue")}${UI.Style.TEXT_NORMAL_BOLD}opencode -s ${session()?.id}${UI.Style.TEXT_NORMAL}`, + ` ${weak("Continue")}${UI.Style.TEXT_NORMAL_BOLD}codemie -s ${session()?.id}${UI.Style.TEXT_NORMAL}`, ``, ].join("\n"), ) diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx index 389fc2418cc..bc846692363 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx @@ -156,11 +156,13 @@ export function PermissionPrompt(props: { request: PermissionRequest }) { body={ - + - This will allow the following patterns until OpenCode is restarted + + This will allow the following patterns until Codemie Code is restarted + {(pattern) => ( @@ -500,7 +502,7 @@ function RejectPrompt(props: { onConfirm: (message: string) => void; onCancel: ( Reject permission - Tell OpenCode what to do differently + Tell Codemie Code what to do differently - OpenCode includes free models so you can start immediately. + Codemie Code uses LiteLLM — models are available after SSO login. Connect from 75+ providers to use other models, including Claude, GPT, Gemini etc @@ -308,9 +308,9 @@ export function Sidebar(props: { sessionID: string; overlay?: boolean }) { {directory().split("/").at(-1)} - Open + Codemie - Code + Code {" "} {Installation.VERSION} diff --git a/packages/opencode/src/cli/cmd/tui/thread.ts b/packages/opencode/src/cli/cmd/tui/thread.ts index 50f63c3dfbd..1b10b65a4d4 100644 --- a/packages/opencode/src/cli/cmd/tui/thread.ts +++ b/packages/opencode/src/cli/cmd/tui/thread.ts @@ -45,12 +45,12 @@ function createEventSource(client: RpcClient): EventSource { export const TuiThreadCommand = cmd({ command: "$0 [project]", - describe: "start opencode tui", + describe: "start codemie-code tui", builder: (yargs) => withNetworkOptions(yargs) .positional("project", { type: "string", - describe: "path to start opencode in", + describe: "path to start codemie-code in", }) .option("model", { type: "string", diff --git a/packages/opencode/src/cli/cmd/uninstall.ts b/packages/opencode/src/cli/cmd/uninstall.ts index 3d8e7e3f75e..841d9d05783 100644 --- a/packages/opencode/src/cli/cmd/uninstall.ts +++ b/packages/opencode/src/cli/cmd/uninstall.ts @@ -24,7 +24,7 @@ interface RemovalTargets { export const UninstallCommand = { command: "uninstall", - describe: "uninstall opencode and remove all related files", + describe: "uninstall codemie-code and remove all related files", builder: (yargs: Argv) => yargs .option("keep-config", { @@ -55,7 +55,7 @@ export const UninstallCommand = { UI.empty() UI.println(UI.logo(" ")) UI.empty() - prompts.intro("Uninstall OpenCode") + prompts.intro("Uninstall Codemie Code") const method = await Installation.method() prompts.log.info(`Installation method: ${method}`) @@ -232,7 +232,7 @@ async function executeUninstall(method: Installation.Method, targets: RemovalTar } UI.empty() - prompts.log.success("Thank you for using OpenCode!") + prompts.log.success("Thank you for using Codemie Code!") } async function getShellConfigFile(): Promise { diff --git a/packages/opencode/src/cli/cmd/upgrade.ts b/packages/opencode/src/cli/cmd/upgrade.ts index 4438fa3b84f..85115517838 100644 --- a/packages/opencode/src/cli/cmd/upgrade.ts +++ b/packages/opencode/src/cli/cmd/upgrade.ts @@ -5,7 +5,7 @@ import { Installation } from "../../installation" export const UpgradeCommand = { command: "upgrade [target]", - describe: "upgrade opencode to the latest or a specific version", + describe: "upgrade codemie-code to the latest or a specific version", builder: (yargs: Argv) => { return yargs .positional("target", { diff --git a/packages/opencode/src/cli/cmd/web.ts b/packages/opencode/src/cli/cmd/web.ts index 0fe056f21f2..7cd90deb668 100644 --- a/packages/opencode/src/cli/cmd/web.ts +++ b/packages/opencode/src/cli/cmd/web.ts @@ -31,7 +31,7 @@ function getNetworkIPs() { export const WebCommand = cmd({ command: "web", builder: (yargs) => withNetworkOptions(yargs), - describe: "start opencode server and open web interface", + describe: "start codemie-code server and open web interface", handler: async (args) => { if (!Flag.OPENCODE_SERVER_PASSWORD) { UI.println(UI.Style.TEXT_WARNING_BOLD + "! " + "OPENCODE_SERVER_PASSWORD is not set; server is unsecured.") diff --git a/packages/opencode/src/cli/error.ts b/packages/opencode/src/cli/error.ts index d7120aa5e98..ff1a93283de 100644 --- a/packages/opencode/src/cli/error.ts +++ b/packages/opencode/src/cli/error.ts @@ -6,13 +6,13 @@ import { UI } from "./ui" export function FormatError(input: unknown) { if (MCP.Failed.isInstance(input)) - return `MCP server "${input.data.name}" failed. Note, opencode does not support MCP authentication yet.` + return `MCP server "${input.data.name}" failed. Note, codemie-code does not support MCP authentication yet.` if (Provider.ModelNotFoundError.isInstance(input)) { const { providerID, modelID, suggestions } = input.data return [ `Model not found: ${providerID}/${modelID}`, ...(Array.isArray(suggestions) && suggestions.length ? ["Did you mean: " + suggestions.join(", ")] : []), - `Try: \`opencode models\` to list available models`, + `Try: \`codemie models\` to list available models`, `Or check your config (opencode.json) provider/model names`, ].join("\n") } diff --git a/packages/opencode/src/cli/logo.ts b/packages/opencode/src/cli/logo.ts index 44fb93c15b3..457d1ec7787 100644 --- a/packages/opencode/src/cli/logo.ts +++ b/packages/opencode/src/cli/logo.ts @@ -1,6 +1,8 @@ -export const logo = { - left: [" ", "█▀▀█ █▀▀█ █▀▀█ █▀▀▄", "█__█ █__█ █^^^ █__█", "▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀~~▀"], - right: [" ▄ ", "█▀▀▀ █▀▀█ █▀▀█ █▀▀█", "█___ █__█ █__█ █^^^", "▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀"], -} +export const logo = [ + " ▄ ", + "█▀▀▀ █▀▀█ █▀▀█ █▀▀█ █▄_▄█ _▀▀_ █▀▀█", + "█___ █__█ █__█ █^^^ █_▀_█ _██_ █^^^", + "▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀___▀ _▀▀_ ▀▀▀▀", +] export const marks = "_^~" diff --git a/packages/opencode/src/cli/network.ts b/packages/opencode/src/cli/network.ts index dd09e1689f5..f4cdaab405d 100644 --- a/packages/opencode/src/cli/network.ts +++ b/packages/opencode/src/cli/network.ts @@ -19,8 +19,8 @@ const options = { }, "mdns-domain": { type: "string" as const, - describe: "custom domain name for mDNS service (default: opencode.local)", - default: "opencode.local", + describe: "custom domain name for mDNS service (default: codemie.local)", + default: "codemie.local", }, cors: { type: "string" as const, diff --git a/packages/opencode/src/cli/ui.ts b/packages/opencode/src/cli/ui.ts index f242a77f6ce..fdfa56745b1 100644 --- a/packages/opencode/src/cli/ui.ts +++ b/packages/opencode/src/cli/ui.ts @@ -43,18 +43,10 @@ export namespace UI { export function logo(pad?: string) { const result: string[] = [] const reset = "\x1b[0m" - const left = { - fg: Bun.color("gray", "ansi") ?? "", - shadow: "\x1b[38;5;235m", - bg: "\x1b[48;5;235m", - } - const right = { - fg: reset, - shadow: "\x1b[38;5;238m", - bg: "\x1b[48;5;238m", - } - const gap = " " - const draw = (line: string, fg: string, shadow: string, bg: string) => { + const bold = "\x1b[1m" + const shadow = "\x1b[38;5;238m" + const bg = "\x1b[48;5;238m" + const draw = (line: string) => { const parts: string[] = [] for (const char of line) { if (char === "_") { @@ -62,7 +54,7 @@ export namespace UI { continue } if (char === "^") { - parts.push(fg, bg, "▀", reset) + parts.push(bold, bg, "▀", reset) continue } if (char === "~") { @@ -73,16 +65,13 @@ export namespace UI { parts.push(" ") continue } - parts.push(fg, char, reset) + parts.push(bold, char, reset) } return parts.join("") } - glyphs.left.forEach((row, index) => { + glyphs.forEach((row) => { if (pad) result.push(pad) - result.push(draw(row, left.fg, left.shadow, left.bg)) - result.push(gap) - const other = glyphs.right[index] ?? "" - result.push(draw(other, right.fg, right.shadow, right.bg)) + result.push(draw(row)) result.push(EOL) }) return result.join("").trimEnd() diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index aad0fd76c4b..9e219fafb89 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -157,6 +157,7 @@ export namespace Config { } const deps = [] + let installChain: Promise = Promise.resolve() for (const dir of unique(directories)) { if (dir.endsWith(".opencode") || dir === Flag.OPENCODE_CONFIG_DIR) { @@ -170,12 +171,11 @@ export namespace Config { } } - deps.push( - iife(async () => { - const shouldInstall = await needsInstall(dir) - if (shouldInstall) await installDependencies(dir) - }), - ) + installChain = installChain.then(async () => { + const shouldInstall = await needsInstall(dir) + if (shouldInstall) await installDependencies(dir) + }) + deps.push(installChain) result.command = mergeDeep(result.command ?? {}, await loadCommand(dir)) result.agent = mergeDeep(result.agent, await loadAgent(dir)) diff --git a/packages/opencode/src/session/prompt/anthropic.txt b/packages/opencode/src/session/prompt/anthropic.txt index 21d9c0e9f21..5557f353630 100644 --- a/packages/opencode/src/session/prompt/anthropic.txt +++ b/packages/opencode/src/session/prompt/anthropic.txt @@ -1,4 +1,4 @@ -You are OpenCode, the best coding agent on the planet. +You are Codemie Code, the best coding agent on the planet. You are an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user. @@ -7,9 +7,9 @@ IMPORTANT: You must NEVER generate or guess URLs for the user unless you are con If the user asks for help or wants to give feedback inform them of the following: - ctrl+p to list available actions - To give feedback, users should report the issue at - https://github.com/anomalyco/opencode + https://github.com/codemie-ai/codemie-opencode -When the user directly asks about OpenCode (eg. "can OpenCode do...", "does OpenCode have..."), or asks in second person (eg. "are you able...", "can you do..."), or asks how to use a specific OpenCode feature (eg. implement a hook, write a slash command, or install an MCP server), use the WebFetch tool to gather information to answer the question from OpenCode docs. The list of available docs is available at https://opencode.ai/docs +When the user directly asks about Codemie Code (eg. "can Codemie Code do...", "does Codemie Code have..."), or asks in second person (eg. "are you able...", "can you do..."), or asks how to use a specific Codemie Code feature (eg. implement a hook, write a slash command, or install an MCP server), use the WebFetch tool to gather information to answer the question from Codemie Code docs. The list of available docs is available at https://codemie.ai # Tone and style - Only use emojis if the user explicitly requests it. Avoid using emojis in all communication unless asked. @@ -18,7 +18,7 @@ When the user directly asks about OpenCode (eg. "can OpenCode do...", "does Open - NEVER create files unless they're absolutely necessary for achieving your goal. ALWAYS prefer editing an existing file to creating a new one. This includes markdown files. # Professional objectivity -Prioritize technical accuracy and truthfulness over validating the user's beliefs. Focus on facts and problem-solving, providing direct, objective technical info without any unnecessary superlatives, praise, or emotional validation. It is best for the user if OpenCode honestly applies the same rigorous standards to all ideas and disagrees when necessary, even if it may not be what the user wants to hear. Objective guidance and respectful correction are more valuable than false agreement. Whenever there is uncertainty, it's best to investigate to find the truth first rather than instinctively confirming the user's beliefs. +Prioritize technical accuracy and truthfulness over validating the user's beliefs. Focus on facts and problem-solving, providing direct, objective technical info without any unnecessary superlatives, praise, or emotional validation. It is best for the user if Codemie Code honestly applies the same rigorous standards to all ideas and disagrees when necessary, even if it may not be what the user wants to hear. Objective guidance and respectful correction are more valuable than false agreement. Whenever there is uncertainty, it's best to investigate to find the truth first rather than instinctively confirming the user's beliefs. # Task Management You have access to the TodoWrite tools to help you manage and plan tasks. Use these tools VERY frequently to ensure that you are tracking your tasks and giving the user visibility into your progress. @@ -69,7 +69,7 @@ I've found some existing telemetry code. Let me mark the first todo as in_progre # Doing tasks The user will primarily request you perform software engineering tasks. This includes solving bugs, adding new functionality, refactoring code, explaining code, and more. For these tasks the following steps are recommended: -- +- - Use the TodoWrite tool to plan the task if required - Tool results and user messages may include tags. tags contain useful information and reminders. They are automatically added by the system, and bear no direct relation to the specific tool results or user messages in which they appear. diff --git a/packages/opencode/src/session/prompt/beast.txt b/packages/opencode/src/session/prompt/beast.txt index e92e4d020f9..62839134cdd 100644 --- a/packages/opencode/src/session/prompt/beast.txt +++ b/packages/opencode/src/session/prompt/beast.txt @@ -1,4 +1,4 @@ -You are opencode, an agent - please keep going until the user’s query is completely resolved, before ending your turn and yielding back to the user. +You are Codemie Code, an agent - please keep going until the user's query is completely resolved, before ending your turn and yielding back to the user. Your thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough. @@ -12,7 +12,7 @@ THE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH. You must use the webfetch tool to recursively gather all information from URL's provided to you by the user, as well as any links you find in the content of those pages. -Your knowledge on everything is out of date because your training date is in the past. +Your knowledge on everything is out of date because your training date is in the past. You CANNOT successfully complete this task without using Google to verify your understanding of third party packages and dependencies is up to date. You must use the webfetch tool to search google for how to properly use libraries, packages, frameworks, dependencies, etc. every single time you install or implement one. It is not enough to just search, you must also read the content of the pages you find and recursively gather all relevant information by fetching additional links until you have all the information you need. @@ -25,7 +25,7 @@ Take your time and think through every step - remember to check your solution ri You MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully. -You MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say "Next I will do X" or "Now I will do Y" or "I will do X", you MUST actually do X or Y instead just saying that you will do it. +You MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say "Next I will do X" or "Now I will do Y" or "I will do X", you MUST actually do X or Y instead just saying that you will do it. You are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input. @@ -71,7 +71,7 @@ Carefully read the issue and think hard about a plan to solve it before coding. - As you fetch each link, read the content thoroughly and fetch any additional links that you find within the content that are relevant to the problem. - Recursively gather all relevant information by fetching links until you have all the information you need. -## 5. Develop a Detailed Plan +## 5. Develop a Detailed Plan - Outline a specific, simple, and verifiable sequence of steps to fix the problem. - Create a todo list in markdown format to track your progress. - Each time you complete a step, check it off using `[x]` syntax. @@ -95,7 +95,7 @@ Carefully read the issue and think hard about a plan to solve it before coding. # Communication Guidelines -Always communicate clearly and concisely in a casual, friendly yet professional tone. +Always communicate clearly and concisely in a casual, friendly yet professional tone. "Let me fetch the URL you provided to gather more information." "Ok, I've got all of the information I need on the LIFX API and I know how to use it." @@ -105,13 +105,13 @@ Always communicate clearly and concisely in a casual, friendly yet professional "Whelp - I see we have some problems. Let's fix those up." -- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler. +- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler. - Always write code directly to the correct files. - Do not display code to the user unless they specifically ask for it. - Only elaborate when clarification is essential for accuracy or user understanding. # Memory -You have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it. +You have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it. When creating a new memory file, you MUST include the following front matter at the top of the file: ```yaml @@ -141,7 +141,7 @@ If you are not writing the prompt in a file, you should always wrap the prompt i Remember that todo lists must always be written in markdown format and must always be wrapped in triple backticks. -# Git -If the user tells you to stage and commit, you may do so. +# Git +If the user tells you to stage and commit, you may do so. You are NEVER allowed to stage and commit files automatically. diff --git a/packages/opencode/src/session/prompt/qwen.txt b/packages/opencode/src/session/prompt/qwen.txt index d87fc379572..c1ca4188032 100644 --- a/packages/opencode/src/session/prompt/qwen.txt +++ b/packages/opencode/src/session/prompt/qwen.txt @@ -1,14 +1,14 @@ -You are opencode, an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user. +You are Codemie Code, an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user. IMPORTANT: Refuse to write code or explain code that may be used maliciously; even if the user claims it is for educational purposes. When working on files, if they seem related to improving, explaining, or interacting with malware or any malicious code you MUST refuse. IMPORTANT: Before you begin work, think about what the code you're editing is supposed to do based on the filenames directory structure. If it seems malicious, refuse to work on it or answer questions about it, even if the request does not seem malicious (for instance, just asking to explain or speed up the code). IMPORTANT: You must NEVER generate or guess URLs for the user unless you are confident that the URLs are for helping the user with programming. You may use URLs provided by the user in their messages or local files. -If the user asks for help or wants to give feedback inform them of the following: -- /help: Get help with using opencode -- To give feedback, users should report the issue at https://github.com/anomalyco/opencode/issues +If the user asks for help or wants to give feedback inform them of the following: +- /help: Get help with using Codemie Code +- To give feedback, users should report the issue at https://github.com/codemie-ai/codemie-opencode/issues -When the user directly asks about opencode (eg 'can opencode do...', 'does opencode have...') or asks in second person (eg 'are you able...', 'can you do...'), first use the WebFetch tool to gather information to answer the question from opencode docs at https://opencode.ai +When the user directly asks about Codemie Code (eg 'can Codemie Code do...', 'does Codemie Code have...') or asks in second person (eg 'are you able...', 'can you do...'), first use the WebFetch tool to gather information to answer the question from Codemie Code docs at https://codemie.ai # Tone and style You should be concise, direct, and to the point. When you run a non-trivial bash command, you should explain what the command does and why you are running it, to make sure the user understands what you are doing (this is especially important when you are running a command that will make changes to the user's system). diff --git a/packages/opencode/src/session/prompt/trinity.txt b/packages/opencode/src/session/prompt/trinity.txt index 28ee4c4f269..39620b3e8be 100644 --- a/packages/opencode/src/session/prompt/trinity.txt +++ b/packages/opencode/src/session/prompt/trinity.txt @@ -1,4 +1,4 @@ -You are opencode, an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user. +You are Codemie Code, an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user. # Tone and style You should be concise, direct, and to the point. When you run a non-trivial bash command, you should explain what the command does and why you are running it, to make sure the user understands what you are doing (this is especially important when you are running a command that will make changes to the user's system). diff --git a/packages/script/src/index.ts b/packages/script/src/index.ts index 1f39d313888..40e4d83243f 100644 --- a/packages/script/src/index.ts +++ b/packages/script/src/index.ts @@ -33,9 +33,10 @@ const IS_PREVIEW = CHANNEL !== "latest" const VERSION = await (async () => { if (env.OPENCODE_VERSION) return env.OPENCODE_VERSION if (IS_PREVIEW) return `0.0.0-${CHANNEL}-${new Date().toISOString().slice(0, 16).replace(/[-:T]/g, "")}` - const version = await fetch("https://registry.npmjs.org/opencode-ai/latest") + const npmPackage = process.env["OPENCODE_NPM_PACKAGE"] || "opencode-ai" + const version = await fetch(`https://registry.npmjs.org/${npmPackage}/latest`) .then((res) => { - if (!res.ok) throw new Error(res.statusText) + if (!res.ok) throw new Error(`Failed to fetch version from npm package "${npmPackage}": ${res.statusText}`) return res.json() }) .then((data: any) => data.version) diff --git a/script/version.ts b/script/version.ts index e011f44539d..e1e11214d71 100755 --- a/script/version.ts +++ b/script/version.ts @@ -6,7 +6,7 @@ import { buildNotes, getLatestRelease } from "./changelog" const output = [`version=${Script.version}`] -if (!Script.preview) { +if (!Script.preview && !process.env.OPENCODE_SKIP_RELEASE) { const previous = await getLatestRelease() const notes = await buildNotes(previous, "HEAD") const body = notes.join("\n") || "No notable changes" diff --git a/sst.config.ts b/sst.config.ts index b8e56473bc5..6bebaabeed3 100644 --- a/sst.config.ts +++ b/sst.config.ts @@ -7,17 +7,12 @@ export default $config({ removal: input?.stage === "production" ? "retain" : "remove", protect: ["production"].includes(input?.stage), home: "cloudflare", - providers: { - stripe: { - apiKey: process.env.STRIPE_SECRET_KEY!, - }, - planetscale: "0.4.1", - }, + providers: {}, } }, async run() { await import("./infra/app.js") - await import("./infra/console.js") + // await import("./infra/console.js") await import("./infra/enterprise.js") }, })