@thebushidocollective/han 1.2.0 → 1.3.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/README.md CHANGED
@@ -32,9 +32,15 @@ npx -y @thebushidocollective/han validate <command>
32
32
  Intelligently analyze your codebase and configure Claude Code with appropriate Han plugins using the Claude Agent SDK.
33
33
 
34
34
  ```bash
35
- npx @thebushidocollective/han install
35
+ npx @thebushidocollective/han install [--scope <project|local>]
36
36
  ```
37
37
 
38
+ **Options:**
39
+
40
+ - `--scope <project|local>` - Installation scope (default: `project`)
41
+ - `project`: Install to `.claude/settings.json` (shared via git)
42
+ - `local`: Install to `.claude/settings.local.json` (git-ignored, machine-specific)
43
+
38
44
  **How it works:**
39
45
 
40
46
  - Spawns a Claude agent to analyze your codebase
@@ -42,7 +48,7 @@ npx @thebushidocollective/han install
42
48
  - Detects languages, frameworks, and testing tools
43
49
  - Recommends appropriate Han plugins based on actual code, not just file patterns
44
50
  - Displays real-time progress with a beautiful Ink-powered terminal UI
45
- - Configures `.claude/settings.json` automatically
51
+ - Configures Claude Code settings automatically
46
52
 
47
53
  **What it detects:**
48
54
 
@@ -56,6 +62,59 @@ npx @thebushidocollective/han install
56
62
  **After installation:**
57
63
  Restart Claude Code to load the new plugins.
58
64
 
65
+ **Examples:**
66
+
67
+ ```bash
68
+ # Install to project settings (default, shared via git)
69
+ npx @thebushidocollective/han install
70
+
71
+ # Install to local settings (machine-specific, not shared)
72
+ npx @thebushidocollective/han install --scope local
73
+ ```
74
+
75
+ ### align
76
+
77
+ Continuously align your Han plugins with your evolving codebase. Automatically adds plugins for new technologies and removes plugins for technologies no longer in use.
78
+
79
+ ```bash
80
+ npx @thebushidocollective/han align [--scope <project|local>]
81
+ ```
82
+
83
+ **Options:**
84
+
85
+ - `--scope <project|local>` - Alignment scope (default: `project`)
86
+ - `project`: Align plugins in `.claude/settings.json` (shared via git)
87
+ - `local`: Align plugins in `.claude/settings.local.json` (git-ignored, machine-specific)
88
+
89
+ **How it works:**
90
+
91
+ - Re-analyzes your codebase to detect current technologies
92
+ - Compares detected plugins with currently installed plugins
93
+ - **Adds** plugins for newly detected technologies
94
+ - **Removes** plugins for technologies no longer found
95
+ - Reports all changes clearly
96
+
97
+ **When to use:**
98
+
99
+ - After adding new dependencies or frameworks
100
+ - After removing technologies from your project
101
+ - Periodically to keep plugins in sync with your codebase
102
+ - Automatically via a Stop hook (see below)
103
+
104
+ **Automatic Alignment:**
105
+
106
+ The bushido plugin includes a Stop hook that automatically runs `han align` at the end of each Claude Code session, ensuring your plugins stay synchronized with your codebase as it evolves.
107
+
108
+ **Examples:**
109
+
110
+ ```bash
111
+ # Align project settings (default)
112
+ npx @thebushidocollective/han align
113
+
114
+ # Align local settings
115
+ npx @thebushidocollective/han align --scope local
116
+ ```
117
+
59
118
  ### uninstall
60
119
 
61
120
  Remove all Han plugins and marketplace configuration from Claude Code.
