@michaelbel/cuckcoder-mcp 1.6.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/assets/rules/architecture.md +15 -0
  2. package/assets/rules/bottom-sheet.md +20 -0
  3. package/assets/rules/compose-color.md +22 -0
  4. package/assets/rules/compose-constraintlayout.md +18 -0
  5. package/assets/rules/compose-screen.md +33 -0
  6. package/assets/rules/compose-spacing.md +39 -0
  7. package/assets/rules/compose.md +54 -0
  8. package/assets/rules/dialog.md +33 -0
  9. package/assets/rules/domain.md +36 -0
  10. package/assets/rules/filesystem.md +3 -0
  11. package/assets/rules/git.md +11 -0
  12. package/assets/rules/github-readme.md +97 -0
  13. package/assets/rules/github-repo.md +65 -0
  14. package/assets/rules/kmp.md +14 -0
  15. package/assets/rules/kotlin.md +48 -0
  16. package/assets/rules/lazylist.md +36 -0
  17. package/assets/rules/mvi-error-handling.md +19 -0
  18. package/assets/rules/mvi-state.md +31 -0
  19. package/assets/rules/mvi.md +39 -0
  20. package/assets/rules/navigation.md +20 -0
  21. package/assets/rules/network.md +36 -0
  22. package/assets/rules/preview.md +31 -0
  23. package/assets/rules/realtime.md +39 -0
  24. package/assets/rules/resource.md +18 -0
  25. package/assets/rules/room.md +33 -0
  26. package/assets/rules/scaffold.md +25 -0
  27. package/assets/rules/shimmer.md +34 -0
  28. package/assets/rules/textfield.md +31 -0
  29. package/assets/rules/typography.md +32 -0
  30. package/assets/rules/usecase.md +60 -0
  31. package/assets/rules/workflow.md +17 -0
  32. package/assets/rules/workmanager.md +44 -0
  33. package/assets/skills/create-data-layer/SKILL.md +60 -0
  34. package/assets/skills/create-datastore-preference/SKILL.md +80 -0
  35. package/assets/skills/create-domain-mapper/SKILL.md +30 -0
  36. package/assets/skills/create-feature-alert-dialog/SKILL.md +549 -0
  37. package/assets/skills/create-feature-bottom-sheet/SKILL.md +300 -0
  38. package/assets/skills/create-feature-scaffold-screen/SKILL.md +74 -0
  39. package/assets/skills/create-feature-scaffold-screen/references/form-screen.md +20 -0
  40. package/assets/skills/create-feature-scaffold-screen/references/network-only-screen.md +20 -0
  41. package/assets/skills/create-feature-scaffold-screen/references/paginated-screen.md +29 -0
  42. package/assets/skills/create-feature-scaffold-screen/references/room-backed-screen.md +23 -0
  43. package/assets/skills/create-feature-scaffold-screen/references/static-screen.md +13 -0
  44. package/assets/skills/create-guide/SKILL.md +169 -0
  45. package/assets/skills/create-guide/references/android-project.md +120 -0
  46. package/assets/skills/create-guide/references/androidx.md +49 -0
  47. package/assets/skills/create-guide/references/existing-guides.yaml +60 -0
  48. package/assets/skills/create-guide/references/github.md +71 -0
  49. package/assets/skills/create-guide/references/guide-defaults.yaml +51 -0
  50. package/assets/skills/create-guide/references/notion.md +121 -0
  51. package/assets/skills/create-guide/references/output-contract.md +79 -0
  52. package/assets/skills/create-guide/references/research.md +64 -0
  53. package/assets/skills/create-guide/references/validation.md +59 -0
  54. package/assets/skills/create-guide/scripts/validate_guide.py +167 -0
  55. package/assets/skills/create-guide/templates/guide-manifest.yaml +67 -0
  56. package/assets/skills/create-guide/templates/implementation-plan.md +30 -0
  57. package/assets/skills/create-guide/templates/notion-page.md +46 -0
  58. package/assets/skills/create-guide/templates/repository/AGENTS.md +7 -0
  59. package/assets/skills/create-guide/templates/repository/README.md +32 -0
  60. package/assets/skills/create-guide/templates/repository/SOURCES.md +32 -0
  61. package/assets/skills/create-guide/templates/validation-report.md +30 -0
  62. package/assets/skills/create-guide/tests/test_validate_guide.py +97 -0
  63. package/assets/skills/create-ktor-endpoint/SKILL.md +33 -0
  64. package/assets/skills/create-notification-flow/SKILL.md +103 -0
  65. package/assets/skills/create-offline-outbox/SKILL.md +110 -0
  66. package/assets/skills/create-paging-flow/SKILL.md +96 -0
  67. package/assets/skills/create-project-from-template/SKILL.md +91 -0
  68. package/assets/skills/create-project-from-template/assets/icons/android.svg +12 -0
  69. package/assets/skills/create-project-from-template/assets/icons/compose.svg +34 -0
  70. package/assets/skills/create-project-from-template/assets/icons/jetpack.svg +10 -0
  71. package/assets/skills/create-project-from-template/references/myapplication-checklist.md +92 -0
  72. package/assets/skills/create-room-storage/SKILL.md +39 -0
  73. package/assets/skills/create-shared-component/SKILL.md +160 -0
  74. package/assets/skills/create-signalr-channel/SKILL.md +39 -0
  75. package/assets/skills/create-usecase/SKILL.md +142 -0
  76. package/assets/skills/create-workmanager-task/SKILL.md +41 -0
  77. package/assets/skills/github-repo-settings/SKILL.md +152 -0
  78. package/assets/skills/interview-me/SKILL.md +150 -0
  79. package/dist/errors.js +49 -0
  80. package/dist/frontmatter.js +44 -0
  81. package/dist/github.js +23 -0
  82. package/dist/index.js +6 -0
  83. package/dist/server.js +131 -0
  84. package/dist/source/bundled.js +78 -0
  85. package/dist/source/cache.js +61 -0
  86. package/dist/source/github-source.js +68 -0
  87. package/dist/source/github.js +185 -0
  88. package/dist/source/index.js +36 -0
  89. package/dist/source/types.js +1 -0
  90. package/dist/validation.js +33 -0
  91. package/dist/version.js +26 -0
  92. package/package.json +38 -0
