Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita50045a

Browse files
committed
Pre-release 0.32.110
1 parent98e2f48 commita50045a

File tree

68 files changed

+2552
-445
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+2552
-445
lines changed

‎.github/actions/set-xcode-version/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ inputs:
66
Xcode version to use, in semver(ish)-style matching the format on the Actions runner image.
77
See available versions at https://github.com/actions/runner-images/blame/main/images/macos/macos-14-Readme.md#xcode
88
required:false
9-
default:'15.3'
9+
default:'16.2'
1010
outputs:
1111
xcode-path:
1212
description:"Path to current Xcode version"

‎CommunicationBridge/ServiceDelegate.swift

Lines changed: 93 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -136,28 +136,100 @@ actor ExtensionServiceLauncher {
136136
isLaunching=true
137137

138138
Logger.communicationBridge.info("Launching extension service app.")
139-
140-
NSWorkspace.shared.openApplication(
141-
at: appURL,
142-
configuration:{
143-
letconfiguration=NSWorkspace.OpenConfiguration()
144-
configuration.createsNewApplicationInstance=false
145-
configuration.addsToRecentItems=false
146-
configuration.activates=false
147-
return configuration
148-
}()
149-
){ app, errorin
150-
iflet error= error{
151-
Logger.communicationBridge.error(
152-
"Failed to launch extension service app:\(error)"
153-
)
154-
}else{
155-
Logger.communicationBridge.info(
156-
"Finished launching extension service app."
157-
)
139+
140+
// First check if the app is already running
141+
iflet runningApp=NSWorkspace.shared.runningApplications.first(where:{
142+
$0.bundleIdentifier== appIdentifier
143+
}){
144+
Logger.communicationBridge.info("Extension service app already running with PID:\(runningApp.processIdentifier)")
145+
self.application= runningApp
146+
self.isLaunching=false
147+
return
148+
}
149+
150+
// Implement a retry mechanism with exponential backoff
151+
Task{
152+
varretryCount=0
153+
letmaxRetries=3
154+
varsuccess=false
155+
156+
while !success && retryCount< maxRetries{
157+
do{
158+
// Add a delay between retries with exponential backoff
159+
if retryCount>0{
160+
letdelaySeconds=pow(2.0,Double(retryCount-1))
161+
Logger.communicationBridge.info("Retrying launch after\(delaySeconds) seconds (attempt\(retryCount+1) of\(maxRetries))")
162+
tryawaitTask.sleep(nanoseconds:UInt64(delaySeconds*1_000_000_000))
163+
}
164+
165+
// Use a task-based approach for launching with timeout
166+
letlaunchTask=Task<NSRunningApplication?,Error>{()->NSRunningApplication?in
167+
returnawaitwithCheckedContinuation{ continuationin
168+
NSWorkspace.shared.openApplication(
169+
at: appURL,
170+
configuration:{
171+
letconfiguration=NSWorkspace.OpenConfiguration()
172+
configuration.createsNewApplicationInstance=false
173+
configuration.addsToRecentItems=false
174+
configuration.activates=false
175+
return configuration
176+
}()
177+
){ app, errorin
178+
iflet error= error{
179+
continuation.resume(returning:nil)
180+
}else{
181+
continuation.resume(returning: app)
182+
}
183+
}
184+
}
185+
}
186+
187+
// Set a timeout for the launch operation
188+
lettimeoutTask=Task{
189+
tryawaitTask.sleep(nanoseconds:10_000_000_000) // 10 seconds
190+
return
191+
}
192+
193+
// Wait for either the launch or the timeout
194+
letapp=tryawaitwithTaskCancellationHandler{
195+
tryawait launchTask.value??nil
196+
} onCancel:{
197+
launchTask.cancel()
198+
}
199+
200+
// Cancel the timeout task
201+
timeoutTask.cancel()
202+
203+
iflet app= app{
204+
// Success!
205+
self.application= app
206+
success=true
207+
break
208+
}else{
209+
// App is nil, retry
210+
retryCount+=1
211+
Logger.communicationBridge.info("Launch attempt\(retryCount) failed, app is nil")
212+
}
213+
}catch{
214+
retryCount+=1
215+
Logger.communicationBridge.error("Error during launch attempt\(retryCount):\(error.localizedDescription)")
216+
}
158217
}
159-
160-
self.application= app
218+
219+
// Double-check we have a valid application
220+
if !success &&self.application==nil{
221+
// After all retries, check once more if the app is running (it might have launched but we missed the callback)
222+
iflet runningApp=NSWorkspace.shared.runningApplications.first(where:{
223+
$0.bundleIdentifier== appIdentifier
224+
}){
225+
Logger.communicationBridge.info("Found running extension service after retries:\(runningApp.processIdentifier)")
226+
self.application= runningApp
227+
success=true
228+
}else{
229+
Logger.communicationBridge.info("Failed to launch extension service after\(maxRetries) attempts")
230+
}
231+
}
232+
161233
self.isLaunching=false
162234
}
163235
}

‎Copilot for Xcode/App.swift

Lines changed: 126 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,113 @@
1+
import SwiftUI
12
import Client
23
import HostApp
34
import LaunchAgentManager
45
import SharedUIComponents
5-
import SwiftUI
66
import UpdateChecker
77
import XPCShared
8+
import HostAppActivator
89

910
structVisualEffect:NSViewRepresentable{
1011
func makeNSView(context:Self.Context)->NSView{returnNSVisualEffectView()}
1112
func updateNSView(_ nsView:NSView, context:Context){}
1213
}
1314

1415
classAppDelegate:NSObject,NSApplicationDelegate{
15-
func applicationShouldTerminateAfterLastWindowClosed(_:NSApplication)->Bool{true}
16+
// Launch modes supported by the app
17+
enumLaunchMode{
18+
case chat
19+
case settings
20+
}
21+
22+
func applicationDidFinishLaunching(_ notification:Notification){
23+
letlaunchMode=determineLaunchMode()
24+
handleLaunchMode(launchMode)
25+
}
26+
27+
func applicationShouldHandleReopen(_ sender:NSApplication, hasVisibleWindows flag:Bool)->Bool{
28+
letlaunchMode=determineLaunchMode()
29+
handleLaunchMode(launchMode)
30+
returntrue
31+
}
32+
33+
// MARK: - Helper Methods
34+
35+
privatefunc determineLaunchMode()->LaunchMode{
36+
letlaunchArgs=CommandLine.arguments
37+
if launchArgs.contains("--settings"){
38+
return.settings
39+
}else{
40+
return.chat
41+
}
42+
}
43+
44+
privatefunc handleLaunchMode(_ mode:LaunchMode){
45+
switch mode{
46+
case.settings:
47+
openSettings()
48+
case.chat:
49+
openChat()
50+
}
51+
}
52+
53+
privatefunc openSettings(){
54+
DispatchQueue.main.async{
55+
NSApp.activate(ignoringOtherApps:true)
56+
if #available(macOS14.0,*){
57+
letenvironment=SettingsEnvironment()
58+
environment.open()
59+
}elseif #available(macOS13.0,*){
60+
NSApp.sendAction(Selector(("showSettingsWindow:")), to:nil, from:nil)
61+
}else{
62+
NSApp.sendAction(Selector(("showPreferencesWindow:")), to:nil, from:nil)
63+
}
64+
}
65+
}
66+
67+
privatefunc openChat(){
68+
DispatchQueue.main.asyncAfter(deadline:.now()+0.5){
69+
Task{
70+
letservice=try?getService()
71+
try?await service?.openChat()
72+
}
73+
}
74+
}
75+
76+
// MARK: - Application Termination
77+
78+
func applicationShouldTerminate(_ sender:NSApplication)->NSApplication.TerminateReply{
79+
// Immediately terminate extension service if it's running
80+
iflet extensionService=NSWorkspace.shared.runningApplications.first(where:{
81+
$0.bundleIdentifier=="\(Bundle.main.bundleIdentifier!).ExtensionService"
82+
}){
83+
extensionService.terminate()
84+
}
85+
86+
// Start cleanup in background without waiting
87+
Task{
88+
letquitTask=Task{
89+
letservice=try?getService()
90+
try?await service?.quitService()
91+
}
92+
93+
// Wait just a tiny bit to allow cleanup to start
94+
try?awaitTask.sleep(nanoseconds:100_000_000) // 100ms
95+
96+
DispatchQueue.main.async{
97+
NSApp.reply(toApplicationShouldTerminate:true)
98+
}
99+
}
100+
101+
return.terminateLater
102+
}
103+
104+
func applicationWillTerminate(_ notification:Notification){
105+
iflet extensionService=NSWorkspace.shared.runningApplications.first(where:{
106+
$0.bundleIdentifier=="\(Bundle.main.bundleIdentifier!).ExtensionService"
107+
}){
108+
extensionService.terminate()
109+
}
110+
}
16111
}
17112

