Skip to content

Commit 4c4566f

Browse files
committed
Fix Windows auth URL opener
1 parent ac62750 commit 4c4566f

5 files changed

Lines changed: 47 additions & 20 deletions

File tree

src/cli.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const OPENCODE_CONFIG_DIR = join(homedir(), ".config", "opencode");
1111
const OPENCODE_COMMAND_DIR = join(OPENCODE_CONFIG_DIR, "command");
1212
const OH_MY_OPENCODE_CONFIG = join(OPENCODE_CONFIG_DIR, "oh-my-opencode.json");
1313
const PLUGIN_NAME = "opencode-supermemory@latest";
14+
const DEFAULT_CONFIG_FILE = CONFIG_FILE ?? join(OPENCODE_CONFIG_DIR, "supermemory.json");
1415

1516
const SUPERMEMORY_INIT_COMMAND = `---
1617
description: Initialize Supermemory with comprehensive codebase knowledge
@@ -377,7 +378,7 @@ interface InstallOptions {
377378
async function install(options: InstallOptions): Promise<number> {
378379
console.log("\n🧠 opencode-supermemory installer\n");
379380

380-
writeInstallDefaults(existsSync(CONFIG_FILE));
381+
writeInstallDefaults(existsSync(DEFAULT_CONFIG_FILE));
381382

382383
const rl = options.tui ? createReadline() : null;
383384

src/config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ function getApiKey(): string | undefined {
102102

103103
export const SUPERMEMORY_API_KEY = getApiKey();
104104
export const CONFIG_FILE = CONFIG_FILES[1];
105+
const DEFAULT_CONFIG_FILE = CONFIG_FILE ?? join(CONFIG_DIR, "supermemory.json");
105106

106107
export const CONFIG = {
107108
similarityThreshold: fileConfig.similarityThreshold ?? DEFAULTS.similarityThreshold,
@@ -140,5 +141,5 @@ export function writeInstallDefaults(isExistingInstall: boolean): void {
140141
next.autoRecallEveryPrompt = false;
141142
next.captureEveryNTurns = 0;
142143
}
143-
writeFileSync(CONFIG_FILE, JSON.stringify(next, null, 2));
144+
writeFileSync(DEFAULT_CONFIG_FILE, JSON.stringify(next, null, 2));
144145
}

src/services/auth.ts

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { createServer, type IncomingMessage, type ServerResponse } from "node:http";
22
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3-
import { exec } from "node:child_process";
43
import { join } from "node:path";
54
import { homedir } from "node:os";
5+
import { openUrl } from "./openUrl.js";
66

77
const CREDENTIALS_DIR = join(homedir(), ".supermemory-opencode");
88
const CREDENTIALS_FILE = join(CREDENTIALS_DIR, "credentials.json");
@@ -40,21 +40,6 @@ export function clearCredentials(): boolean {
4040
return true;
4141
}
4242

43-
function openBrowser(url: string): void {
44-
const platform = process.platform;
45-
46-
const commands: Record<string, string> = {
47-
darwin: `open "${url}"`,
48-
win32: `start "" "${url}"`,
49-
linux: `xdg-open "${url}"`,
50-
};
51-
52-
const cmd = commands[platform] ?? `xdg-open "${url}"`;
53-
exec(cmd, (err) => {
54-
if (err) console.error("Failed to open browser:", err.message);
55-
});
56-
}
57-
5843
export interface AuthResult {
5944
success: boolean;
6045
apiKey?: string;
@@ -129,7 +114,13 @@ export function startAuthFlow(timeoutMs = 120000): Promise<AuthResult> {
129114

130115
console.log("Opening browser for authentication...");
131116
console.log(`If it doesn't open, visit: ${authUrl}`);
132-
openBrowser(authUrl);
117+
openUrl(authUrl).catch((error) => {
118+
if (!resolved) {
119+
resolved = true;
120+
server.close();
121+
resolve({ success: false, error: `Failed to open browser: ${error.message}` });
122+
}
123+
});
133124
});
134125

135126
setTimeout(() => {

src/services/client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ export class SupermemoryClient {
121121
sm_source: "opencode",
122122
sm_capture_mode: metadata?.sm_capture_mode ?? "tool",
123123
...(metadata ?? {}),
124-
} as Record<string, string | number | boolean | string[]>;
124+
} as unknown as Record<string, string | number | boolean | string[]>;
125125

126126
const result = await withTimeout(
127127
this.getClient().memories.add({

src/services/openUrl.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { execFile } from "node:child_process";
2+
3+
function run(command: string, args: string[]): Promise<void> {
4+
return new Promise((resolve, reject) => {
5+
execFile(command, args, { windowsHide: true }, (error) => {
6+
if (error) reject(error);
7+
else resolve();
8+
});
9+
});
10+
}
11+
12+
export async function openUrl(url: string | URL): Promise<void> {
13+
const href = url.toString();
14+
if (!/^https?:\/\//i.test(href)) {
15+
throw new Error("Refusing to open non-http URL");
16+
}
17+
18+
if (process.platform === "win32") {
19+
try {
20+
await run("rundll32.exe", ["url.dll,FileProtocolHandler", href]);
21+
return;
22+
} catch {}
23+
24+
await run("cmd.exe", ["/c", "start", '""', href]);
25+
return;
26+
}
27+
28+
if (process.platform === "darwin") {
29+
await run("open", [href]);
30+
return;
31+
}
32+
33+
await run("xdg-open", [href]);
34+
}

0 commit comments

Comments
 (0)