codeforge-dev 1.10.0 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/.devcontainer/.env +7 -1
  2. package/.devcontainer/.gitignore +1 -0
  3. package/.devcontainer/CHANGELOG.md +138 -0
  4. package/.devcontainer/CLAUDE.md +87 -8
  5. package/.devcontainer/README.md +55 -18
  6. package/.devcontainer/config/defaults/main-system-prompt.md +132 -152
  7. package/.devcontainer/config/defaults/rules/session-search.md +66 -0
  8. package/.devcontainer/config/defaults/rules/spec-workflow.md +39 -12
  9. package/.devcontainer/config/defaults/settings.json +2 -1
  10. package/.devcontainer/config/defaults/writing-system-prompt.md +185 -0
  11. package/.devcontainer/config/file-manifest.json +12 -0
  12. package/.devcontainer/connect-external-terminal.ps1 +1 -1
  13. package/.devcontainer/devcontainer.json +40 -10
  14. package/.devcontainer/docs/configuration-reference.md +3 -0
  15. package/.devcontainer/docs/plugins.md +9 -2
  16. package/.devcontainer/docs/troubleshooting.md +2 -2
  17. package/.devcontainer/features/README.md +8 -9
  18. package/.devcontainer/features/agent-browser/devcontainer-feature.json +21 -21
  19. package/.devcontainer/features/agent-browser/install.sh +0 -7
  20. package/.devcontainer/features/ast-grep/devcontainer-feature.json +22 -22
  21. package/.devcontainer/features/biome/devcontainer-feature.json +12 -14
  22. package/.devcontainer/features/ccms/README.md +50 -0
  23. package/.devcontainer/features/ccms/devcontainer-feature.json +21 -0
  24. package/.devcontainer/features/ccms/install.sh +122 -0
  25. package/.devcontainer/features/ccstatusline/install.sh +24 -2
  26. package/.devcontainer/features/lsp-servers/devcontainer-feature.json +43 -43
  27. package/.devcontainer/features/mcp-qdrant/poststart-hook.sh +2 -1
  28. package/.devcontainer/features/ruff/devcontainer-feature.json +17 -19
  29. package/.devcontainer/features/tmux/install.sh +2 -2
  30. package/.devcontainer/plugins/devs-marketplace/.claude-plugin/marketplace.json +8 -1
  31. package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/README.md +81 -0
  32. package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/README.md +92 -0
  33. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/README.md +250 -0
  34. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/architect.md +1 -0
  35. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/claude-guide.md +2 -2
  36. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/debug-logs.md +1 -1
  37. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/dependency-analyst.md +1 -1
  38. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/doc-writer.md +4 -4
  39. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/explorer.md +1 -1
  40. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/generalist.md +2 -1
  41. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/git-archaeologist.md +2 -2
  42. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/researcher.md +1 -1
  43. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/security-auditor.md +1 -1
  44. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/spec-writer.md +8 -8
  45. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/hooks/hooks.json +10 -0
  46. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/skill-suggester.cpython-314.pyc +0 -0
  47. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/git-state-injector.py +15 -4
  48. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/inject-cwd.py +37 -0
  49. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/skill-suggester.py +24 -0
  50. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/spec-reminder.py +3 -2
  51. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-build/SKILL.md +353 -0
  52. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-build/references/review-checklist.md +175 -0
  53. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-check/SKILL.md +15 -14
  54. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-init/SKILL.md +12 -11
  55. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-init/references/backlog-template.md +1 -1
  56. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-init/references/milestones-template.md +32 -0
  57. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-new/SKILL.md +17 -18
  58. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-new/references/template.md +12 -2
  59. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-review/SKILL.md +229 -0
  60. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-update/SKILL.md +6 -2
  61. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/specification-writing/SKILL.md +1 -1
  62. package/.devcontainer/plugins/devs-marketplace/plugins/codeforge-lsp/.claude-plugin/plugin.json +38 -5
  63. package/.devcontainer/plugins/devs-marketplace/plugins/codeforge-lsp/README.md +41 -0
  64. package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/README.md +72 -0
  65. package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/scripts/block-dangerous.py +73 -47
  66. package/.devcontainer/plugins/devs-marketplace/plugins/notify-hook/README.md +42 -0
  67. package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/README.md +86 -0
  68. package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/hooks/hooks.json +25 -15
  69. package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/guard-protected-bash.py +122 -0
  70. package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/guard-protected.py +3 -3
  71. package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/README.md +96 -0
  72. package/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/.claude-plugin/plugin.json +7 -0
  73. package/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/README.md +94 -0
  74. package/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/hooks/hooks.json +17 -0
  75. package/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/scripts/__pycache__/guard-workspace-scope.cpython-314.pyc +0 -0
  76. package/.devcontainer/plugins/devs-marketplace/plugins/workspace-scope-guard/scripts/guard-workspace-scope.py +132 -0
  77. package/.devcontainer/scripts/check-setup.sh +1 -1
  78. package/.devcontainer/scripts/setup-aliases.sh +68 -75
  79. package/.devcontainer/scripts/setup-projects.sh +23 -16
  80. package/.devcontainer/scripts/setup.sh +48 -5
  81. package/README.md +17 -8
  82. package/package.json +1 -2
  83. package/.devcontainer/features/mcp-reasoner/README.md +0 -177
  84. package/.devcontainer/features/mcp-reasoner/devcontainer-feature.json +0 -25
  85. package/.devcontainer/features/mcp-reasoner/install.sh +0 -184
  86. package/.devcontainer/features/mcp-reasoner/poststart-hook.sh +0 -67
  87. package/.devcontainer/features/splitrail/README.md +0 -140
  88. package/.devcontainer/features/splitrail/devcontainer-feature.json +0 -39
  89. package/.devcontainer/features/splitrail/install.sh +0 -136
  90. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-init/references/roadmap-template.md +0 -33
