codeforge-dev 1.9.0 → 1.10.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 (32) hide show
  1. package/.devcontainer/.env +3 -0
  2. package/.devcontainer/CHANGELOG.md +56 -0
  3. package/.devcontainer/CLAUDE.md +29 -8
  4. package/.devcontainer/README.md +61 -2
  5. package/.devcontainer/config/defaults/main-system-prompt.md +162 -128
  6. package/.devcontainer/config/defaults/rules/spec-workflow.md +10 -2
  7. package/.devcontainer/connect-external-terminal.sh +17 -17
  8. package/.devcontainer/devcontainer.json +143 -144
  9. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/architect.md +4 -3
  10. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/doc-writer.md +3 -3
  11. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/spec-writer.md +21 -11
  12. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/hooks/hooks.json +1 -1
  13. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/advisory-test-runner.py +186 -13
  14. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/spec-reminder.py +2 -1
  15. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/documentation-patterns/SKILL.md +1 -1
  16. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-check/SKILL.md +22 -10
  17. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-init/SKILL.md +7 -5
  18. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-init/references/backlog-template.md +19 -3
  19. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-init/references/roadmap-template.md +28 -8
  20. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-new/SKILL.md +15 -6
  21. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-new/references/template.md +24 -5
  22. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-refine/SKILL.md +194 -0
  23. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-update/SKILL.md +19 -1
  24. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/specification-writing/SKILL.md +19 -12
  25. package/.devcontainer/scripts/check-setup.sh +24 -25
  26. package/.devcontainer/scripts/setup-aliases.sh +88 -76
  27. package/.devcontainer/scripts/setup-projects.sh +172 -131
  28. package/.devcontainer/scripts/setup-terminal.sh +48 -0
  29. package/.devcontainer/scripts/setup-update-claude.sh +49 -107
  30. package/.devcontainer/scripts/setup.sh +4 -17
  31. package/README.md +2 -2
  32. package/package.json +1 -1
@@ -30,15 +30,15 @@ echo "Searching for running devcontainer..."
30
30
  CONTAINER_ID=$(docker ps --filter "label=$CONTAINER_LABEL" --format "{{.ID}}" | head -n1)
31
31
 
32
32
  if [ -z "$CONTAINER_ID" ]; then
33
- echo ""
34
- echo "ERROR: No running devcontainer found."
35
- echo ""
36
- echo "Make sure your devcontainer is running:"
37
- echo " 1. Open VS Code"
38
- echo " 2. Open the folder containing .devcontainer/"
39
- echo " 3. Use 'Dev Containers: Reopen in Container'"
40
- echo ""
41
- exit 1
33
+ echo ""
34
+ echo "ERROR: No running devcontainer found."
35
+ echo ""
36
+ echo "Make sure your devcontainer is running:"
37
+ echo " 1. Open VS Code"
38
+ echo " 2. Open the folder containing .devcontainer/"
39
+ echo " 3. Use 'Dev Containers: Reopen in Container'"
40
+ echo ""
41
+ exit 1
42
42
  fi
43
43
 
44
44
  # Get container name for display
@@ -47,10 +47,10 @@ echo "Found container: $CONTAINER_NAME ($CONTAINER_ID)"
47
47
  echo ""
48
48
 
49
49
  # Check if tmux is available in the container
50
- if ! docker exec "$CONTAINER_ID" which tmux > /dev/null 2>&1; then
51
- echo "ERROR: tmux is not installed in the container."
52
- echo "Rebuild the devcontainer to install the tmux feature."
53
- exit 1
50
+ if ! docker exec "$CONTAINER_ID" which tmux >/dev/null 2>&1; then
51
+ echo "ERROR: tmux is not installed in the container."
52
+ echo "Rebuild the devcontainer to install the tmux feature."
53
+ exit 1
54
54
  fi
55
55
 
56
56
  echo "Connecting to tmux session '$TMUX_SESSION'..."
@@ -68,14 +68,14 @@ echo ""
68
68
  # Pass UTF-8 locale so tmux renders Unicode correctly (not as underscores)
