Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
a6b5612
docs: switch palette to t27.ai black/white with minimal green
gHashTag Aug 9, 2026
9802e4a
fpga: reconstruct the AX7203 RGMII constraints as a real artefact
gHashTag Aug 9, 2026
1c6d865
site: correct the upstream PR states; add the openFPGALoader merges
gHashTag Aug 10, 2026
a72766e
site: all six openXC7 PRs merged
gHashTag Aug 10, 2026
c8486e7
fpga: seed a regression suite for nextpnr-xilinx
gHashTag Aug 10, 2026
6c00cb3
docs(regress): add the README the previous commit silently dropped
gHashTag Aug 10, 2026
a636d8f
docs(regress): the case does not reproduce the failure
gHashTag Aug 10, 2026
ef85841
docs(regress): prjxray-db ruled out by measurement, not argument
gHashTag Aug 10, 2026
86d8f13
docs(regress): mechanism reproduces, symptom does not -- measured bot…
gHashTag Aug 10, 2026
bc6ba35
docs(regress): contention hypothesis tested and disproved at 9 and 21…
gHashTag Aug 10, 2026
93c77bc
docs(regress): reproduced at f8e7643 and bisected -- #109 masks the #…
gHashTag Aug 10, 2026
2e25f13
regress: refuse to pass on a tree where the bug is unreachable
gHashTag Aug 10, 2026
560e56a
site: replace the best-in-class claim with the measured comparison
gHashTag Aug 10, 2026
baba617
site: surface the delta_CP retraction as a first-class list
gHashTag Aug 10, 2026
39cc963
site: the benchmark claim lived in the message catalogue, not the com…
gHashTag Aug 10, 2026
e4b33a7
site: clear every blocked claim from all five locales and the tech tree
gHashTag Aug 10, 2026
513b1cb
Split build from typecheck; fix seven statically-false branches
gHashTag Aug 10, 2026
734b844
Fix 19 more dead branches and a crash on the API-failure path
gHashTag Aug 10, 2026
4d8227e
Guard 18 more crash sites: .toFixed() on fields that exist nowhere
gHashTag Aug 10, 2026
b6842b8
Add an API-contract check, after it first manufactured 19 false findings
gHashTag Aug 10, 2026
24df519
Label sample data as sample data on the FPGA synthesis widget
gHashTag Aug 10, 2026
b5e9bd7
Tag every service fallback as sample data, and stop displaying 0.618
gHashTag Aug 10, 2026
fab549d
Make the unlabelled-fallback pattern fail the check, not just this in…
gHashTag Aug 10, 2026
9f00784
Tag 22 fallbacks the rule missed, and render the badge where it matters
gHashTag Aug 10, 2026
6292089
Stop the dashboard fabricating telemetry and overstating the repo 6.7x
gHashTag Aug 10, 2026
7c96329
Clear every blocking numeric fallback the new checker found
gHashTag Aug 10, 2026
56566b3
feat(website): render check driving real Chrome over CDP
gHashTag Aug 10, 2026
a9a0cc7
fix(website): ship the manifest from source, and stop the render chec…
gHashTag Aug 10, 2026
fe172f2
fix(gitignore): the docs/ exception never worked, hiding 28 documents
gHashTag Aug 10, 2026
60d14a4
docs: restore six documents the site links to, with five claims corre…
gHashTag Aug 10, 2026
21ac2fd
fix(website): the GF-T page's two evidence links were 404
gHashTag Aug 10, 2026
f729b09
fix(website): the RTL was published after all -- correcting my own fi…
gHashTag Aug 10, 2026
861afb2
docs: attribute multiplier-freedom to the network in the patent analysis
gHashTag Aug 10, 2026
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ fpga/tools/weight_pack_wide
*.md
!CLAUDE.md
!.github/
!docs/
!docs/**

# Docker files in root (use deploy/ subdirectory instead)
Dockerfile*
Expand Down
10 changes: 9 additions & 1 deletion apps/queen/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,15 @@ let package = Package(
.macOS(.v14),
.iOS(.v17)
],
products: [],
products: [
.library(
name: "QueenUILib",
type: .dynamic,
targets: ["QueenUILib"]),
.executable(
name: "trinity",
targets: ["trinity"]),
],
targets: [
.target(
name: "QueenUILib",
Expand Down
311 changes: 277 additions & 34 deletions apps/queen/QueenUI/Bridge/ActionQueue.swift
Original file line number Diff line number Diff line change
@@ -1,56 +1,258 @@
import Foundation
import SwiftUI

/// Central action dispatcher — writes actions to .trinity/queen/actions_queue.json
/// Queen Zig daemon reads and executes them on next cycle
enum QueenActionRisk: Equatable {
case safe
case requiresConfirmation
}

enum QueenActionHandling: Equatable {
case refresh
case clearQueue
case queenRuntime
}

struct QueenActionDefinition: Equatable {
let id: String
let title: String
let risk: QueenActionRisk
let handling: QueenActionHandling
}

enum QueenActionCatalog {
static let all: [QueenActionDefinition] = [
action("build", "Rebuild", .safe),
action("cell_create", "Create cell", .requiresConfirmation),
action("farm_evolve", "Evolve farm", .requiresConfirmation),
action("farm_kill_idle", "Kill idle services", .requiresConfirmation),
action("git_commit", "Commit state", .requiresConfirmation),
action("git_push", "Push changes", .requiresConfirmation),
refresh("issues_refresh", "Refresh issues"),
refresh("keys_test", "Test keys"),
action("pipeline_run", "Run pipeline", .requiresConfirmation),
action("queen_approve", "Approve action", .requiresConfirmation),
action("queen_deny", "Deny action", .requiresConfirmation),
QueenActionDefinition(
id: "queue_clear",
title: "Clear action queue",
risk: .requiresConfirmation,
handling: .clearQueue
),
action("redeploy", "Redeploy", .requiresConfirmation),
action("scholar_research", "Start research", .safe),
action("swarm_decompose", "Decompose task", .requiresConfirmation),
refresh("telegram_check", "Check Telegram"),
action("telegram_test", "Send Telegram test", .requiresConfirmation),
]

static func definition(for id: String) -> QueenActionDefinition? {
all.first { $0.id == id }
}

private static func action(
_ id: String,
_ title: String,
_ risk: QueenActionRisk
) -> QueenActionDefinition {
QueenActionDefinition(
id: id,
title: title,
risk: risk,
handling: .queenRuntime
)
}

private static func refresh(
_ id: String,
_ title: String
) -> QueenActionDefinition {
QueenActionDefinition(
id: id,
title: title,
risk: .safe,
handling: .refresh
)
}
}

struct QueenActionEnvelope: Codable, Equatable {
let timestamp: Int
let action: String
let params: [String: String]

enum CodingKeys: String, CodingKey {
case timestamp = "ts"
case action
case params
}
}

enum QueenActionCodec {
static func encode(_ actions: [QueenActionEnvelope]) throws -> Data {
let encoder = JSONEncoder()
encoder.outputFormatting = [.sortedKeys, .withoutEscapingSlashes]
return try encoder.encode(actions)
}

static func decode(_ data: Data) throws -> [QueenActionEnvelope] {
try JSONDecoder().decode([QueenActionEnvelope].self, from: data)
}
}

enum QueenActionPhase: Equatable {
case queued
case running
case succeeded
case failed
}

struct QueenActionFeedback: Identifiable, Equatable {
let id = UUID()
let actionID: String
let title: String
let detail: String
let phase: QueenActionPhase
}

extension Notification.Name {
static let queenWorkspaceRefresh = Notification.Name(
"com.trinity.queen.workspace-refresh"
)
}

/// Central action dispatcher. Runtime actions are written to a durable compact
/// JSON queue; local refresh and clear operations complete immediately.
@MainActor
class ActionQueue: ObservableObject {
static let shared = ActionQueue()

@Published var lastEnqueued: String?
@Published var isProcessing = false
@Published var feedback: QueenActionFeedback?

private var queuePath: String {
let cwd = FileManager.default.currentDirectoryPath
let cwd = TrinityRuntimePaths.projectRoot
return "\(cwd)/.trinity/queen/actions_queue.json"
}

func enqueue(_ action: String, params: [String: String] = [:]) {
let entry: [String: Any] = [
"ts": Int(Date().timeIntervalSince1970),
"action": action,
"params": params,
]

// Read existing queue or create new
var queue: [[String: Any]] = []
if let data = try? Data(contentsOf: URL(fileURLWithPath: queuePath)),
let existing = try? JSONSerialization.jsonObject(with: data) as? [[String: Any]] {
queue = existing
guard let definition = QueenActionCatalog.definition(for: action) else {
showFeedback(
actionID: action,
title: "Unknown action",
detail: "\(action) is not declared in the Queen action catalog.",
phase: .failed
)
return
}

switch definition.handling {
case .refresh:
lastEnqueued = action
NotificationCenter.default.post(
name: .queenWorkspaceRefresh,
object: action
)
showFeedback(
actionID: action,
title: definition.title,
detail: "Live workspace data refreshed.",
phase: .succeeded
)
case .clearQueue:
clearDurableQueue(definition: definition)
case .queenRuntime:
enqueueForRuntime(definition: definition, params: params)
}
}

queue.append(entry)
func dismissFeedback() {
feedback = nil
}

// Ensure directory exists
let dir = (queuePath as NSString).deletingLastPathComponent
try? FileManager.default.createDirectory(atPath: dir, withIntermediateDirectories: true)
private func enqueueForRuntime(
definition: QueenActionDefinition,
params: [String: String]
) {
let url = URL(fileURLWithPath: queuePath)
var queue: [QueenActionEnvelope] = []

// Write
if let data = try? JSONSerialization.data(withJSONObject: queue, options: [.prettyPrinted]) {
try? data.write(to: URL(fileURLWithPath: queuePath))
if let data = try? Data(contentsOf: url) {
queue = (try? QueenActionCodec.decode(data)) ?? []
}

lastEnqueued = action
isProcessing = true
queue.append(
QueenActionEnvelope(
timestamp: Int(Date().timeIntervalSince1970),
action: definition.id,
params: params
)
)

do {
let directory = url.deletingLastPathComponent()
try FileManager.default.createDirectory(
at: directory,
withIntermediateDirectories: true
)
let data = try QueenActionCodec.encode(queue)
try data.write(to: url, options: .atomic)

lastEnqueued = definition.id
isProcessing = false
showFeedback(
actionID: definition.id,
title: definition.title,
detail: "Queued durably for the Queen runtime.",
phase: .queued
)
} catch {
isProcessing = false
showFeedback(
actionID: definition.id,
title: "\(definition.title) failed",
detail: error.localizedDescription,
phase: .failed
)
}
}

// Reset processing indicator after 3s
Task {
try? await Task.sleep(for: .seconds(3))
await MainActor.run {
isProcessing = false
private func clearDurableQueue(definition: QueenActionDefinition) {
let url = URL(fileURLWithPath: queuePath)
do {
if FileManager.default.fileExists(atPath: url.path) {
try FileManager.default.removeItem(at: url)
}
lastEnqueued = definition.id
showFeedback(
actionID: definition.id,
title: definition.title,
detail: "The durable Queen action queue is empty.",
phase: .succeeded
)
} catch {
showFeedback(
actionID: definition.id,
title: "\(definition.title) failed",
detail: error.localizedDescription,
phase: .failed
)
}
}

private func showFeedback(
actionID: String,
title: String,
detail: String,
phase: QueenActionPhase
) {
feedback = QueenActionFeedback(
actionID: actionID,
title: title,
detail: detail,
phase: phase
)
}
}

/// Reusable action button style for dashboard screens
Expand All @@ -61,24 +263,65 @@ struct ActionButton: View {
var action: String
var params: [String: String] = [:]

@StateObject private var queue = ActionQueue.shared
@ObservedObject private var queue = ActionQueue.shared
@State private var showsConfirmation = false

var body: some View {
Button {
ActionQueue.shared.enqueue(action, params: params)
if definition?.risk == .requiresConfirmation {
showsConfirmation = true
} else {
submit()
}
} label: {
HStack(spacing: ParietalSpacing.xxs) {
Text(icon)
.font(WernickeTypography.caption)
if queue.isProcessing && queue.lastEnqueued == action {
ProgressView()
.controlSize(.mini)
} else {
Text(icon)
.font(WernickeTypography.caption)
}
Text(label)
.font(WernickeTypography.captionBold)
}
.foregroundStyle(.black)
.foregroundStyle(V4Color.textPrimary)
.padding(.horizontal, ParietalSpacing.sm)
.padding(.vertical, ParietalSpacing.xxs)
.background(color)
.background(V4Color.surface)
.clipShape(SwiftUI.Capsule())
.overlay {
SwiftUI.Capsule()
.stroke(color.opacity(0.64), lineWidth: 1)
}
}
.buttonStyle(.plain)
.confirmationDialog(
definition?.title ?? label,
isPresented: $showsConfirmation,
titleVisibility: .visible
) {
Button("Confirm", role: confirmationRole) {
submit()
}
Button("Cancel", role: .cancel) {}
} message: {
Text("This action can change project or external state.")
}
.help(definition?.title ?? label)
}

private var definition: QueenActionDefinition? {
QueenActionCatalog.definition(for: action)
}

private var confirmationRole: ButtonRole? {
action == "farm_kill_idle" || action == "queue_clear"
? .destructive
: nil
}

private func submit() {
queue.enqueue(action, params: params)
}
}
6 changes: 3 additions & 3 deletions apps/queen/QueenUI/Bridge/EnvLoader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ struct EnvLoader {
if parent == dir { break }
dir = parent
}
// Fallback to known project root
let fallback = FileManager.default.homeDirectoryForCurrentUser
.appendingPathComponent("trinity-w1/.env")
// Fallback to the configured project root.
let fallback = URL(fileURLWithPath: TrinityRuntimePaths.projectRoot)
.appendingPathComponent(".env")
if FileManager.default.fileExists(atPath: fallback.path) {
return fallback
}
Expand Down
Loading
Loading