Merge d0eb74195a into 4583f88626
This commit is contained in:
commit
eb0cfc4cf5
@ -67,7 +67,7 @@ private struct EventRow: View {
|
||||
|
||||
private var tint: Color {
|
||||
switch self.event.stream {
|
||||
case "job": .blue
|
||||
case "lifecycle": .blue
|
||||
case "tool": .orange
|
||||
case "assistant": .green
|
||||
default: .gray
|
||||
|
||||
@ -379,8 +379,11 @@ final class ControlChannel {
|
||||
let sessionKey = (event.data["sessionKey"]?.value as? String) ?? "main"
|
||||
|
||||
switch event.stream.lowercased() {
|
||||
case "job":
|
||||
if let state = event.data["state"]?.value as? String {
|
||||
case "lifecycle":
|
||||
// Gateway emits phase: "start" | "end" | "error"
|
||||
// WorkActivityStore expects state: "started" | "streaming" | (anything else = done)
|
||||
if let phase = event.data["phase"]?.value as? String {
|
||||
let state = phase.lowercased() == "start" ? "started" : "done"
|
||||
WorkActivityStore.shared.handleJob(sessionKey: sessionKey, state: state)
|
||||
}
|
||||
case "tool":
|
||||
|
||||
@ -6,6 +6,43 @@ public enum ChatMarkdownVariant: String, CaseIterable, Sendable {
|
||||
case compact
|
||||
}
|
||||
|
||||
/// Check if the Textual package's resource bundle is available.
|
||||
/// When running from a packaged app, the bundle may not be in the expected location,
|
||||
/// causing a fatal error when StructuredText tries to access Bundle.module.
|
||||
private let textualBundleAvailable: Bool = {
|
||||
// The Textual package looks for its bundle at specific paths.
|
||||
// Check if we can find it before attempting to use StructuredText.
|
||||
let bundleName = "textual_Textual.bundle"
|
||||
|
||||
// Check in main bundle (packaged app)
|
||||
if Bundle.main.path(forResource: "textual_Textual", ofType: "bundle") != nil {
|
||||
return true
|
||||
}
|
||||
|
||||
// Check in app's PlugIns or Frameworks directories
|
||||
if let pluginsURL = Bundle.main.builtInPlugInsURL,
|
||||
FileManager.default.fileExists(atPath: pluginsURL.appendingPathComponent(bundleName).path)
|
||||
{
|
||||
return true
|
||||
}
|
||||
|
||||
if let frameworksURL = Bundle.main.privateFrameworksURL,
|
||||
FileManager.default.fileExists(atPath: frameworksURL.appendingPathComponent(bundleName).path)
|
||||
{
|
||||
return true
|
||||
}
|
||||
|
||||
// In development (SwiftPM), Bundle.module should work
|
||||
// We can't directly test Bundle.module without triggering the crash,
|
||||
// so we check for a known development path pattern
|
||||
#if DEBUG
|
||||
return true
|
||||
#else
|
||||
// In release builds, if we haven't found the bundle, assume it's not available
|
||||
return false
|
||||
#endif
|
||||
}()
|
||||
|
||||
@MainActor
|
||||
struct ChatMarkdownRenderer: View {
|
||||
enum Context {
|
||||
@ -22,12 +59,20 @@ struct ChatMarkdownRenderer: View {
|
||||
var body: some View {
|
||||
let processed = ChatMarkdownPreprocessor.preprocess(markdown: self.text)
|
||||
VStack(alignment: .leading, spacing: 10) {
|
||||
StructuredText(markdown: processed.cleaned)
|
||||
.modifier(ChatMarkdownStyle(
|
||||
variant: self.variant,
|
||||
context: self.context,
|
||||
font: self.font,
|
||||
textColor: self.textColor))
|
||||
if textualBundleAvailable {
|
||||
StructuredText(markdown: processed.cleaned)
|
||||
.modifier(ChatMarkdownStyle(
|
||||
variant: self.variant,
|
||||
context: self.context,
|
||||
font: self.font,
|
||||
textColor: self.textColor))
|
||||
} else {
|
||||
// Fallback: render as plain text when Textual bundle is unavailable
|
||||
Text(processed.cleaned)
|
||||
.font(self.font)
|
||||
.foregroundStyle(self.textColor)
|
||||
.textSelection(.enabled)
|
||||
}
|
||||
|
||||
if !processed.images.isEmpty {
|
||||
InlineImageList(images: processed.images)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user