69
69
  # Use tmux -u to force UTF-8 mode as a belt-and-suspenders measure
70
70
  exec docker exec -it \
71
- -e LANG=en_US.UTF-8 \
72
- -e LC_ALL=en_US.UTF-8 \
73
- --user vscode "$CONTAINER_ID" bash -c "
71
+ -e LANG=en_US.UTF-8 \
72
+ -e LC_ALL=en_US.UTF-8 \
73
+ --user vscode "$CONTAINER_ID" bash -c "
74
74
  export LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8
75
75
  if tmux has-session -t '$TMUX_SESSION' 2>/dev/null; then
76
76
  tmux -u attach-session -t '$TMUX_SESSION'
77
77
  else
78
- tmux -u new-session -d -s '$TMUX_SESSION' -c /workspaces
78
+ tmux -u new-session -d -s '$TMUX_SESSION' -c \"\${WORKSPACE_ROOT:-/workspaces}\"
79
79
  sleep 0.5
80
80
  tmux send-keys -t '$TMUX_SESSION' 'cc' Enter
81
81
  tmux -u attach-session -t '$TMUX_SESSION'
@@ -1,144 +1,143 @@
1
- {
2
- "name": "CodeForge - ${localWorkspaceFolderBasename}",
3
- "image": "mcr.microsoft.com/devcontainers/python:3.14",
4
-
5
- "workspaceFolder": "/workspaces",
6
- "workspaceMount": "source=${localWorkspaceFolder},target=/workspaces,type=bind",
7
-
8
- "remoteEnv": {
9
- "WORKSPACE_ROOT": "/workspaces",
10
- "CLAUDE_CONFIG_DIR": "/workspaces/.claude",
11
- "GH_CONFIG_DIR": "/workspaces/.gh",
12
- "TMPDIR": "/workspaces/.tmp"
13
- },
14
-
15
- // Feature install order: external runtimes first (Node, uv, Go, Bun),
16
- // then Claude Code (needs Node), then custom features.
17
- // npm-dependent features (agent-browser, ccusage, ccburn, biome, lsp-servers)
18
- // must come after Node. uv-dependent features (ruff, claude-monitor) must
19
- // come after uv. notify-hook is last (lightweight, no dependencies).
20
- "overrideFeatureInstallOrder": [
21
- "ghcr.io/devcontainers/features/node",
22
- "ghcr.io/devcontainers/features/github-cli",
23
- "ghcr.io/devcontainers/features/docker-outside-of-docker",
24
- "ghcr.io/devcontainers-extra/features/uv",
25
- "ghcr.io/devcontainers/features/go",
26
- "ghcr.io/rails/devcontainer/features/bun",
27
- "ghcr.io/anthropics/devcontainer-features/claude-code",
28
- "./features/tmux",
29
- "./features/agent-browser",
30
- "./features/claude-monitor",
31
- "./features/ccusage",
32
- "./features/ccburn",
33
- "./features/ccstatusline",
34
- "./features/ast-grep",
35
- "./features/tree-sitter",
36
- "./features/lsp-servers",
37
- "./features/ruff",
38
- "./features/shfmt",
39
- "./features/dprint",
40
- "./features/shellcheck",
41
- "./features/hadolint",
42
- "./features/biome",
43
- "./features/notify-hook"
44
- ],
45
-
46
- "features": {
47
- "ghcr.io/devcontainers/features/node:1": {
48
- "version": "lts",
49
- "nodeGypDependencies": true
50
- },
51
- "ghcr.io/devcontainers/features/github-cli:1": {},
52
- "ghcr.io/devcontainers/features/docker-outside-of-docker:1":
53
- {
54
- "moby": false
55
- },
56
- "ghcr.io/devcontainers-extra/features/uv:1": {},
57
- "ghcr.io/rails/devcontainer/features/bun:1.0.2": {},
58
- "ghcr.io/anthropics/devcontainer-features/claude-code:1": {},
59
- "./features/tmux": {},
60
- "./features/ccusage": {
61
- "version": "latest",
62
- "shells": "both",
63
- "username": "automatic"
64
- },
65
- "./features/claude-monitor": {
66
- "version": "latest",
67
- "installer": "uv",
68
- "username": "automatic"
69
- },
70
- "./features/ccburn": {
71
- "version": "latest",
72
- "shells": "both",
73
- "username": "automatic"
74
- },
75
- "./features/ccstatusline": {
76
- "username": "automatic"
77
- },
78
- "./features/ast-grep": {},
79
- "./features/tree-sitter": {},
80
- "./features/lsp-servers": {},
81
- "./features/agent-browser": {},
82
- "./features/ruff": {
83
- "version": "latest",
84
- "username": "automatic"
85
- },
86
- "./features/shfmt": {},
87
- "./features/dprint": {
88
- "username": "automatic"
89
- },
90
- "./features/shellcheck": {},
91
- "./features/hadolint": {},
92
- "./features/biome": {},
93
- "./features/notify-hook": {
94
- "enableBell": true,
95
- "enableOsc": true
96
- }
97
- },
98
-
99
- "postStartCommand": "bash ${containerWorkspaceFolder}/.devcontainer/scripts/setup.sh",
100
-
101
- "remoteUser": "vscode",
102
- "containerUser": "vscode",
103
-
104
- "customizations": {
105
- "vscode": {
106
- "settings": {
107
- "terminal.integrated.profiles.linux": {
108
- "bash": {
109
- "path": "bash"
110
- },
111
- "Claude Teams (tmux)": {
112
- "path": "bash",
113
- "args": ["-c", "if tmux has-session -t claude-teams 2>/dev/null; then exec tmux -u new-session -t claude-teams; else exec tmux -u new-session -s claude-teams; fi"]
114
- }
115
- },
116
- "terminal.integrated.defaultProfile.linux": "bash",
117
- "terminal.integrated.enableBell": true,
118
- "terminal.integrated.commandsToSkipShell": [
119
- "-workbench.action.quickOpen",
120
- "-workbench.action.terminal.focusFind"
121
- ],
122
- "remote.extensionKind": {
123
- "wenbopan.vscode-terminal-osc-notifier": ["ui"]
124
- },
125
- "projectManager.git.baseFolders": ["/workspaces"],
126
- "projectManager.git.maxDepthRecursion": 1,
127
- "projectManager.showProjectNameInStatusBar": true,
128
- "projectManager.openInNewWindowWhenClickingInStatusBar": false,
129
- "projectManager.projectsLocation": "/workspaces/.config/project-manager"
130
- },
131
- "extensions": [
132
- "wenbopan.vscode-terminal-osc-notifier",
133
- "GitHub.vscode-github-actions",
134
- "fabiospampinato.vscode-todo-plus",
135
- "alefragnani.project-manager"
136
- ]
137
- }
138
- },
139
-
140
- "runArgs": [
141
- "--memory=4g",
142
- "--memory-swap=8g"
143
- ]
144
- }
1
+ {
2
+ "name": "CodeForge - ${localWorkspaceFolderBasename}",
3
+ "image": "mcr.microsoft.com/devcontainers/python:3.14",
4
+
5
+ "workspaceFolder": "/workspaces",
6
+ "workspaceMount": "source=${localWorkspaceFolder},target=/workspaces,type=bind",
7
+
8
+ "remoteEnv": {
9
+ "WORKSPACE_ROOT": "/workspaces",
10
+ "CLAUDE_CONFIG_DIR": "/workspaces/.claude",
11
+ "GH_CONFIG_DIR": "/workspaces/.gh",
12
+ "TMPDIR": "/workspaces/.tmp"
13
+ },
14
+
15
+ // Feature install order: external runtimes first (Node, uv, Go, Bun),
16
+ // then Claude Code (needs Node), then custom features.
17
+ // npm-dependent features (agent-browser, ccusage, ccburn, biome, lsp-servers)
18
+ // must come after Node. uv-dependent features (ruff, claude-monitor) must
19
+ // come after uv. notify-hook is last (lightweight, no dependencies).
20
+ "overrideFeatureInstallOrder": [
21
+ "ghcr.io/devcontainers/features/node",
22
+ "ghcr.io/devcontainers/features/github-cli",
23
+ "ghcr.io/devcontainers/features/docker-outside-of-docker",
24
+ "ghcr.io/devcontainers-extra/features/uv",
25
+ "ghcr.io/rails/devcontainer/features/bun",
26
+ "ghcr.io/anthropics/devcontainer-features/claude-code",
27
+ "./features/tmux",
28
+ "./features/agent-browser",
29
+ "./features/claude-monitor",
30
+ "./features/ccusage",
31
+ "./features/ccburn",
32
+ "./features/ccstatusline",
33
+ "./features/ast-grep",
34
+ "./features/tree-sitter",
35
+ "./features/lsp-servers",
36
+ "./features/ruff",
37
+ "./features/shfmt",
38
+ "./features/dprint",
39
+ "./features/shellcheck",
40
+ "./features/hadolint",
41
+ "./features/biome",
42
+ "./features/notify-hook"
43
+ ],
44
+
45
+ "features": {
46
+ "ghcr.io/devcontainers/features/node:1": {
47
+ "version": "lts",
48
+ "nodeGypDependencies": true
49
+ },
50
+ "ghcr.io/devcontainers/features/github-cli:1": {},
51
+ "ghcr.io/devcontainers/features/docker-outside-of-docker:1": {
52
+ "moby": false
53
+ },
54
+ "ghcr.io/devcontainers-extra/features/uv:1": {},
55
+ "ghcr.io/rails/devcontainer/features/bun:1.0.2": {},
56
+ "ghcr.io/anthropics/devcontainer-features/claude-code:1": {},
57
+ "./features/tmux": {},
58
+ "./features/ccusage": {
59
+ "version": "latest",
60
+ "shells": "both",
61
+ "username": "automatic"
62
+ },
63
+ "./features/claude-monitor": {
64
+ "version": "latest",
65
+ "installer": "uv",
66
+ "username": "automatic"
67
+ },
68
+ "./features/ccburn": {
69
+ "version": "latest",
70
+ "shells": "both",
71
+ "username": "automatic"
72
+ },
73
+ "./features/ccstatusline": {
74
+ "username": "automatic"
75
+ },
76
+ "./features/ast-grep": {},
77
+ "./features/tree-sitter": {},
78
+ "./features/lsp-servers": {},
79
+ "./features/agent-browser": {},
80
+ "./features/ruff": {
81
+ "version": "latest",
82
+ "username": "automatic"
83
+ },
84
+ "./features/shfmt": { "version": "none" },
85
+ "./features/dprint": {
86
+ "version": "none",
87
+ "username": "automatic"
88
+ },
89
+ "./features/shellcheck": { "version": "none" },
90
+ "./features/hadolint": { "version": "none" },
91
+ "./features/biome": {},
92
+ "./features/notify-hook": {
93
+ "enableBell": true,
94
+ "enableOsc": true
95
+ }
96
+ },
97
+
98
+ "postStartCommand": "bash ${containerWorkspaceFolder}/.devcontainer/scripts/setup.sh",
99
+
100
+ "remoteUser": "vscode",
101
+ "containerUser": "vscode",
102
+
103
+ "customizations": {
104
+ "vscode": {
105
+ "settings": {
106
+ "terminal.integrated.profiles.linux": {
107
+ "bash": {
108
+ "path": "bash"
109
+ },
110
+ "Claude Teams (tmux)": {
111
+ "path": "bash",
112
+ "args": [
113
+ "-c",
114
+ "if tmux has-session -t claude-teams 2>/dev/null; then exec tmux -u new-session -t claude-teams; else exec tmux -u new-session -s claude-teams; fi"
115
+ ]
116
+ }
117
+ },
118
+ "terminal.integrated.defaultProfile.linux": "bash",
119
+ "terminal.integrated.enableBell": true,
120
+ "terminal.integrated.commandsToSkipShell": [
121
+ "-workbench.action.quickOpen",
122
+ "-workbench.action.terminal.focusFind"
123
+ ],
124
+ "remote.extensionKind": {
125
+ "wenbopan.vscode-terminal-osc-notifier": ["ui"]
126
+ },
127
+ "projectManager.git.baseFolders": ["/workspaces"],
128
+ "projectManager.git.maxDepthRecursion": 2,
129
+ "projectManager.showProjectNameInStatusBar": true,
130
+ "projectManager.openInNewWindowWhenClickingInStatusBar": false,
131
+ "projectManager.projectsLocation": "/workspaces/.config/project-manager"
132
+ },
133
+ "extensions": [
134
+ "wenbopan.vscode-terminal-osc-notifier",
135
+ "GitHub.vscode-github-actions",
136
+ "fabiospampinato.vscode-todo-plus",
137
+ "alefragnani.project-manager"
138
+ ]
139
+ }
140
+ },
141
+
142
+ "runArgs": ["--memory=6g", "--memory-swap=12g"]
143
+ }
@@ -171,8 +171,9 @@ Based on your exploration:
171
171
  or update. Distinguish:
172
172
  - **Roadmap entry**: one-line description of what the version delivers (no
173
173
  implementation detail — that belongs in specs)
174
- - **Feature spec**: ≤200 line file following the standard template (Version,
175
- Status, Intent, Acceptance Criteria, Key Files, Schema, API, Dependencies)
174
+ - **Feature spec**: file following the standard template (Version,
175
+ Status, Intent, Acceptance Criteria, Key Files, Schema, API, Dependencies).
176
+ Aim for ~200 lines; split into sub-specs if significantly longer.
176
177
  - **As-built update**: if modifying an existing feature, identify which spec
177
178
  to update post-implementation
178
179
  Plans that mix roadmap-level and spec-level detail produce artifacts too
@@ -239,7 +240,7 @@ List the 3-7 files most critical for implementing this plan:
239
240
  - `/path/to/test_file.py` — Brief reason (e.g., "Test patterns to follow")
240
241
 
241
242
  ### Documentation Outputs
242
- - New spec: `.specs/vX.Y.0/feature-name.md` (≤200 lines)
243
+ - New spec: `.specs/vX.Y.0/feature-name.md`
243
244
  - Updated spec: `.specs/vX.Y.0/existing-feature.md` — changes: [list]
244
245
  - Roadmap update: `.specs/roadmap.md` — add `[ ] feature` to vX.Y.0
