@@ -25,7 +25,9 @@ This addresses the problem of implementing missing SyntaxKit features. Instead o
2525- ` SyntaxParser ` (existing) - for parsing Swift code to AST
2626- ` ConfigKeyKit ` (existing in project) - for configuration key management
2727- ` swift-configuration ` - for CLI argument and environment variable handling
28- - Foundation (URLSession) - for HTTP requests to Claude API
28+ - ` swift-openapi-generator ` - for generating type-safe Claude API client from OpenAPI spec
29+ - ` swift-openapi-runtime ` - runtime support for generated OpenAPI client
30+ - ` swift-openapi-urlsession ` - URLSession transport for OpenAPI client
2931
3032### 2. Core Components
3133
@@ -437,26 +439,143 @@ struct ASTGenerator {
437439
438440#### I. Claude API Client (` ClaudeAPIClient.swift ` )
439441
440- Handles communication with Claude API for code generation:
442+ Wraps the OpenAPI-generated client for code generation:
441443
442444``` swift
445+ import OpenAPIRuntime
446+ import OpenAPIURLSession
447+
443448struct ClaudeAPIClient {
444449 let apiKey: String
445450 let model: String
451+ private let client: Client // Generated from OpenAPI spec
452+
453+ init (apiKey : String , model : String ) {
454+ self .apiKey = apiKey
455+ self .model = model
456+
457+ // Create OpenAPI client with URLSession transport
458+ self .client = Client (
459+ serverURL : try ! Servers.server1 (), // https://api.anthropic.com
460+ transport : URLSessionTransport (),
461+ middlewares : [
462+ AuthenticationMiddleware (apiKey : apiKey)
463+ ]
464+ )
465+ }
446466
447467 /// Sends request to generate updated library code
448468 func generateUpdatedLibrary (
449469 syntaxKitLibrary : String ,
450470 expectedSwift : String ,
451471 swiftAST : String ,
452472 swiftDSL : String
453- ) async throws -> LibraryUpdateResult
473+ ) async throws -> LibraryUpdateResult {
474+ // Create prompt using template
475+ let prompt = PromptTemplate.createAnalysisAndCodeGeneration (
476+ syntaxKitLibrary : syntaxKitLibrary,
477+ expectedSwift : expectedSwift,
478+ swiftAST : swiftAST,
479+ swiftDSL : swiftDSL
480+ )
454481
455- /// Formats the API request payload with code generation instructions
456- private func createRequestPayload (...) -> [String : Any ]
482+ // Call Claude API using generated client
483+ let response = try await client.postV1Messages (
484+ body : .json (
485+ Components.Schemas .MessageRequest (
486+ model : model,
487+ max_tokens : 20000 ,
488+ temperature : 1.0 ,
489+ messages : [
490+ Components.Schemas .Message (
491+ role : .user ,
492+ content : prompt
493+ )
494+ ]
495+ )
496+ )
497+ )
498+
499+ // Extract response content
500+ let messageResponse = try response.ok .body .json
501+ let responseText = messageResponse.content
502+ .compactMap { content -> String ? in
503+ if case .text (let text) = content {
504+ return text.text
505+ }
506+ return nil
507+ }
508+ .joined ()
509+
510+ // Parse code generation response
511+ return try parseCodeGenerationResponse (responseText)
512+ }
457513
458514 /// Parses API response containing generated code
459- private func parseCodeGenerationResponse (_ data : Data) throws -> LibraryUpdateResult
515+ private func parseCodeGenerationResponse (_ text : String ) throws -> LibraryUpdateResult {
516+ // Extract <file> blocks using regex
517+ let filePattern = #" <file path="([^"]+)">(.+?)</file>"#
518+ let regex = try NSRegularExpression (pattern : filePattern, options : [.dotMatchesLineSeparators ])
519+ let nsText = text as NSString
520+ let matches = regex.matches (in : text, range : NSRange (location : 0 , length : nsText.length ))
521+
522+ var updatedFiles: [LibraryUpdateResult.UpdatedFile] = []
523+ var newFiles: [LibraryUpdateResult.NewFile] = []
524+
525+ for match in matches {
526+ let pathRange = match.range (at : 1 )
527+ let contentRange = match.range (at : 2 )
528+
529+ let relativePath = nsText.substring (with : pathRange)
530+ let content = nsText.substring (with : contentRange)
531+ .trimmingCharacters (in : .whitespacesAndNewlines )
532+
533+ // Determine if new or updated file based on library scan
534+ // For now, treat all as new files (can enhance later)
535+ newFiles.append (
536+ LibraryUpdateResult.NewFile (
537+ relativePath : relativePath,
538+ content : content,
539+ purpose : " Generated implementation"
540+ )
541+ )
542+ }
543+
544+ // Extract summary (text before first <file> tag)
545+ let summaryPattern = #" ^(.+?)(?=<file|$)"#
546+ let summaryRegex = try NSRegularExpression (pattern : summaryPattern, options : [.dotMatchesLineSeparators ])
547+ let summaryMatch = summaryRegex.firstMatch (in : text, range : NSRange (location : 0 , length : nsText.length ))
548+ let summary = summaryMatch.map { nsText.substring (with : $0 .range (at : 1 )) } ?? " No summary provided"
549+
550+ return LibraryUpdateResult (
551+ updatedFiles : updatedFiles,
552+ newFiles : newFiles,
553+ unchangedFiles : [],
554+ includeUnchangedFiles : false ,
555+ summary : summary.trimmingCharacters (in : .whitespacesAndNewlines )
556+ )
557+ }
558+ }
559+
560+ /// Custom middleware for adding Anthropic API key header
561+ struct AuthenticationMiddleware : ClientMiddleware {
562+ let apiKey: String
563+
564+ func intercept (
565+ _ request : HTTPRequest,
566+ baseURL : URL,
567+ operationID : String ,
568+ next : (HTTPRequest, URL) async throws -> HTTPResponse
569+ ) async throws -> HTTPResponse {
570+ var modifiedRequest = request
571+ modifiedRequest.headerFields .append (
572+ .init (name : " x-api-key" , value : apiKey)
573+ )
574+ modifiedRequest.headerFields .append (
575+ .init (name : " anthropic-version" , value : " 2023-06-01" )
576+ )
577+ return try await next (modifiedRequest, baseURL)
578+ }
460579}
461580
462581struct LibraryUpdateResult : Codable {
@@ -485,20 +604,31 @@ struct FileReference: Codable {
485604}
486605```
487606
488- API request structure:
489- - Endpoint: ` https://api.anthropic.com/v1/messages `
490- - Headers: ` x-api-key ` , ` anthropic-version: 2023-06-01 ` , ` content-type: application/json `
491- - Body: Enhanced prompt asking Claude to generate actual Swift code, not just describe changes
607+ ** OpenAPI Specification Source** :
608+ - Uses unofficial OpenAPI spec from [ laszukdawid/anthropic-openapi-spec] ( https://github.com/laszukdawid/anthropic-openapi-spec )
609+ - Specifically the ` hosted_spec.json ` file (derived from Anthropic's TypeScript SDK)
610+ - Download to ` Sources/skit-analyze/openapi.json ` or ` openapi.yaml `
611+ - Swift OpenAPI Generator will create type-safe client code at build time
612+
613+ ** Setup Steps** :
614+ 1 . Download OpenAPI spec: ` curl -o Sources/skit-analyze/openapi.json https://raw.githubusercontent.com/laszukdawid/anthropic-openapi-spec/main/hosted_spec.json `
615+ 2 . Create ` Sources/skit-analyze/openapi-generator-config.yaml ` :
616+ ``` yaml
617+ generate :
618+ - types
619+ - client
620+ ` ` `
621+ 3. Swift OpenAPI Generator plugin will generate client code automatically during build
492622
493- Modified Prompt Strategy:
494- - Still uses the Workbench prompt for analysis
623+ ** Modified Prompt Strategy** :
624+ - Uses the Workbench prompt for analysis
495625- **Additionally** asks Claude to generate the actual implementation code
496626- Requests output in structured format using XML-style markers
497627- Each code file marked with: ` <file path="relative/path.swift">...code...</file>`
498628
499629**Response Parsing**:
500- The API client will parse Claude's response by:
501- 1 . Extract all ` <file> ` blocks using regex or XML parsing
630+ The API client parses Claude's response by :
631+ 1. Extract all `<file>` blocks using regex
5026322. For each file block :
503633 - Extract `path` attribute (relative path like "Declarations/Subscript.swift")
504634 - Extract content between tags (complete Swift code)
@@ -598,15 +728,27 @@ User runs: skit-analyze examples/subscript-feature Sources/SyntaxKit output/Synt
598728
599729### 4. Package.swift Changes
600730
601- Add ConfigKeyKit as a local target and integrate swift-configuration:
731+ Add ConfigKeyKit as a local target, integrate swift-configuration, and add OpenAPI Generator :
602732
603733```swift
604- // In dependencies (add swift-configuration) :
734+ // In dependencies:
605735.package(
606736 url: "https://github.com/apple/swift-configuration",
607737 from: "1.0.0",
608738 traits: ["CommandLineArguments"] // Enable CLI args trait
609739),
740+ .package(
741+ url: "https://github.com/apple/swift-openapi-generator",
742+ from: "1.0.0"
743+ ),
744+ .package(
745+ url: "https://github.com/apple/swift-openapi-runtime",
746+ from: "1.0.0"
747+ ),
748+ .package(
749+ url: "https://github.com/apple/swift-openapi-urlsession",
750+ from: "1.0.0"
751+ ),
610752
611753// Add ConfigKeyKit as a target:
612754.target(
@@ -617,13 +759,18 @@ Add ConfigKeyKit as a local target and integrate swift-configuration:
617759 swiftSettings: swiftSettings
618760),
619761
620- // Add new executable target:
762+ // Add new executable target with OpenAPI Generator plugin :
621763.executableTarget(
622764 name: "skit-analyze",
623765 dependencies: [
624766 "SyntaxParser",
625767 "ConfigKeyKit",
626- .product (name : " Configuration" , package : " swift-configuration" )
768+ .product(name: "Configuration", package: "swift-configuration"),
769+ .product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"),
770+ .product(name: "OpenAPIURLSession", package: "swift-openapi-urlsession")
771+ ],
772+ plugins: [
773+ .plugin(name: "OpenAPIGenerator", package: "swift-openapi-generator")
627774 ],
628775 swiftSettings: swiftSettings
629776),
@@ -635,7 +782,27 @@ Add ConfigKeyKit as a local target and integrate swift-configuration:
635782),
636783```
637784
638- ** Note** : ConfigKeyKit already exists in the project directory, so we just need to add it as a target in Package.swift.
785+ ** Setup Requirements** :
786+ 1 . Download OpenAPI spec to ` Sources/skit-analyze/ ` :
787+ ``` bash
788+ curl -o Sources/skit-analyze/openapi.json \
789+ https://raw.githubusercontent.com/laszukdawid/anthropic-openapi-spec/main/hosted_spec.json
790+ ```
791+
792+ 2 . Create ` Sources/skit-analyze/openapi-generator-config.yaml ` :
793+ ``` yaml
794+ generate :
795+ - types
796+ - client
797+ accessModifier : internal
798+ ` ` `
799+
800+ 3. The OpenAPI Generator plugin will automatically generate type-safe client code during build
801+
802+ **Notes**:
803+ - ConfigKeyKit already exists in the project directory, so we just need to add it as a target in Package.swift
804+ - OpenAPI Generator runs as a build plugin and generates Swift code from the OpenAPI spec at build time
805+ - Generated code includes type-safe request/response models and client methods
639806
640807### 5. Configuration & Environment
641808
@@ -729,6 +896,7 @@ Include full API request/response, intermediate parsing steps, file collection d
729896
730897## Critical Files to Create
731898
899+ ### Source Files
7329001. **Sources/skit-analyze/main.swift** - Main entry point
7339012. **Sources/skit-analyze/AnalyzeCommand.swift** - Command implementation using ConfigKeyKit
7349023. **Sources/skit-analyze/AnalyzerConfiguration.swift** - Configuration structure using ConfigKeyKit
@@ -737,10 +905,20 @@ Include full API request/response, intermediate parsing steps, file collection d
7379056. **Sources/skit-analyze/LibraryCollector.swift** - Collects SyntaxKit source files
7389067. **Sources/skit-analyze/LibraryWriter.swift** - Writes updated library to output folder
7399078. **Sources/skit-analyze/ASTGenerator.swift** - Wraps SyntaxParser for AST generation
740- 9 . ** Sources/skit-analyze/ClaudeAPIClient.swift** - Claude API communication for code generation
908+ 9. **Sources/skit-analyze/ClaudeAPIClient.swift** - Wraps OpenAPI-generated client for code generation
74190910. **Sources/skit-analyze/PromptTemplate.swift** - Enhanced Workbench prompt with code generation
74291011. **Sources/skit-analyze/Models.swift** - Data models (LibraryUpdateResult, UpdatedFile, NewFile, AnalyzerError)
743- 12 . ** Package.swift** (modify) - Add ConfigKeyKit target, swift-configuration dependency, and executable target
911+
912+ ### Configuration Files
913+ 12. **Sources/skit-analyze/openapi.json** - Anthropic OpenAPI specification (downloaded)
914+ 13. **Sources/skit-analyze/openapi-generator-config.yaml** - OpenAPI Generator configuration
915+ 14. **Package.swift** (modify) - Add ConfigKeyKit target, dependencies, and OpenAPI plugin
916+
917+ ### Test Mode Files (Section 8)
918+ 15. **Sources/skit-analyze/Testing/TestRunner.swift** - Orchestrates test execution
919+ 16. **Sources/skit-analyze/Testing/TestCaseDiscoverer.swift** - Discovers and loads test cases
920+ 17. **Sources/skit-analyze/Testing/TestValidator.swift** - Validates results against expectations
921+ 18. **Sources/skit-analyze/Testing/TestModels.swift** - Test data structures
744922
745923## Verification Steps
746924
@@ -949,19 +1127,32 @@ skit-analyze --test --test-cases=custom-tests/
9491127
9501128**New Dependencies**:
9511129- `swift-configuration` (1.0.0+) with `CommandLineArguments` trait - Configuration management
1130+ - `swift-openapi-generator` (1.0.0+) - Generates type-safe API client from OpenAPI spec
1131+ - `swift-openapi-runtime` (1.0.0+) - Runtime support for generated OpenAPI client
1132+ - `swift-openapi-urlsession` (1.0.0+) - URLSession transport for OpenAPI client
9521133
9531134**Existing Dependencies** (reused):
9541135- `ConfigKeyKit` (in project) - Configuration key abstraction
9551136- `SwiftSyntax` (601.0.1+) - via SyntaxParser
9561137- `SyntaxParser` (existing module) - AST generation
9571138- Foundation - HTTP requests, file I/O
9581139
959- **Advantages of swift-configuration + ConfigKeyKit**:
960- - Unified handling of CLI args and environment variables
961- - Type-safe configuration keys with automatic naming transformations
962- - Composable provider hierarchy (CLI overrides ENV)
963- - Consistent with project's existing ConfigKeyKit architecture
964- - More flexible than ArgumentParser for complex configuration scenarios
1140+ **External Resources**:
1141+ - [Unofficial Anthropic OpenAPI Spec](https://github.com/laszukdawid/anthropic-openapi-spec) - `hosted_spec.json` derived from Anthropic's TypeScript SDK
1142+
1143+ **Advantages of This Approach**:
1144+ - **swift-configuration + ConfigKeyKit**:
1145+ - Unified handling of CLI args and environment variables
1146+ - Type-safe configuration keys with automatic naming transformations
1147+ - Composable provider hierarchy (CLI overrides ENV)
1148+ - Consistent with project's existing ConfigKeyKit architecture
1149+
1150+ - **Swift OpenAPI Generator**:
1151+ - Type-safe API client generated at build time from OpenAPI spec
1152+ - Automatic request/response serialization
1153+ - Built-in error handling and validation
1154+ - No manual JSON parsing or HTTP request construction
1155+ - Easy to update when Anthropic publishes official OpenAPI spec (just replace the spec file)
9651156
9661157## Build & Install
9671158
0 commit comments