theclawbay 0.2.0 → 0.2.3

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
@@ -2,11 +2,6 @@
2
2
 
3
3
  `theclawbay` is a customer CLI for The Claw Bay.
4
4
 
5
- It now does one job:
6
-
7
- - link your purchased API key
8
- - run a local relay that forwards Codex/OpenAI requests to your The Claw Bay backend
9
-
10
5
  This package no longer runs local account login automation or local account switching flows.
11
6
 
12
7
  > Not affiliated with OpenAI or Codex. Not an official tool.
@@ -14,7 +9,7 @@ This package no longer runs local account login automation or local account swit
14
9
  ## Requirements
15
10
 
16
11
  - Node.js 18+
17
- - Codex CLI installed (`@openai/codex`)
12
+ - Codex CLI (`@openai/codex`) and/or OpenClaw CLI
18
13
 
19
14
  ## Install
20
15
 
@@ -22,25 +17,42 @@ This package no longer runs local account login automation or local account swit
22
17
  npm i -g theclawbay
23
18
  ```
24
19
 
25
- ## Link
20
+ ## One-Time Setup (Recommended)
26
21
 
27
22
  Use your purchased API key from your dashboard:
28
23
 
29
24
  ```sh
30
- theclawbay link --api-key <apiKey>
25
+ theclawbay setup --api-key <apiKey>
26
+ ```
27
+
28
+ This auto-detects installed clients and writes direct WAN API-key config so users can run directly.
29
+
30
+ Explicit client targeting:
31
+
32
+ ```sh
33
+ theclawbay setup --api-key <apiKey> --client codex
34
+ theclawbay setup --api-key <apiKey> --client openclaw
35
+ theclawbay setup --api-key <apiKey> --client both
31
36
  ```
32
37
 
33
- This defaults to `https://theclawbay.com`.
38
+ If needed, skip the automatic Codex login step:
39
+
40
+ ```sh
41
+ theclawbay setup --api-key <apiKey> --skip-login
42
+ ```
34
43
 
35
44
  If you operate a custom backend, pass it explicitly:
36
45
 
37
46
  ```sh
38
- theclawbay link --api-key <apiKey> --backend https://your-domain.com
47
+ theclawbay setup --api-key <apiKey> --backend https://your-domain.com
39
48
  ```
40
49
 
41
- ## Run Relay
50
+ ## Run Relay (Optional)
51
+
52
+ Only needed as a fallback compatibility mode:
42
53
 
43
54
  ```sh
55
+ theclawbay link --api-key <apiKey>
44
56
  theclawbay proxy
45
57
  ```
46
58
 
@@ -48,17 +60,8 @@ By default this starts a local relay on `http://127.0.0.1:2455` and forwards to:
48
60
 
49
61
  - `https://theclawbay.com/api/codex-auth/v1/proxy/...`
50
62
 
51
- The command prints a ready-to-paste Codex provider snippet.
52
-
53
- ## Common Flags
54
-
55
- `theclawbay proxy` supports:
56
-
57
- - `--host` local bind host (default `127.0.0.1`)
58
- - `--port` local bind port (default `2455`)
59
- - `--backend` override backend URL from linked config
60
- - `--api-key` override API key from linked config
61
- - `--base-path` override server proxy path (default `/api/codex-auth/v1/proxy`)
63
+ The command now auto-detects whether `codex`, `openclaw`, or both are installed and prints setup steps for the detected client(s).
64
+ If both are installed and you're in an interactive terminal, it asks which one you want to configure.
62
65
 
63
66
  ## Notes
64
67
 
@@ -7,6 +7,7 @@ export default class ProxyCommand extends BaseCommand {
7
7
  backend: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
8
8
  "api-key": import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
9
9
  "base-path": import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ client: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
10
11
  };
11
12
  run(): Promise<void>;
12
13
  }
@@ -5,6 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const node_http_1 = __importDefault(require("node:http"));
7
7
  const node_stream_1 = require("node:stream");
8
+ const node_child_process_1 = require("node:child_process");
9
+ const promises_1 = require("node:readline/promises");
8
10
  const core_1 = require("@oclif/core");
9
11
  const base_command_1 = require("../lib/base-command");
