@vheins/opencode-9router 0.4.0 → 0.4.2

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.
Files changed (3) hide show
  1. package/README.md +33 -16
  2. package/dist/plugin.js +30 -19
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -8,7 +8,8 @@ Mendaftarkan 9Router sebagai custom provider di OpenCode dengan auto-discovery m
8
8
 
9
9
  ```json
10
10
  {
11
- "plugin": ["@vheins/opencode-9router"]
11
+ "$schema": "https://opencode.ai/config.json",
12
+ "plugin": ["@vheins/opencode-9router@latest"]
12
13
  }
13
14
  ```
14
15
 
@@ -21,10 +22,11 @@ Mendaftarkan 9Router sebagai custom provider di OpenCode dengan auto-discovery m
21
22
  ## Features
22
23
 
23
24
  - **Auto-discover models** — Models dari 9Router otomatis terdeteksi saat startup
24
- - **Configurable baseURL** — Atur Base URL langsung dari `/connect`, bukan dari opencode.json
25
+ - **Configurable baseURL** — Atur Base URL via `/connect`, plugin options, atau environment variable
25
26
  - **Dynamic model list** — Semua model dari 9Router tersedia, termasuk combo kustom
26
27
  - **27+ fallback models** — Well-known models tersedia jika 9Router belum running
27
28
  - **OpenAI-compatible** — Menggunakan `@ai-sdk/openai-compatible`
29
+ - **Type-safe** — Menggunakan `config` hook untuk registrasi provider yang sesuai dengan OpenCode config schema
28
30
 
29
31
  ## Installation
30
32
 
@@ -32,14 +34,18 @@ Mendaftarkan 9Router sebagai custom provider di OpenCode dengan auto-discovery m
32
34
 
33
35
  ```json
34
36
  {
35
- "plugin": ["@vheins/opencode-9router"]
37
+ "$schema": "https://opencode.ai/config.json",
38
+ "plugin": ["@vheins/opencode-9router@latest"]
36
39
  }
37
40
  ```
38
41
 
42
+ Tidak perlu mendefinisikan models atau provider secara manual — plugin mendaftarkan semuanya otomatis.
43
+
39
44
  ### Local file
40
45
 
41
46
  ```bash
42
47
  cp src/plugin.ts .opencode/plugins/9router-provider.ts
48
+ cp src/constants.ts .opencode/plugins/constants.ts
43
49
  ```
44
50
 
45
51
  ## Usage
@@ -63,23 +69,24 @@ cp src/plugin.ts .opencode/plugins/9router-provider.ts
63
69
 
64
70
  ### Custom Base URL
65
71
 
66
- Jika 9Router berjalan di host/port berbeda, masukkan URL saat `/connect`:
72
+ Jika 9Router berjalan di host/port berbeda, ada 3 cara konfigurasi:
67
73
 
68
- ```
69
- Base URL: http://192.168.1.100:20128
70
- ```
74
+ #### Via `/connect` (recommended)
71
75
 
72
- Atau via plugin options:
76
+ Masukkan URL custom saat diminta Base URL.
77
+
78
+ #### Via plugin options
73
79
 
74
80
  ```json
75
81
  {
82
+ "$schema": "https://opencode.ai/config.json",
76
83
  "plugin": [
77
- ["@vheins/opencode-9router", { "baseURL": "http://192.168.1.100:20128" }]
84
+ ["@vheins/opencode-9router@latest", { "baseURL": "http://192.168.1.100:20128" }]
78
85
  ]
79
86
  }
80
87
  ```
81
88
 
82
- Atau via environment variable:
89
+ #### Via environment variable
83
90
 
84
91
  ```bash
85
92
  export ROUTER_BASE_URL=http://192.168.1.100:20128
@@ -106,14 +113,17 @@ export ROUTER_BASE_URL=http://192.168.1.100:20128
106
113
  ## How It Works
107
114
 
108
115
  ```
109
- opencode.json "plugin": ["@vheins/opencode-9router"]
116
+ opencode.json "plugin": ["@vheins/opencode-9router@latest"]
110
117
 
111
118
  Bun installs package from npm
112
119
 
113
120
  Plugin loads at startup:
114
- 1. Try GET /v1/models from 9Router (3s timeout)
115
- 2. If OK register live models
116
- 3. If fail → register 27 fallback models
121
+ 1. Resolve baseURL (options > env > default)
122
+ 2. Try GET /v1/models from 9Router (3s timeout)
123
+ 3. If OK → register live models
124
+ 4. If fail → register 27 fallback models
125
+
126
+ config hook injects provider "9router" into OpenCode config
117
127
 
118
128
  Provider "9router" appears in /models
119
129
 
@@ -127,7 +137,14 @@ Auth loader overrides provider config with user's baseURL
127
137
  ```bash
128
138
  git clone https://github.com/vheins/opencode-9router
129
139
  cd opencode-9router
130
- bun install
140
+ npm install
141
+ npm run build
142
+ ```
143
+
144
+ ### Test
145
+
146
+ ```bash
147
+ node test-minimal.mjs
131
148
  ```
132
149
 
133
150
  ### Publish
@@ -141,10 +158,10 @@ npm publish --access public
141
158
 
