swarm-debug 0.1.0__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.
Files changed (39) hide show
  1. swarm_debug-0.1.0/PKG-INFO +237 -0
  2. swarm_debug-0.1.0/README.md +224 -0
  3. swarm_debug-0.1.0/backend/__init__.py +0 -0
  4. swarm_debug-0.1.0/backend/apps/__init__.py +0 -0
  5. swarm_debug-0.1.0/backend/apps/debugger/__init__.py +0 -0
  6. swarm_debug-0.1.0/backend/apps/debugger/debugger.py +83 -0
  7. swarm_debug-0.1.0/backend/apps/health/__init__.py +0 -0
  8. swarm_debug-0.1.0/backend/apps/health/health.py +33 -0
  9. swarm_debug-0.1.0/backend/config/Apps.py +48 -0
  10. swarm_debug-0.1.0/backend/config/__init__.py +0 -0
  11. swarm_debug-0.1.0/backend/core/DEFAULTS.py +29 -0
  12. swarm_debug-0.1.0/backend/core/Debugleton.py +87 -0
  13. swarm_debug-0.1.0/backend/core/__init__.py +0 -0
  14. swarm_debug-0.1.0/backend/core/data_dir.py +30 -0
  15. swarm_debug-0.1.0/backend/core/log/__init__.py +2 -0
  16. swarm_debug-0.1.0/backend/core/log/log_config.py +46 -0
  17. swarm_debug-0.1.0/backend/core/log/log_mode.py +13 -0
  18. swarm_debug-0.1.0/backend/core/models/DebugFile.py +28 -0
  19. swarm_debug-0.1.0/backend/core/models/Directory.py +216 -0
  20. swarm_debug-0.1.0/backend/core/models/File.py +29 -0
  21. swarm_debug-0.1.0/backend/core/models/__init__.py +4 -0
  22. swarm_debug-0.1.0/backend/core/models/project_scanner.py +153 -0
  23. swarm_debug-0.1.0/backend/core/utils/__init__.py +3 -0
  24. swarm_debug-0.1.0/backend/core/utils/color_adjuster.py +13 -0
  25. swarm_debug-0.1.0/backend/core/utils/debug_arg_parser.py +22 -0
  26. swarm_debug-0.1.0/backend/core/utils/path_mngr.py +15 -0
  27. swarm_debug-0.1.0/backend/debugger_gui_build/bundle.js +102 -0
  28. swarm_debug-0.1.0/backend/debugger_gui_build/bundle.js.LICENSE.txt +68 -0
  29. swarm_debug-0.1.0/backend/debugger_gui_build/index.html +1 -0
  30. swarm_debug-0.1.0/backend/main.py +40 -0
  31. swarm_debug-0.1.0/debug.py +57 -0
  32. swarm_debug-0.1.0/pyproject.toml +39 -0
  33. swarm_debug-0.1.0/setup.cfg +4 -0
  34. swarm_debug-0.1.0/swarm_debug.egg-info/PKG-INFO +237 -0
  35. swarm_debug-0.1.0/swarm_debug.egg-info/SOURCES.txt +37 -0
  36. swarm_debug-0.1.0/swarm_debug.egg-info/dependency_links.txt +1 -0
  37. swarm_debug-0.1.0/swarm_debug.egg-info/entry_points.txt +2 -0
  38. swarm_debug-0.1.0/swarm_debug.egg-info/requires.txt +6 -0
  39. swarm_debug-0.1.0/swarm_debug.egg-info/top_level.txt +2 -0
