namnam-skills 1.0.0 → 1.0.2

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.
@@ -285,6 +285,53 @@ When using Cursor, Windsurf, Cline, or other agents:
285
285
  - Reference previous work
286
286
  - Store important context
287
287
 
288
+ ### @conversation System
289
+
290
+ The project supports cross-conversation context via the `@conversation` feature.
291
+
292
+ #### Recognizing References
293
+ When users include `@conversation:<id>` in their messages:
294
+ ```
295
+ Pattern: @conversation[:\s]+([a-zA-Z0-9_-]+)
296
+ Examples:
297
+ - @conversation:abc123
298
+ - @conversation abc123
299
+ - Based on @conversation:auth01, implement...
300
+ ```
301
+
302
+ #### Loading Context
303
+ Load referenced conversation context:
304
+ ```bash
305
+ # Get formatted context
306
+ namnam conv context <id>
307
+
308
+ # Or read directly from
309
+ .claude/conversations/<full-id>/context.md
310
+ ```
311
+
312
+ #### Using Context
313
+ When conversation context is loaded:
314
+ 1. Treat it as authoritative prior decisions
315
+ 2. Build upon the context, don't contradict it
316
+ 3. Reference specific points when relevant
317
+ 4. Ask for clarification if context seems outdated
318
+
319
+ #### Saving Conversations
320
+ When a session contains important decisions, suggest saving:
321
+ ```bash
322
+ namnam conv save -t "Title" -s "Brief summary"
323
+ ```
324
+
325
+ #### Storage Location
326
+ ```
327
+ .claude/conversations/
328
+ ├── index.json # Conversation index
329
+ └── conv_xxx_yyy/ # Individual conversation
330
+ ├── meta.json # Metadata
331
+ ├── context.md # Loadable context
332
+ └── full.md # Full log (optional)
333
+ ```
334
+
288
335
  ---
289
336
 
290
337
  ## Error Handling
