open-ready 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.
Files changed (2) hide show
  1. package/open-when-ready.mjs +25 -41
  2. package/package.json +1 -2
@@ -1,4 +1,12 @@
1
1
  #!/usr/bin/env node
2
+
3
+ /**
4
+ * @fileoverview CLI tool that spawns a dev server command, monitors its log
5
+ * output for a "ready" signal, and automatically opens the local URL in the
6
+ * browser. If an error is detected first, it opens an AI assistant with the
7
+ * error context for troubleshooting.
8
+ */
9
+
2
10
  import fsPromises from "fs/promises";
3
11
  import fs from "fs";
4
12
  import path from "path";
@@ -20,18 +28,12 @@ const logPath = fs.existsSync(nextDir)
20
28
  ? path.join(".next", "port.log")
21
29
  : "open-when-ready.log";
22
30
 
23
- console.log(`πŸ“ Log: ${logPath} | Poll: ${pollDelay}ms`);
24
31
 
25
32
  /**
26
- * Opens browser when dev server is ready.
27
- *
28
- * ### Features
29
- * - **Automatic**: Detects server start
30
- * - **Versatile**: Supports multiple browsers
31
- *
32
- * ```js
33
- * console.log("Ready!");
34
- * ```
33
+ * Scans log output for error lines and extracts surrounding context
34
+ * as a URL-encoded string suitable for an AI search query.
35
+ * @param {string} log - Raw log output from the dev server
36
+ * @returns {string} URL-encoded error context, or empty string if no error found
35
37
  */
36
38
  function getErrorContext(log) {
37
39
  const lines = log.split(/\n/);
@@ -53,31 +55,31 @@ function getErrorContext(log) {
53
55
  return "";
54
56
  }
55
57
 
58
+ /**
59
+ * Parses log output to find the local dev server URL (e.g. http://localhost:3000).
60
+ * @param {string} log - Raw log output from the dev server
61
+ * @returns {string|null} The localhost URL, or null if not found
62
+ */
56
63
  function extractUrl(log) {
57
64
  // Better regex for Local: line
58
65
  const localMatch = log.match(/Local:\s+(http:\/\/localhost:\d+)/i);
59
- if (localMatch) {
60
- console.log("βœ… EXTRACTED URL:", localMatch[1]);
61
- return localMatch[1];
62
- }
66
+ if (localMatch) return localMatch[1];
63
67
 
64
68
  // Fallback port
65
69
  const portMatch = log.match(/localhost:(\d+)/);
66
- if (portMatch) {
67
- const url = `http://localhost:${portMatch[1]}`;
68
- console.log("βœ… FALLBACK URL:", url);
69
- return url;
70
- }
70
+ if (portMatch) return `http://localhost:${portMatch[1]}`;
71
71
 
72
- console.log("❌ NO URL FOUND");
73
72
  return null;
74
73
  }
75
74
 
75
+ /**
76
+ * Main entry point. Spawns the dev server command, pipes its output to a log
77
+ * file, and polls the log for ready/error signals to open the browser or AI helper.
78
+ */
76
79
  async function run() {
77
80
  try {
78
81
  await fsPromises.rm(logPath, { force: true });
79
82
  } catch {}
80
- console.log("πŸš€ Starting", cmdArgs.join(" "));
81
83
 
82
84
  const proc = spawn(cmdArgs.join(" "), [], {
83
85
  stdio: ["ignore", "pipe", "pipe", "ipc"],
@@ -107,14 +109,9 @@ async function run() {
107
109
  if (logChanged && stats.size > 100) {
108
110
  stableCount = 0;
109
111
  lastLogSize = stats.size;
110
- console.log(
111
- `πŸ“Š ${stats.size}B CHANGED | LOG:\n${currentLog.slice(0, 500)}...`,
112
- );
113
112
  } else if (stats.size > 100) {
114
113
  stableCount++;
115
- console.log(`πŸ“Š ${stats.size}B STABLE (${stableCount}/5)`);
116
114
  if (stableCount >= 5) {
117
- console.log("πŸ›‘ Log stable 5 polls - stopping");
118
115
  clearInterval(poll);
119
116
  return;
120
117
  }
@@ -123,7 +120,6 @@ async function run() {
123
120
  // Error first
124
121
  const errorRegex = /β¨―|[Ss]yntax[Ee]rror|error|failed|exception/i;
125
122
  if (errorRegex.test(currentLog) && !noAi && !errorOpened) {
126
- console.log("🎯 ERROR!");
127
123
  const err = getErrorContext(currentLog);
128
124
  const customPrompt = "Explain what the error is, how to fix it, then give a shell script with the best recommended solution.";
129
125
  const prompt = encodeURIComponent(customPrompt + " ");
@@ -138,33 +134,21 @@ async function run() {
138
134
  if (isReadyNow && !lastReadySeen && !opened) {
139
135
  opened = true;
140
136
  lastReadySeen = true;
141
- console.log("πŸŽ‰ READY DETECTED!");
142
137
  const url = extractUrl(currentLog);
143
138
  if (url && !noOpen) {
144
- console.log("🌐 Testing", url);
145
139
  try {
146
140
  await waitOn(url, { timeout: 10000, http: true });
147
- console.log("βœ… HTTP READY!");
148
- } catch (e) {
149
- console.log(
150
- "⚠ HTTP not ready, but opening:",
151
- e.message.slice(0, 50),
152
- );
153
- }
154
- console.log("πŸš€ OPENING BROWSER:", url);
141
+ } catch {}
155
142
  opener(url);
156
143
  }
157
144
  clearInterval(poll);
158
145
  return;
159
146
  }
160
147
  lastReadySeen = isReadyNow;
161
- } catch (e) {
162
- console.log("Poll error:", e.message);
163
- }
148
+ } catch {}
164
149
  }, pollDelay);
165
150
 
166
151
  process.on("SIGINT", () => {
167
- console.log("\nπŸ‘‹ Exiting (dev server alive)");
168
152
  clearInterval(poll);
169
153
  process.exit(0);
170
154
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-ready",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Smart dev server launcher: errorβ†’AI search, successβ†’auto-open browser. Any CLI tool.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -20,7 +20,6 @@
20
20
  "license": "MIT",
21
21
  "dependencies": {
22
22
  "minimist": "^1.2.8",
23
- "open": "^10.1.0",
24
23
  "opener": "^1.5.2",
25
24
  "wait-on": "^8.0.1"
26
25
  },