@tyroneross/navgator 0.1.0 → 0.2.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 (62) hide show
  1. package/README.md +15 -9
  2. package/dist/cli/index.js +249 -10
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/diagram.d.ts.map +1 -1
  5. package/dist/diagram.js +33 -0
  6. package/dist/diagram.js.map +1 -1
  7. package/dist/scanner.d.ts +2 -0
  8. package/dist/scanner.d.ts.map +1 -1
  9. package/dist/scanner.js +131 -12
  10. package/dist/scanner.js.map +1 -1
  11. package/dist/scanners/connections/ast-scanner.d.ts.map +1 -1
  12. package/dist/scanners/connections/ast-scanner.js +0 -3
  13. package/dist/scanners/connections/ast-scanner.js.map +1 -1
  14. package/dist/scanners/connections/llm-call-tracer.d.ts +83 -0
  15. package/dist/scanners/connections/llm-call-tracer.d.ts.map +1 -0
  16. package/dist/scanners/connections/llm-call-tracer.js +801 -0
  17. package/dist/scanners/connections/llm-call-tracer.js.map +1 -0
  18. package/dist/scanners/connections/service-calls.d.ts.map +1 -1
  19. package/dist/scanners/connections/service-calls.js +44 -47
  20. package/dist/scanners/connections/service-calls.js.map +1 -1
  21. package/dist/scanners/infrastructure/index.d.ts.map +1 -1
  22. package/dist/scanners/infrastructure/index.js +34 -4
  23. package/dist/scanners/infrastructure/index.js.map +1 -1
  24. package/dist/scanners/packages/swift.d.ts +14 -0
  25. package/dist/scanners/packages/swift.d.ts.map +1 -0
  26. package/dist/scanners/packages/swift.js +320 -0
  27. package/dist/scanners/packages/swift.js.map +1 -0
  28. package/dist/scanners/prompts/detector.d.ts +16 -0
  29. package/dist/scanners/prompts/detector.d.ts.map +1 -1
  30. package/dist/scanners/prompts/detector.js +90 -1
  31. package/dist/scanners/prompts/detector.js.map +1 -1
  32. package/dist/scanners/prompts/types.d.ts +4 -0
  33. package/dist/scanners/prompts/types.d.ts.map +1 -1
  34. package/dist/scanners/prompts/types.js.map +1 -1
  35. package/dist/scanners/swift/code-scanner.d.ts +14 -0
  36. package/dist/scanners/swift/code-scanner.d.ts.map +1 -0
  37. package/dist/scanners/swift/code-scanner.js +803 -0
  38. package/dist/scanners/swift/code-scanner.js.map +1 -0
  39. package/dist/storage.d.ts +2 -2
  40. package/dist/storage.d.ts.map +1 -1
  41. package/dist/storage.js +41 -2
  42. package/dist/storage.js.map +1 -1
  43. package/dist/types.d.ts +26 -2
  44. package/dist/types.d.ts.map +1 -1
  45. package/dist/types.js.map +1 -1
  46. package/dist/ui-server.d.ts +7 -7
  47. package/dist/ui-server.d.ts.map +1 -1
  48. package/dist/ui-server.js +80 -792
  49. package/dist/ui-server.js.map +1 -1
  50. package/package.json +15 -10
  51. package/web/public/apple-icon.png +0 -0
  52. package/web/public/icon-dark-32x32.png +0 -0
  53. package/web/public/icon-light-32x32.png +0 -0
  54. package/web/public/icon.svg +26 -0
  55. package/web/public/navgator-logo.png +0 -0
  56. package/web/public/placeholder-logo.png +0 -0
  57. package/web/public/placeholder-logo.svg +1 -0
  58. package/web/public/placeholder-user.jpg +0 -0
  59. package/web/public/placeholder.jpg +0 -0
  60. package/web/public/placeholder.svg +1 -0
  61. package/scripts/ibr-ui-test.mjs +0 -359
  62. package/scripts/postinstall.cjs +0 -35
