一键导入
add-screen
Add a new screen to an existing feature module with StateHolder, UI, factories, and tests
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Add a new screen to an existing feature module with StateHolder, UI, factories, and tests
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Quick review of the current diff for bugs, logic errors, convention violations, and test gaps
Scaffold a new feature module with the appropriate layers and MESA conventions
Scaffold a new Strata interactor with interface, implementation, fake, and test
Add missing test cases, targeting a specific file or all changed files on the branch
Bump library versions in gradle.properties and prepare release notes
Diagnose and fix an error from a build failure, stack trace, or error message
基于 SOC 职业分类
| name | add-screen |
| description | Add a new screen to an existing feature module with StateHolder, UI, factories, and tests |
| disable-model-invocation | true |
| argument-hint | <feature-name> <ScreenName> |
Add a new screen to an existing feature module. This scaffolds the Screen, State, Event, StateHolder, UI, and factory wiring within the feature's existing presentation/ layer, plus the Screen definition in api/.
Input: $ARGUMENTS
Extract the feature name and screen name from the input.
Verify the feature module exists at features/<feature-name>/ and has a presentation/ layer. If the feature doesn't exist, suggest running /add-feature first. If the feature exists but has no presentation/ layer, inform the user that this feature is headless and a presentation layer would need to be added first.
Read the existing screen files in the feature module to match:
build.gradle.kts is configuredAlso read existing screens from other features if the current feature has no prior screens.
Ask the user:
@Assisted params on the StateHolder)TrapezeNavigationResult implementation)api/Place at: features/<feature-name>/api/src/main/java/<package>/api/<ScreenName>Screen.kt
@Parcelize
data class <ScreenName>Screen(
// navigation arguments as properties
) : TrapezeScreen
If the screen returns a result, also create the result type:
@Parcelize
data class <ScreenName>Result(
// result properties
) : TrapezeNavigationResult
presentation/Place at: features/<feature-name>/presentation/src/main/java/<package>/presentation/<ScreenName>State.kt
data class <ScreenName>State(
// display properties
val eventSink: (<ScreenName>Event) -> Unit
) : TrapezeState
presentation/Place at: features/<feature-name>/presentation/src/main/java/<package>/presentation/<ScreenName>Event.kt
sealed interface <ScreenName>Event : TrapezeEvent {
// user interactions
}
presentation/Place at: features/<feature-name>/presentation/src/main/java/<package>/presentation/<ScreenName>StateHolder.kt
class <ScreenName>StateHolder @AssistedInject constructor(
// @Assisted params — navigation args extracted from screen by factory
@Assisted private val navigator: TrapezeNavigator,
// injected dependencies
) : TrapezeStateHolder<<ScreenName>Screen, <ScreenName>State, <ScreenName>Event>() {
@Composable
override fun produceState(): <ScreenName>State {
val wrappedSink = wrapEventSink { event ->
when (event) {
// handle events
}
}
return <ScreenName>State(
eventSink = wrappedSink
)
}
@AssistedFactory
fun interface Factory {
fun create(/* nav args, */ navigator: TrapezeNavigator): <ScreenName>StateHolder
}
}
presentation/Place at: features/<feature-name>/presentation/src/main/java/<package>/presentation/<ScreenName>Ui.kt
@Composable
fun <ScreenName>Ui(
state: <ScreenName>State,
modifier: Modifier = Modifier
) {
// stateless composable
}
presentation/Place at: features/<feature-name>/presentation/src/main/java/<package>/presentation/<ScreenName>Factories.kt
@ContributesIntoSet(AppScope::class)
class <ScreenName>StateHolderFactory @Inject constructor(
private val factory: <ScreenName>StateHolder.Factory
) : Trapeze.StateHolderFactory {
override fun create(screen: TrapezeScreen, navigator: TrapezeNavigator?): TrapezeStateHolder<*, *, *>? {
return if (screen is <ScreenName>Screen && navigator != null) {
factory.create(/* extract screen args, */ navigator)
} else null
}
}
@ContributesIntoSet(AppScope::class)
class <ScreenName>UiFactory @Inject constructor() : Trapeze.UiFactory {
override fun create(screen: TrapezeScreen): TrapezeUi<*>? {
return if (screen is <ScreenName>Screen) ::<ScreenName>Ui else null
}
}
Automatically generate test files following the conventions from the /add-tests skill:
src/test/)<ScreenName>StateHolderTest.kt — BehaviorSpec + Turbine via TrapezeStateHolder.test {}:
src/androidTest/)Three files following the robot pattern:
<ScreenName>UiTest.kt — JUnit4 test class using robotrobot/<ScreenName>UiRobot.kt — UI interactions and assertionstestdata/<ScreenName>UiTestData.kt — State factory methodsAll generated files MUST include the Apache 2.0 license header:
/*
* Copyright 2026 Jason Jamieson
*
* Licensed 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.
*/
Run ./gradlew :features:<feature-name>:presentation:compileDebugKotlin to verify compilation.
Report:
Then ask:
/add-interactor <feature-name> <InteractorName>