Explorar o código

Initial commit

clanker hai 1 mes
achega
d2adb80392

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+/builddir

+ 674 - 0
LICENSE

@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<https://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<https://www.gnu.org/licenses/why-not-lgpl.html>.

+ 354 - 0
README.md

@@ -0,0 +1,354 @@
+# Valaq - VAPI File Query Tool
+
+Valaq is a powerful command-line tool for querying and exploring VAPI (Vala API) files. It provides hierarchical navigation of symbols within VAPI files with support for both human-readable and JSON output formats. Built with libvala for accurate VAPI parsing and symbol extraction.
+
+## Features
+
+- **VAPI File Discovery**: Automatically discovers VAPI files in standard system directories
+- **Symbol Navigation**: Hierarchical exploration of namespaces, classes, methods, and more
+- **Flexible Output**: Both human-readable text and structured JSON output formats
+- **Smart File Resolution**: Supports full paths, basenames with/without extensions
+- **Comprehensive Symbol Support**: Handles all major Vala language constructs
+- **Path-based Navigation**: Intuitive symbol traversal using space or dot-separated paths
+
+## Installation
+
+### Prerequisites
+
+Valaq requires the following dependencies:
+
+- Vala compiler (valac) 0.56 or later
+- libvala-0.56 development package
+- GLib 2.0 development libraries
+- JSON-GLib 1.0 development libraries
+- libgee 0.8 development libraries
+- Meson build system
+- Ninja build system
+
+On Ubuntu/Debian systems:
+
+```bash
+sudo apt-get install valac libvala-0.56-dev libglib2.0-dev libjson-glib-dev libgee-0.8-dev meson ninja-build
+```
+
+On Fedora/RHEL systems:
+
+```bash
+sudo dnf install vala libvala-devel glib2-devel json-glib-devel libgee-devel meson ninja
+```
+
+### Building from Source
+
+```bash
+# Clone the repository
+git clone https://github.com/your-repo/valaq.git
+cd valaq
+
+# Setup build directory
+meson setup builddir
+
+# Compile
+meson compile -C builddir
+
+# Run tests (optional)
+meson test -C builddir
+
+# Install
+sudo meson install -C builddir
+```
+
+## Usage
+
+### Basic Commands
+
+#### List Available VAPI Files
+
+```bash
+# List all available VAPI files in text format
+valaq
+
+# List VAPI files in JSON format
+valaq --json
+```
+
+#### Explore VAPI Files
+
+```bash
+# List top-level symbols using basename without extension
+valaq gtk+-3.0
+
+# List top-level symbols using basename with extension
+valaq gtk+-3.0.vapi
+
+# List top-level symbols using full path
+valaq /usr/share/vala/vapi/gtk+-3.0.vapi
+```
+
+#### Navigate to Specific Symbols
+
+```bash
+# Navigate to a class (space-separated)
+valaq gtk+-3.0 Gtk Window
+
+# Navigate to a method (dot-separated)
+valaq gtk+-3.0 Gtk.Window.show
+
+# Navigate using mixed separators
+valaq gtk+-3.0 Gtk.Window show
+
+# Get JSON output for symbol details
+valaq json-glib-1.0 Json.Object --json
+```
+
+### Command-Line Options
+
+- `-h, --help`: Show help message and exit
+- `-v, --version`: Show version information and exit
+- `-j, --json`: Output in JSON format instead of human-readable text
+
+### Symbol Path Formats
+
+Symbol paths can be specified using spaces or dots as separators:
+
+**Space-separated:**
+```bash
+valaq gtk+-3.0 Gtk Window show
+# Navigates to Gtk -> Window -> show
+```
+
+**Dot-separated:**
+```bash
+valaq gtk+-3.0 Gtk.Window.show
+# Same navigation using dot notation
+```
+
+**Mixed separators:**
+```bash
+valaq gtk+-3.0 Gtk.Window show
+# Combines both formats
+```
+
+### Supported Symbol Types
+
+Valaq supports all major Vala language constructs:
+
+- **Namespaces**: Containers for related symbols
+- **Classes**: Object-oriented class definitions
+- **Interfaces**: Abstract interfaces for classes
+- **Structs**: Value type structures
+- **Enums**: Enumeration types with named values
+- **Delegates**: Function pointer types
+- **Methods**: Member functions with parameters
+- **Properties**: Object properties with getters/setters
+- **Fields**: Member variables
+- **Constants**: Compile-time constant values
+
+### VAPI File Discovery
+
+Valaq automatically searches for VAPI files in standard directories:
+
+- Primary: `/usr/share/vala-0.56/vapi`
+- Secondary: `/usr/share/vala/vapi`
+- Fallbacks: `/usr/share/vala-0.54/vapi`, `/usr/share/vala-0.52/vapi`, `/usr/local/share/vala/vapi`
+
+Run `valaq` with no arguments to see all available VAPI files.
+
+## Examples
+
+### Basic Exploration
+
+```bash
+# List all available VAPI files
+valaq
+
+# Explore GLib namespace
+valaq glib-2.0
+
+# View method details with parameters
+valaq glib-2.0 GLib.Timeout.add
+
+# Examine enum values
+valaq glib-2.0 GLib.FileType
+```
+
+### JSON Output
+
+```bash
+# Get VAPI file list in JSON
+valaq --json
+
+# Get symbol details in JSON format
+valaq json-glib-1.0 Json.Object --json
+
+# JSON output for method with full signature
+valaq gtk+-3.0 Gtk.Window.show --json
+```
+
+### Advanced Navigation
+
+```bash
+# Navigate to nested symbols with dots in names
+valaq package-name Namespace.Class
+
+# Explore namespace contents
+valaq gio-2.0 GLib
+
+# Drill down into specific class methods
+valaq gtk+-3.0 Gtk.Button Button_clicked
+```
+
+## Output Formats
+
+### Text Output
+
+Human-readable output with hierarchical symbol listing:
+
+```
+VAPI file: gtk+-3.0.vapi
+Symbols:
+  Gtk
+    Window
+      show() -> void
+      hide() -> void
+      destroy() -> void
+    Button
+      clicked() -> void
+      set_label(string) -> void
+```
+
+### JSON Output
+
+Structured JSON output for programmatic use:
+
+```json
+{
+  "result_type": "symbol_details",
+  "vapi_file": "gtk+-3.0.vapi",
+  "query_path": ["Gtk", "Window"],
+  "symbol": {
+    "name": "Window",
+    "type": "class",
+    "access": "public",
+    "base_types": ["Bin"],
+    "methods": [
+      {
+        "name": "show",
+        "return_type": "void",
+        "parameters": []
+      }
+    ],
+    "properties": [...],
+    "fields": [...]
+  },
+  "metadata": {
+    "vala_version": "0.56",
+    "timestamp": "2023-..."
+  }
+}
+```
+
+## Exit Codes
+
+- `0`: Success
+- `1`: General error (invalid arguments, file not found, etc.)
+- `2`: Parse error (invalid VAPI file syntax)
+
+## Troubleshooting
+
+### VAPI Files Not Found
+
+If VAPI files are not found:
+
+```bash
+# Run 'valaq' with no arguments to see available files
+valaq
+
+# Use full path to specific file
+valaq /path/to/your/file.vapi
+
+# Check if vala development packages are installed
+dpkg -l | grep libvala
+```
+
+### Symbol Navigation Issues
+
+If symbols are not found:
+
+```bash
+# Check symbol name case (case-sensitive)
+valaq gtk+-3.0 Gtk.Window
+
+# List top-level symbols first to verify names
+valaq gtk+-3.0
+
+# Verify symbol path hierarchy
+valaq gtk+-3.0 Gtk
+valaq gtk+-3.0 Gtk.Window
+valaq gtk+-3.0 Gtk.Window.show
+```
+
+### File Resolution
+
+Valaq supports multiple file reference formats:
+
+- **Full path**: `/usr/share/vala/vapi/gtk+-3.0.vapi`
+- **Basename with extension**: `gtk+-3.0.vapi`
+- **Basename without extension**: `gtk+-3.0`
+
+The tool searches in standard VAPI directories and current working directory.
+
+## Development
+
+### Running Tests
+
+```bash
+# Run all tests
+meson test -C builddir
+
+# Run specific test
+meson test -C builddir test-vapi-parser
+```
+
+### Project Structure
+
+```
+valaq/
+├── src/
+│   ├── main.vala              # Application entry point
+│   ├── cli/
+│   │   ├── argument-parser.vala    # Command-line argument parsing
+│   │   └── command-handler.vala   # Command processing logic
+│   ├── core/
+│   │   ├── vapi-parser.vala        # VAPI file parsing using libvala
+│   │   ├── symbol-navigator.vala   # Symbol hierarchy navigation
+│   │   └── symbol-model.vala       # Data models for symbols
+│   ├── output/
+│   │   ├── formatter.vala          # Output formatting interface
+│   │   ├── text-formatter.vala     # Human-readable output
+│   │   └── json-formatter.vala     # JSON output formatting
+│   └── utils/
+│       ├── file-utils.vala         # File system operations
+│       └── error-handling.vala     # Error handling utilities
+├── tests/                     # Unit tests
+├── meson.build               # Build configuration
+└── README.md
+```
+
+## Contributing
+
+1. Fork the repository
+2. Create a feature branch
+3. Make your changes
+4. Add tests for new functionality
+5. Ensure all tests pass
+6. Submit a pull request
+
+## License
+
+This project is licensed under the GPLv3 License. See the LICENSE file for details.
+
+## Acknowledgments
+
+- Built with [libvala](https://wiki.gnome.org/Projects/Vala) for accurate VAPI parsing
+- Uses [GLib](https://docs.gtk.org/glib/) for core functionality
+- JSON output powered by [JSON-GLib](https://docs.gtk.org/json-glib/)

+ 483 - 0
architecture-plan.md

@@ -0,0 +1,483 @@
+# Valaq CLI Application - Architecture Plan
+
+## 1. Overview
+
+The `valaq` CLI application is a tool for querying and exploring VAPI (Vala API) files. It provides hierarchical navigation of symbols within VAPI files with support for both human-readable and JSON output formats.
+
+## 2. Core Application Components
+
+### 2.1 Main Components
+
+1. **CLI Interface Layer** - Handles command-line argument parsing and user interaction
+2. **VAPI Parser Engine** - Uses libvala to parse and analyze VAPI files
+3. **Symbol Navigator** - Manages hierarchical symbol traversal and filtering
+4. **Output Formatter** - Generates both human-readable and JSON output
+5. **File System Interface** - Handles VAPI file discovery and access
+
+### 2.2 Component Architecture
+
+```
+┌─────────────────┐
+│   CLI Interface │
+└─────────┬───────┘
+          │
+┌─────────▼───────┐
+│ Symbol Navigator│
+└─────────┬───────┘
+          │
+┌─────────▼───────┐
+│ VAPI Parser     │
+│ (libvala)       │
+└─────────┬───────┘
+          │
+┌─────────▼───────┐
+│ File System     │
+│ Interface       │
+└─────────────────┘
+```
+
+## 3. Project File Structure
+
+```
+valaq/
+├── src/
+│   ├── main.vala              # Application entry point
+│   ├── cli/
+│   │   ├── argument-parser.vala    # Command-line argument parsing
+│   │   └── command-handler.vala   # Command processing logic
+│   ├── core/
+│   │   ├── vapi-parser.vala        # VAPI file parsing using libvala
+│   │   ├── symbol-navigator.vala   # Symbol hierarchy navigation
+│   │   └── symbol-model.vala       # Data models for symbols
+│   ├── output/
+│   │   ├── formatter.vala          # Output formatting interface
+│   │   ├── text-formatter.vala     # Human-readable output
+│   │   └── json-formatter.vala     # JSON output formatting
+│   └── utils/
+│       ├── file-utils.vala         # File system operations
+│       └── error-handling.vala     # Error handling utilities
+├── tests/
+│   ├── test-vapi-parser.vala
+│   ├── test-symbol-navigator.vala
+│   └── test-output-formatters.vala
+├── meson.build               # Build configuration
+└── README.md
+```
+
+## 4. Key Classes and Responsibilities
+
+### 4.1 Main Application Classes
+
+#### `ValaqApplication`
+- **Responsibility**: Main application entry point and initialization
+- **Key Methods**: 
+  - `main(string[] args)` - Application entry point
+  - `run()` - Main application loop
+
+#### `ArgumentParser`
+- **Responsibility**: Parse and validate command-line arguments
+- **Key Methods**:
+  - `parse(string[] args)` - Parse command line arguments
+  - `get_vapi_path()` - Get VAPI file path from arguments
+  - `get_symbol_path()` - Get symbol navigation path
+  - `is_json_output()` - Check if JSON output requested
+
+#### `VapiParser`
+- **Responsibility**: Parse VAPI files using libvala
+- **Key Methods**:
+  - `parse_file(string path)` - Parse a VAPI file
+  - `get_root_symbols()` - Get top-level symbols
+  - `get_symbol_details(Symbol symbol)` - Get detailed symbol information
+
+#### `SymbolNavigator`
+- **Responsibility**: Navigate symbol hierarchy and filter results
+- **Key Methods**:
+  - `navigate_to_path(string[] path)` - Navigate to symbol path
+  - `get_child_symbols(Symbol parent)` - Get child symbols
+  - `find_symbol_by_name(string name)` - Find symbol by name
+
+#### `TextFormatter` / `JsonFormatter`
+- **Responsibility**: Format output in different formats
+- **Key Methods**:
+  - `format_symbol_list(Symbol[] symbols)` - Format symbol list
+  - `format_symbol_details(Symbol symbol)` - Format symbol details
+
+### 4.2 Data Model Classes
+
+#### `Symbol`
+- Base class for all symbol types
+- **Properties**: name, symbol_type, access_modifier, parent, children
+
+#### `Class`, `Interface`, `Struct`, `Enum`, `Delegate`, `Method`, `Property`, `Field`
+- Specialized symbol types extending base Symbol class
+- **Specific Properties**: return_type, parameters, etc.
+
+## 5. Data Flow
+
+### 5.1 Application Flow
+
+```mermaid
+graph TD
+    A[CLI Arguments] --> B[ArgumentParser]
+    B --> C{No parameters?}
+    C -->|Yes| D[List VAPI files]
+    C -->|No| E{VAPI file only?}
+    E -->|Yes| F[List toplevel symbols]
+    E -->|No| G[Navigate to symbol path]
+    G --> H[Display symbol details]
+    D --> I[Output Formatter]
+    F --> I
+    H --> I
+    I --> J[Display Results]
+```
+
+### 5.2 VAPI Parsing Flow
+
+```mermaid
+graph TD
+    A[VAPI File] --> B[VapiParser]
+    B --> C[libvala CodeContext]
+    C --> D[Symbol Resolution]
+    D --> E[Build Symbol Tree]
+    E --> F[SymbolNavigator]
+    F --> G[Query/Navigation]
+    G --> H[Output Formatter]
+```
+
+## 6. VAPI Parsing Strategy Using libvala
+
+### 6.1 libvala Integration
+- Use `Vala.CodeContext` as the main parsing context
+- Leverage `Vala.SourceFile` for VAPI file loading
+- Utilize `Vala.SymbolResolver` for symbol resolution
+- Access `Vala.Namespace` and other symbol types through the API
+
+### 6.2 Parsing Process
+1. Initialize `CodeContext` with appropriate reporter
+2. Add VAPI file to context using `add_source_file()`
+3. Run the parser and symbol resolver
+4. Extract symbols from the root namespace
+5. Build internal symbol model for navigation
+
+### 6.3 Symbol Type Mapping
+- Map libvala symbol types to internal model:
+  - `Vala.Class` → `Class` model
+  - `Vala.Interface` → `Interface` model
+  - `Vala.Method` → `Method` model
+  - `Vala.Property` → `Property` model
+  - etc.
+
+## 7. JSON Output Format Design
+
+### 7.1 Top-level Structure
+```json
+{
+  "vapi_file": "path/to/file.vapi",
+  "query_path": ["symbol1", "symbol2"],
+  "result_type": "symbol_list|symbol_details|file_list",
+  "symbols": [...],
+  "metadata": {
+    "vala_version": "0.56",
+    "timestamp": "2023-..."
+  }
+}
+```
+
+### 7.2 Symbol Representation
+```json
+{
+  "name": "symbol_name",
+  "type": "class|interface|method|property|enum|delegate|field|constant",
+  "access": "public|private|protected|internal",
+  "return_type": "ReturnType",
+  "parameters": [
+    {
+      "name": "param_name",
+      "type": "ParamType",
+      "direction": "in|out|ref",
+      "default_value": "optional"
+    }
+  ],
+  "properties": [...],
+  "methods": [...],
+  "fields": [...],
+  "base_types": ["BaseClass1", "Interface1"],
+  "source_location": {
+    "file": "file.vapi",
+    "line": 123
+  },
+  "documentation": "Symbol documentation comment"
+}
+```
+
+### 7.3 File List Format
+```json
+{
+  "result_type": "file_list",
+  "vapi_directory": "/usr/share/vala-0.56/vapi",
+  "files": [
+    {
+      "name": "gtk+-3.0.vapi",
+      "path": "/usr/share/vala-0.56/vapi/gtk+-3.0.vapi",
+      "size": 123456,
+      "modified": "2023-..."
+    }
+  ]
+}
+```
+
+## 8. Error Handling Strategy
+
+### 8.1 Error Types
+- **File System Errors**: Missing VAPI files, permission issues
+- **Parsing Errors**: Invalid VAPI syntax, libvala parsing failures
+- **Navigation Errors**: Invalid symbol paths, symbol not found
+- **Output Errors**: JSON formatting issues
+
+### 8.2 Error Response Format
+```json
+{
+  "error": {
+    "type": "file_not_found|parse_error|navigation_error",
+    "message": "Human readable error message",
+    "details": {
+      "file_path": "path/to/file.vapi",
+      "symbol_path": ["symbol1", "symbol2"],
+      "line_number": 123
+    }
+  }
+}
+```
+
+## 9. Performance Considerations
+
+### 9.1 Caching Strategy
+- Cache parsed VAPI files in memory during session
+- Consider persistent caching for frequently accessed files
+- Lazy loading of symbol details when drilling down
+
+### 9.2 Memory Management
+- Efficient symbol tree representation
+- Proper cleanup of libvala resources
+- Streamlined JSON output generation
+
+## 10. Extensibility Points
+
+### 10.1 Plugin Architecture
+- Pluggable output formatters
+- Custom symbol filters
+- Additional VAPI source locations
+
+### 10.2 Future Enhancements
+- Symbol search functionality
+- Cross-reference analysis
+- Documentation generation
+- Integration with IDEs
+
+## 11. Build System Configuration
+
+### 11.1 Meson Build Requirements
+- Vala compiler (valac)
+- libvala-0.56 dependency
+- JSON-GLib for JSON output
+- POSIX system for file operations
+
+### 11.2 Build Targets
+- `valaq` executable
+- Unit tests
+- Documentation generation
+- Installation scripts
+
+## 12. Testing Strategy
+
+### 12.1 Unit Tests
+- VAPI parser testing with sample files
+- Symbol navigation logic
+- Output formatter validation
+- Error handling scenarios
+
+### 12.2 Integration Tests
+- End-to-end CLI testing
+- Real VAPI file testing
+- Performance benchmarks
+- JSON output validation
+
+## 13. Security Considerations
+
+### 13.1 File System Access
+- Validate file paths to prevent directory traversal
+- Check file permissions before access
+- Limit access to intended VAPI directories
+
+### 13.2 Input Validation
+- Sanitize command-line arguments
+- Validate symbol paths
+- Prevent injection attacks in JSON output
+
+## 14. Deployment and Distribution
+
+### 14.1 Packaging
+- System package integration (deb, rpm, etc.)
+- Standalone binary distribution
+- Container image options
+
+### 14.2 Installation
+- Default VAPI path detection
+- Configuration file support
+- Environment variable handling
+
+## 15. Sample Meson Build Configuration
+
+### 15.1 Main meson.build
+```meson
+project('valaq', 'vala', 'c',
+  version: '1.0.0',
+  license: 'GPLv3',
+  default_options: ['warning_level=2', 'werror=false'],
+)
+
+# Dependencies
+glib_dep = dependency('glib-2.0', version: '>= 2.56')
+gobject_dep = dependency('gobject-2.0', version: '>= 2.56')
+json_glib_dep = dependency('json-glib-1.0', version: '>= 1.0')
+libvala_dep = dependency('libvala-0.56', version: '>= 0.56.0')
+
+# Source files
+sources = files(
+  'src/main.vala',
+  'src/cli/argument-parser.vala',
+  'src/cli/command-handler.vala',
+  'src/core/vapi-parser.vala',
+  'src/core/symbol-navigator.vala',
+  'src/core/symbol-model.vala',
+  'src/output/formatter.vala',
+  'src/output/text-formatter.vala',
+  'src/output/json-formatter.vala',
+  'src/utils/file-utils.vala',
+  'src/utils/error-handling.vala',
+)
+
+# Vala compilation flags
+vala_args = [
+  '--target-glib=2.56',
+  '--pkg', 'glib-2.0',
+  '--pkg', 'gobject-2.0',
+  '--pkg', 'json-glib-1.0',
+  '--pkg', 'libvala-0.56',
+]
+
+# Executable
+executable('valaq',
+  sources,
+  dependencies: [glib_dep, gobject_dep, json_glib_dep, libvala_dep],
+  vala_args: vala_args,
+  install: true,
+)
+
+# Test configuration
+test_dependencies = [glib_dep, gobject_dep, json_glib_dep, libvala_dep]
+
+test_sources = files(
+  'tests/test-vapi-parser.vala',
+  'tests/test-symbol-navigator.vala',
+  'tests/test-output-formatters.vala',
+)
+
+foreach test_file : test_sources
+  test_name = test_file.split('/')[-1].split('.')[0]
+  test(test_name,
+    executable(test_name,
+      test_file,
+      dependencies: test_dependencies,
+      vala_args: vala_args,
+    )
+endforeach
+```
+
+### 15.2 Build Requirements
+- Vala compiler 0.56 or later
+- Meson build system 0.50 or later
+- Ninja build system
+- Required development packages:
+  - libglib2.0-dev
+  - libjson-glib-dev
+  - libvala-0.56-dev
+  - pkg-config
+
+### 15.3 Build Commands
+```bash
+# Setup build directory
+meson setup builddir
+
+# Compile
+meson compile -C builddir
+
+# Run tests
+meson test -C builddir
+
+# Install
+meson install -C builddir
+```
+
+## 16. Implementation Roadmap
+
+### 16.1 Phase 1: Core Foundation
+1. **Project Setup**
+   - Initialize Meson build system
+   - Create basic directory structure
+   - Set up dependencies and compilation
+
+2. **Basic VAPI Parsing**
+   - Implement VapiParser class using libvala
+   - Create basic Symbol model classes
+   - Test with simple VAPI files
+
+3. **CLI Framework**
+   - Implement ArgumentParser for command-line handling
+   - Create basic CommandHandler
+   - Add simple file listing functionality
+
+### 16.2 Phase 2: Navigation and Output
+1. **Symbol Navigation**
+   - Implement SymbolNavigator for hierarchical traversal
+   - Add symbol path resolution logic
+   - Implement filtering and search capabilities
+
+2. **Output Formatters**
+   - Create TextFormatter for human-readable output
+   - Implement JsonFormatter for structured output
+   - Add error handling and validation
+
+### 16.3 Phase 3: Advanced Features
+1. **Performance Optimization**
+   - Implement caching mechanisms
+   - Optimize memory usage
+   - Add lazy loading for large VAPI files
+
+2. **Testing and Validation**
+   - Comprehensive unit test suite
+   - Integration tests with real VAPI files
+   - Performance benchmarking
+
+3. **Documentation and Distribution**
+   - User documentation and examples
+   - Packaging for distribution
+   - CI/CD pipeline setup
+
+## 17. Summary
+
+The `valaq` CLI application architecture provides a solid foundation for building a comprehensive VAPI file exploration tool. The key architectural decisions include:
+
+1. **libvala Integration**: Leveraging the official Vala library ensures accurate and reliable VAPI parsing without reinventing the wheel.
+
+2. **Modular Design**: Clear separation of concerns between CLI interface, parsing, navigation, and output formatting makes the codebase maintainable and extensible.
+
+3. **Hierarchical Navigation**: The symbol navigator provides intuitive traversal of VAPI file structures, supporting both simple listing and deep exploration.
+
+4. **Flexible Output**: Support for both human-readable and JSON output formats makes the tool suitable for interactive use and programmatic integration.
+
+5. **Performance Considerations**: Caching and lazy loading strategies ensure good performance even with large VAPI files.
+
+6. **Extensibility**: The plugin architecture and modular design allow for future enhancements without major refactoring.
+
+This architecture plan provides a comprehensive roadmap for implementing the `valaq` CLI application, addressing all the specified requirements while maintaining flexibility for future enhancements.

+ 304 - 0
man/valaq.1

@@ -0,0 +1,304 @@
+.\" valaq.1 - VAPI File Query Tool man page
+.\"
+.\" Copyright (C) 2023 Valaq Project
+.\" License: GPLv3
+.\"
+.TH VALAQ 1 "2023-12-10" "valaq 1.0.0" "User Commands"
+.SH NAME
+valaq \- VAPI File Query Tool for exploring Vala API files
+.SH SYNOPSIS
+.B valaq
+[\fIOPTIONS\fR] [\fIVAPI_FILE\fR] [\fISYMBOL_PATH\fR...]
+.SH DESCRIPTION
+.B valaq
+is a powerful command-line tool for querying and exploring VAPI (Vala API) files.
+It provides hierarchical navigation of symbols within VAPI files with support for both
+human-readable and JSON output formats. Built with libvala for accurate VAPI parsing
+and symbol extraction.
+
+When run without arguments,
+.B valaq
+lists all available VAPI files in the standard search paths. When a VAPI file is
+specified, it displays the symbols contained in that file. Symbol paths can be used
+to navigate to specific symbols within the hierarchy.
+
+.SH OPTIONS
+.TP
+.B \-h, \-\-help
+Show this help message and exit.
+.TP
+.B \-v, \-\-version
+Show version information and exit.
+.TP
+.B \-j, \-\-json
+Output in JSON format instead of human-readable text.
+
+.SH ARGUMENTS
+.TP
+.B VAPI_FILE
+Path to a VAPI file to analyze. Can be:
+.RS
+.IP \(bu 2
+Full path: \fI/usr/share/vala/vapi/gtk+-3.0.vapi\fR
+.IP \(bu 2
+Basename with extension: \fIgtk+-3.0.vapi\fR
+.IP \(bu 2
+Basename without extension: \fIgtk+-3.0\fR
+.RE
+
+.TP
+.B SYMBOL_PATH...
+Hierarchical path to a symbol. Supports both space-separated and dot-separated paths.
+
+.SH SYMBOL PATH FORMATS
+Symbol paths can be specified using spaces or dots as separators:
+
+.TP
+Space-separated:
+.EX
+valaq gtk+-3.0 Gtk Window show
+.EE
+# Navigates to Gtk -> Window -> show
+
+.TP
+Dot-separated:
+.EX
+valaq gtk+-3.0 Gtk.Window.show
+.EE
+# Same navigation using dot notation
+
+.TP
+Mixed separators:
+.EX
+valaq gtk+-3.0 Gtk.Window show
+.EE
+# Combines both formats
+
+.SH SUPPORTED SYMBOL TYPES
+.B valaq
+supports all major Vala language constructs:
+
+.TP
+.B Namespaces
+Containers for related symbols
+.TP
+.B Classes
+Object-oriented class definitions
+.TP
+.B Interfaces
+Abstract interfaces for classes
+.TP
+.B Structs
+Value type structures
+.TP
+.B Enums
+Enumeration types with named values
+.TP
+.B Delegates
+Function pointer types
+.TP
+.B Methods
+Member functions with parameters
+.TP
+.B Properties
+Object properties with getters/setters
+.TP
+.B Fields
+Member variables
+.TP
+.B Constants
+Compile-time constant values
+
+.SH VAPI FILE DISCOVERY
+.B valaq
+automatically searches for VAPI files in standard directories:
+
+.RS
+.IP \(bu 2
+Primary: \fI/usr/share/vala-0.56/vapi\fR
+.IP \(bu 2
+Secondary: \fI/usr/share/vala/vapi\fR
+.IP \(bu 2
+Fallbacks: \fI/usr/share/vala-0.54/vapi\fR, \fI/usr/share/vala-0.52/vapi\fR, \fI/usr/local/share/vala/vapi\fR
+.RE
+
+Run 'valaq' with no arguments to see all available VAPI files.
+
+.SH OUTPUT FORMATS
+.SS Text Output
+Human-readable output with hierarchical symbol listing:
+
+.EX
+VAPI file: gtk+-3.0.vapi
+Symbols:
+  Gtk
+    Window
+      show() -> void
+      hide() -> void
+      destroy() -> void
+    Button
+      clicked() -> void
+      set_label(string) -> void
+.EE
+
+.SS JSON Output
+Structured JSON output for programmatic use:
+
+.EX
+{
+  "result_type": "symbol_details",
+  "vapi_file": "gtk+-3.0.vapi",
+  "query_path": ["Gtk", "Window"],
+  "symbol": {
+    "name": "Window",
+    "type": "class",
+    "access": "public",
+    "base_types": ["Bin"],
+    "methods": [
+      {
+        "name": "show",
+        "return_type": "void",
+        "parameters": []
+      }
+    ],
+    "properties": [...],
+    "fields": [...]
+  },
+  "metadata": {
+    "vala_version": "0.56",
+    "timestamp": "2023-..."
+  }
+}
+.EE
+
+.SH EXAMPLES
+.TP
+List all available VAPI files
+.EX
+valaq
+.EE
+
+.TP
+List VAPI files in JSON format
+.EX
+valaq --json
+.EE
+
+.TP
+List top-level symbols (using basename without extension)
+.EX
+valaq gtk+-3.0
+.EE
+
+.TP
+List top-level symbols (using basename with extension)
+.EX
+valaq gtk+-3.0.vapi
+.EE
+
+.TP
+List top-level symbols (using full path)
+.EX
+valaq /usr/share/vala/vapi/gtk+-3.0.vapi
+.EE
+
+.TP
+Navigate to a class
+.EX
+valaq gtk+-3.0 Gtk.Window
+.EE
+
+.TP
+Navigate to a method (dot-separated)
+.EX
+valaq gtk+-3.0 Gtk.Window.show
+.EE
+
+.TP
+Navigate to a method (space-separated)
+.EX
+valaq gtk+-3.0 Gtk Window show
+.EE
+
+.TP
+Navigate to nested symbols with dots in names
+.EX
+valaq package-name Namespace.Class
+.EE
+
+.TP
+Get JSON output for symbol details
+.EX
+valaq json-glib-1.0 Json.Object --json
+.EE
+
+.TP
+Explore namespace contents
+.EX
+valaq gio-2.0 GLib
+.EE
+
+.TP
+View method details with parameters
+.EX
+valaq glib-2.0 GLib.Timeout.add
+.EE
+
+.TP
+Examine enum values
+.EX
+valaq glib-2.0 GLib.FileType
+.EE
+
+.SH EXIT STATUS
+.TP
+.B 0
+Success
+.TP
+.B 1
+General error (invalid arguments, file not found, etc.)
+.TP
+.B 2
+Parse error (invalid VAPI file syntax)
+
+.SH TROUBLESHOOTING
+.SS VAPI Files Not Found
+If VAPI files are not found:
+.RS
+.IP \(bu 2
+Run 'valaq' with no arguments to see available files
+.IP \(bu 2
+Use full path: \fIvalaq /path/to/your/file.vapi\fR
+.IP \(bu 2
+Check if vala development packages are installed
+.RE
+
+.SS Symbol Navigation Issues
+If symbols are not found:
+.RS
+.IP \(bu 2
+Check symbol name case (case-sensitive)
+.IP \(bu 2
+List top-level symbols first: \fIvalaq <vapi-file>\fR
+.IP \(bu 2
+Verify symbol path hierarchy
+.RE
+
+.SH SEE ALSO
+.BR valac (1),
+.BR vala (1)
+
+.SH BUGS
+Report bugs to the Valaq project issue tracker at:
+https://github.com/valaq/valaq/issues
+
+.SH AUTHOR
+.B valaq
+was written by the Valaq Project.
+
+This manual page was written for the Valaq Project.
+
+.SH COPYRIGHT
+Copyright (C) 2023 Valaq Project
+License: GPLv3
+This is free software; see the source for copying conditions.

+ 68 - 0
meson.build

@@ -0,0 +1,68 @@
+project('valaq', 'vala', 'c',
+  version: '1.0.0',
+  license: 'GPLv3',
+  default_options: ['warning_level=2', 'werror=false'],
+)
+
+# Dependencies
+glib_dep = dependency('glib-2.0', version: '>= 2.56')
+gobject_dep = dependency('gobject-2.0', version: '>= 2.56')
+json_glib_dep = dependency('json-glib-1.0', version: '>= 1.0')
+gee_dep = dependency('gee-0.8', version: '>= 0.20.0')
+libvala_dep = dependency('libvala-0.56', version: '>= 0.56.0')
+
+# Source files
+sources = files(
+  'src/main.vala',
+  'src/cli/argument-parser.vala',
+  'src/cli/command-handler.vala',
+  'src/core/vapi-parser.vala',
+  'src/core/symbol-navigator.vala',
+  'src/core/symbol-model.vala',
+  'src/output/formatter.vala',
+  'src/output/text-formatter.vala',
+  'src/output/json-formatter.vala',
+  'src/utils/file-utils.vala',
+  'src/utils/error-handling.vala',
+)
+
+# Vala compilation flags
+vala_args = [
+  '--target-glib=2.56',
+  '--pkg', 'glib-2.0',
+  '--pkg', 'gobject-2.0',
+  '--pkg', 'json-glib-1.0',
+  '--pkg', 'gee-0.8',
+  '--pkg', 'libvala-0.56',
+]
+
+# Executable
+executable('valaq',
+  sources,
+  dependencies: [glib_dep, gobject_dep, json_glib_dep, gee_dep, libvala_dep],
+  vala_args: vala_args,
+  install: true,
+)
+
+# Install man page
+install_man('man/valaq.1')
+
+# Test configuration
+test_dependencies = [glib_dep, gobject_dep, json_glib_dep, gee_dep, libvala_dep]
+
+test_sources = [
+  'tests/test-vapi-parser.vala',
+  'tests/test-symbol-navigator.vala',
+  'tests/test-output-formatters.vala',
+]
+
+foreach test_file : test_sources
+  test_name = test_file.split('/')[-1].split('.')[0]
+  test(test_name,
+    executable(test_name,
+      test_file,
+      dependencies: test_dependencies,
+      vala_args: vala_args,
+    )
+  )
+endforeach

+ 344 - 0
src/cli/argument-parser.vala

@@ -0,0 +1,344 @@
+/*
+ * argument-parser.vala
+ *
+ * Command-line argument parsing for valaq.
+ * This class handles parsing and validation of command-line arguments.
+ */
+
+/**
+ * Command-line argument parser for valaq.
+ */
+public class ArgumentParser : Object {
+    
+    private string vapi_path;
+    private string[] symbol_path;
+    private bool json_output;
+    private bool show_help;
+    private bool show_version;
+    private string error_message;
+    
+    /**
+     * Creates a new ArgumentParser instance.
+     */
+    public ArgumentParser () {
+        vapi_path = "";
+        symbol_path = {};
+        json_output = false;
+        show_help = false;
+        show_version = false;
+        error_message = "";
+    }
+    
+    /**
+     * Parses command-line arguments.
+     *
+     * @param args Command-line arguments
+     * @return True if parsing was successful, false otherwise
+     */
+    public bool parse (string[] args) {
+        // Reset error message
+        error_message = "";
+        
+        // No arguments provided
+        if (args.length <= 1) {
+            return true; // This is valid - will list VAPI files
+        }
+        
+        // Parse arguments
+        for (int i = 1; i < args.length; i++) {
+            string arg = args[i];
+            
+            if (arg.has_prefix ("--")) {
+                if (!parse_long_option (arg, args, ref i)) {
+                    return false;
+                }
+            } else if (arg.has_prefix ("-") && arg.length > 1) {
+                if (!parse_short_option (arg, args, ref i)) {
+                    return false;
+                }
+            } else {
+                // Positional argument
+                if (!parse_positional_arg (arg)) {
+                    return false;
+                }
+            }
+        }
+        
+        // Validate argument combinations
+        return validate_arguments ();
+    }
+    
+    /**
+     * Parses a long option (starting with --).
+     */
+    private bool parse_long_option (string arg, string[] args, ref int i) {
+        if (arg == "--help") {
+            show_help = true;
+        } else if (arg == "--version") {
+            show_version = true;
+        } else if (arg == "--json") {
+            json_output = true;
+        } else {
+            error_message = "Unknown option: %s".printf (arg);
+            return false;
+        }
+        return true;
+    }
+    
+    /**
+     * Parses a short option (starting with -).
+     */
+    private bool parse_short_option (string arg, string[] args, ref int i) {
+        // Handle combined short options (e.g., -hj)
+        for (int j = 1; j < arg.length; j++) {
+            char option = arg[j];
+            
+            switch (option) {
+                case 'h':
+                    show_help = true;
+                    break;
+                case 'v':
+                    show_version = true;
+                    break;
+                case 'j':
+                    json_output = true;
+                    break;
+                default:
+                    error_message = "Unknown option: -%c".printf (option);
+                    return false;
+            }
+        }
+        return true;
+    }
+    
+    /**
+     * Parses a positional argument.
+     */
+    private bool parse_positional_arg (string arg) {
+        // Check if this is a VAPI file (with .vapi extension)
+        bool is_vapi_file = arg.has_suffix (".vapi");
+        
+        // For the first positional argument, we need to determine if it's a VAPI basename
+        // If it doesn't have .vapi extension and doesn't contain path separators,
+        // we'll treat it as a potential VAPI basename
+        bool is_potential_vapi_basename = !is_vapi_file &&
+                                        vapi_path == "" &&
+                                        symbol_path.length == 0 &&  // First argument
+                                        !arg.contains ("/") &&
+                                        !arg.has_prefix ("-") &&
+                                        arg.strip ().length > 0;
+        
+        if (is_vapi_file || is_potential_vapi_basename) {
+            if (vapi_path != "") {
+                error_message = "Multiple VAPI files specified: %s and %s".printf (vapi_path, arg);
+                return false;
+            }
+            vapi_path = arg;
+        } else {
+            // Add the argument to symbol path
+            // We'll process dotted paths later when getting the symbol path
+            symbol_path += arg;
+        }
+        return true;
+    }
+    
+    /**
+     * Validates argument combinations.
+     */
+    private bool validate_arguments () {
+        // Help and version override everything else
+        if (show_help || show_version) {
+            return true;
+        }
+        
+        // If symbol path is provided, VAPI file must be specified
+        if (symbol_path.length > 0 && vapi_path == "") {
+            error_message = "Symbol path provided but no VAPI file specified";
+            return false;
+        }
+        
+        return true;
+    }
+    
+    /**
+     * Gets the last error message.
+     */
+    public string get_error_message () {
+        return error_message;
+    }
+    
+    /**
+     * Gets the VAPI file path from arguments.
+     * 
+     * @return VAPI file path
+     */
+    public string get_vapi_path () {
+        return vapi_path;
+    }
+    
+    /**
+     * Gets the symbol navigation path.
+     * Processes dotted paths to split them into individual components.
+     *
+     * @return Array of symbol names
+     */
+    public string[] get_symbol_path () {
+        var processed_path = new Gee.ArrayList<string> ();
+        
+        foreach (string path_component in symbol_path) {
+            // Split on dots to handle namespace/class separators
+            string[] parts = path_component.split (".");
+            
+            foreach (string part in parts) {
+                string trimmed_part = part.strip ();
+                if (trimmed_part.length > 0) {
+                    processed_path.add (trimmed_part);
+                }
+            }
+        }
+        
+        // Convert back to array
+        string[] result = new string[processed_path.size];
+        for (int i = 0; i < processed_path.size; i++) {
+            result[i] = processed_path[i];
+        }
+        
+        return result;
+    }
+    
+    /**
+     * Checks if JSON output was requested.
+     * 
+     * @return True if JSON output requested, false otherwise
+     */
+    public bool is_json_output () {
+        return json_output;
+    }
+    
+    /**
+     * Checks if help was requested.
+     * 
+     * @return True if help requested, false otherwise
+     */
+    public bool is_show_help () {
+        return show_help;
+    }
+    
+    /**
+     * Checks if version was requested.
+     * 
+     * @return True if version requested, false otherwise
+     */
+    public bool is_show_version () {
+        return show_version;
+    }
+    
+    
+    /**
+     * Shows comprehensive usage help.
+     */
+    public void show_help_text () {
+        print ("Valaq - VAPI File Query Tool\n");
+        print ("============================\n\n");
+        print ("USAGE:\n");
+        print ("    valaq [OPTIONS] [VAPI_FILE] [SYMBOL_PATH...]\n\n");
+        print ("DESCRIPTION:\n");
+        print ("    Valaq is a powerful command-line tool for querying and exploring VAPI (Vala API) files.\n");
+        print ("    It provides hierarchical navigation of symbols within VAPI files with support\n");
+        print ("    for both human-readable and JSON output formats.\n");
+        print ("    Built with libvala for accurate VAPI parsing and symbol extraction.\n\n");
+        print ("OPTIONS:\n");
+        print ("    -h, --help          Show this help message and exit\n");
+        print ("    -v, --version       Show version information and exit\n");
+        print ("    -j, --json          Output in JSON format instead of human-readable text\n\n");
+        print ("ARGUMENTS:\n");
+        print ("    VAPI_FILE           Path to a VAPI file to analyze\n");
+        print ("                        Can be:\n");
+        print ("                        - Full path: /usr/share/vala/vapi/gtk+-3.0.vapi\n");
+        print ("                        - Basename with extension: gtk+-3.0.vapi\n");
+        print ("                        - Basename without extension: gtk+-3.0\n");
+        print ("    SYMBOL_PATH...      Hierarchical path to a symbol\n");
+        print ("                        Supports both space-separated and dot-separated paths\n\n");
+        print ("SYMBOL PATH FORMATS:\n");
+        print ("    Symbol paths can be specified using spaces or dots as separators:\n\n");
+        print ("    Space-separated:\n");
+        print ("        valaq gtk+-3.0 Gtk Window show\n");
+        print ("        # Navigates to Gtk -> Window -> show\n\n");
+        print ("    Dot-separated:\n");
+        print ("        valaq gtk+-3.0 Gtk.Window.show\n");
+        print ("        # Same navigation using dot notation\n\n");
+        print ("    Mixed separators:\n");
+        print ("        valaq gtk+-3.0 Gtk.Window show\n");
+        print ("        # Combines both formats\n\n");
+        print ("SUPPORTED SYMBOL TYPES:\n");
+        print ("    - Namespaces: Containers for related symbols\n");
+        print ("    - Classes: Object-oriented class definitions\n");
+        print ("    - Interfaces: Abstract interfaces for classes\n");
+        print ("    - Structs: Value type structures\n");
+        print ("    - Enums: Enumeration types with named values\n");
+        print ("    - Delegates: Function pointer types\n");
+        print ("    - Methods: Member functions with parameters\n");
+        print ("    - Properties: Object properties with getters/setters\n");
+        print ("    - Fields: Member variables\n");
+        print ("    - Constants: Compile-time constant values\n\n");
+        print ("VAPI FILE DISCOVERY:\n");
+        print ("    Valaq automatically searches for VAPI files in standard directories:\n");
+        print ("    - Primary: /usr/share/vala-0.56/vapi\n");
+        print ("    - Secondary: /usr/share/vala/vapi\n");
+        print ("    - Fallbacks: /usr/share/vala-0.54/vapi, /usr/share/vala-0.52/vapi,\n");
+        print ("                 /usr/local/share/vala/vapi\n");
+        print ("    Run 'valaq' with no arguments to see all available VAPI files.\n\n");
+        print ("EXAMPLES:\n");
+        print ("    # List all available VAPI files\n");
+        print ("    valaq\n\n");
+        print ("    # List VAPI files in JSON format\n");
+        print ("    valaq --json\n\n");
+        print ("    # List top-level symbols (using basename without extension)\n");
+        print ("    valaq gtk+-3.0\n\n");
+        print ("    # List top-level symbols (using basename with extension)\n");
+        print ("    valaq gtk+-3.0.vapi\n\n");
+        print ("    # List top-level symbols (using full path)\n");
+        print ("    valaq /usr/share/vala/vapi/gtk+-3.0.vapi\n\n");
+        print ("    # Navigate to a class\n");
+        print ("    valaq gtk+-3.0 Gtk.Window\n\n");
+        print ("    # Navigate to a method (dot-separated)\n");
+        print ("    valaq gtk+-3.0 Gtk.Window.show\n\n");
+        print ("    # Navigate to a method (space-separated)\n");
+        print ("    valaq gtk+-3.0 Gtk Window show\n\n");
+        print ("    # Navigate to nested symbols with dots in names\n");
+        print ("    valaq invercargill-1 Invercargill.DataStructures.HashSet\n\n");
+        print ("    # Get JSON output for symbol details\n");
+        print ("    valaq json-glib-1.0 Json.Object --json\n\n");
+        print ("    # Explore namespace contents\n");
+        print ("    valaq gio-2.0 GLib\n\n");
+        print ("    # View method details with parameters\n");
+        print ("    valaq glib-2.0 GLib.Timeout.add\n\n");
+        print ("    # Examine enum values\n");
+        print ("    valaq glib-2.0 GLib.FileType\n\n");
+        print ("EXIT CODES:\n");
+        print ("    0    Success\n");
+        print ("    1    General error (invalid arguments, file not found, etc.)\n");
+        print ("    2    Parse error (invalid VAPI file syntax)\n\n");
+        print ("TROUBLESHOOTING:\n");
+        print ("    If VAPI files are not found:\n");
+        print ("    - Run 'valaq' with no arguments to see available files\n");
+        print ("    - Use full path: valaq /path/to/your/file.vapi\n");
+        print ("    - Check if vala development packages are installed\n\n");
+        print ("    If symbols are not found:\n");
+        print ("    - Check symbol name case (case-sensitive)\n");
+        print ("    - List top-level symbols first: valaq <vapi-file>\n");
+        print ("    - Verify symbol path hierarchy\n\n");
+        print ("For more information, see the project documentation.\n");
+    }
+    
+    /**
+     * Shows version information.
+     */
+    public void show_version_text () {
+        print ("valaq version 1.0.0\n");
+        print ("VAPI File Query Tool\n\n");
+        print ("Copyright (C) 2023 Valaq Project\n");
+        print ("License: GPLv3\n");
+        print ("This is free software; see the source for copying conditions.\n");
+    }
+}

+ 476 - 0
src/cli/command-handler.vala

@@ -0,0 +1,476 @@
+/*
+ * command-handler.vala
+ *
+ * Command processing logic for valaq.
+ * This class handles processing of parsed commands and coordinates with other components.
+ */
+
+/**
+ * Command handler that processes parsed commands and coordinates with other components.
+ */
+public class CommandHandler : Object {
+    
+    private VapiParser parser;
+    private SymbolNavigator navigator;
+    private OutputFormatter formatter;
+    private FileUtils file_utils;
+    private ErrorHandler error_handler;
+    
+    /**
+     * Creates a new CommandHandler instance.
+     * @throws Error If initialization fails
+     */
+    public CommandHandler () throws Error {
+        try {
+            parser = new VapiParser ();
+            navigator = null;
+            formatter = new TextFormatter ();
+            file_utils = new FileUtils ();
+            error_handler = new ErrorHandler ();
+        } catch (Error e) {
+            throw new ValaqError.INITIALIZATION_ERROR ("Failed to initialize CommandHandler: %s".printf (e.message));
+        }
+    }
+    
+    /**
+     * Handles the command based on parsed arguments.
+     *
+     * @param args Parsed command-line arguments
+     * @return Exit code (0 for success, non-zero for error)
+     */
+    public int handle_command (ArgumentParser args) {
+        try {
+            // Set output formatter based on arguments early for error handling
+            if (args.is_json_output ()) {
+                formatter = new JsonFormatter ();
+            } else {
+                formatter = new TextFormatter ();
+            }
+            
+            if (args.is_show_version ()) {
+                args.show_version_text ();
+                return 0;
+            }
+            
+            if (args.is_show_help ()) {
+                args.show_help_text ();
+                return 0;
+            }
+            
+            string vapi_path = args.get_vapi_path ();
+            
+            // Handle no parameters - list VAPI files
+            if (vapi_path == "") {
+                return list_vapi_files ();
+            }
+            
+            // Validate and process VAPI file
+            return process_vapi_file (args);
+            
+        } catch (ValaqError e) {
+            return handle_valaq_error (e);
+        } catch (FileError e) {
+            return handle_file_error (e);
+        } catch (Error e) {
+            return handle_generic_error (e);
+        }
+    }
+    
+    /**
+     * Processes a VAPI file based on provided arguments.
+     */
+    private int process_vapi_file (ArgumentParser args) throws ValaqError, FileError, Error {
+        string vapi_path = args.get_vapi_path ();
+        string resolved_path = vapi_path;
+        
+        // Check if this is a basename (no path separators) - either with or without .vapi extension
+        bool is_basename = !vapi_path.contains ("/") &&
+                          (vapi_path.has_suffix (".vapi") || !vapi_path.contains ("."));
+        
+        // If the provided path is not an absolute path or doesn't exist, try to resolve it
+        if (!Path.is_absolute (vapi_path) && !file_utils.file_exists (vapi_path)) {
+            string? resolved = file_utils.resolve_vapi_file (vapi_path);
+            if (resolved == null) {
+                // Build error message with all search paths
+                string[] search_paths = file_utils.get_vapi_search_paths ();
+                string paths_str = string.joinv (", ", search_paths);
+                
+                if (is_basename) {
+                    // Check if the basename already has .vapi extension for better error messaging
+                    string display_name = vapi_path.has_suffix (".vapi") ? vapi_path : vapi_path + ".vapi";
+                    throw new ValaqError.FILE_NOT_FOUND ("VAPI basename '%s' not found in any search path: %s".printf (display_name, paths_str));
+                } else {
+                    throw new ValaqError.FILE_NOT_FOUND ("VAPI file '%s' not found in any search path: %s".printf (vapi_path, paths_str));
+                }
+            }
+            resolved_path = resolved;
+        }
+        
+        // Validate VAPI file path
+        if (!file_utils.validate_path (resolved_path)) {
+            throw new ValaqError.INVALID_ARGUMENT ("Invalid VAPI file path: %s".printf (resolved_path));
+        }
+        
+        // Check if VAPI file exists
+        if (!file_utils.file_exists (resolved_path)) {
+            throw new ValaqError.FILE_NOT_FOUND ("VAPI file not found: %s".printf (resolved_path));
+        }
+        
+        // Parse the VAPI file
+        if (!parser.parse_file (resolved_path)) {
+            throw new ValaqError.PARSE_ERROR ("Failed to parse VAPI file: %s".printf (resolved_path));
+        }
+        
+        // Create symbol navigator with parsed symbols
+        navigator = new SymbolNavigator (parser.get_root_symbols ());
+        
+        // Get symbol path and navigate
+        string[] symbol_path = args.get_symbol_path ();
+        if (symbol_path.length == 0) {
+            // Default to root-only behavior for more useful output
+            return list_symbols (navigator.get_root_only_symbols ());
+        } else {
+            // Navigate to specific symbol path
+            return navigate_to_symbol (symbol_path);
+        }
+    }
+    
+    /**
+     * Handles a ValaqError and returns appropriate exit code.
+     */
+    private int handle_valaq_error (ValaqError e) {
+        string error_type = get_error_type_string (e);
+        string message = e.message;
+        
+        if (formatter is JsonFormatter) {
+            print (error_handler.format_error_json (error_type, message));
+        } else {
+            print (error_handler.format_error_text (error_type, message));
+        }
+        
+        return get_exit_code_for_error (e);
+    }
+    
+    /**
+     * Handles a FileError and returns appropriate exit code.
+     */
+    private int handle_file_error (FileError e) {
+        string message = "File system error: %s".printf (e.message);
+        
+        if (formatter is JsonFormatter) {
+            print (error_handler.format_error_json ("file_error", message));
+        } else {
+            print (error_handler.format_error_text ("file_error", message));
+        }
+        
+        return 1;
+    }
+    
+    /**
+     * Handles a generic Error and returns appropriate exit code.
+     */
+    private int handle_generic_error (Error e) {
+        string message = "Unexpected error: %s".printf (e.message);
+        
+        if (formatter is JsonFormatter) {
+            print (error_handler.format_error_json ("unexpected_error", message));
+        } else {
+            print (error_handler.format_error_text ("unexpected_error", message));
+        }
+        
+        return 1;
+    }
+    
+    /**
+     * Gets the string representation of a ValaqError code.
+     */
+    private string get_error_type_string (ValaqError e) {
+        if (e is ValaqError.FILE_NOT_FOUND) {
+            return "file_not_found";
+        } else if (e is ValaqError.PARSE_ERROR) {
+            return "parse_error";
+        } else if (e is ValaqError.NAVIGATION_ERROR) {
+            return "navigation_error";
+        } else if (e is ValaqError.OUTPUT_ERROR) {
+            return "output_error";
+        } else if (e is ValaqError.INVALID_ARGUMENT) {
+            return "invalid_argument";
+        } else if (e is ValaqError.INITIALIZATION_ERROR) {
+            return "initialization_error";
+        } else if (e is ValaqError.ENVIRONMENT_ERROR) {
+            return "environment_error";
+        } else {
+            return "unknown_error";
+        }
+    }
+    
+    /**
+     * Gets the exit code for a ValaqError.
+     */
+    private int get_exit_code_for_error (ValaqError e) {
+        if (e is ValaqError.FILE_NOT_FOUND) {
+            return 1;
+        } else if (e is ValaqError.PARSE_ERROR) {
+            return 2;
+        } else if (e is ValaqError.NAVIGATION_ERROR) {
+            return 1;
+        } else if (e is ValaqError.OUTPUT_ERROR) {
+            return 1;
+        } else if (e is ValaqError.INVALID_ARGUMENT) {
+            return 1;
+        } else if (e is ValaqError.INITIALIZATION_ERROR) {
+            return 1;
+        } else if (e is ValaqError.ENVIRONMENT_ERROR) {
+            return 1;
+        } else {
+            return 1;
+        }
+    }
+    
+    /**
+     * Lists available VAPI files.
+     *
+     * @return Exit code
+     */
+    private int list_vapi_files () {
+        try {
+            // Use the new method to find all VAPI files across search paths
+            var vapi_files = file_utils.find_all_vapi_files ();
+            
+            if (vapi_files.size == 0) {
+                string[] search_paths = file_utils.get_vapi_search_paths ();
+                string paths_str = string.joinv (", ", search_paths);
+                string message = "No VAPI files found in any search path: %s".printf (paths_str);
+                if (formatter is JsonFormatter) {
+                    print (error_handler.format_error_json ("file_not_found", message));
+                } else {
+                    print (error_handler.format_error_text ("file_not_found", message));
+                }
+                return 0;
+            }
+            
+            // Sort files alphabetically
+            vapi_files.sort ((a, b) => {
+                var file_a = File.new_for_path (a);
+                var file_b = File.new_for_path (b);
+                return file_a.get_basename ().collate (file_b.get_basename ());
+            });
+            
+            // Use formatter for output
+            if (formatter is JsonFormatter) {
+                return output_vapi_files_json (vapi_files);
+            } else {
+                return output_vapi_files_text (vapi_files);
+            }
+            
+        } catch (Error e) {
+            if (formatter is JsonFormatter) {
+                print (error_handler.format_error_json ("file_error", "Failed to list VAPI files", e.message));
+            } else {
+                print (error_handler.format_error_text ("file_error", "Failed to list VAPI files: %s".printf (e.message)));
+            }
+            return 1;
+        }
+    }
+    
+    /**
+     * Outputs VAPI files in JSON format.
+     */
+    private int output_vapi_files_json (Gee.ArrayList<string> vapi_files) {
+        var builder = new StringBuilder ();
+        builder.append ("{\n");
+        builder.append ("  \"result_type\": \"file_list\",\n");
+        
+        // Add search paths information
+        string[] search_paths = file_utils.get_vapi_search_paths ();
+        builder.append ("  \"search_paths\": [\n");
+        for (int i = 0; i < search_paths.length; i++) {
+            builder.append ("    \"%s\"".printf (search_paths[i]));
+            if (i < search_paths.length - 1) {
+                builder.append (",");
+            }
+            builder.append ("\n");
+        }
+        builder.append ("  ],\n");
+        
+        builder.append ("  \"files\": [\n");
+        
+        for (int i = 0; i < vapi_files.size; i++) {
+            string file_path = vapi_files[i];
+            var file = File.new_for_path (file_path);
+            string filename = file.get_basename ();
+            
+            builder.append ("    {\n");
+            builder.append ("      \"name\": \"%s\",\n".printf (filename));
+            builder.append ("      \"path\": \"%s\"".printf (file_path));
+            
+            try {
+                var file_info = file.query_info (
+                    FileAttribute.STANDARD_SIZE + "," + FileAttribute.TIME_MODIFIED,
+                    FileQueryInfoFlags.NONE
+                );
+                
+                int64 size = file_info.get_size ();
+                uint64 modified_time = file_info.get_attribute_uint64 (FileAttribute.TIME_MODIFIED);
+                DateTime modified = new DateTime.from_unix_utc ((int64)modified_time);
+                
+                builder.append (",\n");
+                builder.append ("      \"size\": %lld,\n".printf (size));
+                builder.append ("      \"modified\": \"%s\"".printf (modified.format ("%Y-%m-%dT%H:%M:%SZ")));
+                    
+            } catch (Error e) {
+                // Skip file info on error
+            }
+            
+            builder.append ("\n    }");
+            
+            if (i < vapi_files.size - 1) {
+                builder.append (",");
+            }
+            builder.append ("\n");
+        }
+        
+        builder.append ("  ],\n");
+        builder.append ("  \"metadata\": {\n");
+        builder.append ("    \"total_files\": %d,\n".printf (vapi_files.size));
+        builder.append ("    \"timestamp\": \"%s\"\n".printf (get_current_timestamp ()));
+        builder.append ("  }\n");
+        builder.append ("}\n");
+        
+        print ("%s", builder.str);
+        return 0;
+    }
+    
+    /**
+     * Outputs VAPI files in text format.
+     */
+    private int output_vapi_files_text (Gee.ArrayList<string> vapi_files) {
+        // Display search paths
+        string[] search_paths = file_utils.get_vapi_search_paths ();
+        print ("VAPI search paths:\n");
+        foreach (string path in search_paths) {
+            print ("  %s\n", path);
+        }
+        print ("\n");
+        
+        print ("Available VAPI files:\n");
+        print ("\n");
+        
+        foreach (string file_path in vapi_files) {
+            var file = File.new_for_path (file_path);
+            string filename = file.get_basename ();
+            
+            try {
+                var file_info = file.query_info (
+                    FileAttribute.STANDARD_SIZE + "," + FileAttribute.TIME_MODIFIED,
+                    FileQueryInfoFlags.NONE
+                );
+                
+                int64 size = file_info.get_size ();
+                uint64 modified_time = file_info.get_attribute_uint64 (FileAttribute.TIME_MODIFIED);
+                DateTime modified = new DateTime.from_unix_utc ((int64)modified_time);
+                
+                print ("%-30s %8s KB  %s\n",
+                       filename,
+                       (size / 1024).to_string (),
+                       modified.format ("%Y-%m-%d %H:%M"));
+                        
+            } catch (Error e) {
+                print ("%-30s  (unable to get file info)\n", filename);
+            }
+        }
+        
+        print ("\nTotal: %d VAPI files\n", vapi_files.size);
+        return 0;
+    }
+    
+    /**
+     * Lists symbols in a formatted way.
+     *
+     * @param symbols List of symbols to display
+     * @return Exit code
+     */
+    private int list_symbols (Gee.ArrayList<Symbol> symbols) {
+        try {
+            if (symbols.size == 0) {
+                string message = "No symbols found in VAPI file.";
+                if (formatter is JsonFormatter) {
+                    print (error_handler.format_error_json ("no_symbols", message));
+                } else {
+                    print (error_handler.format_error_text ("no_symbols", message));
+                }
+                return 0;
+            }
+            
+            // Use the formatter to output the symbol list
+            string output = formatter.format_symbol_list (symbols);
+            print ("%s", output);
+            
+            return 0;
+        } catch (Error e) {
+            if (formatter is JsonFormatter) {
+                print (error_handler.format_error_json ("output_error", "Failed to format symbol list", e.message));
+            } else {
+                print (error_handler.format_error_text ("output_error", "Failed to format symbol list: %s".printf (e.message)));
+            }
+            return 1;
+        }
+    }
+    
+    /**
+     * Navigates to a symbol and displays its information.
+     *
+     * @param symbol_path Path to the symbol
+     * @return Exit code
+     */
+    private int navigate_to_symbol (string[] symbol_path) {
+        try {
+            if (navigator == null) {
+                throw new ValaqError.NAVIGATION_ERROR ("Symbol navigator not initialized");
+            }
+            
+            // Navigate to the specified symbol path
+            Symbol? target_symbol = navigator.navigate_to_path (symbol_path);
+            
+            if (target_symbol == null) {
+                throw new ValaqError.NAVIGATION_ERROR ("Symbol not found: %s".printf (string.joinv (".", symbol_path)));
+            }
+            
+            // Get detailed information about the symbol
+            SymbolDetails details = parser.get_symbol_details (target_symbol);
+            details.full_path = target_symbol.get_full_path ();
+            
+            // If this is a namespace, get child symbols and add them to details
+            // Only use direct children, not root symbols, to avoid duplication
+            if (target_symbol.symbol_type == "namespace") {
+                var child_symbols = navigator.get_child_symbols (target_symbol);
+                details.child_symbols = child_symbols;
+            }
+            
+            // Display the symbol details using the formatter
+            string output = formatter.format_symbol_details (details);
+            print ("%s", output);
+            
+            return 0;
+        } catch (ValaqError e) {
+            return handle_valaq_error (e);
+        } catch (Error e) {
+            if (formatter is JsonFormatter) {
+                print (error_handler.format_error_json ("navigation_error", "Failed to navigate to symbol", e.message));
+            } else {
+                print (error_handler.format_error_text ("navigation_error", "Failed to navigate to symbol: %s".printf (e.message)));
+            }
+            return 1;
+        }
+    }
+    
+    /**
+     * Gets the current timestamp in ISO 8601 format.
+     *
+     * @return Current timestamp string
+     */
+    private string get_current_timestamp () {
+        var now = new DateTime.now_utc ();
+        return now.format ("%Y-%m-%dT%H:%M:%S.%fZ");
+    }
+}

+ 674 - 0
src/core/symbol-model.vala

@@ -0,0 +1,674 @@
+/*
+ * symbol-model.vala
+ * 
+ * Data models for symbols in VAPI files.
+ * This file contains the base Symbol class and specialized symbol types.
+ */
+
+/**
+ * Base class for all symbol types in VAPI files.
+ *
+ * This abstract class provides common functionality and properties for all symbols
+ * that can be parsed from VAPI files, including classes, interfaces, methods,
+ * properties, and other Vala language constructs.
+ *
+ * Symbols are organized in a hierarchical tree structure where each symbol can
+ * have child symbols and optionally a parent symbol.
+ */
+public abstract class Symbol : Object {
+    /**
+     * The name of the symbol.
+     */
+    public string name { get; set; }
+    
+    /**
+     * The type of symbol (e.g., "class", "interface", "method", "property").
+     */
+    public string symbol_type { get; set; }
+    
+    /**
+     * The access modifier (e.g., "public", "private", "protected").
+     */
+    public string access_modifier { get; set; }
+    
+    /**
+     * The parent symbol in the hierarchy, or null for root symbols.
+     */
+    public Symbol? parent { get; set; }
+    
+    /**
+     * List of child symbols contained within this symbol.
+     */
+    public Gee.ArrayList<Symbol> children { get; set; }
+    
+    /**
+     * Source location information for where this symbol is defined.
+     */
+    public SourceLocation? source_location { get; set; }
+    
+    /**
+     * Documentation comments associated with this symbol.
+     */
+    public string documentation { get; set; }
+    
+    /**
+     * Namespace path for constructing full symbol paths.
+     * This is used to build hierarchical paths like "Gtk.Window.show".
+     */
+    public string namespace_path { get; set; }
+    
+    /**
+     * The number of direct child symbols this symbol contains.
+     * This provides quick access to the count without iterating through the children list.
+     */
+    public int child_count { get; set; }
+    
+    /**
+     * Initializes a new Symbol instance with default values.
+     *
+     * Sets up empty collections and default string values for all properties.
+     */
+    protected Symbol () {
+        children = new Gee.ArrayList<Symbol> ();
+        documentation = "";
+        namespace_path = "";
+        child_count = 0;
+    }
+    
+    /**
+     * Adds a child symbol to this symbol.
+     *
+     * Automatically sets the parent reference of the child to this symbol.
+     * This method maintains the hierarchical tree structure and updates child count.
+     *
+     * @param child The child symbol to add
+     */
+    public void add_child (Symbol child) {
+        child.parent = this;
+        children.add (child);
+        child_count = children.size;
+    }
+    
+    /**
+     * Gets the full hierarchical path of this symbol.
+     *
+     * Constructs a dot-separated path from the root to this symbol.
+     * Uses namespace_path if available, otherwise builds path from parent hierarchy.
+     *
+     * @return The full path as a dot-separated string (e.g., "Gtk.Window.show")
+     */
+    public string get_full_path () {
+        // For namespace symbols, if we have a namespace_path set, use it directly
+        // to avoid duplication (namespace_path already contains the full path)
+        if (symbol_type == "namespace" && namespace_path != "") {
+            return namespace_path;
+        }
+        
+        // For non-namespace symbols, if we have a namespace_path set, use it as the base
+        if (namespace_path != "") {
+            return namespace_path + "." + name;
+        }
+        
+        // Otherwise, fall back to the parent-based path construction
+        if (parent == null) {
+            return name;
+        } else {
+            return parent.get_full_path () + "." + name;
+        }
+    }
+    
+    /**
+     * Gets the depth of this symbol in the hierarchy.
+     *
+     * Root symbols have depth 0, their children have depth 1, and so on.
+     * This is useful for indentation and display formatting.
+     *
+     * @return The depth (0 for root symbols)
+     */
+    public int get_depth () {
+        if (parent == null) {
+            return 0;
+        } else {
+            return parent.get_depth () + 1;
+        }
+    }
+    
+    /**
+     * Finds a direct child symbol by name.
+     *
+     * Only searches immediate children, not grandchildren or deeper descendants.
+     * This is a case-sensitive search.
+     *
+     * @param name The name of the child to find
+     * @return The child symbol, or null if not found
+     */
+    public Symbol? find_child (string name) {
+        foreach (Symbol child in children) {
+            if (child.name == name) {
+                return child;
+            }
+        }
+        return null;
+    }
+    
+    /**
+     * Gets all descendant symbols of a specific type.
+     *
+     * Searches through all children, grandchildren, and deeper descendants
+     * to find symbols matching the specified type.
+     *
+     * @param type The symbol type to search for (e.g., "method", "property")
+     * @return List of matching descendant symbols
+     */
+    public Gee.ArrayList<Symbol> get_descendants_by_type (string type) {
+        var result = new Gee.ArrayList<Symbol> ();
+        get_descendants_by_type_recursive (type, result);
+        return result;
+    }
+    
+    /**
+     * Recursively collects descendants by type.
+     *
+     * Internal helper method that performs the recursive search through
+     * the symbol hierarchy.
+     *
+     * @param type The symbol type to search for
+     * @param result List to store matching symbols
+     */
+    private void get_descendants_by_type_recursive (string type, Gee.ArrayList<Symbol> result) {
+        foreach (Symbol child in children) {
+            if (child.symbol_type == type) {
+                result.add (child);
+            }
+            child.get_descendants_by_type_recursive (type, result);
+        }
+    }
+    
+    /**
+     * Checks if this symbol is a descendant of the given symbol.
+     *
+     * Traverses up the parent chain to determine if the ancestor
+     * is actually an ancestor of this symbol.
+     *
+     * @param ancestor The potential ancestor symbol
+     * @return True if this symbol is a descendant of the ancestor
+     */
+    public bool is_descendant_of (Symbol ancestor) {
+        if (parent == null) {
+            return false;
+        }
+        if (parent == ancestor) {
+            return true;
+        }
+        return parent.is_descendant_of (ancestor);
+    }
+    
+    /**
+     * Gets a string representation of this symbol.
+     *
+     * Returns a concise representation including the symbol type and name.
+     *
+     * @return String representation including type and name
+     */
+    public virtual string to_string () {
+        return "%s %s".printf (symbol_type, name);
+    }
+    
+    /**
+     * Gets a detailed description of this symbol.
+     *
+     * Returns a comprehensive description including access modifier,
+     * symbol type, name, and full hierarchical path.
+     *
+     * @return Detailed description including access modifier and full path
+     */
+    public virtual string get_description () {
+        return "%s %s (%s)".printf (access_modifier, to_string (), get_full_path ());
+    }
+}
+
+/**
+ * Detailed information about a symbol for comprehensive display.
+ *
+ * This class aggregates all available information about a symbol including
+ * methods, properties, fields, parameters, and other metadata.
+ * It's used by output formatters to provide complete symbol details.
+ */
+public class SymbolDetails : Object {
+    /** The name of the symbol */
+    public string name { get; set; }
+    
+    /** The type of symbol (e.g., "class", "interface", "method") */
+    public string symbol_type { get; set; }
+    
+    /** The access modifier (e.g., "public", "private") */
+    public string access { get; set; }
+    
+    /** Return type for methods and delegates */
+    public string return_type { get; set; }
+    
+    /** List of method parameters */
+    public Gee.ArrayList<Parameter> parameters { get; set; }
+    
+    /** List of object properties */
+    public Gee.ArrayList<Property> properties { get; set; }
+    
+    /** List of methods contained in this symbol */
+    public Gee.ArrayList<Method> methods { get; set; }
+    
+    /** List of fields contained in this symbol */
+    public Gee.ArrayList<Field> fields { get; set; }
+    
+    /** List of constants contained in this symbol */
+    public Gee.ArrayList<Constant> constants { get; set; }
+    
+    /** List of base types for classes and interfaces */
+    public Gee.ArrayList<string> base_types { get; set; }
+    
+    /** List of enum values for enum types */
+    public Gee.ArrayList<EnumValue> enum_values { get; set; }
+    
+    /** List of child symbols (primarily for namespaces) */
+    public Gee.ArrayList<Symbol> child_symbols { get; set; }
+    
+    /** Source location where this symbol is defined */
+    public SourceLocation source_location { get; set; }
+    
+    /** Documentation comments for this symbol */
+    public string documentation { get; set; }
+    
+    /** Full hierarchical path of this symbol */
+    public string full_path { get; set; }
+    
+    /** Number of child symbols this symbol contains */
+    public int child_count { get; set; }
+    
+    /**
+     * Initializes a new SymbolDetails instance with empty collections.
+     *
+     * Sets up all collection properties and initializes string values
+     * to empty strings for safe usage.
+     */
+    public SymbolDetails () {
+        parameters = new Gee.ArrayList<Parameter> ();
+        properties = new Gee.ArrayList<Property> ();
+        methods = new Gee.ArrayList<Method> ();
+        fields = new Gee.ArrayList<Field> ();
+        constants = new Gee.ArrayList<Constant> ();
+        base_types = new Gee.ArrayList<string> ();
+        enum_values = new Gee.ArrayList<EnumValue> ();
+        child_symbols = new Gee.ArrayList<Symbol> ();
+        documentation = "";
+        full_path = "";
+        child_count = 0;
+    }
+    
+    /**
+     * Gets a formatted signature for this symbol.
+     *
+     * @return Formatted signature string
+     */
+    public string get_signature () {
+        var builder = new StringBuilder ();
+        
+        // Add access modifier
+        builder.append (access);
+        builder.append (" ");
+        
+        // Add return type for methods and delegates
+        if (symbol_type == "method" || symbol_type == "delegate") {
+            builder.append (return_type);
+            builder.append (" ");
+        }
+        
+        // Add name
+        builder.append (name);
+        
+        // Add parameters for methods and delegates
+        if ((symbol_type == "method" || symbol_type == "delegate") && parameters.size > 0) {
+            builder.append (" (");
+            for (int i = 0; i < parameters.size; i++) {
+                if (i > 0) {
+                    builder.append (", ");
+                }
+                Parameter param = parameters[i];
+                if (param.direction != "in") {
+                    builder.append (param.direction);
+                    builder.append (" ");
+                }
+                builder.append (param.param_type);
+                builder.append (" ");
+                builder.append (param.name);
+                if (param.default_value != "") {
+                    builder.append (" = ");
+                    builder.append (param.default_value);
+                }
+            }
+            builder.append (")");
+        }
+        
+        // Add type information for properties and fields
+        if (symbol_type == "property") {
+            builder.append (" : ");
+            builder.append (return_type);
+        } else if (symbol_type == "field") {
+            builder.append (" : ");
+            builder.append (return_type);
+        }
+        
+        return builder.str;
+    }
+    
+    /**
+     * Gets a summary of this symbol's contents.
+     *
+     * @return Summary string
+     */
+    public string get_summary () {
+        var builder = new StringBuilder ();
+        builder.append (get_signature ());
+        
+        if (base_types.size > 0) {
+            builder.append (" : ");
+            builder.append (string.joinv (", ", base_types.to_array ()));
+        }
+        
+        return builder.str;
+    }
+}
+
+/**
+ * Represents a method parameter in VAPI files.
+ *
+ * Encapsulates information about parameters including their type,
+ * direction (in/out/ref), name, and optional default values.
+ */
+public class Parameter : Object {
+    /** The parameter name */
+    public string name { get; set; }
+    
+    /** The parameter type (e.g., "string", "int", "Gtk.Widget") */
+    public string param_type { get; set; }
+    
+    /** Parameter direction: "in", "out", or "ref" */
+    public string direction { get; set; }
+    
+    /** Default value if the parameter is optional */
+    public string default_value { get; set; }
+}
+
+/**
+ * Represents a source location in a file.
+ *
+ * Stores information about where a symbol is defined,
+ * useful for debugging and reference purposes.
+ */
+public class SourceLocation : Object {
+    /** The file path where the symbol is defined */
+    public string file { get; set; }
+    
+    /** The line number where the symbol is defined */
+    public int line { get; set; }
+}
+
+/**
+ * Specialized symbol types for different Vala language constructs.
+ *
+ * Each class extends the base Symbol class to provide specific
+ * functionality and properties for different symbol types.
+ */
+
+/**
+ * Represents a class symbol in VAPI files.
+ *
+ * Classes are object-oriented types that can inherit from base classes
+ * and contain methods, properties, fields, and other members.
+ */
+public class Class : Symbol {
+    /** List of base classes this class inherits from */
+    public Gee.ArrayList<string> base_classes { get; set; }
+    
+    /**
+     * Initializes a new Class instance.
+     */
+    public Class () {
+        symbol_type = "class";
+        base_classes = new Gee.ArrayList<string> ();
+    }
+}
+
+/**
+ * Represents an interface symbol in VAPI files.
+ *
+ * Interfaces define contracts that classes can implement,
+ * containing method signatures and property definitions.
+ */
+public class Interface : Symbol {
+    /** List of prerequisite interfaces this interface requires */
+    public Gee.ArrayList<string> prerequisites { get; set; }
+    
+    /**
+     * Initializes a new Interface instance.
+     */
+    public Interface () {
+        symbol_type = "interface";
+        prerequisites = new Gee.ArrayList<string> ();
+    }
+}
+
+/**
+ * Represents a struct symbol in VAPI files.
+ *
+ * Structs are value types that can contain fields and methods,
+ * typically used for data structures.
+ */
+public class Struct : Symbol {
+    /** List of base structs this struct inherits from (rarely used) */
+    public Gee.ArrayList<string> base_structs { get; set; }
+    
+    /**
+     * Initializes a new Struct instance.
+     */
+    public Struct () {
+        symbol_type = "struct";
+        base_structs = new Gee.ArrayList<string> ();
+    }
+}
+
+/**
+ * Represents an enum symbol in VAPI files.
+ *
+ * Enums define a set of named constants, useful for
+ * representing a fixed set of possible values.
+ */
+public class Enum : Symbol {
+    /** List of enum values */
+    public Gee.ArrayList<EnumValue> values { get; set; }
+    
+    /**
+     * Initializes a new Enum instance.
+     */
+    public Enum () {
+        symbol_type = "enum";
+        values = new Gee.ArrayList<EnumValue> ();
+    }
+}
+
+/**
+ * Represents an enum value in VAPI files.
+ *
+ * Enum values are the named constants that make up an enum.
+ * They can have optional numeric values and documentation.
+ */
+public class EnumValue : Object {
+    /** The name of the enum value */
+    public string name { get; set; }
+    
+    /** The numeric value of the enum (optional) */
+    public string numeric_value { get; set; }
+    
+    /** Documentation for the enum value (optional) */
+    public string documentation { get; set; }
+    
+    /**
+     * Initializes a new EnumValue instance.
+     */
+    public EnumValue () {
+        numeric_value = "";
+        documentation = "";
+    }
+    
+    /**
+     * Gets a string representation of this enum value.
+     *
+     * @return String representation including name and optional numeric value
+     */
+    public string to_string () {
+        if (numeric_value != "") {
+            return "%s = %s".printf (name, numeric_value);
+        } else {
+            return name;
+        }
+    }
+}
+
+/**
+ * Represents a delegate symbol in VAPI files.
+ *
+ * Delegates are function pointer types that define method signatures
+ * for callbacks and event handlers.
+ */
+public class Delegate : Symbol {
+    /** Return type of the delegate function */
+    public string return_type { get; set; }
+    
+    /** List of parameters for the delegate function */
+    public Gee.ArrayList<Parameter> parameters { get; set; }
+    
+    /**
+     * Initializes a new Delegate instance.
+     */
+    public Delegate () {
+        symbol_type = "delegate";
+        parameters = new Gee.ArrayList<Parameter> ();
+    }
+}
+
+/**
+ * Represents a method symbol in VAPI files.
+ *
+ * Methods are functions that belong to classes, interfaces, or structs,
+ * with parameters, return types, and various modifiers.
+ */
+public class Method : Symbol {
+    /** Return type of the method */
+    public string return_type { get; set; }
+    
+    /** List of method parameters */
+    public Gee.ArrayList<Parameter> parameters { get; set; }
+    
+    /** Whether this is a static method (class method) */
+    public bool is_static { get; set; }
+    
+    /** Whether this is a virtual method (can be overridden) */
+    public bool is_virtual { get; set; }
+    
+    /** Whether this method overrides a base class method */
+    public bool is_override { get; set; }
+    
+    /**
+     * Initializes a new Method instance.
+     */
+    public Method () {
+        symbol_type = "method";
+        parameters = new Gee.ArrayList<Parameter> ();
+    }
+}
+
+/**
+ * Represents a property symbol in VAPI files.
+ *
+ * Properties are member variables with getter/setter semantics,
+ * commonly used in GObject-based APIs.
+ */
+public class Property : Symbol {
+    /** The type of the property */
+    public string property_type { get; set; }
+    
+    /** Whether this property is read-only (no setter) */
+    public bool is_read_only { get; set; }
+    
+    /** Whether this property is write-only (no getter) */
+    public bool is_write_only { get; set; }
+    
+    /** Whether this property is a construct property */
+    public bool is_construct { get; set; }
+    
+    /**
+     * Initializes a new Property instance.
+     */
+    public Property () {
+        symbol_type = "property";
+    }
+}
+
+/**
+ * Represents a field symbol in VAPI files.
+ *
+ * Fields are member variables of classes and structs,
+ * with types, access modifiers, and optional default values.
+ */
+public class Field : Symbol {
+    /** The type of the field */
+    public string field_type { get; set; }
+    
+    /** Whether this is a static field (shared across instances) */
+    public bool is_static { get; set; }
+    
+    /** Default value for the field (if specified) */
+    public string default_value { get; set; }
+    
+    /**
+     * Initializes a new Field instance.
+     */
+    public Field () {
+        symbol_type = "field";
+    }
+}
+
+/**
+ * Represents a constant symbol in VAPI files.
+ *
+ * Constants are compile-time values with fixed types and values,
+ * typically used for configuration and API constants.
+ */
+public class Constant : Symbol {
+    /** The type of the constant */
+    public string constant_type { get; set; }
+    
+    /** The value of the constant */
+    public string value { get; set; }
+    
+    /**
+     * Initializes a new Constant instance.
+     */
+    public Constant () {
+        symbol_type = "constant";
+    }
+}
+
+/**
+ * Represents a namespace symbol in VAPI files.
+ *
+ * Namespaces are containers that group related symbols
+ * and provide hierarchical organization.
+ */
+public class NamespaceSymbol : Symbol {
+    
+    /**
+     * Initializes a new NamespaceSymbol instance.
+     */
+    public NamespaceSymbol () {
+        symbol_type = "namespace";
+    }
+}

+ 399 - 0
src/core/symbol-navigator.vala

@@ -0,0 +1,399 @@
+/*
+ * symbol-navigator.vala
+ *
+ * Symbol hierarchy navigator for VAPI files.
+ * This class manages hierarchical symbol traversal and filtering.
+ */
+
+/**
+ * Symbol navigator that provides hierarchical traversal of symbols in VAPI files.
+ *
+ * This class enables navigation through the symbol tree created by VapiParser.
+ * It supports path-based navigation, symbol searching, filtering,
+ * and various query operations on the hierarchical symbol structure.
+ *
+ * The navigator is essential for implementing CLI commands that need
+ * to locate specific symbols or traverse the symbol hierarchy.
+ */
+public class SymbolNavigator : Object {
+    
+    /**
+     * List of root symbols from the parsed VAPI file.
+     *
+     * These are the top-level symbols that form the root
+     * of the hierarchical symbol tree.
+     */
+    private Gee.ArrayList<Symbol> root_symbols;
+    
+    /**
+     * Creates a new SymbolNavigator instance.
+     *
+     * @param root_symbols List of root symbols from the VAPI file
+     */
+    public SymbolNavigator (Gee.ArrayList<Symbol> root_symbols) {
+        this.root_symbols = root_symbols;
+        calculate_child_counts ();
+    }
+    
+    /**
+     * Navigates to a specific symbol path.
+     *
+     * Follows a hierarchical path through the symbol tree to locate
+     * a specific symbol. The path is traversed from root to leaf,
+     * matching each component against child symbols at each level.
+     *
+     * @param path Array of symbol names representing the hierarchical path
+     * @return The symbol at the specified path, or null if not found
+     */
+    public Symbol? navigate_to_path (string[] path) {
+        if (path.length == 0) {
+            return null;
+        }
+        
+        // Start with root symbols
+        Symbol? current_symbol = null;
+        
+        // Find the first symbol in the path among root symbols
+        foreach (Symbol root_symbol in root_symbols) {
+            if (root_symbol.name == path[0]) {
+                current_symbol = root_symbol;
+                break;
+            }
+        }
+        
+        // If first symbol not found, return null
+        if (current_symbol == null) {
+            return null;
+        }
+        
+        // Navigate through the rest of the path
+        for (int i = 1; i < path.length; i++) {
+            Symbol? next_symbol = null;
+            
+            // Search in current symbol's children
+            foreach (Symbol child in current_symbol.children) {
+                if (child.name == path[i]) {
+                    next_symbol = child;
+                    break;
+                }
+            }
+            
+            // If child not found, return null
+            if (next_symbol == null) {
+                return null;
+            }
+            
+            current_symbol = next_symbol;
+        }
+        
+        return current_symbol;
+    }
+    
+    /**
+     * Gets child symbols of a parent symbol.
+     *
+     * Provides direct access to the children of a given symbol.
+     * This is useful for listing contents of namespaces, classes,
+     * and other container symbols.
+     *
+     * @param parent The parent symbol whose children to retrieve
+     * @return Array of child symbols
+     */
+    public Gee.ArrayList<Symbol> get_child_symbols (Symbol parent) {
+        return parent.children;
+    }
+    
+    /**
+     * Finds a symbol by name within the entire symbol tree.
+     *
+     * Performs a depth-first search through the entire symbol hierarchy
+     * to find a symbol with the specified name. This is useful for
+     * implementing symbol search functionality.
+     *
+     * @param name The name of the symbol to find
+     * @return The symbol with the given name, or null if not found
+     */
+    public Symbol? find_symbol_by_name (string name) {
+        return find_symbol_by_name_recursive (name, root_symbols);
+    }
+    
+    /**
+     * Recursively searches for a symbol by name in a list of symbols.
+     *
+     * @param name The name of the symbol to find
+     * @param symbols List of symbols to search in
+     * @return The symbol with the given name, or null if not found
+     */
+    private Symbol? find_symbol_by_name_recursive (string name, Gee.ArrayList<Symbol> symbols) {
+        foreach (Symbol symbol in symbols) {
+            if (symbol.name == name) {
+                return symbol;
+            }
+            
+            // Search in children recursively
+            if (symbol.children.size > 0) {
+                Symbol? found = find_symbol_by_name_recursive (name, symbol.children);
+                if (found != null) {
+                    return found;
+                }
+            }
+        }
+        
+        return null;
+    }
+    
+    /**
+     * Filters symbols based on specified criteria.
+     *
+     * Applies filtering rules to a list of symbols, allowing users
+     * to narrow down results by symbol type, access modifier,
+     * and other criteria. Useful for implementing advanced queries.
+     *
+     * @param symbols List of symbols to filter
+     * @param filter_criteria Criteria for filtering symbols
+     * @return Filtered list of symbols matching the criteria
+     */
+    public Gee.ArrayList<Symbol> filter_symbols (Gee.ArrayList<Symbol> symbols, FilterCriteria filter_criteria) {
+        var filtered = new Gee.ArrayList<Symbol> ();
+        
+        foreach (Symbol symbol in symbols) {
+            if (matches_filter_criteria (symbol, filter_criteria)) {
+                filtered.add (symbol);
+            }
+        }
+        
+        return filtered;
+    }
+    
+    /**
+     * Checks if a symbol matches the filter criteria.
+     *
+     * @param symbol The symbol to check
+     * @param filter_criteria The filter criteria
+     * @return True if the symbol matches the criteria
+     */
+    private bool matches_filter_criteria (Symbol symbol, FilterCriteria filter_criteria) {
+        // Check symbol type filter
+        if (filter_criteria.symbol_type != "" && symbol.symbol_type != filter_criteria.symbol_type) {
+            return false;
+        }
+        
+        // Check access modifier filter
+        if (filter_criteria.access_modifier != "" && symbol.access_modifier != filter_criteria.access_modifier) {
+            return false;
+        }
+        
+        // Check include_private filter
+        if (!filter_criteria.include_private && symbol.access_modifier == "private") {
+            return false;
+        }
+        
+        return true;
+    }
+    
+    /**
+     * Gets all symbols of a specific type from the entire symbol tree.
+     *
+     * Searches through the complete symbol hierarchy to find all symbols
+     * of the specified type (e.g., all classes, all methods).
+     * This is useful for type-based browsing and analysis.
+     *
+     * @param symbol_type The type of symbols to get (e.g., "class", "method")
+     * @return List of symbols of the specified type
+     */
+    public Gee.ArrayList<Symbol> get_symbols_by_type (string symbol_type) {
+        var result = new Gee.ArrayList<Symbol> ();
+        get_symbols_by_type_recursive (symbol_type, root_symbols, result);
+        return result;
+    }
+    
+    /**
+     * Recursively collects symbols of a specific type.
+     *
+     * @param symbol_type The type of symbols to collect
+     * @param symbols List of symbols to search in
+     * @param result List to store the results
+     */
+    private void get_symbols_by_type_recursive (string symbol_type, Gee.ArrayList<Symbol> symbols, Gee.ArrayList<Symbol> result) {
+        foreach (Symbol symbol in symbols) {
+            if (symbol.symbol_type == symbol_type) {
+                result.add (symbol);
+            }
+            
+            // Search in children recursively
+            if (symbol.children.size > 0) {
+                get_symbols_by_type_recursive (symbol_type, symbol.children, result);
+            }
+        }
+    }
+    
+    /**
+     * Gets the parent symbol of a given symbol.
+     *
+     * Provides access to the parent in the hierarchical symbol tree.
+     * Root symbols will have null parents.
+     *
+     * @param symbol The symbol to get the parent for
+     * @return The parent symbol, or null if it's a root symbol
+     */
+    public Symbol? get_parent_symbol (Symbol symbol) {
+        return symbol.parent;
+    }
+    
+    /**
+     * Gets the full hierarchical path of a symbol as an array of names.
+     *
+     * Constructs the path from root to the specified symbol,
+     * returning each component as a separate array element.
+     * This is useful for path manipulation and display.
+     *
+     * @param symbol The symbol to get the path for
+     * @return Array of symbol names representing the hierarchical path
+     */
+    public string[] get_symbol_path (Symbol symbol) {
+        var path = new Gee.ArrayList<string> ();
+        build_symbol_path (symbol, path);
+        
+        // Convert to array and reverse to get root-to-leaf order
+        string[] result = new string[path.size];
+        for (int i = 0; i < path.size; i++) {
+            result[i] = path[path.size - 1 - i];
+        }
+        
+        return result;
+    }
+    
+    /**
+     * Recursively builds the path from a symbol to the root.
+     *
+     * @param symbol The current symbol
+     * @param path List to store the path components
+     */
+    private void build_symbol_path (Symbol symbol, Gee.ArrayList<string> path) {
+        path.add (symbol.name);
+        
+        if (symbol.parent != null) {
+            build_symbol_path (symbol.parent, path);
+        }
+    }
+    
+    /**
+     * Searches for symbols that match a partial name.
+     *
+     * Performs a substring search through all symbols in the tree,
+     * returning any symbols whose names contain the specified partial name.
+     * This is useful for implementing fuzzy search and autocomplete.
+     *
+     * @param partial_name The partial name to match (case-sensitive)
+     * @return List of symbols containing the partial name
+     */
+    public Gee.ArrayList<Symbol> search_by_partial_name (string partial_name) {
+        var result = new Gee.ArrayList<Symbol> ();
+        search_by_partial_name_recursive (partial_name, root_symbols, result);
+        return result;
+    }
+    
+    /**
+     * Recursively searches for symbols matching a partial name.
+     *
+     * @param partial_name The partial name to match
+     * @param symbols List of symbols to search in
+     * @param result List to store the results
+     */
+    private void search_by_partial_name_recursive (string partial_name, Gee.ArrayList<Symbol> symbols, Gee.ArrayList<Symbol> result) {
+        foreach (Symbol symbol in symbols) {
+            if (symbol.name.contains (partial_name)) {
+                result.add (symbol);
+            }
+            
+            // Search in children recursively
+            if (symbol.children.size > 0) {
+                search_by_partial_name_recursive (partial_name, symbol.children, result);
+            }
+        }
+    }
+    
+    /**
+     * Calculates child counts for all symbols in the tree.
+     *
+     * Traverses the entire symbol hierarchy and updates the child_count
+     * property for each symbol to reflect the actual number of children.
+     * This ensures accurate child count information for display purposes.
+     */
+    public void calculate_child_counts () {
+        calculate_child_counts_recursive (root_symbols);
+    }
+    
+    /**
+     * Recursively calculates child counts for a list of symbols.
+     *
+     * @param symbols List of symbols to update child counts for
+     */
+    private void calculate_child_counts_recursive (Gee.ArrayList<Symbol> symbols) {
+        foreach (Symbol symbol in symbols) {
+            // Update child count based on current children
+            symbol.child_count = symbol.children.size;
+            
+            // For enums, include enum values in child count
+            if (symbol is Enum) {
+                var enum_sym = (Enum) symbol;
+                symbol.child_count += enum_sym.values.size;
+            }
+            
+            // Recursively update child counts for children
+            if (symbol.children.size > 0) {
+                calculate_child_counts_recursive (symbol.children);
+            }
+        }
+    }
+    
+    /**
+     * Gets only root-level symbols from the VAPI file.
+     *
+     * Returns only the symbols that are directly at the root level of the VAPI file.
+     * This includes namespaces, classes, interfaces, enums, and other symbols that are
+     * defined at the top level of the VAPI file. It does not include symbols that are
+     * inside namespaces or other container symbols.
+     *
+     * @return List of root-level symbols (actual symbols at the root level, not their children)
+     */
+    public Gee.ArrayList<Symbol> get_root_only_symbols () {
+        var root_only = new Gee.ArrayList<Symbol> ();
+        
+        // Simply return all root symbols as they are
+        // This includes namespaces, classes, interfaces, enums, etc. that are at the root level
+        foreach (Symbol symbol in root_symbols) {
+            root_only.add (symbol);
+        }
+        
+        return root_only;
+    }
+}
+
+/**
+ * Criteria for filtering symbols in search and query operations.
+ *
+ * This class encapsulates filtering parameters that can be applied
+ * to symbol collections to narrow down results based on various
+ * criteria like type, access level, and visibility.
+ */
+public class FilterCriteria : Object {
+    /** Filter by symbol type (e.g., "class", "method", "property") */
+    public string symbol_type { get; set; }
+    
+    /** Filter by access modifier (e.g., "public", "private", "protected") */
+    public string access_modifier { get; set; }
+    
+    /** Whether to include private symbols in results */
+    public bool include_private { get; set; default = false; }
+    
+    /**
+     * Initializes a new FilterCriteria instance with default values.
+     *
+     * Sets up default filtering behavior that excludes private symbols
+     * and doesn't filter by type or access modifier.
+     */
+    public FilterCriteria () {
+        // Initialize with default values
+    }
+}

+ 925 - 0
src/core/vapi-parser.vala

@@ -0,0 +1,925 @@
+/*
+ * vapi-parser.vala
+ *
+ * VAPI file parser using libvala.
+ * This class handles parsing VAPI files and extracting symbol information.
+ */
+
+/**
+ * VAPI file parser that uses libvala to parse and analyze VAPI files.
+ *
+ * This class provides the core functionality for parsing VAPI (Vala API) files
+ * using the official libvala library. It extracts symbols, builds hierarchical
+ * relationships, and provides access to detailed symbol information.
+ *
+ * The parser handles all major Vala language constructs including classes,
+ * interfaces, structs, enums, delegates, methods, properties, fields,
+ * constants, and namespaces.
+ */
+public class VapiParser : Object {
+    
+    /**
+     * Code context for libvala parsing.
+     *
+     * This context manages the parsing state, symbol resolution,
+     * and error reporting for libvala operations.
+     */
+    private Vala.CodeContext context;
+    
+    /**
+     * Root symbols extracted from the parsed VAPI file.
+     *
+     * Contains all top-level symbols found in the VAPI file,
+     * organized in a hierarchical structure with parent-child relationships.
+     */
+    private Gee.ArrayList<Symbol> root_symbols;
+    private Gee.HashSet<string> processed_symbols;
+    
+    /**
+     * Creates a new VapiParser instance.
+     *
+     * Initializes the symbol collection and sets up the libvala
+     * code context for parsing operations.
+     */
+    public VapiParser () {
+        root_symbols = new Gee.ArrayList<Symbol> ();
+        processed_symbols = new Gee.HashSet<string> ();
+        initialize_context ();
+    }
+    
+    /**
+     * Initializes the libvala code context for parsing.
+     *
+     * Sets up a fresh CodeContext with essential packages and VAPI directories.
+     * The context is configured to find standard Vala libraries and VAPI files.
+     */
+    private void initialize_context () {
+        // Create a new context for each parse to avoid state contamination
+        context = new Vala.CodeContext ();
+        
+        // Add essential packages required for most VAPI files
+        context.add_package ("glib-2.0");
+        context.add_package ("gobject-2.0");
+        
+        // Set the library path for VAPI files
+        // These are standard locations where Vala VAPI files are installed
+        context.vapi_directories = { "/usr/share/vala-0.56/vapi", "/usr/local/share/vala-0.56/vapi" };
+    }
+    
+    /**
+     * Parses a VAPI file and extracts all symbols.
+     *
+     * This is the main entry point for parsing VAPI files. It initializes
+     * the libvala context, parses the file, resolves symbols, and
+     * builds the internal symbol hierarchy.
+     *
+     * @param path Path to the VAPI file to parse
+     * @return True if parsing was successful, false otherwise
+     */
+    public bool parse_file (string path) {
+        try {
+            // Clear previous symbols
+            root_symbols.clear ();
+            processed_symbols.clear ();
+            
+            // Initialize context for parsing
+            initialize_context ();
+            
+            // Set this as the current context
+            Vala.CodeContext.push (context);
+            
+            // Create a source file for the VAPI file
+            // Use SOURCE type instead of PACKAGE to ensure it's parsed
+            var source_file = new Vala.SourceFile (context, Vala.SourceFileType.SOURCE, path);
+            context.add_source_file (source_file);
+            
+            
+            
+            // Parse the VAPI file
+            var parser = new Vala.Parser ();
+            parser.parse (context);
+            
+            // Check for parsing errors
+            if (context.report.get_errors () > 0) {
+                stderr.printf ("Error parsing VAPI file '%s': %d errors found\n",
+                              path, context.report.get_errors ());
+                Vala.CodeContext.pop ();
+                return false;
+            }
+            
+            // Extract symbols from the root namespace
+            var root_ns = context.root;
+            extract_symbols_from_namespace (root_ns);
+            
+            // Pop the context
+            Vala.CodeContext.pop ();
+            
+            return true;
+        } catch (Error e) {
+            stderr.printf ("Error parsing VAPI file '%s': %s\n", path, e.message);
+            // Make sure we pop the context even if there's an error
+            try {
+                Vala.CodeContext.pop ();
+            } catch (Error err) {
+                // Ignore if there's no context to pop
+            }
+            return false;
+        }
+    }
+    
+    /**
+     * Extracts symbols from a libvala namespace and adds them to the root symbols.
+     *
+     * Iterates through all symbol types in the namespace (classes, interfaces,
+     * structs, enums, delegates, methods, constants, fields) and converts
+     * them to internal Symbol objects. Also recursively processes child namespaces.
+     *
+     * @param ns The libvala namespace to extract symbols from
+     */
+    private void extract_symbols_from_namespace (Vala.Namespace ns) {
+        // Only process root namespace directly, child namespaces are handled separately
+        if (ns.parent_symbol == null) {
+            // Add top-level namespace symbols
+            add_namespace_symbols_to_root (ns);
+            
+            // Process child namespaces
+            foreach (Vala.Symbol symbol in ns.get_namespaces ()) {
+                if (should_include_symbol (symbol)) {
+                    var converted = convert_libvala_symbol (symbol);
+                    if (converted != null && converted is NamespaceSymbol) {
+                        var ns_symbol = (NamespaceSymbol) converted;
+                        // Ensure the namespace symbol has the correct full path
+                        ns_symbol.namespace_path = get_namespace_full_path ((Vala.Namespace) symbol);
+                        root_symbols.add (ns_symbol);
+                        // Recursively extract symbols from child namespace
+                        var child_ns = (Vala.Namespace) symbol;
+                        extract_symbols_from_child_namespace (child_ns, ns_symbol);
+                        
+                        // Note: Removed add_child_namespace_symbols_to_root(child_ns) to prevent duplicates
+                        // The SymbolNavigator.get_root_only_symbols() method already handles extracting
+                        // namespace children for root-only display functionality
+                    }
+                }
+            }
+        }
+    }
+    
+    /**
+     * Adds symbols from a namespace to the root symbols list.
+     *
+     * This is used for the root namespace to add all non-namespace symbols
+     * with proper namespace path context.
+     *
+     * @param ns The namespace to extract symbols from
+     */
+    private void add_namespace_symbols_to_root (Vala.Namespace ns) {
+        foreach (Vala.Symbol symbol in ns.get_classes ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol_with_namespace (symbol, ns);
+                if (converted != null) {
+                    root_symbols.add (converted);
+                }
+            }
+        }
+        
+        foreach (Vala.Symbol symbol in ns.get_interfaces ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol_with_namespace (symbol, ns);
+                if (converted != null) {
+                    root_symbols.add (converted);
+                }
+            }
+        }
+        
+        foreach (Vala.Symbol symbol in ns.get_structs ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol_with_namespace (symbol, ns);
+                if (converted != null) {
+                    root_symbols.add (converted);
+                }
+            }
+        }
+        
+        foreach (Vala.Symbol symbol in ns.get_enums ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol_with_namespace (symbol, ns);
+                if (converted != null) {
+                    root_symbols.add (converted);
+                }
+            }
+        }
+        
+        foreach (Vala.Symbol symbol in ns.get_delegates ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol_with_namespace (symbol, ns);
+                if (converted != null) {
+                    root_symbols.add (converted);
+                }
+            }
+        }
+        
+        foreach (Vala.Symbol symbol in ns.get_methods ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol_with_namespace (symbol, ns);
+                if (converted != null) {
+                    root_symbols.add (converted);
+                }
+            }
+        }
+        
+        foreach (Vala.Symbol symbol in ns.get_constants ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol_with_namespace (symbol, ns);
+                if (converted != null) {
+                    root_symbols.add (converted);
+                }
+            }
+        }
+        
+        foreach (Vala.Symbol symbol in ns.get_fields ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol_with_namespace (symbol, ns);
+                if (converted != null) {
+                    root_symbols.add (converted);
+                }
+            }
+        }
+    }
+    
+    /**
+     * Extracts symbols from a child namespace and adds them to the parent namespace symbol.
+     *
+     * This method handles nested namespaces by adding their symbols as children
+     * of the parent namespace symbol, maintaining the proper hierarchy.
+     *
+     * @param ns The child namespace to extract symbols from
+     * @param parent_ns_symbol The parent namespace symbol to add children to
+     */
+    private void extract_symbols_from_child_namespace (Vala.Namespace ns, NamespaceSymbol parent_ns_symbol) {
+        // Add all non-namespace symbols as children of the parent namespace
+        foreach (Vala.Symbol symbol in ns.get_classes ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol_with_namespace (symbol, ns);
+                if (converted != null) {
+                    parent_ns_symbol.add_child (converted);
+                }
+            }
+        }
+        
+        foreach (Vala.Symbol symbol in ns.get_interfaces ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol_with_namespace (symbol, ns);
+                if (converted != null) {
+                    parent_ns_symbol.add_child (converted);
+                }
+            }
+        }
+        
+        foreach (Vala.Symbol symbol in ns.get_structs ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol_with_namespace (symbol, ns);
+                if (converted != null) {
+                    parent_ns_symbol.add_child (converted);
+                }
+            }
+        }
+        
+        foreach (Vala.Symbol symbol in ns.get_enums ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol_with_namespace (symbol, ns);
+                if (converted != null) {
+                    parent_ns_symbol.add_child (converted);
+                }
+            }
+        }
+        
+        foreach (Vala.Symbol symbol in ns.get_delegates ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol_with_namespace (symbol, ns);
+                if (converted != null) {
+                    parent_ns_symbol.add_child (converted);
+                }
+            }
+        }
+        
+        foreach (Vala.Symbol symbol in ns.get_methods ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol_with_namespace (symbol, ns);
+                if (converted != null) {
+                    parent_ns_symbol.add_child (converted);
+                }
+            }
+        }
+        
+        foreach (Vala.Symbol symbol in ns.get_constants ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol_with_namespace (symbol, ns);
+                if (converted != null) {
+                    parent_ns_symbol.add_child (converted);
+                }
+            }
+        }
+        
+        foreach (Vala.Symbol symbol in ns.get_fields ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol_with_namespace (symbol, ns);
+                if (converted != null) {
+                    parent_ns_symbol.add_child (converted);
+                }
+            }
+        }
+        
+        // Recursively process nested child namespaces
+        foreach (Vala.Symbol symbol in ns.get_namespaces ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol (symbol);
+                if (converted != null && converted is NamespaceSymbol) {
+                    // Ensure the namespace symbol has the correct full path
+                    var ns_symbol = (NamespaceSymbol) converted;
+                    ns_symbol.namespace_path = get_namespace_full_path ((Vala.Namespace) symbol);
+                    parent_ns_symbol.add_child (ns_symbol);
+                    var child_ns = (Vala.Namespace) symbol;
+                    extract_symbols_from_child_namespace (child_ns, ns_symbol);
+                }
+            }
+        }
+    }
+    
+    
+    /**
+     * Extracts root symbols from the libvala namespace.
+     *
+     * @param ns The root namespace
+     */
+    /**
+     * Determines if a symbol should be included in the output.
+     *
+     * Filters out private and internal symbols that are typically not
+     * part of the public API. This ensures that only relevant
+     * symbols are displayed to users.
+     *
+     * @param symbol The libvala symbol to check
+     * @return True if the symbol should be included in the output
+     */
+    private bool should_include_symbol (Vala.Symbol symbol) {
+        // Skip private symbols
+        if (symbol.access == Vala.SymbolAccessibility.PRIVATE) {
+            return false;
+        }
+        
+        // Skip internal symbols unless they're explicitly part of the VAPI being parsed
+        if (symbol.access == Vala.SymbolAccessibility.INTERNAL) {
+            return false;
+        }
+        
+        return true;
+    }
+    
+    /**
+     * Converts a libvala symbol to our internal Symbol model.
+     *
+     * Acts as a factory method that dispatches to specific conversion
+     * functions based on the symbol type. This provides a clean
+     * separation between libvala types and our internal model.
+     *
+     * @param vala_symbol The libvala symbol to convert
+     * @return Converted symbol or null if conversion failed
+     */
+    private Symbol? convert_libvala_symbol (Vala.Symbol vala_symbol) {
+        if (vala_symbol is Vala.Class) {
+            return convert_class ((Vala.Class) vala_symbol);
+        } else if (vala_symbol is Vala.Interface) {
+            return convert_interface ((Vala.Interface) vala_symbol);
+        } else if (vala_symbol is Vala.Struct) {
+            return convert_struct ((Vala.Struct) vala_symbol);
+        } else if (vala_symbol is Vala.Enum) {
+            return convert_enum ((Vala.Enum) vala_symbol);
+        } else if (vala_symbol is Vala.Delegate) {
+            return convert_delegate ((Vala.Delegate) vala_symbol);
+        } else if (vala_symbol is Vala.Namespace) {
+            return convert_namespace ((Vala.Namespace) vala_symbol);
+        } else if (vala_symbol is Vala.Method) {
+            return convert_method ((Vala.Method) vala_symbol);
+        } else if (vala_symbol is Vala.Property) {
+            return convert_property ((Vala.Property) vala_symbol);
+        } else if (vala_symbol is Vala.Constant) {
+            return convert_constant ((Vala.Constant) vala_symbol);
+        } else if (vala_symbol is Vala.Field) {
+            return convert_field ((Vala.Field) vala_symbol);
+        }
+        
+        return null;
+    }
+    
+    /**
+     * Converts a libvala symbol to our internal Symbol model with namespace context.
+     *
+     * Similar to convert_libvala_symbol() but also sets the namespace_path
+     * to ensure proper hierarchical path construction for symbols within namespaces.
+     *
+     * @param vala_symbol The libvala symbol to convert
+     * @param ns The namespace containing the symbol
+     * @return Converted symbol or null if conversion failed
+     */
+    private Symbol? convert_libvala_symbol_with_namespace (Vala.Symbol vala_symbol, Vala.Namespace ns) {
+        // Create a unique identifier for this symbol to avoid duplicates
+        string symbol_id = get_symbol_unique_id (vala_symbol, ns);
+        
+        // Check if we've already processed this symbol
+        if (processed_symbols.contains (symbol_id)) {
+            return null; // Skip duplicate
+        }
+        
+        Symbol? symbol = convert_libvala_symbol (vala_symbol);
+        if (symbol != null) {
+            // Set the namespace path for full path construction
+            symbol.namespace_path = get_namespace_full_path (ns);
+            // Mark this symbol as processed
+            processed_symbols.add (symbol_id);
+        }
+        return symbol;
+    }
+    
+    /**
+     * Creates a unique identifier for a symbol to track duplicates.
+     *
+     * Combines the symbol name, type, and full namespace path
+     * to create a unique identifier that can be used to detect
+     * duplicate processing of the same symbol.
+     *
+     * @param vala_symbol The libvala symbol
+     * @param ns The namespace containing the symbol
+     * @return Unique identifier string
+     */
+    private string get_symbol_unique_id (Vala.Symbol vala_symbol, Vala.Namespace ns) {
+        return "%s|%s|%s".printf (vala_symbol.name, vala_symbol.type_name, get_namespace_full_path (ns));
+    }
+    
+    /**
+     * Gets the full path of a namespace as a string.
+     *
+     * Builds the complete namespace hierarchy by traversing up the parent chain.
+     * This ensures that nested namespaces like Invercargill.DataStructures are
+     * properly constructed instead of just returning "DataStructures".
+     *
+     * @param ns The namespace to get the path for
+     * @return Full namespace path (e.g., "Invercargill.DataStructures")
+     */
+    private string get_namespace_full_path (Vala.Namespace ns) {
+        if (ns.name == null || ns.name == "") {
+            return "";
+        }
+        
+        // Build the full namespace path by traversing parent namespaces
+        var path_parts = new Gee.ArrayList<string> ();
+        Vala.Symbol? current = ns;
+        
+        // Traverse up the namespace hierarchy
+        while (current != null && current.name != null && current.name != "") {
+            path_parts.insert (0, current.name);
+            current = current.parent_symbol;
+        }
+        
+        // Join all parts with dots
+        return string.joinv (".", path_parts.to_array ());
+    }
+    
+    /**
+     * Converts a libvala Class to our Class model.
+     */
+    private Class convert_class (Vala.Class vala_class) {
+        var cls = new Class ();
+        cls.name = vala_class.name;
+        cls.access_modifier = get_access_modifier (vala_class.access);
+        
+        // Add base classes
+        foreach (Vala.DataType base_type in vala_class.get_base_types ()) {
+            if (base_type != null) {
+                cls.base_classes.add (base_type.to_string ());
+            }
+        }
+        
+        // Add child symbols (methods, properties, fields)
+        add_child_symbols (cls, vala_class);
+        
+        return cls;
+    }
+    
+    /**
+     * Converts a libvala Interface to our Interface model.
+     */
+    private Interface convert_interface (Vala.Interface vala_interface) {
+        var iface = new Interface ();
+        iface.name = vala_interface.name;
+        iface.access_modifier = get_access_modifier (vala_interface.access);
+        
+        // Add prerequisites
+        foreach (Vala.DataType prereq in vala_interface.get_prerequisites ()) {
+            if (prereq != null) {
+                iface.prerequisites.add (prereq.to_string ());
+            }
+        }
+        
+        // Add child symbols
+        add_child_symbols (iface, vala_interface);
+        
+        return iface;
+    }
+    
+    /**
+     * Converts a libvala Struct to our Struct model.
+     */
+    private Struct convert_struct (Vala.Struct vala_struct) {
+        var struct_sym = new Struct ();
+        struct_sym.name = vala_struct.name;
+        struct_sym.access_modifier = get_access_modifier (vala_struct.access);
+        
+        // Add base structs
+        // Note: Structs in Vala don't typically have base types like classes
+        // This is here for completeness but may not be commonly used
+        
+        // Add child symbols
+        add_child_symbols (struct_sym, vala_struct);
+        
+        return struct_sym;
+    }
+    
+    /**
+     * Converts a libvala Enum to our Enum model.
+     */
+    private Enum convert_enum (Vala.Enum vala_enum) {
+        var enum_sym = new Enum ();
+        enum_sym.name = vala_enum.name;
+        enum_sym.access_modifier = get_access_modifier (vala_enum.access);
+        
+        // Add enum values with metadata
+        foreach (Vala.EnumValue vala_value in vala_enum.get_values ()) {
+            var enum_value = new EnumValue ();
+            enum_value.name = vala_value.name;
+            
+            // Extract numeric value if available
+            if (vala_value.value != null) {
+                enum_value.numeric_value = vala_value.value.to_string ();
+            }
+            
+            // Note: Vala.EnumValue doesn't have a documentation property
+            // Documentation would need to be extracted from source comments separately
+            
+            enum_sym.values.add (enum_value);
+        }
+        
+        return enum_sym;
+    }
+    
+    /**
+     * Converts a libvala Delegate to our Delegate model.
+     */
+    private Delegate convert_delegate (Vala.Delegate vala_delegate) {
+        var del = new Delegate ();
+        del.name = vala_delegate.name;
+        del.access_modifier = get_access_modifier (vala_delegate.access);
+        del.return_type = vala_delegate.return_type != null ? vala_delegate.return_type.to_string () : "void";
+        
+        // Add parameters
+        foreach (Vala.Parameter param in vala_delegate.get_parameters ()) {
+            Parameter p = new Parameter ();
+            p.name = param.name;
+            p.param_type = param.variable_type != null ? param.variable_type.to_string () : "void";
+            p.direction = get_parameter_direction (param.direction);
+            del.parameters.add (p);
+        }
+        
+        return del;
+    }
+    
+    /**
+     * Converts a libvala Namespace to our Symbol model.
+     */
+    private Symbol convert_namespace (Vala.Namespace vala_namespace) {
+        var ns = new NamespaceSymbol ();
+        ns.name = vala_namespace.name;
+        ns.symbol_type = "namespace";
+        ns.access_modifier = "public";
+        
+        // Set the namespace path for proper full path construction
+        ns.namespace_path = get_namespace_full_path (vala_namespace);
+        
+        // Note: Child namespaces are handled elsewhere to avoid duplicates
+        // They are processed in extract_symbols_from_child_namespace() method
+        
+        foreach (Vala.Symbol symbol in vala_namespace.get_classes ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol_with_namespace (symbol, vala_namespace);
+                if (converted != null) {
+                    ns.add_child (converted);
+                }
+            }
+        }
+        
+        foreach (Vala.Symbol symbol in vala_namespace.get_interfaces ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol_with_namespace (symbol, vala_namespace);
+                if (converted != null) {
+                    ns.add_child (converted);
+                }
+            }
+        }
+        
+        foreach (Vala.Symbol symbol in vala_namespace.get_structs ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol_with_namespace (symbol, vala_namespace);
+                if (converted != null) {
+                    ns.add_child (converted);
+                }
+            }
+        }
+        
+        foreach (Vala.Symbol symbol in vala_namespace.get_enums ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol_with_namespace (symbol, vala_namespace);
+                if (converted != null) {
+                    ns.add_child (converted);
+                }
+            }
+        }
+        
+        foreach (Vala.Symbol symbol in vala_namespace.get_delegates ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol_with_namespace (symbol, vala_namespace);
+                if (converted != null) {
+                    ns.add_child (converted);
+                }
+            }
+        }
+        
+        foreach (Vala.Symbol symbol in vala_namespace.get_methods ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol_with_namespace (symbol, vala_namespace);
+                if (converted != null) {
+                    ns.add_child (converted);
+                }
+            }
+        }
+        
+        foreach (Vala.Symbol symbol in vala_namespace.get_constants ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol_with_namespace (symbol, vala_namespace);
+                if (converted != null) {
+                    ns.add_child (converted);
+                }
+            }
+        }
+        
+        foreach (Vala.Symbol symbol in vala_namespace.get_fields ()) {
+            if (should_include_symbol (symbol)) {
+                var converted = convert_libvala_symbol_with_namespace (symbol, vala_namespace);
+                if (converted != null) {
+                    ns.add_child (converted);
+                }
+            }
+        }
+        
+        return ns;
+    }
+    
+    /**
+     * Converts a libvala Method to our Method model.
+     */
+    private Method convert_method (Vala.Method vala_method) {
+        var method = new Method ();
+        method.name = vala_method.name;
+        method.access_modifier = get_access_modifier (vala_method.access);
+        method.return_type = vala_method.return_type != null ? vala_method.return_type.to_string () : "void";
+        method.is_static = vala_method.binding == Vala.MemberBinding.STATIC;
+        method.is_virtual = vala_method.is_virtual;
+        method.is_override = vala_method.overrides;
+        
+        // Add parameters
+        foreach (Vala.Parameter param in vala_method.get_parameters ()) {
+            Parameter p = new Parameter ();
+            p.name = param.name;
+            p.param_type = param.variable_type != null ? param.variable_type.to_string () : "void";
+            p.direction = get_parameter_direction (param.direction);
+            if (param.initializer != null) {
+                p.default_value = param.initializer.to_string ();
+            }
+            method.parameters.add (p);
+        }
+        
+        return method;
+    }
+    
+    /**
+     * Converts a libvala Constant to our Constant model.
+     */
+    private Constant convert_constant (Vala.Constant vala_constant) {
+        var constant = new Constant ();
+        constant.name = vala_constant.name;
+        constant.access_modifier = get_access_modifier (vala_constant.access);
+        constant.constant_type = vala_constant.type_reference != null ? vala_constant.type_reference.to_string () : "void";
+        if (vala_constant.value != null) {
+            constant.value = vala_constant.value.to_string ();
+        }
+        
+        return constant;
+    }
+    
+    /**
+     * Converts a libvala Field to our Field model.
+     */
+    private Field convert_field (Vala.Field vala_field) {
+        var field = new Field ();
+        field.name = vala_field.name;
+        field.access_modifier = get_access_modifier (vala_field.access);
+        field.field_type = vala_field.variable_type != null ? vala_field.variable_type.to_string () : "void";
+        field.is_static = vala_field.binding == Vala.MemberBinding.STATIC;
+        if (vala_field.initializer != null) {
+            field.default_value = vala_field.initializer.to_string ();
+        }
+        
+        return field;
+    }
+    
+    /**
+     * Converts a libvala Property to our Property model.
+     */
+    private Property convert_property (Vala.Property vala_property) {
+        var property = new Property ();
+        property.name = vala_property.name;
+        property.access_modifier = get_access_modifier (vala_property.access);
+        property.property_type = vala_property.property_type != null ? vala_property.property_type.to_string () : "void";
+        
+        // Determine property access modifiers
+        property.is_read_only = (vala_property.get_accessor == null || vala_property.get_accessor.access == Vala.SymbolAccessibility.PRIVATE);
+        property.is_write_only = (vala_property.set_accessor == null || vala_property.set_accessor.access == Vala.SymbolAccessibility.PRIVATE);
+        property.is_construct = vala_property.binding == Vala.MemberBinding.INSTANCE;
+        
+        return property;
+    }
+    
+    /**
+     * Adds child symbols to a parent symbol.
+     */
+    private void add_child_symbols (Symbol parent, Vala.Symbol parent_vala) {
+        if (parent_vala is Vala.Class) {
+            var vala_class = (Vala.Class) parent_vala;
+            foreach (Vala.Symbol child in vala_class.get_members ()) {
+                if (should_include_symbol (child)) {
+                    var converted = convert_libvala_symbol (child);
+                    if (converted != null) {
+                        parent.add_child (converted);
+                    }
+                }
+            }
+        } else if (parent_vala is Vala.Interface) {
+            var vala_interface = (Vala.Interface) parent_vala;
+            foreach (Vala.Symbol child in vala_interface.get_members ()) {
+                if (should_include_symbol (child)) {
+                    var converted = convert_libvala_symbol (child);
+                    if (converted != null) {
+                        parent.add_child (converted);
+                    }
+                }
+            }
+        } else if (parent_vala is Vala.Struct) {
+            var vala_struct = (Vala.Struct) parent_vala;
+            foreach (Vala.Field field in vala_struct.get_fields ()) {
+                if (should_include_symbol (field)) {
+                    var converted = convert_libvala_symbol (field);
+                    if (converted != null) {
+                        parent.add_child (converted);
+                    }
+                }
+            }
+            foreach (Vala.Method method in vala_struct.get_methods ()) {
+                if (should_include_symbol (method)) {
+                    var converted = convert_libvala_symbol (method);
+                    if (converted != null) {
+                        parent.add_child (converted);
+                    }
+                }
+            }
+            foreach (Vala.Property prop in vala_struct.get_properties ()) {
+                if (should_include_symbol (prop)) {
+                    var converted = convert_libvala_symbol (prop);
+                    if (converted != null) {
+                        parent.add_child (converted);
+                    }
+                }
+            }
+        } else if (parent_vala is Vala.Namespace) {
+            // Namespaces are handled specially in convert_namespace
+            // Don't add children here to avoid duplication
+        }
+    }
+    
+    /**
+     * Gets the access modifier string from libvala access.
+     */
+    private string get_access_modifier (Vala.SymbolAccessibility access) {
+        switch (access) {
+            case Vala.SymbolAccessibility.PUBLIC:
+                return "public";
+            case Vala.SymbolAccessibility.PRIVATE:
+                return "private";
+            case Vala.SymbolAccessibility.PROTECTED:
+                return "protected";
+            case Vala.SymbolAccessibility.INTERNAL:
+                return "internal";
+            default:
+                return "public";
+        }
+    }
+    
+    /**
+     * Gets the parameter direction string from libvala direction.
+     */
+    private string get_parameter_direction (Vala.ParameterDirection direction) {
+        switch (direction) {
+            case Vala.ParameterDirection.IN:
+                return "in";
+            case Vala.ParameterDirection.OUT:
+                return "out";
+            case Vala.ParameterDirection.REF:
+                return "ref";
+            default:
+                return "in";
+        }
+    }
+    
+    /**
+     * Gets the root symbols from the parsed VAPI file.
+     *
+     * Returns the collection of all top-level symbols that were
+     * extracted during the parsing process. These symbols form
+     * the root of the hierarchical symbol tree.
+     *
+     * @return Array of root symbols
+     */
+    public Gee.ArrayList<Symbol> get_root_symbols () {
+        return root_symbols;
+    }
+    
+    /**
+     * Gets detailed information about a specific symbol.
+     *
+     * Creates a SymbolDetails object containing comprehensive information
+     * about the symbol including methods, properties, fields, parameters,
+     * and other relevant details. Used by output formatters.
+     *
+     * @param symbol The symbol to get details for
+     * @return Detailed symbol information
+     */
+    public SymbolDetails get_symbol_details (Symbol symbol) {
+        var details = new SymbolDetails ();
+        details.name = symbol.name;
+        details.symbol_type = symbol.symbol_type;
+        details.access = symbol.access_modifier;
+        details.child_count = symbol.child_count;
+        
+        // Add more detailed information based on symbol type
+        if (symbol is Class) {
+            var cls = (Class) symbol;
+            details.base_types = cls.base_classes;
+            
+            // Add methods, properties, fields from children
+            extract_symbol_details_from_children (symbol, details);
+        } else if (symbol is Interface) {
+            var iface = (Interface) symbol;
+            details.base_types = iface.prerequisites;
+            extract_symbol_details_from_children (symbol, details);
+        } else if (symbol is Enum) {
+            var enum_sym = (Enum) symbol;
+            details.enum_values = enum_sym.values;
+        } else if (symbol is Method) {
+            var method = (Method) symbol;
+            details.return_type = method.return_type;
+            details.parameters = method.parameters;
+        } else if (symbol is Delegate) {
+            var del = (Delegate) symbol;
+            details.return_type = del.return_type;
+            details.parameters = del.parameters;
+        } else if (symbol is NamespaceSymbol) {
+            // For namespaces, add child symbols and extract method details
+            details.child_symbols = symbol.children;
+            extract_symbol_details_from_children (symbol, details);
+        }
+        
+        return details;
+    }
+    
+    /**
+     * Extracts detailed information from child symbols.
+     */
+    private void extract_symbol_details_from_children (Symbol symbol, SymbolDetails details) {
+        foreach (Symbol child in symbol.children) {
+            if (child is Method) {
+                details.methods.add ((Method) child);
+            } else if (child is Property) {
+                details.properties.add ((Property) child);
+            } else if (child is Field) {
+                details.fields.add ((Field) child);
+            }
+        }
+    }
+}

