@ai-cortex/daemon 0.1.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.
- package/LICENSE +64 -0
- package/README.md +217 -0
- package/brain/cortex-brain.yaml +3 -0
- package/brain/entries/bash-permission-denied.md +100 -0
- package/brain/entries/cors-preflight.md +98 -0
- package/brain/entries/docker-port-conflict.md +99 -0
- package/brain/entries/env-vars-missing.md +107 -0
- package/brain/entries/git-merge-conflict.md +88 -0
- package/brain/entries/node-esm-import.md +71 -0
- package/brain/entries/npm-peer-deps.md +93 -0
- package/brain/entries/python-import-circular.md +112 -0
- package/brain/entries/python-import-resolution.md +83 -0
- package/brain/entries/python-venv-activate.md +98 -0
- package/brain/entries/react-stale-closure.md +76 -0
- package/brain/entries/sqlite-locked.md +110 -0
- package/brain/entries/typescript-strict-null.md +93 -0
- package/dist/bin/cortex-statusline.js +3 -0
- package/dist/dashboard/index.html +1616 -0
- package/dist/index.js +3 -0
- package/package.json +44 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
Business Source License 1.1
|
|
2
|
+
|
|
3
|
+
Parameters
|
|
4
|
+
|
|
5
|
+
Licensor: Cortex
|
|
6
|
+
Licensed Work: Cortex Daemon 0.1.0
|
|
7
|
+
The Licensed Work is (c) 2026 Cortex.
|
|
8
|
+
Additional Use Grant: You may make use of the Licensed Work, provided that
|
|
9
|
+
you may not use the Licensed Work for a Service that
|
|
10
|
+
competes with the Licensed Work. A "Service" is a
|
|
11
|
+
commercial offering that provides substantially the
|
|
12
|
+
same functionality as the Licensed Work to third
|
|
13
|
+
parties as a managed service, hosted solution, or
|
|
14
|
+
distributed product.
|
|
15
|
+
Change Date: 2030-03-21
|
|
16
|
+
Change License: Apache License, Version 2.0
|
|
17
|
+
|
|
18
|
+
For information about alternative licensing arrangements for the Licensed Work,
|
|
19
|
+
please contact the Licensor.
|
|
20
|
+
|
|
21
|
+
Notice
|
|
22
|
+
|
|
23
|
+
Business Source License 1.1
|
|
24
|
+
|
|
25
|
+
Terms
|
|
26
|
+
|
|
27
|
+
The Licensor hereby grants you the right to copy, modify, create derivative
|
|
28
|
+
works, redistribute, and make non-production use of the Licensed Work. The
|
|
29
|
+
Licensor may make an Additional Use Grant, above, permitting limited production
|
|
30
|
+
use.
|
|
31
|
+
|
|
32
|
+
Effective on the Change Date, or the fourth anniversary of the first publicly
|
|
33
|
+
available distribution of a specific version of the Licensed Work under this
|
|
34
|
+
License, whichever comes first, the Licensor hereby grants you rights under the
|
|
35
|
+
terms of the Change License, and the rights granted in the paragraph above
|
|
36
|
+
terminate.
|
|
37
|
+
|
|
38
|
+
If your use of the Licensed Work does not comply with the requirements currently
|
|
39
|
+
in effect as described in this License, you must purchase a commercial license
|
|
40
|
+
from the Licensor, its affiliated entities, or authorized resellers, or you must
|
|
41
|
+
refrain from using the Licensed Work.
|
|
42
|
+
|
|
43
|
+
All copies of the original and modified Licensed Work, and derivative works of
|
|
44
|
+
the Licensed Work, are subject to this License. This License applies separately
|
|
45
|
+
for each version of the Licensed Work and the Change Date may vary for each
|
|
46
|
+
version of the Licensed Work released by Licensor.
|
|
47
|
+
|
|
48
|
+
You must conspicuously display this License on each original or modified copy of
|
|
49
|
+
the Licensed Work. If you receive the Licensed Work in original or modified form
|
|
50
|
+
from a third party, the terms and conditions set forth in this License apply to
|
|
51
|
+
your use of that work.
|
|
52
|
+
|
|
53
|
+
Any use of the Licensed Work in violation of this License will automatically
|
|
54
|
+
terminate your rights under this License for the current and all other versions
|
|
55
|
+
of the Licensed Work.
|
|
56
|
+
|
|
57
|
+
This License does not grant you any right in any trademark or logo of Licensor
|
|
58
|
+
or its affiliates (provided that you may use a trademark or logo of Licensor as
|
|
59
|
+
expressly required by this License).
|
|
60
|
+
|
|
61
|
+
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN
|
|
62
|
+
"AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS
|
|
63
|
+
OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF MERCHANTABILITY,
|
|
64
|
+
FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND TITLE.
|
package/README.md
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# Cortex
|
|
2
|
+
|
|
3
|
+
A transparent API proxy daemon that makes LLM coding agents smarter. Set one environment variable and Cortex sits between your coding agent and the LLM provider — observing conversations, fingerprinting tasks, injecting relevant knowledge from a local brain directory, and tracking multi-agent sessions in real time.
|
|
4
|
+
|
|
5
|
+
## How It Works
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Claude Code / Cursor / Aider
|
|
9
|
+
│
|
|
10
|
+
▼
|
|
11
|
+
localhost:9090 ◄── Cortex daemon
|
|
12
|
+
│
|
|
13
|
+
│ 1. Detect & classify agent (main, subagent, teammate)
|
|
14
|
+
│ 2. Parse messages
|
|
15
|
+
│ 3. Prune verbose tool outputs (day-1 value)
|
|
16
|
+
│ 4. Fingerprint conversation (rules + semantic embedding)
|
|
17
|
+
│ 5. Match against brain directory (RRF fusion)
|
|
18
|
+
│ 6. Inject best match if confident
|
|
19
|
+
│
|
|
20
|
+
▼
|
|
21
|
+
api.anthropic.com
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Cortex never modifies responses — only request bodies. SSE streaming passes through raw and unmodified.
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Install dependencies
|
|
30
|
+
npm install
|
|
31
|
+
|
|
32
|
+
# Run the interactive setup wizard
|
|
33
|
+
npm run setup
|
|
34
|
+
|
|
35
|
+
# Start the daemon
|
|
36
|
+
npm run dev
|
|
37
|
+
|
|
38
|
+
# In another terminal, point your agent at Cortex
|
|
39
|
+
export ANTHROPIC_BASE_URL=http://localhost:9090
|
|
40
|
+
|
|
41
|
+
# Use your agent normally — Cortex works transparently
|
|
42
|
+
claude
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Day-1 Value
|
|
46
|
+
|
|
47
|
+
With zero configuration and an empty brain, Cortex provides **always-on pruning** of verbose tool outputs. Tool results over 500 tokens are automatically summarized (keeping the first and last 50 tokens with a summary line), reducing context bloat on every request.
|
|
48
|
+
|
|
49
|
+
## Brain Directory
|
|
50
|
+
|
|
51
|
+
The brain is a collection of Markdown files with YAML frontmatter in `brain/entries/`. Each entry is a solution, pattern, or fix that Cortex can inject when it detects a matching situation.
|
|
52
|
+
|
|
53
|
+
```yaml
|
|
54
|
+
---
|
|
55
|
+
id: node-esm-import
|
|
56
|
+
title: "Node.js ESM import resolution"
|
|
57
|
+
language: javascript
|
|
58
|
+
error_types: [ERR_MODULE_NOT_FOUND, "Cannot find module"]
|
|
59
|
+
tags: [debugging, imports, node, esm]
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
When you see ERR_MODULE_NOT_FOUND in an ESM project...
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Cortex ships with 13 seed entries covering common issues (ESM imports, Python venvs, CORS, merge conflicts, etc.). Add your own by dropping `.md` files into `brain/entries/`.
|
|
66
|
+
|
|
67
|
+
### Multi-Source Brain
|
|
68
|
+
|
|
69
|
+
Brain entries can come from multiple sources beyond local files:
|
|
70
|
+
- **local** — Markdown+YAML files from registered directories
|
|
71
|
+
- **cheat.sh** — Community-driven cheat sheets (1 req/sec throttle)
|
|
72
|
+
- **tldr** — Simplified man pages from GitHub
|
|
73
|
+
- **devdocs** — DevDocs API adapter
|
|
74
|
+
|
|
75
|
+
Manage sources with `cortex brain sources`.
|
|
76
|
+
|
|
77
|
+
## Intelligence Pipeline
|
|
78
|
+
|
|
79
|
+
1. **Fingerprinter** — Extracts features from the conversation: programming languages, error types, file types, conversation phase, and a 384-dim semantic embedding via BGE-small (local ONNX model).
|
|
80
|
+
|
|
81
|
+
2. **Matcher** — Two retrieval channels fused via Reciprocal Rank Fusion:
|
|
82
|
+
- CH1: Weighted Jaccard similarity on rule features (language, error types, tags)
|
|
83
|
+
- CH2: Cosine similarity on semantic embeddings
|
|
84
|
+
|
|
85
|
+
3. **Injector** — If the top match exceeds the confidence threshold (0.9), injects the brain entry content into the last user message wrapped in `<cortex_context>` tags. Max 16K chars (~4000 tokens).
|
|
86
|
+
|
|
87
|
+
## Agent Tracking
|
|
88
|
+
|
|
89
|
+
Cortex automatically detects and classifies agents passing through the proxy:
|
|
90
|
+
|
|
91
|
+
- **Main sessions** — Full Claude Code sessions with CLAUDE.md context and Agent tool
|
|
92
|
+
- **Subagents** — Specialized agents spawned by main sessions (shorter TTL)
|
|
93
|
+
- **Teammates** — Agents that are part of a Claude Code team
|
|
94
|
+
|
|
95
|
+
Agent classification uses heuristics (system prompt markers, tool count, model tier) and links children to parents via temporal ordering, team config, or content matching. View the live topology:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
cortex agents topology
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Claude Code Statusline
|
|
102
|
+
|
|
103
|
+
Cortex includes a statusline script for Claude Code that shows real-time pipeline status with gradient colors:
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
◆ Cortex ── Snagged a request ── [████████░░] 72% ── 12.4K saved ── 3 injections
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The statusline shows pipeline phase, context bar, tokens saved, and agent info. Enable it through `cortex setup` or configure manually in `~/.claude/settings.json`.
|
|
110
|
+
|
|
111
|
+
## Dashboard & Management API
|
|
112
|
+
|
|
113
|
+
Cortex runs a management API on port 9091 (configurable) with a built-in HTML dashboard:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
# Open dashboard
|
|
117
|
+
open http://localhost:9091
|
|
118
|
+
|
|
119
|
+
# API endpoints
|
|
120
|
+
curl http://localhost:9091/api/status
|
|
121
|
+
curl http://localhost:9091/api/brain/summary
|
|
122
|
+
curl http://localhost:9091/api/agents
|
|
123
|
+
curl http://localhost:9091/api/agents/topology
|
|
124
|
+
curl http://localhost:9091/api/statusline
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
SSE streams available at `/api/logs/stream` and `/api/pipeline/live`.
|
|
128
|
+
|
|
129
|
+
## CLI
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
cortex start [-d] [--port N] # Start daemon (foreground or detached)
|
|
133
|
+
cortex stop # Graceful shutdown
|
|
134
|
+
cortex status # Query running daemon or show config
|
|
135
|
+
cortex setup # Interactive config wizard (TUI)
|
|
136
|
+
cortex brain <subcommand> # list | search | stats | import | sources
|
|
137
|
+
cortex features <subcommand> # list | enable | disable
|
|
138
|
+
cortex logs [-n N] [--follow] # View or stream JSONL logs
|
|
139
|
+
cortex config <subcommand> # show | path | set (dotted key syntax)
|
|
140
|
+
cortex agents <subcommand> # list | topology | history | detail <id>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Configuration
|
|
144
|
+
|
|
145
|
+
Cortex reads from `~/.cortex/config.yaml` with sensible defaults:
|
|
146
|
+
|
|
147
|
+
```yaml
|
|
148
|
+
proxyPort: 9090
|
|
149
|
+
targetBaseUrl: "https://api.anthropic.com"
|
|
150
|
+
dashboardPort: 9091
|
|
151
|
+
brainDir: "./brain/entries"
|
|
152
|
+
dataDir: "~/.cortex"
|
|
153
|
+
pruneThresholdTokens: 500
|
|
154
|
+
injectionConfidenceThreshold: 0.9
|
|
155
|
+
rrfWeights:
|
|
156
|
+
featureOverlap: 0.5
|
|
157
|
+
semantic: 0.5
|
|
158
|
+
agentTracking:
|
|
159
|
+
maxActive: 1000
|
|
160
|
+
maxHistory: 100
|
|
161
|
+
subagentTtlMs: 300000 # 5 min
|
|
162
|
+
mainTtlMs: 3600000 # 1 hr
|
|
163
|
+
teammateTtlMs: 3600000 # 1 hr
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Environment overrides: `CORTEX_PORT`, `CORTEX_TARGET_URL`, `CORTEX_DASHBOARD_PORT`.
|
|
167
|
+
|
|
168
|
+
## Session Logs
|
|
169
|
+
|
|
170
|
+
Every request is logged as JSONL to `~/.cortex/logs/session-{date}.jsonl` with fingerprint data, match scores, injection decisions, agent classification, and processing time.
|
|
171
|
+
|
|
172
|
+
## Development
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
npm run dev # Start with tsx
|
|
176
|
+
npm run build # TypeScript compile
|
|
177
|
+
npm test # Run vitest (41 test files)
|
|
178
|
+
npx tsc --noEmit # Type-check
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**Note:** Embedding tests require single-fork mode due to ONNX model file locks:
|
|
182
|
+
```bash
|
|
183
|
+
npx vitest run --pool=forks --poolOptions.forks.singleFork
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Requirements
|
|
187
|
+
|
|
188
|
+
- Node.js 20+
|
|
189
|
+
- `better-sqlite3` requires native compilation (VS C++ build tools on Windows)
|
|
190
|
+
- First run downloads BGE-small ONNX model (~130MB) to `~/.cortex/models/`
|
|
191
|
+
|
|
192
|
+
## Project Structure
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
src/
|
|
196
|
+
├── proxy/ HTTP server, body buffering, HTTPS forwarding, SSE passthrough, token cache
|
|
197
|
+
├── context/ Message parser, token estimator, pruner, injector
|
|
198
|
+
├── fingerprint/ Rule extraction, BGE-small embedder, composite fingerprint
|
|
199
|
+
├── matcher/ Feature overlap, cosine similarity, RRF fusion
|
|
200
|
+
├── brain/ SQLite store, Markdown+YAML loader, multi-source adapters
|
|
201
|
+
├── agents/ Agent detection, classification, parent linking, team reader, state registry
|
|
202
|
+
├── core/ CortexCore orchestrator, event emitter, feature manager, accumulator, logger
|
|
203
|
+
├── cli/ Router, commands, console renderer, wizard, Claude settings bridge
|
|
204
|
+
├── api/ Management REST API + SSE streams
|
|
205
|
+
├── dashboard/ Static HTML dashboard
|
|
206
|
+
├── tui/ Interactive config screen (panels, fields, renderer)
|
|
207
|
+
├── statusline/ Pipeline phase phrases and gradient colors
|
|
208
|
+
└── types/ Shared type contracts (Anthropic API, Fingerprint, Brain, Agents, Events)
|
|
209
|
+
|
|
210
|
+
bin/cortex-statusline Node.js statusline script for Claude Code
|
|
211
|
+
brain/entries/ 13 seed brain entries (Markdown + YAML frontmatter)
|
|
212
|
+
tests/ Unit + integration tests (41 test files)
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## License
|
|
216
|
+
|
|
217
|
+
MIT
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: bash-permission-denied
|
|
3
|
+
title: "Bash permission denied errors"
|
|
4
|
+
language: bash
|
|
5
|
+
error_types: ["Permission denied", "EACCES"]
|
|
6
|
+
tags: [debugging, bash, permissions, linux]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Problem
|
|
10
|
+
|
|
11
|
+
Running a script or accessing a file fails with `Permission denied` or `EACCES`.
|
|
12
|
+
|
|
13
|
+
## Common Causes & Fixes
|
|
14
|
+
|
|
15
|
+
### 1. Script not executable
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
ls -la script.sh
|
|
19
|
+
# -rw-r--r-- (no x bit)
|
|
20
|
+
|
|
21
|
+
chmod +x script.sh
|
|
22
|
+
./script.sh # Now works
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### 2. Missing shebang
|
|
26
|
+
|
|
27
|
+
Even with the execute bit, the script needs a shebang line:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
#!/usr/bin/env bash
|
|
31
|
+
echo "Hello"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Without it, the OS does not know which interpreter to use. You can also run it explicitly:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
bash script.sh
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 3. Wrong ownership
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
ls -la /path/to/file
|
|
44
|
+
# Shows owner:group
|
|
45
|
+
|
|
46
|
+
# Change ownership
|
|
47
|
+
sudo chown $USER:$USER /path/to/file
|
|
48
|
+
|
|
49
|
+
# Or change just for the directory
|
|
50
|
+
sudo chown -R $USER:$USER /path/to/directory
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 4. File in a restricted directory
|
|
54
|
+
|
|
55
|
+
Directories need the execute bit (`x`) for traversal:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
chmod +x /path/to/directory
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 5. npm global install fails with EACCES
|
|
62
|
+
|
|
63
|
+
Do not use `sudo npm install -g`. Fix the npm prefix instead:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
mkdir -p ~/.npm-global
|
|
67
|
+
npm config set prefix '~/.npm-global'
|
|
68
|
+
# Add to ~/.bashrc or ~/.zshrc:
|
|
69
|
+
export PATH=~/.npm-global/bin:$PATH
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Or use `npx` to avoid global installs entirely.
|
|
73
|
+
|
|
74
|
+
### 6. Docker volume permission mismatch
|
|
75
|
+
|
|
76
|
+
Files created inside a container may have root ownership on the host:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
sudo chown -R $USER:$USER ./data
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Or run the container with your UID:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
docker run --user $(id -u):$(id -g) myimage
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## `sudo` vs `chown`
|
|
89
|
+
|
|
90
|
+
- **`sudo`** runs a single command as root — use for one-off admin tasks
|
|
91
|
+
- **`chown`** changes file ownership permanently — use when your user should own the file
|
|
92
|
+
- Prefer `chown` over repeatedly using `sudo` for files in your project
|
|
93
|
+
|
|
94
|
+
### Quick Checklist
|
|
95
|
+
|
|
96
|
+
- `ls -la` to check permissions and ownership
|
|
97
|
+
- `chmod +x` to add execute permission
|
|
98
|
+
- `chown $USER` to fix ownership
|
|
99
|
+
- Add shebang (`#!/usr/bin/env bash`) to scripts
|
|
100
|
+
- Never `sudo npm install -g` — fix npm prefix instead
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: cors-preflight
|
|
3
|
+
title: "CORS preflight errors"
|
|
4
|
+
language: javascript
|
|
5
|
+
error_types: ["CORS", "Access-Control-Allow-Origin", "preflight", "blocked by CORS policy"]
|
|
6
|
+
tags: [debugging, cors, http, api, express]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Problem
|
|
10
|
+
|
|
11
|
+
Browser blocks a request with `blocked by CORS policy`. The server does not include the correct `Access-Control-Allow-Origin` header, or the preflight OPTIONS request fails.
|
|
12
|
+
|
|
13
|
+
## What Is CORS
|
|
14
|
+
|
|
15
|
+
Cross-Origin Resource Sharing is a browser security feature. When JavaScript on `http://localhost:3000` calls an API on `http://localhost:8080`, the browser enforces CORS because the origins differ (different port = different origin).
|
|
16
|
+
|
|
17
|
+
The browser sends a **preflight** OPTIONS request first for non-simple requests (custom headers, PUT/DELETE, JSON content-type). The server must respond with the correct CORS headers.
|
|
18
|
+
|
|
19
|
+
## Fix: Express cors Middleware
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install cors
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
import cors from 'cors';
|
|
27
|
+
import express from 'express';
|
|
28
|
+
|
|
29
|
+
const app = express();
|
|
30
|
+
|
|
31
|
+
// Allow all origins (development only)
|
|
32
|
+
app.use(cors());
|
|
33
|
+
|
|
34
|
+
// Or restrict to specific origins (production)
|
|
35
|
+
app.use(cors({
|
|
36
|
+
origin: ['http://localhost:3000', 'https://myapp.com'],
|
|
37
|
+
methods: ['GET', 'POST', 'PUT', 'DELETE'],
|
|
38
|
+
allowedHeaders: ['Content-Type', 'Authorization'],
|
|
39
|
+
credentials: true,
|
|
40
|
+
}));
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Fix: Manual Headers
|
|
44
|
+
|
|
45
|
+
If you cannot use the middleware:
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
app.use((req, res, next) => {
|
|
49
|
+
res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
|
|
50
|
+
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
|
|
51
|
+
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
|
52
|
+
res.header('Access-Control-Allow-Credentials', 'true');
|
|
53
|
+
if (req.method === 'OPTIONS') {
|
|
54
|
+
return res.sendStatus(204);
|
|
55
|
+
}
|
|
56
|
+
next();
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The key: you must handle the OPTIONS method and return the headers.
|
|
61
|
+
|
|
62
|
+
## Fix: Dev Proxy (Avoids CORS Entirely)
|
|
63
|
+
|
|
64
|
+
Use your frontend dev server to proxy API requests — same origin, no CORS:
|
|
65
|
+
|
|
66
|
+
**Vite:**
|
|
67
|
+
|
|
68
|
+
```javascript
|
|
69
|
+
// vite.config.js
|
|
70
|
+
export default {
|
|
71
|
+
server: {
|
|
72
|
+
proxy: {
|
|
73
|
+
'/api': 'http://localhost:8080',
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Create React App:**
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"proxy": "http://localhost:8080"
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Common Gotchas
|
|
88
|
+
|
|
89
|
+
- `credentials: true` requires a specific origin — `*` is not allowed with credentials
|
|
90
|
+
- The `Origin` header is set by the browser and cannot be overridden by JavaScript
|
|
91
|
+
- CORS errors in the console mean the server is wrong, not the client
|
|
92
|
+
|
|
93
|
+
### Quick Checklist
|
|
94
|
+
|
|
95
|
+
- Install and configure `cors` middleware
|
|
96
|
+
- Handle OPTIONS preflight requests
|
|
97
|
+
- Use a dev proxy to avoid CORS during development
|
|
98
|
+
- Set specific origins (not `*`) when using credentials
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: docker-port-conflict
|
|
3
|
+
title: "Docker and system port conflicts"
|
|
4
|
+
language: general
|
|
5
|
+
error_types: ["address already in use", "port is already allocated", "EADDRINUSE"]
|
|
6
|
+
tags: [debugging, docker, networking, ports]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Problem
|
|
10
|
+
|
|
11
|
+
Starting a server or container fails with `address already in use`, `port is already allocated`, or `EADDRINUSE`. Another process is already listening on that port.
|
|
12
|
+
|
|
13
|
+
## Find What Is Using the Port
|
|
14
|
+
|
|
15
|
+
### Linux / macOS
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
lsof -i :3000
|
|
19
|
+
# or
|
|
20
|
+
ss -tlnp | grep 3000
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Windows
|
|
24
|
+
|
|
25
|
+
```powershell
|
|
26
|
+
netstat -ano | findstr :3000
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Docker specifically
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
docker ps --format "table {{.Names}}\t{{.Ports}}"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Kill the Process
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Using the PID from lsof output
|
|
39
|
+
kill -9 <PID>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Or stop a Docker container:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
docker stop <container-name>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Fix Docker Port Mapping
|
|
49
|
+
|
|
50
|
+
If two containers or a container and a host process collide, change the host port mapping:
|
|
51
|
+
|
|
52
|
+
```yaml
|
|
53
|
+
# docker-compose.yml
|
|
54
|
+
services:
|
|
55
|
+
web:
|
|
56
|
+
ports:
|
|
57
|
+
- "3001:3000" # Changed host port from 3000 to 3001
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Or on the command line:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
docker run -p 3001:3000 myimage
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The format is `HOST:CONTAINER` — change the left side to an available port.
|
|
67
|
+
|
|
68
|
+
## Prevent Recurring Conflicts
|
|
69
|
+
|
|
70
|
+
1. **Use `.env` for port config** so different developers can use different ports:
|
|
71
|
+
|
|
72
|
+
```env
|
|
73
|
+
PORT=3000
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
```yaml
|
|
77
|
+
ports:
|
|
78
|
+
- "${PORT}:3000"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
2. **Stop old containers** before starting new ones:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
docker compose down
|
|
85
|
+
docker compose up -d
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
3. **Check before starting:**
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
lsof -i :3000 || echo "Port 3000 is free"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Quick Checklist
|
|
95
|
+
|
|
96
|
+
- `lsof -i :PORT` to find the conflicting process
|
|
97
|
+
- `kill -9 <PID>` or `docker stop` to free the port
|
|
98
|
+
- Change the host port mapping if both services need to run
|
|
99
|
+
- `docker compose down` before `up` to avoid stale containers
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: env-vars-missing
|
|
3
|
+
title: "Environment variables not loading"
|
|
4
|
+
language: general
|
|
5
|
+
error_types: ["undefined", "env var not set", "missing environment variable", "ENOENT .env"]
|
|
6
|
+
tags: [debugging, env, dotenv, configuration]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Problem
|
|
10
|
+
|
|
11
|
+
Application reads `undefined` for environment variables that should be set. The `.env` file exists but values are not reaching the process.
|
|
12
|
+
|
|
13
|
+
## Fix by Runtime
|
|
14
|
+
|
|
15
|
+
### Node.js (dotenv)
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install dotenv
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
// At the very top of your entry point
|
|
23
|
+
import 'dotenv/config';
|
|
24
|
+
|
|
25
|
+
console.log(process.env.DATABASE_URL);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or with Node 20.6+, use the built-in flag:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
node --env-file=.env src/index.js
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Python
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install python-dotenv
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
from dotenv import load_dotenv
|
|
42
|
+
import os
|
|
43
|
+
|
|
44
|
+
load_dotenv() # Reads .env from current directory
|
|
45
|
+
|
|
46
|
+
db_url = os.environ["DATABASE_URL"]
|
|
47
|
+
# or with a default:
|
|
48
|
+
db_url = os.environ.get("DATABASE_URL", "sqlite:///local.db")
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Shell
|
|
52
|
+
|
|
53
|
+
Variables in `.env` are not automatically exported. Source the file:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
export $(grep -v '^#' .env | xargs)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Or set inline:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
export DATABASE_URL=postgres://localhost:5432/mydb
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Add to `~/.bashrc` or `~/.zshrc` for persistence across sessions.
|
|
66
|
+
|
|
67
|
+
### Docker
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
docker run --env-file .env myimage
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
```yaml
|
|
74
|
+
# docker-compose.yml
|
|
75
|
+
services:
|
|
76
|
+
app:
|
|
77
|
+
env_file:
|
|
78
|
+
- .env
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## `.env` File Format
|
|
82
|
+
|
|
83
|
+
```env
|
|
84
|
+
# Comments start with #
|
|
85
|
+
DATABASE_URL=postgres://localhost:5432/mydb
|
|
86
|
+
API_KEY=sk-abc123
|
|
87
|
+
NODE_ENV=development
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Rules:
|
|
91
|
+
- No spaces around `=`
|
|
92
|
+
- No quotes needed (unless value contains spaces)
|
|
93
|
+
- One variable per line
|
|
94
|
+
- Lines starting with `#` are comments
|
|
95
|
+
|
|
96
|
+
## Common Gotchas
|
|
97
|
+
|
|
98
|
+
- `.env` is not committed to git — make sure it exists locally (use `.env.example` as a template)
|
|
99
|
+
- `dotenv` must be imported before any code that reads `process.env`
|
|
100
|
+
- Docker Compose interpolates `${VAR}` in `docker-compose.yml` from the host `.env`, not the container's
|
|
101
|
+
|
|
102
|
+
### Quick Checklist
|
|
103
|
+
|
|
104
|
+
- Verify `.env` file exists and has correct format
|
|
105
|
+
- Load dotenv at the top of entry point
|
|
106
|
+
- Use `--env-file` for Docker
|
|
107
|
+
- `export` for shell — variables are not exported by default
|