@genflowai/opencode-autosetup 1.0.0
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/README.md +265 -0
- package/package.json +20 -0
- package/setup-opencode.js +199 -0
package/README.md
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# GenFlow OpenCode Auto Setup
|
|
2
|
+
|
|
3
|
+
Auto setup provider GenFlowAI untuk OpenCode lewat npm.
|
|
4
|
+
|
|
5
|
+
Script ini akan cek OpenCode, install otomatis jika belum ada, meminta API key GenFlow, meminta model yang ingin dipakai, lalu otomatis membuat atau memperbarui config OpenCode di komputer user.
|
|
6
|
+
|
|
7
|
+
## Syarat
|
|
8
|
+
|
|
9
|
+
- Node.js minimal versi 18
|
|
10
|
+
- npm
|
|
11
|
+
- API key GenFlowAI
|
|
12
|
+
|
|
13
|
+
API docs: <https://genflowai.co/api-docs>
|
|
14
|
+
|
|
15
|
+
Daftar model: <https://genflowai.co/models>
|
|
16
|
+
|
|
17
|
+
## Cara pakai cepat
|
|
18
|
+
|
|
19
|
+
Jalankan:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx @genflowai/opencode-autosetup
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Lalu isi prompt:
|
|
26
|
+
|
|
27
|
+
```text
|
|
28
|
+
Masukkan GenFlow API key: gf_xxxxxxxxx
|
|
29
|
+
Model [gpt-5.5]: gpt-5.5
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Jika ingin pakai default model `gpt-5.5`, cukup tekan Enter saat ditanya model.
|
|
33
|
+
|
|
34
|
+
## Cara pakai dari source lokal
|
|
35
|
+
|
|
36
|
+
Jika repo/script ini sudah ada di komputer:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm run setup
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Apa yang dilakukan script?
|
|
43
|
+
|
|
44
|
+
1. Mengecek apakah command `opencode` sudah tersedia.
|
|
45
|
+
2. Jika belum tersedia, script install otomatis dengan:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm install -g opencode-ai@latest
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
3. Meminta API key GenFlowAI.
|
|
52
|
+
4. Mengambil daftar model dari:
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
https://genflowai.co/v1/models
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
5. Menampilkan beberapa contoh model tersedia.
|
|
59
|
+
6. Meminta user memasukkan model manual.
|
|
60
|
+
7. Validasi model jika endpoint model bisa diakses.
|
|
61
|
+
8. Menulis config OpenCode ke home directory user.
|
|
62
|
+
|
|
63
|
+
Lokasi config default:
|
|
64
|
+
|
|
65
|
+
```text
|
|
66
|
+
~/.config/opencode/opencode.json
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Contoh di Windows akan menjadi:
|
|
70
|
+
|
|
71
|
+
```text
|
|
72
|
+
C:\Users\NAMA_USER\.config\opencode\opencode.json
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Tidak ada path user hardcoded. Path otomatis mengikuti komputer masing-masing user.
|
|
76
|
+
|
|
77
|
+
## Contoh config yang dibuat
|
|
78
|
+
|
|
79
|
+
Jika user memilih model `gpt-5.5`, script akan membuat config seperti ini:
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"$schema": "https://opencode.ai/config.json",
|
|
84
|
+
"model": "genflowai/gpt-5.5",
|
|
85
|
+
"provider": {
|
|
86
|
+
"genflowai": {
|
|
87
|
+
"npm": "@ai-sdk/openai-compatible",
|
|
88
|
+
"name": "GenFlowAI",
|
|
89
|
+
"options": {
|
|
90
|
+
"baseURL": "https://genflowai.co/v1",
|
|
91
|
+
"apiKey": "API_KEY_USER"
|
|
92
|
+
},
|
|
93
|
+
"models": {
|
|
94
|
+
"gpt-5.5": {
|
|
95
|
+
"name": "gpt-5.5"
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Memilih model
|
|
104
|
+
|
|
105
|
+
User bisa memasukkan model apa pun yang tersedia di:
|
|
106
|
+
|
|
107
|
+
```text
|
|
108
|
+
https://genflowai.co/models
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Contoh model:
|
|
112
|
+
|
|
113
|
+
```text
|
|
114
|
+
gpt-5.5
|
|
115
|
+
gpt-5.5-high
|
|
116
|
+
gpt-5.5-medium
|
|
117
|
+
gpt-5.5-low
|
|
118
|
+
gpt-5.4
|
|
119
|
+
gpt-5.3
|
|
120
|
+
gpt-5.2
|
|
121
|
+
gpt-5.1
|
|
122
|
+
claude-opus-4.7
|
|
123
|
+
claude-sonnet-4.6
|
|
124
|
+
gemini-3-pro-preview
|
|
125
|
+
deepseek-v3.2
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Saat prompt muncul:
|
|
129
|
+
|
|
130
|
+
```text
|
|
131
|
+
Model [gpt-5.5]:
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Pilihan:
|
|
135
|
+
|
|
136
|
+
- tekan Enter → pakai `gpt-5.5`
|
|
137
|
+
- ketik manual → contoh `gpt-5.5-high`
|
|
138
|
+
|
|
139
|
+
## Mode non-interaktif
|
|
140
|
+
|
|
141
|
+
Cocok untuk automation/CI/script.
|
|
142
|
+
|
|
143
|
+
Linux/macOS:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
GENFLOW_API_KEY="gf_xxxxxxxxx" npx @genflowai/opencode-autosetup --model gpt-5.5
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Windows PowerShell:
|
|
150
|
+
|
|
151
|
+
```powershell
|
|
152
|
+
$env:GENFLOW_API_KEY="gf_xxxxxxxxx"; npx @genflowai/opencode-autosetup --model gpt-5.5
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Atau langsung lewat argumen:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
npx @genflowai/opencode-autosetup --api-key gf_xxxxxxxxx --model gpt-5.5
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Jika ingin melewati cek/install OpenCode:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
npx @genflowai/opencode-autosetup --skip-opencode-install --api-key gf_xxxxxxxxx --model gpt-5.5
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Custom lokasi config
|
|
168
|
+
|
|
169
|
+
Defaultnya script menulis ke:
|
|
170
|
+
|
|
171
|
+
```text
|
|
172
|
+
~/.config/opencode/opencode.json
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Untuk test atau custom lokasi, pakai `OPENCODE_CONFIG_DIR`.
|
|
176
|
+
|
|
177
|
+
Linux/macOS:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
OPENCODE_CONFIG_DIR="/tmp/opencode" GENFLOW_API_KEY="gf_xxxxxxxxx" npx @genflowai/opencode-autosetup --model gpt-5.5
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Windows PowerShell:
|
|
184
|
+
|
|
185
|
+
```powershell
|
|
186
|
+
$env:OPENCODE_CONFIG_DIR="C:\Temp\opencode"; $env:GENFLOW_API_KEY="gf_xxxxxxxxx"; npx @genflowai/opencode-autosetup --model gpt-5.5
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Setelah setup
|
|
190
|
+
|
|
191
|
+
Jalankan OpenCode:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
opencode
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
OpenCode akan memakai provider:
|
|
198
|
+
|
|
199
|
+
```text
|
|
200
|
+
genflowai
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Dengan model:
|
|
204
|
+
|
|
205
|
+
```text
|
|
206
|
+
genflowai/NAMA_MODEL
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Contoh:
|
|
210
|
+
|
|
211
|
+
```text
|
|
212
|
+
genflowai/gpt-5.5
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Troubleshooting
|
|
216
|
+
|
|
217
|
+
### `API key wajib diisi.`
|
|
218
|
+
|
|
219
|
+
API key kosong. Jalankan ulang lalu isi API key GenFlowAI.
|
|
220
|
+
|
|
221
|
+
### `Model tidak ditemukan`
|
|
222
|
+
|
|
223
|
+
Model yang diketik tidak ada di endpoint model GenFlowAI.
|
|
224
|
+
|
|
225
|
+
Cek daftar model:
|
|
226
|
+
|
|
227
|
+
```text
|
|
228
|
+
https://genflowai.co/models
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Lalu jalankan ulang dengan model yang valid.
|
|
232
|
+
|
|
233
|
+
### `npm` tidak bisa jalan di PowerShell
|
|
234
|
+
|
|
235
|
+
Jika PowerShell memblokir `npm.ps1`, pakai:
|
|
236
|
+
|
|
237
|
+
```powershell
|
|
238
|
+
cmd /c "npm run setup"
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
atau:
|
|
242
|
+
|
|
243
|
+
```powershell
|
|
244
|
+
cmd /c "npx @genflowai/opencode-autosetup"
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Install OpenCode gagal
|
|
248
|
+
|
|
249
|
+
Script otomatis menjalankan:
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
npm install -g opencode-ai@latest
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Jika gagal, cek koneksi internet dan permission npm global. Setelah berhasil, restart terminal lalu jalankan ulang script.
|
|
256
|
+
|
|
257
|
+
Jika OpenCode sudah terinstall tapi script tetap ingin install, jalankan dengan:
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
npx @genflowai/opencode-autosetup --skip-opencode-install
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Config lama sudah ada
|
|
264
|
+
|
|
265
|
+
Script akan membaca config lama lalu menambahkan/memperbarui provider `genflowai`. Config provider lain tetap dipertahankan.
|
package/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@genflowai/opencode-autosetup",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Auto setup GenFlowAI provider for OpenCode",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"genflow-opencode-autosetup": "setup-opencode.js",
|
|
8
|
+
"genflowai-opencode-autosetup": "setup-opencode.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"setup-opencode.js",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"setup": "node setup-opencode.js"
|
|
16
|
+
},
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=18"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createInterface } from "node:readline/promises";
|
|
3
|
+
import { stdin as input, stdout as output } from "node:process";
|
|
4
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
5
|
+
import { existsSync } from "node:fs";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { homedir } from "node:os";
|
|
8
|
+
import { spawn } from "node:child_process";
|
|
9
|
+
|
|
10
|
+
const PROVIDER_ID = "genflowai";
|
|
11
|
+
const BASE_URL = "https://genflowai.co/v1";
|
|
12
|
+
const MODELS_URL = `${BASE_URL}/models`;
|
|
13
|
+
const DEFAULT_MODEL = "gpt-5.5";
|
|
14
|
+
const CONFIG_DIR = process.env.OPENCODE_CONFIG_DIR || join(homedir(), ".config", "opencode");
|
|
15
|
+
const CONFIG_PATH = join(CONFIG_DIR, "opencode.json");
|
|
16
|
+
|
|
17
|
+
function getArgValue(name) {
|
|
18
|
+
const index = process.argv.indexOf(name);
|
|
19
|
+
return index === -1 ? "" : process.argv[index + 1] ?? "";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function hasArg(name) {
|
|
23
|
+
return process.argv.includes(name);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function run(command, args) {
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
const child = spawnProcess(command, args, "inherit");
|
|
29
|
+
child.on("error", reject);
|
|
30
|
+
child.on("close", (code) => {
|
|
31
|
+
if (code === 0) {
|
|
32
|
+
resolve();
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
reject(new Error(`${command} ${args.join(" ")} keluar dengan kode ${code}`));
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function runQuiet(command, args) {
|
|
42
|
+
return new Promise((resolve) => {
|
|
43
|
+
const child = spawnProcess(command, args, "ignore");
|
|
44
|
+
child.on("error", () => resolve(false));
|
|
45
|
+
child.on("close", (code) => resolve(code === 0));
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function spawnProcess(command, args, stdio) {
|
|
50
|
+
if (process.platform !== "win32") {
|
|
51
|
+
return spawn(command, args, { shell: false, stdio });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return spawn(process.env.ComSpec || "cmd.exe", ["/d", "/s", "/c", command, ...args], { shell: false, stdio });
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function npmCommand() {
|
|
58
|
+
return process.platform === "win32" ? "npm.cmd" : "npm";
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function opencodeCommand() {
|
|
62
|
+
return process.platform === "win32" ? "opencode.cmd" : "opencode";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function ensureOpenCodeInstalled() {
|
|
66
|
+
if (hasArg("--skip-opencode-install")) {
|
|
67
|
+
console.log("Skip cek/install OpenCode.");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const installed = await runQuiet(opencodeCommand(), ["--version"]);
|
|
72
|
+
|
|
73
|
+
if (installed) {
|
|
74
|
+
console.log("OpenCode sudah terinstall.");
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
console.log("OpenCode belum terinstall. Menginstall via npm...");
|
|
79
|
+
await run(npmCommand(), ["install", "-g", "opencode-ai@latest"]);
|
|
80
|
+
|
|
81
|
+
const installedAfterInstall = await runQuiet(opencodeCommand(), ["--version"]);
|
|
82
|
+
if (!installedAfterInstall) {
|
|
83
|
+
throw new Error("OpenCode sudah diinstall, tapi command `opencode` belum tersedia di PATH. Restart terminal lalu coba lagi.");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
console.log("OpenCode berhasil terinstall.");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function stripJsonComments(value) {
|
|
90
|
+
return value
|
|
91
|
+
.replace(/\/\*[\s\S]*?\*\//g, "")
|
|
92
|
+
.replace(/(^|[^:])\/\/.*$/gm, "$1");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async function readExistingConfig() {
|
|
96
|
+
if (!existsSync(CONFIG_PATH)) {
|
|
97
|
+
return {};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const raw = await readFile(CONFIG_PATH, "utf8");
|
|
101
|
+
return JSON.parse(stripJsonComments(raw));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function fetchAvailableModels() {
|
|
105
|
+
try {
|
|
106
|
+
const response = await fetch(MODELS_URL);
|
|
107
|
+
|
|
108
|
+
if (!response.ok) {
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const payload = await response.json();
|
|
113
|
+
return Array.isArray(payload.data)
|
|
114
|
+
? payload.data.map((model) => model.id).filter((model) => typeof model === "string")
|
|
115
|
+
: [];
|
|
116
|
+
} catch {
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function printModelHint(models) {
|
|
122
|
+
if (models.length === 0) {
|
|
123
|
+
console.log(`Daftar model: ${MODELS_URL}`);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
console.log("Model tersedia contoh:");
|
|
128
|
+
for (const model of models.slice(0, 12)) {
|
|
129
|
+
console.log(`- ${model}`);
|
|
130
|
+
}
|
|
131
|
+
console.log(`Total model: ${models.length}. Lihat lengkap: https://genflowai.co/models`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function buildConfig(existingConfig, apiKey, model) {
|
|
135
|
+
return {
|
|
136
|
+
...existingConfig,
|
|
137
|
+
$schema: existingConfig.$schema ?? "https://opencode.ai/config.json",
|
|
138
|
+
model: `${PROVIDER_ID}/${model}`,
|
|
139
|
+
provider: {
|
|
140
|
+
...(existingConfig.provider ?? {}),
|
|
141
|
+
[PROVIDER_ID]: {
|
|
142
|
+
npm: "@ai-sdk/openai-compatible",
|
|
143
|
+
name: "GenFlowAI",
|
|
144
|
+
options: {
|
|
145
|
+
baseURL: BASE_URL,
|
|
146
|
+
apiKey
|
|
147
|
+
},
|
|
148
|
+
models: {
|
|
149
|
+
...(existingConfig.provider?.[PROVIDER_ID]?.models ?? {}),
|
|
150
|
+
[model]: {
|
|
151
|
+
name: model
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async function main() {
|
|
160
|
+
const rl = createInterface({ input, output });
|
|
161
|
+
|
|
162
|
+
try {
|
|
163
|
+
await ensureOpenCodeInstalled();
|
|
164
|
+
|
|
165
|
+
const apiKey = (getArgValue("--api-key") || process.env.GENFLOW_API_KEY || await rl.question("Masukkan GenFlow API key: ")).trim();
|
|
166
|
+
|
|
167
|
+
if (!apiKey) {
|
|
168
|
+
throw new Error("API key wajib diisi.");
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const availableModels = await fetchAvailableModels();
|
|
172
|
+
printModelHint(availableModels);
|
|
173
|
+
|
|
174
|
+
const modelInput = (getArgValue("--model") || await rl.question(`Model [${DEFAULT_MODEL}]: `)).trim();
|
|
175
|
+
const model = modelInput || DEFAULT_MODEL;
|
|
176
|
+
|
|
177
|
+
if (availableModels.length > 0 && !availableModels.includes(model)) {
|
|
178
|
+
throw new Error(`Model "${model}" tidak ditemukan di ${MODELS_URL}. Cek https://genflowai.co/models`);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const existingConfig = await readExistingConfig();
|
|
182
|
+
const nextConfig = buildConfig(existingConfig, apiKey, model);
|
|
183
|
+
|
|
184
|
+
await mkdir(CONFIG_DIR, { recursive: true });
|
|
185
|
+
await writeFile(CONFIG_PATH, `${JSON.stringify(nextConfig, null, 2)}\n`, "utf8");
|
|
186
|
+
|
|
187
|
+
console.log(`\nSelesai. Config opencode ditulis ke: ${CONFIG_PATH}`);
|
|
188
|
+
console.log(`Provider: ${PROVIDER_ID}`);
|
|
189
|
+
console.log(`Model: ${PROVIDER_ID}/${model}`);
|
|
190
|
+
console.log("Jalankan: opencode");
|
|
191
|
+
} finally {
|
|
192
|
+
rl.close();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
main().catch((error) => {
|
|
197
|
+
console.error(`Gagal setup opencode: ${error.message}`);
|
|
198
|
+
process.exitCode = 1;
|
|
199
|
+
});
|