Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions .github/workflows/validate-repo-maintenance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,19 @@ on:
branches:
- main

permissions:
contents: read

concurrency:
group: validate-repo-maintenance-${{ github.ref }}
cancel-in-progress: true

jobs:
validate:
name: validate
runs-on: macos-latest
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v5
- name: Install Swift repo-maintenance tools
run: |
brew list swiftformat >/dev/null 2>&1 || brew install swiftformat
brew list swiftlint >/dev/null 2>&1 || brew install swiftlint
- name: Run repo-maintenance validation
run: bash scripts/repo-maintenance/validate-all.sh
4 changes: 3 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ Use the live integration runner when the local Codex CLI is available and the ch
scripts/run-live-codex-integration-tests.sh
```

The default mode runs the maintained release-gate set. Focused modes include `smoke`, `transport`, `capability`, `thread`, `turn`, `approval`, `behavior-matrix`, `server-requests`, `file-scenario`, `rollback`, `same-thread`, and `all`.
The default mode runs the full local release gate, including the ordinary Swift package test suite and the maintained live Codex probe set. Focused modes include `smoke`, `transport`, `capability`, `thread`, `turn`, `approval`, `behavior-matrix`, `server-requests`, `file-scenario`, `rollback`, `same-thread`, and `all`.

Other useful wrappers:

Expand Down Expand Up @@ -156,6 +156,8 @@ Start a standard release from a feature branch or isolated worktree with a clean
bash scripts/repo-maintenance/release.sh --mode standard --version vX.Y.Z
```

Standard release mode runs repo-maintenance validation, bumps release references, then runs the full local release gate before it tags, pushes, opens the release PR, watches remote CI, merges, fast-forwards `main`, and creates the GitHub release.

## Pull Request Expectations

PRs should identify the changed surface, explain any public API or docs boundary decision, and list the validation commands that ran.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ SwiftASB helps Swift apps work with the local Codex app-server without making ap

### Status

SwiftASB has a supported v1 public API for the core local Codex app-server lifecycle. `v1.1.3` is the current released baseline.
SwiftASB has a supported v1 public API for the core local Codex app-server lifecycle. `v1.1.4` is the current released baseline.

### What This Project Is

Expand All @@ -33,7 +33,7 @@ Add SwiftASB from the GitHub package URL:

https://github.com/gaelic-ghost/SwiftASB

Use release `v1.1.3` or newer unless your project intentionally pins an older version.
Use release `v1.1.4` or newer unless your project intentionally pins an older version.

You also need a local Codex CLI installation with app-server support. SwiftASB looks for `codex` in the usual command-line locations, and apps can provide an exact executable path when they need stricter control.

Expand Down
67 changes: 40 additions & 27 deletions ROADMAP.md

