Skip to content

Commit 9495d00

Browse files
authored
Merge branch 'code/cash' into dependabot/gradle/code/cash/gradle-wrapper-9.4.0
2 parents 856a765 + e013509 commit 9495d00

1,854 files changed

Lines changed: 51572 additions & 131954 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
---
2+
name: fetch-protos
3+
description: >
4+
Fetch latest protobuf definitions, verify build, summarize API changes,
5+
and scaffold new service stubs. Usage: /fetch-protos [flipcash|opencode] [commit_sha]
6+
user-invocable: true
7+
argument-hint: "[flipcash|opencode] [commit_sha]"
8+
allowed-tools:
9+
- Bash
10+
- Read
11+
- Edit
12+
- Write
13+
- Glob
14+
- Grep
15+
- Agent
16+
---
17+
18+
# Fetch Protos
19+
20+
Fetch protobuf definitions from upstream repos, verify they compile, summarize
21+
API changes, and scaffold missing service layer implementations.
22+
23+
## Pre-flight context
24+
25+
- Current proto files: !`find definitions/*/protos/src/main/proto -name "*.proto" 2>/dev/null | wc -l | tr -d ' '` proto files across targets
26+
- Git status: !`git status --short definitions/`
27+
28+
## Input
29+
30+
Parse `$ARGUMENTS` to determine targets and optional commit SHA.
31+
32+
**Rules:**
33+
- Known targets: `flipcash`, `opencode`
34+
- If no targets specified, fetch **both** (`flipcash` and `opencode`)
35+
- A hex string (7+ chars) as the last argument is treated as a commit SHA
36+
- Examples:
37+
- `/fetch-protos` → fetch flipcash + opencode at HEAD
38+
- `/fetch-protos flipcash` → fetch flipcash only
39+
- `/fetch-protos opencode abc1234` → fetch opencode at commit abc1234
40+
- `/fetch-protos flipcash opencode` → fetch both explicitly
41+
42+
## Steps
43+
44+
### Step 1 — Fetch protos
45+
46+
For each target, run the fetch script from the repo root:
47+
48+
```bash
49+
bash scripts/fetch-protos.sh -t <target> [commit_sha]
50+
```
51+
52+
Target-to-repo mapping (handled by the script):
53+
| Target | Repository |
54+
|--------|-----------|
55+
| `flipcash` | `git@github.com:code-payments/flipcash2-protobuf-api.git` |
56+
| `opencode` | `git@github.com:code-payments/ocp-protobuf-api.git` |
57+
58+
Show the script output to the user.
59+
60+
### Step 2 — Diff and summarize changes
61+
62+
Run `git diff` on the proto directories to identify what changed:
63+
64+
```bash
65+
git diff --stat definitions/
66+
git diff definitions/
67+
```
68+
69+
For each changed `.proto` file, summarize:
70+
- **New RPCs** added to services
71+
- **Modified RPCs** (changed request/response types or fields)
72+
- **Removed RPCs**
73+
- **New/modified messages** and fields
74+
75+
Present a structured change summary table to the user. If nothing changed, report
76+
that protos are already up to date and stop here.
77+
78+
### Step 3 — Build verification
79+
80+
Build the definitions modules to verify the protos compile:
81+
82+
```bash
83+
./gradlew :definitions:flipcash:models:assembleDebug :definitions:opencode:models:assembleDebug
84+
```
85+
86+
Only build the targets that were fetched. If the build fails, show errors and stop.
87+
88+
### Step 4 — Detect service layer impact
89+
90+
For each new or modified RPC found in Step 2:
91+
92+
1. Identify which service proto file it belongs to (e.g., `account/v1/flipcash_account_service.proto`)
93+
2. Search for the corresponding Api class in `services/<target>/src/**/network/api/`
94+
3. Check if a method exists for the RPC
95+
4. If the RPC is new, check whether Service, Repository, and Controller layers also need updates
96+
97+
Present a report:
98+
99+
| RPC | Api | Service | Repository | Controller | Status |
100+
|-----|-----|---------|------------|------------|--------|
101+
| `NewRpc` | missing | missing | missing | missing | **New — needs scaffolding** |
102+
| `ModifiedRpc` | exists | exists | exists | exists | **Signature may need update** |
103+
104+
### Step 5 — Scaffold new service stubs
105+
106+
For RPCs marked as needing scaffolding, ask the user if they want to scaffold them.
107+
If confirmed, generate code following the patterns below.
108+
109+
#### Api method pattern
110+
111+
Location: `services/<target>/src/main/kotlin/.../internal/network/api/<ServiceName>Api.kt`
112+
113+
```kotlin
114+
// @Singleton class with @Inject constructor taking qualified ManagedChannel
115+
// private val api = XxxGrpcKt.XxxCoroutineStub(managedChannel).withWaitForReady()
116+
117+
suspend fun newRpc(owner: KeyPair, ...): RpcServiceName.NewRpcResponse {
118+
val request = RpcServiceName.NewRpcRequest.newBuilder()
119+
.apply { setAuth(authenticate(owner)) } // or .apply { setSignature(sign(owner)) }
120+
// ... set other fields
121+
.build()
122+
123+
request.validate().orThrow()
124+
125+
return withContext(Dispatchers.IO) {
126+
api.newRpc(request)
127+
}
128+
}
129+
```
130+
131+
Key conventions:
132+
- Use `authenticate(owner)` for Flipcash endpoints (returns `Common.Auth`)
133+
- Use `sign(owner)` for OpenCode endpoints (returns `Model.Signature`)
134+
- Always call `request.validate().orThrow()` before the RPC
135+
- Always dispatch on `Dispatchers.IO`
136+
- Return raw proto response type
137+
138+
#### Service method pattern
139+
140+
Location: `services/<target>/src/main/kotlin/.../internal/network/services/<ServiceName>Service.kt`
141+
142+
```kotlin
143+
// internal class with @Inject constructor(private val api: XxxApi)
144+
145+
suspend fun newRpc(owner: KeyPair, ...): Result<DomainType> {
146+
return runCatching {
147+
api.newRpc(owner, ...)
148+
}.foldWithSuppression(
149+
onSuccess = { response ->
150+
when (response.result) {
151+
RpcServiceName.NewRpcResponse.Result.OK -> Result.success(/* mapped value */)
152+
RpcServiceName.NewRpcResponse.Result.DENIED -> Result.failure(NewRpcError.Denied())
153+
RpcServiceName.NewRpcResponse.Result.UNRECOGNIZED -> Result.failure(NewRpcError.Unrecognized())
154+
else -> Result.failure(NewRpcError.Other())
155+
}
156+
},
157+
onFailure = { cause ->
158+
Result.failure(cause.toValidationOrElse { NewRpcError.Other(cause = it) })
159+
}
160+
)
161+
}
162+
```
163+
164+
#### Error sealed class pattern
165+
166+
Location: `services/<target>/src/main/kotlin/.../models/Errors.kt`
167+
168+
```kotlin
169+
sealed class NewRpcError(
170+
override val message: String? = null,
171+
override val cause: Throwable? = null
172+
) : CodeServerError(message, cause) {
173+
class Denied : NewRpcError("Denied")
174+
class Unrecognized : NewRpcError("Unrecognized"), NotifiableError
175+
data class Other(override val cause: Throwable? = null) : NewRpcError(message = cause?.message, cause = cause), NotifiableError
176+
}
177+
```
178+
179+
Add a subclass for each non-OK result enum value in the proto response. Mark
180+
`Unrecognized` and `Other` with `NotifiableError`. Mark expected/benign errors
181+
(e.g., `NotFound`, `Denied`) without `NotifiableError`.
182+
183+
#### Repository pattern
184+
185+
- **Interface** in `services/<target>/src/main/kotlin/.../repository/`:
186+
```kotlin
187+
suspend fun newRpc(...): Result<DomainType>
188+
```
189+
- **Internal impl** in `services/<target>/src/main/kotlin/.../internal/repositories/`:
190+
```kotlin
191+
override suspend fun newRpc(...): Result<DomainType> {
192+
return service.newRpc(...)
193+
.map { mapper.map(it) } // if domain mapping needed
194+
.onFailure { if (it !is NewRpcError.ExpectedCase) ErrorUtils.handleError(it) }
195+
}
196+
```
197+
198+
#### Controller pattern
199+
200+
Location: `services/<target>/src/main/kotlin/.../controllers/<ServiceName>Controller.kt`
201+
202+
```kotlin
203+
// @Singleton class with @Inject constructor(repository, userManager)
204+
205+
suspend fun newRpc(...): Result<DomainType> {
206+
val owner = userManager.accountCluster?.authority?.keyPair
207+
?: return Result.failure(Throwable("No account cluster"))
208+
return repository.newRpc(owner, ...)
209+
}
210+
```
211+
212+
#### Hilt wiring
213+
214+
If a new Repository interface+impl pair was created, add a `@Provides` binding in
215+
the corresponding Hilt module (`FlipcashModule.kt` or `OpenCodeModule.kt`).
216+
217+
### Step 6 — Review and commit
218+
219+
Show the user a summary of all changes (proto updates + any scaffolded code).
220+
221+
Offer to commit with a conventional commit message:
222+
```
223+
chore(protos): update <target> protobuf definitions
224+
```
225+
226+
If service stubs were also scaffolded, suggest a separate commit:
227+
```
228+
feat(<target>): scaffold service stubs for new RPCs
229+
```
230+
231+
## Never
232+
233+
- Edit generated protobuf code in `definitions/*/models/build/`
234+
- Commit without user approval
235+
- Skip build verification
236+
- Scaffold service code without asking the user first
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
---
2+
name: release-notes
3+
description: Generate GitHub release notes from git tags. Usage - /release-notes <from_tag> <to_tag>. Runs the changelog script, then rewrites the output into polished GitHub release notes.
4+
disable-model-invocation: true
5+
argument-hint: <from_tag> <to_tag>
6+
user-invocable: true
7+
allowed-tools: Bash(git log *), Bash(git tag *), Bash(git describe *), Bash(bash scripts/changelog.sh *), Bash(gh release *), Read, Agent
8+
---
9+
10+
# Release Notes Generator
11+
12+
Generate polished GitHub release notes for the code-android-app repository.
13+
14+
## Pre-flight context
15+
16+
- Latest tag: !`git describe --tags --match 'fcash/*' --abbrev=0 HEAD 2>/dev/null || echo "no tags found"`
17+
- All recent tags: !`git tag --sort=-creatordate | head -10`
18+
19+
## Input
20+
21+
Parse the two tags from `$ARGUMENTS`, e.g.:
22+
- `/release-notes fcash/2026.4.10 fcash/2026.4.11`
23+
- `/release-notes fcash/2026.4.9 HEAD`
24+
25+
If only one tag is provided, use it as `<from>` and default `<to>` to `HEAD`.
26+
If no tags are provided, use the pre-flight latest tag as `<from>` and `HEAD` as `<to>`.
27+
28+
## Steps
29+
30+
### 1. Run the changelog script
31+
32+
```bash
33+
bash scripts/changelog.sh <from_tag> <to_tag>
34+
```
35+
36+
Display the raw output for the user to see.
37+
38+
### 2. Rewrite into release notes
39+
40+
Use the Agent tool with `model: "haiku"`. Pass the raw changelog output with this prompt:
41+
42+
> Given these git commits (conventional commit format), write user-facing release notes.
43+
>
44+
> Rules:
45+
> - Group under: **Features**, **Bug Fixes**, **Improvements** (omit empty sections)
46+
> - Write for end users — no jargon, file names, or internals
47+
> - One short sentence per item
48+
> - Group related commits into a single bullet when they address the same area
49+
> - Use scope as context but write in plain language; keep scope in **bold** prefix when it adds clarity
50+
> - Drop internal-only changes (pure refactors, CI tweaks, build config) unless user-facing
51+
> - Feature bullets start with a lowercase verb (e.g., "add", "support", "enable")
52+
> - Bug fix bullets start with "Fixed" (capitalized)
53+
> - Use 2-space indent before each bullet (` - `)
54+
> - Do NOT include commit hashes
55+
> - If no user-facing changes, output: Bug fixes and performance improvements.
56+
> - Output ONLY the section markdown, no title or fences
57+
58+
### 3. Generate App Store "What's New"
59+
60+
Using the same changelog, write a short "What's New" blurb suitable for the Google Play Store listing. Rules:
61+
- 3–5 bullet lines max, plain dashes (`- `)
62+
- Lead with the most impactful user-facing features
63+
- End with "Bug fixes and performance improvements" if there are fixes/chores
64+
- No markdown bold, no sections headers — just a flat list
65+
- Keep each line under ~60 characters
66+
- If there are no notable user-facing changes, output only: `- Bug fixes and performance improvements`
67+
68+
You can derive this yourself from the changelog without a subagent call.
69+
70+
### 4. Assemble final notes
71+
72+
Combine the agent's output with the changelog compare link:
73+
74+
```markdown
75+
{agent output}
76+
77+
**Full Changelog**: https://github.com/code-payments/code-android-app/compare/<from_tag>...<to_tag>
78+
```
79+
80+
The release title/name is the version number without the `fcash/` prefix (e.g., `2026.4.11`).
81+
82+
### 5. Review gate
83+
84+
Show the assembled GitHub release notes **and** the App Store "What's New" to the user for approval. Do NOT create the release until the user explicitly confirms.
85+
86+
### 6. Publish
87+
88+
After user confirms, create the release:
89+
```bash
90+
gh release create <to_tag> --repo code-payments/code-android-app --title "<version>" --notes "$(cat <<'EOF'
91+
<release_notes>
92+
EOF
93+
)"
94+
```
95+
96+
## Never
97+
- Publish without user approval
98+
- Include commit hashes in the final notes
99+
- Include internal-only changes unless they have user-facing impact

0 commit comments

Comments
 (0)