245
246
 
@@ -160,9 +160,9 @@ For large codebases, focus on the public API surface rather than trying to docum
160
160
 
161
161
  Produce documentation that serves the target audience. Different doc types have different readers.
162
162
 
163
- **Sizing rule:** Documentation files consumed by AI (CLAUDE.md, specs, architecture docs)
164
- should be 200 lines each. Split large documents by concern. Each file should be
165
- independently useful without requiring other docs in the same context window.
163
+ **Sizing guideline:** Documentation files consumed by AI (CLAUDE.md, specs, architecture docs)
164
+ should aim for ~200 lines each. Split large documents by concern when practical. Each file
165
+ should be independently useful without requiring other docs in the same context window.
166
166
 
167
167
  ## Documentation Types
168
168
 
@@ -20,6 +20,7 @@ skills:
20
20
  - spec-update
21
21
  - spec-check
22
22
  - spec-init
23
+ - spec-refine
23
24
  ---
24
25
 
25
26
  # Spec Writer Agent
@@ -57,10 +58,14 @@ When uncertain, investigate first — read the code, check the docs — rather t
57
58
  - **NEVER** make assumptions about behavior without checking the codebase. Use `Read`, `Glob`, and `Grep` to understand the current system before specifying changes.
58
59
  - **NEVER** write vague requirements like "the system should be fast" or "the UI should be user-friendly." Every requirement must be specific, measurable, and testable.