package/src/watcher.js ADDED
@@ -0,0 +1,356 @@
1
+ /**
2
+ * File Watcher for Live Indexing
3
+ *
4
+ * Watches for file changes and triggers incremental index updates.
5
+ * Uses Node.js native fs.watch with debouncing for efficiency.
6
+ */
7
+
8
+ import fs from 'fs-extra';
9
+ import path from 'path';
10
+ import { EventEmitter } from 'events';
11
+ import {
12
+ buildIndex,
13
+ hasIndex,
14
+ getIndexDir,
15
+ checkIndexChanges,
16
+ getIndexMeta,
17
+ updateIndexIncremental
18
+ } from './indexer.js';
19
+
20
+ // Constants
21
+ const DEBOUNCE_MS = 1000; // Wait 1 second after last change
22
+ const BATCH_INTERVAL_MS = 5000; // Process batch every 5 seconds max
23
+
24
+ // File patterns to watch
25
+ const WATCH_EXTENSIONS = new Set([
26
+ '.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs',
27
+ '.py', '.rb', '.go', '.rs', '.java', '.kt',
28
+ '.c', '.cpp', '.h', '.hpp', '.cs',
29
+ '.vue', '.svelte', '.astro',
30
+ '.json', '.yaml', '.yml', '.toml',
31
+ '.md', '.mdx',
32
+ '.css', '.scss', '.less',
33
+ '.html', '.xml',
34
+ '.sql', '.graphql', '.prisma'
35
+ ]);
36
+
37
+ // Directories to skip
38
+ const SKIP_DIRS = new Set([
39
+ 'node_modules', '.git', '.svn', '.hg',
40
+ 'dist', 'build', 'out', '.next', '.nuxt',
41
+ 'coverage', '.nyc_output',
42
+ '__pycache__', '.pytest_cache',
43
+ 'vendor', 'target',
44
+ '.claude', '.cursor', '.vscode'
45
+ ]);
46
+
47
+ /**
48
+ * IndexWatcher - Watches filesystem and triggers index updates
49
+ */
50
+ export class IndexWatcher extends EventEmitter {
51
+ constructor(cwd = process.cwd(), options = {}) {
52
+ super();
53
+ this.cwd = cwd;
54
+ this.options = {
55
+ debounceMs: options.debounceMs || DEBOUNCE_MS,
56
+ batchIntervalMs: options.batchIntervalMs || BATCH_INTERVAL_MS,
57
+ autoRebuild: options.autoRebuild !== false,
58
+ verbose: options.verbose || false,
59
+ ...options
60
+ };
61
+
62
+ this.watchers = new Map();
63
+ this.pendingChanges = new Map();
64
+ this.debounceTimer = null;
65
+ this.batchTimer = null;
66
+ this.isIndexing = false;
67
+ this.isRunning = false;
68
+ this.stats = {
69
+ filesChanged: 0,
70
+ indexUpdates: 0,
71
+ lastUpdate: null
72
+ };
73
+ }
74
+
75
+ /**
76
+ * Start watching the directory
77
+ */
78
+ async start() {
79
+ if (this.isRunning) {
80
+ this.log('Watcher already running');
81
+ return;
82
+ }
83
+
84
+ this.log('Starting file watcher...');
85
+ this.isRunning = true;
86
+
87
+ // Ensure index exists
88
+ if (!(await hasIndex(this.cwd))) {
89
+ this.log('No index found, building initial index...');
90
+ this.emit('indexing', { type: 'initial' });
91
+ await buildIndex(this.cwd, {
92
+ onProgress: (progress) => this.emit('progress', progress)
93
+ });
94
+ this.emit('indexed', { type: 'initial' });
95
+ }
96
+
97
+ // Start watching
98
+ await this.watchDirectory(this.cwd);
99
+
100
+ // Start batch processor
101
+ this.batchTimer = setInterval(() => {
102
+ this.processPendingChanges();
103
+ }, this.options.batchIntervalMs);
104
+
105
+ this.emit('started');
106
+ this.log(`Watching ${this.watchers.size} directories`);
107
+ }
108
+
109
+ /**
110
+ * Stop watching
111
+ */
112
+ stop() {
113
+ if (!this.isRunning) return;
114
+
115
+ this.log('Stopping file watcher...');
116
+ this.isRunning = false;
117
+
118
+ // Clear timers
119
+ if (this.debounceTimer) clearTimeout(this.debounceTimer);
120
+ if (this.batchTimer) clearInterval(this.batchTimer);
121
+
122
+ // Close all watchers
123
+ for (const [dir, watcher] of this.watchers) {
124
+ watcher.close();
125
+ }
126
+ this.watchers.clear();
127
+ this.pendingChanges.clear();
128
+
129
+ this.emit('stopped');
130
+ }
131
+
132
+ /**
133
+ * Watch a directory recursively
134
+ */
135
+ async watchDirectory(dir) {
136
+ try {
137
+ const items = await fs.readdir(dir, { withFileTypes: true });
138
+
139
+ for (const item of items) {
140
+ if (item.isDirectory() && !SKIP_DIRS.has(item.name) && !item.name.startsWith('.')) {
141
+ const subDir = path.join(dir, item.name);
142
+ await this.watchDirectory(subDir);
143
+ }
144
+ }
145
+
146
+ // Watch this directory
147
+ const watcher = fs.watch(dir, (eventType, filename) => {
148
+ if (filename) {
149
+ this.handleFileChange(eventType, path.join(dir, filename));
150
+ }
151
+ });
152
+
153
+ watcher.on('error', (err) => {
154
+ this.log(`Watcher error for ${dir}: ${err.message}`);
155
+ // Try to recover by removing and re-adding watcher
156
+ this.watchers.delete(dir);
157
+ });
158
+
159
+ this.watchers.set(dir, watcher);
160
+ } catch (err) {
161
+ this.log(`Error watching ${dir}: ${err.message}`);
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Handle a file change event
167
+ */
168
+ handleFileChange(eventType, filePath) {
169
+ const ext = path.extname(filePath).toLowerCase();
170
+ const relativePath = path.relative(this.cwd, filePath).replace(/\\/g, '/');
171
+
172
+ // Check if we should watch this file
173
+ if (!WATCH_EXTENSIONS.has(ext)) return;
174
+
175
+ // Skip if in ignored directory
176
+ const parts = relativePath.split('/');
177
+ if (parts.some(part => SKIP_DIRS.has(part))) return;
178
+
179
+ this.log(`File ${eventType}: ${relativePath}`);
180
+
181
+ // Add to pending changes
182
+ this.pendingChanges.set(relativePath, {
183
+ type: eventType,
184
+ path: relativePath,
185
+ fullPath: filePath,
186
+ timestamp: Date.now()
187
+ });
188
+
189
+ this.stats.filesChanged++;
190
+ this.emit('change', { type: eventType, path: relativePath });
191
+
192
+ // Debounce the index update
193
+ if (this.debounceTimer) clearTimeout(this.debounceTimer);
194
+ this.debounceTimer = setTimeout(() => {
195
+ this.processPendingChanges();
196
+ }, this.options.debounceMs);
197
+ }
198
+
199
+ /**
200
+ * Process all pending changes
201
+ */
202
+ async processPendingChanges() {
203
+ if (this.isIndexing || this.pendingChanges.size === 0) return;
204
+
205
+ const changes = Array.from(this.pendingChanges.values());
206
+ this.pendingChanges.clear();
207
+
208
+ if (this.options.autoRebuild) {
209
+ await this.updateIndex(changes);
210
+ } else {
211
+ this.emit('changes-pending', { changes });
212
+ }
213
+ }
214
+
215
+ /**
216
+ * Update the index with changes
217
+ */
218
+ async updateIndex(changes) {
219
+ if (this.isIndexing) return;
220
+
221
+ this.isIndexing = true;
222
+ this.emit('indexing', { type: 'incremental', changes });
223
+
224
+ try {
225
+ // Normalize changes to the format expected by updateIndexIncremental
226
+ const normalizedChanges = changes.map(change => ({
227
+ path: change.path,
228
+ fullPath: change.fullPath,
229
+ type: change.type === 'rename' ? 'add' : change.type // rename could be add or delete
230
+ }));
231
+
232
+ // Use incremental indexing for better performance
233
+ await updateIndexIncremental(normalizedChanges, this.cwd, {
234
+ onProgress: (progress) => this.emit('progress', progress)
235
+ });
236
+
237
+ this.stats.indexUpdates++;
238
+ this.stats.lastUpdate = new Date().toISOString();
239
+
240
+ this.emit('indexed', {
241
+ type: 'incremental',
242
+ changesProcessed: changes.length,
243
+ stats: this.stats
244
+ });
245
+
246
+ this.log(`Index updated (${changes.length} files changed)`);
247
+ } catch (err) {
248
+ this.log(`Index update failed: ${err.message}`);
249
+ this.emit('error', err);
250
+ } finally {
251
+ this.isIndexing = false;
252
+ }
253
+ }
254
+
255
+ /**
256
+ * Force a full index rebuild
257
+ */
258
+ async forceRebuild() {
259
+ this.pendingChanges.clear();
260
+ this.isIndexing = true;
261
+ this.emit('indexing', { type: 'full' });
262
+
263
+ try {
264
+ await buildIndex(this.cwd, {
265
+ onProgress: (progress) => this.emit('progress', progress)
266
+ });
267
+
268
+ this.stats.indexUpdates++;
269
+ this.stats.lastUpdate = new Date().toISOString();
270
+
271
+ this.emit('indexed', { type: 'full', stats: this.stats });
272
+ this.log('Full index rebuild complete');
273
+ } catch (err) {
274
+ this.emit('error', err);
275
+ throw err;
276
+ } finally {
277
+ this.isIndexing = false;
278
+ }
279
+ }
280
+
281
+ /**
282
+ * Get watcher status
283
+ */
284
+ getStatus() {
285
+ return {
286
+ running: this.isRunning,
287
+ indexing: this.isIndexing,
288
+ watchedDirectories: this.watchers.size,
289
+ pendingChanges: this.pendingChanges.size,
290
+ stats: this.stats
291
+ };
292
+ }
293
+
294
+ /**
295
+ * Log message if verbose mode
296
+ */
297
+ log(message) {
298
+ if (this.options.verbose) {
299
+ console.log(`[IndexWatcher] ${message}`);
300
+ }
301
+ }
302
+ }
303
+
304
+ /**
305
+ * Create and start a watcher daemon
306
+ */
307
+ export async function startWatcherDaemon(cwd = process.cwd(), options = {}) {
308
+ const watcher = new IndexWatcher(cwd, options);
309
+
310
+ // Set up event handlers for CLI output
311
+ if (options.verbose) {
312
+ watcher.on('started', () => console.log('File watcher started'));
313
+ watcher.on('stopped', () => console.log('File watcher stopped'));
314
+ watcher.on('change', ({ type, path }) => console.log(` ${type}: ${path}`));
315
+ watcher.on('indexing', ({ type }) => console.log(`Indexing (${type})...`));
316
+ watcher.on('indexed', ({ type, changesProcessed }) => {
317
+ console.log(`Index updated (${type}${changesProcessed ? `, ${changesProcessed} files` : ''})`);
318
+ });
319
+ watcher.on('error', (err) => console.error(`Error: ${err.message}`));
320
+ }
321
+
322
+ await watcher.start();
323
+ return watcher;
324
+ }
325
+
326
+ /**
327
+ * Watch status file for IPC with VS Code extension
328
+ */
329
+ const STATUS_FILE = '.claude/watcher-status.json';
330
+
331
+ export async function writeWatcherStatus(cwd, status) {
332
+ const statusPath = path.join(cwd, STATUS_FILE);
333
+ await fs.ensureDir(path.dirname(statusPath));
334
+ await fs.writeJson(statusPath, {
335
+ ...status,
336
+ pid: process.pid,
337
+ updatedAt: new Date().toISOString()
338
+ }, { spaces: 2 });
339
+ }
340
+
341
+ export async function readWatcherStatus(cwd) {
342
+ const statusPath = path.join(cwd, STATUS_FILE);
343
+ if (await fs.pathExists(statusPath)) {
344
+ return await fs.readJson(statusPath);
345
+ }
346
+ return null;
347
+ }
348
+
349
+ export async function clearWatcherStatus(cwd) {
350
+ const statusPath = path.join(cwd, STATUS_FILE);
351
+ if (await fs.pathExists(statusPath)) {
352
+ await fs.remove(statusPath);
353
+ }
354
+ }
355
+
356
+ export default IndexWatcher;
@@ -1,70 +0,0 @@
1
- # /code-review - Multi-Aspect Code Review
2
-
3
- > Comprehensive code review using parallel expert agents
4
-
5
- ## Usage
6
-
7
- ```
8
- /code-review
9
- /code-review src/auth
10
- /code-review --focus security
11
- ```
12
-
13
- ## Instructions
14
-
15
- When the user invokes `/code-review`:
16
-
17
- ### Step 1: Identify Target
18
-
19
- If no path provided, review recent changes:
20
- ```bash
21
- git diff --name-only HEAD~1
22
- ```
23
-
24
- ### Step 2: Spawn Review Agents
25
-
26
- Run these in parallel:
27
-
28
- | Agent | Focus |
29
- |-------|-------|
30
- | Architecture Reviewer | Design patterns, coupling |
31
- | Code Quality Reviewer | Readability, duplication |
32
- | Security Reviewer | Vulnerabilities, OWASP |
33
- | Performance Reviewer | Bottlenecks, optimization |
34
- | Testing Reviewer | Coverage, quality |
35
- | Documentation Reviewer | Comments, API docs |
36
-
37
- ### Step 3: Aggregate Results
38
-
39
- ```markdown
40
- ## Code Review Report
41
-
42
- ### Summary
43
- - **Files reviewed**: 12
44
- - **Issues found**: 8
45
- - **Severity**: 2 Critical, 3 High, 3 Medium
46
-
47
- ### Critical Issues 🔴
48
- | File:Line | Issue | Recommendation |
49
- |-----------|-------|----------------|
50
- | auth.ts:42 | SQL injection risk | Use parameterized query |
51
-
52
- ### High Priority 🟡
53
- | File:Line | Issue | Recommendation |
54
- |-----------|-------|----------------|
55
- | utils.ts:15 | No input validation | Add validation |
56
-
57
- ### Medium Priority 🟢
58
- | File:Line | Issue | Recommendation |
59
- |-----------|-------|----------------|
60
- | form.tsx:88 | Missing error handling | Add try-catch |
61
-
62
- ### Strengths ✨
63
- - Good separation of concerns
64
- - Consistent naming conventions
65
-
66
- ### Recommendations
67
- 1. Address critical security issues immediately
68
- 2. Add input validation to all user inputs
69
- 3. Increase test coverage to 80%
70
- ```
@@ -1,57 +0,0 @@
1
- # /git:commit - Smart Git Commit
2
-
3
- > Create intelligent git commits with conventional commit format
4
-
5
- ## Usage
6
-
7
- ```
8
- /git:commit
9
- /git:commit fix login validation
10
- ```
11
-
12
- ## Instructions
13
-
14
- When the user invokes `/git:commit`:
15
-
16
- 1. **Check git status**:
17
- ```bash
18
- git status --porcelain
19
- git diff --staged --stat
20
- ```
21
-
22
- 2. **If no staged changes**:
23
- - Show modified/untracked files
24
- - Ask what to stage
25
-
26
- 3. **Analyze changes**:
27
- - Parse diff to understand changes
28
- - Identify commit type: feat, fix, refactor, docs, test, chore
29
-
30
- 4. **Generate commit message**:
31
- - Follow conventional commits: `<type>(<scope>): <subject>`
32
- - Keep subject under 50 chars
33
- - Add body for complex changes
34
-
35
- 5. **Execute**:
36
- ```bash
37
- git commit -m "$(cat <<'EOF'
38
- <type>(<scope>): <subject>
39
-
40
- <body>
41
-
42
- Co-Authored-By: Claude <noreply@anthropic.com>
43
- EOF
44
- )"
45
- ```
46
-
47
- ## Commit Types
48
-
49
- | Type | When to use |
50
- |------|-------------|
51
- | `feat` | New feature |
52
- | `fix` | Bug fix |
53
- | `docs` | Documentation |
54
- | `style` | Formatting |
55
- | `refactor` | Code restructure |
56
- | `test` | Tests |
57
- | `chore` | Maintenance |
@@ -1,53 +0,0 @@
1
- # /git:push - Safe Git Push
2
-
3
- > Push commits to remote with safety checks
4
-
5
- ## Usage
6
-
7
- ```
8
- /git:push
9
- /git:push origin main
10
- ```
11
-
12
- ## Instructions
13
-
14
- When the user invokes `/git:push`:
15
-
16
- 1. **Pre-push checks**:
17
- ```bash
18
- git status
19
- git log origin/HEAD..HEAD --oneline
20
- ```
21
-
22
- 2. **Safety validations**:
23
- - Check if branch is protected
24
- - Warn if pushing to main/master
25
- - Check for uncommitted changes
26
-
27
- 3. **Execute push**:
28
- ```bash
29
- git push -u origin <branch>
30
- ```
31
-
32
- 4. **Post-push summary**:
33
- ```markdown
34
- ## Push Complete
35
-
36
- **Branch**: feature/auth → origin/feature/auth
37
- **Commits pushed**: 3
38
-
39
- ### Commits
40
- - abc123 feat(auth): add login
41
- - def456 fix(auth): validate email
42
- - ghi789 test(auth): add tests
43
-
44
- ### Next Steps
45
- - Create PR: `gh pr create`
46
- - Or use `/commit-push-pr` for full workflow
47
- ```
48
-
49
- ## Safety
50
-
51
- - Never force push without explicit request
52
- - Warn before pushing to protected branches
53
- - Show what will be pushed before confirming
@@ -1,48 +0,0 @@
1
- # /git:status - Enhanced Git Status
2
-
3
- > Intelligent git status with insights
4
-
5
- ## Usage
6
-
7
- ```
8
- /git:status
9
- ```
10
-
11
- ## Instructions
12
-
13
- When the user invokes `/git:status`:
14
-
15
- 1. **Get status**:
16
- ```bash
17
- git status
18
- git diff --stat
19
- ```
20
-
21
- 2. **Analyze and present**:
22
- ```markdown
23
- ## Git Status
24
-
25
- ### Branch
26
- **Current**: feature/auth
27
- **Tracking**: origin/feature/auth (2 ahead, 1 behind)
28
-
29
- ### Changes
30
-
31
- #### Staged (ready to commit)
32
- - ✅ src/auth/login.ts (+42, -15)
33
- - ✅ src/utils/validate.ts (+10, -2)
34
-
35
- #### Modified (not staged)
36
- - 📝 src/components/Form.tsx
37
- - 📝 src/hooks/useAuth.ts
38
-
39
- #### Untracked
40
- - ❓ src/new-file.ts
41
- - ❓ tests/auth.test.ts
42
-
43
- ### Suggestions
44
- - Run `git add .` to stage all changes
45
- - Run `/git:commit` to commit staged changes
46
- ```
47
-
48
- 3. **Provide actionable insights**