codeforge-dev 1.14.2 → 2.0.1
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/config/defaults → .codeforge/config}/ccstatusline-settings.json +44 -6
- package/.codeforge/config/main-system-prompt.md +412 -0
- package/.codeforge/config/orchestrator-system-prompt.md +333 -0
- package/{.devcontainer/config/defaults → .codeforge/config}/settings.json +7 -2
- package/{.devcontainer/config → .codeforge}/file-manifest.json +15 -9
- package/{.devcontainer → .codeforge/scripts}/connect-external-terminal.sh +3 -1
- package/.devcontainer/.env.example +17 -5
- package/.devcontainer/.secrets.example +3 -0
- package/.devcontainer/CHANGELOG.md +215 -0
- package/.devcontainer/CLAUDE.md +26 -43
- package/.devcontainer/README.md +35 -20
- package/.devcontainer/devcontainer.json +36 -17
- package/.devcontainer/features/agent-browser/install.sh +3 -0
- package/.devcontainer/features/ast-grep/install.sh +3 -0
- package/.devcontainer/features/biome/install.sh +3 -0
- package/.devcontainer/features/ccburn/install.sh +2 -0
- package/.devcontainer/features/ccms/install.sh +2 -0
- package/.devcontainer/features/ccstatusline/README.md +7 -6
- package/.devcontainer/features/ccstatusline/install.sh +9 -4
- package/.devcontainer/features/ccusage/install.sh +2 -0
- package/.devcontainer/features/chromaterm/chromaterm.yml +2 -2
- package/.devcontainer/features/chromaterm/install.sh +2 -0
- package/.devcontainer/features/claude-code-native/README.md +47 -0
- package/.devcontainer/features/claude-code-native/devcontainer-feature.json +29 -0
- package/.devcontainer/features/claude-code-native/install.sh +131 -0
- package/.devcontainer/features/claude-monitor/install.sh +2 -0
- package/.devcontainer/features/claude-session-dashboard/README.md +2 -2
- package/.devcontainer/features/claude-session-dashboard/install.sh +3 -0
- package/.devcontainer/features/dprint/install.sh +2 -0
- package/.devcontainer/features/hadolint/install.sh +2 -0
- package/.devcontainer/features/kitty-terminfo/README.md +3 -1
- package/.devcontainer/features/kitty-terminfo/install.sh +2 -0
- package/.devcontainer/features/lsp-servers/install.sh +4 -0
- package/.devcontainer/features/mcp-qdrant/CHANGES.md +3 -3
- package/.devcontainer/features/mcp-qdrant/README.md +1 -0
- package/.devcontainer/features/mcp-qdrant/devcontainer-feature.json +1 -1
- package/.devcontainer/features/mcp-qdrant/install.sh +9 -2
- package/.devcontainer/features/mcp-qdrant/poststart-hook.sh +9 -2
- package/.devcontainer/features/notify-hook/devcontainer-feature.json +1 -1
- package/.devcontainer/features/notify-hook/install.sh +2 -0
- package/.devcontainer/features/ruff/install.sh +2 -0
- package/.devcontainer/features/shellcheck/install.sh +2 -0
- package/.devcontainer/features/shfmt/install.sh +2 -0
- package/.devcontainer/features/tmux/README.md +3 -3
- package/.devcontainer/features/tmux/install.sh +3 -1
- package/.devcontainer/features/tree-sitter/install.sh +4 -0
- package/.devcontainer/plugins/devs-marketplace/.claude-plugin/marketplace.json +27 -11
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/README.md +20 -6
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/architect.md +182 -29
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/bash-exec.md +9 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/claude-guide.md +13 -4
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/debug-logs.md +24 -5
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/dependency-analyst.md +16 -5
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/documenter.md +412 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/explorer.md +18 -6
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/generalist.md +36 -10
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/git-archaeologist.md +10 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/implementer.md +260 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/investigator.md +262 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/migrator.md +10 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/perf-profiler.md +21 -5
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/refactorer.md +18 -8
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/researcher.md +23 -5
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/security-auditor.md +20 -6
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/spec-writer.md +12 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/statusline-config.md +12 -2
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/test-writer.md +22 -7
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/guard-readonly-bash.py +9 -5
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/redirect-builtin-agents.py +2 -5
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/README.md +1 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/scripts/advisory-test-runner.py +4 -2
- package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/README.md +3 -2
- package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/scripts/block-dangerous.py +89 -15
- package/.devcontainer/plugins/devs-marketplace/plugins/git-workflow/.claude-plugin/plugin.json +7 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/git-workflow/README.md +125 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/git-workflow/skills/pr-review/SKILL.md +325 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/git-workflow/skills/ship/SKILL.md +314 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/prompt-snippets/.claude-plugin/plugin.json +5 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/prompt-snippets/README.md +52 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/prompt-snippets/skills/ps/SKILL.md +37 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/README.md +2 -2
- package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/guard-protected-bash.py +80 -6
- package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/guard-protected.py +4 -4
- package/.devcontainer/plugins/devs-marketplace/plugins/session-context/README.md +30 -14
- package/.devcontainer/plugins/devs-marketplace/plugins/session-context/hooks/hooks.json +13 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/session-context/scripts/collect-session-edits.py +44 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/session-context/scripts/commit-reminder.py +89 -10
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/.claude-plugin/plugin.json +1 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/README.md +19 -11
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/scripts/skill-suggester.py +476 -282
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/team/SKILL.md +4 -4
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/worktree/SKILL.md +227 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/worktree/references/manual-worktree-commands.md +238 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/skills/worktree/references/parallel-workflow-patterns.md +228 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/spec-workflow/skills/spec-build/SKILL.md +2 -2
- package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/scripts/ticket-linker.py +2 -2
- package/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/README.md +1 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/scripts/guard-workspace-scope.py +69 -31
- package/.devcontainer/scripts/check-setup.sh +5 -3
- package/.devcontainer/scripts/preflight.sh +113 -0
- package/.devcontainer/scripts/setup-aliases.sh +13 -8
- package/.devcontainer/scripts/setup-auth.sh +46 -0
- package/.devcontainer/scripts/setup-config.sh +29 -10
- package/.devcontainer/scripts/setup-migrate-claude.sh +80 -0
- package/.devcontainer/scripts/setup-migrate-codeforge.sh +60 -0
- package/.devcontainer/scripts/setup-plugins.sh +5 -5
- package/.devcontainer/scripts/setup-projects.sh +4 -2
- package/.devcontainer/scripts/setup-terminal.sh +3 -1
- package/.devcontainer/scripts/setup-update-claude.sh +22 -27
- package/.devcontainer/scripts/setup.sh +78 -5
- package/LICENSE.txt +14 -0
- package/README.md +82 -7
- package/package.json +4 -1
- package/setup.js +392 -21
- package/.devcontainer/config/defaults/main-system-prompt.md +0 -664
- package/.devcontainer/docs/configuration-reference.md +0 -93
- package/.devcontainer/docs/keybindings.md +0 -100
- package/.devcontainer/docs/optional-features.md +0 -64
- package/.devcontainer/docs/plugins.md +0 -176
- package/.devcontainer/docs/troubleshooting.md +0 -128
- package/.devcontainer/plugins/devs-marketplace/plugins/agent-system/agents/doc-writer.md +0 -334
- package/.devcontainer/scripts/setup-symlink-claude.sh +0 -36
- /package/{.devcontainer/config/defaults → .codeforge/config}/keybindings.json +0 -0
- /package/{.devcontainer/config/defaults → .codeforge/config}/rules/session-search.md +0 -0
- /package/{.devcontainer/config/defaults → .codeforge/config}/rules/spec-workflow.md +0 -0
- /package/{.devcontainer/config/defaults → .codeforge/config}/rules/workspace-scope.md +0 -0
- /package/{.devcontainer/config/defaults → .codeforge/config}/writing-system-prompt.md +0 -0
- /package/{.devcontainer → .codeforge/scripts}/connect-external-terminal.ps1 +0 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ps
|
|
3
|
+
description: Inject a behavioral prompt snippet by name.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
argument-hint: "[snippet-name]"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# /ps — Prompt Snippets
|
|
9
|
+
|
|
10
|
+
Apply the prompt snippet matching `$ARGUMENTS` from the table below. Follow its instruction for the **remainder of this conversation** unless the user explicitly overrides it.
|
|
11
|
+
|
|
12
|
+
If `$ARGUMENTS` does not match any snippet name, list all available snippets and ask the user to pick one.
|
|
13
|
+
|
|
14
|
+
## Available Snippets
|
|
15
|
+
|
|
16
|
+
| Snippet | Instruction |
|
|
17
|
+
|---------|-------------|
|
|
18
|
+
| `noaction` | Investigate and report only. Take no action — no edits, no commands, no file writes. |
|
|
19
|
+
| `brief` | Be concise. Short answers, no filler, no preamble. Answer the question and stop. |
|
|
20
|
+
| `plan` | Build a plan before taking any action. Do not implement until the plan is explicitly approved. |
|
|
21
|
+
| `go` | Proceed without asking for confirmation. Use your best judgment on all decisions. |
|
|
22
|
+
| `review` | Review and audit only. Report findings with specific file paths and line numbers. Do not modify anything. |
|
|
23
|
+
| `ship` | Commit all staged changes, push to remote, and create a pull request. |
|
|
24
|
+
| `deep` | Be thorough and comprehensive. Investigate in depth, consider edge cases, leave no stone unturned. |
|
|
25
|
+
| `hold` | Complete the current task but do not commit, push, or publish. Await my review before any git operations. |
|
|
26
|
+
| `recall` | Search past session history with `ccms --no-color --project "$(pwd)"` to find prior decisions, discussions, and context relevant to the current task. Summarize what you find before proceeding. |
|
|
27
|
+
| `wait` | When done, stop. Do not suggest next steps, ask follow-up questions, or continue with related work. Await further instructions. |
|
|
28
|
+
|
|
29
|
+
## Composing Snippets
|
|
30
|
+
|
|
31
|
+
Multiple snippets can be applied in one invocation by separating names with spaces:
|
|
32
|
+
|
|
33
|
+
```text
|
|
34
|
+
/ps noaction brief
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Apply all matching snippets. If instructions conflict, the **last snippet wins** for that specific behavior.
|
|
@@ -10,7 +10,7 @@ Intercepts file operations and checks target paths against a set of protected pa
|
|
|
10
10
|
|
|
11
11
|
| Category | Patterns | Reason |
|
|
12
12
|
|----------|----------|--------|
|
|
13
|
-
| Environment secrets | `.env`, `.env.*` | Contains secrets |
|
|
13
|
+
| Environment secrets | `.env`, `.env.*` (except `.env.example`) | Contains secrets |
|
|
14
14
|
| Git internals | `.git/` | Managed by git |
|
|
15
15
|
| Lock files | `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`, `Gemfile.lock`, `poetry.lock`, `Cargo.lock`, `composer.lock`, `uv.lock` | Must be modified via package manager |
|
|
16
16
|
| Certificates & keys | `.pem`, `.key`, `.crt`, `.p12`, `.pfx` | Sensitive cryptographic material |
|
|
@@ -60,7 +60,7 @@ The Bash guard parses commands for write-indicating patterns and extracts the ta
|
|
|
60
60
|
| Scenario | Behavior |
|
|
61
61
|
|----------|----------|
|
|
62
62
|
| JSON parse failure | Fails closed (exit 2) — blocks the operation |
|
|
63
|
-
| Other exceptions | Fails
|
|
63
|
+
| Other exceptions | Fails closed (exit 2) — logs error, blocks the operation |
|
|
64
64
|
|
|
65
65
|
### Timeout
|
|
66
66
|
|
|
@@ -10,13 +10,14 @@ Exit code 0 allows the command to proceed.
|
|
|
10
10
|
|
|
11
11
|
import json
|
|
12
12
|
import re
|
|
13
|
+
import shlex
|
|
13
14
|
import sys
|
|
14
15
|
|
|
15
16
|
# Same patterns as guard-protected.py
|
|
16
17
|
PROTECTED_PATTERNS = [
|
|
17
18
|
(r"(^|/)\.env$", "Blocked: .env contains secrets - edit manually if needed"),
|
|
18
19
|
(
|
|
19
|
-
r"(^|/)\.env\.[^/]+$",
|
|
20
|
+
r"(^|/)\.env\.(?!example$)[^/]+$",
|
|
20
21
|
"Blocked: .env.* files contain secrets - edit manually if needed",
|
|
21
22
|
),
|
|
22
23
|
(r"(^|/)\.git(/|$)", "Blocked: .git is managed by git"),
|
|
@@ -36,7 +37,7 @@ PROTECTED_PATTERNS = [
|
|
|
36
37
|
(r"\.crt$", "Blocked: .crt certificate files should not be edited directly"),
|
|
37
38
|
(r"\.p12$", "Blocked: .p12 files contain sensitive cryptographic material"),
|
|
38
39
|
(r"\.pfx$", "Blocked: .pfx files contain sensitive cryptographic material"),
|
|
39
|
-
(r"(^|/)credentials\.json$", "Blocked: credentials.json contains secrets"),
|
|
40
|
+
(r"(^|/)\.?credentials\.json$", "Blocked: credentials.json contains secrets"),
|
|
40
41
|
(r"(^|/)secrets\.yaml$", "Blocked: secrets.yaml contains secrets"),
|
|
41
42
|
(r"(^|/)secrets\.yml$", "Blocked: secrets.yml contains secrets"),
|
|
42
43
|
(r"(^|/)secrets\.json$", "Blocked: secrets.json contains secrets"),
|
|
@@ -57,8 +58,8 @@ PROTECTED_PATTERNS = [
|
|
|
57
58
|
# Patterns that indicate a bash command is writing to a file
|
|
58
59
|
# Each captures the target file path for checking against PROTECTED_PATTERNS
|
|
59
60
|
WRITE_PATTERNS = [
|
|
60
|
-
# Redirect:
|
|
61
|
-
r"(
|
|
61
|
+
# Redirect: >> file, > file (>> before > to avoid greedy match)
|
|
62
|
+
r"(?:>>|>)\s*([^\s;&|]+)",
|
|
62
63
|
# tee: tee file, tee -a file
|
|
63
64
|
r"\btee\s+(?:-a\s+)?([^\s;&|]+)",
|
|
64
65
|
# cp/mv: cp src dest, mv src dest
|
|
@@ -67,9 +68,78 @@ WRITE_PATTERNS = [
|
|
|
67
68
|
r'\bsed\s+-i[^\s]*\s+(?:\'[^\']*\'\s+|"[^"]*"\s+|[^\s]+\s+)*([^\s;&|]+)',
|
|
68
69
|
# cat > file (heredoc style)
|
|
69
70
|
r"\bcat\s+(?:<<[^\s]*\s+)?>\s*([^\s;&|]+)",
|
|
71
|
+
# --- Extended patterns (unified with guard-workspace-scope.py) ---
|
|
72
|
+
r"\btouch\s+(?:-[^\s]+\s+)*([^\s;&|]+)", # touch file
|
|
73
|
+
r"\bmkdir\s+(?:-[^\s]+\s+)*([^\s;&|]+)", # mkdir [-p] dir
|
|
74
|
+
r"\brm\s+(?:-[^\s]+\s+)*([^\s;&|]+)", # rm [-rf] path
|
|
75
|
+
r"\bln\s+(?:-[^\s]+\s+)*[^\s]+\s+([^\s;&|]+)", # ln [-s] src dest
|
|
76
|
+
r"\binstall\s+(?:-[^\s]+\s+)*[^\s]+\s+([^\s;&|]+)", # install src dest
|
|
77
|
+
r"\brsync\s+(?:-[^\s]+\s+)*[^\s]+\s+([^\s;&|]+)", # rsync src dest
|
|
78
|
+
r"\bchmod\s+(?:-[^\s]+\s+)*[^\s]+\s+([^\s;&|]+)", # chmod mode path
|
|
79
|
+
r"\bchown\s+(?:-[^\s]+\s+)*[^\s:]+(?::[^\s]+)?\s+([^\s;&|]+)", # chown owner[:group] path
|
|
80
|
+
r"\bdd\b[^;|&]*\bof=([^\s;&|]+)", # dd of=path
|
|
81
|
+
r"\bwget\s+(?:-[^\s]+\s+)*-O\s+([^\s;&|]+)", # wget -O path
|
|
82
|
+
r"\bcurl\s+(?:-[^\s]+\s+)*-o\s+([^\s;&|]+)", # curl -o path
|
|
83
|
+
r"\btar\s+(?:-[^\s]+\s+)*-C\s+([^\s;&|]+)", # tar -C dir
|
|
84
|
+
r"\bunzip\s+(?:-[^\s]+\s+)*-d\s+([^\s;&|]+)", # unzip -d dir
|
|
85
|
+
r"\b(?:gcc|g\+\+|cc|c\+\+|clang)\s+(?:-[^\s]+\s+)*-o\s+([^\s;&|]+)", # gcc -o out
|
|
86
|
+
r"\bsqlite3\s+([^\s;&|]+)", # sqlite3 dbpath
|
|
70
87
|
]
|
|
71
88
|
|
|
72
89
|
|
|
90
|
+
# Commands where all trailing non-flag arguments are file targets
|
|
91
|
+
_MULTI_TARGET_CMDS = frozenset({"rm", "touch", "mkdir"})
|
|
92
|
+
# Commands where the first non-flag arg is NOT a file (mode/owner), rest are
|
|
93
|
+
_SKIP_FIRST_ARG_CMDS = frozenset({"chmod", "chown"})
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _extract_multi_targets(command: str) -> list[str]:
|
|
97
|
+
"""Extract all file targets from commands that accept multiple operands."""
|
|
98
|
+
try:
|
|
99
|
+
tokens = shlex.split(command)
|
|
100
|
+
except ValueError:
|
|
101
|
+
return []
|
|
102
|
+
if not tokens:
|
|
103
|
+
return []
|
|
104
|
+
|
|
105
|
+
# Handle prefixes like sudo, env, etc.
|
|
106
|
+
prefixes = {"sudo", "env", "nohup", "nice", "command"}
|
|
107
|
+
i = 0
|
|
108
|
+
while i < len(tokens) and tokens[i] in prefixes:
|
|
109
|
+
i += 1
|
|
110
|
+
# Skip sudo flags like -u root
|
|
111
|
+
if i > 0 and tokens[i - 1] == "sudo":
|
|
112
|
+
while i < len(tokens) and tokens[i].startswith("-"):
|
|
113
|
+
i += 1
|
|
114
|
+
if i < len(tokens) and not tokens[i].startswith("-"):
|
|
115
|
+
i += 1 # skip flag argument
|
|
116
|
+
# Skip env VAR=val
|
|
117
|
+
if i > 0 and tokens[i - 1] == "env":
|
|
118
|
+
while i < len(tokens) and "=" in tokens[i]:
|
|
119
|
+
i += 1
|
|
120
|
+
if i >= len(tokens):
|
|
121
|
+
return []
|
|
122
|
+
cmd = tokens[i]
|
|
123
|
+
|
|
124
|
+
if cmd not in _MULTI_TARGET_CMDS and cmd not in _SKIP_FIRST_ARG_CMDS:
|
|
125
|
+
return []
|
|
126
|
+
|
|
127
|
+
# Collect non-flag arguments
|
|
128
|
+
args = []
|
|
129
|
+
j = i + 1
|
|
130
|
+
while j < len(tokens):
|
|
131
|
+
if tokens[j].startswith("-"):
|
|
132
|
+
j += 1
|
|
133
|
+
continue
|
|
134
|
+
args.append(tokens[j])
|
|
135
|
+
j += 1
|
|
136
|
+
|
|
137
|
+
if cmd in _SKIP_FIRST_ARG_CMDS and args:
|
|
138
|
+
args = args[1:] # First arg is mode/owner, not a file
|
|
139
|
+
|
|
140
|
+
return args
|
|
141
|
+
|
|
142
|
+
|
|
73
143
|
def extract_write_targets(command: str) -> list[str]:
|
|
74
144
|
"""Extract file paths that the command writes to."""
|
|
75
145
|
targets = []
|
|
@@ -78,6 +148,10 @@ def extract_write_targets(command: str) -> list[str]:
|
|
|
78
148
|
target = match.group(1).strip("'\"")
|
|
79
149
|
if target:
|
|
80
150
|
targets.append(target)
|
|
151
|
+
# Supplement with multi-target extraction for commands like rm, touch, chmod
|
|
152
|
+
for target in _extract_multi_targets(command):
|
|
153
|
+
if target not in targets:
|
|
154
|
+
targets.append(target)
|
|
81
155
|
return targets
|
|
82
156
|
|
|
83
157
|
|
|
@@ -113,9 +187,9 @@ def main():
|
|
|
113
187
|
# Fail closed: can't parse means can't verify safety
|
|
114
188
|
sys.exit(2)
|
|
115
189
|
except Exception as e:
|
|
116
|
-
#
|
|
190
|
+
# Fail closed: unexpected errors should block, not allow
|
|
117
191
|
print(f"Hook error: {e}", file=sys.stderr)
|
|
118
|
-
sys.exit(
|
|
192
|
+
sys.exit(2)
|
|
119
193
|
|
|
120
194
|
|
|
121
195
|
if __name__ == "__main__":
|
|
@@ -16,7 +16,7 @@ PROTECTED_PATTERNS = [
|
|
|
16
16
|
# Environment secrets
|
|
17
17
|
(r"(^|/)\.env$", "Blocked: .env contains secrets - edit manually if needed"),
|
|
18
18
|
(
|
|
19
|
-
r"(^|/)\.env\.[^/]+$",
|
|
19
|
+
r"(^|/)\.env\.(?!example$)[^/]+$",
|
|
20
20
|
"Blocked: .env.* files contain secrets - edit manually if needed",
|
|
21
21
|
),
|
|
22
22
|
# Git internals
|
|
@@ -40,7 +40,7 @@ PROTECTED_PATTERNS = [
|
|
|
40
40
|
(r"\.p12$", "Blocked: .p12 files contain sensitive cryptographic material"),
|
|
41
41
|
(r"\.pfx$", "Blocked: .pfx files contain sensitive cryptographic material"),
|
|
42
42
|
# Credential files
|
|
43
|
-
(r"(^|/)credentials\.json$", "Blocked: credentials.json contains secrets"),
|
|
43
|
+
(r"(^|/)\.?credentials\.json$", "Blocked: credentials.json contains secrets"),
|
|
44
44
|
(r"(^|/)secrets\.yaml$", "Blocked: secrets.yaml contains secrets"),
|
|
45
45
|
(r"(^|/)secrets\.yml$", "Blocked: secrets.yml contains secrets"),
|
|
46
46
|
(r"(^|/)secrets\.json$", "Blocked: secrets.json contains secrets"),
|
|
@@ -100,9 +100,9 @@ def main():
|
|
|
100
100
|
# Fail closed: can't parse means can't verify safety
|
|
101
101
|
sys.exit(2)
|
|
102
102
|
except Exception as e:
|
|
103
|
-
#
|
|
103
|
+
# Fail closed: unexpected errors should block, not allow
|
|
104
104
|
print(f"Hook error: {e}", file=sys.stderr)
|
|
105
|
-
sys.exit(
|
|
105
|
+
sys.exit(2)
|
|
106
106
|
|
|
107
107
|
|
|
108
108
|
if __name__ == "__main__":
|
|
@@ -4,13 +4,14 @@ Claude Code plugin that injects contextual information at session boundaries. Pr
|
|
|
4
4
|
|
|
5
5
|
## What It Does
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Four hooks that run automatically at session lifecycle boundaries:
|
|
8
8
|
|
|
9
9
|
| Phase | Script | What It Injects |
|
|
10
10
|
|-------|--------|-----------------|
|
|
11
11
|
| Session start | `git-state-injector.py` | Current branch, status, recent commits, uncommitted changes |
|
|
12
12
|
| Session start | `todo-harvester.py` | Count and top 10 TODO/FIXME/HACK/XXX markers in the codebase |
|
|
13
|
-
|
|
|
13
|
+
| PostToolUse (Edit/Write) | `collect-session-edits.py` | Tracks which files the session modified (tmp file) |
|
|
14
|
+
| Stop | `commit-reminder.py` | Advisory about uncommitted changes (only if session edited files) |
|
|
14
15
|
|
|
15
16
|
All hooks are non-blocking and cap their output to prevent context bloat.
|
|
16
17
|
|
|
@@ -31,12 +32,19 @@ Scans source files for tech debt markers and injects a summary:
|
|
|
31
32
|
- Shows total count plus top 10 items
|
|
32
33
|
- Output capped at 800 characters
|
|
33
34
|
|
|
35
|
+
### Edit Tracking
|
|
36
|
+
|
|
37
|
+
Lightweight PostToolUse hook on Edit/Write that records file paths to `/tmp/claude-session-edits-{session_id}`. Used by the commit reminder to determine if this session actually modified files.
|
|
38
|
+
|
|
34
39
|
### Commit Reminder
|
|
35
40
|
|
|
36
|
-
Fires when Claude stops responding
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
41
|
+
Fires when Claude stops responding, using tiered logic based on change significance:
|
|
42
|
+
- Checks the session edit tracker — skips entirely if session was read-only
|
|
43
|
+
- **Meaningful changes** (3+ files, 2+ source files, or test files): suggests committing via advisory `systemMessage`
|
|
44
|
+
- **Small changes** (1-2 non-source files): silent, no output
|
|
45
|
+
- Output wrapped in `<system-reminder>` tags — advisory only, never blocks
|
|
46
|
+
- Instructs Claude not to commit without explicit user approval
|
|
47
|
+
- Uses a guard flag to prevent infinite loops
|
|
40
48
|
|
|
41
49
|
## How It Works
|
|
42
50
|
|
|
@@ -58,6 +66,12 @@ Session starts
|
|
|
58
66
|
| +-> Injects count + top 10 as additionalContext
|
|
59
67
|
|
|
|
60
68
|
| ... Claude works ...
|
|
69
|
+
| |
|
|
70
|
+
| +-> PostToolUse (Edit|Write) fires
|
|
71
|
+
| |
|
|
72
|
+
| +-> collect-session-edits.py
|
|
73
|
+
| |
|
|
74
|
+
| +-> Appends file path to /tmp/claude-session-edits-{session_id}
|
|
61
75
|
|
|
|
62
76
|
Claude stops responding
|
|
63
77
|
|
|
|
@@ -65,14 +79,14 @@ Claude stops responding
|
|
|
65
79
|
|
|
|
66
80
|
+-> commit-reminder.py
|
|
67
81
|
|
|
|
68
|
-
+->
|
|
69
|
-
+->
|
|
70
|
-
+->
|
|
82
|
+
+-> Session edited files? (checks tmp file)
|
|
83
|
+
+-> No edits this session? -> Silent (no output)
|
|
84
|
+
+-> Has edits + uncommitted changes? -> Inject advisory systemMessage
|
|
71
85
|
```
|
|
72
86
|
|
|
73
87
|
### Exit Code Behavior
|
|
74
88
|
|
|
75
|
-
All
|
|
89
|
+
All four scripts exit 0 (advisory only). They never block operations.
|
|
76
90
|
|
|
77
91
|
### Error Handling
|
|
78
92
|
|
|
@@ -88,6 +102,7 @@ All three scripts exit 0 (advisory only). They never block operations.
|
|
|
88
102
|
|------|---------|
|
|
89
103
|
| Git state injection | 10s |
|
|
90
104
|
| TODO harvesting | 8s |
|
|
105
|
+
| Edit tracking | 3s |
|
|
91
106
|
| Commit reminder | 8s |
|
|
92
107
|
|
|
93
108
|
## Installation
|
|
@@ -125,11 +140,12 @@ session-context/
|
|
|
125
140
|
+-- .claude-plugin/
|
|
126
141
|
| +-- plugin.json # Plugin metadata
|
|
127
142
|
+-- hooks/
|
|
128
|
-
| +-- hooks.json
|
|
143
|
+
| +-- hooks.json # Hook registrations (SessionStart + PostToolUse + Stop)
|
|
129
144
|
+-- scripts/
|
|
130
|
-
| +-- git-state-injector.py
|
|
131
|
-
| +-- todo-harvester.py
|
|
132
|
-
| +--
|
|
145
|
+
| +-- git-state-injector.py # Git state context (SessionStart)
|
|
146
|
+
| +-- todo-harvester.py # Tech debt markers (SessionStart)
|
|
147
|
+
| +-- collect-session-edits.py # Edit tracking (PostToolUse)
|
|
148
|
+
| +-- commit-reminder.py # Uncommitted changes advisory (Stop)
|
|
133
149
|
+-- README.md # This file
|
|
134
150
|
```
|
|
135
151
|
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "Context injection at session boundaries: git state, TODO harvesting, commit reminders",
|
|
2
|
+
"description": "Context injection at session boundaries: git state, TODO harvesting, edit tracking, commit reminders",
|
|
3
3
|
"hooks": {
|
|
4
|
+
"PostToolUse": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "Edit|Write",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/collect-session-edits.py",
|
|
11
|
+
"timeout": 3
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
],
|
|
4
16
|
"SessionStart": [
|
|
5
17
|
{
|
|
6
18
|
"matcher": "",
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Collect edited file paths for session-aware Stop hooks.
|
|
4
|
+
|
|
5
|
+
Lightweight PostToolUse hook that appends the edited file path
|
|
6
|
+
to a session-scoped temp file. The commit-reminder Stop hook
|
|
7
|
+
reads this file to determine if the session modified any files.
|
|
8
|
+
|
|
9
|
+
Non-blocking: always exits 0. Runs in <10ms.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
import os
|
|
14
|
+
import sys
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def main():
|
|
18
|
+
try:
|
|
19
|
+
input_data = json.load(sys.stdin)
|
|
20
|
+
except (json.JSONDecodeError, ValueError):
|
|
21
|
+
sys.exit(0)
|
|
22
|
+
|
|
23
|
+
session_id = input_data.get("session_id", "")
|
|
24
|
+
tool_input = input_data.get("tool_input", {})
|
|
25
|
+
file_path = tool_input.get("file_path", "")
|
|
26
|
+
|
|
27
|
+
if not file_path or not session_id:
|
|
28
|
+
sys.exit(0)
|
|
29
|
+
|
|
30
|
+
if not os.path.isfile(file_path):
|
|
31
|
+
sys.exit(0)
|
|
32
|
+
|
|
33
|
+
tmp_path = f"/tmp/claude-session-edits-{session_id}"
|
|
34
|
+
try:
|
|
35
|
+
with open(tmp_path, "a") as f:
|
|
36
|
+
f.write(file_path + "\n")
|
|
37
|
+
except OSError:
|
|
38
|
+
pass # non-critical, don't block Claude
|
|
39
|
+
|
|
40
|
+
sys.exit(0)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
if __name__ == "__main__":
|
|
44
|
+
main()
|
package/.devcontainer/plugins/devs-marketplace/plugins/session-context/scripts/commit-reminder.py
CHANGED
|
@@ -2,21 +2,31 @@
|
|
|
2
2
|
"""
|
|
3
3
|
Commit reminder — Stop hook that advises about uncommitted changes.
|
|
4
4
|
|
|
5
|
-
On Stop, checks
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
On Stop, checks whether this session edited any files (via the tmp file
|
|
6
|
+
written by collect-session-edits.py) and whether uncommitted changes exist.
|
|
7
|
+
Uses tiered logic: meaningful changes (3+ files, 2+ source files, or test
|
|
8
|
+
files touched) get an advisory suggestion; small changes are silent.
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
before finishing. The stop_hook_active guard prevents infinite loops.
|
|
10
|
+
Output is a systemMessage wrapped in <system-reminder> tags — advisory only,
|
|
11
|
+
never blocks. The stop_hook_active guard prevents loops.
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
14
|
import json
|
|
15
|
+
import os
|
|
15
16
|
import subprocess
|
|
16
17
|
import sys
|
|
17
18
|
|
|
18
19
|
GIT_CMD_TIMEOUT = 5
|
|
19
20
|
|
|
21
|
+
# Extensions considered source code (not config/docs)
|
|
22
|
+
SOURCE_EXTS = frozenset((
|
|
23
|
+
".py", ".ts", ".tsx", ".js", ".jsx", ".go", ".rs",
|
|
24
|
+
".java", ".kt", ".rb", ".svelte", ".vue", ".c", ".cpp", ".h",
|
|
25
|
+
))
|
|
26
|
+
|
|
27
|
+
# Patterns that indicate test files
|
|
28
|
+
TEST_PATTERNS = ("test_", "_test.", ".test.", ".spec.", "/tests/", "/test/")
|
|
29
|
+
|
|
20
30
|
|
|
21
31
|
def _run_git(args: list[str]) -> str | None:
|
|
22
32
|
"""Run a git command and return stdout, or None on any failure."""
|
|
@@ -34,6 +44,58 @@ def _run_git(args: list[str]) -> str | None:
|
|
|
34
44
|
return None
|
|
35
45
|
|
|
36
46
|
|
|
47
|
+
def _read_session_edits(session_id: str) -> list[str]:
|
|
48
|
+
"""Read the list of files edited this session."""
|
|
49
|
+
tmp_path = f"/tmp/claude-session-edits-{session_id}"
|
|
50
|
+
try:
|
|
51
|
+
with open(tmp_path, "r") as f:
|
|
52
|
+
raw = f.read()
|
|
53
|
+
except OSError:
|
|
54
|
+
return []
|
|
55
|
+
|
|
56
|
+
seen: set[str] = set()
|
|
57
|
+
result: list[str] = []
|
|
58
|
+
for line in raw.strip().splitlines():
|
|
59
|
+
path = line.strip()
|
|
60
|
+
if path and path not in seen:
|
|
61
|
+
seen.add(path)
|
|
62
|
+
result.append(path)
|
|
63
|
+
return result
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _is_source_file(path: str) -> bool:
|
|
67
|
+
"""Check if a file path looks like source code."""
|
|
68
|
+
_, ext = os.path.splitext(path)
|
|
69
|
+
return ext.lower() in SOURCE_EXTS
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _is_test_file(path: str) -> bool:
|
|
73
|
+
"""Check if a file path looks like a test file."""
|
|
74
|
+
lower = path.lower()
|
|
75
|
+
return any(pattern in lower for pattern in TEST_PATTERNS)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _is_meaningful(edited_files: list[str]) -> bool:
|
|
79
|
+
"""Determine if the session's edits are meaningful enough to suggest committing.
|
|
80
|
+
|
|
81
|
+
Meaningful when any of:
|
|
82
|
+
- 3+ total files edited
|
|
83
|
+
- 2+ source code files edited
|
|
84
|
+
- Any test files edited (suggests feature work)
|
|
85
|
+
"""
|
|
86
|
+
if len(edited_files) >= 3:
|
|
87
|
+
return True
|
|
88
|
+
|
|
89
|
+
source_count = sum(1 for f in edited_files if _is_source_file(f))
|
|
90
|
+
if source_count >= 2:
|
|
91
|
+
return True
|
|
92
|
+
|
|
93
|
+
if any(_is_test_file(f) for f in edited_files):
|
|
94
|
+
return True
|
|
95
|
+
|
|
96
|
+
return False
|
|
97
|
+
|
|
98
|
+
|
|
37
99
|
def main():
|
|
38
100
|
try:
|
|
39
101
|
input_data = json.load(sys.stdin)
|
|
@@ -44,7 +106,20 @@ def main():
|
|
|
44
106
|
if input_data.get("stop_hook_active"):
|
|
45
107
|
sys.exit(0)
|
|
46
108
|
|
|
47
|
-
#
|
|
109
|
+
# Only fire if this session actually edited files
|
|
110
|
+
session_id = input_data.get("session_id", "")
|
|
111
|
+
if not session_id:
|
|
112
|
+
sys.exit(0)
|
|
113
|
+
|
|
114
|
+
edited_files = _read_session_edits(session_id)
|
|
115
|
+
if not edited_files:
|
|
116
|
+
sys.exit(0)
|
|
117
|
+
|
|
118
|
+
# Small changes — stay silent
|
|
119
|
+
if not _is_meaningful(edited_files):
|
|
120
|
+
sys.exit(0)
|
|
121
|
+
|
|
122
|
+
# Check if there are any uncommitted changes
|
|
48
123
|
porcelain = _run_git(["status", "--porcelain"])
|
|
49
124
|
if porcelain is None:
|
|
50
125
|
# Not a git repo or git not available
|
|
@@ -79,11 +154,15 @@ def main():
|
|
|
79
154
|
summary = ", ".join(parts) if parts else f"{total} changed"
|
|
80
155
|
|
|
81
156
|
message = (
|
|
82
|
-
|
|
83
|
-
"
|
|
157
|
+
"<system-reminder>\n"
|
|
158
|
+
f"[Session Summary] Modified {total} files ({summary}). "
|
|
159
|
+
"This looks like a complete unit of work.\n"
|
|
160
|
+
"Consider asking the user if they would like to commit.\n"
|
|
161
|
+
"Do NOT commit without explicit user approval.\n"
|
|
162
|
+
"</system-reminder>"
|
|
84
163
|
)
|
|
85
164
|
|
|
86
|
-
json.dump({"
|
|
165
|
+
json.dump({"systemMessage": message}, sys.stdout)
|
|
87
166
|
sys.exit(0)
|
|
88
167
|
|
|
89
168
|
|
package/.devcontainer/plugins/devs-marketplace/plugins/skill-engine/.claude-plugin/plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skill-engine",
|
|
3
|
-
"description": "
|
|
3
|
+
"description": "22 coding knowledge packs with auto-suggestion for frameworks, tools, and patterns",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "AnExiledDev"
|
|
6
6
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# skill-engine
|
|
2
2
|
|
|
3
|
-
Claude Code plugin that provides
|
|
3
|
+
Claude Code plugin that provides 22 coding knowledge packs (skills) with automatic suggestion based on user prompts. Each skill contains domain-specific instructions and reference material that Claude loads on demand via the `/skill` command.
|
|
4
4
|
|
|
5
5
|
## What It Does
|
|
6
6
|
|
|
7
7
|
Two capabilities:
|
|
8
8
|
|
|
9
|
-
1. **Skill library** —
|
|
9
|
+
1. **Skill library** — 22 skills covering frameworks, tools, and development patterns. Each skill is a structured knowledge pack with a `SKILL.md` entrypoint and `references/` subdirectory containing detailed reference docs.
|
|
10
10
|
|
|
11
11
|
2. **Auto-suggestion** — A `UserPromptSubmit` hook watches user prompts for keyword matches and suggests relevant skills as context, so Claude can proactively load the right knowledge.
|
|
12
12
|
|
|
@@ -35,14 +35,18 @@ Two capabilities:
|
|
|
35
35
|
| svelte5 | Runes, reactivity, components, SPA routing, LayerCake |
|
|
36
36
|
| team | Agent team orchestration, parallel workstreams, task coordination |
|
|
37
37
|
| testing | Testing frameworks, FastAPI testing, Svelte testing |
|
|
38
|
+
| worktree | Git worktree lifecycle, EnterWorktree, parallel development |
|
|
38
39
|
|
|
39
40
|
### Auto-Suggestion
|
|
40
41
|
|
|
41
|
-
The `skill-suggester.py` hook
|
|
42
|
+
The `skill-suggester.py` hook scores user prompts against keyword maps for each skill using weighted matching. Suggestions are ranked by confidence and capped at **3 skills maximum** per prompt.
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
- **Phrases** —
|
|
45
|
-
- **Terms** —
|
|
44
|
+
Each skill defines:
|
|
45
|
+
- **Phrases** — `(substring, weight)` tuples. Weight 0.0–1.0 reflects specificity (e.g., `("build a fastapi app", 1.0)` vs `("pydantic model", 0.3)`)
|
|
46
|
+
- **Terms** — Whole-word regex patterns, all scored at 0.6
|
|
47
|
+
- **Negative patterns** — Substrings that instantly disqualify a skill (e.g., `"pydanticai"` suppresses `fastapi`)
|
|
48
|
+
- **Context guards** — Required co-occurring words for low-confidence matches. When the best score is below 0.6, at least one guard word must appear in the prompt or the match is dropped
|
|
49
|
+
- **Priority** — Integer tie-breaker (10 = commands, 7 = tech, 5 = patterns, 3 = generic)
|
|
46
50
|
|
|
47
51
|
## How It Works
|
|
48
52
|
|
|
@@ -55,9 +59,12 @@ User submits a prompt
|
|
|
55
59
|
|
|
|
56
60
|
+-> skill-suggester.py
|
|
57
61
|
|
|
|
58
|
-
+->
|
|
59
|
-
+->
|
|
60
|
-
+->
|
|
62
|
+
+-> Check negative patterns (instant disqualify)
|
|
63
|
+
+-> Score phrases (best weight) and terms (0.6)
|
|
64
|
+
+-> Enforce context guards on low-confidence matches
|
|
65
|
+
+-> Rank by score desc, priority desc
|
|
66
|
+
+-> Return top 3 as additionalContext
|
|
67
|
+
+-> No matches above threshold? -> Silent (no output)
|
|
61
68
|
```
|
|
62
69
|
|
|
63
70
|
### Skill Structure
|
|
@@ -126,9 +133,9 @@ skill-engine/
|
|
|
126
133
|
+-- hooks/
|
|
127
134
|
| +-- hooks.json # UserPromptSubmit hook registration
|
|
128
135
|
+-- scripts/
|
|
129
|
-
| +-- skill-suggester.py #
|
|
136
|
+
| +-- skill-suggester.py # Weighted scoring skill auto-suggestion
|
|
130
137
|
+-- skills/
|
|
131
|
-
| +-- api-design/ #
|
|
138
|
+
| +-- api-design/ # 22 skill directories
|
|
132
139
|
| +-- ast-grep-patterns/
|
|
133
140
|
| +-- claude-agent-sdk/
|
|
134
141
|
| +-- claude-code-headless/
|
|
@@ -149,6 +156,7 @@ skill-engine/
|
|
|
149
156
|
| +-- svelte5/
|
|
150
157
|
| +-- team/
|
|
151
158
|
| +-- testing/
|
|
159
|
+
| +-- worktree/
|
|
152
160
|
+-- README.md # This file
|
|
153
161
|
```
|
|
154
162
|
|