codeforge-dev 1.4.0 → 1.5.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/.devcontainer/CHANGELOG.md +112 -0
- package/.devcontainer/README.md +7 -3
- package/.devcontainer/config/main-system-prompt.md +10 -0
- package/.devcontainer/config/settings.json +9 -5
- package/.devcontainer/connect-external-terminal.ps1 +77 -0
- package/.devcontainer/connect-external-terminal.sh +69 -0
- package/.devcontainer/devcontainer.json +9 -4
- package/.devcontainer/features/agent-browser/install.sh +5 -5
- package/.devcontainer/features/biome/devcontainer-feature.json +16 -0
- package/.devcontainer/features/biome/install.sh +19 -0
- package/.devcontainer/features/tmux/README.md +75 -0
- package/.devcontainer/features/tmux/devcontainer-feature.json +17 -0
- package/.devcontainer/features/tmux/install.sh +52 -0
- package/.devcontainer/plugins/devs-marketplace/.claude-plugin/marketplace.json +2 -2
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/.claude-plugin/plugin.json +1 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/hooks/hooks.json +5 -5
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/scripts/format-on-stop.py +177 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/hooks/hooks.json +2 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/.claude-plugin/commands/debug.md +86 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/.claude-plugin/plugin.json +1 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/debug-logs.md +149 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/hooks/hooks.json +46 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/collect-edited-files.py +44 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/skill-suggester.py +229 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/syntax-validator.py +141 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/debugging/SKILL.md +165 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/debugging/references/error-patterns.md +530 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/debugging/references/log-locations.md +430 -0
- package/README.md +13 -9
- package/package.json +1 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/scripts/format-file.py +0 -101
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/claude-code-headless/SKILL.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/claude-code-headless/references/cli-flags-and-output.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/claude-code-headless/references/sdk-and-mcp.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/docker/SKILL.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/docker/references/compose-services.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/docker/references/dockerfile-patterns.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/docker-py/SKILL.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/docker-py/references/container-lifecycle.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/docker-py/references/resources-and-security.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/fastapi/SKILL.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/fastapi/references/middleware-and-lifespan.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/fastapi/references/pydantic-models.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/fastapi/references/routing-and-dependencies.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/fastapi/references/sse-and-streaming.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/pydantic-ai/SKILL.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/pydantic-ai/references/agents-and-tools.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/pydantic-ai/references/models-and-streaming.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/skill-building/SKILL.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/skill-building/references/cross-vendor-principles.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/skill-building/references/patterns-and-antipatterns.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/skill-building/references/skill-authoring-patterns.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/sqlite/SKILL.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/sqlite/references/advanced-queries.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/sqlite/references/javascript-patterns.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/sqlite/references/python-patterns.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/sqlite/references/schema-and-pragmas.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/svelte5/SKILL.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/svelte5/references/ai-sdk-svelte.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/svelte5/references/component-patterns.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/svelte5/references/layercake.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/svelte5/references/migration-guide.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/svelte5/references/runes-and-reactivity.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/svelte5/references/spa-and-routing.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/svelte5/references/svelte-dnd-action.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/testing/SKILL.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/testing/references/fastapi-testing.md +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/{codedirective-skills → code-directive}/skills/testing/references/svelte-testing.md +0 -0
package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/skill-suggester.py
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Skill suggester hook for UserPromptSubmit and SubagentStart events.
|
|
3
|
+
|
|
4
|
+
Detects which hook event called it via input JSON shape:
|
|
5
|
+
- UserPromptSubmit: {"prompt": "..."} -> {"systemMessage": "..."}
|
|
6
|
+
- SubagentStart: {"subagent_type": "Plan", "prompt": "..."} -> {"additionalContext": "..."}
|
|
7
|
+
|
|
8
|
+
Matches user prompts against skill keyword maps (phrases + terms) and suggests
|
|
9
|
+
relevant skills. Outputs nothing when no skills match.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
import re
|
|
14
|
+
import sys
|
|
15
|
+
|
|
16
|
+
SKILLS = {
|
|
17
|
+
"fastapi": {
|
|
18
|
+
"phrases": [
|
|
19
|
+
"rest api",
|
|
20
|
+
"fastapi",
|
|
21
|
+
"fast api",
|
|
22
|
+
"pydantic model",
|
|
23
|
+
"sse streaming",
|
|
24
|
+
"server-sent event",
|
|
25
|
+
"dependency injection",
|
|
26
|
+
"asgi middleware",
|
|
27
|
+
"api endpoint",
|
|
28
|
+
"api route",
|
|
29
|
+
],
|
|
30
|
+
"terms": ["fastapi", "pydantic", "uvicorn", "starlette"],
|
|
31
|
+
},
|
|
32
|
+
"sqlite": {
|
|
33
|
+
"phrases": [
|
|
34
|
+
"sqlite",
|
|
35
|
+
"wal mode",
|
|
36
|
+
"fts5",
|
|
37
|
+
"full-text search",
|
|
38
|
+
"better-sqlite3",
|
|
39
|
+
"cloudflare d1",
|
|
40
|
+
"json1 extension",
|
|
41
|
+
],
|
|
42
|
+
"terms": ["aiosqlite"],
|
|
43
|
+
},
|
|
44
|
+
"claude-code-headless": {
|
|
45
|
+
"phrases": [
|
|
46
|
+
"headless mode",
|
|
47
|
+
"claude -p",
|
|
48
|
+
"stream-json",
|
|
49
|
+
"agent sdk",
|
|
50
|
+
"claude code headless",
|
|
51
|
+
"run claude in ci",
|
|
52
|
+
"claude in pipeline",
|
|
53
|
+
],
|
|
54
|
+
"terms": [],
|
|
55
|
+
},
|
|
56
|
+
"pydantic-ai": {
|
|
57
|
+
"phrases": [
|
|
58
|
+
"pydantic ai",
|
|
59
|
+
"pydantic-ai",
|
|
60
|
+
"pydanticai",
|
|
61
|
+
"ai agent",
|
|
62
|
+
"runcontext",
|
|
63
|
+
"vercel ai adapter",
|
|
64
|
+
"model fallback",
|
|
65
|
+
],
|
|
66
|
+
"terms": ["pydanticai"],
|
|
67
|
+
},
|
|
68
|
+
"testing": {
|
|
69
|
+
"phrases": [
|
|
70
|
+
"write tests",
|
|
71
|
+
"write a test",
|
|
72
|
+
"add tests",
|
|
73
|
+
"add a test",
|
|
74
|
+
"pytest fixture",
|
|
75
|
+
"vitest config",
|
|
76
|
+
"testing library",
|
|
77
|
+
"mock dependencies",
|
|
78
|
+
"test endpoint",
|
|
79
|
+
"test component",
|
|
80
|
+
"unit test",
|
|
81
|
+
"integration test",
|
|
82
|
+
"run tests",
|
|
83
|
+
"run the tests",
|
|
84
|
+
],
|
|
85
|
+
"terms": ["pytest", "vitest"],
|
|
86
|
+
},
|
|
87
|
+
"docker-py": {
|
|
88
|
+
"phrases": [
|
|
89
|
+
"docker-py",
|
|
90
|
+
"docker py",
|
|
91
|
+
"docker sdk",
|
|
92
|
+
"docker engine api",
|
|
93
|
+
"docker from python",
|
|
94
|
+
"docker api",
|
|
95
|
+
],
|
|
96
|
+
"terms": ["aiodocker"],
|
|
97
|
+
},
|
|
98
|
+
"svelte5": {
|
|
99
|
+
"phrases": [
|
|
100
|
+
"svelte component",
|
|
101
|
+
"sveltekit",
|
|
102
|
+
"svelte kit",
|
|
103
|
+
"svelte rune",
|
|
104
|
+
"svelte 5",
|
|
105
|
+
"svelte5",
|
|
106
|
+
"layercake",
|
|
107
|
+
"layer cake",
|
|
108
|
+
"svelte-dnd-action",
|
|
109
|
+
"svelte dnd",
|
|
110
|
+
],
|
|
111
|
+
"terms": ["sveltekit", "svelte"],
|
|
112
|
+
},
|
|
113
|
+
"docker": {
|
|
114
|
+
"phrases": [
|
|
115
|
+
"dockerfile",
|
|
116
|
+
"docker compose",
|
|
117
|
+
"docker-compose",
|
|
118
|
+
"multi-stage build",
|
|
119
|
+
"health check",
|
|
120
|
+
"healthcheck",
|
|
121
|
+
"docker network",
|
|
122
|
+
"docker volume",
|
|
123
|
+
"docker image",
|
|
124
|
+
],
|
|
125
|
+
"terms": ["dockerfile"],
|
|
126
|
+
},
|
|
127
|
+
"skill-building": {
|
|
128
|
+
"phrases": [
|
|
129
|
+
"build a skill",
|
|
130
|
+
"create a skill",
|
|
131
|
+
"write a skill",
|
|
132
|
+
"skill.md",
|
|
133
|
+
"skill instructions",
|
|
134
|
+
"skill authoring",
|
|
135
|
+
"design a skill",
|
|
136
|
+
],
|
|
137
|
+
"terms": [],
|
|
138
|
+
},
|
|
139
|
+
"debugging": {
|
|
140
|
+
"phrases": [
|
|
141
|
+
"debug logs",
|
|
142
|
+
"check logs",
|
|
143
|
+
"find error",
|
|
144
|
+
"investigate failure",
|
|
145
|
+
"container logs",
|
|
146
|
+
"what went wrong",
|
|
147
|
+
"why did this crash",
|
|
148
|
+
"diagnose the issue",
|
|
149
|
+
"look at the logs",
|
|
150
|
+
"read the logs",
|
|
151
|
+
"analyze error",
|
|
152
|
+
],
|
|
153
|
+
"terms": ["diagnose", "troubleshoot"],
|
|
154
|
+
},
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
# Pre-compile term patterns for whole-word matching
|
|
158
|
+
_TERM_PATTERNS: dict[str, re.Pattern[str]] = {}
|
|
159
|
+
for _skill, _cfg in SKILLS.items():
|
|
160
|
+
for _term in _cfg["terms"]:
|
|
161
|
+
if _term not in _TERM_PATTERNS:
|
|
162
|
+
_TERM_PATTERNS[_term] = re.compile(
|
|
163
|
+
r"\b" + re.escape(_term) + r"\b", re.IGNORECASE
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def match_skills(prompt: str) -> list[str]:
|
|
168
|
+
"""Return sorted list of skill names matching the prompt."""
|
|
169
|
+
lowered = prompt.lower()
|
|
170
|
+
matched: list[str] = []
|
|
171
|
+
|
|
172
|
+
for skill, cfg in SKILLS.items():
|
|
173
|
+
# Check phrases (substring match on lowercased prompt)
|
|
174
|
+
if any(phrase in lowered for phrase in cfg["phrases"]):
|
|
175
|
+
matched.append(skill)
|
|
176
|
+
continue
|
|
177
|
+
|
|
178
|
+
# Check terms (whole-word regex match)
|
|
179
|
+
if any(_TERM_PATTERNS[term].search(prompt) for term in cfg["terms"]):
|
|
180
|
+
matched.append(skill)
|
|
181
|
+
|
|
182
|
+
matched.sort()
|
|
183
|
+
return matched
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def main() -> None:
|
|
187
|
+
raw = sys.stdin.read().strip()
|
|
188
|
+
if not raw:
|
|
189
|
+
return
|
|
190
|
+
|
|
191
|
+
try:
|
|
192
|
+
data = json.loads(raw)
|
|
193
|
+
except json.JSONDecodeError:
|
|
194
|
+
return
|
|
195
|
+
|
|
196
|
+
prompt = data.get("prompt", "")
|
|
197
|
+
if not prompt:
|
|
198
|
+
return
|
|
199
|
+
|
|
200
|
+
skills = match_skills(prompt)
|
|
201
|
+
if not skills:
|
|
202
|
+
return
|
|
203
|
+
|
|
204
|
+
skill_list = ", ".join(f'"{s}"' for s in skills)
|
|
205
|
+
is_subagent = "subagent_type" in data
|
|
206
|
+
|
|
207
|
+
if is_subagent:
|
|
208
|
+
output = {
|
|
209
|
+
"additionalContext": (
|
|
210
|
+
f"Available skills matching this planning task: {skill_list}. "
|
|
211
|
+
"These skills contain project-specific patterns, conventions, "
|
|
212
|
+
"and reference material. Consider their guidance when designing "
|
|
213
|
+
"the implementation approach."
|
|
214
|
+
)
|
|
215
|
+
}
|
|
216
|
+
else:
|
|
217
|
+
output = {
|
|
218
|
+
"systemMessage": (
|
|
219
|
+
f"<system-reminder>The user's prompt matches available skill(s): "
|
|
220
|
+
f"{skill_list}. Load the relevant skill(s) using the Skill tool "
|
|
221
|
+
f"before responding.</system-reminder>"
|
|
222
|
+
)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
json.dump(output, sys.stdout)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
if __name__ == "__main__":
|
|
229
|
+
main()
|
package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/syntax-validator.py
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Data file syntax validator.
|
|
4
|
+
|
|
5
|
+
Validates JSON, JSONC, YAML, and TOML files after editing.
|
|
6
|
+
Uses Python stdlib only (plus PyYAML if available).
|
|
7
|
+
|
|
8
|
+
Reads tool input from stdin, validates syntax, reports errors.
|
|
9
|
+
Non-blocking: always exits 0.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
import os
|
|
14
|
+
import re
|
|
15
|
+
import sys
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
EXTENSIONS = {".json", ".jsonc", ".yaml", ".yml", ".toml"}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def strip_jsonc_comments(text: str) -> str:
|
|
22
|
+
"""Remove // and /* */ comments from JSONC text."""
|
|
23
|
+
# Remove single-line comments (not inside strings)
|
|
24
|
+
text = re.sub(r"(?<!:)//.*$", "", text, flags=re.MULTILINE)
|
|
25
|
+
# Remove multi-line comments
|
|
26
|
+
text = re.sub(r"/\*.*?\*/", "", text, flags=re.DOTALL)
|
|
27
|
+
return text
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def validate_json(file_path: str, is_jsonc: bool) -> str:
|
|
31
|
+
"""Validate JSON/JSONC syntax.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
Error message string, or empty string if valid.
|
|
35
|
+
"""
|
|
36
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
|
37
|
+
content = f.read()
|
|
38
|
+
|
|
39
|
+
if is_jsonc:
|
|
40
|
+
content = strip_jsonc_comments(content)
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
json.loads(content)
|
|
44
|
+
return ""
|
|
45
|
+
except json.JSONDecodeError as e:
|
|
46
|
+
return f"[Syntax] JSON error at line {e.lineno}, col {e.colno}: {e.msg}"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def validate_yaml(file_path: str) -> str:
|
|
50
|
+
"""Validate YAML syntax.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Error message string, or empty string if valid.
|
|
54
|
+
"""
|
|
55
|
+
try:
|
|
56
|
+
import yaml
|
|
57
|
+
except ImportError:
|
|
58
|
+
return "" # PyYAML not available, skip
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
|
62
|
+
yaml.safe_load(f)
|
|
63
|
+
return ""
|
|
64
|
+
except yaml.YAMLError as e:
|
|
65
|
+
if hasattr(e, "problem_mark"):
|
|
66
|
+
mark = e.problem_mark
|
|
67
|
+
return f"[Syntax] YAML error at line {mark.line + 1}, col {mark.column + 1}: {e.problem}"
|
|
68
|
+
return f"[Syntax] YAML error: {e}"
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def validate_toml(file_path: str) -> str:
|
|
72
|
+
"""Validate TOML syntax.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
Error message string, or empty string if valid.
|
|
76
|
+
"""
|
|
77
|
+
try:
|
|
78
|
+
import tomllib
|
|
79
|
+
except ImportError:
|
|
80
|
+
return "" # Python < 3.11, skip
|
|
81
|
+
|
|
82
|
+
try:
|
|
83
|
+
with open(file_path, "rb") as f:
|
|
84
|
+
tomllib.load(f)
|
|
85
|
+
return ""
|
|
86
|
+
except tomllib.TOMLDecodeError as e:
|
|
87
|
+
return f"[Syntax] TOML error: {e}"
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def validate(file_path: str) -> str:
|
|
91
|
+
"""Validate file syntax based on extension.
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
Error message string, or empty string if valid.
|
|
95
|
+
"""
|
|
96
|
+
ext = Path(file_path).suffix.lower()
|
|
97
|
+
|
|
98
|
+
if ext == ".jsonc":
|
|
99
|
+
return validate_json(file_path, is_jsonc=True)
|
|
100
|
+
elif ext == ".json":
|
|
101
|
+
return validate_json(file_path, is_jsonc=False)
|
|
102
|
+
elif ext in {".yaml", ".yml"}:
|
|
103
|
+
return validate_yaml(file_path)
|
|
104
|
+
elif ext == ".toml":
|
|
105
|
+
return validate_toml(file_path)
|
|
106
|
+
|
|
107
|
+
return ""
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def main():
|
|
111
|
+
try:
|
|
112
|
+
input_data = json.load(sys.stdin)
|
|
113
|
+
tool_input = input_data.get("tool_input", {})
|
|
114
|
+
file_path = tool_input.get("file_path", "")
|
|
115
|
+
|
|
116
|
+
if not file_path:
|
|
117
|
+
sys.exit(0)
|
|
118
|
+
|
|
119
|
+
ext = Path(file_path).suffix.lower()
|
|
120
|
+
if ext not in EXTENSIONS:
|
|
121
|
+
sys.exit(0)
|
|
122
|
+
|
|
123
|
+
if not os.path.isfile(file_path):
|
|
124
|
+
sys.exit(0)
|
|
125
|
+
|
|
126
|
+
message = validate(file_path)
|
|
127
|
+
|
|
128
|
+
if message:
|
|
129
|
+
print(json.dumps({"additionalContext": message}))
|
|
130
|
+
|
|
131
|
+
sys.exit(0)
|
|
132
|
+
|
|
133
|
+
except json.JSONDecodeError:
|
|
134
|
+
sys.exit(0)
|
|
135
|
+
except Exception as e:
|
|
136
|
+
print(f"Hook error: {e}", file=sys.stderr)
|
|
137
|
+
sys.exit(0)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
if __name__ == "__main__":
|
|
141
|
+
main()
|
package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/debugging/SKILL.md
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: debugging
|
|
3
|
+
description: >-
|
|
4
|
+
This skill should be used when the user asks to "debug logs", "check logs",
|
|
5
|
+
"find error in logs", "read docker logs", "investigate failure",
|
|
6
|
+
"check container logs", "analyze error output", "find what went wrong",
|
|
7
|
+
"why did this crash", "check what happened", "diagnose the issue",
|
|
8
|
+
"look at the logs", or discusses log analysis, container debugging,
|
|
9
|
+
error investigation, crash diagnosis, or service failure troubleshooting.
|
|
10
|
+
version: 0.1.0
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Debugging & Log Analysis
|
|
14
|
+
|
|
15
|
+
## Mental Model
|
|
16
|
+
|
|
17
|
+
Logs are **forensic evidence**. Debugging is a scientific method: observe symptoms, form hypotheses, gather evidence, test hypotheses, converge on root cause.
|
|
18
|
+
|
|
19
|
+
Every running system produces a trail of structured and unstructured log entries. Errors rarely happen in isolation — they cascade. The first error in a sequence is usually the root cause; everything after it is a consequence. Your job is to find that first domino.
|
|
20
|
+
|
|
21
|
+
**Key principles:**
|
|
22
|
+
- **Broad scan, then narrow focus.** Don't assume you know where the problem is. Survey all available log sources first, then zoom in on anomalies.
|
|
23
|
+
- **Chronology is king.** Timestamps tell you the order of events. The order of events tells you causality.
|
|
24
|
+
- **Absence of evidence is evidence.** If a service has no error logs, that's useful information — the problem is elsewhere.
|
|
25
|
+
- **Correlation across sources.** A single log source gives you symptoms. Multiple correlated sources give you root causes.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Log Discovery by Environment
|
|
30
|
+
|
|
31
|
+
| Environment | Primary Sources | Key Commands |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| **Docker** | Container stdout/stderr, Docker events | `docker logs`, `docker ps -a`, `docker inspect`, `docker events` |
|
|
34
|
+
| **Docker Compose** | Aggregated service logs | `docker compose logs`, `docker compose ps` |
|
|
35
|
+
| **Linux systemd** | Journal, syslog | `journalctl -u <service>`, `journalctl -k` |
|
|
36
|
+
| **Python / FastAPI** | Uvicorn stderr, application loggers | Check `logging.conf`, `UVICORN_LOG_LEVEL`, stdout |
|
|
37
|
+
| **Node.js** | Console output, PM2 logs | `~/.pm2/logs/`, application `logs/` directory |
|
|
38
|
+
| **Nginx** | Access & error logs | `/var/log/nginx/error.log`, `/var/log/nginx/access.log` |
|
|
39
|
+
| **PostgreSQL** | Server log | `/var/log/postgresql/`, `pg_log/` |
|
|
40
|
+
| **Redis** | Server log | `/var/log/redis/`, `redis-server.log` |
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Common Log Locations Quick Reference
|
|
45
|
+
|
|
46
|
+
**System:**
|
|
47
|
+
- `/var/log/syslog` or `/var/log/messages` — General system log
|
|
48
|
+
- `/var/log/kern.log` — Kernel messages (OOM killer lives here)
|
|
49
|
+
- `/var/log/auth.log` — Authentication events
|
|
50
|
+
- `journalctl` — systemd journal (binary, query with flags)
|
|
51
|
+
|
|
52
|
+
**Docker:**
|
|
53
|
+
- Container logs via `docker logs <name>` (stored at `/var/lib/docker/containers/<id>/<id>-json.log`)
|
|
54
|
+
- Docker daemon: `/var/log/docker.log` or `journalctl -u docker`
|
|
55
|
+
|
|
56
|
+
**Applications:**
|
|
57
|
+
- Project `./logs/` directory
|
|
58
|
+
- Framework defaults (see reference files for exhaustive list)
|
|
59
|
+
- `/tmp/*.log` for transient application logs
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Docker Log Analysis
|
|
64
|
+
|
|
65
|
+
Docker captures everything a container writes to stdout and stderr. This is your primary source in containerized environments.
|
|
66
|
+
|
|
67
|
+
**Essential commands:**
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Overview: what's running, what's dead
|
|
71
|
+
docker ps -a --format "table {{.Names}}\t{{.Status}}\t{{.Image}}"
|
|
72
|
+
|
|
73
|
+
# Recent logs with timestamps
|
|
74
|
+
docker logs --tail 200 --timestamps <container>
|
|
75
|
+
|
|
76
|
+
# Time-windowed logs
|
|
77
|
+
docker logs --since "30m" <container>
|
|
78
|
+
|
|
79
|
+
# All Compose services, interleaved chronologically
|
|
80
|
+
docker compose logs --tail 100 --timestamps
|
|
81
|
+
|
|
82
|
+
# Container health and exit info
|
|
83
|
+
docker inspect --format '{{json .State}}' <container> | python3 -m json.tool
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Exit code interpretation:**
|
|
87
|
+
- `0` — Clean exit
|
|
88
|
+
- `1` — Generic application error
|
|
89
|
+
- `2` — Misuse of shell command
|
|
90
|
+
- `126` — Cannot execute (permission denied on entrypoint)
|
|
91
|
+
- `127` — Command not found (bad entrypoint/CMD)
|
|
92
|
+
- `137` — SIGKILL (OOM killer or forced kill)
|
|
93
|
+
- `143` — SIGTERM (graceful shutdown timeout)
|
|
94
|
+
- `255` — Exit status out of range
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Log Format Parsing
|
|
99
|
+
|
|
100
|
+
**JSON logs** (common with structured logging frameworks):
|
|
101
|
+
```bash
|
|
102
|
+
# Parse JSON logs with jq
|
|
103
|
+
docker logs <container> 2>&1 | python3 -c "
|
|
104
|
+
import sys, json
|
|
105
|
+
for line in sys.stdin:
|
|
106
|
+
try:
|
|
107
|
+
obj = json.loads(line)
|
|
108
|
+
level = obj.get('level', obj.get('levelname', '?'))
|
|
109
|
+
msg = obj.get('message', obj.get('msg', line.strip()))
|
|
110
|
+
print(f'{level}: {msg}')
|
|
111
|
+
except json.JSONDecodeError:
|
|
112
|
+
print(line.strip())
|
|
113
|
+
"
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Python tracebacks** — Multi-line. Look for `Traceback (most recent call last):` as the start marker. The actual error is the **last line** of the traceback block.
|
|
117
|
+
|
|
118
|
+
**Stack traces** (Java, Go, Node) — Look for `at `, `goroutine`, or `Error:` as anchors. The top frame is where the error was thrown; the bottom frame is the entry point.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Error Pattern Recognition
|
|
123
|
+
|
|
124
|
+
**Connection errors:**
|
|
125
|
+
- `ECONNREFUSED` / `Connection refused` — Target service isn't running or isn't listening on expected port
|
|
126
|
+
- `ETIMEDOUT` / `Connection timed out` — Network unreachable or firewall blocking
|
|
127
|
+
- `ENOTFOUND` / `Name resolution failed` — DNS failure, usually wrong hostname in config
|
|
128
|
+
|
|
129
|
+
**Resource exhaustion:**
|
|
130
|
+
- `OOMKilled` / `Killed` / exit code 137 — Container exceeded memory limit
|
|
131
|
+
- `No space left on device` — Disk full (check `df -h`, Docker image/volume storage)
|
|
132
|
+
- `Too many open files` — File descriptor limit hit
|
|
133
|
+
|
|
134
|
+
**Permission errors:**
|
|
135
|
+
- `EACCES` / `Permission denied` — File/directory ownership mismatch
|
|
136
|
+
- `EPERM` / `Operation not permitted` — Capability or security context restriction
|
|
137
|
+
- Docker socket permission — User not in `docker` group
|
|
138
|
+
|
|
139
|
+
**Application errors:**
|
|
140
|
+
- `Unhandled promise rejection` / `UnhandledPromiseRejection` — Node.js async error
|
|
141
|
+
- `Traceback (most recent call last)` — Python unhandled exception
|
|
142
|
+
- `panic:` — Go runtime panic
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Ambiguity Policy
|
|
147
|
+
|
|
148
|
+
When the user's request is ambiguous, apply these defaults:
|
|
149
|
+
|
|
150
|
+
| Ambiguity | Default |
|
|
151
|
+
|---|---|
|
|
152
|
+
| **Scope not specified** | Check ALL available sources (Docker first, then files, then system) |
|
|
153
|
+
| **Timeframe not specified** | Last 1 hour |
|
|
154
|
+
| **Severity not specified** | Report ERROR and CRITICAL first, then WARNING if relevant |
|
|
155
|
+
| **Service not specified** | Scan all running containers and accessible log files |
|
|
156
|
+
| **"It's not working"** | Broad scan for any error-level entries in the last hour |
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Reference Files
|
|
161
|
+
|
|
162
|
+
| File | Contents |
|
|
163
|
+
|---|---|
|
|
164
|
+
| [Log Locations](references/log-locations.md) | Exhaustive reference of log file paths organized by system, Docker, Python, Node.js, databases, and web servers |
|
|
165
|
+
| [Error Patterns](references/error-patterns.md) | Error pattern catalog with symptoms, diagnosis commands, and resolutions for connection, resource, permission, application, and Docker-specific errors |
|