@route_33/opencode 0.4.7-rc.5 → 0.4.7-rc.7
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 +23 -14
- package/dist/index.js +38 -1
- package/dist/tui-entry/index.js +105 -7
- package/dist/v2-entry/index.js +38 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,22 +5,27 @@ usage, and use the route_33 models — no API keys to paste, ever.
|
|
|
5
5
|
|
|
6
6
|
## Install
|
|
7
7
|
|
|
8
|
-
**OpenCode v2 (recommended)
|
|
9
|
-
the global configuration (`~/.config/opencode/opencode.json` + `tui.json`):
|
|
8
|
+
**OpenCode v2 (recommended):**
|
|
10
9
|
|
|
11
10
|
```sh
|
|
12
11
|
opencode plugin add @route_33/opencode
|
|
13
12
|
```
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
`tui.json`
|
|
14
|
+
Installs globally — one `plugins` entry in the config's `opencode.json`
|
|
15
|
+
loads every part (the server and TUI parts are auto-discovered from the
|
|
16
|
+
package exports; no `tui.json` exists on v2).
|
|
17
|
+
|
|
18
|
+
**OpenCode v1:**
|
|
18
19
|
|
|
19
20
|
```sh
|
|
20
|
-
opencode plugin @route_33/opencode # project scope
|
|
21
|
+
opencode plugin @route_33/opencode # project scope (default)
|
|
21
22
|
opencode plugin @route_33/opencode --global # global scope
|
|
22
23
|
```
|
|
23
24
|
|
|
25
|
+
Installs at the nearest definition and registers the plugin twice: the
|
|
26
|
+
server part in `opencode.json` and the TUI part in `tui.json` — both files
|
|
27
|
+
are load-bearing on v1, which is why the installer writes both.
|
|
28
|
+
|
|
24
29
|
Either way, restart OpenCode afterwards — plugins load at startup. Prefer
|
|
25
30
|
config? Declare the plugin directly in `opencode.json(c)`:
|
|
26
31
|
|
|
@@ -30,15 +35,19 @@ config? Declare the plugin directly in `opencode.json(c)`:
|
|
|
30
35
|
|
|
31
36
|
## First run
|
|
32
37
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
With `ROUTE33_API_KEY` unset and `ROUTE33_AUTOCONNECT` not `0`, the wizard
|
|
39
|
+
auto-starts at launch and completes **before the first prompt** on OpenCode
|
|
40
|
+
v2 — the setup awaits the whole chain:
|
|
41
|
+
|
|
42
|
+
1. The browser sign-in opens; finish it there.
|
|
43
|
+
2. The budget picker follows in OpenCode — one of your Route 33 projects,
|
|
44
|
+
or your personal key.
|
|
45
|
+
3. The route_33 models appear. Pick one and prompt away.
|
|
39
46
|
|
|
40
|
-
|
|
41
|
-
the
|
|
47
|
+
On OpenCode v1 the wizard also auto-starts, but the 1.x TUI API has no
|
|
48
|
+
pre-prompt hook, so it runs in parallel with the prompt — the models appear
|
|
49
|
+
after the wizard finishes and OpenCode restarts. Use `/r33` any time to
|
|
50
|
+
re-run connect, change the budget, or inspect the session.
|
|
42
51
|
|
|
43
52
|
## Commands
|
|
44
53
|
|
package/dist/index.js
CHANGED
|
@@ -3245,6 +3245,26 @@ var Route33Runtime = class {
|
|
|
3245
3245
|
}
|
|
3246
3246
|
};
|
|
3247
3247
|
|
|
3248
|
+
// src/v1-entry/unattributed-prompt-gate/unattributed-prompt-gate.ts
|
|
3249
|
+
var createUnattributedPromptGate = ({ directory, outsideWorktree }) => (input) => {
|
|
3250
|
+
if (input.model?.providerID !== "route_33") return Promise.resolve();
|
|
3251
|
+
const attribution = readAttribution({ directory, outsideWorktree });
|
|
3252
|
+
if (attribution !== void 0) return Promise.resolve();
|
|
3253
|
+
return Promise.reject(
|
|
3254
|
+
new Error(
|
|
3255
|
+
"Route 33 needs a budget for this folder first \u2014 run /r33 in OpenCode, choose Route 33, and assign a budget."
|
|
3256
|
+
)
|
|
3257
|
+
);
|
|
3258
|
+
};
|
|
3259
|
+
|
|
3260
|
+
// src/v1-entry/workspace-key-headers/workspace-key-headers.ts
|
|
3261
|
+
var createWorkspaceKeyHeaders = ({ resolveKey, session }) => async (input, output) => {
|
|
3262
|
+
const workspace = await session.get({ sessionID: input.sessionID });
|
|
3263
|
+
const key = await resolveKey(workspace.location.directory);
|
|
3264
|
+
if (key === void 0) return;
|
|
3265
|
+
output.headers["Authorization"] = `Bearer ${key.value}`;
|
|
3266
|
+
};
|
|
3267
|
+
|
|
3248
3268
|
// src/create-route33-plugin/create-route33-plugin.ts
|
|
3249
3269
|
var createRoute33Plugin = (options = {}) => {
|
|
3250
3270
|
const baseURL = readEnvBaseUrl();
|
|
@@ -3285,6 +3305,8 @@ var createRoute33Plugin = (options = {}) => {
|
|
|
3285
3305
|
}
|
|
3286
3306
|
}
|
|
3287
3307
|
let credentialProvider;
|
|
3308
|
+
let workspaceHeaders;
|
|
3309
|
+
let promptGate;
|
|
3288
3310
|
if (directKey !== void 0) {
|
|
3289
3311
|
credentialProvider = () => Promise.resolve(parseGatewayKey(directKey));
|
|
3290
3312
|
} else if (runtime === void 0) {
|
|
@@ -3293,13 +3315,28 @@ var createRoute33Plugin = (options = {}) => {
|
|
|
3293
3315
|
);
|
|
3294
3316
|
} else {
|
|
3295
3317
|
credentialProvider = () => runtime.resolveCredential();
|
|
3318
|
+
workspaceHeaders = createWorkspaceKeyHeaders({
|
|
3319
|
+
resolveKey: (directory) => runtime.resolveWorkspaceCredential(directory),
|
|
3320
|
+
session: {
|
|
3321
|
+
get: async ({ sessionID }) => {
|
|
3322
|
+
const session = await options.readSession?.(sessionID);
|
|
3323
|
+
return session ?? { location: { directory: input.worktree } };
|
|
3324
|
+
}
|
|
3325
|
+
}
|
|
3326
|
+
});
|
|
3327
|
+
promptGate = createUnattributedPromptGate({
|
|
3328
|
+
directory: input.worktree,
|
|
3329
|
+
outsideWorktree: "return-undefined"
|
|
3330
|
+
});
|
|
3296
3331
|
}
|
|
3297
3332
|
return Promise.resolve({
|
|
3298
3333
|
config: createConfigHook({
|
|
3299
3334
|
...resolvedConfig,
|
|
3300
3335
|
credentialProvider,
|
|
3301
3336
|
cwd: input.worktree
|
|
3302
|
-
})
|
|
3337
|
+
}),
|
|
3338
|
+
...workspaceHeaders === void 0 ? {} : { "chat.headers": workspaceHeaders },
|
|
3339
|
+
...promptGate === void 0 ? {} : { "chat.message": promptGate }
|
|
3303
3340
|
});
|
|
3304
3341
|
};
|
|
3305
3342
|
};
|
package/dist/tui-entry/index.js
CHANGED
|
@@ -6226,6 +6226,64 @@ var init_route33_runtime2 = __esm({
|
|
|
6226
6226
|
}
|
|
6227
6227
|
});
|
|
6228
6228
|
|
|
6229
|
+
// src/v1-entry/unattributed-prompt-gate/unattributed-prompt-gate.ts
|
|
6230
|
+
var createUnattributedPromptGate;
|
|
6231
|
+
var init_unattributed_prompt_gate = __esm({
|
|
6232
|
+
"src/v1-entry/unattributed-prompt-gate/unattributed-prompt-gate.ts"() {
|
|
6233
|
+
"use strict";
|
|
6234
|
+
init_attribution();
|
|
6235
|
+
createUnattributedPromptGate = ({ directory, outsideWorktree }) => (input) => {
|
|
6236
|
+
if (input.model?.providerID !== "route_33") return Promise.resolve();
|
|
6237
|
+
const attribution = readAttribution({ directory, outsideWorktree });
|
|
6238
|
+
if (attribution !== void 0) return Promise.resolve();
|
|
6239
|
+
return Promise.reject(
|
|
6240
|
+
new Error(
|
|
6241
|
+
"Route 33 needs a budget for this folder first \u2014 run /r33 in OpenCode, choose Route 33, and assign a budget."
|
|
6242
|
+
)
|
|
6243
|
+
);
|
|
6244
|
+
};
|
|
6245
|
+
}
|
|
6246
|
+
});
|
|
6247
|
+
|
|
6248
|
+
// src/v1-entry/unattributed-prompt-gate/index.ts
|
|
6249
|
+
var init_unattributed_prompt_gate2 = __esm({
|
|
6250
|
+
"src/v1-entry/unattributed-prompt-gate/index.ts"() {
|
|
6251
|
+
"use strict";
|
|
6252
|
+
init_unattributed_prompt_gate();
|
|
6253
|
+
}
|
|
6254
|
+
});
|
|
6255
|
+
|
|
6256
|
+
// src/v1-entry/workspace-key-headers/workspace-key-headers.ts
|
|
6257
|
+
var createWorkspaceKeyHeaders;
|
|
6258
|
+
var init_workspace_key_headers = __esm({
|
|
6259
|
+
"src/v1-entry/workspace-key-headers/workspace-key-headers.ts"() {
|
|
6260
|
+
"use strict";
|
|
6261
|
+
createWorkspaceKeyHeaders = ({ resolveKey, session }) => async (input, output) => {
|
|
6262
|
+
const workspace = await session.get({ sessionID: input.sessionID });
|
|
6263
|
+
const key = await resolveKey(workspace.location.directory);
|
|
6264
|
+
if (key === void 0) return;
|
|
6265
|
+
output.headers["Authorization"] = `Bearer ${key.value}`;
|
|
6266
|
+
};
|
|
6267
|
+
}
|
|
6268
|
+
});
|
|
6269
|
+
|
|
6270
|
+
// src/v1-entry/workspace-key-headers/index.ts
|
|
6271
|
+
var init_workspace_key_headers2 = __esm({
|
|
6272
|
+
"src/v1-entry/workspace-key-headers/index.ts"() {
|
|
6273
|
+
"use strict";
|
|
6274
|
+
init_workspace_key_headers();
|
|
6275
|
+
}
|
|
6276
|
+
});
|
|
6277
|
+
|
|
6278
|
+
// src/v1-entry/index.ts
|
|
6279
|
+
var init_v1_entry = __esm({
|
|
6280
|
+
"src/v1-entry/index.ts"() {
|
|
6281
|
+
"use strict";
|
|
6282
|
+
init_unattributed_prompt_gate2();
|
|
6283
|
+
init_workspace_key_headers2();
|
|
6284
|
+
}
|
|
6285
|
+
});
|
|
6286
|
+
|
|
6229
6287
|
// src/create-route33-plugin/create-route33-plugin.ts
|
|
6230
6288
|
var createRoute33Plugin;
|
|
6231
6289
|
var init_create_route33_plugin = __esm({
|
|
@@ -6238,6 +6296,7 @@ var init_create_route33_plugin = __esm({
|
|
|
6238
6296
|
init_requested_client_id2();
|
|
6239
6297
|
init_route33_runtime2();
|
|
6240
6298
|
init_ux();
|
|
6299
|
+
init_v1_entry();
|
|
6241
6300
|
createRoute33Plugin = (options = {}) => {
|
|
6242
6301
|
const baseURL = readEnvBaseUrl();
|
|
6243
6302
|
const clientId = options.clientId ?? readEnvClientId() ?? DEFAULT_ROUTE33_CLIENT_ID;
|
|
@@ -6277,6 +6336,8 @@ var init_create_route33_plugin = __esm({
|
|
|
6277
6336
|
}
|
|
6278
6337
|
}
|
|
6279
6338
|
let credentialProvider;
|
|
6339
|
+
let workspaceHeaders;
|
|
6340
|
+
let promptGate;
|
|
6280
6341
|
if (directKey !== void 0) {
|
|
6281
6342
|
credentialProvider = () => Promise.resolve(parseGatewayKey(directKey));
|
|
6282
6343
|
} else if (runtime === void 0) {
|
|
@@ -6285,13 +6346,28 @@ var init_create_route33_plugin = __esm({
|
|
|
6285
6346
|
);
|
|
6286
6347
|
} else {
|
|
6287
6348
|
credentialProvider = () => runtime.resolveCredential();
|
|
6349
|
+
workspaceHeaders = createWorkspaceKeyHeaders({
|
|
6350
|
+
resolveKey: (directory) => runtime.resolveWorkspaceCredential(directory),
|
|
6351
|
+
session: {
|
|
6352
|
+
get: async ({ sessionID }) => {
|
|
6353
|
+
const session = await options.readSession?.(sessionID);
|
|
6354
|
+
return session ?? { location: { directory: input.worktree } };
|
|
6355
|
+
}
|
|
6356
|
+
}
|
|
6357
|
+
});
|
|
6358
|
+
promptGate = createUnattributedPromptGate({
|
|
6359
|
+
directory: input.worktree,
|
|
6360
|
+
outsideWorktree: "return-undefined"
|
|
6361
|
+
});
|
|
6288
6362
|
}
|
|
6289
6363
|
return Promise.resolve({
|
|
6290
6364
|
config: createConfigHook({
|
|
6291
6365
|
...resolvedConfig,
|
|
6292
6366
|
credentialProvider,
|
|
6293
6367
|
cwd: input.worktree
|
|
6294
|
-
})
|
|
6368
|
+
}),
|
|
6369
|
+
...workspaceHeaders === void 0 ? {} : { "chat.headers": workspaceHeaders },
|
|
6370
|
+
...promptGate === void 0 ? {} : { "chat.message": promptGate }
|
|
6295
6371
|
});
|
|
6296
6372
|
};
|
|
6297
6373
|
};
|
|
@@ -7093,21 +7169,43 @@ var showR33Menu = async (context) => {
|
|
|
7093
7169
|
init_attribution();
|
|
7094
7170
|
init_cli();
|
|
7095
7171
|
|
|
7172
|
+
// src/tui-entry/is-method-not-registered/is-method-not-registered.ts
|
|
7173
|
+
var isMethodNotRegistered = (error) => error instanceof Error && error.message.includes("OAuth method not found");
|
|
7174
|
+
|
|
7175
|
+
// src/tui-entry/v2-connect-surface/v2-connect-surface.ts
|
|
7176
|
+
var v2ConnectSurface = (context) => {
|
|
7177
|
+
const oauth = context.client?.integration?.oauth ?? context.client?.api?.integration?.oauth;
|
|
7178
|
+
return oauth?.connect;
|
|
7179
|
+
};
|
|
7180
|
+
|
|
7096
7181
|
// src/tui-entry/v2-connect-runner/v2-connect-runner.ts
|
|
7097
7182
|
var createV2ConnectRunner = ({
|
|
7098
7183
|
context,
|
|
7184
|
+
maxAttempts = 20,
|
|
7185
|
+
retryDelayMs = 500,
|
|
7099
7186
|
unattributed
|
|
7100
7187
|
}) => {
|
|
7101
|
-
const
|
|
7188
|
+
const connect = v2ConnectSurface(context);
|
|
7189
|
+
const sleep = (ms) => new Promise((resolve2) => {
|
|
7190
|
+
setTimeout(resolve2, ms);
|
|
7191
|
+
});
|
|
7102
7192
|
return async (message) => {
|
|
7103
|
-
const connect = oauth?.connect;
|
|
7104
7193
|
if (connect === void 0) return;
|
|
7105
7194
|
if (!unattributed()) return;
|
|
7106
7195
|
context.ui.toast.show({ message, variant: "info" });
|
|
7107
|
-
|
|
7108
|
-
|
|
7109
|
-
|
|
7110
|
-
|
|
7196
|
+
for (let attempt = 1; ; attempt += 1) {
|
|
7197
|
+
if (!unattributed()) return;
|
|
7198
|
+
try {
|
|
7199
|
+
await connect({
|
|
7200
|
+
integrationID: "route33",
|
|
7201
|
+
methodID: "browser"
|
|
7202
|
+
});
|
|
7203
|
+
return;
|
|
7204
|
+
} catch (error) {
|
|
7205
|
+
if (attempt >= maxAttempts || !isMethodNotRegistered(error)) return;
|
|
7206
|
+
await sleep(retryDelayMs);
|
|
7207
|
+
}
|
|
7208
|
+
}
|
|
7111
7209
|
};
|
|
7112
7210
|
};
|
|
7113
7211
|
|
package/dist/v2-entry/index.js
CHANGED
|
@@ -3248,6 +3248,26 @@ var Route33Runtime = class {
|
|
|
3248
3248
|
}
|
|
3249
3249
|
};
|
|
3250
3250
|
|
|
3251
|
+
// src/v1-entry/unattributed-prompt-gate/unattributed-prompt-gate.ts
|
|
3252
|
+
var createUnattributedPromptGate = ({ directory, outsideWorktree }) => (input) => {
|
|
3253
|
+
if (input.model?.providerID !== "route_33") return Promise.resolve();
|
|
3254
|
+
const attribution = readAttribution({ directory, outsideWorktree });
|
|
3255
|
+
if (attribution !== void 0) return Promise.resolve();
|
|
3256
|
+
return Promise.reject(
|
|
3257
|
+
new Error(
|
|
3258
|
+
"Route 33 needs a budget for this folder first \u2014 run /r33 in OpenCode, choose Route 33, and assign a budget."
|
|
3259
|
+
)
|
|
3260
|
+
);
|
|
3261
|
+
};
|
|
3262
|
+
|
|
3263
|
+
// src/v1-entry/workspace-key-headers/workspace-key-headers.ts
|
|
3264
|
+
var createWorkspaceKeyHeaders = ({ resolveKey, session }) => async (input, output) => {
|
|
3265
|
+
const workspace = await session.get({ sessionID: input.sessionID });
|
|
3266
|
+
const key = await resolveKey(workspace.location.directory);
|
|
3267
|
+
if (key === void 0) return;
|
|
3268
|
+
output.headers["Authorization"] = `Bearer ${key.value}`;
|
|
3269
|
+
};
|
|
3270
|
+
|
|
3251
3271
|
// src/create-route33-plugin/create-route33-plugin.ts
|
|
3252
3272
|
var createRoute33Plugin = (options = {}) => {
|
|
3253
3273
|
const baseURL = readEnvBaseUrl();
|
|
@@ -3288,6 +3308,8 @@ var createRoute33Plugin = (options = {}) => {
|
|
|
3288
3308
|
}
|
|
3289
3309
|
}
|
|
3290
3310
|
let credentialProvider;
|
|
3311
|
+
let workspaceHeaders;
|
|
3312
|
+
let promptGate;
|
|
3291
3313
|
if (directKey !== void 0) {
|
|
3292
3314
|
credentialProvider = () => Promise.resolve(parseGatewayKey(directKey));
|
|
3293
3315
|
} else if (runtime === void 0) {
|
|
@@ -3296,13 +3318,28 @@ var createRoute33Plugin = (options = {}) => {
|
|
|
3296
3318
|
);
|
|
3297
3319
|
} else {
|
|
3298
3320
|
credentialProvider = () => runtime.resolveCredential();
|
|
3321
|
+
workspaceHeaders = createWorkspaceKeyHeaders({
|
|
3322
|
+
resolveKey: (directory) => runtime.resolveWorkspaceCredential(directory),
|
|
3323
|
+
session: {
|
|
3324
|
+
get: async ({ sessionID }) => {
|
|
3325
|
+
const session = await options.readSession?.(sessionID);
|
|
3326
|
+
return session ?? { location: { directory: input.worktree } };
|
|
3327
|
+
}
|
|
3328
|
+
}
|
|
3329
|
+
});
|
|
3330
|
+
promptGate = createUnattributedPromptGate({
|
|
3331
|
+
directory: input.worktree,
|
|
3332
|
+
outsideWorktree: "return-undefined"
|
|
3333
|
+
});
|
|
3299
3334
|
}
|
|
3300
3335
|
return Promise.resolve({
|
|
3301
3336
|
config: createConfigHook({
|
|
3302
3337
|
...resolvedConfig,
|
|
3303
3338
|
credentialProvider,
|
|
3304
3339
|
cwd: input.worktree
|
|
3305
|
-
})
|
|
3340
|
+
}),
|
|
3341
|
+
...workspaceHeaders === void 0 ? {} : { "chat.headers": workspaceHeaders },
|
|
3342
|
+
...promptGate === void 0 ? {} : { "chat.message": promptGate }
|
|
3306
3343
|
});
|
|
3307
3344
|
};
|
|
3308
3345
|
};
|