@@ -0,0 +1,9 @@
1
+ import type { DetectPluginsCallbacks } from './align.js';
2
+ interface AlignProgressProps {
3
+ detectPlugins: (callbacks: DetectPluginsCallbacks) => Promise<void>;
4
+ onAlignComplete: (plugins: string[]) => void;
5
+ onAlignError: (error: Error) => void;
6
+ }
7
+ export declare const AlignProgress: React.FC<AlignProgressProps>;
8
+ export {};
9
+ //# sourceMappingURL=align-progress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"align-progress.d.ts","sourceRoot":"","sources":["../../lib/align-progress.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAe,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAGtE,UAAU,kBAAkB;IAC1B,aAAa,EAAE,CAAC,SAAS,EAAE,sBAAsB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,eAAe,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,YAAY,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACtC;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA+MtD,CAAC"}
@@ -0,0 +1,58 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from 'ink';
3
+ import Spinner from 'ink-spinner';
4
+ import { useEffect, useState } from 'react';
5
+ import { MarkdownWrapper } from './markdown-wrapper.js';
6
+ export const AlignProgress = ({ detectPlugins, onAlignComplete, onAlignError, }) => {
7
+ const [phase, setPhase] = useState('analyzing');
8
+ const [plugins, setPlugins] = useState([]);
9
+ const [fullText, setFullText] = useState('');
10
+ const [currentTool, setCurrentTool] = useState(null);
11
+ const [error, setError] = useState(null);
12
+ const [toolsUsed, setToolsUsed] = useState(new Set());
13
+ useEffect(() => {
14
+ const callbacks = {
15
+ onUpdate: (update) => {
16
+ if (update.type === 'text') {
17
+ setFullText((prev) => prev + update.content);
18
+ }
19
+ else if (update.type === 'tool' && update.toolName) {
20
+ setCurrentTool(update.toolName);
21
+ setToolsUsed((prev) => new Set([...prev, update.toolName]));
22
+ }
23
+ },
24
+ onComplete: (detectedPlugins, analysisText) => {
25
+ setPlugins(detectedPlugins);
26
+ setFullText(analysisText);
27
+ setCurrentTool(null);
28
+ setPhase('analyzed');
29
+ setTimeout(() => {
30
+ setPhase('aligning');
31
+ setTimeout(() => {
32
+ setPhase('complete');
33
+ onAlignComplete(detectedPlugins);
34
+ }, 500);
35
+ }, 1000);
36
+ },
37
+ onError: (err) => {
38
+ setError(err.message);
39
+ setPhase('error');
40
+ onAlignError(err);
41
+ },
42
+ };
43
+ detectPlugins(callbacks);
44
+ }, [detectPlugins, onAlignComplete, onAlignError]);
45
+ const getToolEmoji = (toolName) => {
46
+ const emojiMap = {
47
+ web_fetch: '🌐',
48
+ read_file: '📄',
49
+ glob: '🔍',
50
+ grep: '🔎',
51
+ };
52
+ return emojiMap[toolName] || '🔧';
53
+ };
54
+ return (_jsxs(Box, { flexDirection: "column", paddingY: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "\uD83E\uDD16 Han Plugin Alignment" }) }), phase === 'analyzing' && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { color: "yellow", children: [_jsx(Spinner, { type: "dots" }), " Analyzing codebase..."] }) }), currentTool && (_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { color: "blue", children: [getToolEmoji(currentTool), " ", currentTool] }) })), toolsUsed.size > 0 && (_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { dimColor: true, children: ["Tools used: ", Array.from(toolsUsed).join(', ')] }) })), fullText && (_jsxs(Box, { marginTop: 1, paddingX: 1, borderStyle: "round", borderColor: "gray", flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { dimColor: true, bold: true, children: [_jsx(Spinner, { type: "star" }), " Agent thinking:"] }) }), _jsx(MarkdownWrapper, { children: fullText })] }))] })), (phase === 'analyzed' ||
55
+ phase === 'aligning' ||
56
+ phase === 'complete') && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "green", children: "\u2705 Analysis complete" }) }), fullText && (_jsxs(Box, { marginBottom: 1, paddingX: 1, borderStyle: "round", borderColor: "cyan", flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "\uD83D\uDCCB Agent Analysis:" }) }), _jsx(MarkdownWrapper, { children: fullText })] })), plugins.length > 0 && (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: "green", children: "\u2728 Recommended plugins:" }), plugins.sort().map((plugin) => (_jsx(Box, { marginLeft: 2, children: _jsxs(Text, { children: ["\u2022 ", plugin] }) }, plugin)))] })), phase === 'aligning' && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "yellow", children: [_jsx(Spinner, { type: "dots" }), " Aligning plugins in Claude Code settings..."] }) })), phase === 'complete' && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "green", children: "\u2705 Updated Claude Code settings" }) }), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "green", bold: true, children: "\u2705 Alignment complete!" }) }), _jsx(Box, { children: _jsx(Text, { color: "blue", children: "\uD83D\uDCA1 Restart Claude Code to load plugin changes." }) })] }))] })), phase === 'error' && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "red", bold: true, children: "\u274C Error" }) }), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "red", children: error }) }), fullText && (_jsxs(Box, { marginBottom: 1, paddingX: 1, borderStyle: "round", borderColor: "red", flexDirection: "column", children: [_jsx(Text, { bold: true, color: "red", children: "Partial Analysis:" }), _jsx(Box, { children: _jsx(MarkdownWrapper, { children: fullText }) })] })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "yellow", children: "\u26A0\uFE0F Could not complete alignment, leaving plugins unchanged" }) })] }))] }));
57
+ };
58
+ //# sourceMappingURL=align-progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"align-progress.js","sourceRoot":"","sources":["../../lib/align-progress.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ export interface AgentUpdate {
2
+ type: 'text' | 'tool';
3
+ content: string;
4
+ toolName?: string;
5
+ }
6
+ export interface AlignResult {
7
+ added: string[];
8
+ removed: string[];
9
+ unchanged: string[];
10
+ }
11
+ export interface DetectPluginsCallbacks {
12
+ onUpdate: (update: AgentUpdate) => void;
13
+ onComplete: (plugins: string[], fullText: string) => void;
14
+ onError: (error: Error) => void;
15
+ }
16
+ /**
17
+ * SDK-based align command with Ink UI
18
+ */
19
+ export declare function align(scope?: 'project' | 'local'): Promise<void>;
20
+ //# sourceMappingURL=align.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"align.d.ts","sourceRoot":"","sources":["../../lib/align.ts"],"names":[],"mappings":"AAuBA,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,WAAW;IAC1B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;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;AAiLD;;GAEG;AACH,wBAAsB,KAAK,CAAC,KAAK,GAAE,SAAS,GAAG,OAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqDjF"}
@@ -0,0 +1,208 @@
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
+ import { detectPluginsPrompt } from './detect-plugins-prompt.js';
7
+ const HAN_MARKETPLACE_REPO = 'thebushidocollective/han';
8
+ function getClaudeSettingsPath(scope = 'project') {
9
+ const filename = scope === 'local' ? 'settings.local.json' : 'settings.json';
10
+ return join(process.cwd(), '.claude', filename);
11
+ }
12
+ function ensureClaudeDirectory() {
13
+ const settingsPath = getClaudeSettingsPath();
14
+ const claudeDir = join(settingsPath, '..');
15
+ if (!existsSync(claudeDir)) {
16
+ mkdirSync(claudeDir, { recursive: true });
17
+ }
18
+ }
19
+ function readOrCreateSettings(scope = 'project') {
20
+ const settingsPath = getClaudeSettingsPath(scope);
21
+ if (existsSync(settingsPath)) {
22
+ try {
23
+ return JSON.parse(readFileSync(settingsPath, 'utf8'));
24
+ }
25
+ catch (_error) {
26
+ console.error(`Error reading ${scope === 'local' ? 'settings.local.json' : 'settings.json'}, creating new one`);
27
+ return {};
28
+ }
29
+ }
30
+ return {};
31
+ }
32
+ function writeSettings(settings, scope = 'project') {
33
+ const settingsPath = getClaudeSettingsPath(scope);
34
+ writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}\n`);
35
+ }
36
+ /**
37
+ * Get currently installed Han plugins
38
+ */
39
+ function getInstalledPlugins(scope = 'project') {
40
+ const settings = readOrCreateSettings(scope);
41
+ const enabledPlugins = settings.enabledPlugins || {};
42
+ return Object.keys(enabledPlugins)
43
+ .filter((key) => key.endsWith('@han') && enabledPlugins[key])
44
+ .map((key) => key.replace('@han', ''));
45
+ }
46
+ /**
47
+ * Use Claude Agent SDK to intelligently analyze codebase and recommend plugins
48
+ */
49
+ async function detectPluginsWithAgent(callbacks) {
50
+ // Define allowed tools - only read-only operations
51
+ const allowedTools = ['web_fetch', 'read_file', 'glob', 'grep'];
52
+ const agent = query({
53
+ prompt: detectPluginsPrompt,
54
+ options: {
55
+ model: 'claude-sonnet-4-5-20250929',
56
+ includePartialMessages: true,
57
+ allowedTools,
58
+ permissionMode: 'bypassPermissions',
59
+ },
60
+ });
61
+ let responseContent = '';
62
+ try {
63
+ // Collect all messages from the agent with live updates
64
+ for await (const sdkMessage of agent) {
65
+ if (sdkMessage.type === 'assistant' && sdkMessage.message.content) {
66
+ for (const block of sdkMessage.message.content) {
67
+ if (block.type === 'text') {
68
+ // Send text updates
69
+ callbacks.onUpdate({ type: 'text', content: block.text });
70
+ responseContent += block.text;
71
+ }
72
+ else if (block.type === 'tool_use') {
73
+ // Send tool usage updates
74
+ callbacks.onUpdate({
75
+ type: 'tool',
76
+ content: `Using ${block.name}`,
77
+ toolName: block.name,
78
+ });
79
+ }
80
+ }
81
+ }
82
+ }
83
+ // Extract plugin recommendations from agent response
84
+ const plugins = parsePluginRecommendations(responseContent);
85
+ const finalPlugins = plugins.length > 0 ? plugins : ['bushido'];
86
+ callbacks.onComplete(finalPlugins, responseContent);
87
+ }
88
+ catch (error) {
89
+ callbacks.onError(error);
90
+ }
91
+ }
92
+ /**
93
+ * Parse plugin recommendations from agent response
94
+ */
95
+ function parsePluginRecommendations(content) {
96
+ try {
97
+ // Try to find JSON array in the response
98
+ const jsonMatch = content.match(/\[[\s\S]*?\]/);
99
+ if (jsonMatch) {
100
+ const plugins = JSON.parse(jsonMatch[0]);
101
+ if (Array.isArray(plugins)) {
102
+ plugins.push('bushido');
103
+ return plugins.filter((p) => typeof p === 'string');
104
+ }
105
+ }
106
+ // Fallback: look for plugin names mentioned
107
+ const pluginPattern = /(buki-[\w-]+|do-[\w-]+|sensei-[\w-]+|bushido)/g;
108
+ const matches = content.match(pluginPattern);
109
+ if (matches) {
110
+ return [...new Set(matches)];
111
+ }
112
+ return [];
113
+ }
114
+ catch (_error) {
115
+ return [];
116
+ }
117
+ }
118
+ /**
119
+ * Compare current plugins with recommended plugins and update settings
120
+ */
121
+ function alignPluginsInSettings(recommendedPlugins, scope = 'project') {
122
+ ensureClaudeDirectory();
123
+ const settings = readOrCreateSettings(scope);
124
+ const currentPlugins = getInstalledPlugins(scope);
125
+ // Calculate differences
126
+ const added = [];
127
+ const removed = [];
128
+ const unchanged = [];
129
+ // Add Han marketplace if not present
130
+ if (!settings?.extraKnownMarketplaces?.han) {
131
+ settings.extraKnownMarketplaces = {
132
+ ...settings.extraKnownMarketplaces,
133
+ han: { source: { source: 'github', repo: HAN_MARKETPLACE_REPO } },
134
+ };
135
+ }
136
+ // Initialize enabledPlugins if needed
137
+ if (!settings.enabledPlugins) {
138
+ settings.enabledPlugins = {};
139
+ }
140
+ // Find plugins to add (in recommended but not in current)
141
+ for (const plugin of recommendedPlugins) {
142
+ if (!currentPlugins.includes(plugin)) {
143
+ added.push(plugin);
144
+ settings.enabledPlugins[`${plugin}@han`] = true;
145
+ }
146
+ else {
147
+ unchanged.push(plugin);
148
+ }
149
+ }
150
+ // Find plugins to remove (in current but not in recommended)
151
+ for (const plugin of currentPlugins) {
152
+ if (!recommendedPlugins.includes(plugin)) {
153
+ removed.push(plugin);
154
+ delete settings.enabledPlugins[`${plugin}@han`];
155
+ }
156
+ }
157
+ writeSettings(settings, scope);
158
+ return { added, removed, unchanged };
159
+ }
160
+ /**
161
+ * SDK-based align command with Ink UI
162
+ */
163
+ export async function align(scope = 'project') {
164
+ // Import Ink UI component dynamically
165
+ const { AlignProgress } = await import('./align-progress.js');
166
+ let resolveCompletion;
167
+ let rejectCompletion;
168
+ const completionPromise = new Promise((resolve, reject) => {
169
+ resolveCompletion = resolve;
170
+ rejectCompletion = reject;
171
+ });
172
+ const filename = scope === 'local' ? 'settings.local.json' : 'settings.json';
173
+ console.log(`Aligning plugins in ./.claude/${filename}...\n`);
174
+ const { unmount } = render(React.createElement(AlignProgress, {
175
+ detectPlugins: detectPluginsWithAgent,
176
+ onAlignComplete: (plugins) => {
177
+ const result = alignPluginsInSettings(plugins, scope);
178
+ // Report changes
179
+ if (result.added.length > 0) {
180
+ console.log(`\n✓ Added ${result.added.length} plugin(s): ${result.added.join(', ')}`);
181
+ }
182
+ if (result.removed.length > 0) {
183
+ console.log(`\n✓ Removed ${result.removed.length} plugin(s): ${result.removed.join(', ')}`);
184
+ }
185
+ if (result.added.length === 0 && result.removed.length === 0) {
186
+ console.log('\n✓ No changes needed - plugins are already aligned');
187
+ }
188
+ else {
189
+ console.log('\n⚠️ Please restart Claude Code to load the plugin changes');
190
+ }
191
+ if (resolveCompletion)
192
+ resolveCompletion();
193
+ },
194
+ onAlignError: (error) => {
195
+ if (rejectCompletion)
196
+ rejectCompletion(error);
197
+ },
198
+ }));
199
+ try {
200
+ await completionPromise;
201
+ // Wait a moment for the UI to show completion message
202
+ await new Promise((resolve) => setTimeout(resolve, 1500));
203
+ }
204
+ finally {
205
+ unmount();
206
+ }
207
+ }
208
+ //# sourceMappingURL=align.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"align.js","sourceRoot":"","sources":["../../lib/align.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Shared agent prompt for detecting and recommending Han plugins
3
+ */
4
+ export declare const detectPluginsPrompt = "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.\n\nCRITICAL FIRST STEP:\n1. Fetch the Han marketplace to see ALL available plugins:\n https://raw.githubusercontent.com/TheBushidoCollective/han/refs/heads/main/.claude-plugin/marketplace.json\n2. Study the marketplace.json to understand:\n - What plugins are available in each category\n - What technologies and practices each plugin supports\n - The keywords and descriptions for each plugin\n\nPlugin Categories:\n- buki-* (\u6B66\u5668 weapons): Skills for specific technologies and frameworks\n- do-* (\u9053 disciplines): Specialized agents for development practices and workflows\n- sensei-* (\u5148\u751F teachers): MCP servers for external integrations\n- bushido: Core quality principles (ALWAYS recommend this)\n\nYour Analysis Process:\n1. **Analyze the codebase structure**:\n - Use Glob to discover directory structure and file types\n * Example: glob(\"**/*.md\") to find markdown files\n * Example: glob(\"**/blog/**\") to check for blog directories\n - Use Grep to search for import statements and framework usage\n * Example: grep(\"import.*react\") to find React usage\n * Example: grep(\"^---\") to find frontmatter in markdown files\n - Read configuration files (package.json, Cargo.toml, go.mod, requirements.txt, etc.)\n - Use Read tool to examine specific files when patterns are found\n\n2. **Identify technologies used** (for buki-* recommendations):\n - What programming languages are in use?\n - What frameworks and libraries are imported?\n - What testing frameworks are configured?\n - What build tools and infrastructure are present?\n\n3. **Identify development practices** (for do-* recommendations):\n Analyze the codebase for these specific patterns:\n\n - **Content & Writing**: Look for blog posts, articles, or documentation:\n * Directories: blog/, posts/, content/, articles/, docs/, _posts/\n * Files: .md, .mdx with frontmatter (title, date, author, tags)\n * CMS: contentlayer.config.js, sanity.config.ts, contentful\n * If found \u2192 recommend do-content-creator\n\n - **API Development**: Look for API/backend patterns:\n * Directories: api/, routes/, controllers/, endpoints/\n * Files: OpenAPI/Swagger specs, GraphQL schemas\n * Frameworks: Express routes, tRPC, FastAPI, Rails controllers\n * If found \u2192 recommend do-api-development\n\n - **Testing Practices**: Look for test infrastructure:\n * Directories: __tests__/, tests/, test/, spec/\n * Files: *.test.*, *.spec.*, test configuration files\n * If found \u2192 consider relevant testing do-* plugins\n\n - **DevOps/Infrastructure**: Look for deployment configs:\n * Files: Dockerfile, docker-compose.yml, kubernetes/, terraform/\n * CI/CD: .github/workflows/, .gitlab-ci.yml, .circleci/\n * If found \u2192 recommend do-devops or do-infrastructure\n\n - **Accessibility**: Look for a11y patterns:\n * Dependencies: @axe-core, pa11y, jest-axe\n * Config files: .pa11yci, accessibility test files\n * If found \u2192 recommend do-accessibility-engineering\n\n - **Type of application**:\n * Frontend-heavy (components/, pages/, views/) \u2192 do-frontend-development\n * Mobile (android/, ios/, mobile/) \u2192 do-mobile-development\n * Full-stack (both frontend & backend) \u2192 both frontend and backend do-*\n\n4. **Match findings to available plugins**:\n - Cross-reference detected technologies with buki-* plugins in marketplace\n - Cross-reference development practices with do-* plugins in marketplace\n - Recommend 3-8 total plugins (both buki-* AND do-* types)\n\nReturn ONLY a JSON array of recommended plugin names, like:\n[\"bushido\", \"buki-typescript\", \"buki-react\", \"do-frontend-development\"]\n\nULTRATHINK and perform a thorough analysis. Fetch the marketplace first to know what's available, then analyze the codebase to recommend the most relevant plugins.";
5
+ //# sourceMappingURL=detect-plugins-prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-plugins-prompt.d.ts","sourceRoot":"","sources":["../../lib/detect-plugins-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,mBAAmB,ggIA4EoI,CAAC"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Shared agent prompt for detecting and recommending Han plugins
3
+ */
4
+ export const detectPluginsPrompt = `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.
5
+
6
+ CRITICAL FIRST STEP:
7
+ 1. Fetch the Han marketplace to see ALL available plugins:
8
+ https://raw.githubusercontent.com/TheBushidoCollective/han/refs/heads/main/.claude-plugin/marketplace.json
9
+ 2. Study the marketplace.json to understand:
10
+ - What plugins are available in each category
11
+ - What technologies and practices each plugin supports
12
+ - The keywords and descriptions for each plugin
13
+
14
+ Plugin Categories:
15
+ - buki-* (武器 weapons): Skills for specific technologies and frameworks
16
+ - do-* (道 disciplines): Specialized agents for development practices and workflows
17
+ - sensei-* (先生 teachers): MCP servers for external integrations
18
+ - bushido: Core quality principles (ALWAYS recommend this)
19
+
20
+ Your Analysis Process:
21
+ 1. **Analyze the codebase structure**:
22
+ - Use Glob to discover directory structure and file types
23
+ * Example: glob("**/*.md") to find markdown files
24
+ * Example: glob("**/blog/**") to check for blog directories
25
+ - Use Grep to search for import statements and framework usage
26
+ * Example: grep("import.*react") to find React usage
27
+ * Example: grep("^---") to find frontmatter in markdown files
28
+ - Read configuration files (package.json, Cargo.toml, go.mod, requirements.txt, etc.)
29
+ - Use Read tool to examine specific files when patterns are found
30
+
31
+ 2. **Identify technologies used** (for buki-* recommendations):
32
+ - What programming languages are in use?
33
+ - What frameworks and libraries are imported?
34
+ - What testing frameworks are configured?
35
+ - What build tools and infrastructure are present?
36
+
37
+ 3. **Identify development practices** (for do-* recommendations):
38
+ Analyze the codebase for these specific patterns:
39
+
40
+ - **Content & Writing**: Look for blog posts, articles, or documentation:
41
+ * Directories: blog/, posts/, content/, articles/, docs/, _posts/
42
+ * Files: .md, .mdx with frontmatter (title, date, author, tags)
43
+ * CMS: contentlayer.config.js, sanity.config.ts, contentful
44
+ * If found → recommend do-content-creator
45
+
46
+ - **API Development**: Look for API/backend patterns:
47
+ * Directories: api/, routes/, controllers/, endpoints/
48
+ * Files: OpenAPI/Swagger specs, GraphQL schemas
49
+ * Frameworks: Express routes, tRPC, FastAPI, Rails controllers
50
+ * If found → recommend do-api-development
51
+
52
+ - **Testing Practices**: Look for test infrastructure:
53
+ * Directories: __tests__/, tests/, test/, spec/
54
+ * Files: *.test.*, *.spec.*, test configuration files
55
+ * If found → consider relevant testing do-* plugins
56
+
57
+ - **DevOps/Infrastructure**: Look for deployment configs:
58
+ * Files: Dockerfile, docker-compose.yml, kubernetes/, terraform/
59
+ * CI/CD: .github/workflows/, .gitlab-ci.yml, .circleci/
60
+ * If found → recommend do-devops or do-infrastructure
61
+
62
+ - **Accessibility**: Look for a11y patterns:
63
+ * Dependencies: @axe-core, pa11y, jest-axe
64
+ * Config files: .pa11yci, accessibility test files
65
+ * If found → recommend do-accessibility-engineering
66
+
67
+ - **Type of application**:
68
+ * Frontend-heavy (components/, pages/, views/) → do-frontend-development
69
+ * Mobile (android/, ios/, mobile/) → do-mobile-development
70
+ * Full-stack (both frontend & backend) → both frontend and backend do-*
71
+
72
+ 4. **Match findings to available plugins**:
73
+ - Cross-reference detected technologies with buki-* plugins in marketplace
74
+ - Cross-reference development practices with do-* plugins in marketplace
75
+ - Recommend 3-8 total plugins (both buki-* AND do-* types)
76
+
77
+ Return ONLY a JSON array of recommended plugin names, like:
78
+ ["bushido", "buki-typescript", "buki-react", "do-frontend-development"]
79
+
80
+ ULTRATHINK and perform a thorough analysis. Fetch the marketplace first to know what's available, then analyze the codebase to recommend the most relevant plugins.`;
81
+ //# sourceMappingURL=detect-plugins-prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-plugins-prompt.js","sourceRoot":"","sources":["../../lib/detect-plugins-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oKA4EiI,CAAC"}
@@ -1,4 +1,4 @@
1
- import type { DetectPluginsCallbacks } from "./install.js";
1
+ import type { DetectPluginsCallbacks } from './install.js';
2
2
  interface InstallProgressProps {
3
3
  detectPlugins: (callbacks: DetectPluginsCallbacks) => Promise<void>;
4
4
  onInstallComplete: (plugins: string[]) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"install-progress.d.ts","sourceRoot":"","sources":["../../lib/install-progress.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAe,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAGxE,UAAU,oBAAoB;IAC7B,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;CACvC;AAED,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA8M1D,CAAC"}
1
+ {"version":3,"file":"install-progress.d.ts","sourceRoot":"","sources":["../../lib/install-progress.tsx"],"names":[],"mappings":"AAGA,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"}
@@ -1,22 +1,22 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Box, Text } from "ink";
3
- import Spinner from "ink-spinner";
4
- import { useEffect, useState } from "react";
5
- import { MarkdownWrapper } from "./markdown-wrapper.js";
2
+ import { Box, Text } from 'ink';
3
+ import Spinner from 'ink-spinner';
4
+ import { useEffect, useState } from 'react';
5
+ import { MarkdownWrapper } from './markdown-wrapper.js';
6
6
  export const InstallProgress = ({ detectPlugins, onInstallComplete, onInstallError, }) => {
7
- const [phase, setPhase] = useState("analyzing");
7
+ const [phase, setPhase] = useState('analyzing');
8
8
  const [plugins, setPlugins] = useState([]);
9
- const [fullText, setFullText] = useState("");
9
+ const [fullText, setFullText] = useState('');
10
10
  const [currentTool, setCurrentTool] = useState(null);
11
11
  const [error, setError] = useState(null);
12
12
  const [toolsUsed, setToolsUsed] = useState(new Set());
13
13
  useEffect(() => {
14
14
  const callbacks = {
15
15
  onUpdate: (update) => {
16
- if (update.type === "text") {
16
+ if (update.type === 'text') {
17
17
  setFullText((prev) => prev + update.content);
18
18
  }
19
- else if (update.type === "tool" && update.toolName) {
19
+ else if (update.type === 'tool' && update.toolName) {
20
20
  setCurrentTool(update.toolName);
21
21
  setToolsUsed((prev) => new Set([...prev, update.toolName]));
22
22
  }
@@ -25,18 +25,18 @@ export const InstallProgress = ({ detectPlugins, onInstallComplete, onInstallErr
25
25
  setPlugins(detectedPlugins);
26
26
  setFullText(analysisText);
27
27
  setCurrentTool(null);
28
- setPhase("analyzed");
28
+ setPhase('analyzed');
29
29
  setTimeout(() => {
30
- setPhase("installing");
30
+ setPhase('installing');
31
31
  setTimeout(() => {
32
- setPhase("complete");
32
+ setPhase('complete');
33
33
  onInstallComplete(detectedPlugins);
34
34
  }, 500);
35
35
  }, 1000);
36
36
  },
37
37
  onError: (err) => {
38
38
  setError(err.message);
39
- setPhase("error");
39
+ setPhase('error');
40
40
  onInstallError(err);
41
41
  },
42
42
  };
@@ -44,15 +44,15 @@ export const InstallProgress = ({ detectPlugins, onInstallComplete, onInstallErr
44
44
  }, [detectPlugins, onInstallComplete, onInstallError]);
45
45
  const getToolEmoji = (toolName) => {
46
46
  const emojiMap = {
47
- web_fetch: "🌐",
48
- read_file: "📄",
49
- glob: "🔍",
50
- grep: "🔎",
47
+ web_fetch: '🌐',
48
+ read_file: '📄',
49
+ glob: '🔍',
50
+ grep: '🔎',
51
51
  };
52
- return emojiMap[toolName] || "🔧";
52
+ return emojiMap[toolName] || '🔧';
53
53
  };
54
- return (_jsxs(Box, { flexDirection: "column", paddingY: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "\uD83E\uDD16 Han Plugin Installer" }) }), phase === "analyzing" && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { color: "yellow", children: [_jsx(Spinner, { type: "dots" }), " Analyzing codebase..."] }) }), currentTool && (_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { color: "blue", children: [getToolEmoji(currentTool), " ", currentTool] }) })), toolsUsed.size > 0 && (_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { dimColor: true, children: ["Tools used: ", Array.from(toolsUsed).join(", ")] }) })), fullText && (_jsxs(Box, { marginTop: 1, paddingX: 1, borderStyle: "round", borderColor: "gray", flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { dimColor: true, bold: true, children: [_jsx(Spinner, { type: "star" }), " Agent thinking:"] }) }), _jsx(MarkdownWrapper, { children: fullText })] }))] })), (phase === "analyzed" ||
55
- phase === "installing" ||
56
- phase === "complete") && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "green", children: "\u2705 Analysis complete" }) }), fullText && (_jsxs(Box, { marginBottom: 1, paddingX: 1, borderStyle: "round", borderColor: "cyan", flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "\uD83D\uDCCB Agent Analysis:" }) }), _jsx(MarkdownWrapper, { children: fullText })] })), plugins.length > 0 && (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: "green", children: "\u2728 Adding recommended plugins:" }), plugins.sort().map((plugin) => (_jsx(Box, { marginLeft: 2, children: _jsxs(Text, { children: ["\u2022 ", plugin] }) }, plugin)))] })), phase === "installing" && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "yellow", children: [_jsx(Spinner, { type: "dots" }), " Updating Claude Code settings..."] }) })), phase === "complete" && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "green", children: "\u2705 Updated Claude Code settings" }) }), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "green", bold: true, children: "\u2705 Installation complete!" }) }), _jsx(Box, { children: _jsx(Text, { color: "blue", children: "\uD83D\uDCA1 Restart Claude Code to load the new plugins." }) })] }))] })), phase === "error" && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "red", bold: true, children: "\u274C Error" }) }), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "red", children: error }) }), fullText && (_jsxs(Box, { marginBottom: 1, paddingX: 1, borderStyle: "round", borderColor: "red", flexDirection: "column", children: [_jsx(Text, { bold: true, color: "red", children: "Partial Analysis:" }), _jsx(Box, { children: _jsx(MarkdownWrapper, { children: fullText }) })] })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "yellow", children: "\u26A0\uFE0F Falling back to installing core bushido plugin..." }) })] }))] }));
54
+ return (_jsxs(Box, { flexDirection: "column", paddingY: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "\uD83E\uDD16 Han Plugin Installer" }) }), phase === 'analyzing' && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { color: "yellow", children: [_jsx(Spinner, { type: "dots" }), " Analyzing codebase..."] }) }), currentTool && (_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { color: "blue", children: [getToolEmoji(currentTool), " ", currentTool] }) })), toolsUsed.size > 0 && (_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { dimColor: true, children: ["Tools used: ", Array.from(toolsUsed).join(', ')] }) })), fullText && (_jsxs(Box, { marginTop: 1, paddingX: 1, borderStyle: "round", borderColor: "gray", flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { dimColor: true, bold: true, children: [_jsx(Spinner, { type: "star" }), " Agent thinking:"] }) }), _jsx(MarkdownWrapper, { children: fullText })] }))] })), (phase === 'analyzed' ||
55
+ phase === 'installing' ||
56
+ phase === 'complete') && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "green", children: "\u2705 Analysis complete" }) }), fullText && (_jsxs(Box, { marginBottom: 1, paddingX: 1, borderStyle: "round", borderColor: "cyan", flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "\uD83D\uDCCB Agent Analysis:" }) }), _jsx(MarkdownWrapper, { children: fullText })] })), plugins.length > 0 && (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: "green", children: "\u2728 Adding recommended plugins:" }), plugins.sort().map((plugin) => (_jsx(Box, { marginLeft: 2, children: _jsxs(Text, { children: ["\u2022 ", plugin] }) }, plugin)))] })), phase === 'installing' && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "yellow", children: [_jsx(Spinner, { type: "dots" }), " Updating Claude Code settings..."] }) })), phase === 'complete' && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "green", children: "\u2705 Updated Claude Code settings" }) }), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "green", bold: true, children: "\u2705 Installation complete!" }) }), _jsx(Box, { children: _jsx(Text, { color: "blue", children: "\uD83D\uDCA1 Restart Claude Code to load the new plugins." }) })] }))] })), phase === 'error' && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "red", bold: true, children: "\u274C Error" }) }), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "red", children: error }) }), fullText && (_jsxs(Box, { marginBottom: 1, paddingX: 1, borderStyle: "round", borderColor: "red", flexDirection: "column", children: [_jsx(Text, { bold: true, color: "red", children: "Partial Analysis:" }), _jsx(Box, { children: _jsx(MarkdownWrapper, { children: fullText }) })] })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "yellow", children: "\u26A0\uFE0F Falling back to installing core bushido plugin..." }) })] }))] }));
57
57
  };
58
58
  //# sourceMappingURL=install-progress.js.map