10
12
  const config_1 = require("../lib/managed/config");
@@ -70,6 +72,47 @@ function writeUpstreamHeaders(res, source) {
70
72
  res.setHeader(key, value);
71
73
  });
72
74
  }
75
+ function hasCommand(name) {
76
+ const result = (0, node_child_process_1.spawnSync)("which", [name], { stdio: "ignore" });
77
+ return result.status === 0;
78
+ }
79
+ async function askClientChoice() {
80
+ const rl = (0, promises_1.createInterface)({
81
+ input: process.stdin,
82
+ output: process.stdout,
83
+ });
84
+ try {
85
+ const answer = (await rl.question("Which client do you want to configure? [1] Codex [2] OpenClaw [3] Both: "))
86
+ .trim()
87
+ .toLowerCase();
88
+ if (answer === "2" || answer === "openclaw")
89
+ return "openclaw";
90
+ if (answer === "3" || answer === "both")
91
+ return "both";
92
+ return "codex";
93
+ }
94
+ finally {
95
+ rl.close();
96
+ }
97
+ }
98
+ async function resolveClientChoice(mode) {
99
+ if (mode === "codex" || mode === "openclaw" || mode === "both") {
100
+ return mode;
101
+ }
102
+ const codexInstalled = hasCommand("codex");
103
+ const openclawInstalled = hasCommand("openclaw");
104
+ if (codexInstalled && !openclawInstalled)
105
+ return "codex";
106
+ if (!codexInstalled && openclawInstalled)
107
+ return "openclaw";
108
+ if (codexInstalled && openclawInstalled) {
109
+ if (process.stdin.isTTY && process.stdout.isTTY) {
110
+ return askClientChoice();
111
+ }
112
+ return "both";
113
+ }
114
+ return "codex";
115
+ }
73
116
  class ProxyCommand extends base_command_1.BaseCommand {
74
117
  async run() {
75
118
  await this.runSafe(async () => {
@@ -85,6 +128,7 @@ class ProxyCommand extends base_command_1.BaseCommand {
85
128
  }
86
129
  const basePath = ensureLeadingSlash(flags["base-path"].trim()).replace(/\/+$/g, "");
87
130
  const proxyBase = `${trimTrailingSlash(backendUrl)}${basePath}`;
131
+ const clientChoice = await resolveClientChoice(flags.client);
88
132
  const server = node_http_1.default.createServer(async (req, res) => {
89
133
  const method = req.method?.toUpperCase() ?? "GET";
90
134
  const incomingUrl = new URL(req.url || "/", "http://local-proxy.invalid");
@@ -133,15 +177,37 @@ class ProxyCommand extends base_command_1.BaseCommand {
133
177
  this.log(`theclawbay WAN relay listening at ${localBase}`);
134
178
  this.log(`Forwarding to ${proxyBase}`);
135
179
  this.log("");
136
- this.log("Codex CLI config snippet:");
137
- this.log('model_provider = "theclawbay-wan"');
138
- this.log("");
139
- this.log("[model_providers.theclawbay-wan]");
140
- this.log('name = "OpenAI"');
141
- this.log(`base_url = "${localBase}/backend-api/codex"`);
142
- this.log('wire_api = "responses"');
143
- this.log(`chatgpt_base_url = "${localBase}"`);
144
- this.log("requires_openai_auth = true");
180
+ if (clientChoice === "codex" || clientChoice === "both") {
181
+ this.log("Codex CLI config snippet:");
182
+ this.log('model_provider = "theclawbay-wan"');
183
+ this.log("");
184
+ this.log("[model_providers.theclawbay-wan]");
185
+ this.log('name = "OpenAI"');
186
+ this.log(`base_url = "${localBase}/backend-api/codex"`);
187
+ this.log('wire_api = "responses"');
188
+ this.log(`chatgpt_base_url = "${localBase}"`);
189
+ this.log("requires_openai_auth = true");
190
+ this.log("");
191
+ }
192
+ if (clientChoice === "openclaw" || clientChoice === "both") {
193
+ const openClawProviderJson = JSON.stringify({
194
+ baseUrl: `${localBase}/v1`,
195
+ apiKey: "theclawbay-local",
196
+ api: "openai-responses",
197
+ models: [
198
+ { id: "gpt-5.3-codex", name: "GPT-5.3 Codex" },
199
+ { id: "gpt-5.3-codex-spark", name: "GPT-5.3 Codex Spark" },
200
+ { id: "gpt-5.2-codex", name: "GPT-5.2 Codex" },
201
+ { id: "gpt-5.1-codex", name: "GPT-5.1 Codex" },
202
+ ],
203
+ });
204
+ this.log("OpenClaw setup:");
205
+ this.log("Run these once:");
206
+ this.log('openclaw config set agents.defaults.model.primary "openai/gpt-5.3-codex"');
207
+ this.log('openclaw config set models.mode "merge"');
208
+ this.log(`openclaw config set models.providers.openai '${openClawProviderJson}' --json`);
209
+ this.log("");
210
+ }
145
211
  await new Promise((resolve) => {
146
212
  const stop = () => {
147
213
  server.close(() => resolve());
@@ -175,5 +241,11 @@ ProxyCommand.flags = {
175
241
  default: "/api/codex-auth/v1/proxy",
176
242
  description: "Server proxy base path",
177
243
  }),
244
+ client: core_1.Flags.string({
245
+ required: false,
246
+ default: "auto",
247
+ options: ["auto", "codex", "openclaw", "both"],
248
+ description: "Client target to guide setup for",
249
+ }),
178
250
  };
179
251
  exports.default = ProxyCommand;
@@ -0,0 +1,13 @@
1
+ import { BaseCommand } from "../lib/base-command";
2
+ export default class SetupCommand extends BaseCommand {
3
+ static description: string;
4
+ static flags: {
5
+ backend: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
6
+ "api-key": import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
7
+ provider: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ client: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ "openclaw-model": import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ "skip-login": import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
11
+ };
12
+ run(): Promise<void>;
13
+ }
@@ -0,0 +1,295 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const promises_1 = __importDefault(require("node:fs/promises"));
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const node_child_process_1 = require("node:child_process");
9
+ const promises_2 = require("node:readline/promises");
10
+ const core_1 = require("@oclif/core");
11
+ const base_command_1 = require("../lib/base-command");
12
+ const paths_1 = require("../lib/config/paths");
13
+ const api_key_1 = require("../lib/managed/api-key");
14
+ const config_1 = require("../lib/managed/config");
15
+ const errors_1 = require("../lib/managed/errors");
16
+ const DEFAULT_BACKEND_URL = "https://theclawbay.com";
17
+ const DEFAULT_PROVIDER_ID = "theclawbay-wan";
18
+ const MANAGED_START = "# theclawbay-managed:start";
19
+ const MANAGED_END = "# theclawbay-managed:end";
20
+ const DEFAULT_OPENCLAW_MODEL = "gpt-5.3-codex";
21
+ function trimTrailingSlash(value) {
22
+ return value.replace(/\/+$/g, "");
23
+ }
24
+ function normalizeUrl(raw, label) {
25
+ try {
26
+ const parsed = new URL(raw.trim());
27
+ return trimTrailingSlash(parsed.toString());
28
+ }
29
+ catch {
30
+ throw new Error(`invalid ${label} URL: ${raw}`);
31
+ }
32
+ }
33
+ function hasCommand(name) {
34
+ const result = (0, node_child_process_1.spawnSync)("which", [name], { stdio: "ignore" });
35
+ return result.status === 0;
36
+ }
37
+ async function askClientChoice() {
38
+ const rl = (0, promises_2.createInterface)({
39
+ input: process.stdin,
40
+ output: process.stdout,
41
+ });
42
+ try {
43
+ const answer = (await rl.question("Which client do you want to configure? [1] Codex [2] OpenClaw [3] Both: "))
44
+ .trim()
45
+ .toLowerCase();
46
+ if (answer === "2" || answer === "openclaw")
47
+ return "openclaw";
48
+ if (answer === "3" || answer === "both")
49
+ return "both";
50
+ return "codex";
51
+ }
52
+ finally {
53
+ rl.close();
54
+ }
55
+ }
56
+ async function resolveClientChoice(mode) {
57
+ if (mode === "codex" || mode === "openclaw" || mode === "both") {
58
+ return mode;
59
+ }
60
+ const codexInstalled = hasCommand("codex");
61
+ const openclawInstalled = hasCommand("openclaw");
62
+ if (codexInstalled && !openclawInstalled)
63
+ return "codex";
64
+ if (!codexInstalled && openclawInstalled)
65
+ return "openclaw";
66
+ if (codexInstalled && openclawInstalled) {
67
+ if (process.stdin.isTTY && process.stdout.isTTY) {
68
+ return askClientChoice();
69
+ }
70
+ return "both";
71
+ }
72
+ return "codex";
73
+ }
74
+ function removeManagedBlock(source) {
75
+ const start = source.indexOf(MANAGED_START);
76
+ if (start < 0)
77
+ return source;
78
+ const end = source.indexOf(MANAGED_END, start);
79
+ if (end < 0)
80
+ return source.slice(0, start).trimEnd() + "\n";
81
+ return (source.slice(0, start) + source.slice(end + MANAGED_END.length)).trimEnd() + "\n";
82
+ }
83
+ function removeProviderTable(source, providerId) {
84
+ const header = `[model_providers.${providerId}]`;
85
+ const lines = source.split(/\r?\n/);
86
+ const output = [];
87
+ for (let i = 0; i < lines.length; i++) {
88
+ if (lines[i]?.trim() !== header) {
89
+ output.push(lines[i] ?? "");
90
+ continue;
91
+ }
92
+ i++;
93
+ while (i < lines.length && !/^\s*\[[^\]]+\]\s*$/.test(lines[i] ?? "")) {
94
+ i++;
95
+ }
96
+ i--;
97
+ }
98
+ return `${output.join("\n").trimEnd()}\n`;
99
+ }
100
+ function upsertFirstKeyLine(source, key, tomlValue) {
101
+ const lines = source.split(/\r?\n/);
102
+ for (let i = 0; i < lines.length; i++) {
103
+ const line = lines[i] ?? "";
104
+ if (/^\s*#/.test(line))
105
+ continue;
106
+ if (/^\s*\[/.test(line))
107
+ break;
108
+ if (new RegExp(`^\\s*${key}\\s*=`).test(line)) {
109
+ lines[i] = `${key} = ${tomlValue}`;
110
+ return `${lines.join("\n").trimEnd()}\n`;
111
+ }
112
+ }
113
+ return `${`${key} = ${tomlValue}\n${source}`.trimEnd()}\n`;
114
+ }
115
+ async function writeCodexConfig(params) {
116
+ const configPath = node_path_1.default.join(paths_1.codexDir, "config.toml");
117
+ await promises_1.default.mkdir(paths_1.codexDir, { recursive: true });
118
+ let existing = "";
119
+ try {
120
+ existing = await promises_1.default.readFile(configPath, "utf8");
121
+ }
122
+ catch (error) {
123
+ const err = error;
124
+ if (err.code !== "ENOENT")
125
+ throw error;
126
+ }
127
+ const proxyRoot = `${trimTrailingSlash(params.backendUrl)}/api/codex-auth/v1/proxy`;
128
+ let next = existing;
129
+ next = removeManagedBlock(next);
130
+ next = removeProviderTable(next, params.providerId);
131
+ next = upsertFirstKeyLine(next, "model_provider", `"${params.providerId}"`);
132
+ const managedBlock = [
133
+ MANAGED_START,
134
+ `[model_providers.${params.providerId}]`,
135
+ 'name = "OpenAI"',
136
+ `base_url = "${proxyRoot}/backend-api/codex"`,
137
+ 'wire_api = "responses"',
138
+ `chatgpt_base_url = "${proxyRoot}"`,
139
+ "requires_openai_auth = true",
140
+ MANAGED_END,
141
+ "",
142
+ ].join("\n");
143
+ if (next.trim().length) {
144
+ next = `${next.trimEnd()}\n\n`;
145
+ }
146
+ next += managedBlock;
147
+ await promises_1.default.writeFile(configPath, next, "utf8");
148
+ return configPath;
149
+ }
150
+ function codexLoginWithApiKey(apiKey) {
151
+ const run = (0, node_child_process_1.spawnSync)("codex", ["login", "--with-api-key"], {
152
+ input: `${apiKey}\n`,
153
+ encoding: "utf8",
154
+ stdio: ["pipe", "pipe", "pipe"],
155
+ });
156
+ if (run.status === 0)
157
+ return;
158
+ const stderr = (run.stderr ?? "").trim();
159
+ const stdout = (run.stdout ?? "").trim();
160
+ const details = stderr || stdout || "codex login returned a non-zero exit status";
161
+ throw new Error(`failed to store API key in Codex CLI: ${details}`);
162
+ }
163
+ function runOpenClawConfigCommand(args) {
164
+ const run = (0, node_child_process_1.spawnSync)("openclaw", args, {
165
+ encoding: "utf8",
166
+ stdio: ["ignore", "pipe", "pipe"],
167
+ });
168
+ if (run.status === 0)
169
+ return;
170
+ const stderr = (run.stderr ?? "").trim();
171
+ const stdout = (run.stdout ?? "").trim();
172
+ const details = stderr || stdout || "openclaw command returned a non-zero exit status";
173
+ throw new Error(`failed to update OpenClaw config: ${details}`);
174
+ }
175
+ function setupOpenClaw(params) {
176
+ const base = trimTrailingSlash(params.backendUrl);
177
+ const model = params.model.trim() || DEFAULT_OPENCLAW_MODEL;
178
+ const provider = {
179
+ baseUrl: `${base}/api/codex-auth/v1/proxy/v1`,
180
+ apiKey: params.apiKey,
181
+ api: "openai-responses",
182
+ models: [
183
+ { id: "gpt-5.3-codex", name: "GPT-5.3 Codex" },
184
+ { id: "gpt-5.3-codex-spark", name: "GPT-5.3 Codex Spark" },
185
+ { id: "gpt-5.2-codex", name: "GPT-5.2 Codex" },
186
+ { id: "gpt-5.1-codex", name: "GPT-5.1 Codex" },
187
+ ],
188
+ };
189
+ runOpenClawConfigCommand(["config", "set", "agents.defaults.model.primary", `openai/${model}`]);
190
+ runOpenClawConfigCommand(["config", "set", "models.mode", "merge"]);
191
+ runOpenClawConfigCommand([
192
+ "config",
193
+ "set",
194
+ "models.providers.openai",
195
+ JSON.stringify(provider),
196
+ "--json",
197
+ ]);
198
+ }
199
+ class SetupCommand extends base_command_1.BaseCommand {
200
+ async run() {
201
+ await this.runSafe(async () => {
202
+ const { flags } = await this.parse(SetupCommand);
203
+ let managed = null;
204
+ try {
205
+ managed = await (0, config_1.readManagedConfig)();
206
+ }
207
+ catch (error) {
208
+ if (!(error instanceof errors_1.ManagedConfigMissingError))
209
+ throw error;
210
+ }
211
+ const apiKey = (flags["api-key"] ?? managed?.apiKey ?? "").trim();
212
+ if (!apiKey) {
213
+ throw new Error('API key is required. Run "theclawbay setup --api-key <key>".');
214
+ }
215
+ const backendRaw = flags.backend ?? (0, api_key_1.tryInferBackendUrlFromApiKey)(apiKey) ?? managed?.backendUrl ?? DEFAULT_BACKEND_URL;
216
+ const backendUrl = normalizeUrl(backendRaw, "--backend");
217
+ const clientChoice = await resolveClientChoice(flags.client);
218
+ const codexWanted = clientChoice === "codex" || clientChoice === "both";
219
+ const openClawWanted = clientChoice === "openclaw" || clientChoice === "both";
220
+ await (0, config_1.writeManagedConfig)({ backendUrl, apiKey });
221
+ let codexConfigPath = null;
222
+ if (codexWanted) {
223
+ codexConfigPath = await writeCodexConfig({
224
+ backendUrl,
225
+ providerId: flags.provider.trim() || DEFAULT_PROVIDER_ID,
226
+ });
227
+ }
228
+ if (codexWanted && !flags["skip-login"]) {
229
+ if (!hasCommand("codex")) {
230
+ throw new Error('codex CLI not found. Install @openai/codex, or run setup with --client openclaw.');
231
+ }
232
+ codexLoginWithApiKey(apiKey);
233
+ }
234
+ if (openClawWanted) {
235
+ if (!hasCommand("openclaw")) {
236
+ throw new Error('openclaw CLI not found. Install OpenClaw, or run setup with --client codex.');
237
+ }
238
+ setupOpenClaw({
239
+ backendUrl,
240
+ apiKey,
241
+ model: flags["openclaw-model"],
242
+ });
243
+ }
244
+ this.log(`Linked. Managed config written to ${paths_1.managedConfigPath}`);
245
+ this.log(`Backend: ${backendUrl}`);
246
+ if (codexConfigPath) {
247
+ this.log(`Codex config updated at ${codexConfigPath}`);
248
+ }
249
+ if (openClawWanted) {
250
+ this.log("OpenClaw model provider updated for direct WAN API-key routing.");
251
+ }
252
+ if (codexWanted && flags["skip-login"]) {
253
+ this.log("Skipped Codex login. Run: printenv OPENAI_API_KEY | codex login --with-api-key");
254
+ }
255
+ else if (codexWanted) {
256
+ this.log("Codex API-key login updated.");
257
+ }
258
+ this.log('Done. Users can run directly (no "theclawbay proxy" required in recommended setup).');
259
+ });
260
+ }
261
+ }
262
+ SetupCommand.description = "One-time direct setup for Codex/OpenClaw: link key and route directly to The Claw Bay backend";
263
+ SetupCommand.flags = {
264
+ backend: core_1.Flags.string({
265
+ required: false,
266
+ description: "Backend base URL override (default: https://theclawbay.com)",
267
+ }),
268
+ "api-key": core_1.Flags.string({
269
+ required: false,
270
+ aliases: ["apiKey"],
271
+ description: "API key issued by your The Claw Bay dashboard",
272
+ }),
273
+ provider: core_1.Flags.string({
274
+ required: false,
275
+ default: DEFAULT_PROVIDER_ID,
276
+ description: "Codex model provider id to write into ~/.codex/config.toml",
277
+ }),
278
+ client: core_1.Flags.string({
279
+ required: false,
280
+ default: "auto",
281
+ options: ["auto", "codex", "openclaw", "both"],
282
+ description: "Client target to configure",
283
+ }),
284
+ "openclaw-model": core_1.Flags.string({
285
+ required: false,
286
+ default: DEFAULT_OPENCLAW_MODEL,
287
+ description: "OpenClaw model id to set as default (without provider prefix)",
288
+ }),
289
+ "skip-login": core_1.Flags.boolean({
290
+ required: false,
291
+ default: false,
292
+ description: "Skip `codex login --with-api-key`",
293
+ }),
294
+ };
295
+ exports.default = SetupCommand;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "theclawbay",
3
- "version": "0.2.0",
4
- "description": "The Claw Bay CLI: link an API key and run a local relay to The Claw Bay backend.",
3
+ "version": "0.2.3",
4
+ "description": "The Claw Bay CLI: one-time API-key setup for direct Codex access, with optional relay fallback.",
5
5
  "license": "MIT",
6
6
  "bin": {
7
7
  "theclawbay": "dist/index.js"
@@ -10,7 +10,11 @@
10
10
  "types": "dist/index.d.ts",
11
11
  "scripts": {
12
12
  "build": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.json && node -e \"require('node:fs').chmodSync('dist/index.js',0o755)\"",
13
- "prepublishOnly": "npm run build"
13
+ "prepublishOnly": "npm run build",
14
+ "release:patch": "./scripts/release-npm.sh patch",
15
+ "release:minor": "./scripts/release-npm.sh minor",
16
+ "release:major": "./scripts/release-npm.sh major",
17
+ "release:dry-run": "./scripts/release-npm.sh patch --dry-run"
14
18
  },
15
19
  "engines": {
16
20
  "node": ">=18"
@@ -24,6 +28,8 @@
24
28
  "codex",
25
29
  "claw-bay",
26
30
  "cli",
31
+ "setup",
32
+ "wan",
27
33
  "proxy",
28
34
  "api-key",
29
35
  "relay"