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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: ci

on:
pull_request:
push:
branches: [main]

permissions:
contents: read

jobs:
swift:
runs-on: macos-15
timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- run: swift test
- run: swift build -c release
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
# zed-xcode

Buildable Swift core candidate for a macOS companion app and Xcode Source Editor Extension.
Native Apple integration work for Zed Package Manager state, diagnostics, and confirmation-gated recommended actions.

The core has an injectable process runner, argv execution, timeout, schema validation, output redaction, and unsafe-action rejection. `swift test` covers the contract without launching a user's Xcode instance.
The Swift package now contains:

A dedicated repository still needs the companion dashboard, XcodeKit commands, signed app/appex packaging, entitlements, and clean Xcode-instance UI tests.
- an injectable `zed inspect` process boundary with timeout, schema validation, redaction, and unsafe-action rejection;
- a multi-root workspace projection suitable for a SwiftUI companion dashboard;
- confirmation-gated command previews carrying exact executable, argv, and working directory;
- unit tests that run without launching or mutating a user's Xcode instance.

```sh
swift test
swift build -c release
```

The dedicated repository is established. Remaining distribution work is the SwiftUI companion app target, XcodeKit Source Editor Extension, App Group cache and entitlements, clean Xcode-instance tests, signing/notarization, and app/appex packaging.
59 changes: 59 additions & 0 deletions Sources/ZedCore/ZedWorkspaceModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import Foundation

public struct ZedPackageSnapshot: Sendable, Equatable {
public let root: String
public let errors: Int
public let warnings: Int
public let issues: [ZedIssue]

public init(root: String, errors: Int, warnings: Int, issues: [ZedIssue]) {
self.root = root
self.errors = errors
self.warnings = warnings
self.issues = issues
}

public static func == (lhs: Self, rhs: Self) -> Bool {
lhs.root == rhs.root && lhs.errors == rhs.errors && lhs.warnings == rhs.warnings && lhs.issues.map(\.id) == rhs.issues.map(\.id)
}
}

public struct ZedActionPreview: Sendable, Equatable {
public let executable: String
public let arguments: [String]
public let workingDirectory: String
public let requiresConfirmation: Bool
}

public enum ZedWorkspaceModelError: Error, Equatable {
case nonCommandAction
case confirmationRequired
case missingExecutable
}

public enum ZedWorkspaceModel {
public static func project(_ reports: [ZedReport]) -> [ZedPackageSnapshot] {
reports.map { report in
let errors = report.issues.filter { $0.severity.lowercased() == "error" }.count
let warnings = report.issues.filter { $0.severity.lowercased() == "warning" }.count
return ZedPackageSnapshot(
root: URL(fileURLWithPath: report.workspaceRoot).standardizedFileURL.path,
errors: errors,
warnings: warnings,
issues: report.issues
)
}.sorted { $0.root < $1.root }
}

public static func preview(action: ZedAction, root: String) throws -> ZedActionPreview {
guard action.kind == "command" else { throw ZedWorkspaceModelError.nonCommandAction }
guard action.requiresConfirmation else { throw ZedWorkspaceModelError.confirmationRequired }
guard !action.command.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { throw ZedWorkspaceModelError.missingExecutable }
return ZedActionPreview(
executable: action.command,
arguments: action.arguments,
workingDirectory: URL(fileURLWithPath: root).standardizedFileURL.path,
requiresConfirmation: true
)
}
}
32 changes: 32 additions & 0 deletions Tests/ZedCoreTests/ZedWorkspaceModelTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import Foundation
import Testing
@testable import ZedCore

@Test func projectsMultiRootReportsInStableOrder() {
let reports = [
ZedReport(schemaVersion: 1, workspaceRoot: "/zeta", zedVersion: "0.1", issues: [
ZedIssue(id: "lock.stale", severity: "warning", title: "Stale", detail: "", files: [], actions: [])
]),
ZedReport(schemaVersion: 1, workspaceRoot: "/alpha", zedVersion: "0.1", issues: [
ZedIssue(id: "manifest.invalid", severity: "error", title: "Invalid", detail: "", files: [], actions: [])
])
]
let snapshots = ZedWorkspaceModel.project(reports)
#expect(snapshots.map(\.root) == ["/alpha", "/zeta"])
#expect(snapshots[0].errors == 1)
#expect(snapshots[1].warnings == 1)
}

@Test func previewsOnlyConfirmationGatedCommands() throws {
let action = ZedAction(id: "install", title: "Install", kind: "command", command: "zed", arguments: ["install"], requiresConfirmation: true)
let preview = try ZedWorkspaceModel.preview(action: action, root: "/tmp/work")
#expect(preview.executable == "zed")
#expect(preview.arguments == ["install"])
#expect(preview.requiresConfirmation)
#expect(throws: ZedWorkspaceModelError.confirmationRequired) {
try ZedWorkspaceModel.preview(
action: ZedAction(id: "bad", title: "Bad", kind: "command", command: "zed", arguments: ["install"], requiresConfirmation: false),
root: "/tmp/work"
)
}
}
26 changes: 26 additions & 0 deletions conformance/ide-integration.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"schema": "zed-pkg/ide-integration-conformance/v1",
"integration": "xcode",
"repository": "zed-pkg/zed-xcode",
"contractVersion": 1,
"level": {"core": "pass", "nativeShell": "companion-model", "distribution": "repository"},
"capabilities": {
"multiRootDiscovery": "workspace-model",
"manifestDiagnostics": true,
"lockDiagnostics": true,
"materializationDiagnostics": true,
"stagingRecovery": true,
"argvExecution": true,
"boundedExecution": true,
"outputRedaction": true,
"explicitMutationConfirmation": true,
"versionedInspectAdapter": "pending-zed-cli-191",
"nativeUnitTests": true,
"repoLocalCI": true,
"immutableWorkflowInputs": true,
"fixedRunnerImages": true,
"checkoutCredentialsPersisted": false
},
"remaining": ["SwiftUI companion app target", "XcodeKit Source Editor Extension", "App Group cache/entitlements", "clean Xcode instance test", "signed app/appex packaging"],
"linearIssue": "DEN-2508"
}