18113
classAppUpdateCheckerDelegate:UpdateCheckerDelegate{
@@ -28,16 +123,40 @@ class AppUpdateCheckerDelegate: UpdateCheckerDelegate {
28123
@main
29124
structCopilotForXcodeApp:App{
30125
@NSApplicationDelegateAdaptorprivatevarappDelegate:AppDelegate
126+
127+
init(){
128+
UserDefaults.setupDefaultSettings()
129+
130+
Task{
131+
await hostAppStore
132+
.send(.general(.setupLaunchAgentIfNeeded))
133+
.finish()
134+
}
135+
136+
DistributedNotificationCenter.default().addObserver(
137+
forName:.openSettingsWindowRequest,
138+
object:nil,
139+
queue:.main
140+
){ _in
141+
DispatchQueue.main.async{
142+
NSApp.activate(ignoringOtherApps:true)
143+
if #available(macOS14.0,*){
144+
letenvironment=SettingsEnvironment()
145+
environment.open()
146+
}elseif #available(macOS13.0,*){
147+
NSApp.sendAction(Selector(("showSettingsWindow:")), to:nil, from:nil)
148+
}else{
149+
NSApp.sendAction(Selector(("showPreferencesWindow:")), to:nil, from:nil)
150+
}
151+
}
152+
}
153+
}
31154

32155
varbody:someScene{
33-
WindowGroup{
156+
Settings{
34157
TabContainer()
35158
.frame(minWidth:800, minHeight:600)
36159
.background(VisualEffect().ignoresSafeArea())
37-
.onAppear{
38-
UserDefaults.setupDefaultSettings()
39-
}
40-
.copilotIntroSheet()
41160
.environment(\.updateChecker,UpdateChecker(
42161
hostBundle:Bundle.main,
43162
checkerDelegate:AppUpdateCheckerDelegate()

‎Copilot for Xcode/Assets.xcassets/ChatIcon.imageset/Chat.svg

Lines changed: 0 additions & 10 deletions
This file was deleted.
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
{
22
"images" : [
33
{
4-
"filename" :"Chat.svg",
4+
"filename" :"ChatIcon.svg",
55
"idiom" :"universal"
66
}
77
],
88
"info" : {
99
"author" :"xcode",
1010
"version" :1
11+
},
12+
"properties" : {
13+
"preserves-vector-representation" :true
1114
}
1215
}

‎Core/Package.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,12 @@ let package = Package(
178178
.product(name:"AXHelper",package:"Tool"),
179179
.product(name:"ConversationServiceProvider",package:"Tool"),
180180
.product(name:"GitHubCopilotService",package:"Tool"),
181+
.product(name:"Workspace",package:"Tool")
181182
]),
183+
.testTarget(
184+
name:"ChatServiceTests",
185+
dependencies:["ChatService"]
186+
),
182187

183188
.target(
184189
name:"ConversationTab",
@@ -196,10 +201,6 @@ let package = Package(
196201
.product(name:"Persist",package:"Tool")
197202
]
198203
),
199-
.testTarget(
200-
name:"ConversationTabTests",
201-
dependencies:["ConversationTab"]
202-
),
203204

204205
// MARK: - UI
205206

@@ -218,6 +219,7 @@ let package = Package(
218219
.product(name:"ChatTab",package:"Tool"),
219220
.product(name:"Logger",package:"Tool"),
220221
.product(name:"CustomAsyncAlgorithms",package:"Tool"),
222+
.product(name:"HostAppActivator",package:"Tool"),
221223
.product(name:"AsyncAlgorithms",package:"swift-async-algorithms"),
222224
.product(name:"MarkdownUI",package:"swift-markdown-ui"),
223225
.product(name:"ComposableArchitecture",package:"swift-composable-architecture"),

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp