auto-context-cli 1.0.3__tar.gz → 1.0.5__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. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/PKG-INFO +2 -2
  2. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/README.md +1 -1
  3. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/pyproject.toml +1 -1
  4. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/__init__.py +1 -1
  5. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/commands/init_cmd.py +11 -0
  6. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/commands/scan_cmd.py +9 -3
  7. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/main.py +1 -1
  8. auto_context_cli-1.0.5/src/auto_context/scanner.py +421 -0
  9. auto_context_cli-1.0.5/src/auto_context/templates/AGENTS.template.md +47 -0
  10. auto_context_cli-1.0.5/src/auto_context/templates/GEMINI.template.md +47 -0
  11. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/templates/context.template.md +1 -2
  12. auto_context_cli-1.0.5/src/auto_context/templates/maintain_context.template.md +48 -0
  13. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/templates/rules/hub-satellite-architecture.md +1 -0
  14. auto_context_cli-1.0.3/src/auto_context/scanner.py +0 -297
  15. auto_context_cli-1.0.3/src/auto_context/templates/AGENTS.template.md +0 -53
  16. auto_context_cli-1.0.3/src/auto_context/templates/GEMINI.template.md +0 -53
  17. auto_context_cli-1.0.3/src/auto_context/templates/maintain_context.template.md +0 -37
  18. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/.gitignore +0 -0
  19. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/LICENSE +0 -0
  20. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/commands/__init__.py +0 -0
  21. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/commands/import_cmd.py +0 -0
  22. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/commands/mcp.py +0 -0
  23. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/commands/memory.py +0 -0
  24. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/commands/share.py +0 -0
  25. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/commands/update_cmd.py +0 -0
  26. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/config.py +0 -0
  27. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/security.py +0 -0
  28. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/templates/context.local.template.md +0 -0
  29. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/templates/mcp_config.template.json +0 -0
  30. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/templates/profile.template.md +0 -0
  31. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/templates/rule.template.md +0 -0
  32. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/templates/rules/code-standards.md +0 -0
  33. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/templates/rules/readme-docs-sync.md +0 -0
  34. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/templates/rules/security-boundaries.md +0 -0
  35. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/templates/skill.template.md +0 -0
  36. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/templates/skills/browser-testing/SKILL.md +0 -0
  37. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/templates/skills/docker-ops/SKILL.md +0 -0
  38. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/templates/skills/git-workflow/SKILL.md +0 -0
  39. {auto_context_cli-1.0.3 → auto_context_cli-1.0.5}/src/auto_context/templates/skills/server-diagnostics/SKILL.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: auto-context-cli
3
- Version: 1.0.3
3
+ Version: 1.0.5
4
4
  Summary: Autonomous context & instruction manager for AI coding assistants
5
5
  Author: Arghya Biswas
6
6
  License: MIT
@@ -20,7 +20,7 @@ Description-Content-Type: text/markdown
20
20
 
