assistme 0.1.2 → 0.1.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.
|
@@ -4,7 +4,11 @@ import { createClient } from "@supabase/supabase-js";
|
|
|
4
4
|
// src/utils/config.ts
|
|
5
5
|
import Conf from "conf";
|
|
6
6
|
import { resolve } from "path";
|
|
7
|
+
var SUPABASE_URL_DEFAULT = "https://msgplwbgohpokajtibew.supabase.co";
|
|
8
|
+
var SUPABASE_ANON_KEY_DEFAULT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im1zZ3Bsd2Jnb2hwb2thanRpYmV3Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjE3MTMzNTEsImV4cCI6MjA3NzI4OTM1MX0.YqiluL_mIBWKv5dteIcPAPQ_jRp9rzZlvAXvkQttDjs";
|
|
7
9
|
var CONFIG_DEFAULTS = {
|
|
10
|
+
supabaseUrl: SUPABASE_URL_DEFAULT,
|
|
11
|
+
supabaseAnonKey: SUPABASE_ANON_KEY_DEFAULT,
|
|
8
12
|
sessionName: "Default",
|
|
9
13
|
model: "claude-sonnet-4-20250514",
|
|
10
14
|
maxTurns: 50
|
|
@@ -14,8 +18,8 @@ var config = new Conf({
|
|
|
14
18
|
defaults: CONFIG_DEFAULTS
|
|
15
19
|
});
|
|
16
20
|
function getConfig() {
|
|
17
|
-
const supabaseUrl = process.env.SUPABASE_URL || config.get("supabaseUrl") ||
|
|
18
|
-
const supabaseAnonKey = process.env.SUPABASE_ANON_KEY || config.get("supabaseAnonKey") ||
|
|
21
|
+
const supabaseUrl = process.env.SUPABASE_URL || config.get("supabaseUrl") || SUPABASE_URL_DEFAULT;
|
|
22
|
+
const supabaseAnonKey = process.env.SUPABASE_ANON_KEY || config.get("supabaseAnonKey") || SUPABASE_ANON_KEY_DEFAULT;
|
|
19
23
|
const anthropicApiKey = process.env.ANTHROPIC_API_KEY || config.get("anthropicApiKey") || "";
|
|
20
24
|
const workspacePath = config.get("workspacePath") || process.cwd();
|
|
21
25
|
return {
|
|
@@ -168,28 +172,63 @@ function getSupabase() {
|
|
|
168
172
|
}
|
|
169
173
|
return supabase;
|
|
170
174
|
}
|
|
175
|
+
async function exchangeCliToken(cliToken) {
|
|
176
|
+
const config2 = getConfig();
|
|
177
|
+
const exchangeUrl = `${config2.supabaseUrl}/functions/v1/cli-token-exchange`;
|
|
178
|
+
const res = await fetch(exchangeUrl, {
|
|
179
|
+
method: "POST",
|
|
180
|
+
headers: {
|
|
181
|
+
"Content-Type": "application/json",
|
|
182
|
+
apikey: config2.supabaseAnonKey
|
|
183
|
+
},
|
|
184
|
+
body: JSON.stringify({ token: cliToken })
|
|
185
|
+
});
|
|
186
|
+
if (!res.ok) {
|
|
187
|
+
const body = await res.json().catch(() => ({ error: res.statusText }));
|
|
188
|
+
throw new Error(body.error || `Token exchange failed (${res.status})`);
|
|
189
|
+
}
|
|
190
|
+
const data = await res.json();
|
|
191
|
+
if (!data.access_token || !data.refresh_token) {
|
|
192
|
+
throw new Error("Token exchange returned incomplete session");
|
|
193
|
+
}
|
|
194
|
+
return data;
|
|
195
|
+
}
|
|
171
196
|
async function loginWithToken(cliToken) {
|
|
172
|
-
|
|
173
|
-
try {
|
|
174
|
-
const json = Buffer.from(cliToken, "base64").toString("utf-8");
|
|
175
|
-
parsed = JSON.parse(json);
|
|
176
|
-
if (!parsed.access_token || !parsed.refresh_token) {
|
|
177
|
-
throw new Error("Missing token fields");
|
|
178
|
-
}
|
|
179
|
-
} catch {
|
|
197
|
+
if (!cliToken.startsWith("am_")) {
|
|
180
198
|
throw new Error(
|
|
181
|
-
"Invalid token format.
|
|
199
|
+
"Invalid token format. Use an am_ token from the web page."
|
|
182
200
|
);
|
|
183
201
|
}
|
|
202
|
+
const sessionTokens = await exchangeCliToken(cliToken);
|
|
203
|
+
const store = readAuthStore();
|
|
204
|
+
store["cli_token"] = cliToken;
|
|
205
|
+
writeAuthStore(store);
|
|
184
206
|
const sb = getSupabase();
|
|
185
207
|
const { data, error } = await sb.auth.setSession({
|
|
186
|
-
access_token:
|
|
187
|
-
refresh_token:
|
|
208
|
+
access_token: sessionTokens.access_token,
|
|
209
|
+
refresh_token: sessionTokens.refresh_token
|
|
188
210
|
});
|
|
189
211
|
if (error) throw new Error(`Login failed: ${error.message}`);
|
|
190
212
|
if (!data.user) throw new Error("Login failed: no user returned");
|
|
191
213
|
return data.user.id;
|
|
192
214
|
}
|
|
215
|
+
async function refreshWithCliToken() {
|
|
216
|
+
const store = readAuthStore();
|
|
217
|
+
const cliToken = store["cli_token"];
|
|
218
|
+
if (!cliToken || !cliToken.startsWith("am_")) return null;
|
|
219
|
+
try {
|
|
220
|
+
const sessionTokens = await exchangeCliToken(cliToken);
|
|
221
|
+
const sb = getSupabase();
|
|
222
|
+
const { data, error } = await sb.auth.setSession({
|
|
223
|
+
access_token: sessionTokens.access_token,
|
|
224
|
+
refresh_token: sessionTokens.refresh_token
|
|
225
|
+
});
|
|
226
|
+
if (error || !data.user) return null;
|
|
227
|
+
return data.user.id;
|
|
228
|
+
} catch {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
193
232
|
async function getSession() {
|
|
194
233
|
const sb = getSupabase();
|
|
195
234
|
const { data } = await sb.auth.getSession();
|
|
@@ -199,6 +238,8 @@ async function getCurrentUserId() {
|
|
|
199
238
|
const sb = getSupabase();
|
|
200
239
|
const { data, error } = await sb.auth.getUser();
|
|
201
240
|
if (error || !data.user) {
|
|
241
|
+
const refreshed = await refreshWithCliToken();
|
|
242
|
+
if (refreshed) return refreshed;
|
|
202
243
|
throw new Error("Not authenticated. Run `assistme login`.");
|
|
203
244
|
}
|
|
204
245
|
return data.user.id;
|
|
@@ -391,6 +432,7 @@ export {
|
|
|
391
432
|
DAYBOX_AGENT_ID,
|
|
392
433
|
getSupabase,
|
|
393
434
|
loginWithToken,
|
|
435
|
+
refreshWithCliToken,
|
|
394
436
|
getSession,
|
|
395
437
|
getCurrentUserId,
|
|
396
438
|
logout,
|
package/dist/index.js
CHANGED
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
setLogLevel,
|
|
25
25
|
setSessionBusy,
|
|
26
26
|
updateHeartbeat
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-H5BZPIOY.js";
|
|
28
28
|
|
|
29
29
|
// src/index.ts
|
|
30
30
|
import { Command } from "commander";
|
|
@@ -2839,11 +2839,14 @@ function isThinkingContent(msg) {
|
|
|
2839
2839
|
|
|
2840
2840
|
// src/index.ts
|
|
2841
2841
|
import { createInterface } from "readline";
|
|
2842
|
+
import { createRequire } from "module";
|
|
2842
2843
|
loadEnv();
|
|
2844
|
+
var require2 = createRequire(import.meta.url);
|
|
2845
|
+
var { version } = require2("../package.json");
|
|
2843
2846
|
var program = new Command();
|
|
2844
2847
|
program.name("assistme").description(
|
|
2845
2848
|
"AssistMe CLI Agent - AI assistant that controls your real browser"
|
|
2846
|
-
).version(
|
|
2849
|
+
).version(version);
|
|
2847
2850
|
program.command("login").description("Authenticate with your AssistMe account via browser token").action(async () => {
|
|
2848
2851
|
const config = getConfig();
|
|
2849
2852
|
const webUrl = config.supabaseUrl ? config.supabaseUrl.replace(/\.supabase\.co.*/, ".supabase.co").replace("https://", "") : "";
|
|
@@ -2855,7 +2858,7 @@ program.command("login").description("Authenticate with your AssistMe account vi
|
|
|
2855
2858
|
console.log();
|
|
2856
2859
|
console.log(chalk.cyan(` ${tokenPageUrl}`));
|
|
2857
2860
|
console.log();
|
|
2858
|
-
console.log(" Step 2: Sign in
|
|
2861
|
+
console.log(" Step 2: Sign in, create a token, and copy it.");
|
|
2859
2862
|
console.log();
|
|
2860
2863
|
try {
|
|
2861
2864
|
const { exec: exec2 } = await import("child_process");
|
|
@@ -3005,19 +3008,6 @@ program.command("start", { isDefault: true }).description("Start the agent and l
|
|
|
3005
3008
|
if (opts.name) {
|
|
3006
3009
|
setConfig("sessionName", opts.name);
|
|
3007
3010
|
}
|
|
3008
|
-
const config = getConfig();
|
|
3009
|
-
if (!config.supabaseUrl || !config.supabaseAnonKey) {
|
|
3010
|
-
log.error("Supabase not configured.");
|
|
3011
|
-
log.info("Run: assistme config set supabaseUrl <url>");
|
|
3012
|
-
log.info("Run: assistme config set supabaseAnonKey <key>");
|
|
3013
|
-
process.exit(1);
|
|
3014
|
-
}
|
|
3015
|
-
if (!config.anthropicApiKey) {
|
|
3016
|
-
log.error("Anthropic API key not configured.");
|
|
3017
|
-
log.info("Run: assistme config set anthropicApiKey <key>");
|
|
3018
|
-
log.info("Or set ANTHROPIC_API_KEY environment variable.");
|
|
3019
|
-
process.exit(1);
|
|
3020
|
-
}
|
|
3021
3011
|
console.log();
|
|
3022
3012
|
console.log(
|
|
3023
3013
|
chalk.bold.cyan(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557")
|
|
@@ -3097,7 +3087,7 @@ program.command("start", { isDefault: true }).description("Start the agent and l
|
|
|
3097
3087
|
}
|
|
3098
3088
|
log.agent(`Processing: "${input}"`);
|
|
3099
3089
|
try {
|
|
3100
|
-
const { createTask: createTask2 } = await import("./supabase-
|
|
3090
|
+
const { createTask: createTask2 } = await import("./supabase-DTKGPEER.js");
|
|
3101
3091
|
const session = sessionManager.getSession();
|
|
3102
3092
|
const conversationId = sessionManager.getConversationId();
|
|
3103
3093
|
if (session && conversationId) {
|
|
@@ -3126,7 +3116,7 @@ program.command("start", { isDefault: true }).description("Start the agent and l
|
|
|
3126
3116
|
program.command("status").description("Check the status of the current agent session").action(async () => {
|
|
3127
3117
|
try {
|
|
3128
3118
|
const userId = await getCurrentUserId();
|
|
3129
|
-
const { getSupabase: getSupabase2 } = await import("./supabase-
|
|
3119
|
+
const { getSupabase: getSupabase2 } = await import("./supabase-DTKGPEER.js");
|
|
3130
3120
|
const sb = getSupabase2();
|
|
3131
3121
|
const { data: sessions } = await sb.from("agent_sessions").select("*").eq("user_id", userId).in("status", ["online", "busy"]).order("started_at", { ascending: false }).limit(5);
|
|
3132
3122
|
if (!sessions || sessions.length === 0) {
|
|
@@ -16,10 +16,11 @@ import {
|
|
|
16
16
|
loginWithToken,
|
|
17
17
|
logout,
|
|
18
18
|
pollPendingTasks,
|
|
19
|
+
refreshWithCliToken,
|
|
19
20
|
resetEventSequence,
|
|
20
21
|
setSessionBusy,
|
|
21
22
|
updateHeartbeat
|
|
22
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-H5BZPIOY.js";
|
|
23
24
|
export {
|
|
24
25
|
CLI_AGENT_ID,
|
|
25
26
|
DAYBOX_AGENT_ID,
|
|
@@ -38,6 +39,7 @@ export {
|
|
|
38
39
|
loginWithToken,
|
|
39
40
|
logout,
|
|
40
41
|
pollPendingTasks,
|
|
42
|
+
refreshWithCliToken,
|
|
41
43
|
resetEventSequence,
|
|
42
44
|
setSessionBusy,
|
|
43
45
|
updateHeartbeat
|
package/package.json
CHANGED
package/src/db/supabase.ts
CHANGED
|
@@ -85,27 +85,56 @@ export function getSupabase(): SupabaseClient {
|
|
|
85
85
|
// ── Auth: Token-Based Login ────────────────────────────────────────
|
|
86
86
|
|
|
87
87
|
/**
|
|
88
|
-
*
|
|
89
|
-
|
|
88
|
+
* Exchange an am_ CLI token for a Supabase session via the Edge Function.
|
|
89
|
+
*/
|
|
90
|
+
async function exchangeCliToken(
|
|
91
|
+
cliToken: string
|
|
92
|
+
): Promise<{ access_token: string; refresh_token: string }> {
|
|
93
|
+
const config = getConfig();
|
|
94
|
+
const exchangeUrl = `${config.supabaseUrl}/functions/v1/cli-token-exchange`;
|
|
95
|
+
|
|
96
|
+
const res = await fetch(exchangeUrl, {
|
|
97
|
+
method: "POST",
|
|
98
|
+
headers: {
|
|
99
|
+
"Content-Type": "application/json",
|
|
100
|
+
apikey: config.supabaseAnonKey,
|
|
101
|
+
},
|
|
102
|
+
body: JSON.stringify({ token: cliToken }),
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
if (!res.ok) {
|
|
106
|
+
const body = await res.json().catch(() => ({ error: res.statusText }));
|
|
107
|
+
throw new Error(body.error || `Token exchange failed (${res.status})`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const data = await res.json();
|
|
111
|
+
if (!data.access_token || !data.refresh_token) {
|
|
112
|
+
throw new Error("Token exchange returned incomplete session");
|
|
113
|
+
}
|
|
114
|
+
return data;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Login using an am_ CLI token (exchanged via Edge Function for a Supabase session).
|
|
90
119
|
*/
|
|
91
120
|
export async function loginWithToken(cliToken: string): Promise<string> {
|
|
92
|
-
|
|
93
|
-
try {
|
|
94
|
-
const json = Buffer.from(cliToken, "base64").toString("utf-8");
|
|
95
|
-
parsed = JSON.parse(json);
|
|
96
|
-
if (!parsed.access_token || !parsed.refresh_token) {
|
|
97
|
-
throw new Error("Missing token fields");
|
|
98
|
-
}
|
|
99
|
-
} catch {
|
|
121
|
+
if (!cliToken.startsWith("am_")) {
|
|
100
122
|
throw new Error(
|
|
101
|
-
"Invalid token format.
|
|
123
|
+
"Invalid token format. Use an am_ token from the web page."
|
|
102
124
|
);
|
|
103
125
|
}
|
|
104
126
|
|
|
127
|
+
const sessionTokens = await exchangeCliToken(cliToken);
|
|
128
|
+
|
|
129
|
+
// Persist the CLI token so we can re-authenticate later
|
|
130
|
+
const store = readAuthStore();
|
|
131
|
+
store["cli_token"] = cliToken;
|
|
132
|
+
writeAuthStore(store);
|
|
133
|
+
|
|
105
134
|
const sb = getSupabase();
|
|
106
135
|
const { data, error } = await sb.auth.setSession({
|
|
107
|
-
access_token:
|
|
108
|
-
refresh_token:
|
|
136
|
+
access_token: sessionTokens.access_token,
|
|
137
|
+
refresh_token: sessionTokens.refresh_token,
|
|
109
138
|
});
|
|
110
139
|
|
|
111
140
|
if (error) throw new Error(`Login failed: ${error.message}`);
|
|
@@ -114,6 +143,29 @@ export async function loginWithToken(cliToken: string): Promise<string> {
|
|
|
114
143
|
return data.user.id;
|
|
115
144
|
}
|
|
116
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Re-authenticate using the stored CLI token (am_).
|
|
148
|
+
* Called automatically when the Supabase session has expired.
|
|
149
|
+
*/
|
|
150
|
+
export async function refreshWithCliToken(): Promise<string | null> {
|
|
151
|
+
const store = readAuthStore();
|
|
152
|
+
const cliToken = store["cli_token"];
|
|
153
|
+
if (!cliToken || !cliToken.startsWith("am_")) return null;
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
const sessionTokens = await exchangeCliToken(cliToken);
|
|
157
|
+
const sb = getSupabase();
|
|
158
|
+
const { data, error } = await sb.auth.setSession({
|
|
159
|
+
access_token: sessionTokens.access_token,
|
|
160
|
+
refresh_token: sessionTokens.refresh_token,
|
|
161
|
+
});
|
|
162
|
+
if (error || !data.user) return null;
|
|
163
|
+
return data.user.id;
|
|
164
|
+
} catch {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
117
169
|
export async function getSession() {
|
|
118
170
|
const sb = getSupabase();
|
|
119
171
|
const { data } = await sb.auth.getSession();
|
|
@@ -124,6 +176,9 @@ export async function getCurrentUserId(): Promise<string> {
|
|
|
124
176
|
const sb = getSupabase();
|
|
125
177
|
const { data, error } = await sb.auth.getUser();
|
|
126
178
|
if (error || !data.user) {
|
|
179
|
+
// Try auto-refresh with stored CLI token
|
|
180
|
+
const refreshed = await refreshWithCliToken();
|
|
181
|
+
if (refreshed) return refreshed;
|
|
127
182
|
throw new Error("Not authenticated. Run `assistme login`.");
|
|
128
183
|
}
|
|
129
184
|
return data.user.id;
|
package/src/index.ts
CHANGED
|
@@ -19,9 +19,13 @@ import {
|
|
|
19
19
|
} from "./agent/scheduler.js";
|
|
20
20
|
import { MemoryManager } from "./agent/memory.js";
|
|
21
21
|
import { SkillManager } from "./agent/skills.js";
|
|
22
|
+
import { createRequire } from "module";
|
|
22
23
|
|
|
23
24
|
loadEnv();
|
|
24
25
|
|
|
26
|
+
const require = createRequire(import.meta.url);
|
|
27
|
+
const { version } = require("../package.json");
|
|
28
|
+
|
|
25
29
|
const program = new Command();
|
|
26
30
|
|
|
27
31
|
program
|
|
@@ -29,7 +33,7 @@ program
|
|
|
29
33
|
.description(
|
|
30
34
|
"AssistMe CLI Agent - AI assistant that controls your real browser"
|
|
31
35
|
)
|
|
32
|
-
.version(
|
|
36
|
+
.version(version);
|
|
33
37
|
|
|
34
38
|
// ── assistme login ──────────────────────────────────────────────────
|
|
35
39
|
|
|
@@ -53,7 +57,7 @@ program
|
|
|
53
57
|
console.log();
|
|
54
58
|
console.log(chalk.cyan(` ${tokenPageUrl}`));
|
|
55
59
|
console.log();
|
|
56
|
-
console.log(" Step 2: Sign in
|
|
60
|
+
console.log(" Step 2: Sign in, create a token, and copy it.");
|
|
57
61
|
console.log();
|
|
58
62
|
|
|
59
63
|
// Try to open the URL in the user's default browser
|
|
@@ -269,23 +273,6 @@ program
|
|
|
269
273
|
setConfig("sessionName", opts.name);
|
|
270
274
|
}
|
|
271
275
|
|
|
272
|
-
const config = getConfig();
|
|
273
|
-
|
|
274
|
-
// Validate configuration
|
|
275
|
-
if (!config.supabaseUrl || !config.supabaseAnonKey) {
|
|
276
|
-
log.error("Supabase not configured.");
|
|
277
|
-
log.info("Run: assistme config set supabaseUrl <url>");
|
|
278
|
-
log.info("Run: assistme config set supabaseAnonKey <key>");
|
|
279
|
-
process.exit(1);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
if (!config.anthropicApiKey) {
|
|
283
|
-
log.error("Anthropic API key not configured.");
|
|
284
|
-
log.info("Run: assistme config set anthropicApiKey <key>");
|
|
285
|
-
log.info("Or set ANTHROPIC_API_KEY environment variable.");
|
|
286
|
-
process.exit(1);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
276
|
console.log();
|
|
290
277
|
console.log(
|
|
291
278
|
chalk.bold.cyan(" ╔══════════════════════════════════════════╗")
|
package/src/utils/config.ts
CHANGED
|
@@ -11,7 +11,14 @@ export interface AssistMeConfig {
|
|
|
11
11
|
maxTurns: number;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
const SUPABASE_URL_DEFAULT =
|
|
15
|
+
"https://msgplwbgohpokajtibew.supabase.co";
|
|
16
|
+
const SUPABASE_ANON_KEY_DEFAULT =
|
|
17
|
+
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im1zZ3Bsd2Jnb2hwb2thanRpYmV3Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjE3MTMzNTEsImV4cCI6MjA3NzI4OTM1MX0.YqiluL_mIBWKv5dteIcPAPQ_jRp9rzZlvAXvkQttDjs";
|
|
18
|
+
|
|
14
19
|
const CONFIG_DEFAULTS: Partial<AssistMeConfig> = {
|
|
20
|
+
supabaseUrl: SUPABASE_URL_DEFAULT,
|
|
21
|
+
supabaseAnonKey: SUPABASE_ANON_KEY_DEFAULT,
|
|
15
22
|
sessionName: "Default",
|
|
16
23
|
model: "claude-sonnet-4-20250514",
|
|
17
24
|
maxTurns: 50,
|
|
@@ -24,9 +31,9 @@ const config = new Conf<Partial<AssistMeConfig>>({
|
|
|
24
31
|
|
|
25
32
|
export function getConfig(): AssistMeConfig {
|
|
26
33
|
const supabaseUrl =
|
|
27
|
-
process.env.SUPABASE_URL || config.get("supabaseUrl") ||
|
|
34
|
+
process.env.SUPABASE_URL || config.get("supabaseUrl") || SUPABASE_URL_DEFAULT;
|
|
28
35
|
const supabaseAnonKey =
|
|
29
|
-
process.env.SUPABASE_ANON_KEY || config.get("supabaseAnonKey") ||
|
|
36
|
+
process.env.SUPABASE_ANON_KEY || config.get("supabaseAnonKey") || SUPABASE_ANON_KEY_DEFAULT;
|
|
30
37
|
const anthropicApiKey =
|
|
31
38
|
process.env.ANTHROPIC_API_KEY || config.get("anthropicApiKey") || "";
|
|
32
39
|
const workspacePath =
|