+ 138 - 0
src/main.vala

@@ -0,0 +1,138 @@
+/*
+ * main.vala
+ *
+ * Entry point for the valaq CLI application.
+ * This file contains the main function that initializes and runs the application.
+ */
+
+int main (string[] args) {
+    // Set up error handling
+    int exit_code = 0;
+    
+    try {
+        // Create and run the application
+        var app = new ValaqApplication ();
+        exit_code = app.run (args);
+    } catch (ValaqError e) {
+        // Handle custom valaq errors
+        stderr.printf ("valaq error: %s\n", e.message);
+        exit_code = get_error_code_from_valaq_error (e);
+    } catch (FileError e) {
+        // Handle file system errors
+        stderr.printf ("File error: %s\n", e.message);
+        exit_code = 1;
+    } catch (Error e) {
+        // Handle any other errors
+        stderr.printf ("Unexpected error: %s\n", e.message);
+        exit_code = 1;
+    }
+    
+    // Ensure clean shutdown
+    cleanup_resources ();
+    
+    return exit_code;
+}
+
+/**
+ * Gets the appropriate exit code for a ValaqError.
+ */
+private int get_error_code_from_valaq_error (ValaqError e) {
+    switch (e.code) {
+        case ValaqError.FILE_NOT_FOUND:
+            return 1;
+        case ValaqError.PARSE_ERROR:
+            return 2;
+        case ValaqError.NAVIGATION_ERROR:
+            return 1;
+        case ValaqError.OUTPUT_ERROR:
+            return 1;
+        case ValaqError.INVALID_ARGUMENT:
+            return 1;
+        default:
+            return 1;
+    }
+}
+
+/**
+ * Performs cleanup of resources before exit.
+ */
+private void cleanup_resources () {
+    // Clean up any resources here
+    // This will be expanded as needed
+}
+
+/**
+ * The main application class for valaq.
+ *
+ * This class serves as the primary coordinator for the valaq application.
+ * It handles initialization, argument parsing, component coordination, and
+ * provides the main application flow. The class integrates all major
+ * components including argument parsing, command handling, VAPI parsing,
+ * symbol navigation, and output formatting.
+ *
+ * The application follows a clean architecture with proper error handling
+ * and resource management throughout the execution lifecycle.
+ */
+public class ValaqApplication : Object {
+    
+    /**
+     * Runs the application with the provided command-line arguments.
+     *
+     * This is the main entry point for application logic after
+     * initial setup. It coordinates between argument parsing,
+     * command handling, and error management.
+     *
+     * @param args Command-line arguments from the operating system
+     * @return Exit code (0 for success, non-zero for error)
+     */
+    public int run (string[] args) throws ValaqError, Error {
+        // Validate basic environment
+        validate_environment ();
+        
+        // Initialize argument parser
+        var arg_parser = new ArgumentParser ();
+        
+        // Parse command-line arguments
+        if (!arg_parser.parse (args)) {
+            stderr.printf ("Error: %s\n", arg_parser.get_error_message ());
+            stderr.printf ("Use 'valaq --help' for usage information.\n");
+            return 1;
+        }
+        
+        // Initialize command handler
+        CommandHandler command_handler;
+        try {
+            command_handler = new CommandHandler ();
+        } catch (Error e) {
+            throw new ValaqError.INITIALIZATION_ERROR ("Failed to initialize command handler: %s".printf (e.message));
+        }
+        
+        // Process the command
+        return command_handler.handle_command (arg_parser);
+    }
+    
+    /**
+     * Validates the runtime environment for valaq execution.
+     *
+     * Performs essential environment checks to ensure the application
+     * can run properly. This includes verifying basic system
+     * requirements like directory access and environment variables.
+     *
+     * @throws ValaqError.ENVIRONMENT_ERROR if environment is not suitable
+     */
+    private void validate_environment () throws ValaqError {
+        // Check if we're running in a supported environment
+        // This can be expanded with more checks as needed
+        
+        // Verify basic system requirements
+        if (Environment.get_home_dir () == null) {
+            throw new ValaqError.ENVIRONMENT_ERROR ("Cannot determine user home directory");
+        }
+        
+        // Check if we can access basic directories
+        string current_dir = Environment.get_current_dir ();
+        if (current_dir == "") {
+            throw new ValaqError.ENVIRONMENT_ERROR ("Cannot determine current working directory");
+        }
+    }
+}

