devlinker 1.2.0__tar.gz → 1.2.1__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devlinker
3
- Version: 1.2.0
3
+ Version: 1.2.1
4
4
  Summary: AI-powered linking and automation tool
5
5
  Author-email: Mani <mani1028@users.noreply.github.com>
6
6
  Requires-Python: >=3.7
@@ -20,6 +20,9 @@ Dev Linker runs frontend and backend dev servers, proxies both through a single
20
20
  - Auto-detects backend runtime (Docker Compose, Dockerfile, Node, or Python)
21
21
  - Auto-starts Python/Node backends; Docker is manual by default for reliability
22
22
  - Detects common frontend/backend ports
23
+ - Supports Docker backend port auto-detection
24
+ - Works with dynamic container host ports
25
+ - No config needed for standard Flask/Docker flows
23
26
  - Serves both through one proxy at http://localhost:8000
24
27
  - Creates a public tunnel for sharing (Cloudflare first, ngrok fallback)
25
28
  - Terminal-first workflow
@@ -28,8 +31,8 @@ Dev Linker runs frontend and backend dev servers, proxies both through a single
28
31
  ## Project Structure
29
32
 
30
33
  ```text
31
- onelink/
32
- ├── onelink/
34
+ devlinker/
35
+ ├── devlinker/
33
36
  │ ├── __init__.py
34
37
  │ ├── main.py
35
38
  │ ├── runner.py
@@ -52,7 +55,7 @@ pip install .
52
55
  After publishing to PyPI:
53
56
 
54
57
  ```bash
55
- pip install dev-linker
58
+ pip install devlinker
56
59
  ```
57
60
 
58
61
  ## Run
@@ -64,8 +67,9 @@ devlinker
64
67
  Typical startup output:
65
68
 
66
69
  ```text
67
- Dev Linker v1.2.0
70
+ Dev Linker v0.2.0
68
71
 
72
+ [INFO] Mode: Auto (Flask + Docker detection)
69
73
  [INFO] Booting local services...
70
74
  [INFO] Detecting frontend/backend ports...
71
75
  [OK] Frontend -> 5173
@@ -76,14 +80,16 @@ Dev Linker v1.2.0
76
80
  [OK] Tunnel provider: Cloudflare
77
81
  [OK] Public URL:
78
82
  https://xxxx.trycloudflare.com
83
+ Tip: Press Ctrl+Click to open link
79
84
 
80
85
  [INFO] Share this link with collaborators.
81
86
 
82
- Dev Linker Ready
87
+ DevLinker Ready (in 2.4s)
83
88
  Frontend: http://localhost:5173
84
89
  Backend: http://localhost:5000
85
90
  Proxy: http://localhost:8000
86
- Public: https://xxxx.trycloudflare.com
91
+ PUBLIC URL: https://xxxx.trycloudflare.com
92
+ Tip: Press Ctrl+Click to open link
87
93
  ```
88
94
 
89
95
  Version check:
@@ -98,12 +104,24 @@ Optional overrides:
98
104
  devlinker --frontend 5173 --backend 5000
99
105
  ```
100
106
 
107
+ Backend override alias:
108
+
109
+ ```bash
110
+ devlinker --backend-port 3001
111
+ ```
112
+
101
113
  Enable Docker auto-start explicitly:
102
114
 
103
115
  ```bash
104
116
  devlinker --docker
105
117
  ```
106
118
 
119
+ Run local-only mode without tunnel:
120
+
121
+ ```bash
122
+ devlinker --no-tunnel
123
+ ```
124
+
107
125
  If port 8000 is already in use:
108
126
 
109
127
  ```bash
@@ -112,6 +130,11 @@ devlinker --frontend 5173 --backend 5000 --proxy-port 18000
112
130
 
113
131
  Default behavior also tries fallback ports automatically when 8000 is busy:
114
132
 
133
+ ```text
134
+ [WARN] Port 8000 in use
135
+ [INFO] Using proxy port: 8001
136
+ ```
137
+
115
138
  - 8001
116
139
  - 8002
117
140
  - 18000
@@ -128,6 +151,27 @@ Do not hardcode backend host URLs in frontend code.
128
151
 
129
152
  ## Backend Auto-Detection
130
153
 
154
+ Backend port detection runs in this order:
155
+
156
+ 1. Check localhost port 5000
157
+ 2. If not found, check Docker port mappings for `->5000/tcp`
158
+ 3. Use the mapped host port automatically
159
+ 4. If nothing is found, print next-step guidance and exit
160
+
161
+ Detection messages include source labels, for example:
162
+
163
+ ```text
164
+ [OK] Backend detected (Local) -> port 5000
165
+ ```
166
+
167
+ Example Docker dynamic-port message:
168
+
169
+ ```text
170
+ [WARN] Backend not found on port 5000
171
+ [INFO] Checking Docker containers...
172
+ [OK] Backend detected (Docker) -> port 32768
173
+ ```
174
+
131
175
  Dev Linker checks backend runtime in this order:
132
176
 
133
177
  1. Docker Compose (`backend/docker-compose.yml`, `docker-compose.yaml`, `compose.yml`, or `compose.yaml`)
@@ -8,6 +8,9 @@ Dev Linker runs frontend and backend dev servers, proxies both through a single
8
8
  - Auto-detects backend runtime (Docker Compose, Dockerfile, Node, or Python)
9
9
  - Auto-starts Python/Node backends; Docker is manual by default for reliability
10
10
  - Detects common frontend/backend ports
11
+ - Supports Docker backend port auto-detection
12
+ - Works with dynamic container host ports
13
+ - No config needed for standard Flask/Docker flows
11
14
  - Serves both through one proxy at http://localhost:8000
12
15
  - Creates a public tunnel for sharing (Cloudflare first, ngrok fallback)
13
16
  - Terminal-first workflow
@@ -16,8 +19,8 @@ Dev Linker runs frontend and backend dev servers, proxies both through a single
16
19
  ## Project Structure
17
20
 
18
21
  ```text
19
- onelink/
20
- ├── onelink/
22
+ devlinker/
23
+ ├── devlinker/
21
24
  │ ├── __init__.py
22
25
  │ ├── main.py
23
26
  │ ├── runner.py
@@ -40,7 +43,7 @@ pip install .
40
43
  After publishing to PyPI:
41
44
 
42
45
  ```bash
43
- pip install dev-linker
46
+ pip install devlinker
44
47
  ```
45
48
 
46
49
  ## Run
@@ -52,8 +55,9 @@ devlinker
52
55
  Typical startup output:
53
56
 
54
57
  ```text
55
- Dev Linker v1.2.0
58
+ Dev Linker v0.2.0
56
59
 
60
+ [INFO] Mode: Auto (Flask + Docker detection)
57
61
  [INFO] Booting local services...
58
62
  [INFO] Detecting frontend/backend ports...
59
63
  [OK] Frontend -> 5173
@@ -64,14 +68,16 @@ Dev Linker v1.2.0
64
68
  [OK] Tunnel provider: Cloudflare
65
69
  [OK] Public URL:
66
70
  https://xxxx.trycloudflare.com
71
+ Tip: Press Ctrl+Click to open link
67
72
 
68
73
  [INFO] Share this link with collaborators.
69
74
 
70
- Dev Linker Ready
75
+ DevLinker Ready (in 2.4s)
71
76
  Frontend: http://localhost:5173
72
77
  Backend: http://localhost:5000
73
78
  Proxy: http://localhost:8000
74
- Public: https://xxxx.trycloudflare.com
79
+ PUBLIC URL: https://xxxx.trycloudflare.com
80
+ Tip: Press Ctrl+Click to open link
75
81
  ```
76
82
 
77
83
  Version check:
@@ -86,12 +92,24 @@ Optional overrides:
86
92
  devlinker --frontend 5173 --backend 5000
87
93
  ```
88
94
 
95
+ Backend override alias:
96
+
97
+ ```bash
98
+ devlinker --backend-port 3001
99
+ ```
100
+
89
101
  Enable Docker auto-start explicitly:
90
102
 
91
103
  ```bash
92
104
  devlinker --docker
