Token导航 LogoToken导航

Agent Skill · 前端设计

kotlin-context-di(kotlin 上下文 di)

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

kotlin-context-di 是前端设计类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为需要联网;许可证信息还不明确,第三方扫描已通过,按安装量在前端设计类的 10,216 个 Skill 里排第 7,853。

总安装 336周安装 14GitHub Stars 13下载 112核验 2026-05-01

安装说明

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

安装方式

通过对话安装

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

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

命令行安装

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

skills.shnpx skills
npx skills add https://github.com/anderssv/the-example --skill kotlin-context-di

这个 Skill 是做什么的

前端设计类 Skill 关注页面结构、视觉规范和组件写法,输出通常是可运行的界面代码。

kotlin-context-di 用于处理 Kotlin 上下文依赖注入相关的 GitHub 协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中围绕仓库状态、Issue 或 PR 进行整理和分析。适用于模块化架构、测试隔离或服务生命周期管理场景,可结合项目结构提供 DI 容器配置建议。

通过 npx skills add 命令从指定 GitHub 仓库安装,需确认是否集成特定 DI 框架或仅提供模式识别能力。使用前应检查仓库维护状态、权限范围,并注意是否会触发文件读写或命令执行,避免影响本地环境或触发安全策略。

适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。

来源仓库内路径:skills/kotlin-context-di

上手步骤

4 步
  1. 1

    确认自己的宿主工具

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

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/anderssv/the-example --skill kotlin-context-di;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

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

  4. 4

    按最小权限试用

    它需要需要联网,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

kotlin-context-di 怎么安装?

在终端执行 npx skills add https://github.com/anderssv/the-example --skill kotlin-context-di。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

kotlin-context-di 支持哪些 AI 工具?

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

kotlin-context-di 需要什么权限?

权限级别是需要联网。该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

kotlin-context-di 是免费的吗?

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

kotlin-context-di 用的人多吗?

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

kotlin-context-di 安全吗?

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

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

值得选的地方

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

先想清楚的地方

  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

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

不太适合

  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

前端设计类 Skill 对比

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

前端设计 · Codex、Claude

8,823,360126,072只读MIT通过
vercel-composition-patterns

Vercel 组合模式 · Codex、Claude

3,858,81625,893需要联网MIT通过
vercel-react-native-skills

Vercel React native skills 前端 · Codex、Claude

2,468,66425,878只读MIT通过
adapt

adapt 搜索 · Codex、Claude

2,027,04023,125操作浏览器未明确通过
bolder

bolder 分析 · Codex、Claude

2,004,28823,130只读未明确通过
kotlin-context-di

kotlin 上下文 di · 本页

33613需要联网未明确通过

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

SKILL.md 原文

STARTER_CHARACTER = 🔌

Manual Dependency Injection with AppDependencies, SystemContext and TestContext

Structure Kotlin applications using manual DI with an interface-first contract (AppDependencies), a production context (SystemContext), and a standalone test context (SystemTestContext). This approach provides type-safe dependency management, full control over initialization, and excellent testability without framework overhead.

Core Pattern: AppDependencies Interface

Define an interface as the contract for all application dependencies. Use nested interfaces to group related components:

interface AppDependencies {
    interface Repositories {
        val customerRepo: CustomerRepository
        val orderRepo: OrderRepository
    }

    interface Clients {
        val paymentClient: PaymentClient
        val emailClient: EmailClient
    }

    interface Services {
        val customerService: CustomerService
        val orderService: OrderService
    }

    val repositories: Repositories
    val clients: Clients
    val services: Services
    val clock: Clock
}

Both production and test contexts implement this interface independently — no inheritance between them.

Why an interface (not an open class):

  • Open classes with constructor parameters force test subclasses to satisfy those parameters, even when test fakes never use them (e.g., creating a dummy DataSource just to satisfy a constructor)
  • lazy doesn't protect against production initialization in subclasses — overriding an eager val in a subclass does NOT prevent the base class initializer from running
  • Interfaces have no constructors and no inherited behavior — test implementations must explicitly provide every dependency
  • Each context handles its own initialization independently — no lazy needed

