This is an automated email from the ASF dual-hosted git repository.

zhongxjian pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/dubbo-kubernetes.git


The following commit(s) were added to refs/heads/master by this push:
     new b7f62861 [navi] add agent flag and discovery server (#766)
b7f62861 is described below

commit b7f62861a25c4e57ff1b7fec3bbd4325b5e5f104
Author: Jian Zhong <[email protected]>
AuthorDate: Sat Aug 2 01:46:07 2025 +0800

    [navi] add agent flag and discovery server (#766)
---
 go.mod                                             |  42 +++-
 go.sum                                             |  77 +++++-
 navigator/cmd/navi-agent/app/cmd.go                |   8 +
 navigator/cmd/navi-agent/options/agent_proxy.go    |   2 +
 navigator/pkg/bootstrap/mesh.go                    |  82 +++++++
 navigator/pkg/bootstrap/server.go                  |  16 +-
 navigator/pkg/features/navigator.go                |   2 +
 pkg/config/constants/constants.go                  |   1 +
 .../config/mesh/kubemesh/watcher.go                |  37 ++-
 pkg/filewatcher/fakefilewatcher.go                 | 146 +++++++++++
 pkg/filewatcher/filewatcher.go                     | 194 +++++++++++++++
 pkg/filewatcher/worker.go                          | 268 +++++++++++++++++++++
 pkg/kube/controllers/common.go                     |  29 +++
 pkg/kube/krt/core.go                               |  84 +++++++
 pkg/kube/krt/fetch.go                              |  21 ++
 pkg/kube/krt/files/files.go                        |  19 ++
 pkg/kube/krt/filter.go                             |   3 +
 pkg/kube/krt/internal.go                           |  26 ++
 pkg/kube/krt/options.go                            |  35 +++
 pkg/kube/krt/singleton.go                          |  35 +++
 pkg/kube/krt/sync.go                               |   5 +
 pkg/mesh/meshwatcher/collection.go                 |  55 +++++
 pkg/mesh/meshwatcher/mesh.go                       |   7 +
 pkg/navi-agent/agent.go                            |   3 +-
 pkg/ptr/pointer.go                                 |   5 +
 25 files changed, 1181 insertions(+), 21 deletions(-)

diff --git a/go.mod b/go.mod
index 5fd9a24b..07787406 100644
--- a/go.mod
+++ b/go.mod
@@ -45,6 +45,7 @@ require (
        github.com/tmc/langchaingo v0.1.13
        golang.org/x/crypto v0.40.0
        golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6
+       golang.org/x/net v0.42.0
        golang.org/x/term v0.33.0
        google.golang.org/grpc v1.74.0
        google.golang.org/protobuf v1.36.6
@@ -60,6 +61,7 @@ require (
 )
 
 require (
+       cel.dev/expr v0.24.0 // indirect
        dario.cat/mergo v1.0.2 // indirect
        github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
        github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // 
indirect
@@ -80,6 +82,7 @@ require (
        github.com/ProtonMail/go-crypto v1.1.3 // indirect
        github.com/VividCortex/ewma v1.2.0 // indirect
        github.com/agext/levenshtein v1.2.3 // indirect
+       github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
        github.com/apex/log v1.9.0 // indirect
        github.com/aws/aws-sdk-go-v2 v1.30.3 // indirect
        github.com/aws/aws-sdk-go-v2/config v1.27.27 // indirect
@@ -97,17 +100,21 @@ require (
        github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect
        github.com/aws/smithy-go v1.20.3 // indirect
        github.com/awslabs/amazon-ecr-credential-helper/ecr-login 
v0.0.0-20230522190001-adf1bafd791a // indirect
+       github.com/beorn7/perks v1.0.1 // indirect
        github.com/blang/semver/v4 v4.0.0 // indirect
        github.com/buildpacks/imgutil v0.0.0-20230626185301-726f02e4225c // 
indirect
        github.com/buildpacks/lifecycle v0.17.0 // indirect
        github.com/cespare/xxhash v1.1.0 // indirect
+       github.com/cespare/xxhash/v2 v2.3.0 // indirect
        github.com/chrismellard/docker-credential-acr-env 
v0.0.0-20230304212654-82a0ddb27589 // indirect
        github.com/cloudflare/circl v1.3.7 // indirect
+       github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect
        github.com/containerd/containerd v1.7.27 // indirect
        github.com/containerd/stargz-snapshotter/estargz v0.16.3 // indirect
        github.com/containerd/typeurl/v2 v2.2.3 // indirect
        github.com/cyphar/filepath-securejoin v0.4.1 // indirect
        github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // 
indirect
+       github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
        github.com/dgraph-io/ristretto v0.0.1 // indirect
        github.com/dimchansky/utfbom v1.1.1 // indirect
        github.com/dlclark/regexp2 v1.10.0 // indirect
@@ -116,6 +123,9 @@ require (
        github.com/dustin/go-humanize v1.0.1 // indirect
        github.com/emicklei/go-restful/v3 v3.12.2 // indirect
        github.com/emirpasic/gods v1.18.1 // indirect
+       github.com/envoyproxy/go-control-plane/contrib 
v1.32.5-0.20250627145903-197b96a9c7f8 // indirect
+       github.com/envoyproxy/go-control-plane/envoy 
v1.32.5-0.20250627145903-197b96a9c7f8 // indirect
+       github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
        github.com/fsnotify/fsnotify v1.9.0 // indirect
        github.com/fxamacker/cbor/v2 v2.8.0 // indirect
        github.com/gdamore/encoding v1.0.0 // indirect
@@ -123,19 +133,23 @@ require (
        github.com/go-errors/errors v1.5.1 // indirect
        github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
        github.com/go-logr/logr v1.4.3 // indirect
+       github.com/go-logr/stdr v1.2.2 // indirect
        github.com/go-openapi/jsonpointer v0.21.1 // indirect
        github.com/go-openapi/jsonreference v0.21.0 // indirect
        github.com/go-openapi/swag v0.23.1 // indirect
        github.com/gobwas/glob v0.2.3 // indirect
+       github.com/goccy/go-json v0.10.5 // indirect
        github.com/gogo/protobuf v1.3.2 // indirect
        github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
        github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // 
indirect
        github.com/google/btree v1.1.3 // indirect
+       github.com/google/cel-go v0.25.0 // indirect
        github.com/google/gnostic-models v0.6.9 // indirect
        github.com/google/go-cmp v0.7.0 // indirect
        github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
        github.com/google/uuid v1.6.0 // indirect
        github.com/goph/emperror v0.17.2 // indirect
+       github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // 
indirect
        github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // 
indirect
        github.com/hashicorp/errwrap v1.1.0 // indirect
        github.com/hashicorp/hcl v1.0.0 // indirect
@@ -149,6 +163,12 @@ require (
        github.com/kevinburke/ssh_config v1.2.0 // indirect
        github.com/klauspost/compress v1.18.0 // indirect
        github.com/klauspost/pgzip v1.2.6 // indirect
+       github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect
+       github.com/lestrrat-go/blackmagic v1.0.3 // indirect
+       github.com/lestrrat-go/httpcc v1.0.1 // indirect
+       github.com/lestrrat-go/iter v1.0.2 // indirect
+       github.com/lestrrat-go/jwx v1.2.31 // indirect
+       github.com/lestrrat-go/option v1.0.1 // indirect
        github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
        github.com/magiconair/properties v1.8.7 // indirect
        github.com/mailru/easyjson v0.9.0 // indirect
@@ -164,6 +184,7 @@ require (
        github.com/moby/buildkit v0.21.1 // indirect
        github.com/moby/docker-image-spec v1.3.1 // indirect
        github.com/moby/patternmatcher v0.6.0 // indirect
+       github.com/moby/spdystream v0.5.0 // indirect
        github.com/moby/sys/capability v0.4.0 // indirect
        github.com/moby/sys/mountinfo v0.7.2 // indirect
        github.com/moby/sys/sequential v0.6.0 // indirect
@@ -174,6 +195,7 @@ require (
        github.com/monochromegane/go-gitignore 
v0.0.0-20200626010858-205db1a8cc00 // indirect
        github.com/morikuni/aec v1.0.0 // indirect
        github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 
indirect
+       github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // 
indirect
        github.com/nikolalohinski/gonja v1.5.3 // indirect
        github.com/opencontainers/go-digest v1.0.0 // indirect
        github.com/opencontainers/image-spec v1.1.1 // indirect
@@ -186,6 +208,10 @@ require (
        github.com/pjbgf/sha1cd v0.3.0 // indirect
        github.com/pkoukk/tiktoken-go v0.1.6 // indirect
        github.com/planetscale/vtprotobuf v0.6.1-0.20240409071808-615f978279ca 
// indirect
+       github.com/prometheus/client_golang v1.22.0 // indirect
+       github.com/prometheus/client_model v0.6.2 // indirect
+       github.com/prometheus/common v0.65.0 // indirect
+       github.com/prometheus/procfs v0.16.1 // indirect
        github.com/rivo/tview v0.0.0-20220307222120-9994674d60a8 // indirect
        github.com/rivo/uniseg v0.4.7 // indirect
        github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 // 
indirect
@@ -197,6 +223,7 @@ require (
        github.com/spf13/afero v1.14.0 // indirect
        github.com/spf13/cast v1.8.0 // indirect
        github.com/spf13/jwalterweatherman v1.1.0 // indirect
+       github.com/stoewer/go-strcase v1.3.0 // indirect
        github.com/subosito/gotenv v1.6.0 // indirect
        github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4 // 
indirect
        github.com/ulikunitz/xz v0.5.12 // indirect
@@ -208,13 +235,21 @@ require (
        github.com/xeipuuv/gojsonschema v1.2.0 // indirect
        github.com/xlab/treeprint v1.2.0 // indirect
        github.com/yargevad/filepathx v1.0.0 // indirect
+       go.opentelemetry.io/auto/sdk v1.1.0 // indirect
+       go.opentelemetry.io/otel v1.36.0 // indirect
+       go.opentelemetry.io/otel/exporters/prometheus v0.57.0 // indirect
+       go.opentelemetry.io/otel/metric v1.36.0 // indirect
+       go.opentelemetry.io/otel/sdk v1.36.0 // indirect
+       go.opentelemetry.io/otel/sdk/metric v1.36.0 // indirect
+       go.opentelemetry.io/otel/trace v1.36.0 // indirect
+       go.opentelemetry.io/proto/otlp v1.7.0 // indirect
        go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 // indirect
+       go.uber.org/atomic v1.11.0 // indirect
        go.uber.org/multierr v1.11.0 // indirect
        go.uber.org/zap v1.27.0 // indirect
        go.yaml.in/yaml/v2 v2.4.2 // indirect
        go.yaml.in/yaml/v3 v3.0.3 // indirect
        golang.org/x/mod v0.25.0 // indirect
-       golang.org/x/net v0.42.0 // indirect
        golang.org/x/oauth2 v0.30.0 // indirect
        golang.org/x/sync v0.16.0 // indirect
        golang.org/x/sys v0.34.0 // indirect
@@ -229,13 +264,18 @@ require (
        gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
        gopkg.in/warnings.v0 v0.1.2 // indirect
        gopkg.in/yaml.v2 v2.4.0 // indirect
+       istio.io/client-go v1.26.0-alpha.0.0.20250731213105-2f06e3d976fe // 
indirect
+       k8s.io/apiserver v0.33.2 // indirect
        k8s.io/cli-runtime v0.33.2 // indirect
        k8s.io/klog/v2 v2.130.1 // indirect
        k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
        k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 // indirect
+       sigs.k8s.io/gateway-api v1.3.0 // indirect
+       sigs.k8s.io/gateway-api-inference-extension v0.5.0 // indirect
        sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
        sigs.k8s.io/kustomize/api v0.19.0 // indirect
        sigs.k8s.io/kustomize/kyaml v0.19.0 // indirect
+       sigs.k8s.io/mcs-api v0.1.1-0.20240624222831-d7001fe1d21c // indirect
        sigs.k8s.io/randfill v1.0.0 // indirect
        sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
 )
diff --git a/go.sum b/go.sum
index de0c4407..82d02396 100644
--- a/go.sum
+++ b/go.sum
@@ -1,3 +1,5 @@
+cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
+cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
 cloud.google.com/go v0.26.0/go.mod 
h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.114.0 h1:OIPFAdfrFDFO2ve2U7r/H5SwSbBzEdrBdE7xkgwc+kY=
 cloud.google.com/go v0.114.0/go.mod 
h1:ZV9La5YYxctro1HTPug5lXH/GefROyW8PPD4T8n9J8E=
@@ -87,6 +89,8 @@ github.com/andybalholm/cascadia v1.3.2 
h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsVi
 github.com/andybalholm/cascadia v1.3.2/go.mod 
h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be 
h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod 
h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
+github.com/antlr4-go/antlr/v4 v4.13.1 
h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
+github.com/antlr4-go/antlr/v4 v4.13.1/go.mod 
h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
 github.com/apex/log v1.9.0 h1:FHtw/xuaM8AgmvDDTI9fiwoAL25Sq2cxojnZICUU8l0=
 github.com/apex/log v1.9.0/go.mod 
h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA=
 github.com/apex/logs v1.0.0/go.mod 
h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo=
@@ -160,6 +164,8 @@ github.com/buildpacks/pack v0.30.0 
h1:1beK8QAp7By4K40QigYl9JG/Os4nA93dQxYR/GMMbT
 github.com/buildpacks/pack v0.30.0/go.mod 
h1:ZtkyUJKcTdWgEDFi0KOmtHQAOkeQeOeJ2wre1+0ipnA=
 github.com/cenkalti/backoff v2.2.1+incompatible 
h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
 github.com/cenkalti/backoff v2.2.1+incompatible/go.mod 
h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
+github.com/cenkalti/backoff/v4 v4.3.0 
h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
+github.com/cenkalti/backoff/v4 v4.3.0/go.mod 
h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod 
h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/certifi/gocertifi v0.0.0-20190105021004-abcd57078448/go.mod 
h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
 github.com/cespare/xxhash v1.1.0 
h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
@@ -182,6 +188,8 @@ github.com/chzyer/test v1.0.0/go.mod 
h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38
 github.com/client9/misspell v0.3.4/go.mod 
h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cloudflare/circl v1.3.7 
h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
 github.com/cloudflare/circl v1.3.7/go.mod 
h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
+github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 
h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls=
+github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod 
h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
 github.com/containerd/containerd v1.7.27 
h1:yFyEyojddO3MIGVER2xJLWoCIn+Up4GaHFquP7hsFII=
 github.com/containerd/containerd v1.7.27/go.mod 
h1:xZmPnl75Vc+BLGt4MIfu6bp+fy03gdHAn9bz+FreFR0=
 github.com/containerd/continuity v0.4.5 
h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4=
@@ -205,6 +213,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
 github.com/davecgh/go-spew v1.1.1/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc 
h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 
h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod 
h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
 github.com/dgraph-io/ristretto v0.0.1 
h1:cJwdnj42uV8Jg4+KLrYovLiCgIfz9wtWm6E6KA+1tLs=
 github.com/dgraph-io/ristretto v0.0.1/go.mod 
h1:T40EBc7CJke8TkpiYfGGKAeFjSaxuFXhuXRyumBd6RE=
 github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 
h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
@@ -239,7 +249,13 @@ github.com/emicklei/go-restful/v3 v3.12.2/go.mod 
h1:6n3XBCmQQb25CM2LCACGz8ukIrRr
 github.com/emirpasic/gods v1.18.1 
h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
 github.com/emirpasic/gods v1.18.1/go.mod 
h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
 github.com/envoyproxy/go-control-plane 
v0.9.1-0.20191026205805-5f8ba28d4473/go.mod 
h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane/contrib 
v1.32.5-0.20250627145903-197b96a9c7f8 
h1:KXgXPtBofHkRHr+8dO058dGZnLHapW7m0yJEgSYdAFA=
+github.com/envoyproxy/go-control-plane/contrib 
v1.32.5-0.20250627145903-197b96a9c7f8/go.mod 
h1:Nx/YcyEeIcgjT13QwKHdcPmS060urxZ835MeO8cLOrg=
+github.com/envoyproxy/go-control-plane/envoy 
v1.32.5-0.20250627145903-197b96a9c7f8 
h1:/F9jLyfDeNr4iZxyibtKlZxCDqCFEhoYiLdc9VOZT2E=
+github.com/envoyproxy/go-control-plane/envoy 
v1.32.5-0.20250627145903-197b96a9c7f8/go.mod 
h1:09qwbGVuSWWAyN5t/b3iyVfz5+z8QWGrzkoqm/8SbEs=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod 
h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/envoyproxy/protoc-gen-validate v1.2.1 
h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8=
+github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod 
h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
 github.com/fatih/color v1.7.0/go.mod 
h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
 github.com/fatih/color v1.18.0/go.mod 
h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
@@ -276,6 +292,7 @@ github.com/go-git/go-git-fixtures/v4 
v4.3.2-0.20231010084843-55a94097c399/go.mod
 github.com/go-git/go-git/v5 v5.13.1 
h1:DAQ9APonnlvSWpvolXWIuV6Q6zXy2wHbN4cVlNR5Q+M=
 github.com/go-git/go-git/v5 v5.13.1/go.mod 
h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0qu3XXXVixc=
 github.com/go-logfmt/logfmt v0.4.0/go.mod 
h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-logr/logr v1.2.2/go.mod 
h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
 github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
 github.com/go-logr/logr v1.4.3/go.mod 
h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
@@ -288,10 +305,13 @@ github.com/go-openapi/swag v0.23.1 
h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZ
 github.com/go-openapi/swag v0.23.1/go.mod 
h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0=
 github.com/go-sql-driver/mysql v1.7.1 
h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
 github.com/go-sql-driver/mysql v1.7.1/go.mod 
h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 
h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
 github.com/go-task/slim-sprig/v3 v3.0.0 
h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
 github.com/go-task/slim-sprig/v3 v3.0.0/go.mod 
h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
 github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
 github.com/gobwas/glob v0.2.3/go.mod 
h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
+github.com/goccy/go-json v0.10.5 
h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
+github.com/goccy/go-json v0.10.5/go.mod 
h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
 github.com/gofrs/uuid v3.2.0+incompatible/go.mod 
h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
 github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2/go.mod 
h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
@@ -319,6 +339,8 @@ github.com/golang/protobuf v1.5.4 
h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek
 github.com/golang/protobuf v1.5.4/go.mod 
h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
 github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
 github.com/google/btree v1.1.3/go.mod 
h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
+github.com/google/cel-go v0.25.0 
h1:jsFw9Fhn+3y2kBbltZR4VEz5xKkcIFRPDnuEzAGv5GY=
+github.com/google/cel-go v0.25.0/go.mod 
h1:hjEb6r5SuOSlhCHmFoLzu8HGCERvIsDAbxDAyNU/MmI=
 github.com/google/generative-ai-go v0.15.1 
h1:n8aQUpvhPOlGVuM2DRkJ2jvx04zpp42B778AROJa+pQ=
 github.com/google/generative-ai-go v0.15.1/go.mod 
h1:AAucpWZjXsDKhQYWvCYuP6d0yB1kX998pJlOW1rAesw=
 github.com/google/gnostic-models v0.6.9 
h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=
@@ -358,8 +380,13 @@ github.com/gorilla/css v1.0.0 
h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
 github.com/gorilla/css v1.0.0/go.mod 
h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
 github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
 github.com/gorilla/mux v1.8.1/go.mod 
h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
+github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 
h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
+github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod 
h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
 github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 
h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
 github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod 
h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0 
h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 
h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod 
h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
 github.com/hashicorp/errwrap v1.0.0/go.mod 
h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
 github.com/hashicorp/errwrap v1.1.0 
h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
 github.com/hashicorp/errwrap v1.1.0/go.mod 
h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -410,8 +437,23 @@ github.com/kr/pty v1.1.1/go.mod 
h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod 
h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod 
h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/kylelemons/godebug v1.1.0 
h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
+github.com/kylelemons/godebug v1.1.0/go.mod 
h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
 github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 
h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
 github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod 
h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
+github.com/lestrrat-go/backoff/v2 v2.0.8 
h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A=
+github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod 
h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y=
+github.com/lestrrat-go/blackmagic v1.0.3 
h1:94HXkVLxkZO9vJI/w2u1T0DAoprShFd13xtnSINtDWs=
+github.com/lestrrat-go/blackmagic v1.0.3/go.mod 
h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw=
+github.com/lestrrat-go/httpcc v1.0.1 
h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
+github.com/lestrrat-go/httpcc v1.0.1/go.mod 
h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
+github.com/lestrrat-go/iter v1.0.2 
h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
+github.com/lestrrat-go/iter v1.0.2/go.mod 
h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
+github.com/lestrrat-go/jwx v1.2.31 
h1:/OM9oNl/fzyldpv5HKZ9m7bTywa7COUfg8gujd9nJ54=
+github.com/lestrrat-go/jwx v1.2.31/go.mod 
h1:eQJKoRwWcLg4PfD5CFA5gIZGxhPgoPYq9pZISdxLf0c=
+github.com/lestrrat-go/option v1.0.0/go.mod 
h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
+github.com/lestrrat-go/option v1.0.1 
h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
+github.com/lestrrat-go/option v1.0.1/go.mod 
h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
 github.com/lucasb-eyer/go-colorful v1.2.0 
h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
 github.com/lucasb-eyer/go-colorful v1.2.0/go.mod 
h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
 github.com/magiconair/properties v1.8.1/go.mod 
h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@@ -452,6 +494,8 @@ github.com/moby/docker-image-spec v1.3.1 
h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3N
 github.com/moby/docker-image-spec v1.3.1/go.mod 
h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
 github.com/moby/patternmatcher v0.6.0 
h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
 github.com/moby/patternmatcher v0.6.0/go.mod 
h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
+github.com/moby/spdystream v0.5.0 
h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=
+github.com/moby/spdystream v0.5.0/go.mod 
h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
 github.com/moby/sys/capability v0.4.0 
h1:4D4mI6KlNtWMCM1Z/K0i7RV1FkX+DBDHKVJpCndZoHk=
 github.com/moby/sys/capability v0.4.0/go.mod 
h1:4g9IK291rVkms3LKCDOoYlnV8xKwoDTpIrNEE35Wq0I=
 github.com/moby/sys/mountinfo v0.7.2 
h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
@@ -475,6 +519,8 @@ github.com/morikuni/aec v1.0.0 
h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
 github.com/morikuni/aec v1.0.0/go.mod 
h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 
h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod 
h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f 
h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod 
h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
 github.com/nikolalohinski/gonja v1.5.3 
h1:GsA+EEaZDZPGJ8JtpeGN78jidhOlxeJROpqMT9fTj9c=
 github.com/nikolalohinski/gonja v1.5.3/go.mod 
h1:RmjwxNiXAEqcq1HeK5SSMmqFJvKOfTfXhkJv6YBtPa4=
 github.com/onsi/ginkgo v1.6.0/go.mod 
h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -577,6 +623,8 @@ github.com/spf13/jwalterweatherman v1.1.0/go.mod 
h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0
 github.com/spf13/pflag v1.0.3/go.mod 
h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
 github.com/spf13/pflag v1.0.6/go.mod 
h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/stoewer/go-strcase v1.3.0 
h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
+github.com/stoewer/go-strcase v1.3.0/go.mod 
h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
 github.com/stretchr/objx v0.1.0/go.mod 
h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod 
h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod 
h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
@@ -590,6 +638,7 @@ github.com/stretchr/testify v1.6.1/go.mod 
h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.7.0/go.mod 
h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod 
h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod 
h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1/go.mod 
h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/stretchr/testify v1.8.2/go.mod 
h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/stretchr/testify v1.10.0 
h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
 github.com/stretchr/testify v1.10.0/go.mod 
h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
@@ -649,6 +698,12 @@ 
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRND
 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod 
h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
 go.opentelemetry.io/otel v1.36.0 
h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
 go.opentelemetry.io/otel v1.36.0/go.mod 
h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 
h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod 
h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 
h1:m639+BofXTvcY1q8CGs4ItwQarYtJPOWmVobfM1HpVI=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod 
h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo=
+go.opentelemetry.io/otel/exporters/prometheus v0.57.0 
h1:AHh/lAP1BHrY5gBwk8ncc25FXWm/gmmY3BX258z5nuk=
+go.opentelemetry.io/otel/exporters/prometheus v0.57.0/go.mod 
h1:QpFWz1QxqevfjwzYdbMb4Y1NnlJvqSGwyuU0B4iuc9c=
 go.opentelemetry.io/otel/metric v1.36.0 
h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
 go.opentelemetry.io/otel/metric v1.36.0/go.mod 
h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
 go.opentelemetry.io/otel/sdk v1.36.0 
h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
@@ -657,8 +712,12 @@ go.opentelemetry.io/otel/sdk/metric v1.36.0 
h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFw
 go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod 
h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
 go.opentelemetry.io/otel/trace v1.36.0 
h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
 go.opentelemetry.io/otel/trace v1.36.0/go.mod 
h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
+go.opentelemetry.io/proto/otlp v1.7.0 
h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os=
+go.opentelemetry.io/proto/otlp v1.7.0/go.mod 
h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo=
 go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 
h1:Ss6D3hLXTM0KobyBYEAygXzFfGcjnmfEJOBgSbemCtg=
 go.starlark.net v0.0.0-20230302034142-4b1e35fe2254/go.mod 
h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds=
+go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
+go.uber.org/atomic v1.11.0/go.mod 
h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
 go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
 go.uber.org/automaxprocs v1.6.0/go.mod 
h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
 go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
@@ -845,18 +904,24 @@ honnef.co/go/tools 
v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh
 honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod 
h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 istio.io/api v1.26.3 h1:/TiA7bJi24yBQSgpLy5vHhFkobf4DWS1L+CuUxNk4os=
 istio.io/api v1.26.3/go.mod h1:DTVGH6CLXj5W8FF9JUD3Tis78iRgT1WeuAnxfTz21Wg=
-istio.io/istio v0.0.0-20250731222504-fc3ff90a82a6 
h1:+wiauOGcIOzomDmRyRw46lZHfJctKO2WahHcjJssQfg=
-istio.io/istio v0.0.0-20250731222504-fc3ff90a82a6/go.mod 
h1:n2Rl5PCQ3uQOAFYZqeXTA4z/oVvc1Fj1VfkBs+qRS2Q=
+istio.io/client-go v1.26.0-alpha.0.0.20250731213105-2f06e3d976fe 
h1:A3m5j1PRh1J/Y1YkDHP7wqaaIoxdK0NuFFNewwEqNHQ=
+istio.io/client-go v1.26.0-alpha.0.0.20250731213105-2f06e3d976fe/go.mod 
h1:QE8FEo9JtZNOrXjzYTsKq8kzb9f3xt/Mkp0XXUvg5Hc=
+istio.io/istio v0.0.0-20250801115405-9aa2567b5daf 
h1:nAxrB4KVuux87MkeVn2wYtXDdgTNQdmRsg7qlSk/lvE=
+istio.io/istio v0.0.0-20250801115405-9aa2567b5daf/go.mod 
h1:n2Rl5PCQ3uQOAFYZqeXTA4z/oVvc1Fj1VfkBs+qRS2Q=
 k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY=
 k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs=
 k8s.io/apiextensions-apiserver v0.33.2 
h1:6gnkIbngnaUflR3XwE1mCefN3YS8yTD631JXQhsU6M8=
 k8s.io/apiextensions-apiserver v0.33.2/go.mod 
h1:IvVanieYsEHJImTKXGP6XCOjTwv2LUMos0YWc9O+QP8=
 k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
 k8s.io/apimachinery v0.33.2/go.mod 
h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
+k8s.io/apiserver v0.33.2 h1:KGTRbxn2wJagJowo29kKBp4TchpO1DRO3g+dB/KOJN4=
+k8s.io/apiserver v0.33.2/go.mod h1:9qday04wEAMLPWWo9AwqCZSiIn3OYSZacDyu/AcoM/M=
 k8s.io/cli-runtime v0.33.2 h1:koNYQKSDdq5AExa/RDudXMhhtFasEg48KLS2KSAU74Y=
 k8s.io/cli-runtime v0.33.2/go.mod 
h1:gnhsAWpovqf1Zj5YRRBBU7PFsRc6NkEkwYNQE+mXL88=
 k8s.io/client-go v0.33.2 h1:z8CIcc0P581x/J1ZYf4CNzRKxRvQAwoAolYPbtQes+E=
 k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo=
+k8s.io/component-base v0.33.2 h1:sCCsn9s/dG3ZrQTX/Us0/Sx2R0G5kwa0wbZFYoVp/+0=
+k8s.io/component-base v0.33.2/go.mod 
h1:/41uw9wKzuelhN+u+/C59ixxf4tYQKW7p32ddkYNe2k=
 k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
 k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
 k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff 
h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
@@ -867,12 +932,20 @@ k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 
h1:jgJW5IePPXLGB8e/1wvd0Ich9QE97
 k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979/go.mod 
h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
 nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
 nhooyr.io/websocket v1.8.7/go.mod 
h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
+sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.32.1 
h1:Cf+ed5N8038zbsaXFO7mKQDi/+VcSRafb0jM84KX5so=
+sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.32.1/go.mod 
h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
+sigs.k8s.io/gateway-api v1.3.0 h1:q6okN+/UKDATola4JY7zXzx40WO4VISk7i9DIfOvr9M=
+sigs.k8s.io/gateway-api v1.3.0/go.mod 
h1:d8NV8nJbaRbEKem+5IuxkL8gJGOZ+FJ+NvOIltV8gDk=
+sigs.k8s.io/gateway-api-inference-extension v0.5.0 
h1:bYtXffUF1WUUFT2gYXaQBXIEXxXq/ZZLP9gqQweTrBI=
+sigs.k8s.io/gateway-api-inference-extension v0.5.0/go.mod 
h1:lki0jx1qysZSZT4Ai2BxuAcpx6G8g5oBgOGuuJzjy/k=
 sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 
h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
 sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod 
h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
 sigs.k8s.io/kustomize/api v0.19.0 
h1:F+2HB2mU1MSiR9Hp1NEgoU2q9ItNOaBJl0I4Dlus5SQ=
 sigs.k8s.io/kustomize/api v0.19.0/go.mod 
h1:/BbwnivGVcBh1r+8m3tH1VNxJmHSk1PzP5fkP6lbL1o=
 sigs.k8s.io/kustomize/kyaml v0.19.0 
h1:RFge5qsO1uHhwJsu3ipV7RNolC7Uozc0jUBC/61XSlA=
 sigs.k8s.io/kustomize/kyaml v0.19.0/go.mod 
h1:FeKD5jEOH+FbZPpqUghBP8mrLjJ3+zD3/rf9NNu1cwY=
+sigs.k8s.io/mcs-api v0.1.1-0.20240624222831-d7001fe1d21c 
h1:F7hIEutAxtXDOQX9NXFdvhWmWETu2zmUPHuPPcAez7g=
+sigs.k8s.io/mcs-api v0.1.1-0.20240624222831-d7001fe1d21c/go.mod 
h1:DPFniRsBzCeLB4ANjlPEvQQt9QGIX489d1faK+GPvI4=
 sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod 
h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
 sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
 sigs.k8s.io/randfill v1.0.0/go.mod 
h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
diff --git a/navigator/cmd/navi-agent/app/cmd.go 
b/navigator/cmd/navi-agent/app/cmd.go
index ed03bd0a..0a43e7a2 100644
--- a/navigator/cmd/navi-agent/app/cmd.go
+++ b/navigator/cmd/navi-agent/app/cmd.go
@@ -21,6 +21,7 @@ import (
        "fmt"
        "github.com/apache/dubbo-kubernetes/navigator/cmd/navi-agent/options"
        "github.com/apache/dubbo-kubernetes/pkg/cmd"
+       "github.com/apache/dubbo-kubernetes/pkg/config/constants"
        "github.com/apache/dubbo-kubernetes/pkg/model"
        "github.com/spf13/cobra"
 )
@@ -58,6 +59,7 @@ func newProxyCommand() *cobra.Command {
                        UnknownFlags: true,
                },
                RunE: func(c *cobra.Command, args []string) error {
+                       cmd.PrintFlags(c.Flags())
                        err := initProxy(args)
                        if err != nil {
                                return err
@@ -80,4 +82,10 @@ func initProxy(args []string) error {
 
 func addFlags(proxyCmd *cobra.Command) {
        proxyArgs = options.NewProxyArgs()
+       proxyCmd.PersistentFlags().StringVar(&proxyArgs.DNSDomain, "domain", "",
+               "DNS domain suffix. If not provided uses 
${POD_NAMESPACE}.svc.cluster.local")
+       proxyCmd.PersistentFlags().StringVar(&proxyArgs.MeshConfigFile, 
"meshConfig", "./etc/dubbo/config/mesh",
+               "File name for Dubbo mesh configuration. If not specified, a 
default mesh will be used. This may be overridden by "+
+                       "PROXY_CONFIG environment variable or 
proxy.dubbo.io/config annotation.")
+       proxyCmd.PersistentFlags().StringVar(&proxyArgs.ServiceCluster, 
"serviceCluster", constants.ServiceClusterName, "Service cluster")
 }
diff --git a/navigator/cmd/navi-agent/options/agent_proxy.go 
b/navigator/cmd/navi-agent/options/agent_proxy.go
index aeba967e..991ee64b 100644
--- a/navigator/cmd/navi-agent/options/agent_proxy.go
+++ b/navigator/cmd/navi-agent/options/agent_proxy.go
@@ -22,6 +22,8 @@ import naviagent 
"github.com/apache/dubbo-kubernetes/pkg/navi-agent"
 // ProxyArgs provides all of the configuration parameters for the Navi proxy.
 type ProxyArgs struct {
        naviagent.Proxy
+       MeshConfigFile string
+       ServiceCluster string
 }
 
 func NewProxyArgs() ProxyArgs {
diff --git a/navigator/pkg/bootstrap/mesh.go b/navigator/pkg/bootstrap/mesh.go
new file mode 100644
index 00000000..224f79ec
--- /dev/null
+++ b/navigator/pkg/bootstrap/mesh.go
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package bootstrap
+
+import (
+       "fmt"
+       "github.com/apache/dubbo-kubernetes/navigator/pkg/features"
+       "github.com/apache/dubbo-kubernetes/pkg/config/mesh/kubemesh"
+       "github.com/apache/dubbo-kubernetes/pkg/filewatcher"
+       "github.com/apache/dubbo-kubernetes/pkg/kube/krt"
+       "github.com/apache/dubbo-kubernetes/pkg/mesh/meshwatcher"
+       "os"
+)
+
+const (
+       defaultMeshConfigMapName = "dubbo"
+)
+
+func (s *Server) initMeshConfiguration(args *NaviArgs, fileWatcher 
filewatcher.FileWatcher) {
+       fmt.Printf("initializing mesh configuration %v", args.MeshConfigFile)
+       col := s.getMeshConfiguration(args, fileWatcher)
+       col.AsCollection().WaitUntilSynced(s.internalStop)
+}
+
+func (s *Server) getMeshConfiguration(args *NaviArgs, fileWatcher 
filewatcher.FileWatcher) krt.Singleton[meshwatcher.MeshConfigResource] {
+       opts := krt.NewOptionsBuilder(s.internalStop, "")
+       sources := s.getConfigurationSources(args, fileWatcher, 
args.MeshConfigFile, kubemesh.MeshConfigKey)
+       if len(sources) == 0 {
+               fmt.Printf("Using default mesh - missing file %s and no k8s 
client", args.MeshConfigFile)
+       }
+       return meshwatcher.NewCollection(opts, sources...)
+}
+
+func (s *Server) getConfigurationSources(args *NaviArgs, fileWatcher 
filewatcher.FileWatcher, file string, cmKey string) 
[]meshwatcher.MeshConfigSource {
+       opts := krt.NewOptionsBuilder(s.internalStop, "")
+       var userMeshConfig *meshwatcher.MeshConfigSource
+       if features.SharedMeshConfig != "" && s.kubeClient != nil {
+       }
+       if _, err := os.Stat(file); !os.IsNotExist(err) {
+               fileSource, err := meshwatcher.NewFileSource(fileWatcher, file, 
opts)
+               if err == nil {
+                       return toSources(fileSource, userMeshConfig)
+               }
+       }
+
+       if s.kubeClient == nil {
+               return nil
+       }
+       // configMapName := getMeshConfigMapName("")
+       // primary := kubemesh.NewConfigMapSource(s.kubeClient, args.Namespace, 
configMapName, cmKey, opts)
+       return nil
+}
+
+func toSources(base meshwatcher.MeshConfigSource, user 
*meshwatcher.MeshConfigSource) []meshwatcher.MeshConfigSource {
+       if user != nil {
+               return []meshwatcher.MeshConfigSource{*user, base}
+       }
+       return []meshwatcher.MeshConfigSource{base}
+}
+
+func getMeshConfigMapName(revision string) string {
+       name := defaultMeshConfigMapName
+       if revision == "" || revision == "default" {
+               return name
+       }
+       return name + "-" + revision
+}
diff --git a/navigator/pkg/bootstrap/server.go 
b/navigator/pkg/bootstrap/server.go
index a917c609..d4436616 100644
--- a/navigator/pkg/bootstrap/server.go
+++ b/navigator/pkg/bootstrap/server.go
@@ -25,6 +25,7 @@ import (
        
"github.com/apache/dubbo-kubernetes/navigator/pkg/serviceregistry/providers"
        "github.com/apache/dubbo-kubernetes/navigator/pkg/xds"
        "github.com/apache/dubbo-kubernetes/pkg/cluster"
+       "github.com/apache/dubbo-kubernetes/pkg/filewatcher"
        "github.com/apache/dubbo-kubernetes/pkg/h2c"
        dubbokeepalive "github.com/apache/dubbo-kubernetes/pkg/keepalive"
        kubelib "github.com/apache/dubbo-kubernetes/pkg/kube"
@@ -56,14 +57,19 @@ type Server struct {
        httpsAddr         string
        httpMux           *http.ServeMux
        httpsMux          *http.ServeMux // webhooks
+       fileWatcher       filewatcher.FileWatcher
+       internalStop      chan struct{}
 }
 
 func NewServer(args *NaviArgs, initFuncs ...func(*Server)) (*Server, error) {
        e := model.NewEnvironment()
        s := &Server{
-               environment: e,
-               server:      server.New(),
-               clusterID:   getClusterID(args),
+               environment:  e,
+               server:       server.New(),
+               clusterID:    getClusterID(args),
+               httpMux:      http.NewServeMux(),
+               fileWatcher:  filewatcher.NewWatcher(),
+               internalStop: make(chan struct{}),
        }
        for _, fn := range initFuncs {
                fn(s)
@@ -80,6 +86,8 @@ func NewServer(args *NaviArgs, initFuncs ...func(*Server)) 
(*Server, error) {
        if err := s.initKubeClient(args); err != nil {
                return nil, fmt.Errorf("error initializing kube client: %v", 
err)
        }
+       s.initMeshConfiguration(args, s.fileWatcher)
+
        return s, nil
 }
 
@@ -191,12 +199,10 @@ func (s *Server) initServers(args *NaviArgs) {
                MaxConcurrentStreams: uint32(features.MaxConcurrentStreams),
        }
        multiplexHandler := h2c.NewHandler(http.HandlerFunc(func(w 
http.ResponseWriter, r *http.Request) {
-               // If we detect gRPC, serve using grpcServer
                if r.ProtoMajor == 2 && 
strings.HasPrefix(r.Header.Get("content-type"), "application/grpc") {
                        s.grpcServer.ServeHTTP(w, r)
                        return
                }
-               // Otherwise, this is meant for the standard HTTP server
                s.httpMux.ServeHTTP(w, r)
        }), h2s)
        s.httpServer = &http.Server{
diff --git a/navigator/pkg/features/navigator.go 
b/navigator/pkg/features/navigator.go
index 56113237..7b2d29ac 100644
--- a/navigator/pkg/features/navigator.go
+++ b/navigator/pkg/features/navigator.go
@@ -23,6 +23,8 @@ import (
 )
 
 var (
+       SharedMeshConfig = env.Register("SHARED_MESH_CONFIG", "",
+               "Additional config map to load for shared MeshConfig settings. 
The standard mesh config will take precedence.").Get()
        EnableUnsafeAssertions = env.Register(
                "UNSAFE_NAVIGATOR_ENABLE_RUNTIME_ASSERTIONS",
                false,
diff --git a/pkg/config/constants/constants.go 
b/pkg/config/constants/constants.go
index aa992b7c..9375dd66 100644
--- a/pkg/config/constants/constants.go
+++ b/pkg/config/constants/constants.go
@@ -21,4 +21,5 @@ const (
        DubboSystemNamespace      = "dubbo-system"
        DefaultClusterLocalDomain = "cluster.local"
        DefaultClusterName        = "Kubernetes"
+       ServiceClusterName        = "dubbo-proxy"
 )
diff --git a/navigator/pkg/features/navigator.go 
b/pkg/config/mesh/kubemesh/watcher.go
similarity index 56%
copy from navigator/pkg/features/navigator.go
copy to pkg/config/mesh/kubemesh/watcher.go
index 56113237..f6713668 100644
--- a/navigator/pkg/features/navigator.go
+++ b/pkg/config/mesh/kubemesh/watcher.go
@@ -15,20 +15,33 @@
  * limitations under the License.
  */
 
-package features
+package kubemesh
 
 import (
-       "github.com/apache/dubbo-kubernetes/pkg/config/constants"
-       "github.com/apache/dubbo-kubernetes/pkg/env"
+       "github.com/apache/dubbo-kubernetes/pkg/kube"
+       "github.com/apache/dubbo-kubernetes/pkg/kube/krt"
+       "github.com/apache/dubbo-kubernetes/pkg/mesh/meshwatcher"
+       v1 "k8s.io/api/core/v1"
 )
 
-var (
-       EnableUnsafeAssertions = env.Register(
-               "UNSAFE_NAVIGATOR_ENABLE_RUNTIME_ASSERTIONS",
-               false,
-               "If enabled, addition runtime asserts will be performed. "+
-                       "These checks are both expensive and panic on failure. 
As a result, this should be used only for testing.",
-       ).Get()
-       ClusterName = env.Register("CLUSTER_ID", constants.DefaultClusterName,
-               "Defines the cluster and service registry that this Dubbod 
instance belongs to").Get()
+const (
+       MeshConfigKey   = "mesh"
+       MeshNetworksKey = "meshNetworks"
 )
+
+func NewConfigMapSource(client kube.Client, namespace, name, key string, opts 
krt.OptionsBuilder) meshwatcher.MeshConfigResource {
+       return meshwatcher.MeshConfigResource{}
+}
+
+func meshConfigMapData(cm *v1.ConfigMap, key string) *string {
+       if cm == nil {
+               return nil
+       }
+
+       cfgYaml, exists := cm.Data[key]
+       if !exists {
+               return nil
+       }
+
+       return &cfgYaml
+}
diff --git a/pkg/filewatcher/fakefilewatcher.go 
b/pkg/filewatcher/fakefilewatcher.go
new file mode 100644
index 00000000..731c6c67
--- /dev/null
+++ b/pkg/filewatcher/fakefilewatcher.go
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package filewatcher
+
+import (
+       "errors"
+       "fmt"
+       "sync"
+
+       "github.com/fsnotify/fsnotify"
+)
+
+// NewFileWatcherFunc returns a function which creates a new file
+// watcher. This may be used to provide test hooks for using the
+// FakeWatcher implementation below.
+type NewFileWatcherFunc func() FileWatcher
+
+// FakeWatcher provides a fake file watcher implementation for unit
+// tests. Production code should use the `NewWatcher()`.
+type FakeWatcher struct {
+       sync.Mutex
+
+       events      map[string]chan fsnotify.Event
+       errors      map[string]chan error
+       changedFunc func(path string, added bool)
+}
+
+// InjectEvent injects an event into the fake file watcher.
+func (w *FakeWatcher) InjectEvent(path string, event fsnotify.Event) {
+       w.Lock()
+       ch, ok := w.events[path]
+       w.Unlock()
+
+       if ok {
+               ch <- event
+       }
+}
+
+// InjectError injects an error into the fake file watcher.
+func (w *FakeWatcher) InjectError(path string, err error) {
+       w.Lock()
+       ch, ok := w.errors[path]
+       w.Unlock()
+
+       if ok {
+               ch <- err
+       }
+}
+
+// NewFakeWatcher returns a function which creates a new fake watcher for unit
+// testing. This allows observe callers to inject events and errors per-watched
+// path. changedFunc() provides a callback notification when a new watch is 
added
+// or removed. Production code should use `NewWatcher()`.
+func NewFakeWatcher(changedFunc func(path string, added bool)) 
(NewFileWatcherFunc, *FakeWatcher) {
+       w := &FakeWatcher{
+               events:      make(map[string]chan fsnotify.Event),
+               errors:      make(map[string]chan error),
+               changedFunc: changedFunc,
+       }
+       return func() FileWatcher {
+               return w
+       }, w
+}
+
+// Add is a fake implementation of the FileWatcher interface.
+func (w *FakeWatcher) Add(path string) error {
+       w.Lock()
+
+       // w.events and w.errors are always updated togeather. We only check
+       // the first to determine existence.
+       if _, ok := w.events[path]; ok {
+               w.Unlock()
+               return fmt.Errorf("path %v already exists", path)
+       }
+
+       w.events[path] = make(chan fsnotify.Event, 1000)
+       w.errors[path] = make(chan error, 1000)
+
+       w.Unlock()
+
+       if w.changedFunc != nil {
+               w.changedFunc(path, true)
+       }
+       return nil
+}
+
+// Remove is a fake implementation of the FileWatcher interface.
+func (w *FakeWatcher) Remove(path string) error {
+       w.Lock()
+       defer w.Unlock()
+
+       if _, ok := w.events[path]; !ok {
+               return errors.New("path doesn't exist")
+       }
+
+       delete(w.events, path)
+       delete(w.errors, path)
+       if w.changedFunc != nil {
+               w.changedFunc(path, false)
+       }
+       return nil
+}
+
+// Close is a fake implementation of the FileWatcher interface.
+func (w *FakeWatcher) Close() error {
+       w.Lock()
+       for path, ch := range w.events {
+               close(ch)
+               delete(w.events, path)
+       }
+       for path, ch := range w.errors {
+               close(ch)
+               delete(w.errors, path)
+       }
+       defer w.Unlock()
+       return nil
+}
+
+// Events is a fake implementation of the FileWatcher interface.
+func (w *FakeWatcher) Events(path string) chan fsnotify.Event {
+       w.Lock()
+       defer w.Unlock()
+       return w.events[path]
+}
+
+// Errors is a fake implementation of the FileWatcher interface.
+func (w *FakeWatcher) Errors(path string) chan error {
+       w.Lock()
+       defer w.Unlock()
+       return w.errors[path]
+}
diff --git a/pkg/filewatcher/filewatcher.go b/pkg/filewatcher/filewatcher.go
new file mode 100644
index 00000000..89f0f3c6
--- /dev/null
+++ b/pkg/filewatcher/filewatcher.go
@@ -0,0 +1,194 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package filewatcher
+
+import (
+       "errors"
+       "fmt"
+       "path/filepath"
+       "sync"
+
+       "github.com/fsnotify/fsnotify"
+)
+
+// FileWatcher is an interface that watches a set of files,
+// delivering events to related channel.
+type FileWatcher interface {
+       // Start watching a path. Calling Add multiple times on the same path 
panics.
+       Add(path string) error
+
+       // Stop watching a path. Removing a path that's not currently being 
watched panics.
+       Remove(path string) error
+       Close() error
+       Events(path string) chan fsnotify.Event
+       Errors(path string) chan error
+}
+
+type fileWatcher struct {
+       mu sync.RWMutex
+
+       // The watcher maintain a map of workers,
+       // keyed by watched dir (parent dir of watched files).
+       workers map[string]*workerState
+
+       funcs *patchTable
+}
+
+type workerState struct {
+       worker *worker
+       count  int
+}
+
+// functions that can be replaced in a test setting
+type patchTable struct {
+       newWatcher     func() (*fsnotify.Watcher, error)
+       addWatcherPath func(*fsnotify.Watcher, string) error
+}
+
+// NewWatcher return with a FileWatcher instance that implemented with 
fsnotify.
+func NewWatcher() FileWatcher {
+       return &fileWatcher{
+               workers: map[string]*workerState{},
+
+               // replaceable functions for tests
+               funcs: &patchTable{
+                       newWatcher: fsnotify.NewWatcher,
+                       addWatcherPath: func(watcher *fsnotify.Watcher, path 
string) error {
+                               return watcher.Add(path)
+                       },
+               },
+       }
+}
+
+// Close releases all resources associated with the watcher
+func (fw *fileWatcher) Close() error {
+       fw.mu.Lock()
+       defer fw.mu.Unlock()
+
+       for _, ws := range fw.workers {
+               ws.worker.terminate()
+       }
+       fw.workers = nil
+
+       return nil
+}
+
+// Add a path to watch
+func (fw *fileWatcher) Add(path string) error {
+       fw.mu.Lock()
+       defer fw.mu.Unlock()
+
+       ws, cleanedPath, _, err := fw.getWorker(path)
+       if err != nil {
+               return err
+       }
+
+       if err = ws.worker.addPath(cleanedPath); err == nil {
+               ws.count++
+       }
+
+       return err
+}
+
+// Stop watching a path
+func (fw *fileWatcher) Remove(path string) error {
+       fw.mu.Lock()
+       defer fw.mu.Unlock()
+
+       ws, cleanedPath, parentPath, err := fw.getWorker(path)
+       if err != nil {
+               return err
+       }
+
+       if err = ws.worker.removePath(cleanedPath); err == nil {
+               ws.count--
+               if ws.count == 0 {
+                       ws.worker.terminate()
+                       delete(fw.workers, parentPath)
+               }
+       }
+
+       return err
+}
+
+// Events returns an event notification channel for a path
+func (fw *fileWatcher) Events(path string) chan fsnotify.Event {
+       fw.mu.RLock()
+       defer fw.mu.RUnlock()
+
+       ws, cleanedPath, err := fw.findWorker(path)
+       if err != nil {
+               return nil
+       }
+
+       return ws.worker.eventChannel(cleanedPath)
+}
+
+// Errors returns an error notification channel for a path
+func (fw *fileWatcher) Errors(path string) chan error {
+       fw.mu.RLock()
+       defer fw.mu.RUnlock()
+
+       ws, cleanedPath, err := fw.findWorker(path)
+       if err != nil {
+               return nil
+       }
+
+       return ws.worker.errorChannel(cleanedPath)
+}
+
+func (fw *fileWatcher) getWorker(path string) (*workerState, string, string, 
error) {
+       if fw.workers == nil {
+               return nil, "", "", errors.New("using a closed watcher")
+       }
+
+       cleanedPath := filepath.Clean(path)
+       parentPath, _ := filepath.Split(cleanedPath)
+
+       ws, workerExists := fw.workers[parentPath]
+       if !workerExists {
+               wk, err := newWorker(parentPath, fw.funcs)
+               if err != nil {
+                       return nil, "", "", err
+               }
+
+               ws = &workerState{
+                       worker: wk,
+               }
+
+               fw.workers[parentPath] = ws
+       }
+
+       return ws, cleanedPath, parentPath, nil
+}
+
+func (fw *fileWatcher) findWorker(path string) (*workerState, string, error) {
+       if fw.workers == nil {
+               return nil, "", errors.New("using a closed watcher")
+       }
+
+       cleanedPath := filepath.Clean(path)
+       parentPath, _ := filepath.Split(cleanedPath)
+
+       ws, workerExists := fw.workers[parentPath]
+       if !workerExists {
+               return nil, "", fmt.Errorf("no path registered for %s", path)
+       }
+
+       return ws, cleanedPath, nil
+}
diff --git a/pkg/filewatcher/worker.go b/pkg/filewatcher/worker.go
new file mode 100644
index 00000000..87c7f5e0
--- /dev/null
+++ b/pkg/filewatcher/worker.go
@@ -0,0 +1,268 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package filewatcher
+
+import (
+       "bufio"
+       "bytes"
+       "crypto/sha256"
+       "fmt"
+       "io"
+       "os"
+       "sync"
+
+       "github.com/fsnotify/fsnotify"
+)
+
+type worker struct {
+       mu sync.RWMutex
+
+       // watcher is an fsnotify watcher that watches the parent
+       // dir of watchedFiles.
+       dirWatcher *fsnotify.Watcher
+
+       // The worker maintains a map of channels keyed by watched file path.
+       // The worker watches parent path of given path,
+       // and filters out events of given path, then redirect
+       // to the result channel.
+       // Note that for symlink files, the content in received events
+       // do not have to be related to the file itself.
+       watchedFiles map[string]*fileTracker
+
+       // tracker lifecycle
+       retireTrackerCh chan *fileTracker
+
+       // tells the worker to exit
+       terminateCh chan bool
+}
+
+type fileTracker struct {
+       events chan fsnotify.Event
+       errors chan error
+
+       // Hash sum to indicate if a file has been updated.
+       hash []byte
+}
+
+func newWorker(path string, funcs *patchTable) (*worker, error) {
+       dirWatcher, err := funcs.newWatcher()
+       if err != nil {
+               return nil, err
+       }
+
+       if err = funcs.addWatcherPath(dirWatcher, path); err != nil {
+               _ = dirWatcher.Close()
+               return nil, err
+       }
+
+       wk := &worker{
+               dirWatcher:      dirWatcher,
+               watchedFiles:    make(map[string]*fileTracker),
+               retireTrackerCh: make(chan *fileTracker),
+               terminateCh:     make(chan bool),
+       }
+
+       go wk.listen()
+
+       return wk, nil
+}
+
+func (wk *worker) listen() {
+       wk.loop()
+
+       _ = wk.dirWatcher.Close()
+
+       // drain any retiring trackers that may be pending
+       wk.drainRetiringTrackers()
+
+       // clean up the rest
+       for _, ft := range wk.watchedFiles {
+               retireTracker(ft)
+       }
+}
+
+func (wk *worker) loop() {
+       for {
+               select {
+               case event := <-wk.dirWatcher.Events:
+                       // work on a copy of the watchedFiles map, so that we 
don't interfere
+                       // with the caller's use of the map
+                       for path, ft := range wk.getTrackers() {
+                               if ft.events == nil {
+                                       // tracker has been retired, skip it
+                                       continue
+                               }
+
+                               sum := getHashSum(path)
+                               if !bytes.Equal(sum, ft.hash) {
+                                       ft.hash = sum
+
+                                       select {
+                                       case ft.events <- event:
+                                               // nothing to do
+
+                                       case ft := <-wk.retireTrackerCh:
+                                               retireTracker(ft)
+
+                                       case <-wk.terminateCh:
+                                               return
+                                       }
+                               }
+                       }
+
+               case err := <-wk.dirWatcher.Errors:
+                       for _, ft := range wk.getTrackers() {
+                               if ft.errors == nil {
+                                       // tracker has been retired, skip it
+                                       continue
+                               }
+
+                               select {
+                               case ft.errors <- err:
+                                       // nothing to do
+
+                               case ft := <-wk.retireTrackerCh:
+                                       retireTracker(ft)
+
+                               case <-wk.terminateCh:
+                                       return
+                               }
+                       }
+
+               case ft := <-wk.retireTrackerCh:
+                       retireTracker(ft)
+
+               case <-wk.terminateCh:
+                       return
+               }
+       }
+}
+
+// used only by the worker goroutine
+func (wk *worker) drainRetiringTrackers() {
+       // cleanup any trackers that were in the process
+       // of being retired, but didn't get processed due
+       // to termination
+       for {
+               select {
+               case ft := <-wk.retireTrackerCh:
+                       retireTracker(ft)
+               default:
+                       return
+               }
+       }
+}
+
+// make a local copy of the set of trackers to avoid contention with callers
+// used only by the worker goroutine
+func (wk *worker) getTrackers() map[string]*fileTracker {
+       wk.mu.RLock()
+
+       result := make(map[string]*fileTracker, len(wk.watchedFiles))
+       for k, v := range wk.watchedFiles {
+               result[k] = v
+       }
+
+       wk.mu.RUnlock()
+       return result
+}
+
+// used only by the worker goroutine
+func retireTracker(ft *fileTracker) {
+       close(ft.events)
+       close(ft.errors)
+       ft.events = nil
+       ft.errors = nil
+}
+
+func (wk *worker) terminate() {
+       wk.terminateCh <- true
+}
+
+func (wk *worker) addPath(path string) error {
+       wk.mu.Lock()
+
+       ft := wk.watchedFiles[path]
+       if ft != nil {
+               wk.mu.Unlock()
+               return fmt.Errorf("path %s is already being watched", path)
+       }
+
+       ft = &fileTracker{
+               events: make(chan fsnotify.Event),
+               errors: make(chan error),
+               hash:   getHashSum(path),
+       }
+
+       wk.watchedFiles[path] = ft
+       wk.mu.Unlock()
+
+       return nil
+}
+
+func (wk *worker) removePath(path string) error {
+       wk.mu.Lock()
+
+       ft := wk.watchedFiles[path]
+       if ft == nil {
+               wk.mu.Unlock()
+               return fmt.Errorf("path %s not found", path)
+       }
+
+       delete(wk.watchedFiles, path)
+       wk.mu.Unlock()
+
+       wk.retireTrackerCh <- ft
+       return nil
+}
+
+func (wk *worker) eventChannel(path string) chan fsnotify.Event {
+       wk.mu.RLock()
+       defer wk.mu.RUnlock()
+
+       if ft := wk.watchedFiles[path]; ft != nil {
+               return ft.events
+       }
+
+       return nil
+}
+
+func (wk *worker) errorChannel(path string) chan error {
+       wk.mu.RLock()
+       defer wk.mu.RUnlock()
+
+       if ft := wk.watchedFiles[path]; ft != nil {
+               return ft.errors
+       }
+
+       return nil
+}
+
+// gets the hash of the given file, or nil if there's a problem
+func getHashSum(file string) []byte {
+       f, err := os.Open(file)
+       if err != nil {
+               return nil
+       }
+       defer f.Close()
+       r := bufio.NewReader(f)
+
+       h := sha256.New()
+       _, _ = io.Copy(h, r)
+       return h.Sum(nil)
+}
diff --git a/pkg/kube/controllers/common.go b/pkg/kube/controllers/common.go
new file mode 100644
index 00000000..dc460a41
--- /dev/null
+++ b/pkg/kube/controllers/common.go
@@ -0,0 +1,29 @@
+package controllers
+
+type EventType int
+
+const (
+       // EventAdd is sent when an object is added
+       EventAdd EventType = iota
+
+       // EventUpdate is sent when an object is modified
+       // Captures the modified object
+       EventUpdate
+
+       // EventDelete is sent when an object is deleted
+       // Captures the object at the last known state
+       EventDelete
+)
+
+func (event EventType) String() string {
+       out := "unknown"
+       switch event {
+       case EventAdd:
+               out = "add"
+       case EventUpdate:
+               out = "update"
+       case EventDelete:
+               out = "delete"
+       }
+       return out
+}
diff --git a/pkg/kube/krt/core.go b/pkg/kube/krt/core.go
new file mode 100644
index 00000000..fa267fc1
--- /dev/null
+++ b/pkg/kube/krt/core.go
@@ -0,0 +1,84 @@
+package krt
+
+import "github.com/apache/dubbo-kubernetes/pkg/kube/controllers"
+
+type FetchOption func(*dependency)
+
+type HandlerContext interface {
+       // DiscardResult triggers the result of this invocation to be skipped
+       // This allows a collection to mark that the current state is *invalid* 
and should use the last-known state.
+       //
+       // Note: this differs from returning `nil`, which would otherwise wipe 
out the last known state.
+       //
+       // Note: if the current resource has never been computed, the result 
will not be discarded if it is non-nil. This allows
+       // setting a default. For example, you may always return a static 
default config if the initial results are invalid,
+       // but not revert to this config if later results are invalid. Results 
can unconditionally be discarded by returning nil.
+       DiscardResult()
+       // _internalHandler is an interface that can only be implemented by 
this package.
+       _internalHandler()
+}
+
+type (
+       TransformationEmpty[T any] func(ctx HandlerContext) *T
+)
+
+type Metadata map[string]any
+
+type Event[T any] struct {
+       // Old object, set on Update or Delete.
+       Old *T
+       // New object, set on Add or Update
+       New *T
+       // Event is the change type
+       Event controllers.EventType
+}
+
+type EventStream[T any] interface {
+       Syncer
+       Register(f func(o Event[T])) HandlerRegistration
+       RegisterBatch(f func(o []Event[T]), runExistingState bool) 
HandlerRegistration
+}
+
+type CollectionOption func(*collectionOptions)
+
+type collectionOptions struct {
+       name          string
+       augmentation  func(o any) any
+       stop          <-chan struct{}
+       joinUnchecked bool
+
+       indexCollectionFromString func(string) any
+       metadata                  Metadata
+}
+
+type HandlerRegistration interface {
+       Syncer
+       UnregisterHandler()
+}
+
+type Collection[T any] interface {
+       // GetKey returns an object by its key, if present. Otherwise, nil is 
returned.
+       GetKey(k string) *T
+
+       // List returns all objects in the collection.
+       // Order of the list is undefined.
+       List() []T
+
+       // EventStream provides event handling capabilities for the collection, 
allowing clients to subscribe to changes
+       // and receive notifications when objects are added, modified, or 
removed.
+       EventStream[T]
+
+       // Metadata returns the metadata associated with this collection.
+       // This can be used to store and retrieve arbitrary key-value pairs
+       // that provide additional context or configuration for the collection.
+       Metadata() Metadata
+}
+
+type Singleton[T any] interface {
+       // Get returns the object, or nil if there is none.
+       Get() *T
+       // Register adds an event watcher to the object. Any time it changes, 
the handler will be called
+       Register(f func(o Event[T])) HandlerRegistration
+       AsCollection() Collection[T]
+       Metadata() Metadata
+}
diff --git a/pkg/kube/krt/fetch.go b/pkg/kube/krt/fetch.go
new file mode 100644
index 00000000..4d8408c2
--- /dev/null
+++ b/pkg/kube/krt/fetch.go
@@ -0,0 +1,21 @@
+package krt
+
+func FetchOne[T any](ctx HandlerContext, c Collection[T], opts ...FetchOption) 
*T {
+       res := Fetch[T](ctx, c, opts...)
+       switch len(res) {
+       case 0:
+               return nil
+       case 1:
+               return &res[0]
+       default:
+               panic("FetchOne found for more than 1 item")
+       }
+}
+
+func Fetch[T any](ctx HandlerContext, cc Collection[T], opts ...FetchOption) 
[]T {
+       return fetch[T](ctx, cc, false, opts...)
+}
+
+func fetch[T any](ctx HandlerContext, cc Collection[T], allowMissingContext 
bool, opts ...FetchOption) []T {
+       return nil
+}
diff --git a/pkg/kube/krt/files/files.go b/pkg/kube/krt/files/files.go
new file mode 100644
index 00000000..d00aaf19
--- /dev/null
+++ b/pkg/kube/krt/files/files.go
@@ -0,0 +1,19 @@
+package files
+
+import (
+       "github.com/apache/dubbo-kubernetes/pkg/filewatcher"
+       "github.com/apache/dubbo-kubernetes/pkg/kube/krt"
+)
+
+type FileSingleton[T any] struct {
+       krt.Singleton[T]
+}
+
+func NewFileSingleton[T any](
+       fileWatcher filewatcher.FileWatcher,
+       filename string,
+       readFile func(filename string) (T, error),
+       opts ...krt.CollectionOption,
+) {
+       return
+}
diff --git a/pkg/kube/krt/filter.go b/pkg/kube/krt/filter.go
new file mode 100644
index 00000000..4545782b
--- /dev/null
+++ b/pkg/kube/krt/filter.go
@@ -0,0 +1,3 @@
+package krt
+
+type filter struct{}
diff --git a/pkg/kube/krt/internal.go b/pkg/kube/krt/internal.go
new file mode 100644
index 00000000..58f83b12
--- /dev/null
+++ b/pkg/kube/krt/internal.go
@@ -0,0 +1,26 @@
+package krt
+
+type dependency struct {
+       id             collectionUID
+       collectionName string
+       // Filter over the collection
+       filter *filter
+}
+
+type collectionUID uint64
+
+func GetStop(opts ...CollectionOption) <-chan struct{} {
+       o := buildCollectionOptions(opts...)
+       return o.stop
+}
+
+func buildCollectionOptions(opts ...CollectionOption) collectionOptions {
+       c := &collectionOptions{}
+       for _, o := range opts {
+               o(c)
+       }
+       if c.stop == nil {
+               c.stop = make(chan struct{})
+       }
+       return *c
+}
diff --git a/pkg/kube/krt/options.go b/pkg/kube/krt/options.go
new file mode 100644
index 00000000..c7446c88
--- /dev/null
+++ b/pkg/kube/krt/options.go
@@ -0,0 +1,35 @@
+package krt
+
+type OptionsBuilder struct {
+       namePrefix string
+       stop       <-chan struct{}
+}
+
+type BuilderOption func(opt CollectionOption) OptionsBuilder
+
+func NewOptionsBuilder(stop <-chan struct{}, namePrefix string) OptionsBuilder 
{
+       return OptionsBuilder{
+               namePrefix: namePrefix,
+               stop:       stop,
+       }
+}
+
+func (k OptionsBuilder) WithName(n string) []CollectionOption {
+       name := n
+       if k.namePrefix != "" {
+               name = k.namePrefix + "/" + name
+       }
+       return []CollectionOption{WithStop(k.stop), WithName(name)}
+}
+
+func WithStop(stop <-chan struct{}) CollectionOption {
+       return func(c *collectionOptions) {
+               c.stop = stop
+       }
+}
+
+func WithName(name string) CollectionOption {
+       return func(c *collectionOptions) {
+               c.name = name
+       }
+}
diff --git a/pkg/kube/krt/singleton.go b/pkg/kube/krt/singleton.go
new file mode 100644
index 00000000..414641f3
--- /dev/null
+++ b/pkg/kube/krt/singleton.go
@@ -0,0 +1,35 @@
+package krt
+
+func NewSingleton[O any](hf TransformationEmpty[O], opts ...CollectionOption) 
Singleton[O] {
+       return nil
+}
+
+var (
+       _ Singleton[any] = &collectionAdapter[any]{}
+)
+
+type collectionAdapter[T any] struct {
+       c Collection[T]
+}
+
+func (c collectionAdapter[T]) Get() *T {
+       // Guaranteed to be 0 or 1 len
+       res := c.c.List()
+       if len(res) == 0 {
+               return nil
+       }
+       return &res[0]
+}
+
+func (c collectionAdapter[T]) Metadata() Metadata {
+       // The metadata is passed to the internal dummy collection so just 
return that
+       return c.c.Metadata()
+}
+
+func (c collectionAdapter[T]) Register(f func(o Event[T])) HandlerRegistration 
{
+       return c.c.Register(f)
+}
+
+func (c collectionAdapter[T]) AsCollection() Collection[T] {
+       return c.c
+}
diff --git a/pkg/kube/krt/sync.go b/pkg/kube/krt/sync.go
new file mode 100644
index 00000000..691530a9
--- /dev/null
+++ b/pkg/kube/krt/sync.go
@@ -0,0 +1,5 @@
+package krt
+
+type Syncer interface {
+       WaitUntilSynced(stop <-chan struct{}) bool
+}
diff --git a/pkg/mesh/meshwatcher/collection.go 
b/pkg/mesh/meshwatcher/collection.go
new file mode 100644
index 00000000..04090d47
--- /dev/null
+++ b/pkg/mesh/meshwatcher/collection.go
@@ -0,0 +1,55 @@
+package meshwatcher
+
+import (
+       "fmt"
+       "github.com/apache/dubbo-kubernetes/pkg/filewatcher"
+       "github.com/apache/dubbo-kubernetes/pkg/kube/krt"
+       krtfiles "github.com/apache/dubbo-kubernetes/pkg/kube/krt/files"
+       "github.com/apache/dubbo-kubernetes/pkg/mesh"
+
+       "os"
+       "path"
+)
+
+type MeshConfigSource = krt.Singleton[string]
+
+func NewFileSource(fileWatcher filewatcher.FileWatcher, filename string, opts 
krt.OptionsBuilder) (MeshConfigSource, error) {
+       return krtfiles.NewFileSingleton[string](fileWatcher, filename, 
func(filename string) (string, error) {
+               b, err := os.ReadFile(filename)
+               if err != nil {
+                       return "", err
+               }
+               return string(b), nil
+       }, opts.WithName("Mesh_File_"+path.Base(filename))...)
+}
+
+func NewCollection(opts krt.OptionsBuilder, sources ...MeshConfigSource) 
krt.Singleton[MeshConfigResource] {
+       if len(sources) > 2 {
+               panic("currently only 2 sources are supported")
+       }
+       return krt.NewSingleton[MeshConfigResource](
+               func(ctx krt.HandlerContext) *MeshConfigResource {
+                       meshCfg := mesh.DefaultMeshConfig()
+
+                       for _, attempt := range sources {
+                               s := krt.FetchOne(ctx, attempt.AsCollection())
+                               if s == nil {
+                                       fmt.Println("mesh configuration source 
missing")
+                                       continue
+                               }
+                               n, err := mesh.ApplyMeshConfig(*s, meshCfg)
+                               if err != nil {
+                                       if len(sources) == 1 {
+                                               fmt.Errorf("invalid mesh 
config, using last known state: %v", err)
+                                               ctx.DiscardResult()
+                                               return 
&MeshConfigResource{mesh.DefaultMeshConfig()}
+                                       }
+                                       fmt.Printf("invalid mesh config, 
ignoring: %v", err)
+                                       continue
+                               }
+                               meshCfg = n
+                       }
+                       return &MeshConfigResource{meshCfg}
+               }, opts.WithName("MeshConfig")...,
+       )
+}
diff --git a/pkg/mesh/meshwatcher/mesh.go b/pkg/mesh/meshwatcher/mesh.go
new file mode 100644
index 00000000..27d5ebab
--- /dev/null
+++ b/pkg/mesh/meshwatcher/mesh.go
@@ -0,0 +1,7 @@
+package meshwatcher
+
+import meshconfig "istio.io/api/mesh/v1alpha1"
+
+type MeshConfigResource struct {
+       *meshconfig.MeshConfig
+}
diff --git a/pkg/navi-agent/agent.go b/pkg/navi-agent/agent.go
index aee9c873..e79eecea 100644
--- a/pkg/navi-agent/agent.go
+++ b/pkg/navi-agent/agent.go
@@ -21,5 +21,6 @@ import "github.com/apache/dubbo-kubernetes/pkg/model"
 
 // Shared properties with Pilot Proxy struct.
 type Proxy struct {
-       Type model.NodeType
+       Type      model.NodeType
+       DNSDomain string
 }
diff --git a/pkg/ptr/pointer.go b/pkg/ptr/pointer.go
new file mode 100644
index 00000000..5388152e
--- /dev/null
+++ b/pkg/ptr/pointer.go
@@ -0,0 +1,5 @@
+package ptr
+
+func Of[T any](t T) *T {
+       return &t
+}

Reply via email to