diff --git a/.github/workflows/validate-repo-maintenance.yml b/.github/workflows/validate-repo-maintenance.yml index 51c0624..b33210e 100644 --- a/.github/workflows/validate-repo-maintenance.yml +++ b/.github/workflows/validate-repo-maintenance.yml @@ -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 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8c47e5e..3ee568a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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: @@ -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. diff --git a/README.md b/README.md index 1465603..f2a745e 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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. diff --git a/ROADMAP.md b/ROADMAP.md index e902eae..decb2cd 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -41,7 +41,7 @@ | --- | --- | --- | | Bundled schema-driven wire generation | `Shipped internally` | `scripts/generate-wire-types.sh` derives from the bundled v2 schema, patches dynamic JSON to `CodexWireJSONValue`, and validates the staged Swift output. | | Promoted generated v2 wire snapshot | `Shipped internally` | `Sources/SwiftASB/Generated/CodexWire/Latest/` now contains a wider lifecycle batch covering bootstrap, stored and loaded thread reads, filesystem reads and watches, config reads, extension inventory, thread goals, and many thread, turn, item, reasoning, and tool-progress notifications, alongside the hand-owned `CodexWireInitializeResponse` shim. | -| Codex CLI schema review | `Shipped / ongoing` | The current reviewed compatibility window is `codex-cli 0.128.x`; the v0.128 schema families have been classified for the v1 boundary, and `scripts/dump-codex-schemas.sh` makes future versioned experimental dumps repeatable by default. Future Codex CLI schema families still need public/observable/internal decisions before promotion. | +| Codex CLI schema review | `Shipped / ongoing` | The current reviewed compatibility window is `codex-cli 0.129.x`; the v0.129 schema families have been classified for the current boundary, and `scripts/dump-codex-schemas.sh` makes future versioned experimental dumps repeatable by default. Future Codex CLI schema families still need public/observable/internal decisions before promotion. | | Stdio subprocess transport | `Shipped internally` | The transport launches `codex app-server --listen stdio://`, frames newline-delimited JSON, correlates request IDs, and captures stderr for diagnostics. | | Raw server-event fanout | `Shipped internally` | Transport can stream raw JSON-RPC notifications and server requests to higher layers. | | Typed protocol request encoding | `Shipped internally` | `initialize`, `initialized`, core thread and turn methods, archive-state actions, filesystem reads and watches, config reads, app/skill/plugin/collaboration-mode inventory, model/MCP/hook reads, MCP resource reads, and thread-goal methods are encoded through the protocol layer. | @@ -76,14 +76,14 @@ | Non-UI local history-reading helpers | `Partially shipped` | `CodexThread` now exposes a lightweight `HistoryWindow` page shape for recent local history, older or newer local windows around a known boundary turn id, centered `windowAroundTurn(...)` reads, centered `windowAroundItem(...)` reads, direct `ClosedTurn` reads for one turn, and convenience array helpers over those same windows. This gives non-UI callers an intentional path into the local history store without binding a UI-oriented observable, while still deferring a broader public cursor model, transcript search surface, and richer history-query helpers. | | Public API curation | `Shipped / ongoing` | The source-organization pass has split app-wide model, MCP, thread-management, history, and observable companion values into focused public files while preserving `CodexAppServer`, `CodexThread`, and `CodexTurnHandle` as the three real owners. The connected public-surface review closed the v1 ownership model; post-v1 curation now includes app-server-owned project identity and thread source facts for launcher UI without exposing generated wire models. Future curation should stay tied to concrete public API additions. | | DocC documentation | `Shipped / ongoing` | `Sources/SwiftASB/SwiftASB.docc/` contains a package landing page, public-handle extension pages, conceptual articles for app-wide capabilities, interactive lifecycle, thread management, history/observable companions, generated-wire boundary notes, and copy-pasteable walkthroughs for startup, progress/approval handling, diagnostics/history, and SwiftUI observable companions. The catalog is validated through Xcode `docbuild`; future work is ordinary stale-link, prose, and symbol-comment refinement as the public API grows. | -| Swift Package Index readiness | `Shipped` | `.spi.yml` declares `SwiftASB` as the documentation target, and Swift Package Index lists `gaelic-ghost/SwiftASB` with a documentation link, compatibility/build results, Package ID `9B5839D9-9551-473F-A939-841534A3FC55`, and a 2026-05-06 update timestamp for the latest confirmed indexed release. Recheck SPI after the `v1.1.3` tag is published. | +| Swift Package Index readiness | `Shipped` | `.spi.yml` declares `SwiftASB` as the documentation target, and Swift Package Index lists `gaelic-ghost/SwiftASB` with a documentation link, compatibility/build results, Package ID `9B5839D9-9551-473F-A939-841534A3FC55`, and a 2026-05-06 update timestamp for the latest confirmed indexed release. Recheck SPI after the `v1.1.4` tag is published. | | Contributor documentation split | `Shipped` | `README.md` is now focused on Swift and SwiftUI package users, while `CONTRIBUTING.md` owns contributor setup, validation, DocC, live-test flags, generated-wire refresh, and PR expectations. | | `CodexTurnHandle` live observable companion | `Partially shipped` | `CodexTurnHandle` owns a live `Minimap` companion that is attached when the handle is created and maintains current-state call snapshots for command, file-edit, dynamic-tool, collab-tool, and MCP item activity. It also now mirrors whether thread context compaction is active for the turn and supports explicit `complete()` handoff into a caller-owned sealed turn snapshot. | | Additional turn event mapping | `Partially shipped` | The public event layer covers the current interactive lifecycle plus the item-start and item-complete events needed for observable call-state mirrors. Raw command-output and file-change-output deltas now stay internal as transport detail but drive the shipped `RecentCommands` and `RecentFiles` companions, and streamed or patch-updated payloads are preserved when later completed snapshots are thinner. Richer MCP-progress detail still remains internal, while warning, guardian-warning, config-warning, deprecation, MCP-server-status, remote-control-status, model-reroute, and model-verification notifications now surface through hand-owned diagnostic events. | | Server request / approval handling | `Partially shipped` | Typed approval and elicitation request models now surface on thread and turn event streams, explicit response APIs exist on `CodexThread` and `CodexTurnHandle`, request resolution is tracked by JSON-RPC request id, and deterministic command-approval plus permissions-approval completion are covered through the real app-server with a mock Responses provider. Diagnostics are now separated from control flows: passive warning/model/guardian signals are public diagnostics, while guardian denied-action approval remains internal until SwiftASB owns a stable request/response model for it. | | Internal thread history persistence | `Partially shipped` | The package now has a Core Data-backed `ThreadHistoryStore` that persists live-built thread and turn history, hydrates stored turns from `thread/read`, `thread/resume`, `thread/fork`, and `thread/turns/list`, seeds previously unknown local threads from paged history, widens persisted turn identity to stay thread-scoped across forks, and records explicit fork lineage while preserving conservative reconciliation that keeps richer local detail when upstream stored history is thinner. Public history paging/search helpers and archive-retention policy are still open. | | Convenience run API | `Not started` | No `run(...)` or one-shot text convenience layer yet. | -| Binary discovery and compatibility policy | `Partially shipped` | Explicit binary override exists, the docs now define a current-reviewed Codex CLI support window of `0.128.x`, transport startup checks PATH, common Homebrew paths, and the npm global prefix on macOS, and `cliExecutableDiagnostics()` now exposes the resolved binary, version string, and documented support-window assessment. Any further diagnostics work is now expansion rather than a missing baseline surface. | +| Binary discovery and compatibility policy | `Partially shipped` | Explicit binary override exists, the docs now define a current-reviewed Codex CLI support window of `0.129.x`, transport startup checks PATH, common Homebrew paths, and the npm global prefix on macOS, and `cliExecutableDiagnostics()` now exposes the resolved binary, version string, and documented support-window assessment. Any further diagnostics work is now expansion rather than a missing baseline surface. | | README-level consumer docs | `Shipped / ongoing` | The README covers installation, runtime assumptions, first-use examples, the supported lifecycle, SwiftUI companion surfaces, and the current Codex CLI compatibility window. Future README work should track new public API additions rather than prerelease readiness. | | Agent workflow guidance | `Shipped / ongoing` | SwiftASB-specific Codex guidance now ships through `socket`'s [`swiftasb-skills`](https://github.com/gaelic-ghost/socket/tree/main/plugins/swiftasb-skills) plugin, with skills for explaining SwiftASB, choosing an integration shape, building SwiftUI-facing app state, and diagnosing integration failures. This repo now points package users and maintainers at that plugin while keeping SwiftASB source, DocC, tests, generated-wire review, and release notes here as the package source of truth. | | End-to-end subprocess integration tests | `Shipped / ongoing` | The package includes opt-in live Codex CLI integration tests with temp workspaces and time limits, including raw transport startup, single-turn completion, cross-thread completion, app-wide model/MCP/hook diagnostics snapshots, thread-name mutation, stored-history materialization, same-thread concurrency probing, deterministic command and permissions approvals through a mock Responses provider, a best-effort prompt-driven approval-path probe, a disposable live rollback scenario, and a multi-turn file-mutation scenario that creates, edits, and deletes files through the real CLI. The umbrella runner is `scripts/run-live-codex-integration-tests.sh`; it defaults to the release-gate set and exposes focused modes for smoke, transport, capability, thread, turn, approval, file-scenario, rollback, same-thread, and all opt-in live tests. Stored-history materialization remains in focused `thread`/`all` runs instead of the release-gate smoke group because the live app-server can delay history materialization. | @@ -104,7 +104,7 @@ The next meaningful package step is no longer proving the v1 interactive lifecycle, SPI visibility, basic history hydration, first-pass reconciliation, or command-approval completion. Those slices now exist and shipped in the -`v1.1.3` baseline. +`v1.1.4` baseline. The next meaningful work is to widen the reviewed app-server schema and protocol coverage before adding more public query descriptors. Descriptors should compile @@ -177,7 +177,7 @@ That means the current priority order is: ## V1 Readiness Checklist -This checklist records the work that made `SwiftASB` ready for the `v1.1.3` +This checklist records the work that made `SwiftASB` ready for the `v1.1.4` tag. The goal was not to make every possible app-server feature public before v1. The goal was to make the supported lifecycle honest, durable, well documented, and intentionally shaped. @@ -343,8 +343,8 @@ workflow earns them in a later feature release. ### Documentation And Examples -- [x] Update stale release references after the `v1.1.3` release. - Decision: README now names `v1.1.3` as the current released baseline and no +- [x] Update stale release references after the `v1.1.4` release. + Decision: README now names `v1.1.4` as the current released baseline and no longer describes the package as early development. - [x] Finish DocC symbol comments for the supported lifecycle, not just the conceptual articles. @@ -432,6 +432,15 @@ workflow earns them in a later feature release. are a clean public candidate, and thread goals, realtime, fuzzy file search, remote-control management, marketplace/account-management families, and guardian denied-action approval stay post-v1. +- [x] Classify the Codex CLI `v0.129.0` schema diff before promotion. + Decision: generated plugin sharing and plugin skill-read families, + standalone `process/*` control, Windows sandbox readiness, `threadSource`, + `itemsView`, model service-tier metadata, and remote plugin availability + fields remain internal scaffolding for now. Hook compact event names are + observable through the existing hook metadata and dashboard event enums. + Request-side `serviceTier` stays public as the existing hand-owned + `CodexAppServer.ServiceTier` while the internal wire now carries open string + values. - [x] Confirm generated wire stays internal in docs, source organization, and public examples. Decision: generated wire remains internal scaffolding. Public docs and README @@ -441,13 +450,15 @@ workflow earns them in a later feature release. declarations expose `CodexWire...` names. - [x] Re-run schema drift fixture coverage after any promoted generated-wire refresh. - Progress: `swift test` has been rerun after the v0.128 promoted-wire refresh + Progress: `swift test` has been rerun after the v0.129 promoted-wire refresh and exercises the v0.128 permission-profile fixtures, request/response - envelopes, notification fixtures, and public conversion paths. + envelopes, notification fixtures, public conversion paths, and v0.129 + generated-wire compatibility for new thread and item lifecycle fields. - [x] Decide whether v1 should support only the latest documented rolling window or whether a shorter first-v1 compatibility promise is more honest. - Decision: use a narrow `0.128.x` support window for the first v1 boundary, - then widen deliberately after generated-wire and public API review catches up + Decision: use a narrow latest-reviewed-minor support window, currently + `0.129.x`, and widen deliberately after generated-wire and public API review + catches up with later Codex CLI releases. ### History And Observable Companions @@ -509,10 +520,10 @@ workflow earns them in a later feature release. the `release/v1.0.0` branch on 2026-05-02 and on the `release/v1.0.1-prep` branch on 2026-05-02. - [x] Decide whether another targeted `v0.9.x` patch release is needed before - `v1.1.3`, or whether the remaining work should go straight into the v1 + `v1.1.4`, or whether the remaining work should go straight into the v1 release branch. Decision: no additional `v0.9.x` patch is needed. The remaining work should go - straight into the `v1.1.3` release branch. + straight into the `v1.1.4` release branch. - [x] Prepare v1 release notes with explicit sections for public surface, intentionally internal surfaces, compatibility window, migration notes, validation performed, and known post-v1 work. @@ -545,17 +556,18 @@ workflow earns them in a later feature release. - Generated `CodexWire...` models remain internal scaffolding and are not part of the public Swift API. - Broader app-server families remain post-v1 until their consumer workflows are - clearer, including guardian denied-action approval, marketplace/account - management, remote-control management, thread goals, realtime, fuzzy file search, - hook mutation, external-agent config import, richer MCP progress, and - structured patch previews. + clearer, including guardian denied-action approval, plugin sharing and remote + marketplace management, standalone process control, Windows sandbox readiness, + remote-control management, thread goals, realtime, fuzzy file search, hook + mutation, external-agent config import, richer MCP progress, and structured + patch previews. - A one-shot `run(...)` convenience API is intentionally deferred until the lower-level lifecycle has more production mileage. #### Compatibility Window -- The first v1 compatibility promise is intentionally narrow: reviewed support - for Codex CLI `0.128.x`. +- The compatibility promise is intentionally narrow while app-server schema is + moving quickly: reviewed support for Codex CLI `0.129.x`. - SwiftASB discovers `codex` from an explicit executable URL, `PATH`, common Homebrew locations, or the npm global prefix, and exposes startup diagnostics through `cliExecutableDiagnostics()`. @@ -565,7 +577,7 @@ workflow earns them in a later feature release. #### Migration Notes - Existing `v0.9.x` consumers should update the SwiftPM dependency to - `from: "1.1.3"` once the tag is published. + `from: "1.1.4"` once the tag is published. - The v1 API surface has removed stale pre-v1 compatibility shims and phantom fields that no longer exist in the reviewed `v0.128.0` schema. - Same-thread overlapping turns are rejected client-side with @@ -590,7 +602,7 @@ workflow earns them in a later feature release. - Keep an eye on future Swift Package Index builds after compatibility-window or DocC changes; the `v1.1.1` listing and documentation link are live, and - `v1.1.3` should be rechecked after the patch tag is indexed. + `v1.1.4` should be rechecked after the patch tag is indexed. - Add broader live server-request coverage for permissions and MCP elicitation if those become stronger public runtime guarantees. - Continue tuning recent companion cache calibration, richer file previews, @@ -874,11 +886,12 @@ not as the current maintainer priority. - Centered local history reads through `windowAroundTurn(...)` and `windowAroundItem(...)` before any broader cursor or transcript-search contract. -- A `v0.128.0` experimental schema compatibility pass has refreshed the staging - generator, updated the Codex CLI compatibility window, kept generated - permission-profile shapes internal, removed the older permission-profile - compatibility shim, and promoted `hooks/list` as a post-v1 public - diagnostics/capability surface. +- A `v0.129.0` experimental schema compatibility pass has refreshed the staging + generator, updated the Codex CLI compatibility window, kept plugin-sharing, + process-control, Windows-sandbox-readiness, thread-source, and turn-items-view + schema families internal, made new thread/item required fields tolerant of + v0.128 payloads, and promoted compact hook event names through the existing + hook metadata and dashboard surfaces. - API curation and DocC docs good enough that a Swift consumer can understand the supported package surface without reading maintainer notes, including walkthroughs for the primary v1 lifecycle jobs. @@ -1164,7 +1177,7 @@ Completed - [x] Add version-compatibility policy notes for the local Codex binary. - [x] Refresh the compatibility window and promoted generated snapshot against the current `v0.124.0` schema dump once the added endpoint, notification, and field families have been classified. - [x] Curate the public API before v1 by splitting large source files along existing responsibility boundaries where still helpful, tightening public names/defaults, and finishing targeted source-level symbol documentation for the supported lifecycle. - Decision: completed for the `v1.1.3` boundary through the public API audit, + Decision: completed for the `v1.1.4` boundary through the public API audit, symbol inventory, source-comment pass, and focused public file organization. - [x] Add the first DocC documentation catalog before v1, including a package landing page, public-handle topic groups, and conceptual articles for the interactive lifecycle, history companions, and generated-wire boundary. - [x] Validate the DocC catalog through Xcode `docbuild` and document the maintainer command. diff --git a/Sources/SwiftASB/Generated/CodexWire/Latest/CodexLifecycleV2Batch+JSONValue.swift b/Sources/SwiftASB/Generated/CodexWire/Latest/CodexLifecycleV2Batch+JSONValue.swift index 6365185..ab89396 100644 --- a/Sources/SwiftASB/Generated/CodexWire/Latest/CodexLifecycleV2Batch+JSONValue.swift +++ b/Sources/SwiftASB/Generated/CodexWire/Latest/CodexLifecycleV2Batch+JSONValue.swift @@ -67,6 +67,25 @@ struct CodexWireCodexLifecycleV2Batch: Codable, Equatable, Sendable { let pluginListResponse: CodexWirePluginListResponse? let pluginReadParams: CodexWirePluginReadParams? let pluginReadResponse: CodexWirePluginReadResponse? + let pluginShareDeleteParams: CodexWirePluginShareDeleteParams? + let pluginShareDeleteResponse, pluginShareListParams: [String: CodexWireJSONValue]? + let pluginShareListResponse: CodexWirePluginShareListResponse? + let pluginShareSaveParams: CodexWirePluginShareSaveParams? + let pluginShareSaveResponse: CodexWirePluginShareSaveResponse? + let pluginShareUpdateTargetsParams: CodexWirePluginShareUpdateTargetsParams? + let pluginShareUpdateTargetsResponse: CodexWirePluginShareUpdateTargetsResponse? + let pluginSkillReadParams: CodexWirePluginSkillReadParams? + let pluginSkillReadResponse: CodexWirePluginSkillReadResponse? + let processExitedNotification: CodexWireProcessExitedNotification? + let processKillParams: CodexWireProcessKillParams? + let processKillResponse: [String: CodexWireJSONValue]? + let processOutputDeltaNotification: CodexWireProcessOutputDeltaNotification? + let processResizePtyParams: CodexWireProcessResizePtyParams? + let processResizePtyResponse: [String: CodexWireJSONValue]? + let processSpawnParams: CodexWireProcessSpawnParams? + let processSpawnResponse: [String: CodexWireJSONValue]? + let processWriteStdinParams: CodexWireProcessWriteStdinParams? + let processWriteStdinResponse: [String: CodexWireJSONValue]? let rawResponseItemCompletedNotification: CodexWireRawResponseItemCompletedNotification? let reasoningSummaryPartAddedNotification: CodexWireReasoningSummaryPartAddedNotification? let reasoningSummaryTextDeltaNotification: CodexWireReasoningSummaryTextDeltaNotification? @@ -118,12 +137,13 @@ struct CodexWireCodexLifecycleV2Batch: Codable, Equatable, Sendable { let turnStartParams: CodexWireTurnStartParams? let turnStartResponse: CodexWireTurnStartResponse? let warningNotification: CodexWireWarningNotification? + let windowsSandboxReadinessResponse: CodexWireWindowsSandboxReadinessResponse? enum CodingKeys: String, CodingKey { case agentMessageDeltaNotification, appListUpdatedNotification, appsListParams, appsListResponse, collaborationModeListParams, collaborationModeListResponse, commandExecOutputDeltaNotification, commandExecutionOutputDeltaNotification, configReadParams, configReadResponse, configRequirementsReadResponse, configWarningNotification, contextCompactedNotification, deprecationNoticeNotification, errorNotification, externalAgentConfigImportCompletedNotification, fileChangeOutputDeltaNotification, fileChangePatchUpdatedNotification, fsChangedNotification, fsGetMetadataParams, fsGetMetadataResponse, fsReadDirectoryParams, fsReadDirectoryResponse, fsReadFileParams, fsReadFileResponse, fsUnwatchParams, fsUnwatchResponse, fsWatchParams, fsWatchResponse, guardianWarningNotification, hookCompletedNotification, hookStartedNotification, initializeParams, itemCompletedNotification, itemGuardianApprovalReviewCompletedNotification, itemGuardianApprovalReviewStartedNotification, itemStartedNotification case listMCPServerStatusParams = "listMcpServerStatusParams" case listMCPServerStatusResponse = "listMcpServerStatusResponse" - case mcpResourceReadParams, mcpResourceReadResponse, mcpServerStatusUpdatedNotification, mcpToolCallProgressNotification, modelListParams, modelListResponse, modelReroutedNotification, modelVerificationNotification, planDeltaNotification, pluginListParams, pluginListResponse, pluginReadParams, pluginReadResponse, rawResponseItemCompletedNotification, reasoningSummaryPartAddedNotification, reasoningSummaryTextDeltaNotification, reasoningTextDeltaNotification, remoteControlStatusChangedNotification, serverRequestResolvedNotification, skillsChangedNotification, skillsListParams, skillsListResponse, threadApproveGuardianDeniedActionParams, threadApproveGuardianDeniedActionResponse, threadArchivedNotification, threadArchiveParams, threadArchiveResponse, threadClosedNotification, threadCompactStartParams, threadCompactStartResponse, threadGoalClearedNotification, threadGoalClearParams, threadGoalClearResponse, threadGoalGetParams, threadGoalGetResponse, threadGoalSetParams, threadGoalSetResponse, threadGoalUpdatedNotification, threadLoadedListParams, threadLoadedListResponse, threadMetadataUpdateParams, threadMetadataUpdateResponse, threadNameUpdatedNotification, threadRollbackParams, threadRollbackResponse, threadSetNameParams, threadSetNameResponse, threadStartedNotification, threadStartParams, threadStartResponse, threadStatusChangedNotification, threadTokenUsageUpdatedNotification, threadTurnsListParams, threadTurnsListResponse, threadUnarchivedNotification, threadUnarchiveParams, threadUnarchiveResponse, turnCompletedNotification, turnDiffUpdatedNotification, turnPlanUpdatedNotification, turnStartedNotification, turnStartParams, turnStartResponse, warningNotification + case mcpResourceReadParams, mcpResourceReadResponse, mcpServerStatusUpdatedNotification, mcpToolCallProgressNotification, modelListParams, modelListResponse, modelReroutedNotification, modelVerificationNotification, planDeltaNotification, pluginListParams, pluginListResponse, pluginReadParams, pluginReadResponse, pluginShareDeleteParams, pluginShareDeleteResponse, pluginShareListParams, pluginShareListResponse, pluginShareSaveParams, pluginShareSaveResponse, pluginShareUpdateTargetsParams, pluginShareUpdateTargetsResponse, pluginSkillReadParams, pluginSkillReadResponse, processExitedNotification, processKillParams, processKillResponse, processOutputDeltaNotification, processResizePtyParams, processResizePtyResponse, processSpawnParams, processSpawnResponse, processWriteStdinParams, processWriteStdinResponse, rawResponseItemCompletedNotification, reasoningSummaryPartAddedNotification, reasoningSummaryTextDeltaNotification, reasoningTextDeltaNotification, remoteControlStatusChangedNotification, serverRequestResolvedNotification, skillsChangedNotification, skillsListParams, skillsListResponse, threadApproveGuardianDeniedActionParams, threadApproveGuardianDeniedActionResponse, threadArchivedNotification, threadArchiveParams, threadArchiveResponse, threadClosedNotification, threadCompactStartParams, threadCompactStartResponse, threadGoalClearedNotification, threadGoalClearParams, threadGoalClearResponse, threadGoalGetParams, threadGoalGetResponse, threadGoalSetParams, threadGoalSetResponse, threadGoalUpdatedNotification, threadLoadedListParams, threadLoadedListResponse, threadMetadataUpdateParams, threadMetadataUpdateResponse, threadNameUpdatedNotification, threadRollbackParams, threadRollbackResponse, threadSetNameParams, threadSetNameResponse, threadStartedNotification, threadStartParams, threadStartResponse, threadStatusChangedNotification, threadTokenUsageUpdatedNotification, threadTurnsListParams, threadTurnsListResponse, threadUnarchivedNotification, threadUnarchiveParams, threadUnarchiveResponse, turnCompletedNotification, turnDiffUpdatedNotification, turnPlanUpdatedNotification, turnStartedNotification, turnStartParams, turnStartResponse, warningNotification, windowsSandboxReadinessResponse } } @@ -366,7 +386,7 @@ struct CodexWireCommandExecOutputDeltaNotification: Codable, Equatable, Sendable /// Client-supplied, connection-scoped `processId` from the original `command/exec` request. let processID: String /// Output stream for this chunk. - let stream: CodexWireCommandExecOutputStream + let stream: CodexWireOutputStream enum CodingKeys: String, CodingKey { case capReached, deltaBase64 @@ -382,7 +402,11 @@ struct CodexWireCommandExecOutputDeltaNotification: Codable, Equatable, Sendable /// stdout stream. PTY mode multiplexes terminal output here. /// /// stderr stream. -enum CodexWireCommandExecOutputStream: String, Codable, Equatable, Sendable { +/// +/// Output stream this chunk belongs to. +/// +/// Stream label for `process/outputDelta` notifications. +enum CodexWireOutputStream: String, Codable, Equatable, Sendable { case stderr = "stderr" case stdout = "stdout" } @@ -459,7 +483,7 @@ struct CodexWireConfig: Codable, Equatable, Sendable { let reviewModel: String? let sandboxMode: CodexWireSandboxMode? let sandboxWorkspaceWrite: CodexWireSandboxWorkspaceWrite? - let serviceTier: CodexWireServiceTier? + let serviceTier: String? let tools: CodexWireToolsV2? let webSearch: CodexWireWebSearchMode? @@ -657,7 +681,7 @@ struct CodexWireProfileV2: Codable, Equatable, Sendable { let modelReasoningEffort: CodexWireReasoningEffort? let modelReasoningSummary: CodexWireReasoningSummary? let modelVerbosity: CodexWireVerbosity? - let serviceTier: CodexWireServiceTier? + let serviceTier: String? let tools: CodexWireToolsV2? let webSearch: CodexWireWebSearchMode? @@ -676,11 +700,6 @@ struct CodexWireProfileV2: Codable, Equatable, Sendable { } } -enum CodexWireServiceTier: String, Codable, Equatable, Sendable { - case fast = "fast" - case flex = "flex" -} - // // Hashable or Equatable: // The compiler will not be able to synthesize the implementation of Hashable or Equatable @@ -899,14 +918,16 @@ enum CodexWireResidencyRequirement: String, Codable, Equatable, Sendable { // MARK: - CodexWireManagedHooksRequirements struct CodexWireManagedHooksRequirements: Codable, Equatable, Sendable { let managedDir: String? - let permissionRequest, postToolUse, preToolUse, sessionStart: [CodexWireConfiguredHookMatcherGroup] - let stop, userPromptSubmit: [CodexWireConfiguredHookMatcherGroup] + let permissionRequest, postCompact, postToolUse, preCompact: [CodexWireConfiguredHookMatcherGroup] + let preToolUse, sessionStart, stop, userPromptSubmit: [CodexWireConfiguredHookMatcherGroup] let windowsManagedDir: String? enum CodingKeys: String, CodingKey { case managedDir case permissionRequest = "PermissionRequest" + case postCompact = "PostCompact" case postToolUse = "PostToolUse" + case preCompact = "PreCompact" case preToolUse = "PreToolUse" case sessionStart = "SessionStart" case stop = "Stop" @@ -1236,6 +1257,9 @@ enum CodexWireCodexErrorInfoEnum: String, Codable, Equatable, Sendable { // for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be // synthesized for types that have collections (such as arrays or dictionaries). +/// Deprecated legacy notification for `apply_patch` textual output. +/// +/// The server no longer emits this notification. // MARK: - CodexWireFileChangeOutputDeltaNotification struct CodexWireFileChangeOutputDeltaNotification: Codable, Equatable, Sendable { let delta, itemID, threadID, turnID: String @@ -1572,7 +1596,9 @@ enum CodexWireHookOutputEntryKind: String, Codable, Equatable, Sendable { enum CodexWireHookEventName: String, Codable, Equatable, Sendable { case permissionRequest = "permissionRequest" + case postCompact = "postCompact" case postToolUse = "postToolUse" + case preCompact = "preCompact" case preToolUse = "preToolUse" case sessionStart = "sessionStart" case stop = "stop" @@ -1683,10 +1709,13 @@ struct CodexWireClientInfo: Codable, Equatable, Sendable { // MARK: - CodexWireItemCompletedNotification struct CodexWireItemCompletedNotification: Codable, Equatable, Sendable { + /// Unix timestamp (in milliseconds) when this item lifecycle completed. + let completedAtMS: Int? let item: CodexWireThreadItem let threadID, turnID: String enum CodingKeys: String, CodingKey { + case completedAtMS = "completedAtMs" case item case threadID = "threadId" case turnID = "turnId" @@ -2377,10 +2406,13 @@ struct CodexWireItemGuardianApprovalReviewStartedNotification: Codable, Equatabl // MARK: - CodexWireItemStartedNotification struct CodexWireItemStartedNotification: Codable, Equatable, Sendable { let item: CodexWireThreadItem + /// Unix timestamp (in milliseconds) when this item lifecycle started. + let startedAtMS: Int? let threadID, turnID: String enum CodingKeys: String, CodingKey { case item + case startedAtMS = "startedAtMs" case threadID = "threadId" case turnID = "turnId" } @@ -2635,6 +2667,7 @@ struct CodexWireModelListResponse: Codable, Equatable, Sendable { // MARK: - CodexWireModel struct CodexWireModel: Codable, Equatable, Sendable { + /// Deprecated: use `serviceTiers` instead. let additionalSpeedTiers: [String]? let availabilityNux: CodexWireModelAvailabilityNux? let defaultReasoningEffort: CodexWireReasoningEffort @@ -2644,6 +2677,7 @@ struct CodexWireModel: Codable, Equatable, Sendable { let inputModalities: [CodexWireInputModality]? let isDefault: Bool let model: String + let serviceTiers: [CodexWireModelServiceTier]? let supportedReasoningEfforts: [CodexWireReasoningEffortOption] let supportsPersonality: Bool? let upgrade: String? @@ -2677,6 +2711,17 @@ enum CodexWireInputModality: String, Codable, Equatable, Sendable { // for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be // synthesized for types that have collections (such as arrays or dictionaries). +// MARK: - CodexWireModelServiceTier +struct CodexWireModelServiceTier: Codable, Equatable, Sendable { + let description, id, name: String +} + +// +// Hashable or Equatable: +// The compiler will not be able to synthesize the implementation of Hashable or Equatable +// for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be +// synthesized for types that have collections (such as arrays or dictionaries). + // MARK: - CodexWireReasoningEffortOption struct CodexWireReasoningEffortOption: Codable, Equatable, Sendable { let description: String @@ -2773,6 +2818,15 @@ struct CodexWirePluginListParams: Codable, Equatable, Sendable { /// Optional working directories used to discover repo marketplaces. When omitted, only /// home-scoped marketplaces and the official curated marketplace are considered. let cwds: [String]? + /// Optional marketplace kind filter. When omitted, only local marketplaces are queried, plus + /// the default remote catalog when enabled by feature flag. + let marketplaceKinds: [CodexWirePluginListMarketplaceKind]? +} + +enum CodexWirePluginListMarketplaceKind: String, Codable, Equatable, Sendable { + case local = "local" + case sharedWithMe = "shared-with-me" + case workspaceDirectory = "workspace-directory" } // @@ -2840,12 +2894,17 @@ struct CodexWireMarketplaceInterface: Codable, Equatable, Sendable { // MARK: - CodexWirePluginSummary struct CodexWirePluginSummary: Codable, Equatable, Sendable { let authPolicy: CodexWirePluginAuthPolicy + /// Availability state for installing and using the plugin. + let availability: CodexWirePluginAvailability? let enabled: Bool let id: String let installed: Bool let installPolicy: CodexWirePluginInstallPolicy let interface: CodexWirePluginInterface? + let keywords: [String]? let name: String + /// Remote sharing context associated with this plugin when available. + let shareContext: CodexWirePluginShareContext? let source: CodexWirePluginSource } @@ -2854,6 +2913,16 @@ enum CodexWirePluginAuthPolicy: String, Codable, Equatable, Sendable { case onUse = "ON_USE" } +/// Availability state for installing and using the plugin. +/// +/// Plugin-service currently sends `"ENABLED"` for available remote plugins. Codex app-server +/// exposes `"AVAILABLE"` in its API; the alias keeps decoding compatible with that upstream +/// response. +enum CodexWirePluginAvailability: String, Codable, Equatable, Sendable { + case available = "AVAILABLE" + case disabledByAdmin = "DISABLED_BY_ADMIN" +} + enum CodexWirePluginInstallPolicy: String, Codable, Equatable, Sendable { case available = "AVAILABLE" case installedByDefault = "INSTALLED_BY_DEFAULT" @@ -2909,6 +2978,24 @@ struct CodexWirePluginInterface: Codable, Equatable, Sendable { // for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be // synthesized for types that have collections (such as arrays or dictionaries). +// MARK: - CodexWirePluginShareContext +struct CodexWirePluginShareContext: Codable, Equatable, Sendable { + let creatorAccountUserID, creatorName: String? + let remotePluginID: String + + enum CodingKeys: String, CodingKey { + case creatorAccountUserID = "creatorAccountUserId" + case creatorName + case remotePluginID = "remotePluginId" + } +} + +// +// Hashable or Equatable: +// The compiler will not be able to synthesize the implementation of Hashable or Equatable +// for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be +// synthesized for types that have collections (such as arrays or dictionaries). + /// The plugin is available in the remote catalog. Download metadata is kept server-side and /// is not exposed through the app-server API. // MARK: - CodexWirePluginSource @@ -3021,6 +3108,360 @@ struct CodexWireSkillInterface: Codable, Equatable, Sendable { // for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be // synthesized for types that have collections (such as arrays or dictionaries). +// MARK: - CodexWirePluginShareDeleteParams +struct CodexWirePluginShareDeleteParams: Codable, Equatable, Sendable { + let remotePluginID: String + + enum CodingKeys: String, CodingKey { + case remotePluginID = "remotePluginId" + } +} + +// +// Hashable or Equatable: +// The compiler will not be able to synthesize the implementation of Hashable or Equatable +// for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be +// synthesized for types that have collections (such as arrays or dictionaries). + +// MARK: - CodexWirePluginShareListResponse +struct CodexWirePluginShareListResponse: Codable, Equatable, Sendable { + let data: [CodexWirePluginShareListItem] +} + +// +// Hashable or Equatable: +// The compiler will not be able to synthesize the implementation of Hashable or Equatable +// for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be +// synthesized for types that have collections (such as arrays or dictionaries). + +// MARK: - CodexWirePluginShareListItem +struct CodexWirePluginShareListItem: Codable, Equatable, Sendable { + let localPluginPath: String? + let plugin: CodexWirePluginSummary + let shareURL: String + + enum CodingKeys: String, CodingKey { + case localPluginPath, plugin + case shareURL = "shareUrl" + } +} + +// +// Hashable or Equatable: +// The compiler will not be able to synthesize the implementation of Hashable or Equatable +// for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be +// synthesized for types that have collections (such as arrays or dictionaries). + +// MARK: - CodexWirePluginShareSaveParams +struct CodexWirePluginShareSaveParams: Codable, Equatable, Sendable { + let discoverability: CodexWirePluginShareDiscoverability? + let pluginPath: String + let remotePluginID: String? + let shareTargets: [CodexWirePluginShareTarget]? + + enum CodingKeys: String, CodingKey { + case discoverability, pluginPath + case remotePluginID = "remotePluginId" + case shareTargets + } +} + +enum CodexWirePluginShareDiscoverability: String, Codable, Equatable, Sendable { + case listed = "LISTED" + case pluginShareDiscoverabilityPRIVATE = "PRIVATE" + case unlisted = "UNLISTED" +} + +// +// Hashable or Equatable: +// The compiler will not be able to synthesize the implementation of Hashable or Equatable +// for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be +// synthesized for types that have collections (such as arrays or dictionaries). + +// MARK: - CodexWirePluginShareTarget +struct CodexWirePluginShareTarget: Codable, Equatable, Sendable { + let principalID: String + let principalType: CodexWirePluginSharePrincipalType + + enum CodingKeys: String, CodingKey { + case principalID = "principalId" + case principalType + } +} + +enum CodexWirePluginSharePrincipalType: String, Codable, Equatable, Sendable { + case group = "group" + case user = "user" + case workspace = "workspace" +} + +// +// Hashable or Equatable: +// The compiler will not be able to synthesize the implementation of Hashable or Equatable +// for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be +// synthesized for types that have collections (such as arrays or dictionaries). + +// MARK: - CodexWirePluginShareSaveResponse +struct CodexWirePluginShareSaveResponse: Codable, Equatable, Sendable { + let remotePluginID, shareURL: String + + enum CodingKeys: String, CodingKey { + case remotePluginID = "remotePluginId" + case shareURL = "shareUrl" + } +} + +// +// Hashable or Equatable: +// The compiler will not be able to synthesize the implementation of Hashable or Equatable +// for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be +// synthesized for types that have collections (such as arrays or dictionaries). + +// MARK: - CodexWirePluginShareUpdateTargetsParams +struct CodexWirePluginShareUpdateTargetsParams: Codable, Equatable, Sendable { + let remotePluginID: String + let shareTargets: [CodexWirePluginShareTarget] + + enum CodingKeys: String, CodingKey { + case remotePluginID = "remotePluginId" + case shareTargets + } +} + +// +// Hashable or Equatable: +// The compiler will not be able to synthesize the implementation of Hashable or Equatable +// for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be +// synthesized for types that have collections (such as arrays or dictionaries). + +// MARK: - CodexWirePluginShareUpdateTargetsResponse +struct CodexWirePluginShareUpdateTargetsResponse: Codable, Equatable, Sendable { + let principals: [CodexWirePluginSharePrincipal] +} + +// +// Hashable or Equatable: +// The compiler will not be able to synthesize the implementation of Hashable or Equatable +// for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be +// synthesized for types that have collections (such as arrays or dictionaries). + +// MARK: - CodexWirePluginSharePrincipal +struct CodexWirePluginSharePrincipal: Codable, Equatable, Sendable { + let name, principalID: String + let principalType: CodexWirePluginSharePrincipalType + + enum CodingKeys: String, CodingKey { + case name + case principalID = "principalId" + case principalType + } +} + +// +// Hashable or Equatable: +// The compiler will not be able to synthesize the implementation of Hashable or Equatable +// for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be +// synthesized for types that have collections (such as arrays or dictionaries). + +// MARK: - CodexWirePluginSkillReadParams +struct CodexWirePluginSkillReadParams: Codable, Equatable, Sendable { + let remoteMarketplaceName, remotePluginID, skillName: String + + enum CodingKeys: String, CodingKey { + case remoteMarketplaceName + case remotePluginID = "remotePluginId" + case skillName + } +} + +// +// Hashable or Equatable: +// The compiler will not be able to synthesize the implementation of Hashable or Equatable +// for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be +// synthesized for types that have collections (such as arrays or dictionaries). + +// MARK: - CodexWirePluginSkillReadResponse +struct CodexWirePluginSkillReadResponse: Codable, Equatable, Sendable { + let contents: String? +} + +// +// Hashable or Equatable: +// The compiler will not be able to synthesize the implementation of Hashable or Equatable +// for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be +// synthesized for types that have collections (such as arrays or dictionaries). + +/// Final process exit notification for `process/spawn`. +// MARK: - CodexWireProcessExitedNotification +struct CodexWireProcessExitedNotification: Codable, Equatable, Sendable { + /// Process exit code. + let exitCode: Int + /// Client-supplied, connection-scoped `processHandle` from `process/spawn`. + let processHandle: String + /// Buffered stderr capture. + /// + /// Empty when stderr was streamed via `process/outputDelta`. + let stderr: String + /// Whether stderr reached `outputBytesCap`. + /// + /// In streaming mode, stderr is empty and cap state is also reported on the final stderr + /// `process/outputDelta` notification. + let stderrCapReached: Bool + /// Buffered stdout capture. + /// + /// Empty when stdout was streamed via `process/outputDelta`. + let stdout: String + /// Whether stdout reached `outputBytesCap`. + /// + /// In streaming mode, stdout is empty and cap state is also reported on the final stdout + /// `process/outputDelta` notification. + let stdoutCapReached: Bool +} + +// +// Hashable or Equatable: +// The compiler will not be able to synthesize the implementation of Hashable or Equatable +// for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be +// synthesized for types that have collections (such as arrays or dictionaries). + +/// Terminate a running `process/spawn` session. +// MARK: - CodexWireProcessKillParams +struct CodexWireProcessKillParams: Codable, Equatable, Sendable { + /// Client-supplied, connection-scoped `processHandle` from `process/spawn`. + let processHandle: String +} + +// +// Hashable or Equatable: +// The compiler will not be able to synthesize the implementation of Hashable or Equatable +// for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be +// synthesized for types that have collections (such as arrays or dictionaries). + +/// Base64-encoded output chunk emitted for a streaming `process/spawn` request. +// MARK: - CodexWireProcessOutputDeltaNotification +struct CodexWireProcessOutputDeltaNotification: Codable, Equatable, Sendable { + /// True on the final streamed chunk for this stream when output was truncated by + /// `outputBytesCap`. + let capReached: Bool + /// Base64-encoded output bytes. + let deltaBase64: String + /// Client-supplied, connection-scoped `processHandle` from `process/spawn`. + let processHandle: String + /// Output stream this chunk belongs to. + let stream: CodexWireOutputStream +} + +// +// Hashable or Equatable: +// The compiler will not be able to synthesize the implementation of Hashable or Equatable +// for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be +// synthesized for types that have collections (such as arrays or dictionaries). + +/// Resize a running PTY-backed `process/spawn` session. +// MARK: - CodexWireProcessResizePtyParams +struct CodexWireProcessResizePtyParams: Codable, Equatable, Sendable { + /// Client-supplied, connection-scoped `processHandle` from `process/spawn`. + let processHandle: String + /// New PTY size in character cells. + let size: CodexWireProcessTerminalSize +} + +// +// Hashable or Equatable: +// The compiler will not be able to synthesize the implementation of Hashable or Equatable +// for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be +// synthesized for types that have collections (such as arrays or dictionaries). + +/// New PTY size in character cells. +/// +/// PTY size in character cells for `process/spawn` PTY sessions. +// MARK: - CodexWireProcessTerminalSize +struct CodexWireProcessTerminalSize: Codable, Equatable, Sendable { + /// Terminal width in character cells. + let cols: Int + /// Terminal height in character cells. + let rows: Int +} + +// +// Hashable or Equatable: +// The compiler will not be able to synthesize the implementation of Hashable or Equatable +// for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be +// synthesized for types that have collections (such as arrays or dictionaries). + +/// Spawn a standalone process (argv vector) without a Codex sandbox on the host where the +/// app server is running. +/// +/// `process/spawn` returns after the process has started and the connection-scoped +/// `processHandle` has been registered. Process output and exit are reported via +/// `process/outputDelta` and `process/exited` notifications. +// MARK: - CodexWireProcessSpawnParams +struct CodexWireProcessSpawnParams: Codable, Equatable, Sendable { + /// Command argv vector. Empty arrays are rejected. + let command: [String] + /// Absolute working directory for the process. + let cwd: String + /// Optional environment overrides merged into the app-server process environment. + /// + /// Matching names override inherited values. Set a key to `null` to unset an inherited + /// variable. + let env: [String: String?]? + /// Optional per-stream stdout/stderr capture cap in bytes. + /// + /// When omitted, the server default applies. Set to `null` to disable the cap. + let outputBytesCap: Int? + /// Client-supplied, connection-scoped process handle. + /// + /// Duplicate active handles are rejected on the same connection. The same handle can be + /// reused after the prior process exits. + let processHandle: String + /// Optional initial PTY size in character cells. Only valid when `tty` is true. + let size: CodexWireProcessTerminalSize? + /// Allow follow-up `process/writeStdin` requests to write stdin bytes. + let streamStdin: Bool? + /// Stream stdout/stderr via `process/outputDelta` notifications. + /// + /// Streamed bytes are not duplicated into the `process/exited` notification. + let streamStdoutStderr: Bool? + /// Optional timeout in milliseconds. + /// + /// When omitted, the server default applies. Set to `null` to disable the timeout. + let timeoutMS: Int? + /// Enable PTY mode. + /// + /// This implies `streamStdin` and `streamStdoutStderr`. + let tty: Bool? + + enum CodingKeys: String, CodingKey { + case command, cwd, env, outputBytesCap, processHandle, size, streamStdin, streamStdoutStderr + case timeoutMS = "timeoutMs" + case tty + } +} + +// +// Hashable or Equatable: +// The compiler will not be able to synthesize the implementation of Hashable or Equatable +// for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be +// synthesized for types that have collections (such as arrays or dictionaries). + +/// Write stdin bytes to a running `process/spawn` session, close stdin, or both. +// MARK: - CodexWireProcessWriteStdinParams +struct CodexWireProcessWriteStdinParams: Codable, Equatable, Sendable { + /// Close stdin after writing `deltaBase64`, if present. + let closeStdin: Bool? + /// Optional base64-encoded stdin bytes to write. + let deltaBase64: String? + /// Client-supplied, connection-scoped `processHandle` from `process/spawn`. + let processHandle: String +} + +// +// Hashable or Equatable: +// The compiler will not be able to synthesize the implementation of Hashable or Equatable +// for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be +// synthesized for types that have collections (such as arrays or dictionaries). + // MARK: - CodexWireRawResponseItemCompletedNotification struct CodexWireRawResponseItemCompletedNotification: Codable, Equatable, Sendable { let item: CodexWireResponseItem @@ -3211,6 +3652,7 @@ enum CodexWireSummaryTextReasoningItemReasoningSummaryType: String, Codable, Equ enum CodexWireResponseItemType: String, Codable, Equatable, Sendable { case compaction = "compaction" + case contextCompaction = "context_compaction" case customToolCall = "custom_tool_call" case customToolCallOutput = "custom_tool_call_output" case functionCall = "function_call" @@ -3815,10 +4257,14 @@ struct CodexWireThread: Codable, Equatable, Sendable { let path: String? /// Usually the first user message in the thread, if available. let preview: String + /// Session id shared by threads that belong to the same session tree. + let sessionID: String? /// Origin of the thread (CLI, VSCode, codex exec, codex app-server, etc.). let source: CodexWireSessionSourceUnion /// Current runtime status for the thread. let status: CodexWireThreadStatus + /// Optional analytics source classification for this thread. + let threadSource: CodexWireThreadSource? /// Only populated on `thread/resume`, `thread/rollback`, `thread/fork`, and `thread/read` /// (when `includeTurns` is true) responses. For all other responses and notifications /// returning a Thread, the turns field will be an empty list. @@ -3829,7 +4275,9 @@ struct CodexWireThread: Codable, Equatable, Sendable { enum CodingKeys: String, CodingKey { case agentNickname, agentRole, cliVersion, createdAt, cwd, ephemeral case forkedFromID = "forkedFromId" - case gitInfo, id, modelProvider, name, path, preview, source, status, turns, updatedAt + case gitInfo, id, modelProvider, name, path, preview + case sessionID = "sessionId" + case source, status, threadSource, turns, updatedAt } } @@ -3996,6 +4444,12 @@ enum CodexWireThreadStatusType: String, Codable, Equatable, Sendable { case systemError = "systemError" } +enum CodexWireThreadSource: String, Codable, Equatable, Sendable { + case memoryConsolidation = "memory_consolidation" + case subagent = "subagent" + case user = "user" +} + // // Hashable or Equatable: // The compiler will not be able to synthesize the implementation of Hashable or Equatable @@ -4011,9 +4465,10 @@ struct CodexWireTurn: Codable, Equatable, Sendable { /// Only populated when the Turn's status is failed. let error: CodexWireTurnError? let id: String - /// Only populated on a `thread/resume` or `thread/fork` response. For all other responses - /// and notifications returning a Turn, the items field will be an empty list. + /// Thread items currently included in this turn payload. let items: [CodexWireThreadItem] + /// Describes how much of `items` has been loaded for this turn. + let itemsView: CodexWireTurnItemsView? /// Unix timestamp (in seconds) when the turn started. let startedAt: Int? let status: CodexWireTurnStatus @@ -4021,10 +4476,24 @@ struct CodexWireTurn: Codable, Equatable, Sendable { enum CodingKeys: String, CodingKey { case completedAt case durationMS = "durationMs" - case error, id, items, startedAt, status + case error, id, items, itemsView, startedAt, status } } +/// Describes how much of `items` has been loaded for this turn. +/// +/// `items` was not loaded for this turn. The field is intentionally empty. +/// +/// `items` contains only a display summary for this turn. +/// +/// `items` contains every ThreadItem available from persisted app-server history for this +/// turn. +enum CodexWireTurnItemsView: String, Codable, Equatable, Sendable { + case full = "full" + case notLoaded = "notLoaded" + case summary = "summary" +} + enum CodexWireTurnStatus: String, Codable, Equatable, Sendable { case completed = "completed" case failed = "failed" @@ -4136,14 +4605,15 @@ struct CodexWireThreadStartParams: Codable, Equatable, Sendable { /// `modifications` for supported turn/thread adjustments instead of replacing the full /// permissions profile. let permissions: CodexWirePermissionProfileSelectionParams? - /// If true, persist additional rollout EventMsg variants required to reconstruct a richer - /// thread history on resume/fork/read. + /// Deprecated and ignored by app-server. Kept only so older clients can continue sending the + /// field while rollout persistence always uses the limited history policy. let persistExtendedHistory: Bool? let personality: CodexWirePersonality? let sandbox: CodexWireSandboxMode? - let serviceName: String? - let serviceTier: CodexWireServiceTier? + let serviceName, serviceTier: String? let sessionStartSource: CodexWireThreadStartSource? + /// Optional client-supplied analytics source classification for this thread. + let threadSource: CodexWireThreadSource? } // @@ -4248,7 +4718,7 @@ struct CodexWireThreadStartResponse: Codable, Equatable, Sendable { /// Legacy sandbox policy retained for compatibility. Experimental clients should prefer /// `permissionProfile` when they need exact runtime permissions. let sandbox: CodexWireSandboxPolicy - let serviceTier: CodexWireServiceTier? + let serviceTier: String? let thread: CodexWireThread } @@ -4667,7 +5137,7 @@ struct CodexWireTurnStartParams: Codable, Equatable, Sendable { /// Override the sandbox policy for this turn and subsequent turns. let sandboxPolicy: CodexWireDangerFullAccessSandboxPolicyClass? /// Override the service tier for this turn and subsequent turns. - let serviceTier: CodexWireServiceTier? + let serviceTier: String? /// Override the reasoning summary for this turn and subsequent turns. let summary: CodexWireReasoningSummary? let threadID: String @@ -4772,6 +5242,23 @@ struct CodexWireWarningNotification: Codable, Equatable, Sendable { } } +// +// Hashable or Equatable: +// The compiler will not be able to synthesize the implementation of Hashable or Equatable +// for types that require the use of CodexWireJSONValue, nor will the implementation of Hashable be +// synthesized for types that have collections (such as arrays or dictionaries). + +// MARK: - CodexWireWindowsSandboxReadinessResponse +struct CodexWireWindowsSandboxReadinessResponse: Codable, Equatable, Sendable { + let status: CodexWireWindowsSandboxReadiness +} + +enum CodexWireWindowsSandboxReadiness: String, Codable, Equatable, Sendable { + case notConfigured = "notConfigured" + case ready = "ready" + case updateRequired = "updateRequired" +} + indirect enum CodexWireJSONValue: Codable, Equatable, Sendable { case null case bool(Bool) diff --git a/Sources/SwiftASB/Protocol/CodexAppServerProtocol+Types.swift b/Sources/SwiftASB/Protocol/CodexAppServerProtocol+Types.swift index 192eaf7..ee0954f 100644 --- a/Sources/SwiftASB/Protocol/CodexAppServerProtocol+Types.swift +++ b/Sources/SwiftASB/Protocol/CodexAppServerProtocol+Types.swift @@ -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 { @@ -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 { @@ -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 diff --git a/Sources/SwiftASB/Public/CodexAppServer+Hooks.swift b/Sources/SwiftASB/Public/CodexAppServer+Hooks.swift index da974a0..93184ff 100644 --- a/Sources/SwiftASB/Public/CodexAppServer+Hooks.swift +++ b/Sources/SwiftASB/Public/CodexAppServer+Hooks.swift @@ -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 @@ -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: diff --git a/Sources/SwiftASB/Public/CodexAppServer+WireMapping.swift b/Sources/SwiftASB/Public/CodexAppServer+WireMapping.swift index c575bad..3343ccf 100644 --- a/Sources/SwiftASB/Public/CodexAppServer+WireMapping.swift +++ b/Sources/SwiftASB/Public/CodexAppServer+WireMapping.swift @@ -117,7 +117,8 @@ extension CodexAppServer.ThreadStartRequest { sandbox: sandboxMode?.wireValue, serviceName: serviceName, serviceTier: serviceTier?.wireValue, - sessionStartSource: sessionStartSource?.wireValue + sessionStartSource: sessionStartSource?.wireValue, + threadSource: nil ) } } @@ -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 } } @@ -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: diff --git a/Sources/SwiftASB/Public/CodexAppServer.swift b/Sources/SwiftASB/Public/CodexAppServer.swift index 57fcfd9..f41c309 100644 --- a/Sources/SwiftASB/Public/CodexAppServer.swift +++ b/Sources/SwiftASB/Public/CodexAppServer.swift @@ -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( diff --git a/Sources/SwiftASB/Public/CodexThread+Dashboard.swift b/Sources/SwiftASB/Public/CodexThread+Dashboard.swift index 3b2049e..eea0798 100644 --- a/Sources/SwiftASB/Public/CodexThread+Dashboard.swift +++ b/Sources/SwiftASB/Public/CodexThread+Dashboard.swift @@ -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 diff --git a/Sources/SwiftASB/Transport/CodexCLIExecutableResolver.swift b/Sources/SwiftASB/Transport/CodexCLIExecutableResolver.swift index c7c1ea8..88e5695 100644 --- a/Sources/SwiftASB/Transport/CodexCLIExecutableResolver.swift +++ b/Sources/SwiftASB/Transport/CodexCLIExecutableResolver.swift @@ -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 diff --git a/Tests/SwiftASBTests/Protocol/CodexAppServerProtocolTests.swift b/Tests/SwiftASBTests/Protocol/CodexAppServerProtocolTests.swift index f812b26..6232461 100644 --- a/Tests/SwiftASBTests/Protocol/CodexAppServerProtocolTests.swift +++ b/Tests/SwiftASBTests/Protocol/CodexAppServerProtocolTests.swift @@ -79,8 +79,9 @@ struct CodexAppServerProtocolTests { personality: .friendly, sandbox: .workspaceWrite, serviceName: "codex", - serviceTier: .fast, - sessionStartSource: .clear + serviceTier: "fast", + sessionStartSource: .clear, + threadSource: nil ) ) @@ -270,7 +271,7 @@ struct CodexAppServerProtocolTests { personality: .friendly, sandbox: .workspaceWrite, serviceName: "codex", - serviceTier: .fast, + serviceTier: "fast", threadID: "thread-123" ) ) @@ -312,7 +313,7 @@ struct CodexAppServerProtocolTests { personality: .pragmatic, sandbox: .workspaceWrite, serviceName: "codex", - serviceTier: .fast, + serviceTier: "fast", threadID: "thread-123" ) ) @@ -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") @@ -640,7 +641,7 @@ struct CodexAppServerProtocolTests { personality: .pragmatic, responsesapiClientMetadata: nil, sandboxPolicy: nil, - serviceTier: .flex, + serviceTier: "flex", summary: .concise, threadID: "thread-123" ) @@ -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) diff --git a/Tests/SwiftASBTests/Public/CodexAppServerLiveApprovalProbeTests.swift b/Tests/SwiftASBTests/Public/CodexAppServerLiveApprovalProbeTests.swift index 717c635..98cdfad 100644 --- a/Tests/SwiftASBTests/Public/CodexAppServerLiveApprovalProbeTests.swift +++ b/Tests/SwiftASBTests/Public/CodexAppServerLiveApprovalProbeTests.swift @@ -329,7 +329,8 @@ extension CodexAppServerLiveIntegrationTests { sandbox: .readOnly, serviceName: nil, serviceTier: nil, - sessionStartSource: nil + sessionStartSource: nil, + threadSource: nil ) ) let threadResponsePayload = try await withTimeout( @@ -512,7 +513,8 @@ extension CodexAppServerLiveIntegrationTests { sandbox: .readOnly, serviceName: nil, serviceTier: nil, - sessionStartSource: nil + sessionStartSource: nil, + threadSource: nil ) ) let threadResponsePayload = try await withTimeout( diff --git a/Tests/SwiftASBTests/Public/CodexAppServerLiveElicitationProbeTests.swift b/Tests/SwiftASBTests/Public/CodexAppServerLiveElicitationProbeTests.swift index aab6378..bdb2b6b 100644 --- a/Tests/SwiftASBTests/Public/CodexAppServerLiveElicitationProbeTests.swift +++ b/Tests/SwiftASBTests/Public/CodexAppServerLiveElicitationProbeTests.swift @@ -100,7 +100,8 @@ extension CodexAppServerLiveIntegrationTests { sandbox: .readOnly, serviceName: nil, serviceTier: nil, - sessionStartSource: nil + sessionStartSource: nil, + threadSource: nil ) ) let threadResponsePayload = try await withTimeout( @@ -282,7 +283,8 @@ extension CodexAppServerLiveIntegrationTests { sandbox: .readOnly, serviceName: nil, serviceTier: nil, - sessionStartSource: nil + sessionStartSource: nil, + threadSource: nil ) ) let threadResponsePayload = try await withTimeout( @@ -463,7 +465,8 @@ extension CodexAppServerLiveIntegrationTests { sandbox: .readOnly, serviceName: nil, serviceTier: nil, - sessionStartSource: nil + sessionStartSource: nil, + threadSource: nil ) ) let threadResponsePayload = try await withTimeout( diff --git a/Tests/SwiftASBTests/Public/CodexAppServerLiveIntegrationTests.swift b/Tests/SwiftASBTests/Public/CodexAppServerLiveIntegrationTests.swift index d06b6cc..e682905 100644 --- a/Tests/SwiftASBTests/Public/CodexAppServerLiveIntegrationTests.swift +++ b/Tests/SwiftASBTests/Public/CodexAppServerLiveIntegrationTests.swift @@ -152,7 +152,8 @@ struct CodexAppServerLiveIntegrationTests { sandbox: .workspaceWrite, serviceName: nil, serviceTier: nil, - sessionStartSource: nil + sessionStartSource: nil, + threadSource: nil ) ) let threadResponsePayload = try await withTimeout( @@ -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 { @@ -295,7 +296,8 @@ struct CodexAppServerLiveIntegrationTests { sandbox: .workspaceWrite, serviceName: nil, serviceTier: nil, - sessionStartSource: nil + sessionStartSource: nil, + threadSource: nil ) ) let threadResponsePayload = try await withTimeout( @@ -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)" diff --git a/Tests/SwiftASBTests/Public/CodexAppServerTests.swift b/Tests/SwiftASBTests/Public/CodexAppServerTests.swift index 94d201f..4377e5a 100644 --- a/Tests/SwiftASBTests/Public/CodexAppServerTests.swift +++ b/Tests/SwiftASBTests/Public/CodexAppServerTests.swift @@ -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) @@ -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() } diff --git a/Tests/SwiftASBTests/Transport/CodexAppServerTransportTests.swift b/Tests/SwiftASBTests/Transport/CodexAppServerTransportTests.swift index 6a9b9a6..1cd324c 100644 --- a/Tests/SwiftASBTests/Transport/CodexAppServerTransportTests.swift +++ b/Tests/SwiftASBTests/Transport/CodexAppServerTransportTests.swift @@ -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 diff --git a/Tests/SwiftASBTests/Transport/CodexCLIExecutableResolverTests.swift b/Tests/SwiftASBTests/Transport/CodexCLIExecutableResolverTests.swift index cf2cf23..8ebbc10 100644 --- a/Tests/SwiftASBTests/Transport/CodexCLIExecutableResolverTests.swift +++ b/Tests/SwiftASBTests/Transport/CodexCLIExecutableResolverTests.swift @@ -23,8 +23,8 @@ struct CodexCLIExecutableResolverTests { #expect(resolution.launchExecutableURL == explicitURL) #expect(resolution.launchArgumentsPrefix.isEmpty) #expect(resolution.resolvedExecutableURL == explicitURL) - #expect(resolution.versionString == "codex-cli 0.128.0") - #expect(resolution.compatibility == .supported(documentedWindow: "0.128.x")) + #expect(resolution.versionString == "codex-cli 0.129.0") + #expect(resolution.compatibility == .supported(documentedWindow: "0.129.x")) #expect(recorder.recordedInvocations == [ .init(executablePath: explicitURL.path, arguments: ["--version"]) ]) @@ -48,7 +48,7 @@ struct CodexCLIExecutableResolverTests { #expect(resolution.launchExecutableURL.path == "/usr/bin/env") #expect(resolution.launchArgumentsPrefix == ["codex"]) #expect(resolution.resolvedExecutableURL == nil) - #expect(resolution.compatibility == .supported(documentedWindow: "0.128.x")) + #expect(resolution.compatibility == .supported(documentedWindow: "0.129.x")) #expect(recorder.recordedInvocations == [ .init(executablePath: "/usr/bin/env", arguments: ["codex", "--version"]) ]) @@ -76,7 +76,7 @@ struct CodexCLIExecutableResolverTests { #expect(resolution.launchExecutableURL.path == homebrewPath) #expect(resolution.launchArgumentsPrefix.isEmpty) #expect(resolution.resolvedExecutableURL?.path == homebrewPath) - #expect(resolution.compatibility == .supported(documentedWindow: "0.128.x")) + #expect(resolution.compatibility == .supported(documentedWindow: "0.129.x")) #expect(recorder.recordedInvocations == [ .init(executablePath: "/usr/bin/env", arguments: ["codex", "--version"]), .init(executablePath: homebrewPath, arguments: ["--version"]) @@ -106,7 +106,7 @@ struct CodexCLIExecutableResolverTests { #expect(resolution.launchExecutableURL.path == npmCodexPath) #expect(resolution.launchArgumentsPrefix.isEmpty) #expect(resolution.resolvedExecutableURL?.path == npmCodexPath) - #expect(resolution.compatibility == .supported(documentedWindow: "0.128.x")) + #expect(resolution.compatibility == .supported(documentedWindow: "0.129.x")) #expect(recorder.recordedInvocations == [ .init(executablePath: "/usr/bin/env", arguments: ["codex", "--version"]), .init(executablePath: "/usr/bin/env", arguments: ["npm", "prefix", "-g"]), @@ -139,7 +139,7 @@ struct CodexCLIExecutableResolverTests { @Test("marks supported versions inside the documented support window") func marksSupportedVersionsInsideSupportWindow() throws { let explicitURL = URL(fileURLWithPath: "/tmp/codex-explicit") - let recorder = CommandRecorder(pathVersionStandardOutput: "codex-cli 0.128.3") + let recorder = CommandRecorder(pathVersionStandardOutput: "codex-cli 0.129.3") let resolver = CodexCLIExecutableResolver( explicitExecutableURL: explicitURL, @@ -150,13 +150,13 @@ struct CodexCLIExecutableResolverTests { ) let resolution = try resolver.resolve() - #expect(resolution.compatibility == .supported(documentedWindow: "0.128.x")) + #expect(resolution.compatibility == .supported(documentedWindow: "0.129.x")) } @Test("marks older minor versions outside the documented support window") func marksOlderMinorVersionsOutsideSupportWindow() throws { let explicitURL = URL(fileURLWithPath: "/tmp/codex-explicit") - let recorder = CommandRecorder(pathVersionStandardOutput: "codex-cli 0.127.9") + let recorder = CommandRecorder(pathVersionStandardOutput: "codex-cli 0.128.9") let resolver = CodexCLIExecutableResolver( explicitExecutableURL: explicitURL, @@ -167,7 +167,7 @@ struct CodexCLIExecutableResolverTests { ) let resolution = try resolver.resolve() - #expect(resolution.compatibility == .outsideDocumentedWindow(documentedWindow: "0.128.x")) + #expect(resolution.compatibility == .outsideDocumentedWindow(documentedWindow: "0.129.x")) } @Test("marks unparseable version strings as unknown format") @@ -184,7 +184,7 @@ struct CodexCLIExecutableResolverTests { ) let resolution = try resolver.resolve() - #expect(resolution.compatibility == .unknownVersionFormat(documentedWindow: "0.128.x")) + #expect(resolution.compatibility == .unknownVersionFormat(documentedWindow: "0.129.x")) } } @@ -204,7 +204,7 @@ private final class CommandRecorder: @unchecked Sendable { init( pathVersionTerminationStatus: Int32 = 0, - pathVersionStandardOutput: String = "codex-cli 0.128.0", + pathVersionStandardOutput: String = "codex-cli 0.129.0", pathVersionStandardError: String = "", npmPrefixTerminationStatus: Int32 = 0, npmPrefixOutput: String = "/Users/galew/.npm-global", diff --git a/docs/maintainers/interactive-lifecycle-release-boundary.md b/docs/maintainers/interactive-lifecycle-release-boundary.md index 53e4223..45a4c2a 100644 --- a/docs/maintainers/interactive-lifecycle-release-boundary.md +++ b/docs/maintainers/interactive-lifecycle-release-boundary.md @@ -50,6 +50,7 @@ runtime while the app-server schema is moving quickly before v1. Current policy: - support the latest reviewed public Codex CLI minor release +- current reviewed minor release: `0.129.x` - widen back to a rolling window only after the latest generated-wire and public API boundaries have caught up with the current app-server shape - reassess this policy when Codex reaches a future major-version release diff --git a/docs/maintainers/quicktype-codegen-notes.md b/docs/maintainers/quicktype-codegen-notes.md index 6050397..e1476e1 100644 --- a/docs/maintainers/quicktype-codegen-notes.md +++ b/docs/maintainers/quicktype-codegen-notes.md @@ -71,18 +71,21 @@ inspecting upstream schema changes or quicktype regressions. ## Current generated batch The default generated batch currently stages against the local experimental -`v0.128.0` schema dump: +`v0.129.0` schema dump: -- `SCHEMA_VERSION=v0.128.0` +- `SCHEMA_VERSION=v0.129.0` - promoted output: `Sources/SwiftASB/Generated/CodexWire/Latest/CodexLifecycleV2Batch+JSONValue.swift` The promoted `Latest` snapshot is intentionally not swapped blindly just -because staging generation succeeds. The v0.128 experimental dump keeps -`permissionProfile`, adds `activePermissionProfile`, adds request-side -`permissions` profile selection, and removes older `GhostCommit` and -`ReadOnlyAccess` generated definitions. Promote generated changes only after -classifying public, observable-only, and internal effects. +because staging generation succeeds. The v0.129 experimental dump keeps the +v0.128 permission-profile shape, widens `serviceTier` from a closed generated +enum to an open string, adds plugin sharing and plugin skill-read request +families, adds standalone `process/*` request and notification families, adds +Windows sandbox readiness, adds hook compact event names, and adds thread and +turn metadata such as `threadSource`, `sessionId`, and `itemsView`. Promote +generated changes only after classifying public, observable-only, and internal +effects. ## Compatibility Shim Policy @@ -265,6 +268,13 @@ still concentrated in a small number of fields: Those are now patched to `CodexWireJSONValue`. +The same patch step also keeps a few v0.129-required fields optional in the +promoted Swift so the v0.128 drift-guard tests still decode older payloads: + +- `CodexWireThread.sessionID` +- `CodexWireItemStartedNotification.startedAtMS` +- `CodexWireItemCompletedNotification.completedAtMS` + ## `CodexWireJSONValue` The patch helper injects: diff --git a/docs/maintainers/v1-public-api-audit.md b/docs/maintainers/v1-public-api-audit.md index 92fc7b2..7dc1c1c 100644 --- a/docs/maintainers/v1-public-api-audit.md +++ b/docs/maintainers/v1-public-api-audit.md @@ -2,7 +2,7 @@ This document is the working checklist for the `SwiftASB` v1 public API curation pass. The goal is to freeze a compact, Swift-native surface for the -supported app-server lifecycle before `v1.1.3`, not to expose every generated +supported app-server lifecycle before `v1.1.4`, not to expose every generated wire family. ## Current Public Source Inventory @@ -429,7 +429,7 @@ Use these decisions for every public symbol: - [x] Add symbol comments for every stable v1 public type and method that is not self-explanatory from its declaration. - Decision: complete for the `v1.1.3` release boundary. Default-bearing public + Decision: complete for the `v1.1.4` release boundary. Default-bearing public initializers and methods now document whether omission delegates to Codex, chooses a SwiftASB local-history/UI default, or applies an explicit safety default such as `.turn` or `.unchanged`. The source-level pass also covers the @@ -495,7 +495,7 @@ Use these decisions for every public symbol: Decision: covered by the startup, progress/approval, diagnostics/history, and SwiftUI observable companion walkthroughs in `Sources/SwiftASB/SwiftASB.docc/`. - [x] Update stale README release references before the next release. - Decision: README now names `v1.1.3` as the current released baseline. + Decision: README now names `v1.1.4` as the current released baseline. - [x] Confirm README, DocC, and this audit use the same v1 release boundary. Decision: README, DocC, and this audit now describe the same narrow v1 promise: app-server lifecycle, app-wide capability reads, stored-thread diff --git a/docs/maintainers/v1-public-api-symbol-inventory.md b/docs/maintainers/v1-public-api-symbol-inventory.md index b317b1b..770bedb 100644 --- a/docs/maintainers/v1-public-api-symbol-inventory.md +++ b/docs/maintainers/v1-public-api-symbol-inventory.md @@ -1,10 +1,10 @@ # V1 Public API Symbol Inventory -Generated from `swift package dump-symbol-graph --minimum-access-level public --skip-synthesized-members` on 2026-05-02 after the v0.128 generated-wire promotion and final pre-v1 public-surface tightening, then updated on 2026-05-05 for the post-v1 app-wide library snapshot, on 2026-05-06 for the public query descriptor, filesystem, config, extension-inventory, thread-goal, recent-activity descriptor, repository-grouping, workspace permission-profile, and file-discovery slices, and on 2026-05-08 for the `CodexWorkspace.ProjectInfo` cleanup and `CodexAppServer.ThreadSource` promotion. This is a maintainer ledger for the v1 public API freeze plus accepted post-v1 app-wide additions; it records public/open declarations visible through the `SwiftASB` library product, excluding synthesized members. +Generated from `swift package dump-symbol-graph --minimum-access-level public --skip-synthesized-members` on 2026-05-02 after the v0.128 generated-wire promotion and final pre-v1 public-surface tightening, then updated on 2026-05-05 for the post-v1 app-wide library snapshot, on 2026-05-06 for the public query descriptor, filesystem, config, extension-inventory, thread-goal, recent-activity descriptor, repository-grouping, workspace permission-profile, and file-discovery slices, and on 2026-05-08 for the `CodexWorkspace.ProjectInfo` cleanup, `CodexAppServer.ThreadSource` promotion, and v0.129 hook compact event names. This is a maintainer ledger for the v1 public API freeze plus accepted post-v1 app-wide additions; it records public/open declarations visible through the `SwiftASB` library product, excluding synthesized members. ## Summary -- Public/open symbols: 1867 +- Public/open symbols: 1869 - Public/open types: 293 - Public/open initializers: 130 - Public/open methods and type methods: 129 @@ -661,7 +661,9 @@ Generated from `swift package dump-symbol-graph --minimum-access-level public -- - `CodexThread.Dashboard.HookRun.Entry.Kind.stop` - `case stop` - Sources/SwiftASB/Public/CodexThread+Dashboard.swift - `CodexThread.Dashboard.HookRun.Entry.Kind.warning` - `case warning` - Sources/SwiftASB/Public/CodexThread+Dashboard.swift - `CodexThread.Dashboard.HookRun.EventName.permissionRequest` - `case permissionRequest` - Sources/SwiftASB/Public/CodexThread+Dashboard.swift +- `CodexThread.Dashboard.HookRun.EventName.postCompact` - `case postCompact` - Sources/SwiftASB/Public/CodexThread+Dashboard.swift - `CodexThread.Dashboard.HookRun.EventName.postToolUse` - `case postToolUse` - Sources/SwiftASB/Public/CodexThread+Dashboard.swift +- `CodexThread.Dashboard.HookRun.EventName.preCompact` - `case preCompact` - Sources/SwiftASB/Public/CodexThread+Dashboard.swift - `CodexThread.Dashboard.HookRun.EventName.preToolUse` - `case preToolUse` - Sources/SwiftASB/Public/CodexThread+Dashboard.swift - `CodexThread.Dashboard.HookRun.EventName.sessionStart` - `case sessionStart` - Sources/SwiftASB/Public/CodexThread+Dashboard.swift - `CodexThread.Dashboard.HookRun.EventName.stop` - `case stop` - Sources/SwiftASB/Public/CodexThread+Dashboard.swift diff --git a/scripts/generate-wire-types.sh b/scripts/generate-wire-types.sh index f3475c3..06452cc 100644 --- a/scripts/generate-wire-types.sh +++ b/scripts/generate-wire-types.sh @@ -2,7 +2,7 @@ set -eu ROOT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) -SCHEMA_VERSION=${SCHEMA_VERSION:-v0.128.0} +SCHEMA_VERSION=${SCHEMA_VERSION:-v0.129.0} SCHEMA_ROOT="$ROOT_DIR/codex-schemas/$SCHEMA_VERSION" DERIVED_DIR="$ROOT_DIR/tmp/derived-schemas/${SCHEMA_VERSION//./_}" OUT_DIR="$ROOT_DIR/tmp/quicktype-wire/${SCHEMA_VERSION//./_}" @@ -145,8 +145,19 @@ build_batch \ PluginListResponse \ PluginReadParams \ PluginReadResponse \ + PluginSkillReadParams \ + PluginSkillReadResponse \ + PluginShareSaveParams \ + PluginShareSaveResponse \ + PluginShareUpdateTargetsParams \ + PluginShareUpdateTargetsResponse \ + PluginShareListParams \ + PluginShareListResponse \ + PluginShareDeleteParams \ + PluginShareDeleteResponse \ CollaborationModeListParams \ CollaborationModeListResponse \ + WindowsSandboxReadinessResponse \ ThreadStartedNotification \ ThreadStatusChangedNotification \ ThreadNameUpdatedNotification \ @@ -173,6 +184,16 @@ build_batch \ CommandExecOutputDeltaNotification \ FileChangeOutputDeltaNotification \ FileChangePatchUpdatedNotification \ + ProcessSpawnParams \ + ProcessSpawnResponse \ + ProcessWriteStdinParams \ + ProcessWriteStdinResponse \ + ProcessKillParams \ + ProcessKillResponse \ + ProcessResizePtyParams \ + ProcessResizePtyResponse \ + ProcessOutputDeltaNotification \ + ProcessExitedNotification \ ModelListParams \ ModelListResponse \ ListMcpServerStatusParams \ diff --git a/scripts/patch_quicktype_swift_any.py b/scripts/patch_quicktype_swift_any.py index 3d6a1c7..262a3e9 100644 --- a/scripts/patch_quicktype_swift_any.py +++ b/scripts/patch_quicktype_swift_any.py @@ -126,6 +126,21 @@ def patch_codable_output(source: str) -> str: patched = helper_pattern.sub(f"\n{JSON_VALUE_DECLARATION}\n", source) patched = patched.replace("JSONAny", "CodexWireJSONValue") patched = patched.replace("JSONNull", "CodexWireJSONValue") + patched = patch_cross_version_compatibility(patched) + return patched + + +def patch_cross_version_compatibility(source: str) -> str: + """Keep the promoted v0.129 graph tolerant of v0.128 guardrail payloads.""" + replacements = [ + (" let completedAtMS: Int\n", " let completedAtMS: Int?\n"), + (" let startedAtMS: Int\n", " let startedAtMS: Int?\n"), + (" let sessionID: String\n", " let sessionID: String?\n"), + ] + + patched = source + for old, new in replacements: + patched = patched.replace(old, new) return patched diff --git a/scripts/repo-maintenance/release.sh b/scripts/repo-maintenance/release.sh index 5e15e63..4402859 100755 --- a/scripts/repo-maintenance/release.sh +++ b/scripts/repo-maintenance/release.sh @@ -11,6 +11,7 @@ load_env_file "$SELF_DIR/config/release.env" mode="${REPO_MAINTENANCE_DEFAULT_RELEASE_MODE:-standard}" release_tag="" skip_validate="false" +skip_local_release_gate="false" skip_gh_release="false" skip_version_bump="false" base_branch="${REPO_MAINTENANCE_RELEASE_BRANCH:-main}" @@ -32,6 +33,10 @@ while [ "$#" -gt 0 ]; do skip_validate="true" shift ;; + --skip-local-release-gate) + skip_local_release_gate="true" + shift + ;; --skip-gh-release) skip_gh_release="true" shift @@ -59,7 +64,7 @@ while [ "$#" -gt 0 ]; do -h|--help) cat <<'USAGE' Usage: - release.sh --mode standard --version [--base-branch main] [--skip-validate] [--skip-version-bump] [--skip-gh-release] [--review-comments-addressed] [--skip-branch-cleanup] [--dry-run] + release.sh --mode standard --version [--base-branch main] [--skip-validate] [--skip-local-release-gate] [--skip-version-bump] [--skip-gh-release] [--review-comments-addressed] [--skip-branch-cleanup] [--dry-run] release.sh --mode submodule --version [--skip-validate] [--skip-gh-release] [--dry-run] USAGE exit 0 @@ -134,6 +139,26 @@ run_version_bump() { log "Committed version bump for $RELEASE_TAG." } +run_local_release_gate() { + release_gate_script="$REPO_ROOT/scripts/run-live-codex-release-gate.sh" + + if [ "$skip_local_release_gate" = "true" ]; then + log "Skipping local release gate because --skip-local-release-gate was requested." + return 0 + fi + + [ -f "$release_gate_script" ] || die "Standard release mode expected a local release gate at $release_gate_script so the release candidate can run full Swift package tests and live Codex probes before publishing." + + if [ "$REPO_MAINTENANCE_DRY_RUN" = "true" ]; then + log "Would run local release gate at $release_gate_script." + return 0 + fi + + log "Running local release gate before publishing $RELEASE_TAG." + sh "$release_gate_script" + log "Local release gate passed for $RELEASE_TAG." +} + create_release_tag() { head_sha="$(git -C "$REPO_ROOT" rev-parse HEAD)" tag_sha="$(git -C "$REPO_ROOT" rev-parse -q --verify "refs/tags/$RELEASE_TAG" 2>/dev/null || true)" @@ -376,6 +401,8 @@ run_standard_release() { run_version_bump ensure_clean_worktree + run_local_release_gate + ensure_clean_worktree create_release_tag push_branch_and_tag "$branch_name" create_or_update_pr "$branch_name" diff --git a/scripts/run-live-codex-integration-tests.sh b/scripts/run-live-codex-integration-tests.sh index fb58da7..a7129cb 100755 --- a/scripts/run-live-codex-integration-tests.sh +++ b/scripts/run-live-codex-integration-tests.sh @@ -9,7 +9,7 @@ usage() { Usage: scripts/run-live-codex-integration-tests.sh [mode] Modes: - release-gate Run the maintained release-gate live probe set. This is the default. + release-gate Run the full local release gate, including swift test and live probes. smoke Run startup, transport, capability, thread, turn, and concurrency probes. transport Run raw transport initialize/thread/turn probes. capability Run model, MCP, and hook diagnostics snapshot probes. diff --git a/scripts/run-live-codex-release-gate.sh b/scripts/run-live-codex-release-gate.sh index 9b3b8f1..86ff9b2 100755 --- a/scripts/run-live-codex-release-gate.sh +++ b/scripts/run-live-codex-release-gate.sh @@ -10,7 +10,10 @@ export SWIFTASB_LIVE_CODEX_REPORT_DIR mkdir -p "$SWIFTASB_LIVE_CODEX_REPORT_DIR" printf '%s\n' 'Running SwiftASB live Codex release gate.' -printf '%s\n' 'Step 1/4: startup, transport, capability, thread, turn, and concurrency smoke probes' +printf '%s\n' 'Step 1/6: full Swift package test suite' +swift test + +printf '%s\n' 'Step 2/6: startup, transport, capability, thread, turn, and concurrency smoke probes' env SWIFTASB_ENABLE_LIVE_CODEX_TRANSPORT_TESTS=1 \ SWIFTASB_ENABLE_LIVE_CODEX_CAPABILITY_TESTS=1 \ SWIFTASB_ENABLE_LIVE_CODEX_THREAD_MANAGEMENT_TESTS=1 \ @@ -20,13 +23,16 @@ env SWIFTASB_ENABLE_LIVE_CODEX_TRANSPORT_TESTS=1 \ SWIFTASB_LIVE_CODEX_REPORT_DIR="$SWIFTASB_LIVE_CODEX_REPORT_DIR" \ swift test --filter CodexAppServerLiveIntegrationTests -printf '%s\n' 'Step 2/4: approval and server-request probes' -sh "$REPO_ROOT/scripts/run-live-codex-approval-probe.sh" +printf '%s\n' 'Step 3/6: approval and server-request probes' +sh "$REPO_ROOT/scripts/run-live-codex-server-request-probes.sh" + +printf '%s\n' 'Step 4/6: behavior matrix probes' +sh "$REPO_ROOT/scripts/run-live-codex-behavior-matrix.sh" -printf '%s\n' 'Step 3/4: multi-turn file mutation scenario' +printf '%s\n' 'Step 5/6: multi-turn file mutation scenario' sh "$REPO_ROOT/scripts/run-live-codex-file-scenario.sh" -printf '%s\n' 'Step 4/4: rollback scenario' +printf '%s\n' 'Step 6/6: rollback scenario' sh "$REPO_ROOT/scripts/run-live-codex-rollback-scenario.sh" printf '%s\n' 'SwiftASB live Codex release gate completed successfully.'