Production: SystemContext

A plain class implementing AppDependencies — no open, no lazy, eager val initialization throughout. Infrastructure (DataSource, credentials, JWKS) lives directly on SystemContext, not exposed through AppDependencies. Grouping implementations are anonymous objects:

class SystemContext(
    private val config: Config,
) : AppDependencies {
    // Infrastructure — not exposed through AppDependencies
    private val dataSource = HikariDataSource(config.dbConfig)

    override val clock: Clock = Clock.systemDefaultZone()

    override val repositories = object : AppDependencies.Repositories {
        override val customerRepo: CustomerRepository = CustomerRepositoryImpl(dataSource)
        override val orderRepo: OrderRepository = OrderRepositoryImpl(dataSource)
    }

    override val clients = object : AppDependencies.Clients {
        override val paymentClient: PaymentClient = PaymentClientImpl(config.paymentApiKey)
        override val emailClient: EmailClient = EmailClientImpl(config.smtpConfig)
    }

    override val services = object : AppDependencies.Services {
        override val customerService = CustomerService(repositories.customerRepo)
        override val orderService = OrderService(
            repositories.orderRepo,
            clients.paymentClient,
            clients.emailClient,
        )
    }
}

Key characteristics:

  • No open — this class is not designed for extension
  • No lazy — eager initialization throughout
  • No default values in production config — all config must be explicit per environment
  • Infrastructure captured by anonymous objects from the enclosing scope
  • Anonymous objects keep production wiring in one place

Test: SystemTestContext (Standalone)

A standalone class implementing AppDependencies — does NOT extend SystemContext. Uses inner classes for groupings (access to enclosing context properties). Covariant override inference means concrete fake types are available directly — no dual-access needed:

class SystemTestContext(
    dataSource: DataSource? = null,
) : AppDependencies {

    override val clock = TestClock.now()

    inner class TestRepositories : AppDependencies.Repositories {
        override val customerRepo = CustomerRepositoryFake()   // concrete type!
        override val orderRepo = OrderRepositoryFake()         // concrete type!
    }

    inner class TestClients : AppDependencies.Clients {
        override val paymentClient = PaymentClientFake()       // concrete type!
        override val emailClient = EmailClientFake()           // concrete type!
    }

    override val repositories =
        if (dataSource != null) {
            object : AppDependencies.Repositories {
                override val customerRepo = CustomerRepositoryImpl(dataSource)
                override val orderRepo = OrderRepositoryImpl(dataSource)
            }
        } else {
            TestRepositories()
        }

    override val clients = TestClients()

    override val services = object : AppDependencies.Services {
        override val customerService = CustomerService(repositories.customerRepo)
        override val orderService = OrderService(
            repositories.orderRepo,
            clients.paymentClient,
            clients.emailClient,
        )
    }
}

Key characteristics:

  • Does NOT extend SystemContext — no inheritance between production and test
  • Inner class for groupings — allows access to enclosing context properties
  • Covariant override inference — override val repositories = TestRepositories() infers the concrete type, so repositories.customerRepo resolves to CustomerRepositoryFake in test scope
  • No dual-access needed — no separate testRepositories vs repositories
  • Constructor injection with defaults — SystemTestContext(dataSource = realDs) for integration, no-arg for unit tests

Covariant Override Inference

This is the key mechanism that eliminates dual-access properties. When SystemTestContext declares:

override val repositories = TestRepositories()

Kotlin infers the property type as TestRepositories (the concrete type), not AppDependencies.Repositories (the interface type). When test code uses with(SystemTestContext()), the receiver type is SystemTestContext, and repositories.customerRepo resolves to CustomerRepositoryFake.

In tests — direct access to fake methods, no casting needed:

@Test
fun testOrderCreation() {
    with(SystemTestContext()) {
        // Act
        services.orderService.createOrder(customerId, items)

        // Assert — direct access to fake methods via covariant inference
        assertThat(repositories.orderRepo.getSavedOrders())
            .contains(order)
    }
}

