Skip to content

Commit ff798ee

Browse files
authored
fix(please-plugins): setup command fails to find root package.json (#130)
* docs(track): add fix-setup-glob-pattern-20260329 Add bugfix track for setup command failing to find root package.json due to Glob result truncation by node_modules entries. Plan: delegate dependency scanning to check-dependencies.ts via --setup CLI mode. Refs: #129 * chore(track): fix-setup-glob-pattern-20260329 start implementation * feat(please-plugins): add --setup CLI mode to check-dependencies Add scanForSetup() function that outputs structured JSON with detected plugins and their source packages/files, separated by install status. Update main() to handle --setup flag bypassing stdin hook protocol. Refs: #129 * fix(please-plugins): rewrite setup command to use script delegation Replace ambiguous LLM prose instructions with direct script invocation of check-dependencies.ts --setup. Eliminates Glob truncation bug where node_modules entries buried the root package.json. Refs: #129 * chore(checkpoint): complete all phases for fix-setup-glob-pattern All 9 tasks completed. Tests pass (46/46). Manual verification confirms setup --setup mode correctly finds root package.json in project with node_modules/. Refs: #129 * fix(please-plugins): apply review suggestions - Use ESM import for mkdirSync instead of require() in test - Remove redundant truthiness check on loadEnabledPlugins result Refs: #129 * refactor(please-plugins): reduce duplication in scanForSetup by reusing detectPackages/detectTooling Extract resolvePackageSource and resolveToolingSource helpers to annotate detection results with source info, so scanForSetup can delegate all detection logic to the existing functions rather than duplicating it.
1 parent 01e7e75 commit ff798ee

8 files changed

Lines changed: 421 additions & 24 deletions

File tree

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
## Bug Investigation Report
2+
3+
### 1. Reproduction Status
4+
5+
[Reproduced — Always reproducible]
6+
7+
**Reproduction Path:**
8+
1. `plugins/please-plugins/commands/setup.md:12` — Ambiguous instruction "Read `package.json` in the current working directory"
9+
2. Claude selects `Glob` tool with pattern `package.json`
10+
3. In projects with `node_modules/`, 250+ results returned sorted by mtime
11+
4. Root `package.json` truncated beyond Glob's `head_limit` (250)
12+
5. **Failure point**: Command reports file not found or reads wrong nested `package.json`
13+
14+
### 2. Root Cause Analysis
15+
16+
**Problem Location:**
17+
- File: `plugins/please-plugins/commands/setup.md`
18+
- Section: Step 1: Scan Dependencies
19+
- Line: 12
20+
21+
**Root Cause:**
22+
The instruction "Read `package.json` in the current working directory" is ambiguous — it doesn't specify which tool to use or constrain the path. Claude may use Glob before Read, and in projects with `node_modules/`, the Glob results are overwhelmed by nested `package.json` files sorted by modification time, truncating the root file from results.
23+
24+
**Code Context:**
25+
```markdown
26+
## Step 1: Scan Dependencies
27+
28+
Read `package.json` in the current working directory. If it doesn't exist, inform the user and stop.
29+
```
30+
31+
The TypeScript hook `check-dependencies.ts:223-233` handles this correctly:
32+
```typescript
33+
function loadPackageJson(cwd: string): Record<string, unknown> | null {
34+
const pkgPath = join(cwd, 'package.json') // direct path construction
35+
try {
36+
if (!existsSync(pkgPath)) return null
37+
const content = readFileSync(pkgPath, 'utf-8')
38+
return JSON.parse(content)
39+
} catch { return null }
40+
}
41+
```
42+
43+
### 3. Proposed Solutions
44+
45+
#### Solution 1: Script Delegation (Recommended)
46+
47+
Refactor `setup.md` to delegate dependency scanning to `check-dependencies.ts` via a CLI mode, outputting structured JSON for the command to display. Eliminates the problem class entirely.
48+
49+
**Pros:** Reliable, tested, no LLM interpretation ambiguity, DRY with existing hook
50+
**Cons:** Requires adding a CLI entry point to `check-dependencies.ts`
51+
52+
#### Solution 2: Explicit Tool Instructions
53+
54+
Replace ambiguous prose with explicit tool instructions:
55+
> Use the `Read` tool with path `./package.json`. Do not use Glob.
56+
57+
**Pros:** Minimal change, quick fix
58+
**Cons:** Still relies on LLM following instructions, fragile, duplicates logic
59+
60+
### 4. Testing Requirements
61+
62+
1. **Bug Scenario:** Run setup in a project with `node_modules/` — must find root `package.json`
63+
2. **Edge Cases:** Project without `package.json`, project without `node_modules/`
64+
3. **Regression:** Existing `check-dependencies.test.ts` tests must pass
65+
66+
### 5. Similar Code Patterns
67+
68+
- `setup.md:27` — Step 2 reads `.claude/settings.json` with same ambiguous pattern (lower risk but same class of bug)
69+
- No other command files in `plugins/*/commands/` have this pattern
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"track_id": "fix-setup-glob-pattern-20260329",
3+
"type": "bugfix",
4+
"status": "in_progress",
5+
"created_at": "2026-03-29T14:50:32+09:00",
6+
"updated_at": "2026-03-29T14:56:00+09:00",
7+
"issue": "#129",
8+
"pr": "",
9+
"project": ""
10+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Plan: Fix setup command package.json discovery
2+
3+
> Track: fix-setup-glob-pattern-20260329
4+
> Spec: [spec.md](./spec.md)
5+
6+
## Overview
7+
- **Source**: /please:plan
8+
- **Track**: fix-setup-glob-pattern-20260329
9+
- **Created**: 2026-03-29
10+
- **Approach**: Script delegation — add `--setup` CLI mode to `check-dependencies.ts`
11+
12+
## Purpose
13+
14+
Fix `/please-plugins:setup` command that fails to find root `package.json` due to Glob result truncation by `node_modules/` entries.
15+
16+
## Context
17+
18+
`check-dependencies.ts` already implements all detection logic correctly (with direct path construction), but is only invocable via stdin-based hook protocol. The setup command reimplements the same logic as ambiguous LLM prose instructions.
19+
20+
## Architecture Decision
21+
22+
**Script delegation** over explicit tool instructions. Rationale:
23+
- Eliminates the problem class entirely (no LLM interpretation of file paths)
24+
- DRY — reuses tested logic in `check-dependencies.ts`
25+
- Precedent: `cubic:review` command uses same pattern (invoke CLI, parse JSON)
26+
27+
## Tasks
28+
29+
### Phase 1: Add `--setup` CLI mode to check-dependencies.ts
30+
31+
- [x] T-1: Add `SetupOutput` interface with `detected` and `installed` arrays, tracking source package/file per match
32+
- [x] T-2: Add `scanForSetup(cwd: string)` function that calls `loadPackageJson`, `detectPackages`, `detectTooling`, `loadEnabledPlugins`, and returns `SetupOutput`
33+
- [x] T-3: Update `main()` to check `process.argv` for `--setup` flag and branch to `scanForSetup()` with JSON stdout
34+
- [x] T-4: Write tests for `scanForSetup()` — success, no package.json, no matches, with installed plugins
35+
36+
### Phase 2: Rewrite setup.md to use script delegation
37+
38+
- [x] T-5: Replace Steps 1-2 in `setup.md` with single `bun run` invocation of `check-dependencies.ts --setup`
39+
- [x] T-6: Update Step 3 to parse JSON output and present results using `AskUserQuestion`
40+
- [x] T-7: Ensure Step 4 (install) and Step 5 (summary) remain unchanged
41+
42+
### Phase 3: Verification
43+
44+
- [x] T-8: Run existing `check-dependencies.test.ts` — all must pass (regression)
45+
- [x] T-9: Manual verification in a project with `node_modules/`
46+
47+
## Key Files
48+
49+
| File | Action |
50+
|------|--------|
51+
| `plugins/please-plugins/hooks/check-dependencies.ts` | Add `--setup` mode, `scanForSetup()`, `SetupOutput` |
52+
| `plugins/please-plugins/hooks/check-dependencies.test.ts` | Add tests for `scanForSetup()` |
53+
| `plugins/please-plugins/commands/setup.md` | Rewrite Steps 1-2 to delegate to script |
54+
55+
## Verification
56+
57+
1. Run `bun test plugins/please-plugins/hooks/check-dependencies.test.ts`
58+
2. Run `bun run plugins/please-plugins/hooks/check-dependencies.ts --setup` in a project with `node_modules/`
59+
3. Invoke `/please-plugins:setup` and verify it finds root `package.json`
60+
61+
## Progress
62+
63+
_(Updated by /please:implement)_
64+
65+
## Decision Log
66+
67+
| Date | Decision | Rationale |
68+
|------|----------|-----------|
69+
| 2026-03-29 | Script delegation over explicit tool instructions | Eliminates problem class, DRY, tested |
70+
| 2026-03-29 | Monorepo workspace scanning out of scope | Separate feature, not part of this bugfix |
71+
72+
## Surprises & Discoveries
73+
74+
- `check-dependencies.ts` has no CLI entry point — only stdin-based hook protocol
75+
- No existing command in the repo delegates to a TypeScript script; `cubic:review` (external CLI) is closest precedent
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Bug Fix: setup command fails to find root package.json
2+
3+
> Track: fix-setup-glob-pattern-20260329
4+
> Investigation: [investigation.md](./investigation.md)
5+
6+
## Overview
7+
8+
The `/please-plugins:setup` command instructs Claude to "Read `package.json` in the current working directory" (line 12), but this ambiguous instruction allows Claude to use the Glob tool first. In projects with `node_modules/`, hundreds of nested `package.json` files bury the root file beyond the Glob result limit (250), making the setup command unusable.
9+
10+
## Reproduction
11+
12+
1. Open any project with `node_modules/` directory
13+
2. Run `/please-plugins:setup`
14+
3. Claude Globs for `package.json`, gets 250+ results sorted by mtime
15+
4. Root `package.json` is truncated from results
16+
5. Command fails: "package.json not found" or reads wrong file
17+
18+
**Expected**: Setup reads root `./package.json` directly and scans dependencies
19+
**Actual**: Setup fails to find or reads wrong `package.json`
20+
21+
## Root Cause
22+
23+
`setup.md:12` uses ambiguous prose ("Read `package.json`") without constraining tool choice or path. The TypeScript hook `check-dependencies.ts` already handles this correctly with `join(cwd, 'package.json')` — the command reimplements the same logic as fragile LLM instructions.
24+
25+
## Requirements
26+
27+
### Functional Requirements
28+
29+
- [ ] FR-1: Refactor `setup.md` Step 1 to delegate dependency scanning to the existing `check-dependencies.ts` script rather than reimplementing in natural language
30+
- [ ] FR-2: Ensure the script outputs structured JSON that the command can parse and display
31+
- [ ] FR-3: Fix any other ambiguous file-read instructions in `setup.md` (e.g., `.claude/settings.json` in Step 2)
32+
33+
### Testing Requirements
34+
35+
- [ ] TR-1: Verify setup works in a project with `node_modules/` present
36+
- [ ] TR-2: Verify setup works in a project without `node_modules/`
37+
- [ ] TR-3: Verify setup works when `package.json` doesn't exist (graceful error)
38+
39+
## Acceptance Criteria
40+
41+
- [ ] AC-1: `/please-plugins:setup` reliably finds root `package.json` regardless of `node_modules/` presence
42+
- [ ] AC-2: All existing `check-dependencies.test.ts` tests continue to pass
43+
- [ ] AC-3: Setup command uses script delegation instead of ambiguous LLM instructions for file discovery
44+
45+
## Out of Scope
46+
47+
- Rewriting `check-dependencies.ts` internals
48+
- Adding new plugin mappings
49+
- Changes to the hook system itself
50+
- Monorepo workspace scanning (separate track)

.please/docs/tracks/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
| [add-code-intelligence-marketplace-20260328](active/add-code-intelligence-marketplace-20260328/plan.md) | Add code-intelligence marketplace | feature | - | 2026-03-28 | planned |
1212
| [hooks-if-field-20260328](active/hooks-if-field-20260328/) | Add `if` field to hooks | feature || 2026-03-28 | planned |
1313
| [web-nuxt-update-20260328](active/web-nuxt-update-20260328/plan.md) | Web App Dependency Update | chore | #126 | 2026-03-28 | in_progress |
14+
| [fix-setup-glob-pattern-20260329](active/fix-setup-glob-pattern-20260329/plan.md) | Fix setup command package.json discovery | bugfix | #129 | 2026-03-29 | in_progress |
1415

1516
## Recently Completed
1617

plugins/please-plugins/commands/setup.md

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,61 @@
11
---
22
description: Scan project dependencies and install recommended Claude Code plugins
3-
allowed-tools: Read, Bash, Glob, Grep, AskUserQuestion
3+
allowed-tools: Read, Bash, AskUserQuestion
44
---
55

66
# Plugin Recommender Setup
77

8-
Scan the current project's `package.json` and tooling files to detect packages that have corresponding Claude Code plugins in the `pleaseai` marketplace, then help the user install them.
8+
Scan the current project's dependencies and tooling files to detect packages that have corresponding Claude Code plugins in the `pleaseai` marketplace, then help the user install them.
99

1010
## Step 1: Scan Dependencies
1111

12-
Read `package.json` in the current working directory. If it doesn't exist, inform the user and stop.
13-
14-
Read the plugin mappings and tooling mappings from the plugin's data files:
12+
Run the dependency scanner script to detect matching plugins:
1513

1614
```bash
17-
cat "${CLAUDE_PLUGIN_ROOT}/hooks/plugin-mappings.json"
18-
cat "${CLAUDE_PLUGIN_ROOT}/hooks/tooling-mappings.json"
15+
bun run "${CLAUDE_PLUGIN_ROOT}/hooks/check-dependencies.ts" --setup
16+
```
17+
18+
Parse the JSON output. The script returns:
19+
20+
```json
21+
{
22+
"detected": [
23+
{ "pluginName": "nuxt-ui", "source": "@nuxt/ui" },
24+
{ "pluginName": "turborepo", "source": "turbo.json" }
25+
],
26+
"installed": ["vitest"]
27+
}
1928
```
2029

21-
Parse the project's `dependencies` and `devDependencies` to find matches against the plugin mappings. Also check for tooling indicators:
22-
- Lock files: `pnpm-lock.yaml`, `turbo.json`
23-
- `packageManager` field in `package.json`
30+
- `detected`: Plugins that are available but not yet installed, with the source package or file that triggered the match.
31+
- `installed`: Plugin names that are already installed.
2432

25-
## Step 2: Check Installed Plugins
33+
If the script exits with a non-zero code, inform the user of the error and stop.
2634

27-
Read `.claude/settings.json` (project-level) to check which plugins are already installed. Look for entries in `enabledPlugins` matching `<pluginName>@pleaseai`.
35+
## Step 2: Show Results
2836

29-
## Step 3: Show Results
37+
If `detected` is empty and `installed` is empty: inform the user "No matching plugins found for this project's dependencies."
3038

31-
Present the scan results to the user, categorized:
39+
If `detected` is empty and `installed` is not empty: inform the user "All recommended plugins are already installed!"
40+
41+
Otherwise, present the scan results:
3242

3343
```
3444
AskUserQuestion({
3545
questions: [{
3646
header: "Plugins",
37-
question: "Detected packages and their plugin status:\n\n{for each detected plugin: ✅ installed / ⬜ not installed — source package}\n\nSelect plugins to install:",
47+
question: "Detected packages and their plugin status:\n\n{for each installed plugin: ✅ {pluginName}}\n{for each detected plugin: ⬜ {pluginName} — {source}}\n\nSelect plugins to install:",
3848
multiSelect: true,
3949
options: [
40-
// Only list NOT-installed plugins as selectable options
41-
{ label: "{pluginName}", description: "Detected: {source package or tooling indicator}" },
50+
// Only list detected (not-installed) plugins as selectable options
51+
{ label: "{pluginName}", description: "Detected: {source}" },
4252
...
4353
]
4454
}]
4555
})
4656
```
4757

48-
If all detected plugins are already installed, inform the user: "All recommended plugins are already installed!"
49-
50-
If no packages match any plugin mappings, inform the user: "No matching plugins found for this project's dependencies."
51-
52-
## Step 4: Install Selected Plugins
58+
## Step 3: Install Selected Plugins
5359

5460
For each selected plugin, run the install command:
5561

@@ -59,7 +65,7 @@ claude plugin install {pluginName}@pleaseai
5965

6066
Show the result of each installation.
6167

62-
## Step 5: Summary
68+
## Step 4: Summary
6369

6470
Show a summary of what was installed:
6571

0 commit comments

Comments
 (0)