21
21
  [![PyPI - Version](https://img.shields.io/pypi/v/auto-context-cli.svg?color=blue)](https://pypi.org/project/auto-context-cli/)
22
22
  [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/auto-context-cli.svg)](https://pypi.org/project/auto-context-cli/)
23
- [![GitHub Release](https://img.shields.io/github/v/release/Cyber-arghya/auto-context?color=green)](https://github.com/Cyber-arghya/auto-context/releases/tag/v1.0.3)
23
+ [![GitHub Release](https://img.shields.io/github/v/release/Cyber-arghya/auto-context?color=green)](https://github.com/Cyber-arghya/auto-context/releases/tag/v1.0.5)
24
24
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
25
25
  [![Platform](https://img.shields.io/badge/Platform-Windows%20%7C%20macOS%20%7C%20Linux%20WSL2-success.svg)](#-quick-one-line-install)
26
26
  [![AI Supported](https://img.shields.io/badge/AI%20Supported-Antigravity%20%7C%20Cursor%20%7C%20Claude%20Code%20%7C%20Copilot%20%7C%20Windsurf-orange.svg)](#-supported-ai-assistants)
@@ -6,7 +6,7 @@
6
6
 
7
7
  [![PyPI - Version](https://img.shields.io/pypi/v/auto-context-cli.svg?color=blue)](https://pypi.org/project/auto-context-cli/)
8
8
  [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/auto-context-cli.svg)](https://pypi.org/project/auto-context-cli/)
9
- [![GitHub Release](https://img.shields.io/github/v/release/Cyber-arghya/auto-context?color=green)](https://github.com/Cyber-arghya/auto-context/releases/tag/v1.0.3)
9
+ [![GitHub Release](https://img.shields.io/github/v/release/Cyber-arghya/auto-context?color=green)](https://github.com/Cyber-arghya/auto-context/releases/tag/v1.0.5)
10
10
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
11
11
  [![Platform](https://img.shields.io/badge/Platform-Windows%20%7C%20macOS%20%7C%20Linux%20WSL2-success.svg)](#-quick-one-line-install)
12
12
  [![AI Supported](https://img.shields.io/badge/AI%20Supported-Antigravity%20%7C%20Cursor%20%7C%20Claude%20Code%20%7C%20Copilot%20%7C%20Windsurf-orange.svg)](#-supported-ai-assistants)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "auto-context-cli"
3
- version = "1.0.3"
3
+ version = "1.0.5"
4
4
  description = "Autonomous context & instruction manager for AI coding assistants"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -1,3 +1,3 @@
1
1
  """auto-context: Autonomous context & instruction manager for AI coding assistants."""
2
2
 
3
- __version__ = "1.0.3"
3
+ __version__ = "1.0.5"
@@ -102,6 +102,17 @@ def detect_stack(project_dir: Path) -> tuple[str, str]:
102
102
 
103
103
  return stack, "Standard"
104
104
 
105
+ # Fallback: check immediate child directories if current folder has no manifest
106
+ try:
107
+ for child in project_dir.iterdir():
108
+ if child.is_dir() and not child.name.startswith((".", "node_modules", "venv", "__pycache__")):
109
+ for filename, stack, kind in config.STACK_INDICATORS:
110
+ if (child / filename).exists():
111
+ sub_stack, sub_fw = detect_stack(child)
112
+ return f"{sub_stack} (in {child.name}/)", sub_fw
113
+ except Exception:
114
+ pass
115
+
105
116
  return "General / Multi-stack", "Not detected"
106
117
 
107
118
 
@@ -59,15 +59,20 @@ def scan(
59
59
  for svc, port, src in ports:
60
60
  ports_table += f"| **{svc}** | `{port}` | {src} |\n"
61
61
  else:
62
- ports_table += "| **App Port** | `3000` (Default) | Inferred |\n"
62
+ is_web = any(w in (stack + framework).lower() for w in ("next", "react", "vue", "express", "fastapi", "flask", "django", "node", "web", "nest", "svelte"))
63
+ if is_web:
64
+ ports_table += "| **App Port** | `3000` (Default) | Inferred web port |\n"
65
+ else:
66
+ ports_table += "| **Network Ports** | `None` | CLI / Library (No local server ports detected) |\n"
63
67
 
64
- # Build runbook table
68
+ # Build runbook table (Strictly verified executable commands, zero hallucinated fallbacks)
65
69
  runbook_table = "| Task | Executable Command |\n| :--- | :--- |\n"
66
70
  if commands:
67
71
  for action, cmd in commands:
68
72
  runbook_table += f"| {action} | `{cmd}` |\n"
69
73
  else:
70
- runbook_table += "| Start Development | `npm run dev` / `python main.py` |\n"
74
+ runbook_table += "| Project Runbook | No startup scripts declared in manifests |\n"
75
+ runbook_table += "| Rescan Codebase | `init-context scan` |\n"
71
76
 
72
77
  # Build satellites index section
73
78
  satellites_index = ""
@@ -131,3 +136,4 @@ def scan(
131
136
  f"• Hub size (context.md): [bold green]< 60 lines (Token Optimized)[/]",
132
137
  border_style="green",
133
138
  ))
139
+
@@ -69,7 +69,7 @@ def root(
69
69
  try:
70
70
  v = pkg_version("auto-context")
71
71
  except Exception:
72
- v = "1.0.3"
72
+ v = "1.0.5"
73
73
  console.print(f"init-context v{v}")
74
74
  raise typer.Exit()
75
75
 
@@ -0,0 +1,421 @@
1
+ """
2
+ scanner.py — Stack-Adaptive Codebase Introspection & Brownfield Discovery Engine.
3
+
4
+ Discovers ports, routes, database schemas, services, and runbooks using lightweight
5
+ filesystem convention heuristics (0 LLM tokens, 100% crash-proof, idempotency-guaranteed).
6
+ """
7
+ import hashlib
8
+ import json
9
+ from pathlib import Path
10
+ import re
11
+ from typing import Optional
12
+ try:
13
+ import tomllib
14
+ except ImportError:
15
+ try:
16
+ import tomli as tomllib # type: ignore
17
+ except ImportError:
18
+ tomllib = None
19
+
20
+ from rich.console import Console
21
+
22
+ console = Console()
23
+
24
+
25
+ # ── Idempotency & Hash Helpers ────────────────────────────────────────────────
26
+
27
+ def get_content_hash(text: str) -> str:
28
+ """Compute SHA-256 hash of text content."""
29
+ return hashlib.sha256(text.encode("utf-8")).hexdigest()
30
+
31
+
32
+ def write_idempotent(path: Path, content: str, label: str = "File") -> bool:
33
+ """
34
+ Write content to path only if content has changed (Content-Hash Guard).
35
+ Returns True if a write occurred, False if content was already identical.
36
+ """
37
+ if path.exists():
38
+ try:
39
+ existing = path.read_text(encoding="utf-8")
40
+ if get_content_hash(existing) == get_content_hash(content):
41
+ console.print(f" [dim]— Up to date:[/] {path.name}")
42
+ return False
43
+ except Exception:
44
+ pass
45
+
46
+ path.parent.mkdir(parents=True, exist_ok=True)
47
+ path.write_text(content, encoding="utf-8")
48
+ console.print(f" [green][✓] Synchronized:[/] {path.name}")
49
+ return True
50
+
51
+
52
+ def _get_project_search_roots(project_dir: Path) -> list[Path]:
53
+ """
54
+ Returns [project_dir] plus any immediate child directories containing manifests.
55
+ Guards against scanning dependencies or virtual environments.
56
+ """
57
+ roots = [project_dir]
58
+ ignore_names = {
59
+ "node_modules", ".git", ".venv", "venv", "__pycache__",
60
+ ".agents", ".gemini", "dist", "build", "site-packages", ".idea", ".vscode"
61
+ }
62
+ manifest_names = {
63
+ "package.json", "pyproject.toml", "Makefile", "manage.py",
64
+ "Cargo.toml", "go.mod", "docker-compose.yml", "compose.yaml", "requirements.txt"
65
+ }
66
+ try:
67
+ for child in project_dir.iterdir():
68
+ if child.is_dir() and child.name not in ignore_names and not child.name.startswith("."):
69
+ if any((child / m).exists() for m in manifest_names):
70
+ roots.append(child)
71
+ except Exception:
72
+ pass
73
+ return roots
74
+
75
+
76
+ # ── Port & Service Extractor ──────────────────────────────────────────────────
77
+
78
+ def discover_ports_and_services(project_dir: Path) -> list[tuple[str, str, str]]:
79
+ """
80
+ Extract network ports and service bindings from configs without leaking secrets.
81
+ Returns list of (Service, Port, SourceFile).
82
+ """
83
+ results: list[tuple[str, str, str]] = []
84
+ seen_ports: set[str] = set()
85
+
86
+ for d in _get_project_search_roots(project_dir):
87
+ # 1. Check docker-compose.yml / compose.yaml
88
+ for compose_name in ("docker-compose.yml", "docker-compose.yaml", "compose.yml", "compose.yaml"):
89
+ compose_file = d / compose_name
90
+ if compose_file.exists():
91
+ try:
92
+ text = compose_file.read_text(encoding="utf-8", errors="ignore")
93
+ matches = re.findall(r'["\']?(\d{2,5}):(\d{2,5})["\']?', text)
94
+ for host_port, container_port in matches:
95
+ if host_port not in seen_ports and int(host_port) > 80:
96
+ seen_ports.add(host_port)
97
+ src_label = compose_name if d == project_dir else f"{d.name}/{compose_name}"
98
+ results.append(("Container Port", host_port, src_label))
99
+ except Exception:
100
+ pass
101
+
102
+ # 2. Check .env.example / .env
103
+ for env_name in (".env.example", ".env", ".env.local"):
104
+ env_file = d / env_name
105
+ if env_file.exists():
106
+ try:
107
+ for line in env_file.read_text(encoding="utf-8", errors="ignore").splitlines():
108
+ line = line.strip()
109
+ if line.startswith("#") or "=" not in line:
110
+ continue
111
+ key, val = line.split("=", 1)
112
+ key = key.strip()
113
+ val = val.strip().strip('"').strip("'")
114
+ if "PORT" in key.upper() and val.isdigit() and val not in seen_ports:
115
+ seen_ports.add(val)
116
+ src_label = env_name if d == project_dir else f"{d.name}/{env_name}"
117
+ results.append((key, val, src_label))
118
+ except Exception:
119
+ pass
120
+
121
+ # 3. Check Dockerfile
122
+ dockerfile = d / "Dockerfile"
123
+ if dockerfile.exists():
124
+ try:
125
+ for line in dockerfile.read_text(encoding="utf-8", errors="ignore").splitlines():
126
+ if line.strip().upper().startswith("EXPOSE "):
127
+ port = line.strip().split()[1]
128
+ if port.isdigit() and port not in seen_ports:
129
+ seen_ports.add(port)
130
+ src_label = "Dockerfile" if d == project_dir else f"{d.name}/Dockerfile"
131
+ results.append(("Exposed Port", port, src_label))
132
+ except Exception:
133
+ pass
134
+
135
+ return results
136
+
137
+
138
+ # ── Runbook Command Extractor ─────────────────────────────────────────────────
139
+
140
+ def discover_runbook_commands(project_dir: Path) -> list[tuple[str, str]]:
141
+ """
142
+ Extract executable development, build, and test commands from project manifests.
143
+ Guarantees 100% executable commands without hallucinated placeholders.
144
+ Returns list of (Action, Command).
145
+ """
146
+ commands: list[tuple[str, str]] = []
147
+ seen_commands: set[str] = set()
148
+
149
+ for d in _get_project_search_roots(project_dir):
150
+ dir_label = "" if d == project_dir else f" ({d.name})"
151
+
152
+ # 1. package.json scripts
153
+ pkg_file = d / "package.json"
154
+ if pkg_file.exists():
155
+ try:
156
+ data = json.loads(pkg_file.read_text(encoding="utf-8", errors="ignore"))
157
+ scripts = data.get("scripts", {})
158
+ runner = "pnpm" if (d / "pnpm-lock.yaml").exists() else (
159
+ "yarn" if (d / "yarn.lock").exists() else (
160
+ "bun" if (d / "bun.lockb").exists() else "npm"
161
+ )
162
+ )
163
+ for key in ("dev", "start", "build", "test", "lint"):
164
+ if key in scripts:
165
+ if d == project_dir:
166
+ cmd = f"{runner} run {key}" if runner != "yarn" else f"yarn {key}"
167
+ else:
168
+ cmd = f"{runner} --prefix {d.name} run {key}" if runner == "npm" else f"{runner} --cwd {d.name} run {key}"
169
+ if cmd not in seen_commands:
170
+ seen_commands.add(cmd)
171
+ commands.append((f"Run {key}{dir_label}", cmd))
172
+ except Exception:
173
+ pass
174
+
175
+ # 2. pyproject.toml (scripts & test runner)
176
+ pyproj = d / "pyproject.toml"
177
+ if pyproj.exists():
178
+ try:
179
+ raw_text = pyproj.read_text(encoding="utf-8", errors="ignore")
180
+ data = tomllib.loads(raw_text) if tomllib else {}
181
+ scripts = data.get("project", {}).get("scripts", {})
182
+ for script_name in scripts:
183
+ cmd = f"uv run {script_name}" if d == project_dir else f"uv run --directory {d.name} {script_name}"
184
+ if cmd not in seen_commands:
185
+ seen_commands.add(cmd)
186
+ commands.append((f"Run CLI ({script_name}){dir_label}", cmd))
187
+
188
+ if "pytest" in raw_text or (d / "tests").is_dir() or (d / "test").is_dir():
189
+ cmd = "uv run pytest" if d == project_dir else f"uv run --directory {d.name} pytest"
190
+ if cmd not in seen_commands:
191
+ seen_commands.add(cmd)
192
+ commands.append((f"Run Tests{dir_label}", cmd))
193
+ except Exception:
194
+ pass
195
+
196
+ # 3. Python indicators (manage.py, main.py, app.py, server.py)
197
+ if (d / "manage.py").exists():
198
+ target = "manage.py" if d == project_dir else f"{d.name}/manage.py"
199
+ cmd_run = f"python {target} runserver"
200
+ cmd_mig = f"python {target} migrate"
201
+ if cmd_run not in seen_commands:
202
+ seen_commands.add(cmd_run)
203
+ commands.append((f"Django Runserver{dir_label}", cmd_run))
204
+ if cmd_mig not in seen_commands:
205
+ seen_commands.add(cmd_mig)
206
+ commands.append((f"Django Migrate{dir_label}", cmd_mig))
207
+ else:
208
+ for main_candidate in ("main.py", "app.py", "server.py", "wsgi.py"):
209
+ if (d / main_candidate).exists():
210
+ target = main_candidate if d == project_dir else f"{d.name}/{main_candidate}"
211
+ cmd = f"python {target}"
212
+ if cmd not in seen_commands:
213
+ seen_commands.add(cmd)
214
+ commands.append((f"Start Server{dir_label}", cmd))
215
+ break
216
+
217
+ # 4. Makefile targets
218
+ makefile = d / "Makefile"
219
+ if makefile.exists():
220
+ try:
221
+ targets = re.findall(r"^([a-zA-Z0-9_-]+):", makefile.read_text(encoding="utf-8", errors="ignore"), re.M)
222
+ preferred = [t for t in targets if not t.startswith(".") and t in ("dev", "start", "build", "test", "lint", "all", "run")]
223
+ if not preferred:
224
+ preferred = [t for t in targets if not t.startswith(".")][:3]
225
+ for t in preferred[:3]:
226
+ cmd = f"make {t}" if d == project_dir else f"make -C {d.name} {t}"
227
+ if cmd not in seen_commands:
228
+ seen_commands.add(cmd)
229
+ commands.append((f"Make {t}{dir_label}", cmd))
230
+ except Exception:
231
+ pass
232
+
233
+ # 5. Rust Cargo
234
+ cargo = d / "Cargo.toml"
235
+ if cargo.exists():
236
+ cmd_run = "cargo run" if d == project_dir else f"cargo run --manifest-path {d.name}/Cargo.toml"
237
+ cmd_test = "cargo test" if d == project_dir else f"cargo test --manifest-path {d.name}/Cargo.toml"
238
+ if cmd_run not in seen_commands:
239
+ seen_commands.add(cmd_run)
240
+ commands.append((f"Cargo Run{dir_label}", cmd_run))
241
+ if cmd_test not in seen_commands:
242
+ seen_commands.add(cmd_test)
243
+ commands.append((f"Cargo Test{dir_label}", cmd_test))
244
+
245
+ # 6. Go mod
246
+ go_mod = d / "go.mod"
247
+ if go_mod.exists():
248
+ cmd_run = "go run ." if d == project_dir else f"cd {d.name} && go run ."
249
+ cmd_test = "go test ./..." if d == project_dir else f"cd {d.name} && go test ./..."
250
+ if cmd_run not in seen_commands:
251
+ seen_commands.add(cmd_run)
252
+ commands.append((f"Go Run{dir_label}", cmd_run))
253
+ if cmd_test not in seen_commands:
254
+ seen_commands.add(cmd_test)
255
+ commands.append((f"Go Test{dir_label}", cmd_test))
256
+
257
+ # 7. Docker Compose
258
+ if (d / "docker-compose.yml").exists() or (d / "compose.yaml").exists():
259
+ cmd = "docker compose up -d" if d == project_dir else f"docker compose -f {d.name}/docker-compose.yml up -d"
260
+ if cmd not in seen_commands:
261
+ seen_commands.add(cmd)
262
+ commands.append((f"Start Docker Services{dir_label}", cmd))
263
+
264
+ return commands[:6]
265
+
266
+
267
+ # ── Routes & Endpoints Extractor ──────────────────────────────────────────────
268
+
269
+ def discover_routes(project_dir: Path) -> list[str]:
270
+ """
271
+ Extract API and UI routes using Next.js, Express, FastAPI, and Django conventions.
272
+ Returns clean list of detected route paths.
273
+ """
274
+ routes: list[str] = []
275
+
276
+ try:
277
+ # 1. Next.js App Router (app/ or src/app/)
278
+ app_dirs = [d for d in (project_dir / "app", project_dir / "src" / "app") if d.is_dir()]
279
+ for app_dir in app_dirs:
280
+ for file_path in app_dir.rglob("*"):
281
+ if file_path.is_file() and file_path.name in ("route.ts", "route.js", "page.tsx", "page.jsx"):
282
+ rel = file_path.parent.relative_to(app_dir).as_posix()
283
+ route_path = "/" if rel == "." else f"/{rel}"
284
+ kind = "API" if file_path.name.startswith("route") else "Page"
285
+ routes.append(f"[{kind}] {route_path} -> {file_path.relative_to(project_dir).as_posix()}")
286
+
287
+ # 2. Next.js Pages Router (pages/ or src/pages/)
288
+ page_dirs = [d for d in (project_dir / "pages", project_dir / "src" / "pages") if d.is_dir()]
289
+ for page_dir in page_dirs:
290
+ for file_path in page_dir.rglob("*.tsx"):
291
+ if not file_path.name.startswith("_"):
292
+ rel = file_path.relative_to(page_dir).with_suffix("").as_posix()
293
+ route_path = "/" if rel == "index" else f"/{rel.replace('/index', '')}"
294
+ kind = "API" if "api" in rel else "Page"
295
+ routes.append(f"[{kind}] {route_path} -> {file_path.relative_to(project_dir).as_posix()}")
296
+
297
+ # 3. Modular Route, Controller & CLI Command Folders (Deep Convention Search)
298
+ target_dirs = ("routes", "controllers", "routers", "endpoints", "commands", "handlers", "views", "api")
299
+ ignore_parts = {"node_modules", ".git", ".venv", "venv", "__pycache__", ".agents", ".gemini", "dist", "build", "site-packages"}
300
+
301
+ for folder in project_dir.rglob("*"):
302
+ if folder.is_dir() and folder.name in target_dirs:
303
+ if any(ignored in folder.parts for ignored in ignore_parts):
304
+ continue
305
+
306
+ label = "Command" if folder.name in ("commands", "cli") else "Route"
307
+ for ext in ("*.ts", "*.tsx", "*.js", "*.jsx", "*.py", "*.go", "*.rs"):
308
+ for f in folder.glob(ext):
309
+ if not f.name.startswith(("_", ".")):
310
+ rel_file = f.relative_to(project_dir).as_posix()
311
+ routes.append(f"[{label}] {f.stem} -> {rel_file}")
312
+
313
+ except Exception:
314
+ pass
315
+
316
+ return routes[:35] # Cap to prevent unbounded lists
317
+
318
+
319
+ # ── Database Models Extractor ─────────────────────────────────────────────────
320
+
321
+ def discover_database_models(project_dir: Path) -> list[str]:
322
+ """
323
+ Extract data models from Prisma, Django, SQLAlchemy, Drizzle schemas.
324
+ Returns list of discovered model names and schema files.
325
+ """
326
+ models: list[str] = []
327
+
328
+ try:
329
+ # 1. Prisma schema
330
+ for prisma_path in (project_dir / "prisma" / "schema.prisma", project_dir / "schema.prisma"):
331
+ if prisma_path.exists():
332
+ text = prisma_path.read_text(encoding="utf-8", errors="ignore")
333
+ found = re.findall(r"\bmodel\s+([A-Za-z0-9_]+)\s*\{", text)
334
+ for m in found:
335
+ models.append(f"[Prisma] {m} ({prisma_path.relative_to(project_dir).as_posix()})")
336
+
337
+ # 2. Django / SQLAlchemy models.py
338
+ for models_file in project_dir.rglob("models.py"):
339
+ if "venv" not in models_file.parts and ".git" not in models_file.parts:
340
+ text = models_file.read_text(encoding="utf-8", errors="ignore")
341
+ found = re.findall(r"\bclass\s+([A-Za-z0-9_]+)\s*\(", text)
342
+ for m in found:
343
+ if m not in ("Meta",):
344
+ models.append(f"[Model] {m} ({models_file.relative_to(project_dir).as_posix()})")
345
+
346
+ # 3. Drizzle schema
347
+ for drizzle_file in project_dir.rglob("schema.ts"):
348
+ if "node_modules" not in drizzle_file.parts:
349
+ text = drizzle_file.read_text(encoding="utf-8", errors="ignore")
350
+ found = re.findall(r"export\s+const\s+([A-Za-z0-9_]+)\s+=\s+(?:pgTable|mysqlTable|sqliteTable)", text)
351
+ for m in found:
352
+ models.append(f"[Drizzle] {m} ({drizzle_file.relative_to(project_dir).as_posix()})")
353
+
354
+ except Exception:
355
+ pass
356
+
357
+ return models[:30]
358
+
359
+
360
+ # ── Satellites Generator (.agents/context/) ───────────────────────────────────
361
+
362
+ def generate_satellites(project_dir: Path, force: bool = False) -> dict[str, Path]:
363
+ """
364
+ Generate stack-adaptive satellite files in .agents/context/ on-demand.
365
+ Enforces strict idempotency and zero token bloat in the main hub.
366
+ """
367
+ satellites_dir = project_dir / ".agents" / "context"
368
+ satellites_dir.mkdir(parents=True, exist_ok=True)
369
+ generated: dict[str, Path] = {}
370
+
371
+ routes = discover_routes(project_dir)
372
+ models = discover_database_models(project_dir)
373
+
374
+ # 1. routes.md (if web routes detected)
375
+ if routes:
376
+ routes_path = satellites_dir / "routes.md"
377
+ routes_content = (
378
+ "# System Route & Endpoint Map\n\n"
379
+ "> Discovered automatically via convention scanner. Used by AI agents for precision navigation.\n\n"
380
+ "| Kind | Route Path | Implementation File |\n"
381
+ "| :--- | :--- | :--- |\n"
382
+ )
383
+ for r in routes:
384
+ parts = r.split(" -> ")
385
+ kind_path = parts[0]
386
+ impl = parts[1] if len(parts) > 1 else ""
387
+ routes_content += f"| {kind_path} | `{impl}` |\n"
388
+
389
+ write_idempotent(routes_path, routes_content, "Routes Satellite")
390
+ generated["routes"] = routes_path
391
+
392
+ # 2. schema.md (if database models detected)
393
+ if models:
394
+ schema_path = satellites_dir / "schema.md"
395
+ schema_content = (
396
+ "# Database Schema & Entity Models\n\n"
397
+ "> Discovered data models and ORM schema definitions. Used by AI agents for database context.\n\n"
398
+ "| Model / Entity | Definition File |\n"
399
+ "| :--- | :--- |\n"
400
+ )
401
+ for m in models:
402
+ schema_content += f"| {m} |\n"
403
+
404
+ write_idempotent(schema_path, schema_content, "Schema Satellite")
405
+ generated["schema"] = schema_path
406
+
407
+ # 3. gotchas.md (Critical Traps & Anti-Patterns — Replaces useless bug diaries)
408
+ gotchas_path = satellites_dir / "gotchas.md"
409
+ if not gotchas_path.exists() or force:
410
+ gotchas_content = (
411
+ "# Critical Gotchas, Anti-Patterns & Architecture Invariants\n\n"
412
+ "> Institutional knowledge and non-obvious traps that cannot be guessed from reading code.\n\n"
413
+ "## ⚠️ Active Constraints & Traps\n\n"
414
+ "1. **Port Invariants:** Inspect discovered ports before binding local services.\n"
415
+ "2. **Secret Isolation:** Production secrets belong in `.env`; dummy dev accounts belong in `context.local.md`.\n"
416
+ "3. **State Boundaries:** Verify migrations before initiating build or release cycles.\n"
417
+ )
418
+ write_idempotent(gotchas_path, gotchas_content, "Gotchas Satellite")
419
+ generated["gotchas"] = gotchas_path
420
+
421
+ return generated
@@ -0,0 +1,47 @@
1
+ # Standing Agent Rules for {{PROJECT_NAME}}
2
+
3
+ ## Critical Mandate: Autonomous Context Synchronization & Precision Architecture
4
+ As an AI coding assistant working in this repository (`{{PROJECT_DIR}}`), you are **strictly mandated** to maintain the Hub & Satellite context architecture, navigate codebases with laser precision, and autonomously crystallize new rules and skills. The user must **never** need to remind or instruct you.
5
+
6
+ ### 1. Precision Context Navigation Protocol
7
+ Whenever exploring code or resolving tasks during an active session, follow the precision formula:
8
+ $$\text{Precision Context} = \text{Route Map (Macro)} + \text{Grep/Symbol (Micro)} + \text{Targeted Range Read}$$
9
+ - **Never bulk-read entire directories or loop through 50+ source files.**
10
+ - First inspect `.agents/context/routes.md` or Section 2 of `context.md` for high-level file locations.
11
+ - Use `grep` or symbol search to pinpoint exact files and line numbers.
12
+ - Read only the specific target line range (e.g. `#L30-L70`) rather than loading entire large files.
13
+
14
+ ### 2. Mandatory Post-Action Protocol & Satellite Sync (Phase 3)
15
+ Before concluding any turn or session, the agent MUST inspect and update context:
16
+ - **Routes & Pages:** If any API endpoint or UI view is created, modified, or removed, immediately update `.agents/context/routes.md` (or run `init-context scan`).
17
+ - **Database Models:** If any schema, migration, or entity is changed, immediately update `.agents/context/schema.md`.
18
+ - **Architecture Gotchas:** If a non-obvious trap, port collision, or bug invariant is discovered, immediately record it in `.agents/context/gotchas.md`.
19
+ - **Core Hub:** Keep `context.md` compact (< 400 tokens / 60 lines) as an executive routing hub.
20
+
21
+ ### 3. Domain Consolidation & Anti-Fragmentation (Single Responsibility)
22
+ When codifying new guidelines or workflows, DO NOT create fragmented micro-files if a domain file already exists:
23
+ - **Docker & Containerization:** Update/append to `.agents/skills/docker-ops/SKILL.md`.
24
+ - **Git & Release Workflows:** Update/append to `.agents/skills/git-workflow/SKILL.md`.
25
+ - **Coding Standards & Patterns:** Update/append to `.agents/rules/code-standards.md`.
26
+ - **Security Boundaries:** Update/append to `.agents/rules/security-boundaries.md`.
27
+ - Only create a new rule or skill file (`init-context -r` / `-s`) if it represents a distinctly new, independent domain.
28
+
29
+ ### 4. Context Distillation over Blind Deletion
30
+ Never blindly delete or truncate context:
31
+ - When problem logs or debugging notes grow beyond 50 lines, distill and synthesize the technical root causes into high-density invariants inside `.agents/context/gotchas.md`.
32
+ - Preserve 100% of the architectural wisdom with 90% fewer tokens.
33
+
34
+ ### 5. Local Sandbox Test Credentials (`context.local.md`)
35
+ - **Chat Continuity:** When starting a new session or switching chats, always read `context.local.md` to identify local dev ports, seed users, and mock passwords (`admin@test.local`) before running browser automation or curl tests.
36
+ - **Strict Boundary:** Real production secrets, payment keys, and cloud tokens belong strictly in `.env`.
37
+ - Ensure `context.local.md` is protected with `.gitignore` and `chmod 600`.
38
+
39
+ ### 6. Autonomous Learning & Tool Access
40
+ - **Zero Token Waste:** DO NOT burn tokens manually searching directories to check for duplicates. Directly run `init-context -r <name> [-g]` — the CLI has instant built-in duplicate detection and collision guards.
41
+ - **Mandatory Global Scope:** When the user mentions "for future", "always", or defines a reusable standard, **MANDATORY: Always pass `--global` (`-g`)** and immediately follow with `init-context memory push`.
42
+ - Available CLI commands:
43
+ - `init-context scan`: Refresh stack-adaptive satellites (`routes.md`, `schema.md`, `gotchas.md`).
44
+ - `init-context -r <name> [-g]`: Create rule.
45
+ - `init-context -s <name> [-g]`: Create skill.
46
+ - `init-context update`: Safely sync public rules and upstream capabilities (non-breaking).
47
+ - `init-context memory push`: Push updates to central memory.
@@ -0,0 +1,47 @@
1
+ # Standing Agent Rules for {{PROJECT_NAME}}
2
+
3
+ ## Critical Mandate: Autonomous Context Synchronization & Precision Architecture
4
+ As an AI coding assistant working in this repository (`{{PROJECT_DIR}}`), you are **strictly mandated** to maintain the Hub & Satellite context architecture, navigate codebases with laser precision, and autonomously crystallize new rules and skills. The user must **never** need to remind or instruct you.
5
+
6
+ ### 1. Precision Context Navigation Protocol
7
+ Whenever exploring code or resolving tasks during an active session, follow the precision formula:
8
+ $$\text{Precision Context} = \text{Route Map (Macro)} + \text{Grep/Symbol (Micro)} + \text{Targeted Range Read}$$
9
+ - **Never bulk-read entire directories or loop through 50+ source files.**
10
+ - First inspect `.agents/context/routes.md` or Section 2 of `context.md` for high-level file locations.
11
+ - Use `grep` or symbol search to pinpoint exact files and line numbers.
12
+ - Read only the specific target line range (e.g. `#L30-L70`) rather than loading entire large files.
13
+
14
+ ### 2. Mandatory Post-Action Protocol & Satellite Sync (Phase 3)
15
+ Before concluding any turn or session, the agent MUST inspect and update context:
16
+ - **Routes & Pages:** If any API endpoint or UI view is created, modified, or removed, immediately update `.agents/context/routes.md` (or run `init-context scan`).
17
+ - **Database Models:** If any schema, migration, or entity is changed, immediately update `.agents/context/schema.md`.
18
+ - **Architecture Gotchas:** If a non-obvious trap, port collision, or bug invariant is discovered, immediately record it in `.agents/context/gotchas.md`.
19
+ - **Core Hub:** Keep `context.md` compact (< 400 tokens / 60 lines) as an executive routing hub.
20
+
21
+ ### 3. Domain Consolidation & Anti-Fragmentation (Single Responsibility)
22
+ When codifying new guidelines or workflows, DO NOT create fragmented micro-files if a domain file already exists:
23
+ - **Docker & Containerization:** Update/append to `.agents/skills/docker-ops/SKILL.md`.
24
+ - **Git & Release Workflows:** Update/append to `.agents/skills/git-workflow/SKILL.md`.
25
+ - **Coding Standards & Patterns:** Update/append to `.agents/rules/code-standards.md`.
26
+ - **Security Boundaries:** Update/append to `.agents/rules/security-boundaries.md`.
27
+ - Only create a new rule or skill file (`init-context -r` / `-s`) if it represents a distinctly new, independent domain.
28
+
29
+ ### 4. Context Distillation over Blind Deletion
30
+ Never blindly delete or truncate context:
31
+ - When problem logs or debugging notes grow beyond 50 lines, distill and synthesize the technical root causes into high-density invariants inside `.agents/context/gotchas.md`.
32
+ - Preserve 100% of the architectural wisdom with 90% fewer tokens.
33
+
34
+ ### 5. Local Sandbox Test Credentials (`context.local.md`)
35
+ - **Chat Continuity:** When starting a new session or switching chats, always read `context.local.md` to identify local dev ports, seed users, and mock passwords (`admin@test.local`) before running browser automation or curl tests.
36
+ - **Strict Boundary:** Real production secrets, payment keys, and cloud tokens belong strictly in `.env`.
37
+ - Ensure `context.local.md` is protected with `.gitignore` and `chmod 600`.
38
+
39
+ ### 6. Autonomous Learning & Tool Access
40
+ - **Zero Token Waste:** DO NOT burn tokens manually searching directories to check for duplicates. Directly run `init-context -r <name> [-g]` — the CLI has instant built-in duplicate detection and collision guards.
41
+ - **Mandatory Global Scope:** When the user mentions "for future", "always", or defines a reusable standard, **MANDATORY: Always pass `--global` (`-g`)** and immediately follow with `init-context memory push`.
42
+ - Available CLI commands:
43
+ - `init-context scan`: Refresh stack-adaptive satellites (`routes.md`, `schema.md`, `gotchas.md`).
44
+ - `init-context -r <name> [-g]`: Create rule.
45
+ - `init-context -s <name> [-g]`: Create skill.
46
+ - `init-context update`: Safely sync public rules and upstream capabilities (non-breaking).
47
+ - `init-context memory push`: Push updates to central memory.
@@ -28,8 +28,7 @@
28
28
 
29
29
  | Action | Command |
30
30
  | :--- | :--- |
31
- | **Start Development** | `npm run dev` / `python main.py` |
32
- | **Codebase Rescan** | `init-context scan` |
31
+ | **Rescan & Sync Runbook** | `init-context scan` |
33
32
  <!-- AUTO-CONTEXT:DISCOVERY:END -->
34
33
 
35
34
  ---
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: maintain_context
3
+ description: Mandates autonomous, continuous synchronization of context.md and proactive rule/skill learning on any repository or server configuration change without requiring user prompting.
4
+ trigger: always_on
5
+ ---
6
+
7
+ # Autonomous Context Maintenance & Self-Evolution Rule
8
+
9
+ ## 1. Precision Context Navigation Protocol
10
+ Whenever exploring code or resolving tasks during an active session, follow the precision formula:
11
+ $$\text{Precision Context} = \text{Route Map (Macro)} + \text{Grep/Symbol (Micro)} + \text{Targeted Range Read}$$
12
+ - **Never bulk-read entire directories or loop through 50+ source files.**
13
+ - First inspect `.agents/context/routes.md` or Section 2 of `context.md` for high-level file locations.
14
+ - Use `grep` or symbol search to pinpoint exact files and line numbers.
15
+ - Read only the specific target line range (e.g. `#L30-L70`) rather than loading entire large files.
16
+
17
+ ## 2. Mandatory Post-Action Protocol & Satellite Sync (Phase 3)
18
+ Before concluding any turn or session, the agent MUST inspect and update context:
19
+ - **Routes & Pages:** If any API endpoint or UI view is created, modified, or removed, immediately update `.agents/context/routes.md` (or run `init-context scan`).
20
+ - **Database Models:** If any schema, migration, or entity is changed, immediately update `.agents/context/schema.md`.
21
+ - **Architecture Gotchas:** If a non-obvious trap, port collision, or bug invariant is discovered, immediately record it in `.agents/context/gotchas.md`.
22
+ - **Core Hub:** Keep `context.md` compact (< 400 tokens / 60 lines) as an executive routing hub.
23
+
24
+ ## 3. Domain Consolidation & Anti-Fragmentation (Single Responsibility)
25
+ When codifying new guidelines or workflows, DO NOT create fragmented micro-files if a domain file already exists:
26
+ - **Docker & Containerization:** Update/append to `.agents/skills/docker-ops/SKILL.md`.
27
+ - **Git & Release Workflows:** Update/append to `.agents/skills/git-workflow/SKILL.md`.
28
+ - **Coding Standards & Patterns:** Update/append to `.agents/rules/code-standards.md`.
29
+ - **Security Boundaries:** Update/append to `.agents/rules/security-boundaries.md`.
30
+ - Only create a new rule or skill file (`init-context -r` / `-s`) if it represents a distinctly new, independent domain.
31
+
32
+ ## 4. Context Distillation over Blind Deletion
33
+ Never blindly delete or truncate context:
34
+ - When problem logs or debugging notes grow beyond 50 lines, distill and synthesize the technical root causes into high-density invariants inside `.agents/context/gotchas.md`.
35
+ - Preserve 100% of the architectural wisdom with 90% fewer tokens.
36
+
37
+ ## 5. Local Sandbox Test Credentials (`context.local.md`)
38
+ - **Chat Continuity:** When starting a new session or switching chats, always read `context.local.md` to identify local dev ports, seed users, and mock passwords (`admin@test.local`) before running browser automation or curl tests.
39
+ - **Strict Boundary:** Real production secrets, payment keys, and cloud tokens belong strictly in `.env`.
40
+ - Ensure `context.local.md` is protected with `.gitignore` and `chmod 600`.
41
+
42
+ ## 6. Autonomous Learning & Tooling
43
+ - **Zero Token Waste:** DO NOT burn tokens manually searching directories to check for duplicates. Directly run `init-context -r <name> [-g]` — the CLI has instant built-in duplicate detection and collision guards.
44
+ - **Mandatory Global Scope:** When the user mentions "for future", "always", or defines a reusable standard, **MANDATORY: Always pass `--global` (`-g`)** and immediately follow with `init-context memory push`.
45
+ - The agent has full access to run `init-context`:
46
+ - `init-context scan`: Refresh stack-adaptive satellites (`routes.md`, `schema.md`, `gotchas.md`).
47
+ - `init-context update`: Safely sync public rules and upstream capabilities (non-breaking).
48
+ - `init-context memory push`: Push updates to central memory.
@@ -31,3 +31,4 @@ Prevent monolithic context file bloat, eliminate token waste, ensure 100% idempo
31
31
  4. **KISS & DRY Heuristics:**
32
32
  - Prefer language-agnostic filesystem convention heuristics (directories, manifests) over heavy language AST parsers that crash on in-flight syntax errors.
33
33
  - All scanners must degrade gracefully with zero unhandled exceptions.
34
+
@@ -1,297 +0,0 @@
1
- """
2
- scanner.py — Stack-Adaptive Codebase Introspection & Brownfield Discovery Engine.
3
-
4
- Discovers ports, routes, database schemas, services, and runbooks using lightweight
5
- filesystem convention heuristics (0 LLM tokens, 100% crash-proof, idempotency-guaranteed).
6
- """
7
- import hashlib
8
- import json
9
- from pathlib import Path
10
- import re
11
- from typing import Optional
12
-
13
- from rich.console import Console
14
-
15
- console = Console()
16
-
17
-
18
- # ── Idempotency & Hash Helpers ────────────────────────────────────────────────
19
-
20
- def get_content_hash(text: str) -> str:
21
- """Compute SHA-256 hash of text content."""
22
- return hashlib.sha256(text.encode("utf-8")).hexdigest()
23
-
24
-
25
- def write_idempotent(path: Path, content: str, label: str = "File") -> bool:
26
- """
27
- Write content to path only if content has changed (Content-Hash Guard).
28
- Returns True if a write occurred, False if content was already identical.
29
- """
30
- if path.exists():
31
- try:
32
- existing = path.read_text(encoding="utf-8")
33
- if get_content_hash(existing) == get_content_hash(content):
34
- console.print(f" [dim]— Up to date:[/] {path.name}")
35
- return False
36
- except Exception:
37
- pass
38
-
39
- path.parent.mkdir(parents=True, exist_ok=True)
40
- path.write_text(content, encoding="utf-8")
41
- console.print(f" [green][✓] Synchronized:[/] {path.name}")
42
- return True
43
-
44
-
45
- # ── Port & Service Extractor ──────────────────────────────────────────────────
46
-
47
- def discover_ports_and_services(project_dir: Path) -> list[tuple[str, str, str]]:
48
- """
49
- Extract network ports and service bindings from configs without leaking secrets.
50
- Returns list of (Service, Port, SourceFile).
51
- """
52
- results: list[tuple[str, str, str]] = []
53
- seen_ports: set[str] = set()
54
-
55
- # 1. Check docker-compose.yml / compose.yaml
56
- for compose_name in ("docker-compose.yml", "docker-compose.yaml", "compose.yml", "compose.yaml"):
57
- compose_file = project_dir / compose_name
58
- if compose_file.exists():
59
- try:
60
- text = compose_file.read_text(encoding="utf-8", errors="ignore")
61
- matches = re.findall(r'["\']?(\d{2,5}):(\d{2,5})["\']?', text)
62
- for host_port, container_port in matches:
63
- if host_port not in seen_ports and int(host_port) > 80:
64
- seen_ports.add(host_port)
65
- results.append(("Container Port", host_port, compose_name))
66
- except Exception:
67
- pass
68
-
69
- # 2. Check .env.example / .env
70
- for env_name in (".env.example", ".env", ".env.local"):
71
- env_file = project_dir / env_name
72
- if env_file.exists():
73
- try:
74
- for line in env_file.read_text(encoding="utf-8", errors="ignore").splitlines():
75
- line = line.strip()
76
- if line.startswith("#") or "=" not in line:
77
- continue
78
- key, val = line.split("=", 1)
79
- key = key.strip()
80
- val = val.strip().strip('"').strip("'")
81
- if "PORT" in key.upper() and val.isdigit() and val not in seen_ports:
82
- seen_ports.add(val)
83
- results.append((key, val, env_name))
84
- except Exception:
85
- pass
86
-
87
- # 3. Check Dockerfile
88
- dockerfile = project_dir / "Dockerfile"
89
- if dockerfile.exists():
90
- try:
91
- for line in dockerfile.read_text(encoding="utf-8", errors="ignore").splitlines():
92
- if line.strip().upper().startswith("EXPOSE "):
93
- port = line.strip().split()[1]
94
- if port.isdigit() and port not in seen_ports:
95
- seen_ports.add(port)
96
- results.append(("Exposed Port", port, "Dockerfile"))
97
- except Exception:
98
- pass
99
-
100
- return results
101
-
102
-
103
- # ── Runbook Command Extractor ─────────────────────────────────────────────────
104
-
105
- def discover_runbook_commands(project_dir: Path) -> list[tuple[str, str]]:
106
- """
107
- Extract executable development, build, and test commands from project manifests.
108
- Returns list of (Action, Command).
109
- """
110
- commands: list[tuple[str, str]] = []
111
-
112
- # 1. package.json scripts
113
- pkg_file = project_dir / "package.json"
114
- if pkg_file.exists():
115
- try:
116
- data = json.loads(pkg_file.read_text(encoding="utf-8", errors="ignore"))
117
- scripts = data.get("scripts", {})
118
- for key in ("dev", "start", "build", "test", "lint"):
119
- if key in scripts:
120
- commands.append((f"Run {key}", f"npm run {key}"))
121
- except Exception:
122
- pass
123
-
124
- # 2. Makefile
125
- makefile = project_dir / "Makefile"
126
- if makefile.exists():
127
- try:
128
- targets = re.findall(r"^([a-zA-Z0-9_-]+):", makefile.read_text(encoding="utf-8", errors="ignore"), re.M)
129
- for t in targets[:4]:
130
- if not t.startswith("."):
131
- commands.append((f"Make {t}", f"make {t}"))
132
- except Exception:
133
- pass
134
-
135
- # 3. Python indicators
136
- if (project_dir / "manage.py").exists():
137
- commands.append(("Django Runserver", "python manage.py runserver"))
138
- commands.append(("Django Migrate", "python manage.py migrate"))
139
- elif (project_dir / "pyproject.toml").exists() or (project_dir / "requirements.txt").exists():
140
- for main_candidate in ("main.py", "app.py", "server.py", "wsgi.py"):
141
- if (project_dir / main_candidate).exists():
142
- commands.append(("Start Python Server", f"python {main_candidate}"))
143
- break
144
-
145
- # 4. Docker Compose
146
- if (project_dir / "docker-compose.yml").exists() or (project_dir / "compose.yaml").exists():
147
- commands.append(("Start Docker Services", "docker compose up -d"))
148
-
149
- return commands
150
-
151
-
152
- # ── Routes & Endpoints Extractor ──────────────────────────────────────────────
153
-
154
- def discover_routes(project_dir: Path) -> list[str]:
155
- """
156
- Extract API and UI routes using Next.js, Express, FastAPI, and Django conventions.
157
- Returns clean list of detected route paths.
158
- """
159
- routes: list[str] = []
160
-
161
- try:
162
- # 1. Next.js App Router (app/ or src/app/)
163
- app_dirs = [d for d in (project_dir / "app", project_dir / "src" / "app") if d.is_dir()]
164
- for app_dir in app_dirs:
165
- for file_path in app_dir.rglob("*"):
166
- if file_path.is_file() and file_path.name in ("route.ts", "route.js", "page.tsx", "page.jsx"):
167
- rel = file_path.parent.relative_to(app_dir).as_posix()
168
- route_path = "/" if rel == "." else f"/{rel}"
169
- kind = "API" if file_path.name.startswith("route") else "Page"
170
- routes.append(f"[{kind}] {route_path} -> {file_path.relative_to(project_dir).as_posix()}")
171
-
172
- # 2. Next.js Pages Router (pages/ or src/pages/)
173
- page_dirs = [d for d in (project_dir / "pages", project_dir / "src" / "pages") if d.is_dir()]
174
- for page_dir in page_dirs:
175
- for file_path in page_dir.rglob("*.tsx"):
176
- if not file_path.name.startswith("_"):
177
- rel = file_path.relative_to(page_dir).with_suffix("").as_posix()
178
- route_path = "/" if rel == "index" else f"/{rel.replace('/index', '')}"
179
- kind = "API" if "api" in rel else "Page"
180
- routes.append(f"[{kind}] {route_path} -> {file_path.relative_to(project_dir).as_posix()}")
181
-
182
- # 3. Express / FastAPI / Django Route folders
183
- for folder_name in ("routes", "controllers", "routers", "endpoints"):
184
- for candidate in (project_dir / folder_name, project_dir / "src" / folder_name):
185
- if candidate.is_dir():
186
- for f in candidate.glob("*.py") if candidate.glob("*.py") else candidate.glob("*.ts"):
187
- routes.append(f"[Module] {f.stem} -> {f.relative_to(project_dir).as_posix()}")
188
-
189
- except Exception:
190
- pass
191
-
192
- return routes[:35] # Cap to prevent unbounded lists
193
-
194
-
195
- # ── Database Models Extractor ─────────────────────────────────────────────────
196
-
197
- def discover_database_models(project_dir: Path) -> list[str]:
198
- """
199
- Extract data models from Prisma, Django, SQLAlchemy, Drizzle schemas.
200
- Returns list of discovered model names and schema files.
201
- """
202
- models: list[str] = []
203
-
204
- try:
205
- # 1. Prisma schema
206
- for prisma_path in (project_dir / "prisma" / "schema.prisma", project_dir / "schema.prisma"):
207
- if prisma_path.exists():
208
- text = prisma_path.read_text(encoding="utf-8", errors="ignore")
209
- found = re.findall(r"\bmodel\s+([A-Za-z0-9_]+)\s*\{", text)
210
- for m in found:
211
- models.append(f"[Prisma] {m} ({prisma_path.relative_to(project_dir).as_posix()})")
212
-
213
- # 2. Django / SQLAlchemy models.py
214
- for models_file in project_dir.rglob("models.py"):
215
- if "venv" not in models_file.parts and ".git" not in models_file.parts:
216
- text = models_file.read_text(encoding="utf-8", errors="ignore")
217
- found = re.findall(r"\bclass\s+([A-Za-z0-9_]+)\s*\(", text)
218
- for m in found:
219
- if m not in ("Meta",):
220
- models.append(f"[Model] {m} ({models_file.relative_to(project_dir).as_posix()})")
221
-
222
- # 3. Drizzle schema
223
- for drizzle_file in project_dir.rglob("schema.ts"):
224
- if "node_modules" not in drizzle_file.parts:
225
- text = drizzle_file.read_text(encoding="utf-8", errors="ignore")
226
- found = re.findall(r"export\s+const\s+([A-Za-z0-9_]+)\s+=\s+(?:pgTable|mysqlTable|sqliteTable)", text)
227
- for m in found:
228
- models.append(f"[Drizzle] {m} ({drizzle_file.relative_to(project_dir).as_posix()})")
229
-
230
- except Exception:
231
- pass
232
-
233
- return models[:30]
234
-
235
-
236
- # ── Satellites Generator (.agents/context/) ───────────────────────────────────
237
-
238
- def generate_satellites(project_dir: Path, force: bool = False) -> dict[str, Path]:
239
- """
240
- Generate stack-adaptive satellite files in .agents/context/ on-demand.
241
- Enforces strict idempotency and zero token bloat in the main hub.
242
- """
243
- satellites_dir = project_dir / ".agents" / "context"
244
- satellites_dir.mkdir(parents=True, exist_ok=True)
245
- generated: dict[str, Path] = {}
246
-
247
- routes = discover_routes(project_dir)
248
- models = discover_database_models(project_dir)
249
-
250
- # 1. routes.md (if web routes detected)
251
- if routes:
252
- routes_path = satellites_dir / "routes.md"
253
- routes_content = (
254
- "# System Route & Endpoint Map\n\n"
255
- "> Discovered automatically via convention scanner. Used by AI agents for precision navigation.\n\n"
256
- "| Kind | Route Path | Implementation File |\n"
257
- "| :--- | :--- | :--- |\n"
258
- )
259
- for r in routes:
260
- parts = r.split(" -> ")
261
- kind_path = parts[0]
262
- impl = parts[1] if len(parts) > 1 else ""
263
- routes_content += f"| {kind_path} | `{impl}` |\n"
264
-
265
- write_idempotent(routes_path, routes_content, "Routes Satellite")
266
- generated["routes"] = routes_path
267
-
268
- # 2. schema.md (if database models detected)
269
- if models:
270
- schema_path = satellites_dir / "schema.md"
271
- schema_content = (
272
- "# Database Schema & Entity Models\n\n"
273
- "> Discovered data models and ORM schema definitions. Used by AI agents for database context.\n\n"
274
- "| Model / Entity | Definition File |\n"
275
- "| :--- | :--- |\n"
276
- )
277
- for m in models:
278
- schema_content += f"| {m} |\n"
279
-
280
- write_idempotent(schema_path, schema_content, "Schema Satellite")
281
- generated["schema"] = schema_path
282
-
283
- # 3. gotchas.md (Critical Traps & Anti-Patterns — Replaces useless bug diaries)
284
- gotchas_path = satellites_dir / "gotchas.md"
285
- if not gotchas_path.exists() or force:
286
- gotchas_content = (
287
- "# Critical Gotchas, Anti-Patterns & Architecture Invariants\n\n"
288
- "> Institutional knowledge and non-obvious traps that cannot be guessed from reading code.\n\n"
289
- "## ⚠️ Active Constraints & Traps\n\n"
290
- "1. **Port Invariants:** Inspect discovered ports before binding local services.\n"
291
- "2. **Secret Isolation:** Production secrets belong in `.env`; dummy dev accounts belong in `context.local.md`.\n"
292
- "3. **State Boundaries:** Verify migrations before initiating build or release cycles.\n"
293
- )
294
- write_idempotent(gotchas_path, gotchas_content, "Gotchas Satellite")
295
- generated["gotchas"] = gotchas_path
296
-
297
- return generated
@@ -1,53 +0,0 @@
1
- # Standing Agent Rules for {{PROJECT_NAME}}
2
-
3
- ## Critical Mandate: Autonomous `context.md` Synchronization & Self-Evolution
4
- As an AI coding assistant working in this repository (`{{PROJECT_DIR}}`), you are **strictly mandated** to keep `{{PROJECT_DIR}}/context.md` continuously up to date and autonomously learn, persist, and crystallize new rules and skills. The user must **never** need to remind or instruct you.
5
-
6
- ### 1. Mandatory Post-Action Protocol
7
- Whenever ANY of the following events occur in any session or conversation turn:
8
- - A configuration file or script is created, edited, moved, or deleted.
9
- - A problem, bug, or error is encountered and diagnosed.
10
- - Credentials, tokens, user accounts, or security keys are generated or updated.
11
- - Architectural decisions or operational steps are modified.
12
-
13
- **You MUST immediately update `{{PROJECT_DIR}}/context.md` before finalizing your response.**
14
-
15
- ### 2. Autonomous Learning & Self-Evolution Protocol
16
- Whenever you learn a new pattern, receive a correction, observe a coding preference, or resolve a complex repeatable problem:
17
- 1. **Identify the Type:**
18
- - **Rule:** If it is a constraint, coding standard, safety boundary, or architectural preference -> Create a Rule (`init-context -r <name>`).
19
- - **Skill:** If it is a multi-step procedure, deployment workflow, diagnosis runbook, or CLI sequence -> Create a Skill (`init-context -s <name>`).
20
- 2. **Zero Token Waste:**
21
- - **DO NOT burn tokens manually searching directories or reading files to check for existing rules.** Directly run `init-context -r <name> [-g]` — the CLI has instant built-in duplicate detection and collision guards.
22
- 3. **Mandatory Global Scope:**
23
- - When the user mentions "for future", "always", or defines a reusable standard, **MANDATORY: Always pass `--global` (`-g`)** and immediately follow with `init-context memory push`.
24
- - **Project-Specific:** Only omit `-g` if strictly confined to this specific project repository.
25
- 4. **Execution:**
26
- - Use the `init-context` CLI tool to scaffold the file.
27
- - Populate it with clear objectives, constraints, or step-by-step instructions.
28
- - Inform the user of the new rule or skill codified.
29
-
30
- ### 3. Tool Access: `init-context`
31
- You have native access to run `init-context` via terminal commands:
32
- - `init-context`: Scaffolds or repairs project context.
33
- - `init-context -r <rule-name> [-g]`: Creates a new rule with frontmatter.
34
- - `init-context -s <skill-name> [-g]`: Creates a new skill with frontmatter.
35
- - `init-context update`: Safely syncs public rules and upstream capabilities (non-breaking).
36
- - `init-context memory push`: Synchronizes central brain memory to private Git repository.
37
-
38
- ### 4. Required Content & Structure in `context.md`
39
- 1. **Master Credentials & Configuration Vault (Section 1):** Keep all ports, IPs, secrets, tokens, and endpoints synchronized.
40
- 2. **Chronological Problem Log & Technical Solutions (Section 2):** Document symptom, root cause, exact commands/code used, and update Mermaid diagram.
41
- 3. **Architecture & Component Layout (Section 3):** Keep stack overview and directory maps accurate.
42
- 4. **Operations Runbook (Section 4):** Ensure 1-step reproduction instructions remain functional.
43
-
44
- ### 5. Local Sandbox Credentials & Dummy Test Fixtures (`context.local.md`)
45
- - **Inspection Mandate:** When testing local dev servers, performing browser automation (Playwright/Puppeteer), or authenticating API endpoints, ALWAYS read `context.local.md` first before prompting the user for credentials.
46
- - **Strict Mock Boundary:** ONLY store dummy test credentials, mock accounts (`admin@test.local`), seed users, and local dev ports in `context.local.md`.
47
- - **Zero Real Secrets:** Real production secrets, payment keys, or personal tokens MUST NEVER be stored in `context.local.md` or `context.md`; reference them via `.env` or system environment variables.
48
- - **Git Protection:** Ensure `context.local.md` remains strictly ignored by Git (`.gitignore`) and protected with `chmod 600`.
49
-
50
- ### 6. Two-Tier Progressive Disclosure Protocol (Token Optimization)
51
- - **Initial Boot Budget:** NEVER read full `SKILL.md` files into the initial context. Use Section 5 of `context.md` for lightweight routing (< 800 tokens).
52
- - **Dynamic On-Demand Loading:** Only when a user prompt matches a skill's triggers (e.g. "docker", "rebase", "diagnostics", "browser"), dynamically inspect the file using `read_file`.
53
- - **Zero Session Bloat:** Once the task concludes, do not keep the full skill body in persistent memory.
@@ -1,53 +0,0 @@
1
- # Standing Agent Rules for {{PROJECT_NAME}}
2
-
3
- ## Critical Mandate: Autonomous `context.md` Synchronization & Self-Evolution
4
- As an AI coding assistant working in this repository (`{{PROJECT_DIR}}`), you are **strictly mandated** to keep `{{PROJECT_DIR}}/context.md` continuously up to date and autonomously learn, persist, and crystallize new rules and skills. The user must **never** need to remind or instruct you.
5
-
6
- ### 1. Mandatory Post-Action Protocol
7
- Whenever ANY of the following events occur in any session or conversation turn:
8
- - A configuration file or script is created, edited, moved, or deleted.
9
- - A problem, bug, or error is encountered and diagnosed.
10
- - Credentials, tokens, user accounts, or security keys are generated or updated.
11
- - Architectural decisions or operational steps are modified.
12
-
13
- **You MUST immediately update `{{PROJECT_DIR}}/context.md` before finalizing your response.**
14
-
15
- ### 2. Autonomous Learning & Self-Evolution Protocol
16
- Whenever you learn a new pattern, receive a correction, observe a coding preference, or resolve a complex repeatable problem:
17
- 1. **Identify the Type:**
18
- - **Rule:** If it is a constraint, coding standard, safety boundary, or architectural preference -> Create a Rule (`init-context -r <name>`).
19
- - **Skill:** If it is a multi-step procedure, deployment workflow, diagnosis runbook, or CLI sequence -> Create a Skill (`init-context -s <name>`).
20
- 2. **Zero Token Waste:**
21
- - **DO NOT burn tokens manually searching directories or reading files to check for existing rules.** Directly run `init-context -r <name> [-g]` — the CLI has instant built-in duplicate detection and collision guards.
22
- 3. **Mandatory Global Scope:**
23
- - When the user mentions "for future", "always", or defines a reusable standard, **MANDATORY: Always pass `--global` (`-g`)** and immediately follow with `init-context memory push`.
24
- - **Project-Specific:** Only omit `-g` if strictly confined to this specific project repository.
25
- 4. **Execution:**
26
- - Use the `init-context` CLI tool to scaffold the file.
27
- - Populate it with clear objectives, constraints, or step-by-step instructions.
28
- - Inform the user of the new rule or skill codified.
29
-
30
- ### 3. Tool Access: `init-context`
31
- You have native access to run `init-context` via terminal commands:
32
- - `init-context`: Scaffolds or repairs project context.
33
- - `init-context -r <rule-name> [-g]`: Creates a new rule with frontmatter.
34
- - `init-context -s <skill-name> [-g]`: Creates a new skill with frontmatter.
35
- - `init-context update`: Safely syncs public rules and upstream capabilities (non-breaking).
36
- - `init-context memory push`: Synchronizes central brain memory to private Git repository.
37
-
38
- ### 4. Required Content & Structure in `context.md`
39
- 1. **Master Credentials & Configuration Vault (Section 1):** Keep all ports, IPs, secrets, tokens, and endpoints synchronized.
40
- 2. **Chronological Problem Log & Technical Solutions (Section 2):** Document symptom, root cause, exact commands/code used, and update Mermaid diagram.
41
- 3. **Architecture & Component Layout (Section 3):** Keep stack overview and directory maps accurate.
42
- 4. **Operations Runbook (Section 4):** Ensure 1-step reproduction instructions remain functional.
43
-
44
- ### 5. Local Sandbox Credentials & Dummy Test Fixtures (`context.local.md`)
45
- - **Inspection Mandate:** When testing local dev servers, performing browser automation (Playwright/Puppeteer), or authenticating API endpoints, ALWAYS read `context.local.md` first before prompting the user for credentials.
46
- - **Strict Mock Boundary:** ONLY store dummy test credentials, mock accounts (`admin@test.local`), seed users, and local dev ports in `context.local.md`.
47
- - **Zero Real Secrets:** Real production secrets, payment keys, or personal tokens MUST NEVER be stored in `context.local.md` or `context.md`; reference them via `.env` or system environment variables.
48
- - **Git Protection:** Ensure `context.local.md` remains strictly ignored by Git (`.gitignore`) and protected with `chmod 600`.
49
-
50
- ### 6. Two-Tier Progressive Disclosure Protocol (Token Optimization)
51
- - **Initial Boot Budget:** NEVER read full `SKILL.md` files into the initial context. Use Section 5 of `context.md` for lightweight routing (< 800 tokens).
52
- - **Dynamic On-Demand Loading:** Only when a user prompt matches a skill's triggers (e.g. "docker", "rebase", "diagnostics", "browser"), dynamically inspect the file using `read_file`.
53
- - **Zero Session Bloat:** Once the task concludes, do not keep the full skill body in persistent memory.
@@ -1,37 +0,0 @@
1
- ---
2
- name: maintain_context
3
- description: Mandates autonomous, continuous synchronization of context.md and proactive rule/skill learning on any repository or server configuration change without requiring user prompting.
4
- trigger: always_on
5
- ---
6
-
7
- # Autonomous Context Maintenance & Self-Evolution Rule
8
-
9
- 1. **Mandatory Synchronization**: Every agent working in this workspace MUST inspect and update `context.md` before finishing their turn whenever any of the following occur:
10
- - Script or configuration edits (environment variables, docker-compose, configs, network parameters).
11
- - Problem diagnosis, debugging steps, and technical solutions.
12
- - User credentials, tokens, secrets, or permissions changes.
13
- - Architectural decisions or operational runbooks.
14
-
15
- 2. **Autonomous Learning & Skill Crystallization**:
16
- - **Zero Token Waste:** DO NOT burn tokens manually searching directories or reading files to check for existing rules. Directly run `init-context -r <name> [-g]` — the CLI has instant built-in duplicate detection and collision guards.
17
- - **Mandatory Global Scope:** When the user mentions "for future", "always", or defines a reusable standard, **MANDATORY: Always pass `--global` (`-g`)** and immediately follow with `init-context memory push`.
18
- - Populates the file with clear instructions and notifies the user.
19
-
20
- 3. **CLI Tool Availability**:
21
- - The agent has full access to run `init-context` directly via terminal:
22
- - `init-context`: Initialize/repair context.
23
- - `init-context -r <name> [-g]`: Create rule.
24
- - `init-context -s <name> [-g]`: Create skill.
25
- - `init-context update`: Safely sync public rules and upstream capabilities (non-breaking).
26
- - `init-context memory push`: Push updates to central memory.
27
-
28
- 4. **No User Reminder Needed**: The user must never need to ask the agent to update `context.md` or learn rules. This is a strict automated post-condition for all actions.
29
-
30
- 5. **Local Sandbox Test Credentials (`context.local.md`)**:
31
- - For local dev logins, automated browser testing, and mock fixtures, inspect and update `context.local.md`.
32
- - Never store real production secrets or payment tokens in markdown files. Real secrets belong in `.env`.
33
- - Ensure `context.local.md` is strictly git-ignored and protected with `chmod 600`.
34
-
35
- 6. **Two-Tier Progressive Disclosure**:
36
- - Never load full `SKILL.md` bodies into the initial context. Use Section 5 of `context.md` for routing.
37
- - Dynamically load specific skills via `read_file` only when a user prompt matches their triggers.