@alltomatos/opencode 1.21.11-dev.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +158 -0
- package/bin/opencode.exe +10 -0
- package/package.json +34 -0
- package/postinstall.mjs +194 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 opencode
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://github.com/alltomatos/opencode">
|
|
3
|
+
<picture>
|
|
4
|
+
<source srcset="packages/console/app/src/asset/logo-ornate-dark.svg" media="(prefers-color-scheme: dark)">
|
|
5
|
+
<source srcset="packages/console/app/src/asset/logo-ornate-light.svg" media="(prefers-color-scheme: light)">
|
|
6
|
+
<img src="packages/console/app/src/asset/logo-ornate-light.svg" alt="OpenCode logo">
|
|
7
|
+
</picture>
|
|
8
|
+
</a>
|
|
9
|
+
</p>
|
|
10
|
+
<p align="center">OpenCode by Alltomatos — a fork of the open source AI coding agent.</p>
|
|
11
|
+
<p align="center">Grupo de Apoio: https://chat.whatsapp.com/DOLzfQ4aPZ12R7ZRbLabNh</p>
|
|
12
|
+
|
|
13
|
+
<p align="center">
|
|
14
|
+
<a href="https://github.com/alltomatos/opencode/releases"><img alt="Latest release" src="https://img.shields.io/github/v/release/alltomatos/opencode?style=flat-square" /></a>
|
|
15
|
+
<a href="https://github.com/alltomatos/opencode/actions"><img alt="Build status" src="https://img.shields.io/github/actions/workflow/status/alltomatos/opencode/publish.yml?style=flat-square&branch=dev" /></a>
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
[](https://github.com/alltomatos/opencode)
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
### Screenshots
|
|
23
|
+
|
|
24
|
+
<p align="center">
|
|
25
|
+
<img src="packages/web/src/assets/lander/t2.png" alt="Modos de permissão (Automático, Manual, Aceitar edições, Planejar)" width="49%">
|
|
26
|
+
<img src="packages/web/src/assets/lander/config.png" alt="Tela de Configurações, com suporte a português" width="49%">
|
|
27
|
+
</p>
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
Este é um fork pessoal do [OpenCode](https://github.com/anomalyco/opencode), mantido por [Alltomatos](https://github.com/alltomatos), com o foco no app desktop para Windows e ajustes de UI/UX específicos deste fork (sidebar de projetos, terminal e browser embutidos no cabeçalho da sessão, seed de skills padrão, entre outros — veja o [changelog](./changelog.json) e as [releases](https://github.com/alltomatos/opencode/releases) para o histórico completo).
|
|
32
|
+
|
|
33
|
+
### Branches
|
|
34
|
+
|
|
35
|
+
Este fork trabalha com duas branches:
|
|
36
|
+
|
|
37
|
+
- **`prod`** — branch de produção. Só ela gera releases publicados (o app instalado e o auto-updater apontam pra cá). É pra onde `dev` é promovida quando um lote de mudanças está maduro.
|
|
38
|
+
- **`dev`** — branch de desenvolvimento. Todo o trabalho novo (features, correções, UI/UX) acontece aqui primeiro, roda em modo dev localmente pra validar, e só depois é promovida pra `prod`.
|
|
39
|
+
|
|
40
|
+
### App Desktop (produção)
|
|
41
|
+
|
|
42
|
+
Baixe o instalador direto na [página de releases](https://github.com/alltomatos/opencode/releases/latest) — sempre gerado a partir da branch `prod`.
|
|
43
|
+
|
|
44
|
+
| Plataforma | Download |
|
|
45
|
+
| ---------------- | ------------------------------------------ |
|
|
46
|
+
| Windows | `opencode-desktop-win-x64.exe` (instalador NSIS) |
|
|
47
|
+
| macOS (Intel/ARM) | `opencode-desktop-mac-x64.dmg` / `opencode-desktop-mac-arm64.dmg` |
|
|
48
|
+
| Linux (Debian/Ubuntu) | `opencode-desktop-linux-x64.deb` |
|
|
49
|
+
| Linux (Fedora/RHEL) | `opencode-desktop-linux-x64.rpm` |
|
|
50
|
+
| Linux (universal) | `opencode-desktop-linux-x64.AppImage` |
|
|
51
|
+
|
|
52
|
+
Instalação via PowerShell no Windows (sempre baixa a última versão publicada):
|
|
53
|
+
|
|
54
|
+
```powershell
|
|
55
|
+
irm https://raw.githubusercontent.com/alltomatos/opencode/prod/install.ps1 | iex
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
No macOS e Linux, baixe o instalador correspondente direto da [página de releases](https://github.com/alltomatos/opencode/releases/latest) e instale manualmente (`.dmg`, `dpkg -i *.deb`, `rpm -i *.rpm`, ou dê permissão de execução no `.AppImage`).
|
|
59
|
+
|
|
60
|
+
> **Nota (macOS):** os builds de Mac não são assinados/notarizados por este fork (não temos uma conta Apple Developer configurada). Na primeira abertura o Gatekeeper vai avisar que o app "não pode ser verificado" — clique com o botão direito no app → **Abrir** para liberar manualmente.
|
|
61
|
+
|
|
62
|
+
O app verifica atualizações automaticamente contra este repositório (`alltomatos/opencode`), não contra o projeto original.
|
|
63
|
+
|
|
64
|
+
### Rodando em desenvolvimento
|
|
65
|
+
|
|
66
|
+
Pra validar mudanças antes de promover `dev` pra `prod`, rode o app desktop localmente a partir da branch `dev`:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
git clone https://github.com/alltomatos/opencode.git
|
|
70
|
+
cd opencode
|
|
71
|
+
git checkout dev
|
|
72
|
+
bun install
|
|
73
|
+
cd packages/desktop
|
|
74
|
+
bun run dev
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Isso abre o Electron em modo desenvolvimento (canal `dev`, auto-update desativado, ícone de dev). Pra buildar um instalador local sem publicar:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
cd packages/desktop
|
|
81
|
+
OPENCODE_CHANNEL=prod bun run build
|
|
82
|
+
bun run package:win # Windows (feito manualmente nesta máquina)
|
|
83
|
+
bun run package:mac # macOS — precisa rodar num Mac
|
|
84
|
+
bun run package:linux # Linux — precisa de dpkg/rpm/fpm disponíveis
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
O instalador gerado fica em `packages/desktop/dist/`.
|
|
88
|
+
|
|
89
|
+
**Publicação real é automática**: assim que a branch `prod` recebe um push (a promoção `dev` → `prod`), o workflow [`release-desktop.yml`](./.github/workflows/release-desktop.yml) dispara sozinho e builda Windows/macOS/Linux em paralelo (`windows-latest`/`macos-latest`/`ubuntu-latest`), publicando os três num único release do GitHub com a versão que estiver em `packages/desktop/package.json` no momento do push. Não precisa mais buildar nada manualmente nesta máquina — só bumpar a versão, commitar, e promover. Pra reexecutar manualmente (ex: retry de uma plataforma que falhou), use `gh workflow run release-desktop.yml`.
|
|
90
|
+
|
|
91
|
+
### CLI via npm (canais dev/prod)
|
|
92
|
+
|
|
93
|
+
Além do app desktop, o CLI deste fork é publicado direto no npm sob o escopo `@alltomatos`, separado dos pacotes `opencode-ai`/`@opencode-ai/*` do projeto original — instala com canal via a sintaxe `@tag` do próprio npm:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npm install -g @alltomatos/opencode@dev # última publicada a cada push em dev
|
|
97
|
+
npm install -g @alltomatos/opencode@latest # última publicada a cada push em prod
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Publicação é automática pelo workflow [`release-npm-fork.yml`](./.github/workflows/release-npm-fork.yml): builda os binários (cross-compilados num único runner) e publica com a tag correspondente à branch. Útil pra testar mudanças de `dev` via CLI/servidor sem precisar instalar o app desktop.
|
|
101
|
+
|
|
102
|
+
### Memória entre sessões
|
|
103
|
+
|
|
104
|
+
Este fork adiciona um sistema de memória cross-sessão (global e por projeto), habilitado por padrão. O modelo tem acesso a duas tools sob demanda — `memory_search` (consulta memórias relevantes) e `memory_save` (registra algo pra lembrar depois) — chamadas quando o próprio modelo decide que é relevante, sem injetar tudo automaticamente em todo prompt.
|
|
105
|
+
|
|
106
|
+
- **Ativar/desativar e escolher modelo**: Configurações → Memória (mesmo padrão de toggle instantâneo do resto do app).
|
|
107
|
+
- **Memória global** (`~/.local/share/opencode/memory/global/`) fica disponível como skill carregada automaticamente em qualquer sessão/projeto, além de consultável via `memory_search`.
|
|
108
|
+
- **Memória por projeto** (`~/.local/share/opencode/memory/projects/<projeto>/`) fica isolada por diretório.
|
|
109
|
+
|
|
110
|
+
### Rodando numa VPS (servidor remoto)
|
|
111
|
+
|
|
112
|
+
O OpenCode também roda como servidor puro, sem o app desktop — útil pra manter sessões ativas 24/7 e acessar de qualquer lugar.
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
export OPENCODE_SERVER_PASSWORD="uma-senha-forte-aqui"
|
|
116
|
+
opencode web --hostname 0.0.0.0 --port 4096 # UI web embutida, acessível pelo navegador
|
|
117
|
+
# ou
|
|
118
|
+
opencode serve --hostname 0.0.0.0 --port 4096 # só a API, pra conectar via app desktop ou TUI
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Depois é só adicionar esse endereço como servidor remoto em **Configurações → Servidores** no app desktop, ou abrir a URL direto no navegador. Guia completo (systemd, proxy reverso/TLS, segurança) em [`docs/vps-hosting.md`](./docs/vps-hosting.md).
|
|
122
|
+
|
|
123
|
+
**Bot do Telegram**: conecte em Configurações → Integrações → Telegram (token do @BotFather). Cada pedido roda em segundo plano; se um turno ficar travado (ex.: uma pergunta sem resposta) ele cancela sozinho depois de 10 minutos e avisa no chat — ou use `/cancel` pra cancelar na hora, sem precisar reiniciar o servidor. `/new` começa uma sessão nova a qualquer momento.
|
|
124
|
+
|
|
125
|
+
### Agents
|
|
126
|
+
|
|
127
|
+
OpenCode includes two built-in agents you can switch between with the `Tab` key.
|
|
128
|
+
|
|
129
|
+
- **build** - Default, full-access agent for development work
|
|
130
|
+
- **plan** - Read-only agent for analysis and code exploration
|
|
131
|
+
- Denies file edits by default
|
|
132
|
+
- Asks permission before running bash commands
|
|
133
|
+
- Ideal for exploring unfamiliar codebases or planning changes
|
|
134
|
+
|
|
135
|
+
Also included is a **general** subagent for complex searches and multistep tasks.
|
|
136
|
+
This is used internally and can be invoked using `@general` in messages.
|
|
137
|
+
|
|
138
|
+
Learn more about [agents](https://opencode.ai/docs/agents) in the original project's docs.
|
|
139
|
+
|
|
140
|
+
### Documentation
|
|
141
|
+
|
|
142
|
+
A documentação de configuração geral segue a do projeto original: [opencode.ai/docs](https://opencode.ai/docs). Diferenças específicas deste fork (sidebar de projetos, seed de skills, canal de atualização, etc.) não estão documentadas lá — consulte o [changelog](./changelog.json) deste repositório.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Créditos
|
|
147
|
+
|
|
148
|
+
Este fork existe graças ao trabalho da equipe original do **[OpenCode](https://github.com/anomalyco/opencode)** (anomalyco). Todo o núcleo do produto — o agente de codificação, a TUI, o protocolo, o SDK — vem do projeto original; este fork adiciona e ajusta principalmente a camada do app desktop.
|
|
149
|
+
|
|
150
|
+
- Projeto original: [github.com/anomalyco/opencode](https://github.com/anomalyco/opencode)
|
|
151
|
+
- Site oficial: [opencode.ai](https://opencode.ai)
|
|
152
|
+
- Discord oficial: [opencode.ai/discord](https://opencode.ai/discord)
|
|
153
|
+
|
|
154
|
+
Se você não está procurando especificamente por este fork, use o [projeto original](https://github.com/anomalyco/opencode)
|
|
155
|
+
|
|
156
|
+
### Building on OpenCode
|
|
157
|
+
|
|
158
|
+
If you are working on a project that's related to OpenCode and is using "opencode" as part of its name, for example "opencode-dashboard" or "opencode-mobile", please add a note to your README to clarify that it is not built by the OpenCode team and is not affiliated with them in any way.
|
package/bin/opencode.exe
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
echo "Error: @alltomatos/opencode's postinstall script was not run." >&2
|
|
2
|
+
echo "" >&2
|
|
3
|
+
echo "This occurs when using --ignore-scripts during installation, or when using a" >&2
|
|
4
|
+
echo "package manager like pnpm that does not run postinstall scripts by default." >&2
|
|
5
|
+
echo "" >&2
|
|
6
|
+
echo "To fix this, run the postinstall script manually:" >&2
|
|
7
|
+
echo " cd node_modules/@alltomatos/opencode && node postinstall.mjs" >&2
|
|
8
|
+
echo "" >&2
|
|
9
|
+
echo "Or reinstall @alltomatos/opencode without the --ignore-scripts flag." >&2
|
|
10
|
+
exit 1
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@alltomatos/opencode",
|
|
3
|
+
"bin": {
|
|
4
|
+
"opencode": "./bin/opencode.exe"
|
|
5
|
+
},
|
|
6
|
+
"scripts": {
|
|
7
|
+
"postinstall": "node ./postinstall.mjs"
|
|
8
|
+
},
|
|
9
|
+
"version": "1.21.11-dev.10",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"os": [
|
|
12
|
+
"darwin",
|
|
13
|
+
"linux",
|
|
14
|
+
"win32"
|
|
15
|
+
],
|
|
16
|
+
"cpu": [
|
|
17
|
+
"arm64",
|
|
18
|
+
"x64"
|
|
19
|
+
],
|
|
20
|
+
"optionalDependencies": {
|
|
21
|
+
"@alltomatos/opencode-darwin-x64-baseline": "1.21.11-dev.10",
|
|
22
|
+
"@alltomatos/opencode-darwin-x64": "1.21.11-dev.10",
|
|
23
|
+
"@alltomatos/opencode-darwin-arm64": "1.21.11-dev.10",
|
|
24
|
+
"@alltomatos/opencode-linux-arm64-musl": "1.21.11-dev.10",
|
|
25
|
+
"@alltomatos/opencode-linux-x64-baseline": "1.21.11-dev.10",
|
|
26
|
+
"@alltomatos/opencode-windows-x64": "1.21.11-dev.10",
|
|
27
|
+
"@alltomatos/opencode-linux-x64-baseline-musl": "1.21.11-dev.10",
|
|
28
|
+
"@alltomatos/opencode-windows-arm64": "1.21.11-dev.10",
|
|
29
|
+
"@alltomatos/opencode-linux-x64": "1.21.11-dev.10",
|
|
30
|
+
"@alltomatos/opencode-linux-x64-musl": "1.21.11-dev.10",
|
|
31
|
+
"@alltomatos/opencode-linux-arm64": "1.21.11-dev.10",
|
|
32
|
+
"@alltomatos/opencode-windows-x64-baseline": "1.21.11-dev.10"
|
|
33
|
+
}
|
|
34
|
+
}
|
package/postinstall.mjs
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import childProcess from "child_process"
|
|
4
|
+
import fs from "fs"
|
|
5
|
+
import os from "os"
|
|
6
|
+
import path from "path"
|
|
7
|
+
import { createRequire } from "module"
|
|
8
|
+
import { fileURLToPath } from "url"
|
|
9
|
+
|
|
10
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
11
|
+
const require = createRequire(import.meta.url)
|
|
12
|
+
const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, "package.json"), "utf8"))
|
|
13
|
+
|
|
14
|
+
const platformMap = {
|
|
15
|
+
darwin: "darwin",
|
|
16
|
+
linux: "linux",
|
|
17
|
+
win32: "windows",
|
|
18
|
+
}
|
|
19
|
+
const archMap = {
|
|
20
|
+
x64: "x64",
|
|
21
|
+
arm64: "arm64",
|
|
22
|
+
arm: "arm",
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const platform = platformMap[os.platform()] ?? os.platform()
|
|
26
|
+
const arch = archMap[os.arch()] ?? os.arch()
|
|
27
|
+
// Per-platform binary packages carry the same npm scope as this wrapper
|
|
28
|
+
// package (e.g. `@alltomatos/opencode` -> `@alltomatos/opencode-linux-x64`).
|
|
29
|
+
// Unscoped installs (upstream's own `opencode-ai`) have no scope, so this is
|
|
30
|
+
// a no-op there.
|
|
31
|
+
const [, scope] = /^(@[^/]+\/)/.exec(packageJson.name) ?? []
|
|
32
|
+
const base = `${scope ?? ""}opencode-${platform}-${arch}`
|
|
33
|
+
const sourceBinary = platform === "windows" ? "opencode.exe" : "opencode"
|
|
34
|
+
const targetBinary = path.join(__dirname, "bin", "opencode.exe")
|
|
35
|
+
|
|
36
|
+
function supportsAvx2() {
|
|
37
|
+
if (arch !== "x64") return false
|
|
38
|
+
|
|
39
|
+
if (platform === "linux") {
|
|
40
|
+
try {
|
|
41
|
+
return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
|
|
42
|
+
} catch {
|
|
43
|
+
return false
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (platform === "darwin") {
|
|
48
|
+
try {
|
|
49
|
+
const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], {
|
|
50
|
+
encoding: "utf8",
|
|
51
|
+
timeout: 1500,
|
|
52
|
+
})
|
|
53
|
+
if (result.status !== 0) return false
|
|
54
|
+
return (result.stdout || "").trim() === "1"
|
|
55
|
+
} catch {
|
|
56
|
+
return false
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (platform === "windows") {
|
|
61
|
+
const command =
|
|
62
|
+
'(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)'
|
|
63
|
+
|
|
64
|
+
for (const executable of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
|
|
65
|
+
try {
|
|
66
|
+
const result = childProcess.spawnSync(executable, ["-NoProfile", "-NonInteractive", "-Command", command], {
|
|
67
|
+
encoding: "utf8",
|
|
68
|
+
timeout: 3000,
|
|
69
|
+
windowsHide: true,
|
|
70
|
+
})
|
|
71
|
+
if (result.status !== 0) continue
|
|
72
|
+
const output = (result.stdout || "").trim().toLowerCase()
|
|
73
|
+
if (output === "true" || output === "1") return true
|
|
74
|
+
if (output === "false" || output === "0") return false
|
|
75
|
+
} catch {
|
|
76
|
+
continue
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return false
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function isMusl() {
|
|
85
|
+
if (platform !== "linux") return false
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
if (fs.existsSync("/etc/alpine-release")) return true
|
|
89
|
+
} catch {
|
|
90
|
+
// Ignore filesystem probes that are blocked by the host.
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
|
|
95
|
+
return `${result.stdout || ""}${result.stderr || ""}`.toLowerCase().includes("musl")
|
|
96
|
+
} catch {
|
|
97
|
+
return false
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function packageNames() {
|
|
102
|
+
const baseline = arch === "x64" && !supportsAvx2()
|
|
103
|
+
|
|
104
|
+
if (platform === "linux") {
|
|
105
|
+
if (isMusl()) {
|
|
106
|
+
if (arch === "x64")
|
|
107
|
+
return baseline
|
|
108
|
+
? [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
|
|
109
|
+
: [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
|
|
110
|
+
return [`${base}-musl`, base]
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (arch === "x64")
|
|
114
|
+
return baseline
|
|
115
|
+
? [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
|
|
116
|
+
: [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
|
|
117
|
+
return [base, `${base}-musl`]
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (arch === "x64") return baseline ? [`${base}-baseline`, base] : [base, `${base}-baseline`]
|
|
121
|
+
return [base]
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function resolveBinary(name) {
|
|
125
|
+
const packageJsonPath = require.resolve(`${name}/package.json`)
|
|
126
|
+
const binaryPath = path.join(path.dirname(packageJsonPath), "bin", sourceBinary)
|
|
127
|
+
if (!fs.existsSync(binaryPath)) throw new Error(`Binary not found at ${binaryPath}`)
|
|
128
|
+
return binaryPath
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function installPackage(name) {
|
|
132
|
+
const version = packageJson.optionalDependencies?.[name]
|
|
133
|
+
if (!version) return
|
|
134
|
+
|
|
135
|
+
const temp = fs.mkdtempSync(path.join(os.tmpdir(), "opencode-install-"))
|
|
136
|
+
try {
|
|
137
|
+
const result = childProcess.spawnSync(
|
|
138
|
+
"npm",
|
|
139
|
+
["install", "--ignore-scripts", "--no-save", "--loglevel=error", "--prefix", temp, `${name}@${version}`],
|
|
140
|
+
{ stdio: "inherit", windowsHide: true },
|
|
141
|
+
)
|
|
142
|
+
if (result.status !== 0) return
|
|
143
|
+
const packageDir = path.join(temp, "node_modules", name)
|
|
144
|
+
copyBinary(path.join(packageDir, "bin", sourceBinary), targetBinary)
|
|
145
|
+
return true
|
|
146
|
+
} finally {
|
|
147
|
+
fs.rmSync(temp, { recursive: true, force: true })
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function copyBinary(source, target) {
|
|
152
|
+
if (!fs.existsSync(source)) throw new Error(`Binary not found at ${source}`)
|
|
153
|
+
fs.mkdirSync(path.dirname(target), { recursive: true })
|
|
154
|
+
if (fs.existsSync(target)) fs.unlinkSync(target)
|
|
155
|
+
try {
|
|
156
|
+
fs.linkSync(source, target)
|
|
157
|
+
} catch {
|
|
158
|
+
fs.copyFileSync(source, target)
|
|
159
|
+
}
|
|
160
|
+
fs.chmodSync(target, 0o755)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function verifyBinary() {
|
|
164
|
+
const result = childProcess.spawnSync(targetBinary, ["--version"], {
|
|
165
|
+
encoding: "utf8",
|
|
166
|
+
stdio: "ignore",
|
|
167
|
+
windowsHide: true,
|
|
168
|
+
})
|
|
169
|
+
return result.status === 0
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function main() {
|
|
173
|
+
for (const name of packageNames()) {
|
|
174
|
+
try {
|
|
175
|
+
copyBinary(resolveBinary(name), targetBinary)
|
|
176
|
+
if (verifyBinary()) return
|
|
177
|
+
} catch {
|
|
178
|
+
if (installPackage(name) && verifyBinary()) return
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
throw new Error(
|
|
183
|
+
`It seems your package manager failed to install the right opencode CLI package. Try manually installing ${packageNames()
|
|
184
|
+
.map((name) => JSON.stringify(name))
|
|
185
|
+
.join(" or ")}.`,
|
|
186
|
+
)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
try {
|
|
190
|
+
main()
|
|
191
|
+
} catch (error) {
|
|
192
|
+
console.error(error.message)
|
|
193
|
+
process.exit(1)
|
|
194
|
+
}
|