Large diffs are not rendered by default.

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions Sources/SwiftASB/Protocol/CodexAppServerProtocol+Types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ struct CodexProtocolThreadResumeParams: Encodable, Equatable, Sendable {
let personality: CodexWirePersonality?
let sandbox: CodexWireSandboxMode?
let serviceName: String?
let serviceTier: CodexWireServiceTier?
let serviceTier: String?
let threadID: String

enum CodingKeys: String, CodingKey {
Expand Down Expand Up @@ -194,7 +194,7 @@ struct CodexProtocolThreadForkParams: Encodable, Equatable, Sendable {
let personality: CodexWirePersonality?
let sandbox: CodexWireSandboxMode?
let serviceName: String?
let serviceTier: CodexWireServiceTier?
let serviceTier: String?
let threadID: String

enum CodingKeys: String, CodingKey {
Expand Down Expand Up @@ -342,7 +342,9 @@ struct CodexProtocolHooksListResponse: Decodable, Equatable, Sendable {

enum EventName: String, Decodable, Equatable, Sendable {
case permissionRequest
case postCompact
case postToolUse
case preCompact
case preToolUse
case sessionStart
case stop
Expand Down
6 changes: 6 additions & 0 deletions Sources/SwiftASB/Public/CodexAppServer+Hooks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,9 @@ public extension CodexAppServer {
/// Hook event that triggers this configured hook.
public enum EventName: String, Sendable, Equatable {
case permissionRequest
case postCompact
case postToolUse
case preCompact
case preToolUse
case sessionStart
case stop
Expand Down Expand Up @@ -190,8 +192,12 @@ extension CodexAppServer.HookMetadata.EventName {
switch protocolValue {
case .permissionRequest:
self = .permissionRequest
case .postCompact:
self = .postCompact
case .postToolUse:
self = .postToolUse
case .preCompact:
self = .preCompact
case .preToolUse:
self = .preToolUse
case .sessionStart:
Expand Down
25 changes: 10 additions & 15 deletions Sources/SwiftASB/Public/CodexAppServer+WireMapping.swift
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ extension CodexAppServer.ThreadStartRequest {
sandbox: sandboxMode?.wireValue,
serviceName: serviceName,
serviceTier: serviceTier?.wireValue,
sessionStartSource: sessionStartSource?.wireValue
sessionStartSource: sessionStartSource?.wireValue,
threadSource: nil
)
}
}
Expand Down Expand Up @@ -385,23 +386,13 @@ extension CodexAppServer.SandboxMode {
}

extension CodexAppServer.ServiceTier {
init?(wireValue: CodexWireServiceTier?) {
init?(wireValue: String?) {
guard let wireValue else { return nil }
switch wireValue {
case .fast:
self = .fast
case .flex:
self = .flex
}
self.init(rawValue: wireValue)
}

var wireValue: CodexWireServiceTier {
switch self {
case .fast:
.fast
case .flex:
.flex
}
var wireValue: String {
rawValue
}
}

Expand Down Expand Up @@ -750,8 +741,12 @@ extension CodexThread.Dashboard.HookRun.EventName {
switch wireValue {
case .permissionRequest:
self = .permissionRequest
case .postCompact:
self = .postCompact
case .postToolUse:
self = .postToolUse
case .preCompact:
self = .preCompact
case .preToolUse:
self = .preToolUse
case .sessionStart:
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftASB/Public/CodexAppServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1139,7 +1139,7 @@ public actor CodexAppServer {
do {
let requestPayload = try protocolLayer.makePluginListRequest(
id: requestID,
params: .init(cwds: request.currentDirectoryPaths)
params: .init(cwds: request.currentDirectoryPaths, marketplaceKinds: nil)
)
let responsePayload = try await transport.send(requestPayload, id: requestID)
let response = try protocolLayer.decodePluginListResponse(
Expand Down
2 changes: 2 additions & 0 deletions Sources/SwiftASB/Public/CodexThread+Dashboard.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ extension CodexThread {

public enum EventName: String, Sendable, Equatable {
case permissionRequest
case postCompact
case postToolUse
case preCompact
case preToolUse
case sessionStart
case stop
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ internal struct CodexCLIExecutableResolver {
internal let patch: Int

private static let regex = try! NSRegularExpression(pattern: #"(\d+)\.(\d+)\.(\d+)"#)
internal static let latestSupportedPublicRelease = Version(major: 0, minor: 128, patch: 0)
internal static let latestSupportedPublicRelease = Version(major: 0, minor: 129, patch: 0)

internal static var documentedWindowDescription: String {
let latest = latestSupportedPublicRelease
Expand Down
15 changes: 8 additions & 7 deletions Tests/SwiftASBTests/Protocol/CodexAppServerProtocolTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,9 @@ struct CodexAppServerProtocolTests {
personality: .friendly,
sandbox: .workspaceWrite,
serviceName: "codex",
serviceTier: .fast,
sessionStartSource: .clear
serviceTier: "fast",
sessionStartSource: .clear,
threadSource: nil
)
)

Expand Down Expand Up @@ -270,7 +271,7 @@ struct CodexAppServerProtocolTests {
personality: .friendly,
sandbox: .workspaceWrite,
serviceName: "codex",
serviceTier: .fast,
serviceTier: "fast",
threadID: "thread-123"
)
)
Expand Down Expand Up @@ -312,7 +313,7 @@ struct CodexAppServerProtocolTests {
personality: .pragmatic,
sandbox: .workspaceWrite,
serviceName: "codex",
serviceTier: .fast,
serviceTier: "fast",
threadID: "thread-123"
)
)
Expand Down Expand Up @@ -591,7 +592,7 @@ struct CodexAppServerProtocolTests {

let pluginPayload = try protocolLayer.makePluginListRequest(
id: .string("plugin-list-1"),
params: .init(cwds: ["/tmp/project"])
params: .init(cwds: ["/tmp/project"], marketplaceKinds: nil)
)
let pluginRequest = try #require(try JSONSerialization.jsonObject(with: pluginPayload) as? [String: Any])
#expect(pluginRequest["method"] as? String == "plugin/list")
Expand Down Expand Up @@ -640,7 +641,7 @@ struct CodexAppServerProtocolTests {
personality: .pragmatic,
responsesapiClientMetadata: nil,
sandboxPolicy: nil,
serviceTier: .flex,
serviceTier: "flex",
summary: .concise,
threadID: "thread-123"
)
Expand Down Expand Up @@ -770,7 +771,7 @@ struct CodexAppServerProtocolTests {
#expect(response.cwd == "/tmp/project")
#expect(response.model == "gpt-5.4")
#expect(response.modelProvider == "openai")
#expect(response.serviceTier == .fast)
#expect(response.serviceTier == "fast")
#expect(response.thread.id == "thread-123")
#expect(response.thread.preview == "Hello")
#expect(response.thread.turns.isEmpty)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,8 @@ extension CodexAppServerLiveIntegrationTests {
sandbox: .readOnly,
serviceName: nil,
serviceTier: nil,
sessionStartSource: nil
sessionStartSource: nil,
threadSource: nil
)
)
let threadResponsePayload = try await withTimeout(
Expand Down Expand Up @@ -512,7 +513,8 @@ extension CodexAppServerLiveIntegrationTests {
sandbox: .readOnly,
serviceName: nil,
serviceTier: nil,
sessionStartSource: nil
sessionStartSource: nil,
threadSource: nil
)
)
let threadResponsePayload = try await withTimeout(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ extension CodexAppServerLiveIntegrationTests {
sandbox: .readOnly,
serviceName: nil,
serviceTier: nil,
sessionStartSource: nil
sessionStartSource: nil,
threadSource: nil
)
)
let threadResponsePayload = try await withTimeout(
Expand Down Expand Up @@ -282,7 +283,8 @@ extension CodexAppServerLiveIntegrationTests {
sandbox: .readOnly,
serviceName: nil,
serviceTier: nil,
sessionStartSource: nil
sessionStartSource: nil,
threadSource: nil
)
)
let threadResponsePayload = try await withTimeout(
Expand Down Expand Up @@ -463,7 +465,8 @@ extension CodexAppServerLiveIntegrationTests {
sandbox: .readOnly,
serviceName: nil,
serviceTier: nil,
sessionStartSource: nil
sessionStartSource: nil,
threadSource: nil
)
)
let threadResponsePayload = try await withTimeout(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,8 @@ struct CodexAppServerLiveIntegrationTests {
sandbox: .workspaceWrite,
serviceName: nil,
serviceTier: nil,
sessionStartSource: nil
sessionStartSource: nil,
threadSource: nil
)
)
let threadResponsePayload = try await withTimeout(
Expand Down Expand Up @@ -197,7 +198,7 @@ struct CodexAppServerLiveIntegrationTests {
let diagnostics = try await client.cliExecutableDiagnostics()
#expect(diagnostics.resolvedExecutablePath == harness.codexExecutableURL.path)
#expect(diagnostics.versionString.contains("codex-cli"))
#expect(diagnostics.compatibility == .supported(documentedWindow: "0.128.x"))
#expect(diagnostics.compatibility == .supported(documentedWindow: "0.129.x"))

await client.stop()
} catch {
Expand Down Expand Up @@ -295,7 +296,8 @@ struct CodexAppServerLiveIntegrationTests {
sandbox: .workspaceWrite,
serviceName: nil,
serviceTier: nil,
sessionStartSource: nil
sessionStartSource: nil,
threadSource: nil
)
)
let threadResponsePayload = try await withTimeout(
Expand Down Expand Up @@ -574,7 +576,8 @@ struct CodexAppServerLiveIntegrationTests {
let thread = try await startThread(
on: client,
workspacePath: harness.threadAWorkspace.path,
label: "thread-name"
label: "thread-name",
ephemeral: false
)
let expectedName = "SwiftASB live name \(UUID().uuidString)"

Expand Down
8 changes: 4 additions & 4 deletions Tests/SwiftASBTests/Public/CodexAppServerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ struct CodexAppServerTests {
launchArgumentsPrefix: [],
resolvedExecutableURL: URL(fileURLWithPath: "/opt/homebrew/bin/codex"),
source: .homebrewAppleSilicon,
versionString: "codex-cli 0.128.0",
compatibility: .supported(documentedWindow: "0.128.x")
versionString: "codex-cli 0.129.0",
compatibility: .supported(documentedWindow: "0.129.x")
)
)
let client = CodexAppServer(transport: transport)
Expand All @@ -94,8 +94,8 @@ struct CodexAppServerTests {
let diagnostics = try await client.cliExecutableDiagnostics()
#expect(diagnostics.source == .homebrewAppleSilicon)
#expect(diagnostics.resolvedExecutablePath == "/opt/homebrew/bin/codex")
#expect(diagnostics.versionString == "codex-cli 0.128.0")
#expect(diagnostics.compatibility == .supported(documentedWindow: "0.128.x"))
#expect(diagnostics.versionString == "codex-cli 0.129.0")
#expect(diagnostics.compatibility == .supported(documentedWindow: "0.129.x"))

await client.stop()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ private let fakeCodexScript = """
#!/bin/sh

if [ "$1" = "--version" ]; then
printf '%s\\n' 'codex-cli 0.128.0'
printf '%s\\n' 'codex-cli 0.129.0'
exit 0
fi

Expand Down
Loading