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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "soulsync",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "description": "SoulSync plugin for OpenClaw - cross-bot memory synchronization",
5
5
  "main": "index.js",
6
6
  "repository": {
package/src/client.py CHANGED
@@ -48,8 +48,6 @@ class OpenClawClient:
48
48
  new_device_id = str(uuid.uuid4())
49
49
  with open(device_id_file, 'w') as f:
50
50
  f.write(new_device_id)
51
-
52
- print(f"Generated new device_id: {new_device_id}")
53
51
  return new_device_id
54
52
 
55
53
  def _save_token(self, token: str):
package/src/main.py CHANGED
@@ -92,9 +92,16 @@ class SoulSyncPlugin:
92
92
  except:
93
93
  config = {}
94
94
 
95
- # 保存 email password(如果 auth_result 包含)
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
- print("\n[SoulSync] ========================================")
111
- print("[SoulSync] Welcome to SoulSync! / 欢迎使用 SoulSync!")
112
- print("[SoulSync] ========================================")
113
- print("[SoulSync] 1. Register / 注册")
114
- print("[SoulSync] 2. Login / 登录")
115
- print("[SoulSync] ========================================")
116
-
117
- choice = input("[SoulSync] Choose / 选择 (1/2): ").strip()
118
-
119
- if choice == '1':
120
- return self._interactive_register()
121
- elif choice == '2':
122
- return self._interactive_login()
123
- else:
124
- print("[SoulSync] Invalid choice / 无效选择")
125
- sys.exit(0)
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
- max_retries = 5
132
- retry_count = 0
150
+ print("\n--- Login / 登录 ---")
133
151
 
134
- while retry_count < max_retries:
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
- continue
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
- continue
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
- try:
147
- temp_client = OpenClawClient(self.config)
148
- result = temp_client.authenticate(email, password)
149
- if result:
150
- print("\n[SoulSync] ✓ Login successful! / 登录成功!")
151
- self._save_auth_to_config(result)
152
- return True
153
- except Exception as e:
154
- retry_count += 1
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("\n[SoulSync] ❌ Too many failed attempts. Please try again in 15 minutes. / 登录失败次数过多,请15分钟后再试")
171
- print("[SoulSync] Exiting... / 退出...")
172
- sys.exit(0)
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
- max_retries = 5
179
- retry_count = 0
200
+ print("\n--- Register / 注册 ---")
180
201
 
181
- while retry_count < max_retries:
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
- continue
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
- password = getpass.getpass("[SoulSync] Password / 密码: ")
189
- if len(password) < 6:
190
- print("[SoulSync] Password must be at least 6 characters / 密码至少6位")
191
- continue
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
- temp_client = OpenClawClient(self.config)
201
- temp_client.send_verification_code(email)
202
- print("[SoulSync] ✓ Verification code sent! / 验证码已发送!")
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
- print(f"[SoulSync] Failed to send code: {e}")
205
- continue
206
-
207
- code_retry = 0
208
- while code_retry < max_retries:
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(f"[SoulSync] ❌ Registration failed: {e}")
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] Exiting... / 退出...")
249
- sys.exit(0)
273
+ print(f"[SoulSync] Registration failed: {e}")
250
274
 
251
- print("\n[SoulSync] Too many registration attempts / 注册尝试次数过多")
252
- print("[SoulSync] Exiting... / 退出...")
253
- sys.exit(0)
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] Login failed: invalid email or password / 登录失败:邮箱或密码错误")
294
- print("[SoulSync] Please check your config file / 请检查配置文件:")
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("\nStarting file watcher...")
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("\nConnecting to WebSocket...")
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\nShutting down...")
433
+ print("\n[SoulSync] Shutting down...")
409
434
  self.shutdown()
410
435
  except Exception as e:
411
- print(f"\nError: {e}")
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
- parser = argparse.ArgumentParser(description='SoulSync Plugin')
440
- parser.add_argument('--setup', action='store_true', help='Run interactive setup (register/login)')
441
- parser.add_argument('--start', action='store_true', help='Start sync service (auto-login from config)')
442
-
443
- args = parser.parse_args()
444
-
445
- plugin = SoulSyncPlugin()
446
-
447
- if args.setup:
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
- plugin.run_setup()
450
- print("\n[SoulSync] Setup complete! Run 'openclaw soulsync:start' to begin syncing.")
451
- print("[SoulSync] 设置完成!运行 'openclaw soulsync:start' 开始同步。")
452
- sys.exit(0)
453
-
454
- plugin.load_config()
455
-
456
- email = plugin.config.get('email', '').strip()
457
- password = plugin.config.get('password', '').strip()
458
-
459
- if not email or not password:
460
- print("\n[SoulSync] ========================================")
461
- print("[SoulSync] Not configured. Run 'openclaw soulsync:setup' first.")
462
- print("[SoulSync] 尚未配置,请先运行 'openclaw soulsync:setup'")
463
- print("[SoulSync] ========================================\n")
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()