@tyroneross/navgator 0.1.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.
Files changed (84) hide show
  1. package/.claude-plugin/plugin.json +10 -0
  2. package/LICENSE +21 -0
  3. package/README.md +486 -0
  4. package/agents/architecture-advisor.md +109 -0
  5. package/commands/nav-check.md +64 -0
  6. package/commands/nav-connections.md +58 -0
  7. package/commands/nav-diagram.md +106 -0
  8. package/commands/nav-export.md +71 -0
  9. package/commands/nav-impact.md +58 -0
  10. package/commands/nav-scan.md +46 -0
  11. package/commands/nav-status.md +44 -0
  12. package/dist/cli/index.d.ts +7 -0
  13. package/dist/cli/index.d.ts.map +1 -0
  14. package/dist/cli/index.js +627 -0
  15. package/dist/cli/index.js.map +1 -0
  16. package/dist/config.d.ts +95 -0
  17. package/dist/config.d.ts.map +1 -0
  18. package/dist/config.js +262 -0
  19. package/dist/config.js.map +1 -0
  20. package/dist/diagram.d.ts +36 -0
  21. package/dist/diagram.d.ts.map +1 -0
  22. package/dist/diagram.js +333 -0
  23. package/dist/diagram.js.map +1 -0
  24. package/dist/index.d.ts +16 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +18 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/scanner.d.ts +57 -0
  29. package/dist/scanner.d.ts.map +1 -0
  30. package/dist/scanner.js +282 -0
  31. package/dist/scanner.js.map +1 -0
  32. package/dist/scanners/connections/ast-scanner.d.ts +26 -0
  33. package/dist/scanners/connections/ast-scanner.d.ts.map +1 -0
  34. package/dist/scanners/connections/ast-scanner.js +430 -0
  35. package/dist/scanners/connections/ast-scanner.js.map +1 -0
  36. package/dist/scanners/connections/service-calls.d.ts +14 -0
  37. package/dist/scanners/connections/service-calls.d.ts.map +1 -0
  38. package/dist/scanners/connections/service-calls.js +719 -0
  39. package/dist/scanners/connections/service-calls.js.map +1 -0
  40. package/dist/scanners/infrastructure/index.d.ts +27 -0
  41. package/dist/scanners/infrastructure/index.d.ts.map +1 -0
  42. package/dist/scanners/infrastructure/index.js +233 -0
  43. package/dist/scanners/infrastructure/index.js.map +1 -0
  44. package/dist/scanners/packages/npm.d.ts +18 -0
  45. package/dist/scanners/packages/npm.d.ts.map +1 -0
  46. package/dist/scanners/packages/npm.js +256 -0
  47. package/dist/scanners/packages/npm.js.map +1 -0
  48. package/dist/scanners/packages/pip.d.ts +14 -0
  49. package/dist/scanners/packages/pip.d.ts.map +1 -0
  50. package/dist/scanners/packages/pip.js +228 -0
  51. package/dist/scanners/packages/pip.js.map +1 -0
  52. package/dist/scanners/prompts/detector.d.ts +119 -0
  53. package/dist/scanners/prompts/detector.d.ts.map +1 -0
  54. package/dist/scanners/prompts/detector.js +617 -0
  55. package/dist/scanners/prompts/detector.js.map +1 -0
  56. package/dist/scanners/prompts/index.d.ts +51 -0
  57. package/dist/scanners/prompts/index.d.ts.map +1 -0
  58. package/dist/scanners/prompts/index.js +340 -0
  59. package/dist/scanners/prompts/index.js.map +1 -0
  60. package/dist/scanners/prompts/types.d.ts +127 -0
  61. package/dist/scanners/prompts/types.d.ts.map +1 -0
  62. package/dist/scanners/prompts/types.js +37 -0
  63. package/dist/scanners/prompts/types.js.map +1 -0
  64. package/dist/setup.d.ts +65 -0
  65. package/dist/setup.d.ts.map +1 -0
  66. package/dist/setup.js +261 -0
  67. package/dist/setup.js.map +1 -0
  68. package/dist/storage.d.ts +147 -0
  69. package/dist/storage.d.ts.map +1 -0
  70. package/dist/storage.js +931 -0
  71. package/dist/storage.js.map +1 -0
  72. package/dist/types.d.ts +296 -0
  73. package/dist/types.d.ts.map +1 -0
  74. package/dist/types.js +55 -0
  75. package/dist/types.js.map +1 -0
  76. package/dist/ui-server.d.ts +17 -0
  77. package/dist/ui-server.d.ts.map +1 -0
  78. package/dist/ui-server.js +815 -0
  79. package/dist/ui-server.js.map +1 -0
  80. package/hooks/hooks.json +57 -0
  81. package/package.json +80 -0
  82. package/scripts/ibr-ui-test.mjs +359 -0
  83. package/scripts/postinstall.cjs +35 -0
  84. package/skills/architecture-awareness/SKILL.md +141 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-server.js","sourceRoot":"","sources":["../src/ui-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ {
2
+ "hooks": {
3
+ "SessionStart": [
4
+ {
5
+ "matcher": "",
6
+ "hooks": [
7
+ {
8
+ "type": "prompt",
9
+ "prompt": "Check if NavGator architecture data exists and is fresh:\n1. Look for .claude/architecture/index.json\n2. If missing: 'This project hasn't been scanned. Run `navgator setup` to map the architecture.'\n3. If >24h old: 'Architecture data is stale. Consider running `navgator scan` to refresh.'\n4. If fresh: Note the component and connection counts for context.\n\nWhen architecture data exists, you should consult it BEFORE making changes to:\n- Database schemas or queries\n- API endpoints\n- External service integrations (Stripe, OpenAI, etc.)\n- Queue workers or job handlers\n- Shared utilities used across the codebase"
10
+ }
11
+ ]
12
+ }
13
+ ],
14
+ "PreToolUse": [
15
+ {
16
+ "matcher": "Edit|Write",
17
+ "hooks": [
18
+ {
19
+ "type": "prompt",
20
+ "prompt": "Before modifying this file, check if it involves architecture-critical code:\n\n1. **Database/ORM files** (prisma, drizzle, sequelize, models/): Run `navgator impact <table-name>` to see affected APIs\n2. **API routes** (api/, routes/, controllers/): Run `navgator connections <endpoint>` to see frontend callers\n3. **External services** (stripe, openai, twilio, sendgrid): Run `navgator impact <service>` to see all usage locations\n4. **Queue/worker files** (workers/, jobs/, queues/): Check what triggers these and what they affect\n5. **Shared utilities** (lib/, utils/, helpers/): These often have wide impact\n\nIf the file matches any of these patterns and NavGator data exists, briefly note what else might need updating."
21
+ }
22
+ ]
23
+ }
24
+ ],
25
+ "PostToolUse": [
26
+ {
27
+ "matcher": "Bash",
28
+ "hooks": [
29
+ {
30
+ "type": "prompt",
31
+ "prompt": "Check if this command affects architecture:\n\n1. **Package install/remove** (npm install, yarn add, pip install, cargo add, go get):\n → Run `navgator scan --quick` to update package tracking\n\n2. **Database migrations** (prisma migrate, drizzle push, alembic, knex migrate):\n → Run `navgator scan` to update schema connections\n\n3. **New service setup** (stripe, supabase, firebase init):\n → Run `navgator scan` to detect new service connections\n\nIf the command matches, remind about updating architecture data."
32
+ }
33
+ ]
34
+ },
35
+ {
36
+ "matcher": "Edit|Write",
37
+ "hooks": [
38
+ {
39
+ "type": "prompt",
40
+ "prompt": "If you just modified an architecture-critical file (API route, database model, service integration, queue handler), note that the architecture connections may have changed. After completing the current task, consider running `navgator scan` to update the connection map."
41
+ }
42
+ ]
43
+ }
44
+ ],
45
+ "Stop": [
46
+ {
47
+ "matcher": "",
48
+ "hooks": [
49
+ {
50
+ "type": "prompt",
51
+ "prompt": "Before finishing, if you made significant architectural changes during this session (new APIs, database changes, service integrations, refactored connections), remind the user: 'You may want to run `navgator scan` to update the architecture map with these changes.'"
52
+ }
53
+ ]
54
+ }
55
+ ]
56
+ }
57
+ }
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "@tyroneross/navgator",
3
+ "version": "0.1.0",
4
+ "description": "Architecture connection tracker for Claude Code - know your stack before you change it",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "navgator": "./dist/cli/index.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ },
16
+ "./scanner": {
17
+ "types": "./dist/scanner.d.ts",
18
+ "import": "./dist/scanner.js"
19
+ },
20
+ "./setup": {
21
+ "types": "./dist/setup.d.ts",
22
+ "import": "./dist/setup.js"
23
+ }
24
+ },
25
+ "files": [
26
+ "dist",
27
+ "scripts",
28
+ "commands",
29
+ "skills",
30
+ "hooks",
31
+ "agents",
32
+ ".claude-plugin",
33
+ "README.md"
34
+ ],
35
+ "scripts": {
36
+ "build": "tsc && npm run build:fixshebang",
37
+ "build:fixshebang": "node -e \"const fs=require('fs');const f='dist/cli/index.js';let c=fs.readFileSync(f,'utf8');if(!c.startsWith('#!')){c='#!/usr/bin/env node\\n'+c;fs.writeFileSync(f,c);}\"",
38
+ "dev": "tsc --watch",
39
+ "start": "node dist/cli/index.js",
40
+ "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
41
+ "lint": "eslint src/**/*.ts",
42
+ "clean": "rm -rf dist",
43
+ "prepublishOnly": "npm run clean && npm run build",
44
+ "postinstall": "node scripts/postinstall.cjs",
45
+ "link:local": "npm run build && npm link"
46
+ },
47
+ "keywords": [
48
+ "claude-code",
49
+ "architecture",
50
+ "dependencies",
51
+ "devtools",
52
+ "cli",
53
+ "connections",
54
+ "impact-analysis"
55
+ ],
56
+ "author": "Tyrone Ross",
57
+ "license": "MIT",
58
+ "repository": {
59
+ "type": "git",
60
+ "url": "https://github.com/tyroneross/navgator"
61
+ },
62
+ "homepage": "https://github.com/tyroneross/navgator#readme",
63
+ "bugs": {
64
+ "url": "https://github.com/tyroneross/navgator/issues"
65
+ },
66
+ "engines": {
67
+ "node": ">=18.0.0"
68
+ },
69
+ "dependencies": {
70
+ "commander": "^12.0.0",
71
+ "glob": "^10.3.10"
72
+ },
73
+ "optionalDependencies": {
74
+ "ts-morph": "^22.0.0"
75
+ },
76
+ "devDependencies": {
77
+ "@types/node": "^20.10.0",
78
+ "typescript": "^5.3.0"
79
+ }
80
+ }
@@ -0,0 +1,359 @@
1
+ /**
2
+ * NavGator UI Functional Test Script
3
+ * Uses InterfaceBuiltRight (IBR) to verify all selectable buttons,
4
+ * navigation, and interactive elements across the Next.js dashboard.
5
+ *
6
+ * Prerequisites:
7
+ * - NavGator web dashboard running: cd web && npm run dev
8
+ * - IBR installed: npm install @tyroneross/interface-built-right
9
+ *
10
+ * Usage:
11
+ * node scripts/ibr-ui-test.mjs [--base-url http://localhost:3000]
12
+ */
13
+
14
+ import { InterfaceBuiltRight } from '@tyroneross/interface-built-right';
15
+
16
+ const BASE_URL = process.argv.includes('--base-url')
17
+ ? process.argv[process.argv.indexOf('--base-url') + 1]
18
+ : 'http://localhost:3000';
19
+
20
+ const ibr = new InterfaceBuiltRight({
21
+ baseUrl: BASE_URL,
22
+ outputDir: './.ibr',
23
+ fullPage: true,
24
+ timeout: 15000,
25
+ });
26
+
27
+ const results = [];
28
+ let session;
29
+
30
+ function log(status, msg) {
31
+ const icon = status === 'PASS' ? '\u2713' : status === 'FAIL' ? '\u2717' : '\u2022';
32
+ console.log(` ${icon} ${msg}`);
33
+ results.push({ status, msg });
34
+ }
35
+
36
+ async function test(name, fn) {
37
+ try {
38
+ await fn();
39
+ log('PASS', name);
40
+ } catch (err) {
41
+ log('FAIL', `${name} — ${err.message}`);
42
+ }
43
+ }
44
+
45
+ // ==========================================================================
46
+ // 1. INITIAL LOAD & SEMANTIC ANALYSIS
47
+ // ==========================================================================
48
+
49
+ console.log('\n--- NavGator IBR UI Test ---\n');
50
+ console.log(`Target: ${BASE_URL}\n`);
51
+
52
+ console.log('[1] Page Load & Semantic Understanding');
53
+
54
+ session = await ibr.start('/', { viewport: 'desktop' });
55
+ const semantic = await session.understand();
56
+
57
+ test('Page loads with title', async () => {
58
+ const title = await session.page.title();
59
+ if (!title) throw new Error('No page title');
60
+ });
61
+
62
+ test('Header renders with NavGator branding', async () => {
63
+ await session.page.waitForSelector('header', { timeout: 5000 });
64
+ });
65
+
66
+ test('Sidebar renders with navigation items', async () => {
67
+ await session.page.waitForSelector('aside nav', { timeout: 5000 });
68
+ });
69
+
70
+ // ==========================================================================
71
+ // 2. SIDEBAR NAVIGATION — All 7 views
72
+ // ==========================================================================
73
+
74
+ console.log('\n[2] Sidebar Navigation (7 views)');
75
+
76
+ const sidebarViews = [
77
+ { label: 'Overview', expectText: 'Architecture Status' },
78
+ { label: 'Components', expectText: 'Components' },
79
+ { label: 'Connections', expectText: 'Connections' },
80
+ { label: 'Impact', expectText: 'Impact' },
81
+ { label: 'Diagram', expectText: 'Diagram' },
82
+ { label: 'LLM Tracking', expectText: 'LLM' },
83
+ { label: 'Settings', expectText: 'Settings' },
84
+ ];
85
+
86
+ for (const view of sidebarViews) {
87
+ await test(`Navigate to "${view.label}" view`, async () => {
88
+ // Click sidebar button by text
89
+ const btn = await session.page.locator(`aside button:has-text("${view.label}")`).first();
90
+ await btn.click();
91
+ await session.page.waitForTimeout(500);
92
+
93
+ // Verify view rendered (check main content area has expected text)
94
+ const main = await session.page.locator('main').textContent();
95
+ if (!main.includes(view.expectText)) {
96
+ throw new Error(`Expected "${view.expectText}" in main content`);
97
+ }
98
+ });
99
+ }
100
+
101
+ // ==========================================================================
102
+ // 3. HEADER ELEMENTS
103
+ // ==========================================================================
104
+
105
+ console.log('\n[3] Header Interactive Elements');
106
+
107
+ await test('Search input is present and focusable', async () => {
108
+ const input = session.page.locator('header input[placeholder*="Search"]');
109
+ if (await input.count() === 0) throw new Error('Search input not found');
110
+ await input.focus();
111
+ });
112
+
113
+ await test('Scan button is present and clickable', async () => {
114
+ const scanBtn = session.page.locator('header button:has-text("Scan")');
115
+ if (await scanBtn.count() === 0) throw new Error('Scan button not found');
116
+ // Don't actually trigger scan, just verify it exists and is enabled
117
+ const disabled = await scanBtn.isDisabled();
118
+ if (disabled) throw new Error('Scan button is disabled');
119
+ });
120
+
121
+ // ==========================================================================
122
+ // 4. OVERVIEW — Stat cards & quick actions
123
+ // ==========================================================================
124
+
125
+ console.log('\n[4] Overview — Stat Cards & Quick Actions');
126
+
127
+ // Navigate back to overview
128
+ await session.page.locator('aside button:has-text("Overview")').first().click();
129
+ await session.page.waitForTimeout(500);
130
+
131
+ await test('Stat cards are clickable (Components card)', async () => {
132
+ const card = session.page.locator('main button:has-text("Components")').first();
133
+ if (await card.count() === 0) throw new Error('Components stat card not found');
134
+ await card.click();
135
+ await session.page.waitForTimeout(300);
136
+ // Should navigate to components view
137
+ const main = await session.page.locator('main').textContent();
138
+ if (!main.includes('Components')) throw new Error('Did not navigate to Components');
139
+ });
140
+
141
+ // Go back to overview
142
+ await session.page.locator('aside button:has-text("Overview")').first().click();
143
+ await session.page.waitForTimeout(500);
144
+
145
+ await test('Quick Action: "View Diagram" navigates to diagram', async () => {
146
+ const btn = session.page.locator('main button:has-text("View Diagram")');
147
+ if (await btn.count() === 0) throw new Error('View Diagram action not found');
148
+ await btn.click();
149
+ await session.page.waitForTimeout(300);
150
+ const main = await session.page.locator('main').textContent();
151
+ if (!main.includes('Diagram')) throw new Error('Did not navigate to Diagram');
152
+ });
153
+
154
+ // Go back to overview
155
+ await session.page.locator('aside button:has-text("Overview")').first().click();
156
+ await session.page.waitForTimeout(500);
157
+
158
+ await test('Quick Action: "Impact Analysis" navigates to impact', async () => {
159
+ const btn = session.page.locator('main button:has-text("Impact Analysis")');
160
+ if (await btn.count() === 0) throw new Error('Impact Analysis action not found');
161
+ await btn.click();
162
+ await session.page.waitForTimeout(300);
163
+ });
164
+
165
+ await test('"View all" link in Components by Type card', async () => {
166
+ await session.page.locator('aside button:has-text("Overview")').first().click();
167
+ await session.page.waitForTimeout(500);
168
+ const viewAll = session.page.locator('main button:has-text("View all"), main a:has-text("View all")').first();
169
+ if (await viewAll.count() > 0) {
170
+ await viewAll.click();
171
+ await session.page.waitForTimeout(300);
172
+ }
173
+ // Acceptable if no data present — just check it doesn't crash
174
+ });
175
+
176
+ // ==========================================================================
177
+ // 5. SETTINGS — Tabs, switches, selects, buttons
178
+ // ==========================================================================
179
+
180
+ console.log('\n[5] Settings Panel — Tabs, Switches, Selects, Buttons');
181
+
182
+ await session.page.locator('aside button:has-text("Settings")').first().click();
183
+ await session.page.waitForTimeout(500);
184
+
185
+ const settingsTabs = ['Scanning', 'Detection', 'Notifications', 'Display'];
186
+
187
+ for (const tab of settingsTabs) {
188
+ await test(`Settings tab: "${tab}" is clickable`, async () => {
189
+ const tabBtn = session.page.locator(`button[role="tab"]:has-text("${tab}"), [data-value="${tab.toLowerCase()}"]`).first();
190
+ // Fallback: find by text in tabs area
191
+ const fallback = session.page.locator(`button:has-text("${tab}")`).first();
192
+ const target = (await tabBtn.count() > 0) ? tabBtn : fallback;
193
+ await target.click();
194
+ await session.page.waitForTimeout(300);
195
+ });
196
+ }
197
+
198
+ await test('Save Changes button is clickable', async () => {
199
+ const saveBtn = session.page.locator('button:has-text("Save")').first();
200
+ if (await saveBtn.count() === 0) throw new Error('Save button not found');
201
+ await saveBtn.click();
202
+ await session.page.waitForTimeout(500);
203
+ // Check for "Saved" feedback
204
+ const text = await session.page.locator('button:has-text("Saved")').count();
205
+ if (text === 0) {
206
+ // Also accept if button still says "Save Changes" (no API connected)
207
+ }
208
+ });
209
+
210
+ await test('Reset button is clickable', async () => {
211
+ const resetBtn = session.page.locator('button:has-text("Reset")').first();
212
+ if (await resetBtn.count() === 0) throw new Error('Reset button not found');
213
+ await resetBtn.click();
214
+ });
215
+
216
+ await test('Switch toggles respond to click', async () => {
217
+ // Click the Scanning tab first
218
+ await session.page.locator('button:has-text("Scanning")').first().click();
219
+ await session.page.waitForTimeout(300);
220
+
221
+ const switches = session.page.locator('button[role="switch"]');
222
+ const count = await switches.count();
223
+ if (count === 0) throw new Error('No switch toggles found');
224
+
225
+ // Toggle the first switch
226
+ const first = switches.first();
227
+ const before = await first.getAttribute('data-state');
228
+ await first.click();
229
+ await session.page.waitForTimeout(200);
230
+ const after = await first.getAttribute('data-state');
231
+ if (before === after) throw new Error('Switch did not toggle');
232
+ // Toggle back
233
+ await first.click();
234
+ });
235
+
236
+ await test('Select dropdowns open and have options', async () => {
237
+ const triggers = session.page.locator('button[role="combobox"]');
238
+ const count = await triggers.count();
239
+ if (count === 0) throw new Error('No select dropdowns found');
240
+
241
+ // Open first select
242
+ await triggers.first().click();
243
+ await session.page.waitForTimeout(300);
244
+
245
+ const options = session.page.locator('[role="option"]');
246
+ const optCount = await options.count();
247
+ if (optCount === 0) throw new Error('Select opened but no options found');
248
+
249
+ // Close by pressing Escape
250
+ await session.page.keyboard.press('Escape');
251
+ });
252
+
253
+ // ==========================================================================
254
+ // 6. HELP BUTTON (non-functional check)
255
+ // ==========================================================================
256
+
257
+ console.log('\n[6] Non-Functional Element Check');
258
+
259
+ await test('Help button exists but has no navigation action', async () => {
260
+ const helpBtn = session.page.locator('aside button:has-text("Help")');
261
+ if (await helpBtn.count() === 0) throw new Error('Help button not found');
262
+ // This button has no onClick handler — it's non-functional
263
+ // IBR flags this as a potential Calm Precision violation (Affordance Theory)
264
+ });
265
+
266
+ // ==========================================================================
267
+ // 7. INTERACTIVITY TEST (IBR built-in)
268
+ // ==========================================================================
269
+
270
+ console.log('\n[7] IBR Interactivity Audit');
271
+
272
+ // Navigate to overview for broadest element coverage
273
+ await session.page.locator('aside button:has-text("Overview")').first().click();
274
+ await session.page.waitForTimeout(500);
275
+
276
+ await test('IBR interactivity test passes', async () => {
277
+ const interactivity = await session.testInteractivity();
278
+ const issues = interactivity.issues || [];
279
+ const critical = issues.filter(i => i.severity === 'critical' || i.severity === 'error');
280
+ if (critical.length > 0) {
281
+ throw new Error(`${critical.length} critical interactivity issues: ${critical.map(i => i.message).join('; ')}`);
282
+ }
283
+ console.log(` Found ${interactivity.buttons?.length || 0} buttons, ${interactivity.links?.length || 0} links, ${interactivity.forms?.length || 0} forms`);
284
+ if (issues.length > 0) {
285
+ console.log(` Warnings: ${issues.length}`);
286
+ issues.slice(0, 3).forEach(i => console.log(` - ${i.message}`));
287
+ }
288
+ });
289
+
290
+ // ==========================================================================
291
+ // 8. PERFORMANCE CHECK (IBR built-in)
292
+ // ==========================================================================
293
+
294
+ console.log('\n[8] IBR Performance Metrics');
295
+
296
+ await test('Web Vitals within acceptable range', async () => {
297
+ const perf = await session.measurePerformance();
298
+ const ratings = perf.ratings || {};
299
+ console.log(` LCP: ${ratings.LCP?.value || 'N/A'}ms (${ratings.LCP?.rating || '?'})`);
300
+ console.log(` CLS: ${ratings.CLS?.value || 'N/A'} (${ratings.CLS?.rating || '?'})`);
301
+ console.log(` TBT: ${ratings.TBT?.value || 'N/A'}ms (${ratings.TBT?.rating || '?'})`);
302
+
303
+ if (ratings.LCP?.rating === 'poor') {
304
+ throw new Error(`LCP is poor: ${ratings.LCP.value}ms`);
305
+ }
306
+ });
307
+
308
+ // ==========================================================================
309
+ // 9. VISUAL BASELINE CAPTURE
310
+ // ==========================================================================
311
+
312
+ console.log('\n[9] Visual Baseline Capture');
313
+
314
+ const viewsToCapture = ['/', '/?view=components', '/?view=settings'];
315
+ // Capture baselines by navigating sidebar
316
+ const viewMap = [
317
+ { label: 'Overview', name: 'overview' },
318
+ { label: 'Components', name: 'components' },
319
+ { label: 'Settings', name: 'settings' },
320
+ ];
321
+
322
+ for (const view of viewMap) {
323
+ await test(`Capture baseline: ${view.name}`, async () => {
324
+ await session.page.locator(`aside button:has-text("${view.label}")`).first().click();
325
+ await session.page.waitForTimeout(500);
326
+ await session.screenshot(`.ibr/navgator-${view.name}-baseline.png`);
327
+ });
328
+ }
329
+
330
+ // ==========================================================================
331
+ // SUMMARY
332
+ // ==========================================================================
333
+
334
+ await session.close();
335
+
336
+ console.log('\n========================================');
337
+ console.log('TEST SUMMARY');
338
+ console.log('========================================\n');
339
+
340
+ const passed = results.filter(r => r.status === 'PASS').length;
341
+ const failed = results.filter(r => r.status === 'FAIL').length;
342
+ const total = results.length;
343
+
344
+ console.log(` Total: ${total}`);
345
+ console.log(` Passed: ${passed}`);
346
+ console.log(` Failed: ${failed}`);
347
+ console.log();
348
+
349
+ if (failed > 0) {
350
+ console.log(' FAILURES:');
351
+ results.filter(r => r.status === 'FAIL').forEach(r => {
352
+ console.log(` \u2717 ${r.msg}`);
353
+ });
354
+ console.log();
355
+ process.exit(1);
356
+ } else {
357
+ console.log(' All tests passed.\n');
358
+ process.exit(0);
359
+ }
@@ -0,0 +1,35 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const os = require('os');
4
+
5
+ const pluginDir = path.join(os.homedir(), '.claude', 'plugins');
6
+ const linkPath = path.join(pluginDir, 'navgator');
7
+ const packageRoot = path.resolve(__dirname, '..');
8
+
9
+ // Only link if .claude directory exists (user has Claude Code)
10
+ if (fs.existsSync(path.join(os.homedir(), '.claude'))) {
11
+ fs.mkdirSync(pluginDir, { recursive: true });
12
+
13
+ // Remove existing link if stale
14
+ try {
15
+ const existing = fs.readlinkSync(linkPath);
16
+ if (existing !== packageRoot) fs.unlinkSync(linkPath);
17
+ } catch {}
18
+
19
+ if (!fs.existsSync(linkPath)) {
20
+ try {
21
+ fs.symlinkSync(packageRoot, linkPath, 'dir');
22
+ console.log('\n\u{1F40A} NavGator plugin linked to Claude Code');
23
+ console.log(` ${linkPath} -> ${packageRoot}\n`);
24
+ } catch (err) {
25
+ console.log('\n\u{1F40A} NavGator installed but could not auto-link plugin.');
26
+ console.log(' Link manually:');
27
+ console.log(` ln -s ${packageRoot} ${linkPath}\n`);
28
+ }
29
+ } else {
30
+ console.log('\n\u{1F40A} NavGator plugin already linked. Run: navgator setup\n');
31
+ }
32
+ } else {
33
+ console.log('\n\u{1F40A} NavGator installed! Run: navgator setup');
34
+ console.log(' (Claude Code not detected - plugin not auto-linked)\n');
35
+ }
@@ -0,0 +1,141 @@
1
+ ---
2
+ name: Architecture Awareness
3
+ description: Use this skill BEFORE making architectural changes. Triggers on "what packages", "what framework", "dependencies", "tech stack", "what version", "upgrade", "update packages", "add library", "install", "architecture", "what uses", "what calls", "impact of changing", database changes, API modifications, service integrations, or refactoring discussions.
4
+ version: 1.0.0
5
+ ---
6
+
7
+ # Architecture Awareness Workflow
8
+
9
+ **Core principle:** Know your stack before you change it.
10
+
11
+ ## CRITICAL: When to Check NavGator
12
+
13
+ ### ALWAYS check NavGator impact BEFORE modifying:
14
+
15
+ 1. **Database schemas/models**
16
+ ```bash
17
+ navgator impact "users-table" # See which APIs touch this table
18
+ ```
19
+
20
+ 2. **API endpoints**
21
+ ```bash
22
+ navgator connections "api-endpoint" # See frontend components that call it
23
+ ```
24
+
25
+ 3. **External service integrations** (Stripe, OpenAI, Twilio, etc.)
26
+ ```bash
27
+ navgator impact "Stripe" # See all files using this service
28
+ ```
29
+
30
+ 4. **Queue workers/job handlers**
31
+ ```bash
32
+ navgator connections "bullmq" # See what triggers and is triggered by queues
33
+ ```
34
+
35
+ 5. **Shared utilities** (lib/, utils/, helpers/)
36
+ ```bash
37
+ navgator impact "utility-name" # These often have wide impact
38
+ ```
39
+
40
+ ## Quick Reference
41
+
42
+ | Situation | Command | Why |
43
+ |-----------|---------|-----|
44
+ | Before changing DB schema | `navgator impact <table>` | Find all APIs that need updating |
45
+ | Before modifying API | `navgator connections <endpoint>` | Find frontend code to update |
46
+ | Before touching service code | `navgator impact <service>` | Find all usage locations |
47
+ | After npm install | `navgator scan --quick` | Update package tracking |
48
+ | After migrations | `navgator scan` | Update schema connections |
49
+ | Starting new session | `navgator status` | Check if data is fresh |
50
+
51
+ ## Workflow Examples
52
+
53
+ ### Example 1: Changing a Database Table
54
+
55
+ **Before:**
56
+ ```bash
57
+ navgator impact "users"
58
+ ```
59
+ This shows:
60
+ - Which API endpoints read/write this table
61
+ - Which services depend on user data
62
+ - File:line locations to update
63
+
64
+ **Then:** Make your changes knowing what else needs updating.
65
+
66
+ **After:**
67
+ ```bash
68
+ navgator scan
69
+ ```
70
+
71
+ ### Example 2: Adding a New Service Integration
72
+
73
+ ```bash
74
+ # Check current architecture
75
+ navgator status
76
+
77
+ # Add the package
78
+ npm install stripe
79
+
80
+ # Update architecture
81
+ navgator scan --quick
82
+
83
+ # Start implementing - NavGator now tracks your Stripe calls
84
+ ```
85
+
86
+ ### Example 3: Refactoring an API Endpoint
87
+
88
+ ```bash
89
+ # Before refactoring
90
+ navgator connections "api/users"
91
+
92
+ # Shows:
93
+ # - Frontend components calling this endpoint
94
+ # - Services that depend on it
95
+ # - Exact file:line references
96
+
97
+ # Now you know what else needs updating when you change the API contract
98
+ ```
99
+
100
+ ## Session Start Checklist
101
+
102
+ When starting work on a project:
103
+
104
+ 1. Check if architecture data exists: `navgator status`
105
+ 2. If missing or stale (>24h): `navgator setup` or `navgator scan`
106
+ 3. Before any architectural change: `navgator impact <component>`
107
+
108
+ ## What NavGator Tracks
109
+
110
+ **Components:**
111
+ - Packages (npm, pip, cargo, go, gem, composer)
112
+ - Frameworks (Next.js, React, Django, FastAPI)
113
+ - Databases (PostgreSQL, MongoDB, Redis, Supabase)
114
+ - Queues (BullMQ, Celery, SQS)
115
+ - Infrastructure (Railway, Vercel, Docker)
116
+ - External Services (Stripe, OpenAI, Twilio)
117
+
118
+ **Connections:**
119
+ - API → Database (which endpoints touch which tables)
120
+ - Frontend → API (which components call which endpoints)
121
+ - Queue → Handler (which jobs trigger which code)
122
+ - Service calls (where external APIs are used, with file:line)
123
+
124
+ ## Commands
125
+
126
+ | Command | Use When |
127
+ |---------|----------|
128
+ | `navgator setup` | First time scanning a project |
129
+ | `navgator scan` | Refresh after changes |
130
+ | `navgator scan --quick` | After package install |
131
+ | `navgator status` | Check scan freshness |
132
+ | `navgator impact <X>` | Before modifying component X |
133
+ | `navgator connections <X>` | Understanding how X is connected |
134
+ | `navgator diagram` | Generate visual architecture |
135
+ | `navgator ui` | Launch visual dashboard |
136
+
137
+ ## Key Principle
138
+
139
+ **Don't modify architecture-critical code without checking impact first.**
140
+
141
+ The few seconds to run `navgator impact` can save hours of debugging missed updates.