Token导航 LogoToken导航

Agent Skill · 开发

kmp-networking(KMP 网络)

kmp-networking 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

kmp-networking 是开发类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为接触敏感数据;许可证信息还不明确,第三方扫描已通过,按安装量在开发类的 21,746 个 Skill 里排第 17,767。

总安装 380周安装 16GitHub Stars 42下载 133核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:kmp-networking(KMP 网络)
来源仓库:https://github.com/ahmed3elshaer/everything-claude-code-mobile
仓库路径:skills/kmp-networking
安装命令:
npx skills add https://github.com/ahmed3elshaer/everything-claude-code-mobile --skill kmp-networking
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/ahmed3elshaer/everything-claude-code-mobile --skill kmp-networking

这个 Skill 是做什么的

开发类 Skill 面向写代码、改代码和排查问题,一般会读写仓库文件,部分还会执行构建或测试命令。

kmp-networking 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息。适合在 Codex、Claude、Cursor、Gemini CLI 中围绕仓库状态、代码变更或协作事项进行整理。

通过 npx skills add 命令从指定 GitHub 仓库安装,需结合原始 README 确认具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写操作。注意该技能当前无底部简介,功能以实际仓库内容为准。

来源仓库内路径:skills/kmp-networking

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/ahmed3elshaer/everything-claude-code-mobile --…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要接触敏感数据,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

kmp-networking 怎么安装?

在终端执行 npx skills add https://github.com/ahmed3elshaer/everything-claude-code-mobile --skill kmp-…。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

kmp-networking 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

kmp-networking 需要什么权限?

权限级别是接触敏感数据。该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

kmp-networking 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

kmp-networking 用的人多吗?

公开数据是累计安装 380 次,近一周安装 16 次,下载 133 次,GitHub 42 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

kmp-networking 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 第三方扫描已通过,常见的高风险行为没有命中。

先想清楚的地方

  • 需要接触敏感数据,装到常用环境前要先评估影响面。
  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理开发类任务、又不想每次都手写提示词的人。

不太适合

  • 环境里有大量密钥、凭证,不方便给第三方 Skill 读取的人。
  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

开发类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
skill-vetter

技能审查员 · OpenClaw

8,779,018986操作浏览器MIT-0通过
ontology

本体论 · OpenClaw

6,636,960576只读MIT-0通过
entra-app-registration

内部应用程序注册 · Codex、Claude

6,631,872764接触敏感数据未明确通过
entra-app-registration

内部应用程序注册 · Codex、Claude

3,757,680201接触敏感数据未明确通过
nano-banana-pro

纳米香蕉专业版 · OpenClaw

3,526,898364接触敏感数据MIT-0有提醒
kmp-networking

KMP 网络 · 本页

38042接触敏感数据未明确通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

KMP Networking with Ktor

Configure Ktor client for cross-platform networking with platform-optimized engines.

Dependencies

// build.gradle.kts (shared module)
plugins {
    kotlin("multiplatform")
    kotlin("plugin.serialization")
}

kotlin {
    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation("io.ktor:ktor-client-core:2.3.7")
                implementation("io.ktor:ktor-client-content-negotiation:2.3.7")
                implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.7")
                implementation("io.ktor:ktor-client-logging:2.3.7")
                implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
            }
        }
        val androidMain by getting {
            dependencies {
                implementation("io.ktor:ktor-client-okhttp:2.3.7")
            }
        }
        val iosMain by getting {
            dependencies {
                implementation("io.ktor:ktor-client-darwin:2.3.7")
            }
        }
    }
}

HttpClient Factory

// commonMain/kotlin/network/HttpClientFactory.kt
object HttpClientFactory {
    fun create(
        platform: Platform,
        isDebug: Boolean = false
    ): HttpClient {
        return HttpClient(createEngine(platform)) {
            install(ContentNegotiation) {
                json(Json {
                    ignoreUnknownKeys = true
                    isLenient = true
                    encodeDefaults = false
                })
            }

            if (isDebug) {
                install(Logging) {
                    level = LogLevel.INFO
                    logger = object : Logger {
                        override fun log(message: String) {
                            println("Ktor: $message")
                        }
                    }
                }
            }

            install(Auth) {
                bearer {
                    loadTokens {
                        // Access Token from secure storage
                        BearerTokens(
                            accessTokenStorage.get() ?: "",
                            refreshTokenStorage.get() ?: ""
                        )
                    }
                    refreshTokens {
                        // Refresh token logic
                        val newTokens = authApi.refreshToken()
                        accessTokenStorage.save(newTokens.accessToken)
                        refreshTokenStorage.save(newTokens.refreshToken)
                        BearerTokens(newTokens.accessToken, newTokens.refreshToken)
                    }
                }
            }

            defaultRequest {
                url {
                    protocol = URLProtocol.HTTPS
                    host = "api.example.com"
                }
                header("X-API-Version", "1.0")
                header("X-Platform", platform.name)
            }

            expectSuccess = true
            HttpResponseValidator {
                handleResponseExceptionWithRequest { exception, request ->
                    when (exception) {
                        is ClientRequestException -> {
                            val statusCode = exception.response.status.value
                            when (statusCode) {
                                401 -> throw UnauthorizedException()
                                403 -> throw ForbiddenException()
                                404 -> throw NotFoundException()
                                in 500..599 -> throw ServerException()
                            }
                        }
                        is ServerResponseException -> throw ServerException()
                    }
                }
            }

            install(ResponseObserver) {
                onResponse { response ->
                    // Track response times, errors
                }
            }
        }
    }