+ 56 - 0
src/output/formatter.vala

@@ -0,0 +1,56 @@
+/*
+ * formatter.vala
+ * 
+ * Output formatting interface for valaq.
+ * This file defines the interface for output formatters.
+ */
+
+/**
+ * Interface for output formatters.
+ *
+ * This interface defines the contract for all output formatters in valaq.
+ * It provides a unified way to format symbols, error messages, and
+ * other output in different formats (text, JSON, etc.).
+ *
+ * All output formatters must implement this interface to ensure
+ * consistent behavior across different output types.
+ */
+public interface OutputFormatter : Object {
+    
+    /**
+     * Formats a list of symbols for output.
+     *
+     * Takes a collection of symbols and formats them according to the
+     * specific output format (text, JSON, etc.). This is typically
+     * used for displaying top-level symbols or search results.
+     *
+     * @param symbols List of symbols to format
+     * @return Formatted output string ready for display
+     */
+    public abstract string format_symbol_list (Gee.ArrayList<Symbol> symbols);
+    
+    /**
+     * Formats detailed information about a symbol.
+     *
+     * Takes a SymbolDetails object containing comprehensive information
+     * about a symbol and formats it for display. This is used
+     * when users navigate to a specific symbol and need full details.
+     *
+     * @param symbol The symbol details to format
+     * @return Formatted output string ready for display
+     */
+    public abstract string format_symbol_details (SymbolDetails symbol);
+    
+    /**
+     * Formats an error message.
+     *
+     * Takes error information and formats it appropriately for the
+     * specific output format. This ensures consistent error reporting
+     * across all formatter implementations.
+     *
+     * @param error_type Type of error (e.g., "file_not_found", "parse_error")
+     * @param message Human-readable error message
+     * @return Formatted error string ready for display
+     */
+    public abstract string format_error (string error_type, string message);
+}

