@theaux/clawdbot 2026.1.14 → 2026.1.16
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/dist/commands/antigravity-oauth.js +24 -32
- package/dist/commands/auth-choice-options.js +10 -0
- package/dist/commands/auth-choice.apply.custom-openai.js +116 -0
- package/dist/commands/auth-choice.apply.js +2 -0
- package/dist/commands/auth-choice.apply.oauth.js +10 -2
- package/dist/security/audit-extra.js +525 -0
- package/dist/security/audit-fs.js +55 -0
- package/dist/security/audit.js +469 -0
- package/dist/security/fix.js +317 -0
- package/package.json +2 -1
|
@@ -6,8 +6,6 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { createHash, randomBytes } from "node:crypto";
|
|
8
8
|
import { readFileSync } from "node:fs";
|
|
9
|
-
import { stdin, stdout } from "node:process";
|
|
10
|
-
import { createInterface } from "node:readline/promises";
|
|
11
9
|
import { loginAntigravity } from "@mariozechner/pi-ai";
|
|
12
10
|
// OAuth constants - decoded from pi-ai's base64 encoded values to stay in sync
|
|
13
11
|
const decode = (s) => Buffer.from(s, "base64").toString();
|
|
@@ -247,28 +245,16 @@ async function fetchProjectId(accessToken) {
|
|
|
247
245
|
// Use fallback project ID
|
|
248
246
|
return DEFAULT_PROJECT_ID;
|
|
249
247
|
}
|
|
250
|
-
/**
|
|
251
|
-
* Prompt user for input via readline.
|
|
252
|
-
*/
|
|
253
|
-
async function promptInput(message) {
|
|
254
|
-
const rl = createInterface({ input: stdin, output: stdout });
|
|
255
|
-
try {
|
|
256
|
-
return (await rl.question(message)).trim();
|
|
257
|
-
}
|
|
258
|
-
finally {
|
|
259
|
-
rl.close();
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
248
|
/**
|
|
263
249
|
* VPS-aware Antigravity OAuth login.
|
|
264
250
|
*
|
|
265
251
|
* On local machines: Uses the standard pi-ai flow with automatic localhost callback.
|
|
266
252
|
* On VPS/SSH: Shows URL and prompts user to paste the callback URL manually.
|
|
267
253
|
*/
|
|
268
|
-
export async function loginAntigravityVpsAware(onUrl, onProgress) {
|
|
254
|
+
export async function loginAntigravityVpsAware(prompter, onUrl, onProgress) {
|
|
269
255
|
// Check if we're in a remote environment
|
|
270
256
|
if (shouldUseManualOAuthFlow()) {
|
|
271
|
-
return loginAntigravityManual(onUrl, onProgress);
|
|
257
|
+
return loginAntigravityManual(prompter, onUrl, onProgress);
|
|
272
258
|
}
|
|
273
259
|
// Use the standard pi-ai flow for local environments
|
|
274
260
|
try {
|
|
@@ -284,7 +270,7 @@ export async function loginAntigravityVpsAware(onUrl, onProgress) {
|
|
|
284
270
|
err.message.includes("port") ||
|
|
285
271
|
err.message.includes("listen"))) {
|
|
286
272
|
onProgress?.("Local callback server failed. Switching to manual mode...");
|
|
287
|
-
return loginAntigravityManual(onUrl, onProgress);
|
|
273
|
+
return loginAntigravityManual(prompter, onUrl, onProgress);
|
|
288
274
|
}
|
|
289
275
|
throw err;
|
|
290
276
|
}
|
|
@@ -292,26 +278,32 @@ export async function loginAntigravityVpsAware(onUrl, onProgress) {
|
|
|
292
278
|
/**
|
|
293
279
|
* Manual Antigravity OAuth login for VPS/headless environments.
|
|
294
280
|
*
|
|
295
|
-
* Shows the OAuth URL and prompts user to paste the callback URL.
|
|
281
|
+
* Shows the OAuth URL and prompts user to paste the callback URL using prompter.
|
|
296
282
|
*/
|
|
297
|
-
export async function loginAntigravityManual(onUrl, onProgress) {
|
|
283
|
+
export async function loginAntigravityManual(prompter, onUrl, onProgress) {
|
|
298
284
|
const { verifier, challenge } = generatePKCESync();
|
|
299
285
|
const authUrl = buildAuthUrl(challenge, verifier);
|
|
300
286
|
// Show the URL to the user
|
|
301
287
|
await onUrl(authUrl);
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
288
|
+
// Stop the spinner completely before prompting for input
|
|
289
|
+
// This prevents the continuous update loop that interferes with input
|
|
290
|
+
onProgress?.("");
|
|
291
|
+
// Show instructions using prompter.note for consistent UI
|
|
292
|
+
await prompter.note([
|
|
293
|
+
"1. Open the URL above in your LOCAL browser",
|
|
294
|
+
"2. Complete the Google sign-in",
|
|
295
|
+
"3. Your browser will redirect to a localhost URL that won't load",
|
|
296
|
+
"4. Copy the ENTIRE URL from your browser's address bar",
|
|
297
|
+
"5. Paste it below and press Enter",
|
|
298
|
+
"",
|
|
299
|
+
"The URL will look like:",
|
|
300
|
+
"http://localhost:51121/oauth-callback?code=xxx&state=yyy",
|
|
301
|
+
].join("\n"), "VPS/Remote Mode - Manual OAuth");
|
|
302
|
+
// Use prompter.text() for clean input (same pattern as Telegram bot token)
|
|
303
|
+
const callbackInput = String(await prompter.text({
|
|
304
|
+
message: "Paste the redirect URL here",
|
|
305
|
+
validate: (value) => (value?.trim() ? undefined : "Required"),
|
|
306
|
+
})).trim();
|
|
315
307
|
const parsed = parseCallbackInput(callbackInput, verifier);
|
|
316
308
|
if ("error" in parsed) {
|
|
317
309
|
throw new Error(parsed.error);
|
|
@@ -7,6 +7,12 @@ const AUTH_CHOICE_GROUP_DEFS = [
|
|
|
7
7
|
hint: "Codex OAuth + API key",
|
|
8
8
|
choices: ["codex-cli", "openai-codex", "openai-api-key"],
|
|
9
9
|
},
|
|
10
|
+
{
|
|
11
|
+
value: "custom-openai",
|
|
12
|
+
label: "Custom OpenAI",
|
|
13
|
+
hint: "OpenAI-compatible API",
|
|
14
|
+
choices: ["custom-openai-api-key"],
|
|
15
|
+
},
|
|
10
16
|
{
|
|
11
17
|
value: "anthropic",
|
|
12
18
|
label: "Anthropic",
|
|
@@ -123,6 +129,10 @@ export function buildAuthChoiceOptions(params) {
|
|
|
123
129
|
});
|
|
124
130
|
options.push({ value: "chutes", label: "Chutes (OAuth)" });
|
|
125
131
|
options.push({ value: "openai-api-key", label: "OpenAI API key" });
|
|
132
|
+
options.push({
|
|
133
|
+
value: "custom-openai-api-key",
|
|
134
|
+
label: "Custom OpenAI (OpenAI-compatible API)"
|
|
135
|
+
});
|
|
126
136
|
options.push({ value: "openrouter-api-key", label: "OpenRouter API key" });
|
|
127
137
|
options.push({ value: "moonshot-api-key", label: "Moonshot AI API key" });
|
|
128
138
|
options.push({ value: "synthetic-api-key", label: "Synthetic API key" });
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { applyAuthProfileConfig } from "./onboard-auth.js";
|
|
2
|
+
export async function applyAuthChoiceCustomOpenAI(params) {
|
|
3
|
+
if (params.authChoice !== "custom-openai-api-key") {
|
|
4
|
+
return null;
|
|
5
|
+
}
|
|
6
|
+
let nextConfig = params.config;
|
|
7
|
+
// Prompt for custom endpoint URL
|
|
8
|
+
const endpointUrl = await params.prompter.text({
|
|
9
|
+
message: "Enter OpenAI-compatible API endpoint URL",
|
|
10
|
+
placeholder: "https://api.example.com/v1",
|
|
11
|
+
validate: (value) => {
|
|
12
|
+
if (!value?.trim())
|
|
13
|
+
return "URL is required";
|
|
14
|
+
try {
|
|
15
|
+
new URL(value);
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return "Invalid URL format";
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
const baseUrl = String(endpointUrl ?? "").trim();
|
|
24
|
+
if (!baseUrl) {
|
|
25
|
+
throw new Error("Custom endpoint URL is required");
|
|
26
|
+
}
|
|
27
|
+
// Prompt for API key
|
|
28
|
+
const apiKeyInput = await params.prompter.text({
|
|
29
|
+
message: "Enter API key for custom endpoint",
|
|
30
|
+
});
|
|
31
|
+
const apiKey = String(apiKeyInput ?? "").trim();
|
|
32
|
+
if (!apiKey) {
|
|
33
|
+
throw new Error("API key is required");
|
|
34
|
+
}
|
|
35
|
+
// Apply to OpenAI provider
|
|
36
|
+
nextConfig = applyCustomOpenAIConfig(nextConfig, { baseUrl, apiKey });
|
|
37
|
+
// Set auth profile
|
|
38
|
+
nextConfig = applyAuthProfileConfig(nextConfig, {
|
|
39
|
+
profileId: "openai:default",
|
|
40
|
+
provider: "openai",
|
|
41
|
+
mode: "api_key",
|
|
42
|
+
});
|
|
43
|
+
return { config: nextConfig };
|
|
44
|
+
}
|
|
45
|
+
function applyCustomOpenAIConfig(cfg, params) {
|
|
46
|
+
const providers = { ...cfg.models?.providers };
|
|
47
|
+
// Configure OpenAI provider with custom endpoint
|
|
48
|
+
providers.openai = {
|
|
49
|
+
...providers.openai,
|
|
50
|
+
api: "openai-completions",
|
|
51
|
+
baseUrl: params.baseUrl,
|
|
52
|
+
apiKey: params.apiKey,
|
|
53
|
+
models: [
|
|
54
|
+
{
|
|
55
|
+
id: "gpt-4",
|
|
56
|
+
name: "GPT-4",
|
|
57
|
+
reasoning: false,
|
|
58
|
+
input: ["text"],
|
|
59
|
+
contextWindow: 8192,
|
|
60
|
+
maxTokens: 4096,
|
|
61
|
+
cost: {
|
|
62
|
+
input: 30,
|
|
63
|
+
output: 60,
|
|
64
|
+
cacheRead: 3,
|
|
65
|
+
cacheWrite: 37.5,
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
id: "gpt-3.5-turbo",
|
|
70
|
+
name: "GPT-3.5 Turbo",
|
|
71
|
+
reasoning: false,
|
|
72
|
+
input: ["text"],
|
|
73
|
+
contextWindow: 4096,
|
|
74
|
+
maxTokens: 4096,
|
|
75
|
+
cost: {
|
|
76
|
+
input: 0.5,
|
|
77
|
+
output: 1.5,
|
|
78
|
+
cacheRead: 0.05,
|
|
79
|
+
cacheWrite: 0.625,
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
};
|
|
84
|
+
// Add model allowlist entries
|
|
85
|
+
const models = { ...cfg.agents?.defaults?.models };
|
|
86
|
+
models["openai/gpt-4"] = {};
|
|
87
|
+
models["openai/gpt-3.5-turbo"] = {};
|
|
88
|
+
return {
|
|
89
|
+
...cfg,
|
|
90
|
+
models: {
|
|
91
|
+
...cfg.models,
|
|
92
|
+
providers,
|
|
93
|
+
},
|
|
94
|
+
agents: {
|
|
95
|
+
...cfg.agents,
|
|
96
|
+
defaults: {
|
|
97
|
+
...cfg.agents?.defaults,
|
|
98
|
+
models,
|
|
99
|
+
model: {
|
|
100
|
+
...(cfg.agents?.defaults?.model &&
|
|
101
|
+
"fallbacks" in cfg.agents.defaults.model
|
|
102
|
+
? {
|
|
103
|
+
fallbacks: cfg.agents.defaults.model.fallbacks,
|
|
104
|
+
}
|
|
105
|
+
: undefined),
|
|
106
|
+
primary: "openai/gpt-4",
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
env: {
|
|
111
|
+
...cfg.env,
|
|
112
|
+
OPENAI_API_KEY: params.apiKey,
|
|
113
|
+
OPENAI_BASE_URL: params.baseUrl,
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { applyAuthChoiceAnthropic } from "./auth-choice.apply.anthropic.js";
|
|
2
2
|
import { applyAuthChoiceApiProviders } from "./auth-choice.apply.api-providers.js";
|
|
3
|
+
import { applyAuthChoiceCustomOpenAI } from "./auth-choice.apply.custom-openai.js";
|
|
3
4
|
import { applyAuthChoiceGitHubCopilot } from "./auth-choice.apply.github-copilot.js";
|
|
4
5
|
import { applyAuthChoiceMiniMax } from "./auth-choice.apply.minimax.js";
|
|
5
6
|
import { applyAuthChoiceOAuth } from "./auth-choice.apply.oauth.js";
|
|
6
7
|
import { applyAuthChoiceOpenAI } from "./auth-choice.apply.openai.js";
|
|
7
8
|
export async function applyAuthChoice(params) {
|
|
8
9
|
const handlers = [
|
|
10
|
+
applyAuthChoiceCustomOpenAI,
|
|
9
11
|
applyAuthChoiceAnthropic,
|
|
10
12
|
applyAuthChoiceOpenAI,
|
|
11
13
|
applyAuthChoiceOAuth,
|
|
@@ -97,7 +97,7 @@ export async function applyAuthChoiceOAuth(params) {
|
|
|
97
97
|
const spin = params.prompter.progress("Starting OAuth flow…");
|
|
98
98
|
let oauthCreds = null;
|
|
99
99
|
try {
|
|
100
|
-
oauthCreds = await loginAntigravityVpsAware(async (url) => {
|
|
100
|
+
oauthCreds = await loginAntigravityVpsAware(params.prompter, async (url) => {
|
|
101
101
|
if (isRemote) {
|
|
102
102
|
spin.stop("OAuth URL ready");
|
|
103
103
|
params.runtime.log(`\nOpen this URL in your LOCAL browser:\n\n${url}\n`);
|
|
@@ -107,7 +107,15 @@ export async function applyAuthChoiceOAuth(params) {
|
|
|
107
107
|
await openUrl(url);
|
|
108
108
|
params.runtime.log(`Open: ${url}`);
|
|
109
109
|
}
|
|
110
|
-
}, (msg) =>
|
|
110
|
+
}, (msg) => {
|
|
111
|
+
// Stop the spinner when signaled (empty message means stop)
|
|
112
|
+
if (msg === "") {
|
|
113
|
+
spin.stop("Waiting for callback URL...");
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
spin.update(msg);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
111
119
|
spin.stop("Antigravity OAuth complete");
|
|
112
120
|
if (oauthCreds) {
|
|
113
121
|
await writeOAuthCredentials("google-antigravity", oauthCreds, params.agentDir);
|