Skip to content
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Listen to the SwiftASB Codex apps promo clip:

### Status

SwiftASB is actively maintained and supported by Gale. Our current API is v1, and `v1.6.0` is the current and latest release.
SwiftASB is actively maintained and supported by Gale. Our current API is v1, and `v1.7.0` is the current and latest release.

### What This Project Is

Expand All @@ -38,7 +38,7 @@ I built SwiftASB because I saw so many others building and forking existing Apps
Add SwiftASB to your `Package.swift` dependencies:

```swift
.package(url: "https://github.com/gaelic-ghost/SwiftASB", from: "1.6.0"),
.package(url: "https://github.com/gaelic-ghost/SwiftASB", from: "1.7.0"),
```

Then add the library product to your target dependencies:
Expand Down
176 changes: 125 additions & 51 deletions ROADMAP.md

Large diffs are not rendered by default.

39 changes: 39 additions & 0 deletions Sources/SwiftASB/Protocol/CodexAppServerProtocol+Types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ enum CodexAppServerProtocolEvent: Equatable, Sendable {
case turnCompleted(CodexWireTurnCompletedNotification)
case itemStarted(CodexWireItemStartedNotification)
case itemCompleted(CodexWireItemCompletedNotification)
case itemGuardianApprovalReviewStarted(CodexWireItemGuardianApprovalReviewStartedNotification)
case itemGuardianApprovalReviewCompleted(CodexProtocolGuardianApprovalReviewCompletedNotification)
case commandExecOutputDelta(CodexWireCommandExecOutputDeltaNotification)
case commandExecutionOutputDelta(CodexWireCommandExecutionOutputDeltaNotification)
case fileChangeOutputDelta(CodexWireFileChangeOutputDeltaNotification)
Expand All @@ -61,6 +63,13 @@ struct CodexProtocolThreadArchiveResponse: Decodable, Equatable, Sendable {}

struct CodexProtocolThreadSetNameResponse: Decodable, Equatable, Sendable {}

struct CodexProtocolThreadApproveGuardianDeniedActionResponse: Decodable, Equatable, Sendable {}

struct CodexProtocolGuardianApprovalReviewCompletedNotification: Equatable, Sendable {
let event: CodexWireJSONValue
let notification: CodexWireItemGuardianApprovalReviewCompletedNotification
}

struct CodexProtocolModelProviderCapabilitiesReadParams: Encodable, Equatable, Sendable {}

struct CodexProtocolModelProviderCapabilitiesReadResponse: Decodable, Equatable, Sendable {
Expand Down Expand Up @@ -137,6 +146,36 @@ enum CodexProtocolConfigWriteStatus: String, Decodable, Equatable, Sendable {
case okOverridden
}

struct CodexProtocolFSWriteFileParams: Encodable, Equatable, Sendable {
let dataBase64: String
let path: String
}

struct CodexProtocolFSCreateDirectoryParams: Encodable, Equatable, Sendable {
let path: String
let recursive: Bool?
}

struct CodexProtocolFSRemoveParams: Encodable, Equatable, Sendable {
let force: Bool?
let path: String
let recursive: Bool?
}

struct CodexProtocolFSCopyParams: Encodable, Equatable, Sendable {
let destinationPath: String
let recursive: Bool?
let sourcePath: String
}

struct CodexProtocolFSWriteFileResponse: Decodable, Equatable, Sendable {}

struct CodexProtocolFSCreateDirectoryResponse: Decodable, Equatable, Sendable {}

struct CodexProtocolFSRemoveResponse: Decodable, Equatable, Sendable {}

struct CodexProtocolFSCopyResponse: Decodable, Equatable, Sendable {}

struct CodexProtocolThreadMetadataUpdateParams: Encodable, Equatable, Sendable {
let gitInfo: GitInfo?
let threadID: String
Expand Down
140 changes: 139 additions & 1 deletion Sources/SwiftASB/Protocol/CodexAppServerProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ struct CodexAppServerProtocol {
case threadGoalSet = "thread/goal/set"
case threadGoalClear = "thread/goal/clear"
case threadShellCommand = "thread/shellCommand"
case threadApproveGuardianDeniedAction = "thread/approveGuardianDeniedAction"
case turnStart = "turn/start"
case turnSteer = "turn/steer"
case turnInterrupt = "turn/interrupt"
Expand All @@ -30,6 +31,10 @@ struct CodexAppServerProtocol {
case fsReadFile = "fs/readFile"
case fsWatch = "fs/watch"
case fsUnwatch = "fs/unwatch"
case fsWriteFile = "fs/writeFile"
case fsCreateDirectory = "fs/createDirectory"
case fsRemove = "fs/remove"
case fsCopy = "fs/copy"
case appList = "app/list"
case collaborationModeList = "collaborationMode/list"
case configRead = "config/read"
Expand Down Expand Up @@ -105,6 +110,16 @@ struct CodexAppServerProtocol {
)
}

func makeThreadApproveGuardianDeniedActionRequest(
id: CodexRPCRequestID,
params: CodexWireThreadApproveGuardianDeniedActionParams
) throws -> Data {
try encodeRequest(
JSONRPCRequestEnvelope(id: id, method: .threadApproveGuardianDeniedAction, params: params),
method: .threadApproveGuardianDeniedAction
)
}

func makeReviewStartRequest(
id: CodexRPCRequestID,
params: CodexWireReviewStartParams
Expand Down Expand Up @@ -295,6 +310,46 @@ struct CodexAppServerProtocol {
)
}

func makeFSWriteFileRequest(
id: CodexRPCRequestID,
params: CodexProtocolFSWriteFileParams
) throws -> Data {
try encodeRequest(
JSONRPCRequestEnvelope(id: id, method: .fsWriteFile, params: params),
method: .fsWriteFile
)
}

func makeFSCreateDirectoryRequest(
id: CodexRPCRequestID,
params: CodexProtocolFSCreateDirectoryParams
) throws -> Data {
try encodeRequest(
JSONRPCRequestEnvelope(id: id, method: .fsCreateDirectory, params: params),
method: .fsCreateDirectory
)
}

func makeFSRemoveRequest(
id: CodexRPCRequestID,
params: CodexProtocolFSRemoveParams
) throws -> Data {
try encodeRequest(
JSONRPCRequestEnvelope(id: id, method: .fsRemove, params: params),
method: .fsRemove
)
}

func makeFSCopyRequest(
id: CodexRPCRequestID,
params: CodexProtocolFSCopyParams
) throws -> Data {
try encodeRequest(
JSONRPCRequestEnvelope(id: id, method: .fsCopy, params: params),
method: .fsCopy
)
}

func makeConfigReadRequest(
id: CodexRPCRequestID,
params: CodexWireConfigReadParams
Expand Down Expand Up @@ -604,6 +659,18 @@ struct CodexAppServerProtocol {
)
}

func decodeThreadApproveGuardianDeniedActionResponse(
_ responsePayload: Data,
expectedID: CodexRPCRequestID
) throws -> CodexProtocolThreadApproveGuardianDeniedActionResponse {
try decodeResponse(
responsePayload,
expectedID: expectedID,
method: .threadApproveGuardianDeniedAction,
resultType: CodexProtocolThreadApproveGuardianDeniedActionResponse.self
)
}

func decodeThreadMetadataUpdateResponse(
_ responsePayload: Data,
expectedID: CodexRPCRequestID
Expand Down Expand Up @@ -784,6 +851,54 @@ struct CodexAppServerProtocol {
)
}

func decodeFSWriteFileResponse(
_ responsePayload: Data,
expectedID: CodexRPCRequestID
) throws -> CodexProtocolFSWriteFileResponse {
try decodeResponse(
responsePayload,
expectedID: expectedID,
method: .fsWriteFile,
resultType: CodexProtocolFSWriteFileResponse.self
)
}

func decodeFSCreateDirectoryResponse(
_ responsePayload: Data,
expectedID: CodexRPCRequestID
) throws -> CodexProtocolFSCreateDirectoryResponse {
try decodeResponse(
responsePayload,
expectedID: expectedID,
method: .fsCreateDirectory,
resultType: CodexProtocolFSCreateDirectoryResponse.self
)
}

func decodeFSRemoveResponse(
_ responsePayload: Data,
expectedID: CodexRPCRequestID
) throws -> CodexProtocolFSRemoveResponse {
try decodeResponse(
responsePayload,
expectedID: expectedID,
method: .fsRemove,
resultType: CodexProtocolFSRemoveResponse.self
)
}

func decodeFSCopyResponse(
_ responsePayload: Data,
expectedID: CodexRPCRequestID
) throws -> CodexProtocolFSCopyResponse {
try decodeResponse(
responsePayload,
expectedID: expectedID,
method: .fsCopy,
resultType: CodexProtocolFSCopyResponse.self
)
}

func decodeConfigReadResponse(
_ responsePayload: Data,
expectedID: CodexRPCRequestID
Expand Down Expand Up @@ -1071,7 +1186,7 @@ struct CodexAppServerProtocol {
resultType: [String: CodexWireJSONValue].self
)
)
case "mcpServer/status/updated":
case "mcpServer/startupStatus/updated":
return .mcpServerStatusUpdated(
try decodeNotification(
payload,
Expand Down Expand Up @@ -1279,6 +1394,29 @@ struct CodexAppServerProtocol {
resultType: CodexWireItemCompletedNotification.self
)
)
case "item/autoApprovalReview/started":
return .itemGuardianApprovalReviewStarted(
try decodeNotification(
payload,
method: method,
resultType: CodexWireItemGuardianApprovalReviewStartedNotification.self
)
)
case "item/autoApprovalReview/completed":
return .itemGuardianApprovalReviewCompleted(
.init(
event: try decodeNotification(
payload,
method: method,
resultType: CodexWireJSONValue.self
),
notification: try decodeNotification(
payload,
method: method,
resultType: CodexWireItemGuardianApprovalReviewCompletedNotification.self
)
)
)
case "item/commandExecution/outputDelta":
return .commandExecutionOutputDelta(
try decodeNotification(
Expand Down
19 changes: 16 additions & 3 deletions Sources/SwiftASB/Protocol/CodexRPCEnvelope.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,26 @@ internal enum CodexRPCEnvelope {
)
}

let doubleValue = number.doubleValue
let integerValue = number.intValue
guard doubleValue.rounded(.towardZero) == doubleValue else {
let decimalValue = number.decimalValue
var roundedValue = Decimal()
var sourceValue = decimalValue
NSDecimalRound(&roundedValue, &sourceValue, 0, .plain)
guard roundedValue == decimalValue else {
throw CodexTransportError.invalidJSONRPCEnvelope(
reason: "JSON-RPC numeric request IDs must be whole numbers."
)
}
guard decimalValue >= Decimal(Int.min), decimalValue <= Decimal(Int.max) else {
throw CodexTransportError.invalidJSONRPCEnvelope(
reason: "JSON-RPC numeric request ID \(number) is outside the supported Swift Int range."
)
}

guard let integerValue = Int(exactly: NSDecimalNumber(decimal: decimalValue)) else {
throw CodexTransportError.invalidJSONRPCEnvelope(
reason: "JSON-RPC numeric request ID \(number) could not be represented exactly as a Swift Int."
)
}
return .int(integerValue)
}

Expand Down
Loading