142
159
  ```
143
160
  opencode-9router/
144
- index.ts # Re-exports
145
161
  src/
146
162
  plugin.ts # Main plugin logic
147
163
  constants.ts # Models, defaults, prefixes
164
+ dist/ # Compiled output (generated)
148
165
  package.json # npm package config
149
166
  tsconfig.json # TypeScript config
150
167
  README.md # This file
package/dist/plugin.js CHANGED
@@ -1,4 +1,4 @@
1
- import { PLUGIN_NAME, PROVIDER_DISPLAY_NAME, DEFAULT_BASE_URL, DEFAULT_API_PATH, FALLBACK_MODELS, KNOWN_PROVIDER_PREFIXES, } from "./constants.js";
1
+ import { PLUGIN_NAME, PROVIDER_DISPLAY_NAME, DEFAULT_BASE_URL, DEFAULT_API_PATH, KNOWN_PROVIDER_PREFIXES, } from "./constants.js";
2
2
  function formatModelName(modelId) {
3
3
  for (const [prefix, provider] of Object.entries(KNOWN_PROVIDER_PREFIXES)) {
4
4
  if (modelId.startsWith(prefix)) {
@@ -7,8 +7,24 @@ function formatModelName(modelId) {
7
7
  }
8
8
  return modelId;
9
9
  }
10
+ function normalizeBaseURL(url) {
11
+ return url.replace(/\/+$/, "");
12
+ }
13
+ function resolveBaseURL(options) {
14
+ if (options?.baseURL && typeof options.baseURL === "string") {
15
+ return normalizeBaseURL(options.baseURL);
16
+ }
17
+ const envURL = globalThis.process;
18
+ if (envURL?.env?.ROUTER_BASE_URL) {
19
+ return normalizeBaseURL(envURL.env.ROUTER_BASE_URL);
20
+ }
21
+ return DEFAULT_BASE_URL;
22
+ }
23
+ function ensureAPIPath(baseURL) {
24
+ return baseURL.endsWith(DEFAULT_API_PATH) ? baseURL : `${baseURL}${DEFAULT_API_PATH}`;
25
+ }
10
26
  async function discoverModels(baseURL) {
11
- const apiURL = `${baseURL}${DEFAULT_API_PATH}`;
27
+ const apiURL = ensureAPIPath(baseURL);
12
28
  try {
13
29
  const response = await fetch(`${apiURL}/models`, {
14
30
  signal: AbortSignal.timeout(3000),
@@ -29,36 +45,37 @@ async function discoverModels(baseURL) {
29
45
  return null;
30
46
  }
31
47
  }
32
- export const NineRouterPlugin = async ({ client }) => {
33
- const configuredBaseURL = DEFAULT_BASE_URL;
48
+ export const NineRouterPlugin = async ({ client }, options) => {
49
+ const configuredBaseURL = resolveBaseURL(options);
34
50
  const discovered = await discoverModels(configuredBaseURL);
35
- const models = discovered ?? FALLBACK_MODELS;
36
51
  if (!discovered && client?.app?.log) {
37
52
  await client.app.log({
38
53
  body: {
39
54
  service: "9router-provider",
40
- level: "warn",
41
- message: `9Router not reachable at ${configuredBaseURL}. Using well-known model list. Start 9Router and restart opencode to auto-discover models.`,
55
+ level: "error",
56
+ message: `9Router not reachable at ${configuredBaseURL}. Please check if 9Router is running and accessible.`,
42
57
  },
43
58
  });
44
59
  }
45
60
  return {
46
- provider: {
47
- [PLUGIN_NAME]: {
61
+ config: async (config) => {
62
+ config.provider ??= {};
63
+ config.provider[PLUGIN_NAME] = {
48
64
  npm: "@ai-sdk/openai-compatible",
49
65
  name: PROVIDER_DISPLAY_NAME,
50
66
  options: {
51
- baseURL: `${configuredBaseURL}${DEFAULT_API_PATH}`,
67
+ baseURL: ensureAPIPath(configuredBaseURL),
52
68
  },
53
- models,
54
- },
69
+ models: discovered ?? {},
70
+ };
55
71
  },
56
72
  auth: {
57
73
  provider: PLUGIN_NAME,
58
74
  async loader(getAuth) {
59
75
  const auth = await getAuth();
60
76
  if (auth && typeof auth === "object" && "baseURL" in auth) {
61
- return { baseURL: `${String(auth.baseURL)}${DEFAULT_API_PATH}` };
77
+ const userURL = normalizeBaseURL(String(auth.baseURL));
78
+ return { baseURL: ensureAPIPath(userURL) };
62
79
  }
63
80
  return {};
64
81
  },
@@ -71,12 +88,6 @@ export const NineRouterPlugin = async ({ client }) => {
71
88
  type: "text",
72
89
  message: `${PROVIDER_DISPLAY_NAME} Base URL (default: ${DEFAULT_BASE_URL})`,
73
90
  key: "baseURL",
74
- default: DEFAULT_BASE_URL,
75
- },
76
- {
77
- type: "text",
78
- message: `${PROVIDER_DISPLAY_NAME} API Key (from Dashboard → Endpoints)`,
79
- key: "apiKey",
80
91
  },
81
92
  ],
82
93
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vheins/opencode-9router",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "OpenCode plugin provider for 9Router — FREE AI Router & Token Saver. 40+ providers, 100+ models.",
5
5
  "author": "vheins",
6
6
  "keywords": [