@researai/deepscientist 1.5.3 → 1.5.4

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.
Files changed (90) hide show
  1. package/README.md +1 -1
  2. package/bin/ds.js +27 -187
  3. package/docs/en/00_QUICK_START.md +1 -1
  4. package/docs/en/01_SETTINGS_REFERENCE.md +13 -4
  5. package/docs/en/99_ACKNOWLEDGEMENTS.md +1 -0
  6. package/docs/images/connectors/discord-setup-overview.svg +52 -0
  7. package/docs/images/connectors/feishu-setup-overview.svg +53 -0
  8. package/docs/images/connectors/slack-setup-overview.svg +51 -0
  9. package/docs/images/connectors/telegram-setup-overview.svg +55 -0
  10. package/docs/images/connectors/whatsapp-setup-overview.svg +51 -0
  11. package/docs/images/lingzhu/lingzhu-openclaw-config.svg +17 -0
  12. package/docs/images/lingzhu/lingzhu-platform-values.svg +16 -0
  13. package/docs/images/lingzhu/lingzhu-settings-overview.svg +30 -0
  14. package/docs/images/qq/tencent-cloud-qq-chat.png +0 -0
  15. package/docs/images/qq/tencent-cloud-qq-register.png +0 -0
  16. package/docs/images/quickstart/00-home.png +0 -0
  17. package/docs/images/quickstart/01-start-research.png +0 -0
  18. package/docs/images/quickstart/02-list-quest.png +0 -0
  19. package/docs/zh/00_QUICK_START.md +1 -1
  20. package/docs/zh/01_SETTINGS_REFERENCE.md +14 -5
  21. package/docs/zh/99_ACKNOWLEDGEMENTS.md +1 -0
  22. package/package.json +8 -4
  23. package/pyproject.toml +1 -1
  24. package/src/deepscientist/__init__.py +1 -1
  25. package/src/deepscientist/bridges/base.py +2 -1
  26. package/src/deepscientist/bridges/connectors.py +2 -1
  27. package/src/deepscientist/channels/discord_gateway.py +2 -2
  28. package/src/deepscientist/channels/qq_gateway.py +2 -2
  29. package/src/deepscientist/channels/slack_socket.py +2 -2
  30. package/src/deepscientist/channels/telegram_polling.py +2 -1
  31. package/src/deepscientist/cli.py +4 -1
  32. package/src/deepscientist/config/models.py +7 -3
  33. package/src/deepscientist/config/service.py +52 -2
  34. package/src/deepscientist/daemon/api/handlers.py +6 -6
  35. package/src/deepscientist/daemon/app.py +65 -10
  36. package/src/deepscientist/network.py +78 -0
  37. package/src/deepscientist/prompts/builder.py +22 -3
  38. package/src/deepscientist/quest/service.py +1 -1
  39. package/src/deepscientist/skills/installer.py +77 -1
  40. package/src/prompts/system.md +78 -2
  41. package/src/skills/analysis-campaign/SKILL.md +8 -0
  42. package/src/skills/idea/SKILL.md +245 -3
  43. package/src/skills/write/SKILL.md +151 -1
  44. package/src/tui/package.json +1 -1
  45. package/src/ui/dist/assets/{AiManusChatView-qzChi9uh.js → AiManusChatView-BGLArZRn.js} +11 -11
  46. package/src/ui/dist/assets/{AnalysisPlugin-CcC_-UqN.js → AnalysisPlugin-BgDGSigG.js} +1 -1
  47. package/src/ui/dist/assets/{AutoFigurePlugin-DD8LkJLe.js → AutoFigurePlugin-B65HD7L4.js} +5 -5
  48. package/src/ui/dist/assets/{CliPlugin-DJJFfVmW.js → CliPlugin-CUqgsFHC.js} +9 -9
  49. package/src/ui/dist/assets/{CodeEditorPlugin-CrjkHNLh.js → CodeEditorPlugin-CF5EdvaS.js} +8 -8
  50. package/src/ui/dist/assets/{CodeViewerPlugin-obnD6G5R.js → CodeViewerPlugin-DEeU063D.js} +5 -5
  51. package/src/ui/dist/assets/{DocViewerPlugin-DB9SUQVd.js → DocViewerPlugin-Df-FuDlZ.js} +3 -3
  52. package/src/ui/dist/assets/{GitDiffViewerPlugin-DZLlNlD2.js → GitDiffViewerPlugin-RAnNaRxM.js} +1 -1
  53. package/src/ui/dist/assets/{ImageViewerPlugin-BGwfDZ0Y.js → ImageViewerPlugin-DXJ0ZJGg.js} +5 -5
  54. package/src/ui/dist/assets/{LabCopilotPanel-dfLptQcR.js → LabCopilotPanel-BlO-sKsj.js} +10 -10
  55. package/src/ui/dist/assets/{LabPlugin-CeGjAl3A.js → LabPlugin-BajPZW5v.js} +1 -1
  56. package/src/ui/dist/assets/{LatexPlugin-BBJ7kd1V.js → LatexPlugin-F1OEol8D.js} +7 -7
  57. package/src/ui/dist/assets/{MarkdownViewerPlugin-DKZi7BcB.js → MarkdownViewerPlugin-MhUupqwT.js} +4 -4
  58. package/src/ui/dist/assets/{MarketplacePlugin-C_k-9jD0.js → MarketplacePlugin-DxhIEsv0.js} +3 -3
  59. package/src/ui/dist/assets/{NotebookEditor-4R88_BMO.js → NotebookEditor-q7TkhewC.js} +1 -1
  60. package/src/ui/dist/assets/{PdfLoader-DwEFQLrw.js → PdfLoader-B8ZOTKFc.js} +1 -1
  61. package/src/ui/dist/assets/{PdfMarkdownPlugin-D-jdsqF8.js → PdfMarkdownPlugin-xFPvzvWh.js} +3 -3
  62. package/src/ui/dist/assets/{PdfViewerPlugin-CmeBGDY0.js → PdfViewerPlugin-EjEcsIB8.js} +10 -10
  63. package/src/ui/dist/assets/{SearchPlugin-Dlz2WKJ4.js → SearchPlugin-ixY-1lgW.js} +1 -1
  64. package/src/ui/dist/assets/{Stepper-ClOgzWM3.js → Stepper-gYFK2Pgz.js} +1 -1
  65. package/src/ui/dist/assets/{TextViewerPlugin-DDQWxibk.js → TextViewerPlugin-Cym6pv_n.js} +4 -4
  66. package/src/ui/dist/assets/{VNCViewer-CJXT0Nm8.js → VNCViewer-BPmIHcmK.js} +9 -9
  67. package/src/ui/dist/assets/{bibtex-DLr4Rtk4.js → bibtex-Btv6Wi7f.js} +1 -1
  68. package/src/ui/dist/assets/{code-DgKK408Y.js → code-BlG7g85c.js} +1 -1
  69. package/src/ui/dist/assets/{file-content-6HBqQnvQ.js → file-content-DBT5OfTZ.js} +1 -1
  70. package/src/ui/dist/assets/{file-diff-panel-Dhu0TbBM.js → file-diff-panel-BWXYzqHk.js} +1 -1
  71. package/src/ui/dist/assets/{file-socket-CP3iwVZG.js → file-socket-wDlx6byM.js} +1 -1
  72. package/src/ui/dist/assets/{file-utils-BsS-Aw68.js → file-utils-Ba3nJmH0.js} +1 -1
  73. package/src/ui/dist/assets/{image-ByeK-Zcv.js → image-BwtCyguk.js} +1 -1
  74. package/src/ui/dist/assets/{index-BdsE0uRz.js → index-B-2scqCJ.js} +11 -11
  75. package/src/ui/dist/assets/{index-BLjo5--a.js → index-Bz5AaWL7.js} +50793 -50661
  76. package/src/ui/dist/assets/{index-DyremSIv.js → index-CfRpE209.js} +2 -2
  77. package/src/ui/dist/assets/{index-C-eX-N6A.js → index-DcqvKzeJ.js} +1 -1
  78. package/src/ui/dist/assets/{index-CuQhlrR-.css → index-DpMZw8aM.css} +2 -2
  79. package/src/ui/dist/assets/{message-square-DnagiLnc.js → message-square-BnlyWVH0.js} +1 -1
  80. package/src/ui/dist/assets/{monaco-4kBFeprs.js → monaco-CXe0pAVe.js} +1 -1
  81. package/src/ui/dist/assets/{popover-hRCXZzs2.js → popover-BCHmVhHj.js} +1 -1
  82. package/src/ui/dist/assets/{project-sync-O_85YuP6.js → project-sync-Brk6kaOD.js} +1 -1
  83. package/src/ui/dist/assets/{sigma-DvKopSnL.js → sigma-D72eSUep.js} +1 -1
  84. package/src/ui/dist/assets/{tooltip-BmlPc6kc.js → tooltip-BMWd0dqX.js} +1 -1
  85. package/src/ui/dist/assets/{trash-n-UvdZFR.js → trash-BIt_eWIS.js} +1 -1
  86. package/src/ui/dist/assets/{useCliAccess-WDd3_wIh.js → useCliAccess-N1hkTRrR.js} +1 -1
  87. package/src/ui/dist/assets/{useFileDiffOverlay-rXLIL2NF.js → useFileDiffOverlay-DPRPv6rv.js} +1 -1
  88. package/src/ui/dist/assets/{wrap-text-qIYQ4a_W.js → wrap-text-E5-UheyP.js} +1 -1
  89. package/src/ui/dist/assets/{zoom-out-fZXCEFsy.js → zoom-out-D4TR-ZZ_.js} +1 -1
  90. package/src/ui/dist/index.html +2 -2