@@ -0,0 +1,237 @@
1
+ Metadata-Version: 2.4
2
+ Name: swarm-debug
3
+ Version: 0.1.0
4
+ Summary: A colorized, toggleable debug logger with a web GUI
5
+ License: MIT
6
+ Requires-Python: >=3.9
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: fastapi[standard]
9
+ Requires-Dist: typeguard>=4.4
10
+ Requires-Dist: uvicorn[standard]
11
+ Provides-Extra: dev
12
+ Requires-Dist: vulture; extra == "dev"
13
+
14
+ # swarm-debug
15
+
16
+ A drop-in replacement for `print()` debugging. Colorized, per-file toggleable output with a visual web GUI to control it all.
17
+
18
+ ```bash
19
+ pip install swarm-debug
20
+ ```
21
+
22
+ ## What it does
23
+
24
+ `debug()` works like `print()`, but every call is:
25
+
26
+ - **Colorized** -- each file gets its own color so you can visually separate output
27
+ - **Toggleable** -- turn debug output on/off per file or entire directories without touching code
28
+ - **Context-aware** -- automatically shows the calling function, class, variable name, and indentation level
29
+ - **Emoji-tagged** -- assign emojis to files for instant visual scanning
30
+ - **Error-aware** -- exceptions are auto-highlighted in red with a dedicated emoji
31
+
32
+ All configuration is managed through a web GUI. No config files to write, no decorators to add.
33
+
34
+ ## Usage
35
+
36
+ ### 1. Add `debug()` calls to your code
37
+
38
+ ```python
39
+ import debug
40
+
41
+ x = 42
42
+ debug(x)
43
+ # ⚫ [my_script.py] : x = 42
44
+
45
+ debug("loading config")
46
+ # ⚫ [my_script.py] : loading config
47
+
48
+ def process(data):
49
+ debug(data, len(data))
50
+ # ⚫ [MyClass.process] : data = [1, 2, 3]
51
+ # ⚫ [MyClass.process] : len(data) = 3
52
+ ```
53
+
54
+ Strings are rendered as italic labels. Everything else shows `name = value`. Errors are auto-detected and forced on in red regardless of toggle state.
55
+
56
+ ### 2. Launch the GUI
57
+
58
+ ```bash
59
+ debug-server
60
+ ```
61
+
62
+ Open [http://localhost:8324](http://localhost:8324). You'll see a file tree of your project showing every file that calls `debug()`. From there you can:
63
+
64
+ - Toggle files/directories on and off
65
+ - Assign custom colors per file or directory (children inherit from parents)
66
+ - Assign emojis for visual tagging
67
+ - Push/pull configuration changes
68
+ - Reset colors or emojis to defaults
69
+
70
+ The server scans whichever directory you launched it from. To point it at a different project:
71
+
72
+ ```bash
73
+ # Option A: cd into the project first
74
+ cd /path/to/my/project && debug-server
75
+
76
+ # Option B: set an env var
77
+ SWARM_DEBUG_ROOT=/path/to/my/project debug-server
78
+
79
+ # Option C: use the API
80
+ curl -X POST http://localhost:8324/api/debugger/root_dir \
81
+ -H "Content-Type: application/json" \
82
+ -d '{"root_dir": "/path/to/my/project"}'
83
+ ```
84
+
85
+ The root dir persists across restarts (saved to `~/.swarm-debug/root_dir.txt`).
86
+
87
+ ### Configuration storage
88
+
89
+ All runtime state lives in `~/.swarm-debug/`:
90
+
91
+ | File | Purpose |
92
+ |------|---------|
93
+ | `debug_toggles.json` | Per-file toggle, color, and emoji state |
94
+ | `root_dir.txt` | Persisted project root directory |
95
+ | `log_mode.txt` | Log output mode (`all`, `debug`, etc.) |
96
+ | `needs_resync.txt` | Internal flag for syncing state |
97
+
98
+ ### API endpoints
99
+
100
+ | Method | Endpoint | Description |
101
+ |--------|----------|-------------|
102
+ | GET | `/api/health/check` | Health check |
103
+ | GET | `/api/debugger/pull_structure` | Get file tree with toggle states |
104
+ | POST | `/api/debugger/push_structure` | Save toggle/color/emoji config |
105
+ | POST | `/api/debugger/reset_color` | Reset all colors to defaults |
106
+ | POST | `/api/debugger/reset_emoji` | Reset all emojis to defaults |
107
+ | GET | `/api/debugger/root_dir` | Get current project root |
108
+ | POST | `/api/debugger/root_dir` | Set project root (triggers resync) |
109
+
110
+ Full interactive docs at [http://localhost:8324/docs](http://localhost:8324/docs).
111
+
112
+ ---
113
+
114
+ ## Development (source)
115
+
116
+ ### Prerequisites
117
+
118
+ - Python 3.9+
119
+ - Node.js 18+
120
+
121
+ ### Running locally
122
+
123
+ Both services (backend on `:8324`, frontend dev server on `:3000`):
124
+
125
+ ```bash
126
+ bash run.sh
127
+ ```
128
+
129
+ Individually:
130
+
131
+ ```bash
132
+ bash backend/run.sh # FastAPI backend only
133
+ bash frontend/run.sh # Webpack dev server only
134
+ ```
135
+
136
+ ### Tech stack
137
+
138
+ | Layer | Tech |
139
+ |-------|------|
140
+ | Frontend | React 18, TypeScript, Webpack 5, MUI v7, Redux Toolkit, Framer Motion |
141
+ | Backend | FastAPI, Uvicorn, Python 3.9+ |
142
+ | Runtime types | typeguard (`@typechecked` on endpoints) |
143
+
144
+ ### Architecture
145
+
146
+ **Backend** uses a SubApp pattern -- each feature is a self-contained module with its own APIRouter and async lifespan, auto-mounted at `/api/{name}/`. SubApps are registered in `backend/config/Apps.py` and composed into the FastAPI app in `backend/main.py`.
147
+
148
+ **Frontend** uses a custom design token system layered on MUI, accessed via `useClaudeTokens()`. See `frontend/DESIGN.md` for the full spec.
149
+
150
+ **Debugleton** is a thread-safe singleton that holds the scanned project tree in memory and resyncs when the `needs_resync` flag is set (after any push from the GUI).
151
+
152
+ ### Project structure
153
+
154
+ ```
155
+ debugger/
156
+ ├── debug.py # The debug() function -- pip module entry point
157
+ ├── pyproject.toml # PyPI package config (swarm-debug)
158
+ ├── publish.sh # Build + publish to PyPI
159
+ ├── run.sh # Dev orchestrator: backend -> frontend
160
+ ├── ports.conf # Port configuration
161
+ ├── backend/
162
+ │ ├── main.py # FastAPI app, CORS, static file serving
163
+ │ ├── config/Apps.py # SubApp / MainApp framework
164
+ │ ├── apps/
165
+ │ │ ├── health/health.py # GET /api/health/check
166
+ │ │ └── debugger/debugger.py # All debugger API endpoints
167
+ │ ├── core/
168
+ │ │ ├── data_dir.py # ~/.swarm-debug/ path management
169
+ │ │ ├── DEFAULTS.py # Default values, get/set_root_dir
170
+ │ │ ├── Debugleton.py # Thread-safe singleton for project state
171
+ │ │ ├── models/
172
+ │ │ │ ├── File.py # Base file class
173
+ │ │ │ ├── DebugFile.py # File with color/toggle/emoji
174
+ │ │ │ ├── Directory.py # Recursive directory tree
175
+ │ │ │ └── project_scanner.py
176
+ │ │ ├── log/
177
+ │ │ │ ├── log_config.py # Custom logger with modes
178
+ │ │ │ └── log_mode.py # Read/write log mode
179
+ │ │ └── utils/
180
+ │ │ ├── color_adjuster.py
181
+ │ │ ├── debug_arg_parser.py
182
+ │ │ └── path_mngr.py
183
+ │ └── data/ # Legacy data dir (runtime state now in ~/.swarm-debug/)
184
+ └── frontend/
185
+ ├── package.json
186
+ ├── webpack.config.js
187
+ ├── DESIGN.md # Design system specification
188
+ └── src/
189
+ ├── index.tsx
190
+ ├── app/
191
+ │ ├── Main.tsx
192
+ │ ├── pages/Debugger/
193
+ │ └── components/ # Tree, SyncSection, EmojiPicker, SettingsModal
194
+ └── shared/
195
+ ├── state/ # Redux store, slice, thunks
196
+ ├── styles/ # Theme tokens
197
+ └── constants/
198
+ ```
199
+
200
+ ---
201
+
202
+ ## Publishing to PyPI
203
+
204
+ Everything is handled by a single script:
205
+
206
+ ```bash
207
+ # Publish to test.pypi.org (for testing)
208
+ ./publish.sh --test
209
+
210
+ # Publish to pypi.org (for real)
211
+ ./publish.sh --real
212
+ ```
213
+
214
+ The script will:
215
+ 1. Clean previous build artifacts
216
+ 2. Build the React frontend (`npm ci && npm run build`)
217
+ 3. Bundle the build into `backend/debugger_gui_build/`
218
+ 4. Build the Python sdist + wheel
219
+ 5. Upload via twine
220
+
221
+ ### Prerequisites for publishing
222
+
223
+ ```bash
224
+ pip install build twine
225
+ ```
226
+
227
+ You'll need a PyPI account and API token. Configure `~/.pypirc` or pass credentials when prompted by twine.
228
+
229
+ ### How the pip package works
230
+
231
+ When installed from PyPI, the pre-built React frontend is bundled inside the wheel at `backend/debugger_gui_build/`. The FastAPI server serves these static files alongside the API, so end users get both the GUI and the API on a single port (8324) with zero Node.js dependency.
232
+
233
+ The `debug` module uses a `sys.modules` trick to make itself callable -- `import debug` gives you a function, not a module. This means `debug(x)` works directly after import with no extra setup.
234
+
235
+ ## License
236
+
237
+ MIT
@@ -0,0 +1,224 @@
1
+ # swarm-debug
2
+
3
+ A drop-in replacement for `print()` debugging. Colorized, per-file toggleable output with a visual web GUI to control it all.
4
+
5
+ ```bash
6
+ pip install swarm-debug
7
+ ```
8
+
9
+ ## What it does
10
+
11
+ `debug()` works like `print()`, but every call is:
12
+
13
+ - **Colorized** -- each file gets its own color so you can visually separate output
14
+ - **Toggleable** -- turn debug output on/off per file or entire directories without touching code
15
+ - **Context-aware** -- automatically shows the calling function, class, variable name, and indentation level
16
+ - **Emoji-tagged** -- assign emojis to files for instant visual scanning
17
+ - **Error-aware** -- exceptions are auto-highlighted in red with a dedicated emoji
18
+
19
+ All configuration is managed through a web GUI. No config files to write, no decorators to add.
20
+
21
+ ## Usage
22
+
23
+ ### 1. Add `debug()` calls to your code
24
+
25
+ ```python
26
+ import debug
27
+
28
+ x = 42
29
+ debug(x)
30
+ # ⚫ [my_script.py] : x = 42
31
+
32
+ debug("loading config")
33
+ # ⚫ [my_script.py] : loading config
34
+
35
+ def process(data):
36
+ debug(data, len(data))
37
+ # ⚫ [MyClass.process] : data = [1, 2, 3]
38
+ # ⚫ [MyClass.process] : len(data) = 3
39
+ ```
40
+
41
+ Strings are rendered as italic labels. Everything else shows `name = value`. Errors are auto-detected and forced on in red regardless of toggle state.
42
+
43
+ ### 2. Launch the GUI
44
+
45
+ ```bash
46
+ debug-server
47
+ ```
48
+
49
+ Open [http://localhost:8324](http://localhost:8324). You'll see a file tree of your project showing every file that calls `debug()`. From there you can:
50
+
51
+ - Toggle files/directories on and off
52
+ - Assign custom colors per file or directory (children inherit from parents)
53
+ - Assign emojis for visual tagging
54
+ - Push/pull configuration changes
55
+ - Reset colors or emojis to defaults
56
+
57
+ The server scans whichever directory you launched it from. To point it at a different project:
58
+
59
+ ```bash
60
+ # Option A: cd into the project first
61
+ cd /path/to/my/project && debug-server
62
+
63
+ # Option B: set an env var
64
+ SWARM_DEBUG_ROOT=/path/to/my/project debug-server
65
+
66
+ # Option C: use the API
67
+ curl -X POST http://localhost:8324/api/debugger/root_dir \
68
+ -H "Content-Type: application/json" \
69
+ -d '{"root_dir": "/path/to/my/project"}'
70
+ ```
71
+
72
+ The root dir persists across restarts (saved to `~/.swarm-debug/root_dir.txt`).
73
+
74
+ ### Configuration storage
75
+
76
+ All runtime state lives in `~/.swarm-debug/`:
77
+
78
+ | File | Purpose |
79
+ |------|---------|
80
+ | `debug_toggles.json` | Per-file toggle, color, and emoji state |
81
+ | `root_dir.txt` | Persisted project root directory |
82
+ | `log_mode.txt` | Log output mode (`all`, `debug`, etc.) |
83
+ | `needs_resync.txt` | Internal flag for syncing state |
84
+
85
+ ### API endpoints
86
+
87
+ | Method | Endpoint | Description |
88
+ |--------|----------|-------------|
89
+ | GET | `/api/health/check` | Health check |
90
+ | GET | `/api/debugger/pull_structure` | Get file tree with toggle states |
91
+ | POST | `/api/debugger/push_structure` | Save toggle/color/emoji config |
92
+ | POST | `/api/debugger/reset_color` | Reset all colors to defaults |
93
+ | POST | `/api/debugger/reset_emoji` | Reset all emojis to defaults |
94
+ | GET | `/api/debugger/root_dir` | Get current project root |
95
+ | POST | `/api/debugger/root_dir` | Set project root (triggers resync) |
96
+
97
+ Full interactive docs at [http://localhost:8324/docs](http://localhost:8324/docs).
98
+
99
+ ---
100
+
101
+ ## Development (source)
102
+
103
+ ### Prerequisites
104
+
105
+ - Python 3.9+
106
+ - Node.js 18+
107
+
108
+ ### Running locally
109
+
110
+ Both services (backend on `:8324`, frontend dev server on `:3000`):
111
+
112
+ ```bash
113
+ bash run.sh
114
+ ```
115
+
116
+ Individually:
117
+
118
+ ```bash
119
+ bash backend/run.sh # FastAPI backend only
120
+ bash frontend/run.sh # Webpack dev server only
121
+ ```
122
+
123
+ ### Tech stack
124
+
125
+ | Layer | Tech |
126
+ |-------|------|
127
+ | Frontend | React 18, TypeScript, Webpack 5, MUI v7, Redux Toolkit, Framer Motion |
128
+ | Backend | FastAPI, Uvicorn, Python 3.9+ |
129
+ | Runtime types | typeguard (`@typechecked` on endpoints) |
130
+
131
+ ### Architecture
132
+
133
+ **Backend** uses a SubApp pattern -- each feature is a self-contained module with its own APIRouter and async lifespan, auto-mounted at `/api/{name}/`. SubApps are registered in `backend/config/Apps.py` and composed into the FastAPI app in `backend/main.py`.
134
+
135
+ **Frontend** uses a custom design token system layered on MUI, accessed via `useClaudeTokens()`. See `frontend/DESIGN.md` for the full spec.
136
+
137
+ **Debugleton** is a thread-safe singleton that holds the scanned project tree in memory and resyncs when the `needs_resync` flag is set (after any push from the GUI).
138
+
139
+ ### Project structure
140
+
141
+ ```
142
+ debugger/
143
+ ├── debug.py # The debug() function -- pip module entry point
144
+ ├── pyproject.toml # PyPI package config (swarm-debug)
145
+ ├── publish.sh # Build + publish to PyPI
146
+ ├── run.sh # Dev orchestrator: backend -> frontend
147
+ ├── ports.conf # Port configuration
148
+ ├── backend/
149
+ │ ├── main.py # FastAPI app, CORS, static file serving
150
+ │ ├── config/Apps.py # SubApp / MainApp framework
151
+ │ ├── apps/
152
+ │ │ ├── health/health.py # GET /api/health/check
153
+ │ │ └── debugger/debugger.py # All debugger API endpoints
154
+ │ ├── core/
155
+ │ │ ├── data_dir.py # ~/.swarm-debug/ path management
156
+ │ │ ├── DEFAULTS.py # Default values, get/set_root_dir
157
+ │ │ ├── Debugleton.py # Thread-safe singleton for project state
158
+ │ │ ├── models/
159
+ │ │ │ ├── File.py # Base file class
160
+ │ │ │ ├── DebugFile.py # File with color/toggle/emoji
161
+ │ │ │ ├── Directory.py # Recursive directory tree
162
+ │ │ │ └── project_scanner.py
163
+ │ │ ├── log/
164
+ │ │ │ ├── log_config.py # Custom logger with modes
165
+ │ │ │ └── log_mode.py # Read/write log mode
166
+ │ │ └── utils/
167
+ │ │ ├── color_adjuster.py
168
+ │ │ ├── debug_arg_parser.py
169
+ │ │ └── path_mngr.py
170
+ │ └── data/ # Legacy data dir (runtime state now in ~/.swarm-debug/)
171
+ └── frontend/
172
+ ├── package.json
173
+ ├── webpack.config.js
174
+ ├── DESIGN.md # Design system specification
175
+ └── src/
176
+ ├── index.tsx
177
+ ├── app/
178
+ │ ├── Main.tsx
179
+ │ ├── pages/Debugger/
180
+ │ └── components/ # Tree, SyncSection, EmojiPicker, SettingsModal
181
+ └── shared/
182
+ ├── state/ # Redux store, slice, thunks
183
+ ├── styles/ # Theme tokens
184
+ └── constants/
185
+ ```
186
+
187
+ ---
188
+
189
+ ## Publishing to PyPI
190
+
191
+ Everything is handled by a single script:
192
+
193
+ ```bash
194
+ # Publish to test.pypi.org (for testing)
195
+ ./publish.sh --test
196
+
197
+ # Publish to pypi.org (for real)
198
+ ./publish.sh --real
199
+ ```
200
+
201
+ The script will:
202
+ 1. Clean previous build artifacts
203
+ 2. Build the React frontend (`npm ci && npm run build`)
204
+ 3. Bundle the build into `backend/debugger_gui_build/`
205
+ 4. Build the Python sdist + wheel
206
+ 5. Upload via twine
207
+
208
+ ### Prerequisites for publishing
209
+
210
+ ```bash
211
+ pip install build twine
212
+ ```
213
+
214
+ You'll need a PyPI account and API token. Configure `~/.pypirc` or pass credentials when prompted by twine.
215
+
216
+ ### How the pip package works
217
+
218
+ When installed from PyPI, the pre-built React frontend is bundled inside the wheel at `backend/debugger_gui_build/`. The FastAPI server serves these static files alongside the API, so end users get both the GUI and the API on a single port (8324) with zero Node.js dependency.
219
+
220
+ The `debug` module uses a `sys.modules` trick to make itself callable -- `import debug` gives you a function, not a module. This means `debug(x)` works directly after import with no extra setup.
221
+
222
+ ## License
223
+
224
+ MIT
File without changes
File without changes
File without changes
@@ -0,0 +1,83 @@
1
+ import logging
2
+ import json
3
+ import os
4
+ from backend.config.Apps import SubApp
5
+ from backend.core.models.project_scanner import update_debug_toggles, dir_to_output_format
6
+ from backend.core.data_dir import NEEDS_RESYNC_FILE, TOGGLE_FILE as DEBUG_TOGGLE_FILE
7
+ from backend.core.DEFAULTS import get_root_dir, set_root_dir
8
+ from contextlib import asynccontextmanager
9
+ from fastapi.responses import JSONResponse
10
+ from typeguard import typechecked
11
+
12
+ log = logging.getLogger(__name__)
13
+
14
+
15
+ @asynccontextmanager
16
+ async def debugger_lifespan():
17
+ log.debug("debugger_lifespan START")
18
+ yield
19
+ log.debug("debugger_lifespan END")
20
+
21
+
22
+ debugger = SubApp("debugger", debugger_lifespan)
23
+
24
+
25
+ @debugger.router.get("/pull_structure")
26
+ @typechecked
27
+ async def pull_structure() -> JSONResponse:
28
+ log.info("GET /api/debugger/pull_structure")
29
+ scanned_dir = update_debug_toggles(save_to_file=True)
30
+ output = dir_to_output_format(scanned_dir)
31
+ return JSONResponse(content=output)
32
+
33
+
34
+ @debugger.router.post("/push_structure")
35
+ @typechecked
36
+ async def push_structure(data: dict) -> JSONResponse:
37
+ log.info("POST /api/debugger/push_structure")
38
+ project_structure = data['projectStructure']
39
+ with open(DEBUG_TOGGLE_FILE, 'w', encoding='utf-8') as file:
40
+ json.dump(project_structure, file, indent=4)
41
+ with open(NEEDS_RESYNC_FILE, 'w') as f:
42
+ f.write('1')
43
+ return JSONResponse(content={"status": "success"})
44
+
45
+
46
+ @debugger.router.post("/reset_color")
47
+ @typechecked
48
+ async def reset_color() -> JSONResponse:
49
+ log.info("POST /api/debugger/reset_color")
50
+ scanned_dir = update_debug_toggles(save_to_file=False)
51
+ scanned_dir.reset_colors()
52
+ output = dir_to_output_format(scanned_dir)
53
+ return JSONResponse(content=output)
54
+
55
+
56
+ @debugger.router.post("/reset_emoji")
57
+ @typechecked
58
+ async def reset_emoji() -> JSONResponse:
59
+ log.info("POST /api/debugger/reset_emoji")
60
+ scanned_dir = update_debug_toggles(save_to_file=False)
61
+ scanned_dir.reset_emojis()
62
+ output = dir_to_output_format(scanned_dir)
63
+ return JSONResponse(content=output)
64
+
65
+
66
+ @debugger.router.get("/root_dir")
67
+ @typechecked
68
+ async def get_root() -> JSONResponse:
69
+ log.info("GET /api/debugger/root_dir")
70
+ return JSONResponse(content={"root_dir": get_root_dir()})
71
+
72
+
73
+ @debugger.router.post("/root_dir")
74
+ @typechecked
75
+ async def set_root(data: dict) -> JSONResponse:
76
+ log.info("POST /api/debugger/root_dir")
77
+ path = data.get("root_dir", "")
78
+ if not path or not os.path.isdir(path):
79
+ return JSONResponse(content={"error": "Invalid directory path"}, status_code=400)
80
+ set_root_dir(path)
81
+ with open(NEEDS_RESYNC_FILE, 'w') as f:
82
+ f.write('1')
83
+ return JSONResponse(content={"root_dir": get_root_dir()})
File without changes
@@ -0,0 +1,33 @@
1
+ import logging
2
+ from backend.config.Apps import SubApp
3
+ from contextlib import asynccontextmanager
4
+ from fastapi.responses import PlainTextResponse
5
+ from typeguard import typechecked
6
+ from fastapi import status
7
+
8
+ log = logging.getLogger(__name__)
9
+
10
+ @asynccontextmanager
11
+ async def health_lifespan():
12
+ log.debug("health_lifespan START")
13
+ yield
14
+ log.debug("health_lifespan END")
15
+
16
+ health = SubApp("health", health_lifespan)
17
+
18
+ ######################################
19
+ # Health Check Endpoints #
20
+ ######################################
21
+
22
+ @health.router.get("/check")
23
+ @typechecked
24
+ async def check() -> PlainTextResponse:
25
+ log.info("Health check successful")
26
+ return PlainTextResponse(
27
+ content="OK",
28
+ status_code=status.HTTP_200_OK,
29
+ headers={
30
+ "Content-Type": "text/plain",
31
+ "Content-Length": "2"
32
+ }
33
+ )
@@ -0,0 +1,48 @@
1
+ import logging
2
+ import os
3
+ from fastapi import FastAPI, APIRouter
4
+ from uuid import uuid4
5
+ from typing import List
6
+ from contextlib import asynccontextmanager
7
+ from contextlib import AsyncExitStack
8
+ from typing import Callable
9
+
10
+ log = logging.getLogger(__name__)
11
+
12
+
13
+ class SubApp:
14
+ def __init__(self, name:str, lifespan:Callable):
15
+ log.debug("SubApp.__init__ START: %s", name)
16
+ self.id = uuid4()
17
+ self.name = name
18
+ self.prefix = f"/api/{name}"
19
+ self.lifespan = lifespan
20
+ self.router = APIRouter()
21
+ log.debug("SubApp.__init__ END")
22
+
23
+ def __str__(self):
24
+ return f"SubApp(name={self.name}, prefix={self.prefix}, id={self.id})"
25
+
26
+ class MainApp:
27
+ def __init__(self, sub_apps: List[SubApp]):
28
+ log.debug("MainApp.__init__ START")
29
+
30
+ @asynccontextmanager
31
+ async def lifespan(app: FastAPI):
32
+ async with AsyncExitStack() as stack:
33
+ for sub_app in sub_apps:
34
+ log.debug("Starting lifespan for sub_app: %s", sub_app.name)
35
+ await stack.enter_async_context(sub_app.lifespan())
36
+ port = os.environ.get("BACKEND_PORT", "8324")
37
+ print(f"\nCheck out the API docs at: http://127.0.0.1:{port}/docs\n")
38
+ yield
39
+
40
+ self.app = FastAPI(lifespan=lifespan)
41
+
42
+ for sub_app in sub_apps:
43
+ self.app.include_router(
44
+ sub_app.router,
45
+ prefix=sub_app.prefix,
46
+ tags=[sub_app.name]
47
+ )
48
+ log.debug("MainApp.__init__ END")
File without changes
@@ -0,0 +1,29 @@
1
+ import os
2
+ from backend.core.data_dir import TOGGLE_FILE, ROOT_DIR_FILE
3
+
4
+ DEFAULT_COLOR = '#ffffff'
5
+ DEFAULT_TOGGLED = False
6
+ DEFAULT_SET_MANUALLY = False
7
+ DEFAULT_SET_MANUALLY_EMOJI = False
8
+ DEFAULT_EMOJI = '⚫'
9
+
10
+
11
+ def get_root_dir() -> str:
12
+ """Priority: env var > persisted file > cwd."""
13
+ env = os.environ.get("SWARM_DEBUG_ROOT")
14
+ if env:
15
+ return os.path.abspath(env)
16
+
17
+ if os.path.exists(ROOT_DIR_FILE):
18
+ with open(ROOT_DIR_FILE, "r") as f:
19
+ saved = f.read().strip()
20
+ if saved:
21
+ return saved
22
+
23
+ return os.getcwd()
24
+
25
+
26
+ def set_root_dir(path: str):
27
+ path = os.path.abspath(path)
28
+ with open(ROOT_DIR_FILE, "w") as f:
29
+ f.write(path)