93
105
  ```
94
106
 
107
+ Run local-only mode without tunnel:
108
+
109
+ ```bash
110
+ devlinker --no-tunnel
111
+ ```
112
+
95
113
  If port 8000 is already in use:
96
114
 
97
115
  ```bash
@@ -100,6 +118,11 @@ devlinker --frontend 5173 --backend 5000 --proxy-port 18000
100
118
 
101
119
  Default behavior also tries fallback ports automatically when 8000 is busy:
102
120
 
121
+ ```text
122
+ [WARN] Port 8000 in use
123
+ [INFO] Using proxy port: 8001
124
+ ```
125
+
103
126
  - 8001
104
127
  - 8002
105
128
  - 18000
@@ -116,6 +139,27 @@ Do not hardcode backend host URLs in frontend code.
116
139
 
117
140
  ## Backend Auto-Detection
118
141
 
142
+ Backend port detection runs in this order:
143
+
144
+ 1. Check localhost port 5000
145
+ 2. If not found, check Docker port mappings for `->5000/tcp`
146
+ 3. Use the mapped host port automatically
147
+ 4. If nothing is found, print next-step guidance and exit
148
+
149
+ Detection messages include source labels, for example:
150
+
151
+ ```text
152
+ [OK] Backend detected (Local) -> port 5000
153
+ ```
154
+
155
+ Example Docker dynamic-port message:
156
+
157
+ ```text
158
+ [WARN] Backend not found on port 5000
159
+ [INFO] Checking Docker containers...
160
+ [OK] Backend detected (Docker) -> port 32768
161
+ ```
162
+
119
163
  Dev Linker checks backend runtime in this order:
120
164
 
121
165
  1. Docker Compose (`backend/docker-compose.yml`, `docker-compose.yaml`, `compose.yml`, or `compose.yaml`)
@@ -0,0 +1,16 @@
1
+ """Dev Linker package."""
2
+
3
+ try:
4
+ from importlib.metadata import version
5
+
6
+ __version__ = version("devlinker")
7
+ except Exception:
8
+ __version__ = "0.0.0"
9
+
10
+ __all__ = [
11
+ "main",
12
+ "runner",
13
+ "detector",
14
+ "proxy",
15
+ "tunnel",
16
+ ]
@@ -9,7 +9,7 @@ import click
9
9
  from . import __version__
10
10
  from .detector import check_port, detect_ports, is_vite_port
11
11
  from .proxy import start_proxy
12
- from .runner import start_servers
12
+ from .runner import detect_backend_port, start_servers
13
13
  from .tunnel import start_tunnel
14
14
 
15
15
 
@@ -30,7 +30,8 @@ def _select_proxy_port(requested_port: int) -> int:
30
30
 
31
31
  for candidate in (8001, 8002, 18000):
32
32
  if not _is_port_in_use(candidate):
33
- print(f"Port 8000 is busy. Falling back to proxy port {candidate}.")
33
+ print("[WARN] Port 8000 in use")
34
+ print(f"[INFO] Using proxy port: {candidate}")
34
35
  return candidate
35
36
 