Fresh Context Per Test

Create a fresh context per test when fakes are stateful (the common case):

@Test
fun `should save order`() {
    with(SystemTestContext()) {
        services.orderService.createOrder(request)
        assertThat(repositories.orderRepo.getSavedOrders()).hasSize(1)
    }
}

@Test
fun `should not save order when payment fails`() {
    with(SystemTestContext()) {
        clients.paymentClient.failOnNextCharge()
        services.orderService.createOrder(request)
        assertThat(repositories.orderRepo.getSavedOrders()).isEmpty()
    }
}

Why: Fakes are stateful — OrderRepositoryFake accumulates saved orders, EmailClientFake accumulates sent emails. Sharing a context across tests causes state from one test to leak into the next, leading to order-dependent failures and flaky tests.

The with(SystemTestContext()) {...} pattern is idiomatic, cheap (no real I/O), and prevents test pollution.

Share a context only when fakes are truly stateless or when you have explicit reset logic — this is uncommon.

E2E: Delegation for Partial Overrides

For end-to-end tests that need to replace specific services while keeping the rest intact, use Kotlin's delegation:

val testContext = SystemTestContext()
val dependencies = object : AppDependencies by testContext {
    override val services = object : AppDependencies.Services by testContext.services {
        override val orderService = customOrderService
    }
}

This creates a new AppDependencies that delegates everything to testContext except services.orderService, which is replaced with a custom implementation.

Nullable-to-Non-nullable Narrowing in Tests

When production interfaces have nullable dependencies (because configuration may be absent), test implementations can narrow them to non-nullable:

// Production interface — nullable because config may not exist
interface Clients {
    val authClient: AuthClient?
    val notificationClient: NotificationClient?
}

// Test implementation — non-nullable
inner class TestClients : AppDependencies.Clients {
    override val authClient = AuthClientStub()            // non-nullable!
    override val notificationClient = NotificationClientStub()  // non-nullable!
}

This is valid Kotlin because non-nullable types are subtypes of nullable types. Tests never need null checks when accessing test clients, even though production code handles the nullable case. This is a significant ergonomic win — test code stays clean and focused on behavior.

Route Functions Accept AppDependencies

Route functions (or controllers) accept the AppDependencies interface, not the context object — destructure inside:

fun Application.orderRoutes(deps: AppDependencies) {
    routing {
        get("/orders/{id}") {
            val orderId = call.parameters["id"]!!
            val order = deps.services.orderService.getOrder(orderId)
            call.respond(order)
        }

        post("/orders") {
            val request = call.receive<CreateOrderRequest>()
            val order = deps.services.orderService.createOrder(request)
            call.respond(order)
        }
    }
}

Type Safety Benefits

Compile-time checking:

  • Typos caught immediately
  • Refactoring tools work perfectly (rename, move, find usages)
  • Missing dependencies fail at compile time, not runtime

IDE support:

  • Full autocomplete for all dependencies
  • Jump to definition works seamlessly
  • No string-based lookups or reflection

Clear dependency graph:

  • Constructor parameters show exact dependencies
  • Easy to trace where any component is used
  • No hidden framework magic

Integration with Test Doubles

TestContext typically contains Fakes (in-memory implementations of interfaces):

class CustomerRepositoryFake : CustomerRepository {
    private val db = mutableMapOf<String, Customer>()

    override fun save(customer: Customer) {
        db[customer.id] = customer
    }

    override fun findById(id: String): Customer? {
        return db[id]
    }

    // Test-specific methods (not in interface)
    fun getSavedCustomers(): List<Customer> = db.values.toList()
    fun failOnNextSave() { /* ... */ }
}

The TestContext wires these Fakes and exposes them with concrete types via covariant override inference:

class SystemTestContext : AppDependencies {
    inner class TestRepositories : AppDependencies.Repositories {
        override val customerRepo = CustomerRepositoryFake()  // concrete type
    }

    override val repositories = TestRepositories()  // inferred as TestRepositories
}

