@tyroneross/navgator 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (395) hide show
  1. package/dist/cli/index.js +201 -10
  2. package/dist/cli/index.js.map +1 -1
  3. package/dist/diagram.d.ts.map +1 -1
  4. package/dist/diagram.js +33 -0
  5. package/dist/diagram.js.map +1 -1
  6. package/dist/scanner.d.ts +2 -0
  7. package/dist/scanner.d.ts.map +1 -1
  8. package/dist/scanner.js +131 -12
  9. package/dist/scanner.js.map +1 -1
  10. package/dist/scanners/connections/ast-scanner.d.ts.map +1 -1
  11. package/dist/scanners/connections/ast-scanner.js +0 -3
  12. package/dist/scanners/connections/ast-scanner.js.map +1 -1
  13. package/dist/scanners/connections/llm-call-tracer.d.ts +83 -0
  14. package/dist/scanners/connections/llm-call-tracer.d.ts.map +1 -0
  15. package/dist/scanners/connections/llm-call-tracer.js +801 -0
  16. package/dist/scanners/connections/llm-call-tracer.js.map +1 -0
  17. package/dist/scanners/connections/service-calls.d.ts.map +1 -1
  18. package/dist/scanners/connections/service-calls.js +44 -47
  19. package/dist/scanners/connections/service-calls.js.map +1 -1
  20. package/dist/scanners/infrastructure/index.d.ts.map +1 -1
  21. package/dist/scanners/infrastructure/index.js +34 -4
  22. package/dist/scanners/infrastructure/index.js.map +1 -1
  23. package/dist/scanners/packages/swift.d.ts +14 -0
  24. package/dist/scanners/packages/swift.d.ts.map +1 -0
  25. package/dist/scanners/packages/swift.js +320 -0
  26. package/dist/scanners/packages/swift.js.map +1 -0
  27. package/dist/scanners/prompts/detector.d.ts +16 -0
  28. package/dist/scanners/prompts/detector.d.ts.map +1 -1
  29. package/dist/scanners/prompts/detector.js +90 -1
  30. package/dist/scanners/prompts/detector.js.map +1 -1
  31. package/dist/scanners/prompts/types.d.ts +4 -0
  32. package/dist/scanners/prompts/types.d.ts.map +1 -1
  33. package/dist/scanners/prompts/types.js.map +1 -1
  34. package/dist/scanners/swift/code-scanner.d.ts +14 -0
  35. package/dist/scanners/swift/code-scanner.d.ts.map +1 -0
  36. package/dist/scanners/swift/code-scanner.js +803 -0
  37. package/dist/scanners/swift/code-scanner.js.map +1 -0
  38. package/dist/storage.d.ts +2 -2
  39. package/dist/storage.d.ts.map +1 -1
  40. package/dist/storage.js +41 -2
  41. package/dist/storage.js.map +1 -1
  42. package/dist/types.d.ts +26 -2
  43. package/dist/types.d.ts.map +1 -1
  44. package/dist/types.js.map +1 -1
  45. package/dist/ui-server.d.ts +7 -7
  46. package/dist/ui-server.d.ts.map +1 -1
  47. package/dist/ui-server.js +80 -792
  48. package/dist/ui-server.js.map +1 -1
  49. package/package.json +15 -9
  50. package/web/.next/standalone/web/.next/BUILD_ID +1 -0
  51. package/web/.next/standalone/web/.next/app-path-routes-manifest.json +13 -0
  52. package/web/.next/standalone/web/.next/build-manifest.json +20 -0
  53. package/web/.next/standalone/web/.next/package.json +1 -0
  54. package/web/.next/standalone/web/.next/prerender-manifest.json +88 -0
  55. package/web/.next/standalone/web/.next/required-server-files.json +317 -0
  56. package/web/.next/standalone/web/.next/routes-manifest.json +110 -0
  57. package/web/.next/standalone/web/.next/server/app/_global-error/page/app-paths-manifest.json +3 -0
  58. package/web/.next/standalone/web/.next/server/app/_global-error/page/build-manifest.json +17 -0
  59. package/web/.next/standalone/web/.next/server/app/_global-error/page/next-font-manifest.json +6 -0
  60. package/web/.next/standalone/web/.next/server/app/_global-error/page/react-loadable-manifest.json +1 -0
  61. package/web/.next/standalone/web/.next/server/app/_global-error/page/server-reference-manifest.json +4 -0
  62. package/web/.next/standalone/web/.next/server/app/_global-error/page.js +10 -0
  63. package/web/.next/standalone/web/.next/server/app/_global-error/page.js.map +5 -0
  64. package/web/.next/standalone/web/.next/server/app/_global-error/page.js.nft.json +1 -0
  65. package/web/.next/standalone/web/.next/server/app/_global-error/page_client-reference-manifest.js +2 -0
  66. package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -0
  67. package/web/.next/standalone/web/.next/server/app/_global-error.meta +15 -0
  68. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +12 -0
  69. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +5 -0
  70. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +12 -0
  71. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +7 -0
  72. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +4 -0
  73. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -0
  74. package/web/.next/standalone/web/.next/server/app/_not-found/page/app-paths-manifest.json +3 -0
  75. package/web/.next/standalone/web/.next/server/app/_not-found/page/build-manifest.json +17 -0
  76. package/web/.next/standalone/web/.next/server/app/_not-found/page/next-font-manifest.json +11 -0
  77. package/web/.next/standalone/web/.next/server/app/_not-found/page/react-loadable-manifest.json +1 -0
  78. package/web/.next/standalone/web/.next/server/app/_not-found/page/server-reference-manifest.json +4 -0
  79. package/web/.next/standalone/web/.next/server/app/_not-found/page.js +13 -0
  80. package/web/.next/standalone/web/.next/server/app/_not-found/page.js.map +5 -0
  81. package/web/.next/standalone/web/.next/server/app/_not-found/page.js.nft.json +1 -0
  82. package/web/.next/standalone/web/.next/server/app/_not-found/page_client-reference-manifest.js +2 -0
  83. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -0
  84. package/web/.next/standalone/web/.next/server/app/_not-found.meta +16 -0
  85. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +17 -0
  86. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +17 -0
  87. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +8 -0
  88. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +8 -0
  89. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +5 -0
  90. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +4 -0
  91. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +3 -0
  92. package/web/.next/standalone/web/.next/server/app/api/components/route/app-paths-manifest.json +3 -0
  93. package/web/.next/standalone/web/.next/server/app/api/components/route/build-manifest.json +11 -0
  94. package/web/.next/standalone/web/.next/server/app/api/components/route/server-reference-manifest.json +4 -0
  95. package/web/.next/standalone/web/.next/server/app/api/components/route.js +6 -0
  96. package/web/.next/standalone/web/.next/server/app/api/components/route.js.map +5 -0
  97. package/web/.next/standalone/web/.next/server/app/api/components/route.js.nft.json +1 -0
  98. package/web/.next/standalone/web/.next/server/app/api/components/route_client-reference-manifest.js +2 -0
  99. package/web/.next/standalone/web/.next/server/app/api/connections/route/app-paths-manifest.json +3 -0
  100. package/web/.next/standalone/web/.next/server/app/api/connections/route/build-manifest.json +11 -0
  101. package/web/.next/standalone/web/.next/server/app/api/connections/route/server-reference-manifest.json +4 -0
  102. package/web/.next/standalone/web/.next/server/app/api/connections/route.js +6 -0
  103. package/web/.next/standalone/web/.next/server/app/api/connections/route.js.map +5 -0
  104. package/web/.next/standalone/web/.next/server/app/api/connections/route.js.nft.json +1 -0
  105. package/web/.next/standalone/web/.next/server/app/api/connections/route_client-reference-manifest.js +2 -0
  106. package/web/.next/standalone/web/.next/server/app/api/graph/route/app-paths-manifest.json +3 -0
  107. package/web/.next/standalone/web/.next/server/app/api/graph/route/build-manifest.json +11 -0
  108. package/web/.next/standalone/web/.next/server/app/api/graph/route/server-reference-manifest.json +4 -0
  109. package/web/.next/standalone/web/.next/server/app/api/graph/route.js +6 -0
  110. package/web/.next/standalone/web/.next/server/app/api/graph/route.js.map +5 -0
  111. package/web/.next/standalone/web/.next/server/app/api/graph/route.js.nft.json +1 -0
  112. package/web/.next/standalone/web/.next/server/app/api/graph/route_client-reference-manifest.js +2 -0
  113. package/web/.next/standalone/web/.next/server/app/api/projects/route/app-paths-manifest.json +3 -0
  114. package/web/.next/standalone/web/.next/server/app/api/projects/route/build-manifest.json +11 -0
  115. package/web/.next/standalone/web/.next/server/app/api/projects/route/server-reference-manifest.json +4 -0
  116. package/web/.next/standalone/web/.next/server/app/api/projects/route.js +6 -0
  117. package/web/.next/standalone/web/.next/server/app/api/projects/route.js.map +5 -0
  118. package/web/.next/standalone/web/.next/server/app/api/projects/route.js.nft.json +1 -0
  119. package/web/.next/standalone/web/.next/server/app/api/projects/route_client-reference-manifest.js +2 -0
  120. package/web/.next/standalone/web/.next/server/app/api/prompts/route/app-paths-manifest.json +3 -0
  121. package/web/.next/standalone/web/.next/server/app/api/prompts/route/build-manifest.json +11 -0
  122. package/web/.next/standalone/web/.next/server/app/api/prompts/route/server-reference-manifest.json +4 -0
  123. package/web/.next/standalone/web/.next/server/app/api/prompts/route.js +7 -0
  124. package/web/.next/standalone/web/.next/server/app/api/prompts/route.js.map +5 -0
  125. package/web/.next/standalone/web/.next/server/app/api/prompts/route.js.nft.json +1 -0
  126. package/web/.next/standalone/web/.next/server/app/api/prompts/route_client-reference-manifest.js +2 -0
  127. package/web/.next/standalone/web/.next/server/app/api/scan/route/app-paths-manifest.json +3 -0
  128. package/web/.next/standalone/web/.next/server/app/api/scan/route/build-manifest.json +11 -0
  129. package/web/.next/standalone/web/.next/server/app/api/scan/route/server-reference-manifest.json +4 -0
  130. package/web/.next/standalone/web/.next/server/app/api/scan/route.js +6 -0
  131. package/web/.next/standalone/web/.next/server/app/api/scan/route.js.map +5 -0
  132. package/web/.next/standalone/web/.next/server/app/api/scan/route.js.nft.json +1 -0
  133. package/web/.next/standalone/web/.next/server/app/api/scan/route_client-reference-manifest.js +2 -0
  134. package/web/.next/standalone/web/.next/server/app/api/settings/route/app-paths-manifest.json +3 -0
  135. package/web/.next/standalone/web/.next/server/app/api/settings/route/build-manifest.json +11 -0
  136. package/web/.next/standalone/web/.next/server/app/api/settings/route/server-reference-manifest.json +4 -0
  137. package/web/.next/standalone/web/.next/server/app/api/settings/route.js +6 -0
  138. package/web/.next/standalone/web/.next/server/app/api/settings/route.js.map +5 -0
  139. package/web/.next/standalone/web/.next/server/app/api/settings/route.js.nft.json +1 -0
  140. package/web/.next/standalone/web/.next/server/app/api/settings/route_client-reference-manifest.js +2 -0
  141. package/web/.next/standalone/web/.next/server/app/api/status/route/app-paths-manifest.json +3 -0
  142. package/web/.next/standalone/web/.next/server/app/api/status/route/build-manifest.json +11 -0
  143. package/web/.next/standalone/web/.next/server/app/api/status/route/server-reference-manifest.json +4 -0
  144. package/web/.next/standalone/web/.next/server/app/api/status/route.js +6 -0
  145. package/web/.next/standalone/web/.next/server/app/api/status/route.js.map +5 -0
  146. package/web/.next/standalone/web/.next/server/app/api/status/route.js.nft.json +1 -0
  147. package/web/.next/standalone/web/.next/server/app/api/status/route_client-reference-manifest.js +2 -0
  148. package/web/.next/standalone/web/.next/server/app/index.html +1 -0
  149. package/web/.next/standalone/web/.next/server/app/index.meta +14 -0
  150. package/web/.next/standalone/web/.next/server/app/index.rsc +23 -0
  151. package/web/.next/standalone/web/.next/server/app/index.segments/__PAGE__.segment.rsc +9 -0
  152. package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +23 -0
  153. package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +8 -0
  154. package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +8 -0
  155. package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +5 -0
  156. package/web/.next/standalone/web/.next/server/app/page/app-paths-manifest.json +3 -0
  157. package/web/.next/standalone/web/.next/server/app/page/build-manifest.json +17 -0
  158. package/web/.next/standalone/web/.next/server/app/page/next-font-manifest.json +11 -0
  159. package/web/.next/standalone/web/.next/server/app/page/react-loadable-manifest.json +1 -0
  160. package/web/.next/standalone/web/.next/server/app/page/server-reference-manifest.json +4 -0
  161. package/web/.next/standalone/web/.next/server/app/page.js +15 -0
  162. package/web/.next/standalone/web/.next/server/app/page.js.map +5 -0
  163. package/web/.next/standalone/web/.next/server/app/page.js.nft.json +1 -0
  164. package/web/.next/standalone/web/.next/server/app/page_client-reference-manifest.js +2 -0
  165. package/web/.next/standalone/web/.next/server/app-paths-manifest.json +13 -0
  166. package/web/.next/standalone/web/.next/server/chunks/2374f_next_dist_esm_build_templates_app-route_0bb4e66a.js +19 -0
  167. package/web/.next/standalone/web/.next/server/chunks/[root-of-the-server]__006b837d._.js +3 -0
  168. package/web/.next/standalone/web/.next/server/chunks/[root-of-the-server]__1ab91221._.js +3 -0
  169. package/web/.next/standalone/web/.next/server/chunks/[root-of-the-server]__2e09fec9._.js +3 -0
  170. package/web/.next/standalone/web/.next/server/chunks/[root-of-the-server]__38d0390f._.js +3 -0
  171. package/web/.next/standalone/web/.next/server/chunks/[root-of-the-server]__539ef30d._.js +3 -0
  172. package/web/.next/standalone/web/.next/server/chunks/[root-of-the-server]__594bcf20._.js +3 -0
  173. package/web/.next/standalone/web/.next/server/chunks/[root-of-the-server]__b888fadf._.js +3 -0
  174. package/web/.next/standalone/web/.next/server/chunks/[root-of-the-server]__f3450c22._.js +21 -0
  175. package/web/.next/standalone/web/.next/server/chunks/[root-of-the-server]__fa2ec862._.js +3 -0
  176. package/web/.next/standalone/web/.next/server/chunks/[turbopack]_runtime.js +770 -0
  177. package/web/.next/standalone/web/.next/server/chunks/ssr/2374f_e6039567._.js +6 -0
  178. package/web/.next/standalone/web/.next/server/chunks/ssr/2374f_next_dist_09351209._.js +6 -0
  179. package/web/.next/standalone/web/.next/server/chunks/ssr/2374f_next_dist_222be7ae._.js +6 -0
  180. package/web/.next/standalone/web/.next/server/chunks/ssr/2374f_next_dist_2346e1b3._.js +3 -0
  181. package/web/.next/standalone/web/.next/server/chunks/ssr/2374f_next_dist_cec86455._.js +4 -0
  182. package/web/.next/standalone/web/.next/server/chunks/ssr/2374f_next_dist_client_components_9c5d1a14._.js +3 -0
  183. package/web/.next/standalone/web/.next/server/chunks/ssr/2374f_next_dist_client_components_builtin_forbidden_8eae0c85.js +3 -0
  184. package/web/.next/standalone/web/.next/server/chunks/ssr/2374f_next_dist_client_components_builtin_global-error_81159d60.js +3 -0
  185. package/web/.next/standalone/web/.next/server/chunks/ssr/2374f_next_dist_client_components_builtin_unauthorized_7d34a31c.js +3 -0
  186. package/web/.next/standalone/web/.next/server/chunks/ssr/2374f_next_dist_e03afa0e._.js +3 -0
  187. package/web/.next/standalone/web/.next/server/chunks/ssr/2374f_next_dist_esm_build_templates_app-page_2c8d71b9.js +4 -0
  188. package/web/.next/standalone/web/.next/server/chunks/ssr/2374f_next_dist_server_route-modules_app-page_vendored_ssr_react-dom_8910f04c.js +3 -0
  189. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__1a0663e6._.js +3 -0
  190. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__4306eafc._.js +3 -0
  191. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__44903626._.js +3 -0
  192. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__60278e3f._.js +3 -0
  193. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__61942f24._.js +4 -0
  194. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__8c45c3c9._.js +3 -0
  195. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__9a2f110d._.js +3 -0
  196. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__ed07bd88._.js +3 -0
  197. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__f2db61af._.js +3 -0
  198. package/web/.next/standalone/web/.next/server/chunks/ssr/[turbopack]_runtime.js +770 -0
  199. package/web/.next/standalone/web/.next/server/chunks/ssr/web_0103e631._.js +4 -0
  200. package/web/.next/standalone/web/.next/server/chunks/ssr/web_171de0df._.js +14 -0
  201. package/web/.next/standalone/web/.next/server/chunks/ssr/web__next-internal_server_app__global-error_page_actions_2a1e94d4.js +3 -0
  202. package/web/.next/standalone/web/.next/server/chunks/ssr/web__next-internal_server_app__not-found_page_actions_9eaa9845.js +3 -0
  203. package/web/.next/standalone/web/.next/server/chunks/ssr/web__next-internal_server_app_page_actions_ec26bf28.js +3 -0
  204. package/web/.next/standalone/web/.next/server/chunks/web__next-internal_server_app_api_components_route_actions_c88bf2a6.js +3 -0
  205. package/web/.next/standalone/web/.next/server/chunks/web__next-internal_server_app_api_connections_route_actions_b1d5e95a.js +3 -0
  206. package/web/.next/standalone/web/.next/server/chunks/web__next-internal_server_app_api_graph_route_actions_e2dd052c.js +3 -0
  207. package/web/.next/standalone/web/.next/server/chunks/web__next-internal_server_app_api_projects_route_actions_3f671cbb.js +3 -0
  208. package/web/.next/standalone/web/.next/server/chunks/web__next-internal_server_app_api_prompts_route_actions_85b56166.js +3 -0
  209. package/web/.next/standalone/web/.next/server/chunks/web__next-internal_server_app_api_scan_route_actions_861cde8d.js +3 -0
  210. package/web/.next/standalone/web/.next/server/chunks/web__next-internal_server_app_api_settings_route_actions_e19026ae.js +3 -0
  211. package/web/.next/standalone/web/.next/server/chunks/web__next-internal_server_app_api_status_route_actions_8b8c6c89.js +3 -0
  212. package/web/.next/standalone/web/.next/server/functions-config-manifest.json +4 -0
  213. package/web/.next/standalone/web/.next/server/middleware-build-manifest.js +21 -0
  214. package/web/.next/standalone/web/.next/server/middleware-manifest.json +6 -0
  215. package/web/.next/standalone/web/.next/server/next-font-manifest.js +1 -0
  216. package/web/.next/standalone/web/.next/server/next-font-manifest.json +15 -0
  217. package/web/.next/standalone/web/.next/server/pages/404.html +1 -0
  218. package/web/.next/standalone/web/.next/server/pages/500.html +2 -0
  219. package/web/.next/standalone/web/.next/server/pages-manifest.json +4 -0
  220. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -0
  221. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +5 -0
  222. package/web/.next/standalone/web/.next/static/WH0NvTGUEDs9QVUjcPJKx/_buildManifest.js +11 -0
  223. package/web/.next/standalone/web/.next/static/WH0NvTGUEDs9QVUjcPJKx/_clientMiddlewareManifest.json +1 -0
  224. package/web/.next/standalone/web/.next/static/WH0NvTGUEDs9QVUjcPJKx/_ssgManifest.js +1 -0
  225. package/web/.next/standalone/web/.next/static/chunks/062ae79751df2759.js +1 -0
  226. package/web/.next/standalone/web/.next/static/chunks/159889e17b2cf1f8.js +2 -0
  227. package/web/.next/standalone/web/.next/static/chunks/458d6f37339fc069.js +1 -0
  228. package/web/.next/standalone/web/.next/static/chunks/6d3d39425a878d7f.js +1 -0
  229. package/web/.next/standalone/web/.next/static/chunks/8a80e7184ad3a13f.css +2 -0
  230. package/web/.next/standalone/web/.next/static/chunks/a6dad97d9634a72d.js +1 -0
  231. package/web/.next/standalone/web/.next/static/chunks/c056475f5f4424b6.css +1 -0
  232. package/web/.next/standalone/web/.next/static/chunks/c57fee8cce8d7cb9.js +1 -0
  233. package/web/.next/standalone/web/.next/static/chunks/cb3513192b63e480.js +12 -0
  234. package/web/.next/standalone/web/.next/static/chunks/dd22b5f2beb2cc31.js +1 -0
  235. package/web/.next/standalone/web/.next/static/chunks/e0affeef0ddb9a97.js +4 -0
  236. package/web/.next/standalone/web/.next/static/chunks/f74a6859e1c4d5e3.js +1 -0
  237. package/web/.next/standalone/web/.next/static/chunks/turbopack-c0c89f9e6f0a38c4.js +3 -0
  238. package/web/.next/standalone/web/.next/static/media/4fa387ec64143e14-s.c1fdd6c2.woff2 +0 -0
  239. package/web/.next/standalone/web/.next/static/media/7178b3e590c64307-s.b97b3418.woff2 +0 -0
  240. package/web/.next/standalone/web/.next/static/media/797e433ab948586e-s.p.dbea232f.woff2 +0 -0
  241. package/web/.next/standalone/web/.next/static/media/8a480f0b521d4e75-s.8e0177b5.woff2 +0 -0
  242. package/web/.next/standalone/web/.next/static/media/bbc41e54d2fcbd21-s.799d8ef8.woff2 +0 -0
  243. package/web/.next/standalone/web/.next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2 +0 -0
  244. package/web/.next/standalone/web/app/api/components/route.ts +252 -0
  245. package/web/.next/standalone/web/app/api/connections/route.ts +319 -0
  246. package/web/.next/standalone/web/app/api/graph/route.ts +235 -0
  247. package/web/.next/standalone/web/app/api/projects/route.ts +221 -0
  248. package/web/.next/standalone/web/app/api/prompts/route.ts +328 -0
  249. package/web/.next/standalone/web/app/api/scan/route.ts +108 -0
  250. package/web/.next/standalone/web/app/api/settings/route.ts +198 -0
  251. package/web/.next/standalone/web/app/api/status/route.ts +169 -0
  252. package/web/.next/standalone/web/app/globals.css +99 -0
  253. package/web/.next/standalone/web/app/layout.tsx +49 -0
  254. package/web/.next/standalone/web/app/page.tsx +94 -0
  255. package/web/.next/standalone/web/components/components-panel.tsx +240 -0
  256. package/web/.next/standalone/web/components/connections-panel.tsx +220 -0
  257. package/web/.next/standalone/web/components/diagram-view.tsx +735 -0
  258. package/web/.next/standalone/web/components/header.tsx +225 -0
  259. package/web/.next/standalone/web/components/impact-analysis.tsx +358 -0
  260. package/web/.next/standalone/web/components/llm-tracking-panel.tsx +1483 -0
  261. package/web/.next/standalone/web/components/settings-panel.tsx +671 -0
  262. package/web/.next/standalone/web/components/sidebar.tsx +74 -0
  263. package/web/.next/standalone/web/components/status-overview.tsx +326 -0
  264. package/web/.next/standalone/web/components/theme-provider.tsx +11 -0
  265. package/web/.next/standalone/web/components/ui/accordion.tsx +66 -0
  266. package/web/.next/standalone/web/components/ui/alert-dialog.tsx +157 -0
  267. package/web/.next/standalone/web/components/ui/alert.tsx +66 -0
  268. package/web/.next/standalone/web/components/ui/aspect-ratio.tsx +11 -0
  269. package/web/.next/standalone/web/components/ui/avatar.tsx +53 -0
  270. package/web/.next/standalone/web/components/ui/badge.tsx +46 -0
  271. package/web/.next/standalone/web/components/ui/breadcrumb.tsx +109 -0
  272. package/web/.next/standalone/web/components/ui/button-group.tsx +83 -0
  273. package/web/.next/standalone/web/components/ui/button.tsx +60 -0
  274. package/web/.next/standalone/web/components/ui/calendar.tsx +213 -0
  275. package/web/.next/standalone/web/components/ui/card.tsx +92 -0
  276. package/web/.next/standalone/web/components/ui/carousel.tsx +241 -0
  277. package/web/.next/standalone/web/components/ui/chart.tsx +353 -0
  278. package/web/.next/standalone/web/components/ui/checkbox.tsx +32 -0
  279. package/web/.next/standalone/web/components/ui/collapsible.tsx +33 -0
  280. package/web/.next/standalone/web/components/ui/command.tsx +184 -0
  281. package/web/.next/standalone/web/components/ui/context-menu.tsx +252 -0
  282. package/web/.next/standalone/web/components/ui/dialog.tsx +143 -0
  283. package/web/.next/standalone/web/components/ui/drawer.tsx +135 -0
  284. package/web/.next/standalone/web/components/ui/dropdown-menu.tsx +257 -0
  285. package/web/.next/standalone/web/components/ui/empty.tsx +104 -0
  286. package/web/.next/standalone/web/components/ui/field.tsx +244 -0
  287. package/web/.next/standalone/web/components/ui/form.tsx +167 -0
  288. package/web/.next/standalone/web/components/ui/hover-card.tsx +44 -0
  289. package/web/.next/standalone/web/components/ui/input-group.tsx +169 -0
  290. package/web/.next/standalone/web/components/ui/input-otp.tsx +77 -0
  291. package/web/.next/standalone/web/components/ui/input.tsx +21 -0
  292. package/web/.next/standalone/web/components/ui/item.tsx +193 -0
  293. package/web/.next/standalone/web/components/ui/kbd.tsx +28 -0
  294. package/web/.next/standalone/web/components/ui/label.tsx +24 -0
  295. package/web/.next/standalone/web/components/ui/menubar.tsx +276 -0
  296. package/web/.next/standalone/web/components/ui/navigation-menu.tsx +166 -0
  297. package/web/.next/standalone/web/components/ui/pagination.tsx +127 -0
  298. package/web/.next/standalone/web/components/ui/popover.tsx +48 -0
  299. package/web/.next/standalone/web/components/ui/progress.tsx +31 -0
  300. package/web/.next/standalone/web/components/ui/radio-group.tsx +45 -0
  301. package/web/.next/standalone/web/components/ui/resizable.tsx +56 -0
  302. package/web/.next/standalone/web/components/ui/scroll-area.tsx +58 -0
  303. package/web/.next/standalone/web/components/ui/select.tsx +185 -0
  304. package/web/.next/standalone/web/components/ui/separator.tsx +28 -0
  305. package/web/.next/standalone/web/components/ui/sheet.tsx +139 -0
  306. package/web/.next/standalone/web/components/ui/sidebar.tsx +726 -0
  307. package/web/.next/standalone/web/components/ui/skeleton.tsx +13 -0
  308. package/web/.next/standalone/web/components/ui/slider.tsx +63 -0
  309. package/web/.next/standalone/web/components/ui/sonner.tsx +25 -0
  310. package/web/.next/standalone/web/components/ui/spinner.tsx +16 -0
  311. package/web/.next/standalone/web/components/ui/switch.tsx +31 -0
  312. package/web/.next/standalone/web/components/ui/table.tsx +116 -0
  313. package/web/.next/standalone/web/components/ui/tabs.tsx +66 -0
  314. package/web/.next/standalone/web/components/ui/textarea.tsx +18 -0
  315. package/web/.next/standalone/web/components/ui/toast.tsx +129 -0
  316. package/web/.next/standalone/web/components/ui/toaster.tsx +35 -0
  317. package/web/.next/standalone/web/components/ui/toggle-group.tsx +73 -0
  318. package/web/.next/standalone/web/components/ui/toggle.tsx +47 -0
  319. package/web/.next/standalone/web/components/ui/tooltip.tsx +61 -0
  320. package/web/.next/standalone/web/components/ui/use-mobile.tsx +19 -0
  321. package/web/.next/standalone/web/components/ui/use-toast.ts +191 -0
  322. package/web/.next/standalone/web/components.json +21 -0
  323. package/web/.next/standalone/web/hooks/use-mobile.ts +19 -0
  324. package/web/.next/standalone/web/hooks/use-toast.ts +191 -0
  325. package/web/.next/standalone/web/lib/hooks/index.ts +8 -0
  326. package/web/.next/standalone/web/lib/hooks/use-components.ts +83 -0
  327. package/web/.next/standalone/web/lib/hooks/use-connections.ts +83 -0
  328. package/web/.next/standalone/web/lib/hooks/use-projects.ts +116 -0
  329. package/web/.next/standalone/web/lib/hooks/use-prompts.ts +122 -0
  330. package/web/.next/standalone/web/lib/hooks/use-settings.ts +135 -0
  331. package/web/.next/standalone/web/lib/hooks/use-status.ts +80 -0
  332. package/web/.next/standalone/web/lib/project-context.tsx +46 -0
  333. package/web/.next/standalone/web/lib/transform.ts +625 -0
  334. package/web/.next/standalone/web/lib/types.ts +198 -0
  335. package/web/.next/standalone/web/lib/utils.ts +6 -0
  336. package/web/.next/standalone/web/next.config.mjs +12 -0
  337. package/web/.next/standalone/web/package-lock.json +3987 -0
  338. package/web/.next/standalone/web/package.json +73 -0
  339. package/web/.next/standalone/web/pnpm-lock.yaml +5 -0
  340. package/web/.next/standalone/web/postcss.config.mjs +8 -0
  341. package/web/.next/standalone/web/public/apple-icon.png +0 -0
  342. package/web/.next/standalone/web/public/icon-dark-32x32.png +0 -0
  343. package/web/.next/standalone/web/public/icon-light-32x32.png +0 -0
  344. package/web/.next/standalone/web/public/icon.svg +26 -0
  345. package/web/.next/standalone/web/public/navgator-logo.png +0 -0
  346. package/web/.next/standalone/web/public/placeholder-logo.png +0 -0
  347. package/web/.next/standalone/web/public/placeholder-logo.svg +1 -0
  348. package/web/.next/standalone/web/public/placeholder-user.jpg +0 -0
  349. package/web/.next/standalone/web/public/placeholder.jpg +0 -0
  350. package/web/.next/standalone/web/public/placeholder.svg +1 -0
  351. package/web/.next/standalone/web/public/public/apple-icon.png +0 -0
  352. package/web/.next/standalone/web/public/public/icon-dark-32x32.png +0 -0
  353. package/web/.next/standalone/web/public/public/icon-light-32x32.png +0 -0
  354. package/web/.next/standalone/web/public/public/icon.svg +26 -0
  355. package/web/.next/standalone/web/public/public/navgator-logo.png +0 -0
  356. package/web/.next/standalone/web/public/public/placeholder-logo.png +0 -0
  357. package/web/.next/standalone/web/public/public/placeholder-logo.svg +1 -0
  358. package/web/.next/standalone/web/public/public/placeholder-user.jpg +0 -0
  359. package/web/.next/standalone/web/public/public/placeholder.jpg +0 -0
  360. package/web/.next/standalone/web/public/public/placeholder.svg +1 -0
  361. package/web/.next/standalone/web/server.js +38 -0
  362. package/web/.next/standalone/web/styles/globals.css +125 -0
  363. package/web/.next/standalone/web/tsconfig.json +41 -0
  364. package/web/.next/static/WH0NvTGUEDs9QVUjcPJKx/_buildManifest.js +11 -0
  365. package/web/.next/static/WH0NvTGUEDs9QVUjcPJKx/_clientMiddlewareManifest.json +1 -0
  366. package/web/.next/static/WH0NvTGUEDs9QVUjcPJKx/_ssgManifest.js +1 -0
  367. package/web/.next/static/chunks/062ae79751df2759.js +1 -0
  368. package/web/.next/static/chunks/159889e17b2cf1f8.js +2 -0
  369. package/web/.next/static/chunks/458d6f37339fc069.js +1 -0
  370. package/web/.next/static/chunks/6d3d39425a878d7f.js +1 -0
  371. package/web/.next/static/chunks/8a80e7184ad3a13f.css +2 -0
  372. package/web/.next/static/chunks/a6dad97d9634a72d.js +1 -0
  373. package/web/.next/static/chunks/c056475f5f4424b6.css +1 -0
  374. package/web/.next/static/chunks/c57fee8cce8d7cb9.js +1 -0
  375. package/web/.next/static/chunks/cb3513192b63e480.js +12 -0
  376. package/web/.next/static/chunks/dd22b5f2beb2cc31.js +1 -0
  377. package/web/.next/static/chunks/e0affeef0ddb9a97.js +4 -0
  378. package/web/.next/static/chunks/f74a6859e1c4d5e3.js +1 -0
  379. package/web/.next/static/chunks/turbopack-c0c89f9e6f0a38c4.js +3 -0
  380. package/web/.next/static/media/4fa387ec64143e14-s.c1fdd6c2.woff2 +0 -0
  381. package/web/.next/static/media/7178b3e590c64307-s.b97b3418.woff2 +0 -0
  382. package/web/.next/static/media/797e433ab948586e-s.p.dbea232f.woff2 +0 -0
  383. package/web/.next/static/media/8a480f0b521d4e75-s.8e0177b5.woff2 +0 -0
  384. package/web/.next/static/media/bbc41e54d2fcbd21-s.799d8ef8.woff2 +0 -0
  385. package/web/.next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2 +0 -0
  386. package/web/public/apple-icon.png +0 -0
  387. package/web/public/icon-dark-32x32.png +0 -0
  388. package/web/public/icon-light-32x32.png +0 -0
  389. package/web/public/icon.svg +26 -0
  390. package/web/public/navgator-logo.png +0 -0
  391. package/web/public/placeholder-logo.png +0 -0
  392. package/web/public/placeholder-logo.svg +1 -0
  393. package/web/public/placeholder-user.jpg +0 -0
  394. package/web/public/placeholder.jpg +0 -0
  395. package/web/public/placeholder.svg +1 -0