    private fun createEngine(platform: Platform): HttpClientEngine {
        return when (platform) {
            Platform.ANDROID -> createOkhttpEngine()
            Platform.IOS -> createDarwinEngine()
        }
    }
}

Platform-Specific Engines

Android (OkHttp)

// androidMain/kotlin/network/OkHttpEngineFactory.kt
fun createOkhttpEngine(): OkHttpEngine {
    val config = OkHttpConfig {
        preconfigured = OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
            .addInterceptor { chain ->
                val request = chain.request().newBuilder()
                    .header("User-Agent", "Android App/1.0")
                    .build()
                chain.proceed(request)
            }
            .addInterceptor(HttpLoggingInterceptor().apply {
                level = if (BuildConfig.DEBUG) {
                    HttpLoggingInterceptor.Level.BODY
                } else {
                    HttpLoggingInterceptor.Level.NONE
                }
            })
            .cache(
                Cache(
                    File(context.cacheDir, "http_cache"),
                    10 * 1024 * 1024 // 10MB
                )
            )
            .build()
    }
    return OkHttpEngine(config)
}

iOS (Darwin)

// iosMain/kotlin/network/DarwinEngineFactory.kt
fun createDarwinEngine(): DarwinEngine {
    val config = DarwinClientConfig {
        configureSession {
            setAllowsCellularAccess(true)
            setAllowsExpensiveNetworkAccess(true)
            setAllowsConstrainedNetworkAccess(true)

            // Configure timeout
            setTimeoutIntervalForRequest(30.0)
            setTimeoutIntervalForResource(60.0)

            // Configure cache
            URLCache(
                sharedCacheDirectory,
                10 * 1024 * 1024 // 10MB
            ).let {
                URLCache.setSharedURLCache(it)
            }
        }
    }
    return DarwinEngine(config)
}

API Service Pattern

// commonMain/kotlin/network/api/UserApi.kt
class UserApi(
    private val client: HttpClient
) {
    suspend fun getUsers(page: Int = 1): PaginatedResponse<User> {
        return client.get("/users") {
            parameter("page", page)
            parameter("limit", 20)
        }.body()
    }

    suspend fun getUser(id: String): User {
        return client.get("/users/$id").body()
    }

    suspend fun createUser(request: CreateUserRequest): User {
        return client.post("/users") {
            setBody(request)
            contentType(ContentType.Application.Json)
        }.body()
    }

    suspend fun updateUser(id: String, request: UpdateUserRequest): User {
        return client.put("/users/$id") {
            setBody(request)
            contentType(ContentType.Application.Json)
        }.body()
    }

    suspend fun deleteUser(id: String) {
        return client.delete("/users/$id")
    }

    suspend fun uploadAvatar(userId: String, file: ByteArray): String {
        return client.submitFormWithBinaryData(
            url = "https://api.example.com/users/$userId/avatar",
            formData = formData {
                append("avatar", file, Headers.build {
                    append(HttpHeaders.ContentDisposition, "filename=avatar.jpg")
                })
            }
        ).body()
    }
}

Network Exceptions

// commonMain/kotlin/network/NetworkExceptions.kt
sealed class NetworkException(message: String? = null) : Exception(message)

class UnauthorizedException : NetworkException("User not authenticated")
class ForbiddenException : NetworkException("Access forbidden")
class NotFoundException : NetworkException("Resource not found")
class ServerException : NetworkException("Server error occurred")
class NetworkUnavailableException : NetworkException("Network unavailable")
class TimeoutException : NetworkException("Request timeout")