Now services.customerService uses CustomerRepositoryFake automatically because it references repositories.customerRepo, and tests access fake-specific methods via repositories.customerRepo without casting — the covariant inference gives you the concrete type.

Application Wiring

Main entry point:

fun main() {
    val context = SystemContext(Config.fromEnvironment())

    val app = Application(
        context.services.orderService,
        context.services.userService,
    )

    app.start()
}

Web framework integration (Ktor example):

fun Application.module() {
    val context = SystemContext(Config.fromEnvironment())

    orderRoutes(context)
    userRoutes(context)
}

Routes accept AppDependencies, not the context object. No framework-specific annotations or registrations needed.

Why This Pattern Works

Simplicity:

  • No annotations to learn
  • No configuration files
  • No classpath scanning or reflection
  • Plain Kotlin code

Debuggability:

  • Step through initialization in debugger
  • Set breakpoints in context creation
  • No framework magic hiding behavior

Readability:

  • Dependencies visible in one place
  • Constructor calls show exactly what's needed
  • No surprising behavior from framework lifecycle

Test control:

  • Full control over what gets loaded
  • Fast test startup (only load what you need)
  • Easy to inject test doubles
  • No special test runners or annotations
  • No casting needed to access test-specific methods

Flexibility:

  • Change initialization order easily
  • Add conditional logic (feature flags, environment checks)
  • Compose contexts using delegation

Scalability:

  • Pattern stays simple as project grows
  • More dependencies just mean more properties in context classes
  • No framework limitations or architectural constraints

Anti-patterns

Avoid using open classes for dependency grouping:

// Don't do this — forces test subclasses to satisfy constructor parameters
open class Repositories(private val dataSource: DataSource) {
    open val customerRepo: CustomerRepository = CustomerRepositoryImpl(dataSource)
}

Use interfaces instead — they have no constructors and force explicit implementation.

Avoid lazy in production context:

// Don't do this — lazy doesn't protect against production initialization in subclasses
open class SystemContext {
    open val repositories by lazy { ... }
}

Lazy adds complexity and gives false security. With interface + standalone implementations, each context initializes independently.

Avoid inheritance between production and test contexts:

// Don't do this
class SystemTestContext : SystemContext() {  // Inherits production initialization!
    override val repositories = TestRepositories()
}

Use standalone classes that both implement the AppDependencies interface.

Avoid casting to access test-specific methods:

// Don't do this
val emailClient = clients.emailClient as EmailClientFake
assertThat(emailClient.sentEmails).hasSize(1)

Use covariant override inference — inner class groupings give you concrete types automatically.

Avoid dual-access properties:

// Don't do this
val testRepositories = TestRepositories()
override val repositories: Repositories get() = testRepositories

With standalone test context and covariant override inference, repositories already resolves to TestRepositories.

Avoid deep context hierarchies:

// Too complex
open class DatabaseContext : InfrastructureContext()
open class RepositoryContext : DatabaseContext()
open class ServiceContext : RepositoryContext()
open class SystemContext : ServiceContext()

Keep it flat: one AppDependencies interface with nested interface groups for organization.

Don't mix with annotation-based DI:

// Don't mix patterns
@Inject lateinit var customerService: CustomerService  // Framework DI
val orderService = OrderService(repositories.orderRepo)  // Manual DI

Choose one approach and stick with it.

Migration Path

Adding to existing project:

  1. Create AppDependencies interface with nested grouping interfaces
  2. Create SystemContext implementing it with existing components
  3. Wire main entry point to use context
  4. Gradually move initialization logic into context
  5. Create SystemTestContext and migrate tests incrementally

From framework DI:

  1. Create parallel AppDependencies + SystemContext alongside framework
  2. New code uses the interface-first pattern
  3. Gradually migrate existing code
  4. Remove framework once migration complete

No big-bang rewrite required. Adopt incrementally.

平台分布

Codex

37.36%
按下载量换算42

Claude

29.47%
按下载量换算33

Cursor

17.35%
按下载量换算19

Gemini CLI

9.31%
按下载量换算10

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

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

继续浏览同类 Skills