@steipete/oracle 0.9.0 → 0.10.0

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.
Files changed (177) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +61 -48
  3. package/dist/bin/oracle-cli.js +455 -402
  4. package/dist/bin/oracle-mcp.js +2 -2
  5. package/dist/bin/oracle.js +165 -279
  6. package/dist/scripts/agent-send.js +31 -31
  7. package/dist/scripts/check.js +6 -6
  8. package/dist/scripts/debug/extract-chatgpt-response.js +10 -10
  9. package/dist/scripts/docs-list.js +30 -30
  10. package/dist/scripts/git-policy.js +25 -23
  11. package/dist/scripts/run-cli.js +8 -8
  12. package/dist/scripts/runner.js +203 -195
  13. package/dist/scripts/test-browser.js +21 -18
  14. package/dist/scripts/test-remote-chrome.js +20 -20
  15. package/dist/src/bridge/connection.js +18 -18
  16. package/dist/src/bridge/userConfigFile.js +7 -7
  17. package/dist/src/browser/actions/assistantResponse.js +149 -101
  18. package/dist/src/browser/actions/attachmentDataTransfer.js +49 -47
  19. package/dist/src/browser/actions/attachments.js +246 -150
  20. package/dist/src/browser/actions/domEvents.js +2 -2
  21. package/dist/src/browser/actions/modelSelection.js +275 -117
  22. package/dist/src/browser/actions/navigation.js +161 -137
  23. package/dist/src/browser/actions/promptComposer.js +100 -64
  24. package/dist/src/browser/actions/remoteFileTransfer.js +10 -10
  25. package/dist/src/browser/actions/thinkingTime.js +207 -110
  26. package/dist/src/browser/chromeLifecycle.js +62 -60
  27. package/dist/src/browser/config.js +34 -15
  28. package/dist/src/browser/constants.js +17 -12
  29. package/dist/src/browser/cookies.js +19 -19
  30. package/dist/src/browser/detect.js +62 -62
  31. package/dist/src/browser/domDebug.js +1 -1
  32. package/dist/src/browser/index.js +390 -295
  33. package/dist/src/browser/modelStrategy.js +1 -1
  34. package/dist/src/browser/pageActions.js +5 -5
  35. package/dist/src/browser/policies.js +16 -13
  36. package/dist/src/browser/profileState.js +44 -39
  37. package/dist/src/browser/prompt.js +72 -42
  38. package/dist/src/browser/promptSummary.js +5 -5
  39. package/dist/src/browser/providerDomFlow.js +1 -1
  40. package/dist/src/browser/providers/chatgptDomProvider.js +9 -9
  41. package/dist/src/browser/providers/geminiDeepThinkDomProvider.js +51 -42
  42. package/dist/src/browser/providers/index.js +2 -2
  43. package/dist/src/browser/reattach.js +67 -34
  44. package/dist/src/browser/reattachHelpers.js +31 -26
  45. package/dist/src/browser/sessionRunner.js +37 -25
  46. package/dist/src/browser/utils.js +9 -9
  47. package/dist/src/browserMode.js +1 -1
  48. package/dist/src/cli/bridge/claudeConfig.js +16 -16
  49. package/dist/src/cli/bridge/client.js +28 -20
  50. package/dist/src/cli/bridge/codexConfig.js +16 -16
  51. package/dist/src/cli/bridge/doctor.js +47 -39
  52. package/dist/src/cli/bridge/host.js +58 -56
  53. package/dist/src/cli/browserConfig.js +62 -48
  54. package/dist/src/cli/browserDefaults.js +27 -26
  55. package/dist/src/cli/bundleWarnings.js +1 -1
  56. package/dist/src/cli/clipboard.js +11 -2
  57. package/dist/src/cli/detach.js +2 -2
  58. package/dist/src/cli/dryRun.js +29 -25
  59. package/dist/src/cli/duplicatePromptGuard.js +3 -3
  60. package/dist/src/cli/engine.js +9 -9
  61. package/dist/src/cli/errorUtils.js +1 -1
  62. package/dist/src/cli/fileSize.js +3 -3
  63. package/dist/src/cli/format.js +2 -2
  64. package/dist/src/cli/help.js +28 -28
  65. package/dist/src/cli/hiddenAliases.js +3 -3
  66. package/dist/src/cli/markdownBundle.js +7 -7
  67. package/dist/src/cli/markdownRenderer.js +15 -15
  68. package/dist/src/cli/notifier.js +77 -67
  69. package/dist/src/cli/options.js +127 -106
  70. package/dist/src/cli/oscUtils.js +1 -1
  71. package/dist/src/cli/promptRequirement.js +2 -2
  72. package/dist/src/cli/renderOutput.js +1 -1
  73. package/dist/src/cli/rootAlias.js +1 -1
  74. package/dist/src/cli/runOptions.js +32 -28
  75. package/dist/src/cli/sessionCommand.js +31 -21
  76. package/dist/src/cli/sessionDisplay.js +95 -81
  77. package/dist/src/cli/sessionLineage.js +6 -2
  78. package/dist/src/cli/sessionRunner.js +103 -93
  79. package/dist/src/cli/sessionTable.js +26 -23
  80. package/dist/src/cli/stdin.js +22 -0
  81. package/dist/src/cli/tagline.js +121 -124
  82. package/dist/src/cli/tui/index.js +139 -128
  83. package/dist/src/cli/writeOutputPath.js +5 -5
  84. package/dist/src/config.js +7 -7
  85. package/dist/src/gemini-web/browserSessionManager.js +19 -15
  86. package/dist/src/gemini-web/client.js +76 -70
  87. package/dist/src/gemini-web/executionMode.js +6 -8
  88. package/dist/src/gemini-web/executor.js +98 -93
  89. package/dist/src/gemini-web/index.js +1 -1
  90. package/dist/src/mcp/server.js +16 -12
  91. package/dist/src/mcp/tools/consult.js +51 -47
  92. package/dist/src/mcp/tools/sessionResources.js +12 -12
  93. package/dist/src/mcp/tools/sessions.js +26 -17
  94. package/dist/src/mcp/types.js +5 -5
  95. package/dist/src/mcp/utils.js +15 -7
  96. package/dist/src/oracle/background.js +15 -15
  97. package/dist/src/oracle/claude.js +53 -25
  98. package/dist/src/oracle/client.js +50 -41
  99. package/dist/src/oracle/config.js +96 -66
  100. package/dist/src/oracle/errors.js +38 -38
  101. package/dist/src/oracle/files.js +55 -46
  102. package/dist/src/oracle/finishLine.js +10 -8
  103. package/dist/src/oracle/format.js +3 -3
  104. package/dist/src/oracle/gemini.js +37 -33
  105. package/dist/src/oracle/logging.js +7 -7
  106. package/dist/src/oracle/markdown.js +28 -28
  107. package/dist/src/oracle/modelResolver.js +16 -16
  108. package/dist/src/oracle/multiModelRunner.js +12 -12
  109. package/dist/src/oracle/oscProgress.js +8 -8
  110. package/dist/src/oracle/promptAssembly.js +6 -3
  111. package/dist/src/oracle/request.js +16 -13
  112. package/dist/src/oracle/run.js +156 -134
  113. package/dist/src/oracle/runUtils.js +8 -5
  114. package/dist/src/oracle/tokenEstimate.js +6 -6
  115. package/dist/src/oracle/tokenStats.js +5 -5
  116. package/dist/src/oracle/tokenStringifier.js +5 -5
  117. package/dist/src/oracle.js +12 -12
  118. package/dist/src/oracleHome.js +3 -3
  119. package/dist/src/remote/client.js +25 -25
  120. package/dist/src/remote/health.js +20 -20
  121. package/dist/src/remote/remoteServiceConfig.js +9 -9
  122. package/dist/src/remote/server.js +129 -118
  123. package/dist/src/sessionManager.js +77 -75
  124. package/dist/src/sessionStore.js +3 -3
  125. package/dist/src/version.js +10 -10
  126. package/dist/vendor/oracle-notifier/README.md +2 -0
  127. package/package.json +66 -62
  128. package/vendor/oracle-notifier/README.md +2 -0
  129. package/dist/markdansi/types/index.js +0 -4
  130. package/dist/oracle/bin/oracle-cli.js +0 -472
  131. package/dist/oracle/src/browser/actions/assistantResponse.js +0 -471
  132. package/dist/oracle/src/browser/actions/attachments.js +0 -82
  133. package/dist/oracle/src/browser/actions/modelSelection.js +0 -190
  134. package/dist/oracle/src/browser/actions/navigation.js +0 -75
  135. package/dist/oracle/src/browser/actions/promptComposer.js +0 -167
  136. package/dist/oracle/src/browser/chromeLifecycle.js +0 -104
  137. package/dist/oracle/src/browser/config.js +0 -33
  138. package/dist/oracle/src/browser/constants.js +0 -40
  139. package/dist/oracle/src/browser/cookies.js +0 -210
  140. package/dist/oracle/src/browser/domDebug.js +0 -36
  141. package/dist/oracle/src/browser/index.js +0 -331
  142. package/dist/oracle/src/browser/pageActions.js +0 -5
  143. package/dist/oracle/src/browser/prompt.js +0 -88
  144. package/dist/oracle/src/browser/promptSummary.js +0 -20
  145. package/dist/oracle/src/browser/sessionRunner.js +0 -80
  146. package/dist/oracle/src/browser/types.js +0 -1
  147. package/dist/oracle/src/browser/utils.js +0 -62
  148. package/dist/oracle/src/browserMode.js +0 -1
  149. package/dist/oracle/src/cli/browserConfig.js +0 -44
  150. package/dist/oracle/src/cli/dryRun.js +0 -59
  151. package/dist/oracle/src/cli/engine.js +0 -17
  152. package/dist/oracle/src/cli/errorUtils.js +0 -9
  153. package/dist/oracle/src/cli/help.js +0 -70
  154. package/dist/oracle/src/cli/markdownRenderer.js +0 -15
  155. package/dist/oracle/src/cli/options.js +0 -103
  156. package/dist/oracle/src/cli/promptRequirement.js +0 -14
  157. package/dist/oracle/src/cli/rootAlias.js +0 -30
  158. package/dist/oracle/src/cli/sessionCommand.js +0 -77
  159. package/dist/oracle/src/cli/sessionDisplay.js +0 -270
  160. package/dist/oracle/src/cli/sessionRunner.js +0 -94
  161. package/dist/oracle/src/heartbeat.js +0 -43
  162. package/dist/oracle/src/oracle/client.js +0 -48
  163. package/dist/oracle/src/oracle/config.js +0 -29
  164. package/dist/oracle/src/oracle/errors.js +0 -101
  165. package/dist/oracle/src/oracle/files.js +0 -220
  166. package/dist/oracle/src/oracle/format.js +0 -33
  167. package/dist/oracle/src/oracle/fsAdapter.js +0 -7
  168. package/dist/oracle/src/oracle/oscProgress.js +0 -60
  169. package/dist/oracle/src/oracle/request.js +0 -48
  170. package/dist/oracle/src/oracle/run.js +0 -444
  171. package/dist/oracle/src/oracle/tokenStats.js +0 -39
  172. package/dist/oracle/src/oracle/types.js +0 -1
  173. package/dist/oracle/src/oracle.js +0 -9
  174. package/dist/oracle/src/sessionManager.js +0 -205
  175. package/dist/oracle/src/version.js +0 -39
  176. package/dist/scripts/chrome/browser-tools.js +0 -295
  177. package/dist/src/browser/profileSync.js +0 -141