@@ -0,0 +1,803 @@
1
+ /**
2
+ * Swift Code Scanner
3
+ * Detects runtime connections in .swift files:
4
+ * - String-keyed deps (UserDefaults, @AppStorage, NotificationCenter, asset names)
5
+ * - Protocol conformance
6
+ * - State observation (@Published, @Observable, @EnvironmentObject)
7
+ * - URLSession calls to LLM APIs
8
+ * - Entitlement requirements from framework usage
9
+ */
10
+ import * as fs from 'fs';
11
+ import * as path from 'path';
12
+ import { glob } from 'glob';
13
+ import { generateComponentId, generateConnectionId, } from '../../types.js';
14
+ // =============================================================================
15
+ // FRAMEWORK → ENTITLEMENT MAP
16
+ // =============================================================================
17
+ const FRAMEWORK_ENTITLEMENTS = {
18
+ 'HealthKit': { entitlement: 'com.apple.developer.healthkit', plistKey: 'NSHealthShareUsageDescription' },
19
+ 'CloudKit': { entitlement: 'com.apple.developer.icloud-services' },
20
+ 'HomeKit': { entitlement: 'com.apple.developer.homekit', plistKey: 'NSHomeKitUsageDescription' },
21
+ 'CoreLocation': { plistKey: 'NSLocationWhenInUseUsageDescription' },
22
+ 'AVFoundation': { plistKey: 'NSCameraUsageDescription' },
23
+ 'Photos': { plistKey: 'NSPhotoLibraryUsageDescription' },
24
+ 'PhotosUI': { plistKey: 'NSPhotoLibraryUsageDescription' },
25
+ 'Contacts': { plistKey: 'NSContactsUsageDescription' },
26
+ 'EventKit': { plistKey: 'NSCalendarsUsageDescription' },
27
+ 'Speech': { plistKey: 'NSSpeechRecognitionUsageDescription' },
28
+ 'LocalAuthentication': { plistKey: 'NSFaceIDUsageDescription' },
29
+ 'CoreBluetooth': { plistKey: 'NSBluetoothAlwaysUsageDescription' },
30
+ 'CoreMotion': { plistKey: 'NSMotionUsageDescription' },
31
+ 'UserNotifications': { entitlement: 'com.apple.developer.push-notifications' },
32
+ 'StoreKit': { entitlement: 'com.apple.developer.in-app-payments' },
33
+ 'MapKit': { plistKey: 'NSLocationWhenInUseUsageDescription' },
34
+ 'NearbyInteraction': { plistKey: 'NSNearbyInteractionUsageDescription' },
35
+ };
36
+ // =============================================================================
37
+ // LLM API URL PATTERNS
38
+ // =============================================================================
39
+ const LLM_URL_PATTERNS = [
40
+ { pattern: /api\.anthropic\.com/, provider: 'Claude (Anthropic)' },
41
+ { pattern: /api\.openai\.com/, provider: 'OpenAI' },
42
+ { pattern: /generativelanguage\.googleapis\.com/, provider: 'Gemini (Google)' },
43
+ { pattern: /api\.groq\.com/, provider: 'Groq' },
44
+ { pattern: /api\.cohere\.ai/, provider: 'Cohere' },
45
+ { pattern: /api\.mistral\.ai/, provider: 'Mistral' },
46
+ { pattern: /api-inference\.huggingface\.co/, provider: 'HuggingFace' },
47
+ { pattern: /api\.replicate\.com/, provider: 'Replicate' },
48
+ { pattern: /api\.together\.xyz/, provider: 'Together AI' },
49
+ { pattern: /api\.fireworks\.ai/, provider: 'Fireworks AI' },
50
+ ];
51
+ // Swift SDK import patterns for LLMs
52
+ const LLM_IMPORT_PATTERNS = [
53
+ { pattern: /^import\s+OpenAI\b/, provider: 'OpenAI' },
54
+ { pattern: /^import\s+Anthropic\b/, provider: 'Claude (Anthropic)' },
55
+ { pattern: /^import\s+GoogleGenerativeAI\b/, provider: 'Gemini (Google)' },
56
+ { pattern: /^import\s+FoundationModels\b/, provider: 'Apple Intelligence' },
57
+ ];
58
+ // Swift SDK call patterns
59
+ const LLM_CALL_PATTERNS = [
60
+ { pattern: /ChatQuery\(/, provider: 'OpenAI' },
61
+ { pattern: /\.chats\(query:/, provider: 'OpenAI' },
62
+ { pattern: /\.completions\.create\(/, provider: 'OpenAI' },
63
+ { pattern: /AnthropicClient\(/, provider: 'Claude (Anthropic)' },
64
+ { pattern: /\.messages\.create\(/, provider: 'Claude (Anthropic)' },
65
+ { pattern: /GenerativeModel\(name:/, provider: 'Gemini (Google)' },
66
+ { pattern: /\.generateContent\(/, provider: 'Gemini (Google)' },
67
+ { pattern: /LanguageModelSession\(\)/, provider: 'Apple Intelligence' },
68
+ { pattern: /\.respond\(to:/, provider: 'Apple Intelligence' },
69
+ { pattern: /@Generable\b/, provider: 'Apple Intelligence' },
70
+ ];
71
+ // =============================================================================
72
+ // MAIN SCANNER
73
+ // =============================================================================
74
+ export async function scanSwiftCode(projectRoot) {
75
+ const components = [];
76
+ const connections = [];
77
+ const warnings = [];
78
+ const timestamp = Date.now();
79
+ // Load all Swift files
80
+ const swiftFiles = await glob('**/*.swift', {
81
+ cwd: projectRoot,
82
+ ignore: ['.build/**', 'DerivedData/**', '.swiftpm/**', 'Pods/**', 'Carthage/**', '*.playground/**'],
83
+ });
84
+ const files = [];
85
+ for (const relPath of swiftFiles) {
86
+ try {
87
+ const content = await fs.promises.readFile(path.join(projectRoot, relPath), 'utf-8');
88
+ files.push({ relativePath: relPath, content, lines: content.split('\n') });
89
+ }
90
+ catch {
91
+ // skip unreadable
92
+ }
93
+ }
94
+ if (files.length === 0) {
95
+ return { components, connections, warnings, projectMeta: {} };
96
+ }
97
+ // ---- String-keyed runtime deps ----
98
+ const stringKeys = scanStringKeys(files);
99
+ const fragileKeys = buildFragileKeys(stringKeys);
100
+ // Create components + connections for shared keys
101
+ const keyGroups = groupByKey(stringKeys);
102
+ for (const [groupKey, hits] of keyGroups) {
103
+ if (hits.length < 1)
104
+ continue;
105
+ const keyType = hits[0].type;
106
+ const rawKey = hits[0].key;
107
+ const compId = generateComponentId('other', groupKey);
108
+ components.push({
109
+ component_id: compId,
110
+ name: groupKey,
111
+ type: 'other',
112
+ role: { purpose: `${keyType} key "${rawKey}"`, layer: 'backend', critical: hits.length > 1 },
113
+ source: { detection_method: 'auto', config_files: [], confidence: 0.95 },
114
+ connects_to: [],
115
+ connected_from: [],
116
+ status: 'active',
117
+ tags: ['swift', 'string-key', keyType.toLowerCase(), hits.length > 1 ? 'shared' : 'single'],
118
+ metadata: { keyType, key: rawKey, fileCount: hits.length, files: [...new Set(hits.map(h => h.file))] },
119
+ timestamp,
120
+ last_updated: timestamp,
121
+ });
122
+ for (const hit of hits) {
123
+ connections.push({
124
+ connection_id: generateConnectionId('stores'),
125
+ from: { component_id: compId, location: { file: hit.file, line: hit.line } },
126
+ to: { component_id: compId },
127
+ connection_type: 'stores',
128
+ code_reference: {
129
+ file: hit.file,
130
+ symbol: hit.symbol,
131
+ symbol_type: 'variable',
132
+ line_start: hit.line,
133
+ code_snippet: hit.snippet.slice(0, 100),
134
+ },
135
+ description: `${hit.type} key "${rawKey}" in ${hit.file}`,
136
+ detected_from: 'swift-code-scanner',
137
+ confidence: 0.95,
138
+ timestamp,
139
+ last_verified: timestamp,
140
+ });
141
+ }
142
+ }
143
+ // ---- Protocol conformance ----
144
+ const conformances = scanProtocolConformance(files);
145
+ const protocolMap = new Map();
146
+ for (const c of conformances) {
147
+ for (const proto of c.protocols) {
148
+ if (!protocolMap.has(proto))
149
+ protocolMap.set(proto, []);
150
+ protocolMap.get(proto).push(c);
151
+ }
152
+ }
153
+ for (const [proto, conformers] of protocolMap) {
154
+ if (conformers.length < 1)
155
+ continue;
156
+ const compId = generateComponentId('other', `protocol:${proto}`);
157
+ components.push({
158
+ component_id: compId,
159
+ name: `protocol:${proto}`,
160
+ type: 'other',
161
+ role: { purpose: `Protocol ${proto} (${conformers.length} conformer${conformers.length > 1 ? 's' : ''})`, layer: 'backend', critical: conformers.length > 2 },
162
+ source: { detection_method: 'auto', config_files: [], confidence: 0.85 },
163
+ connects_to: [],
164
+ connected_from: [],
165
+ status: 'active',
166
+ tags: ['swift', 'protocol', conformers.length > 2 ? 'widely-used' : 'local'],
167
+ metadata: { conformers: conformers.map(c => ({ type: c.typeName, file: c.file, line: c.line })) },
168
+ timestamp,
169
+ last_updated: timestamp,
170
+ });
171
+ for (const conf of conformers) {
172
+ connections.push({
173
+ connection_id: generateConnectionId('conforms-to'),
174
+ from: { component_id: generateComponentId('other', conf.typeName), location: { file: conf.file, line: conf.line } },
175
+ to: { component_id: compId },
176
+ connection_type: 'conforms-to',
177
+ code_reference: {
178
+ file: conf.file,
179
+ symbol: conf.typeName,
180
+ symbol_type: 'class',
181
+ line_start: conf.line,
182
+ code_snippet: `${conf.typeName}: ${conf.protocols.join(', ')}`,
183
+ },
184
+ description: `${conf.typeName} conforms to ${proto}`,
185
+ detected_from: 'swift-code-scanner',
186
+ confidence: 0.85,
187
+ timestamp,
188
+ last_verified: timestamp,
189
+ });
190
+ }
191
+ }
192
+ // ---- State observation (@Published, @EnvironmentObject, etc.) ----
193
+ const observations = scanStateObservation(files);
194
+ // Group @Published → find consumers via @ObservedObject/@EnvironmentObject/@StateObject
195
+ const publishers = observations.filter(o => o.wrapper === '@Published');
196
+ const consumers = observations.filter(o => ['@ObservedObject', '@EnvironmentObject', '@StateObject'].includes(o.wrapper));
197
+ for (const pub of publishers) {
198
+ for (const con of consumers) {
199
+ // Match if the consumer type matches the publisher's owner type
200
+ if (con.ownerType !== pub.ownerType)
201
+ continue;
202
+ connections.push({
203
+ connection_id: generateConnectionId('observes'),
204
+ from: { component_id: generateComponentId('component', con.ownerType), location: { file: con.file, line: con.line } },
205
+ to: { component_id: generateComponentId('component', pub.ownerType), location: { file: pub.file, line: pub.line } },
206
+ connection_type: 'observes',
207
+ code_reference: {
208
+ file: con.file,
209
+ symbol: con.propertyName,
210
+ symbol_type: 'variable',
211
+ line_start: con.line,
212
+ code_snippet: `${con.wrapper} var ${con.propertyName}: ${con.ownerType}`,
213
+ },
214
+ description: `${con.file} observes ${pub.ownerType}.${pub.propertyName}`,
215
+ detected_from: 'swift-code-scanner',
216
+ confidence: 0.8,
217
+ timestamp,
218
+ last_verified: timestamp,
219
+ });
220
+ }
221
+ }
222
+ // ---- LLM API calls ----
223
+ const llmCalls = scanLLMCalls(files);
224
+ for (const call of llmCalls) {
225
+ const compId = generateComponentId('llm', call.provider);
226
+ // Only add component if not already present
227
+ if (!components.find(c => c.name === call.provider && c.type === 'llm')) {
228
+ components.push({
229
+ component_id: compId,
230
+ name: call.provider,
231
+ type: 'llm',
232
+ role: { purpose: `${call.provider} LLM API`, layer: 'external', critical: true },
233
+ source: { detection_method: 'auto', config_files: [], confidence: 0.9 },
234
+ connects_to: [],
235
+ connected_from: [],
236
+ status: 'active',
237
+ tags: ['swift', 'llm', 'external'],
238
+ timestamp,
239
+ last_updated: timestamp,
240
+ });
241
+ }
242
+ connections.push({
243
+ connection_id: generateConnectionId('service-call'),
244
+ from: { component_id: generateComponentId('other', call.file), location: { file: call.file, line: call.line } },
245
+ to: { component_id: compId },
246
+ connection_type: 'service-call',
247
+ code_reference: {
248
+ file: call.file,
249
+ symbol: call.symbol,
250
+ symbol_type: 'function',
251
+ line_start: call.line,
252
+ code_snippet: call.snippet.slice(0, 100),
253
+ },
254
+ description: `${call.provider} API call in ${call.file}`,
255
+ detected_from: 'swift-code-scanner',
256
+ confidence: 0.9,
257
+ timestamp,
258
+ last_verified: timestamp,
259
+ });
260
+ }
261
+ // ---- Entitlement requirements ----
262
+ const frameworkImports = scanFrameworkImports(files);
263
+ const entitlementReqs = [];
264
+ for (const imp of frameworkImports) {
265
+ const req = FRAMEWORK_ENTITLEMENTS[imp.framework];
266
+ if (req) {
267
+ if (req.entitlement) {
268
+ entitlementReqs.push({ key: req.entitlement, framework: imp.framework, file: imp.file, line: imp.line });
269
+ }
270
+ if (req.plistKey) {
271
+ entitlementReqs.push({ key: req.plistKey, framework: imp.framework, file: imp.file, line: imp.line });
272
+ }
273
+ }
274
+ }
275
+ for (const req of entitlementReqs) {
276
+ connections.push({
277
+ connection_id: generateConnectionId('requires-entitlement'),
278
+ from: { component_id: generateComponentId('framework', req.framework), location: { file: req.file, line: req.line } },
279
+ to: { component_id: generateComponentId('other', `entitlement:${req.key}`) },
280
+ connection_type: 'requires-entitlement',
281
+ code_reference: {
282
+ file: req.file,
283
+ symbol: `import ${req.framework}`,
284
+ symbol_type: 'import',
285
+ line_start: req.line,
286
+ code_snippet: `import ${req.framework} → requires ${req.key}`,
287
+ },
288
+ description: `${req.framework} requires entitlement/plist key: ${req.key}`,
289
+ detected_from: 'swift-code-scanner',
290
+ confidence: 0.85,
291
+ timestamp,
292
+ last_verified: timestamp,
293
+ });
294
+ }
295
+ // ---- Prompt patterns in Swift ----
296
+ const prompts = scanSwiftPrompts(files);
297
+ for (const prompt of prompts) {
298
+ const compId = generateComponentId('prompt', prompt.name);
299
+ components.push({
300
+ component_id: compId,
301
+ name: prompt.name,
302
+ type: 'prompt',
303
+ role: { purpose: `AI prompt: ${prompt.name}`, layer: 'backend', critical: false },
304
+ source: { detection_method: 'auto', config_files: [], confidence: prompt.confidence },
305
+ connects_to: [],
306
+ connected_from: [],
307
+ status: 'active',
308
+ tags: ['swift', 'prompt'],
309
+ metadata: { preview: prompt.preview },
310
+ timestamp,
311
+ last_updated: timestamp,
312
+ });
313
+ connections.push({
314
+ connection_id: generateConnectionId('prompt-location'),
315
+ from: { component_id: compId, location: { file: prompt.file, line: prompt.line } },
316
+ to: { component_id: compId },
317
+ connection_type: 'prompt-location',
318
+ code_reference: {
319
+ file: prompt.file,
320
+ symbol: prompt.name,
321
+ symbol_type: 'variable',
322
+ line_start: prompt.line,
323
+ code_snippet: prompt.preview.slice(0, 100),
324
+ },
325
+ description: `Prompt "${prompt.name}" defined in ${prompt.file}`,
326
+ detected_from: 'swift-code-scanner',
327
+ confidence: prompt.confidence,
328
+ timestamp,
329
+ last_verified: timestamp,
330
+ });
331
+ }
332
+ // ---- Build project metadata ----
333
+ const projectMeta = buildProjectMetadata(files, frameworkImports, projectRoot, fragileKeys, entitlementReqs);
334
+ return { components, connections, warnings, projectMeta };
335
+ }
336
+ // =============================================================================
337
+ // STRING KEY DETECTION
338
+ // =============================================================================
339
+ function scanStringKeys(files) {
340
+ const hits = [];
341
+ for (const file of files) {
342
+ for (let i = 0; i < file.lines.length; i++) {
343
+ const line = file.lines[i];
344
+ const trimmed = line.trim();
345
+ // Skip comments
346
+ if (trimmed.startsWith('//') || trimmed.startsWith('*') || trimmed.startsWith('/*'))
347
+ continue;
348
+ // @AppStorage("key") — normalizes to UserDefaults since @AppStorage is a UserDefaults wrapper
349
+ const appStorageMatch = line.match(/@AppStorage\(["']([^"']+)["']\)/);
350
+ if (appStorageMatch) {
351
+ hits.push({
352
+ key: appStorageMatch[1],
353
+ type: 'UserDefaults',
354
+ file: file.relativePath,
355
+ line: i + 1,
356
+ symbol: extractNearestSymbol(file.lines, i) || appStorageMatch[1],
357
+ snippet: trimmed,
358
+ });
359
+ }
360
+ // UserDefaults.standard.set(..., forKey: "key") / .object(forKey: "key") / etc.
361
+ const udWriteMatch = line.match(/UserDefaults\.(?:standard|[a-zA-Z]+)\.(?:set|setValue|removeObject)\([^)]*forKey:\s*["']([^"']+)["']\)/);
362
+ if (udWriteMatch) {
363
+ hits.push({
364
+ key: udWriteMatch[1],
365
+ type: 'UserDefaults',
366
+ file: file.relativePath,
367
+ line: i + 1,
368
+ symbol: extractNearestSymbol(file.lines, i) || udWriteMatch[1],
369
+ snippet: trimmed,
370
+ });
371
+ }
372
+ const udReadMatch = line.match(/UserDefaults\.(?:standard|[a-zA-Z]+)\.(?:object|string|integer|bool|double|float|array|dictionary|data|url)\(forKey:\s*["']([^"']+)["']\)/);
373
+ if (udReadMatch) {
374
+ hits.push({
375
+ key: udReadMatch[1],
376
+ type: 'UserDefaults',
377
+ file: file.relativePath,
378
+ line: i + 1,
379
+ symbol: extractNearestSymbol(file.lines, i) || udReadMatch[1],
380
+ snippet: trimmed,
381
+ });
382
+ }
383
+ // NotificationCenter — .post(name: .someNotification) or Notification.Name("string")
384
+ const notifPostMatch = line.match(/\.post\(name:\s*(?:\.(\w+)|Notification\.Name\(["']([^"']+)["']\))/);
385
+ if (notifPostMatch) {
386
+ const key = notifPostMatch[1] || notifPostMatch[2];
387
+ hits.push({
388
+ key,
389
+ type: 'NotificationCenter',
390
+ file: file.relativePath,
391
+ line: i + 1,
392
+ symbol: extractNearestSymbol(file.lines, i) || key,
393
+ snippet: trimmed,
394
+ });
395
+ }
396
+ const notifObserveMatch = line.match(/\.addObserver\([^)]*name:\s*(?:\.(\w+)|Notification\.Name\(["']([^"']+)["']\))/);
397
+ if (notifObserveMatch) {
398
+ const key = notifObserveMatch[1] || notifObserveMatch[2];
399
+ hits.push({
400
+ key,
401
+ type: 'NotificationCenter',
402
+ file: file.relativePath,
403
+ line: i + 1,
404
+ symbol: extractNearestSymbol(file.lines, i) || key,
405
+ snippet: trimmed,
406
+ });
407
+ }
408
+ // Image("name") or Image(systemName: "name") — asset names
409
+ const imageMatch = line.match(/Image\(\s*["']([^"']+)["']\s*\)/);
410
+ if (imageMatch) {
411
+ hits.push({
412
+ key: imageMatch[1],
413
+ type: 'AssetName',
414
+ file: file.relativePath,
415
+ line: i + 1,
416
+ symbol: extractNearestSymbol(file.lines, i) || imageMatch[1],
417
+ snippet: trimmed,
418
+ });
419
+ }
420
+ // UIImage(named: "name")
421
+ const uiImageMatch = line.match(/UIImage\(named:\s*["']([^"']+)["']\)/);
422
+ if (uiImageMatch) {
423
+ hits.push({
424
+ key: uiImageMatch[1],
425
+ type: 'AssetName',
426
+ file: file.relativePath,
427
+ line: i + 1,
428
+ symbol: extractNearestSymbol(file.lines, i) || uiImageMatch[1],
429
+ snippet: trimmed,
430
+ });
431
+ }
432
+ // Color("name")
433
+ const colorMatch = line.match(/Color\(\s*["']([^"']+)["']\s*\)/);
434
+ if (colorMatch) {
435
+ hits.push({
436
+ key: colorMatch[1],
437
+ type: 'AssetName',
438
+ file: file.relativePath,
439
+ line: i + 1,
440
+ symbol: extractNearestSymbol(file.lines, i) || colorMatch[1],
441
+ snippet: trimmed,
442
+ });
443
+ }
444
+ // NSSound(named: .init("name"))
445
+ const nsSoundMatch = line.match(/NSSound\(named:\s*\.init\(["']([^"']+)["']\)\)/);
446
+ if (nsSoundMatch) {
447
+ hits.push({
448
+ key: nsSoundMatch[1],
449
+ type: 'AssetName',
450
+ file: file.relativePath,
451
+ line: i + 1,
452
+ symbol: extractNearestSymbol(file.lines, i) || nsSoundMatch[1],
453
+ snippet: trimmed,
454
+ });
455
+ }
456
+ // Keychain — kSecAttrService or KeychainAccess
457
+ const keychainMatch = line.match(/(?:kSecAttrService|kSecAttrAccount|Keychain\(service:)\s*(?::|as\s+.+?,\s*)?["']([^"']+)["']/);
458
+ if (keychainMatch) {
459
+ hits.push({
460
+ key: keychainMatch[1],
461
+ type: 'Keychain',
462
+ file: file.relativePath,
463
+ line: i + 1,
464
+ symbol: extractNearestSymbol(file.lines, i) || keychainMatch[1],
465
+ snippet: trimmed,
466
+ });
467
+ }
468
+ }
469
+ }
470
+ return hits;
471
+ }
472
+ // =============================================================================
473
+ // PROTOCOL CONFORMANCE
474
+ // =============================================================================
475
+ function scanProtocolConformance(files) {
476
+ const conformances = [];
477
+ // Well-known protocols worth tracking
478
+ const interestingProtocols = new Set([
479
+ 'ObservableObject', 'Observable', 'Codable', 'Decodable', 'Encodable',
480
+ 'Identifiable', 'Hashable', 'Equatable', 'Comparable',
481
+ 'View', 'App', 'Scene', 'Widget', 'TimelineProvider',
482
+ 'Sendable', 'Actor',
483
+ 'URLSessionDelegate', 'URLSessionDataDelegate',
484
+ ]);
485
+ for (const file of files) {
486
+ for (let i = 0; i < file.lines.length; i++) {
487
+ const line = file.lines[i];
488
+ // Match: struct/class/enum/actor TypeName: Protocol1, Protocol2 {
489
+ const match = line.match(/^\s*(?:(?:public|private|internal|open|final|@\w+)\s+)*(?:struct|class|enum|actor)\s+(\w+)\s*(?:<[^>]*>)?\s*:\s*([^{]+)/);
490
+ if (match) {
491
+ const typeName = match[1];
492
+ const rawProtocols = match[2].split(',').map(p => p.trim()).filter(Boolean);
493
+ const protocols = rawProtocols.filter(p => {
494
+ // Filter out generic superclasses (rough heuristic: known protocols or capitalized single words)
495
+ return interestingProtocols.has(p) || /^[A-Z]\w+(?:Protocol|Delegate|DataSource|able)$/.test(p);
496
+ });
497
+ if (protocols.length > 0) {
498
+ conformances.push({ typeName, protocols, file: file.relativePath, line: i + 1 });
499
+ }
500
+ }
501
+ }
502
+ }
503
+ return conformances;
504
+ }
505
+ // =============================================================================
506
+ // STATE OBSERVATION
507
+ // =============================================================================
508
+ function scanStateObservation(files) {
509
+ const observations = [];
510
+ const wrappers = ['@Published', '@ObservedObject', '@EnvironmentObject', '@StateObject', '@State', '@Binding'];
511
+ for (const file of files) {
512
+ let currentType = '';
513
+ for (let i = 0; i < file.lines.length; i++) {
514
+ const line = file.lines[i];
515
+ // Track current type context
516
+ const typeMatch = line.match(/^\s*(?:(?:public|private|internal|open|final|@\w+)\s+)*(?:struct|class|enum|actor)\s+(\w+)/);
517
+ if (typeMatch) {
518
+ currentType = typeMatch[1];
519
+ }
520
+ for (const wrapper of wrappers) {
521
+ if (!line.includes(wrapper))
522
+ continue;
523
+ // Match: @Published var name: Type
524
+ const propMatch = line.match(new RegExp(`${wrapper.replace('$', '\\$')}\\s+(?:private\\s+|private\\(set\\)\\s+)?var\\s+(\\w+)\\s*(?::\\s*(\\w+))?`));
525
+ if (propMatch) {
526
+ const propName = propMatch[1];
527
+ const propType = propMatch[2] || '';
528
+ // For @Published, the ownerType is the containing type's name (what gets observed)
529
+ // For @ObservedObject/@EnvironmentObject, the propType IS the observed type
530
+ const ownerType = wrapper === '@Published' ? currentType : propType;
531
+ observations.push({
532
+ propertyName: propName,
533
+ wrapper,
534
+ ownerType,
535
+ file: file.relativePath,
536
+ line: i + 1,
537
+ });
538
+ }
539
+ }
540
+ }
541
+ }
542
+ return observations;
543
+ }
544
+ // =============================================================================
545
+ // LLM CALL DETECTION
546
+ // =============================================================================
547
+ function scanLLMCalls(files) {
548
+ const calls = [];
549
+ for (const file of files) {
550
+ for (let i = 0; i < file.lines.length; i++) {
551
+ const line = file.lines[i];
552
+ const trimmed = line.trim();
553
+ // Skip comments
554
+ if (trimmed.startsWith('//') || trimmed.startsWith('*'))
555
+ continue;
556
+ // Check URL patterns in string literals
557
+ for (const { pattern, provider } of LLM_URL_PATTERNS) {
558
+ if (pattern.test(line)) {
559
+ calls.push({
560
+ provider,
561
+ url: line.match(/"([^"]*)"/)?.[1],
562
+ file: file.relativePath,
563
+ line: i + 1,
564
+ symbol: extractNearestSymbol(file.lines, i) || 'urlRequest',
565
+ snippet: trimmed,
566
+ });
567
+ }
568
+ }
569
+ // Check SDK import patterns
570
+ for (const { pattern, provider } of LLM_IMPORT_PATTERNS) {
571
+ if (pattern.test(trimmed)) {
572
+ calls.push({
573
+ provider,
574
+ file: file.relativePath,
575
+ line: i + 1,
576
+ symbol: `import ${provider}`,
577
+ snippet: trimmed,
578
+ });
579
+ }
580
+ }
581
+ // Check SDK call patterns
582
+ for (const { pattern, provider } of LLM_CALL_PATTERNS) {
583
+ if (pattern.test(line)) {
584
+ calls.push({
585
+ provider,
586
+ file: file.relativePath,
587
+ line: i + 1,
588
+ symbol: extractNearestSymbol(file.lines, i) || provider,
589
+ snippet: trimmed,
590
+ });
591
+ }
592
+ }
593
+ }
594
+ }
595
+ // Deduplicate by file+provider (keep first occurrence)
596
+ const seen = new Set();
597
+ return calls.filter(c => {
598
+ const key = `${c.file}:${c.provider}`;
599
+ if (seen.has(key))
600
+ return false;
601
+ seen.add(key);
602
+ return true;
603
+ });
604
+ }
605
+ // =============================================================================
606
+ // FRAMEWORK IMPORT SCANNING (for entitlement detection)
607
+ // =============================================================================
608
+ function scanFrameworkImports(files) {
609
+ const results = [];
610
+ const entitlementFrameworks = new Set(Object.keys(FRAMEWORK_ENTITLEMENTS));
611
+ for (const file of files) {
612
+ for (let i = 0; i < file.lines.length; i++) {
613
+ const match = file.lines[i].match(/^\s*import\s+(\w+)/);
614
+ if (match && entitlementFrameworks.has(match[1])) {
615
+ results.push({ framework: match[1], file: file.relativePath, line: i + 1 });
616
+ }
617
+ }
618
+ }
619
+ // Deduplicate by framework (keep first)
620
+ const seen = new Set();
621
+ return results.filter(r => {
622
+ if (seen.has(r.framework))
623
+ return false;
624
+ seen.add(r.framework);
625
+ return true;
626
+ });
627
+ }
628
+ // =============================================================================
629
+ // PROMPT DETECTION IN SWIFT
630
+ // =============================================================================
631
+ function scanSwiftPrompts(files) {
632
+ const prompts = [];
633
+ for (const file of files) {
634
+ for (let i = 0; i < file.lines.length; i++) {
635
+ const line = file.lines[i];
636
+ // Match: static let systemPrompt = """ ... """
637
+ // Match: let prompt = "You are a..."
638
+ // Match: var SYSTEM_PROMPT = """
639
+ const promptVarMatch = line.match(/(?:static\s+)?(?:let|var)\s+(\w*(?:[Pp]rompt|[Ss]ystem|[Ii]nstruction)\w*)\s*(?::\s*String)?\s*=\s*(".*"|""")/);
640
+ if (promptVarMatch) {
641
+ const name = promptVarMatch[1];
642
+ let preview = promptVarMatch[2];
643
+ // For multi-line strings, grab more lines
644
+ if (preview === '"""') {
645
+ const nextLines = [];
646
+ for (let j = i + 1; j < Math.min(i + 10, file.lines.length); j++) {
647
+ if (file.lines[j].includes('"""'))
648
+ break;
649
+ nextLines.push(file.lines[j].trim());
650
+ }
651
+ preview = nextLines.join(' ').slice(0, 200);
652
+ }
653
+ prompts.push({
654
+ name,
655
+ file: file.relativePath,
656
+ line: i + 1,
657
+ preview: preview.replace(/^"|"$/g, '').slice(0, 200),
658
+ confidence: 0.85,
659
+ });
660
+ }
661
+ // Match: "role": "system" or role: .system in messages arrays
662
+ if (/role.*system/i.test(line) && /content|message/i.test(file.lines[Math.min(i + 1, file.lines.length - 1)] || '')) {
663
+ const name = extractNearestSymbol(file.lines, i) || `prompt_${file.relativePath}:${i + 1}`;
664
+ prompts.push({
665
+ name,
666
+ file: file.relativePath,
667
+ line: i + 1,
668
+ preview: line.trim().slice(0, 200),
669
+ confidence: 0.7,
670
+ });
671
+ }
672
+ }
673
+ }
674
+ return prompts;
675
+ }
676
+ // =============================================================================
677
+ // PROJECT METADATA BUILDER
678
+ // =============================================================================
679
+ function buildProjectMetadata(files, frameworkImports, projectRoot, fragileKeys, entitlementReqs) {
680
+ const meta = { type: 'swift-app' };
681
+ // Detect platforms from framework usage
682
+ const platforms = new Set();
683
+ const allImports = new Set();
684
+ for (const file of files) {
685
+ for (const line of file.lines) {
686
+ const m = line.match(/^\s*import\s+(\w+)/);
687
+ if (m)
688
+ allImports.add(m[1]);
689
+ }
690
+ }
691
+ if (allImports.has('UIKit') || allImports.has('SwiftUI'))
692
+ platforms.add('iOS');
693
+ if (allImports.has('AppKit'))
694
+ platforms.add('macOS');
695
+ if (allImports.has('WatchKit'))
696
+ platforms.add('watchOS');
697
+ if (allImports.has('WidgetKit'))
698
+ platforms.add('iOS'); // Widgets are iOS typically
699
+ // SwiftUI can be any platform — check for platform-specific APIs
700
+ if (allImports.has('SwiftUI') && !allImports.has('UIKit') && !allImports.has('AppKit')) {
701
+ platforms.add('iOS'); // Default assumption for SwiftUI-only
702
+ platforms.add('macOS');
703
+ }
704
+ meta.platforms = [...platforms];
705
+ // Detect architecture pattern
706
+ if (allImports.has('ComposableArchitecture')) {
707
+ meta.architecture_pattern = 'TCA (Composable Architecture)';
708
+ }
709
+ else {
710
+ // Check for MVVM indicators: ObservableObject/Observable classes separate from Views
711
+ const hasObservableObjects = files.some(f => f.content.includes('ObservableObject') || f.content.includes('@Observable'));
712
+ const hasViews = files.some(f => f.content.includes(': View'));
713
+ if (hasObservableObjects && hasViews) {
714
+ meta.architecture_pattern = 'MVVM';
715
+ }
716
+ else if (allImports.has('UIKit') && files.some(f => f.content.includes(': UIViewController'))) {
717
+ meta.architecture_pattern = 'MVC';
718
+ }
719
+ }
720
+ // Detect deployment target from Package.swift
721
+ try {
722
+ const pkgSwiftPath = path.join(projectRoot, 'Package.swift');
723
+ if (fs.existsSync(pkgSwiftPath)) {
724
+ const pkgContent = fs.readFileSync(pkgSwiftPath, 'utf-8');
725
+ const deployments = {};
726
+ const platformMatches = pkgContent.matchAll(/\.(iOS|macOS|watchOS|tvOS|visionOS)\("([^"]+)"\)/g);
727
+ for (const m of platformMatches) {
728
+ deployments[m[1]] = m[2];
729
+ }
730
+ const platformMatchesV2 = pkgContent.matchAll(/\.(iOS|macOS|watchOS|tvOS|visionOS)\(\.v(\d+)/g);
731
+ for (const m of platformMatchesV2) {
732
+ deployments[m[1]] = `${m[2]}.0`;
733
+ }
734
+ if (Object.keys(deployments).length > 0) {
735
+ meta.min_deployment = deployments;
736
+ }
737
+ }
738
+ }
739
+ catch {
740
+ // Skip if unreadable
741
+ }
742
+ // Parse targets from Package.swift
743
+ try {
744
+ const pkgSwiftPath = path.join(projectRoot, 'Package.swift');
745
+ if (fs.existsSync(pkgSwiftPath)) {
746
+ const pkgContent = fs.readFileSync(pkgSwiftPath, 'utf-8');
747
+ const targets = [];
748
+ const targetMatches = pkgContent.matchAll(/\.(?:executableTarget|target|testTarget)\(\s*name:\s*"([^"]+)"/g);
749
+ for (const m of targetMatches) {
750
+ const targetType = m[0].includes('testTarget') ? 'test' : m[0].includes('executableTarget') ? 'executable' : 'library';
751
+ targets.push({ name: m[1], type: targetType, dependencies: [] });
752
+ }
753
+ if (targets.length > 0) {
754
+ meta.targets = targets;
755
+ }
756
+ }
757
+ }
758
+ catch {
759
+ // Skip
760
+ }
761
+ // Entitlements
762
+ if (entitlementReqs.length > 0) {
763
+ meta.entitlements = entitlementReqs.map(r => ({ key: r.key, file: r.framework }));
764
+ }
765
+ // Fragile keys
766
+ meta.fragile_keys = fragileKeys;
767
+ return meta;
768
+ }
769
+ // =============================================================================
770
+ // HELPERS
771
+ // =============================================================================
772
+ function extractNearestSymbol(lines, lineIndex) {
773
+ // Look backwards for func/var/let/class/struct declaration
774
+ for (let j = lineIndex; j >= Math.max(0, lineIndex - 5); j--) {
775
+ const funcMatch = lines[j].match(/(?:func|var|let|class|struct|enum)\s+(\w+)/);
776
+ if (funcMatch)
777
+ return funcMatch[1];
778
+ }
779
+ return undefined;
780
+ }
781
+ function groupByKey(hits) {
782
+ const groups = new Map();
783
+ for (const hit of hits) {
784
+ const key = `${hit.type}:${hit.key}`;
785
+ if (!groups.has(key))
786
+ groups.set(key, []);
787
+ groups.get(key).push(hit);
788
+ }
789
+ return groups;
790
+ }
791
+ function buildFragileKeys(hits) {
792
+ const groups = groupByKey(hits);
793
+ const fragile = [];
794
+ for (const [key, keyHits] of groups) {
795
+ fragile.push({
796
+ key,
797
+ type: keyHits[0].type,
798
+ files: [...new Set(keyHits.map(h => h.file))],
799
+ });
800
+ }
801
+ return fragile.length > 0 ? fragile : undefined;
802
+ }
803
+ //# sourceMappingURL=code-scanner.js.map