Add GitHub workflows and update approval FFI shim (#1)

Copy the CI/release workflow setup from onde-swift, adapted for Ed: - scheme Ed (not Onde); no watchOS job because watchOS is currently disabled in Package.swift - release tag pattern vX.Y.Z, with the 'v' prefix stripped before the SwiftPM 'from:' version Also update ApprovalAdapter and EventHub in EdAgent.swift to match the generated FFI: the v1.0.1 xcframework exposes FfiApprovalHandler.approve and FfiEventListener.approvalRequested with a FfiApprovalRequest parameter (carrying both the tool call and risk), not the bare FfiToolCall that the prior 1.0.0 release shipped. Without this fix a clean checkout fails to compile the Ed target against the released framework. Co-authored-by: siGit Code v1.5.13-acp <noreply@sigit.si>

Seto Elkahfi committed Oct 4, 2026 at 22:36 UTC 62a5426fc3b0a689ee51f8622085b082059cb1bd
3 files changed +148 -3
.github/workflows/ci.yml new
+76
@@ -0,0 +1,76 @@
1 +name: CI
2 +
3 +on:
4 + push:
5 + branches: [main]
6 + pull_request:
7 + branches: [main]
8 + workflow_dispatch:
9 +
10 +concurrency:
11 + group: ci-${{ github.ref }}
12 + cancel-in-progress: true
13 +
14 +permissions:
15 + contents: read
16 +
17 +jobs:
18 + validate:
19 + name: Validate manifest
20 + runs-on: macos-26
21 + steps:
22 + - uses: actions/checkout@v6
23 + - name: Dump package
24 + run: swift package dump-package
25 + - name: Resolve dependencies
26 + run: swift package resolve
27 +
28 + build-macos:
29 + name: Build (macOS)
30 + needs: validate
31 + runs-on: macos-26
32 + steps:
33 + - uses: actions/checkout@v6
34 + - run: swift build
35 +
36 + build-ios:
37 + name: Build (iOS)
38 + needs: validate
39 + runs-on: macos-26
40 + steps:
41 + - uses: actions/checkout@v6
42 + - name: Build for iOS
43 + run: >
44 + xcodebuild build
45 + -scheme Ed
46 + -destination 'generic/platform=iOS'
47 + -skipPackagePluginValidation
48 + -skipMacroValidation
49 +
50 + build-tvos:
51 + name: Build (tvOS)
52 + needs: validate
53 + runs-on: macos-26
54 + steps:
55 + - uses: actions/checkout@v6
56 + - name: Build for tvOS
57 + run: >
58 + xcodebuild build
59 + -scheme Ed
60 + -destination 'generic/platform=tvOS'
61 + -skipPackagePluginValidation
62 + -skipMacroValidation
63 +
64 + build-visionos:
65 + name: Build (visionOS)
66 + needs: validate
67 + runs-on: macos-26
68 + steps:
69 + - uses: actions/checkout@v6
70 + - name: Build for visionOS
71 + run: >
72 + xcodebuild build
73 + -scheme Ed
74 + -destination 'generic/platform=visionOS'
75 + -skipPackagePluginValidation
76 + -skipMacroValidation
.github/workflows/release.yml new
+69
@@ -0,0 +1,69 @@
1 +name: Release
2 +
3 +on:
4 + push:
5 + tags:
6 + - "v[0-9]+.[0-9]+.[0-9]+"
7 +
8 +permissions:
9 + contents: write
10 +
11 +jobs:
12 + validate:
13 + name: Validate package
14 + runs-on: macos-26
15 + steps:
16 + - uses: actions/checkout@v6
17 +
18 + - name: Resolve dependencies
19 + run: swift package resolve
20 +
21 + - name: Build for macOS
22 + run: swift build
23 +
24 + - name: Build for iOS
25 + run: >
26 + xcodebuild build
27 + -scheme Ed
28 + -destination 'generic/platform=iOS'
29 + -skipPackagePluginValidation
30 + -skipMacroValidation
31 +
32 + release:
33 + name: Create GitHub Release
34 + needs: validate
35 + runs-on: ubuntu-latest
36 + steps:
37 + - uses: actions/checkout@v6
38 +
39 + # Ed tags carry a `v` prefix, which SwiftPM's `from:` does not accept.
40 + - id: version
41 + run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
42 +
43 + - name: Create GitHub Release
44 + uses: softprops/action-gh-release@v2
45 + with:
46 + name: ${{ github.ref_name }}
47 + body: |
48 + ## Ed Swift SDK ${{ github.ref_name }}
49 +
50 + ### Installation
51 +
52 + Add Ed to your `Package.swift` dependencies:
53 +
54 + ```swift
55 + .package(url: "https://github.com/ondeinference/ed-swift.git", from: "${{ steps.version.outputs.version }}")
56 + ```
57 +
58 + ### Platforms
59 +
60 + | Platform | Minimum Version |
61 + |----------|----------------|
62 + | iOS | 16.0 |
63 + | macOS | 14.0 |
64 + | tvOS | 16.0 |
65 + | visionOS | 1.0 |
66 +
67 + ### What's Changed
68 +
69 + See the full changelog in the [Ed ${{ github.ref_name }}](https://github.com/ondeinference/ed/releases/tag/${{ github.ref_name }}) release.
Sources/Ed/EdAgent.swift
+3 -3
@@ -417,8 +417,8 @@ private final class ApprovalAdapter: FfiApprovalHandler, @unchecked Sendable {
417 self.handler = handler
418 }
419
420 - func approve(call: FfiToolCall) async -> FfiApprovalDecision {
421 - await handler(call.swift).ffi
420 + func approve(request: FfiApprovalRequest) async -> FfiApprovalDecision {
421 + await handler(request.call.swift).ffi
422 }
423 }
424
@@ -445,7 +445,7 @@ private final class EventHub: FfiEventListener, @unchecked Sendable {
445 }
446
447 func toolRequested(call: FfiToolCall) { emit(.toolRequested(call.swift)) }
448 - func approvalRequested(call: FfiToolCall) { emit(.approvalRequested(call.swift)) }
448 + func approvalRequested(request: FfiApprovalRequest) { emit(.approvalRequested(request.call.swift)) }
449 func toolStarted(call: FfiToolCall) { emit(.toolStarted(call.swift)) }
450
451 func toolFinished(toolCallId: String, content: String, isError: Bool) {