@route_33/opencode 0.4.7-rc.2 → 0.4.7-rc.4

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @route_33/opencode
2
2
 
3
- The Route 33 plugin for OpenCode: sign in with your browser, pick who pays for
3
+ The Route 33 plugin for OpenCode: sign in with your browser, assign the budget for
4
4
  usage, and use the route_33 models — no API keys to paste, ever.
5
5
 
6
6
  ## Install
@@ -22,20 +22,20 @@ Prefer config? Add the package to `opencode.jsonc` instead:
22
22
  1. Pick any route_33 model (or run `/connect` and choose **Route 33**).
23
23
  2. Open the sign-in link — your browser finishes at a Route 33 confirmation
24
24
  page.
25
- 3. Connect again and pick **who pays for usage in this folder**: one of your
25
+ 3. Connect again and assign **which budget covers usage in this folder**: one of your
26
26
  Route 33 projects, or your personal key.
27
27
  4. The route_33 models appear. Done.
28
28
 
29
- To change who pays later, connect again and pick another option. `/r33` shows
29
+ To change the budget later, connect again and pick another option. `/r33` shows
30
30
  the current state at any time.
31
31
 
32
32
  ## Commands
33
33
 
34
- | Command | Effect |
35
- | ------------- | --------------------------------------------------------- |
36
- | `/r33` | Show who pays, the active key, and its rotation state |
37
- | `/r33 rotate` | Rotate the key immediately |
38
- | `/r33 reset` | Clear who pays — connect again to pick a different option |
34
+ | Command | Effect |
35
+ | ------------- | -------------------------------------------------------------------- |
36
+ | `/r33` | Show the assigned budget, the active key, and its rotation state |
37
+ | `/r33 rotate` | Rotate the key immediately |
38
+ | `/r33 reset` | Clear the assigned budget — connect again to pick a different option |
39
39
 
40
40
  A browser is required for every sign-in; restarts afterwards sign in silently.
41
41
 
@@ -260,7 +260,7 @@ var buildCallbackPage = (state, errorCode) => {
260
260
  const safeCode = (errorCode ?? "").replace(/[^a-z0-9_-]/gi, "");
261
261
  const title = isError ? "Sign-in failed" : "Signed in";
262
262
  const headline = isError ? "Sign-in failed" : "Signed in to route33";
263
- const subline = isError ? "Return to OpenCode and retry." : "Return to OpenCode \u2014 one more step may wait there: if it asks who pays for usage, pick a project. Then this window can be closed.";
263
+ const subline = isError ? "Return to OpenCode and retry." : "Return to OpenCode \u2014 one more step may wait there: if it asks which budget covers usage, pick a project. Then this window can be closed.";
264
264
  const statusLabel = isError ? "Authentication error" : "Authenticated";
265
265
  const dotClass = isError ? "r33-status__dot r33-status__dot--error" : "r33-status__dot";
266
266
  const codeLine = isError && safeCode.length > 0 ? `<p class="r33-code">Error code: <span class="r33-code__value">${safeCode}</span></p>` : "";
@@ -421,7 +421,7 @@ var createPkceVerifierAndChallenge = () => {
421
421
  };
422
422
 
423
423
  // src/auth/requested-scopes/requested-scopes.ts
424
- var REQUESTED_OAUTH_SCOPES = "openid offline_access projects:read api-keys:read api-keys:create api-keys:rotate api-keys:delete";
424
+ var REQUESTED_OAUTH_SCOPES = "openid offline_access projects:read keys:read keys:write";
425
425
 
426
426
  // src/auth/login-flow/login-flow.ts
427
427
  var loginFlow = async (options) => {
package/dist/index.js CHANGED
@@ -2546,7 +2546,7 @@ var createAttributionPrompt = (projects) => {
2546
2546
 
2547
2547
  // src/ux/attribution-prompt-error/attribution-prompt-error.ts
2548
2548
  var MESSAGES = {
2549
- ATTRIBUTION_PRESENTER_UNAVAILABLE: "Route 33 needs OpenCode v2 to choose who pays for usage in this folder. Update to OpenCode v2, run /connect, choose Route 33, and follow the steps.",
2549
+ ATTRIBUTION_PRESENTER_UNAVAILABLE: "Route 33 needs OpenCode v2 to assign a budget for this folder. Update to OpenCode v2, run /connect, choose Route 33, and follow the steps.",
2550
2550
  ATTRIBUTION_SELECTION_INVALID: "That Route 33 option is no longer available. Connect again and pick another."
2551
2551
  };
2552
2552
  var AttributionPromptError = class extends GatewayCredentialError {
@@ -2762,7 +2762,7 @@ var buildCallbackPage = (state, errorCode) => {
2762
2762
  const safeCode = (errorCode ?? "").replace(/[^a-z0-9_-]/gi, "");
2763
2763
  const title = isError ? "Sign-in failed" : "Signed in";
2764
2764
  const headline = isError ? "Sign-in failed" : "Signed in to route33";
2765
- const subline = isError ? "Return to OpenCode and retry." : "Return to OpenCode \u2014 one more step may wait there: if it asks who pays for usage, pick a project. Then this window can be closed.";
2765
+ const subline = isError ? "Return to OpenCode and retry." : "Return to OpenCode \u2014 one more step may wait there: if it asks which budget covers usage, pick a project. Then this window can be closed.";
2766
2766
  const statusLabel = isError ? "Authentication error" : "Authenticated";
2767
2767
  const dotClass = isError ? "r33-status__dot r33-status__dot--error" : "r33-status__dot";
2768
2768
  const codeLine = isError && safeCode.length > 0 ? `<p class="r33-code">Error code: <span class="r33-code__value">${safeCode}</span></p>` : "";
@@ -2923,7 +2923,7 @@ var createPkceVerifierAndChallenge = () => {
2923
2923
  };
2924
2924
 
2925
2925
  // src/auth/requested-scopes/requested-scopes.ts
2926
- var REQUESTED_OAUTH_SCOPES = "openid offline_access projects:read api-keys:read api-keys:create api-keys:rotate api-keys:delete";
2926
+ var REQUESTED_OAUTH_SCOPES = "openid offline_access projects:read keys:read keys:write";
2927
2927
 
2928
2928
  // src/auth/login-flow/login-flow.ts
2929
2929
  var loginFlow = async (options) => {
@@ -1242,7 +1242,7 @@ html,body{margin:0}
1242
1242
  const safeCode = (errorCode ?? "").replace(/[^a-z0-9_-]/gi, "");
1243
1243
  const title = isError ? "Sign-in failed" : "Signed in";
1244
1244
  const headline = isError ? "Sign-in failed" : "Signed in to route33";
1245
- const subline = isError ? "Return to OpenCode and retry." : "Return to OpenCode \u2014 one more step may wait there: if it asks who pays for usage, pick a project. Then this window can be closed.";
1245
+ const subline = isError ? "Return to OpenCode and retry." : "Return to OpenCode \u2014 one more step may wait there: if it asks which budget covers usage, pick a project. Then this window can be closed.";
1246
1246
  const statusLabel = isError ? "Authentication error" : "Authenticated";
1247
1247
  const dotClass = isError ? "r33-status__dot r33-status__dot--error" : "r33-status__dot";
1248
1248
  const codeLine = isError && safeCode.length > 0 ? `<p class="r33-code">Error code: <span class="r33-code__value">${safeCode}</span></p>` : "";
@@ -1479,7 +1479,7 @@ var REQUESTED_OAUTH_SCOPES;
1479
1479
  var init_requested_scopes = __esm({
1480
1480
  "src/auth/requested-scopes/requested-scopes.ts"() {
1481
1481
  "use strict";
1482
- REQUESTED_OAUTH_SCOPES = "openid offline_access projects:read api-keys:read api-keys:create api-keys:rotate api-keys:delete";
1482
+ REQUESTED_OAUTH_SCOPES = "openid offline_access projects:read keys:read keys:write";
1483
1483
  }
1484
1484
  });
1485
1485
 
@@ -5811,7 +5811,7 @@ var init_attribution_prompt_error = __esm({
5811
5811
  "use strict";
5812
5812
  init_config();
5813
5813
  MESSAGES = {
5814
- ATTRIBUTION_PRESENTER_UNAVAILABLE: "Route 33 needs OpenCode v2 to choose who pays for usage in this folder. Update to OpenCode v2, run /connect, choose Route 33, and follow the steps.",
5814
+ ATTRIBUTION_PRESENTER_UNAVAILABLE: "Route 33 needs OpenCode v2 to assign a budget for this folder. Update to OpenCode v2, run /connect, choose Route 33, and follow the steps.",
5815
5815
  ATTRIBUTION_SELECTION_INVALID: "That Route 33 option is no longer available. Connect again and pick another."
5816
5816
  };
5817
5817
  AttributionPromptError = class extends GatewayCredentialError {
@@ -6870,7 +6870,7 @@ var runConnect = async (api, composeOptions) => {
6870
6870
  }
6871
6871
  if (readAttribution(state) !== void 0) {
6872
6872
  const change = await confirmFromDialog(api, {
6873
- message: "Change who pays for usage in this folder?",
6873
+ message: "Change the budget assigned to this folder?",
6874
6874
  title: "Route 33"
6875
6875
  });
6876
6876
  if (change !== true) {
@@ -6943,13 +6943,55 @@ var createV1ConnectWizard = (composeOptions = productionOptions) => (api) => {
6943
6943
  {
6944
6944
  onSelect: () => runConnect(api, composeOptions),
6945
6945
  slash: { name: "r33" },
6946
- title: "Route 33: sign in and pick who pays for this folder",
6946
+ title: "Route 33: sign in and assign a budget for this folder",
6947
6947
  value: "route33.connect"
6948
6948
  }
6949
6949
  ]);
6950
6950
  return Promise.resolve();
6951
6951
  };
6952
6952
 
6953
+ // src/tui-entry/show-r33-menu/show-r33-menu.ts
6954
+ var menuOptions = [
6955
+ {
6956
+ title: "Connect \u2014 sign in and assign a budget",
6957
+ value: "connect"
6958
+ },
6959
+ {
6960
+ title: "Inspect session \u2014 attribution and key metadata",
6961
+ value: "inspect"
6962
+ },
6963
+ {
6964
+ title: "Rotate key now",
6965
+ value: "rotate"
6966
+ },
6967
+ {
6968
+ title: "Change budget \u2014 reassign this folder",
6969
+ value: "change"
6970
+ },
6971
+ {
6972
+ title: "Reset attribution \u2014 clear the assigned budget",
6973
+ value: "reset"
6974
+ }
6975
+ ];
6976
+ var showR33Menu = async (context) => {
6977
+ const selection = await context.ui.dialog.select({
6978
+ title: "Route 33 \u2014 choose an action",
6979
+ options: menuOptions
6980
+ });
6981
+ if (selection === void 0) return;
6982
+ if (selection === "connect") {
6983
+ context.ui.toast.show({
6984
+ message: "Route 33 connect \u2014 finish the browser sign-in, then run /connect in OpenCode and choose Route 33 to assign a budget.",
6985
+ variant: "info"
6986
+ });
6987
+ return;
6988
+ }
6989
+ context.ui.toast.show({
6990
+ message: `Route 33 ${selection} runs through /r33 ${selection} \u2014 type it in the prompt and send.`,
6991
+ variant: "info"
6992
+ });
6993
+ };
6994
+
6953
6995
  // src/tui-entry/v2-autoconnect/v2-autoconnect.ts
6954
6996
  init_attribution();
6955
6997
  init_cli();
@@ -6957,6 +6999,8 @@ var v2Autoconnect = async (context) => {
6957
6999
  if (readEnvDirectApiKey() !== void 0 || readEnvAutoconnectDisabled() || context.location === void 0) {
6958
7000
  return;
6959
7001
  }
7002
+ const oauth = context.client?.api?.integration?.oauth;
7003
+ if (oauth === void 0 || oauth.connect === void 0) return;
6960
7004
  const attribution = readAttribution({
6961
7005
  directory: context.location.directory,
6962
7006
  outsideWorktree: "return-undefined"
@@ -6965,20 +7009,42 @@ var v2Autoconnect = async (context) => {
6965
7009
  return;
6966
7010
  }
6967
7011
  context.ui.toast.show({
6968
- message: "Route 33 is not connected \u2014 signing in now. Follow the browser prompt, then run /connect to pick who pays.",
7012
+ message: "Route 33 is not connected \u2014 signing in now. Follow the browser prompt, then run /connect to assign a budget.",
6969
7013
  variant: "info"
6970
7014
  });
6971
- await context.client.api.integration.oauth.connect({
7015
+ await oauth.connect({
6972
7016
  integrationID: "route33",
6973
7017
  methodID: "browser"
6974
7018
  }).catch(() => void 0);
6975
7019
  };
6976
7020
 
6977
- // src/tui-entry/index.ts
6978
- var route33V2Tui = {
7021
+ // src/tui-entry/v2-tui/v2-tui.ts
7022
+ var createV2Tui = () => ({
6979
7023
  id: "route33",
6980
- setup: (context) => v2Autoconnect(context)
6981
- };
7024
+ setup: async (context) => {
7025
+ await v2Autoconnect(context);
7026
+ context.keymap?.layer(() => ({
7027
+ mode: "global",
7028
+ priority: 10,
7029
+ commands: [
7030
+ {
7031
+ id: "route33.menu",
7032
+ title: "Route 33: menu",
7033
+ group: "Route 33",
7034
+ slash: { name: "r33", arguments: true },
7035
+ enabled: () => true,
7036
+ run: async () => {
7037
+ await showR33Menu(context);
7038
+ }
7039
+ }
7040
+ ],
7041
+ bindings: ["route33.menu"]
7042
+ }));
7043
+ }
7044
+ });
7045
+
7046
+ // src/tui-entry/index.ts
7047
+ var route33V2Tui = createV2Tui();
6982
7048
  var tui = createV1ConnectWizard();
6983
7049
  var tui_entry_default = route33V2Tui;
6984
7050
  export {
@@ -2549,7 +2549,7 @@ var createAttributionPrompt = (projects) => {
2549
2549
 
2550
2550
  // src/ux/attribution-prompt-error/attribution-prompt-error.ts
2551
2551
  var MESSAGES = {
2552
- ATTRIBUTION_PRESENTER_UNAVAILABLE: "Route 33 needs OpenCode v2 to choose who pays for usage in this folder. Update to OpenCode v2, run /connect, choose Route 33, and follow the steps.",
2552
+ ATTRIBUTION_PRESENTER_UNAVAILABLE: "Route 33 needs OpenCode v2 to assign a budget for this folder. Update to OpenCode v2, run /connect, choose Route 33, and follow the steps.",
2553
2553
  ATTRIBUTION_SELECTION_INVALID: "That Route 33 option is no longer available. Connect again and pick another."
2554
2554
  };
2555
2555
  var AttributionPromptError = class extends GatewayCredentialError {
@@ -2765,7 +2765,7 @@ var buildCallbackPage = (state, errorCode) => {
2765
2765
  const safeCode = (errorCode ?? "").replace(/[^a-z0-9_-]/gi, "");
2766
2766
  const title = isError ? "Sign-in failed" : "Signed in";
2767
2767
  const headline = isError ? "Sign-in failed" : "Signed in to route33";
2768
- const subline = isError ? "Return to OpenCode and retry." : "Return to OpenCode \u2014 one more step may wait there: if it asks who pays for usage, pick a project. Then this window can be closed.";
2768
+ const subline = isError ? "Return to OpenCode and retry." : "Return to OpenCode \u2014 one more step may wait there: if it asks which budget covers usage, pick a project. Then this window can be closed.";
2769
2769
  const statusLabel = isError ? "Authentication error" : "Authenticated";
2770
2770
  const dotClass = isError ? "r33-status__dot r33-status__dot--error" : "r33-status__dot";
2771
2771
  const codeLine = isError && safeCode.length > 0 ? `<p class="r33-code">Error code: <span class="r33-code__value">${safeCode}</span></p>` : "";
@@ -2926,7 +2926,7 @@ var createPkceVerifierAndChallenge = () => {
2926
2926
  };
2927
2927
 
2928
2928
  // src/auth/requested-scopes/requested-scopes.ts
2929
- var REQUESTED_OAUTH_SCOPES = "openid offline_access projects:read api-keys:read api-keys:create api-keys:rotate api-keys:delete";
2929
+ var REQUESTED_OAUTH_SCOPES = "openid offline_access projects:read keys:read keys:write";
2930
2930
 
2931
2931
  // src/auth/login-flow/login-flow.ts
2932
2932
  var loginFlow = async (options) => {
@@ -3794,7 +3794,7 @@ var CONNECT_COPY = {
3794
3794
  failFastClientId: "This Route 33 build has no OAuth client id. Reinstall it from the opencode-dist ref, or set ROUTE33_CLIENT_ID and restart OpenCode.",
3795
3795
  failFastWorktree: "Route 33 attributes usage to a project inside a Git worktree. Open a Git repository (or run git init), then connect again.",
3796
3796
  selectionInvalid: "That Route 33 option is no longer available. Connect again and pick another.",
3797
- signedInNextStep: "Signed in to Route 33 \u2713. One more step: connect again, choose Route 33, and pick who pays for usage in this folder."
3797
+ signedInNextStep: "Signed in to Route 33 \u2713. One more step: connect again, choose Route 33, and assign a budget for this folder."
3798
3798
  };
3799
3799
 
3800
3800
  // src/v2-entry/parse-connect-answer/parse-connect-answer.ts
@@ -3870,7 +3870,7 @@ var buildConnectForm = (plan) => ({
3870
3870
  value: option.selection
3871
3871
  })),
3872
3872
  required: true,
3873
- title: "Who pays for Route 33 usage in this folder?",
3873
+ title: "Which budget covers Route 33 usage in this folder?",
3874
3874
  type: "string"
3875
3875
  });
3876
3876
 
@@ -3987,7 +3987,7 @@ var executeR33Command = async (input) => {
3987
3987
  return "Route 33 is not connected in this folder. Run /connect, choose Route 33, and follow the steps.";
3988
3988
  }
3989
3989
  if (subcommand === "help") {
3990
- return "Route 33 usage: /r33 [inspect|rotate|reset] \u2014 inspect shows attribution and key rotation, rotate rotates the key now, reset clears who pays (pick again with /connect).";
3990
+ return "Route 33 usage: /r33 [inspect|rotate|reset] \u2014 inspect shows attribution and key rotation, rotate rotates the key now, reset clears the assigned budget (assign again with /connect).";
3991
3991
  }
3992
3992
  switch (subcommand) {
3993
3993
  case "rotate": {
@@ -3996,7 +3996,7 @@ var executeR33Command = async (input) => {
3996
3996
  }
3997
3997
  case "reset": {
3998
3998
  await input.handlers["reset-attribution"]();
3999
- return "Route 33 attribution cleared. Run /connect, choose Route 33, and pick who pays again.";
3999
+ return "Route 33 attribution cleared. Run /connect, choose Route 33, and assign a budget again.";
4000
4000
  }
4001
4001
  default: {
4002
4002
  return JSON.stringify(input.handlers["inspect-session"](), null, 2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@route_33/opencode",
3
- "version": "0.4.7-rc.2",
3
+ "version": "0.4.7-rc.4",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -42,8 +42,8 @@
42
42
  "eslint": "10.13.0",
43
43
  "typescript": "6.0.3",
44
44
  "vitest": "5.0.5",
45
- "@cronos-ai-lab/typescript-config": "0.1.1",
46
- "@cronos-ai-lab/eslint-config": "0.1.1"
45
+ "@cronos-ai-lab/eslint-config": "0.1.2",
46
+ "@cronos-ai-lab/typescript-config": "0.1.2"
47
47
  },
48
48
  "scripts": {
49
49
  "build": "esbuild src/index.ts src/v2-entry/index.ts src/tui-entry/index.ts src/cli/production-smoke/production-smoke.ts --bundle --format=esm --platform=node --packages=external --outbase=src --outdir=dist --alias:@opencode-ai/plugin-v2=@opencode/plugin --define:__ROUTE33_DEFAULT_CLIENT_ID__=\\\"${ROUTE33_DEFAULT_CLIENT_ID:-}\\\"",