seeclaudecode 1.0.8 → 1.0.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "seeclaudecode",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "description": "Real-time visualization of repository structure - watch Claude Code edit your codebase",
5
5
  "main": "server.js",
6
6
  "type": "module",
@@ -36,5 +36,6 @@
36
36
  },
37
37
  "engines": {
38
38
  "node": ">=18.0.0"
39
- }
39
+ },
40
+ "claudeCodePlugin": ".claude-plugin/plugin.json"
40
41
  }
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "seeclaudecode",
3
+ "description": "Real-time repository visualization for Claude Code",
4
+ "version": "1.0.1",
5
+ "author": {
6
+ "name": "Nina Lu"
7
+ },
8
+ "homepage": "https://github.com/ninajlu/seeclaudecode",
9
+ "repository": "https://github.com/ninajlu/seeclaudecode",
10
+ "license": "MIT",
11
+ "skills": "../skills/"
12
+ }
@@ -0,0 +1,27 @@
1
+ name: Publish to npm
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ publish:
11
+ runs-on: ubuntu-latest
12
+ permissions:
13
+ contents: read
14
+ id-token: write
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - uses: actions/setup-node@v4
19
+ with:
20
+ node-version: '20'
21
+ registry-url: 'https://registry.npmjs.org'
22
+
23
+ - run: npm install
24
+
25
+ - run: npm publish --access public
26
+ env:
27
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -0,0 +1,155 @@
1
+ # SeeClaudeCode
2
+
3
+ Real-time visualization of your repository structure while Claude Code edits your codebase.
4
+
5
+ ![SeeClaudeCode Screenshot](https://seeclaudecode.fly.dev/screenshot.jpg)
6
+
7
+ ## Features
8
+
9
+ - **Architecture Graph** - Interactive diagram showing your project's directory structure with pan/zoom
10
+ - **Sunburst View** - Radial visualization of your codebase hierarchy
11
+ - **File Explorer** - Traditional tree view with change tracking
12
+ - **Real-time Git Diff** - See exactly what changed in any file or directory
13
+ - **Live Highlighting**:
14
+ - **Yellow pulse** - Files with pending changes (git diff)
15
+ - **Green pulse** - Files currently being edited
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install -g seeclaudecode
21
+ npx seeclaudecode
22
+ ```
23
+
24
+ ## Claude Code Plugin
25
+
26
+ Install the SeeClaudeCode skill directly in Claude Code:
27
+
28
+ ```bash
29
+ /plugin marketplace add ninajlu/seeclaudecode
30
+ /plugin install seeclaudecode@seeclaudecode
31
+ ```
32
+
33
+ This adds a skill that helps Claude understand when and how to use SeeClaudeCode during your coding sessions.
34
+
35
+ ## Usage
36
+
37
+ ```bash
38
+ # Quick start with npx (no install needed)
39
+ npx seeclaudecode
40
+
41
+ # Interactive mode - prompts for directory selection
42
+ seeclaudecode
43
+
44
+ # Monitor specific directory
45
+ npx seeclaudecode ./my-project
46
+
47
+ # Monitor with absolute path
48
+ npx seeclaudecode /path/to/repo
49
+
50
+ # Use custom port
51
+ npx seeclaudecode . --port 4000
52
+
53
+ # Don't auto-open browser
54
+ npx seeclaudecode . --no-open
55
+ ```
56
+
57
+ When started without a directory argument, you'll see an interactive menu:
58
+ ```
59
+ Select a directory to monitor:
60
+
61
+ 1) Current directory
62
+ /Users/you/projects
63
+ 2) my-app
64
+ /Users/you/projects/my-app
65
+
66
+ Or enter a custom path
67
+
68
+ 📁 Directory:
69
+ ```
70
+
71
+ ## Switching Directories
72
+
73
+ While running, you can switch to a different directory at any time:
74
+ - Type a new path and press Enter to switch
75
+ - Type `quit` or `exit` to stop
76
+
77
+ ## Options
78
+
79
+ | Option | Description |
80
+ |--------|-------------|
81
+ | `-p, --port <port>` | Port to run server on (default: 3847) |
82
+ | `-n, --no-open` | Don't automatically open browser |
83
+ | `-h, --help` | Show help message |
84
+ | `-v, --version` | Show version number |
85
+
86
+ ## How It Works
87
+
88
+ 1. Start SeeClaudeCode (it will prompt for a directory or use the one you specify)
89
+ 2. Open the displayed URL in your browser
90
+ 3. Run Claude Code in the same directory
91
+ 4. Watch as files pulse and highlight when Claude makes changes
92
+ 5. Click on any file or directory to see the git diff
93
+ 6. Switch directories anytime by typing a new path
94
+
95
+ ## Views
96
+
97
+ ### Architecture Graph
98
+ An interactive node-based diagram showing your project structure. Changed files appear below their parent directories with pulsing yellow highlights.
99
+
100
+ ### Sunburst View
101
+ A radial visualization where each ring represents a directory level. Click on segments to see diffs for that directory.
102
+
103
+ ### File Explorer
104
+ A traditional tree view showing all files with color-coded change indicators.
105
+
106
+ ## Visual Indicators
107
+
108
+ | Indicator | Meaning |
109
+ |-----------|---------|
110
+ | Yellow pulsing | Pending changes (in git diff) |
111
+ | Green pulsing | Currently being edited |
112
+ | Purple nodes | Directories |
113
+ | Green nodes | Code files (.js, .ts, .py, etc.) |
114
+ | Pink nodes | Style files (.css, .scss) |
115
+ | Orange nodes | Config files (.json, .yaml) |
116
+ | Blue nodes | Documentation (.md, .txt) |
117
+
118
+ ## Requirements
119
+
120
+ - Node.js 18.0.0 or higher
121
+ - Git (for diff functionality)
122
+
123
+ ## Development
124
+
125
+ ```bash
126
+ # Clone and install
127
+ git clone <repo-url>
128
+ cd seeclaudecode
129
+ npm install
130
+
131
+ # Run locally
132
+ npm start /path/to/repo
133
+
134
+ # Link for global testing
135
+ npm link
136
+ seeclaudecode /path/to/repo
137
+ ```
138
+
139
+ ## Architecture
140
+
141
+ ```
142
+ seeclaudecode/
143
+ ├── bin/
144
+ │ └── cli.js # CLI entry point
145
+ ├── public/
146
+ │ ├── index.html # Main HTML structure
147
+ │ ├── styles.css # Styling and animations
148
+ │ └── app.js # Frontend visualization logic
149
+ ├── server.js # Express server with WebSocket & file watching
150
+ └── package.json
151
+ ```
152
+
153
+ ## License
154
+
155
+ MIT
@@ -0,0 +1,336 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { fileURLToPath } from 'url';
4
+ import { dirname, join, resolve } from 'path';
5
+ import { existsSync, statSync, readdirSync } from 'fs';
6
+ import { spawn } from 'child_process';
7
+ import { createInterface } from 'readline';
8
+ import { createServer } from 'net';
9
+
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = dirname(__filename);
12
+
13
+ // Parse arguments
14
+ const args = process.argv.slice(2);
15
+ let targetDir = null; // Don't default to cwd - prompt instead
16
+ let port = 3847;
17
+ let openBrowser = true;
18
+
19
+ // Help text
20
+ const helpText = `
21
+ SeeClaudeCode - Watch Claude Code edit your codebase in real-time
22
+
23
+ Usage:
24
+ seeclaudecode [directory] [options]
25
+
26
+ Arguments:
27
+ directory Directory to monitor (will prompt if not provided)
28
+
29
+ Options:
30
+ -p, --port <port> Port to run server on (default: 3847)
31
+ -n, --no-open Don't automatically open browser
32
+ -h, --help Show this help message
33
+ -v, --version Show version number
34
+
35
+ Examples:
36
+ seeclaudecode # Prompts for directory
37
+ seeclaudecode ./my-project # Monitor specific directory
38
+ seeclaudecode /path/to/repo # Monitor absolute path
39
+ seeclaudecode . --port 4000 # Use custom port
40
+
41
+ While running:
42
+ Type a new path and press Enter to switch directories
43
+ Type 'quit' or 'exit' to stop
44
+
45
+ Once running, open the displayed URL in your browser to see:
46
+ - Architecture graph of your codebase
47
+ - Sunburst visualization
48
+ - File explorer with change tracking
49
+ - Real-time git diff viewer
50
+ - Yellow pulsing highlights for pending changes
51
+ - Green pulsing for files being actively edited
52
+ `;
53
+
54
+ // Parse arguments
55
+ for (let i = 0; i < args.length; i++) {
56
+ const arg = args[i];
57
+
58
+ if (arg === '-h' || arg === '--help') {
59
+ console.log(helpText);
60
+ process.exit(0);
61
+ }
62
+
63
+ if (arg === '-v' || arg === '--version') {
64
+ const pkg = await import('../package.json', { with: { type: 'json' } });
65
+ console.log(`seeclaudecode v${pkg.default.version}`);
66
+ process.exit(0);
67
+ }
68
+
69
+ if (arg === '-p' || arg === '--port') {
70
+ port = parseInt(args[++i], 10);
71
+ if (isNaN(port)) {
72
+ console.error('Error: Invalid port number');
73
+ process.exit(1);
74
+ }
75
+ continue;
76
+ }
77
+
78
+ if (arg === '-n' || arg === '--no-open') {
79
+ openBrowser = false;
80
+ continue;
81
+ }
82
+
83
+ if (!arg.startsWith('-')) {
84
+ targetDir = resolve(arg);
85
+ }
86
+ }
87
+
88
+ // Create readline interface
89
+ const rl = createInterface({
90
+ input: process.stdin,
91
+ output: process.stdout
92
+ });
93
+
94
+ // Promisified question
95
+ function question(prompt) {
96
+ return new Promise((resolve) => {
97
+ rl.question(prompt, resolve);
98
+ });
99
+ }
100
+
101
+ // Check if port is available
102
+ function isPortAvailable(port) {
103
+ return new Promise((resolve) => {
104
+ const server = createServer();
105
+ server.once('error', () => resolve(false));
106
+ server.once('listening', () => {
107
+ server.close();
108
+ resolve(true);
109
+ });
110
+ server.listen(port);
111
+ });
112
+ }
113
+
114
+ // Find an available port starting from the given port
115
+ async function findAvailablePort(startPort) {
116
+ let currentPort = startPort;
117
+ const maxAttempts = 10;
118
+
119
+ for (let i = 0; i < maxAttempts; i++) {
120
+ if (await isPortAvailable(currentPort)) {
121
+ return currentPort;
122
+ }
123
+ currentPort++;
124
+ }
125
+
126
+ throw new Error(`Could not find an available port after ${maxAttempts} attempts`);
127
+ }
128
+
129
+ // Validate directory
130
+ function validateDirectory(dir) {
131
+ const resolved = resolve(dir);
132
+ if (!existsSync(resolved)) {
133
+ return { valid: false, error: `Directory does not exist: ${resolved}` };
134
+ }
135
+ if (!statSync(resolved).isDirectory()) {
136
+ return { valid: false, error: `Path is not a directory: ${resolved}` };
137
+ }
138
+ return { valid: true, path: resolved };
139
+ }
140
+
141
+ // Get suggested directories (recent git repos, common project locations)
142
+ function getSuggestedDirs() {
143
+ const suggestions = [];
144
+ const cwd = process.cwd();
145
+
146
+ // Add current directory
147
+ suggestions.push({ path: cwd, label: 'Current directory' });
148
+
149
+ // Check for subdirectories that look like projects
150
+ try {
151
+ const entries = readdirSync(cwd, { withFileTypes: true });
152
+ for (const entry of entries) {
153
+ if (entry.isDirectory() && !entry.name.startsWith('.') && !entry.name.startsWith('node_modules')) {
154
+ const subPath = join(cwd, entry.name);
155
+ // Check if it's a git repo or has package.json
156
+ if (existsSync(join(subPath, '.git')) || existsSync(join(subPath, 'package.json'))) {
157
+ suggestions.push({ path: subPath, label: entry.name });
158
+ }
159
+ }
160
+ }
161
+ } catch (e) {
162
+ // Ignore errors
163
+ }
164
+
165
+ return suggestions.slice(0, 5); // Max 5 suggestions
166
+ }
167
+
168
+ // Print banner
169
+ function printBanner() {
170
+ console.log(`
171
+ \x1b[36m╔═══════════════════════════════════════════════════════════╗
172
+ ║ ║
173
+ ║ \x1b[33m👁️ SeeClaudeCode\x1b[36m ║
174
+ ║ \x1b[90mWatch Claude Code edit your codebase in real-time\x1b[36m ║
175
+ ║ ║
176
+ ╚═══════════════════════════════════════════════════════════╝\x1b[0m
177
+ `);
178
+ }
179
+
180
+ // Prompt for directory
181
+ async function promptForDirectory() {
182
+ const suggestions = getSuggestedDirs();
183
+
184
+ console.log('\x1b[36mSelect a directory to monitor:\x1b[0m\n');
185
+
186
+ suggestions.forEach((s, i) => {
187
+ console.log(` \x1b[33m${i + 1})\x1b[0m ${s.label}`);
188
+ if (s.label !== s.path) {
189
+ console.log(` \x1b[90m${s.path}\x1b[0m`);
190
+ }
191
+ });
192
+
193
+ console.log(`\n \x1b[90mOr enter a custom path\x1b[0m\n`);
194
+
195
+ while (true) {
196
+ const answer = await question('\x1b[36m📁 Directory:\x1b[0m ');
197
+
198
+ // Check if it's a number selection
199
+ const num = parseInt(answer, 10);
200
+ if (!isNaN(num) && num >= 1 && num <= suggestions.length) {
201
+ return suggestions[num - 1].path;
202
+ }
203
+
204
+ // Treat as a path
205
+ if (answer.trim()) {
206
+ const result = validateDirectory(answer.trim());
207
+ if (result.valid) {
208
+ return result.path;
209
+ }
210
+ console.log(`\x1b[31m${result.error}\x1b[0m`);
211
+ }
212
+ }
213
+ }
214
+
215
+ // Server management
216
+ let server = null;
217
+ let currentDir = null;
218
+
219
+ function startServer(dir) {
220
+ currentDir = dir;
221
+
222
+ console.log(`\n\x1b[90m📁 Monitoring:\x1b[0m ${dir}`);
223
+ console.log(`\x1b[90m🌐 Server:\x1b[0m http://localhost:${port}`);
224
+ console.log(`\n\x1b[90m💡 Type a new path to switch directories, or 'quit' to exit\x1b[0m\n`);
225
+
226
+ const serverPath = join(__dirname, '..', 'server.js');
227
+ server = spawn('node', [serverPath, dir], {
228
+ stdio: ['pipe', 'inherit', 'inherit'],
229
+ env: { ...process.env, PORT: port.toString() }
230
+ });
231
+
232
+ server.on('close', (code) => {
233
+ if (code !== null && code !== 0) {
234
+ console.error(`\x1b[31mServer exited with code ${code}\x1b[0m`);
235
+ }
236
+ });
237
+
238
+ return server;
239
+ }
240
+
241
+ function stopServer() {
242
+ if (server) {
243
+ server.kill('SIGTERM');
244
+ server = null;
245
+ }
246
+ }
247
+
248
+ function restartServer(newDir) {
249
+ console.log(`\n\x1b[33m🔄 Switching to: ${newDir}\x1b[0m`);
250
+ stopServer();
251
+
252
+ // Brief delay before restarting
253
+ setTimeout(() => {
254
+ startServer(newDir);
255
+ }, 500);
256
+ }
257
+
258
+ // Main
259
+ async function main() {
260
+ printBanner();
261
+
262
+ // If directory wasn't provided as argument, prompt for it
263
+ if (!targetDir) {
264
+ targetDir = await promptForDirectory();
265
+ } else {
266
+ // Validate provided directory
267
+ const result = validateDirectory(targetDir);
268
+ if (!result.valid) {
269
+ console.error(`\x1b[31mError: ${result.error}\x1b[0m`);
270
+ process.exit(1);
271
+ }
272
+ targetDir = result.path;
273
+ }
274
+
275
+ // Find available port
276
+ const requestedPort = port;
277
+ port = await findAvailablePort(port);
278
+ if (port !== requestedPort) {
279
+ console.log(`\x1b[33mPort ${requestedPort} is in use, using port ${port} instead\x1b[0m`);
280
+ }
281
+
282
+ // Start the server
283
+ startServer(targetDir);
284
+
285
+ // Open browser after a short delay
286
+ if (openBrowser) {
287
+ setTimeout(async () => {
288
+ try {
289
+ const open = (await import('open')).default;
290
+ await open(`http://localhost:${port}`);
291
+ } catch (e) {
292
+ // Silently fail if can't open browser
293
+ }
294
+ }, 1500);
295
+ }
296
+
297
+ // Listen for directory changes
298
+ rl.on('line', (input) => {
299
+ const trimmed = input.trim();
300
+
301
+ if (trimmed === 'quit' || trimmed === 'exit') {
302
+ console.log('\n\x1b[90mShutting down...\x1b[0m');
303
+ stopServer();
304
+ rl.close();
305
+ process.exit(0);
306
+ }
307
+
308
+ if (trimmed) {
309
+ const result = validateDirectory(trimmed);
310
+ if (result.valid) {
311
+ restartServer(result.path);
312
+ } else {
313
+ console.log(`\x1b[31m${result.error}\x1b[0m`);
314
+ }
315
+ }
316
+ });
317
+
318
+ // Handle exit
319
+ process.on('SIGINT', () => {
320
+ console.log('\n\x1b[90mShutting down...\x1b[0m');
321
+ stopServer();
322
+ rl.close();
323
+ process.exit(0);
324
+ });
325
+
326
+ process.on('SIGTERM', () => {
327
+ stopServer();
328
+ rl.close();
329
+ process.exit(0);
330
+ });
331
+ }
332
+
333
+ main().catch((err) => {
334
+ console.error(err);
335
+ process.exit(1);
336
+ });