Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
078eaa6
[Beta] Stage 1 Refactor
johnwatso Mar 13, 2026
4c044d4
refactor: extract typed gateway dispatch slices
johnwatso Mar 13, 2026
065dfbd
refactor: type slash and member gateway events
johnwatso Mar 13, 2026
eb07c9a
refactor: type message and voice gateway events
johnwatso Mar 13, 2026
8b15513
refactor: route payload sends through app output helper
johnwatso Mar 13, 2026
93ac320
refactor: centralize app output action wrappers
johnwatso Mar 13, 2026
9c0c81c
test: restore mesh suite compatibility baseline
johnwatso Mar 13, 2026
6f7581e
refactor: extract app voice presence store
johnwatso Mar 13, 2026
fdb4260
refactor: extract discord voice rule state store
johnwatso Mar 13, 2026
b7f04cc
refactor: centralize rule pipeline execution
johnwatso Mar 13, 2026
03990b1
refactor: extract discord message rest client
johnwatso Mar 13, 2026
6a79488
refactor: extract discord guild rest client
johnwatso Mar 13, 2026
626583a
refactor: expand discord message rest client
johnwatso Mar 13, 2026
d2459aa
refactor: extract discord interaction rest client
johnwatso Mar 13, 2026
8a20a89
refactor: extract discord identity and dm helpers
johnwatso Mar 13, 2026
6e6f706
refactor: move discord message fetch helpers
johnwatso Mar 13, 2026
62c2e0c
refactor: move discord identity probe helpers
johnwatso Mar 13, 2026
87be43f
refactor: move rich token validation into identity client
johnwatso Mar 13, 2026
a911361
refactor: extract discord ai service
johnwatso Mar 13, 2026
a25e53e
refactor: extract wiki lookup service
johnwatso Mar 13, 2026
8262579
refactor: extract rule execution service
johnwatso Mar 13, 2026
8fc9d96
refactor: extract discord gateway transport
johnwatso Mar 13, 2026
256b11a
refactor: extract command processor
johnwatso Mar 13, 2026
6c19542
refactor: trim dead command helpers
johnwatso Mar 13, 2026
97cda98
refactor: trim dead discord facade wrappers
johnwatso Mar 13, 2026
93e6c63
refactor: share ai and wiki services
johnwatso Mar 13, 2026
1d12704
refactor: migrate identity rest calls
johnwatso Mar 13, 2026
55f526d
refactor: share message rest client reads
johnwatso Mar 13, 2026
f019060
refactor: share guild rest client reads
johnwatso Mar 13, 2026
2b18b66
refactor: normalize app output helper guards
johnwatso Mar 13, 2026
a87f7b8
refactor: trim dead guild permission wrappers
johnwatso Mar 13, 2026
7b5cdbf
Update project.pbxproj
johnwatso Mar 13, 2026
9d44556
Refactor - Fixed Oauth issues
johnwatso Mar 13, 2026
f1db35e
Last Refactor Commit for 14/03/2026
johnwatso Mar 13, 2026
31b3db5
[Beta]Pre Pull
johnwatso Mar 13, 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
639 changes: 639 additions & 0 deletions ARCHITECTURE_ANALYSIS_REPORT.md

Large diffs are not rendered by default.

