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.
Files changed (148) hide show
  1. package/.devcontainer/CHANGELOG.md +146 -4
  2. package/.devcontainer/CLAUDE.md +61 -276
  3. package/.devcontainer/README.md +1 -1
  4. package/.devcontainer/config/defaults/ccstatusline-settings.json +147 -0
  5. package/.devcontainer/config/defaults/main-system-prompt.md +6 -1
  6. package/.devcontainer/config/defaults/rules/spec-workflow.md +1 -55
  7. package/.devcontainer/config/file-manifest.json +14 -0
  8. package/.devcontainer/devcontainer.json +19 -1
  9. package/.devcontainer/docs/optional-features.md +0 -65
  10. package/.devcontainer/docs/plugins.md +38 -23
  11. package/.devcontainer/features/ast-grep/devcontainer-feature.json +0 -1
  12. package/.devcontainer/features/biome/install.sh +13 -0
  13. package/.devcontainer/features/ccburn/devcontainer-feature.json +0 -6
  14. package/.devcontainer/features/ccms/devcontainer-feature.json +0 -1
  15. package/.devcontainer/features/ccms/install.sh +1 -1
  16. package/.devcontainer/features/ccstatusline/devcontainer-feature.json +0 -1
  17. package/.devcontainer/features/ccstatusline/install.sh +17 -115
  18. package/.devcontainer/features/ccusage/devcontainer-feature.json +0 -6
  19. package/.devcontainer/features/chromaterm/README.md +42 -0
  20. package/.devcontainer/features/chromaterm/chromaterm.yml +35 -0
  21. package/.devcontainer/features/chromaterm/devcontainer-feature.json +22 -0
  22. package/.devcontainer/features/chromaterm/install.sh +113 -0
  23. package/.devcontainer/features/claude-monitor/devcontainer-feature.json +0 -6
  24. package/.devcontainer/features/claude-session-dashboard/README.md +2 -2
  25. package/.devcontainer/features/claude-session-dashboard/devcontainer-feature.json +2 -4
  26. package/.devcontainer/features/claude-session-dashboard/install.sh +2 -2
  27. package/.devcontainer/features/kitty-terminfo/README.md +32 -0
  28. package/.devcontainer/features/kitty-terminfo/devcontainer-feature.json +13 -0
  29. package/.devcontainer/features/kitty-terminfo/install.sh +72 -0
  30. package/.devcontainer/features/lsp-servers/devcontainer-feature.json +0 -1
  31. package/.devcontainer/features/mcp-qdrant/devcontainer-feature.json +0 -7
  32. package/.devcontainer/features/shellcheck/install.sh +6 -2
  33. package/.devcontainer/features/tree-sitter/devcontainer-feature.json +0 -7
  34. package/.devcontainer/plugins/devs-marketplace/.claude-plugin/marketplace.json +37 -69
  35. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/.claude-plugin/plugin.json +0 -1
  36. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/README.md +197 -0
  37. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/architect.md +3 -1
  38. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/bash-exec.md +3 -0
  39. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/claude-guide.md +4 -1
  40. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/debug-logs.md +6 -1
  41. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/dependency-analyst.md +5 -1
  42. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/doc-writer.md +4 -1
  43. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/explorer.md +3 -1
  44. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/generalist.md +9 -1
  45. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/git-archaeologist.md +3 -0
  46. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/migrator.md +4 -1
  47. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/perf-profiler.md +4 -1
  48. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/refactorer.md +5 -1
  49. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/researcher.md +5 -1
  50. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/security-auditor.md +4 -1
  51. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/spec-writer.md +3 -1
  52. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/statusline-config.md +4 -1
  53. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/test-writer.md +4 -1
  54. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/hooks/hooks.json +23 -1
  55. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/guard-readonly-bash.py +2 -2
  56. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/inject-cwd.py +7 -4
  57. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/task-completed-check.py +166 -0
  58. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/teammate-idle-check.py +81 -0
  59. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/verify-no-regression.py +14 -10
  60. package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/verify-tests-pass.py +2 -14
  61. package/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/README.md +17 -31
  62. package/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/hooks/hooks.json +5 -1
  63. package/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/scripts/advisory-test-runner.py +9 -8
  64. package/.devcontainer/plugins/devs-marketplace/plugins/codeforge-lsp/README.md +28 -0
  65. package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/README.md +28 -0
  66. package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/scripts/block-dangerous.py +2 -2
  67. package/.devcontainer/plugins/devs-marketplace/plugins/notify-hook/README.md +28 -0
  68. package/.devcontainer/plugins/devs-marketplace/plugins/notify-hook/hooks/hooks.json +0 -1
  69. package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/README.md +28 -0
  70. package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/guard-protected-bash.py +1 -1
  71. package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/guard-protected.py +2 -2
  72. package/.devcontainer/plugins/devs-marketplace/plugins/session-context/.claude-plugin/plugin.json +0 -1
  73. package/.devcontainer/plugins/devs-marketplace/plugins/session-context/README.md +140 -0
  74. package/.devcontainer/plugins/devs-marketplace/plugins/session-context/hooks/hooks.json +0 -1
  75. package/.devcontainer/plugins/devs-marketplace/plugins/session-context/scripts/commit-reminder.py +3 -2
  76. package/.devcontainer/plugins/devs-marketplace/plugins/session-context/scripts/git-state-injector.py +18 -2
  77. package/.devcontainer/plugins/devs-marketplace/plugins/session-context/scripts/todo-harvester.py +9 -1
  78. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/.claude-plugin/plugin.json +0 -1
  79. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/README.md +158 -0
  80. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/hooks/hooks.json +1 -14
  81. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/scripts/skill-suggester.py +189 -100
  82. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/api-design/SKILL.md +9 -6
  83. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/ast-grep-patterns/SKILL.md +7 -6
  84. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/claude-agent-sdk/SKILL.md +8 -8
  85. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/claude-code-headless/SKILL.md +8 -9
  86. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/debugging/SKILL.md +11 -7
  87. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/dependency-management/SKILL.md +10 -6
  88. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/docker/SKILL.md +8 -8
  89. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/docker-py/SKILL.md +9 -7
  90. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/documentation-patterns/SKILL.md +7 -6
  91. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/fastapi/SKILL.md +9 -8
  92. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/git-forensics/SKILL.md +11 -9
  93. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/migration-patterns/SKILL.md +7 -6
  94. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/performance-profiling/SKILL.md +10 -8
  95. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/pydantic-ai/SKILL.md +8 -7
  96. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/refactoring-patterns/SKILL.md +9 -8
  97. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/security-checklist/SKILL.md +9 -8
  98. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/skill-building/SKILL.md +7 -7
  99. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/sqlite/SKILL.md +9 -7
  100. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/svelte5/SKILL.md +7 -8
  101. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/team/SKILL.md +71 -5
  102. package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/testing/SKILL.md +10 -7
  103. package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/.claude-plugin/plugin.json +0 -1
  104. package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/README.md +192 -0
  105. package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/hooks/hooks.json +0 -1
  106. package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/scripts/spec-reminder.py +3 -2
  107. package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-build/SKILL.md +9 -6
  108. package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-check/SKILL.md +10 -5
  109. package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-init/SKILL.md +8 -4
  110. package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-new/SKILL.md +8 -4
  111. package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-refine/SKILL.md +10 -7
  112. package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-review/SKILL.md +10 -6
  113. package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-update/SKILL.md +10 -5
  114. package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/specification-writing/SKILL.md +9 -9
  115. package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/plugin.json +1 -2
  116. package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/README.md +28 -0
  117. package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/hooks/hooks.json +0 -1
  118. package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/scripts/ticket-linker.py +9 -1
  119. package/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/README.md +104 -32
  120. package/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/hooks/hooks.json +49 -3
  121. package/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/scripts/guard-workspace-scope.py +269 -56
  122. package/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/scripts/inject-workspace-cwd.py +44 -0
  123. package/.devcontainer/scripts/setup-aliases.sh +13 -5
  124. package/.devcontainer/scripts/setup-config.sh +1 -0
  125. package/README.md +5 -5
  126. package/package.json +6 -2
  127. package/setup.js +3 -2
  128. package/.devcontainer/.env +0 -33
  129. package/.devcontainer/features/README.md +0 -126
  130. package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/.claude-plugin/plugin.json +0 -7
  131. package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/README.md +0 -81
  132. package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/hooks/hooks.json +0 -17
  133. package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/scripts/__pycache__/format-on-stop.cpython-314.pyc +0 -0
  134. package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/scripts/format-on-stop.py +0 -297
  135. package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/.claude-plugin/plugin.json +0 -7
  136. package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/README.md +0 -92
  137. package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/hooks/hooks.json +0 -17
  138. package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/scripts/__pycache__/lint-file.cpython-314.pyc +0 -0
  139. package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/scripts/lint-file.py +0 -536
  140. package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/scripts/__pycache__/block-dangerous.cpython-314.pyc +0 -0
  141. package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/__pycache__/guard-protected.cpython-314.pyc +0 -0
  142. package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/system-prompt.md +0 -184
  143. package/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/scripts/__pycache__/guard-workspace-scope.cpython-314.pyc +0 -0
  144. /package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/{.claude-plugin/commands/debug.md → skills/debug/SKILL.md} +0 -0
  145. /package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/{.claude-plugin/commands/ticket/357/200/272create-pr.md" → skills/ticketcreate-pr/SKILL.md} +0 -0
  146. /package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/{.claude-plugin/commands/ticket/357/200/272new.md" → skills/ticketnew/SKILL.md} +0 -0
  147. /package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/{.claude-plugin/commands/ticket/357/200/272review-commit.md" → skills/ticketreview-commit/SKILL.md} +0 -0
  148. /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 and subagent configuration hooks",
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
  }
@@ -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). Returns JSON on stdout.
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
- json.dump({"error": error}, sys.stdout)
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
- "additionalContext": (
27
- f"Working Directory: {cwd} — restrict all file operations to "
28
- f"this directory unless explicitly instructed otherwise."
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
  )
@@ -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()
@@ -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()
@@ -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
- "additionalContext": f"[Tests] {framework} timed out after 60s — skipping regression check."
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
- json.dump(
203
- {
204
- "error": (
205
- f"Regression detected after editing {edited} "
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
- {"additionalContext": f"[Tests] No regression ({framework}): all tests passed"},
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)
@@ -136,12 +136,7 @@ def main():
136
136
  timeout=60,
137
137
  )
138
138
  except subprocess.TimeoutExpired:
139
- json.dump(
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
- json.dump(
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
- ### 1. Place the plugin
53
+ ### CodeForge DevContainer
54
54
 
55
- Copy the `auto-code-quality/` directory into your Claude Code plugin marketplace:
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
- ### 2. Register in marketplace.json
59
+ Use this plugin in any Claude Code setup:
66
60
 
67
- Add this entry to your `marketplace.json` `plugins` array:
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
- ### 3. Enable in settings.json
63
+ ```bash
64
+ git clone https://github.com/AnExiledDev/CodeForge.git
65
+ ```
80
66
 
81
- Add to your Claude Code `settings.json` under `enabledPlugins`:
67
+ 2. Enable the plugin in your `.claude/settings.json`:
82
68
 
83
- ```json
84
- {
85
- "enabledPlugins": {
86
- "auto-code-quality@your-marketplace": true
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 `your-marketplace` with the name of your marketplace.
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 additionalContext so Claude
8
- sees pass/fail info without being blocked.
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 (advisory, never blocking).
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
- {"additionalContext": f"[Tests] All tests passed ({framework})"},
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
- {"additionalContext": (f"[Tests] Some tests FAILED ({framework}):\n{output}")},
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 message and exit 2 to block
120
- print(json.dumps({"error": message}))
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
  ```
@@ -3,7 +3,6 @@
3
3
  "hooks": {
4
4
  "Stop": [
5
5
  {
6
- "matcher": "",
7
6
  "hooks": [
8
7
  {
9
8
  "type": "command",