@thebushidocollective/han 1.0.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.
- package/LICENSE +21 -0
- package/README.md +209 -0
- package/dist/lib/install-progress.d.ts +10 -0
- package/dist/lib/install-progress.d.ts.map +1 -0
- package/dist/lib/install-progress.js +114 -0
- package/dist/lib/install-progress.js.map +1 -0
- package/dist/lib/install.d.ts +15 -0
- package/dist/lib/install.d.ts.map +1 -0
- package/dist/lib/install.js +191 -0
- package/dist/lib/install.js.map +1 -0
- package/dist/lib/main.d.ts +3 -0
- package/dist/lib/main.d.ts.map +1 -0
- package/dist/lib/main.js +48 -0
- package/dist/lib/main.js.map +1 -0
- package/dist/lib/markdown-text.d.ts +11 -0
- package/dist/lib/markdown-text.d.ts.map +1 -0
- package/dist/lib/markdown-text.js +87 -0
- package/dist/lib/markdown-text.js.map +1 -0
- package/dist/lib/markdown-wrapper.d.ts +7 -0
- package/dist/lib/markdown-wrapper.d.ts.map +1 -0
- package/dist/lib/markdown-wrapper.js +21 -0
- package/dist/lib/markdown-wrapper.js.map +1 -0
- package/dist/lib/uninstall.d.ts +2 -0
- package/dist/lib/uninstall.d.ts.map +1 -0
- package/dist/lib/uninstall.js +90 -0
- package/dist/lib/uninstall.js.map +1 -0
- package/dist/lib/validate.d.ts +8 -0
- package/dist/lib/validate.d.ts.map +1 -0
- package/dist/lib/validate.js +98 -0
- package/dist/lib/validate.js.map +1 -0
- package/dist/test/han.test.d.ts +2 -0
- package/dist/test/han.test.d.ts.map +1 -0
- package/dist/test/han.test.js +151 -0
- package/dist/test/han.test.js.map +1 -0
- package/package.json +64 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 The Bushido Collective
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# @thebushidocollective/han
|
|
2
|
+
|
|
3
|
+
Monorepo validation tool and Claude Code plugin installer for Han (bushido) plugins.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
### Global Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g @thebushidocollective/han
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Use with npx (No Installation)
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx -y @thebushidocollective/han validate <command>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Use in Claude Code Hooks
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"type": "command",
|
|
24
|
+
"command": "npx -y @thebushidocollective/han validate --fail-fast --dirs-with Gemfile bundle exec rspec"
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Commands
|
|
29
|
+
|
|
30
|
+
### install
|
|
31
|
+
|
|
32
|
+
Intelligently analyze your codebase and configure Claude Code with appropriate Han plugins using the Claude Agent SDK.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npx @thebushidocollective/han install
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**How it works:**
|
|
39
|
+
|
|
40
|
+
- Spawns a Claude agent to analyze your codebase
|
|
41
|
+
- Uses Glob, Grep, and Read tools to understand your project
|
|
42
|
+
- Detects languages, frameworks, and testing tools
|
|
43
|
+
- Recommends appropriate Han plugins based on actual code, not just file patterns
|
|
44
|
+
- Displays real-time progress with a beautiful Ink-powered terminal UI
|
|
45
|
+
- Configures `.claude/settings.json` automatically
|
|
46
|
+
|
|
47
|
+
**What it detects:**
|
|
48
|
+
|
|
49
|
+
- Programming languages (TypeScript, Python, Go, Rust, Ruby, etc.)
|
|
50
|
+
- Frontend frameworks (React, Vue, Angular, Next.js, etc.)
|
|
51
|
+
- Backend frameworks (NestJS, Django, FastAPI, Rails, etc.)
|
|
52
|
+
- Testing frameworks (Jest, Pytest, RSpec, etc.)
|
|
53
|
+
- GraphQL implementations
|
|
54
|
+
- Monorepo tools (Nx, Turborepo, Lerna)
|
|
55
|
+
|
|
56
|
+
**After installation:**
|
|
57
|
+
Restart Claude Code to load the new plugins.
|
|
58
|
+
|
|
59
|
+
### uninstall
|
|
60
|
+
|
|
61
|
+
Remove all Han plugins and marketplace configuration from Claude Code.
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npx @thebushidocollective/han uninstall
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### validate
|
|
68
|
+
|
|
69
|
+
Run validation commands across monorepo packages.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
han validate [options] <command>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
#### Options
|
|
76
|
+
|
|
77
|
+
- `--fail-fast` - Stop on first failure
|
|
78
|
+
- `--dirs-with <file>` - Only run in directories containing the specified file
|
|
79
|
+
|
|
80
|
+
#### Examples
|
|
81
|
+
|
|
82
|
+
Run RSpec tests in all directories with a Gemfile:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
han validate --fail-fast --dirs-with Gemfile bundle exec rspec
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Run npm test in all directories with package.json:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
han validate --dirs-with package.json npm test
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Run go test in all directories:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
han validate go test ./...
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Exit Codes
|
|
101
|
+
|
|
102
|
+
- `0` - All validations passed
|
|
103
|
+
- `1` - Invalid usage or no directories found
|
|
104
|
+
- `2` - One or more validations failed
|
|
105
|
+
|
|
106
|
+
## How It Works
|
|
107
|
+
|
|
108
|
+
1. **Auto-discovers directories** - Uses git to find tracked directories,
|
|
109
|
+
falls back to filesystem scan
|
|
110
|
+
2. **Filters by marker files** - Only runs in directories containing
|
|
111
|
+
the specified file (e.g., `Gemfile`, `package.json`)
|
|
112
|
+
3. **Runs command in each** - Executes the command in each matching
|
|
113
|
+
directory
|
|
114
|
+
4. **Reports failures** - Shows which directories failed with clear
|
|
115
|
+
error messages
|
|
116
|
+
5. **Exits with code 2** - Hard failure prevents Claude from bypassing
|
|
117
|
+
validation
|
|
118
|
+
|
|
119
|
+
## Use Cases
|
|
120
|
+
|
|
121
|
+
### Monorepo Testing
|
|
122
|
+
|
|
123
|
+
Run tests across all packages in a monorepo:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# JavaScript/TypeScript packages
|
|
127
|
+
npx -y @thebushidocollective/han validate --dirs-with package.json npm test
|
|
128
|
+
|
|
129
|
+
# Ruby packages
|
|
130
|
+
npx -y @thebushidocollective/han validate --dirs-with Gemfile bundle exec rspec
|
|
131
|
+
|
|
132
|
+
# Go modules
|
|
133
|
+
npx -y @thebushidocollective/han validate --dirs-with go.mod go test ./...
|
|
134
|
+
|
|
135
|
+
# Python packages
|
|
136
|
+
npx -y @thebushidocollective/han validate --dirs-with pyproject.toml pytest
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Claude Code Hooks
|
|
140
|
+
|
|
141
|
+
Perfect for enforcing quality in Claude Code plugins:
|
|
142
|
+
|
|
143
|
+
```json
|
|
144
|
+
{
|
|
145
|
+
"hooks": {
|
|
146
|
+
"Stop": [
|
|
147
|
+
{
|
|
148
|
+
"hooks": [
|
|
149
|
+
{
|
|
150
|
+
"type": "command",
|
|
151
|
+
"command": "npx -y @thebushidocollective/han validate --fail-fast --dirs-with package.json npm test || (echo 'Please fix failing tests before continuing:\\n'; exit 2)"
|
|
152
|
+
}
|
|
153
|
+
]
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Development
|
|
161
|
+
|
|
162
|
+
This package is written in TypeScript and uses React (via Ink) for the terminal UI.
|
|
163
|
+
|
|
164
|
+
### Prerequisites
|
|
165
|
+
|
|
166
|
+
- Node.js >= 24
|
|
167
|
+
- TypeScript 5.9+
|
|
168
|
+
|
|
169
|
+
### Building
|
|
170
|
+
|
|
171
|
+
The build process compiles TypeScript to ES modules:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
npm run build # Compile TypeScript to dist/
|
|
175
|
+
npm run typecheck # Type-check without emitting
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
The compiled output is in `dist/` and is what gets published to npm.
|
|
179
|
+
|
|
180
|
+
### Testing
|
|
181
|
+
|
|
182
|
+
Tests run against the compiled JavaScript:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
npm test # Run tests from dist/test/
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Linting
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
npm run lint # Check for issues
|
|
192
|
+
npm run lint:fix # Auto-fix issues
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### UI Development
|
|
196
|
+
|
|
197
|
+
The install command uses [Ink](https://github.com/vadimdemedes/ink) for a rich terminal UI experience. The UI components are in:
|
|
198
|
+
|
|
199
|
+
- `lib/install-progress.tsx` - Main UI component
|
|
200
|
+
- `lib/install.ts` - Integration with Claude Agent SDK
|
|
201
|
+
|
|
202
|
+
## Contributing
|
|
203
|
+
|
|
204
|
+
See [RELEASING.md](RELEASING.md) for information on publishing new
|
|
205
|
+
versions.
|
|
206
|
+
|
|
207
|
+
## License
|
|
208
|
+
|
|
209
|
+
MIT
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { DetectPluginsCallbacks } from './install.js';
|
|
3
|
+
interface InstallProgressProps {
|
|
4
|
+
detectPlugins: (callbacks: DetectPluginsCallbacks) => Promise<void>;
|
|
5
|
+
onInstallComplete: (plugins: string[]) => void;
|
|
6
|
+
onInstallError: (error: Error) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare const InstallProgress: React.FC<InstallProgressProps>;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=install-progress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-progress.d.ts","sourceRoot":"","sources":["../../lib/install-progress.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA8B,MAAM,OAAO,CAAC;AACnD,OAAO,KAAK,EAAe,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAGxE,UAAU,oBAAoB;IAC5B,aAAa,EAAE,CAAC,SAAS,EAAE,sBAAsB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,iBAAiB,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC/C,cAAc,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACxC;AAED,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA8M1D,CAAC"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { Box, Text } from 'ink';
|
|
2
|
+
import Spinner from 'ink-spinner';
|
|
3
|
+
import React, { useEffect, useState } from 'react';
|
|
4
|
+
import { MarkdownWrapper } from './markdown-wrapper.js';
|
|
5
|
+
export const InstallProgress = ({ detectPlugins, onInstallComplete, onInstallError, }) => {
|
|
6
|
+
const [phase, setPhase] = useState('analyzing');
|
|
7
|
+
const [plugins, setPlugins] = useState([]);
|
|
8
|
+
const [fullText, setFullText] = useState('');
|
|
9
|
+
const [currentTool, setCurrentTool] = useState(null);
|
|
10
|
+
const [error, setError] = useState(null);
|
|
11
|
+
const [toolsUsed, setToolsUsed] = useState(new Set());
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
const callbacks = {
|
|
14
|
+
onUpdate: (update) => {
|
|
15
|
+
if (update.type === 'text') {
|
|
16
|
+
setFullText((prev) => prev + update.content);
|
|
17
|
+
}
|
|
18
|
+
else if (update.type === 'tool' && update.toolName) {
|
|
19
|
+
setCurrentTool(update.toolName);
|
|
20
|
+
setToolsUsed((prev) => new Set([...prev, update.toolName]));
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
onComplete: (detectedPlugins, analysisText) => {
|
|
24
|
+
setPlugins(detectedPlugins);
|
|
25
|
+
setFullText(analysisText);
|
|
26
|
+
setCurrentTool(null);
|
|
27
|
+
setPhase('analyzed');
|
|
28
|
+
setTimeout(() => {
|
|
29
|
+
setPhase('installing');
|
|
30
|
+
setTimeout(() => {
|
|
31
|
+
setPhase('complete');
|
|
32
|
+
onInstallComplete(detectedPlugins);
|
|
33
|
+
}, 500);
|
|
34
|
+
}, 1000);
|
|
35
|
+
},
|
|
36
|
+
onError: (err) => {
|
|
37
|
+
setError(err.message);
|
|
38
|
+
setPhase('error');
|
|
39
|
+
onInstallError(err);
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
detectPlugins(callbacks);
|
|
43
|
+
}, [detectPlugins, onInstallComplete, onInstallError]);
|
|
44
|
+
const getToolEmoji = (toolName) => {
|
|
45
|
+
const emojiMap = {
|
|
46
|
+
web_fetch: '🌐',
|
|
47
|
+
read_file: '📄',
|
|
48
|
+
glob: '🔍',
|
|
49
|
+
grep: '🔎',
|
|
50
|
+
};
|
|
51
|
+
return emojiMap[toolName] || '🔧';
|
|
52
|
+
};
|
|
53
|
+
return (React.createElement(Box, { flexDirection: "column", paddingY: 1 },
|
|
54
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
55
|
+
React.createElement(Text, { bold: true, color: "cyan" }, "\uD83E\uDD16 Han Plugin Installer")),
|
|
56
|
+
phase === 'analyzing' && (React.createElement(Box, { flexDirection: "column" },
|
|
57
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
58
|
+
React.createElement(Text, { color: "yellow" },
|
|
59
|
+
React.createElement(Spinner, { type: "dots" }),
|
|
60
|
+
" Analyzing codebase...")),
|
|
61
|
+
currentTool && (React.createElement(Box, { marginBottom: 1 },
|
|
62
|
+
React.createElement(Text, { color: "blue" },
|
|
63
|
+
getToolEmoji(currentTool),
|
|
64
|
+
" ",
|
|
65
|
+
currentTool))),
|
|
66
|
+
toolsUsed.size > 0 && (React.createElement(Box, { marginBottom: 1 },
|
|
67
|
+
React.createElement(Text, { dimColor: true },
|
|
68
|
+
"Tools used: ",
|
|
69
|
+
Array.from(toolsUsed).join(', ')))),
|
|
70
|
+
fullText && (React.createElement(Box, { marginTop: 1, paddingX: 1, borderStyle: "round", borderColor: "gray", flexDirection: "column" },
|
|
71
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
72
|
+
React.createElement(Text, { dimColor: true, bold: true },
|
|
73
|
+
React.createElement(Spinner, { type: "star" }),
|
|
74
|
+
" Agent thinking:")),
|
|
75
|
+
React.createElement(MarkdownWrapper, null, fullText))))),
|
|
76
|
+
(phase === 'analyzed' ||
|
|
77
|
+
phase === 'installing' ||
|
|
78
|
+
phase === 'complete') && (React.createElement(Box, { flexDirection: "column" },
|
|
79
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
80
|
+
React.createElement(Text, { color: "green" }, "\u2705 Analysis complete")),
|
|
81
|
+
fullText && (React.createElement(Box, { marginBottom: 1, paddingX: 1, borderStyle: "round", borderColor: "cyan", flexDirection: "column" },
|
|
82
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
83
|
+
React.createElement(Text, { bold: true, color: "cyan" }, "\uD83D\uDCCB Agent Analysis:")),
|
|
84
|
+
React.createElement(MarkdownWrapper, null, fullText))),
|
|
85
|
+
plugins.length > 0 && (React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
|
|
86
|
+
React.createElement(Text, { bold: true, color: "green" }, "\u2728 Adding recommended plugins:"),
|
|
87
|
+
plugins.sort().map((plugin) => (React.createElement(Box, { key: plugin, marginLeft: 2 },
|
|
88
|
+
React.createElement(Text, null,
|
|
89
|
+
"\u2022 ",
|
|
90
|
+
plugin)))))),
|
|
91
|
+
phase === 'installing' && (React.createElement(Box, { marginTop: 1 },
|
|
92
|
+
React.createElement(Text, { color: "yellow" },
|
|
93
|
+
React.createElement(Spinner, { type: "dots" }),
|
|
94
|
+
" Updating Claude Code settings..."))),
|
|
95
|
+
phase === 'complete' && (React.createElement(Box, { flexDirection: "column", marginTop: 1 },
|
|
96
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
97
|
+
React.createElement(Text, { color: "green" }, "\u2705 Updated Claude Code settings")),
|
|
98
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
99
|
+
React.createElement(Text, { color: "green", bold: true }, "\u2705 Installation complete!")),
|
|
100
|
+
React.createElement(Box, null,
|
|
101
|
+
React.createElement(Text, { color: "blue" }, "\uD83D\uDCA1 Restart Claude Code to load the new plugins.")))))),
|
|
102
|
+
phase === 'error' && (React.createElement(Box, { flexDirection: "column" },
|
|
103
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
104
|
+
React.createElement(Text, { color: "red", bold: true }, "\u274C Error")),
|
|
105
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
106
|
+
React.createElement(Text, { color: "red" }, error)),
|
|
107
|
+
fullText && (React.createElement(Box, { marginBottom: 1, paddingX: 1, borderStyle: "round", borderColor: "red", flexDirection: "column" },
|
|
108
|
+
React.createElement(Text, { bold: true, color: "red" }, "Partial Analysis:"),
|
|
109
|
+
React.createElement(Box, null,
|
|
110
|
+
React.createElement(MarkdownWrapper, null, fullText)))),
|
|
111
|
+
React.createElement(Box, { marginTop: 1 },
|
|
112
|
+
React.createElement(Text, { color: "yellow" }, "\u26A0\uFE0F Falling back to installing core bushido plugin..."))))));
|
|
113
|
+
};
|
|
114
|
+
//# sourceMappingURL=install-progress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-progress.js","sourceRoot":"","sources":["../../lib/install-progress.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface AgentUpdate {
|
|
2
|
+
type: 'text' | 'tool';
|
|
3
|
+
content: string;
|
|
4
|
+
toolName?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface DetectPluginsCallbacks {
|
|
7
|
+
onUpdate: (update: AgentUpdate) => void;
|
|
8
|
+
onComplete: (plugins: string[], fullText: string) => void;
|
|
9
|
+
onError: (error: Error) => void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* SDK-based install command with Ink UI
|
|
13
|
+
*/
|
|
14
|
+
export declare function install(): Promise<void>;
|
|
15
|
+
//# sourceMappingURL=install.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../lib/install.ts"],"names":[],"mappings":"AAsBA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;IACxC,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1D,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACjC;AA4KD;;GAEG;AACH,wBAAsB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAgC7C"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { query } from '@anthropic-ai/claude-agent-sdk';
|
|
4
|
+
import { render } from 'ink';
|
|
5
|
+
import React from 'react';
|
|
6
|
+
const HAN_MARKETPLACE_REPO = 'thebushidocollective/han';
|
|
7
|
+
function getClaudeSettingsPath() {
|
|
8
|
+
const rootDir = process.cwd();
|
|
9
|
+
return join(rootDir, '.claude', 'settings.json');
|
|
10
|
+
}
|
|
11
|
+
function ensureClaudeDirectory() {
|
|
12
|
+
const rootDir = process.cwd();
|
|
13
|
+
const claudeDir = join(rootDir, '.claude');
|
|
14
|
+
if (!existsSync(claudeDir)) {
|
|
15
|
+
mkdirSync(claudeDir, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function readOrCreateSettings() {
|
|
19
|
+
const settingsPath = getClaudeSettingsPath();
|
|
20
|
+
if (existsSync(settingsPath)) {
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(readFileSync(settingsPath, 'utf8'));
|
|
23
|
+
}
|
|
24
|
+
catch (_error) {
|
|
25
|
+
console.error('Error reading settings.json, creating new one');
|
|
26
|
+
return {};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
function writeSettings(settings) {
|
|
32
|
+
const settingsPath = getClaudeSettingsPath();
|
|
33
|
+
writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}\n`);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Use Claude Agent SDK to intelligently analyze codebase and recommend plugins
|
|
37
|
+
*/
|
|
38
|
+
async function detectPluginsWithAgent(callbacks) {
|
|
39
|
+
const agentPrompt = `You are a Han plugin installer assistant. Your goal is to analyze the current codebase and recommend appropriate Claude Code plugins from the Han marketplace.
|
|
40
|
+
|
|
41
|
+
Available Plugin Categories:
|
|
42
|
+
- buki-* (武器 weapons): Skills for specific technologies (e.g., buki-typescript, buki-react, buki-go)
|
|
43
|
+
- do-* (道 disciplines): Specialized agents for development practices
|
|
44
|
+
- sensei-* (先生 teachers): MCP servers for external integrations
|
|
45
|
+
- bushido: Core quality and testing principles
|
|
46
|
+
|
|
47
|
+
Your Task:
|
|
48
|
+
1. Use Glob to discover what files exist in the repository
|
|
49
|
+
2. Use Grep to search for framework/library usage patterns
|
|
50
|
+
3. Read key configuration files (package.json, Cargo.toml, go.mod, etc.)
|
|
51
|
+
4. Get the latest han plugins from the marketplace https://raw.githubusercontent.com/TheBushidoCollective/han/refs/heads/main/.claude-plugin/marketplace.json
|
|
52
|
+
5. Recommend Han plugins that match the detected technologies
|
|
53
|
+
6. Return your recommendations as a JSON array of plugin names
|
|
54
|
+
|
|
55
|
+
Focus on detecting:
|
|
56
|
+
- Programming languages (TypeScript, Python, Go, Rust, Ruby, etc.)
|
|
57
|
+
- Frontend frameworks (React, Vue, Angular, Next.js, etc.)
|
|
58
|
+
- Backend frameworks (NestJS, Django, FastAPI, Rails, etc.)
|
|
59
|
+
- Testing frameworks (Jest, Pytest, RSpec, etc.)
|
|
60
|
+
- GraphQL implementations
|
|
61
|
+
- Monorepo tools (Nx, Turborepo, Lerna)
|
|
62
|
+
|
|
63
|
+
ALWAYS add the bushido plugin!
|
|
64
|
+
|
|
65
|
+
Return ONLY a JSON array of recommended plugin names, like:
|
|
66
|
+
["bushido", "buki-typescript", "buki-react", "buki-jest"]
|
|
67
|
+
|
|
68
|
+
ULTRATHINK and Analyze this codebase and recommend appropriate Han plugins.`;
|
|
69
|
+
// Define allowed tools - only read-only operations
|
|
70
|
+
const allowedTools = ['web_fetch', 'read_file', 'glob', 'grep'];
|
|
71
|
+
const agent = query({
|
|
72
|
+
prompt: agentPrompt,
|
|
73
|
+
options: {
|
|
74
|
+
model: 'claude-sonnet-4-5-20250929',
|
|
75
|
+
includePartialMessages: true,
|
|
76
|
+
allowedTools,
|
|
77
|
+
permissionMode: 'bypassPermissions',
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
let responseContent = '';
|
|
81
|
+
try {
|
|
82
|
+
// Collect all messages from the agent with live updates
|
|
83
|
+
for await (const sdkMessage of agent) {
|
|
84
|
+
if (sdkMessage.type === 'assistant' && sdkMessage.message.content) {
|
|
85
|
+
for (const block of sdkMessage.message.content) {
|
|
86
|
+
if (block.type === 'text') {
|
|
87
|
+
// Send text updates
|
|
88
|
+
callbacks.onUpdate({ type: 'text', content: block.text });
|
|
89
|
+
responseContent += block.text;
|
|
90
|
+
}
|
|
91
|
+
else if (block.type === 'tool_use') {
|
|
92
|
+
// Send tool usage updates
|
|
93
|
+
callbacks.onUpdate({
|
|
94
|
+
type: 'tool',
|
|
95
|
+
content: `Using ${block.name}`,
|
|
96
|
+
toolName: block.name,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Extract plugin recommendations from agent response
|
|
103
|
+
const plugins = parsePluginRecommendations(responseContent);
|
|
104
|
+
const finalPlugins = plugins.length > 0 ? plugins : ['bushido'];
|
|
105
|
+
callbacks.onComplete(finalPlugins, responseContent);
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
callbacks.onError(error);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Parse plugin recommendations from agent response
|
|
113
|
+
*/
|
|
114
|
+
function parsePluginRecommendations(content) {
|
|
115
|
+
try {
|
|
116
|
+
// Try to find JSON array in the response
|
|
117
|
+
const jsonMatch = content.match(/\[[\s\S]*?\]/);
|
|
118
|
+
if (jsonMatch) {
|
|
119
|
+
const plugins = JSON.parse(jsonMatch[0]);
|
|
120
|
+
if (Array.isArray(plugins)) {
|
|
121
|
+
return plugins.filter((p) => typeof p === 'string');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Fallback: look for plugin names mentioned
|
|
125
|
+
const pluginPattern = /(buki-[\w-]+|do-[\w-]+|sensei-[\w-]+|bushido)/g;
|
|
126
|
+
const matches = content.match(pluginPattern);
|
|
127
|
+
if (matches) {
|
|
128
|
+
return [...new Set(matches)];
|
|
129
|
+
}
|
|
130
|
+
return [];
|
|
131
|
+
}
|
|
132
|
+
catch (_error) {
|
|
133
|
+
return [];
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Install plugins to Claude settings
|
|
138
|
+
*/
|
|
139
|
+
function installPluginsToSettings(plugins) {
|
|
140
|
+
ensureClaudeDirectory();
|
|
141
|
+
const settings = readOrCreateSettings();
|
|
142
|
+
// Add Han marketplace to extraMarketplaces
|
|
143
|
+
if (!settings?.extraKnownMarketplaces?.han) {
|
|
144
|
+
settings.extraKnownMarketplaces = {
|
|
145
|
+
...settings.extraKnownMarketplaces,
|
|
146
|
+
han: { source: { source: 'github', repo: HAN_MARKETPLACE_REPO } },
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
// Add plugins
|
|
150
|
+
for (const plugin of plugins) {
|
|
151
|
+
settings.enabledPlugins = {
|
|
152
|
+
...settings.enabledPlugins,
|
|
153
|
+
[`${plugin}@han`]: true,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
writeSettings(settings);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* SDK-based install command with Ink UI
|
|
160
|
+
*/
|
|
161
|
+
export async function install() {
|
|
162
|
+
// Import Ink UI component dynamically to avoid issues with React
|
|
163
|
+
const { InstallProgress } = await import('./install-progress.js');
|
|
164
|
+
let resolveCompletion;
|
|
165
|
+
let rejectCompletion;
|
|
166
|
+
const completionPromise = new Promise((resolve, reject) => {
|
|
167
|
+
resolveCompletion = resolve;
|
|
168
|
+
rejectCompletion = reject;
|
|
169
|
+
});
|
|
170
|
+
const { unmount } = render(React.createElement(InstallProgress, {
|
|
171
|
+
detectPlugins: detectPluginsWithAgent,
|
|
172
|
+
onInstallComplete: (plugins) => {
|
|
173
|
+
installPluginsToSettings(plugins);
|
|
174
|
+
if (resolveCompletion)
|
|
175
|
+
resolveCompletion();
|
|
176
|
+
},
|
|
177
|
+
onInstallError: (error) => {
|
|
178
|
+
if (rejectCompletion)
|
|
179
|
+
rejectCompletion(error);
|
|
180
|
+
},
|
|
181
|
+
}));
|
|
182
|
+
try {
|
|
183
|
+
await completionPromise;
|
|
184
|
+
// Wait a moment for the UI to show completion message
|
|
185
|
+
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
186
|
+
}
|
|
187
|
+
finally {
|
|
188
|
+
unmount();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../lib/install.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../lib/main.ts"],"names":[],"mappings":""}
|
package/dist/lib/main.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
const program = new Command();
|
|
4
|
+
program
|
|
5
|
+
.name('han')
|
|
6
|
+
.description("Utilities for The Bushido Collective's Han Code Marketplace")
|
|
7
|
+
.version('1.0.0');
|
|
8
|
+
// Install command
|
|
9
|
+
program
|
|
10
|
+
.command('install')
|
|
11
|
+
.description('Install Han marketplace and plugins')
|
|
12
|
+
.action(async () => {
|
|
13
|
+
try {
|
|
14
|
+
const { install } = await import('./install.js');
|
|
15
|
+
await install();
|
|
16
|
+
process.exit(0);
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
console.error('Error during installation:', error instanceof Error ? error.message : error);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
// Uninstall command
|
|
24
|
+
program
|
|
25
|
+
.command('uninstall')
|
|
26
|
+
.description('Remove Han marketplace and plugins')
|
|
27
|
+
.action(async () => {
|
|
28
|
+
const { uninstall } = await import('./uninstall.js');
|
|
29
|
+
uninstall();
|
|
30
|
+
process.exit(0);
|
|
31
|
+
});
|
|
32
|
+
// Validate command
|
|
33
|
+
program
|
|
34
|
+
.command('validate')
|
|
35
|
+
.description('Validate directories')
|
|
36
|
+
.option('--fail-fast', 'Stop on first failure')
|
|
37
|
+
.option('--dirs-with <file>', 'Only run in directories containing the specified file')
|
|
38
|
+
.argument('<command...>', 'Command to run in each directory')
|
|
39
|
+
.action(async (commandArgs, options) => {
|
|
40
|
+
const { validate } = await import('./validate.js');
|
|
41
|
+
validate({
|
|
42
|
+
failFast: options.failFast || false,
|
|
43
|
+
dirsWith: options.dirsWith || null,
|
|
44
|
+
command: commandArgs.join(' '),
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
program.parse();
|
|
48
|
+
//# sourceMappingURL=main.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../lib/main.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,KAAK,CAAC;KACX,WAAW,CAAC,6DAA6D,CAAC;KAC1E,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,kBAAkB;AAClB,OAAO;KACJ,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CAAC,qCAAqC,CAAC;KAClD,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,IAAI,CAAC;QACH,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;QACjD,MAAM,OAAO,EAAE,CAAC;QAChB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,OAAO,CAAC,KAAK,CACX,4BAA4B,EAC5B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAC/C,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,oBAAoB;AACpB,OAAO;KACJ,OAAO,CAAC,WAAW,CAAC;KACpB,WAAW,CAAC,oCAAoC,CAAC;KACjD,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC;IACrD,SAAS,EAAE,CAAC;IACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEL,mBAAmB;AACnB,OAAO;KACJ,OAAO,CAAC,UAAU,CAAC;KACnB,WAAW,CAAC,sBAAsB,CAAC;KACnC,MAAM,CAAC,aAAa,EAAE,uBAAuB,CAAC;KAC9C,MAAM,CACL,oBAAoB,EACpB,uDAAuD,CACxD;KACA,QAAQ,CAAC,cAAc,EAAE,kCAAkC,CAAC;KAC5D,MAAM,CACL,KAAK,EACH,WAAqB,EACrB,OAAkD,EAClD,EAAE;IACF,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;IACnD,QAAQ,CAAC;QACP,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,KAAK;QACnC,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,IAAI;QAClC,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC;KAC/B,CAAC,CAAC;AACL,CAAC,CACF,CAAC;AAEJ,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface MarkdownTextProps {
|
|
3
|
+
children: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Simple markdown-like formatter for terminal output
|
|
7
|
+
* Handles basic formatting without requiring heavy dependencies
|
|
8
|
+
*/
|
|
9
|
+
export declare const MarkdownText: React.FC<MarkdownTextProps>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=markdown-text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-text.d.ts","sourceRoot":"","sources":["../../lib/markdown-text.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,UAAU,iBAAiB;IACzB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAgHpD,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { Box, Text } from 'ink';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* Simple markdown-like formatter for terminal output
|
|
5
|
+
* Handles basic formatting without requiring heavy dependencies
|
|
6
|
+
*/
|
|
7
|
+
export const MarkdownText = ({ children }) => {
|
|
8
|
+
const lines = children.split('\n');
|
|
9
|
+
const elements = [];
|
|
10
|
+
for (let i = 0; i < lines.length; i++) {
|
|
11
|
+
const line = lines[i];
|
|
12
|
+
// Headers (# ## ###)
|
|
13
|
+
const headerMatch = line.match(/^(#{1,3})\s+(.+)$/);
|
|
14
|
+
if (headerMatch) {
|
|
15
|
+
const level = headerMatch[1].length;
|
|
16
|
+
const text = headerMatch[2];
|
|
17
|
+
elements.push(React.createElement(Box, { key: i, marginTop: level === 1 ? 1 : 0, marginBottom: 1 },
|
|
18
|
+
React.createElement(Text, { bold: true, color: level === 1 ? 'cyan' : level === 2 ? 'blue' : 'white' }, text)));
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
// Bullet lists (- or *)
|
|
22
|
+
const bulletMatch = line.match(/^[\s]*[-*]\s+(.+)$/);
|
|
23
|
+
if (bulletMatch) {
|
|
24
|
+
const text = bulletMatch[1];
|
|
25
|
+
const indent = line.match(/^(\s*)/)?.[1].length || 0;
|
|
26
|
+
elements.push(React.createElement(Box, { key: i, marginLeft: Math.floor(indent / 2) },
|
|
27
|
+
React.createElement(Text, null,
|
|
28
|
+
"\u2022 ",
|
|
29
|
+
text)));
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
// Numbered lists (1. 2. etc)
|
|
33
|
+
const numberedMatch = line.match(/^[\s]*(\d+)\.\s+(.+)$/);
|
|
34
|
+
if (numberedMatch) {
|
|
35
|
+
const num = numberedMatch[1];
|
|
36
|
+
const text = numberedMatch[2];
|
|
37
|
+
const indent = line.match(/^(\s*)/)?.[1].length || 0;
|
|
38
|
+
elements.push(React.createElement(Box, { key: i, marginLeft: Math.floor(indent / 2) },
|
|
39
|
+
React.createElement(Text, null,
|
|
40
|
+
num,
|
|
41
|
+
". ",
|
|
42
|
+
text)));
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
// Code blocks (```)
|
|
46
|
+
if (line.trim() === '```' || line.trim().startsWith('```')) {
|
|
47
|
+
// Skip code fence markers
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
// Inline code (`code`)
|
|
51
|
+
const codeMatch = line.match(/`([^`]+)`/g);
|
|
52
|
+
if (codeMatch) {
|
|
53
|
+
const parts = line.split(/(`[^`]+`)/);
|
|
54
|
+
elements.push(React.createElement(Box, { key: i },
|
|
55
|
+
React.createElement(Text, null, parts.map((part, idx) => {
|
|
56
|
+
if (part.startsWith('`') && part.endsWith('`')) {
|
|
57
|
+
return (React.createElement(Text, { key: idx, backgroundColor: "gray", color: "white" }, part.slice(1, -1)));
|
|
58
|
+
}
|
|
59
|
+
return part;
|
|
60
|
+
}))));
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
// Bold (**text**)
|
|
64
|
+
const boldMatch = line.match(/\*\*([^*]+)\*\*/g);
|
|
65
|
+
if (boldMatch) {
|
|
66
|
+
const parts = line.split(/(\*\*[^*]+\*\*)/);
|
|
67
|
+
elements.push(React.createElement(Box, { key: i },
|
|
68
|
+
React.createElement(Text, null, parts.map((part, idx) => {
|
|
69
|
+
if (part.startsWith('**') && part.endsWith('**')) {
|
|
70
|
+
return React.createElement(Text, { key: idx, bold: true }, part.slice(2, -2));
|
|
71
|
+
}
|
|
72
|
+
return part;
|
|
73
|
+
}))));
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
// Empty lines
|
|
77
|
+
if (line.trim() === '') {
|
|
78
|
+
elements.push(React.createElement(Box, { key: i, height: 1 }));
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
// Regular text
|
|
82
|
+
elements.push(React.createElement(Box, { key: i },
|
|
83
|
+
React.createElement(Text, { wrap: "wrap" }, line)));
|
|
84
|
+
}
|
|
85
|
+
return React.createElement(Box, { flexDirection: "column" }, elements);
|
|
86
|
+
};
|
|
87
|
+
//# sourceMappingURL=markdown-text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-text.js","sourceRoot":"","sources":["../../lib/markdown-text.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAgC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;IACxE,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,QAAQ,GAAsB,EAAE,CAAC;IAEvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAEtB,qBAAqB;QACrB,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACpD,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,KAAK,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YACpC,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;YAC5B,QAAQ,CAAC,IAAI,CACX,oBAAC,GAAG,IAAC,GAAG,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC;gBAC1D,oBAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,IACpE,IAAI,CACA,CACH,CACP,CAAC;YACF,SAAS;QACX,CAAC;QAED,wBAAwB;QACxB,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACrD,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;YAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC;YACrD,QAAQ,CAAC,IAAI,CACX,oBAAC,GAAG,IAAC,GAAG,EAAE,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;gBAC7C,oBAAC,IAAI;;oBAAI,IAAI,CAAQ,CACjB,CACP,CAAC;YACF,SAAS;QACX,CAAC;QAED,6BAA6B;QAC7B,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;QAC1D,IAAI,aAAa,EAAE,CAAC;YAClB,MAAM,GAAG,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;YAC7B,MAAM,IAAI,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;YAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC;YACrD,QAAQ,CAAC,IAAI,CACX,oBAAC,GAAG,IAAC,GAAG,EAAE,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;gBAC7C,oBAAC,IAAI;oBAAE,GAAG;;oBAAI,IAAI,CAAQ,CACtB,CACP,CAAC;YACF,SAAS;QACX,CAAC;QAED,oBAAoB;QACpB,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3D,0BAA0B;YAC1B,SAAS;QACX,CAAC;QAED,uBAAuB;QACvB,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAC3C,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;YACtC,QAAQ,CAAC,IAAI,CACX,oBAAC,GAAG,IAAC,GAAG,EAAE,CAAC;gBACT,oBAAC,IAAI,QACF,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;oBACvB,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;wBAC/C,OAAO,CACL,oBAAC,IAAI,IAAC,GAAG,EAAE,GAAG,EAAE,eAAe,EAAC,MAAM,EAAC,KAAK,EAAC,OAAO,IACjD,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CACb,CACR,CAAC;oBACJ,CAAC;oBACD,OAAO,IAAI,CAAC;gBACd,CAAC,CAAC,CACG,CACH,CACP,CAAC;YACF,SAAS;QACX,CAAC;QAED,kBAAkB;QAClB,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACjD,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;YAC5C,QAAQ,CAAC,IAAI,CACX,oBAAC,GAAG,IAAC,GAAG,EAAE,CAAC;gBACT,oBAAC,IAAI,QACF,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;oBACvB,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;wBACjD,OAAO,oBAAC,IAAI,IAAC,GAAG,EAAE,GAAG,EAAE,IAAI,UAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAQ,CAAC;oBACzD,CAAC;oBACD,OAAO,IAAI,CAAC;gBACd,CAAC,CAAC,CACG,CACH,CACP,CAAC;YACF,SAAS;QACX,CAAC;QAED,cAAc;QACd,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACvB,QAAQ,CAAC,IAAI,CAAC,oBAAC,GAAG,IAAC,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,GAAI,CAAC,CAAC;YAC1C,SAAS;QACX,CAAC;QAED,eAAe;QACf,QAAQ,CAAC,IAAI,CACX,oBAAC,GAAG,IAAC,GAAG,EAAE,CAAC;YACT,oBAAC,IAAI,IAAC,IAAI,EAAC,MAAM,IAAE,IAAI,CAAQ,CAC3B,CACP,CAAC;IACJ,CAAC;IAED,OAAO,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,IAAE,QAAQ,CAAO,CAAC;AACtD,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-wrapper.d.ts","sourceRoot":"","sources":["../../lib/markdown-wrapper.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,UAAU,oBAAoB;IAC5B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAQD,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAW1D,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Text } from 'ink';
|
|
2
|
+
import { marked } from 'marked';
|
|
3
|
+
import TerminalRenderer from 'marked-terminal';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
// Configure marked globally with terminal renderer
|
|
6
|
+
marked.setOptions({
|
|
7
|
+
// @ts-expect-error - marked-terminal types are not perfectly aligned
|
|
8
|
+
renderer: new TerminalRenderer(),
|
|
9
|
+
});
|
|
10
|
+
export const MarkdownWrapper = ({ children, }) => {
|
|
11
|
+
try {
|
|
12
|
+
const parsed = marked.parse(children);
|
|
13
|
+
const output = typeof parsed === 'string' ? parsed.trim() : '';
|
|
14
|
+
return React.createElement(Text, null, output);
|
|
15
|
+
}
|
|
16
|
+
catch (_error) {
|
|
17
|
+
// Fallback to plain text if markdown parsing fails
|
|
18
|
+
return React.createElement(Text, { wrap: "wrap" }, children);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=markdown-wrapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-wrapper.js","sourceRoot":"","sources":["../../lib/markdown-wrapper.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAC3B,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,gBAAgB,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B,mDAAmD;AACnD,MAAM,CAAC,UAAU,CAAC;IAChB,qEAAqE;IACrE,QAAQ,EAAE,IAAI,gBAAgB,EAAE;CACjC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,eAAe,GAAmC,CAAC,EAC9D,QAAQ,GACT,EAAE,EAAE;IACH,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/D,OAAO,oBAAC,IAAI,QAAE,MAAM,CAAQ,CAAC;IAC/B,CAAC;IAAC,OAAO,MAAM,EAAE,CAAC;QAChB,mDAAmD;QACnD,OAAO,oBAAC,IAAI,IAAC,IAAI,EAAC,MAAM,IAAE,QAAQ,CAAQ,CAAC;IAC7C,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uninstall.d.ts","sourceRoot":"","sources":["../../lib/uninstall.ts"],"names":[],"mappings":"AAqCA,wBAAgB,SAAS,IAAI,IAAI,CA+EhC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
const HAN_MARKETPLACE_URL = 'https://github.com/thebushidocollective/sensei';
|
|
4
|
+
function getClaudeSettingsPath() {
|
|
5
|
+
const rootDir = process.cwd();
|
|
6
|
+
return join(rootDir, '.claude', 'settings.json');
|
|
7
|
+
}
|
|
8
|
+
function readSettings() {
|
|
9
|
+
const settingsPath = getClaudeSettingsPath();
|
|
10
|
+
if (!existsSync(settingsPath)) {
|
|
11
|
+
console.log('No .claude/settings.json found. Nothing to uninstall.');
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
return JSON.parse(readFileSync(settingsPath, 'utf8'));
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
console.error('Error reading settings.json:', error.message);
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function writeSettings(settings) {
|
|
23
|
+
const settingsPath = getClaudeSettingsPath();
|
|
24
|
+
writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}\n`);
|
|
25
|
+
}
|
|
26
|
+
export function uninstall() {
|
|
27
|
+
console.log('🗑️ Removing Han marketplace and plugins from Claude Code settings...\n');
|
|
28
|
+
const settings = readSettings();
|
|
29
|
+
if (!settings) {
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
let changes = false;
|
|
33
|
+
// Remove Han marketplace from extraMarketplaces
|
|
34
|
+
if (settings.extraMarketplaces) {
|
|
35
|
+
const before = settings.extraMarketplaces.length;
|
|
36
|
+
settings.extraMarketplaces = settings.extraMarketplaces.filter((url) => url !== HAN_MARKETPLACE_URL);
|
|
37
|
+
const after = settings.extraMarketplaces.length;
|
|
38
|
+
if (before > after) {
|
|
39
|
+
console.log(`✓ Removed Han marketplace: ${HAN_MARKETPLACE_URL}`);
|
|
40
|
+
changes = true;
|
|
41
|
+
}
|
|
42
|
+
if (settings.extraMarketplaces.length === 0) {
|
|
43
|
+
delete settings.extraMarketplaces;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Remove all Han plugins (those starting with buki-, do-, sensei-, or named bushido)
|
|
47
|
+
if (settings.plugins) {
|
|
48
|
+
const before = settings.plugins.length;
|
|
49
|
+
settings.plugins = settings.plugins.filter((plugin) => !plugin.startsWith('buki-') &&
|
|
50
|
+
!plugin.startsWith('do-') &&
|
|
51
|
+
!plugin.startsWith('sensei-') &&
|
|
52
|
+
plugin !== 'bushido');
|
|
53
|
+
const after = settings.plugins.length;
|
|
54
|
+
const removed = before - after;
|
|
55
|
+
if (removed > 0) {
|
|
56
|
+
console.log(`✓ Removed ${removed} Han plugin(s)`);
|
|
57
|
+
changes = true;
|
|
58
|
+
}
|
|
59
|
+
if (settings.plugins.length === 0) {
|
|
60
|
+
delete settings.plugins;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (!changes) {
|
|
64
|
+
console.log('No Han marketplace or plugins found in settings.');
|
|
65
|
+
process.exit(0);
|
|
66
|
+
}
|
|
67
|
+
writeSettings(settings);
|
|
68
|
+
console.log('\n✅ Uninstallation complete!');
|
|
69
|
+
console.log('\nRemaining configuration in .claude/settings.json:');
|
|
70
|
+
if (settings.plugins && settings.plugins.length > 0) {
|
|
71
|
+
console.log(` Plugins: ${settings.plugins.length}`);
|
|
72
|
+
for (const plugin of settings.plugins) {
|
|
73
|
+
console.log(` - ${plugin}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
console.log(' No plugins configured');
|
|
78
|
+
}
|
|
79
|
+
if (settings.extraMarketplaces && settings.extraMarketplaces.length > 0) {
|
|
80
|
+
console.log(` Marketplaces: ${settings.extraMarketplaces.length}`);
|
|
81
|
+
for (const marketplace of settings.extraMarketplaces) {
|
|
82
|
+
console.log(` - ${marketplace}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
console.log(' No extra marketplaces configured');
|
|
87
|
+
}
|
|
88
|
+
console.log('\nRestart Claude Code to apply changes.');
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=uninstall.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uninstall.js","sourceRoot":"","sources":["../../lib/uninstall.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../lib/validate.ts"],"names":[],"mappings":"AAIA,UAAU,eAAe;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB;AAiED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,CAmDvD"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
// Find directories
|
|
5
|
+
function findDirectories(rootDir) {
|
|
6
|
+
const dirs = [];
|
|
7
|
+
// Try to use git to find tracked directories
|
|
8
|
+
try {
|
|
9
|
+
const gitDirs = execSync('git ls-files', {
|
|
10
|
+
cwd: rootDir,
|
|
11
|
+
encoding: 'utf8',
|
|
12
|
+
})
|
|
13
|
+
.split('\n')
|
|
14
|
+
.map((file) => {
|
|
15
|
+
const parts = file.split('/');
|
|
16
|
+
return parts.length > 1 ? parts[0] : null;
|
|
17
|
+
})
|
|
18
|
+
.filter((dir) => dir !== null);
|
|
19
|
+
const uniqueDirs = [...new Set(gitDirs)];
|
|
20
|
+
uniqueDirs.forEach((dir) => {
|
|
21
|
+
const fullPath = join(rootDir, dir);
|
|
22
|
+
if (existsSync(fullPath) && statSync(fullPath).isDirectory()) {
|
|
23
|
+
dirs.push(fullPath);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
catch (_e) {
|
|
28
|
+
// Git not available or not in git repo, use glob
|
|
29
|
+
const entries = readdirSync(rootDir, { withFileTypes: true });
|
|
30
|
+
entries.forEach((entry) => {
|
|
31
|
+
if (entry.isDirectory() && !entry.name.startsWith('.')) {
|
|
32
|
+
dirs.push(join(rootDir, entry.name));
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return dirs;
|
|
37
|
+
}
|
|
38
|
+
// Filter directories by marker file
|
|
39
|
+
function filterDirectories(dirs, markerFile) {
|
|
40
|
+
if (!markerFile)
|
|
41
|
+
return dirs;
|
|
42
|
+
return dirs.filter((dir) => {
|
|
43
|
+
return existsSync(join(dir, markerFile));
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
// Run command in directory
|
|
47
|
+
function runCommand(dir, cmd) {
|
|
48
|
+
try {
|
|
49
|
+
execSync(cmd, {
|
|
50
|
+
cwd: dir,
|
|
51
|
+
stdio: 'inherit',
|
|
52
|
+
encoding: 'utf8',
|
|
53
|
+
});
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
catch (_e) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export function validate(options) {
|
|
61
|
+
const { failFast, dirsWith, command: commandToRun } = options;
|
|
62
|
+
// Main execution
|
|
63
|
+
const rootDir = process.cwd();
|
|
64
|
+
const allDirs = findDirectories(rootDir);
|
|
65
|
+
const targetDirs = filterDirectories(allDirs, dirsWith);
|
|
66
|
+
if (targetDirs.length === 0) {
|
|
67
|
+
if (dirsWith) {
|
|
68
|
+
console.log(`No directories found with ${dirsWith}`);
|
|
69
|
+
process.exit(0);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
console.error('No directories found');
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const failures = [];
|
|
77
|
+
for (const dir of targetDirs) {
|
|
78
|
+
const success = runCommand(dir, commandToRun);
|
|
79
|
+
if (!success) {
|
|
80
|
+
const relativePath = dir.replace(`${rootDir}/`, '');
|
|
81
|
+
failures.push(relativePath);
|
|
82
|
+
console.error(`\nFailed when trying to run \`${commandToRun}\` in directory: \`${relativePath}\`\n`);
|
|
83
|
+
if (failFast) {
|
|
84
|
+
process.exit(2);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (failures.length > 0) {
|
|
89
|
+
console.error(`\n❌ ${failures.length} director${failures.length === 1 ? 'y' : 'ies'} failed validation:\n`);
|
|
90
|
+
for (const dir of failures) {
|
|
91
|
+
console.error(` - ${dir}`);
|
|
92
|
+
}
|
|
93
|
+
process.exit(2);
|
|
94
|
+
}
|
|
95
|
+
console.log(`\n✅ All ${targetDirs.length} director${targetDirs.length === 1 ? 'y' : 'ies'} passed validation`);
|
|
96
|
+
process.exit(0);
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../lib/validate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"han.test.d.ts","sourceRoot":"","sources":["../../test/han.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { strictEqual } from 'node:assert';
|
|
2
|
+
import { execSync, } from 'node:child_process';
|
|
3
|
+
import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
// Get __dirname equivalent in ES modules
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = dirname(__filename);
|
|
9
|
+
// Test runs from dist/test, so go up to dist, then to lib/main.js
|
|
10
|
+
const binPath = join(__dirname, '..', 'lib', 'main.js');
|
|
11
|
+
function setup() {
|
|
12
|
+
const testDir = join(__dirname, 'fixtures');
|
|
13
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
14
|
+
mkdirSync(testDir, { recursive: true });
|
|
15
|
+
return testDir;
|
|
16
|
+
}
|
|
17
|
+
function teardown() {
|
|
18
|
+
const testDir = join(__dirname, 'fixtures');
|
|
19
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
20
|
+
}
|
|
21
|
+
function test(name, fn) {
|
|
22
|
+
try {
|
|
23
|
+
fn();
|
|
24
|
+
console.log(`✓ ${name}`);
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
console.error(`✗ ${name}`);
|
|
28
|
+
console.error(error.message);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Test: shows help when no command provided
|
|
33
|
+
test('shows help when no command provided', () => {
|
|
34
|
+
try {
|
|
35
|
+
execSync(`node ${binPath} --help`, { encoding: 'utf8' });
|
|
36
|
+
// Help command should exit with 0
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
const execError = error;
|
|
40
|
+
const stdout = execError.message || '';
|
|
41
|
+
strictEqual(stdout.includes('Usage:') || stdout.includes('han'), true);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
// Test: shows error when validate has no command argument
|
|
45
|
+
test('shows error when validate has no command argument', () => {
|
|
46
|
+
try {
|
|
47
|
+
execSync(`node ${binPath} validate`, { encoding: 'utf8' });
|
|
48
|
+
throw new Error('Should have failed');
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
const execError = error;
|
|
52
|
+
strictEqual(execError.status, 1);
|
|
53
|
+
const stderr = execError.stderr?.toString() || '';
|
|
54
|
+
strictEqual(stderr.includes('missing required argument') ||
|
|
55
|
+
stderr.includes('error') ||
|
|
56
|
+
stderr.length > 0, true);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
// Test: passes when no directories match filter
|
|
60
|
+
test('passes when no directories match filter', () => {
|
|
61
|
+
const testDir = setup();
|
|
62
|
+
try {
|
|
63
|
+
const output = execSync(`node ${binPath} validate --dirs-with nonexistent.txt echo test`, { cwd: testDir, encoding: 'utf8' });
|
|
64
|
+
strictEqual(output.includes('No directories found with nonexistent.txt'), true);
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
teardown();
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
// Test: runs command in matching directories
|
|
71
|
+
test('runs command in matching directories', () => {
|
|
72
|
+
const testDir = setup();
|
|
73
|
+
try {
|
|
74
|
+
// Create test structure
|
|
75
|
+
mkdirSync(join(testDir, 'pkg1'));
|
|
76
|
+
mkdirSync(join(testDir, 'pkg2'));
|
|
77
|
+
writeFileSync(join(testDir, 'pkg1', 'package.json'), '{}');
|
|
78
|
+
writeFileSync(join(testDir, 'pkg2', 'package.json'), '{}');
|
|
79
|
+
// Initialize git repo so directories are discovered
|
|
80
|
+
execSync('git init', { cwd: testDir });
|
|
81
|
+
execSync('git add .', { cwd: testDir });
|
|
82
|
+
const output = execSync(`node ${binPath} validate --dirs-with package.json echo success`, {
|
|
83
|
+
cwd: testDir,
|
|
84
|
+
encoding: 'utf8',
|
|
85
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
86
|
+
});
|
|
87
|
+
strictEqual(output.includes('success'), true);
|
|
88
|
+
strictEqual(output.includes('passed validation'), true);
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
teardown();
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
// Test: fails with exit code 2 when command fails
|
|
95
|
+
test('fails with exit code 2 when command fails', () => {
|
|
96
|
+
const testDir = setup();
|
|
97
|
+
try {
|
|
98
|
+
mkdirSync(join(testDir, 'pkg1'));
|
|
99
|
+
writeFileSync(join(testDir, 'pkg1', 'package.json'), '{}');
|
|
100
|
+
// Initialize git repo
|
|
101
|
+
execSync('git init', { cwd: testDir });
|
|
102
|
+
execSync('git add .', { cwd: testDir });
|
|
103
|
+
try {
|
|
104
|
+
execSync(`node ${binPath} validate --dirs-with package.json exit 1`, {
|
|
105
|
+
cwd: testDir,
|
|
106
|
+
encoding: 'utf8',
|
|
107
|
+
stdio: 'pipe',
|
|
108
|
+
});
|
|
109
|
+
throw new Error('Should have failed');
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
const execError = error;
|
|
113
|
+
const exitCode = execError.status || execError.code;
|
|
114
|
+
strictEqual(exitCode, 2, `Expected exit code 2, got ${exitCode}`);
|
|
115
|
+
const stderr = execError.stderr?.toString() || '';
|
|
116
|
+
strictEqual(stderr.includes('failed validation') || stderr.includes('Failed when'), true);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
teardown();
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
// Test: stops on first failure with --fail-fast
|
|
124
|
+
test('stops on first failure with --fail-fast', () => {
|
|
125
|
+
const testDir = setup();
|
|
126
|
+
try {
|
|
127
|
+
mkdirSync(join(testDir, 'pkg1'));
|
|
128
|
+
mkdirSync(join(testDir, 'pkg2'));
|
|
129
|
+
writeFileSync(join(testDir, 'pkg1', 'package.json'), '{}');
|
|
130
|
+
writeFileSync(join(testDir, 'pkg2', 'package.json'), '{}');
|
|
131
|
+
// Initialize git repo
|
|
132
|
+
execSync('git init', { cwd: testDir });
|
|
133
|
+
execSync('git add .', { cwd: testDir });
|
|
134
|
+
try {
|
|
135
|
+
execSync(`node ${binPath} validate --fail-fast --dirs-with package.json exit 1`, { cwd: testDir, encoding: 'utf8', stdio: 'pipe' });
|
|
136
|
+
throw new Error('Should have failed');
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
const execError = error;
|
|
140
|
+
const exitCode = execError.status || execError.code;
|
|
141
|
+
strictEqual(exitCode, 2, `Expected exit code 2, got ${exitCode}`);
|
|
142
|
+
const stderr = execError.stderr?.toString() || '';
|
|
143
|
+
strictEqual(stderr.includes('Failed when trying to run'), true);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
finally {
|
|
147
|
+
teardown();
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
console.log('\nAll tests passed! ✓');
|
|
151
|
+
//# sourceMappingURL=han.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"han.test.js","sourceRoot":"","sources":["../../test/han.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@thebushidocollective/han",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Monorepo validation tool for Claude Code hooks",
|
|
5
|
+
"main": "dist/lib/main.js",
|
|
6
|
+
"types": "dist/lib/main.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"bin": {
|
|
9
|
+
"han": "./dist/lib/main.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"postbuild": "chmod +x dist/lib/main.js",
|
|
14
|
+
"typecheck": "tsc --noEmit",
|
|
15
|
+
"test": "node dist/test/han.test.js",
|
|
16
|
+
"lint": "biome check .",
|
|
17
|
+
"lint:fix": "biome check --write .",
|
|
18
|
+
"prepack": "npm run build && npm run lint && npm test"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "https://github.com/thebushidocollective/han.git"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/thebushidocollective/han",
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/thebushidocollective/han/issues"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"bushido",
|
|
30
|
+
"monorepo",
|
|
31
|
+
"validation",
|
|
32
|
+
"hooks",
|
|
33
|
+
"claude",
|
|
34
|
+
"claude-code",
|
|
35
|
+
"testing",
|
|
36
|
+
"ci"
|
|
37
|
+
],
|
|
38
|
+
"author": "The Bushido Collective",
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=24"
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"dist/",
|
|
45
|
+
"README.md"
|
|
46
|
+
],
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@biomejs/biome": "^2.3.6",
|
|
49
|
+
"@types/commander": "^2.12.0",
|
|
50
|
+
"@types/marked-terminal": "^6.1.1",
|
|
51
|
+
"@types/node": "^20.19.25",
|
|
52
|
+
"@types/react": "^19.2.6",
|
|
53
|
+
"typescript": "^5.9.3"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"@anthropic-ai/claude-agent-sdk": "^0.1.47",
|
|
57
|
+
"commander": "^14.0.2",
|
|
58
|
+
"ink": "^6.5.1",
|
|
59
|
+
"ink-spinner": "^5.0.0",
|
|
60
|
+
"marked": "^15.0.12",
|
|
61
|
+
"marked-terminal": "^7.3.0",
|
|
62
|
+
"react": "^19.2.0"
|
|
63
|
+
}
|
|
64
|
+
}
|