+ 445 - 0
src/output/json-formatter.vala

@@ -0,0 +1,445 @@
+/*
+ * json-formatter.vala
+ *
+ * JSON output formatter for valaq.
+ * This class provides JSON formatting for symbol information.
+ */
+
+/**
+ * JSON formatter for structured output.
+ */
+public class JsonFormatter : Object, OutputFormatter {
+    
+    /**
+     * Creates a new JsonFormatter instance.
+     */
+    public JsonFormatter () {
+        // Initialize JSON formatter
+    }
+    
+    /**
+     * Converts a Json.Node to a formatted JSON string.
+     *
+     * @param node The JSON node to convert
+     * @return Formatted JSON string
+     */
+    private string json_to_string (Json.Node node) {
+        var generator = new Json.Generator ();
+        generator.set_root (node);
+        generator.set_pretty (true);
+        generator.set_indent (2);
+        return generator.to_data (null);
+    }
+    
+    /**
+     * Formats a list of symbols as JSON.
+     *
+     * @param symbols List of symbols to format
+     * @return Formatted JSON string
+     */
+    public string format_symbol_list (Gee.ArrayList<Symbol> symbols) {
+        var builder = new Json.Builder ();
+        
+        builder.begin_object ();
+        
+        // Add result_type
+        builder.set_member_name ("result_type");
+        builder.add_string_value ("symbol_list");
+        
+        // Add symbols array
+        builder.set_member_name ("symbols");
+        builder.begin_array ();
+        
+        foreach (Symbol symbol in symbols) {
+            build_symbol_json (builder, symbol);
+        }
+        
+        builder.end_array ();
+        
+        // Add metadata
+        builder.set_member_name ("metadata");
+        builder.begin_object ();
+        builder.set_member_name ("total_symbols");
+        builder.add_int_value (symbols.size);
+        builder.set_member_name ("timestamp");
+        builder.add_string_value (get_current_timestamp ());
+        builder.end_object ();
+        
+        builder.end_object ();
+        
+        return json_to_string (builder.get_root ());
+    }
+    
+    /**
+     * Formats detailed information about a symbol as JSON.
+     *
+     * @param symbol The symbol to format
+     * @return Formatted JSON string
+     */
+    public string format_symbol_details (SymbolDetails symbol) {
+        var builder = new Json.Builder ();
+        
+        builder.begin_object ();
+        
+        // Add result_type
+        builder.set_member_name ("result_type");
+        builder.add_string_value ("symbol_details");
+        
+        // Add symbol object
+        builder.set_member_name ("symbol");
+        builder.begin_object ();
+        build_symbol_details_json (builder, symbol);
+        builder.end_object ();
+        
+        // Add metadata
+        builder.set_member_name ("metadata");
+        builder.begin_object ();
+        builder.set_member_name ("timestamp");
+        builder.add_string_value (get_current_timestamp ());
+        builder.end_object ();
+        
+        builder.end_object ();
+        
+        return json_to_string (builder.get_root ());
+    }
+    
+    /**
+     * Formats an error message as JSON.
+     *
+     * @param error_type Type of error
+     * @param message Error message
+     * @return Formatted JSON string
+     */
+    public string format_error (string error_type, string message) {
+        var builder = new Json.Builder ();
+        
+        builder.begin_object ();
+        
+        // Add error object
+        builder.set_member_name ("error");
+        builder.begin_object ();
+        builder.set_member_name ("type");
+        builder.add_string_value (error_type);
+        builder.set_member_name ("message");
+        builder.add_string_value (message);
+        builder.end_object ();
+        
+        // Add metadata
+        builder.set_member_name ("metadata");
+        builder.begin_object ();
+        builder.set_member_name ("timestamp");
+        builder.add_string_value (get_current_timestamp ());
+        builder.end_object ();
+        
+        builder.end_object ();
+        
+        return json_to_string (builder.get_root ());
+    }
+    
+    /**
+     * Builds a symbol JSON object using Json.Builder.
+     *
+     * @param builder The Json.Builder instance
+     * @param symbol The symbol to build JSON for
+     */
+    private void build_symbol_json (Json.Builder builder, Symbol symbol) {
+        builder.begin_object ();
+        
+        builder.set_member_name ("name");
+        builder.add_string_value (symbol.name);
+        
+        builder.set_member_name ("type");
+        builder.add_string_value (symbol.symbol_type);
+        
+        builder.set_member_name ("access");
+        builder.add_string_value (symbol.access_modifier);
+        
+        // Add full_path field
+        builder.set_member_name ("full_path");
+        builder.add_string_value (symbol.get_full_path ());
+        
+        // Add child_count field
+        builder.set_member_name ("child_count");
+        builder.add_int_value (symbol.child_count);
+        
+        if (symbol.source_location != null) {
+            builder.set_member_name ("source_location");
+            builder.begin_object ();
+            builder.set_member_name ("file");
+            builder.add_string_value (symbol.source_location.file);
+            builder.set_member_name ("line");
+            builder.add_int_value (symbol.source_location.line);
+            builder.end_object ();
+        }
+        
+        if (symbol.documentation != "") {
+            builder.set_member_name ("documentation");
+            builder.add_string_value (symbol.documentation);
+        }
+        
+        builder.end_object ();
+    }
+    
+    /**
+     * Builds detailed symbol information JSON using Json.Builder.
+     *
+     * @param builder The Json.Builder instance
+     * @param symbol The symbol details to build JSON for
+     */
+    private void build_symbol_details_json (Json.Builder builder, SymbolDetails symbol) {
+        builder.set_member_name ("name");
+        builder.add_string_value (symbol.name);
+        
+        builder.set_member_name ("type");
+        builder.add_string_value (symbol.symbol_type);
+        
+        builder.set_member_name ("access");
+        builder.add_string_value (symbol.access);
+        
+        // Add child_count field
+        builder.set_member_name ("child_count");
+        builder.add_int_value (symbol.child_count);
+        
+        if (symbol.return_type != "") {
+            builder.set_member_name ("return_type");
+            builder.add_string_value (symbol.return_type);
+        }
+        
+        if (symbol.full_path != "") {
+            builder.set_member_name ("full_path");
+            builder.add_string_value (symbol.full_path);
+        }
+        
+        // Parameters
+        if (symbol.parameters.size > 0) {
+            builder.set_member_name ("parameters");
+            builder.begin_array ();
+            foreach (Parameter param in symbol.parameters) {
+                builder.begin_object ();
+                builder.set_member_name ("name");
+                builder.add_string_value (param.name);
+                builder.set_member_name ("type");
+                builder.add_string_value (param.param_type);
+                builder.set_member_name ("direction");
+                builder.add_string_value (param.direction);
+                
+                if (param.default_value != "") {
+                    builder.set_member_name ("default_value");
+                    builder.add_string_value (param.default_value);
+                }
+                
+                builder.end_object ();
+            }
+            builder.end_array ();
+        }
+        
+        // Properties
+        if (symbol.properties.size > 0) {
+            builder.set_member_name ("properties");
+            builder.begin_array ();
+            foreach (Property prop in symbol.properties) {
+                builder.begin_object ();
+                builder.set_member_name ("name");
+                builder.add_string_value (prop.name);
+                builder.set_member_name ("type");
+                builder.add_string_value (prop.property_type);
+                builder.set_member_name ("access");
+                builder.add_string_value (prop.access_modifier);
+                
+                if (prop.is_read_only) {
+                    builder.set_member_name ("read_only");
+                    builder.add_boolean_value (true);
+                }
+                if (prop.is_write_only) {
+                    builder.set_member_name ("write_only");
+                    builder.add_boolean_value (true);
+                }
+                if (prop.is_construct) {
+                    builder.set_member_name ("construct");
+                    builder.add_boolean_value (true);
+                }
+                
+                builder.end_object ();
+            }
+            builder.end_array ();
+        }
+        
+        // Methods
+        if (symbol.methods.size > 0) {
+            builder.set_member_name ("methods");
+            builder.begin_array ();
+            foreach (Method method in symbol.methods) {
+                builder.begin_object ();
+                builder.set_member_name ("name");
+                builder.add_string_value (method.name);
+                builder.set_member_name ("return_type");
+                builder.add_string_value (method.return_type);
+                builder.set_member_name ("access");
+                builder.add_string_value (method.access_modifier);
+                
+                if (method.is_static) {
+                    builder.set_member_name ("static");
+                    builder.add_boolean_value (true);
+                }
+                if (method.is_virtual) {
+                    builder.set_member_name ("virtual");
+                    builder.add_boolean_value (true);
+                }
+                if (method.is_override) {
+                    builder.set_member_name ("override");
+                    builder.add_boolean_value (true);
+                }
+                
+                // Method parameters
+                if (method.parameters.size > 0) {
+                    builder.set_member_name ("parameters");
+                    builder.begin_array ();
+                    foreach (Parameter param in method.parameters) {
+                        builder.begin_object ();
+                        builder.set_member_name ("name");
+                        builder.add_string_value (param.name);
+                        builder.set_member_name ("type");
+                        builder.add_string_value (param.param_type);
+                        builder.set_member_name ("direction");
+                        builder.add_string_value (param.direction);
+                        
+                        if (param.default_value != "") {
+                            builder.set_member_name ("default_value");
+                            builder.add_string_value (param.default_value);
+                        }
+                        
+                        builder.end_object ();
+                    }
+                    builder.end_array ();
+                }
+                
+                builder.end_object ();
+            }
+            builder.end_array ();
+        }
+        
+        // Fields
+        if (symbol.fields.size > 0) {
+            builder.set_member_name ("fields");
+            builder.begin_array ();
+            foreach (Field field in symbol.fields) {
+                builder.begin_object ();
+                builder.set_member_name ("name");
+                builder.add_string_value (field.name);
+                builder.set_member_name ("type");
+                builder.add_string_value (field.field_type);
+                builder.set_member_name ("access");
+                builder.add_string_value (field.access_modifier);
+                
+                if (field.is_static) {
+                    builder.set_member_name ("static");
+                    builder.add_boolean_value (true);
+                }
+                if (field.default_value != "") {
+                    builder.set_member_name ("default_value");
+                    builder.add_string_value (field.default_value);
+                }
+                
+                builder.end_object ();
+            }
+            builder.end_array ();
+        }
+        
+        // Constants
+        if (symbol.constants.size > 0) {
+            builder.set_member_name ("constants");
+            builder.begin_array ();
+            foreach (Constant constant in symbol.constants) {
+                builder.begin_object ();
+                builder.set_member_name ("name");
+                builder.add_string_value (constant.name);
+                builder.set_member_name ("type");
+                builder.add_string_value (constant.constant_type);
+                builder.set_member_name ("access");
+                builder.add_string_value (constant.access_modifier);
+                
+                if (constant.value != "") {
+                    builder.set_member_name ("value");
+                    builder.add_string_value (constant.value);
+                }
+                
+                builder.end_object ();
+            }
+            builder.end_array ();
+        }
+        
+        // Base types
+        if (symbol.base_types.size > 0) {
+            builder.set_member_name ("base_types");
+            builder.begin_array ();
+            foreach (string base_type in symbol.base_types) {
+                builder.add_string_value (base_type);
+            }
+            builder.end_array ();
+        }
+        
+        // Enum values
+        if (symbol.enum_values.size > 0) {
+            builder.set_member_name ("enum_values");
+            builder.begin_array ();
+            foreach (EnumValue enum_value in symbol.enum_values) {
+                builder.begin_object ();
+                builder.set_member_name ("name");
+                builder.add_string_value (enum_value.name);
+                
+                if (enum_value.numeric_value != "") {
+                    builder.set_member_name ("numeric_value");
+                    builder.add_string_value (enum_value.numeric_value);
+                }
+                
+                if (enum_value.documentation != "") {
+                    builder.set_member_name ("documentation");
+                    builder.add_string_value (enum_value.documentation);
+                }
+                
+                builder.end_object ();
+            }
+            builder.end_array ();
+        }
+        
+        // Source location
+        if (symbol.source_location != null) {
+            builder.set_member_name ("source_location");
+            builder.begin_object ();
+            builder.set_member_name ("file");
+            builder.add_string_value (symbol.source_location.file);
+            builder.set_member_name ("line");
+            builder.add_int_value (symbol.source_location.line);
+            builder.end_object ();
+        }
+        
+        // Documentation
+        if (symbol.documentation != "") {
+            builder.set_member_name ("documentation");
+            builder.add_string_value (symbol.documentation);
+        }
+        
+        // Child symbols (for namespaces)
+        if (symbol.child_symbols.size > 0) {
+            builder.set_member_name ("child_symbols");
+            builder.begin_array ();
+            
+            foreach (Symbol child in symbol.child_symbols) {
+                build_symbol_json (builder, child);
+            }
+            
+            builder.end_array ();
+        }
+    }
+    
+    
+    /**
+     * Gets the current timestamp in ISO 8601 format.
+     *
+     * @return Current timestamp string
+     */
+    private string get_current_timestamp () {
+        var now = new DateTime.now_utc ();
+        return now.format ("%Y-%m-%dT%H:%M:%S.%fZ");
+    }
+}