@@ -0,0 +1,17 @@
1
+ {
2
+ "description": "Enforce workspace scope for file operations",
3
+ "hooks": {
4
+ "PreToolUse": [
5
+ {
6
+ "matcher": "Read|Write|Edit|NotebookEdit|Glob|Grep",
7
+ "hooks": [
8
+ {
9
+ "type": "command",
10
+ "command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/guard-workspace-scope.py",
11
+ "timeout": 5
12
+ }
13
+ ]
14
+ }
15
+ ]
16
+ }
17
+ }
@@ -0,0 +1,132 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Enforce workspace scope for file operations.
4
+
5
+ Blocks write operations (Write, Edit, NotebookEdit) to files outside the
6
+ current working directory. Warns on read operations (Read, Glob, Grep)
7
+ outside the working directory. Allows unrestricted access when cwd is
8
+ /workspaces (the workspace root).
9
+
10
+ Exit code 2 blocks the operation with an error message.
11
+ Exit code 0 allows the operation to proceed (with optional warning context).
12
+ """
13
+
14
+ import json
15
+ import os
16
+ import sys
17
+
18
+ # Paths that are always allowed regardless of working directory
19
+ ALLOWED_PREFIXES = [
20
+ "/workspaces/.claude/",
21
+ "/workspaces/.tmp/",
22
+ "/workspaces/.devcontainer/",
23
+ "/tmp/",
24
+ "/home/vscode/",
25
+ ]
26
+
27
+ WRITE_TOOLS = {"Write", "Edit", "NotebookEdit"}
28
+ READ_TOOLS = {"Read", "Glob", "Grep"}
29
+
30
+ # Tool input field that contains the target path
31
+ PATH_FIELDS = {
32
+ "Read": "file_path",
33
+ "Write": "file_path",
34
+ "Edit": "file_path",
35
+ "NotebookEdit": "notebook_path",
36
+ "Glob": "path",
37
+ "Grep": "path",
38
+ }
39
+
40
+
41
+ def get_target_path(tool_name: str, tool_input: dict) -> str | None:
42
+ """Extract the target path from tool input.
43
+
44
+ Returns None if no path field is present or the field is empty,
45
+ which means the tool defaults to cwd (always in scope).
46
+ """
47
+ field = PATH_FIELDS.get(tool_name)
48
+ if not field:
49
+ return None
50
+ return tool_input.get(field) or None
51
+
52
+
53
+ def is_in_scope(resolved_path: str, cwd: str) -> bool:
54
+ """Check if resolved_path is within the working directory."""
55
+ cwd_prefix = cwd if cwd.endswith("/") else cwd + "/"
56
+ return resolved_path == cwd or resolved_path.startswith(cwd_prefix)
57
+
58
+
59
+ def is_allowlisted(resolved_path: str) -> bool:
60
+ """Check if resolved_path falls under an allowed prefix."""
61
+ return any(resolved_path.startswith(prefix) for prefix in ALLOWED_PREFIXES)
62
+
63
+
64
+ def main():
65
+ try:
66
+ input_data = json.load(sys.stdin)
67
+ tool_name = input_data.get("tool_name", "")
68
+ tool_input = input_data.get("tool_input", {})
69
+
70
+ cwd = os.getcwd()
71
+
72
+ # Unrestricted when working from the workspace root
73
+ if cwd == "/workspaces":
74
+ sys.exit(0)
75
+
76
+ target_path = get_target_path(tool_name, tool_input)
77
+
78
+ # No path specified — tool defaults to cwd, which is in scope
79
+ if target_path is None:
80
+ sys.exit(0)
81
+
82
+ resolved = os.path.realpath(target_path)
83
+
84
+ if is_in_scope(resolved, cwd):
85
+ sys.exit(0)
86
+
87
+ if is_allowlisted(resolved):
88
+ sys.exit(0)
89
+
90
+ # Out of scope
91
+ if tool_name in WRITE_TOOLS:
92
+ print(
93
+ json.dumps(
94
+ {
95
+ "error": (
96
+ f"Blocked: {tool_name} targets '{target_path}' which is "
97
+ f"outside the working directory ({cwd}). Move to that "
98
+ f"project's directory first or work from /workspaces."
99
+ )
100
+ }
101
+ )
102
+ )
103
+ sys.exit(2)
104
+
105
+ if tool_name in READ_TOOLS:
106
+ print(
107
+ json.dumps(
108
+ {
109
+ "additionalContext": (
110
+ f"Warning: {tool_name} targets '{target_path}' which is "
111
+ f"outside the working directory ({cwd}). This read is "
112
+ f"allowed but may indicate unintended cross-project access."
113
+ )
114
+ }
115
+ )
116
+ )
117
+ sys.exit(0)
118
+
119
+ # Unknown tool — allow by default
120
+ sys.exit(0)
121
+
122
+ except json.JSONDecodeError:
123
+ # Can't parse input — allow by default
124
+ sys.exit(0)
125
+ except Exception as e:
126
+ # Don't block on hook failure
127
+ print(f"Hook error: {e}", file=sys.stderr)
128
+ sys.exit(0)
129
+
130
+
131
+ if __name__ == "__main__":
132
+ main()
@@ -34,7 +34,7 @@ warn_check() {
34
34
  echo ""
35
35
  echo "Core:"
36
36
  check "Claude Code installed" "command -v claude"
37
- warn_check "Claude native binary" "[ -x /usr/local/bin/claude ]"
37
+ warn_check "Claude native binary" "[ -x ~/.local/bin/claude ] || [ -x /usr/local/bin/claude ]"
38
38
  check "cc alias configured" "grep -q 'alias cc=' ~/.bashrc 2>/dev/null || grep -q 'alias cc=' ~/.zshrc 2>/dev/null"
39
39
  check "Config directory exists" "[ -d '${CLAUDE_CONFIG_DIR:-/workspaces/.claude}' ]"
40
40
  check "Settings file exists" "[ -f '${CLAUDE_CONFIG_DIR:-/workspaces/.claude}/settings.json' ]"
@@ -1,129 +1,122 @@
1
1
  #!/bin/bash
2
2
  # Setup cc/claude/ccraw aliases for claude with local system prompt support
3
+ #
4
+ # Idempotent: removes the entire managed block then re-writes it fresh.
5
+ # Safe to run on every container start via postStartCommand.
3
6
 
4
7
  CLAUDE_DIR="${CLAUDE_CONFIG_DIR:?CLAUDE_CONFIG_DIR not set}"
5
8
 
6
9
  echo "[setup-aliases] Configuring Claude aliases..."
7
10
 
8
- # Simple alias definitions (not functions functions don't behave reliably across shell contexts)
9
- # Aliases reference $_CLAUDE_BIN which is resolved at shell startup to prefer the native binary.
10
- ALIAS_CC='alias cc='"'"'CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 command "$_CLAUDE_BIN" --system-prompt-file "$CLAUDE_CONFIG_DIR/system-prompt.md" --permission-mode plan --allow-dangerously-skip-permissions'"'"''
11
- ALIAS_CLAUDE='alias claude='"'"'CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 command "$_CLAUDE_BIN" --system-prompt-file "$CLAUDE_CONFIG_DIR/system-prompt.md" --permission-mode plan --allow-dangerously-skip-permissions'"'"''
12
- ALIAS_CCRAW='alias ccraw='"'"'command "$_CLAUDE_BIN"'"'"''
11
+ # Resolve check-setup path once (used inside the block we write)
12
+ DEVCONTAINER_SCRIPTS="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13
+
14
+ BLOCK_START='# === CodeForge Claude aliases START (managed by setup-aliases.sh do not edit) ==='
15
+ BLOCK_END='# === CodeForge Claude aliases END ==='
13
16
 
14
17
  for rc in ~/.bashrc ~/.zshrc; do
15
18
  if [ -f "$rc" ]; then
16
- # --- Backup before modifying ---
19
+ # --- 1. Backup before modifying ---
17
20
  cp "$rc" "${rc}.bak.$(date +%s)" 2>/dev/null || true
18
21
  # Clean old backups (keep last 3)
19
22
  ls -t "${rc}.bak."* 2>/dev/null | tail -n +4 | xargs rm -f 2>/dev/null || true
20
23
 
21
- # --- Cleanup old definitions ---
24
+ # --- 2. Remove existing managed block (if present) ---
25
+ sed -i '/# === CodeForge Claude aliases START/,/# === CodeForge Claude aliases END/d' "$rc"
22
26
 
23
- # Remove old cc alias
24
- if grep -q "alias cc=" "$rc" 2>/dev/null; then
25
- sed -i '/alias cc=/d' "$rc"
26
- echo "[setup-aliases] Removed old cc alias from $(basename $rc)"
27
- fi
28
- # Remove old cc function (single-line or multi-line)
27
+ # --- 3. Legacy cleanup (pre-marker formats only) ---
28
+ # These remove remnants from versions that predated the block-marker system.
29
+ # After step 2, anything matching these patterns is orphaned from old formats.
30
+
31
+ # Old function forms (pre-v1.10.0)
29
32
  if grep -q "^cc()" "$rc" 2>/dev/null; then
30
33
  sed -i '/^cc() {/,/^}/d' "$rc"
31
- echo "[setup-aliases] Removed old cc function from $(basename $rc)"
34
+ echo "[setup-aliases] Removed legacy cc() function from $(basename "$rc")"
32
35
  fi
33
- # Remove old _claude_with_config function
34
36
  if grep -q "^_claude_with_config()" "$rc" 2>/dev/null; then
35
37
  sed -i '/^_claude_with_config() {/,/^}/d' "$rc"
36
- echo "[setup-aliases] Removed old _claude_with_config function from $(basename $rc)"
38
+ echo "[setup-aliases] Removed legacy _claude_with_config() function from $(basename "$rc")"
37
39
  fi
38
- # Remove old claude function override
39
- if grep -q "^claude() {" "$rc" 2>/dev/null; then
40
+ if grep -q "^claude() { _claude_with_config" "$rc" 2>/dev/null; then
40
41
  sed -i '/^claude() { _claude_with_config/d' "$rc"
41
- echo "[setup-aliases] Removed old claude function from $(basename $rc)"
42
- fi
43
- # Remove old claude alias
44
- if grep -q "alias claude=" "$rc" 2>/dev/null; then
45
- sed -i '/alias claude=/d' "$rc"
42
+ echo "[setup-aliases] Removed legacy claude() function from $(basename "$rc")"
46
43
  fi
47
- # Remove old ccraw alias
48
- if grep -q "alias ccraw=" "$rc" 2>/dev/null; then
49
- sed -i '/alias ccraw=/d' "$rc"
50
- fi
51
- # Remove old specwright alias
52
44
  if grep -q "alias specwright=" "$rc" 2>/dev/null; then
53
45
  sed -i '/alias specwright=/d' "$rc"
46
+ echo "[setup-aliases] Removed legacy specwright alias from $(basename "$rc")"
54
47
  fi
55
- # Remove old cc-tools/check-setup functions
48
+
49
+ # Old alias/export form (v1.10.0 — no block markers)
50
+ sed -i '/# Claude Code environment and aliases/d' "$rc"
51
+ sed -i '/^export CLAUDE_CONFIG_DIR="/d' "$rc"
52
+ sed -i '/^export LANG=en_US\.UTF-8$/d' "$rc"
53
+ sed -i '/^export LC_ALL=en_US\.UTF-8$/d' "$rc"
54
+ # _CLAUDE_BIN if-block (4 patterns: if, elif, else, fi + assignments)
55
+ sed -i '/^if \[ -x "\$HOME\/\.local\/bin\/claude" \]/,/^fi$/d' "$rc"
56
+ sed -i '/^ _CLAUDE_BIN=/d' "$rc"
57
+ # Standalone aliases from old format
58
+ sed -i "/^alias cc='/d" "$rc"
59
+ sed -i "/^alias claude='/d" "$rc"
60
+ sed -i "/^alias ccraw='/d" "$rc"
61
+ sed -i "/^alias ccw='/d" "$rc"
62
+ sed -i '/^alias check-setup=/d' "$rc"
63
+ # cc-tools function from old format
56
64
  if grep -q "^cc-tools()" "$rc" 2>/dev/null; then
57
65
  sed -i '/^cc-tools() {/,/^}/d' "$rc"
58
66
  fi
59
- if grep -q "alias check-setup=" "$rc" 2>/dev/null; then
60
- sed -i '/alias check-setup=/d' "$rc"
61
- fi
62
- # --- Add environment and aliases (idempotent) ---
63
- # Guard: skip if aliases already present from a previous run
64
- if grep -q '# Claude Code environment and aliases' "$rc" 2>/dev/null; then
65
- echo "[setup-aliases] Aliases already present in $(basename $rc), skipping"
66
- continue
67
- fi
68
- echo "" >>"$rc"
69
- echo "# Claude Code environment and aliases (managed by setup-aliases.sh)" >>"$rc"
70
- # Export CLAUDE_CONFIG_DIR so it's available in all shells (not just VS Code remoteEnv)
71
- if ! grep -q 'export CLAUDE_CONFIG_DIR=' "$rc" 2>/dev/null; then
72
- echo "export CLAUDE_CONFIG_DIR=\"${CLAUDE_CONFIG_DIR}\"" >>"$rc"
73
- fi
74
- # Export UTF-8 locale so tmux renders Unicode correctly (docker exec doesn't inherit locale)
75
- if ! grep -q 'export LANG=en_US.UTF-8' "$rc" 2>/dev/null; then
76
- echo 'export LANG=en_US.UTF-8' >>"$rc"
77
- echo 'export LC_ALL=en_US.UTF-8' >>"$rc"
78
- fi
79
- # Prefer native binary over npm-installed version
80
- # 'claude install' puts the binary at ~/.local/bin/claude
81
- # Legacy manual installs used /usr/local/bin/claude — check both
82
- cat >>"$rc" <<'CLAUDEBIN_EOF'
83
- if [ -x "$HOME/.local/bin/claude" ]; then
84
- _CLAUDE_BIN="$HOME/.local/bin/claude"
67
+
68
+ # --- 5. Write fresh managed block ---
69
+ cat >>"$rc" <<BLOCK_EOF
70
+
71
+ ${BLOCK_START}
72
+ export CLAUDE_CONFIG_DIR="${CLAUDE_CONFIG_DIR}"
73
+ export LANG=en_US.UTF-8
74
+ export LC_ALL=en_US.UTF-8
75
+
76
+ # Prefer native binary over npm-installed version
77
+ if [ -x "\$HOME/.local/bin/claude" ]; then
78
+ _CLAUDE_BIN="\$HOME/.local/bin/claude"
85
79
  elif [ -x /usr/local/bin/claude ]; then
86
80
  _CLAUDE_BIN=/usr/local/bin/claude
87
81
  else
88
82
  _CLAUDE_BIN=claude
89
83
  fi
90
- CLAUDEBIN_EOF
91
- echo "$ALIAS_CC" >>"$rc"
92
- echo "$ALIAS_CLAUDE" >>"$rc"
93
- echo "$ALIAS_CCRAW" >>"$rc"
94
84
 
95
- # cc-tools: list all available CodeForge tools with version info
96
- cat >>"$rc" <<'CCTOOLS_EOF'
85
+ alias cc='CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 command "\$_CLAUDE_BIN" --system-prompt-file "\$CLAUDE_CONFIG_DIR/main-system-prompt.md" --permission-mode plan --allow-dangerously-skip-permissions'
86
+ alias claude='CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 command "\$_CLAUDE_BIN" --system-prompt-file "\$CLAUDE_CONFIG_DIR/main-system-prompt.md" --permission-mode plan --allow-dangerously-skip-permissions'
87
+ alias ccraw='command "\$_CLAUDE_BIN"'
88
+ alias ccw='CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 command "\$_CLAUDE_BIN" --system-prompt-file "\$CLAUDE_CONFIG_DIR/writing-system-prompt.md" --permission-mode plan --allow-dangerously-skip-permissions'
89
+
97
90
  cc-tools() {
98
91
  echo "CodeForge Available Tools"
99
92
  echo "━━━━━━━━━━━━━━━━━━━━━━━━"
100
93
  printf " %-20s %s\n" "COMMAND" "STATUS"
101
94
  echo " ────────────────────────────────────"
102
- for cmd in claude cc ccraw ccusage ccburn claude-monitor \
103
- ruff biome dprint shfmt shellcheck hadolint \
104
- ast-grep tree-sitter pyright typescript-language-server \
95
+ for cmd in claude cc ccw ccraw ccusage ccburn claude-monitor \\
96
+ ccms cargo ruff biome dprint shfmt shellcheck hadolint \\
97
+ ast-grep tree-sitter pyright typescript-language-server \\
105
98
  agent-browser gh docker git jq tmux bun go; do
106
- if command -v "$cmd" >/dev/null 2>&1; then
107
- ver=$("$cmd" --version 2>/dev/null | head -1 || echo "installed")
108
- printf " %-20s ✓ %s\n" "$cmd" "$ver"
99
+ if command -v "\$cmd" >/dev/null 2>&1; then
100
+ ver=\$("\$cmd" --version 2>/dev/null | head -1 || echo "installed")
101
+ printf " %-20s ✓ %s\n" "\$cmd" "\$ver"
109
102
  else
110
- printf " %-20s ✗ not found\n" "$cmd"
103
+ printf " %-20s ✗ not found\n" "\$cmd"
111
104
  fi
112
105
  done
113
106
  }
114
- CCTOOLS_EOF
115
107
 
116
- # check-setup: alias to the health check script
117
- DEVCONTAINER_SCRIPTS="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
118
- echo "alias check-setup='bash ${DEVCONTAINER_SCRIPTS}/check-setup.sh'" >>"$rc"
108
+ alias check-setup='bash ${DEVCONTAINER_SCRIPTS}/check-setup.sh'
109
+ ${BLOCK_END}
110
+ BLOCK_EOF
119
111
 
120
- echo "[setup-aliases] Added aliases to $(basename $rc)"
112
+ echo "[setup-aliases] Added aliases to $(basename "$rc")"
121
113
  fi
122
114
  done
123
115
 
124
116
  echo "[setup-aliases] Aliases configured:"
125
- echo " cc -> claude with \$CLAUDE_CONFIG_DIR/system-prompt.md"
126
- echo " claude -> claude with \$CLAUDE_CONFIG_DIR/system-prompt.md"
117
+ echo " cc -> claude with \$CLAUDE_CONFIG_DIR/main-system-prompt.md"
118
+ echo " claude -> claude with \$CLAUDE_CONFIG_DIR/main-system-prompt.md"
127
119
  echo " ccraw -> vanilla claude without any config"
120
+ echo " ccw -> claude with \$CLAUDE_CONFIG_DIR/writing-system-prompt.md"
128
121
  echo " cc-tools -> list all available CodeForge tools"
129
122
  echo " check-setup -> verify CodeForge setup health"
@@ -29,7 +29,7 @@ is_excluded() {
29
29
 
30
30
  has_project_markers() {
31
31
  local dir="$1"
32
- [ -d "$dir/.git" ] || [ -f "$dir/package.json" ] || [ -f "$dir/pyproject.toml" ] ||
32
+ [ -d "$dir/.git" ] || [ -f "$dir/.git" ] || [ -f "$dir/package.json" ] || [ -f "$dir/pyproject.toml" ] ||
33
33
  [ -f "$dir/Cargo.toml" ] || [ -f "$dir/go.mod" ] || [ -f "$dir/deno.json" ] ||
34
34
  [ -f "$dir/Makefile" ] || [ -f "$dir/CLAUDE.md" ]
35
35
  }
@@ -38,7 +38,11 @@ detect_tags() {
38
38
  local dir="$1"
39
39
  local tags=()
40
40
 
41
- [ -d "$dir/.git" ] && tags+=("git")
41
+ if [ -f "$dir/.git" ] && grep -q "gitdir:" "$dir/.git" 2>/dev/null; then
42
+ tags+=("git" "worktree")
43
+ elif [ -d "$dir/.git" ]; then
44
+ tags+=("git")
45
+ fi
42
46
  [ -f "$dir/package.json" ] && tags+=("node")
43
47
  [ -f "$dir/pyproject.toml" ] && tags+=("python")
44
48
  [ -f "$dir/Cargo.toml" ] && tags+=("rust")
@@ -95,6 +99,19 @@ scan_and_update() {
95
99
  is_excluded "$subname" && continue
96
100
  new_projects=$(register_project "$new_projects" "$subname" "$subdir")
97
101
  done
102
+
103
+ # Depth 3: .worktrees/ is hidden (not matched by */) — scan explicitly
104
+ local wtcontainer="${dir%/}/.worktrees"
105
+ if [ -d "$wtcontainer" ]; then
106
+ for wtdir in "${wtcontainer%/}"/*/; do
107
+ [ -d "$wtdir" ] || continue
108
+ local wtname
109
+ wtname=$(basename "$wtdir")
110
+ if has_project_markers "$wtdir"; then
111
+ new_projects=$(register_project "$new_projects" "$wtname" "$wtdir")
112
+ fi
113
+ done
114
+ fi
98
115
  fi
99
116
  done
100
117
 
@@ -158,20 +175,10 @@ start_watcher() {
158
175
  stop_watcher
159
176
  fi
160
177
 
161
- # Check if inotifywait is available
178
+ # Check if inotifywait is available (installed by tmux feature at build time)
162
179
  if ! command -v inotifywait &>/dev/null; then
163
- echo "$LOG_PREFIX Installing inotify-tools..."
164
- if command -v sudo &>/dev/null; then
165
- sudo apt-get update -qq && sudo apt-get install -y -qq inotify-tools >/dev/null 2>&1
166
- else
167
- apt-get update -qq && apt-get install -y -qq inotify-tools >/dev/null 2>&1
168
- fi
169
-
170
- if ! command -v inotifywait &>/dev/null; then
171
- echo "$LOG_PREFIX WARNING: Could not install inotify-tools, watcher disabled"
172
- return 1
173
- fi
174
- echo "$LOG_PREFIX inotify-tools installed"
180
+ echo "$LOG_PREFIX WARNING: inotify-tools not installed, watcher disabled"
181
+ return 1
175
182
  fi
176
183
 
177
184
  # Fork background watcher in its own process group for clean shutdown
@@ -181,7 +188,7 @@ start_watcher() {
181
188
  # -r watches subdirectories (catches events inside container dirs like projects/)
182
189
  # --exclude filters noisy dirs that generate frequent irrelevant events
183
190
  inotifywait -m -r -q -e create,delete,moved_to,moved_from \
184
- --exclude '(node_modules|\.git/|\.tmp|__pycache__|\.venv)' \
191
+ --exclude '(node_modules|\.git|\.tmp|__pycache__|\.venv)' \
185
192
  --format '%w%f %e' "$WORKSPACE_ROOT" 2>/dev/null |
186
193
  while read -r _path event; do
187
194
  # Small delay to let filesystem settle (e.g., move operations)
@@ -22,8 +22,9 @@ fi
22
22
  : "${SETUP_UPDATE_CLAUDE:=true}"
23
23
  : "${SETUP_PROJECTS:=true}"
24
24
  : "${SETUP_TERMINAL:=true}"
25
+ : "${SETUP_POSTSTART:=true}"
25
26
 
26
- export CLAUDE_CONFIG_DIR CONFIG_SOURCE_DIR SETUP_CONFIG SETUP_ALIASES SETUP_AUTH SETUP_PLUGINS SETUP_UPDATE_CLAUDE SETUP_PROJECTS SETUP_TERMINAL
27
+ export CLAUDE_CONFIG_DIR CONFIG_SOURCE_DIR SETUP_CONFIG SETUP_ALIASES SETUP_AUTH SETUP_PLUGINS SETUP_UPDATE_CLAUDE SETUP_PROJECTS SETUP_TERMINAL SETUP_POSTSTART
27
28
 
28
29
  SETUP_START=$(date +%s)
29
30
  SETUP_RESULTS=()
@@ -42,12 +43,16 @@ run_script() {
42
43
  if [ "$enabled" = "true" ]; then
43
44
  if [ -f "$script" ]; then
44
45
  printf " %-30s" "$name..."
45
- if bash "$script" 2>&1; then
46
+ local output
47
+ if output=$(bash "$script" 2>&1); then
46
48
  echo "done"
47
49
  SETUP_RESULTS+=("$name:ok")
48
50
  else
49
- echo "FAILED (exit $?)"
51
+ local exit_code=$?
52
+ echo "FAILED (exit $exit_code)"
50
53
  SETUP_RESULTS+=("$name:failed")
54
+ # Show output on failure for diagnostics
55
+ echo "$output" | sed 's/^/ /'
51
56
  fi
52
57
  else
53
58
  echo " $name... not found, skipping"
@@ -59,6 +64,30 @@ run_script() {
59
64
  fi
60
65
  }
61
66
 
67
+ run_poststart_hooks() {
68
+ local hook_dir="/usr/local/devcontainer-poststart.d"
69
+ if [ ! -d "$hook_dir" ]; then
70
+ return 0
71
+ fi
72
+ local count=0
73
+ for hook in "$hook_dir"/*.sh; do
74
+ [ -f "$hook" ] || continue
75
+ [ -x "$hook" ] || continue
76
+ local name
77
+ name="$(basename "$hook")"
78
+ printf " %-30s" "$name..."
79
+ if bash "$hook" 2>&1; then
80
+ echo "done"
81
+ count=$((count + 1))
82
+ else
83
+ echo "FAILED (exit $?)"
84
+ fi
85
+ done
86
+ if [ $count -gt 0 ]; then
87
+ SETUP_RESULTS+=("poststart-hooks:ok ($count)")
88
+ fi
89
+ }
90
+
62
91
  run_script "$SCRIPT_DIR/setup-symlink-claude.sh" "true"
63
92
  run_script "$SCRIPT_DIR/setup-auth.sh" "$SETUP_AUTH"
64
93
  run_script "$SCRIPT_DIR/setup-config.sh" "$SETUP_CONFIG"
@@ -66,7 +95,20 @@ run_script "$SCRIPT_DIR/setup-aliases.sh" "$SETUP_ALIASES"
66
95
  run_script "$SCRIPT_DIR/setup-plugins.sh" "$SETUP_PLUGINS"
67
96
  run_script "$SCRIPT_DIR/setup-projects.sh" "$SETUP_PROJECTS"
68
97
  run_script "$SCRIPT_DIR/setup-terminal.sh" "$SETUP_TERMINAL"
69
- run_script "$SCRIPT_DIR/setup-update-claude.sh" "$SETUP_UPDATE_CLAUDE"
98
+
99
+ # Background the update to avoid blocking container start
100
+ if [ "$SETUP_UPDATE_CLAUDE" = "true" ] && [ -f "$SCRIPT_DIR/setup-update-claude.sh" ]; then
101
+ bash "$SCRIPT_DIR/setup-update-claude.sh" &>/dev/null &
102
+ disown
103
+ SETUP_RESULTS+=("setup-update-claude:background")
104
+ else
105
+ SETUP_RESULTS+=("setup-update-claude:disabled")
106
+ fi
107
+
108
+ # Run post-start hooks
109
+ if [ "$SETUP_POSTSTART" = "true" ]; then
110
+ run_poststart_hooks
111
+ fi
70
112
 
71
113
  echo ""
72
114
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@@ -77,10 +119,11 @@ for result in "${SETUP_RESULTS[@]}"; do
77
119
  name="${result%%:*}"
78
120
  status="${result##*:}"
79
121
  case "$status" in
80
- ok) printf " ✓ %s\n" "$name" ;;
122
+ ok*) printf " ✓ %s\n" "$name" ;;
81
123
  failed) printf " ✗ %s (FAILED)\n" "$name"; FAILURES=$((FAILURES + 1)) ;;
82
124
  disabled) printf " - %s (disabled)\n" "$name" ;;
83
125
  missing) printf " ? %s (not found)\n" "$name" ;;
126
+ background) printf " ⇢ %s (background)\n" "$name" ;;
84
127
  esac
85
128
  done
86
129
  ELAPSED=$(( $(date +%s) - SETUP_START ))
package/README.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  [![License: GPL-3.0](https://img.shields.io/badge/License-GPL%203.0-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
4
4
  [![npm version](https://img.shields.io/npm/v/codeforge-dev.svg)](https://www.npmjs.com/package/codeforge-dev)
5
+ [![Changelog](https://img.shields.io/badge/changelog-view-blue)](.devcontainer/CHANGELOG.md)
6
+ [![GitHub last commit](https://img.shields.io/github/last-commit/AnExiledDev/CodeForge)](https://github.com/AnExiledDev/CodeForge/commits)
7
+ [![npm downloads](https://img.shields.io/npm/dm/codeforge-dev)](https://www.npmjs.com/package/codeforge-dev)
8
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D14.0.0-brightgreen)](https://nodejs.org/)
9
+ [![GitHub issues](https://img.shields.io/github/issues/AnExiledDev/CodeForge)](https://github.com/AnExiledDev/CodeForge/issues)
5
10
 
6
11
  A curated development environment optimized for AI-powered coding with Claude Code. CodeForge comes pre-configured with language servers, code intelligence tools, and official Anthropic plugins to streamline your development workflow.
7
12
 
@@ -43,15 +48,15 @@ npx codeforge-dev@1.2.3
43
48
 
44
49
  ### Languages & Runtimes
45
50
 
46
- Python 3.14, Node.js LTS, TypeScript, Go
51
+ Python 3.14, Node.js LTS, TypeScript, Rust, Bun, Go (optional)
47
52
 
48
53
  ### Package Managers
49
54
 
50
- `uv`, `npm`, `pip` / `pipx`
55
+ `uv`, `npm`, `bun`, `pip` / `pipx`
51
56
 
52
57
  ### Development Tools
53
58
 
54
- `gh` (GitHub CLI), `docker`, `git`, `jq`, `curl`, `tmux`, `biome`, `agent-browser`
59
+ `gh` (GitHub CLI), `docker`, `git`, `jq`, `curl`, `tmux`, `biome`, `ruff`, `ccms`, `agent-browser`
55
60
 
56
61
  ### Code Intelligence
57
62
 
@@ -59,15 +64,15 @@ tree-sitter (JS/TS/Python), ast-grep, Pyright, TypeScript LSP
59
64
 
60
65
  ### Claude Code Tools
61
66
 
62
- `claude`, `cc` (wrapper), `ccusage`, `ccburn`, `ccstatusline`, `claude-monitor`
67
+ `claude`, `cc` (wrapper), `ccw` (writing mode wrapper), `ccusage`, `ccburn`, `ccstatusline`, `claude-monitor`
63
68
 
64
- ### Custom Features (14)
69
+ ### Custom Features (18)
65
70
 
66
- tmux, agent-browser, claude-monitor, ccusage, ccburn, ccstatusline, ast-grep, tree-sitter, lsp-servers, biome, notify-hook, mcp-qdrant, mcp-reasoner, splitrail
71
+ tmux, agent-browser, claude-monitor, ccusage, ccburn, ccstatusline, ast-grep, tree-sitter, lsp-servers, biome, ruff, shfmt, shellcheck, hadolint, dprint, ccms, notify-hook, mcp-qdrant
67
72
 
68
- ### Agents (17) & Skills (17)
73
+ ### Agents (17) & Skills (28)
69
74
 
70
- The `code-directive` plugin includes 17 specialized agents (architect, explorer, test-writer, security-auditor, etc.) and 17 domain-specific coding reference skills (fastapi, svelte5, docker, testing, spec-refine, etc.).
75
+ The `code-directive` plugin includes 17 specialized agents (architect, explorer, test-writer, security-auditor, etc.) and 28 domain-specific coding reference skills (fastapi, svelte5, docker, testing, spec-workflow, security-checklist, etc.).
71
76
 
72
77
  ## Quick Start
73
78
 
@@ -95,6 +100,10 @@ npm test
95
100
  npm publish
96
101
  ```
97
102
 
103
+ ## Changelog
104
+
105
+ See [CHANGELOG.md](.devcontainer/CHANGELOG.md) for release history. Current version: **1.12.0** (2026-02-18).
106
+
98
107
  ## Further Reading
99
108
 
100
109
  - [Full Usage Guide](.devcontainer/README.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeforge-dev",
3
- "version": "1.10.0",
3
+ "version": "1.12.0",
4
4
  "description": "Complete development container that sets up Claude Code with modular devcontainer features, modern dev tools, and persistent configurations. Drop it into any project and get a production-ready AI development environment in minutes.",
5
5
  "main": "setup.js",
6
6
  "bin": {
@@ -20,7 +20,6 @@
20
20
  "vscode",
21
21
  "container",
22
22
  "qdrant",
23
- "reasoner",
24
23
  "ai-development"
25
24
  ],
26
25
  "author": "AnExiledDev",