719 changes: 719 additions & 0 deletions ARCHITECTURE_ANALYSIS_REPORT_PDF.txt

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,14 @@ public struct AMDUpdateSource: UpdateSource, Sendable {

/// Intel Arc driver update source.
public struct IntelUpdateSource: UpdateSource, Sendable {
public var cacheKey: String { "intel-default" }
public var sourceKey: String { cacheKey }
public let sourceKey: String
private let service: IntelService

public init(service: IntelService = IntelService()) {
public init(
sourceKey: String = CacheKeyBuilder.build(vendor: "Intel", channel: "default"),
service: IntelService = IntelService()
) {
self.sourceKey = sourceKey
self.service = service
}

Expand Down
64 changes: 60 additions & 4 deletions SwiftBot.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

43 changes: 7 additions & 36 deletions SwiftBotApp/AIBotsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,14 @@ struct AIBotsView: View {
@State private var showAppleSettings = false
@State private var showOllamaSettings = false
@State private var showOpenAISettings = false
@State private var baselineSettings = AIBotsSettingsSnapshot()
@State private var baselineSettings = AppPreferencesSnapshot()

private var hasUnsavedChanges: Bool {
currentSettingsSnapshot != baselineSettings
}

private var currentSettingsSnapshot: AIBotsSettingsSnapshot {
AIBotsSettingsSnapshot(
localAIDMReplyEnabled: app.settings.localAIDMReplyEnabled,
useAIInGuildChannels: app.settings.behavior.useAIInGuildChannels,
allowDMs: app.settings.behavior.allowDMs,
preferredAIProvider: app.settings.preferredAIProvider,
ollamaBaseURL: app.settings.ollamaBaseURL,
ollamaModel: app.settings.localAIModel,
ollamaEnabled: app.settings.ollamaEnabled,
openAIEnabled: app.settings.openAIEnabled,
openAIAPIKey: app.settings.openAIAPIKey,
openAIModel: app.settings.openAIModel,
openAIImageGenerationEnabled: app.settings.openAIImageGenerationEnabled,
openAIImageModel: app.settings.openAIImageModel,
openAIImageMonthlyLimitPerUser: app.settings.openAIImageMonthlyLimitPerUser,
localAISystemPrompt: app.settings.localAISystemPrompt
)
private var currentSettingsSnapshot: AppPreferencesSnapshot {
app.createPreferencesSnapshot()
}

var body: some View {
Expand Down Expand Up @@ -60,7 +45,9 @@ struct AIBotsView: View {
if hasUnsavedChanges && !app.isFailoverManagedNode {
StickySaveButton(label: "Save AI Settings", systemImage: "square.and.arrow.down.fill") {
app.saveSettings()
baselineSettings = currentSettingsSnapshot
withAnimation {
baselineSettings = currentSettingsSnapshot
}
}
.padding(.trailing, 22)
.padding(.bottom, 18)
Expand Down Expand Up @@ -559,24 +546,8 @@ private struct EngineStatusStackView: View {
.foregroundStyle(isPrimary ? Color.accentColor : Color.secondary)
}
}
}
}

private struct AIBotsSettingsSnapshot: Equatable {
var localAIDMReplyEnabled = false
var useAIInGuildChannels = true
var allowDMs = false
var preferredAIProvider: AIProviderPreference = .apple
var ollamaBaseURL = ""
var ollamaModel = ""
var ollamaEnabled = true
var openAIEnabled = true
var openAIAPIKey = ""
var openAIModel = ""
var openAIImageGenerationEnabled = true
var openAIImageModel = ""
var openAIImageMonthlyLimitPerUser = 5
var localAISystemPrompt = ""
}

private enum AIEngineStatus {
case online
Expand Down
44 changes: 40 additions & 4 deletions SwiftBotApp/AdminWebServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,9 @@ actor AdminWebServer {
loadPersistedSessions()
let previous = self.config
self.config = config

// Refresh the active public base URL so OAuth redirect URIs pick up config changes immediately.
self.activePublicBaseURL = resolvedPublicBaseURL(usingTLS: activeTransportUsesTLS)

if !config.enabled {
await stop()
Expand Down Expand Up @@ -1567,7 +1570,6 @@ actor AdminWebServer {
)

let uri = redirectURI()
await logger?("[OAuth] Redirect URI: \(uri)")

var components = URLComponents(string: "https://discord.com/oauth2/authorize")
components?.queryItems = [
Expand Down Expand Up @@ -1956,11 +1958,45 @@ actor AdminWebServer {
}

private func redirectURI() -> String {
let resolvedBase = activePublicBaseURL.isEmpty
var resolvedBase = activePublicBaseURL.isEmpty
? resolvedPublicBaseURL(usingTLS: config.https != nil)
: activePublicBaseURL
let base = resolvedBase.hasSuffix("/") ? String(resolvedBase.dropLast()) : resolvedBase
return base + config.redirectPath

// Ensure scheme exists
if !resolvedBase.isEmpty && !resolvedBase.contains("://") {
resolvedBase = "https://" + resolvedBase
}

let path = config.redirectPath.hasPrefix("/") ? config.redirectPath : "/" + config.redirectPath

Task {
await logger?("[OAuth] Constructing redirectURI from base='\(resolvedBase)' and path='\(path)'")
}

guard var components = URLComponents(string: resolvedBase) else {
let fallback = resolvedBase + (resolvedBase.hasSuffix("/") ? String(path.dropFirst()) : path)
Task {
await logger?("[OAuth] redirectURI fallback construction: \(fallback)")
}
return fallback
}

// Handle existing path in base URL (e.g. proxy subpath)
if !components.path.isEmpty && components.path != "/" {
let base_path = components.path.hasSuffix("/") ? String(components.path.dropLast()) : components.path
let sub_path = path.hasPrefix("/") ? path : "/" + path
components.path = base_path + sub_path
} else {
components.path = path
}

let result = components.url?.absoluteString ?? (resolvedBase + (resolvedBase.hasSuffix("/") ? String(path.dropFirst()) : path))

Task {
await logger?("[OAuth] Resulting redirectURI: \(result)")
}

return result
}

private func percentEncode(_ value: String) -> String {
Expand Down
Loading
Loading