diff --git a/.clang-format b/.clang-format
deleted file mode 100644
index bb00198a..00000000
--- a/.clang-format
+++ /dev/null
@@ -1,53 +0,0 @@
----
-# Google C++ Style Guide
-# https://google.github.io/styleguide/cppguide.html
-BasedOnStyle: Google
-IndentWidth: 2
-ColumnLimit: 80
----
-Language: Cpp
-# Force pointers to the type for C++.
-DerivePointerAlignment: false
-PointerAlignment: Left
-# Other adjustments
-AccessModifierOffset: -1
-AllowShortFunctionsOnASingleLine: All
-AllowShortIfStatementsOnASingleLine: false
-AllowShortLoopsOnASingleLine: false
-AlwaysBreakTemplateDeclarations: true
-BinPackParameters: false
-BreakBeforeBraces: Attach
-BreakConstructorInitializers: BeforeColon
-ConstructorInitializerAllOnOneLineOrOnePerLine: true
-Cpp11BracedListStyle: true
-IncludeBlocks: Regroup
-IncludeCategories:
- # Standard library headers
- - Regex: '^<[^/]+>$'
- Priority: 1
- # Other library headers
- - Regex: '^<.+>$'
- Priority: 2
- # Project headers with quotes
- - Regex: '^"mcp/.+"$'
- Priority: 3
- # Other project headers
- - Regex: '^".+"$'
- Priority: 4
-IndentCaseLabels: true
-KeepEmptyLinesAtTheStartOfBlocks: false
-NamespaceIndentation: None
-SortIncludes: true
-SpaceAfterCStyleCast: false
-SpaceAfterTemplateKeyword: true
-SpaceBeforeAssignmentOperators: true
-SpaceBeforeParens: ControlStatements
-SpaceInEmptyParentheses: false
-SpacesInAngles: false
-SpacesInCStyleCastParentheses: false
-SpacesInParentheses: false
-SpacesInSquareBrackets: false
-Standard: c++14
-UseTab: Never
-# Remove trailing whitespace
-InsertTrailingCommas: None
\ No newline at end of file
diff --git a/.github/workflows/pr-format-check.yml b/.github/workflows/pr-format-check.yml
deleted file mode 100644
index 769b322b..00000000
--- a/.github/workflows/pr-format-check.yml
+++ /dev/null
@@ -1,86 +0,0 @@
-name: PR Format Check
-
-on:
- pull_request:
- types: [opened, synchronize, reopened]
-
-jobs:
- clang-format:
- name: Clang Format
- runs-on: ubuntu-latest
- permissions:
- contents: read
- pull-requests: write
-
- steps:
- - name: Checkout PR
- uses: actions/checkout@v4
- with:
- fetch-depth: 0
- submodules: recursive
-
- - name: Install clang-format
- run: |
- sudo apt-get update
- sudo apt-get install -y clang-format-14
-
- - name: Check changed files
- id: changed-files
- run: |
- # Get list of changed C/C++ files (excluding submodules)
- git diff --name-only origin/${{ github.base_ref }}...HEAD | \
- grep -E '\.(h|hpp|c|cc|cpp)$' | \
- grep -v '^third_party/' > changed_files.txt || true
-
- if [ -s changed_files.txt ]; then
- echo "has_changes=true" >> $GITHUB_OUTPUT
- echo "Changed C/C++ files:"
- cat changed_files.txt
- else
- echo "has_changes=false" >> $GITHUB_OUTPUT
- echo "No C/C++ files changed"
- fi
-
- - name: Check formatting of changed files
- if: steps.changed-files.outputs.has_changes == 'true'
- run: |
- exit_code=0
- while IFS= read -r file; do
- if [ -f "$file" ]; then
- echo "Checking $file..."
- clang-format-14 --style=file --dry-run --Werror "$file" || {
- echo "::error file=$file::File is not properly formatted"
- exit_code=1
- }
- fi
- done < changed_files.txt
-
- if [ $exit_code -ne 0 ]; then
- echo ""
- echo "::error::Some files are not properly formatted."
- echo "To fix, run: make format"
- exit 1
- fi
-
- - name: Post PR comment on failure
- if: failure() && steps.changed-files.outputs.has_changes == 'true'
- uses: actions/github-script@v7
- with:
- script: |
- const comment = `## Code Formatting Check Failed
-
- Some files in this PR are not properly formatted according to the project's clang-format rules.
-
- **To fix this issue:**
- \`\`\`bash
- make format
- \`\`\`
-
- Then commit and push the changes.`;
-
- github.rest.issues.createComment({
- issue_number: context.issue.number,
- owner: context.repo.owner,
- repo: context.repo.repo,
- body: comment
- });
diff --git a/.gitignore b/.gitignore
index 457c7687..64528d80 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,109 +1,119 @@
-# Build directories
-build/
-build-*/
-build_*/
-cmake-build-*/
-out/
-bin/
-lib/
-# Exception: Allow Ruby SDK lib directory
-!sdk/ruby/lib/
-
-# CMake generated files
-CMakeCache.txt
-CMakeFiles/
-cmake_install.cmake
-CTestTestfile.cmake
-Testing/
-_deps/
-# Note: We have a hand-written Makefile at root, so only ignore generated ones in subdirs
-*/Makefile
-
-# Compiled object files
-*.o
-*.obj
-*.lo
-*.slo
+# Build results
+[Dd]ebug/
+[Rr]elease/
+x64/
+x86/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Oo]ut/
+[Ll]og/
+[Ll]ogs/
-# Precompiled Headers
-*.gch
-*.pch
+# Visual Studio files
+.vs/
+*.user
+*.userosscache
+*.sln.docstates
+*.suo
+*.cache
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
-# Compiled Dynamic libraries
-*.so
-*.dylib
-*.dll
-
-# Compiled Static libraries
-*.lai
-*.la
-*.a
-*.lib
-
-# Executables
-*.exe
-*.out
-*.app
-test_variant
-test_variant_advanced
-test_variant_extensive
-test_optional
-test_optional_advanced
-test_optional_extensive
-test_type_helpers
-test_mcp_types
-test_mcp_types_extended
-test_mcp_type_helpers
-test_compat
-test_buffer
-test_json
-test_event_loop
-test_io_socket_handle
-test_address
-test_socket
-test_socket_interface
-test_socket_option
-
-# IDE specific files
+# Visual Studio Code
.vscode/
+
+# Rider
.idea/
-*.swp
-*.swo
-*~
-.DS_Store
-# Debug files
-*.dSYM/
-*.su
-*.idb
+# User-specific files
+*.rsuser
+*.userprefs
+
+# NuGet
+*.nupkg
+*.snupkg
+packages/
+project.lock.json
+project.fragment.lock.json
+artifacts/
+packages/
+
+# MSBuild
+*.gpState
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.vsix
+*.manifest
+*.spec
-# Dependency directories
-node_modules/
-vendor/
+# Test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# JetBrains Rider
+*.sln.iml
-# Coverage files
-*.gcov
-*.gcda
-*.gcno
-coverage/
-*.info
+# OS generated files
+.DS_Store
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+ehthumbs.db
+Thumbs.db
-# Documentation
-docs/html/
-docs/latex/
-doxygen/
+# Native library build
+native/
+cmake-build-*/
# Temporary files
*.tmp
*.temp
-*.log
+*.swp
+*.swo
+*~
-# Python cache (if using Python scripts)
-__pycache__/
-*.py[cod]
-*$py.class
+# Node.js (for example MCP servers)
+node_modules/
-# OS generated files
-Thumbs.db
-Desktop.ini
\ No newline at end of file
+# NuGet packages output
+packages/
+examples/ClientExampleJson/
diff --git a/.gitmodules b/.gitmodules
index f7c1a54e..d5cd4211 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,4 +1,3 @@
-[submodule "third_party/gopher-mcp"]
- path = third_party/gopher-mcp
- url = https://github.com/GopherSecurity/gopher-mcp.git
- branch = main
+[submodule "third_party/gopher-orch"]
+ path = third_party/gopher-orch
+ url = https://github.com/GopherSecurity/gopher-orch.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
deleted file mode 100644
index 80c90036..00000000
--- a/CMakeLists.txt
+++ /dev/null
@@ -1,253 +0,0 @@
-cmake_minimum_required(VERSION 3.10)
-project(gopher-orch VERSION 0.1.0 LANGUAGES C CXX)
-
-# Prevent in-source builds
-if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
- message(FATAL_ERROR "In-source builds are not allowed. Please create a build directory and run cmake from there.")
-endif()
-
-# Set C++ standard
-set(CMAKE_CXX_STANDARD 14)
-set(CMAKE_CXX_STANDARD_REQUIRED ON)
-set(CMAKE_CXX_EXTENSIONS OFF)
-message(STATUS "Using C++14")
-
-# Default to Debug build
-if(NOT CMAKE_BUILD_TYPE)
- set(CMAKE_BUILD_TYPE Debug CACHE STRING "Build type" FORCE)
-endif()
-
-# Build options
-option(BUILD_SHARED_LIBS "Build shared libraries" ON)
-option(BUILD_STATIC_LIBS "Build static libraries" ON)
-option(BUILD_TESTS "Build tests" ON)
-option(BUILD_EXAMPLES "Build examples" ON)
-option(ORCH_STRICT_WARNINGS "Enable strict compiler warnings" OFF)
-option(USE_SUBMODULE_GOPHER_MCP "Use gopher-mcp as submodule (vs find_package)" ON)
-option(BUILD_WITHOUT_GOPHER_MCP "Build without gopher-mcp dependency (for testing)" OFF)
-
-# Set output directories
-set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
-set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
-set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
-
-# Compiler flags
-if(CMAKE_BUILD_TYPE STREQUAL "Debug")
- add_compile_options(-g -O0)
- add_compile_definitions(_DEBUG)
-elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
- add_compile_options(-O3)
- add_compile_definitions(NDEBUG)
-endif()
-
-# Platform-specific settings
-if(APPLE)
- set(CMAKE_MACOSX_RPATH ON)
- set(CMAKE_INSTALL_RPATH "@loader_path/../lib")
-elseif(UNIX)
- set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib")
-endif()
-
-# Warning flags
-if(ORCH_STRICT_WARNINGS)
- if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
- add_compile_options(
- -Wall -Wextra -Wpedantic
- -Wno-unused-parameter
- -Wno-unused-variable
- -Wno-unused-function
- -Werror
- )
- elseif(MSVC)
- add_compile_options(/W4 /WX)
- endif()
-else()
- if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
- add_compile_options(
- -Wall
- -Wno-unused-parameter
- -Wno-unused-variable
- -Wno-unused-function
- )
- endif()
-endif()
-
-# Handle gopher-mcp dependency
-if(BUILD_WITHOUT_GOPHER_MCP)
- # Build without gopher-mcp for testing
- message(STATUS "Building without gopher-mcp dependency")
- set(GOPHER_MCP_LIBRARIES "")
- set(GOPHER_MCP_INCLUDE_DIR "")
-elseif(USE_SUBMODULE_GOPHER_MCP)
- # Use gopher-mcp as submodule
- if(NOT EXISTS "${CMAKE_SOURCE_DIR}/third_party/gopher-mcp/.git")
- message(STATUS "gopher-mcp submodule not found. Initializing...")
- execute_process(
- COMMAND git submodule add https://github.com/GopherSecurity/gopher-mcp.git third_party/gopher-mcp
- WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
- RESULT_VARIABLE GIT_SUBMOD_RESULT
- )
- if(NOT GIT_SUBMOD_RESULT EQUAL "0")
- # Submodule might already exist, try update
- execute_process(
- COMMAND git submodule update --init --recursive third_party/gopher-mcp
- WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
- RESULT_VARIABLE GIT_SUBMOD_UPDATE_RESULT
- )
- if(NOT GIT_SUBMOD_UPDATE_RESULT EQUAL "0")
- message(FATAL_ERROR "Failed to initialize gopher-mcp submodule")
- endif()
- endif()
- else()
- message(STATUS "Updating gopher-mcp submodule...")
- execute_process(
- COMMAND git submodule update --init --recursive third_party/gopher-mcp
- WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
- )
- endif()
-
- # Set include directories for gopher-mcp BEFORE adding subdirectory
- set(GOPHER_MCP_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/third_party/gopher-mcp/include)
-
- # Temporarily add gopher-mcp include directories before processing subdirectory
- # This ensures gopher-mcp can find its own headers when building as submodule
- include_directories(${GOPHER_MCP_INCLUDE_DIR})
-
- # Disable gopher-mcp tests and examples to speed up build
- set(BUILD_TESTS_SAVED ${BUILD_TESTS})
- set(BUILD_EXAMPLES_SAVED ${BUILD_EXAMPLES})
- set(BUILD_TESTS OFF CACHE BOOL "" FORCE)
- set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
- set(BUILD_BINDINGS_EXAMPLES OFF CACHE BOOL "" FORCE)
-
- # Disable fmt installation if gopher-mcp uses it
- set(FMT_INSTALL OFF CACHE BOOL "Disable fmt installation" FORCE)
-
- # Add gopher-mcp subdirectory
- add_subdirectory(third_party/gopher-mcp EXCLUDE_FROM_ALL)
-
- # Restore our settings
- set(BUILD_TESTS ${BUILD_TESTS_SAVED} CACHE BOOL "" FORCE)
- set(BUILD_EXAMPLES ${BUILD_EXAMPLES_SAVED} CACHE BOOL "" FORCE)
-
- # Make gopher-mcp libraries available
- # Use static libraries for tests to avoid duplicate initialization
- if(BUILD_TESTS AND TARGET gopher-mcp-static)
- set(GOPHER_MCP_LIBRARIES gopher-mcp-static gopher-mcp-event-static)
- else()
- set(GOPHER_MCP_LIBRARIES gopher-mcp gopher-mcp-event)
- endif()
-
- message(STATUS "Using gopher-mcp from submodule")
-else()
- # Use system-installed gopher-mcp
- find_package(gopher-mcp REQUIRED)
- message(STATUS "Using system gopher-mcp: ${gopher-mcp_DIR}")
-endif()
-
-# Include directories
-message(STATUS "GOPHER_MCP_INCLUDE_DIR: ${GOPHER_MCP_INCLUDE_DIR}")
-include_directories(
- ${CMAKE_SOURCE_DIR}/include
- ${GOPHER_MCP_INCLUDE_DIR}
-)
-
-# Export compile commands for tools like clangd
-set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
-
-# Find required packages
-find_package(Threads REQUIRED)
-
-# Testing setup
-if(BUILD_TESTS)
- enable_testing()
- include(CTest)
-
- # Fetch Google Test
- include(FetchContent)
-
- # Prevent Google Test from being installed
- set(INSTALL_GTEST OFF CACHE BOOL "Disable installation of googletest" FORCE)
- set(INSTALL_GMOCK OFF CACHE BOOL "Disable installation of googlemock" FORCE)
- set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
-
- FetchContent_Declare(
- googletest
- GIT_REPOSITORY https://github.com/google/googletest.git
- GIT_TAG v1.14.0
- CMAKE_ARGS -DINSTALL_GTEST=OFF -DINSTALL_GMOCK=OFF
- )
-
- FetchContent_MakeAvailable(googletest)
-
- # Include Google Test and Google Mock
- include(GoogleTest)
-endif()
-
-# Add subdirectories
-add_subdirectory(src)
-
-if(BUILD_TESTS)
- add_subdirectory(tests)
-endif()
-
-if(BUILD_EXAMPLES)
- add_subdirectory(examples)
-endif()
-
-# Installation rules
-install(DIRECTORY include/orch
- DESTINATION include
- COMPONENT development
- FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp"
-)
-
-# Package configuration
-include(CMakePackageConfigHelpers)
-
-configure_package_config_file(
- "${CMAKE_CURRENT_SOURCE_DIR}/cmake/gopher-orch-config.cmake.in"
- "${CMAKE_CURRENT_BINARY_DIR}/gopher-orch-config.cmake"
- INSTALL_DESTINATION lib/cmake/gopher-orch
-)
-
-write_basic_package_version_file(
- "${CMAKE_CURRENT_BINARY_DIR}/gopher-orch-config-version.cmake"
- VERSION ${PROJECT_VERSION}
- COMPATIBILITY SameMajorVersion
-)
-
-install(FILES
- "${CMAKE_CURRENT_BINARY_DIR}/gopher-orch-config.cmake"
- "${CMAKE_CURRENT_BINARY_DIR}/gopher-orch-config-version.cmake"
- DESTINATION lib/cmake/gopher-orch
- COMPONENT development
-)
-
-# Add uninstall target
-if(NOT TARGET uninstall)
- configure_file(
- "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in"
- "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
- IMMEDIATE @ONLY
- )
-
- add_custom_target(uninstall
- COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake
- )
-endif()
-
-# Print configuration summary
-message(STATUS "")
-message(STATUS "=== gopher-orch Configuration Summary ===")
-message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
-message(STATUS "C++ Standard: ${CMAKE_CXX_STANDARD}")
-message(STATUS "Build shared libs: ${BUILD_SHARED_LIBS}")
-message(STATUS "Build static libs: ${BUILD_STATIC_LIBS}")
-message(STATUS "Build tests: ${BUILD_TESTS}")
-message(STATUS "Build examples: ${BUILD_EXAMPLES}")
-message(STATUS "Strict warnings: ${ORCH_STRICT_WARNINGS}")
-message(STATUS "Use submodule gopher-mcp: ${USE_SUBMODULE_GOPHER_MCP}")
-message(STATUS "Install prefix: ${CMAKE_INSTALL_PREFIX}")
-message(STATUS "==========================================")
-message(STATUS "")
diff --git a/GopherOrch.sln b/GopherOrch.sln
new file mode 100644
index 00000000..b05b3b10
--- /dev/null
+++ b/GopherOrch.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GopherOrch", "src\GopherOrch\GopherOrch.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GopherOrch.Tests", "tests\GopherOrch.Tests\GopherOrch.Tests.csproj", "{B2C3D4E5-F6A7-8901-BCDE-F12345678901}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/Makefile b/Makefile
deleted file mode 100644
index 5639a8ff..00000000
--- a/Makefile
+++ /dev/null
@@ -1,374 +0,0 @@
-# gopher-orch Makefile
-# Consolidates all CMake commands for easy building
-
-# Build configuration
-BUILD_DIR ?= build
-BUILD_TYPE ?= Debug
-GENERATOR ?= "Unix Makefiles"
-PARALLEL_JOBS ?= $(shell nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)
-
-# Library build options (both by default)
-BUILD_STATIC ?= ON
-BUILD_SHARED ?= ON
-
-# CMake options
-CMAKE_OPTIONS ?=
-VERBOSE ?= 0
-
-# Colors for output
-RED := \033[0;31m
-GREEN := \033[0;32m
-YELLOW := \033[1;33m
-BLUE := \033[0;34m
-NC := \033[0m # No Color
-
-# Default target
-.PHONY: all
-all: build test
- @echo "$(GREEN)Build and test completed successfully$(NC)"
-
-# Configure with CMake
-.PHONY: configure
-configure:
- @echo "$(BLUE)Configuring with CMake...$(NC)"
- @echo " Build type: $(BUILD_TYPE)"
- @echo " Static library: $(BUILD_STATIC)"
- @echo " Shared library: $(BUILD_SHARED)"
- @mkdir -p $(BUILD_DIR)
- @cd $(BUILD_DIR) && cmake .. -G $(GENERATOR) \
- -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) \
- -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
- -DBUILD_STATIC_LIBS=$(BUILD_STATIC) \
- -DBUILD_SHARED_LIBS=$(BUILD_SHARED) \
- $(CMAKE_OPTIONS)
- @echo "$(GREEN)Configuration complete$(NC)"
-
-# Build the project
-.PHONY: build
-build: configure
- @echo "$(BLUE)Building gopher-orch libraries...$(NC)"
- @cmake --build $(BUILD_DIR) -- -j$(PARALLEL_JOBS)
- @echo "$(GREEN)Build complete$(NC)"
- @$(MAKE) --no-print-directory lib-info-summary
-
-# Build in release mode
-.PHONY: release
-release:
- @echo "$(BLUE)Building in Release mode...$(NC)"
- @$(MAKE) BUILD_TYPE=Release build test
- @echo "$(GREEN)Release build complete$(NC)"
-
-# Build in debug mode (explicit)
-.PHONY: debug
-debug:
- @echo "$(BLUE)Building in Debug mode...$(NC)"
- @$(MAKE) BUILD_TYPE=Debug build
- @echo "$(GREEN)Debug build complete$(NC)"
-
-# Run tests
-.PHONY: test
-test: build
- @echo "$(BLUE)Running tests...$(NC)"
- @cd $(BUILD_DIR) && ctest --output-on-failure
- @echo "$(GREEN)All tests passed$(NC)"
-
-# Run tests with verbose output
-.PHONY: test-verbose
-test-verbose: build
- @echo "$(BLUE)Running tests (verbose)...$(NC)"
- @cd $(BUILD_DIR) && ctest -V
- @echo "$(GREEN)All tests passed$(NC)"
-
-# Run tests in parallel
-.PHONY: test-parallel
-test-parallel: build
- @echo "$(BLUE)Running tests in parallel...$(NC)"
- @cd $(BUILD_DIR) && ctest -j$(PARALLEL_JOBS) --output-on-failure
- @echo "$(GREEN)All tests passed$(NC)"
-
-# Run specific test
-.PHONY: test-one
-test-one: build
- @if [ -z "$(TEST)" ]; then \
- echo "$(RED)Error: TEST variable not set. Usage: make test-one TEST=test_name$(NC)"; \
- exit 1; \
- fi
- @echo "$(BLUE)Running test: $(TEST)...$(NC)"
- @cd $(BUILD_DIR) && ctest -R $(TEST) -V
- @echo "$(GREEN)Test complete$(NC)"
-
-# Build only the libraries (respects current configuration)
-.PHONY: libs
-libs: configure
- @echo "$(BLUE)Building libraries...$(NC)"
- @if [ -f $(BUILD_DIR)/CMakeCache.txt ]; then \
- if grep -q "BUILD_STATIC_LIBS:BOOL=ON" $(BUILD_DIR)/CMakeCache.txt 2>/dev/null; then \
- cmake --build $(BUILD_DIR) --target gopher-orch-static -- -j$(PARALLEL_JOBS); \
- fi; \
- if grep -q "BUILD_SHARED_LIBS:BOOL=ON" $(BUILD_DIR)/CMakeCache.txt 2>/dev/null; then \
- cmake --build $(BUILD_DIR) --target gopher-orch-shared -- -j$(PARALLEL_JOBS); \
- fi; \
- else \
- cmake --build $(BUILD_DIR) --target gopher-orch-static -- -j$(PARALLEL_JOBS); \
- fi
- @echo "$(GREEN)Libraries built$(NC)"
-
-# Build only the examples
-.PHONY: examples
-examples: libs
- @echo "$(BLUE)Building examples...$(NC)"
- @cmake --build $(BUILD_DIR) --target hello_world_example -- -j$(PARALLEL_JOBS)
- @echo "$(GREEN)Examples built$(NC)"
-
-# Run the hello world example
-.PHONY: run-hello
-run-hello: examples
- @echo "$(BLUE)Running hello_world_example...$(NC)"
- @$(BUILD_DIR)/bin/hello_world_example
- @echo "$(GREEN)Example completed$(NC)"
-
-# Clean build directory
-.PHONY: clean
-clean:
- @echo "$(YELLOW)Cleaning build directory...$(NC)"
- @rm -rf $(BUILD_DIR)
- @echo "$(GREEN)Clean complete$(NC)"
-
-# Deep clean (including submodules)
-.PHONY: distclean
-distclean: clean
- @echo "$(YELLOW)Deep cleaning...$(NC)"
- @git submodule deinit -f .
- @rm -rf third_party/gopher-mcp
- @rm -rf .git/modules/third_party
- @echo "$(GREEN)Deep clean complete$(NC)"
-
-# Format all source files
-.PHONY: format
-format:
- @echo "$(BLUE)Formatting all source files with clang-format...$(NC)"
- @find . -path "./$(BUILD_DIR)*" -prune -o -path "./third_party" -prune -o \
- \( -name "*.h" -o -name "*.hpp" -o -name "*.cpp" -o -name "*.cc" -o -name "*.c" \) -print | \
- xargs clang-format -i
- @echo "$(GREEN)Formatting complete$(NC)"
-
-# Check formatting without modifying files
-.PHONY: check-format
-check-format:
- @echo "$(BLUE)Checking source file formatting...$(NC)"
- @find . -path "./$(BUILD_DIR)*" -prune -o -path "./third_party" -prune -o \
- \( -name "*.h" -o -name "*.hpp" -o -name "*.cpp" -o -name "*.cc" -o -name "*.c" \) -print | \
- xargs clang-format --dry-run --Werror
- @if [ $$? -eq 0 ]; then \
- echo "$(GREEN)All files are properly formatted$(NC)"; \
- else \
- echo "$(RED)Format check failed - run 'make format' to fix$(NC)"; \
- exit 1; \
- fi
-
-# Alias for consistency with gopher-mcp
-.PHONY: format-check
-format-check: check-format
-
-# Install the library
-.PHONY: install
-install: build
- @echo "$(BLUE)Installing gopher-orch...$(NC)"
- @cmake --build $(BUILD_DIR) --target install
- @echo "$(GREEN)Installation complete$(NC)"
-
-# Uninstall the library
-.PHONY: uninstall
-uninstall:
- @echo "$(YELLOW)Uninstalling gopher-orch...$(NC)"
- @if [ ! -f $(BUILD_DIR)/install_manifest.txt ]; then \
- echo "$(RED)Error: No installation found. Run 'make install' first.$(NC)"; \
- exit 1; \
- fi
- @cmake --build $(BUILD_DIR) --target uninstall
- @echo "$(GREEN)Uninstall complete$(NC)"
-
-# Generate documentation (requires doxygen)
-.PHONY: docs
-docs:
- @echo "$(BLUE)Generating documentation...$(NC)"
- @doxygen Doxyfile 2>/dev/null || echo "$(YELLOW)Warning: Doxygen not found or configured$(NC)"
- @echo "$(GREEN)Documentation generated$(NC)"
-
-# Update submodules
-.PHONY: update-submodules
-update-submodules:
- @echo "$(BLUE)Updating submodules...$(NC)"
- @git submodule update --init --recursive
- @echo "$(GREEN)Submodules updated$(NC)"
-
-# Configure to use system gopher-mcp instead of submodule
-.PHONY: use-system-gopher-mcp
-use-system-gopher-mcp:
- @echo "$(BLUE)Configuring to use system gopher-mcp...$(NC)"
- @$(MAKE) CMAKE_OPTIONS="-DUSE_SUBMODULE_GOPHER_MCP=OFF" configure
- @echo "$(GREEN)Configured to use system gopher-mcp$(NC)"
-
-# Configure to use submodule gopher-mcp
-.PHONY: use-submodule-gopher-mcp
-use-submodule-gopher-mcp:
- @echo "$(BLUE)Configuring to use submodule gopher-mcp...$(NC)"
- @$(MAKE) CMAKE_OPTIONS="-DUSE_SUBMODULE_GOPHER_MCP=ON" configure
- @echo "$(GREEN)Configured to use submodule gopher-mcp$(NC)"
-
-# Build shared library only
-.PHONY: shared
-shared:
- @$(MAKE) BUILD_STATIC=OFF BUILD_SHARED=ON clean build
-
-# Build static library only
-.PHONY: static
-static:
- @$(MAKE) BUILD_STATIC=ON BUILD_SHARED=OFF clean build
-
-# Build both static and shared libraries (default behavior)
-.PHONY: both
-both:
- @$(MAKE) BUILD_STATIC=ON BUILD_SHARED=ON clean build
-
-# Build standalone (without gopher-mcp dependency)
-.PHONY: standalone
-standalone:
- @echo "$(BLUE)Building standalone (without gopher-mcp)...$(NC)"
- @$(MAKE) CMAKE_OPTIONS="-DBUILD_WITHOUT_GOPHER_MCP=ON" build
- @echo "$(GREEN)Standalone build complete$(NC)"
-
-# Show brief library summary (used after build)
-.PHONY: lib-info-summary
-lib-info-summary:
- @if [ -f $(BUILD_DIR)/lib/libgopher-orch.a ]; then \
- echo " $(GREEN)Static library: $(BUILD_DIR)/lib/libgopher-orch.a ($$(du -h $(BUILD_DIR)/lib/libgopher-orch.a 2>/dev/null | cut -f1))$(NC)"; \
- fi
- @if [ -f $(BUILD_DIR)/lib/libgopher-orch.so ]; then \
- echo " $(GREEN)Shared library: $(BUILD_DIR)/lib/libgopher-orch.so ($$(du -h $(BUILD_DIR)/lib/libgopher-orch.so 2>/dev/null | cut -f1))$(NC)"; \
- elif [ -f $(BUILD_DIR)/lib/libgopher-orch.dylib ]; then \
- echo " $(GREEN)Shared library: $(BUILD_DIR)/lib/libgopher-orch.dylib ($$(du -h $(BUILD_DIR)/lib/libgopher-orch.dylib 2>/dev/null | cut -f1))$(NC)"; \
- fi
-
-# Show detailed library information
-.PHONY: lib-info
-lib-info:
- @echo "$(BLUE)Library Information:$(NC)"
- @if [ -f $(BUILD_DIR)/lib/libgopher-orch.a ]; then \
- echo "$(GREEN)Static library:$(NC)"; \
- echo " Path: $(BUILD_DIR)/lib/libgopher-orch.a"; \
- echo " Size: $$(du -h $(BUILD_DIR)/lib/libgopher-orch.a | cut -f1)"; \
- if command -v ar >/dev/null 2>&1; then \
- echo " Objects: $$(ar -t $(BUILD_DIR)/lib/libgopher-orch.a 2>/dev/null | wc -l) files"; \
- fi; \
- else \
- echo "$(YELLOW)Static library not found$(NC)"; \
- fi
- @echo ""
- @if [ -f $(BUILD_DIR)/lib/libgopher-orch.so ] || [ -f $(BUILD_DIR)/lib/libgopher-orch.dylib ]; then \
- echo "$(GREEN)Shared library:$(NC)"; \
- LIB_PATH=$$(find $(BUILD_DIR)/lib -name "libgopher-orch.so*" -o -name "libgopher-orch.dylib" | head -1); \
- if [ -n "$$LIB_PATH" ]; then \
- echo " Path: $$LIB_PATH"; \
- echo " Size: $$(du -h $$LIB_PATH | cut -f1)"; \
- if command -v ldd >/dev/null 2>&1; then \
- echo " Dependencies:"; \
- ldd $$LIB_PATH | head -5 | sed 's/^/ /'; \
- elif command -v otool >/dev/null 2>&1; then \
- echo " Dependencies:"; \
- otool -L $$LIB_PATH | head -5 | sed 's/^/ /'; \
- fi; \
- fi; \
- else \
- echo "$(YELLOW)Shared library not found$(NC)"; \
- fi
- @echo ""
- @if [ -f $(BUILD_DIR)/CMakeCache.txt ]; then \
- echo "$(BLUE)Current configuration:$(NC)"; \
- grep -E "^(BUILD_SHARED_LIBS|BUILD_STATIC_LIBS):BOOL=" $(BUILD_DIR)/CMakeCache.txt | sed 's/^/ /'; \
- fi
-
-# Show build configuration
-.PHONY: info
-info:
- @echo "$(BLUE)Build Configuration:$(NC)"
- @echo " Build directory: $(BUILD_DIR)"
- @echo " Build type: $(BUILD_TYPE)"
- @echo " Generator: $(GENERATOR)"
- @echo " Parallel jobs: $(PARALLEL_JOBS)"
- @echo " Build static libs: $(BUILD_STATIC)"
- @echo " Build shared libs: $(BUILD_SHARED)"
- @echo " CMake options: $(CMAKE_OPTIONS)"
- @if [ -f $(BUILD_DIR)/CMakeCache.txt ]; then \
- echo "\n$(BLUE)Current CMake cache:$(NC)"; \
- grep -E "^(CMAKE_BUILD_TYPE|BUILD_SHARED_LIBS|BUILD_STATIC_LIBS|USE_SUBMODULE_GOPHER_MCP)" $(BUILD_DIR)/CMakeCache.txt || true; \
- else \
- echo "\n$(YELLOW)No build directory found. Run 'make configure' first.$(NC)"; \
- fi
-
-# Help target
-.PHONY: help
-help:
- @echo "$(BLUE)gopher-orch Build System$(NC)"
- @echo ""
- @echo "$(GREEN)Common targets:$(NC)"
- @echo " make - Build both libraries and run tests (default)"
- @echo " make build - Build both static and shared libraries"
- @echo " make release - Build and test in release mode"
- @echo " make test - Run tests"
- @echo " make clean - Clean build directory"
- @echo " make install - Install the libraries"
- @echo " make uninstall - Uninstall the libraries"
- @echo ""
- @echo "$(GREEN)Library build targets:$(NC)"
- @echo " make both - Build both library types (default)"
- @echo " make static - Build static library only (with clean)"
- @echo " make shared - Build shared library only (with clean)"
- @echo " make libs - Build libraries (current config)"
- @echo " make lib-info - Show detailed library information"
- @echo ""
- @echo "$(GREEN)Build modes:$(NC)"
- @echo " make debug - Build in debug mode"
- @echo " make release - Build in release mode"
- @echo " make standalone - Build without gopher-mcp"
- @echo ""
- @echo "$(GREEN)Test targets:$(NC)"
- @echo " make test-verbose - Run tests with verbose output"
- @echo " make test-parallel - Run tests in parallel"
- @echo " make test-one TEST=name - Run specific test"
- @echo ""
- @echo "$(GREEN)Component targets:$(NC)"
- @echo " make libs - Build only libraries"
- @echo " make examples - Build examples"
- @echo " make run-hello - Run hello world example"
- @echo ""
- @echo "$(GREEN)Dependency management:$(NC)"
- @echo " make update-submodules - Update git submodules"
- @echo " make use-system-gopher-mcp - Use system gopher-mcp"
- @echo " make use-submodule-gopher-mcp - Use submodule gopher-mcp"
- @echo ""
- @echo "$(GREEN)Code Quality:$(NC)"
- @echo " make format - Auto-format all source files"
- @echo " make check-format - Check formatting without modifying"
- @echo " make format-check - Alias for check-format"
- @echo ""
- @echo "$(GREEN)Utilities:$(NC)"
- @echo " make docs - Generate documentation"
- @echo " make info - Show build configuration"
- @echo " make distclean - Deep clean including submodules"
- @echo ""
- @echo "$(GREEN)Variables:$(NC)"
- @echo " BUILD_DIR=dir - Set build directory (default: build)"
- @echo " BUILD_TYPE=type - Set build type (Debug/Release, default: Debug)"
- @echo " BUILD_STATIC=ON/OFF - Build static library (default: ON)"
- @echo " BUILD_SHARED=ON/OFF - Build shared library (default: ON)"
- @echo " CMAKE_OPTIONS=opts - Additional CMake options"
- @echo " PARALLEL_JOBS=n - Number of parallel jobs"
- @echo ""
- @echo "$(GREEN)Examples:$(NC)"
- @echo " make - Build both libraries (default)"
- @echo " make BUILD_SHARED=OFF - Build static library only"
- @echo " make BUILD_TYPE=Release - Build both libraries in release mode"
- @echo " make static - Build only static library"
-
-.DEFAULT_GOAL := all
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..99d7abe7
--- /dev/null
+++ b/README.md
@@ -0,0 +1,218 @@
+# gopher-orch C# SDK
+
+C# SDK for gopher-orch, providing AI agent orchestration with native C++ performance through P/Invoke bindings.
+
+## Features
+
+- .NET Standard 2.0 compatibility (works with .NET Core 2.0+, .NET 5+, .NET Framework 4.6.1+)
+- P/Invoke FFI bindings to native gopher-orch library
+- `GopherAgent` class with builder pattern configuration
+- `IDisposable` support for automatic resource cleanup
+- Typed exceptions (`AgentException`, `ApiKeyException`, etc.)
+- xUnit tests
+
+## Requirements
+
+- .NET SDK 6.0 or later (for building)
+- CMake 3.16+ (for native library)
+- C++17 compatible compiler
+
+## Quick Start
+
+### Building
+
+```bash
+# Build everything (native library + C# SDK)
+./build.sh
+
+# Or build manually:
+dotnet build
+dotnet test
+```
+
+### Usage
+
+```csharp
+using GopherOrch;
+
+// Create an agent with API key
+using var agent = GopherAgent.Create(
+ GopherAgentConfig.CreateBuilder()
+ .WithProvider("AnthropicProvider")
+ .WithModel("claude-3-haiku-20240307")
+ .WithApiKey("your-api-key")
+ .Build()
+);
+
+// Run a query
+string answer = agent.Run("What time is it in Tokyo?");
+Console.WriteLine(answer);
+```
+
+### Using JSON Server Configuration
+
+```csharp
+using GopherOrch;
+
+string serverConfig = @"{
+ ""succeeded"": true,
+ ""code"": 200000000,
+ ""message"": ""success"",
+ ""data"": {
+ ""servers"": [
+ {
+ ""version"": ""2025-01-09"",
+ ""serverId"": ""1"",
+ ""name"": ""server1"",
+ ""transport"": ""http_sse"",
+ ""config"": {""url"": ""http://127.0.0.1:3001/mcp"", ""headers"": {}},
+ ""connectTimeout"": 5000,
+ ""requestTimeout"": 30000
+ }
+ ]
+ }
+}";
+
+using var agent = GopherAgent.CreateWithServerConfig(
+ "AnthropicProvider",
+ "claude-3-haiku-20240307",
+ serverConfig
+);
+
+string answer = agent.Run("What tools are available?");
+Console.WriteLine(answer);
+```
+
+## API Reference
+
+### GopherAgent
+
+Main entry point for agent operations.
+
+```csharp
+// Create with config
+var agent = GopherAgent.Create(config);
+
+// Create with API key
+var agent = GopherAgent.Create(provider, model, apiKey);
+
+// Create with server config
+var agent = GopherAgent.CreateWithServerConfig(provider, model, serverConfig);
+
+// Run query
+string response = agent.Run("your query");
+
+// Run with timeout
+string response = agent.Run("your query", timeoutMs: 30000);
+
+// Run with detailed result
+AgentResult result = agent.RunDetailed("your query");
+
+// Cleanup
+agent.Dispose();
+```
+
+### GopherAgentConfig
+
+Configuration builder for agent creation.
+
+```csharp
+var config = GopherAgentConfig.CreateBuilder()
+ .WithProvider("AnthropicProvider")
+ .WithModel("claude-3-haiku-20240307")
+ .WithApiKey("your-api-key") // OR
+ .WithServerConfig(jsonConfig) // Use one or the other
+ .Build();
+```
+
+### AgentResult
+
+Detailed result from query execution.
+
+```csharp
+AgentResult result = agent.RunDetailed("query");
+
+Console.WriteLine(result.Response);
+Console.WriteLine(result.Status); // Success, Error, Timeout
+Console.WriteLine(result.IsSuccess);
+Console.WriteLine(result.IterationCount);
+Console.WriteLine(result.TokensUsed);
+```
+
+### Exceptions
+
+- `AgentException` - Base exception for agent operations
+- `ApiKeyException` - API key related errors
+- `ConnectionException` - Connection related errors
+- `TimeoutException` - Timeout related errors
+
+## Development
+
+### Code Formatting
+
+```bash
+# Format code
+dotnet format
+
+# Check formatting without making changes
+dotnet format --verify-no-changes
+
+# Build with warnings
+dotnet build
+
+# Run tests
+dotnet test
+```
+
+## Examples
+
+The `examples/` directory contains runnable examples:
+
+```bash
+# Run the JSON server config example
+./examples/client_example_json_run.sh
+```
+
+This starts two MCP servers (server3001, server3002) and runs a client that queries them.
+
+## Project Structure
+
+```
+gopher-mcp-csharp/
+├── GopherOrch.sln # Solution file
+├── build.sh # Build script
+├── src/
+│ └── GopherOrch/ # Main library
+│ ├── GopherOrch.csproj
+│ ├── GopherAgent.cs
+│ ├── GopherAgentConfig.cs
+│ ├── AgentResult.cs
+│ ├── AgentResultStatus.cs
+│ ├── ServerConfig.cs
+│ ├── Errors/
+│ │ ├── AgentException.cs
+│ │ ├── ApiKeyException.cs
+│ │ ├── ConnectionException.cs
+│ │ └── TimeoutException.cs
+│ └── Ffi/
+│ └── GopherOrchLibrary.cs
+├── tests/
+│ └── GopherOrch.Tests/ # Unit tests
+│ ├── GopherOrch.Tests.csproj
+│ ├── AgentResultTest.cs
+│ └── GopherAgentConfigTest.cs
+├── examples/
+│ ├── client_example_json_run.sh # Example runner script
+│ ├── ClientExampleJson/ # Example client project
+│ ├── server3001/ # MCP server example
+│ └── server3002/ # MCP server example
+├── third_party/
+│ └── gopher-orch/ # Native library (git submodule)
+└── native/ # Built native libraries (generated)
+ ├── lib/
+ └── include/
+```
+
+## License
+
+See [LICENSE](LICENSE) for details.
diff --git a/build.sh b/build.sh
index 3aa8a1ca..a3ab76c0 100755
--- a/build.sh
+++ b/build.sh
@@ -1,123 +1,183 @@
-#!/bin/bash -x
+#!/bin/bash
-# Build script for gopher-orch with submodule support
-
-set -e
+set -e # Exit on error
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
-BLUE='\033[0;34m'
NC='\033[0m' # No Color
-echo -e "${BLUE}=== gopher-orch Build Script ===${NC}"
-
-# Parse arguments
-BUILD_TYPE="${BUILD_TYPE:-Debug}"
-BUILD_DIR="${BUILD_DIR:-build}"
-USE_SUBMODULE=ON
-BUILD_TESTS=ON
-BUILD_EXAMPLES=ON
-
-for arg in "$@"; do
- case $arg in
- --release)
- BUILD_TYPE=Release
- shift
- ;;
- --no-submodule)
- USE_SUBMODULE=OFF
- shift
- ;;
- --no-tests)
- BUILD_TESTS=OFF
- shift
- ;;
- --no-examples)
- BUILD_EXAMPLES=OFF
- shift
- ;;
- --standalone)
- # Build without gopher-mcp for testing
- USE_SUBMODULE=OFF
- BUILD_WITHOUT_MCP=ON
- shift
- ;;
- --clean)
- echo -e "${YELLOW}Cleaning build directory...${NC}"
- rm -rf "$BUILD_DIR"
- shift
- ;;
- --help)
- echo "Usage: $0 [options]"
- echo "Options:"
- echo " --release Build in Release mode (default: Debug)"
- echo " --no-submodule Use system gopher-mcp instead of submodule"
- echo " --no-tests Don't build tests"
- echo " --no-examples Don't build examples"
- echo " --standalone Build without gopher-mcp dependency"
- echo " --clean Clean build directory before building"
- echo " --help Show this help message"
- exit 0
- ;;
- esac
-done
-
-# Initialize submodule if needed
-if [ "$USE_SUBMODULE" = "ON" ] && [ "${BUILD_WITHOUT_MCP:-OFF}" = "OFF" ]; then
- if [ ! -f "third_party/gopher-mcp/CMakeLists.txt" ]; then
- echo -e "${YELLOW}Initializing gopher-mcp submodule...${NC}"
- git submodule update --init --recursive third_party/gopher-mcp
- else
- echo -e "${GREEN}gopher-mcp submodule already initialized${NC}"
+# Get the script directory
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+NATIVE_DIR="${SCRIPT_DIR}/third_party/gopher-orch"
+BUILD_DIR="${NATIVE_DIR}/build"
+
+# Handle --clean flag (cleans CMake cache but preserves _deps)
+if [ "$1" = "--clean" ]; then
+ echo -e "${YELLOW}Cleaning build artifacts (preserving _deps)...${NC}"
+ rm -rf "${SCRIPT_DIR}/native"
+ rm -f "${BUILD_DIR}/CMakeCache.txt"
+ rm -rf "${BUILD_DIR}/CMakeFiles"
+ rm -rf "${BUILD_DIR}/lib"
+ rm -rf "${BUILD_DIR}/bin"
+ echo -e "${GREEN}✓ Clean complete${NC}"
+ if [ "$2" != "--build" ]; then
+ exit 0
+ fi
+fi
+
+echo -e "${GREEN}======================================${NC}"
+echo -e "${GREEN}Building gopher-orch C# SDK${NC}"
+echo -e "${GREEN}======================================${NC}"
+echo ""
+
+# Step 1: Update submodules recursively
+echo -e "${YELLOW}Step 1: Updating submodules...${NC}"
+
+# Support custom SSH host for multiple GitHub accounts
+# Usage: GITHUB_SSH_HOST=bettercallsaulj ./build.sh
+SSH_HOST="${GITHUB_SSH_HOST:-github.com}"
+if [ -n "${GITHUB_SSH_HOST}" ]; then
+ echo -e "${YELLOW} Using custom SSH host: ${GITHUB_SSH_HOST}${NC}"
+fi
+
+# Configure SSH URL rewrite for GopherSecurity repos
+git config --local url."git@${SSH_HOST}:GopherSecurity/".insteadOf "https://github.com/GopherSecurity/"
+git config --local submodule.third_party/gopher-orch.url "git@${SSH_HOST}:GopherSecurity/gopher-orch.git"
+
+# Update main submodule
+if ! git submodule update --init 2>/dev/null; then
+ echo -e "${RED}Error: Failed to clone gopher-orch submodule${NC}"
+ echo -e "${YELLOW}If you have multiple GitHub accounts, use:${NC}"
+ echo -e " GITHUB_SSH_HOST=your-ssh-alias ./build.sh"
+ exit 1
+fi
+
+# Update nested submodule (gopher-mcp inside gopher-orch)
+# Note: gopher-orch/.gitmodules has 'update = none' so we must explicitly update
+if [ -d "${NATIVE_DIR}" ]; then
+ cd "${NATIVE_DIR}"
+ git config --local url."git@${SSH_HOST}:GopherSecurity/".insteadOf "https://github.com/GopherSecurity/"
+ # Override 'update = none' by using --checkout
+ git submodule update --init --checkout third_party/gopher-mcp 2>/dev/null || true
+ # Also update gopher-mcp's nested submodules recursively
+ if [ -d "third_party/gopher-mcp" ]; then
+ cd third_party/gopher-mcp
+ git config --local url."git@${SSH_HOST}:GopherSecurity/".insteadOf "https://github.com/GopherSecurity/"
+ git submodule update --init --recursive 2>/dev/null || true
fi
+ cd "${SCRIPT_DIR}"
+fi
+
+echo -e "${GREEN}✓ Submodules updated${NC}"
+echo ""
+
+# Step 2: Check if gopher-orch exists
+if [ ! -d "${NATIVE_DIR}" ]; then
+ echo -e "${RED}Error: gopher-orch submodule not found at ${NATIVE_DIR}${NC}"
+ echo -e "${RED}Run: git submodule update --init --recursive${NC}"
+ exit 1
fi
+# Step 3: Build gopher-orch native library
+echo -e "${YELLOW}Step 2: Building gopher-orch native library...${NC}"
+cd "${NATIVE_DIR}"
+
# Create build directory
-mkdir -p "$BUILD_DIR"
-
-# Configure
-echo -e "${BLUE}Configuring with CMake...${NC}"
-echo " Build type: $BUILD_TYPE"
-echo " Use submodule: $USE_SUBMODULE"
-echo " Build tests: $BUILD_TESTS"
-echo " Build examples: $BUILD_EXAMPLES"
-
-CMAKE_ARGS=(
- -DCMAKE_BUILD_TYPE="$BUILD_TYPE"
- -DUSE_SUBMODULE_GOPHER_MCP="$USE_SUBMODULE"
- -DBUILD_TESTS="$BUILD_TESTS"
- -DBUILD_EXAMPLES="$BUILD_EXAMPLES"
-)
-
-if [ "${BUILD_WITHOUT_MCP:-OFF}" = "ON" ]; then
- CMAKE_ARGS+=(-DBUILD_WITHOUT_GOPHER_MCP=ON)
- echo -e "${YELLOW}Building without gopher-mcp dependency (standalone mode)${NC}"
+if [ ! -d "${BUILD_DIR}" ]; then
+ mkdir -p "${BUILD_DIR}"
fi
-cmake -B "$BUILD_DIR" -S . "${CMAKE_ARGS[@]}"
+cd "${BUILD_DIR}"
+
+# Configure with CMake
+echo -e "${YELLOW} Configuring CMake...${NC}"
+cmake .. \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DCMAKE_INSTALL_PREFIX="${SCRIPT_DIR}/native" \
+ -DBUILD_SHARED_LIBS=ON \
+ -DCMAKE_POSITION_INDEPENDENT_CODE=ON
# Build
-echo -e "${BLUE}Building...${NC}"
-cmake --build "$BUILD_DIR" -j$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)
+echo -e "${YELLOW} Compiling...${NC}"
+cmake --build . --config Release -j$(sysctl -n hw.ncpu 2>/dev/null || nproc 2>/dev/null || echo 4)
-echo -e "${GREEN}Build completed successfully!${NC}"
+# Install to native directory
+echo -e "${YELLOW} Installing...${NC}"
+cmake --install .
+
+# Copy dependency libraries (gopher-mcp, fmt) that gopher-orch depends on
+echo -e "${YELLOW} Copying dependency libraries...${NC}"
+NATIVE_LIB_DIR="${SCRIPT_DIR}/native/lib"
+mkdir -p "${NATIVE_LIB_DIR}"
+
+# Copy gopher-mcp libraries
+cp -P "${BUILD_DIR}/lib/libgopher-mcp"*.dylib "${NATIVE_LIB_DIR}/" 2>/dev/null || \
+cp -P "${BUILD_DIR}/lib/libgopher-mcp"*.so "${NATIVE_LIB_DIR}/" 2>/dev/null || true
+
+# Copy fmt library
+cp -P "${BUILD_DIR}/lib/libfmt"*.dylib "${NATIVE_LIB_DIR}/" 2>/dev/null || \
+cp -P "${BUILD_DIR}/lib/libfmt"*.so "${NATIVE_LIB_DIR}/" 2>/dev/null || true
+
+echo -e "${GREEN}✓ Native library built successfully${NC}"
+echo ""
+
+# Step 4: Verify build artifacts
+echo -e "${YELLOW}Step 3: Verifying native build artifacts...${NC}"
+
+NATIVE_LIB_DIR="${SCRIPT_DIR}/native/lib"
+NATIVE_INCLUDE_DIR="${SCRIPT_DIR}/native/include"
+
+if [ -d "${NATIVE_LIB_DIR}" ]; then
+ echo -e "${GREEN}✓ Libraries installed to: ${NATIVE_LIB_DIR}${NC}"
+ ls -lh "${NATIVE_LIB_DIR}"/*.dylib 2>/dev/null || ls -lh "${NATIVE_LIB_DIR}"/*.so 2>/dev/null || true
+else
+ echo -e "${YELLOW}⚠ Library directory not found: ${NATIVE_LIB_DIR}${NC}"
+fi
-# Run tests if built
-if [ "$BUILD_TESTS" = "ON" ]; then
- echo -e "${BLUE}Running tests...${NC}"
- (cd "$BUILD_DIR" && ctest --output-on-failure) || {
- echo -e "${RED}Some tests failed${NC}"
- exit 1
- }
- echo -e "${GREEN}All tests passed!${NC}"
+if [ -d "${NATIVE_INCLUDE_DIR}" ]; then
+ echo -e "${GREEN}✓ Headers installed to: ${NATIVE_INCLUDE_DIR}${NC}"
+else
+ echo -e "${YELLOW}⚠ Include directory not found: ${NATIVE_INCLUDE_DIR}${NC}"
fi
-# Show example usage
-if [ "$BUILD_EXAMPLES" = "ON" ] && [ -f "$BUILD_DIR/bin/hello_world_example" ]; then
- echo -e "${BLUE}Example built:${NC}"
- echo " Run: ./$BUILD_DIR/bin/hello_world_example"
+echo ""
+
+# Step 4: Build C# SDK
+echo -e "${YELLOW}Step 4: Building C# SDK...${NC}"
+cd "${SCRIPT_DIR}"
+
+# Check for dotnet
+if ! command -v dotnet &> /dev/null; then
+ echo -e "${RED}Error: .NET SDK not found. Please install .NET SDK first.${NC}"
+ echo -e "${YELLOW} macOS: brew install dotnet${NC}"
+ echo -e "${YELLOW} Linux: https://docs.microsoft.com/en-us/dotnet/core/install/linux${NC}"
+ exit 1
fi
-echo -e "${GREEN}=== Build Complete ===${NC}"
+# Build with dotnet
+echo -e "${YELLOW} Compiling C# SDK...${NC}"
+dotnet build -c Release
+
+echo -e "${GREEN}✓ C# SDK built successfully${NC}"
+echo ""
+
+# Step 5: Run tests
+echo -e "${YELLOW}Step 5: Running tests...${NC}"
+dotnet test -c Release --no-build 2>/dev/null && echo -e "${GREEN}✓ Tests passed${NC}" || echo -e "${YELLOW}⚠ Some tests may have failed (native library required)${NC}"
+
+# Package NuGet
+echo -e "${YELLOW}Step 6: Packaging NuGet...${NC}"
+dotnet pack -c Release --no-build -o "${SCRIPT_DIR}/packages"
+echo -e "${GREEN}✓ NuGet package created${NC}"
+
+echo ""
+echo -e "${GREEN}======================================${NC}"
+echo -e "${GREEN}Build completed successfully!${NC}"
+echo -e "${GREEN}======================================${NC}"
+echo ""
+echo -e "Native libraries: ${YELLOW}${NATIVE_LIB_DIR}${NC}"
+echo -e "Native headers: ${YELLOW}${NATIVE_INCLUDE_DIR}${NC}"
+echo -e "Run tests: ${YELLOW}dotnet test${NC}"
+echo -e "Package NuGet: ${YELLOW}dotnet pack${NC}"
diff --git a/cmake/cmake_uninstall.cmake.in b/cmake/cmake_uninstall.cmake.in
deleted file mode 100644
index 25ae5708..00000000
--- a/cmake/cmake_uninstall.cmake.in
+++ /dev/null
@@ -1,49 +0,0 @@
-# cmake_uninstall.cmake.in
-# Uninstall script for gopher-orch
-
-if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
- message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt")
-endif()
-
-file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files)
-string(REGEX REPLACE "\n" ";" files "${files}")
-
-foreach(file ${files})
- message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
- if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
- exec_program(
- "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
- OUTPUT_VARIABLE rm_out
- RETURN_VALUE rm_retval
- )
- if(NOT "${rm_retval}" STREQUAL 0)
- message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
- endif()
- else()
- message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
- endif()
-endforeach()
-
-# Remove empty directories
-set(DIRS_TO_CHECK
- "@CMAKE_INSTALL_PREFIX@/lib/cmake/gopher-orch"
- "@CMAKE_INSTALL_PREFIX@/include/orch/core"
- "@CMAKE_INSTALL_PREFIX@/include/orch"
-)
-
-foreach(dir ${DIRS_TO_CHECK})
- if(EXISTS "$ENV{DESTDIR}${dir}")
- file(GLOB dir_contents "$ENV{DESTDIR}${dir}/*")
- list(LENGTH dir_contents n_contents)
- if(n_contents EQUAL 0)
- message(STATUS "Removing empty directory: $ENV{DESTDIR}${dir}")
- exec_program(
- "@CMAKE_COMMAND@" ARGS "-E remove_directory \"$ENV{DESTDIR}${dir}\""
- OUTPUT_VARIABLE rm_out
- RETURN_VALUE rm_retval
- )
- endif()
- endif()
-endforeach()
-
-message(STATUS "Uninstall complete")
diff --git a/cmake/gopher-orch-config.cmake.in b/cmake/gopher-orch-config.cmake.in
deleted file mode 100644
index 89457eef..00000000
--- a/cmake/gopher-orch-config.cmake.in
+++ /dev/null
@@ -1,23 +0,0 @@
-@PACKAGE_INIT@
-
-include(CMakeFindDependencyMacro)
-
-# Find required dependencies
-if(@USE_SUBMODULE_GOPHER_MCP@)
- # When gopher-orch was built with submodule, users need gopher-mcp
- find_dependency(gopher-mcp REQUIRED)
-endif()
-
-# Find threads
-find_dependency(Threads REQUIRED)
-
-# Include the targets file
-include("${CMAKE_CURRENT_LIST_DIR}/gopher-orch-targets.cmake")
-
-# Set variables for compatibility
-set(gopher-orch_FOUND TRUE)
-set(gopher-orch_INCLUDE_DIRS "@CMAKE_INSTALL_PREFIX@/include")
-set(gopher-orch_LIBRARIES gopher-orch)
-
-# Check required components
-check_required_components(gopher-orch)
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
deleted file mode 100644
index 240bb3ee..00000000
--- a/examples/CMakeLists.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-# gopher-orch examples
-
-# Hello World example (basic orch functionality)
-add_subdirectory(hello_world)
-
-# MCP Client example (demonstrates gopher-mcp integration)
-add_subdirectory(mcp_client)
diff --git a/examples/ClientExampleJson.cs b/examples/ClientExampleJson.cs
new file mode 100644
index 00000000..c84c258b
--- /dev/null
+++ b/examples/ClientExampleJson.cs
@@ -0,0 +1,74 @@
+using System;
+using GopherOrch;
+
+namespace Examples
+{
+ ///
+ /// Example using JSON server configuration.
+ ///
+ public class ClientExampleJson
+ {
+ // Server configuration for local MCP servers
+ private static readonly string ServerConfig = "{"
+ + "\"succeeded\": true,"
+ + "\"code\": 200000000,"
+ + "\"message\": \"success\","
+ + "\"data\": {"
+ + " \"servers\": ["
+ + " {"
+ + " \"version\": \"2025-01-09\","
+ + " \"serverId\": \"1\","
+ + " \"name\": \"server1\","
+ + " \"transport\": \"http_sse\","
+ + " \"config\": {\"url\": \"http://127.0.0.1:3001/mcp\", \"headers\": {}},"
+ + " \"connectTimeout\": 5000,"
+ + " \"requestTimeout\": 30000"
+ + " },"
+ + " {"
+ + " \"version\": \"2025-01-09\","
+ + " \"serverId\": \"2\","
+ + " \"name\": \"server2\","
+ + " \"transport\": \"http_sse\","
+ + " \"config\": {\"url\": \"http://127.0.0.1:3002/mcp\", \"headers\": {}},"
+ + " \"connectTimeout\": 5000,"
+ + " \"requestTimeout\": 30000"
+ + " }"
+ + " ]"
+ + "}"
+ + "}";
+
+ public static void Main(string[] args)
+ {
+ string provider = "AnthropicProvider";
+ string model = "claude-3-haiku-20240307";
+
+ try
+ {
+ // Create agent with JSON server configuration
+ using var agent = GopherAgent.CreateWithServerConfig(
+ provider,
+ model,
+ ServerConfig
+ );
+ Console.WriteLine("GopherAgent created!");
+
+ // Get question from command line args or use default
+ string question = args.Length > 0
+ ? string.Join(" ", args)
+ : "What is the weather like in New York?";
+ Console.WriteLine($"Question: {question}");
+
+ // Run the query
+ string answer = agent.Run(question);
+ Console.WriteLine("Answer:");
+ Console.WriteLine(answer);
+ }
+ catch (Exception e)
+ {
+ Console.Error.WriteLine($"Error: {e.Message}");
+ Console.Error.WriteLine(e.StackTrace);
+ Environment.Exit(1);
+ }
+ }
+ }
+}
diff --git a/examples/client_example_json_run.sh b/examples/client_example_json_run.sh
new file mode 100755
index 00000000..5f2b49e0
--- /dev/null
+++ b/examples/client_example_json_run.sh
@@ -0,0 +1,111 @@
+#!/bin/bash
+
+# Run the C# client example with local MCP servers
+
+set -e
+
+# Colors for output
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+NC='\033[0m' # No Color
+
+# Get the script directory
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
+
+# Cleanup function
+cleanup() {
+ echo -e "\n${YELLOW}Cleaning up...${NC}"
+ # Kill the process groups to ensure child processes (tsx/node) are also killed
+ if [ -n "$SERVER3001_PID" ]; then
+ kill -- -$SERVER3001_PID 2>/dev/null || kill $SERVER3001_PID 2>/dev/null || true
+ fi
+ if [ -n "$SERVER3002_PID" ]; then
+ kill -- -$SERVER3002_PID 2>/dev/null || kill $SERVER3002_PID 2>/dev/null || true
+ fi
+ # Also kill any remaining tsx/node processes on our ports
+ lsof -ti:3001 | xargs kill 2>/dev/null || true
+ lsof -ti:3002 | xargs kill 2>/dev/null || true
+ echo -e "${GREEN}Done${NC}"
+}
+
+trap cleanup EXIT
+
+echo -e "${GREEN}======================================${NC}"
+echo -e "${GREEN}Running C# Client Example${NC}"
+echo -e "${GREEN}======================================${NC}"
+echo ""
+
+# Check if native library exists
+if [ ! -d "$PROJECT_DIR/native/lib" ]; then
+ echo -e "${RED}Error: Native library not found at $PROJECT_DIR/native/lib${NC}"
+ echo -e "${YELLOW}Please run ./build.sh first${NC}"
+ exit 1
+fi
+
+# Start server3001
+echo -e "${YELLOW}Starting server3001...${NC}"
+cd "$SCRIPT_DIR/server3001"
+if [ ! -d "node_modules" ]; then
+ echo -e "${YELLOW}Installing dependencies for server3001...${NC}"
+ npm install
+fi
+npm run dev &
+SERVER3001_PID=$!
+echo -e "${GREEN}server3001 started (PID: $SERVER3001_PID)${NC}"
+
+# Start server3002
+echo -e "${YELLOW}Starting server3002...${NC}"
+cd "$SCRIPT_DIR/server3002"
+if [ ! -d "node_modules" ]; then
+ echo -e "${YELLOW}Installing dependencies for server3002...${NC}"
+ npm install
+fi
+npm run dev &
+SERVER3002_PID=$!
+echo -e "${GREEN}server3002 started (PID: $SERVER3002_PID)${NC}"
+
+# Wait for servers to start
+echo -e "${YELLOW}Waiting for servers to start...${NC}"
+sleep 3
+
+# Build and run the C# example
+echo ""
+echo -e "${YELLOW}Building and running C# client...${NC}"
+echo ""
+cd "$PROJECT_DIR"
+
+# Create a temporary console project for the example
+EXAMPLE_PROJECT_DIR="$PROJECT_DIR/examples/ClientExampleJson"
+mkdir -p "$EXAMPLE_PROJECT_DIR"
+
+# Create project file (use forward slashes for cross-platform compatibility)
+cat > "$EXAMPLE_PROJECT_DIR/ClientExampleJson.csproj" << 'EOF'
+
+
+
+ Exe
+ net6.0
+ 10.0
+ enable
+
+
+
+
+
+
+
+
+
+
+
+EOF
+
+# Run with dotnet
+DYLD_LIBRARY_PATH="$PROJECT_DIR/native/lib" \
+LD_LIBRARY_PATH="$PROJECT_DIR/native/lib" \
+dotnet run --project "$EXAMPLE_PROJECT_DIR/ClientExampleJson.csproj" -- "$@"
+
+echo ""
+echo -e "${GREEN}Example completed${NC}"
diff --git a/examples/hello_world/CMakeLists.txt b/examples/hello_world/CMakeLists.txt
deleted file mode 100644
index 236c04f8..00000000
--- a/examples/hello_world/CMakeLists.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-add_executable(hello_world_example main.cpp)
-
-target_link_libraries(hello_world_example
- gopher-orch
- ${GOPHER_MCP_LIBRARIES}
- Threads::Threads
-)
-
-target_include_directories(hello_world_example PRIVATE
- ${CMAKE_SOURCE_DIR}/include
- ${GOPHER_MCP_INCLUDE_DIR}
-)
-
-# Examples are not installed by default
-# To install, use: cmake --install . --component examples
diff --git a/examples/hello_world/main.cpp b/examples/hello_world/main.cpp
deleted file mode 100644
index 5c79dbd8..00000000
--- a/examples/hello_world/main.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-#include
-#include
-#include
-
-#include "orch/core/hello.h"
-#include "orch/core/version.h"
-
-using namespace gopher::orch::core;
-
-int main(int argc, char* argv[]) {
- std::cout << "gopher-orch version: " << Version::string() << std::endl;
- std::cout << "----------------------------------------" << std::endl;
-
- // Basic usage
- {
- std::cout << "\n1. Basic Hello usage:" << std::endl;
- Hello hello;
- std::cout << " " << hello.greet() << std::endl;
-
- hello.set_name("gopher-orch User");
- std::cout << " " << hello.greet() << std::endl;
- }
-
- // Constructor with parameter
- {
- std::cout << "\n2. Parameterized constructor:" << std::endl;
- Hello hello("Alice");
- std::cout << " " << hello.greet() << std::endl;
- }
-
- // Custom prefix
- {
- std::cout << "\n3. Custom prefix greetings:" << std::endl;
- Hello hello("Bob");
- std::cout << " " << hello.greet_with_prefix("Hi") << std::endl;
- std::cout << " " << hello.greet_with_prefix("Welcome") << std::endl;
- std::cout << " " << hello.greet_with_prefix("Greetings") << std::endl;
- }
-
- // Builder pattern
- {
- std::cout << "\n4. Using HelloBuilder:" << std::endl;
- HelloBuilder builder;
-
- auto hello1 = builder.with_name("Charlie").build();
- std::cout << " " << hello1->greet() << std::endl;
-
- auto hello2 =
- builder.with_name("Diana").with_greeting_style("formal").build();
- std::cout << " " << hello2->greet() << std::endl;
- }
-
- // Command line argument
- if (argc > 1) {
- std::cout << "\n5. Using command line argument:" << std::endl;
- Hello hello(argv[1]);
- std::cout << " " << hello.greet() << std::endl;
- }
-
- // Multiple instances
- {
- std::cout << "\n6. Multiple instances:" << std::endl;
- std::vector> hellos;
-
- hellos.push_back(std::make_unique("User1"));
- hellos.push_back(std::make_unique("User2"));
- hellos.push_back(std::make_unique("User3"));
-
- for (const auto& hello : hellos) {
- std::cout << " " << hello->greet() << std::endl;
- }
- }
-
- std::cout << "\n----------------------------------------" << std::endl;
- std::cout << "Example completed successfully!" << std::endl;
-
- return 0;
-}
diff --git a/examples/mcp_client/CMakeLists.txt b/examples/mcp_client/CMakeLists.txt
deleted file mode 100644
index 6437f789..00000000
--- a/examples/mcp_client/CMakeLists.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-# MCP Client Example
-# Demonstrates gopher-mcp integration with gopher-orch
-cmake_minimum_required(VERSION 3.10)
-
-# Define the executable
-add_executable(mcp_client_example
- mcp_client_example.cc
-)
-
-# Set target properties
-set_target_properties(mcp_client_example PROPERTIES
- CXX_STANDARD 14
- CXX_STANDARD_REQUIRED ON
- RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
-)
-
-# Link against gopher-orch and gopher-mcp libraries
-target_link_libraries(mcp_client_example PRIVATE
- gopher-orch-static
- gopher-mcp
- gopher-mcp-event
- ${CMAKE_THREAD_LIBS_INIT}
-)
-
-# Include directories
-target_include_directories(mcp_client_example PRIVATE
- ${CMAKE_SOURCE_DIR}/include
- ${GOPHER_MCP_INCLUDE_DIR}
-)
-
-# Examples are not installed by default
-# To install, use: cmake --install . --component examples
diff --git a/examples/mcp_client/mcp_client_example.cc b/examples/mcp_client/mcp_client_example.cc
deleted file mode 100644
index 28575339..00000000
--- a/examples/mcp_client/mcp_client_example.cc
+++ /dev/null
@@ -1,152 +0,0 @@
-/**
- * @file mcp_client_example.cc
- * @brief Example demonstrating gopher-orch integration with gopher-mcp
- *
- * This example shows how gopher-orch can extend and use gopher-mcp
- * functionality. It demonstrates:
- * 1. Using gopher-orch's Hello class
- * 2. Using gopher-mcp types and utilities
- * 3. Integration between both libraries
- */
-
-#include
-#include
-#include
-
-// gopher-orch includes
-#include "orch/core/hello.h"
-#include "orch/core/version.h"
-
-// gopher-mcp includes
-#include "mcp/json/json_bridge.h"
-#include "mcp/types.h"
-
-using namespace gopher::orch::core;
-using namespace mcp;
-
-int main(int argc, char* argv[]) {
- std::cout << "=== gopher-orch + gopher-mcp Integration Example ==="
- << std::endl;
- std::cout << std::endl;
-
- // Show versions
- std::cout << "Versions:" << std::endl;
- std::cout << " gopher-orch: " << Version::string() << std::endl;
- std::cout << std::endl;
-
- // Demonstrate gopher-orch Hello class
- std::cout << "1. gopher-orch Hello class:" << std::endl;
- Hello hello("MCP User");
- std::cout << " " << hello.greet() << std::endl;
- std::cout << std::endl;
-
- // Demonstrate gopher-mcp types
- std::cout << "2. gopher-mcp types:" << std::endl;
-
- // Create a Tool definition
- Tool calculator_tool;
- calculator_tool.name = "calculator";
- calculator_tool.description = make_optional(
- std::string("A simple calculator tool for basic arithmetic"));
-
- // Create input schema
- json::JsonValue schema;
- schema["type"] = "object";
- schema["properties"]["operation"]["type"] = "string";
- schema["properties"]["a"]["type"] = "number";
- schema["properties"]["b"]["type"] = "number";
-
- auto required_arr = json::JsonValue::array();
- required_arr.push_back("operation");
- required_arr.push_back("a");
- required_arr.push_back("b");
- schema["required"] = required_arr;
-
- calculator_tool.inputSchema = make_optional(schema);
-
- std::cout << " Created Tool: " << calculator_tool.name << std::endl;
- if (calculator_tool.description.has_value()) {
- std::cout << " Description: " << calculator_tool.description.value()
- << std::endl;
- }
- std::cout << std::endl;
-
- // Create a Resource definition
- Resource sample_resource;
- sample_resource.uri = "file:///example/data.json";
- sample_resource.name = "Example Data";
- sample_resource.description =
- make_optional(std::string("Sample JSON data resource for testing"));
- sample_resource.mimeType = make_optional(std::string("application/json"));
-
- std::cout << "3. MCP Resource:" << std::endl;
- std::cout << " URI: " << sample_resource.uri << std::endl;
- std::cout << " Name: " << sample_resource.name << std::endl;
- if (sample_resource.mimeType.has_value()) {
- std::cout << " MIME Type: " << sample_resource.mimeType.value()
- << std::endl;
- }
- std::cout << std::endl;
-
- // Create a Prompt definition
- Prompt greeting_prompt;
- greeting_prompt.name = "greeting";
- greeting_prompt.description =
- make_optional(std::string("A simple greeting prompt"));
-
- PromptArgument name_arg;
- name_arg.name = "name";
- name_arg.description = make_optional(std::string("The name to greet"));
- name_arg.required = true;
-
- greeting_prompt.arguments =
- make_optional(std::vector{name_arg});
-
- std::cout << "4. MCP Prompt:" << std::endl;
- std::cout << " Name: " << greeting_prompt.name << std::endl;
- if (greeting_prompt.description.has_value()) {
- std::cout << " Description: " << greeting_prompt.description.value()
- << std::endl;
- }
- if (greeting_prompt.arguments.has_value()) {
- std::cout << " Arguments: " << greeting_prompt.arguments.value().size()
- << std::endl;
- for (const auto& arg : greeting_prompt.arguments.value()) {
- std::cout << " - " << arg.name;
- if (arg.required) {
- std::cout << " (required)";
- }
- std::cout << std::endl;
- }
- }
- std::cout << std::endl;
-
- // Demonstrate JSON serialization
- std::cout << "5. JSON Operations:" << std::endl;
- json::JsonValue data;
- data["greeting"] = hello.greet();
- data["version"] = Version::string();
- data["tool_count"] = 1;
- data["resource_count"] = 1;
-
- std::cout << " Created JSON object with greeting and version info"
- << std::endl;
- std::cout << std::endl;
-
- // Integration example: Using gopher-orch to enhance gopher-mcp
- std::cout << "6. Integration Example:" << std::endl;
- HelloBuilder builder;
- auto orchestrator = builder.with_name("MCP Orchestrator").build();
- std::cout << " " << orchestrator->greet() << std::endl;
- std::cout
- << " This demonstrates gopher-orch extending gopher-mcp capabilities"
- << std::endl;
- std::cout << std::endl;
-
- std::cout << "=== Example Complete ===" << std::endl;
- std::cout
- << "The gopher-orch library successfully integrates with gopher-mcp!"
- << std::endl;
-
- return 0;
-}
diff --git a/examples/server3001/README.md b/examples/server3001/README.md
new file mode 100644
index 00000000..379c47a8
--- /dev/null
+++ b/examples/server3001/README.md
@@ -0,0 +1,21 @@
+# MCP Server 3001
+
+Simple MCP server with weather tools.
+
+## Tools
+
+- `get-weather` - Get current weather for a city
+- `get-forecast` - Get weather forecast for a city
+- `get-weather-alerts` - Get weather alerts for a region
+
+## Quick Start
+
+```bash
+npm install
+npm run dev
+```
+
+## Endpoints
+
+- MCP: http://127.0.0.1:3001/mcp
+- Health: http://127.0.0.1:3001/health
diff --git a/examples/server3001/package-lock.json b/examples/server3001/package-lock.json
new file mode 100644
index 00000000..fbe27aa0
--- /dev/null
+++ b/examples/server3001/package-lock.json
@@ -0,0 +1,1644 @@
+{
+ "name": "mcp-server-3001",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "mcp-server-3001",
+ "version": "1.0.0",
+ "license": "MIT",
+ "dependencies": {
+ "body-parser": "^2.2.0",
+ "cors": "^2.8.5",
+ "express": "^5.1.0"
+ },
+ "devDependencies": {
+ "@types/cors": "^2.8.19",
+ "@types/express": "^5.0.5",
+ "@types/node": "^20.11.5",
+ "tsx": "^4.7.0",
+ "typescript": "^5.9.3"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "../../mcp-cpp-sdk/sdk/typescript": {
+ "name": "@mcp/filter-sdk",
+ "version": "1.0.0",
+ "extraneous": true,
+ "license": "MIT",
+ "dependencies": {
+ "@modelcontextprotocol/sdk": "^1.20.0",
+ "body-parser": "^1.20.3",
+ "cors": "^2.8.5",
+ "express": "^4.21.0",
+ "jose": "^5.10.0",
+ "koffi": "^2.13.0"
+ },
+ "devDependencies": {
+ "@types/cors": "^2.8.19",
+ "@types/express": "^5.0.4",
+ "@types/jest": "^29.5.14",
+ "@types/node": "^18.19.123",
+ "@typescript-eslint/eslint-plugin": "^6.21.0",
+ "@typescript-eslint/parser": "^6.21.0",
+ "eslint": "^8.0.0",
+ "jest": "^29.0.0",
+ "prettier": "^3.6.2",
+ "ts-jest": "^29.0.0",
+ "tsx": "^4.20.6",
+ "typescript": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=16.0.0 <19.0.0"
+ }
+ },
+ "../gopher-auth-sdk-nodejs": {
+ "version": "1.0.0",
+ "extraneous": true,
+ "license": "MIT",
+ "dependencies": {
+ "axios": "^1.6.5",
+ "express": "^5.1.0",
+ "jose": "^5.2.0"
+ },
+ "devDependencies": {
+ "@types/express": "^5.0.5",
+ "@types/jest": "^29.5.11",
+ "@types/node": "^20.11.5",
+ "@typescript-eslint/eslint-plugin": "^6.19.0",
+ "@typescript-eslint/parser": "^6.19.0",
+ "eslint": "^8.56.0",
+ "jest": "^29.7.0",
+ "prettier": "^3.2.4",
+ "ts-jest": "^29.1.1",
+ "typescript": "^5.3.3"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
+ "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
+ "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
+ "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
+ "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
+ "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
+ "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
+ "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
+ "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
+ "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
+ "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
+ "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
+ "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
+ "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
+ "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
+ "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
+ "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
+ "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
+ "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
+ "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
+ "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
+ "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
+ "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
+ "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@types/body-parser": {
+ "version": "1.19.6",
+ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz",
+ "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/connect": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/connect": {
+ "version": "3.4.38",
+ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
+ "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/cors": {
+ "version": "2.8.19",
+ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz",
+ "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/express": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.5.tgz",
+ "integrity": "sha512-LuIQOcb6UmnF7C1PCFmEU1u2hmiHL43fgFQX67sN3H4Z+0Yk0Neo++mFsBjhOAuLzvlQeqAAkeDOZrJs9rzumQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/body-parser": "*",
+ "@types/express-serve-static-core": "^5.0.0",
+ "@types/serve-static": "^1"
+ }
+ },
+ "node_modules/@types/express-serve-static-core": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.0.tgz",
+ "integrity": "sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*",
+ "@types/qs": "*",
+ "@types/range-parser": "*",
+ "@types/send": "*"
+ }
+ },
+ "node_modules/@types/http-errors": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz",
+ "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/mime": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
+ "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/node": {
+ "version": "20.19.24",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.24.tgz",
+ "integrity": "sha512-FE5u0ezmi6y9OZEzlJfg37mqqf6ZDSF2V/NLjUyGrR9uTZ7Sb9F7bLNZ03S4XVUNRWGA7Ck4c1kK+YnuWjl+DA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.21.0"
+ }
+ },
+ "node_modules/@types/qs": {
+ "version": "6.14.0",
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz",
+ "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/range-parser": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
+ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/send": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz",
+ "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/serve-static": {
+ "version": "1.15.10",
+ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz",
+ "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/http-errors": "*",
+ "@types/node": "*",
+ "@types/send": "<1"
+ }
+ },
+ "node_modules/@types/serve-static/node_modules/@types/send": {
+ "version": "0.17.6",
+ "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz",
+ "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/mime": "^1",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/accepts": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
+ "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-types": "^3.0.0",
+ "negotiator": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/body-parser": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
+ "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "^3.1.2",
+ "content-type": "^1.0.5",
+ "debug": "^4.4.0",
+ "http-errors": "^2.0.0",
+ "iconv-lite": "^0.6.3",
+ "on-finished": "^2.4.1",
+ "qs": "^6.14.0",
+ "raw-body": "^3.0.0",
+ "type-is": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/body-parser/node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/call-bound": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/content-disposition": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz",
+ "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "5.2.1"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
+ "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.6.0"
+ }
+ },
+ "node_modules/cors": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+ "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+ "license": "MIT",
+ "dependencies": {
+ "object-assign": "^4",
+ "vary": "^1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+ "license": "MIT"
+ },
+ "node_modules/encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-object-atoms": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+ "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
+ "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.25.12",
+ "@esbuild/android-arm": "0.25.12",
+ "@esbuild/android-arm64": "0.25.12",
+ "@esbuild/android-x64": "0.25.12",
+ "@esbuild/darwin-arm64": "0.25.12",
+ "@esbuild/darwin-x64": "0.25.12",
+ "@esbuild/freebsd-arm64": "0.25.12",
+ "@esbuild/freebsd-x64": "0.25.12",
+ "@esbuild/linux-arm": "0.25.12",
+ "@esbuild/linux-arm64": "0.25.12",
+ "@esbuild/linux-ia32": "0.25.12",
+ "@esbuild/linux-loong64": "0.25.12",
+ "@esbuild/linux-mips64el": "0.25.12",
+ "@esbuild/linux-ppc64": "0.25.12",
+ "@esbuild/linux-riscv64": "0.25.12",
+ "@esbuild/linux-s390x": "0.25.12",
+ "@esbuild/linux-x64": "0.25.12",
+ "@esbuild/netbsd-arm64": "0.25.12",
+ "@esbuild/netbsd-x64": "0.25.12",
+ "@esbuild/openbsd-arm64": "0.25.12",
+ "@esbuild/openbsd-x64": "0.25.12",
+ "@esbuild/openharmony-arm64": "0.25.12",
+ "@esbuild/sunos-x64": "0.25.12",
+ "@esbuild/win32-arm64": "0.25.12",
+ "@esbuild/win32-ia32": "0.25.12",
+ "@esbuild/win32-x64": "0.25.12"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+ "license": "MIT"
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/express": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
+ "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
+ "license": "MIT",
+ "dependencies": {
+ "accepts": "^2.0.0",
+ "body-parser": "^2.2.0",
+ "content-disposition": "^1.0.0",
+ "content-type": "^1.0.5",
+ "cookie": "^0.7.1",
+ "cookie-signature": "^1.2.1",
+ "debug": "^4.4.0",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "finalhandler": "^2.1.0",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.0",
+ "merge-descriptors": "^2.0.0",
+ "mime-types": "^3.0.0",
+ "on-finished": "^2.4.1",
+ "once": "^1.4.0",
+ "parseurl": "^1.3.3",
+ "proxy-addr": "^2.0.7",
+ "qs": "^6.14.0",
+ "range-parser": "^1.2.1",
+ "router": "^2.2.0",
+ "send": "^1.1.0",
+ "serve-static": "^2.2.0",
+ "statuses": "^2.0.1",
+ "type-is": "^2.0.1",
+ "vary": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz",
+ "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.0",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "on-finished": "^2.4.1",
+ "parseurl": "^1.3.3",
+ "statuses": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
+ "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/get-tsconfig": {
+ "version": "4.13.0",
+ "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz",
+ "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "resolve-pkg-maps": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "license": "MIT",
+ "dependencies": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
+ "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "license": "ISC"
+ },
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/is-promise": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
+ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
+ "license": "MIT"
+ },
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/media-typer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
+ "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
+ "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
+ "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "^1.54.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT"
+ },
+ "node_modules/negotiator": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
+ "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/path-to-regexp": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz",
+ "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "license": "MIT",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.14.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
+ "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz",
+ "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.7.0",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/resolve-pkg-maps": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
+ "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
+ }
+ },
+ "node_modules/router": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
+ "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.0",
+ "depd": "^2.0.0",
+ "is-promise": "^4.0.0",
+ "parseurl": "^1.3.3",
+ "path-to-regexp": "^8.0.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "license": "MIT"
+ },
+ "node_modules/send": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
+ "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.3.5",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.0",
+ "mime-types": "^3.0.1",
+ "ms": "^2.1.3",
+ "on-finished": "^2.4.1",
+ "range-parser": "^1.2.1",
+ "statuses": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/serve-static": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
+ "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==",
+ "license": "MIT",
+ "dependencies": {
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "parseurl": "^1.3.3",
+ "send": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+ "license": "ISC"
+ },
+ "node_modules/side-channel": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+ "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3",
+ "side-channel-list": "^1.0.0",
+ "side-channel-map": "^1.0.1",
+ "side-channel-weakmap": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-list": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
+ "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-weakmap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3",
+ "side-channel-map": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/tsx": {
+ "version": "4.20.6",
+ "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz",
+ "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "~0.25.0",
+ "get-tsconfig": "^4.7.5"
+ },
+ "bin": {
+ "tsx": "dist/cli.mjs"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ }
+ },
+ "node_modules/type-is": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
+ "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
+ "license": "MIT",
+ "dependencies": {
+ "content-type": "^1.0.5",
+ "media-typer": "^1.1.0",
+ "mime-types": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
+ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "license": "ISC"
+ },
+ "sdk": {
+ "name": "@mcp/filter-sdk",
+ "version": "1.0.0",
+ "extraneous": true,
+ "license": "MIT",
+ "dependencies": {
+ "@modelcontextprotocol/sdk": "^1.20.0",
+ "body-parser": "^1.20.3",
+ "cors": "^2.8.5",
+ "express": "^4.21.0",
+ "jose": "^5.10.0",
+ "koffi": "^2.13.0"
+ },
+ "devDependencies": {
+ "@types/cors": "^2.8.19",
+ "@types/express": "^5.0.4",
+ "@types/jest": "^29.5.14",
+ "@types/node": "^18.19.123",
+ "@typescript-eslint/eslint-plugin": "^6.21.0",
+ "@typescript-eslint/parser": "^6.21.0",
+ "eslint": "^8.0.0",
+ "jest": "^29.0.0",
+ "prettier": "^3.6.2",
+ "ts-jest": "^29.0.0",
+ "tsx": "^4.20.6",
+ "typescript": "^5.9.3"
+ },
+ "engines": {
+ "node": ">=16.0.0 <19.0.0"
+ }
+ }
+ }
+}
diff --git a/examples/server3001/package.json b/examples/server3001/package.json
new file mode 100644
index 00000000..fa6c1510
--- /dev/null
+++ b/examples/server3001/package.json
@@ -0,0 +1,35 @@
+{
+ "name": "mcp-server-3001",
+ "version": "1.0.0",
+ "description": "Simple MCP server (weather tools)",
+ "main": "dist/index.js",
+ "type": "module",
+ "scripts": {
+ "build": "tsc",
+ "dev": "tsx src/index.ts",
+ "start": "node dist/src/index.js",
+ "lint": "eslint src --ext .ts",
+ "format": "prettier --write \"src/**/*.ts\""
+ },
+ "keywords": [
+ "mcp",
+ "model-context-protocol"
+ ],
+ "author": "",
+ "license": "MIT",
+ "dependencies": {
+ "body-parser": "^2.2.0",
+ "cors": "^2.8.5",
+ "express": "^5.1.0"
+ },
+ "devDependencies": {
+ "@types/cors": "^2.8.19",
+ "@types/express": "^5.0.5",
+ "@types/node": "^20.11.5",
+ "tsx": "^4.7.0",
+ "typescript": "^5.9.3"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+}
diff --git a/examples/server3001/src/index.ts b/examples/server3001/src/index.ts
new file mode 100644
index 00000000..a6a356f6
--- /dev/null
+++ b/examples/server3001/src/index.ts
@@ -0,0 +1,143 @@
+#!/usr/bin/env node
+
+/**
+ * Simple MCP Server (No Authentication)
+ */
+
+import express, { Request, Response } from 'express';
+import cors from 'cors';
+import bodyParser from 'body-parser';
+
+import { getWeather } from './tools/get-weather.js';
+import { getForecast } from './tools/get-forecast.js';
+import { getAlerts } from './tools/get-alerts.js';
+
+const SERVER_PORT = parseInt(process.env.SERVER_PORT || '3001', 10);
+const SERVER_URL = process.env.SERVER_URL || `http://127.0.0.1:${SERVER_PORT}`;
+const SERVER_NAME = process.env.SERVER_NAME || 'mcp-server-3001';
+const SERVER_VERSION = process.env.SERVER_VERSION || '1.0.0';
+
+const TOOLS = [
+ {
+ name: 'get-weather',
+ description: 'Get current weather for a city',
+ inputSchema: {
+ type: 'object',
+ properties: { city: { type: 'string', description: 'City name' } },
+ required: ['city'],
+ },
+ },
+ {
+ name: 'get-forecast',
+ description: 'Get weather forecast for a city',
+ inputSchema: {
+ type: 'object',
+ properties: {
+ city: { type: 'string', description: 'City name' },
+ days: { type: 'number', description: 'Days (1-7)', minimum: 1, maximum: 7 },
+ },
+ required: ['city'],
+ },
+ },
+ {
+ name: 'get-weather-alerts',
+ description: 'Get weather alerts for a region',
+ inputSchema: {
+ type: 'object',
+ properties: { region: { type: 'string', description: 'Region name' } },
+ required: ['region'],
+ },
+ },
+];
+
+async function startServer() {
+ const app = express();
+
+ app.use(cors({ origin: true, credentials: true }));
+ app.use(bodyParser.json());
+
+ // Health check
+ app.get('/health', (_req: Request, res: Response) => {
+ res.json({ status: 'healthy', timestamp: new Date().toISOString() });
+ });
+
+ // MCP endpoint
+ app.all('/mcp', async (req: Request, res: Response) => {
+ const { method, params, id } = req.body || {};
+ let response: any;
+
+ switch (method) {
+ case 'initialize':
+ response = {
+ jsonrpc: '2.0',
+ result: {
+ protocolVersion: params?.protocolVersion || '2024-11-05',
+ capabilities: { tools: {} },
+ serverInfo: { name: SERVER_NAME, version: SERVER_VERSION },
+ },
+ id,
+ };
+ break;
+
+ case 'tools/list':
+ response = { jsonrpc: '2.0', result: { tools: TOOLS }, id };
+ break;
+
+ case 'tools/call':
+ try {
+ const toolName = params?.name;
+ let result: any;
+
+ switch (toolName) {
+ case 'get-weather':
+ result = await getWeather.handler(req.body);
+ break;
+ case 'get-forecast':
+ result = await getForecast.handler(req.body);
+ break;
+ case 'get-weather-alerts':
+ result = await getAlerts.handler(req.body);
+ break;
+ default:
+ result = {
+ content: [{ type: 'text', text: `Unknown tool: ${toolName}` }],
+ isError: true,
+ };
+ }
+ response = { jsonrpc: '2.0', result, id };
+ } catch (error) {
+ response = {
+ jsonrpc: '2.0',
+ error: { code: -32603, message: error instanceof Error ? error.message : 'Error' },
+ id,
+ };
+ }
+ break;
+
+ default:
+ response = {
+ jsonrpc: '2.0',
+ error: { code: -32601, message: `Method not found: ${method}` },
+ id,
+ };
+ }
+
+ res.json(response);
+ });
+
+ app.listen(SERVER_PORT, '127.0.0.1', () => {
+ console.log(`MCP Server running at ${SERVER_URL}`);
+ console.log(` POST ${SERVER_URL}/mcp`);
+ console.log(` GET ${SERVER_URL}/health`);
+ });
+
+ process.on('SIGINT', () => {
+ console.log('\nShutting down...');
+ process.exit(0);
+ });
+}
+
+startServer().catch(error => {
+ console.error('Failed to start server:', error);
+ process.exit(1);
+});
diff --git a/examples/server3001/src/tools/get-alerts.ts b/examples/server3001/src/tools/get-alerts.ts
new file mode 100644
index 00000000..653d5062
--- /dev/null
+++ b/examples/server3001/src/tools/get-alerts.ts
@@ -0,0 +1,57 @@
+/**
+ * Get weather alerts
+ * Requires mcp:admin scope for severe weather alerts
+ */
+export const getAlerts = {
+ name: 'get-weather-alerts',
+ description: 'Get weather alerts and warnings for a region (requires mcp:admin scope)',
+ inputSchema: {
+ type: 'object',
+ properties: {
+ region: {
+ type: 'string',
+ description: 'Region or city name',
+ },
+ },
+ required: ['region'],
+ },
+ handler: async (request: any) => {
+ const { region } = request.params;
+
+ // Simulate weather alerts
+ const alerts = [
+ {
+ severity: 'moderate',
+ type: 'Heavy Rain',
+ message: 'Heavy rain expected in the next 6 hours',
+ },
+ { severity: 'low', type: 'Wind', message: 'Strong winds possible this evening' },
+ ];
+
+ const hasAlerts = Math.random() > 0.5;
+
+ if (!hasAlerts) {
+ return {
+ content: [
+ {
+ type: 'text',
+ text: `No active weather alerts for ${region}`,
+ },
+ ],
+ };
+ }
+
+ const alertText = alerts
+ .map(alert => `[${alert.severity.toUpperCase()}] ${alert.type}: ${alert.message}`)
+ .join('\n');
+
+ return {
+ content: [
+ {
+ type: 'text',
+ text: `Weather Alerts for ${region}:\n\n${alertText}`,
+ },
+ ],
+ };
+ },
+};
diff --git a/examples/server3001/src/tools/get-forecast.ts b/examples/server3001/src/tools/get-forecast.ts
new file mode 100644
index 00000000..2808e8dc
--- /dev/null
+++ b/examples/server3001/src/tools/get-forecast.ts
@@ -0,0 +1,58 @@
+/**
+ * Get 5-day weather forecast
+ * Requires mcp:read scope
+ */
+export const getForecast = {
+ name: 'get-forecast',
+ description:
+ 'Get 5-day weather forecast for a city (requires authentication with mcp:read scope)',
+ inputSchema: {
+ type: 'object',
+ properties: {
+ city: {
+ type: 'string',
+ description: 'City name',
+ },
+ days: {
+ type: 'number',
+ description: 'Number of days to forecast (1-5)',
+ default: 5,
+ },
+ },
+ required: ['city'],
+ },
+ handler: async (request: any) => {
+ const { city, days = 5 } = request.params;
+
+ // In a real app, you'd check authentication here
+ // For now, just return mock data
+
+ const forecastDays = Math.min(days, 5);
+ const forecast = [];
+
+ for (let i = 0; i < forecastDays; i++) {
+ const date = new Date();
+ date.setDate(date.getDate() + i);
+
+ forecast.push({
+ date: date.toLocaleDateString(),
+ temp_high: Math.floor(Math.random() * 10) + 20,
+ temp_low: Math.floor(Math.random() * 10) + 10,
+ condition: ['Sunny', 'Cloudy', 'Rainy', 'Partly Cloudy'][Math.floor(Math.random() * 4)],
+ });
+ }
+
+ const forecastText = forecast
+ .map(day => `${day.date}: ${day.temp_low}-${day.temp_high}°C, ${day.condition}`)
+ .join('\n');
+
+ return {
+ content: [
+ {
+ type: 'text',
+ text: `${forecastDays}-day forecast for ${city}:\n\n${forecastText}`,
+ },
+ ],
+ };
+ },
+};
diff --git a/examples/server3001/src/tools/get-weather.ts b/examples/server3001/src/tools/get-weather.ts
new file mode 100644
index 00000000..4e1ea376
--- /dev/null
+++ b/examples/server3001/src/tools/get-weather.ts
@@ -0,0 +1,45 @@
+/**
+ * Get current weather for a city
+ * No authentication required - public tool
+ */
+export const getWeather = {
+ name: 'get-weather',
+ description: 'Get current weather information for a specific city',
+ inputSchema: {
+ type: 'object',
+ properties: {
+ city: {
+ type: 'string',
+ description: 'City name (e.g., "London", "New York", "Tokyo")',
+ },
+ },
+ required: ['city'],
+ },
+ handler: async (request: any) => {
+ const { city } = request.params;
+
+ // Simulate weather data (in a real app, you'd call a weather API)
+ const weatherData = {
+ London: { temp: 15, condition: 'Cloudy', humidity: 75 },
+ 'New York': { temp: 22, condition: 'Sunny', humidity: 60 },
+ Tokyo: { temp: 18, condition: 'Rainy', humidity: 80 },
+ Paris: { temp: 17, condition: 'Partly Cloudy', humidity: 70 },
+ Sydney: { temp: 25, condition: 'Sunny', humidity: 55 },
+ };
+
+ const weather = weatherData[city as keyof typeof weatherData] || {
+ temp: Math.floor(Math.random() * 30) + 10,
+ condition: ['Sunny', 'Cloudy', 'Rainy', 'Partly Cloudy'][Math.floor(Math.random() * 4)],
+ humidity: Math.floor(Math.random() * 40) + 50,
+ };
+
+ return {
+ content: [
+ {
+ type: 'text',
+ text: `Weather in ${city}:\nTemperature: ${weather.temp}°C\nCondition: ${weather.condition}\nHumidity: ${weather.humidity}%`,
+ },
+ ],
+ };
+ },
+};
diff --git a/examples/server3001/start-mcp-server.sh b/examples/server3001/start-mcp-server.sh
new file mode 100755
index 00000000..5ac0cf6a
--- /dev/null
+++ b/examples/server3001/start-mcp-server.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# Start MCP Server (Weather Tools)
+
+set -e
+
+DIR_CURR=$(cd "$(dirname "$0")";pwd)
+cd $DIR_CURR
+
+# Stop existing server on port 3001
+lsof -i :3001 | grep LISTEN | awk '{print $2}' | xargs kill -9 2>/dev/null || true
+sleep 1
+
+# Install dependencies if needed
+if [ ! -d "node_modules" ]; then
+ npm install
+fi
+
+echo "🚀 Starting MCP Server on port 3001..."
+echo " 📡 MCP Endpoint: http://127.0.0.1:3001/mcp"
+echo " 💚 Health: http://127.0.0.1:3001/health"
+echo ""
+
+npm run dev
diff --git a/examples/server3001/tsconfig.json b/examples/server3001/tsconfig.json
new file mode 100644
index 00000000..7f748950
--- /dev/null
+++ b/examples/server3001/tsconfig.json
@@ -0,0 +1,21 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "module": "ESNext",
+ "lib": ["ES2022"],
+ "moduleResolution": "node",
+ "outDir": "./dist",
+ "rootDir": "./",
+ "strict": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "resolveJsonModule": true,
+ "declaration": true,
+ "declarationMap": true,
+ "sourceMap": true,
+ "allowSyntheticDefaultImports": true
+ },
+ "include": ["src/**/*", "sdk/src/**/*"],
+ "exclude": ["node_modules", "dist", "src/examples"]
+}
diff --git a/examples/server3002/README.md b/examples/server3002/README.md
new file mode 100644
index 00000000..46fe9266
--- /dev/null
+++ b/examples/server3002/README.md
@@ -0,0 +1,20 @@
+# MCP Server 3002
+
+Simple MCP server with utility tools.
+
+## Tools
+
+- `get-time` - Get current time for a timezone or city
+- `generate-password` - Generate a secure password
+
+## Quick Start
+
+```bash
+npm install
+npm run dev
+```
+
+## Endpoints
+
+- MCP: http://127.0.0.1:3002/mcp
+- Health: http://127.0.0.1:3002/health
diff --git a/examples/server3002/package-lock.json b/examples/server3002/package-lock.json
new file mode 100644
index 00000000..bad6cec4
--- /dev/null
+++ b/examples/server3002/package-lock.json
@@ -0,0 +1,1644 @@
+{
+ "name": "mcp-server-3002",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "mcp-server-3002",
+ "version": "1.0.0",
+ "license": "MIT",
+ "dependencies": {
+ "body-parser": "^2.2.0",
+ "cors": "^2.8.5",
+ "express": "^5.1.0"
+ },
+ "devDependencies": {
+ "@types/cors": "^2.8.19",
+ "@types/express": "^5.0.5",
+ "@types/node": "^20.11.5",
+ "tsx": "^4.7.0",
+ "typescript": "^5.9.3"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "../../mcp-cpp-sdk/sdk/typescript": {
+ "name": "@mcp/filter-sdk",
+ "version": "1.0.0",
+ "extraneous": true,
+ "license": "MIT",
+ "dependencies": {
+ "@modelcontextprotocol/sdk": "^1.20.0",
+ "body-parser": "^1.20.3",
+ "cors": "^2.8.5",
+ "express": "^4.21.0",
+ "jose": "^5.10.0",
+ "koffi": "^2.13.0"
+ },
+ "devDependencies": {
+ "@types/cors": "^2.8.19",
+ "@types/express": "^5.0.4",
+ "@types/jest": "^29.5.14",
+ "@types/node": "^18.19.123",
+ "@typescript-eslint/eslint-plugin": "^6.21.0",
+ "@typescript-eslint/parser": "^6.21.0",
+ "eslint": "^8.0.0",
+ "jest": "^29.0.0",
+ "prettier": "^3.6.2",
+ "ts-jest": "^29.0.0",
+ "tsx": "^4.20.6",
+ "typescript": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=16.0.0 <19.0.0"
+ }
+ },
+ "../gopher-auth-sdk-nodejs": {
+ "version": "1.0.0",
+ "extraneous": true,
+ "license": "MIT",
+ "dependencies": {
+ "axios": "^1.6.5",
+ "express": "^5.1.0",
+ "jose": "^5.2.0"
+ },
+ "devDependencies": {
+ "@types/express": "^5.0.5",
+ "@types/jest": "^29.5.11",
+ "@types/node": "^20.11.5",
+ "@typescript-eslint/eslint-plugin": "^6.19.0",
+ "@typescript-eslint/parser": "^6.19.0",
+ "eslint": "^8.56.0",
+ "jest": "^29.7.0",
+ "prettier": "^3.2.4",
+ "ts-jest": "^29.1.1",
+ "typescript": "^5.3.3"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
+ "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
+ "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
+ "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
+ "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
+ "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
+ "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
+ "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
+ "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
+ "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
+ "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
+ "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
+ "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
+ "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
+ "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
+ "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
+ "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
+ "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
+ "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
+ "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
+ "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
+ "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
+ "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
+ "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@types/body-parser": {
+ "version": "1.19.6",
+ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz",
+ "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/connect": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/connect": {
+ "version": "3.4.38",
+ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
+ "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/cors": {
+ "version": "2.8.19",
+ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz",
+ "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/express": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.5.tgz",
+ "integrity": "sha512-LuIQOcb6UmnF7C1PCFmEU1u2hmiHL43fgFQX67sN3H4Z+0Yk0Neo++mFsBjhOAuLzvlQeqAAkeDOZrJs9rzumQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/body-parser": "*",
+ "@types/express-serve-static-core": "^5.0.0",
+ "@types/serve-static": "^1"
+ }
+ },
+ "node_modules/@types/express-serve-static-core": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.0.tgz",
+ "integrity": "sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*",
+ "@types/qs": "*",
+ "@types/range-parser": "*",
+ "@types/send": "*"
+ }
+ },
+ "node_modules/@types/http-errors": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz",
+ "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/mime": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
+ "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/node": {
+ "version": "20.19.24",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.24.tgz",
+ "integrity": "sha512-FE5u0ezmi6y9OZEzlJfg37mqqf6ZDSF2V/NLjUyGrR9uTZ7Sb9F7bLNZ03S4XVUNRWGA7Ck4c1kK+YnuWjl+DA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.21.0"
+ }
+ },
+ "node_modules/@types/qs": {
+ "version": "6.14.0",
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz",
+ "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/range-parser": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
+ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/send": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz",
+ "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/serve-static": {
+ "version": "1.15.10",
+ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz",
+ "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/http-errors": "*",
+ "@types/node": "*",
+ "@types/send": "<1"
+ }
+ },
+ "node_modules/@types/serve-static/node_modules/@types/send": {
+ "version": "0.17.6",
+ "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz",
+ "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/mime": "^1",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/accepts": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
+ "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-types": "^3.0.0",
+ "negotiator": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/body-parser": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
+ "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "^3.1.2",
+ "content-type": "^1.0.5",
+ "debug": "^4.4.0",
+ "http-errors": "^2.0.0",
+ "iconv-lite": "^0.6.3",
+ "on-finished": "^2.4.1",
+ "qs": "^6.14.0",
+ "raw-body": "^3.0.0",
+ "type-is": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/body-parser/node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/call-bound": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/content-disposition": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz",
+ "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "5.2.1"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
+ "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.6.0"
+ }
+ },
+ "node_modules/cors": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+ "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+ "license": "MIT",
+ "dependencies": {
+ "object-assign": "^4",
+ "vary": "^1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+ "license": "MIT"
+ },
+ "node_modules/encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-object-atoms": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+ "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
+ "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.25.12",
+ "@esbuild/android-arm": "0.25.12",
+ "@esbuild/android-arm64": "0.25.12",
+ "@esbuild/android-x64": "0.25.12",
+ "@esbuild/darwin-arm64": "0.25.12",
+ "@esbuild/darwin-x64": "0.25.12",
+ "@esbuild/freebsd-arm64": "0.25.12",
+ "@esbuild/freebsd-x64": "0.25.12",
+ "@esbuild/linux-arm": "0.25.12",
+ "@esbuild/linux-arm64": "0.25.12",
+ "@esbuild/linux-ia32": "0.25.12",
+ "@esbuild/linux-loong64": "0.25.12",
+ "@esbuild/linux-mips64el": "0.25.12",
+ "@esbuild/linux-ppc64": "0.25.12",
+ "@esbuild/linux-riscv64": "0.25.12",
+ "@esbuild/linux-s390x": "0.25.12",
+ "@esbuild/linux-x64": "0.25.12",
+ "@esbuild/netbsd-arm64": "0.25.12",
+ "@esbuild/netbsd-x64": "0.25.12",
+ "@esbuild/openbsd-arm64": "0.25.12",
+ "@esbuild/openbsd-x64": "0.25.12",
+ "@esbuild/openharmony-arm64": "0.25.12",
+ "@esbuild/sunos-x64": "0.25.12",
+ "@esbuild/win32-arm64": "0.25.12",
+ "@esbuild/win32-ia32": "0.25.12",
+ "@esbuild/win32-x64": "0.25.12"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+ "license": "MIT"
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/express": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
+ "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
+ "license": "MIT",
+ "dependencies": {
+ "accepts": "^2.0.0",
+ "body-parser": "^2.2.0",
+ "content-disposition": "^1.0.0",
+ "content-type": "^1.0.5",
+ "cookie": "^0.7.1",
+ "cookie-signature": "^1.2.1",
+ "debug": "^4.4.0",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "finalhandler": "^2.1.0",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.0",
+ "merge-descriptors": "^2.0.0",
+ "mime-types": "^3.0.0",
+ "on-finished": "^2.4.1",
+ "once": "^1.4.0",
+ "parseurl": "^1.3.3",
+ "proxy-addr": "^2.0.7",
+ "qs": "^6.14.0",
+ "range-parser": "^1.2.1",
+ "router": "^2.2.0",
+ "send": "^1.1.0",
+ "serve-static": "^2.2.0",
+ "statuses": "^2.0.1",
+ "type-is": "^2.0.1",
+ "vary": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz",
+ "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.0",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "on-finished": "^2.4.1",
+ "parseurl": "^1.3.3",
+ "statuses": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
+ "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/get-tsconfig": {
+ "version": "4.13.0",
+ "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz",
+ "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "resolve-pkg-maps": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "license": "MIT",
+ "dependencies": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
+ "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "license": "ISC"
+ },
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/is-promise": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
+ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
+ "license": "MIT"
+ },
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/media-typer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
+ "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
+ "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
+ "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "^1.54.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT"
+ },
+ "node_modules/negotiator": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
+ "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/path-to-regexp": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz",
+ "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "license": "MIT",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.14.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
+ "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz",
+ "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.7.0",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/resolve-pkg-maps": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
+ "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
+ }
+ },
+ "node_modules/router": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
+ "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.0",
+ "depd": "^2.0.0",
+ "is-promise": "^4.0.0",
+ "parseurl": "^1.3.3",
+ "path-to-regexp": "^8.0.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "license": "MIT"
+ },
+ "node_modules/send": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
+ "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.3.5",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.0",
+ "mime-types": "^3.0.1",
+ "ms": "^2.1.3",
+ "on-finished": "^2.4.1",
+ "range-parser": "^1.2.1",
+ "statuses": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/serve-static": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
+ "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==",
+ "license": "MIT",
+ "dependencies": {
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "parseurl": "^1.3.3",
+ "send": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+ "license": "ISC"
+ },
+ "node_modules/side-channel": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+ "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3",
+ "side-channel-list": "^1.0.0",
+ "side-channel-map": "^1.0.1",
+ "side-channel-weakmap": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-list": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
+ "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-weakmap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3",
+ "side-channel-map": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/tsx": {
+ "version": "4.20.6",
+ "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz",
+ "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "~0.25.0",
+ "get-tsconfig": "^4.7.5"
+ },
+ "bin": {
+ "tsx": "dist/cli.mjs"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ }
+ },
+ "node_modules/type-is": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
+ "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
+ "license": "MIT",
+ "dependencies": {
+ "content-type": "^1.0.5",
+ "media-typer": "^1.1.0",
+ "mime-types": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
+ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "license": "ISC"
+ },
+ "sdk": {
+ "name": "@mcp/filter-sdk",
+ "version": "1.0.0",
+ "extraneous": true,
+ "license": "MIT",
+ "dependencies": {
+ "@modelcontextprotocol/sdk": "^1.20.0",
+ "body-parser": "^1.20.3",
+ "cors": "^2.8.5",
+ "express": "^4.21.0",
+ "jose": "^5.10.0",
+ "koffi": "^2.13.0"
+ },
+ "devDependencies": {
+ "@types/cors": "^2.8.19",
+ "@types/express": "^5.0.4",
+ "@types/jest": "^29.5.14",
+ "@types/node": "^18.19.123",
+ "@typescript-eslint/eslint-plugin": "^6.21.0",
+ "@typescript-eslint/parser": "^6.21.0",
+ "eslint": "^8.0.0",
+ "jest": "^29.0.0",
+ "prettier": "^3.6.2",
+ "ts-jest": "^29.0.0",
+ "tsx": "^4.20.6",
+ "typescript": "^5.9.3"
+ },
+ "engines": {
+ "node": ">=16.0.0 <19.0.0"
+ }
+ }
+ }
+}
diff --git a/examples/server3002/package.json b/examples/server3002/package.json
new file mode 100644
index 00000000..ef13ccff
--- /dev/null
+++ b/examples/server3002/package.json
@@ -0,0 +1,35 @@
+{
+ "name": "mcp-server-3002",
+ "version": "1.0.0",
+ "description": "Simple MCP server (time and password tools)",
+ "main": "dist/index.js",
+ "type": "module",
+ "scripts": {
+ "build": "tsc",
+ "dev": "tsx src/index.ts",
+ "start": "node dist/src/index.js",
+ "lint": "eslint src --ext .ts",
+ "format": "prettier --write \"src/**/*.ts\""
+ },
+ "keywords": [
+ "mcp",
+ "model-context-protocol"
+ ],
+ "author": "",
+ "license": "MIT",
+ "dependencies": {
+ "body-parser": "^2.2.0",
+ "cors": "^2.8.5",
+ "express": "^5.1.0"
+ },
+ "devDependencies": {
+ "@types/cors": "^2.8.19",
+ "@types/express": "^5.0.5",
+ "@types/node": "^20.11.5",
+ "tsx": "^4.7.0",
+ "typescript": "^5.9.3"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+}
diff --git a/examples/server3002/src/index.ts b/examples/server3002/src/index.ts
new file mode 100644
index 00000000..31ec8b2e
--- /dev/null
+++ b/examples/server3002/src/index.ts
@@ -0,0 +1,138 @@
+#!/usr/bin/env node
+
+/**
+ * Simple MCP Server (No Authentication)
+ */
+
+import express, { Request, Response } from 'express';
+import cors from 'cors';
+import bodyParser from 'body-parser';
+
+import { getTime } from './tools/get-time.js';
+import { generatePassword } from './tools/generate-password.js';
+
+const SERVER_PORT = parseInt(process.env.SERVER_PORT || '3002', 10);
+const SERVER_URL = process.env.SERVER_URL || `http://127.0.0.1:${SERVER_PORT}`;
+const SERVER_NAME = process.env.SERVER_NAME || 'mcp-server-3002';
+const SERVER_VERSION = process.env.SERVER_VERSION || '1.0.0';
+
+const TOOLS = [
+ {
+ name: 'get-time',
+ description: 'Get current time for a timezone or city',
+ inputSchema: {
+ type: 'object',
+ properties: {
+ location: {
+ type: 'string',
+ description: 'Timezone (e.g., "UTC", "America/New_York") or city name',
+ },
+ },
+ required: ['location'],
+ },
+ },
+ {
+ name: 'generate-password',
+ description: 'Generate a secure password',
+ inputSchema: {
+ type: 'object',
+ properties: {
+ length: { type: 'number', description: 'Length (8-128)', minimum: 8, maximum: 128 },
+ includeUppercase: { type: 'boolean', description: 'Include A-Z' },
+ includeLowercase: { type: 'boolean', description: 'Include a-z' },
+ includeNumbers: { type: 'boolean', description: 'Include 0-9' },
+ includeSymbols: { type: 'boolean', description: 'Include symbols' },
+ },
+ required: [],
+ },
+ },
+];
+
+async function startServer() {
+ const app = express();
+
+ app.use(cors({ origin: true, credentials: true }));
+ app.use(bodyParser.json());
+
+ // Health check
+ app.get('/health', (_req: Request, res: Response) => {
+ res.json({ status: 'healthy', timestamp: new Date().toISOString() });
+ });
+
+ // MCP endpoint
+ app.all('/mcp', async (req: Request, res: Response) => {
+ const { method, params, id } = req.body || {};
+ let response: any;
+
+ switch (method) {
+ case 'initialize':
+ response = {
+ jsonrpc: '2.0',
+ result: {
+ protocolVersion: params?.protocolVersion || '2024-11-05',
+ capabilities: { tools: {} },
+ serverInfo: { name: SERVER_NAME, version: SERVER_VERSION },
+ },
+ id,
+ };
+ break;
+
+ case 'tools/list':
+ response = { jsonrpc: '2.0', result: { tools: TOOLS }, id };
+ break;
+
+ case 'tools/call':
+ try {
+ const toolName = params?.name;
+ let result: any;
+
+ switch (toolName) {
+ case 'get-time':
+ result = await getTime.handler(req.body);
+ break;
+ case 'generate-password':
+ result = await generatePassword.handler(req.body);
+ break;
+ default:
+ result = {
+ content: [{ type: 'text', text: `Unknown tool: ${toolName}` }],
+ isError: true,
+ };
+ }
+ response = { jsonrpc: '2.0', result, id };
+ } catch (error) {
+ response = {
+ jsonrpc: '2.0',
+ error: { code: -32603, message: error instanceof Error ? error.message : 'Error' },
+ id,
+ };
+ }
+ break;
+
+ default:
+ response = {
+ jsonrpc: '2.0',
+ error: { code: -32601, message: `Method not found: ${method}` },
+ id,
+ };
+ }
+
+ res.json(response);
+ });
+
+ app.listen(SERVER_PORT, '127.0.0.1', () => {
+ console.log(`MCP Server running at ${SERVER_URL}`);
+ console.log(` POST ${SERVER_URL}/mcp`);
+ console.log(` GET ${SERVER_URL}/health`);
+ });
+
+ process.on('SIGINT', () => {
+ console.log('\nShutting down...');
+ process.exit(0);
+ });
+}
+
+startServer().catch(error => {
+ console.error('Failed to start server:', error);
+ process.exit(1);
+});
diff --git a/examples/server3002/src/tools/generate-password.ts b/examples/server3002/src/tools/generate-password.ts
new file mode 100644
index 00000000..5315b081
--- /dev/null
+++ b/examples/server3002/src/tools/generate-password.ts
@@ -0,0 +1,196 @@
+/**
+ * Generate a secure password with customizable options
+ * No authentication required - public tool
+ */
+export const generatePassword = {
+ name: 'generate-password',
+ description: 'Generate a secure password with customizable length and character sets',
+ inputSchema: {
+ type: 'object',
+ properties: {
+ length: {
+ type: 'number',
+ description: 'Length of the password (8-128 characters)',
+ minimum: 8,
+ maximum: 128,
+ default: 16,
+ },
+ includeUppercase: {
+ type: 'boolean',
+ description: 'Include uppercase letters (A-Z)',
+ default: true,
+ },
+ includeLowercase: {
+ type: 'boolean',
+ description: 'Include lowercase letters (a-z)',
+ default: true,
+ },
+ includeNumbers: {
+ type: 'boolean',
+ description: 'Include numbers (0-9)',
+ default: true,
+ },
+ includeSymbols: {
+ type: 'boolean',
+ description: 'Include symbols (!@#$%^&*)',
+ default: true,
+ },
+ excludeSimilar: {
+ type: 'boolean',
+ description: 'Exclude similar looking characters (0,O,l,1,I)',
+ default: false,
+ },
+ },
+ required: [],
+ },
+ handler: async (request: any) => {
+ // Handle different parameter structures
+ let params = {};
+
+ if (request.params?.arguments) {
+ if (typeof request.params.arguments === 'string') {
+ // Gopher-orch sends arguments as JSON string
+ try {
+ params = JSON.parse(request.params.arguments);
+ } catch (e) {
+ params = {};
+ }
+ } else {
+ // Direct calls send arguments as object
+ params = request.params.arguments;
+ }
+ } else {
+ // Fallback to direct params
+ params = request.params || {};
+ }
+
+ const {
+ length = 16,
+ includeUppercase = true,
+ includeLowercase = true,
+ includeNumbers = true,
+ includeSymbols = true,
+ excludeSimilar = false,
+ } = params;
+
+ // Validate length
+ if (length < 8 || length > 128) {
+ return {
+ content: [
+ {
+ type: 'text',
+ text: 'Error: Password length must be between 8 and 128 characters.',
+ },
+ ],
+ isError: true,
+ };
+ }
+
+ // Character sets
+ let uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
+ let lowercase = 'abcdefghijklmnopqrstuvwxyz';
+ let numbers = '0123456789';
+ let symbols = '!@#$%^&*()_+-=[]{}|;:,.<>?';
+
+ // Exclude similar characters if requested
+ if (excludeSimilar) {
+ uppercase = uppercase.replace(/[O]/g, '');
+ lowercase = lowercase.replace(/[l]/g, '');
+ numbers = numbers.replace(/[01]/g, '');
+ symbols = symbols.replace(/[|]/g, '');
+ }
+
+ // Build character pool
+ let charPool = '';
+ let requiredChars: string[] = [];
+
+ if (includeUppercase) {
+ charPool += uppercase;
+ requiredChars.push(uppercase[Math.floor(Math.random() * uppercase.length)]);
+ }
+ if (includeLowercase) {
+ charPool += lowercase;
+ requiredChars.push(lowercase[Math.floor(Math.random() * lowercase.length)]);
+ }
+ if (includeNumbers) {
+ charPool += numbers;
+ requiredChars.push(numbers[Math.floor(Math.random() * numbers.length)]);
+ }
+ if (includeSymbols) {
+ charPool += symbols;
+ requiredChars.push(symbols[Math.floor(Math.random() * symbols.length)]);
+ }
+
+ // Ensure at least one character set is selected
+ if (charPool.length === 0) {
+ return {
+ content: [
+ {
+ type: 'text',
+ text: 'Error: At least one character set must be included.',
+ },
+ ],
+ isError: true,
+ };
+ }
+
+ // Generate password
+ let password = '';
+
+ // First, add required characters to ensure all selected types are present
+ for (const char of requiredChars) {
+ password += char;
+ }
+
+ // Fill the rest with random characters
+ for (let i = password.length; i < length; i++) {
+ password += charPool[Math.floor(Math.random() * charPool.length)];
+ }
+
+ // Shuffle the password to randomize the position of required characters
+ password = password
+ .split('')
+ .sort(() => Math.random() - 0.5)
+ .join('');
+
+ // Calculate password strength
+ let strength = 0;
+ let strengthText = '';
+
+ if (includeUppercase) strength += 26;
+ if (includeLowercase) strength += 26;
+ if (includeNumbers) strength += 10;
+ if (includeSymbols) strength += symbols.length;
+
+ const entropy = Math.log2(Math.pow(strength, length));
+
+ if (entropy < 40) {
+ strengthText = 'Weak';
+ } else if (entropy < 60) {
+ strengthText = 'Fair';
+ } else if (entropy < 80) {
+ strengthText = 'Good';
+ } else if (entropy < 100) {
+ strengthText = 'Strong';
+ } else {
+ strengthText = 'Very Strong';
+ }
+
+ // Build settings summary
+ const settings: string[] = [];
+ if (includeUppercase) settings.push('Uppercase');
+ if (includeLowercase) settings.push('Lowercase');
+ if (includeNumbers) settings.push('Numbers');
+ if (includeSymbols) settings.push('Symbols');
+ if (excludeSimilar) settings.push('No Similar Chars');
+
+ return {
+ content: [
+ {
+ type: 'text',
+ text: `Generated Password:\n\n🔐 ${password}\n\nSettings:\n• Length: ${length} characters\n• Character types: ${settings.join(', ')}\n• Strength: ${strengthText}\n• Entropy: ${entropy.toFixed(1)} bits\n\n💡 Tip: Store this password securely and don't reuse it for multiple accounts.`,
+ },
+ ],
+ };
+ },
+};
diff --git a/examples/server3002/src/tools/get-time.ts b/examples/server3002/src/tools/get-time.ts
new file mode 100644
index 00000000..160e16bf
--- /dev/null
+++ b/examples/server3002/src/tools/get-time.ts
@@ -0,0 +1,130 @@
+/**
+ * Get current time for a timezone or location
+ * No authentication required - public tool
+ */
+export const getTime = {
+ name: 'get-time',
+ description: 'Get current time and date for a specific timezone or city',
+ inputSchema: {
+ type: 'object',
+ properties: {
+ location: {
+ type: 'string',
+ description:
+ 'Timezone (e.g., "UTC", "America/New_York") or city name (e.g., "London", "Tokyo")',
+ },
+ },
+ required: ['location'],
+ },
+ handler: async (request: any) => {
+ // Handle different parameter structures
+ let location;
+
+ if (request.params?.arguments) {
+ if (typeof request.params.arguments === 'string') {
+ // Gopher-orch sends arguments as JSON string
+ try {
+ const parsedArgs = JSON.parse(request.params.arguments);
+ location = parsedArgs.location;
+ } catch (e) {
+ location = undefined;
+ }
+ } else {
+ // Direct calls send arguments as object
+ location = request.params.arguments.location;
+ }
+ } else {
+ // Fallback to direct params
+ location = request.params?.location;
+ }
+
+ if (!location) {
+ return {
+ content: [
+ {
+ type: 'text',
+ text: 'Error: No location parameter provided',
+ },
+ ],
+ isError: true,
+ };
+ }
+
+ // Map common city names to timezones
+ const cityToTimezone: { [key: string]: string } = {
+ london: 'Europe/London',
+ 'new york': 'America/New_York',
+ tokyo: 'Asia/Tokyo',
+ paris: 'Europe/Paris',
+ france: 'Europe/Paris',
+ sydney: 'Australia/Sydney',
+ 'los angeles': 'America/Los_Angeles',
+ chicago: 'America/Chicago',
+ dubai: 'Asia/Dubai',
+ singapore: 'Asia/Singapore',
+ mumbai: 'Asia/Kolkata',
+ beijing: 'Asia/Shanghai',
+ moscow: 'Europe/Moscow',
+ berlin: 'Europe/Berlin',
+ toronto: 'America/Toronto',
+ };
+
+ // Determine timezone
+ let timezone = location;
+ const normalizedLocation = location.toLowerCase();
+
+ if (cityToTimezone[normalizedLocation]) {
+ timezone = cityToTimezone[normalizedLocation];
+ }
+
+ try {
+ // Get current time in specified timezone
+ const now = new Date();
+ const timeInTimezone = now.toLocaleString('en-US', {
+ timeZone: timezone,
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric',
+ hour: '2-digit',
+ minute: '2-digit',
+ second: '2-digit',
+ timeZoneName: 'short',
+ });
+
+ const dateOnly = now.toLocaleDateString('en-US', {
+ timeZone: timezone,
+ weekday: 'long',
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric',
+ });
+
+ const timeOnly = now.toLocaleTimeString('en-US', {
+ timeZone: timezone,
+ hour: '2-digit',
+ minute: '2-digit',
+ second: '2-digit',
+ timeZoneName: 'short',
+ });
+
+ return {
+ content: [
+ {
+ type: 'text',
+ text: `Current time in ${location}:\n\nFull Date & Time: ${timeInTimezone}\nDate: ${dateOnly}\nTime: ${timeOnly}\nTimezone: ${timezone}`,
+ },
+ ],
+ };
+ } catch (error) {
+ return {
+ content: [
+ {
+ type: 'text',
+ text: `Error: Invalid timezone or location "${location}". Please use a valid timezone (e.g., "UTC", "America/New_York") or city name (e.g., "London", "Tokyo").`,
+ },
+ ],
+ isError: true,
+ };
+ }
+ },
+};
diff --git a/examples/server3002/start-mcp-server.sh b/examples/server3002/start-mcp-server.sh
new file mode 100755
index 00000000..3e00f8ad
--- /dev/null
+++ b/examples/server3002/start-mcp-server.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# Start MCP Server (Time & Password Tools)
+
+set -e
+
+DIR_CURR=$(cd "$(dirname "$0")";pwd)
+cd $DIR_CURR
+
+# Stop existing server on port 3002
+lsof -i :3002 | grep LISTEN | awk '{print $2}' | xargs kill -9 2>/dev/null || true
+sleep 1
+
+# Install dependencies if needed
+if [ ! -d "node_modules" ]; then
+ npm install
+fi
+
+echo "🚀 Starting MCP Server on port 3002..."
+echo " 📡 MCP Endpoint: http://127.0.0.1:3002/mcp"
+echo " 💚 Health: http://127.0.0.1:3002/health"
+echo ""
+
+npm run dev
diff --git a/examples/server3002/tsconfig.json b/examples/server3002/tsconfig.json
new file mode 100644
index 00000000..7f748950
--- /dev/null
+++ b/examples/server3002/tsconfig.json
@@ -0,0 +1,21 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "module": "ESNext",
+ "lib": ["ES2022"],
+ "moduleResolution": "node",
+ "outDir": "./dist",
+ "rootDir": "./",
+ "strict": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "resolveJsonModule": true,
+ "declaration": true,
+ "declarationMap": true,
+ "sourceMap": true,
+ "allowSyntheticDefaultImports": true
+ },
+ "include": ["src/**/*", "sdk/src/**/*"],
+ "exclude": ["node_modules", "dist", "src/examples"]
+}
diff --git a/include/orch/core/hello.h b/include/orch/core/hello.h
deleted file mode 100644
index 48c6cdc7..00000000
--- a/include/orch/core/hello.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#pragma once
-
-#include
-#include
-
-namespace gopher {
-namespace orch {
-namespace core {
-
-// Hello class demonstrates basic gopher-orch functionality
-// This is a simple example to verify the build system works correctly
-class Hello {
- public:
- Hello();
- explicit Hello(const std::string& name);
- ~Hello();
-
- std::string greet() const;
- std::string greet_with_prefix(const std::string& prefix) const;
-
- void set_name(const std::string& name);
- const std::string& get_name() const;
-
- static std::string get_version();
-
- private:
- class Impl;
- std::unique_ptr impl_;
-};
-
-// Builder pattern for Hello class construction
-class HelloBuilder {
- public:
- HelloBuilder& with_name(const std::string& name);
- HelloBuilder& with_greeting_style(const std::string& style);
-
- std::unique_ptr build() const;
-
- private:
- std::string name_ = "World";
- std::string style_ = "default";
-};
-
-} // namespace core
-} // namespace orch
-} // namespace gopher
diff --git a/include/orch/core/version.h b/include/orch/core/version.h
deleted file mode 100644
index d86166e9..00000000
--- a/include/orch/core/version.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#pragma once
-
-#define GOPHER_ORCH_VERSION_MAJOR 0
-#define GOPHER_ORCH_VERSION_MINOR 1
-#define GOPHER_ORCH_VERSION_PATCH 0
-
-#define GOPHER_ORCH_VERSION_STRING "0.1.0"
-
-namespace gopher {
-namespace orch {
-namespace core {
-
-struct Version {
- static constexpr int major() { return GOPHER_ORCH_VERSION_MAJOR; }
- static constexpr int minor() { return GOPHER_ORCH_VERSION_MINOR; }
- static constexpr int patch() { return GOPHER_ORCH_VERSION_PATCH; }
- static const char* string() { return GOPHER_ORCH_VERSION_STRING; }
-};
-
-} // namespace core
-} // namespace orch
-} // namespace gopher
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
deleted file mode 100644
index 709369ef..00000000
--- a/src/CMakeLists.txt
+++ /dev/null
@@ -1,103 +0,0 @@
-# gopher-orch source files
-
-# Core library sources (orch-specific extensions)
-set(ORCH_CORE_SOURCES
- orch/hello.cpp
-)
-
-# Combine all sources
-set(GOPHER_ORCH_SOURCES
- ${ORCH_CORE_SOURCES}
-)
-
-# Build static library
-if(BUILD_STATIC_LIBS)
- add_library(gopher-orch-static STATIC ${GOPHER_ORCH_SOURCES})
- target_include_directories(gopher-orch-static PUBLIC
- $
- $
- $
- )
-
- # Link dependencies
- if(NOT BUILD_WITHOUT_GOPHER_MCP)
- target_link_libraries(gopher-orch-static PUBLIC
- ${GOPHER_MCP_LIBRARIES}
- Threads::Threads
- )
- else()
- target_link_libraries(gopher-orch-static PUBLIC
- Threads::Threads
- )
- endif()
-
- set_target_properties(gopher-orch-static PROPERTIES
- OUTPUT_NAME gopher-orch
- POSITION_INDEPENDENT_CODE ON
- )
-
- # Set the main library alias
- add_library(gopher-orch ALIAS gopher-orch-static)
-
- # Installation
- install(TARGETS gopher-orch-static
- EXPORT gopher-orch-targets
- LIBRARY DESTINATION lib
- ARCHIVE DESTINATION lib
- RUNTIME DESTINATION bin
- COMPONENT libraries
- )
-endif()
-
-# Build shared library
-if(BUILD_SHARED_LIBS)
- add_library(gopher-orch-shared SHARED ${GOPHER_ORCH_SOURCES})
- target_include_directories(gopher-orch-shared PUBLIC
- $
- $
- $
- )
-
- # Link dependencies
- if(NOT BUILD_WITHOUT_GOPHER_MCP)
- target_link_libraries(gopher-orch-shared PUBLIC
- ${GOPHER_MCP_LIBRARIES}
- Threads::Threads
- )
- else()
- target_link_libraries(gopher-orch-shared PUBLIC
- Threads::Threads
- )
- endif()
-
- set_target_properties(gopher-orch-shared PROPERTIES
- OUTPUT_NAME gopher-orch
- VERSION ${PROJECT_VERSION}
- SOVERSION ${PROJECT_VERSION_MAJOR}
- )
-
- # If only building shared, set it as the main library
- if(NOT BUILD_STATIC_LIBS)
- add_library(gopher-orch ALIAS gopher-orch-shared)
- endif()
-
- # Installation
- install(TARGETS gopher-orch-shared
- EXPORT gopher-orch-targets
- LIBRARY DESTINATION lib
- ARCHIVE DESTINATION lib
- RUNTIME DESTINATION bin
- COMPONENT libraries
- )
-endif()
-
-# Export targets only when not using submodule
-# (When using submodule, gopher-mcp targets aren't installable)
-if(NOT USE_SUBMODULE_GOPHER_MCP)
- install(EXPORT gopher-orch-targets
- FILE gopher-orch-targets.cmake
- NAMESPACE gopher-orch::
- DESTINATION lib/cmake/gopher-orch
- COMPONENT development
- )
-endif()
diff --git a/src/GopherOrch/AgentResult.cs b/src/GopherOrch/AgentResult.cs
new file mode 100644
index 00000000..e96c9215
--- /dev/null
+++ b/src/GopherOrch/AgentResult.cs
@@ -0,0 +1,129 @@
+using System;
+
+namespace GopherOrch
+{
+ ///
+ /// Result from agent query execution.
+ ///
+ public sealed class AgentResult
+ {
+ ///
+ /// The response from the agent.
+ ///
+ public string Response { get; }
+
+ ///
+ /// The status of the query execution.
+ ///
+ public AgentResultStatus Status { get; }
+
+ ///
+ /// Number of iterations performed.
+ ///
+ public int? IterationCount { get; }
+
+ ///
+ /// Number of tokens used.
+ ///
+ public int? TokensUsed { get; }
+
+ private AgentResult(string response, AgentResultStatus status, int? iterationCount, int? tokensUsed)
+ {
+ Response = response ?? throw new ArgumentNullException(nameof(response));
+ Status = status;
+ IterationCount = iterationCount;
+ TokensUsed = tokensUsed;
+ }
+
+ ///
+ /// Check if the query was successful.
+ ///
+ public bool IsSuccess => Status == AgentResultStatus.Success;
+
+ ///
+ /// Create a new builder for AgentResult.
+ ///
+ public static Builder CreateBuilder() => new Builder();
+
+ ///
+ /// Create a success result.
+ ///
+ public static AgentResult Success(string response)
+ {
+ return CreateBuilder()
+ .WithResponse(response)
+ .WithStatus(AgentResultStatus.Success)
+ .Build();
+ }
+
+ ///
+ /// Create an error result.
+ ///
+ public static AgentResult Error(string message)
+ {
+ return CreateBuilder()
+ .WithResponse(message)
+ .WithStatus(AgentResultStatus.Error)
+ .Build();
+ }
+
+ ///
+ /// Create a timeout result.
+ ///
+ public static AgentResult Timeout(string message)
+ {
+ return CreateBuilder()
+ .WithResponse(message)
+ .WithStatus(AgentResultStatus.Timeout)
+ .Build();
+ }
+
+ public override string ToString()
+ {
+ return $"AgentResult{{Response='{Response}', Status={Status}, IterationCount={IterationCount}, TokensUsed={TokensUsed}}}";
+ }
+
+ ///
+ /// Builder for AgentResult.
+ ///
+ public sealed class Builder
+ {
+ private string? _response;
+ private AgentResultStatus _status;
+ private int? _iterationCount;
+ private int? _tokensUsed;
+
+ public Builder WithResponse(string response)
+ {
+ _response = response;
+ return this;
+ }
+
+ public Builder WithStatus(AgentResultStatus status)
+ {
+ _status = status;
+ return this;
+ }
+
+ public Builder WithIterationCount(int? iterationCount)
+ {
+ _iterationCount = iterationCount;
+ return this;
+ }
+
+ public Builder WithTokensUsed(int? tokensUsed)
+ {
+ _tokensUsed = tokensUsed;
+ return this;
+ }
+
+ public AgentResult Build()
+ {
+ if (_response == null)
+ throw new InvalidOperationException("Response is required");
+
+ return new AgentResult(_response, _status, _iterationCount, _tokensUsed);
+ }
+ }
+ }
+}
diff --git a/src/GopherOrch/AgentResultStatus.cs b/src/GopherOrch/AgentResultStatus.cs
new file mode 100644
index 00000000..0f69648a
--- /dev/null
+++ b/src/GopherOrch/AgentResultStatus.cs
@@ -0,0 +1,23 @@
+namespace GopherOrch
+{
+ ///
+ /// Status of agent query execution.
+ ///
+ public enum AgentResultStatus
+ {
+ ///
+ /// Query completed successfully.
+ ///
+ Success,
+
+ ///
+ /// Query failed with an error.
+ ///
+ Error,
+
+ ///
+ /// Query timed out.
+ ///
+ Timeout
+ }
+}
diff --git a/src/GopherOrch/Errors/AgentException.cs b/src/GopherOrch/Errors/AgentException.cs
new file mode 100644
index 00000000..ed7e5915
--- /dev/null
+++ b/src/GopherOrch/Errors/AgentException.cs
@@ -0,0 +1,35 @@
+using System;
+
+namespace GopherOrch.Errors
+{
+ ///
+ /// Base exception class for agent operations.
+ ///
+ public class AgentException : Exception
+ {
+ ///
+ /// Error code from the native library.
+ ///
+ public string? Code { get; }
+
+ public AgentException(string message) : base(message)
+ {
+ Code = null;
+ }
+
+ public AgentException(string message, string? code) : base(message)
+ {
+ Code = code;
+ }
+
+ public AgentException(string message, Exception innerException) : base(message, innerException)
+ {
+ Code = null;
+ }
+
+ public AgentException(string message, string? code, Exception innerException) : base(message, innerException)
+ {
+ Code = code;
+ }
+ }
+}
diff --git a/src/GopherOrch/Errors/ApiKeyException.cs b/src/GopherOrch/Errors/ApiKeyException.cs
new file mode 100644
index 00000000..85a61873
--- /dev/null
+++ b/src/GopherOrch/Errors/ApiKeyException.cs
@@ -0,0 +1,16 @@
+namespace GopherOrch.Errors
+{
+ ///
+ /// Exception for API key related errors.
+ ///
+ public class ApiKeyException : AgentException
+ {
+ public ApiKeyException(string message) : base(message, "API_KEY_ERROR")
+ {
+ }
+
+ public ApiKeyException(string message, string? code) : base(message, code)
+ {
+ }
+ }
+}
diff --git a/src/GopherOrch/Errors/ConnectionException.cs b/src/GopherOrch/Errors/ConnectionException.cs
new file mode 100644
index 00000000..6f5c722c
--- /dev/null
+++ b/src/GopherOrch/Errors/ConnectionException.cs
@@ -0,0 +1,16 @@
+namespace GopherOrch.Errors
+{
+ ///
+ /// Exception for connection related errors.
+ ///
+ public class ConnectionException : AgentException
+ {
+ public ConnectionException(string message) : base(message, "CONNECTION_ERROR")
+ {
+ }
+
+ public ConnectionException(string message, string? code) : base(message, code)
+ {
+ }
+ }
+}
diff --git a/src/GopherOrch/Errors/TimeoutException.cs b/src/GopherOrch/Errors/TimeoutException.cs
new file mode 100644
index 00000000..c19550c6
--- /dev/null
+++ b/src/GopherOrch/Errors/TimeoutException.cs
@@ -0,0 +1,16 @@
+namespace GopherOrch.Errors
+{
+ ///
+ /// Exception for timeout related errors.
+ ///
+ public class TimeoutException : AgentException
+ {
+ public TimeoutException(string message) : base(message, "TIMEOUT_ERROR")
+ {
+ }
+
+ public TimeoutException(string message, string? code) : base(message, code)
+ {
+ }
+ }
+}
diff --git a/src/GopherOrch/Ffi/GopherOrchLibrary.cs b/src/GopherOrch/Ffi/GopherOrchLibrary.cs
new file mode 100644
index 00000000..adae6958
--- /dev/null
+++ b/src/GopherOrch/Ffi/GopherOrchLibrary.cs
@@ -0,0 +1,187 @@
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+
+namespace GopherOrch.Ffi
+{
+ ///
+ /// P/Invoke bindings to the gopher-orch native library.
+ ///
+ public static class GopherOrchLibrary
+ {
+ private const string LibraryName = "gopher-orch";
+
+ private static bool? _isAvailable;
+ private static readonly object _lock = new object();
+
+ ///
+ /// Check if the native library is available.
+ ///
+ public static bool IsAvailable
+ {
+ get
+ {
+ if (_isAvailable.HasValue)
+ return _isAvailable.Value;
+
+ lock (_lock)
+ {
+ if (_isAvailable.HasValue)
+ return _isAvailable.Value;
+
+ try
+ {
+ // Try to call a simple function to verify library is loaded
+ var ptr = gopher_orch_last_error();
+ _isAvailable = true;
+ }
+ catch (DllNotFoundException)
+ {
+ _isAvailable = false;
+ }
+ catch (EntryPointNotFoundException)
+ {
+ _isAvailable = false;
+ }
+
+ return _isAvailable.Value;
+ }
+ }
+ }
+
+ // Agent functions
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
+ public static extern IntPtr gopher_orch_agent_create_by_json(
+ string provider,
+ string model,
+ string serverJson);
+
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
+ public static extern IntPtr gopher_orch_agent_create_by_api_key(
+ string provider,
+ string model,
+ string apiKey);
+
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "gopher_orch_agent_run")]
+ private static extern IntPtr gopher_orch_agent_run_native(
+ IntPtr agent,
+ string query,
+ long timeoutMs);
+
+ ///
+ /// Run a query on the agent.
+ ///
+ public static string? AgentRun(IntPtr agent, string query, long timeoutMs)
+ {
+ IntPtr resultPtr = gopher_orch_agent_run_native(agent, query, timeoutMs);
+ if (resultPtr == IntPtr.Zero)
+ return null;
+ return Marshal.PtrToStringAnsi(resultPtr);
+ }
+
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void gopher_orch_agent_add_ref(IntPtr agent);
+
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void gopher_orch_agent_release(IntPtr agent);
+
+ // API functions
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "gopher_orch_api_fetch_servers")]
+ private static extern IntPtr gopher_orch_api_fetch_servers_native(string apiKey);
+
+ ///
+ /// Fetch servers configuration from API.
+ ///
+ public static string? ApiFetchServers(string apiKey)
+ {
+ IntPtr resultPtr = gopher_orch_api_fetch_servers_native(apiKey);
+ if (resultPtr == IntPtr.Zero)
+ return null;
+ return Marshal.PtrToStringAnsi(resultPtr);
+ }
+
+ // Error functions
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr gopher_orch_last_error();
+
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void gopher_orch_clear_error();
+
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void gopher_orch_free(IntPtr ptr);
+
+ ///
+ /// Get the last error message from the native library.
+ ///
+ public static string? GetLastError()
+ {
+ if (!IsAvailable)
+ return null;
+
+ try
+ {
+ IntPtr errorPtr = gopher_orch_last_error();
+ if (errorPtr == IntPtr.Zero)
+ return null;
+
+ // Read the error info structure
+ var errorInfo = Marshal.PtrToStructure(errorPtr);
+ return errorInfo.Message;
+ }
+ catch
+ {
+ return null;
+ }
+ }
+
+ ///
+ /// Set the native library search path.
+ /// Call this before any other library operations.
+ ///
+ public static void SetLibraryPath(string path)
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ SetDllDirectory(path);
+ }
+ else
+ {
+ // On Unix, we need to set the path before library load
+ var ldPath = Environment.GetEnvironmentVariable("LD_LIBRARY_PATH") ?? "";
+ var dyldPath = Environment.GetEnvironmentVariable("DYLD_LIBRARY_PATH") ?? "";
+
+ Environment.SetEnvironmentVariable("LD_LIBRARY_PATH",
+ string.IsNullOrEmpty(ldPath) ? path : path + Path.PathSeparator + ldPath);
+ Environment.SetEnvironmentVariable("DYLD_LIBRARY_PATH",
+ string.IsNullOrEmpty(dyldPath) ? path : path + Path.PathSeparator + dyldPath);
+ }
+ }
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
+ private static extern bool SetDllDirectory(string lpPathName);
+ }
+
+ ///
+ /// Error info structure matching C:
+ /// typedef struct {
+ /// gopher_orch_error_t code;
+ /// const char* message;
+ /// const char* details;
+ /// const char* file;
+ /// int32_t line;
+ /// } gopher_orch_error_info_t;
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public struct GopherOrchErrorInfo
+ {
+ public int Code;
+ public IntPtr MessagePtr;
+ public IntPtr DetailsPtr;
+ public IntPtr FilePtr;
+ public int Line;
+
+ public string? Message => MessagePtr != IntPtr.Zero ? Marshal.PtrToStringAnsi(MessagePtr) : null;
+ public string? Details => DetailsPtr != IntPtr.Zero ? Marshal.PtrToStringAnsi(DetailsPtr) : null;
+ public string? File => FilePtr != IntPtr.Zero ? Marshal.PtrToStringAnsi(FilePtr) : null;
+ }
+}
diff --git a/src/GopherOrch/GopherAgent.cs b/src/GopherOrch/GopherAgent.cs
new file mode 100644
index 00000000..0ba49172
--- /dev/null
+++ b/src/GopherOrch/GopherAgent.cs
@@ -0,0 +1,306 @@
+using System;
+using GopherOrch.Errors;
+using GopherOrch.Ffi;
+
+namespace GopherOrch
+{
+ ///
+ /// GopherAgent - Main entry point for the gopher-orch C# SDK.
+ ///
+ /// Provides a clean, C#-friendly interface to the gopher-orch agent functionality.
+ ///
+ /// Example:
+ ///
+ /// // Create an agent with API key
+ /// var agent = GopherAgent.Create(
+ /// GopherAgentConfig.CreateBuilder()
+ /// .WithProvider("AnthropicProvider")
+ /// .WithModel("claude-3-haiku-20240307")
+ /// .WithApiKey("your-api-key")
+ /// .Build()
+ /// );
+ ///
+ /// // Run a query
+ /// string answer = agent.Run("What time is it in Tokyo?");
+ /// Console.WriteLine(answer);
+ ///
+ /// // Cleanup (optional - happens automatically on Dispose)
+ /// agent.Dispose();
+ ///
+ ///
+ /// Or use `using` statement for automatic cleanup:
+ ///
+ /// using (var agent = GopherAgent.Create(config))
+ /// {
+ /// string answer = agent.Run("What time is it in Tokyo?");
+ /// Console.WriteLine(answer);
+ /// }
+ ///
+ ///
+ public sealed class GopherAgent : IDisposable
+ {
+ private static readonly object _initLock = new object();
+ private static bool _initialized;
+
+ private readonly IntPtr _handle;
+ private bool _disposed;
+ private readonly object _disposeLock = new object();
+
+ private GopherAgent(IntPtr handle)
+ {
+ _handle = handle;
+ }
+
+ ///
+ /// Initialize the gopher-orch library.
+ /// Must be called before creating any agents. Called automatically by Create() if not already initialized.
+ ///
+ public static void Init()
+ {
+ lock (_initLock)
+ {
+ if (_initialized)
+ return;
+
+ if (!GopherOrchLibrary.IsAvailable)
+ {
+ throw new AgentException("Failed to load gopher-orch native library");
+ }
+
+ _initialized = true;
+ }
+ }
+
+ ///
+ /// Shutdown the gopher-orch library.
+ ///
+ public static void Shutdown()
+ {
+ lock (_initLock)
+ {
+ _initialized = false;
+ }
+ }
+
+ ///
+ /// Check if the library is initialized.
+ ///
+ public static bool IsInitialized
+ {
+ get
+ {
+ lock (_initLock)
+ {
+ return _initialized;
+ }
+ }
+ }
+
+ ///
+ /// Create a new GopherAgent instance.
+ ///
+ /// Agent configuration
+ /// GopherAgent instance
+ /// If agent creation fails
+ public static GopherAgent Create(GopherAgentConfig config)
+ {
+ if (config == null)
+ throw new ArgumentNullException(nameof(config));
+
+ if (!_initialized)
+ {
+ Init();
+ }
+
+ IntPtr handle;
+ try
+ {
+ if (config.HasApiKey)
+ {
+ handle = GopherOrchLibrary.gopher_orch_agent_create_by_api_key(
+ config.Provider,
+ config.Model,
+ config.ApiKey!
+ );
+ }
+ else
+ {
+ handle = GopherOrchLibrary.gopher_orch_agent_create_by_json(
+ config.Provider,
+ config.Model,
+ config.ServerConfig!
+ );
+ }
+ }
+ catch (Exception e)
+ {
+ throw new AgentException("Failed to create agent: " + e.Message, e);
+ }
+
+ if (handle == IntPtr.Zero)
+ {
+ var error = GopherOrchLibrary.GetLastError();
+ GopherOrchLibrary.gopher_orch_clear_error();
+ throw new AgentException(error ?? "Failed to create agent from JSON configuration");
+ }
+
+ return new GopherAgent(handle);
+ }
+
+ ///
+ /// Create a new GopherAgent with API key.
+ ///
+ /// Provider name (e.g., "AnthropicProvider")
+ /// Model name (e.g., "claude-3-haiku-20240307")
+ /// API key for fetching remote server config
+ /// GopherAgent instance
+ public static GopherAgent Create(string provider, string model, string apiKey)
+ {
+ return Create(GopherAgentConfig.CreateBuilder()
+ .WithProvider(provider)
+ .WithModel(model)
+ .WithApiKey(apiKey)
+ .Build());
+ }
+
+ ///
+ /// Create a new GopherAgent with JSON server config.
+ ///
+ /// Provider name (e.g., "AnthropicProvider")
+ /// Model name (e.g., "claude-3-haiku-20240307")
+ /// JSON server configuration
+ /// GopherAgent instance
+ public static GopherAgent CreateWithServerConfig(string provider, string model, string serverConfig)
+ {
+ return Create(GopherAgentConfig.CreateBuilder()
+ .WithProvider(provider)
+ .WithModel(model)
+ .WithServerConfig(serverConfig)
+ .Build());
+ }
+
+ ///
+ /// Run a query against the agent.
+ ///
+ /// The user query to process
+ /// The agent's response
+ /// If the query fails
+ public string Run(string query)
+ {
+ return Run(query, 60000);
+ }
+
+ ///
+ /// Run a query against the agent with custom timeout.
+ ///
+ /// The user query to process
+ /// Timeout in milliseconds
+ /// The agent's response
+ /// If the query fails
+ public string Run(string query, long timeoutMs)
+ {
+ EnsureNotDisposed();
+
+ try
+ {
+ var response = GopherOrchLibrary.AgentRun(_handle, query, timeoutMs);
+ if (response == null)
+ {
+ return $"No response for query: \"{query}\"";
+ }
+ return response;
+ }
+ catch (Exception e)
+ {
+ throw new AgentException("Query execution failed: " + e.Message, e);
+ }
+ }
+
+ ///
+ /// Run a query with detailed result information.
+ ///
+ /// The user query to process
+ /// AgentResult with response and metadata
+ public AgentResult RunDetailed(string query)
+ {
+ return RunDetailed(query, 60000);
+ }
+
+ ///
+ /// Run a query with detailed result information and custom timeout.
+ ///
+ /// The user query to process
+ /// Timeout in milliseconds
+ /// AgentResult with response and metadata
+ public AgentResult RunDetailed(string query, long timeoutMs)
+ {
+ try
+ {
+ var response = Run(query, timeoutMs);
+ return AgentResult.CreateBuilder()
+ .WithResponse(response)
+ .WithStatus(AgentResultStatus.Success)
+ .WithIterationCount(1)
+ .WithTokensUsed(0)
+ .Build();
+ }
+ catch (Errors.TimeoutException e)
+ {
+ return AgentResult.Timeout(e.Message);
+ }
+ catch (Exception e)
+ {
+ return AgentResult.Error(e.Message);
+ }
+ }
+
+ ///
+ /// Check if agent is disposed.
+ ///
+ public bool IsDisposed
+ {
+ get
+ {
+ lock (_disposeLock)
+ {
+ return _disposed;
+ }
+ }
+ }
+
+ ///
+ /// Dispose of the agent and free resources.
+ ///
+ public void Dispose()
+ {
+ lock (_disposeLock)
+ {
+ if (_disposed)
+ return;
+
+ _disposed = true;
+
+ if (_handle != IntPtr.Zero)
+ {
+ GopherOrchLibrary.gopher_orch_agent_release(_handle);
+ }
+ }
+ }
+
+ private void EnsureNotDisposed()
+ {
+ lock (_disposeLock)
+ {
+ if (_disposed)
+ {
+ throw new AgentException("Agent has been disposed");
+ }
+ }
+ }
+
+ ~GopherAgent()
+ {
+ Dispose();
+ }
+ }
+}
diff --git a/src/GopherOrch/GopherAgentConfig.cs b/src/GopherOrch/GopherAgentConfig.cs
new file mode 100644
index 00000000..8695a4bc
--- /dev/null
+++ b/src/GopherOrch/GopherAgentConfig.cs
@@ -0,0 +1,121 @@
+using System;
+
+namespace GopherOrch
+{
+ ///
+ /// Configuration options for creating a GopherAgent.
+ ///
+ public sealed class GopherAgentConfig
+ {
+ ///
+ /// The LLM provider (e.g., "AnthropicProvider").
+ ///
+ public string Provider { get; }
+
+ ///
+ /// The model name (e.g., "claude-3-haiku-20240307").
+ ///
+ public string Model { get; }
+
+ ///
+ /// The API key for fetching remote server config (optional).
+ ///
+ public string? ApiKey { get; }
+
+ ///
+ /// The JSON server configuration (optional).
+ ///
+ public string? ServerConfig { get; }
+
+ private GopherAgentConfig(string provider, string model, string? apiKey, string? serverConfig)
+ {
+ Provider = provider ?? throw new ArgumentNullException(nameof(provider));
+ Model = model ?? throw new ArgumentNullException(nameof(model));
+ ApiKey = apiKey;
+ ServerConfig = serverConfig;
+
+ if (apiKey == null && serverConfig == null)
+ {
+ throw new ArgumentException("Either apiKey or serverConfig is required");
+ }
+ if (apiKey != null && serverConfig != null)
+ {
+ throw new ArgumentException("Cannot specify both apiKey and serverConfig");
+ }
+ }
+
+ ///
+ /// Check if this config uses an API key.
+ ///
+ public bool HasApiKey => ApiKey != null;
+
+ ///
+ /// Check if this config uses a server config.
+ ///
+ public bool HasServerConfig => ServerConfig != null;
+
+ ///
+ /// Create a new builder for GopherAgentConfig.
+ ///
+ public static Builder CreateBuilder() => new Builder();
+
+ ///
+ /// Builder for GopherAgentConfig.
+ ///
+ public sealed class Builder
+ {
+ private string? _provider;
+ private string? _model;
+ private string? _apiKey;
+ private string? _serverConfig;
+
+ ///
+ /// Set the LLM provider (e.g., "AnthropicProvider").
+ ///
+ public Builder WithProvider(string provider)
+ {
+ _provider = provider;
+ return this;
+ }
+
+ ///
+ /// Set the model name (e.g., "claude-3-haiku-20240307").
+ ///
+ public Builder WithModel(string model)
+ {
+ _model = model;
+ return this;
+ }
+
+ ///
+ /// Set the API key for fetching remote server config.
+ /// Mutually exclusive with ServerConfig.
+ ///
+ public Builder WithApiKey(string apiKey)
+ {
+ _apiKey = apiKey;
+ return this;
+ }
+
+ ///
+ /// Set the JSON server configuration.
+ /// Mutually exclusive with ApiKey.
+ ///
+ public Builder WithServerConfig(string serverConfig)
+ {
+ _serverConfig = serverConfig;
+ return this;
+ }
+
+ public GopherAgentConfig Build()
+ {
+ if (_provider == null)
+ throw new InvalidOperationException("Provider is required");
+ if (_model == null)
+ throw new InvalidOperationException("Model is required");
+
+ return new GopherAgentConfig(_provider, _model, _apiKey, _serverConfig);
+ }
+ }
+ }
+}
diff --git a/src/GopherOrch/GopherOrch.csproj b/src/GopherOrch/GopherOrch.csproj
new file mode 100644
index 00000000..74627a6a
--- /dev/null
+++ b/src/GopherOrch/GopherOrch.csproj
@@ -0,0 +1,20 @@
+
+
+
+ netstandard2.0
+ 8.0
+ enable
+ GopherOrch
+ 0.1.0
+ GopherSecurity
+ GopherSecurity
+ C# SDK for gopher-orch - MCP client orchestration framework
+ mcp;ai;orchestration;gopher
+ false
+
+
+
+
+
+
+
diff --git a/src/GopherOrch/ServerConfig.cs b/src/GopherOrch/ServerConfig.cs
new file mode 100644
index 00000000..6571bd3a
--- /dev/null
+++ b/src/GopherOrch/ServerConfig.cs
@@ -0,0 +1,20 @@
+using GopherOrch.Ffi;
+
+namespace GopherOrch
+{
+ ///
+ /// Utility class for fetching server configuration from the API.
+ ///
+ public static class ServerConfig
+ {
+ ///
+ /// Fetch server configuration from the API using an API key.
+ ///
+ /// The API key to use for authentication
+ /// JSON string containing server configuration
+ public static string? FetchServers(string apiKey)
+ {
+ return GopherOrchLibrary.ApiFetchServers(apiKey);
+ }
+ }
+}
diff --git a/src/orch/hello.cpp b/src/orch/hello.cpp
deleted file mode 100644
index 9b05263c..00000000
--- a/src/orch/hello.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-#include "orch/core/hello.h"
-
-#include
-
-#include "orch/core/version.h"
-
-namespace gopher {
-namespace orch {
-namespace core {
-
-class Hello::Impl {
- public:
- Impl() : name_("World") {}
- explicit Impl(const std::string& name) : name_(name) {}
-
- std::string name_;
-};
-
-Hello::Hello() : impl_(std::make_unique()) {}
-
-Hello::Hello(const std::string& name) : impl_(std::make_unique(name)) {}
-
-Hello::~Hello() = default;
-
-std::string Hello::greet() const {
- std::ostringstream oss;
- oss << "Hello, " << impl_->name_ << "!";
- return oss.str();
-}
-
-std::string Hello::greet_with_prefix(const std::string& prefix) const {
- std::ostringstream oss;
- oss << prefix << " " << impl_->name_ << "!";
- return oss.str();
-}
-
-void Hello::set_name(const std::string& name) { impl_->name_ = name; }
-
-const std::string& Hello::get_name() const { return impl_->name_; }
-
-std::string Hello::get_version() { return Version::string(); }
-
-HelloBuilder& HelloBuilder::with_name(const std::string& name) {
- name_ = name;
- return *this;
-}
-
-HelloBuilder& HelloBuilder::with_greeting_style(const std::string& style) {
- style_ = style;
- return *this;
-}
-
-std::unique_ptr HelloBuilder::build() const {
- return std::make_unique(name_);
-}
-
-} // namespace core
-} // namespace orch
-} // namespace gopher
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
deleted file mode 100644
index 88a9c7d4..00000000
--- a/tests/CMakeLists.txt
+++ /dev/null
@@ -1,83 +0,0 @@
-# gopher-orch tests
-
-# Test utilities and helpers
-set(TEST_UTIL_SOURCES
- # test_utils.cpp
-)
-
-# Orch-specific core tests
-set(ORCH_CORE_TEST_SOURCES
- orch/hello_test.cpp
-)
-
-# Helper function to create orch test executables
-function(add_orch_test test_name test_sources)
- add_executable(${test_name} ${test_sources} ${TEST_UTIL_SOURCES})
- # Use static library for tests to avoid duplicate symbol issues
- if(TARGET gopher-orch-static)
- set(GOPHER_ORCH_TEST_LIB gopher-orch-static)
- else()
- set(GOPHER_ORCH_TEST_LIB gopher-orch)
- endif()
- target_link_libraries(${test_name}
- ${GOPHER_ORCH_TEST_LIB}
- ${GOPHER_MCP_LIBRARIES}
- GTest::gtest
- GTest::gtest_main
- GTest::gmock
- Threads::Threads
- )
- target_include_directories(${test_name} PRIVATE
- ${CMAKE_SOURCE_DIR}/include
- ${CMAKE_SOURCE_DIR}/tests
- ${GOPHER_MCP_INCLUDE_DIR}
- )
-
- # Add test to CTest
- gtest_discover_tests(${test_name}
- WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
- PROPERTIES LABELS ${ARGN}
- )
-endfunction()
-
-# Create individual orch test executables
-add_orch_test(hello_test "${ORCH_CORE_TEST_SOURCES}" "orch")
-
-# Create a combined orch test executable for convenience
-add_executable(gopher-orch-tests
- ${ORCH_CORE_TEST_SOURCES}
- ${TEST_UTIL_SOURCES}
-)
-
-# Use static library for tests to avoid duplicate symbol issues
-if(TARGET gopher-orch-static)
- set(GOPHER_ORCH_TEST_LIB gopher-orch-static)
-else()
- set(GOPHER_ORCH_TEST_LIB gopher-orch)
-endif()
-
-target_link_libraries(gopher-orch-tests
- ${GOPHER_ORCH_TEST_LIB}
- ${GOPHER_MCP_LIBRARIES}
- GTest::gtest
- GTest::gtest_main
- GTest::gmock
- Threads::Threads
-)
-
-target_include_directories(gopher-orch-tests PRIVATE
- ${CMAKE_SOURCE_DIR}/include
- ${CMAKE_SOURCE_DIR}/tests
- ${GOPHER_MCP_INCLUDE_DIR}
-)
-
-# Custom test targets
-add_custom_target(test-verbose
- COMMAND ${CMAKE_CTEST_COMMAND} -V
- WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
-)
-
-add_custom_target(test-parallel
- COMMAND ${CMAKE_CTEST_COMMAND} -j${CMAKE_BUILD_PARALLEL_LEVEL}
- WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
-)
diff --git a/tests/GopherOrch.Tests/AgentResultTest.cs b/tests/GopherOrch.Tests/AgentResultTest.cs
new file mode 100644
index 00000000..3a1bcbca
--- /dev/null
+++ b/tests/GopherOrch.Tests/AgentResultTest.cs
@@ -0,0 +1,63 @@
+using Xunit;
+
+namespace GopherOrch.Tests
+{
+ public class AgentResultTest
+ {
+ [Fact]
+ public void TestSuccessResult()
+ {
+ var result = AgentResult.Success("test response");
+
+ Assert.Equal("test response", result.Response);
+ Assert.Equal(AgentResultStatus.Success, result.Status);
+ Assert.True(result.IsSuccess);
+ }
+
+ [Fact]
+ public void TestErrorResult()
+ {
+ var result = AgentResult.Error("error message");
+
+ Assert.Equal("error message", result.Response);
+ Assert.Equal(AgentResultStatus.Error, result.Status);
+ Assert.False(result.IsSuccess);
+ }
+
+ [Fact]
+ public void TestTimeoutResult()
+ {
+ var result = AgentResult.Timeout("timeout message");
+
+ Assert.Equal("timeout message", result.Response);
+ Assert.Equal(AgentResultStatus.Timeout, result.Status);
+ Assert.False(result.IsSuccess);
+ }
+
+ [Fact]
+ public void TestBuilderWithAllFields()
+ {
+ var result = AgentResult.CreateBuilder()
+ .WithResponse("response")
+ .WithStatus(AgentResultStatus.Success)
+ .WithIterationCount(5)
+ .WithTokensUsed(100)
+ .Build();
+
+ Assert.Equal("response", result.Response);
+ Assert.Equal(AgentResultStatus.Success, result.Status);
+ Assert.Equal(5, result.IterationCount);
+ Assert.Equal(100, result.TokensUsed);
+ }
+
+ [Fact]
+ public void TestToString()
+ {
+ var result = AgentResult.Success("test");
+ var str = result.ToString();
+
+ Assert.Contains("test", str);
+ Assert.Contains("Success", str);
+ }
+ }
+}
diff --git a/tests/GopherOrch.Tests/Ffi/GopherOrchLibraryTest.cs b/tests/GopherOrch.Tests/Ffi/GopherOrchLibraryTest.cs
new file mode 100644
index 00000000..e1cf82f9
--- /dev/null
+++ b/tests/GopherOrch.Tests/Ffi/GopherOrchLibraryTest.cs
@@ -0,0 +1,198 @@
+using System;
+using GopherOrch.Ffi;
+using Xunit;
+
+namespace GopherOrch.Tests.Ffi
+{
+ ///
+ /// Tests for FFI bindings to the native gopher-orch library.
+ /// These tests verify that the C# side can correctly call C++ functions
+ /// through P/Invoke FFI bindings.
+ ///
+ public class GopherOrchLibraryTest
+ {
+ private static readonly string ServerConfig = "{"
+ + "\"succeeded\": true,"
+ + "\"code\": 200000000,"
+ + "\"message\": \"success\","
+ + "\"data\": {"
+ + " \"servers\": ["
+ + " {"
+ + " \"version\": \"2025-01-09\","
+ + " \"serverId\": \"1\","
+ + " \"name\": \"test-server\","
+ + " \"transport\": \"http_sse\","
+ + " \"config\": {\"url\": \"http://127.0.0.1:9999/mcp\", \"headers\": {}},"
+ + " \"connectTimeout\": 5000,"
+ + " \"requestTimeout\": 30000"
+ + " }"
+ + " ]"
+ + "}"
+ + "}";
+
+ ///
+ /// Check if native library is available for tests.
+ ///
+ private static bool IsNativeLibraryAvailable => GopherOrchLibrary.IsAvailable;
+
+ [SkippableFact]
+ public void TestLibraryIsAvailable()
+ {
+ // This test verifies that the native library can be loaded
+ bool available = GopherOrchLibrary.IsAvailable;
+ Skip.IfNot(available, "Native library not available. " +
+ "Run ./build.sh first to build the native library.");
+ Assert.True(available);
+ }
+
+ [SkippableFact]
+ public void TestAgentCreateByJsonWithValidConfig()
+ {
+ Skip.IfNot(IsNativeLibraryAvailable, "Native library not available");
+
+ // Valid server configuration JSON
+ // Call native function to create agent
+ var handle = GopherOrchLibrary.gopher_orch_agent_create_by_json(
+ "AnthropicProvider",
+ "claude-3-haiku-20240307",
+ ServerConfig
+ );
+
+ // Agent should be created (handle may be null if no API key, but function should not crash)
+ // The important thing is that the FFI call works without throwing
+ if (handle != IntPtr.Zero)
+ {
+ // Clean up if agent was created
+ GopherOrchLibrary.gopher_orch_agent_release(handle);
+ }
+ }
+
+ [SkippableFact]
+ public void TestAgentCreateByJsonWithEmptyConfig()
+ {
+ Skip.IfNot(IsNativeLibraryAvailable, "Native library not available");
+
+ // Empty/invalid config should return null handle
+ var handle = GopherOrchLibrary.gopher_orch_agent_create_by_json(
+ "AnthropicProvider",
+ "claude-3-haiku-20240307",
+ "{}"
+ );
+
+ // Should handle gracefully (null or valid pointer, but no crash)
+ if (handle != IntPtr.Zero)
+ {
+ GopherOrchLibrary.gopher_orch_agent_release(handle);
+ }
+ }
+
+ [SkippableFact]
+ public void TestAgentCreateByApiKey()
+ {
+ Skip.IfNot(IsNativeLibraryAvailable, "Native library not available");
+
+ // Call with a dummy API key - should not crash
+ var handle = GopherOrchLibrary.gopher_orch_agent_create_by_api_key(
+ "AnthropicProvider",
+ "claude-3-haiku-20240307",
+ "test-api-key-12345"
+ );
+
+ // May return null if API key is invalid, but should not crash
+ if (handle != IntPtr.Zero)
+ {
+ GopherOrchLibrary.gopher_orch_agent_release(handle);
+ }
+ }
+
+ [SkippableFact]
+ public void TestLastErrorAndClearError()
+ {
+ Skip.IfNot(IsNativeLibraryAvailable, "Native library not available");
+
+ // Try to get last error (may be null if no error)
+ var exception = Record.Exception(() =>
+ {
+ var errorPtr = GopherOrchLibrary.gopher_orch_last_error();
+ // errorPtr may be null or have null message if no error
+ });
+
+ Assert.Null(exception);
+
+ // Clear error should not throw
+ exception = Record.Exception(() =>
+ {
+ GopherOrchLibrary.gopher_orch_clear_error();
+ });
+
+ Assert.Null(exception);
+ }
+
+ [SkippableFact]
+ public void TestApiFetchServers()
+ {
+ Skip.IfNot(IsNativeLibraryAvailable, "Native library not available");
+
+ // Call with dummy API key - should return JSON (possibly error response)
+ var exception = Record.Exception(() =>
+ {
+ var result = GopherOrchLibrary.ApiFetchServers("test-api-key");
+ // Result may be null or contain error, but should not crash
+ });
+
+ Assert.Null(exception);
+ }
+
+ [SkippableFact]
+ public void TestAgentRunWithNullHandle()
+ {
+ Skip.IfNot(IsNativeLibraryAvailable, "Native library not available");
+
+ // Running with null handle should be handled gracefully
+ var exception = Record.Exception(() =>
+ {
+ var result = GopherOrchLibrary.AgentRun(IntPtr.Zero, "test query", 1000);
+ // May return null or error message, but should not crash
+ });
+
+ // Exception is acceptable for null handle
+ }
+
+ [SkippableFact]
+ public void TestAgentReleaseWithNullHandle()
+ {
+ Skip.IfNot(IsNativeLibraryAvailable, "Native library not available");
+
+ // Releasing null handle should be handled gracefully
+ var exception = Record.Exception(() =>
+ {
+ GopherOrchLibrary.gopher_orch_agent_release(IntPtr.Zero);
+ });
+
+ // Exception is acceptable for null handle
+ }
+
+ [SkippableFact]
+ public void TestFreeWithNullPointer()
+ {
+ Skip.IfNot(IsNativeLibraryAvailable, "Native library not available");
+
+ // Free with null should be handled gracefully
+ var exception = Record.Exception(() =>
+ {
+ GopherOrchLibrary.gopher_orch_free(IntPtr.Zero);
+ });
+
+ // Exception is acceptable for null pointer
+ }
+
+ [Fact]
+ public void TestGetLastErrorWhenLibraryNotLoaded()
+ {
+ // This tests the static helper method
+ var error = GopherOrchLibrary.GetLastError();
+ // Should return null gracefully, not throw
+ // (error may be null or a message depending on state)
+ }
+ }
+}
diff --git a/tests/GopherOrch.Tests/GopherAgentConfigTest.cs b/tests/GopherOrch.Tests/GopherAgentConfigTest.cs
new file mode 100644
index 00000000..eda9551d
--- /dev/null
+++ b/tests/GopherOrch.Tests/GopherAgentConfigTest.cs
@@ -0,0 +1,85 @@
+using System;
+using Xunit;
+
+namespace GopherOrch.Tests
+{
+ public class GopherAgentConfigTest
+ {
+ [Fact]
+ public void TestBuildWithApiKey()
+ {
+ var config = GopherAgentConfig.CreateBuilder()
+ .WithProvider("AnthropicProvider")
+ .WithModel("claude-3-haiku-20240307")
+ .WithApiKey("test-api-key")
+ .Build();
+
+ Assert.Equal("AnthropicProvider", config.Provider);
+ Assert.Equal("claude-3-haiku-20240307", config.Model);
+ Assert.Equal("test-api-key", config.ApiKey);
+ Assert.Null(config.ServerConfig);
+ Assert.True(config.HasApiKey);
+ Assert.False(config.HasServerConfig);
+ }
+
+ [Fact]
+ public void TestBuildWithServerConfig()
+ {
+ var serverConfig = "{\"servers\": []}";
+ var config = GopherAgentConfig.CreateBuilder()
+ .WithProvider("AnthropicProvider")
+ .WithModel("claude-3-haiku-20240307")
+ .WithServerConfig(serverConfig)
+ .Build();
+
+ Assert.Equal("AnthropicProvider", config.Provider);
+ Assert.Equal("claude-3-haiku-20240307", config.Model);
+ Assert.Null(config.ApiKey);
+ Assert.Equal(serverConfig, config.ServerConfig);
+ Assert.False(config.HasApiKey);
+ Assert.True(config.HasServerConfig);
+ }
+
+ [Fact]
+ public void TestBuildWithoutProviderThrows()
+ {
+ var builder = GopherAgentConfig.CreateBuilder()
+ .WithModel("claude-3-haiku-20240307")
+ .WithApiKey("test-api-key");
+
+ Assert.Throws(() => builder.Build());
+ }
+
+ [Fact]
+ public void TestBuildWithoutModelThrows()
+ {
+ var builder = GopherAgentConfig.CreateBuilder()
+ .WithProvider("AnthropicProvider")
+ .WithApiKey("test-api-key");
+
+ Assert.Throws(() => builder.Build());
+ }
+
+ [Fact]
+ public void TestBuildWithoutApiKeyOrServerConfigThrows()
+ {
+ var builder = GopherAgentConfig.CreateBuilder()
+ .WithProvider("AnthropicProvider")
+ .WithModel("claude-3-haiku-20240307");
+
+ Assert.Throws(() => builder.Build());
+ }
+
+ [Fact]
+ public void TestBuildWithBothApiKeyAndServerConfigThrows()
+ {
+ var builder = GopherAgentConfig.CreateBuilder()
+ .WithProvider("AnthropicProvider")
+ .WithModel("claude-3-haiku-20240307")
+ .WithApiKey("test-api-key")
+ .WithServerConfig("{\"servers\": []}");
+
+ Assert.Throws(() => builder.Build());
+ }
+ }
+}
diff --git a/tests/GopherOrch.Tests/GopherAgentIntegrationTest.cs b/tests/GopherOrch.Tests/GopherAgentIntegrationTest.cs
new file mode 100644
index 00000000..738ee376
--- /dev/null
+++ b/tests/GopherOrch.Tests/GopherAgentIntegrationTest.cs
@@ -0,0 +1,260 @@
+using System;
+using GopherOrch.Errors;
+using GopherOrch.Ffi;
+using Xunit;
+
+namespace GopherOrch.Tests
+{
+ ///
+ /// Integration tests for GopherAgent that verify the full flow through FFI.
+ /// These tests require the native library to be built and available.
+ ///
+ public class GopherAgentIntegrationTest
+ {
+ private static readonly string ServerConfig = "{"
+ + "\"succeeded\": true,"
+ + "\"code\": 200000000,"
+ + "\"message\": \"success\","
+ + "\"data\": {"
+ + " \"servers\": ["
+ + " {"
+ + " \"version\": \"2025-01-09\","
+ + " \"serverId\": \"1\","
+ + " \"name\": \"test-server\","
+ + " \"transport\": \"http_sse\","
+ + " \"config\": {\"url\": \"http://127.0.0.1:9999/mcp\", \"headers\": {}},"
+ + " \"connectTimeout\": 5000,"
+ + " \"requestTimeout\": 30000"
+ + " }"
+ + " ]"
+ + "}"
+ + "}";
+
+ ///
+ /// Check if native library is available for tests.
+ ///
+ private static bool IsNativeLibraryAvailable => GopherOrchLibrary.IsAvailable;
+
+ ///
+ /// Helper method to create an agent, skipping test if creation fails.
+ /// Agent creation may fail without API key or network access.
+ ///
+ private GopherAgent? TryCreateAgent()
+ {
+ try
+ {
+ return GopherAgent.CreateWithServerConfig(
+ "AnthropicProvider",
+ "claude-3-haiku-20240307",
+ ServerConfig
+ );
+ }
+ catch (AgentException)
+ {
+ // Agent creation failed - skip test
+ return null;
+ }
+ }
+
+ [SkippableFact]
+ public void TestInitialization()
+ {
+ Skip.IfNot(IsNativeLibraryAvailable, "Native library not available");
+
+ // Test that initialization works
+ GopherAgent.Init();
+ Assert.True(GopherAgent.IsInitialized);
+ }
+
+ [SkippableFact]
+ public void TestCreateAgentWithServerConfig()
+ {
+ Skip.IfNot(IsNativeLibraryAvailable, "Native library not available");
+
+ // Test creating agent with server config through FFI
+ var config = GopherAgentConfig.CreateBuilder()
+ .WithProvider("AnthropicProvider")
+ .WithModel("claude-3-haiku-20240307")
+ .WithServerConfig(ServerConfig)
+ .Build();
+
+ GopherAgent? agent = null;
+ try
+ {
+ agent = GopherAgent.Create(config);
+ Assert.NotNull(agent);
+ Assert.False(agent.IsDisposed);
+ }
+ catch (AgentException)
+ {
+ // Agent creation may fail without API key - this is expected
+ Skip.If(true, "Agent creation failed - likely no API key available");
+ }
+ finally
+ {
+ if (agent != null)
+ {
+ agent.Dispose();
+ Assert.True(agent.IsDisposed);
+ }
+ }
+ }
+
+ [SkippableFact]
+ public void TestCreateAgentWithHelperMethod()
+ {
+ Skip.IfNot(IsNativeLibraryAvailable, "Native library not available");
+
+ // Test the convenience method
+ var agent = TryCreateAgent();
+ Skip.If(agent == null, "Agent creation failed - likely no API key available");
+
+ try
+ {
+ Assert.NotNull(agent);
+ }
+ finally
+ {
+ agent?.Dispose();
+ }
+ }
+
+ [SkippableFact]
+ public void TestUsingStatement()
+ {
+ Skip.IfNot(IsNativeLibraryAvailable, "Native library not available");
+
+ // Test IDisposable implementation
+ GopherAgent? capturedAgent = null;
+
+ var agent = TryCreateAgent();
+ Skip.If(agent == null, "Agent creation failed - likely no API key available");
+
+ using (agent)
+ {
+ Assert.NotNull(agent);
+ Assert.False(agent.IsDisposed);
+ capturedAgent = agent;
+ }
+
+ // After using statement, agent should be disposed
+ Assert.NotNull(capturedAgent);
+ Assert.True(capturedAgent.IsDisposed);
+ }
+
+ [SkippableFact]
+ public void TestDisposeIdempotent()
+ {
+ Skip.IfNot(IsNativeLibraryAvailable, "Native library not available");
+
+ // Test that dispose can be called multiple times safely
+ var agent = TryCreateAgent();
+ Skip.If(agent == null, "Agent creation failed - likely no API key available");
+
+ agent.Dispose();
+ Assert.True(agent.IsDisposed);
+
+ // Second dispose should not throw
+ agent.Dispose();
+ Assert.True(agent.IsDisposed);
+ }
+
+ [SkippableFact]
+ public void TestRunAfterDisposeThrows()
+ {
+ Skip.IfNot(IsNativeLibraryAvailable, "Native library not available");
+
+ var agent = TryCreateAgent();
+ Skip.If(agent == null, "Agent creation failed - likely no API key available");
+
+ agent.Dispose();
+
+ // Running on disposed agent should throw
+ Assert.Throws(() => agent.Run("test query"));
+ }
+
+ [SkippableFact]
+ public void TestRunDetailedReturnsResult()
+ {
+ Skip.IfNot(IsNativeLibraryAvailable, "Native library not available");
+
+ var agent = TryCreateAgent();
+ Skip.If(agent == null, "Agent creation failed - likely no API key available");
+
+ using (agent)
+ {
+ // Run with very short timeout to get quick response (likely timeout or error)
+ var result = agent.RunDetailed("test query", 100);
+
+ Assert.NotNull(result);
+ Assert.NotNull(result.Response);
+ }
+ }
+
+ [SkippableFact]
+ public void TestMultipleAgentsCanBeCreated()
+ {
+ Skip.IfNot(IsNativeLibraryAvailable, "Native library not available");
+
+ var agent1 = TryCreateAgent();
+ Skip.If(agent1 == null, "Agent creation failed - likely no API key available");
+
+ var agent2 = TryCreateAgent();
+ Skip.If(agent2 == null, "Agent creation failed - likely no API key available");
+
+ try
+ {
+ Assert.NotNull(agent1);
+ Assert.NotNull(agent2);
+ Assert.NotSame(agent1, agent2);
+ }
+ finally
+ {
+ agent1?.Dispose();
+ agent2?.Dispose();
+ }
+ }
+
+ [Fact]
+ public void TestCreateWithoutNativeLibraryHandled()
+ {
+ // This test verifies error handling when native library is not available
+ // Skip if library IS available (we're testing the error case)
+ if (GopherOrchLibrary.IsAvailable)
+ {
+ // Library is available, so we can't test the "not available" case
+ // Just verify that create works (or gracefully fails without API key)
+ try
+ {
+ using var agent = GopherAgent.CreateWithServerConfig(
+ "AnthropicProvider",
+ "claude-3-haiku-20240307",
+ ServerConfig
+ );
+ }
+ catch (AgentException)
+ {
+ // Expected if no API key is available
+ }
+ }
+ // If library is not available, Init() would throw AgentException
+ }
+
+ [SkippableFact]
+ public void TestShutdownAndReinit()
+ {
+ Skip.IfNot(IsNativeLibraryAvailable, "Native library not available");
+
+ // Test that shutdown and re-init work correctly
+ GopherAgent.Init();
+ Assert.True(GopherAgent.IsInitialized);
+
+ GopherAgent.Shutdown();
+ Assert.False(GopherAgent.IsInitialized);
+
+ // Re-init should work
+ GopherAgent.Init();
+ Assert.True(GopherAgent.IsInitialized);
+ }
+ }
+}
diff --git a/tests/GopherOrch.Tests/GopherOrch.Tests.csproj b/tests/GopherOrch.Tests/GopherOrch.Tests.csproj
new file mode 100644
index 00000000..960abda1
--- /dev/null
+++ b/tests/GopherOrch.Tests/GopherOrch.Tests.csproj
@@ -0,0 +1,28 @@
+
+
+
+ net6.0
+ 10.0
+ enable
+ false
+
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
diff --git a/tests/orch/hello_test.cpp b/tests/orch/hello_test.cpp
deleted file mode 100644
index a6672772..00000000
--- a/tests/orch/hello_test.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-#include "orch/core/hello.h"
-
-#include
-#include
-
-#include "orch/core/version.h"
-
-using namespace gopher::orch::core;
-using namespace testing;
-
-class HelloTest : public ::testing::Test {
- protected:
- void SetUp() override {
- // Setup code if needed
- }
-
- void TearDown() override {
- // Teardown code if needed
- }
-};
-
-TEST_F(HelloTest, DefaultConstructor) {
- Hello hello;
- EXPECT_EQ(hello.greet(), "Hello, World!");
- EXPECT_EQ(hello.get_name(), "World");
-}
-
-TEST_F(HelloTest, ParameterizedConstructor) {
- Hello hello("Alice");
- EXPECT_EQ(hello.greet(), "Hello, Alice!");
- EXPECT_EQ(hello.get_name(), "Alice");
-}
-
-TEST_F(HelloTest, SetName) {
- Hello hello;
- hello.set_name("Bob");
- EXPECT_EQ(hello.greet(), "Hello, Bob!");
- EXPECT_EQ(hello.get_name(), "Bob");
-}
-
-TEST_F(HelloTest, GreetWithPrefix) {
- Hello hello("Charlie");
- EXPECT_EQ(hello.greet_with_prefix("Hi"), "Hi Charlie!");
- EXPECT_EQ(hello.greet_with_prefix("Welcome"), "Welcome Charlie!");
-}
-
-TEST_F(HelloTest, GetVersion) { EXPECT_EQ(Hello::get_version(), "0.1.0"); }
-
-TEST_F(HelloTest, EmptyName) {
- Hello hello("");
- EXPECT_EQ(hello.greet(), "Hello, !");
- EXPECT_EQ(hello.get_name(), "");
-}
-
-TEST_F(HelloTest, SpecialCharacters) {
- Hello hello("User@123!");
- EXPECT_EQ(hello.greet(), "Hello, User@123!!");
- EXPECT_EQ(hello.get_name(), "User@123!");
-}
-
-TEST_F(HelloTest, LongName) {
- std::string long_name(1000, 'a');
- Hello hello(long_name);
- EXPECT_EQ(hello.get_name(), long_name);
- EXPECT_THAT(hello.greet(), StartsWith("Hello, "));
- EXPECT_THAT(hello.greet(), EndsWith("!"));
-}
-
-// Test HelloBuilder
-class HelloBuilderTest : public ::testing::Test {
- protected:
- HelloBuilder builder;
-};
-
-TEST_F(HelloBuilderTest, DefaultBuild) {
- auto hello = builder.build();
- EXPECT_EQ(hello->greet(), "Hello, World!");
-}
-
-TEST_F(HelloBuilderTest, WithName) {
- auto hello = builder.with_name("Diana").build();
- EXPECT_EQ(hello->greet(), "Hello, Diana!");
-}
-
-TEST_F(HelloBuilderTest, ChainedCalls) {
- auto hello = builder.with_name("Eve").with_greeting_style("formal").build();
- EXPECT_EQ(hello->greet(), "Hello, Eve!");
-}
-
-TEST_F(HelloBuilderTest, MultipleBuildsSameBuilder) {
- builder.with_name("Frank");
- auto hello1 = builder.build();
- auto hello2 = builder.build();
-
- EXPECT_EQ(hello1->greet(), "Hello, Frank!");
- EXPECT_EQ(hello2->greet(), "Hello, Frank!");
-
- // Verify they are independent objects
- hello1->set_name("George");
- EXPECT_EQ(hello1->get_name(), "George");
- EXPECT_EQ(hello2->get_name(), "Frank");
-}
-
-// Version tests
-TEST(VersionTest, VersionConstants) {
- EXPECT_EQ(Version::major(), 0);
- EXPECT_EQ(Version::minor(), 1);
- EXPECT_EQ(Version::patch(), 0);
- EXPECT_STREQ(Version::string(), "0.1.0");
-}
diff --git a/third_party/gopher-mcp b/third_party/gopher-mcp
deleted file mode 160000
index 5f6d6fd4..00000000
--- a/third_party/gopher-mcp
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 5f6d6fd4c70149eacab072cf9ba9a333107c0d36
diff --git a/third_party/gopher-orch b/third_party/gopher-orch
new file mode 160000
index 00000000..6b45ffbb
--- /dev/null
+++ b/third_party/gopher-orch
@@ -0,0 +1 @@
+Subproject commit 6b45ffbbee74d5ae034008fc2cb2a927f3131992