@@ -5,14 +5,15 @@
5
5
  * - Verifies the DevTools /json/version endpoint responds.
6
6
  * - Prints a WSL-friendly firewall hint if the port is unreachable.
7
7
  */
8
- import { setTimeout as sleep } from 'node:timers/promises';
9
- import { launch } from 'chrome-launcher';
10
- import os from 'node:os';
11
- import { readFileSync } from 'node:fs';
8
+ import { setTimeout as sleep } from "node:timers/promises";
9
+ import { launch } from "chrome-launcher";
10
+ import os from "node:os";
11
+ import { readFileSync } from "node:fs";
12
12
  const DEFAULT_PORT = 45871;
13
- const port = normalizePort(process.env.ORACLE_BROWSER_PORT ?? process.env.ORACLE_BROWSER_DEBUG_PORT) ?? DEFAULT_PORT;
13
+ const port = normalizePort(process.env.ORACLE_BROWSER_PORT ?? process.env.ORACLE_BROWSER_DEBUG_PORT) ??
14
+ DEFAULT_PORT;
14
15
  const hostHint = resolveWslHost();
15
- const targetHost = hostHint ?? '127.0.0.1';
16
+ const targetHost = hostHint ?? "127.0.0.1";
16
17
  function normalizePort(raw) {
17
18
  if (!raw)
18
19
  return null;
@@ -22,18 +23,18 @@ function normalizePort(raw) {
22
23
  return value;
23
24
  }
24
25
  function isWsl() {
25
- if (process.platform !== 'linux')
26
+ if (process.platform !== "linux")
26
27
  return false;
27
28
  if (process.env.WSL_DISTRO_NAME)
28
29
  return true;
29
- return os.release().toLowerCase().includes('microsoft');
30
+ return os.release().toLowerCase().includes("microsoft");
30
31
  }
31
32
  function resolveWslHost() {
32
33
  if (!isWsl())
33
34
  return null;
34
35
  try {
35
- const resolv = readFileSync('/etc/resolv.conf', 'utf8');
36
- for (const line of resolv.split('\n')) {
36
+ const resolv = readFileSync("/etc/resolv.conf", "utf8");
37
+ for (const line of resolv.split("\n")) {
37
38
  const match = line.match(/^nameserver\s+([0-9.]+)/);
38
39
  if (match?.[1])
39
40
  return match[1];
@@ -49,19 +50,21 @@ function firewallHint(host, devtoolsPort) {
49
50
  return null;
50
51
  return [
51
52
  `DevTools port ${host}:${devtoolsPort} is blocked from WSL.`,
52
- '',
53
- 'PowerShell (admin):',
53
+ "",
54
+ "PowerShell (admin):",
54
55
  `New-NetFirewallRule -DisplayName 'Chrome DevTools ${devtoolsPort}' -Direction Inbound -Action Allow -Protocol TCP -LocalPort ${devtoolsPort}`,
55
56
  "New-NetFirewallRule -DisplayName 'Chrome DevTools (chrome.exe)' -Direction Inbound -Action Allow -Program 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe' -Protocol TCP",
56
- '',
57
- 'Re-run ./runner pnpm test:browser after adding the rule.',
58
- ].join('\n');
57
+ "",
58
+ "Re-run ./runner pnpm test:browser after adding the rule.",
59
+ ].join("\n");
59
60
  }
60
61
  async function fetchVersion(host, devtoolsPort) {
61
62
  const controller = new AbortController();
62
63
  const timer = setTimeout(() => controller.abort(), 5000);
63
64
  try {
64
- const res = await fetch(`http://${host}:${devtoolsPort}/json/version`, { signal: controller.signal });
65
+ const res = await fetch(`http://${host}:${devtoolsPort}/json/version`, {
66
+ signal: controller.signal,
67
+ });
65
68
  if (!res.ok)
66
69
  return false;
67
70
  const json = (await res.json());
@@ -78,7 +81,7 @@ async function main() {
78
81
  console.log(`[browser-test] launching Chrome on ${targetHost}:${port} (headful)…`);
79
82
  const chrome = await launch({
80
83
  port,
81
- chromeFlags: ['--remote-debugging-address=0.0.0.0'],
84
+ chromeFlags: ["--remote-debugging-address=0.0.0.0"],
82
85
  });
83
86
  let ok = await fetchVersion(targetHost, chrome.port);
84
87
  if (!ok) {
@@ -98,6 +101,6 @@ async function main() {
98
101
  process.exit(1);
99
102
  }
100
103
  main().catch((error) => {
101
- console.error('[browser-test] Unexpected failure:', error instanceof Error ? error.message : String(error));
104
+ console.error("[browser-test] Unexpected failure:", error instanceof Error ? error.message : String(error));
102
105
  process.exit(1);
103
106
  });
@@ -8,30 +8,30 @@
8
8
  * Then run this script:
9
9
  * npx tsx scripts/test-remote-chrome.ts <remote-host> [port]
10
10
  */
11
- import CDP from 'chrome-remote-interface';
11
+ import CDP from "chrome-remote-interface";
12
12
  async function main() {
13
- const host = process.argv[2] || 'localhost';
14
- const port = parseInt(process.argv[3] || '9222', 10);
13
+ const host = process.argv[2] || "localhost";
14
+ const port = parseInt(process.argv[3] || "9222", 10);
15
15
  console.log(`Attempting to connect to Chrome at ${host}:${port}...`);
16
16
  try {
17
17
  // Test connection
18
18
  const client = await CDP({ host, port });
19
- console.log('✓ Connected to Chrome DevTools Protocol');
19
+ console.log("✓ Connected to Chrome DevTools Protocol");
20
20
  const { Network, Page, Runtime } = client;
21
21
  // Enable domains
22
22
  await Promise.all([Network.enable(), Page.enable()]);
23
- console.log('✓ Enabled Network and Page domains');
23
+ console.log("✓ Enabled Network and Page domains");
24
24
  // Get browser version info
25
25
  const version = await CDP.Version({ host, port });
26
26
  console.log(`✓ Browser: ${version.Browser}`);
27
- console.log(`✓ Protocol: ${version['Protocol-Version']}`);
27
+ console.log(`✓ Protocol: ${version["Protocol-Version"]}`);
28
28
  // Navigate to ChatGPT
29
- console.log('\nNavigating to ChatGPT...');
30
- await Page.navigate({ url: 'https://chatgpt.com/' });
29
+ console.log("\nNavigating to ChatGPT...");
30
+ await Page.navigate({ url: "https://chatgpt.com/" });
31
31
  await Page.loadEventFired();
32
- console.log('✓ Page loaded');
32
+ console.log("✓ Page loaded");
33
33
  // Check current URL
34
- const evalResult = await Runtime.evaluate({ expression: 'window.location.href' });
34
+ const evalResult = await Runtime.evaluate({ expression: "window.location.href" });
35
35
  console.log(`✓ Current URL: ${evalResult.result.value}`);
36
36
  // Check if logged in (look for specific elements)
37
37
  const checkLogin = await Runtime.evaluate({
@@ -49,19 +49,19 @@ async function main() {
49
49
  });
50
50
  console.log(`✓ Login status: ${JSON.stringify(checkLogin.result.value)}`);
51
51
  await client.close();
52
- console.log('\n✓ POC successful! Remote Chrome connection works.');
53
- console.log('\nTo use Oracle with remote Chrome, you would need to:');
54
- console.log('1. Ensure cookies are loaded in remote Chrome');
55
- console.log('2. Configure Oracle with --remote-chrome <host:port> to use this instance');
56
- console.log('3. Ensure Oracle skips local Chrome launch when --remote-chrome is specified');
52
+ console.log("\n✓ POC successful! Remote Chrome connection works.");
53
+ console.log("\nTo use Oracle with remote Chrome, you would need to:");
54
+ console.log("1. Ensure cookies are loaded in remote Chrome");
55
+ console.log("2. Configure Oracle with --remote-chrome <host:port> to use this instance");
56
+ console.log("3. Ensure Oracle skips local Chrome launch when --remote-chrome is specified");
57
57
  }
58
58
  catch (error) {
59
- console.error('✗ Connection failed:', error instanceof Error ? error.message : error);
60
- console.log('\nTroubleshooting:');
61
- console.log('1. Ensure Chrome is running on remote machine with:');
59
+ console.error("✗ Connection failed:", error instanceof Error ? error.message : error);
60
+ console.log("\nTroubleshooting:");
61
+ console.log("1. Ensure Chrome is running on remote machine with:");
62
62
  console.log(` google-chrome --remote-debugging-port=${port} --remote-debugging-address=0.0.0.0`);
63
- console.log('2. Check firewall allows connections to port', port);
64
- console.log('3. Verify network connectivity to', host);
63
+ console.log("2. Check firewall allows connections to port", port);
64
+ console.log("3. Verify network connectivity to", host);
65
65
  process.exit(1);
66
66
  }
67
67
  }
@@ -1,9 +1,9 @@
1
- import fs from 'node:fs/promises';
2
- import path from 'node:path';
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
3
  export function normalizeHostPort(hostname, port) {
4
4
  const trimmed = hostname.trim();
5
- const unwrapped = trimmed.startsWith('[') && trimmed.endsWith(']') ? trimmed.slice(1, -1) : trimmed;
6
- if (unwrapped.includes(':')) {
5
+ const unwrapped = trimmed.startsWith("[") && trimmed.endsWith("]") ? trimmed.slice(1, -1) : trimmed;
6
+ if (unwrapped.includes(":")) {
7
7
  return `[${unwrapped}]:${port}`;
8
8
  }
9
9
  return `${unwrapped}:${port}`;
@@ -11,7 +11,7 @@ export function normalizeHostPort(hostname, port) {
11
11
  export function parseHostPort(raw) {
12
12
  const target = raw.trim();
13
13
  if (!target) {
14
- throw new Error('Expected host:port but received an empty value.');
14
+ throw new Error("Expected host:port but received an empty value.");
15
15
  }
16
16
  const ipv6Match = target.match(/^\[(.+)]:(\d+)$/);
17
17
  let hostname;
@@ -21,43 +21,43 @@ export function parseHostPort(raw) {
21
21
  portSegment = ipv6Match[2]?.trim();
22
22
  }
23
23
  else {
24
- const lastColon = target.lastIndexOf(':');
24
+ const lastColon = target.lastIndexOf(":");
25
25
  if (lastColon === -1) {
26
26
  throw new Error(`Invalid host:port format: ${target}. Expected host:port (IPv6 must use [host]:port notation).`);
27
27
  }
28
28
  hostname = target.slice(0, lastColon).trim();
29
29
  portSegment = target.slice(lastColon + 1).trim();
30
- if (hostname.includes(':')) {
30
+ if (hostname.includes(":")) {
31
31
  throw new Error(`Invalid host:port format: ${target}. Wrap IPv6 addresses in brackets, e.g. "[2001:db8::1]:9473".`);
32
32
  }
33
33
  }
34
34
  if (!hostname) {
35
35
  throw new Error(`Invalid host:port format: ${target}. Host portion is missing.`);
36
36
  }
37
- const port = Number.parseInt(portSegment ?? '', 10);
37
+ const port = Number.parseInt(portSegment ?? "", 10);
38
38
  if (!Number.isFinite(port) || port <= 0 || port > 65_535) {
39
- throw new Error(`Invalid port: "${portSegment ?? ''}". Expected a number between 1 and 65535.`);
39
+ throw new Error(`Invalid port: "${portSegment ?? ""}". Expected a number between 1 and 65535.`);
40
40
  }
41
41
  return { hostname, port };
42
42
  }
43
43
  export function parseBridgeConnectionString(input) {
44
44
  const raw = input.trim();
45
45
  if (!raw) {
46
- throw new Error('Missing connection string.');
46
+ throw new Error("Missing connection string.");
47
47
  }
48
48
  let url;
49
49
  try {
50
- url = raw.includes('://') ? new URL(raw) : new URL(`oracle+tcp://${raw}`);
50
+ url = raw.includes("://") ? new URL(raw) : new URL(`oracle+tcp://${raw}`);
51
51
  }
52
52
  catch (error) {
53
53
  throw new Error(`Invalid connection string: ${error instanceof Error ? error.message : String(error)}`);
54
54
  }
55
55
  const hostname = url.hostname?.trim();
56
- const port = Number.parseInt(url.port ?? '', 10);
56
+ const port = Number.parseInt(url.port ?? "", 10);
57
57
  if (!hostname || !Number.isFinite(port) || port <= 0 || port > 65_535) {
58
58
  throw new Error(`Invalid connection string host: ${raw}. Expected host:port.`);
59
59
  }
60
- const token = url.searchParams.get('token')?.trim() ?? '';
60
+ const token = url.searchParams.get("token")?.trim() ?? "";
61
61
  if (!token) {
62
62
  throw new Error('Connection string is missing token. Expected "?token=...".');
63
63
  }
@@ -74,11 +74,11 @@ export function formatBridgeConnectionString(connection, options = {}) {
74
74
  return `${base}?${params.toString()}`;
75
75
  }
76
76
  export function looksLikePath(value) {
77
- return value.includes('/') || value.includes('\\') || value.endsWith('.json');
77
+ return value.includes("/") || value.includes("\\") || value.endsWith(".json");
78
78
  }
79
79
  export async function readBridgeConnectionArtifact(filePath) {
80
80
  const resolved = path.resolve(process.cwd(), filePath);
81
- const raw = await fs.readFile(resolved, 'utf8');
81
+ const raw = await fs.readFile(resolved, "utf8");
82
82
  let parsed;
83
83
  try {
84
84
  parsed = JSON.parse(raw);
@@ -86,15 +86,15 @@ export async function readBridgeConnectionArtifact(filePath) {
86
86
  catch (error) {
87
87
  throw new Error(`Failed to parse connection artifact JSON at ${resolved}: ${error instanceof Error ? error.message : String(error)}`);
88
88
  }
89
- if (!parsed || typeof parsed !== 'object') {
89
+ if (!parsed || typeof parsed !== "object") {
90
90
  throw new Error(`Invalid connection artifact at ${resolved}: expected an object.`);
91
91
  }
92
92
  const remoteHost = parsed.remoteHost;
93
93
  const remoteToken = parsed.remoteToken;
94
- if (typeof remoteHost !== 'string' || remoteHost.trim().length === 0) {
94
+ if (typeof remoteHost !== "string" || remoteHost.trim().length === 0) {
95
95
  throw new Error(`Invalid connection artifact at ${resolved}: remoteHost is missing.`);
96
96
  }
97
- if (typeof remoteToken !== 'string' || remoteToken.trim().length === 0) {
97
+ if (typeof remoteToken !== "string" || remoteToken.trim().length === 0) {
98
98
  throw new Error(`Invalid connection artifact at ${resolved}: remoteToken is missing.`);
99
99
  }
100
100
  // Validate host formatting early so downstream checks don't crash.
@@ -1,15 +1,15 @@
1
- import fs from 'node:fs/promises';
2
- import path from 'node:path';
3
- import JSON5 from 'json5';
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import JSON5 from "json5";
4
4
  export async function readUserConfigFile(configPath) {
5
5
  try {
6
- const raw = await fs.readFile(configPath, 'utf8');
6
+ const raw = await fs.readFile(configPath, "utf8");
7
7
  const parsed = JSON5.parse(raw);
8
8
  return { config: parsed ?? {}, loaded: true };
9
9
  }
10
10
  catch (error) {
11
11
  const code = error.code;
12
- if (code === 'ENOENT') {
12
+ if (code === "ENOENT") {
13
13
  return { config: {}, loaded: false };
14
14
  }
15
15
  throw new Error(`Failed to read ${configPath}: ${error instanceof Error ? error.message : String(error)}`);
@@ -20,9 +20,9 @@ export async function writeUserConfigFile(configPath, config) {
20
20
  await fs.mkdir(dir, { recursive: true, mode: 0o700 });
21
21
  const contents = `${JSON.stringify(config, null, 2)}\n`;
22
22
  const tempPath = `${configPath}.tmp-${process.pid}-${Date.now()}`;
23
- await fs.writeFile(tempPath, contents, { encoding: 'utf8', mode: 0o600 });
23
+ await fs.writeFile(tempPath, contents, { encoding: "utf8", mode: 0o600 });
24
24
  await fs.rename(tempPath, configPath);
25
- if (process.platform !== 'win32') {
25
+ if (process.platform !== "win32") {
26
26
  await fs.chmod(configPath, 0o600).catch(() => undefined);
27
27
  }
28
28
  }