+ 408 - 0
src/output/text-formatter.vala

@@ -0,0 +1,408 @@
+/*
+ * text-formatter.vala
+ *
+ * Human-readable output formatter for valaq.
+ * This class provides text-based formatting for symbol information.
+ */
+
+/**
+ * Text formatter for human-readable output.
+ */
+public class TextFormatter : Object, OutputFormatter {
+    
+    /**
+     * Creates a new TextFormatter instance.
+     */
+    public TextFormatter () {
+        // Initialize text formatter
+    }
+    
+    /**
+     * Formats a list of symbols for human-readable output.
+     *
+     * @param symbols List of symbols to format
+     * @return Formatted output string
+     */
+    public string format_symbol_list (Gee.ArrayList<Symbol> symbols) {
+        if (symbols.size == 0) {
+            return "No symbols found.\n";
+        }
+        
+        var builder = new StringBuilder ();
+        
+        // Group symbols by type
+        var classes = new Gee.ArrayList<Symbol> ();
+        var interfaces = new Gee.ArrayList<Symbol> ();
+        var structs = new Gee.ArrayList<Symbol> ();
+        var enums = new Gee.ArrayList<Symbol> ();
+        var delegates = new Gee.ArrayList<Symbol> ();
+        var namespaces = new Gee.ArrayList<Symbol> ();
+        var methods = new Gee.ArrayList<Symbol> ();
+        var constants = new Gee.ArrayList<Symbol> ();
+        var fields = new Gee.ArrayList<Symbol> ();
+        
+        foreach (Symbol symbol in symbols) {
+            switch (symbol.symbol_type) {
+                case "class":
+                    classes.add (symbol);
+                    break;
+                case "interface":
+                    interfaces.add (symbol);
+                    break;
+                case "struct":
+                    structs.add (symbol);
+                    break;
+                case "enum":
+                    enums.add (symbol);
+                    break;
+                case "delegate":
+                    delegates.add (symbol);
+                    break;
+                case "namespace":
+                    namespaces.add (symbol);
+                    break;
+                case "method":
+                    methods.add (symbol);
+                    break;
+                case "constant":
+                    constants.add (symbol);
+                    break;
+                case "field":
+                    fields.add (symbol);
+                    break;
+                default:
+                    // Handle other types
+                    break;
+            }
+        }
+        
+        // Print symbols grouped by type
+        format_symbol_group (builder, "Namespaces", namespaces);
+        format_symbol_group (builder, "Classes", classes);
+        format_symbol_group (builder, "Interfaces", interfaces);
+        format_symbol_group (builder, "Structs", structs);
+        format_symbol_group (builder, "Enums", enums);
+        format_symbol_group (builder, "Delegates", delegates);
+        format_symbol_group (builder, "Methods", methods);
+        format_symbol_group (builder, "Constants", constants);
+        format_symbol_group (builder, "Fields", fields);
+        
+        builder.append ("\nTotal: %d symbols\n".printf (symbols.size));
+        
+        return builder.str;
+    }
+    
+    /**
+     * Formats detailed information about a symbol for human-readable output.
+     *
+     * @param symbol The symbol to format
+     * @return Formatted output string
+     */
+    public string format_symbol_details (SymbolDetails symbol) {
+        var builder = new StringBuilder ();
+        
+        builder.append ("Symbol Details:\n");
+        builder.append ("===============\n");
+        builder.append ("Name: %s\n".printf (symbol.name));
+        builder.append ("Type: %s\n".printf (symbol.symbol_type));
+        builder.append ("Access: %s\n".printf (symbol.access));
+        
+        if (symbol.full_path != "") {
+            builder.append ("Full Path: %s\n".printf (symbol.full_path));
+        }
+        
+        if (symbol.return_type != "") {
+            builder.append ("Return Type: %s\n".printf (symbol.return_type));
+        }
+        
+        if (symbol.base_types.size > 0) {
+            builder.append ("Base Types: %s\n".printf (string.joinv (", ", symbol.base_types.to_array ())));
+        }
+        
+        if (symbol.enum_values.size > 0) {
+            builder.append ("Enum Values:\n");
+            foreach (EnumValue enum_value in symbol.enum_values) {
+                string value_str = "  %s".printf (enum_value.name);
+                if (enum_value.numeric_value != "") {
+                    value_str += " = %s".printf (enum_value.numeric_value);
+                }
+                builder.append ("%s\n".printf (value_str));
+                
+                // Add documentation if available
+                if (enum_value.documentation != "") {
+                    builder.append ("    %s\n".printf (enum_value.documentation));
+                }
+            }
+            builder.append ("\n");
+        }
+        
+        // Display source location
+        if (symbol.source_location != null) {
+            builder.append ("Source: %s:%d\n".printf (symbol.source_location.file, symbol.source_location.line));
+        }
+        
+        // Display documentation
+        if (symbol.documentation != "") {
+            builder.append ("\nDocumentation:\n");
+            builder.append ("%s\n".printf (symbol.documentation));
+        }
+        
+        // For namespaces, show child symbols grouped by type
+        if (symbol.symbol_type == "namespace" && symbol.child_symbols.size > 0) {
+            builder.append ("\nChild Symbols:\n");
+            builder.append ("==============\n");
+            
+            // Group child symbols by type
+            var child_classes = new Gee.ArrayList<Symbol> ();
+            var child_interfaces = new Gee.ArrayList<Symbol> ();
+            var child_structs = new Gee.ArrayList<Symbol> ();
+            var child_enums = new Gee.ArrayList<Symbol> ();
+            var child_delegates = new Gee.ArrayList<Symbol> ();
+            var child_methods = new Gee.ArrayList<Symbol> ();
+            var child_constants = new Gee.ArrayList<Symbol> ();
+            var child_fields = new Gee.ArrayList<Symbol> ();
+            var child_namespaces = new Gee.ArrayList<Symbol> ();
+            
+            foreach (Symbol child in symbol.child_symbols) {
+                switch (child.symbol_type) {
+                    case "class":
+                        child_classes.add (child);
+                        break;
+                    case "interface":
+                        child_interfaces.add (child);
+                        break;
+                    case "struct":
+                        child_structs.add (child);
+                        break;
+                    case "enum":
+                        child_enums.add (child);
+                        break;
+                    case "delegate":
+                        child_delegates.add (child);
+                        break;
+                    case "namespace":
+                        child_namespaces.add (child);
+                        break;
+                    case "method":
+                        child_methods.add (child);
+                        break;
+                    case "constant":
+                        child_constants.add (child);
+                        break;
+                    case "field":
+                        child_fields.add (child);
+                        break;
+                    default:
+                        // Handle other types
+                        break;
+                }
+            }
+            
+            // Print child symbols grouped by type
+            format_child_symbol_group (builder, "Namespaces", child_namespaces);
+            format_child_symbol_group (builder, "Classes", child_classes);
+            format_child_symbol_group (builder, "Interfaces", child_interfaces);
+            format_child_symbol_group (builder, "Structs", child_structs);
+            format_child_symbol_group (builder, "Enums", child_enums);
+            format_child_symbol_group (builder, "Delegates", child_delegates);
+            format_child_symbol_group (builder, "Methods", child_methods);
+            format_child_symbol_group (builder, "Constants", child_constants);
+            format_child_symbol_group (builder, "Fields", child_fields);
+            
+            builder.append ("\nTotal child symbols: %d\n".printf (symbol.child_symbols.size));
+        }
+        
+        // Display parameters for methods and delegates
+        if (symbol.parameters.size > 0) {
+            builder.append ("\nParameters:\n");
+            foreach (Parameter param in symbol.parameters) {
+                string param_str = "  %s %s".printf (param.param_type, param.name);
+                if (param.direction != "in") {
+                    param_str = "  %s %s %s".printf (param.direction, param.param_type, param.name);
+                }
+                if (param.default_value != "") {
+                    param_str += " = %s".printf (param.default_value);
+                }
+                builder.append ("%s\n".printf (param_str));
+            }
+        }
+        
+        // Display methods (only for non-namespace symbols to avoid duplication)
+        if (symbol.methods.size > 0 && symbol.symbol_type != "namespace") {
+            builder.append ("\nMethods:\n");
+            foreach (Method method in symbol.methods) {
+                string method_sig = format_method_signature (method);
+                builder.append ("  %s\n".printf (method_sig));
+            }
+        }
+        
+        // Display properties
+        if (symbol.properties.size > 0) {
+            builder.append ("\nProperties:\n");
+            foreach (Property prop in symbol.properties) {
+                string prop_str = "  %s %s".printf (prop.property_type, prop.name);
+                if (prop.is_read_only) {
+                    prop_str += " { read-only }";
+                } else if (prop.is_write_only) {
+                    prop_str += " { write-only }";
+                }
+                if (prop.is_construct) {
+                    prop_str += " { construct }";
+                }
+                builder.append ("%s\n".printf (prop_str));
+            }
+        }
+        
+        // Display fields
+        if (symbol.fields.size > 0) {
+            builder.append ("\nFields:\n");
+            foreach (Field field in symbol.fields) {
+                string field_str = "  %s %s".printf (field.field_type, field.name);
+                if (field.is_static) {
+                    field_str += " { static }";
+                }
+                if (field.default_value != "") {
+                    field_str += " = %s".printf (field.default_value);
+                }
+                builder.append ("%s\n".printf (field_str));
+            }
+        }
+        
+        // Display constants
+        if (symbol.constants.size > 0) {
+            builder.append ("\nConstants:\n");
+            foreach (Constant constant in symbol.constants) {
+                string const_str = "  %s %s".printf (constant.constant_type, constant.name);
+                if (constant.value != "") {
+                    const_str += " = %s".printf (constant.value);
+                }
+                builder.append ("%s\n".printf (const_str));
+            }
+        }
+        
+        return builder.str;
+    }
+    
+    /**
+     * Formats an error message for human-readable output.
+     *
+     * @param error_type Type of error
+     * @param message Error message
+     * @return Formatted error string
+     */
+    public string format_error (string error_type, string message) {
+        return "Error [%s]: %s\n".printf (error_type, message);
+    }
+    
+    /**
+     * Formats a group of symbols with a header.
+     *
+     * @param builder StringBuilder to append to
+     * @param title Title of the group
+     * @param symbols List of symbols in the group
+     */
+    private void format_symbol_group (StringBuilder builder, string title, Gee.ArrayList<Symbol> symbols) {
+        if (symbols.size == 0) {
+            return;
+        }
+        
+        builder.append ("%s:\n".printf (title));
+        foreach (Symbol symbol in symbols) {
+            string full_path = symbol.get_full_path ();
+            string display_name;
+            
+            // Add child count for symbols that can have children
+            if (symbol.child_count > 0) {
+                display_name = "%s (%d)".printf (full_path, symbol.child_count);
+            } else {
+                display_name = full_path;
+            }
+            
+            builder.append ("  %-30s %s\n".printf (display_name, symbol.access_modifier));
+        }
+        builder.append ("\n");
+    }
+    
+    /**
+     * Formats a method signature for display.
+     *
+     * @param method The method to format
+     * @return Formatted method signature
+     */
+    private string format_method_signature (Method method) {
+        var builder = new StringBuilder ();
+        
+        // Add access modifier
+        builder.append (method.access_modifier);
+        builder.append (" ");
+        
+        // Add modifiers
+        if (method.is_static) {
+            builder.append ("static ");
+        }
+        if (method.is_virtual) {
+            builder.append ("virtual ");
+        }
+        if (method.is_override) {
+            builder.append ("override ");
+        }
+        
+        // Add return type and name
+        builder.append ("%s %s".printf (method.return_type, method.name));
+        
+        // Add parameters
+        builder.append (" (");
+        for (int i = 0; i < method.parameters.size; i++) {
+            if (i > 0) {
+                builder.append (", ");
+            }
+            Parameter param = method.parameters[i];
+            if (param.direction != "in") {
+                builder.append (param.direction);
+                builder.append (" ");
+            }
+            builder.append ("%s %s".printf (param.param_type, param.name));
+            if (param.default_value != "") {
+                builder.append (" = %s".printf (param.default_value));
+            }
+        }
+        builder.append (")");
+        
+        return builder.str;
+    }
+    
+    /**
+     * Formats a group of child symbols with a header.
+     *
+     * @param builder StringBuilder to append to
+     * @param title Title of the group
+     * @param symbols List of symbols in the group
+     */
+    private void format_child_symbol_group (StringBuilder builder, string title, Gee.ArrayList<Symbol> symbols) {
+        if (symbols.size == 0) {
+            return;
+        }
+        
+        builder.append ("%s:\n".printf (title));
+        foreach (Symbol symbol in symbols) {
+            // Special handling for methods to show detailed signatures
+            if (symbol.symbol_type == "method") {
+                string method_sig = format_method_signature ((Method) symbol);
+                builder.append ("  %s\n".printf (method_sig));
+            } else {
+                string full_path = symbol.get_full_path ();
+                string display_name;
+                
+                // Add child count for symbols that can have children
+                if (symbol.child_count > 0) {
+                    display_name = "%s (%d)".printf (full_path, symbol.child_count);
+                } else {
+                    display_name = full_path;
+                }
+                
+                builder.append ("  %-30s %s\n".printf (display_name, symbol.access_modifier));
+            }
+        }
+        builder.append ("\n");
+    }
+}

