codeforge-dev 1.13.0 → 1.14.2
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 +146 -4
- package/.devcontainer/CLAUDE.md +61 -276
- package/.devcontainer/README.md +1 -1
- package/.devcontainer/config/defaults/ccstatusline-settings.json +147 -0
- package/.devcontainer/config/defaults/main-system-prompt.md +6 -1
- package/.devcontainer/config/defaults/rules/spec-workflow.md +1 -55
- package/.devcontainer/config/file-manifest.json +14 -0
- package/.devcontainer/devcontainer.json +19 -1
- package/.devcontainer/docs/optional-features.md +0 -65
- package/.devcontainer/docs/plugins.md +38 -23
- package/.devcontainer/features/ast-grep/devcontainer-feature.json +0 -1
- package/.devcontainer/features/biome/install.sh +13 -0
- package/.devcontainer/features/ccburn/devcontainer-feature.json +0 -6
- package/.devcontainer/features/ccms/devcontainer-feature.json +0 -1
- package/.devcontainer/features/ccms/install.sh +1 -1
- package/.devcontainer/features/ccstatusline/devcontainer-feature.json +0 -1
- package/.devcontainer/features/ccstatusline/install.sh +17 -115
- package/.devcontainer/features/ccusage/devcontainer-feature.json +0 -6
- package/.devcontainer/features/chromaterm/README.md +42 -0
- package/.devcontainer/features/chromaterm/chromaterm.yml +35 -0
- package/.devcontainer/features/chromaterm/devcontainer-feature.json +22 -0
- package/.devcontainer/features/chromaterm/install.sh +113 -0
- package/.devcontainer/features/claude-monitor/devcontainer-feature.json +0 -6
- package/.devcontainer/features/claude-session-dashboard/README.md +2 -2
- package/.devcontainer/features/claude-session-dashboard/devcontainer-feature.json +2 -4
- package/.devcontainer/features/claude-session-dashboard/install.sh +2 -2
- package/.devcontainer/features/kitty-terminfo/README.md +32 -0
- package/.devcontainer/features/kitty-terminfo/devcontainer-feature.json +13 -0
- package/.devcontainer/features/kitty-terminfo/install.sh +72 -0
- package/.devcontainer/features/lsp-servers/devcontainer-feature.json +0 -1
- package/.devcontainer/features/mcp-qdrant/devcontainer-feature.json +0 -7
- package/.devcontainer/features/shellcheck/install.sh +6 -2
- package/.devcontainer/features/tree-sitter/devcontainer-feature.json +0 -7
- package/.devcontainer/plugins/devs-marketplace/.claude-plugin/marketplace.json +37 -69
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/.claude-plugin/plugin.json +0 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/README.md +197 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/architect.md +3 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/bash-exec.md +3 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/claude-guide.md +4 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/debug-logs.md +6 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/dependency-analyst.md +5 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/doc-writer.md +4 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/explorer.md +3 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/generalist.md +9 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/git-archaeologist.md +3 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/migrator.md +4 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/perf-profiler.md +4 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/refactorer.md +5 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/researcher.md +5 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/security-auditor.md +4 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/spec-writer.md +3 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/statusline-config.md +4 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/test-writer.md +4 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/hooks/hooks.json +23 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/guard-readonly-bash.py +2 -2
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/inject-cwd.py +7 -4
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/task-completed-check.py +166 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/teammate-idle-check.py +81 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/verify-no-regression.py +14 -10
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/verify-tests-pass.py +2 -14
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/README.md +17 -31
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/hooks/hooks.json +5 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/scripts/advisory-test-runner.py +9 -8
- package/.devcontainer/plugins/devs-marketplace/plugins/codeforge-lsp/README.md +28 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/README.md +28 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/scripts/block-dangerous.py +2 -2
- package/.devcontainer/plugins/devs-marketplace/plugins/notify-hook/README.md +28 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/notify-hook/hooks/hooks.json +0 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/README.md +28 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/guard-protected-bash.py +1 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/guard-protected.py +2 -2
- package/.devcontainer/plugins/devs-marketplace/plugins/session-context/.claude-plugin/plugin.json +0 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/session-context/README.md +140 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/session-context/hooks/hooks.json +0 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/session-context/scripts/commit-reminder.py +3 -2
- package/.devcontainer/plugins/devs-marketplace/plugins/session-context/scripts/git-state-injector.py +18 -2
- package/.devcontainer/plugins/devs-marketplace/plugins/session-context/scripts/todo-harvester.py +9 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/.claude-plugin/plugin.json +0 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/README.md +158 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/hooks/hooks.json +1 -14
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/scripts/skill-suggester.py +189 -100
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/api-design/SKILL.md +9 -6
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/ast-grep-patterns/SKILL.md +7 -6
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/claude-agent-sdk/SKILL.md +8 -8
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/claude-code-headless/SKILL.md +8 -9
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/debugging/SKILL.md +11 -7
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/dependency-management/SKILL.md +10 -6
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/docker/SKILL.md +8 -8
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/docker-py/SKILL.md +9 -7
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/documentation-patterns/SKILL.md +7 -6
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/fastapi/SKILL.md +9 -8
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/git-forensics/SKILL.md +11 -9
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/migration-patterns/SKILL.md +7 -6
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/performance-profiling/SKILL.md +10 -8
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/pydantic-ai/SKILL.md +8 -7
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/refactoring-patterns/SKILL.md +9 -8
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/security-checklist/SKILL.md +9 -8
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/skill-building/SKILL.md +7 -7
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/sqlite/SKILL.md +9 -7
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/svelte5/SKILL.md +7 -8
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/team/SKILL.md +71 -5
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/testing/SKILL.md +10 -7
- package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/.claude-plugin/plugin.json +0 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/README.md +192 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/hooks/hooks.json +0 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/scripts/spec-reminder.py +3 -2
- package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-build/SKILL.md +9 -6
- package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-check/SKILL.md +10 -5
- package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-init/SKILL.md +8 -4
- package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-new/SKILL.md +8 -4
- package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-refine/SKILL.md +10 -7
- package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-review/SKILL.md +10 -6
- package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-update/SKILL.md +10 -5
- package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/specification-writing/SKILL.md +9 -9
- package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/plugin.json +1 -2
- package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/README.md +28 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/hooks/hooks.json +0 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/scripts/ticket-linker.py +9 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/README.md +104 -32
- package/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/hooks/hooks.json +49 -3
- package/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/scripts/guard-workspace-scope.py +269 -56
- package/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/scripts/inject-workspace-cwd.py +44 -0
- package/.devcontainer/scripts/setup-aliases.sh +13 -5
- package/.devcontainer/scripts/setup-config.sh +1 -0
- package/README.md +5 -5
- package/package.json +6 -2
- package/setup.js +3 -2
- package/.devcontainer/.env +0 -33
- package/.devcontainer/features/README.md +0 -126
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/.claude-plugin/plugin.json +0 -7
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/README.md +0 -81
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/hooks/hooks.json +0 -17
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/scripts/__pycache__/format-on-stop.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/scripts/format-on-stop.py +0 -297
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/.claude-plugin/plugin.json +0 -7
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/README.md +0 -92
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/hooks/hooks.json +0 -17
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/scripts/__pycache__/lint-file.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/scripts/lint-file.py +0 -536
- package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/scripts/__pycache__/block-dangerous.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/__pycache__/guard-protected.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/system-prompt.md +0 -184
- package/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/scripts/__pycache__/guard-workspace-scope.cpython-314.pyc +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/{.claude-plugin/commands/debug.md → skills/debug/SKILL.md} +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/{.claude-plugin/commands/ticket/357/200/272create-pr.md" → skills/ticketcreate-pr/SKILL.md} +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/{.claude-plugin/commands/ticket/357/200/272new.md" → skills/ticketnew/SKILL.md} +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/{.claude-plugin/commands/ticket/357/200/272review-commit.md" → skills/ticketreview-commit/SKILL.md} +0 -0
- /package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/{.claude-plugin/commands/ticket/357/200/272work.md" → skills/ticketwork/SKILL.md} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "Agent redirection
|
|
2
|
+
"description": "Agent redirection, subagent configuration, and team quality gate hooks",
|
|
3
3
|
"hooks": {
|
|
4
4
|
"PreToolUse": [
|
|
5
5
|
{
|
|
@@ -24,6 +24,28 @@
|
|
|
24
24
|
}
|
|
25
25
|
]
|
|
26
26
|
}
|
|
27
|
+
],
|
|
28
|
+
"TeammateIdle": [
|
|
29
|
+
{
|
|
30
|
+
"hooks": [
|
|
31
|
+
{
|
|
32
|
+
"type": "command",
|
|
33
|
+
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/teammate-idle-check.py",
|
|
34
|
+
"timeout": 10
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"TaskCompleted": [
|
|
40
|
+
{
|
|
41
|
+
"hooks": [
|
|
42
|
+
{
|
|
43
|
+
"type": "command",
|
|
44
|
+
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/task-completed-check.py",
|
|
45
|
+
"timeout": 60
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
27
49
|
]
|
|
28
50
|
}
|
|
29
51
|
}
|
package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/guard-readonly-bash.py
CHANGED
|
@@ -12,7 +12,7 @@ command substitution ($(), backticks), backgrounding (&), redirections
|
|
|
12
12
|
(>, >>), eval/exec, inline scripting (python -c, node -e), and
|
|
13
13
|
path/backslash prefix bypasses (/usr/bin/rm, \\rm).
|
|
14
14
|
|
|
15
|
-
Reads tool input from stdin (JSON).
|
|
15
|
+
Reads tool input from stdin (JSON). Outputs block reason to stderr.
|
|
16
16
|
Exit 0: Command is safe (allowed)
|
|
17
17
|
Exit 2: Command would modify state (blocked)
|
|
18
18
|
"""
|
|
@@ -601,7 +601,7 @@ def main():
|
|
|
601
601
|
error = check_general_readonly(command)
|
|
602
602
|
|
|
603
603
|
if error:
|
|
604
|
-
|
|
604
|
+
print(error, file=sys.stderr)
|
|
605
605
|
sys.exit(2)
|
|
606
606
|
|
|
607
607
|
sys.exit(0)
|
|
@@ -23,10 +23,13 @@ def main():
|
|
|
23
23
|
|
|
24
24
|
json.dump(
|
|
25
25
|
{
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
"hookSpecificOutput": {
|
|
27
|
+
"hookEventName": "SubagentStart",
|
|
28
|
+
"additionalContext": (
|
|
29
|
+
f"Working Directory: {cwd} — restrict all file operations to "
|
|
30
|
+
f"this directory unless explicitly instructed otherwise."
|
|
31
|
+
),
|
|
32
|
+
}
|
|
30
33
|
},
|
|
31
34
|
sys.stdout,
|
|
32
35
|
)
|
package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/task-completed-check.py
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
TaskCompleted quality gate — runs project test suite before allowing completion.
|
|
4
|
+
|
|
5
|
+
Detects the project's test framework and runs it. If tests fail, the task
|
|
6
|
+
stays open and the teammate receives feedback to fix the failures.
|
|
7
|
+
|
|
8
|
+
Exit 0: Tests pass (or no test framework / runner not installed)
|
|
9
|
+
Exit 2: Tests fail (task stays open, feedback sent via stderr)
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
import os
|
|
14
|
+
import subprocess
|
|
15
|
+
import sys
|
|
16
|
+
|
|
17
|
+
TIMEOUT_SECONDS = 60
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def detect_test_framework(cwd: str) -> tuple[str, list[str]]:
|
|
21
|
+
"""Detect which test framework is available in the project.
|
|
22
|
+
|
|
23
|
+
Checks for: pytest, vitest, jest, mocha, go test, cargo test.
|
|
24
|
+
Falls back to npm test if a test script is defined.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
Tuple of (framework_name, command_list) or ("", []) if none found.
|
|
28
|
+
"""
|
|
29
|
+
try:
|
|
30
|
+
entries = set(os.listdir(cwd))
|
|
31
|
+
except OSError:
|
|
32
|
+
return ("", [])
|
|
33
|
+
|
|
34
|
+
# Python: pytest
|
|
35
|
+
if "pytest.ini" in entries or "conftest.py" in entries:
|
|
36
|
+
return ("pytest", ["python3", "-m", "pytest", "--tb=short", "-q"])
|
|
37
|
+
|
|
38
|
+
for cfg_name in ("pyproject.toml", "setup.cfg", "tox.ini"):
|
|
39
|
+
cfg_path = os.path.join(cwd, cfg_name)
|
|
40
|
+
if os.path.isfile(cfg_path):
|
|
41
|
+
try:
|
|
42
|
+
with open(cfg_path, "r", encoding="utf-8") as f:
|
|
43
|
+
content = f.read()
|
|
44
|
+
if any(
|
|
45
|
+
marker in content
|
|
46
|
+
for marker in ("[tool.pytest", "[pytest]", "[tool:pytest]")
|
|
47
|
+
):
|
|
48
|
+
return ("pytest", ["python3", "-m", "pytest", "--tb=short", "-q"])
|
|
49
|
+
except OSError:
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
if "tests" in entries and os.path.isdir(os.path.join(cwd, "tests")):
|
|
53
|
+
return ("pytest", ["python3", "-m", "pytest", "--tb=short", "-q"])
|
|
54
|
+
|
|
55
|
+
for entry in entries:
|
|
56
|
+
if entry.startswith("test_") and entry.endswith(".py"):
|
|
57
|
+
return ("pytest", ["python3", "-m", "pytest", "--tb=short", "-q"])
|
|
58
|
+
|
|
59
|
+
# JavaScript: vitest
|
|
60
|
+
for name in entries:
|
|
61
|
+
if name.startswith("vitest.config"):
|
|
62
|
+
return ("vitest", ["npx", "vitest", "run", "--reporter=verbose"])
|
|
63
|
+
|
|
64
|
+
for vite_cfg in ("vite.config.ts", "vite.config.js"):
|
|
65
|
+
cfg_path = os.path.join(cwd, vite_cfg)
|
|
66
|
+
if os.path.isfile(cfg_path):
|
|
67
|
+
try:
|
|
68
|
+
with open(cfg_path, "r", encoding="utf-8") as f:
|
|
69
|
+
if "test" in f.read():
|
|
70
|
+
return (
|
|
71
|
+
"vitest",
|
|
72
|
+
["npx", "vitest", "run", "--reporter=verbose"],
|
|
73
|
+
)
|
|
74
|
+
except OSError:
|
|
75
|
+
pass
|
|
76
|
+
|
|
77
|
+
# JavaScript: jest
|
|
78
|
+
for name in entries:
|
|
79
|
+
if name.startswith("jest.config"):
|
|
80
|
+
return ("jest", ["npx", "jest", "--verbose"])
|
|
81
|
+
|
|
82
|
+
pkg_json = os.path.join(cwd, "package.json")
|
|
83
|
+
if os.path.isfile(pkg_json):
|
|
84
|
+
try:
|
|
85
|
+
with open(pkg_json, "r", encoding="utf-8") as f:
|
|
86
|
+
pkg = json.loads(f.read())
|
|
87
|
+
|
|
88
|
+
if "jest" in pkg:
|
|
89
|
+
return ("jest", ["npx", "jest", "--verbose"])
|
|
90
|
+
|
|
91
|
+
dev_deps = pkg.get("devDependencies", {})
|
|
92
|
+
deps = pkg.get("dependencies", {})
|
|
93
|
+
|
|
94
|
+
if "mocha" in dev_deps or "mocha" in deps:
|
|
95
|
+
return ("mocha", ["npx", "mocha", "--reporter", "spec"])
|
|
96
|
+
|
|
97
|
+
test_script = pkg.get("scripts", {}).get("test", "")
|
|
98
|
+
if test_script and "no test specified" not in test_script:
|
|
99
|
+
return ("npm-test", ["npm", "test"])
|
|
100
|
+
except (OSError, json.JSONDecodeError):
|
|
101
|
+
pass
|
|
102
|
+
|
|
103
|
+
# Go
|
|
104
|
+
if "go.mod" in entries:
|
|
105
|
+
return ("go", ["go", "test", "./...", "-count=1"])
|
|
106
|
+
|
|
107
|
+
# Rust
|
|
108
|
+
if "Cargo.toml" in entries:
|
|
109
|
+
return ("cargo", ["cargo", "test"])
|
|
110
|
+
|
|
111
|
+
return ("", [])
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def main():
|
|
115
|
+
try:
|
|
116
|
+
json.load(sys.stdin)
|
|
117
|
+
except (json.JSONDecodeError, ValueError):
|
|
118
|
+
pass
|
|
119
|
+
|
|
120
|
+
cwd = os.getcwd()
|
|
121
|
+
framework, cmd = detect_test_framework(cwd)
|
|
122
|
+
|
|
123
|
+
if not framework:
|
|
124
|
+
sys.exit(0)
|
|
125
|
+
|
|
126
|
+
try:
|
|
127
|
+
result = subprocess.run(
|
|
128
|
+
cmd,
|
|
129
|
+
cwd=cwd,
|
|
130
|
+
capture_output=True,
|
|
131
|
+
text=True,
|
|
132
|
+
timeout=TIMEOUT_SECONDS,
|
|
133
|
+
)
|
|
134
|
+
except subprocess.TimeoutExpired:
|
|
135
|
+
# Timeout is not a definitive failure — allow completion but warn
|
|
136
|
+
print(
|
|
137
|
+
f"Tests timed out ({framework}, {TIMEOUT_SECONDS}s). "
|
|
138
|
+
f"Task completion allowed — verify tests manually.",
|
|
139
|
+
file=sys.stderr,
|
|
140
|
+
)
|
|
141
|
+
sys.exit(0)
|
|
142
|
+
except FileNotFoundError:
|
|
143
|
+
sys.exit(0)
|
|
144
|
+
except OSError:
|
|
145
|
+
sys.exit(0)
|
|
146
|
+
|
|
147
|
+
if result.returncode == 0:
|
|
148
|
+
sys.exit(0)
|
|
149
|
+
|
|
150
|
+
output = (result.stdout + "\n" + result.stderr).strip()
|
|
151
|
+
if not output:
|
|
152
|
+
output = "(no test output)"
|
|
153
|
+
|
|
154
|
+
lines = output.splitlines()
|
|
155
|
+
if len(lines) > 50:
|
|
156
|
+
output = "...(truncated)\n" + "\n".join(lines[-50:])
|
|
157
|
+
|
|
158
|
+
print(
|
|
159
|
+
f"Tests failed ({framework}). Fix failures before marking task complete:\n{output}",
|
|
160
|
+
file=sys.stderr,
|
|
161
|
+
)
|
|
162
|
+
sys.exit(2)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
if __name__ == "__main__":
|
|
166
|
+
main()
|
package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/teammate-idle-check.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
TeammateIdle quality gate — checks if teammate has incomplete tasks.
|
|
4
|
+
|
|
5
|
+
Runs when a teammate is about to go idle. Queries the shared task list
|
|
6
|
+
directory for tasks assigned to this teammate that aren't yet completed.
|
|
7
|
+
|
|
8
|
+
Exit 0: Allow idle (no incomplete tasks or unable to determine)
|
|
9
|
+
Exit 2: Send feedback via stderr (incomplete tasks found)
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
import os
|
|
14
|
+
import sys
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def find_incomplete_tasks(teammate_name: str) -> list[str]:
|
|
18
|
+
"""Scan task directories for incomplete tasks owned by this teammate."""
|
|
19
|
+
config_dir = os.environ.get("CLAUDE_CONFIG_DIR", os.path.expanduser("~/.claude"))
|
|
20
|
+
tasks_base = os.path.join(config_dir, "tasks")
|
|
21
|
+
|
|
22
|
+
if not os.path.isdir(tasks_base):
|
|
23
|
+
return []
|
|
24
|
+
|
|
25
|
+
incomplete = []
|
|
26
|
+
for entry in os.listdir(tasks_base):
|
|
27
|
+
team_dir = os.path.join(tasks_base, entry)
|
|
28
|
+
if not os.path.isdir(team_dir):
|
|
29
|
+
continue
|
|
30
|
+
|
|
31
|
+
for filename in sorted(os.listdir(team_dir)):
|
|
32
|
+
if not filename.endswith(".json"):
|
|
33
|
+
continue
|
|
34
|
+
|
|
35
|
+
task_path = os.path.join(team_dir, filename)
|
|
36
|
+
try:
|
|
37
|
+
with open(task_path, "r", encoding="utf-8") as f:
|
|
38
|
+
task = json.load(f)
|
|
39
|
+
|
|
40
|
+
owner = task.get("owner", "")
|
|
41
|
+
status = task.get("status", "")
|
|
42
|
+
subject = task.get("subject", filename)
|
|
43
|
+
|
|
44
|
+
if owner == teammate_name and status in ("pending", "in_progress"):
|
|
45
|
+
incomplete.append(subject)
|
|
46
|
+
except (OSError, json.JSONDecodeError, ValueError):
|
|
47
|
+
continue
|
|
48
|
+
|
|
49
|
+
return incomplete
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def main():
|
|
53
|
+
try:
|
|
54
|
+
input_data = json.load(sys.stdin)
|
|
55
|
+
except (json.JSONDecodeError, ValueError):
|
|
56
|
+
sys.exit(0)
|
|
57
|
+
|
|
58
|
+
teammate_name = (
|
|
59
|
+
input_data.get("teammate_name")
|
|
60
|
+
or input_data.get("agent_name")
|
|
61
|
+
or ""
|
|
62
|
+
)
|
|
63
|
+
if not teammate_name:
|
|
64
|
+
sys.exit(0)
|
|
65
|
+
|
|
66
|
+
incomplete = find_incomplete_tasks(teammate_name)
|
|
67
|
+
if not incomplete:
|
|
68
|
+
sys.exit(0)
|
|
69
|
+
|
|
70
|
+
task_list = "; ".join(incomplete[:5])
|
|
71
|
+
suffix = f" (and {len(incomplete) - 5} more)" if len(incomplete) > 5 else ""
|
|
72
|
+
print(
|
|
73
|
+
f"You have {len(incomplete)} incomplete task(s): {task_list}{suffix}. "
|
|
74
|
+
f"Check TaskList and continue working before going idle.",
|
|
75
|
+
file=sys.stderr,
|
|
76
|
+
)
|
|
77
|
+
sys.exit(2)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
if __name__ == "__main__":
|
|
81
|
+
main()
|
package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/verify-no-regression.py
CHANGED
|
@@ -178,7 +178,10 @@ def main():
|
|
|
178
178
|
# Timeout is non-critical for PostToolUse — don't block the agent
|
|
179
179
|
json.dump(
|
|
180
180
|
{
|
|
181
|
-
"
|
|
181
|
+
"hookSpecificOutput": {
|
|
182
|
+
"hookEventName": "PostToolUse",
|
|
183
|
+
"additionalContext": f"[Tests] {framework} timed out after 60s — skipping regression check.",
|
|
184
|
+
}
|
|
182
185
|
},
|
|
183
186
|
sys.stdout,
|
|
184
187
|
)
|
|
@@ -199,19 +202,20 @@ def main():
|
|
|
199
202
|
|
|
200
203
|
if result.returncode != 0:
|
|
201
204
|
edited = os.path.basename(file_path)
|
|
202
|
-
|
|
203
|
-
{
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
f"({framework}). Fix the failing tests before continuing:\n{output}"
|
|
207
|
-
)
|
|
208
|
-
},
|
|
209
|
-
sys.stdout,
|
|
205
|
+
print(
|
|
206
|
+
f"Regression detected after editing {edited} "
|
|
207
|
+
f"({framework}). Fix the failing tests before continuing:\n{output}",
|
|
208
|
+
file=sys.stderr,
|
|
210
209
|
)
|
|
211
210
|
sys.exit(2)
|
|
212
211
|
|
|
213
212
|
json.dump(
|
|
214
|
-
{
|
|
213
|
+
{
|
|
214
|
+
"hookSpecificOutput": {
|
|
215
|
+
"hookEventName": "PostToolUse",
|
|
216
|
+
"additionalContext": f"[Tests] No regression ({framework}): all tests passed",
|
|
217
|
+
}
|
|
218
|
+
},
|
|
215
219
|
sys.stdout,
|
|
216
220
|
)
|
|
217
221
|
sys.exit(0)
|
package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/verify-tests-pass.py
CHANGED
|
@@ -136,12 +136,7 @@ def main():
|
|
|
136
136
|
timeout=60,
|
|
137
137
|
)
|
|
138
138
|
except subprocess.TimeoutExpired:
|
|
139
|
-
|
|
140
|
-
{
|
|
141
|
-
"additionalContext": f"[Tests] {framework} timed out after 60s. Consider running tests manually."
|
|
142
|
-
},
|
|
143
|
-
sys.stdout,
|
|
144
|
-
)
|
|
139
|
+
print(f"Tests timed out ({framework})", file=sys.stderr)
|
|
145
140
|
sys.exit(2)
|
|
146
141
|
except FileNotFoundError:
|
|
147
142
|
# Test runner not installed — non-critical
|
|
@@ -159,16 +154,9 @@ def main():
|
|
|
159
154
|
output = "...(truncated)\n" + "\n".join(lines[-50:])
|
|
160
155
|
|
|
161
156
|
if result.returncode != 0:
|
|
162
|
-
|
|
163
|
-
{"error": f"Tests failed ({framework}):\n{output}"},
|
|
164
|
-
sys.stdout,
|
|
165
|
-
)
|
|
157
|
+
print(f"Tests failed ({framework}):\n{output}", file=sys.stderr)
|
|
166
158
|
sys.exit(2)
|
|
167
159
|
|
|
168
|
-
json.dump(
|
|
169
|
-
{"additionalContext": f"[Tests] All tests passed ({framework})"},
|
|
170
|
-
sys.stdout,
|
|
171
|
-
)
|
|
172
160
|
sys.exit(0)
|
|
173
161
|
|
|
174
162
|
|
|
@@ -50,45 +50,31 @@ Biome is resolved in this order:
|
|
|
50
50
|
|
|
51
51
|
## Installation
|
|
52
52
|
|
|
53
|
-
###
|
|
53
|
+
### CodeForge DevContainer
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
Pre-installed and activated automatically — no setup needed.
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
your-marketplace/
|
|
59
|
-
├── .claude-plugin/
|
|
60
|
-
│ └── marketplace.json
|
|
61
|
-
└── plugins/
|
|
62
|
-
└── auto-code-quality/ ← this directory
|
|
63
|
-
```
|
|
57
|
+
### From GitHub
|
|
64
58
|
|
|
65
|
-
|
|
59
|
+
Use this plugin in any Claude Code setup:
|
|
66
60
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
```json
|
|
70
|
-
{
|
|
71
|
-
"name": "auto-code-quality",
|
|
72
|
-
"description": "Self-contained code quality: auto-format + auto-lint edited files",
|
|
73
|
-
"version": "1.0.0",
|
|
74
|
-
"source": "./plugins/auto-code-quality",
|
|
75
|
-
"category": "development"
|
|
76
|
-
}
|
|
77
|
-
```
|
|
61
|
+
1. Clone the [CodeForge](https://github.com/AnExiledDev/CodeForge) repository:
|
|
78
62
|
|
|
79
|
-
|
|
63
|
+
```bash
|
|
64
|
+
git clone https://github.com/AnExiledDev/CodeForge.git
|
|
65
|
+
```
|
|
80
66
|
|
|
81
|
-
|
|
67
|
+
2. Enable the plugin in your `.claude/settings.json`:
|
|
82
68
|
|
|
83
|
-
```json
|
|
84
|
-
{
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
```
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"enabledPlugins": {
|
|
72
|
+
"auto-code-quality@<clone-path>/.devcontainer/plugins/devs-marketplace": true
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
90
76
|
|
|
91
|
-
Replace
|
|
77
|
+
Replace `<clone-path>` with the absolute path to your CodeForge clone.
|
|
92
78
|
|
|
93
79
|
## How It Works
|
|
94
80
|
|
|
@@ -20,7 +20,6 @@
|
|
|
20
20
|
],
|
|
21
21
|
"Stop": [
|
|
22
22
|
{
|
|
23
|
-
"matcher": "",
|
|
24
23
|
"hooks": [
|
|
25
24
|
{
|
|
26
25
|
"type": "command",
|
|
@@ -31,6 +30,11 @@
|
|
|
31
30
|
"type": "command",
|
|
32
31
|
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/lint-file.py",
|
|
33
32
|
"timeout": 60
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"type": "command",
|
|
36
|
+
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/advisory-test-runner.py",
|
|
37
|
+
"timeout": 20
|
|
34
38
|
}
|
|
35
39
|
]
|
|
36
40
|
}
|
|
@@ -4,11 +4,11 @@ Advisory test runner — Stop hook that injects test results as context.
|
|
|
4
4
|
|
|
5
5
|
Reads the list of files edited this session (written by collect-edited-files.py),
|
|
6
6
|
maps them to affected test files, and runs only those tests. Skips entirely
|
|
7
|
-
if no files were edited. Results are returned as
|
|
8
|
-
|
|
7
|
+
if no files were edited. Results are returned as systemMessage (pass/timeout) or decision/reason
|
|
8
|
+
block (failure) so Claude acts on test failures before finishing.
|
|
9
9
|
|
|
10
10
|
Reads hook input from stdin (JSON). Returns JSON on stdout.
|
|
11
|
-
Always exits 0
|
|
11
|
+
Always exits 0. Failures use decision: "block" to prevent stopping.
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
14
|
import json
|
|
@@ -310,9 +310,7 @@ def main():
|
|
|
310
310
|
)
|
|
311
311
|
except subprocess.TimeoutExpired:
|
|
312
312
|
json.dump(
|
|
313
|
-
{
|
|
314
|
-
"additionalContext": f"[Tests] {framework} timed out after {TIMEOUT_SECONDS}s"
|
|
315
|
-
},
|
|
313
|
+
{"systemMessage": f"[Tests] {framework} timed out after {TIMEOUT_SECONDS}s"},
|
|
316
314
|
sys.stdout,
|
|
317
315
|
)
|
|
318
316
|
sys.exit(0)
|
|
@@ -323,7 +321,7 @@ def main():
|
|
|
323
321
|
|
|
324
322
|
if result.returncode == 0:
|
|
325
323
|
json.dump(
|
|
326
|
-
{"
|
|
324
|
+
{"systemMessage": f"[Tests] All tests passed ({framework})"},
|
|
327
325
|
sys.stdout,
|
|
328
326
|
)
|
|
329
327
|
sys.exit(0)
|
|
@@ -337,7 +335,10 @@ def main():
|
|
|
337
335
|
output = "...(truncated)\n" + "\n".join(lines[-30:])
|
|
338
336
|
|
|
339
337
|
json.dump(
|
|
340
|
-
{
|
|
338
|
+
{
|
|
339
|
+
"decision": "block",
|
|
340
|
+
"reason": f"[Tests] Some tests FAILED ({framework}):\n{output}",
|
|
341
|
+
},
|
|
341
342
|
sys.stdout,
|
|
342
343
|
)
|
|
343
344
|
sys.exit(0)
|
|
@@ -20,6 +20,34 @@ The plugin uses the `lspServers` field in `plugin.json` to declare server config
|
|
|
20
20
|
|
|
21
21
|
Each server maps file extensions to language identifiers. When Claude Code opens a file matching a registered extension, it routes it to the corresponding LSP server for diagnostics, completions, and other language features.
|
|
22
22
|
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
### CodeForge DevContainer
|
|
26
|
+
|
|
27
|
+
Pre-installed and activated automatically — no setup needed.
|
|
28
|
+
|
|
29
|
+
### From GitHub
|
|
30
|
+
|
|
31
|
+
Use this plugin in any Claude Code setup:
|
|
32
|
+
|
|
33
|
+
1. Clone the [CodeForge](https://github.com/AnExiledDev/CodeForge) repository:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
git clone https://github.com/AnExiledDev/CodeForge.git
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
2. Enable the plugin in your `.claude/settings.json`:
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"enabledPlugins": {
|
|
44
|
+
"codeforge-lsp@<clone-path>/.devcontainer/plugins/devs-marketplace": true
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Replace `<clone-path>` with the absolute path to your CodeForge clone.
|
|
50
|
+
|
|
23
51
|
## Plugin Structure
|
|
24
52
|
|
|
25
53
|
```
|
|
@@ -53,6 +53,34 @@ Claude calls the Bash tool
|
|
|
53
53
|
|
|
54
54
|
The hook has a 5-second timeout. If the script takes longer, Claude Code proceeds with the command.
|
|
55
55
|
|
|
56
|
+
## Installation
|
|
57
|
+
|
|
58
|
+
### CodeForge DevContainer
|
|
59
|
+
|
|
60
|
+
Pre-installed and activated automatically — no setup needed.
|
|
61
|
+
|
|
62
|
+
### From GitHub
|
|
63
|
+
|
|
64
|
+
Use this plugin in any Claude Code setup:
|
|
65
|
+
|
|
66
|
+
1. Clone the [CodeForge](https://github.com/AnExiledDev/CodeForge) repository:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
git clone https://github.com/AnExiledDev/CodeForge.git
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
2. Enable the plugin in your `.claude/settings.json`:
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"enabledPlugins": {
|
|
77
|
+
"dangerous-command-blocker@<clone-path>/.devcontainer/plugins/devs-marketplace": true
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Replace `<clone-path>` with the absolute path to your CodeForge clone.
|
|
83
|
+
|
|
56
84
|
## Plugin Structure
|
|
57
85
|
|
|
58
86
|
```
|
|
@@ -116,8 +116,8 @@ def main():
|
|
|
116
116
|
is_dangerous, message = check_command(command)
|
|
117
117
|
|
|
118
118
|
if is_dangerous:
|
|
119
|
-
# Output error
|
|
120
|
-
print(
|
|
119
|
+
# Output error to stderr (exit 2 ignores stdout)
|
|
120
|
+
print(message, file=sys.stderr)
|
|
121
121
|
sys.exit(2)
|
|
122
122
|
|
|
123
123
|
# Allow command to proceed
|
|
@@ -25,6 +25,34 @@ Claude stops responding (Stop event)
|
|
|
25
25
|
|
|
26
26
|
The hook has a 5-second timeout. The plugin contains no scripts of its own — it delegates entirely to the `claude-notify` binary.
|
|
27
27
|
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
### CodeForge DevContainer
|
|
31
|
+
|
|
32
|
+
Pre-installed and activated automatically — no setup needed.
|
|
33
|
+
|
|
34
|
+
### From GitHub
|
|
35
|
+
|
|
36
|
+
Use this plugin in any Claude Code setup:
|
|
37
|
+
|
|
38
|
+
1. Clone the [CodeForge](https://github.com/AnExiledDev/CodeForge) repository:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
git clone https://github.com/AnExiledDev/CodeForge.git
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
2. Enable the plugin in your `.claude/settings.json`:
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"enabledPlugins": {
|
|
49
|
+
"notify-hook@<clone-path>/.devcontainer/plugins/devs-marketplace": true
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Replace `<clone-path>` with the absolute path to your CodeForge clone.
|
|
55
|
+
|
|
28
56
|
## Plugin Structure
|
|
29
57
|
|
|
30
58
|
```
|