@@ -1 +1 @@
1
- {"version":3,"file":"ui-server.js","sourceRoot":"","sources":["../src/ui-server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC3F,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,YAAY,GAAG,IAAI,CAAC;AAE1B;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAInC;IACC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,YAAY,CAAC;IAC1C,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACzD,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAE3B,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QAClD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,oBAAoB,IAAI,EAAE,CAAC,CAAC;QAEhE,eAAe;QACf,GAAG,CAAC,SAAS,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;QAClD,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,cAAc,CAAC,CAAC;QAC9D,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,cAAc,CAAC,CAAC;QAE9D,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC7B,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACnB,GAAG,CAAC,GAAG,EAAE,CAAC;YACV,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,kDAAkD;YAClD,IAAI,GAAG,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;gBACnC,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;gBACnD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,EAAE,KAAK,EAAE,mCAAmC,EAAE,CAAC,CAAC,CAAC;gBACjF,OAAO;YACT,CAAC;YAED,IAAI,GAAG,CAAC,QAAQ,KAAK,iBAAiB,EAAE,CAAC;gBACvC,MAAM,UAAU,GAAG,MAAM,iBAAiB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;gBAChE,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;gBACpC,OAAO;YACT,CAAC;YAED,IAAI,GAAG,CAAC,QAAQ,KAAK,kBAAkB,EAAE,CAAC;gBACxC,MAAM,WAAW,GAAG,MAAM,kBAAkB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;gBAClE,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;gBACrC,OAAO;YACT,CAAC;YAED,IAAI,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;gBAClC,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;gBACnD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;gBAC3D,OAAO;YACT,CAAC;YAED,uBAAuB;YACvB,IAAI,GAAG,CAAC,QAAQ,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;gBAC3D,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;gBACpD,GAAG,CAAC,GAAG,CAAC,qBAAqB,CAAC,WAAW,CAAC,CAAC,CAAC;gBAC5C,OAAO;YACT,CAAC;YAED,MAAM;YACN,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,CAAC;YACrD,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACvB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;YAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;QACpD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;YACvB,OAAO,CAAC;gBACN,IAAI;gBACJ,KAAK,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE;aAC5B,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,SAAS,qBAAqB,CAAC,WAAmB;IAChD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iCA4PwB,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA+dpC,CAAC;AACT,CAAC"}
1
+ {"version":3,"file":"ui-server.js","sourceRoot":"","sources":["../src/ui-server.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,QAInC;IACC,MAAM,IAAI,KAAK,CACb,sEAAsE;QACtE,iDAAiD,CAClD,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,kDAAkD;AAClD,gFAAgF;AAEhF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsFE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tyroneross/navgator",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Architecture connection tracker for Claude Code - know your stack before you change it",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -24,7 +24,9 @@
24
24
  },
25
25
  "files": [
26
26
  "dist",
27
- "scripts",
27
+ "web/.next/standalone",
28
+ "web/.next/static",
29
+ "web/public",
28
30
  "commands",
29
31
  "skills",
30
32
  "hooks",
@@ -33,15 +35,18 @@
33
35
  "README.md"
34
36
  ],
35
37
  "scripts": {
36
- "build": "tsc && npm run build:fixshebang",
38
+ "build": "npm run build:cli && npm run build:web",
39
+ "build:cli": "tsc && npm run build:fixshebang",
37
40
  "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);}\"",
41
+ "build:web": "cd web && npm run build && cd .. && npm run build:standalone",
42
+ "build:standalone": "cp -r web/.next/static web/.next/standalone/web/.next/static && test -d web/public && cp -r web/public web/.next/standalone/web/public || true",
38
43
  "dev": "tsc --watch",
44
+ "dev:web": "cd web && next dev",
39
45
  "start": "node dist/cli/index.js",
40
46
  "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
41
47
  "lint": "eslint src/**/*.ts",
42
- "clean": "rm -rf dist",
48
+ "clean": "rm -rf dist web/.next",
43
49
  "prepublishOnly": "npm run clean && npm run build",
44
- "postinstall": "node scripts/postinstall.cjs",
45
50
  "link:local": "npm run build && npm link"
46
51
  },
47
52
  "keywords": [
@@ -64,17 +69,17 @@
64
69
  "url": "https://github.com/tyroneross/navgator/issues"
65
70
  },
66
71
  "engines": {
67
- "node": ">=18.0.0"
72
+ "node": ">=20.0.0"
68
73
  },
69
74
  "dependencies": {
70
- "commander": "^12.0.0",
71
- "glob": "^10.3.10"
75
+ "commander": "^14.0.0",
76
+ "glob": "^13.0.0"
72
77
  },
73
78
  "optionalDependencies": {
74
- "ts-morph": "^22.0.0"
79
+ "ts-morph": "^27.0.0"
75
80
  },
76
81
  "devDependencies": {
77
- "@types/node": "^20.10.0",
82
+ "@types/node": "^22.0.0",
78
83
  "typescript": "^5.3.0"
79
84
  }
80
85
  }
Binary file
Binary file
Binary file
@@ -0,0 +1,26 @@
1
+ <svg width="180" height="180" viewBox="0 0 180 180" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <style>
3
+ @media (prefers-color-scheme: light) {
4
+ .background { fill: black; }
5
+ .foreground { fill: white; }
6
+ }
7
+ @media (prefers-color-scheme: dark) {
8
+ .background { fill: white; }
9
+ .foreground { fill: black; }
10
+ }
11
+ </style>
12
+ <g clip-path="url(#clip0_7960_43945)">
13
+ <rect class="background" width="180" height="180" rx="37" />
14
+ <g style="transform: scale(95%); transform-origin: center">
15
+ <path class="foreground"
16
+ d="M101.141 53H136.632C151.023 53 162.689 64.6662 162.689 79.0573V112.904H148.112V79.0573C148.112 78.7105 148.098 78.3662 148.072 78.0251L112.581 112.898C112.701 112.902 112.821 112.904 112.941 112.904H148.112V126.672H112.941C98.5504 126.672 86.5638 114.891 86.5638 100.5V66.7434H101.141V100.5C101.141 101.15 101.191 101.792 101.289 102.422L137.56 66.7816C137.255 66.7563 136.945 66.7434 136.632 66.7434H101.141V53Z" />
17
+ <path class="foreground"
18
+ d="M65.2926 124.136L14 66.7372H34.6355L64.7495 100.436V66.7372H80.1365V118.47C80.1365 126.278 70.4953 129.958 65.2926 124.136Z" />
19
+ </g>
20
+ </g>
21
+ <defs>
22
+ <clipPath id="clip0_7960_43945">
23
+ <rect width="180" height="180" fill="white" />
24
+ </clipPath>
25
+ </defs>
26
+ </svg>
Binary file
Binary file
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="215" height="48" fill="none"><path fill="#000" d="M57.588 9.6h6L73.828 38h-5.2l-2.36-6.88h-11.36L52.548 38h-5.2l10.24-28.4Zm7.16 17.16-4.16-12.16-4.16 12.16h8.32Zm23.694-2.24c-.186-1.307-.706-2.32-1.56-3.04-.853-.72-1.866-1.08-3.04-1.08-1.68 0-2.986.613-3.92 1.84-.906 1.227-1.36 2.947-1.36 5.16s.454 3.933 1.36 5.16c.934 1.227 2.24 1.84 3.92 1.84 1.254 0 2.307-.373 3.16-1.12.854-.773 1.387-1.867 1.6-3.28l5.12.24c-.186 1.68-.733 3.147-1.64 4.4-.906 1.227-2.08 2.173-3.52 2.84-1.413.667-2.986 1-4.72 1-2.08 0-3.906-.453-5.48-1.36-1.546-.907-2.76-2.2-3.64-3.88-.853-1.68-1.28-3.627-1.28-5.84 0-2.24.427-4.187 1.28-5.84.88-1.68 2.094-2.973 3.64-3.88 1.574-.907 3.4-1.36 5.48-1.36 1.68 0 3.227.32 4.64.96 1.414.64 2.56 1.56 3.44 2.76.907 1.2 1.454 2.6 1.64 4.2l-5.12.28Zm11.486-7.72.12 3.4c.534-1.227 1.307-2.173 2.32-2.84 1.04-.693 2.267-1.04 3.68-1.04 1.494 0 2.76.387 3.8 1.16 1.067.747 1.827 1.813 2.28 3.2.507-1.44 1.294-2.52 2.36-3.24 1.094-.747 2.414-1.12 3.96-1.12 1.414 0 2.64.307 3.68.92s1.84 1.52 2.4 2.72c.56 1.2.84 2.667.84 4.4V38h-4.96V25.92c0-1.813-.293-3.187-.88-4.12-.56-.96-1.413-1.44-2.56-1.44-.906 0-1.68.213-2.32.64-.64.427-1.133 1.053-1.48 1.88-.32.827-.48 1.84-.48 3.04V38h-4.56V25.92c0-1.2-.133-2.213-.4-3.04-.24-.827-.626-1.453-1.16-1.88-.506-.427-1.133-.64-1.88-.64-.906 0-1.68.227-2.32.68-.64.427-1.133 1.053-1.48 1.88-.32.827-.48 1.827-.48 3V38h-4.96V16.8h4.48Zm26.723 10.6c0-2.24.427-4.187 1.28-5.84.854-1.68 2.067-2.973 3.64-3.88 1.574-.907 3.4-1.36 5.48-1.36 1.84 0 3.494.413 4.96 1.24 1.467.827 2.64 2.08 3.52 3.76.88 1.653 1.347 3.693 1.4 6.12v1.32h-15.08c.107 1.813.614 3.227 1.52 4.24.907.987 2.134 1.48 3.68 1.48.987 0 1.88-.253 2.68-.76a4.803 4.803 0 0 0 1.84-2.2l5.08.36c-.64 2.027-1.84 3.64-3.6 4.84-1.733 1.173-3.733 1.76-6 1.76-2.08 0-3.906-.453-5.48-1.36-1.573-.907-2.786-2.2-3.64-3.88-.853-1.68-1.28-3.627-1.28-5.84Zm15.16-2.04c-.213-1.733-.76-3.013-1.64-3.84-.853-.827-1.893-1.24-3.12-1.24-1.44 0-2.6.453-3.48 1.36-.88.88-1.44 2.12-1.68 3.72h9.92ZM163.139 9.6V38h-5.04V9.6h5.04Zm8.322 7.2.24 5.88-.64-.36c.32-2.053 1.094-3.56 2.32-4.52 1.254-.987 2.787-1.48 4.6-1.48 2.32 0 4.107.733 5.36 2.2 1.254 1.44 1.88 3.387 1.88 5.84V38h-4.96V25.92c0-1.253-.12-2.28-.36-3.08-.24-.8-.64-1.413-1.2-1.84-.533-.427-1.253-.64-2.16-.64-1.44 0-2.573.48-3.4 1.44-.8.933-1.2 2.307-1.2 4.12V38h-4.96V16.8h4.48Zm30.003 7.72c-.186-1.307-.706-2.32-1.56-3.04-.853-.72-1.866-1.08-3.04-1.08-1.68 0-2.986.613-3.92 1.84-.906 1.227-1.36 2.947-1.36 5.16s.454 3.933 1.36 5.16c.934 1.227 2.24 1.84 3.92 1.84 1.254 0 2.307-.373 3.16-1.12.854-.773 1.387-1.867 1.6-3.28l5.12.24c-.186 1.68-.733 3.147-1.64 4.4-.906 1.227-2.08 2.173-3.52 2.84-1.413.667-2.986 1-4.72 1-2.08 0-3.906-.453-5.48-1.36-1.546-.907-2.76-2.2-3.64-3.88-.853-1.68-1.28-3.627-1.28-5.84 0-2.24.427-4.187 1.28-5.84.88-1.68 2.094-2.973 3.64-3.88 1.574-.907 3.4-1.36 5.48-1.36 1.68 0 3.227.32 4.64.96 1.414.64 2.56 1.56 3.44 2.76.907 1.2 1.454 2.6 1.64 4.2l-5.12.28Zm11.443 8.16V38h-5.6v-5.32h5.6Z"/><path fill="#171717" fill-rule="evenodd" d="m7.839 40.783 16.03-28.054L20 6 0 40.783h7.839Zm8.214 0H40L27.99 19.894l-4.02 7.032 3.976 6.914H20.02l-3.967 6.943Z" clip-rule="evenodd"/></svg>
Binary file
Binary file
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1200" height="1200" fill="none"><rect width="1200" height="1200" fill="#EAEAEA" rx="3"/><g opacity=".5"><g opacity=".5"><path fill="#FAFAFA" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/></g><path stroke="url(#a)" stroke-width="2.418" d="M0-1.209h553.581" transform="scale(1 -1) rotate(45 1163.11 91.165)"/><path stroke="url(#b)" stroke-width="2.418" d="M404.846 598.671h391.726"/><path stroke="url(#c)" stroke-width="2.418" d="M599.5 795.742V404.017"/><path stroke="url(#d)" stroke-width="2.418" d="m795.717 796.597-391.441-391.44"/><path fill="#fff" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/><g clip-path="url(#e)"><path fill="#666" fill-rule="evenodd" d="M616.426 586.58h-31.434v16.176l3.553-3.554.531-.531h9.068l.074-.074 8.463-8.463h2.565l7.18 7.181V586.58Zm-15.715 14.654 3.698 3.699 1.283 1.282-2.565 2.565-1.282-1.283-5.2-5.199h-6.066l-5.514 5.514-.073.073v2.876a2.418 2.418 0 0 0 2.418 2.418h26.598a2.418 2.418 0 0 0 2.418-2.418v-8.317l-8.463-8.463-7.181 7.181-.071.072Zm-19.347 5.442v4.085a6.045 6.045 0 0 0 6.046 6.045h26.598a6.044 6.044 0 0 0 6.045-6.045v-7.108l1.356-1.355-1.282-1.283-.074-.073v-17.989h-38.689v23.43l-.146.146.146.147Z" clip-rule="evenodd"/></g><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/></g><defs><linearGradient id="a" x1="554.061" x2="-.48" y1=".083" y2=".087" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="b" x1="796.912" x2="404.507" y1="599.963" y2="599.965" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="c" x1="600.792" x2="600.794" y1="403.677" y2="796.082" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="d" x1="404.85" x2="796.972" y1="403.903" y2="796.02" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><clipPath id="e"><path fill="#fff" d="M581.364 580.535h38.689v38.689h-38.689z"/></clipPath></defs></svg>
@@ -1,359 +0,0 @@
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
- }
@@ -1,35 +0,0 @@
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
- }