36
37
  raise click.ClickException(
@@ -54,13 +55,15 @@ def _print_summary(
54
55
  backend_port: int,
55
56
  proxy_port: int,
56
57
  public_url: str | None,
58
+ startup_seconds: float,
57
59
  ) -> None:
58
- print("\nDev Linker Ready")
60
+ print(f"\nDevLinker Ready (in {startup_seconds:.1f}s)")
59
61
  print(f"Frontend: http://localhost:{frontend_port}")
60
62
  print(f"Backend: http://localhost:{backend_port}")
61
63
  print(f"Proxy: http://localhost:{proxy_port}")
62
64
  if public_url:
63
- print(f"Public: {public_url}")
65
+ print(f"PUBLIC URL: {public_url}")
66
+ print("Tip: Press Ctrl+Click to open link")
64
67
  else:
65
68
  print("Public: unavailable (local proxy still active)")
66
69
 
@@ -68,7 +71,14 @@ def _print_summary(
68
71
  @click.command()
69
72
  @click.version_option(version=__version__, prog_name="devlinker")
70
73
  @click.option("--frontend", type=int, default=None, help="Override detected frontend port.")
71
- @click.option("--backend", type=int, default=None, help="Override detected backend port.")
74
+ @click.option(
75
+ "--backend",
76
+ "--backend-port",
77
+ "backend_port_override",
78
+ type=int,
79
+ default=None,
80
+ help="Override detected backend port.",
81
+ )
72
82
  @click.option("--proxy-port", type=int, default=8000, show_default=True, help="Proxy listen port.")
73
83
  @click.option(
74
84
  "--docker",
@@ -76,19 +86,33 @@ def _print_summary(
76
86
  is_flag=True,
77
87
  help="Auto-start Docker backends (manual Docker is the default).",
78
88
  )
89
+ @click.option("--no-tunnel", is_flag=True, help="Skip public tunnel and run local proxy only.")
90
+ @click.option("--debug", is_flag=True, hidden=True, help="Enable debug logging.")
79
91
  def cli(
80
92
  frontend: int | None,
81
- backend: int | None,
93
+ backend_port_override: int | None,
82
94
  proxy_port: int,
83
95
  auto_start_docker: bool,
96
+ no_tunnel: bool,
97
+ debug: bool,
84
98
  ) -> None:
99
+ started = time.perf_counter()
85
100
  print(f"\nDev Linker v{__version__}")
101
+ print("[INFO] Mode: Auto (Flask + Docker detection)")
86
102
  print("[INFO] Booting local services...")
87
103
 
88
104
  start_servers(auto_start_docker=auto_start_docker)
89
105
 
106
+ backend_port = detect_backend_port(
107
+ default_port=5000,
108
+ override_port=backend_port_override,
109
+ debug=debug,
110
+ )
111
+ if backend_port is None:
112
+ raise SystemExit(1)
113
+
90
114
  print("[INFO] Detecting frontend/backend ports...")
91
- frontend_port, backend_port = detect_ports(frontend=frontend, backend=backend)
115
+ frontend_port, backend_port = detect_ports(frontend=frontend, backend=backend_port)
92
116
 
93
117
  if frontend_port is None:
94
118
  raise click.ClickException(
@@ -123,22 +147,32 @@ def cli(
123
147
 
124
148
  print(f"\n[OK] Proxy ready at http://localhost:{proxy_port}\n")
125
149
  warning_free_url: str | None = None
126
- try:
127
- print("[INFO] Opening public tunnel...")
128
- provider, public_url = start_tunnel(proxy_port)
129
- warning_free_url = _with_ngrok_skip_warning(public_url)
130
- provider_label = "Cloudflare" if provider == "cloudflare" else "ngrok"
131
- print(f"[OK] Tunnel provider: {provider_label}")
132
- print("[OK] Public URL:")
133
- print(f" {warning_free_url}\n")
134
- print("[INFO] Share this link with collaborators.")
135
- except RuntimeError as exc:
136
- print(f"[WARN] Tunnel failed: {exc}")
137
- print("[INFO] Next step: install cloudflared or configure ngrok auth.")
138
- print("[INFO] Tip: run 'ngrok config add-authtoken <token>' for ngrok fallback.")
139
- print(f"[OK] Continuing with local proxy at http://localhost:{proxy_port}")
140
-
141
- _print_summary(frontend_port, backend_port, proxy_port, warning_free_url)
150
+ if no_tunnel:
151
+ print("[INFO] Tunnel disabled by --no-tunnel; local proxy only.")
152
+ else:
153
+ try:
154
+ print("[INFO] Opening public tunnel...")
155
+ provider, public_url = start_tunnel(proxy_port)
156
+ warning_free_url = _with_ngrok_skip_warning(public_url)
157
+ provider_label = "Cloudflare" if provider == "cloudflare" else "ngrok"
158
+ print(f"[OK] Tunnel provider: {provider_label}")
159
+ print("[OK] Public URL:")
160
+ print(f" {warning_free_url}\n")
161
+ print("Tip: Press Ctrl+Click to open link")
162
+ print("[INFO] Share this link with collaborators.")
163
+ except RuntimeError as exc:
164
+ print(f"[WARN] Tunnel failed: {exc}")
165
+ print("[INFO] Next step: install cloudflared or configure ngrok auth.")
166
+ print("[INFO] Tip: run 'ngrok config add-authtoken <token>' for ngrok fallback.")
167
+ print(f"[OK] Continuing with local proxy at http://localhost:{proxy_port}")
168
+
169
+ _print_summary(
170
+ frontend_port,
171
+ backend_port,
172
+ proxy_port,
173
+ warning_free_url,
174
+ startup_seconds=time.perf_counter() - started,
175
+ )
142
176
 
143
177
  try:
144
178
  while True:
@@ -2,9 +2,12 @@ from __future__ import annotations
2
2
 
3
3
  import json
4
4
  import os
5
+ import re
5
6
  import shutil
7
+ import socket
6
8
  import subprocess
7
9
  import sys
10
+ import time
8
11
  from pathlib import Path
9
12
  from typing import List
10
13
 
@@ -22,6 +25,130 @@ def _log(level: str, message: str) -> None:
22
25
  print(f"{prefix} {message}")
23
26
 
24
27
 
28
+ def _debug_log(enabled: bool, message: str) -> None:
29
+ if enabled:
30
+ print(f"[DEBUG] {message}")
31
+
32
+
33
+ def is_port_open(port: int) -> bool:
34
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
35
+ sock.settimeout(1)
36
+ return sock.connect_ex(("localhost", port)) == 0
37
+
38
+
39
+ def _extract_host_port(ports_text: str, container_port: int) -> int | None:
40
+ # Covers typical Docker mappings: 0.0.0.0:32768->5000/tcp, [::]:32768->5000/tcp
41
+ pattern = rf"(?:0\.0\.0\.0|127\.0\.0\.1|\[::\]|::):(\d+)->{container_port}/tcp"
42
+ match = re.search(pattern, ports_text)
43
+ if match:
44
+ return int(match.group(1))
45
+ return None
46
+
47
+
48
+ def get_docker_backend_port(
49
+ default_container_port: int = 5000,
50
+ debug: bool = False,
51
+ ) -> tuple[int, str, int] | None:
52
+ try:
53
+ output = subprocess.check_output( # noqa: S603
54
+ ["docker", "ps", "--format", "{{.Names}}\t{{.Ports}}"],
55
+ stderr=subprocess.DEVNULL,
56
+ ).decode("utf-8", errors="ignore")
57
+ except Exception:
58
+ return None
59
+
60
+ _debug_log(debug, "docker ps port map output:")
61
+ if debug:
62
+ for raw_line in output.splitlines():
63
+ _debug_log(True, raw_line)
64
+
65
+ candidates: list[tuple[str, int]] = []
66
+ for line in output.splitlines():
67
+ stripped = line.strip()
68
+ if not stripped:
69
+ continue
70
+
71
+ if "\t" in stripped:
72
+ name, ports = stripped.split("\t", 1)
73
+ else:
74
+ parts = stripped.split(maxsplit=1)
75
+ if len(parts) != 2:
76
+ continue
77
+ name, ports = parts[0], parts[1]
78
+
79
+ host_port = _extract_host_port(ports, default_container_port)
80
+ if host_port is not None:
81
+ candidates.append((name, host_port))
82
+
83
+ if not candidates:
84
+ return None
85
+
86
+ # Prefer container names that look like backend services.
87
+ for name, port in candidates:
88
+ if "backend" in name.lower():
89
+ _debug_log(debug, f"Selected Docker backend container '{name}' on host port {port}")
90
+ return port, name, len(candidates)
91
+
92
+ # docker ps is already newest-first; fallback to first match.
93
+ name, port = candidates[0]
94
+ _debug_log(debug, f"Selected first Docker match '{name}' on host port {port}")
95
+ return port, name, len(candidates)
96
+
97
+
98
+ def _wait_for_port(port: int, retries: int = 5, delay_seconds: float = 1.0, debug: bool = False) -> bool:
99
+ for attempt in range(1, retries + 1):
100
+ if is_port_open(port):
101
+ return True
102
+ _debug_log(debug, f"Port {port} not open yet (attempt {attempt}/{retries})")
103
+ time.sleep(delay_seconds)
104
+ return False
105
+
106
+
107
+ def detect_backend_port(
108
+ default_port: int = 5000,
109
+ override_port: int | None = None,
110
+ debug: bool = False,
111
+ ) -> int | None:
112
+ started = time.perf_counter()
113
+
114
+ if override_port is not None:
115
+ _log("info", f"Using backend port override: {override_port}")
116
+ _log("info", f"Backend detected in {time.perf_counter() - started:.1f}s")
117
+ return override_port
118
+
119
+ _log("info", "Checking backend...")
120
+ _debug_log(debug, f"Scanned local port: {default_port}")
121
+ if is_port_open(default_port):
122
+ _log("ok", f"Backend detected (Local) -> port {default_port}")
123
+ _log("info", f"Backend detected in {time.perf_counter() - started:.1f}s")
124
+ return default_port
125
+
126
+ _log("warn", f"Backend not found on port {default_port}")
127
+ _log("info", "Checking Docker containers...")
128
+ _debug_log(debug, f"Scanned Docker container target port: {default_port}")
129
+
130
+ docker_match = get_docker_backend_port(default_container_port=default_port, debug=debug)
131
+ if docker_match is not None:
132
+ docker_port, container_name, match_count = docker_match
133
+ if match_count > 1:
134
+ _log("warn", "Multiple backend containers found")
135
+ _log("info", f"Using: {container_name}")
136
+ if _wait_for_port(docker_port, retries=5, delay_seconds=1.0, debug=debug):
137
+ _log("ok", f"Backend detected (Docker) -> port {docker_port}")
138
+ _log("info", f"Backend detected in {time.perf_counter() - started:.1f}s")
139
+ return docker_port
140
+ _log("warn", f"Docker mapped port {docker_port} found but backend is not ready yet")
141
+
142
+ _log("error", "Backend not detected")
143
+ print("Checked:")
144
+ print(f"- localhost:{default_port}")
145
+ print("- Docker containers")
146
+ print("Next step:")
147
+ print(" - Start Flask: python app.py")
148
+ print(" - OR expose Docker port: -p 5000:5000")
149
+ return None
150
+
151
+
25
152
  def _detect_backend_mode(backend_path: Path) -> str | None:
26
153
  compose_files = (
27
154
  "docker-compose.yml",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devlinker
3
- Version: 1.2.0
3
+ Version: 1.2.1
4
4
  Summary: AI-powered linking and automation tool
5
5
  Author-email: Mani <mani1028@users.noreply.github.com>
6
6
  Requires-Python: >=3.7
@@ -20,6 +20,9 @@ Dev Linker runs frontend and backend dev servers, proxies both through a single
20
20
  - Auto-detects backend runtime (Docker Compose, Dockerfile, Node, or Python)
21
21
  - Auto-starts Python/Node backends; Docker is manual by default for reliability
22
22
  - Detects common frontend/backend ports
23
+ - Supports Docker backend port auto-detection
24
+ - Works with dynamic container host ports
25
+ - No config needed for standard Flask/Docker flows
23
26
  - Serves both through one proxy at http://localhost:8000
24
27
  - Creates a public tunnel for sharing (Cloudflare first, ngrok fallback)
25
28
  - Terminal-first workflow
@@ -28,8 +31,8 @@ Dev Linker runs frontend and backend dev servers, proxies both through a single
28
31
  ## Project Structure
29
32
 
30
33
  ```text
31
- onelink/
32
- ├── onelink/
34
+ devlinker/
35
+ ├── devlinker/
33
36
  │ ├── __init__.py
34
37
  │ ├── main.py
35
38
  │ ├── runner.py
@@ -52,7 +55,7 @@ pip install .
52
55
  After publishing to PyPI:
53
56
 
54
57
  ```bash
55
- pip install dev-linker
58
+ pip install devlinker
56
59
  ```
57
60
 
58
61
  ## Run
@@ -64,8 +67,9 @@ devlinker
64
67
  Typical startup output:
65
68
 
66
69
  ```text
67
- Dev Linker v1.2.0
70
+ Dev Linker v0.2.0
68
71
 
72
+ [INFO] Mode: Auto (Flask + Docker detection)
69
73
  [INFO] Booting local services...
70
74
  [INFO] Detecting frontend/backend ports...
71
75
  [OK] Frontend -> 5173
@@ -76,14 +80,16 @@ Dev Linker v1.2.0
76
80
  [OK] Tunnel provider: Cloudflare
77
81
  [OK] Public URL:
78
82
  https://xxxx.trycloudflare.com
83
+ Tip: Press Ctrl+Click to open link
79
84
 
80
85
  [INFO] Share this link with collaborators.
81
86
 
82
- Dev Linker Ready
87
+ DevLinker Ready (in 2.4s)
83
88
  Frontend: http://localhost:5173
84
89
  Backend: http://localhost:5000
85
90
  Proxy: http://localhost:8000
86
- Public: https://xxxx.trycloudflare.com
91
+ PUBLIC URL: https://xxxx.trycloudflare.com
92
+ Tip: Press Ctrl+Click to open link
87
93
  ```
88
94
 
89
95
  Version check:
@@ -98,12 +104,24 @@ Optional overrides:
98
104
  devlinker --frontend 5173 --backend 5000
99
105
  ```
100
106
 
107
+ Backend override alias:
108
+
109
+ ```bash
110
+ devlinker --backend-port 3001
111
+ ```
112
+
101
113
  Enable Docker auto-start explicitly:
102
114
 
103
115
  ```bash
104
116
  devlinker --docker
105
117
  ```
106
118
 
119
+ Run local-only mode without tunnel:
120
+
121
+ ```bash
122
+ devlinker --no-tunnel
123
+ ```
124
+
107
125
  If port 8000 is already in use:
108
126
 
109
127
  ```bash
@@ -112,6 +130,11 @@ devlinker --frontend 5173 --backend 5000 --proxy-port 18000
112
130
 
113
131
  Default behavior also tries fallback ports automatically when 8000 is busy:
114
132
 
133
+ ```text
134
+ [WARN] Port 8000 in use
135
+ [INFO] Using proxy port: 8001
136
+ ```
137
+
115
138
  - 8001
116
139
  - 8002
117
140
  - 18000
@@ -128,6 +151,27 @@ Do not hardcode backend host URLs in frontend code.
128
151
 
129
152
  ## Backend Auto-Detection
130
153
 
154
+ Backend port detection runs in this order:
155
+
156
+ 1. Check localhost port 5000
157
+ 2. If not found, check Docker port mappings for `->5000/tcp`
158
+ 3. Use the mapped host port automatically
159
+ 4. If nothing is found, print next-step guidance and exit
160
+
161
+ Detection messages include source labels, for example:
162
+
163
+ ```text
164
+ [OK] Backend detected (Local) -> port 5000
165
+ ```
166
+
167
+ Example Docker dynamic-port message:
168
+
169
+ ```text
170
+ [WARN] Backend not found on port 5000
171
+ [INFO] Checking Docker containers...
172
+ [OK] Backend detected (Docker) -> port 32768
173
+ ```
174
+
131
175
  Dev Linker checks backend runtime in this order:
132
176
 
133
177
  1. Docker Compose (`backend/docker-compose.yml`, `docker-compose.yaml`, `compose.yml`, or `compose.yaml`)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "devlinker"
7
- version = "1.2.0"
7
+ version = "1.2.1"
8
8
  description = "AI-powered linking and automation tool"
9
9
  authors = [
10
10
  { name = "Mani", email = "mani1028@users.noreply.github.com" }
@@ -1,11 +0,0 @@
1
- """Dev Linker package."""
2
-
3
- __version__ = "1.2.0"
4
-
5
- __all__ = [
6
- "main",
7
- "runner",
8
- "detector",
9
- "proxy",
10
- "tunnel",
11
- ]
File without changes
File without changes
File without changes
File without changes