@@ -0,0 +1,39 @@
1
+ ---
2
+ name: create-room-storage
3
+ description: >-
4
+ Use when пользователь просит добавить или изменить законченную единицу Room-хранилища: entity,
5
+ DAO, Pojo/relations, регистрацию в AppDatabase, version и migration. Не используй для сетевого
6
+ endpoint, mapper, use case или полного data flow; выбирай соответствующий отдельный skill.
7
+ metadata:
8
+ author: michaelbel
9
+ ---
10
+
11
+ # Создание Room-хранилища
12
+
13
+ Сначала изучи существующие `AppDatabase`, DAO, entity, migrations и соглашения имён таблиц в
14
+ целевом проекте. Сохраняй их стиль и меняй только части схемы, нужные задаче.
15
+
16
+ ## Результат
17
+
18
+ - Создай по одному файлу на `Entity` и Pojo-модель.
19
+ - Создай или расширь один тематический `@Dao` с нужными `Flow`- и suspend-операциями.
20
+ - Зарегистрируй entity и DAO в `AppDatabase`.
21
+ - При любом изменении таблицы/entity увеличь `DATABASE_VERSION` и добавь migration, если проект не
22
+ использует явно destructive/schema-managed стратегию.
23
+ - Обнови schema fixtures/exported schema, если они отслеживаются проектом.
24
+
25
+ ## Инварианты
26
+
27
+ - Объявляй ключи в `@Entity(primaryKeys = [...])`; не используй `@PrimaryKey` на свойствах.
28
+ - Располагай обычные `fun`, включая методы с `Flow`, перед `suspend fun`.
29
+ - Для flow без параметров предпочитай существующую в проекте форму `@get:Query val`; для flow с
30
+ параметрами используй функцию.
31
+ - Добавляй `@Transaction` методам, возвращающим Pojo с отношениями.
32
+ - Предоставляй nullable `select` и отдельный `selectNotNull`, только когда оба контракта реально
33
+ нужны вызывающему коду.
34
+ - Не создавай DAO-метод, который императивно вызывает другие DAO-методы. Несколько записей собирай
35
+ через `AppDatabase.withTransaction` в use case; один DAO-вызов транзакцией не оборачивай.
36
+ - Выбирай `@Upsert`, `@Insert`, `@Update` или `@Delete` по требуемой конфликтной семантике, а не
37
+ автоматически.
38
+
39
+ Проверь компиляцию Room/KSP целевого модуля и migration/schema-тесты, если они есть.
@@ -0,0 +1,160 @@
1
+ ---
2
+ name: create-shared-component
3
+ description: >-
4
+ Use when пользователь просит создать переиспользуемый Compose UI-компонент для
5
+ `shared/ui/components`, или говорит "create a shared component", "add a reusable component", "new
6
+ UI component". Строит либо простой composable с обычными типизированными параметрами (для
7
+ универсальных layout-примитивов), либо composable с `{Component}State`-холдером (для компонентов
8
+ конкретной предметной области, просто вынесенных в отдельный файл), плюс его preview. Не используй
9
+ для диалога; используй вместо этого
10
+ [create-feature-alert-dialog](../create-feature-alert-dialog/SKILL.md). Не используй для bottom
11
+ sheet; используй вместо этого
12
+ [create-feature-bottom-sheet](../create-feature-bottom-sheet/SKILL.md). Не используй для полного
13
+ экрана, привязанного к ViewModel; используй вместо этого
14
+ [create-feature-scaffold-screen](../create-feature-scaffold-screen/SKILL.md).
15
+ metadata:
16
+ author: michaelbel
17
+ ---
18
+
19
+ # Новый общий компонент
20
+
21
+ Требует зависимость `androidx.compose.foundation`.
22
+
23
+ Создаёт переиспользуемый Compose-компонент проекта. Замени `{Component}` на имя компонента
24
+ (например, `SharedCard`, `BarcodeFrameBox`), а `{package}` на целевой пакет.
25
+
26
+ ## Фаза 1: разместить файл компонента
27
+
28
+ Один файл на компонент — `{Component}.kt`. Размещай его прямо в `shared/ui/components`, если это
29
+ универсальный layout-примитив или обёртка (как `SharedRow`, `SharedColumn`); для компонента
30
+ конкретной предметной области создавай тематическую подпапку, например `shared/ui/components/scan`.
31
+
32
+ ## Фаза 2: выбери форму компонента
33
+
34
+ - Универсальный layout-примитив или обёртка, не завязанная на конкретную предметную область (как
35
+ `SharedRow`, `SharedColumn`) — без State, обычные параметры.
36
+ - Компонент, который не такой общий, а просто вынесен в отдельный файл и представляет конкретный
37
+ предметный смысл (иконка-пресет, карточка определённого содержимого и т. д.) — с
38
+ `{Component}State` наверху файла.
39
+
40
+ ## Универсальный примитив (без State)
41
+
42
+ ```kotlin
43
+ package {package}
44
+
45
+ import androidx.compose.runtime.Composable
46
+ import androidx.compose.ui.Modifier
47
+ import androidx.compose.ui.tooling.preview.Preview
48
+
49
+ @Composable
50
+ fun {Component}(
51
+ title: String,
52
+ onClick: () -> Unit,
53
+ modifier: Modifier = Modifier
54
+ ) {
55
+ // component content
56
+ }
57
+
58
+ @Preview(showBackground = true)
59
+ @Composable
60
+ private fun {Component}Preview() {
61
+ {Component}(
62
+ title = "Example",
63
+ onClick = {}
64
+ )
65
+ }
66
+ ```
67
+
68
+ ## Компонент с State
69
+
70
+ Наверху файла размести `{Component}State` — `data class`, если данные варьируются свободно, или
71
+ `sealed class` с несколькими `data object`-вариантами, если у компонента всего пара
72
+ фиксированных пресетов. Сам компонент принимает один параметр `state`; `modifier` добавляй вторым
73
+ параметром, только если он реально нужен.
74
+
75
+ ```kotlin
76
+ package {package}
77
+
78
+ // Добавь все необходимые импорты
79
+
80
+ sealed class {Component}State(
81
+ val iconRes: Int,
82
+ val iconModifier: Modifier
83
+ ) {
84
+ data object SampleA: {Component}State(
85
+ iconRes = AppIcons.SampleA,
86
+ iconModifier = Modifier.size(107.dp, 131.dp)
87
+ )
88
+
89
+ data object SampleB: {Component}State(
90
+ iconRes = AppIcons.SampleB,
91
+ iconModifier = Modifier.size(164.dp, 164.dp)
92
+ )
93
+ }
94
+
95
+ @Composable
96
+ fun {Component}(
97
+ state: {Component}State
98
+ ) {
99
+ Box(
100
+ modifier = Modifier
101
+ .size(192.dp)
102
+ .clip(CircleShape)
103
+ .background(MaterialTheme.colorScheme.surface),
104
+ contentAlignment = Alignment.Center
105
+ ) {
106
+ Icon(
107
+ painter = painterResource(state.iconRes),
108
+ contentDescription = null,
109
+ modifier = state.iconModifier,
110
+ tint = Color.Unspecified
111
+ )
112
+ }
113
+ }
114
+
115
+ @PreviewWrapper(ThemeWrapper::class)
116
+ @Preview
117
+ @Composable
118
+ private fun {Component}Preview(
119
+ @PreviewParameter({Component}StatePreviewParameterProvider::class) state: {Component}State
120
+ ) {
121
+ {Component}(
122
+ state = state
123
+ )
124
+ }
125
+
126
+ private class {Component}StatePreviewParameterProvider: PreviewParameterProvider<{Component}State> {
127
+ override val values: Sequence<{Component}State> = sequenceOf(
128
+ {Component}State.SampleA,
129
+ {Component}State.SampleB
130
+ )
131
+ }
132
+ ```
133
+
134
+ Правила:
135
+ - Универсальный примитив принимает свои данные как обычные типизированные параметры — не
136
+ оборачивай их в `{Component}State`, даже если параметров несколько.
137
+ - Компонент, который не такой общий, а просто вынесен в отдельный файл, оборачивает свои данные в
138
+ `{Component}State` наверху того же файла и принимает единственный параметр `state`; `modifier`
139
+ добавляй вторым параметром только при реальной необходимости.
140
+ - Порядок параметров универсального примитива: сначала обязательные (без значения по умолчанию),
141
+ затем `modifier: Modifier = Modifier`, затем остальные параметры со значением по умолчанию, а
142
+ завершающей идёт обязательная trailing-лямбда `content`, если компонент оборачивает содержимое
143
+ (например `content: @Composable ColumnScope.() -> Unit`).
144
+ - Каждый компонент находится в своём файле; не объявляй несколько компонентов в одном файле.
145
+ - `@PreviewWrapper(ThemeWrapper::class)` используй только для компонента с `{Component}State` —
146
+ ему нужна реальная тема приложения (иконки, цвета). Для универсального примитива без State
147
+ preview — обычный `@Preview`, без `PreviewWrapper`.
148
+ - Указывай `showBackground = true`, только если у компонента нет собственного видимого фона —
149
+ например `Text` или список на прозрачном фоне (`SharedRow`, `SharedColumn`,
150
+ `SharedLazyColumn`). Если компонент сам рисует себе фон или форму (как `SharedDragHandle` или
151
+ `{Component}` с State выше), `showBackground` не нужен.
152
+ - Не создавай preview вовсе, если статичный снимок ничего не покажет без реального взаимодействия
153
+ или внешнего состояния — например обёртка видимости (`SharedAnimatedVisibility`), хост снекбара
154
+ без активного снекбара (`SharedSnackbarHost`) или модальный bottom sheet.
155
+ - Для компонента с `{Component}State` всегда создавай приватный
156
+ `{Component}StatePreviewParameterProvider: PreviewParameterProvider<{Component}State>` в том же
157
+ файле. Для универсального примитива без State создавай `PreviewParameterProvider`, только если у
158
+ компонента есть несколько содержательно разных состояний, которые стоит показать; иначе preview
159
+ вызывает компонент напрямую с представительными литеральными значениями.
160
+ - Preview-функция всегда `private`.
@@ -0,0 +1,39 @@
1
+ ---
2
+ name: create-signalr-channel
3
+ description: >-
4
+ Use when пользователь просит добавить или изменить SignalR hub/channel, realtime DataSource,
5
+ обработчики server events либо подключить канал к session lifecycle. Не используй для Ktor HTTP
6
+ endpoint, Ktor WebSocket или общего socket-решения на другом протоколе.
7
+ metadata:
8
+ author: michaelbel
9
+ ---
10
+
11
+ # Создание SignalR-канала
12
+
13
+ Сначала изучи общую connection factory/infrastructure, существующие `RealtimeDataSource` и
14
+ `StartRealtimeUseCase`. Переиспользуй их retry, authentication и cleanup; не создавай второй
15
+ параллельный менеджер соединений.
16
+
17
+ ## Реализация
18
+
19
+ - Создай один DataSource на один hub/domain и зарегистрируй server event handlers до `start`.
20
+ - Выполни команды подписки после успешного подключения.
21
+ - Для сигнала «authoritative state изменилось» используй приватный `MutableSharedFlow` и публичный
22
+ read-only `SharedFlow`; его допустимо conflated/drop только когда следующий reload получает полное
23
+ состояние. Для каждого обязательного payload-события используй lossless `Channel`/очередь либо
24
+ durable Room-запись, а не `SharedFlow(replay = 0)`.
25
+ - По устойчивому событию вызывай обычный use case для reload/update Room, оставляя Room источником
26
+ истины. Не обновляй UI напрямую payload-ом, если событие должно переживать пересоздание экрана.
27
+ - Подключи запуск DataSource и сбор его событий в `StartRealtimeUseCase`, чтобы смена session через
28
+ отменяемый flow закрывала старые соединения и запускала новые с актуальным токеном.
29
+ - Запусти collectors до connect/initial subscription, например принятым в проекте undispatched
30
+ start; альтернативно гарантируй initial reload после подключения, который перекрывает возможную
31
+ потерю первого invalidation-сигнала.
32
+ - Используй общий retry/backoff. Никогда не поглощай `CancellationException`; cleanup выполняй в
33
+ `finally`, при необходимости в `NonCancellable` с ограниченным timeout.
34
+ - Не допускай двух экземпляров одного hub для одной session и не повторяй retry после logout.
35
+ - Логируй lifecycle и ошибки без access token и чувствительного event payload.
36
+
37
+ Проверь сценарии connect/event/reload, reconnect, session change/logout и отмену во время retry или
38
+ cleanup. Если инфраструктуры realtime ещё нет, отдели shared connection factory от первого
39
+ domain-specific DataSource, не смешивая их ответственность.
@@ -0,0 +1,142 @@
1
+ ---
2
+ name: create-usecase
3
+ description: >-
4
+ Use when пользователь просит добавить один `UseCase` или `FlowUseCase` в
5
+ `shared/domain/usecase` — одну suspend-операцию или один наблюдаемый Flow — или говорит "add a use
6
+ case", "new UseCase", "new FlowUseCase". Предполагает, что требуемые endpoint, DAO/entity и
7
+ мапперы уже существуют. Не используй для их создания, Worker/realtime lifecycle или ViewModel;
8
+ выбери соответствующий атомарный skill либо create-data-layer для составного потока.
9
+ metadata:
10
+ author: michaelbel
11
+ ---
12
+
13
+ # Новый UseCase
14
+
15
+ Создаёт один `UseCase` или `FlowUseCase` в `shared/domain/usecase`.
16
+
17
+ ## Граница ответственности
18
+
19
+ Этот skill оформляет одну business-операцию или один наблюдаемый поток и их `Result`/dispatcher
20
+ семантику. Он не создаёт endpoint, request/response, Room entity/DAO, mapper, Worker, realtime
21
+ connection или Screen. Для reload по realtime и фоновой синхронизации use case содержит
22
+ переиспользуемую business-логику, а realtime data source или Worker только инициирует его.
23
+
24
+ ## Выбор базового класса
25
+
26
+ - Используй `UseCase<P, R>` для одноразовых suspend-операций.
27
+ - Используй `FlowUseCase<P, R>` для наблюдаемых потоков.
28
+ - Не создавай обёртки Repository или Interactor для новой работы.
29
+
30
+ ## Зависимости конструктора
31
+
32
+ Внедряй конкретные зависимости напрямую:
33
+ - `NetworkService` для вызовов Ktor.
34
+ - `AppDatabase`, когда нужна транзакция Room.
35
+ - Классы DAO для чтения/записи Room.
36
+ - Классы DataStore для сохраняемых настроек.
37
+ - Другие use case при композиции поведения.
38
+ - `SharedDispatchers` как не-`private` параметр, передаваемый в базовый класс.
39
+
40
+ ## Параметры
41
+
42
+ - Без входных данных: используй `Unit` и оставляй `execute(params: Unit)`.
43
+ - Один входной параметр: используй domain-тип как `P`, переименуй override-параметр и добавь
44
+ `@file:Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")`.
45
+ - Два и более входных параметра: добавь вложенный `data class Params(...)` и используй его как `P`.
46
+
47
+ ## Шаблон одноразового UseCase
48
+
49
+ ```kotlin
50
+ @file:Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")
51
+
52
+ class ThingsDetailsUseCase @Inject constructor(
53
+ private val networkService: NetworkService,
54
+ private val thingDao: ThingDao,
55
+ dispatchers: SharedDispatchers
56
+ ): UseCase<ThingId, Unit>(dispatchers.io) {
57
+
58
+ override suspend fun execute(thingId: ThingId) {
59
+ handleResponse(
60
+ request = {
61
+ val request = ThingsDetailsRequest(thingId)
62
+ networkService.thingsDetails(request)
63
+ },
64
+ onSuccess = { data ->
65
+ thingDao.upsert(data.entity)
66
+ },
67
+ onFailure = { error -> throw ThingsDetailsException(error.message) }
68
+ )
69
+ }
70
+
71
+ data class ThingsDetailsException(
72
+ override val message: String
73
+ ): AppNetworkException(message)
74
+ }
75
+ ```
76
+
77
+ Замени `AppNetworkException` на базовое сетевое исключение целевого проекта. Имя use case и
78
+ вложенного исключения выводи из endpoint path или имени метода `NetworkService`, а не из intent
79
+ экрана.
80
+
81
+ ## Шаблон Flow
82
+
83
+ ```kotlin
84
+ @file:Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")
85
+
86
+ class ThingEntityFlowUseCase @Inject constructor(
87
+ private val thingDao: ThingDao,
88
+ dispatchers: SharedDispatchers
89
+ ): FlowUseCase<ThingId, ThingEntity>(dispatchers.io) {
90
+
91
+ override fun execute(thingId: ThingId): Flow<ThingEntity> {
92
+ return thingDao.selectFlow(thingId)
93
+ }
94
+ }
95
+ ```
96
+
97
+ ## Шаблон значения сети
98
+
99
+ Используй это, когда сетевой ответ нужен как значение внутри `execute`.
100
+
101
+ ```kotlin
102
+ @file:Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")
103
+
104
+ class ThingsDetailsUseCase @Inject constructor(
105
+ private val networkService: NetworkService,
106
+ dispatchers: SharedDispatchers
107
+ ): UseCase<ThingId, ThingEntity>(dispatchers.io) {
108
+
109
+ override suspend fun execute(thingId: ThingId): ThingEntity {
110
+ val data = handleResponseResult {
111
+ val request = ThingsDetailsRequest(thingId)
112
+ networkService.thingsDetails(request)
113
+ }.getOrElse { throwable ->
114
+ if (throwable is CancellationException) throw throwable
115
+ throw ThingsDetailsException(throwable.message.orEmpty())
116
+ }
117
+
118
+ return data.entity
119
+ }
120
+
121
+ data class ThingsDetailsException(
122
+ override val message: String
123
+ ): AppNetworkException(message)
124
+ }
125
+ ```
126
+
127
+ Здесь преобразование ошибки в endpoint-specific exception является содержательной классификацией,
128
+ а не повторным оборачиванием того же `Result`. Всегда пробрасывай `CancellationException` без
129
+ преобразования.
130
+
131
+ ## Обязательное поведение
132
+
133
+ - `UseCase.execute` возвращает сырой `R`, а не `Result<R>`.
134
+ - Выбрасывай domain-специфичные исключения при ошибках; позволяй базовому `UseCase` конвертировать
135
+ их в `Result.failure`.
136
+ - Используй `handleResponseResult(...).getOrThrow()`, когда generic exception достаточно; для
137
+ endpoint-specific exception используй `getOrElse`, пробрось `CancellationException` и выбрось
138
+ конкретный тип.
139
+ - Вызывай другие use case через `.getOrThrow()`.
140
+ - Вызывай одноразовые use case из ViewModel через `.getOrThrow()` внутри `launch { ... }`.
141
+ - Не добавляй `withContext` или `flowOn`; базовые классы сами обрабатывают диспетчеры.
142
+ - Создавай `val request = ...` перед каждым вызовом `networkService`.
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: create-workmanager-task
3
+ description: >-
4
+ Use when пользователь просит создать или изменить Android WorkManager-задачу, CoroutineWorker,
5
+ её enqueue/cancel use case, constraints, unique work или retry policy. Не используй для обычного
6
+ suspend use case без фонового планирования или для foreground service.
7
+ metadata:
8
+ author: michaelbel
9
+ ---
10
+
11
+ # Создание WorkManager-задачи
12
+
13
+ Перед изменениями изучи существующие worker, Hilt/WorkManager setup и способы вызова use case в
14
+ целевом проекте. Определи семантику задачи: one-time или periodic, unique identity, условия запуска,
15
+ временные и постоянные ошибки, отмена и идемпотентность.
16
+
17
+ ## Реализация
18
+
19
+ - Создай тонкий `CoroutineWorker`, который валидирует input, вызывает существующий бизнес-use case
20
+ через `.getOrThrow()` и преобразует результат в `success`, `retry` или `failure`. Для чисто
21
+ системной операции вроде показа notification допустим прямой Android API без бизнес-логики.
22
+ - Следуй существующей Hilt-конвенции: `@HiltWorker`/`@AssistedInject` при настроенном
23
+ `HiltWorkerFactory` либо существующий Hilt `EntryPoint`; не смешивай оба подхода.
24
+ - Создай отдельный scheduling `UseCase` и, когда сценарий требует отмены, cancellation `UseCase`.
25
+ UI/ViewModel взаимодействуют с ними, а не с `WorkManager` и не с `Worker.enqueue()`.
26
+ - Используй stable unique work name/tag только при реальном identity задачи. Выбери
27
+ `ExistingWorkPolicy` или `ExistingPeriodicWorkPolicy` по тому, должна ли новая заявка сохранять,
28
+ заменять или продолжать старую.
29
+ - Добавь только необходимые `Constraints`, delay/interval и backoff. Для временных ошибок ограничь
30
+ повторы через `runAttemptCount`, если продукт не требует неограниченного retry.
31
+ - Передавай через `Data` небольшие primitive/string значения. Для payload и очереди операций
32
+ используй Room и передавай worker стабильный id.
33
+ - Пробрасывай `CancellationException`; не превращай отмену в результат работы.
34
+ - Держи операцию идемпотентной, поскольку повторный запуск возможен после частичного выполнения.
35
+ - Для account/session-scoped задачи включи owner/session generation в identity и input. Подключи
36
+ отмену к logout, но не полагайся на неё как на барьер: worker повторно проверяет актуальную сессию
37
+ перед запросом и перед Room commit и завершает устаревшую работу без записи.
38
+
39
+ Проверь, что worker доступен фабрике приложения, scheduling и cancellation используют одинаковый
40
+ identity, а тесты покрывают хотя бы permanent error, transient retry и success, если в проекте есть
41
+ WorkManager test infrastructure.
@@ -0,0 +1,152 @@
1
+ ---
2
+ name: github-repo-settings
3
+ description: >-
4
+ Use when the user asks to configure a GitHub repository after creation — set its description
5
+ and topics, disable Wikis, Issues, Discussions, Projects and Pull Requests, hide Releases,
6
+ Packages and Deployments from the repository home page, enable Sponsorships, or says "configure
7
+ repo settings" or "set up GitHub repository". Applies and verifies repository-level settings
8
+ step by step through `gh`, the documented GitHub REST API and browser UI. Do not use for tracked
9
+ repository files such as README.md, FUNDING.yml, CODEOWNERS or `.github/workflows`.
10
+ metadata:
11
+ author: michaelbel
12
+ ---
13
+
14
+ # Настройка GitHub-репозитория
15
+
16
+ Приведи уже созданный GitHub-репозиторий к стандартному состоянию. Это внешние изменения на
17
+ GitHub; они не разрешают редактировать tracked files, менять visibility, Actions, secrets,
18
+ collaborators, branch protection, Pages, merge policy или security settings.
19
+
20
+ ## Целевое состояние
21
+
22
+ - задано короткое фактическое description;
23
+ - задано 3–6 релевантных lowercase topics;
24
+ - Wikis, Issues, Discussions, Projects и Pull Requests выключены;
25
+ - Releases, Packages и Deployments скрыты из блока About на главной странице;
26
+ - Sponsorships включены, если валидный `.github/FUNDING.yml` уже находится в default branch;
27
+ - GitHub Actions остаётся включённым.
28
+
29
+ ## 1. Определи точный репозиторий
30
+
31
+ 1. Если пользователь передал `OWNER/REPO` или URL, используй его.
32
+ 2. Иначе получи remote из текущего проекта и разреши его через
33
+ `gh repo view --json nameWithOwner -q .nameWithOwner`.
34
+ 3. Перед любым write покажи в update точный `OWNER/REPO`. Не работай с репозиторием, который
35
+ определился неоднозначно, и не полагайся на случайный current directory.
36
+ 4. Выполни `gh auth status`, затем проверь
37
+ `gh repo view OWNER/REPO --json viewerPermission,isArchived`. Нужен admin-доступ; archived
38
+ repository не изменяй.
39
+
40
+ Не печатай auth token, secrets или полный environment.
41
+
42
+ ## 2. Собери исходное состояние
43
+
44
+ Сначала выполни read-only проверки:
45
+
46
+ ```bash
47
+ gh repo view OWNER/REPO \
48
+ --json nameWithOwner,description,repositoryTopics,hasWikiEnabled,hasIssuesEnabled,hasDiscussionsEnabled,hasProjectsEnabled,viewerPermission,isArchived
49
+
50
+ gh api repos/OWNER/REPO \
51
+ -H "X-GitHub-Api-Version: 2026-03-10" \
52
+ --jq '{has_pull_requests,default_branch,visibility}'
53
+ ```
54
+
55
+ Проверь default branch на наличие `.github/FUNDING.yml`, не изменяя файл. Текущее состояние нужно
56
+ для итогового diff и чтобы не выполнять лишние write-запросы.
57
+
58
+ ## 3. Подготовь description и topics
59
+
60
+ 1. Возьми назначение проекта из README и фактического кода; не придумывай возможности продукта.
61
+ 2. Сформулируй description одним коротким предложением без точки в конце, badges и marketing copy.
62
+ 3. Выбери 3–6 topics по платформе, языку, UI/framework и назначению проекта. Topics должны быть
63
+ lowercase, не длиннее 50 символов и содержать только буквы, цифры и дефисы.
64
+ 4. Сохрани релевантные существующие topics и удали только устаревшие или относящиеся к шаблону.
65
+ Если корректный итоговый набор нельзя вывести из проекта, согласуй его до write-запроса.
66
+
67
+ ## 4. Примени CLI-настройки
68
+
69
+ Сначала установи description и отключи функции, которые поддерживает `gh repo edit`:
70
+
71
+ ```bash
72
+ gh repo edit OWNER/REPO \
73
+ --description "PROJECT_DESCRIPTION" \
74
+ --enable-wiki=false \
75
+ --enable-issues=false \
76
+ --enable-discussions=false \
77
+ --enable-projects=false
78
+ ```
79
+
80
+ Затем приведи topics к согласованному точному набору. Endpoint заменяет весь список, поэтому не
81
+ запускай его до проверки текущих topics:
82
+
83
+ ```bash
84
+ gh api --method PUT repos/OWNER/REPO/topics \
85
+ -H "X-GitHub-Api-Version: 2026-03-10" \
86
+ -F 'names[]=TOPIC_ONE' \
87
+ -F 'names[]=TOPIC_TWO' \
88
+ -F 'names[]=TOPIC_THREE'
89
+ ```
90
+
91
+ Отключи Pull Requests через документированный REST field, которого пока нет среди флагов
92
+ `gh repo edit`:
93
+
94
+ ```bash
95
+ gh api --method PATCH repos/OWNER/REPO \
96
+ -H "X-GitHub-Api-Version: 2026-03-10" \
97
+ -F has_pull_requests=false
98
+ ```
99
+
100
+ Не объединяй эти операции с изменением visibility, default branch или merge settings. При `401`,
101
+ `403` или `404` остановись, перепроверь target/auth/permission и не повторяй write вслепую.
102
+
103
+ ## 5. Примени UI-настройки
104
+
105
+ Используй доступный browser control с существующей авторизованной GitHub-сессией. Если browser
106
+ недоступен или пользователь не авторизован, не пытайся обходить login: перечисли оставшиеся шаги.
107
+
108
+ 1. Открой главную страницу `https://github.com/OWNER/REPO`.
109
+ 2. В блоке **About** нажми шестерёнку.
110
+ 3. В **Include in the home page** выключи показанные **Releases**, **Packages** и **Deployments**,
111
+ затем сохрани. Если конкретного переключателя нет, не имитируй его через private API — отметь
112
+ его как отсутствующий в текущем UI.
113
+ 4. Открой **Settings → General → Features**.
114
+ 5. Если `.github/FUNDING.yml` существует в default branch, включи **Sponsorships**. Не создавай и
115
+ не редактируй funding file в рамках этого skill.
116
+
117
+ Не используй private/undocumented endpoint для UI-only toggles: интерфейс может изменить внутренний
118
+ запрос без обратной совместимости.
119
+
120
+ ## 6. Проверь результат
121
+
122
+ Повтори CLI-проверки из шага 2 и сравни их с целевым состоянием. Отдельно проверь topics:
123
+
124
+ ```bash
125
+ gh api repos/OWNER/REPO/topics \
126
+ -H "X-GitHub-Api-Version: 2026-03-10" \
127
+ --jq '.names'
128
+ ```
129
+
130
+ В браузере обнови страницы About и Settings → General и убедись, что UI-переключатели сохранились.
131
+ Не считай задачу завершённой только по успешному exit code команды.
132
+
133
+ В финальном ответе кратко перечисли:
134
+
135
+ - настроенный `OWNER/REPO`;
136
+ - итоговые description и topics;
137
+ - подтверждённые выключенные функции;
138
+ - статус Releases/Packages/Deployments и Sponsorships;
139
+ - шаги, которые не удалось выполнить из-за permissions или отсутствия browser session.
140
+
141
+ ## Актуальность API
142
+
143
+ Workflow основан на текущих официальных интерфейсах:
144
+
145
+ - [`gh repo edit`](https://cli.github.com/manual/gh_repo_edit);
146
+ - [REST: Update a repository](https://docs.github.com/en/rest/repos/repos?apiVersion=2026-03-10#update-a-repository);
147
+ - [REST: Replace all repository topics](https://docs.github.com/en/rest/repos/repos?apiVersion=2026-03-10#replace-all-repository-topics);
148
+ - [Disabling pull requests](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/disabling-pull-requests);
149
+ - [Displaying a sponsor button](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/displaying-a-sponsor-button-in-your-repository).
150
+
151
+ Если GitHub отклоняет `X-GitHub-Api-Version: 2026-03-10` или документированный field, сначала
152
+ перепроверь актуальную официальную документацию. Не переключайся автоматически на private API.