59
60
  - **NEVER** combine multiple independent requirements into a single statement. One requirement per line — this makes requirements individually testable and trackable.
60
- - **NEVER** produce a specification exceeding 200 lines. If a feature requires
61
- more, split it into independently loadable sub-specs (one per sub-feature)
62
- with a parent overview file that links them. Monolithic specs rot faster
63
- than they're consumed no AI context window can use a 4,000-line spec.
61
+ - **NEVER** present decisions as settled facts unless the user explicitly approved them. Tech choices, architecture decisions, scope boundaries, performance targets, and behavioral defaults that you chose without user input MUST go in `## Open Questions` with options and trade-offs — not in Requirements as decided items.
62
+ - **ALL** requirements you generate MUST be tagged `[assumed]`. You never produce `[user-approved]` requirements only `/spec-refine` does that after explicit user validation.
63
+ - **ALL** specs you produce MUST carry `**Approval:** draft`. After presenting a draft, state: "This spec requires `/spec-refine` before implementation can begin. All requirements are marked [assumed] until user-approved."
64
+ - **Aim for ~200 lines per spec.** When a spec grows beyond that, recommend
65
+ splitting into sub-specs in a feature subdirectory with a parent overview
66
+ that links them. Shorter specs are easier to consume and maintain, but
67
+ complex features sometimes need more space — don't sacrifice completeness
68
+ for an arbitrary cap.
64
69
  - **NEVER** reproduce source code, SQL schemas, or type definitions inline.