+ 191 - 0
src/utils/error-handling.vala

@@ -0,0 +1,191 @@
+/*
+ * error-handling.vala
+ *
+ * Error handling utilities for valaq.
+ * This class provides error handling and reporting functionality.
+ */
+
+/**
+ * Custom error types for valaq.
+ */
+public enum ValaqErrorType {
+    FILE_NOT_FOUND,
+    PARSE_ERROR,
+    NAVIGATION_ERROR,
+    OUTPUT_ERROR,
+    INVALID_ARGUMENT,
+    INITIALIZATION_ERROR,
+    ENVIRONMENT_ERROR
+}
+
+/**
+ * Custom error domain for valaq.
+ */
+public errordomain ValaqError {
+    FILE_NOT_FOUND,
+    PARSE_ERROR,
+    NAVIGATION_ERROR,
+    OUTPUT_ERROR,
+    INVALID_ARGUMENT,
+    INITIALIZATION_ERROR,
+    ENVIRONMENT_ERROR
+}
+
+/**
+ * Error handling utilities.
+ */
+public class ErrorHandler : Object {
+    
+    /**
+     * Creates a new ErrorHandler instance.
+     */
+    public ErrorHandler () {
+        // Initialize error handler
+    }
+    
+    /**
+     * Handles a file not found error.
+     *
+     * @param file_path Path to the file that was not found
+     * @return Formatted error message
+     */
+    public string handle_file_not_found (string file_path) {
+        return "File not found: %s".printf (file_path);
+    }
+    
+    /**
+     * Handles a VAPI parse error.
+     *
+     * @param file_path Path to the file that failed to parse
+     * @param details Additional error details
+     * @return Formatted error message
+     */
+    public string handle_parse_error (string file_path, string details) {
+        return "Parse error in file %s: %s".printf (file_path, details);
+    }
+    
+    /**
+     * Handles a navigation error.
+     *
+     * @param symbol_path Symbol path that could not be found
+     * @return Formatted error message
+     */
+    public string handle_navigation_error (string[] symbol_path) {
+        return "Symbol not found: %s".printf (string.joinv (".", symbol_path));
+    }
+    
+    /**
+     * Handles an invalid argument error.
+     *
+     * @param argument Invalid argument
+     * @param reason Reason why the argument is invalid
+     * @return Formatted error message
+     */
+    public string handle_invalid_argument (string argument, string reason) {
+        return "Invalid argument '%s': %s".printf (argument, reason);
+    }
+    
+    /**
+     * Handles an output error.
+     *
+     * @param details Error details
+     * @return Formatted error message
+     */
+    public string handle_output_error (string details) {
+        return "Output error: %s".printf (details);
+    }
+    
+    /**
+     * Handles an initialization error.
+     *
+     * @param component Component that failed to initialize
+     * @param details Additional error details
+     * @return Formatted error message
+     */
+    public string handle_initialization_error (string component, string details) {
+        return "Failed to initialize %s: %s".printf (component, details);
+    }
+    
+    /**
+     * Handles an environment error.
+     *
+     * @param issue Description of the environment issue
+     * @return Formatted error message
+     */
+    public string handle_environment_error (string issue) {
+        return "Environment error: %s".printf (issue);
+    }
+    
+    /**
+     * Formats an error for JSON output.
+     *
+     * @param error_type Type of error
+     * @param message Error message
+     * @param details Additional error details (optional)
+     * @return JSON formatted error string
+     */
+    public string format_error_json (string error_type, string message, string? details = null) {
+        var builder = new StringBuilder ();
+        builder.append ("{\n");
+        builder.append ("  \"error\": {\n");
+        builder.append ("    \"type\": \"%s\",\n".printf (error_type));
+        builder.append ("    \"message\": \"%s\",\n".printf (escape_json_string (message)));
+        
+        if (details != null && details != "") {
+            builder.append ("    \"details\": \"%s\"\n".printf (escape_json_string (details)));
+        }
+        
+        builder.append ("  },\n");
+        builder.append ("  \"metadata\": {\n");
+        builder.append ("    \"timestamp\": \"%s\"\n".printf (get_current_timestamp ()));
+        builder.append ("  }\n");
+        builder.append ("}\n");
+        
+        return builder.str;
+    }
+    
+    /**
+     * Formats an error for text output.
+     *
+     * @param error_type Type of error
+     * @param message Error message
+     * @param details Additional error details (optional)
+     * @return Text formatted error string
+     */
+    public string format_error_text (string error_type, string message, string? details = null) {
+        var builder = new StringBuilder ();
+        builder.append ("Error: %s\n".printf (message));
+        
+        if (details != null && details != "") {
+            builder.append ("Details: %s\n".printf (details));
+        }
+        
+        builder.append ("Type: %s\n".printf (error_type));
+        
+        return builder.str;
+    }
+    
+    /**
+     * Escapes a string for JSON output.
+     *
+     * @param str String to escape
+     * @return Escaped string
+     */
+    private string escape_json_string (string str) {
+        return str.replace ("\\", "\\\\")
+                 .replace ("\"", "\\\"")
+                 .replace ("\n", "\\n")
+                 .replace ("\r", "\\r")
+                 .replace ("\t", "\\t");
+    }
+    
+    /**
+     * Gets the current timestamp in ISO 8601 format.
+     *
+     * @return Current timestamp string
+     */
+    private string get_current_timestamp () {
+        var now = new DateTime.now_utc ();
+        return now.format ("%Y-%m-%dT%H:%M:%S.%fZ");
+    }
+}

