Skip to content

Commit 0c0e9e3

Browse files
Merge pull request #19 from gpu-cli/fix/spec-compile-49
fix(generator): all 54 specs compile (gitea Swagger 2.0 skipped)
2 parents 22b29d9 + e8e6404 commit 0c0e9e3

30 files changed

Lines changed: 1424 additions & 192 deletions

.beads/.gitignore

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Dolt database (managed by Dolt, not git)
2+
dolt/
3+
embeddeddolt/
4+
5+
# Runtime files
6+
bd.sock
7+
bd.sock.startlock
8+
sync-state.json
9+
last-touched
10+
.exclusive-lock
11+
12+
# Daemon runtime (lock, log, pid)
13+
daemon.*
14+
15+
# Interactions log (runtime, not versioned)
16+
interactions.jsonl
17+
18+
# Push state (runtime, per-machine)
19+
push-state.json
20+
21+
# Lock files (various runtime locks)
22+
*.lock
23+
24+
# Credential key (encryption key for federation peer auth — never commit)
25+
.beads-credential-key
26+
27+
# Local version tracking (prevents upgrade notification spam after git ops)
28+
.local_version
29+
30+
# Worktree redirect file (contains relative path to main repo's .beads/)
31+
# Must not be committed as paths would be wrong in other clones
32+
redirect
33+
34+
# Sync state (local-only, per-machine)
35+
# These files are machine-specific and should not be shared across clones
36+
.sync.lock
37+
export-state/
38+
export-state.json
39+
40+
# Ephemeral store (SQLite - wisps/molecules, intentionally not versioned)
41+
ephemeral.sqlite3
42+
ephemeral.sqlite3-journal
43+
ephemeral.sqlite3-wal
44+
ephemeral.sqlite3-shm
45+
46+
# Dolt server management (auto-started by bd)
47+
dolt-server.pid
48+
dolt-server.log
49+
dolt-server.lock
50+
dolt-server.port
51+
dolt-server.activity
52+
53+
# Corrupt backup directories (created by bd doctor --fix recovery)
54+
*.corrupt.backup/
55+
56+
# Backup data (auto-exported JSONL, local-only)
57+
backup/
58+
59+
# Per-project environment file (Dolt connection config, GH#2520)
60+
.env
61+
62+
# Legacy files (from pre-Dolt versions)
63+
*.db
64+
*.db?*
65+
*.db-journal
66+
*.db-wal
67+
*.db-shm
68+
db.sqlite
69+
bd.db
70+
# NOTE: Do NOT add negation patterns here.
71+
# They would override fork protection in .git/info/exclude.
72+
# Config files (metadata.json, config.yaml) are tracked by git by default
73+
# since no pattern above ignores them.

