sequant 2.0.1 → 2.1.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/dist/bin/cli.js +2 -1
- package/dist/marketplace/external_plugins/sequant/.claude-plugin/plugin.json +1 -1
- package/dist/marketplace/external_plugins/sequant/.mcp.json +6 -0
- package/dist/marketplace/external_plugins/sequant/README.md +58 -8
- package/dist/marketplace/external_plugins/sequant/hooks/post-tool.sh +19 -8
- package/dist/marketplace/external_plugins/sequant/hooks/pre-tool.sh +36 -49
- package/dist/marketplace/external_plugins/sequant/skills/_shared/references/subagent-types.md +158 -48
- package/dist/marketplace/external_plugins/sequant/skills/assess/SKILL.md +354 -352
- package/dist/marketplace/external_plugins/sequant/skills/exec/SKILL.md +1155 -33
- package/dist/marketplace/external_plugins/sequant/skills/fullsolve/SKILL.md +35 -4
- package/dist/marketplace/external_plugins/sequant/skills/qa/SKILL.md +2157 -104
- package/dist/marketplace/external_plugins/sequant/skills/qa/scripts/quality-checks.sh +1 -1
- package/dist/marketplace/external_plugins/sequant/skills/setup/SKILL.md +386 -0
- package/dist/marketplace/external_plugins/sequant/skills/solve/SKILL.md +38 -664
- package/dist/marketplace/external_plugins/sequant/skills/spec/SKILL.md +505 -120
- package/dist/marketplace/external_plugins/sequant/skills/test/SKILL.md +246 -1
- package/dist/marketplace/external_plugins/sequant/skills/testgen/SKILL.md +138 -1
- package/dist/src/commands/dashboard.js +1 -1
- package/dist/src/commands/doctor.js +1 -1
- package/dist/src/commands/init.js +10 -10
- package/dist/src/commands/logs.js +1 -1
- package/dist/src/commands/run.js +49 -39
- package/dist/src/commands/state.js +3 -3
- package/dist/src/commands/status.js +5 -5
- package/dist/src/commands/sync.js +8 -8
- package/dist/src/commands/update.js +16 -16
- package/dist/src/lib/cli-ui.js +20 -19
- package/dist/src/lib/mcp-config.js +1 -1
- package/dist/src/lib/merge-check/index.js +2 -2
- package/dist/src/lib/settings.d.ts +8 -0
- package/dist/src/lib/settings.js +1 -0
- package/dist/src/lib/shutdown.js +1 -1
- package/dist/src/lib/templates.js +2 -0
- package/dist/src/lib/wizard.js +6 -4
- package/dist/src/lib/workflow/batch-executor.js +1 -1
- package/dist/src/lib/workflow/log-writer.js +6 -6
- package/dist/src/lib/workflow/metrics-writer.js +5 -3
- package/dist/src/lib/workflow/phase-executor.js +5 -1
- package/dist/src/lib/workflow/platforms/github.js +5 -1
- package/dist/src/lib/workflow/state-cleanup.js +1 -1
- package/dist/src/lib/workflow/state-manager.js +15 -13
- package/dist/src/lib/workflow/state-rebuild.js +2 -2
- package/dist/src/lib/workflow/types.d.ts +11 -0
- package/dist/src/lib/workflow/worktree-manager.js +40 -41
- package/dist/src/lib/worktree-isolation.d.ts +130 -0
- package/dist/src/lib/worktree-isolation.js +310 -0
- package/package.json +8 -8
- package/templates/agents/sequant-explorer.md +23 -0
- package/templates/agents/sequant-implementer.md +18 -0
- package/templates/agents/sequant-qa-checker.md +24 -0
- package/templates/agents/sequant-testgen.md +25 -0
- package/templates/scripts/cleanup-worktree.sh +18 -0
- package/templates/skills/_shared/references/subagent-types.md +158 -48
- package/templates/skills/exec/SKILL.md +72 -6
- package/templates/skills/qa/SKILL.md +8 -217
- package/templates/skills/spec/SKILL.md +446 -120
- package/templates/skills/testgen/SKILL.md +138 -1
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
{
|
|
9
9
|
"name": "sequant",
|
|
10
10
|
"description": "Structured workflow system for Claude Code - GitHub issue resolution with spec, exec, test, and QA phases. Includes 17 skills, MCP server with workflow tools, and pre/post-tool hooks.",
|
|
11
|
-
"version": "1.
|
|
11
|
+
"version": "2.1.0",
|
|
12
12
|
"author": {
|
|
13
13
|
"name": "sequant-io",
|
|
14
14
|
"email": "hello@sequant.io"
|
package/dist/bin/cli.js
CHANGED
|
@@ -66,7 +66,7 @@ configureUI({
|
|
|
66
66
|
// This helps users who accidentally have a stale local install
|
|
67
67
|
if (!process.argv.includes("--quiet") && isLocalNodeModulesInstall()) {
|
|
68
68
|
const pmCommands = getPackageManagerCommands(detectPackageManagerSync());
|
|
69
|
-
console.warn(chalk.yellow("
|
|
69
|
+
console.warn(chalk.yellow("! Running sequant from local node_modules\n" +
|
|
70
70
|
" For latest version: npx sequant@latest\n" +
|
|
71
71
|
` To remove local: ${pmCommands.removePkg} sequant\n`));
|
|
72
72
|
}
|
|
@@ -152,6 +152,7 @@ program
|
|
|
152
152
|
.option("--no-pr", "Skip PR creation after successful QA (manual PR workflow)")
|
|
153
153
|
.option("-f, --force", "Force re-execution of completed issues (bypass pre-flight state guard)")
|
|
154
154
|
.option("--concurrency <n>", "Max concurrent issues in parallel mode (default: 3)", parseInt)
|
|
155
|
+
.option("--isolate-parallel", "Isolate parallel agent groups in separate worktrees (prevents file conflicts)")
|
|
155
156
|
.option("--reflect", "Analyze run results and suggest improvements")
|
|
156
157
|
.option("--agent <name>", 'Agent driver for phase execution (default: "claude-code")')
|
|
157
158
|
.action(runCommand);
|
|
@@ -2,31 +2,81 @@
|
|
|
2
2
|
|
|
3
3
|
Structured workflow system for Claude Code — GitHub issue resolution with spec, exec, test, and QA phases.
|
|
4
4
|
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- **Git** with a GitHub remote
|
|
8
|
+
- **GitHub CLI** (`gh`) authenticated (`gh auth status`)
|
|
9
|
+
- **Node.js 20+** (for MCP server via `npx`)
|
|
10
|
+
|
|
5
11
|
## Installation
|
|
6
12
|
|
|
13
|
+
### Plugin (interactive users)
|
|
14
|
+
|
|
7
15
|
```
|
|
8
|
-
/plugin install sequant@
|
|
16
|
+
/plugin install sequant@sequant-io/sequant
|
|
9
17
|
```
|
|
10
18
|
|
|
11
19
|
Or browse in `/plugin > Discover`.
|
|
12
20
|
|
|
13
|
-
|
|
21
|
+
After installing, run `/sequant:setup` to configure your project.
|
|
22
|
+
|
|
23
|
+
### npm (power users / CI)
|
|
14
24
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
25
|
+
```bash
|
|
26
|
+
npm install -g sequant
|
|
27
|
+
sequant init
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## What You Get
|
|
19
31
|
|
|
20
|
-
|
|
32
|
+
### 17 Workflow Skills
|
|
21
33
|
|
|
22
34
|
| Skill | Purpose |
|
|
23
35
|
|-------|---------|
|
|
36
|
+
| `/assess` | Triage issue, recommend workflow |
|
|
24
37
|
| `/spec` | Plan implementation and extract acceptance criteria |
|
|
25
38
|
| `/exec` | Implement changes in a feature worktree |
|
|
26
39
|
| `/test` | Browser-based UI testing |
|
|
27
40
|
| `/qa` | Code review and AC validation |
|
|
28
41
|
| `/fullsolve` | End-to-end issue resolution |
|
|
29
|
-
| `/
|
|
42
|
+
| `/loop` | Quality loop — iterate until gates pass |
|
|
43
|
+
| `/testgen` | Generate test stubs from spec criteria |
|
|
44
|
+
| `/verify` | CLI/script execution verification |
|
|
45
|
+
| `/docs` | Generate documentation for features |
|
|
46
|
+
| `/reflect` | Strategic workflow reflection |
|
|
47
|
+
| `/improve` | Codebase analysis and improvement |
|
|
48
|
+
| `/clean` | Repository cleanup |
|
|
49
|
+
| `/security-review` | Deep security analysis |
|
|
50
|
+
| `/release` | Automated release workflow |
|
|
51
|
+
| `/merger` | Multi-issue integration and merge |
|
|
52
|
+
| `/setup` | Project initialization for plugin users |
|
|
53
|
+
|
|
54
|
+
### MCP Tools (automatic with plugin)
|
|
55
|
+
|
|
56
|
+
| Tool | Purpose |
|
|
57
|
+
|------|---------|
|
|
58
|
+
| `sequant_status` | Check issue progress and workflow state |
|
|
59
|
+
| `sequant_run` | Execute workflow phases |
|
|
60
|
+
| `sequant_logs` | Review past run results |
|
|
61
|
+
|
|
62
|
+
### MCP Resources
|
|
63
|
+
|
|
64
|
+
| Resource | Purpose |
|
|
65
|
+
|----------|---------|
|
|
66
|
+
| `sequant://state` | Dashboard view of all tracked issues |
|
|
67
|
+
| `sequant://config` | Current workflow settings |
|
|
68
|
+
|
|
69
|
+
### Hooks
|
|
70
|
+
|
|
71
|
+
- **Pre-tool guardrails** — blocks dangerous commands, enforces worktree safety
|
|
72
|
+
- **Post-tool tracking** — timing, quality metrics, smart test runner
|
|
73
|
+
|
|
74
|
+
## Quick Start
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
/assess 123 # Analyze issue, get recommended workflow
|
|
78
|
+
/fullsolve 123 # End-to-end: spec → exec → qa → PR
|
|
79
|
+
```
|
|
30
80
|
|
|
31
81
|
## Documentation
|
|
32
82
|
|
|
@@ -38,24 +38,35 @@ else
|
|
|
38
38
|
TOOL_OUTPUT=$(echo "$INPUT_JSON" | grep -oE '"tool_response"\s*:\s*\{[^}]+\}' | head -1)
|
|
39
39
|
fi
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
_TMPDIR="${TMPDIR:-/tmp}"
|
|
42
|
+
|
|
43
|
+
# Use CLAUDE_PLUGIN_DATA for persistent logs (survives plugin updates)
|
|
44
|
+
if [[ -n "${CLAUDE_PLUGIN_DATA}" ]]; then
|
|
45
|
+
_LOG_DIR="${CLAUDE_PLUGIN_DATA}/logs"
|
|
46
|
+
mkdir -p "$_LOG_DIR"
|
|
47
|
+
else
|
|
48
|
+
_LOG_DIR="${_TMPDIR}"
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
TIMING_LOG="${_LOG_DIR}/claude-timing.log"
|
|
52
|
+
QUALITY_LOG="${_LOG_DIR}/claude-quality.log"
|
|
53
|
+
TESTS_LOG="${_LOG_DIR}/claude-tests.log"
|
|
54
|
+
PARALLEL_MARKER_PREFIX="${_TMPDIR}/claude-parallel-"
|
|
45
55
|
|
|
46
56
|
# === AGENT ID DETECTION ===
|
|
47
57
|
# For parallel agents, detect group ID from marker files
|
|
48
|
-
# Format: /
|
|
58
|
+
# Format: ${_TMPDIR}/claude-parallel-<group-id>.marker
|
|
49
59
|
AGENT_ID=""
|
|
50
60
|
IS_PARALLEL_AGENT="false"
|
|
51
|
-
|
|
52
|
-
|
|
61
|
+
# Find marker files using find (works in both bash and zsh)
|
|
62
|
+
while IFS= read -r marker; do
|
|
63
|
+
if [[ -n "$marker" && -f "$marker" ]]; then
|
|
53
64
|
# Extract group ID from marker filename
|
|
54
65
|
AGENT_ID=$(basename "$marker" | sed 's/claude-parallel-//' | sed 's/\.marker//')
|
|
55
66
|
IS_PARALLEL_AGENT="true"
|
|
56
67
|
break
|
|
57
68
|
fi
|
|
58
|
-
done
|
|
69
|
+
done < <(find "${_TMPDIR}" -maxdepth 1 -name "claude-parallel-*.marker" 2>/dev/null)
|
|
59
70
|
|
|
60
71
|
# === TIMING END ===
|
|
61
72
|
# Include agent ID in log format if available (AC-4)
|
|
@@ -33,20 +33,32 @@ else
|
|
|
33
33
|
fi
|
|
34
34
|
fi
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
_TMPDIR="${TMPDIR:-/tmp}"
|
|
37
|
+
|
|
38
|
+
# Use CLAUDE_PLUGIN_DATA for persistent logs (survives plugin updates)
|
|
39
|
+
if [[ -n "${CLAUDE_PLUGIN_DATA}" ]]; then
|
|
40
|
+
_LOG_DIR="${CLAUDE_PLUGIN_DATA}/logs"
|
|
41
|
+
mkdir -p "$_LOG_DIR"
|
|
42
|
+
else
|
|
43
|
+
_LOG_DIR="${_TMPDIR}"
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
TIMING_LOG="${_LOG_DIR}/claude-timing.log"
|
|
47
|
+
HOOK_LOG="${_LOG_DIR}/claude-hook.log"
|
|
48
|
+
PARALLEL_MARKER_PREFIX="${_TMPDIR}/claude-parallel-"
|
|
38
49
|
|
|
39
50
|
# === AGENT ID DETECTION ===
|
|
40
51
|
# For parallel agents, detect group ID from marker files
|
|
41
|
-
# Format: /
|
|
52
|
+
# Format: ${_TMPDIR}/claude-parallel-<group-id>.marker
|
|
42
53
|
AGENT_ID=""
|
|
43
|
-
|
|
44
|
-
|
|
54
|
+
# Find marker files using find (works in both bash and zsh)
|
|
55
|
+
while IFS= read -r marker; do
|
|
56
|
+
if [[ -n "$marker" && -f "$marker" ]]; then
|
|
45
57
|
# Extract group ID from marker filename
|
|
46
58
|
AGENT_ID=$(basename "$marker" | sed 's/claude-parallel-//' | sed 's/\.marker//')
|
|
47
59
|
break
|
|
48
60
|
fi
|
|
49
|
-
done
|
|
61
|
+
done < <(find "${_TMPDIR}" -maxdepth 1 -name "claude-parallel-*.marker" 2>/dev/null)
|
|
50
62
|
|
|
51
63
|
# === TIMING START ===
|
|
52
64
|
# Include agent ID in log format if available (AC-4)
|
|
@@ -75,38 +87,38 @@ if [[ "$TOOL_NAME" == "Bash" ]]; then
|
|
|
75
87
|
if ! echo "$TOOL_INPUT" | grep -qE '^gh (issue|pr) '; then
|
|
76
88
|
# Pattern requires command to START with file reader (not match in quoted strings)
|
|
77
89
|
if echo "$TOOL_INPUT" | grep -qE '^(cat|less|head|tail|more) .*\.(env|pem|key)'; then
|
|
78
|
-
echo "HOOK_BLOCKED: Reading secret file" | tee -a
|
|
90
|
+
echo "HOOK_BLOCKED: Reading secret file" | tee -a "$HOOK_LOG" >&2
|
|
79
91
|
exit 2
|
|
80
92
|
fi
|
|
81
93
|
|
|
82
94
|
if echo "$TOOL_INPUT" | grep -qE '^(cat|less) .*~/\.(ssh|aws|gnupg|config/gh)'; then
|
|
83
|
-
echo "HOOK_BLOCKED: Reading credential directory" | tee -a
|
|
95
|
+
echo "HOOK_BLOCKED: Reading credential directory" | tee -a "$HOOK_LOG" >&2
|
|
84
96
|
exit 2
|
|
85
97
|
fi
|
|
86
98
|
fi
|
|
87
99
|
|
|
88
100
|
# Bare environment dump
|
|
89
101
|
if echo "$TOOL_INPUT" | grep -qE '^(env|printenv|export)$'; then
|
|
90
|
-
echo "HOOK_BLOCKED: Environment dump" | tee -a
|
|
102
|
+
echo "HOOK_BLOCKED: Environment dump" | tee -a "$HOOK_LOG" >&2
|
|
91
103
|
exit 2
|
|
92
104
|
fi
|
|
93
105
|
|
|
94
106
|
# Destructive system commands
|
|
95
107
|
if echo "$TOOL_INPUT" | grep -qE 'sudo|rm -rf /|rm -rf ~|rm -rf \$HOME'; then
|
|
96
|
-
echo "HOOK_BLOCKED: Destructive system command" | tee -a
|
|
108
|
+
echo "HOOK_BLOCKED: Destructive system command" | tee -a "$HOOK_LOG" >&2
|
|
97
109
|
exit 2
|
|
98
110
|
fi
|
|
99
111
|
|
|
100
112
|
# Deployment (should never happen in issue automation)
|
|
101
113
|
if echo "$TOOL_INPUT" | grep -qE 'vercel (deploy|--prod)|terraform (apply|destroy)|kubectl (apply|delete)'; then
|
|
102
|
-
echo "HOOK_BLOCKED: Deployment command" | tee -a
|
|
114
|
+
echo "HOOK_BLOCKED: Deployment command" | tee -a "$HOOK_LOG" >&2
|
|
103
115
|
exit 2
|
|
104
116
|
fi
|
|
105
117
|
|
|
106
118
|
# Force push
|
|
107
119
|
# Pattern requires -f to be a standalone flag (not part of branch name like -fix)
|
|
108
120
|
if echo "$TOOL_INPUT" | grep -qE 'git push.*(--force| -f($| ))'; then
|
|
109
|
-
echo "HOOK_BLOCKED: Force push" | tee -a
|
|
121
|
+
echo "HOOK_BLOCKED: Force push" | tee -a "$HOOK_LOG" >&2
|
|
110
122
|
exit 2
|
|
111
123
|
fi
|
|
112
124
|
|
|
@@ -149,14 +161,14 @@ if echo "$TOOL_INPUT" | grep -qE 'git reset.*(--hard|origin)'; then
|
|
|
149
161
|
echo " git stash # save changes"
|
|
150
162
|
echo " git merge --abort # cancel merge"
|
|
151
163
|
echo " Or run directly in terminal (outside Claude Code) to bypass"
|
|
152
|
-
} | tee -a
|
|
164
|
+
} | tee -a "$HOOK_LOG" >&2
|
|
153
165
|
exit 2
|
|
154
166
|
fi
|
|
155
167
|
fi
|
|
156
168
|
|
|
157
169
|
# CI/CD triggers (automation shouldn't trigger more automation)
|
|
158
170
|
if echo "$TOOL_INPUT" | grep -qE 'gh workflow run'; then
|
|
159
|
-
echo "HOOK_BLOCKED: Workflow trigger" | tee -a
|
|
171
|
+
echo "HOOK_BLOCKED: Workflow trigger" | tee -a "$HOOK_LOG" >&2
|
|
160
172
|
exit 2
|
|
161
173
|
fi
|
|
162
174
|
|
|
@@ -222,7 +234,7 @@ if [[ "${CLAUDE_HOOKS_SECURITY:-true}" != "false" ]]; then
|
|
|
222
234
|
{
|
|
223
235
|
echo "HOOK_BLOCKED: Hardcoded secret detected in staged changes"
|
|
224
236
|
echo " Use 'git commit --no-verify' to bypass if this is a false positive"
|
|
225
|
-
} | tee -a
|
|
237
|
+
} | tee -a "$HOOK_LOG" >&2
|
|
226
238
|
exit 2
|
|
227
239
|
fi
|
|
228
240
|
|
|
@@ -233,7 +245,7 @@ if [[ "${CLAUDE_HOOKS_SECURITY:-true}" != "false" ]]; then
|
|
|
233
245
|
echo "HOOK_BLOCKED: Sensitive file in commit (${STAGED_FILES})"
|
|
234
246
|
echo " Files like .env, *.pem, *.key should not be committed"
|
|
235
247
|
echo " Use 'git commit --no-verify' to bypass if this is intentional"
|
|
236
|
-
} | tee -a
|
|
248
|
+
} | tee -a "$HOOK_LOG" >&2
|
|
237
249
|
exit 2
|
|
238
250
|
fi
|
|
239
251
|
fi
|
|
@@ -262,7 +274,7 @@ if [[ "$TOOL_NAME" == "Bash" ]] && echo "$TOOL_INPUT" | grep -qE 'git commit'; t
|
|
|
262
274
|
fi
|
|
263
275
|
|
|
264
276
|
if [[ "$CHANGES" -eq 0 ]]; then
|
|
265
|
-
echo "HOOK_BLOCKED: No changes to commit. Stage files with 'git add' first." | tee -a
|
|
277
|
+
echo "HOOK_BLOCKED: No changes to commit. Stage files with 'git add' first." | tee -a "$HOOK_LOG" >&2
|
|
266
278
|
exit 2
|
|
267
279
|
fi
|
|
268
280
|
fi
|
|
@@ -271,7 +283,7 @@ fi
|
|
|
271
283
|
# --- Worktree Validation (AC-8) ---
|
|
272
284
|
# Warn (but don't block) when committing outside a feature worktree
|
|
273
285
|
# This catches accidental commits to main repo during feature work
|
|
274
|
-
QUALITY_LOG="/
|
|
286
|
+
QUALITY_LOG="${_LOG_DIR}/claude-quality.log"
|
|
275
287
|
if [[ "$TOOL_NAME" == "Bash" ]] && echo "$TOOL_INPUT" | grep -qE 'git commit'; then
|
|
276
288
|
CWD=$(pwd)
|
|
277
289
|
if ! echo "$CWD" | grep -qE 'worktrees/feature/'; then
|
|
@@ -321,7 +333,7 @@ if [[ "$TOOL_NAME" == "Bash" ]] && echo "$TOOL_INPUT" | grep -qE 'git commit'; t
|
|
|
321
333
|
fi
|
|
322
334
|
echo " Types: feat|fix|docs|style|refactor|test|chore|ci|build|perf"
|
|
323
335
|
echo " Got: $MSG"
|
|
324
|
-
} | tee -a
|
|
336
|
+
} | tee -a "$HOOK_LOG" >&2
|
|
325
337
|
exit 2
|
|
326
338
|
fi
|
|
327
339
|
fi
|
|
@@ -356,7 +368,7 @@ if [[ "$TOOL_NAME" == "Edit" || "$TOOL_NAME" == "Write" ]]; then
|
|
|
356
368
|
# AC-4 (Issue #31): Check worktree directory exists before path validation
|
|
357
369
|
# Prevents Write tool from creating non-existent worktree directories
|
|
358
370
|
if [[ ! -d "$EXPECTED_WORKTREE" ]]; then
|
|
359
|
-
echo "HOOK_BLOCKED: Worktree does not exist: $EXPECTED_WORKTREE" | tee -a
|
|
371
|
+
echo "HOOK_BLOCKED: Worktree does not exist: $EXPECTED_WORKTREE" | tee -a "$HOOK_LOG" >&2
|
|
360
372
|
exit 2
|
|
361
373
|
fi
|
|
362
374
|
|
|
@@ -385,7 +397,7 @@ if [[ "$TOOL_NAME" == "Edit" || "$TOOL_NAME" == "Write" ]]; then
|
|
|
385
397
|
if [[ -n "${SEQUANT_ISSUE:-}" ]]; then
|
|
386
398
|
echo " Issue: #$SEQUANT_ISSUE"
|
|
387
399
|
fi
|
|
388
|
-
} | tee -a
|
|
400
|
+
} | tee -a "$HOOK_LOG" >&2
|
|
389
401
|
exit 2
|
|
390
402
|
fi
|
|
391
403
|
fi
|
|
@@ -408,7 +420,7 @@ if [[ "${CLAUDE_HOOKS_FILE_LOCKING:-true}" == "true" ]]; then
|
|
|
408
420
|
|
|
409
421
|
if [[ -n "$FILE_PATH" ]]; then
|
|
410
422
|
# Create a lock file based on file path hash (handles special chars)
|
|
411
|
-
LOCK_FILE="/
|
|
423
|
+
LOCK_FILE="${_TMPDIR}/claude-lock-$(echo "$FILE_PATH" | md5 -q 2>/dev/null || echo "$FILE_PATH" | md5sum | cut -d' ' -f1).lock"
|
|
412
424
|
|
|
413
425
|
# Try to acquire lock with 30 second timeout
|
|
414
426
|
# Use a subshell to hold the lock during the tool execution
|
|
@@ -416,7 +428,7 @@ if [[ "${CLAUDE_HOOKS_FILE_LOCKING:-true}" == "true" ]]; then
|
|
|
416
428
|
# macOS: use lockf
|
|
417
429
|
exec 200>"$LOCK_FILE"
|
|
418
430
|
if ! lockf -t 30 200 2>/dev/null; then
|
|
419
|
-
echo "HOOK_BLOCKED: File locked by another agent: $FILE_PATH" | tee -a
|
|
431
|
+
echo "HOOK_BLOCKED: File locked by another agent: $FILE_PATH" | tee -a "$HOOK_LOG" >&2
|
|
420
432
|
exit 2
|
|
421
433
|
fi
|
|
422
434
|
# Lock will be released when the file descriptor closes (process exits)
|
|
@@ -424,7 +436,7 @@ if [[ "${CLAUDE_HOOKS_FILE_LOCKING:-true}" == "true" ]]; then
|
|
|
424
436
|
# Linux: use flock
|
|
425
437
|
exec 200>"$LOCK_FILE"
|
|
426
438
|
if ! flock -w 30 200 2>/dev/null; then
|
|
427
|
-
echo "HOOK_BLOCKED: File locked by another agent: $FILE_PATH" | tee -a
|
|
439
|
+
echo "HOOK_BLOCKED: File locked by another agent: $FILE_PATH" | tee -a "$HOOK_LOG" >&2
|
|
428
440
|
exit 2
|
|
429
441
|
fi
|
|
430
442
|
fi
|
|
@@ -433,31 +445,6 @@ if [[ "${CLAUDE_HOOKS_FILE_LOCKING:-true}" == "true" ]]; then
|
|
|
433
445
|
fi
|
|
434
446
|
fi
|
|
435
447
|
|
|
436
|
-
# === PRE-MERGE WORKTREE CLEANUP ===
|
|
437
|
-
# Auto-remove worktree before `gh pr merge` to prevent --delete-branch failure
|
|
438
|
-
# The worktree locks the branch, causing merge to partially fail
|
|
439
|
-
if [[ "$TOOL_NAME" == "Bash" ]] && echo "$TOOL_INPUT" | grep -qE 'gh pr merge'; then
|
|
440
|
-
# Extract PR number from command
|
|
441
|
-
PR_NUM=$(echo "$TOOL_INPUT" | grep -oE 'gh pr merge [0-9]+' | grep -oE '[0-9]+')
|
|
442
|
-
|
|
443
|
-
if [[ -n "$PR_NUM" ]]; then
|
|
444
|
-
# Get the branch name for this PR
|
|
445
|
-
BRANCH_NAME=$(gh pr view "$PR_NUM" --json headRefName --jq '.headRefName' 2>/dev/null || true)
|
|
446
|
-
|
|
447
|
-
if [[ -n "$BRANCH_NAME" ]]; then
|
|
448
|
-
# Check if a worktree exists for this branch
|
|
449
|
-
# Note: worktree line is 2 lines before branch line in porcelain output
|
|
450
|
-
WORKTREE_PATH=$(git worktree list --porcelain 2>/dev/null | grep -B2 "branch refs/heads/$BRANCH_NAME" | grep "^worktree " | sed 's/^worktree //' || true)
|
|
451
|
-
|
|
452
|
-
if [[ -n "$WORKTREE_PATH" && -d "$WORKTREE_PATH" ]]; then
|
|
453
|
-
# Remove the worktree before merge proceeds
|
|
454
|
-
git worktree remove "$WORKTREE_PATH" --force 2>/dev/null || true
|
|
455
|
-
echo "PRE-MERGE: Removed worktree $WORKTREE_PATH for branch $BRANCH_NAME" >> /tmp/claude-hook.log
|
|
456
|
-
fi
|
|
457
|
-
fi
|
|
458
|
-
fi
|
|
459
|
-
fi
|
|
460
|
-
|
|
461
448
|
# === ALLOW EVERYTHING ELSE ===
|
|
462
449
|
# Slash commands need: git, npm, file edits, gh pr/issue, MCP tools
|
|
463
450
|
exit 0
|