package/README.md CHANGED
@@ -55,7 +55,7 @@ Use `ds --home <path>` if you want to place the runtime somewhere else.
55
55
  If you want to use the current working directory directly as the DeepScientist home, use:
56
56
 
57
57
  ```bash
58
- ds --hero
58
+ ds --here
59
59
  ```
60
60
 
61
61
  This is equivalent to launching with `ds --home "$PWD"`.
package/bin/ds.js CHANGED
@@ -35,7 +35,6 @@ const pythonCommands = new Set([
35
35
  ]);
36
36
  const UPDATE_PACKAGE_NAME = String(packageJson.name || '@researai/deepscientist').trim() || '@researai/deepscientist';
37
37
  const UPDATE_CHECK_TTL_MS = 12 * 60 * 60 * 1000;
38
- const UPDATE_PROMPT_TTL_MS = 12 * 60 * 60 * 1000;
39
38
 
40
39
  const optionsWithValues = new Set(['--home', '--host', '--port', '--quest-id', '--mode']);
41
40
 
@@ -48,8 +47,8 @@ Usage:
48
47
  ds update --check
49
48
  ds update --yes
50
49
  ds migrate /data/DeepScientist
51
- ds --hero
52
- ds --hero doctor
50
+ ds --here
51
+ ds --here doctor
53
52
  ds --tui
54
53
  ds --both
55
54
  ds --host 0.0.0.0 --port 21000
@@ -71,7 +70,7 @@ Launcher flags:
71
70
  --stop Stop the managed daemon
72
71
  --restart Restart the managed daemon
73
72
  --home <path> Use a custom DeepScientist home
74
- --hero Use the current working directory as DeepScientist home
73
+ --here Use the current working directory as DeepScientist home
75
74
  --quest-id <id> Open the TUI on one quest directly
76
75
 
77
76
  Update:
@@ -185,10 +184,7 @@ function detectInstallMode(rootPath = repoRoot) {
185
184
  }
186
185
 
187
186
  function updateManualCommand(installMode) {
188
- if (installMode === 'npm-package') {
189
- return `npm install -g ${UPDATE_PACKAGE_NAME}@latest`;
190
- }
191
- return 'git pull && bash install.sh';
187
+ return `npm install -g ${UPDATE_PACKAGE_NAME}@latest`;
192
188
  }
193
189
 