// Wrap Ktor exceptions
fun Throwable.toNetworkException(): NetworkException {
    return when (this) {
        is NetworkException -> this
        is ClientRequestException -> when (response.status.value) {
            401 -> UnauthorizedException()
            403 -> ForbiddenException()
            404 -> NotFoundException()
            else -> NetworkException(message)
        }
        is ServerResponseException -> ServerException()
        is HttpRequestTimeoutException -> TimeoutException()
        is UnreachableAddressException,
        is ConnectTimeoutException -> NetworkUnavailableException()
        else -> NetworkException(message ?: "Unknown network error")
    }
}

Result Wrapper

// commonMain/kotlin/network/ApiResult.kt
sealed class ApiResult<out T> {
    data class Success<T>(val data: T) : ApiResult<T>()
    data class Error(val error: NetworkException) : ApiResult<Nothing>()

    suspend fun <R> map(transform: (T) -> R): ApiResult<R> = when (this) {
        is Success -> Success(transform(data))
        is Error -> this
    }

    suspend fun <R> flatMap(transform: (T) -> ApiResult<R>): ApiResult<R> = when (this) {
        is Success -> transform(data)
        is Error -> this
    }

    fun getOrNull(): T? = when (this) {
        is Success -> data
        is Error -> null
    }

    fun getOrElse(defaultValue: T): T = when (this) {
        is Success -> data
        is Error -> defaultValue
    }
}

suspend fun <T> apiCall(block: suspend () -> T): ApiResult<T> = try {
    ApiResult.Success(block())
} catch (e: Exception) {
    ApiResult.Error(e.toNetworkException())
}

// Usage
val result: ApiResult<User> = apiCall { userApi.getUser("123") }
when (result) {
    is ApiResult.Success -> showUser(result.data)
    is ApiResult.Error -> showError(result.error)
}

Retry Logic

// commonMain/kotlin/network/Retry.kt
suspend fun <T> retryApiCall(
    maxRetries: Int = 3,
    delayMs: Long = 1000,
    block: suspend () -> T
): T {
    var lastException: Exception? = null
    repeat(maxRetries) { attempt ->
        try {
            return block()
        } catch (e: Exception) {
            lastException = e
            if (e is NetworkUnavailableException || e is TimeoutException) {
                if (attempt < maxRetries - 1) {
                    delay(delayMs * (attempt + 1))
                }
            } else {
                throw e
            }
        }
    }
    throw lastException ?: RuntimeException("Max retries exceeded")
}

Offline Support

// commonMain/kotlin/network/OfflineCapableApi.kt
class OfflineCapableApi<T : Any>(
    private val api: T,
    private val cache: DatabaseCache
) : OfflineCapableApi<T> by api {

    suspend fun <R> withCache(
        key: String,
        ttl: Duration,
        block: suspend () -> R
    ): R = withContext(Dispatchers.IO) {
        // Try cache first
        cache.get<R>(key)?.let { cached ->
            if (cached.timestamp + ttl.toMillisMilliseconds() > Clock.System.now()) {
                return@withContext cached.data
            }
        }

        // Fetch from network
        try {
            val result = block()
            cache.put(key, CachedData(result, Clock.System.now()))
            result
        } catch (e: NetworkException) {
            // Return stale cache if network fails
            cache.get<R>(key)?.data ?: throw e
        }
    }
}

Dependency Injection Setup

// commonMain/kotlin/di/NetworkModule.kt
val networkModule = module {
    single { HttpClientFactory.create(get(), get()) }
    single { UserApi(get()) }
    single { AuthApi(get()) }
    factory { ConnectivityMonitor(get()) }
}

Best Practices

✅ DO

// ✅ Use typed API services
class UserApi(private val client: HttpClient)

// ✅ Wrap calls in result types
suspend fun getUser(): ApiResult<User>

// ✅ Configure timeouts
config { setTimeoutIntervalForRequest(30.0) }

// ✅ Add logging for debug builds
if (isDebug) { install(Logging) }

// ✅ Handle exceptions at boundaries
try { api.call() } catch (e: NetworkException) { /* handle */ }

❌ DON'T

// ❌ Don't create multiple HttpClient instances
// Use singleton via DI

// ❌ Don't block on suspend calls
runBlocking { api.call() }  // ❌

// ❌ Don't ignore exceptions
try { api.call() } catch (e: Exception) { }  // ❌

// ❌ Don't hardcode URLs
client.get("https://api.example.com/users")  // ❌
// Configure base URL in defaultRequest

Remember: Networking is the bridge between your app and the world. Make it robust, testable, and platform-optimized.

平台分布

Codex

33.2%
按下载量换算44

Claude

31%
按下载量换算41

Cursor

20.47%
按下载量换算27

Gemini CLI

8.87%
按下载量换算12

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

接触敏感数据

该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills