Skip to content
Open
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
6 changes: 3 additions & 3 deletions .claude.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
"provenance": {
"generator": "scripts/build-cognitive-manifest.py",
"repository": "Aegis-Omega/AEGIS-OMEGA",
"source_ref": "claude/blissful-rubin-mt9jS",
"parent_state_hash": "410bcd49c721e65050382ae759db7af2f41fa9f572e625174252c72a8748ea93",
"source_ref": "feat/app-intents-under-version-control",
"parent_state_hash": "e9f0ec153b0b320a1e791092f73209442ec43a982e503203d9c101ec40949cba",
"signature_mode": "GITHUB_OIDC_ATTESTATION"
},
"hashing": {
Expand Down Expand Up @@ -488,5 +488,5 @@
"on_success": "broadcast-attested-verified-event-stream"
}
},
"state_hash": "e9f0ec153b0b320a1e791092f73209442ec43a982e503203d9c101ec40949cba"
"state_hash": "77d2014edd826149d8fa6ced78db0ed81bd1811c1430f201ba3f64329f60ce15"
}
27 changes: 27 additions & 0 deletions clients/aegis-omega-app-intents/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// swift-tools-version: 5.9

import PackageDescription

let package = Package(
name: "AEGISOmegaAppIntents",
defaultLocalization: "en",
platforms: [
.iOS(.v17),
.macOS(.v14),
],
products: [
.library(
name: "AEGISOmegaAppIntents",
targets: ["AEGISOmegaAppIntents"]
),
],
targets: [
.target(
name: "AEGISOmegaAppIntents"
),
.testTarget(
name: "AEGISOmegaAppIntentsTests",
dependencies: ["AEGISOmegaAppIntents"]
),
]
)
51 changes: 51 additions & 0 deletions clients/aegis-omega-app-intents/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# AEGIS Omega — App Intents client

Siri / Spotlight / Shortcuts entry points that hand a single system-facing route into the app's
root scene.

## Why this is in the repository

It was previously stranded in a transient agent scratch directory
(`Documents\Codex\2026-07-28\build-ios-apps-ios-app-intents-2\outputs\`). That is the same class
of location where the "holon-gram compiler" (8 files, +4446/−889) was lost permanently when its
container was reclaimed — see `CLAUDE.md` § *Verified Failure Modes* V1. Work that only exists in
an agent's working directory is one cleanup away from gone.

## Layout

| File | Platform | Purpose |
|---|---|---|
| `AEGISIntentRoute.swift` | any | `AEGISIntentRoute` / `AEGISSessionMode` — pure `Foundation` route model |
| `AEGISIntentRouter.swift` | any | `@MainActor @Observable` singleton the root scene observes |
| `AEGISAppIntents.swift` | Apple only | `AppIntent` conformances + `AEGISSessionModeIntentValue` |
| `AEGISAppShortcuts.swift` | Apple only | `AppShortcutsProvider` phrases |

## Cross-platform guard

`AppIntents` ships only in Apple SDKs. The two Apple-only sources are wrapped in
`#if canImport(AppIntents)`, and the test that exercises `AEGISSessionModeIntentValue` is guarded
the same way. On Apple platforms everything compiles unchanged; on Linux/Windows the pure
`Foundation` core and its tests still build, so the routing logic stays continuously verifiable
without a Mac.

## Build

```bash
swift build
swift test
```

**Windows prerequisite:** the Swift toolchain requires MSVC's `link.exe`. Without the Visual
Studio C++ workload, `swift build` fails with `toolchain is invalid: could not find CLI tool
'link'`. Installing that workload requires an **elevated** process — a non-elevated
`setup.exe --quiet` exits `5007` and silently does nothing.

**iOS builds require macOS + Xcode.** No Windows toolchain can produce an iOS app; on Windows only
the cross-platform core and its tests are exercised.

## Tests

`AEGISIntentRouteTests` covers route equality by payload, `AEGISSessionMode` raw-value round trip
(including the rejection of an unknown value), that `accept` replaces the pending handoff with a
fresh identity, and that `clear` on a superseded handoff does not drop the current one. Router
tests reset shared state via `defer`, since `AEGISIntentRouter.shared` is a singleton.
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// AppIntents ships only in Apple SDKs. Guarded so the pure-Swift core and its
// tests still build on Linux/Windows; on Apple platforms this compiles unchanged.
#if canImport(AppIntents)
import AppIntents

public enum AEGISSessionModeIntentValue: String, AppEnum {
case focused
case governed
case recovery

public static let typeDisplayRepresentation: TypeDisplayRepresentation = "Session mode"

public static let caseDisplayRepresentations: [Self: DisplayRepresentation] = [
.focused: "Focused",
.governed: "Governed",
.recovery: "Recovery",
]

var domainValue: AEGISSessionMode {
switch self {
case .focused: .focused
case .governed: .governed
case .recovery: .recovery
}
}
}

public struct ContinueContextIntent: AppIntent {
public static let title: LocalizedStringResource = "Continue context"
public static let description = IntentDescription(
"Open AEGIS Omega with context captured from Siri, Spotlight, or another shortcut."
)
public static let openAppWhenRun = true

@Parameter(
title: "Context",
inputConnectionBehavior: .connectToPreviousIntentResult
)
public var context: String?

public init() {}

public init(context: String?) {
self.context = context
}

public func perform() async throws -> some IntentResult {
await AEGISIntentRouter.shared.accept(.continueContext(text: context))
return .result()
}
}

public struct StartGovernedSessionIntent: AppIntent {
public static let title: LocalizedStringResource = "Start governed session"
public static let description = IntentDescription(
"Open AEGIS Omega ready to begin a focused, governed, or recovery session."
)
public static let openAppWhenRun = true

@Parameter(title: "Objective")
public var objective: String?

@Parameter(title: "Mode", default: .governed)
public var mode: AEGISSessionModeIntentValue

public init() {}

public init(objective: String?, mode: AEGISSessionModeIntentValue = .governed) {
self.objective = objective
self.mode = mode
}

public func perform() async throws -> some IntentResult {
await AEGISIntentRouter.shared.accept(
.startSession(objective: objective, mode: mode.domainValue)
)
return .result()
}
}

public struct InspectEvidenceIntent: AppIntent {
public static let title: LocalizedStringResource = "Inspect evidence"
public static let description = IntentDescription(
"Open AEGIS Omega at the evidence surface, optionally focused on a reference."
)
public static let openAppWhenRun = true

@Parameter(
title: "Reference",
inputConnectionBehavior: .connectToPreviousIntentResult
)
public var reference: String?

public init() {}

public init(reference: String?) {
self.reference = reference
}

public func perform() async throws -> some IntentResult {
await AEGISIntentRouter.shared.accept(.inspectEvidence(reference: reference))
return .result()
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Intent definitions that live in a Swift package (rather than the app bundle) are not
// indexed by Siri / Spotlight / Shortcuts unless the app declares the package. Providing
// this type lets the app target opt in:
//
// struct MyApp: App, AppIntentsPackage {
// static var includedPackages: [any AppIntentsPackage.Type] {
// [AEGISOmegaAppIntentsPackage.self]
// }
// }
//
// AppIntents ships only in Apple SDKs, so this is guarded like the other intent sources.
#if canImport(AppIntents)
import AppIntents

public struct AEGISOmegaAppIntentsPackage: AppIntentsPackage {
public init() {}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// AppIntents ships only in Apple SDKs. Guarded so the pure-Swift core and its
// tests still build on Linux/Windows; on Apple platforms this compiles unchanged.
#if canImport(AppIntents)
import AppIntents

public struct AEGISAppShortcuts: AppShortcutsProvider {
Comment thread
tarikskalic33 marked this conversation as resolved.
public static var appShortcuts: [AppShortcut] {
AppShortcut(
intent: ContinueContextIntent(),
phrases: [
"Continue context in \(.applicationName)",
"Remember this with \(.applicationName)",
],
shortTitle: "Continue context",
systemImageName: "brain.head.profile"
)

AppShortcut(
intent: StartGovernedSessionIntent(),
phrases: [
"Start a governed session in \(.applicationName)",
"Begin a session with \(.applicationName)",
],
shortTitle: "Start session",
systemImageName: "point.3.connected.trianglepath.dotted"
)

AppShortcut(
intent: InspectEvidenceIntent(),
phrases: [
"Inspect evidence in \(.applicationName)",
"Open evidence with \(.applicationName)",
],
shortTitle: "Inspect evidence",
systemImageName: "checkmark.seal"
)
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Foundation

/// The single system-facing route passed from App Intents into the main scene.
public enum AEGISIntentRoute: Equatable, Sendable {
case continueContext(text: String?)
case startSession(objective: String?, mode: AEGISSessionMode)
case inspectEvidence(reference: String?)
}

public enum AEGISSessionMode: String, CaseIterable, Codable, Sendable {
case focused
case governed
case recovery
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import Foundation
import Observation

/// Main-actor handoff point observed by the app's root scene.
@MainActor
@Observable
public final class AEGISIntentRouter {
public struct Handoff: Identifiable, Equatable, Sendable {
public let id: UUID
public let route: AEGISIntentRoute

public init(id: UUID = UUID(), route: AEGISIntentRoute) {
self.id = id
self.route = route
}
}

public static let shared = AEGISIntentRouter()

/// Read-only to callers: mutation must go through `accept(_:)` / `clear(_:)` so the
/// id-matching guard in `clear(_:)` cannot be bypassed by an external write.
public private(set) var pendingHandoff: Handoff?

private init() {}

public func accept(_ route: AEGISIntentRoute) {
pendingHandoff = Handoff(route: route)
}

public func clear(_ handoff: Handoff) {
guard pendingHandoff?.id == handoff.id else { return }
pendingHandoff = nil
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import XCTest
@testable import AEGISOmegaAppIntents

// Every test method here is nonisolated and `async`, and the main-actor hop happens inside
// the body. SwiftPM builds its test-discovery list out of unapplied method references, so a
// method's isolation leaks into that list's element type: `@MainActor` methods produce
// `(Self) -> @MainActor () -> Void`, which off-Apple fails to compile when mixed with
// nonisolated methods and fails to *cast* at run time when it isn't. Keeping the whole class
// nonisolated keeps the element type uniform and castable, so the tests are actually invoked.
final class AEGISIntentRouteTests: XCTestCase {

/// Returns the router to a known-empty state through its public API only,
/// since `pendingHandoff` is read-only to callers.
@MainActor
private func drain(_ router: AEGISIntentRouter) {
while let h = router.pendingHandoff { router.clear(h) }
}

// Exercises the AppIntents-facing enum, so it can only run where AppIntents exists.
#if canImport(AppIntents)
func testSessionModesMapWithoutLosingMeaning() async {
XCTAssertEqual(AEGISSessionModeIntentValue.focused.domainValue, .focused)
XCTAssertEqual(AEGISSessionModeIntentValue.governed.domainValue, .governed)
XCTAssertEqual(AEGISSessionModeIntentValue.recovery.domainValue, .recovery)
}
#endif

func testRouterReplacesThePendingHandoffAtomically() async {
await MainActor.run {
let router = AEGISIntentRouter.shared
defer { drain(router) }

router.accept(.continueContext(text: "first"))
let first = router.pendingHandoff

router.accept(.inspectEvidence(reference: "receipt-42"))
let second = router.pendingHandoff

XCTAssertNotEqual(first?.id, second?.id)
XCTAssertEqual(second?.route, .inspectEvidence(reference: "receipt-42"))
}
}

// The route model is pure Foundation, so these run on every platform.
func testRouteEqualityDistinguishesPayloads() async {
XCTAssertEqual(
AEGISIntentRoute.continueContext(text: "a"),
AEGISIntentRoute.continueContext(text: "a")
)
XCTAssertNotEqual(
AEGISIntentRoute.continueContext(text: "a"),
AEGISIntentRoute.continueContext(text: "b")
)
XCTAssertNotEqual(
AEGISIntentRoute.startSession(objective: nil, mode: .focused),
AEGISIntentRoute.startSession(objective: nil, mode: .governed)
)
}

func testSessionModeRoundTripsThroughItsRawValue() async {
for mode in AEGISSessionMode.allCases {
XCTAssertEqual(AEGISSessionMode(rawValue: mode.rawValue), mode)
}
XCTAssertNil(AEGISSessionMode(rawValue: "not-a-mode"))
}

func testClearOnlyDropsTheMatchingHandoff() async {
await MainActor.run {
let router = AEGISIntentRouter.shared
defer { drain(router) }

router.accept(.startSession(objective: "audit", mode: .recovery))
guard let stale = router.pendingHandoff else { return XCTFail("expected a handoff") }

router.accept(.inspectEvidence(reference: "receipt-7"))
router.clear(stale)

XCTAssertEqual(
router.pendingHandoff?.route,
.inspectEvidence(reference: "receipt-7"),
"clearing a superseded handoff must not drop the current one"
)
}
}
}
Loading