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
36 changes: 36 additions & 0 deletions SwiftBot.xcodeproj/project.pbxproj

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions SwiftBotApp/AdminWebServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ actor AdminWebServer {
var redirectPath: String
var allowedUserIDs: [String]
var remoteAccessToken: String
var devFeaturesEnabled: Bool
}

private struct HTTPRequest {
Expand Down Expand Up @@ -407,7 +408,8 @@ actor AdminWebServer {
localAuthPassword: "",
redirectPath: "/auth/discord/callback",
allowedUserIDs: [],
remoteAccessToken: ""
remoteAccessToken: "",
devFeaturesEnabled: false
)
private var listener: NWListener?
private var nioChannel: Channel?
Expand Down Expand Up @@ -1710,10 +1712,12 @@ actor AdminWebServer {
config.localAuthEnabled &&
!config.localAuthUsername.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty &&
!config.localAuthPassword.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
let devFeaturesEnabled = config.devFeaturesEnabled

return jsonResponse([
"discordEnabled": discordConfigured,
"localEnabled": localEnabled
"localEnabled": localEnabled && devFeaturesEnabled,
"devFeaturesEnabled": devFeaturesEnabled
])
}

Expand Down
125 changes: 75 additions & 50 deletions SwiftBotApp/AppModel+CommandProcessor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,18 @@ extension AppModel {
func makeCommandProcessor() -> CommandProcessor {
CommandProcessor(
dependencies: .init(
configuration: { [unowned self] in
.init(
configuration: { [weak self] in
guard let self else {
return .init(
commandsEnabled: false,
prefixCommandsEnabled: false,
slashCommandsEnabled: false,
wikiEnabled: false,
prefix: "/",
helpSettings: .init()
)
}
return .init(
commandsEnabled: self.settings.commandsEnabled,
prefixCommandsEnabled: self.settings.prefixCommandsEnabled,
slashCommandsEnabled: self.settings.slashCommandsEnabled,
Expand All @@ -14,107 +24,122 @@ extension AppModel {
helpSettings: self.settings.help
)
},
canonicalPrefixCommandName: { [unowned self] name in
self.canonicalPrefixCommandName(name)
canonicalPrefixCommandName: { [weak self] name in
self?.canonicalPrefixCommandName(name) ?? name
},
isCommandEnabled: { [unowned self] name, surface in
self.isCommandEnabled(name: name, surface: surface)
isCommandEnabled: { [weak self] name, surface in
self?.isCommandEnabled(name: name, surface: surface) ?? false
},
buildHelpCatalog: { [unowned self] prefix in
self.buildHelpCatalog(prefix: prefix)
buildHelpCatalog: { [weak self] prefix in
self?.buildHelpCatalog(prefix: prefix) ?? CommandCatalog(entries: [])
},
send: { [unowned self] channelId, message in
await self.send(channelId, message)
send: { [weak self] channelId, message in
guard let self else { return false }
return await self.send(channelId, message)
},
sendEmbed: { [unowned self] channelId, embed in
await self.sendEmbed(channelId, embed: embed)
sendEmbed: { [weak self] channelId, embed in
guard let self else { return false }
return await self.sendEmbed(channelId, embed: embed)
},
generateHelpReply: { [unowned self] messages, systemPrompt in
await self.aiService.generateHelpReply(messages: messages, systemPrompt: systemPrompt)
generateHelpReply: { [weak self] messages, systemPrompt in
guard let self else { return nil }
return await self.aiService.generateHelpReply(messages: messages, systemPrompt: systemPrompt)
},
rollDice: { [unowned self] notation in
self.rollDice(notation)
rollDice: { [weak self] notation in
self?.rollDice(notation) ?? ""
},
generateImageCommand: { [unowned self] prompt, userId, username, channelId in
await self.generateImageCommand(
generateImageCommand: { [weak self] prompt, userId, username, channelId in
guard let self else { return false }
return await self.generateImageCommand(
prompt: prompt,
userId: userId,
username: username,
channelId: channelId
)
},
authorId: { [unowned self] raw in
self.authorId(from: raw)
authorId: { [weak self] raw in
self?.authorId(from: raw) ?? ""
},
clusterCommand: { [unowned self] action, channelId in
await self.clusterCommand(action: action, channelId: channelId)
clusterCommand: { [weak self] action, channelId in
guard let self else { return false }
return await self.clusterCommand(action: action, channelId: channelId)
},
setNotificationChannel: { [unowned self] raw, channelId in
await self.setNotificationChannel(for: raw, currentChannelId: channelId)
setNotificationChannel: { [weak self] raw, channelId in
guard let self else { return false }
return await self.setNotificationChannel(for: raw, currentChannelId: channelId)
},
updateIgnoredChannels: { [unowned self] tokens, raw, channelId in
await self.updateIgnoredChannels(tokens: tokens, raw: raw, responseChannelId: channelId)
updateIgnoredChannels: { [weak self] tokens, raw, channelId in
guard let self else { return false }
return await self.updateIgnoredChannels(tokens: tokens, raw: raw, responseChannelId: channelId)
},
notifyStatus: { [unowned self] raw, channelId in
await self.notifyStatus(raw: raw, responseChannelId: channelId)
notifyStatus: { [weak self] raw, channelId in
guard let self else { return false }
return await self.notifyStatus(raw: raw, responseChannelId: channelId)
},
canRunDebugCommand: { [unowned self] raw in
await self.canRunDebugCommand(raw: raw)
canRunDebugCommand: { [weak self] raw in
await self?.canRunDebugCommand(raw: raw) ?? false
},
refreshDebugSnapshot: { [unowned self] in
refreshDebugSnapshot: { [weak self] in
guard let self else { return }
await self.pollClusterStatus()
self.clusterSnapshot = await self.cluster.currentSnapshot()
},
debugSummaryEmbed: { [unowned self] in
self.debugSummaryEmbed()
debugSummaryEmbed: { [weak self] in
self?.debugSummaryEmbed() ?? .init()
},
bugReportText: { [unowned self] raw in
self.bugReportText(for: raw)
bugReportText: { [weak self] raw in
self?.bugReportText(for: raw) ?? ""
},
weeklySummary: { [unowned self] in
self.weeklyPlugin?.snapshotSummary() ?? "No data yet."
weeklySummary: { [weak self] in
self?.weeklyPlugin?.snapshotSummary() ?? "No data yet."
},
fetchFinalsMeta: { [unowned self] in
await self.wikiLookupService.fetchFinalsMetaFromSkycoach()
fetchFinalsMeta: { [weak self] in
guard let self else { return nil }
return await self.wikiLookupService.fetchFinalsMetaFromSkycoach()
},
resolveWikiCommand: { [unowned self] name in
self.resolveWikiCommand(named: name).map { ($0.source, $0.command) }
resolveWikiCommand: { [weak self] name in
self?.resolveWikiCommand(named: name).map { ($0.source, $0.command) }
},
defaultWikiCommand: { [unowned self] in
defaultWikiCommand: { [weak self] in
guard let self else { return nil }
for source in self.orderedEnabledWikiSources() {
if let first = source.commands.first(where: \.enabled) {
return (source: source, command: first)
}
}
return nil
},
performWikiLookup: { [unowned self] command, source, query, channelId in
await self.performWikiLookup(
performWikiLookup: { [weak self] command, source, query, channelId in
guard let self else { return false }
return await self.performWikiLookup(
command: command,
source: source,
query: query,
channelId: channelId
)
},
handleLogABugSlash: { [unowned self] raw, username, channelId, errorText in
await self.handleLogABugSlash(
handleLogABugSlash: { [weak self] raw, username, channelId, errorText in
guard let self else { return (ok: false, message: "Bug report failed: app unavailable.") }
return await self.handleLogABugSlash(
raw: raw,
username: username,
channelId: channelId,
errorText: errorText
)
},
handleFeatureRequestSlash: { [unowned self] raw, username, channelId, featureText, reasonText in
await self.handleFeatureRequestSlash(
handleFeatureRequestSlash: { [weak self] raw, username, channelId, featureText, reasonText in
guard let self else { return (ok: false, message: "Feature request failed: app unavailable.") }
return await self.handleFeatureRequestSlash(
raw: raw,
username: username,
channelId: channelId,
featureText: featureText,
reasonText: reasonText
)
},
lookupFinalsWiki: { [unowned self] query in
await self.wikiLookupService.lookupFinalsWiki(query: query)
lookupFinalsWiki: { [weak self] query in
guard let self else { return nil }
return await self.wikiLookupService.lookupFinalsWiki(query: query)
}
)
)
Expand Down
2 changes: 1 addition & 1 deletion SwiftBotApp/AppModel+Commands.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2115,7 +2115,7 @@ extension AppModel {
currentContent: String
) async -> (messages: [Message], wikiContext: String) {
let maxHistory = 8
var recent = await conversationStore.recentMessages(for: scope, limit: maxHistory)
var recent = await conversationStore.recentMessages(in: scope, limit: maxHistory)

if !currentContent.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
recent.append(
Expand Down
Loading
Loading