+ 306 - 0
src/utils/file-utils.vala

@@ -0,0 +1,306 @@
+/*
+ * file-utils.vala
+ *
+ * File system operations for valaq.
+ * This class provides utility functions for file operations.
+ */
+
+/**
+ * Utility class for file system operations.
+ *
+ * Provides comprehensive file system functionality including VAPI file discovery,
+ * path resolution, validation, and security checks. This class handles
+ * the complex task of locating VAPI files across multiple standard directories
+ * and provides safe file access with proper validation.
+ */
+public class FileUtils : Object {
+    
+    /**
+     * Array of VAPI search paths in order of preference.
+     *
+     * These paths are searched sequentially when resolving VAPI file names.
+     * The order is important for precedence - earlier paths have priority.
+     */
+    private string[] vapi_search_paths;
+    
+    /**
+     * Creates a new FileUtils instance.
+     *
+     * Initializes the VAPI search paths with standard system directories
+     and any additional fallback paths that might exist on the system.
+     */
+    public FileUtils () {
+        // Initialize VAPI search paths
+        initialize_vapi_search_paths ();
+    }
+    
+    /**
+     * Initializes the VAPI search paths in order of preference.
+     */
+    private void initialize_vapi_search_paths () {
+        vapi_search_paths = new string[0];
+        
+        // Primary search path
+        vapi_search_paths += "/usr/share/vala-0.56/vapi";
+        
+        // Secondary search path
+        vapi_search_paths += "/usr/share/vala/vapi";
+        
+        // Additional fallback paths (for backward compatibility)
+        string[] fallback_paths = {
+            "/usr/share/vala-0.54/vapi",
+            "/usr/share/vala-0.52/vapi",
+            "/usr/local/share/vala/vapi"
+        };
+        
+        foreach (string path in fallback_paths) {
+            if (file_exists (path)) {
+                vapi_search_paths += path;
+            }
+        }
+    }
+    
+    /**
+     * Gets the VAPI search paths.
+     *
+     * @return Array of VAPI search paths in order of preference
+     */
+    public string[] get_vapi_search_paths () {
+        return vapi_search_paths;
+    }
+    
+    /**
+     * Checks if a file exists.
+     *
+     * @param path Path to the file
+     * @return True if file exists, false otherwise
+     */
+    public bool file_exists (string path) {
+        return File.new_for_path (path).query_exists ();
+    }
+    
+    /**
+     * Checks if a path is a VAPI file.
+     *
+     * Determines if the given path points to a VAPI file by checking
+     * the file extension. This is used for filtering and validation.
+     *
+     * @param path Path to check
+     * @return True if path is a VAPI file, false otherwise
+     */
+    public bool is_vapi_file (string path) {
+        return path.has_suffix (".vapi");
+    }
+    
+    /**
+     * Finds VAPI files in a directory.
+     *
+     * Scans the specified directory for files with .vapi extension.
+     * Returns full paths to all found VAPI files. Handles directory
+     * access errors gracefully and continues operation.
+     *
+     * @param directory Directory path to search for VAPI files
+     * @return Array of VAPI file paths found in directory
+     */
+    public Gee.ArrayList<string> find_vapi_files (string directory) {
+        var vapi_files = new Gee.ArrayList<string> ();
+        
+        try {
+            var dir = File.new_for_path (directory);
+            if (!dir.query_exists ()) {
+                stderr.printf ("Warning: VAPI directory does not exist: %s\n", directory);
+                return vapi_files;
+            }
+            
+            var enumerator = dir.enumerate_children (
+                FileAttribute.STANDARD_NAME + "," + FileAttribute.STANDARD_TYPE,
+                FileQueryInfoFlags.NONE
+            );
+            
+            FileInfo file_info;
+            while ((file_info = enumerator.next_file ()) != null) {
+                string filename = file_info.get_name ();
+                if (is_vapi_file (filename)) {
+                    vapi_files.add (Path.build_filename (directory, filename));
+                }
+            }
+        } catch (Error e) {
+            stderr.printf ("Error scanning VAPI directory: %s\n", e.message);
+        }
+        
+        return vapi_files;
+    }
+    
+    /**
+     * Finds VAPI files across all search paths.
+     *
+     * Scans all configured VAPI directories and returns a consolidated
+     * list of available VAPI files. Removes duplicates based on basename
+     * to avoid showing the same file from multiple directories.
+     *
+     * @return Array of VAPI file paths with duplicates removed
+     */
+    public Gee.ArrayList<string> find_all_vapi_files () {
+        var all_vapi_files = new Gee.ArrayList<string> ();
+        var seen_files = new Gee.HashSet<string> ();
+        
+        foreach (string search_path in vapi_search_paths) {
+            var vapi_files = find_vapi_files (search_path);
+            
+            foreach (string file_path in vapi_files) {
+                var file = File.new_for_path (file_path);
+                string basename = file.get_basename ();
+                
+                // Avoid duplicates by checking basename
+                if (!seen_files.contains (basename)) {
+                    seen_files.add (basename);
+                    all_vapi_files.add (file_path);
+                }
+            }
+        }
+        
+        return all_vapi_files;
+    }
+    
+    /**
+     * Resolves a VAPI file name across all search paths.
+     * Supports both basenames (e.g., "zlib.vapi") and names without extension (e.g., "zlib").
+     * The first found file is used, with primary search path taking precedence.
+     *
+     * @param vapi_name Name of the VAPI file (with or without .vapi extension)
+     * @return Full path to the VAPI file, or null if not found
+     */
+    public string? resolve_vapi_file (string vapi_name) {
+        // Validate input
+        if (vapi_name == "" || vapi_name.strip () == "") {
+            return null;
+        }
+        
+        // Check if this is a full path (contains path separators)
+        if (vapi_name.contains ("/") || vapi_name.contains ("\\")) {
+            // For full paths, we don't resolve through search paths
+            // Just check if the file exists as-is
+            return file_exists (vapi_name) ? vapi_name : null;
+        }
+        
+        // This is a basename - ensure it has .vapi extension for searching
+        string filename = vapi_name;
+        if (!filename.has_suffix (".vapi")) {
+            filename += ".vapi";
+        }
+        
+        // First, check the current working directory
+        string current_dir = Environment.get_current_dir ();
+        string current_dir_path = Path.build_filename (current_dir, filename);
+        if (file_exists (current_dir_path)) {
+            return current_dir_path;
+        }
+        
+        // Then search in all VAPI paths in order of preference
+        foreach (string search_path in vapi_search_paths) {
+            string full_path = Path.build_filename (search_path, filename);
+            if (file_exists (full_path)) {
+                return full_path;
+            }
+        }
+        
+        return null;
+    }
+    
+    /**
+     * Gets information about which search path contains a VAPI file.
+     *
+     * @param vapi_name Name of the VAPI file (with or without .vapi extension)
+     * @return Array containing [search_path, full_path], or null if not found
+     */
+    public string[]? find_vapi_file_location (string vapi_name) {
+        // Ensure the name has .vapi extension
+        string filename = vapi_name;
+        if (!filename.has_suffix (".vapi")) {
+            filename += ".vapi";
+        }
+        
+        // Search in all paths in order of preference
+        foreach (string search_path in vapi_search_paths) {
+            string full_path = Path.build_filename (search_path, filename);
+            if (file_exists (full_path)) {
+                return { search_path, full_path };
+            }
+        }
+        
+        return null;
+    }
+    
+    /**
+     * Gets the default VAPI directory.
+     *
+     * @return Path to the default VAPI directory (first in search paths)
+     */
+    public string get_default_vapi_directory () {
+        // Return the first search path that exists
+        foreach (string path in vapi_search_paths) {
+            if (file_exists (path)) {
+                return path;
+            }
+        }
+        
+        // Default fallback to the primary search path
+        return vapi_search_paths.length > 0 ? vapi_search_paths[0] : "/usr/share/vala/vapi";
+    }
+    
+    /**
+     * Validates a file path for security and accessibility.
+     *
+     * Performs security checks to prevent directory traversal attacks
+     * and ensures the path is within allowed directories. This is
+     * crucial for preventing unauthorized file access.
+     *
+     * Security measures:
+     * - Prevents "../" directory traversal
+     * - Restricts access to VAPI directories and current working directory
+     * - Allows absolute paths to existing VAPI files
+     *
+     * @param path Path to validate for security and accessibility
+     * @return True if path is safe and allowed, false otherwise
+     */
+    public bool validate_path (string path) {
+        // Check for directory traversal attempts
+        if (path.contains ("../") || path.contains ("..\\")) {
+            return false;
+        }
+        
+        // Convert to absolute path and check if it's within allowed directories
+        var file = File.new_for_path (path);
+        string absolute_path;
+        
+        try {
+            absolute_path = file.get_path ();
+        } catch (Error e) {
+            return false;
+        }
+        
+        // Allow paths in any VAPI search directory or current working directory
+        string[] allowed_prefixes = {};
+        
+        // Add all VAPI search paths
+        foreach (string vapi_path in vapi_search_paths) {
+            allowed_prefixes += vapi_path;
+        }
+        
+        // Add current working directory
+        allowed_prefixes += Environment.get_current_dir ();
+        
+        foreach (string prefix in allowed_prefixes) {
+            if (absolute_path.has_prefix (prefix)) {
+                return true;
+            }
+        }
+        
+        // Also allow absolute paths to VAPI files directly
+        if (absolute_path.has_suffix (".vapi") && file_exists (absolute_path)) {
+            return true;
+        }
+        
+        return false;
+    }
+}