194
190
  function updateSupportSummary(installMode, npmBinary, launcherPath) {
@@ -203,14 +199,14 @@ function updateSupportSummary(installMode, npmBinary, launcherPath) {
203
199
  return {
204
200
  canCheck: true,
205
201
  canSelfUpdate: false,
206
- reason: 'This DeepScientist installation comes from a source checkout and should be updated from Git.',
202
+ reason: 'Self-update is disabled for this installation. Use the npm command below to install the latest release build.',
207
203
  };
208
204
  }
209
205
  if (!launcherPath || !fs.existsSync(launcherPath)) {
210
206
  return {
211
207
  canCheck: true,
212
208
  canSelfUpdate: false,
213
- reason: 'The launcher entrypoint could not be resolved.',
209
+ reason: 'Self-update is disabled because the launcher entrypoint could not be resolved. Use the npm command below instead.',
214
210
  };
215
211
  }
216
212
  return {
@@ -288,14 +284,17 @@ function buildUpdateStatus(home, statePatch = {}) {
288
284
  const support = updateSupportSummary(installMode, npmBinary, launcherPath);
289
285
  const currentVersion = normalizeVersion(state.current_version || packageJson.version);
290
286
  const latestVersion = normalizeVersion(state.latest_version || '');
287
+ const promptedVersion = normalizeVersion(state.last_prompted_version || '');
291
288
  const updateAvailable = Boolean(latestVersion) && compareVersions(latestVersion, currentVersion) > 0;
292
289
  const skippedVersion = normalizeVersion(state.last_skipped_version || '');
290
+ const promptedCurrentTarget = Boolean(updateAvailable && promptedVersion && promptedVersion === latestVersion);
293
291
  const skippedCurrentTarget = Boolean(updateAvailable && skippedVersion && skippedVersion === latestVersion);
294
292
  const promptRecommended =
295
293
  Boolean(updateAvailable)
296
294
  && !Boolean(state.busy)
295
+ && !promptedCurrentTarget
297
296
  && !skippedCurrentTarget
298
- && isExpired(state.last_prompted_at || state.last_deferred_at, UPDATE_PROMPT_TTL_MS);
297
+ ;
299
298
 
300
299
  return {
301
300
  ok: true,
@@ -311,6 +310,7 @@ function buildUpdateStatus(home, statePatch = {}) {
311
310
  last_checked_at: state.last_checked_at || null,
312
311
  last_check_error: state.last_check_error || null,
313
312
  last_prompted_at: state.last_prompted_at || null,
313
+ last_prompted_version: promptedVersion || null,
314
314
  last_deferred_at: state.last_deferred_at || null,
315
315
  last_skipped_version: skippedVersion || null,
316
316
  last_update_started_at: state.last_update_started_at || null,
@@ -354,10 +354,12 @@ function checkForUpdates(home, { force = false, timeoutMs = 3500 } = {}) {
354
354
  }
355
355
 
356
356
  function markUpdateDeferred(home, version) {
357
+ const normalizedVersion = normalizeVersion(version || readUpdateState(home).latest_version || '');
357
358
  const patched = mergeUpdateState(home, {
358
359
  last_prompted_at: new Date().toISOString(),
359
360
  last_deferred_at: new Date().toISOString(),
360
- latest_version: normalizeVersion(version || readUpdateState(home).latest_version || '') || null,
361
+ last_prompted_version: normalizedVersion || null,
362
+ latest_version: normalizedVersion || null,
361
363
  });
362
364
  return buildUpdateStatus(home, patched);
363
365
  }
@@ -366,6 +368,7 @@ function markUpdateSkipped(home, version) {
366
368
  const normalized = normalizeVersion(version);
367
369
  const patched = mergeUpdateState(home, {
368
370
  last_prompted_at: new Date().toISOString(),
371
+ last_prompted_version: normalized || null,
369
372
  last_skipped_version: normalized || null,
370
373
  });
371
374
  return buildUpdateStatus(home, patched);
@@ -393,7 +396,7 @@ function resolveHome(args) {
393
396
  if (index >= 0 && index + 1 < args.length) {
394
397
  return path.resolve(args[index + 1]);
395
398
  }
396
- if (args.includes('--hero') || args.includes('--here')) {
399
+ if (args.includes('--here')) {
397
400
  return process.cwd();
398
401
  }
399
402
  if (process.env.DEEPSCIENTIST_HOME) {
@@ -566,7 +569,7 @@ function renderLaunchHints({ home, url, bindUrl, pythonSelection }) {
566
569
  renderKeyValueRows([
567
570
  ['ds --port 21000', 'Change the web port'],
568
571
  ['ds --host 0.0.0.0 --port 21000', 'Bind on all interfaces'],
569
- ['ds --hero', 'Use the current directory as home'],
572
+ ['ds --here', 'Use the current directory as home'],
570
573
  ['ds --both', 'Start web + TUI together'],
571
574
  ['ds --tui', 'Start the terminal workspace only'],
572
575
  ['ds --no-browser', 'Do not auto-open the browser'],
@@ -2031,7 +2034,7 @@ function normalizePythonCliArgs(args, home) {
2031
2034
  index += 1;
2032
2035
  continue;
2033
2036
  }
2034
- if (arg === '--hero' || arg === '--here') {
2037
+ if (arg === '--here') {
2035
2038
  continue;
2036
2039
  }
2037
2040
  normalized.push(arg);
@@ -2492,96 +2495,11 @@ function runNpmInstallLatest(home, npmBinary) {
2492
2495
  };
2493
2496
  }
2494
2497
 
2495
- async function promptUpdateAction(status) {
2496
- const options = [
2497
- {
2498
- value: 'update',
2499
- label: status.can_self_update ? 'Update now' : 'Show manual update',
2500
- },
2501
- { value: 'later', label: 'Remind me later' },
2502
- { value: 'skip', label: 'Skip this version' },
2503
- ];
2504
- if (!process.stdin.isTTY || !process.stdout.isTTY) {
2505
- return 'later';
2506
- }
2507
- return new Promise((resolve) => {
2508
- let selected = 1;
2509
- const lines = [
2510
- '',
2511
- 'A new DeepScientist version is available.',
2512
- '',
2513
- `Current: ${status.current_version}`,
2514
- `Latest: ${status.latest_version || 'unknown'}`,
2515
- '',
2516
- status.can_self_update
2517
- ? 'What do you want to do?'
2518
- : 'Self-update is not available for this installation. Choose an action:',
2519
- ];
2520
-
2521
- const cleanup = () => {
2522
- process.stdin.off('keypress', onKeypress);
2523
- if (process.stdin.isTTY) {
2524
- process.stdin.setRawMode(false);
2525
- }
2526
- process.stdin.pause();
2527
- console.log('');
2528
- };
2529
-
2530
- const render = () => {
2531
- console.clear();
2532
- for (const line of lines) {
2533
- console.log(line);
2534
- }
2535
- for (let index = 0; index < options.length; index += 1) {
2536
- const option = options[index];
2537
- console.log(`${index === selected ? '>' : ' '} ${option.label}`);
2538
- }
2539
- console.log('');
2540
- console.log('Use ↑/↓ and Enter.');
2541
- };
2542
-
2543
- const onKeypress = (_str, key) => {
2544
- if (key?.name === 'up') {
2545
- selected = (selected - 1 + options.length) % options.length;
2546
- render();
2547
- return;
2548
- }
2549
- if (key?.name === 'down') {
2550
- selected = (selected + 1) % options.length;
2551
- render();
2552
- return;
2553
- }
2554
- if (key?.name === 'return') {
2555
- const choice = options[selected].value;
2556
- cleanup();
2557
- resolve(choice);
2558
- return;
2559
- }
2560
- if (key?.ctrl && key?.name === 'c') {
2561
- cleanup();
2562
- resolve('later');
2563
- }
2564
- };
2565
-
2566
- readline.emitKeypressEvents(process.stdin);
2567
- process.stdin.setRawMode(true);
2568
- process.stdin.resume();
2569
- process.stdin.on('keypress', onKeypress);
2570
- render();
2571
- });
2572
- }
2573
-
2574
2498
  function printUpdateStatus(status, { compact = false } = {}) {
2575
2499
  if (compact) {
2576
2500
  if (status.update_available) {
2577
- console.log(
2578
- `DeepScientist update available: ${status.current_version} -> ${status.latest_version}`
2579
- );
2580
- if (status.can_self_update) {
2581
- console.log('Run `ds update --yes` to install it.');
2582
- } else {
2583
- console.log(`Manual update: ${status.manual_update_command}`);
2584
- }
2501
+ console.log(`DeepScientist update available: ${status.current_version} -> ${status.latest_version}`);
2502
+ console.log(`Update with: ${status.manual_update_command}`);
2585
2503
  return;
2586
2504
  }
2587
2505
  console.log(`DeepScientist is up to date (${status.current_version}).`);
@@ -2594,16 +2512,15 @@ function printUpdateStatus(status, { compact = false } = {}) {
2594
2512
  ['Latest', status.latest_version || 'unknown'],
2595
2513
  ['Available', status.update_available ? 'yes' : 'no'],
2596
2514
  ['Install mode', status.install_mode],
2597
- ['Self-update', status.can_self_update ? 'supported' : 'manual-only'],
2598
2515
  ['Last checked', status.last_checked_at || 'never'],
2599
2516
  ]);
2600
2517
  if (status.last_check_error) {
2601
2518
  console.log('');
2602
2519
  console.log(`Version check error: ${status.last_check_error}`);
2603
2520
  }
2604
- if (!status.can_self_update) {
2521
+ if (status.update_available || status.manual_update_command) {
2605
2522
  console.log('');
2606
- console.log(`Manual update command: ${status.manual_update_command}`);
2523
+ console.log(`Update command: ${status.manual_update_command}`);
2607
2524
  if (status.reason) {
2608
2525
  console.log(status.reason);
2609
2526
  }
@@ -2631,26 +2548,6 @@ function spawnDetachedNode(args, options = {}) {
2631
2548
  return child;
2632
2549
  }
2633
2550
 
2634
- async function restartIntoUpdatedLauncher(rawArgs) {
2635
- const launcherPath = resolveLauncherPath();
2636
- if (!launcherPath) {
2637
- throw new Error('Could not resolve the DeepScientist launcher after the update.');
2638
- }
2639
- const args = [launcherPath, '--skip-update-check', ...rawArgs.filter((item) => item !== '--skip-update-check')];
2640
- const child = spawn(process.execPath, args, {
2641
- cwd: repoRoot,
2642
- stdio: 'inherit',
2643
- env: process.env,
2644
- });
2645
- await new Promise((resolve, reject) => {
2646
- child.on('error', reject);
2647
- child.on('exit', (code) => {
2648
- process.exit(code ?? 0);
2649
- resolve();
2650
- });
2651
- });
2652
- }
2653
-
2654
2551
  async function performSelfUpdate(home, options = {}) {
2655
2552
  const status = checkForUpdates(home, { force: true });
2656
2553
  if (!status.update_available) {
@@ -2816,42 +2713,8 @@ async function maybeHandleStartupUpdate(home, rawArgs, options = {}) {
2816
2713
  return false;
2817
2714
  }
2818
2715
 
2819
- if (!process.stdin.isTTY || !process.stdout.isTTY) {
2820
- printUpdateStatus(status, { compact: true });
2821
- mergeUpdateState(home, {
2822
- last_prompted_at: new Date().toISOString(),
2823
- });
2824
- return false;
2825
- }
2826
-
2827
- const action = await promptUpdateAction(status);
2828
- if (action === 'later') {
2829
- markUpdateDeferred(home, status.latest_version);
2830
- return false;
2831
- }
2832
- if (action === 'skip') {
2833
- markUpdateSkipped(home, status.latest_version);
2834
- return false;
2835
- }
2836
- if (action === 'update' && !status.can_self_update) {
2837
- console.log(`Manual update required: ${status.manual_update_command}`);
2838
- if (status.reason) {
2839
- console.log(status.reason);
2840
- }
2841
- markUpdateDeferred(home, status.latest_version);
2842
- return false;
2843
- }
2844
- if (action === 'update') {
2845
- console.log(`Updating DeepScientist ${status.current_version} -> ${status.latest_version} ...`);
2846
- const result = await performSelfUpdate(home, { restartDaemon: false });
2847
- if (!result.ok) {
2848
- console.error(result.message);
2849
- return false;
2850
- }
2851
- console.log(result.message);
2852
- await restartIntoUpdatedLauncher(rawArgs);
2853
- return true;
2854
- }
2716
+ printUpdateStatus(status, { compact: true });
2717
+ markUpdateDeferred(home, status.latest_version);
2855
2718
  return false;
2856
2719
  }
2857
2720
 
@@ -3218,32 +3081,8 @@ async function updateMain(rawArgs) {
3218
3081
  printUpdateStatus(status, { compact: true });
3219
3082
  process.exit(0);
3220
3083
  }
3221
-
3222
- const action = await promptUpdateAction(status);
3223
- if (action === 'later') {
3224
- markUpdateDeferred(home, status.latest_version);
3225
- console.log('Update reminder deferred.');
3226
- process.exit(0);
3227
- }
3228
- if (action === 'skip') {
3229
- markUpdateSkipped(home, status.latest_version);
3230
- console.log(`Skipped ${status.latest_version}.`);
3231
- process.exit(0);
3232
- }
3233
- if (!status.can_self_update) {
3234
- console.log(`Manual update command: ${status.manual_update_command}`);
3235
- if (status.reason) {
3236
- console.log(status.reason);
3237
- }
3238
- process.exit(0);
3239
- }
3240
- const payload = await performSelfUpdate(home, {
3241
- host: options.host,
3242
- port: options.port,
3243
- restartDaemon: options.restartDaemon,
3244
- });
3245
- console.log(payload.message);
3246
- process.exit(payload.ok ? 0 : 1);
3084
+ printUpdateStatus(status, { compact: true });
3085
+ process.exit(0);
3247
3086
  }
3248
3087
 
3249
3088
  async function migrateMain(rawArgs) {
@@ -3531,6 +3370,7 @@ module.exports = {
3531
3370
  useEditableProjectInstall,
3532
3371
  compareVersions,
3533
3372
  detectInstallMode,
3373
+ updateManualCommand,
3534
3374
  buildUpdateStatus,
3535
3375
  },
3536
3376
  };
@@ -42,7 +42,7 @@ By default, the DeepScientist home is `~/DeepScientist` on macOS and Linux, and
42
42
  If you want to use the current working directory as the DeepScientist home directly, run:
43
43
 
44
44
  ```bash
45
- ds --hero
45
+ ds --here
46
46
  ```
47
47
 
48
48
  This is equivalent to `ds --home "$PWD"`.
@@ -44,7 +44,7 @@ Connector-specific setup guides:
44
44
  ```yaml
45
45
  home: ~/DeepScientist
46
46
  default_runner: codex
47
- default_locale: zh-CN
47
+ default_locale: en-US # or zh-CN, initialized from the browser on first web launch
48
48
  daemon:
49
49
  session_restore_on_start: true
50
50
  max_concurrent_quests: 1
@@ -67,6 +67,14 @@ skills:
67
67
  sync_global_on_init: true
68
68
  sync_quest_on_create: true
69
69
  sync_quest_on_open: true
70
+ bootstrap:
71
+ codex_ready: false
72
+ codex_last_checked_at: null
73
+ codex_last_result: {}
74
+ locale_source: browser
75
+ locale_initialized_from_browser: true
76
+ locale_initialized_at: 2026-03-18T00:00:00+00:00
77
+ locale_initialized_browser_locale: en-US
70
78
  connectors:
71
79
  auto_ack: true
72
80
  milestone_push: true
@@ -108,10 +116,11 @@ acp:
108
116
  **`default_locale`**
109
117
 
110
118
  - Type: `string`
111
- - Default: `zh-CN`
119
+ - Default: initialized from the browser language on the first web launch, then persisted as `zh-CN` or `en-US`
112
120
  - Allowed values: `zh-CN`, `en-US`
113
121
  - UI label: `Default locale`
114
- - Meaning: default prompt and UI language preference.
122
+ - Meaning: default language preference used by prompts and runtime copy.
123
+ - Notes: after the first browser-driven initialization, changing this field in `Settings` makes it a manual override and DeepScientist will not auto-follow the browser again.
115
124
 
116
125
  ### Daemon policy
117
126
 
@@ -1074,7 +1083,7 @@ servers:
1074
1083
  ```yaml
1075
1084
  # config.yaml
1076
1085
  default_runner: codex
1077
- default_locale: zh-CN
1086
+ default_locale: en-US
1078
1087
  ui:
1079
1088
  host: 0.0.0.0
1080
1089
  port: 20999
@@ -11,6 +11,7 @@ We especially thank the following projects for their ideas, research direction,
11
11
  - AlphaEvolve
12
12
  - OpenEvolve
13
13
  - EvoScientist
14
+ - Orchestra-Research/AI-Research-SKILLs
14
15
 
15
16
  These projects have been important references for thinking about automated research, open-ended exploration, evolutionary search, experiment organization, and long-horizon research agents.
16
17
 
@@ -0,0 +1,52 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720" fill="none">
2
+ <rect width="1280" height="720" rx="32" fill="#F7F7FF"/>
3
+ <rect x="40" y="40" width="1200" height="640" rx="28" fill="#FFFFFF" stroke="#DADCFB" stroke-width="2"/>
4
+ <circle cx="110" cy="108" r="34" fill="#5865F2"/>
5
+ <path d="M124.6 96.6c-2.4-1.8-4.8-3-7.4-3.8-.1 0-.2 0-.2.1-.3.6-.6 1.2-.9 1.9-2.8-.4-5.5-.4-8.2 0-.3-.6-.6-1.3-.9-1.9-.1-.1-.1-.1-.2-.1-2.6.8-5.1 2-7.4 3.8-.1 0-.1.1-.1.1-4.5 6.7-5.7 13.2-5.1 19.6 0 .1 0 .1.1.2 3.1 2.3 6.2 3.7 9.2 4.7.1 0 .2 0 .2-.1.7-1 1.3-2 1.8-3 .1-.1 0-.2-.1-.2-1-.4-1.9-.8-2.8-1.4-.1 0-.1-.2 0-.2.2-.1.4-.3.6-.4h.1c6 2.7 12.5 2.7 18.5 0h.1c.2.1.4.3.6.4.1.1.1.2 0 .2-.9.5-1.8 1-2.8 1.4-.1 0-.1.1-.1.2.5 1 1.1 2 1.8 3 .1.1.1.1.2.1 3-.9 6.1-2.4 9.2-4.7.1 0 .1-.1.1-.2.7-7.4-1.1-13.8-5.1-19.6 0 0 0-.1-.1-.1ZM104.8 112.5c-1.8 0-3.3-1.6-3.3-3.7s1.4-3.7 3.3-3.7c1.8 0 3.3 1.6 3.3 3.7-.1 2-1.5 3.7-3.3 3.7Zm14.4 0c-1.8 0-3.3-1.6-3.3-3.7s1.4-3.7 3.3-3.7c1.8 0 3.3 1.6 3.3 3.7s-1.4 3.7-3.3 3.7Z" fill="#fff"/>
6
+ <text x="164" y="98" fill="#0F172A" font-family="Arial, sans-serif" font-size="34" font-weight="700">Discord Setup Flow</text>
7
+ <text x="164" y="138" fill="#475569" font-family="Arial, sans-serif" font-size="20">Developer Portal -&gt; Bot token + Application ID -&gt; invite bot -&gt; one DM or mention</text>
8
+
9
+ <rect x="72" y="198" width="340" height="414" rx="26" fill="#FBFBFF" stroke="#D7D9FE" stroke-width="2"/>
10
+ <rect x="98" y="224" width="90" height="34" rx="17" fill="#EDE9FE"/>
11
+ <text x="122" y="246" fill="#4338CA" font-family="Arial, sans-serif" font-size="18" font-weight="700">Step 1</text>
12
+ <text x="98" y="292" fill="#0F172A" font-family="Arial, sans-serif" font-size="28" font-weight="700">Create the app</text>
13
+ <rect x="98" y="324" width="288" height="76" rx="18" fill="#fff" stroke="#E3E5FF"/>
14
+ <text x="122" y="352" fill="#0F172A" font-family="Arial, sans-serif" font-size="18" font-weight="700">Developer Portal</text>
15
+ <text x="122" y="378" fill="#475569" font-family="Arial, sans-serif" font-size="16">General Information + Bot tab</text>
16
+ <rect x="98" y="416" width="288" height="92" rx="18" fill="#EEF2FF"/>
17
+ <text x="122" y="446" fill="#0F172A" font-family="Arial, sans-serif" font-size="18" font-weight="700">Copy two values</text>
18
+ <text x="122" y="474" fill="#4338CA" font-family="Arial, sans-serif" font-size="16">bot_token</text>
19
+ <text x="122" y="498" fill="#4338CA" font-family="Arial, sans-serif" font-size="16">application_id</text>
20
+ <rect x="98" y="524" width="288" height="60" rx="18" fill="#fff" stroke="#E3E5FF"/>
21
+ <text x="122" y="560" fill="#475569" font-family="Arial, sans-serif" font-size="16">Enable bot user and keep Gateway mode</text>
22
+
23
+ <rect x="470" y="198" width="340" height="414" rx="26" fill="#FBFCFF" stroke="#DADCFB" stroke-width="2"/>
24
+ <rect x="496" y="224" width="90" height="34" rx="17" fill="#DBEAFE"/>
25
+ <text x="520" y="246" fill="#1D4ED8" font-family="Arial, sans-serif" font-size="18" font-weight="700">Step 2</text>
26
+ <text x="496" y="292" fill="#0F172A" font-family="Arial, sans-serif" font-size="28" font-weight="700">Fill Settings</text>
27
+ <rect x="496" y="324" width="288" height="220" rx="18" fill="#fff" stroke="#DFE4FD"/>
28
+ <text x="520" y="356" fill="#0F172A" font-family="Arial, sans-serif" font-size="18" font-weight="700">Connector fields</text>
29
+ <text x="520" y="390" fill="#334155" font-family="Arial, sans-serif" font-size="17">Enabled: on</text>
30
+ <text x="520" y="422" fill="#334155" font-family="Arial, sans-serif" font-size="17">transport: gateway</text>
31
+ <text x="520" y="454" fill="#334155" font-family="Arial, sans-serif" font-size="17">bot_token: paste from Bot tab</text>
32
+ <text x="520" y="486" fill="#334155" font-family="Arial, sans-serif" font-size="17">application_id: paste from General Info</text>
33
+ <text x="520" y="518" fill="#334155" font-family="Arial, sans-serif" font-size="17">guild_allowlist: optional</text>
34
+ <rect x="496" y="560" width="288" height="24" rx="12" fill="#111827"/>
35
+
36
+ <rect x="868" y="198" width="340" height="414" rx="26" fill="#FCFCFF" stroke="#DADCFB" stroke-width="2"/>
37
+ <rect x="894" y="224" width="90" height="34" rx="17" fill="#DCFCE7"/>
38
+ <text x="918" y="246" fill="#166534" font-family="Arial, sans-serif" font-size="18" font-weight="700">Step 3</text>
39
+ <text x="894" y="292" fill="#0F172A" font-family="Arial, sans-serif" font-size="28" font-weight="700">Invite and verify</text>
40
+ <rect x="894" y="324" width="288" height="76" rx="18" fill="#fff" stroke="#E4E7FD"/>
41
+ <text x="918" y="352" fill="#0F172A" font-family="Arial, sans-serif" font-size="18" font-weight="700">Generate one real event</text>
42
+ <text x="918" y="378" fill="#475569" font-family="Arial, sans-serif" font-size="16">Invite bot, then send one DM or @mention</text>
43
+ <rect x="894" y="416" width="288" height="76" rx="18" fill="#fff" stroke="#E4E7FD"/>
44
+ <text x="918" y="444" fill="#0F172A" font-family="Arial, sans-serif" font-size="18" font-weight="700">Back to DeepScientist</text>
45
+ <text x="918" y="470" fill="#475569" font-family="Arial, sans-serif" font-size="16">Use the discovered target, not a guessed id</text>
46
+ <rect x="894" y="508" width="288" height="76" rx="18" fill="#ECFDF5"/>
47
+ <text x="918" y="536" fill="#0F172A" font-family="Arial, sans-serif" font-size="18" font-weight="700">Final actions</text>
48
+ <text x="918" y="564" fill="#166534" font-family="Arial, sans-serif" font-size="16">Check -&gt; Send probe</text>
49
+
50
+ <path d="M423 406H455" stroke="#94A3B8" stroke-width="8" stroke-linecap="round"/>
51
+ <path d="M821 406H853" stroke="#94A3B8" stroke-width="8" stroke-linecap="round"/>
52
+ </svg>
@@ -0,0 +1,53 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720" fill="none">
2
+ <rect width="1280" height="720" rx="32" fill="#F8FCFF"/>
3
+ <rect x="40" y="40" width="1200" height="640" rx="28" fill="#FFFFFF" stroke="#D7E7FF" stroke-width="2"/>
4
+ <rect x="76" y="74" width="68" height="68" rx="18" fill="#fff" stroke="#D7E7FF"/>
5
+ <path d="M104.3 112.1c18.1 0 33.9-10 42.1-24.8.3-.5.6-1 .9-1.5-.4.8-.9 1.5-1.4 2.2-.2.2-.4.4-.6.7-.2.3-.5.6-.8.8-.2.2-.4.4-.6.6-.4.4-.9.8-1.3 1.2-.2.2-.5.4-.8.6-.3.3-.6.5-.9.7l-.6.4-.6.4c-.5.3-1 .5-1.5.7-.4.2-.8.4-1.2.5-.5.2-1 .4-1.6.5-.8.2-1.6.4-2.3.5-.6.1-1.2.2-1.8.2-.7 0-1.4 0-2.1-.1-.7-.1-1.3-.1-2-.2-.5-.1-1-.2-1.5-.3l-.8-.2c-.7-.2-1.4-.4-2.1-.6-.3-.1-.7-.2-1-.3-.5-.2-1.1-.3-1.6-.5-.4-.1-.8-.3-1.3-.4-.4-.1-.8-.3-1.2-.4l-1.3-.5c-.3-.1-.7-.2-1-.4l-.9-.3c-.5-.2-1-.4-1.4-.6l-.8-.3-.9-.4-.9-.4-1.2-.5-1.3-.6c-.5-.2-.9-.4-1.4-.6l-1.1-.5c-20.4-10.2-38.7-23.9-54.2-40.6-.5-.5-1.3-.5-1.8 0-.2.2-.3.5-.3.9v17.3c0 3.6 1.8 6.9 4.8 8.8 14.3 9.5 31.1 14.5 48.2 14.5Z" fill="#3370FF"/>
6
+ <path d="M118.7 88.7c-1.9-3.1-1.1-7 .8-9.5 8.1-7.8 12.9-19.1 11.9-31.4C129.9 28.5 114 13.6 94.2 12.2 70.2 10.6 50 29.7 50 53.5v51.1c0 2.1 1.7 3.8 3.8 3.8h12.5c2.1 0 3.8-1.7 3.8-3.8V84.9c0-.6.1-1.2.2-1.8.8-3.7 3.9-6.6 7.8-6.8 4.1-.3 7.9 2.4 9 6.3l.7 2.5 5.9 21.6c.5 1.6 1.9 2.8 3.6 2.8h14.8c2.8 0 4.7-3 3.3-5.5l-12.2-23.1-.1-.2Zm-19.1-14.2c-8.6 1.1-15.9-6.2-14.8-14.9.7-5.9 5.4-10.6 11.3-11.4 8.6-1.1 15.9 6.2 14.8 14.8-.7 5.9-5.4 10.7-11.3 11.5Z" fill="#00D6B9"/>
7
+ <path d="M151.6 52.4c-6.8-3.3-14.5-4-21.8-2-.3.1-.6.2-.9.3l-.6.2c-.4.1-.9.3-1.2.4-.8.3-1.6.6-2.4 1-.8.4-1.5.8-2.2 1.2-.8.5-1.5.9-2.1 1.5-.5.4-1 .8-1.4 1.3-.5.5-1 .9-1.5 1.4l-.9.8-1.3 1.3-1 1-.8.8-.9.9-.8.8-1.4 1.4-.9.8-.3.3c-.2.1-.3.3-.5.5l-.3.3-.3.3c-3.4 3.1-7.2 5.8-11.2 8l1.2.5.9.4.9.4.9.3 1 .4 1.3.5c.4.1.8.3 1.2.4.5.2.9.3 1.4.5.5.2 1 .3 1.6.5.3.1.7.2 1 .3.7.2 1.4.4 2.1.6l.8.2c.5.1 1 .2 1.5.3.6.1 1.3.2 2 .2.7.1 1.4.1 2.1.1.6 0 1.2-.1 1.8-.2.8-.1 1.6-.3 2.3-.5.6-.1 1.1-.3 1.6-.5.4-.1.8-.3 1.2-.5.5-.2 1-.4 1.5-.7l.6-.4.6-.4c.3-.2.6-.4.9-.7.3-.2.5-.4.8-.6.5-.4.9-.8 1.3-1.2.2-.2.4-.4.6-.6.3-.3.5-.6.8-.8.2-.2.4-.5.6-.7.6-.7 1-1.4 1.4-2.2l.5-1 4.6-9.3.1-.1c1.5-3.3 3.6-6.3 6.1-8.8Z" fill="#133C9A"/>
8
+ <text x="164" y="98" fill="#0F172A" font-family="Arial, sans-serif" font-size="34" font-weight="700">Feishu / Lark Setup Flow</text>
9
+ <text x="164" y="138" fill="#475569" font-family="Arial, sans-serif" font-size="20">Open Platform -&gt; App ID + App Secret -&gt; long connection -&gt; one DM or @mention -&gt; probe</text>
10
+
11
+ <rect x="72" y="198" width="340" height="414" rx="26" fill="#FBFDFF" stroke="#D8E8FF" stroke-width="2"/>
12
+ <rect x="98" y="224" width="90" height="34" rx="17" fill="#DBEAFE"/>
13
+ <text x="122" y="246" fill="#1D4ED8" font-family="Arial, sans-serif" font-size="18" font-weight="700">Step 1</text>
14
+ <text x="98" y="292" fill="#0F172A" font-family="Arial, sans-serif" font-size="28" font-weight="700">Create the app</text>
15
+ <rect x="98" y="324" width="288" height="84" rx="18" fill="#fff" stroke="#E0ECFF"/>
16
+ <text x="122" y="352" fill="#0F172A" font-family="Arial, sans-serif" font-size="18" font-weight="700">Feishu Open Platform</text>
17
+ <text x="122" y="378" fill="#475569" font-family="Arial, sans-serif" font-size="16">Credentials page + app installation</text>
18
+ <rect x="98" y="424" width="288" height="84" rx="18" fill="#F0F9FF"/>
19
+ <text x="122" y="452" fill="#0F172A" font-family="Arial, sans-serif" font-size="18" font-weight="700">Copy two values</text>
20
+ <text x="122" y="480" fill="#0369A1" font-family="Arial, sans-serif" font-size="16">app_id</text>
21
+ <text x="122" y="502" fill="#0369A1" font-family="Arial, sans-serif" font-size="16">app_secret</text>
22
+ <rect x="98" y="524" width="288" height="60" rx="18" fill="#fff" stroke="#E0ECFF"/>
23
+ <text x="122" y="560" fill="#475569" font-family="Arial, sans-serif" font-size="16">Install the app into the target tenant</text>
24
+
25
+ <rect x="470" y="198" width="340" height="414" rx="26" fill="#FCFDFF" stroke="#D8E8FF" stroke-width="2"/>
26
+ <rect x="496" y="224" width="90" height="34" rx="17" fill="#DCFCE7"/>
27
+ <text x="520" y="246" fill="#166534" font-family="Arial, sans-serif" font-size="18" font-weight="700">Step 2</text>
28
+ <text x="496" y="292" fill="#0F172A" font-family="Arial, sans-serif" font-size="28" font-weight="700">Fill Settings</text>
29
+ <rect x="496" y="324" width="288" height="220" rx="18" fill="#fff" stroke="#E0ECFF"/>
30
+ <text x="520" y="356" fill="#0F172A" font-family="Arial, sans-serif" font-size="18" font-weight="700">Connector fields</text>
31
+ <text x="520" y="390" fill="#334155" font-family="Arial, sans-serif" font-size="17">Enabled: on</text>
32
+ <text x="520" y="422" fill="#334155" font-family="Arial, sans-serif" font-size="17">transport: long_connection</text>
33
+ <text x="520" y="454" fill="#334155" font-family="Arial, sans-serif" font-size="17">app_id: paste from platform</text>
34
+ <text x="520" y="486" fill="#334155" font-family="Arial, sans-serif" font-size="17">app_secret: paste from platform</text>
35
+ <text x="520" y="518" fill="#334155" font-family="Arial, sans-serif" font-size="17">require_mention_in_groups: optional</text>
36
+ <rect x="496" y="560" width="288" height="24" rx="12" fill="#111827"/>
37
+
38
+ <rect x="868" y="198" width="340" height="414" rx="26" fill="#FBFDFF" stroke="#D8E8FF" stroke-width="2"/>
39
+ <rect x="894" y="224" width="90" height="34" rx="17" fill="#FDE68A"/>
40
+ <text x="918" y="246" fill="#92400E" font-family="Arial, sans-serif" font-size="18" font-weight="700">Step 3</text>
41
+ <text x="894" y="292" fill="#0F172A" font-family="Arial, sans-serif" font-size="28" font-weight="700">Start one chat</text>
42
+ <rect x="894" y="324" width="288" height="84" rx="18" fill="#fff" stroke="#E0ECFF"/>
43
+ <text x="918" y="352" fill="#0F172A" font-family="Arial, sans-serif" font-size="18" font-weight="700">Generate one event</text>
44
+ <text x="918" y="378" fill="#475569" font-family="Arial, sans-serif" font-size="16">Send one DM or @mention in Feishu</text>
45
+ <rect x="894" y="424" width="288" height="84" rx="18" fill="#fff" stroke="#E0ECFF"/>
46
+ <text x="918" y="452" fill="#0F172A" font-family="Arial, sans-serif" font-size="18" font-weight="700">Back to DeepScientist</text>
47
+ <text x="918" y="478" fill="#475569" font-family="Arial, sans-serif" font-size="16">Wait until discovered targets appear</text>
48
+ <rect x="894" y="524" width="288" height="60" rx="18" fill="#FEFCE8"/>
49
+ <text x="918" y="560" fill="#92400E" font-family="Arial, sans-serif" font-size="16">Check -&gt; Send probe</text>
50
+
51
+ <path d="M423 406H455" stroke="#94A3B8" stroke-width="8" stroke-linecap="round"/>
52
+ <path d="M821 406H853" stroke="#94A3B8" stroke-width="8" stroke-linecap="round"/>
53
+ </svg>
@@ -0,0 +1,51 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720" fill="none">
2
+ <rect width="1280" height="720" rx="32" fill="#FCF8FC"/>
3
+ <rect x="40" y="40" width="1200" height="640" rx="28" fill="#FFFFFF" stroke="#E7D7E7" stroke-width="2"/>
4
+ <circle cx="110" cy="108" r="34" fill="#4A154B"/>
5
+ <path d="M103.1 93.3c0-3 2.4-5.5 5.5-5.5 3 0 5.5 2.5 5.5 5.5v5.5h-5.5c-3.1 0-5.5-2.5-5.5-5.5Zm-10.8 10.8h5.5v5.5c0 3.1-2.5 5.5-5.5 5.5-3.1 0-5.5-2.4-5.5-5.5 0-3 2.4-5.5 5.5-5.5Zm21.8 0h5.5c3 0 5.5 2.5 5.5 5.5 0 3.1-2.5 5.5-5.5 5.5-3.1 0-5.5-2.4-5.5-5.5v-5.5Zm-5.5 16.3v-5.5h5.5c3 0 5.5 2.5 5.5 5.5 0 3.1-2.5 5.5-5.5 5.5-3.1 0-5.5-2.4-5.5-5.5Zm-10.8-10.8v-5.5h5.5c3 0 5.5 2.5 5.5 5.5v16.3c0 3.1-2.5 5.5-5.5 5.5-3.1 0-5.5-2.4-5.5-5.5v-16.3Zm16.3-10.8v-5.5c0-3 2.4-5.5 5.5-5.5 3 0 5.5 2.5 5.5 5.5 0 3-2.5 5.5-5.5 5.5h-5.5Zm-16.3 0H92.3c-3.1 0-5.5-2.5-5.5-5.5 0-3 2.4-5.5 5.5-5.5 3 0 5.5 2.5 5.5 5.5v5.5Z" fill="#fff"/>
6
+ <text x="164" y="98" fill="#0F172A" font-family="Arial, sans-serif" font-size="34" font-weight="700">Slack Setup Flow</text>
7
+ <text x="164" y="138" fill="#475569" font-family="Arial, sans-serif" font-size="20">Slack app dashboard -&gt; Socket Mode -&gt; xoxb + xapp -&gt; one mention -&gt; probe</text>
8
+
9
+ <rect x="72" y="198" width="340" height="414" rx="26" fill="#FFFDFE" stroke="#E9D9E9" stroke-width="2"/>
10
+ <rect x="98" y="224" width="90" height="34" rx="17" fill="#F3E8FF"/>
11
+ <text x="122" y="246" fill="#6B21A8" font-family="Arial, sans-serif" font-size="18" font-weight="700">Step 1</text>
12
+ <text x="98" y="292" fill="#0F172A" font-family="Arial, sans-serif" font-size="28" font-weight="700">Prepare the app</text>
13
+ <rect x="98" y="324" width="288" height="84" rx="18" fill="#fff" stroke="#EEE2EE"/>
14
+ <text x="122" y="352" fill="#0F172A" font-family="Arial, sans-serif" font-size="18" font-weight="700">Slack App dashboard</text>
15
+ <text x="122" y="378" fill="#475569" font-family="Arial, sans-serif" font-size="16">Basic Information + Socket Mode</text>
16
+ <rect x="98" y="424" width="288" height="84" rx="18" fill="#FDF4FF"/>
17
+ <text x="122" y="452" fill="#0F172A" font-family="Arial, sans-serif" font-size="18" font-weight="700">Copy two tokens</text>
18
+ <text x="122" y="480" fill="#6B21A8" font-family="Arial, sans-serif" font-size="16">Bot User OAuth Token: xoxb-...</text>
19
+ <text x="122" y="502" fill="#6B21A8" font-family="Arial, sans-serif" font-size="16">App-Level Token: xapp-...</text>
20
+ <rect x="98" y="524" width="288" height="60" rx="18" fill="#fff" stroke="#EEE2EE"/>
21
+ <text x="122" y="560" fill="#475569" font-family="Arial, sans-serif" font-size="16">Install app into the target workspace</text>
22
+
23
+ <rect x="470" y="198" width="340" height="414" rx="26" fill="#FFFCFF" stroke="#E7D7E7" stroke-width="2"/>
24
+ <rect x="496" y="224" width="90" height="34" rx="17" fill="#FDE68A"/>
25
+ <text x="520" y="246" fill="#92400E" font-family="Arial, sans-serif" font-size="18" font-weight="700">Step 2</text>
26
+ <text x="496" y="292" fill="#0F172A" font-family="Arial, sans-serif" font-size="28" font-weight="700">Fill Settings</text>
27
+ <rect x="496" y="324" width="288" height="220" rx="18" fill="#fff" stroke="#EEE2EE"/>
28
+ <text x="520" y="356" fill="#0F172A" font-family="Arial, sans-serif" font-size="18" font-weight="700">Connector fields</text>
29
+ <text x="520" y="390" fill="#334155" font-family="Arial, sans-serif" font-size="17">Enabled: on</text>
30
+ <text x="520" y="422" fill="#334155" font-family="Arial, sans-serif" font-size="17">transport: socket_mode</text>
31
+ <text x="520" y="454" fill="#334155" font-family="Arial, sans-serif" font-size="17">bot_token: xoxb-...</text>
32
+ <text x="520" y="486" fill="#334155" font-family="Arial, sans-serif" font-size="17">app_token: xapp-...</text>
33
+ <text x="520" y="518" fill="#334155" font-family="Arial, sans-serif" font-size="17">require_mention_in_groups: recommended</text>
34
+ <rect x="496" y="560" width="288" height="24" rx="12" fill="#111827"/>
35
+
36
+ <rect x="868" y="198" width="340" height="414" rx="26" fill="#FFFDFF" stroke="#E7D7E7" stroke-width="2"/>
37
+ <rect x="894" y="224" width="90" height="34" rx="17" fill="#DCFCE7"/>
38
+ <text x="918" y="246" fill="#166534" font-family="Arial, sans-serif" font-size="18" font-weight="700">Step 3</text>
39
+ <text x="894" y="292" fill="#0F172A" font-family="Arial, sans-serif" font-size="28" font-weight="700">Mention and verify</text>
40
+ <rect x="894" y="324" width="288" height="84" rx="18" fill="#fff" stroke="#EEE2EE"/>
41
+ <text x="918" y="352" fill="#0F172A" font-family="Arial, sans-serif" font-size="18" font-weight="700">Generate one event</text>
42
+ <text x="918" y="378" fill="#475569" font-family="Arial, sans-serif" font-size="16">Mention the app or send one DM in Slack</text>
43
+ <rect x="894" y="424" width="288" height="84" rx="18" fill="#fff" stroke="#EEE2EE"/>
44
+ <text x="918" y="452" fill="#0F172A" font-family="Arial, sans-serif" font-size="18" font-weight="700">Use discovered target</text>
45
+ <text x="918" y="478" fill="#475569" font-family="Arial, sans-serif" font-size="16">Let runtime fill the channel or DM id first</text>
46
+ <rect x="894" y="524" width="288" height="60" rx="18" fill="#ECFDF5"/>
47
+ <text x="918" y="560" fill="#166534" font-family="Arial, sans-serif" font-size="16">Check -&gt; Send probe</text>
48
+
49
+ <path d="M423 406H455" stroke="#94A3B8" stroke-width="8" stroke-linecap="round"/>
50
+ <path d="M821 406H853" stroke="#94A3B8" stroke-width="8" stroke-linecap="round"/>
51
+ </svg>