.beads/README.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Beads - AI-Native Issue Tracking
2+
3+
Welcome to Beads! This repository uses **Beads** for issue tracking - a modern, AI-native tool designed to live directly in your codebase alongside your code.
4+
5+
## What is Beads?
6+
7+
Beads is issue tracking that lives in your repo, making it perfect for AI coding agents and developers who want their issues close to their code. No web UI required - everything works through the CLI and integrates seamlessly with git.
8+
9+
**Learn more:** [github.com/steveyegge/beads](https://github.com/steveyegge/beads)
10+
11+
## Quick Start
12+
13+
### Essential Commands
14+
15+
```bash
16+
# Create new issues
17+
bd create "Add user authentication"
18+
19+
# View all issues
20+
bd list
21+
22+
# View issue details
23+
bd show <issue-id>
24+
25+
# Update issue status
26+
bd update <issue-id> --claim
27+
bd update <issue-id> --status done
28+
29+
# Sync with Dolt remote
30+
bd dolt push
31+
```
32+
33+
### Working with Issues
34+
35+
Issues in Beads are:
36+
- **Git-native**: Stored in Dolt database with version control and branching
37+
- **AI-friendly**: CLI-first design works perfectly with AI coding agents
38+
- **Branch-aware**: Issues can follow your branch workflow
39+
- **Always in sync**: Auto-syncs with your commits
40+
41+
## Why Beads?
42+
43+
**AI-Native Design**
44+
- Built specifically for AI-assisted development workflows
45+
- CLI-first interface works seamlessly with AI coding agents
46+
- No context switching to web UIs
47+
48+
🚀 **Developer Focused**
49+
- Issues live in your repo, right next to your code
50+
- Works offline, syncs when you push
51+
- Fast, lightweight, and stays out of your way
52+
53+
🔧 **Git Integration**
54+
- Automatic sync with git commits
55+
- Branch-aware issue tracking
56+
- Dolt-native three-way merge resolution
57+
58+
## Get Started with Beads
59+
60+
Try Beads in your own projects:
61+
62+
```bash
63+
# Install Beads
64+
curl -sSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash
65+
66+
# Initialize in your repo
67+
bd init
68+
69+
# Create your first issue
70+
bd create "Try out Beads"
71+
```
72+
73+
## Learn More
74+
75+
- **Documentation**: [github.com/steveyegge/beads/docs](https://github.com/steveyegge/beads/tree/main/docs)
76+
- **Quick Start Guide**: Run `bd quickstart`
77+
- **Examples**: [github.com/steveyegge/beads/examples](https://github.com/steveyegge/beads/tree/main/examples)
78+
79+
---
80+
81+
*Beads: Issue tracking that moves at the speed of thought*

.beads/config.yaml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Beads Configuration File
2+
# This file configures default behavior for all bd commands in this repository
3+
# All settings can also be set via environment variables (BD_* prefix)
4+
# or overridden with command-line flags
5+
6+
# Issue prefix for this repository (used by bd init)
7+
# If not set, bd init will auto-detect from directory name
8+
# Example: issue-prefix: "myproject" creates issues like "myproject-1", "myproject-2", etc.
9+
# issue-prefix: ""
10+
11+
# Use no-db mode: JSONL-only, no Dolt database
12+
# When true, bd will use .beads/issues.jsonl as the source of truth
13+
# no-db: false
14+
15+
# Enable JSON output by default
16+
# json: false
17+
18+
# Feedback title formatting for mutating commands (create/update/close/dep/edit)
19+
# 0 = hide titles, N > 0 = truncate to N characters
20+
# output:
21+
# title-length: 255
22+
23+
# Default actor for audit trails (overridden by BEADS_ACTOR or --actor)
24+
# actor: ""
25+
26+
# Export events (audit trail) to .beads/events.jsonl on each flush/sync
27+
# When enabled, new events are appended incrementally using a high-water mark.
28+
# Use 'bd export --events' to trigger manually regardless of this setting.
29+
# events-export: false
30+
31+
# Multi-repo configuration (experimental - bd-307)
32+
# Allows hydrating from multiple repositories and routing writes to the correct database
33+
# repos:
34+
# primary: "." # Primary repo (where this database lives)
35+
# additional: # Additional repos to hydrate from (read-only)
36+
# - ~/beads-planning # Personal planning repo
37+
# - ~/work-planning # Work planning repo
38+
39+
# JSONL backup (periodic export for off-machine recovery)
40+
# Auto-enabled when a git remote exists. Override explicitly:
41+
# backup:
42+
# enabled: false # Disable auto-backup entirely
43+
# interval: 15m # Minimum time between auto-exports
44+
# git-push: false # Disable git push (export locally only)
45+
# git-repo: "" # Separate git repo for backups (default: project repo)
46+
47+
# Integration settings (access with 'bd config get/set')
48+
# These are stored in the database, not in this file:
49+
# - jira.url
50+
# - jira.project
51+
# - linear.url
52+
# - linear.api-key
53+
# - github.org
54+
# - github.repo
55+
56+
sync.remote: "git+ssh://git@github.com/gpu-cli/openapi-to-rust.git"

.beads/hooks/post-checkout

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/usr/bin/env sh
2+
# --- BEGIN BEADS INTEGRATION v1.0.2 ---
3+
# This section is managed by beads. Do not remove these markers.
4+
if command -v bd >/dev/null 2>&1; then
5+
export BD_GIT_HOOK=1
6+
_bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
7+
if command -v timeout >/dev/null 2>&1; then
8+
timeout "$_bd_timeout" bd hooks run post-checkout "$@"
9+
_bd_exit=$?
10+
if [ $_bd_exit -eq 124 ]; then
11+
echo >&2 "beads: hook 'post-checkout' timed out after ${_bd_timeout}s — continuing without beads"
12+
_bd_exit=0
13+
fi
14+
else
15+
bd hooks run post-checkout "$@"
16+
_bd_exit=$?
17+
fi
18+
if [ $_bd_exit -eq 3 ]; then
19+
echo >&2 "beads: database not initialized — skipping hook 'post-checkout'"
20+
_bd_exit=0
21+
fi
22+
if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
23+
fi
24+
# --- END BEADS INTEGRATION v1.0.2 ---

.beads/hooks/post-merge

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/usr/bin/env sh
2+
# --- BEGIN BEADS INTEGRATION v1.0.2 ---
3+
# This section is managed by beads. Do not remove these markers.
4+
if command -v bd >/dev/null 2>&1; then
5+
export BD_GIT_HOOK=1
6+
_bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
7+
if command -v timeout >/dev/null 2>&1; then
8+
timeout "$_bd_timeout" bd hooks run post-merge "$@"
9+
_bd_exit=$?
10+
if [ $_bd_exit -eq 124 ]; then
11+
echo >&2 "beads: hook 'post-merge' timed out after ${_bd_timeout}s — continuing without beads"
12+
_bd_exit=0
13+
fi
14+
else
15+
bd hooks run post-merge "$@"
16+
_bd_exit=$?
17+
fi
18+
if [ $_bd_exit -eq 3 ]; then
19+
echo >&2 "beads: database not initialized — skipping hook 'post-merge'"
20+
_bd_exit=0
21+
fi
22+
if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
23+
fi
24+
# --- END BEADS INTEGRATION v1.0.2 ---

.beads/hooks/pre-commit

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/usr/bin/env sh
2+
# --- BEGIN BEADS INTEGRATION v1.0.2 ---
3+
# This section is managed by beads. Do not remove these markers.
4+
if command -v bd >/dev/null 2>&1; then
5+
export BD_GIT_HOOK=1
6+
_bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
7+
if command -v timeout >/dev/null 2>&1; then
8+
timeout "$_bd_timeout" bd hooks run pre-commit "$@"
9+
_bd_exit=$?
10+
if [ $_bd_exit -eq 124 ]; then
11+
echo >&2 "beads: hook 'pre-commit' timed out after ${_bd_timeout}s — continuing without beads"
12+
_bd_exit=0
13+
fi
14+
else
15+
bd hooks run pre-commit "$@"
16+
_bd_exit=$?
17+
fi
18+
if [ $_bd_exit -eq 3 ]; then
19+
echo >&2 "beads: database not initialized — skipping hook 'pre-commit'"
20+
_bd_exit=0
21+
fi
22+
if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
23+
fi
24+
# --- END BEADS INTEGRATION v1.0.2 ---

.beads/hooks/pre-push

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/usr/bin/env sh
2+
# --- BEGIN BEADS INTEGRATION v1.0.2 ---
3+
# This section is managed by beads. Do not remove these markers.
4+
if command -v bd >/dev/null 2>&1; then
5+
export BD_GIT_HOOK=1
6+
_bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
7+
if command -v timeout >/dev/null 2>&1; then
8+
timeout "$_bd_timeout" bd hooks run pre-push "$@"
9+
_bd_exit=$?
10+
if [ $_bd_exit -eq 124 ]; then
11+
echo >&2 "beads: hook 'pre-push' timed out after ${_bd_timeout}s — continuing without beads"
12+
_bd_exit=0
13+
fi
14+
else
15+
bd hooks run pre-push "$@"
16+
_bd_exit=$?
17+
fi
18+
if [ $_bd_exit -eq 3 ]; then
19+
echo >&2 "beads: database not initialized — skipping hook 'pre-push'"
20+
_bd_exit=0
21+
fi
22+
if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
23+
fi
24+
# --- END BEADS INTEGRATION v1.0.2 ---

.beads/hooks/prepare-commit-msg

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/usr/bin/env sh
2+
# --- BEGIN BEADS INTEGRATION v1.0.2 ---
3+
# This section is managed by beads. Do not remove these markers.
4+
if command -v bd >/dev/null 2>&1; then
5+
export BD_GIT_HOOK=1
6+
_bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
7+
if command -v timeout >/dev/null 2>&1; then
8+
timeout "$_bd_timeout" bd hooks run prepare-commit-msg "$@"
9+
_bd_exit=$?
10+
if [ $_bd_exit -eq 124 ]; then
11+
echo >&2 "beads: hook 'prepare-commit-msg' timed out after ${_bd_timeout}s — continuing without beads"
12+
_bd_exit=0
13+
fi
14+
else
15+
bd hooks run prepare-commit-msg "$@"
16+
_bd_exit=$?
17+
fi
18+
if [ $_bd_exit -eq 3 ]; then
19+
echo >&2 "beads: database not initialized — skipping hook 'prepare-commit-msg'"
20+
_bd_exit=0
21+
fi
22+
if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
23+
fi
24+
# --- END BEADS INTEGRATION v1.0.2 ---

.beads/issues.jsonl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{"id":"openapi-generator-8tu","title":"[Q4] Tagged discriminator enums (drop untagged when discriminator+mapping is present)","description":"When a schema has discriminator: { propertyName: 'type', mapping: { ... } }, we know exactly which type to deserialize at runtime by reading one field. Yet today we still emit #[serde(untagged)] on the union enum, which makes serde try every variant in order on every deserialization (slow) and emits the variant payload's JSON inline instead of a tagged shape on serialization (loses the discriminator on round-trip). Anthropic's content blocks (text/image/tool_use/tool_result) and OpenAI's response items are exactly this pattern. Tagged is much better. Approach: in generate_discriminated_enum, when the spec provides discriminator with mapping, emit #[serde(tag = '\u003cdiscriminator.property_name\u003e')] and rename each variant to the mapping value. For unions WITHOUT a discriminator, untagged remains.\n\n## Context\nFiles: src/generator.rs. Evidence: src/generator.rs:1107 generate_discriminated_enum and 1251 generate_union_enum both emit #[serde(untagged)] regardless of discriminator presence. See umbrella gpu-cli/openapi-to-rust#14.","acceptance_criteria":"- [ ] Discriminator + mapping → #[serde(tag = ...)] enum, not untagged.\n- [ ] Round-trip test: deserialize a JSON sample, serialize back, byte-equal modulo whitespace.\n- [ ] Variants ordered to match mapping insertion order (deterministic codegen).\n- [ ] Pet/Cat/Dog allOf-parent pattern (umbrella H12) supported.\n- [ ] All 49 currently-compiling specs still compile.","status":"open","priority":2,"issue_type":"task","owner":"james@littlebearlabs.io","created_at":"2026-05-08T23:13:12Z","created_by":"James Lal","updated_at":"2026-05-08T23:13:12Z","labels":["phase4","quality","schema"],"dependency_count":0,"dependent_count":0,"comment_count":0}
2+
{"id":"openapi-generator-st8","title":"[Q3] Builder pattern for operations with many parameters","description":"OpenAI's responses_create has 25+ parameters. Even with Option\u003cT\u003e for optionals, the call site is hostile: client.responses_create(model, None, None, ..., Some('system prompt'), None, ...). Goal: emit a \u003cOp\u003eBuilder\u003c'_\u003e per op with .field(value) setters and a final .send().await. Required path/header params remain positional on the entry method; optional + body fields become builder setters. For struct-typed bodies, also generate per-field setters on the builder (delegating into the body struct).\n\n## Context\nFiles: src/client_generator.rs. Evidence: src/client_generator.rs:836 generate_request_param emits flat positional method args. See umbrella gpu-cli/openapi-to-rust#14.","acceptance_criteria":"- [ ] [generator.builders] enabled = true; threshold = 3 in TOML config.\n- [ ] Each operation with \u003ethreshold optional params gets a builder struct.\n- [ ] Required params stay positional on the entry method.\n- [ ] .send(self) -\u003e Result\u003c\u003cResponseT\u003e, ApiOpError\u003c...\u003e\u003e runs the existing emitted body.\n- [ ] Snapshot tests for an op with many optional params show the new shape compiles and the existing call compiles.\n- [ ] All 49 currently-compiling specs still compile.","status":"open","priority":2,"issue_type":"task","owner":"james@littlebearlabs.io","created_at":"2026-05-08T23:11:55Z","created_by":"James Lal","updated_at":"2026-05-08T23:11:55Z","labels":["codegen","phase4","quality"],"dependency_count":0,"dependent_count":1,"comment_count":0}
3+
{"id":"openapi-generator-quq","title":"[Q2] Format-typed scalars (date-time, uuid, byte, binary, ipv4, ipv6, uri)","description":"Real-world specs use 'format' tags everywhere. Today everything collapses to String/Vec\u003cu8\u003e. Add typed scalars: date-time → chrono::DateTime\u003cUtc\u003e; date → chrono::NaiveDate; time → chrono::NaiveTime; duration → chrono::Duration; uuid → uuid::Uuid; byte → Vec\u003cu8\u003e + base64 serde; binary → bytes::Bytes; ipv4/ipv6 → std::net::Ipv*Addr; uri/url → url::Url. Configurable via [generator.types] TOML section with per-format choices (chrono vs time vs string, bytes vs vec_u8, etc.). Default: 'string' (current behavior, opt-in).\n\n## Context\nFiles: Cargo.toml, src/analysis.rs, src/generator.rs, scripts/spec-compile.sh. Evidence: src/analysis.rs:3091 get_number_rust_type only handles int32/int64/float/double; string format never produces typed scalars. See umbrella gpu-cli/openapi-to-rust#14.","acceptance_criteria":"- [ ] All formats above accept a TOML override.\n- [ ] Default ('string') matches today's behavior — no spec regresses.\n- [ ] When chrono is selected, generated structs use chrono::serde::rfc3339 for format: date-time.\n- [ ] When uuid is selected, generated structs use uuid::Uuid (with serde feature).\n- [ ] byte round-trips via base64 (matches OAS spec).\n- [ ] One end-to-end fixture per format under tests/conformance/fixtures/schema/format-*.yaml proving the types deserialize a real example.\n- [ ] Generated crate's Cargo.toml gets the right feature-gated deps.","status":"open","priority":2,"issue_type":"task","owner":"james@littlebearlabs.io","created_at":"2026-05-08T23:11:40Z","created_by":"James Lal","updated_at":"2026-05-08T23:11:40Z","labels":["phase4","quality","schema"],"dependency_count":0,"dependent_count":0,"comment_count":0}
4+
{"id":"openapi-generator-99a","title":"[Q1] Method-name canonicalization","description":"Heuristic post-processor on snake-cased operationId: tokenize path template, drop trailing tokens that match path tokens (in reverse path order), drop trailing HTTP-method verb. Re-check uniqueness; restore tokens for collisions. Goal: Anthropic's betaGetFileMetadataV1FilesFileIdGet + path /v1/files/{fileId} + GET → get_file_metadata.\n\n## Context\nToday get_method_name emits op.operation_id.to_snake_case() verbatim. Anthropic's spec produces names like beta_get_file_metadata_v1_files_file_id_get — the path and HTTP method are literally appended into the operationId. See umbrella issue gpu-cli/openapi-to-rust#14.","acceptance_criteria":"- [ ] Heuristic implemented in src/client_generator.rs:get_method_name (line ~859).\n- [ ] Unique across operation set; collisions fall back to original.\n- [ ] CLI/config flag [generator.method_names] strip_path = true (default true).\n- [ ] Snapshot tests confirm anthropic produces get_file_metadata not beta_get_file_metadata_v1_files_file_id_get.\n- [ ] All 49 currently-compiling specs still compile.","status":"open","priority":2,"issue_type":"task","owner":"james@littlebearlabs.io","created_at":"2026-05-08T23:10:47Z","created_by":"James Lal","updated_at":"2026-05-08T23:10:47Z","labels":["codegen","phase4","quality"],"dependencies":[{"issue_id":"openapi-generator-99a","depends_on_id":"openapi-generator-st8","type":"blocks","created_at":"2026-05-08T17:11:55Z","created_by":"James Lal","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0}
5+
{"id":"openapi-generator-81u","title":"[Q5] Display for ApiOpError that surfaces the typed body","description":"Today format!('{e}', e: ApiOpError\u003cE\u003e) on an Api variant prints 'API error 404: {full body}'. For a Stripe error that includes a huge param_documentation blob, the message becomes a wall of JSON. Users complain they can't tell at a glance what the typed variant captured. Approach: in ApiError::Display, truncate body to ~500 chars with a '… (truncated)' marker; if typed.is_some(), prepend '(typed: \u003cvariant_name\u003e)' (E: fmt::Debug bound already exists); if parse_error.is_some() and typed.is_none(), append '(parse error: …)'. Full body still accessible via .body field.\n\n## Context\nFiles: src/http_error.rs. Evidence: src/http_error.rs:234 ApiError Display prints body verbatim — for huge JSON bodies this is unreadable; typed.is_some() info is hidden. See umbrella gpu-cli/openapi-to-rust#14.","acceptance_criteria":"- [ ] ApiError Display truncates body at 500 chars (configurable via const).\n- [ ] Typed variant name appears when typed.is_some().\n- [ ] Parse error reason appears when typed parsing failed.\n- [ ] Full body still accessible via .body — no info loss.\n- [ ] Unit test in src/http_error.rs covers all three branches.","status":"open","priority":3,"issue_type":"task","owner":"james@littlebearlabs.io","created_at":"2026-05-08T23:13:13Z","created_by":"James Lal","updated_at":"2026-05-08T23:13:13Z","labels":["codegen","phase4","quality"],"dependency_count":0,"dependent_count":0,"comment_count":0}

.beads/metadata.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"database": "dolt",
3+
"backend": "dolt",
4+
"dolt_mode": "embedded",
5+
"dolt_database": "openapi_generator",
6+
"project_id": "15f6e5bd-f411-4caa-9e43-33483634d62c"
7+
}

0 commit comments

Comments
 (0)