+ 36 - 0
test_enums.vapi

@@ -0,0 +1,36 @@
+// Test file with various enum types to verify child count behavior
+
+// Simple enum with 3 values
+public enum SimpleEnum {
+    FIRST,
+    SECOND,
+    THIRD
+}
+
+// Enum with numeric values
+public enum NumericEnum {
+    ONE = 1,
+    TWO = 2,
+    THREE = 3,
+    FOUR = 4
+}
+
+// Single value enum
+public enum SingleEnum {
+    ONLY_VALUE
+}
+
+// Empty enum (edge case)
+public enum EmptyEnum {
+}
+
+// Namespace with enums
+namespace TestNamespace {
+    public enum NamespaceEnum {
+        NAMESPACE_FIRST,
+        NAMESPACE_SECOND,
+        NAMESPACE_THIRD,
+        NAMESPACE_FOURTH,
+        NAMESPACE_FIFTH
+    }
+}

+ 12 - 0
test_namespace_methods.vapi

@@ -0,0 +1,12 @@
+namespace Invercargill {
+    public void intersect_with (Invercargill.Enumerable<T> items = (null)) {}
+    
+    public static void create_from_array (T[] array) {}
+    
+    namespace DataStructures {
+        public class HashSet {
+            public void add (string item) {}
+            public virtual void remove (string item) {}
+        }
+    }
+}

+ 20 - 0
test_nested.vapi

@@ -0,0 +1,20 @@
+namespace Invercargill {
+    namespace DataStructures {
+        public class HashSet {
+            public void add (string item) {}
+            public void remove (string item) {}
+            public bool contains (string item) { return false; }
+        }
+        
+        public class LinkedList {
+            public void append (string item) {}
+            public void prepend (string item) {}
+        }
+    }
+    
+    namespace Utils {
+        public class StringHelper {
+            public static string to_upper (string input) { return input; }
+        }
+    }
+}

+ 26 - 0
test_root_only.vapi

@@ -0,0 +1,26 @@
+// Root-level symbols
+public class RootClass {
+    public void root_method () {}
+}
+
+public interface RootInterface {
+    public abstract void interface_method ();
+}
+
+public enum RootEnum {
+    VALUE1,
+    VALUE2,
+    VALUE3
+}
+
+// Namespace symbols
+namespace TestNamespace {
+    public class NamespaceClass {
+        public void namespace_method () {}
+    }
+    
+    public enum NamespaceEnum {
+        NAMESPACE_VALUE1,
+        NAMESPACE_VALUE2
+    }
+}

+ 14 - 0
tests/test-output-formatters.vala

@@ -0,0 +1,14 @@
+/*
+ * test-output-formatters.vala
+ * 
+ * Unit tests for output formatter functionality.
+ */
+
+int main (string[] args) {
+    print ("Running output formatter tests...\n");
+    
+    // TODO: Implement output formatter tests
+    print ("Output formatter tests not yet implemented\n");
+    
+    return 0;
+}

+ 14 - 0
tests/test-symbol-navigator.vala

@@ -0,0 +1,14 @@
+/*
+ * test-symbol-navigator.vala
+ * 
+ * Unit tests for symbol navigator functionality.
+ */
+
+int main (string[] args) {
+    print ("Running symbol navigator tests...\n");
+    
+    // TODO: Implement symbol navigator tests
+    print ("Symbol navigator tests not yet implemented\n");
+    
+    return 0;
+}

+ 14 - 0
tests/test-vapi-parser.vala

@@ -0,0 +1,14 @@
+/*
+ * test-vapi-parser.vala
+ * 
+ * Unit tests for VAPI parser functionality.
+ */
+
+int main (string[] args) {
+    print ("Running VAPI parser tests...\n");
+    
+    // TODO: Implement VAPI parser tests
+    print ("VAPI parser tests not yet implemented\n");
+    
+    return 0;
+}