65
70
  Reference file paths instead (e.g., "see `src/engine/db/migrations/002.sql`
66
71
  lines 48-70"). The code is the source of truth; duplicated snippets go stale.
@@ -116,9 +121,10 @@ Write the specification using the formats below.
116
121
  3. **Write acceptance criteria** — Given/When/Then scenarios that define "done."
117
122
  4. **Define non-functional requirements** — Performance, security, accessibility where relevant.
118
123
  5. **List open questions** — Any unresolved decisions or unknowns that need stakeholder input.
119
- 6. **Check length** — Count lines. If the draft exceeds 200 lines, split into
120
- sub-specs by feature boundary. Create a parent overview (≤50 lines) linking
121
- the sub-specs. Each sub-spec must be independently loadable.
124
+ 6. **Check length** — If the draft exceeds ~200 lines, consider whether it
125
+ would be clearer as sub-specs split by feature boundary with a parent
126
+ overview linking them. Each sub-spec should be independently loadable.
127
+ If the length is justified by complexity, note it and proceed.
122
128
  7. **Reference, don't reproduce** — Scan your draft for inline code blocks
123
129
  containing schemas, SQL, type definitions, or configuration. Replace with
124
130
  file path references and brief descriptions of what's there.
@@ -235,6 +241,7 @@ Present specifications in this structure:
235
241
  **Version:** v0.X.0
236
242
  **Status:** planned
237
243
  **Last Updated:** YYYY-MM-DD
244
+ **Approval:** draft
238
245
 
239
246
  ## Intent
240
247
  [Problem statement + why — what exists now, what should change, who is affected]
@@ -258,18 +265,21 @@ Present specifications in this structure:
258
265
  ## Requirements
259
266
 
260
267
  ### Functional Requirements
261
- FR-1: [EARS requirement]
262
- FR-2: [EARS requirement]
268
+ FR-1 [assumed]: [EARS requirement]
269
+ FR-2 [assumed]: [EARS requirement]
263
270
  ...
264
271
 
265
272
  ### Non-Functional Requirements
266
- NFR-1: [EARS requirement]
267
- NFR-2: [EARS requirement]
273
+ NFR-1 [assumed]: [EARS requirement]
274
+ NFR-2 [assumed]: [EARS requirement]
268
275
  ...
269
276
 
270
277
  ## Dependencies
271
278
  - [External system or module this feature depends on]
272
279
 
280
+ ## Resolved Questions
281
+ [Populated by `/spec-refine`. Decisions explicitly approved by the user.]
282
+
273
283
  ## Open Questions
274
284
  [Group related unknowns. For each question, provide:]
275
285
  1. [Question] — **Type**: missing info / ambiguous behavior / policy decision
@@ -49,7 +49,7 @@
49
49
  {
50
50
  "type": "command",
51
51
  "command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/advisory-test-runner.py",
52
- "timeout": 65
52
+ "timeout": 20
53
53
  },
54
54
  {
55
55
  "type": "command",