soulsync 1.0.10 → 1.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +6 -0
- package/package.json +1 -1
- package/src/client.py +0 -2
- package/src/main.py +210 -172
package/index.js
CHANGED
|
@@ -49,6 +49,12 @@ function startPythonService(mode = '--start') {
|
|
|
49
49
|
pythonProcess.on('close', (code) => {
|
|
50
50
|
console.log(`[SoulSync] Python process exited with code ${code}`);
|
|
51
51
|
pythonProcess = null;
|
|
52
|
+
|
|
53
|
+
// If setup succeeded (code 0), auto-start sync
|
|
54
|
+
if (mode === '--setup' && code === 0) {
|
|
55
|
+
console.log('[SoulSync] Setup completed, starting sync service...');
|
|
56
|
+
startPythonService('--start');
|
|
57
|
+
}
|
|
52
58
|
});
|
|
53
59
|
|
|
54
60
|
pythonProcess.on('error', (err) => {
|
package/package.json
CHANGED
package/src/client.py
CHANGED
package/src/main.py
CHANGED
|
@@ -92,9 +92,16 @@ class SoulSyncPlugin:
|
|
|
92
92
|
except:
|
|
93
93
|
config = {}
|
|
94
94
|
|
|
95
|
-
# 保存 email
|
|
96
|
-
if 'user' in auth_result:
|
|
95
|
+
# 保存 email(支持两种返回格式:authenticate 有 user 对象,register 只有一个字段)
|
|
96
|
+
if 'user' in auth_result and isinstance(auth_result.get('user'), dict):
|
|
97
97
|
config['email'] = auth_result['user'].get('email', '')
|
|
98
|
+
elif 'email' in auth_result:
|
|
99
|
+
config['email'] = auth_result.get('email', '')
|
|
100
|
+
|
|
101
|
+
# 保存 password(注册时输入的密码,需要保存以便自动登录)
|
|
102
|
+
# 注意:登录时我们只有从 config 读取的 password
|
|
103
|
+
if 'password' in auth_result:
|
|
104
|
+
config['password'] = auth_result.get('password', '')
|
|
98
105
|
|
|
99
106
|
# 保存 token
|
|
100
107
|
if 'token' in auth_result:
|
|
@@ -106,151 +113,168 @@ class SoulSyncPlugin:
|
|
|
106
113
|
print("[SoulSync] Auth info saved to config.json")
|
|
107
114
|
|
|
108
115
|
def run_setup(self):
|
|
109
|
-
"""
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
116
|
+
"""交互式设置:注册或登录(带循环)"""
|
|
117
|
+
while True:
|
|
118
|
+
print("\n[SoulSync] ========================================")
|
|
119
|
+
print("[SoulSync] Welcome to SoulSync! / 欢迎使用 SoulSync!")
|
|
120
|
+
print("[SoulSync] ========================================")
|
|
121
|
+
print("[SoulSync] 1. Register / 注册")
|
|
122
|
+
print("[SoulSync] 2. Login / 登录")
|
|
123
|
+
print("[SoulSync] 0. Exit / 退出")
|
|
124
|
+
print("[SoulSync] ========================================")
|
|
125
|
+
|
|
126
|
+
try:
|
|
127
|
+
choice = input("[SoulSync] Choose / 选择 (0/1/2): ").strip()
|
|
128
|
+
except KeyboardInterrupt:
|
|
129
|
+
print("\n[SoulSync] Cancelled by user. Goodbye! / 已取消,再见!")
|
|
130
|
+
sys.exit(0)
|
|
131
|
+
|
|
132
|
+
if choice == '1':
|
|
133
|
+
result = self._interactive_register()
|
|
134
|
+
if result:
|
|
135
|
+
return result
|
|
136
|
+
elif choice == '2':
|
|
137
|
+
result = self._interactive_login()
|
|
138
|
+
if result:
|
|
139
|
+
return result
|
|
140
|
+
elif choice == '0':
|
|
141
|
+
print("[SoulSync] Goodbye! / 再见!")
|
|
142
|
+
sys.exit(2)
|
|
143
|
+
else:
|
|
144
|
+
print("[SoulSync] Invalid choice / 无效选择")
|
|
126
145
|
|
|
127
146
|
def _interactive_login(self):
|
|
128
|
-
"""
|
|
147
|
+
"""交互式登录(失败返回 None,由主循环处理)"""
|
|
129
148
|
from client import OpenClawClient
|
|
130
149
|
|
|
131
|
-
|
|
132
|
-
retry_count = 0
|
|
150
|
+
print("\n--- Login / 登录 ---")
|
|
133
151
|
|
|
134
|
-
|
|
135
|
-
print("\n--- Login / 登录 ---")
|
|
152
|
+
try:
|
|
136
153
|
email = input("[SoulSync] Email / 邮箱: ").strip()
|
|
137
154
|
if not email:
|
|
138
155
|
print("[SoulSync] Email cannot be empty / 邮箱不能为空")
|
|
139
|
-
|
|
140
|
-
|
|
156
|
+
return None
|
|
157
|
+
except KeyboardInterrupt:
|
|
158
|
+
print("\n[SoulSync] Cancelled. Returning to menu... / 已取消,返回菜单...")
|
|
159
|
+
return None
|
|
160
|
+
|
|
161
|
+
try:
|
|
141
162
|
password = getpass.getpass("[SoulSync] Password / 密码: ")
|
|
142
163
|
if not password:
|
|
143
164
|
print("[SoulSync] Password cannot be empty / 密码不能为空")
|
|
144
|
-
|
|
165
|
+
return None
|
|
166
|
+
except KeyboardInterrupt:
|
|
167
|
+
print("\n[SoulSync] Cancelled. Returning to menu... / 已取消,返回菜单...")
|
|
168
|
+
return None
|
|
169
|
+
|
|
170
|
+
try:
|
|
171
|
+
temp_client = OpenClawClient(self.config)
|
|
172
|
+
result = temp_client.authenticate(email, password)
|
|
173
|
+
if result:
|
|
174
|
+
result['email'] = email
|
|
175
|
+
result['password'] = password
|
|
176
|
+
print("\n[SoulSync] ✓ Login successful! / 登录成功!")
|
|
177
|
+
self._save_auth_to_config(result)
|
|
178
|
+
return True
|
|
179
|
+
except Exception as e:
|
|
180
|
+
error_msg = str(e)
|
|
145
181
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
remaining = max_retries - retry_count
|
|
156
|
-
error_msg = str(e)
|
|
157
|
-
|
|
158
|
-
if "429" in error_msg or "too many" in error_msg.lower():
|
|
159
|
-
print(f"\n[SoulSync] ❌ {e}")
|
|
160
|
-
print("\n[SoulSync] Too many failed attempts / 登录失败次数过多")
|
|
161
|
-
print("[SoulSync] Exiting... / 退出...")
|
|
162
|
-
sys.exit(0)
|
|
163
|
-
|
|
164
|
-
if remaining > 0:
|
|
165
|
-
print(f"\n[SoulSync] ❌ Login failed: {e} / 登录失败: {e}")
|
|
166
|
-
print(f"[SoulSync] Remaining attempts / 剩余尝试次数: {remaining}")
|
|
167
|
-
else:
|
|
168
|
-
print(f"\n[SoulSync] ❌ Login failed: {e} / 登录失败: {e}")
|
|
182
|
+
if "429" in error_msg or "too many" in error_msg.lower():
|
|
183
|
+
print(f"\n[SoulSync] ❌ {e}")
|
|
184
|
+
print("\n[SoulSync] Too many failed attempts. Please try again later / 登录失败次数过多,请稍后再试")
|
|
185
|
+
print("[SoulSync] Exiting... / 退出...")
|
|
186
|
+
sys.exit(0)
|
|
187
|
+
|
|
188
|
+
print(f"\n[SoulSync] ❌ {e}")
|
|
189
|
+
print("[SoulSync] Returning to menu... / 返回菜单...")
|
|
190
|
+
return None
|
|
169
191
|
|
|
170
|
-
print("
|
|
171
|
-
print("[SoulSync]
|
|
172
|
-
|
|
192
|
+
print("[SoulSync] ❌ Login failed / 登录失败")
|
|
193
|
+
print("[SoulSync] Returning to menu... / 返回菜单...")
|
|
194
|
+
return None
|
|
173
195
|
|
|
174
196
|
def _interactive_register(self):
|
|
175
|
-
"""
|
|
197
|
+
"""交互式注册(失败返回 None)"""
|
|
176
198
|
from client import OpenClawClient
|
|
177
199
|
|
|
178
|
-
|
|
179
|
-
retry_count = 0
|
|
200
|
+
print("\n--- Register / 注册 ---")
|
|
180
201
|
|
|
181
|
-
|
|
182
|
-
print("\n--- Register / 注册 ---")
|
|
202
|
+
try:
|
|
183
203
|
email = input("[SoulSync] Email / 邮箱: ").strip()
|
|
184
204
|
if not email or '@' not in email:
|
|
185
205
|
print("[SoulSync] Invalid email / 无效邮箱")
|
|
186
|
-
|
|
206
|
+
return None
|
|
207
|
+
except KeyboardInterrupt:
|
|
208
|
+
print("\n[SoulSync] Cancelled. Returning to menu... / 已取消,返回菜单...")
|
|
209
|
+
return None
|
|
210
|
+
|
|
211
|
+
password = None
|
|
212
|
+
while password is None:
|
|
213
|
+
try:
|
|
214
|
+
password = getpass.getpass("[SoulSync] Password / 密码: ")
|
|
215
|
+
if len(password) < 6:
|
|
216
|
+
print("[SoulSync] Password must be at least 6 characters / 密码至少6位")
|
|
217
|
+
password = None
|
|
218
|
+
continue
|
|
219
|
+
except KeyboardInterrupt:
|
|
220
|
+
print("\n[SoulSync] Cancelled. Returning to menu... / 已取消,返回菜单...")
|
|
221
|
+
return None
|
|
187
222
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
223
|
+
try:
|
|
224
|
+
password2 = getpass.getpass("[SoulSync] Confirm password / 确认密码: ")
|
|
225
|
+
except KeyboardInterrupt:
|
|
226
|
+
print("\n[SoulSync] Cancelled. Returning to menu... / 已取消,返回菜单...")
|
|
227
|
+
return None
|
|
192
228
|
|
|
193
|
-
password2 = getpass.getpass("[SoulSync] Confirm password / 确认密码: ")
|
|
194
229
|
if password != password2:
|
|
195
230
|
print("[SoulSync] Passwords do not match / 两次密码不一致")
|
|
231
|
+
password = None
|
|
232
|
+
|
|
233
|
+
print(f"\n[SoulSync] Sending verification code to {email}...")
|
|
234
|
+
try:
|
|
235
|
+
temp_client = OpenClawClient(self.config)
|
|
236
|
+
temp_client.send_verification_code(email)
|
|
237
|
+
print("[SoulSync] ✓ Verification code sent! / 验证码已发送!")
|
|
238
|
+
except Exception as e:
|
|
239
|
+
print(f"[SoulSync] ❌ Failed to send code: {e}")
|
|
240
|
+
print("[SoulSync] Returning to menu... / 返回菜单...")
|
|
241
|
+
return None
|
|
242
|
+
|
|
243
|
+
code_success = False
|
|
244
|
+
code_retry = 0
|
|
245
|
+
max_code_retries = 3
|
|
246
|
+
|
|
247
|
+
while code_retry < max_code_retries and not code_success:
|
|
248
|
+
try:
|
|
249
|
+
code = input(f"[SoulSync] Enter code / 输入验证码 ({max_code_retries - code_retry} left): ").strip()
|
|
250
|
+
except KeyboardInterrupt:
|
|
251
|
+
print("\n[SoulSync] Cancelled. Returning to menu... / 已取消,返回菜单...")
|
|
252
|
+
return None
|
|
253
|
+
|
|
254
|
+
if len(code) != 6 or not code.isdigit():
|
|
255
|
+
code_retry += 1
|
|
256
|
+
print("[SoulSync] Invalid code format / 验证码格式错误")
|
|
196
257
|
continue
|
|
197
258
|
|
|
198
|
-
print(f"\n[SoulSync] Sending verification code to {email}...")
|
|
199
259
|
try:
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
260
|
+
result = temp_client.register(email, password, code)
|
|
261
|
+
print("\n[SoulSync] ✓ Registration successful! / 注册成功!")
|
|
262
|
+
self._save_auth_to_config(result)
|
|
263
|
+
return True
|
|
203
264
|
except Exception as e:
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
code = input(f"[SoulSync] Enter code / 输入验证码 ({max_retries - code_retry} attempts left): ").strip()
|
|
210
|
-
if len(code) != 6 or not code.isdigit():
|
|
211
|
-
code_retry += 1
|
|
212
|
-
print("[SoulSync] Invalid code format / 验证码格式错误")
|
|
213
|
-
continue
|
|
214
|
-
|
|
215
|
-
try:
|
|
216
|
-
result = temp_client.register(email, password, code)
|
|
217
|
-
print("\n[SoulSync] ✓ Registration successful! / 注册成功!")
|
|
218
|
-
self._save_auth_to_config(result)
|
|
219
|
-
return True
|
|
220
|
-
except Exception as e:
|
|
221
|
-
code_retry += 1
|
|
222
|
-
remaining_code = max_retries - code_retry
|
|
223
|
-
if "invalid" in str(e).lower() or "expired" in str(e).lower():
|
|
224
|
-
if remaining_code > 0:
|
|
225
|
-
print(f"[SoulSync] ❌ Invalid or expired code: {e}")
|
|
226
|
-
print(f"[SoulSync] Remaining attempts / 剩余尝试: {remaining_code}")
|
|
227
|
-
else:
|
|
228
|
-
print("[SoulSync] ❌ Too many code attempts / 验证码错误次数过多")
|
|
229
|
-
break
|
|
265
|
+
code_retry += 1
|
|
266
|
+
if "invalid" in str(e).lower() or "expired" in str(e).lower():
|
|
267
|
+
if code_retry < max_code_retries:
|
|
268
|
+
print(f"[SoulSync] ❌ Invalid or expired code: {e}")
|
|
269
|
+
print(f"[SoulSync] Remaining attempts / 剩余尝试: {max_code_retries - code_retry}")
|
|
230
270
|
else:
|
|
231
|
-
print(
|
|
232
|
-
break
|
|
233
|
-
|
|
234
|
-
if code_retry >= max_retries:
|
|
235
|
-
print("\n[SoulSync] Too many code verification failures.")
|
|
236
|
-
print("[SoulSync] 1. Resend code / 重新发送验证码")
|
|
237
|
-
print("[SoulSync] 2. Start over / 重新开始")
|
|
238
|
-
print("[SoulSync] 3. Exit / 退出")
|
|
239
|
-
|
|
240
|
-
sub_choice = input("[SoulSync] Choose / 选择 (1/2/3): ").strip()
|
|
241
|
-
if sub_choice == '1':
|
|
242
|
-
retry_count = 0
|
|
243
|
-
continue
|
|
244
|
-
elif sub_choice == '2':
|
|
245
|
-
retry_count = 0
|
|
246
|
-
break
|
|
271
|
+
print("[SoulSync] ❌ Too many code attempts / 验证码错误次数过多")
|
|
247
272
|
else:
|
|
248
|
-
print("[SoulSync]
|
|
249
|
-
sys.exit(0)
|
|
273
|
+
print(f"[SoulSync] ❌ Registration failed: {e}")
|
|
250
274
|
|
|
251
|
-
print("\n[SoulSync]
|
|
252
|
-
print("[SoulSync]
|
|
253
|
-
|
|
275
|
+
print("\n[SoulSync] Too many code verification failures.")
|
|
276
|
+
print("[SoulSync] Returning to menu... / 返回菜单...")
|
|
277
|
+
return None
|
|
254
278
|
|
|
255
279
|
def initialize(self):
|
|
256
280
|
"""初始化组件"""
|
|
@@ -277,22 +301,23 @@ class SoulSyncPlugin:
|
|
|
277
301
|
try:
|
|
278
302
|
result = self.client.authenticate(email, password)
|
|
279
303
|
if result:
|
|
304
|
+
result['email'] = email
|
|
305
|
+
result['password'] = password
|
|
280
306
|
print("[SoulSync] Login successful! / 登录成功!")
|
|
281
307
|
self._save_auth_to_config(result)
|
|
282
308
|
token = self.client.token
|
|
283
309
|
except Exception as e:
|
|
284
310
|
error_msg = str(e)
|
|
285
|
-
print(f"[SoulSync] Login failed: {e}")
|
|
286
311
|
|
|
287
312
|
if "429" in error_msg or "too many" in error_msg.lower():
|
|
288
313
|
print("\n[SoulSync] ========================================")
|
|
314
|
+
print(f"[SoulSync] ❌ {e}")
|
|
289
315
|
print("[SoulSync] Too many failed attempts. Please try again later / 登录失败次数过多,请稍后再试")
|
|
290
316
|
print("[SoulSync] ========================================\n")
|
|
291
317
|
else:
|
|
292
318
|
print("\n[SoulSync] ========================================")
|
|
293
|
-
print("[SoulSync]
|
|
294
|
-
print("[SoulSync] Please
|
|
295
|
-
print(f" {os.path.normpath(os.path.join(PLUGIN_DIR, 'config.json'))}")
|
|
319
|
+
print(f"[SoulSync] ❌ {e}")
|
|
320
|
+
print("[SoulSync] Please run 'openclaw soulsync:setup' to reconfigure / 请运行 'openclaw soulsync:setup' 重新配置")
|
|
296
321
|
print("[SoulSync] ========================================\n")
|
|
297
322
|
|
|
298
323
|
sys.exit(0)
|
|
@@ -323,13 +348,13 @@ class SoulSyncPlugin:
|
|
|
323
348
|
self.config.get('workspace')
|
|
324
349
|
)
|
|
325
350
|
|
|
326
|
-
print("Pulling all profiles from cloud...")
|
|
351
|
+
print("[SoulSync] Pulling all profiles from cloud...")
|
|
327
352
|
try:
|
|
328
353
|
self.profile_sync.pull_all()
|
|
329
354
|
except Exception as e:
|
|
330
|
-
print(f"Warning: Could not pull profiles: {e}")
|
|
355
|
+
print(f"[SoulSync] Warning: Could not pull profiles: {e}")
|
|
331
356
|
|
|
332
|
-
print("\
|
|
357
|
+
print("\n[SoulSync] Starting file watcher...")
|
|
333
358
|
watch_files = self.config.get('watch_files', [])
|
|
334
359
|
self.watcher = OpenClawMultiWatcher(
|
|
335
360
|
self.config.get('workspace'),
|
|
@@ -338,29 +363,29 @@ class SoulSyncPlugin:
|
|
|
338
363
|
)
|
|
339
364
|
self.watcher.start()
|
|
340
365
|
|
|
341
|
-
print("\
|
|
366
|
+
print("\n[SoulSync] Connecting to WebSocket...")
|
|
342
367
|
try:
|
|
343
368
|
self.client.connect_websocket(self.on_websocket_message)
|
|
344
369
|
except Exception as e:
|
|
345
|
-
print(f"Warning: Could not connect WebSocket: {e}")
|
|
370
|
+
print(f"[SoulSync] Warning: Could not connect WebSocket: {e}")
|
|
346
371
|
|
|
347
372
|
self.running = True
|
|
348
373
|
|
|
349
374
|
def on_file_change(self, event_type: str, relative_path: str, absolute_path: str = None):
|
|
350
375
|
"""文件变化回调"""
|
|
351
|
-
print(f"\n[File {event_type}] {relative_path}")
|
|
376
|
+
print(f"\n[SoulSync] [File {event_type}] {relative_path}")
|
|
352
377
|
|
|
353
378
|
if event_type in ['modified', 'created']:
|
|
354
379
|
time.sleep(0.5)
|
|
355
380
|
|
|
356
381
|
try:
|
|
357
382
|
self.profile_sync.push_file(relative_path)
|
|
358
|
-
print(f"Upload completed: {relative_path}")
|
|
383
|
+
print(f"[SoulSync] Upload completed: {relative_path}")
|
|
359
384
|
except Exception as e:
|
|
360
|
-
print(f"Upload error: {e}")
|
|
385
|
+
print(f"[SoulSync] Upload error: {e}")
|
|
361
386
|
|
|
362
387
|
elif event_type == 'deleted':
|
|
363
|
-
print(f"File deleted (not synced to cloud): {relative_path}")
|
|
388
|
+
print(f"[SoulSync] File deleted (not synced to cloud): {relative_path}")
|
|
364
389
|
|
|
365
390
|
def on_websocket_message(self, data: dict):
|
|
366
391
|
"""WebSocket 消息回调"""
|
|
@@ -369,24 +394,24 @@ class SoulSyncPlugin:
|
|
|
369
394
|
if event == 'file_updated':
|
|
370
395
|
file_path = data.get('file_path')
|
|
371
396
|
version = data.get('version')
|
|
372
|
-
print(f"\n[WebSocket] File updated: {file_path} (v{version})")
|
|
397
|
+
print(f"\n[SoulSync] [WebSocket] File updated: {file_path} (v{version})")
|
|
373
398
|
try:
|
|
374
399
|
self.profile_sync.on_remote_change(file_path, version)
|
|
375
400
|
except Exception as e:
|
|
376
|
-
print(f"Sync error: {e}")
|
|
401
|
+
print(f"[SoulSync] Sync error: {e}")
|
|
377
402
|
|
|
378
403
|
elif event == 'new_memory':
|
|
379
|
-
print(f"\n[WebSocket] New memory available!")
|
|
404
|
+
print(f"\n[SoulSync] [WebSocket] New memory available!")
|
|
380
405
|
try:
|
|
381
406
|
self.profile_sync.pull_all()
|
|
382
|
-
print("Memory synced from remote")
|
|
407
|
+
print("[SoulSync] Memory synced from remote")
|
|
383
408
|
except Exception as e:
|
|
384
|
-
print(f"Sync error: {e}")
|
|
409
|
+
print(f"[SoulSync] Sync error: {e}")
|
|
385
410
|
|
|
386
411
|
elif data.get('type') == 'authenticated':
|
|
387
|
-
print(f"[WebSocket] Authenticated, socket_id: {data.get('socket_id')}")
|
|
412
|
+
print(f"[SoulSync] [WebSocket] Authenticated, socket_id: {data.get('socket_id')}")
|
|
388
413
|
elif data.get('type') == 'error':
|
|
389
|
-
print(f"[WebSocket] Error: {data.get('message')}")
|
|
414
|
+
print(f"[SoulSync] [WebSocket] Error: {data.get('message')}")
|
|
390
415
|
|
|
391
416
|
def run(self):
|
|
392
417
|
"""运行插件"""
|
|
@@ -398,17 +423,17 @@ class SoulSyncPlugin:
|
|
|
398
423
|
self.load_config()
|
|
399
424
|
self.initialize()
|
|
400
425
|
|
|
401
|
-
print("\n=== Plugin Running ===")
|
|
402
|
-
print("Press Ctrl+C to stop\n")
|
|
426
|
+
print("\n[SoulSync] === Plugin Running ===")
|
|
427
|
+
print("[SoulSync] Press Ctrl+C to stop\n")
|
|
403
428
|
|
|
404
429
|
while self.running:
|
|
405
430
|
time.sleep(1)
|
|
406
431
|
|
|
407
432
|
except KeyboardInterrupt:
|
|
408
|
-
print("\n
|
|
433
|
+
print("\n[SoulSync] Shutting down...")
|
|
409
434
|
self.shutdown()
|
|
410
435
|
except Exception as e:
|
|
411
|
-
print(f"\
|
|
436
|
+
print(f"\n[SoulSync] Error: {e}")
|
|
412
437
|
import traceback
|
|
413
438
|
traceback.print_exc()
|
|
414
439
|
self.shutdown()
|
|
@@ -416,54 +441,67 @@ class SoulSyncPlugin:
|
|
|
416
441
|
|
|
417
442
|
def shutdown(self):
|
|
418
443
|
"""关闭插件"""
|
|
419
|
-
print("Shutting down SoulSync plugin...")
|
|
444
|
+
print("[SoulSync] Shutting down SoulSync plugin...")
|
|
420
445
|
self.running = False
|
|
421
446
|
|
|
422
447
|
if self.watcher:
|
|
423
448
|
try:
|
|
424
449
|
self.watcher.stop()
|
|
425
|
-
print("File watcher stopped")
|
|
450
|
+
print("[SoulSync] File watcher stopped")
|
|
426
451
|
except Exception as e:
|
|
427
|
-
print(f"Error stopping watcher: {e}")
|
|
452
|
+
print(f"[SoulSync] Error stopping watcher: {e}")
|
|
428
453
|
|
|
429
454
|
if self.client:
|
|
430
455
|
try:
|
|
431
456
|
self.client.close()
|
|
432
|
-
print("Client connection closed")
|
|
457
|
+
print("[SoulSync] Client connection closed")
|
|
433
458
|
except Exception as e:
|
|
434
|
-
print(f"Error closing client: {e}")
|
|
459
|
+
print(f"[SoulSync] Error closing client: {e}")
|
|
435
460
|
|
|
436
|
-
print("Plugin shutdown complete")
|
|
461
|
+
print("[SoulSync] Plugin shutdown complete")
|
|
437
462
|
def main():
|
|
438
463
|
"""主函数"""
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
464
|
+
try:
|
|
465
|
+
parser = argparse.ArgumentParser(description='SoulSync Plugin')
|
|
466
|
+
parser.add_argument('--setup', action='store_true', help='Run interactive setup (register/login)')
|
|
467
|
+
parser.add_argument('--start', action='store_true', help='Start sync service (auto-login from config)')
|
|
468
|
+
|
|
469
|
+
args = parser.parse_args()
|
|
470
|
+
|
|
471
|
+
plugin = SoulSyncPlugin()
|
|
472
|
+
|
|
473
|
+
if args.setup:
|
|
474
|
+
try:
|
|
475
|
+
plugin.load_config()
|
|
476
|
+
result = plugin.run_setup()
|
|
477
|
+
if result:
|
|
478
|
+
print("\n[SoulSync] ✓ Setup complete! Starting sync... / 设置完成!正在启动同步...")
|
|
479
|
+
print("\n[SoulSync] ========================================")
|
|
480
|
+
print("[SoulSync] Starting SoulSync sync service...")
|
|
481
|
+
print("[SoulSync] ========================================\n")
|
|
482
|
+
plugin.initialize()
|
|
483
|
+
plugin.run()
|
|
484
|
+
return
|
|
485
|
+
except KeyboardInterrupt:
|
|
486
|
+
print("\n[SoulSync] Cancelled by user. Goodbye! / 已取消,再见!")
|
|
487
|
+
sys.exit(2)
|
|
488
|
+
|
|
448
489
|
plugin.load_config()
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
print("[SoulSync]
|
|
490
|
+
|
|
491
|
+
email = plugin.config.get('email', '').strip()
|
|
492
|
+
password = plugin.config.get('password', '').strip()
|
|
493
|
+
|
|
494
|
+
if not email or not password:
|
|
495
|
+
print("\n[SoulSync] ========================================")
|
|
496
|
+
print("[SoulSync] Not configured. Run 'openclaw soulsync:setup' first.")
|
|
497
|
+
print("[SoulSync] 尚未配置,请先运行 'openclaw soulsync:setup'")
|
|
498
|
+
print("[SoulSync] ========================================\n")
|
|
499
|
+
sys.exit(0)
|
|
500
|
+
|
|
501
|
+
plugin.initialize()
|
|
502
|
+
plugin.run()
|
|
503
|
+
except KeyboardInterrupt:
|
|
504
|
+
print("\n[SoulSync] Cancelled by user. Goodbye! / 已取消,再见!")
|
|
464
505
|
sys.exit(0)
|
|
465
|
-
|
|
466
|
-
plugin.initialize()
|
|
467
|
-
plugin.run()
|
|
468
506
|
if __name__ == '__main__':
|
|
469
507
|
main()
|