ai-helper-agent 2.0.0 → 2.2.0
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/README.md +28 -5
- package/README.zh-CN.md +28 -5
- package/bin/agent.js +150 -0
- package/dist/assets/{agent-store-BFaBECYz.js → agent-store-DOyMdB_7.js} +2 -2
- package/dist/assets/{agent-store-BFaBECYz.js.map → agent-store-DOyMdB_7.js.map} +1 -1
- package/dist/assets/background.js +86 -87
- package/dist/assets/background.js.map +1 -1
- package/dist/assets/content.js +84 -80
- package/dist/assets/{i18n-CohqPkkN.js → i18n-MmYITlVj.js} +9 -7
- package/dist/assets/i18n-MmYITlVj.js.map +1 -0
- package/dist/assets/model-profiles-CV_sUuPf.js +25 -0
- package/dist/assets/model-profiles-CV_sUuPf.js.map +1 -0
- package/dist/assets/options-Df_1Dtn8.css +1 -0
- package/dist/assets/options.js +78 -63
- package/dist/assets/options.js.map +1 -1
- package/dist/assets/page-snapshot-renderer-CE53ibi-.js +4 -0
- package/dist/assets/page-snapshot-renderer-CE53ibi-.js.map +1 -0
- package/dist/assets/session-store-B0ZPGm7d.js +77 -0
- package/dist/assets/session-store-B0ZPGm7d.js.map +1 -0
- package/dist/assets/side_panel.css +1 -1
- package/dist/assets/side_panel.js +478 -439
- package/dist/assets/side_panel.js.map +1 -1
- package/dist/icons/badges/version.svg +4 -4
- package/dist/manifest.json +6 -3
- package/dist/offscreen/offscreen.js +10 -8
- package/dist/options.html +3 -12
- package/dist/side_panel.html +120 -32
- package/package.json +1 -1
- package/src/install-mode.js +128 -0
- package/src/locales/cli.json +24 -0
- package/src/rag/install.js +4 -0
- package/src/server.js +3 -1
- package/dist/assets/i18n-CohqPkkN.js.map +0 -1
- package/dist/assets/model-profiles-BS2LIjxf.js +0 -2
- package/dist/assets/model-profiles-BS2LIjxf.js.map +0 -1
- package/dist/assets/options-CE9-fjJV.css +0 -1
- package/dist/assets/session-store-DwXNnVF5.js +0 -100
- package/dist/assets/session-store-DwXNnVF5.js.map +0 -1
package/dist/options.html
CHANGED
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title data-i18n="settings.docTitle">AI Helper - 配置</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/i18n-
|
|
8
|
-
<script type="module" crossorigin src="/assets/model-profiles-
|
|
7
|
+
<script type="module" crossorigin src="/assets/i18n-MmYITlVj.js"></script>
|
|
8
|
+
<script type="module" crossorigin src="/assets/model-profiles-CV_sUuPf.js"></script>
|
|
9
9
|
<script type="module" crossorigin src="/assets/options.js"></script>
|
|
10
10
|
<script type="module" crossorigin src="/assets/modulepreload-polyfill-P2Xu9kJm.js"></script>
|
|
11
|
-
<link rel="stylesheet" crossorigin href="/assets/options-
|
|
11
|
+
<link rel="stylesheet" crossorigin href="/assets/options-Df_1Dtn8.css">
|
|
12
12
|
</head>
|
|
13
13
|
<body>
|
|
14
14
|
<div class="container">
|
|
@@ -440,14 +440,6 @@
|
|
|
440
440
|
<span class="reflection-toggle-slider"></span>
|
|
441
441
|
</label>
|
|
442
442
|
</div>
|
|
443
|
-
<div class="reflection-toggle-row" id="toolReflectionSection">
|
|
444
|
-
<span class="reflection-row-icon">🔧</span>
|
|
445
|
-
<span class="reflection-row-text"><span data-i18n="reflection.toolReflection">工具级反思</span><span class="reflection-row-hint" data-i18n="reflection.toolReflectionHint">(工具执行后评估结果)</span></span>
|
|
446
|
-
<label class="reflection-toggle-switch">
|
|
447
|
-
<input type="checkbox" id="toolReflectionEnabled" checked>
|
|
448
|
-
<span class="reflection-toggle-slider"></span>
|
|
449
|
-
</label>
|
|
450
|
-
</div>
|
|
451
443
|
<div class="reflection-toggle-row" id="subtaskReflectionSection">
|
|
452
444
|
<span class="reflection-row-icon">📋</span>
|
|
453
445
|
<span class="reflection-row-text"><span data-i18n="reflection.subtaskReflection">子任务反思</span><span class="reflection-row-hint" data-i18n="reflection.subtaskReflectionHint">(高级功能,默认关闭)</span></span>
|
|
@@ -462,7 +454,6 @@
|
|
|
462
454
|
<h3 data-i18n="reflection.configGuide">💡 反思配置说明</h3>
|
|
463
455
|
<p>
|
|
464
456
|
<strong data-i18n="reflection.guidePostReflection">后置反思</strong><span data-i18n="reflection.guidePostReflectionDesc">:在推理循环结束后,AI 会对最终结果进行自我评估。如果评分低于阈值,会自动修订或重新执行。</span><br>
|
|
465
|
-
<strong data-i18n="reflection.guideToolReflection">工具级反思</strong><span data-i18n="reflection.guideToolReflectionDesc">:在每次工具调用后,AI 会自动检查执行结果是否符合预期,遇到错误或异常时调整策略。</span><br>
|
|
466
457
|
<strong data-i18n="reflection.guideSubtaskReflection">子任务反思</strong><span data-i18n="reflection.guideSubtaskReflectionDesc">:对于复杂任务拆解后的子任务进行单独评估,默认关闭(高级功能)。</span><br>
|
|
467
458
|
<span data-i18n="reflection.guideTip">• 启用反思会增加 API 调用次数,建议根据需求权衡</span>
|
|
468
459
|
</p>
|
package/dist/side_panel.html
CHANGED
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title data-i18n="header.docTitle">AI Helper - 模型问答</title>
|
|
7
7
|
<script type="module" crossorigin src="/assets/rolldown-runtime-C0FnF6B9.js"></script>
|
|
8
|
-
<script type="module" crossorigin src="/assets/i18n-
|
|
9
|
-
<script type="module" crossorigin src="/assets/model-profiles-
|
|
10
|
-
<script type="module" crossorigin src="/assets/session-store-
|
|
11
|
-
<script type="module" crossorigin src="/assets/agent-store-
|
|
8
|
+
<script type="module" crossorigin src="/assets/i18n-MmYITlVj.js"></script>
|
|
9
|
+
<script type="module" crossorigin src="/assets/model-profiles-CV_sUuPf.js"></script>
|
|
10
|
+
<script type="module" crossorigin src="/assets/session-store-B0ZPGm7d.js"></script>
|
|
11
|
+
<script type="module" crossorigin src="/assets/agent-store-DOyMdB_7.js"></script>
|
|
12
12
|
<script type="module" crossorigin src="/assets/side_panel.js"></script>
|
|
13
13
|
<script type="module" crossorigin src="/assets/modulepreload-polyfill-P2Xu9kJm.js"></script>
|
|
14
14
|
<link rel="stylesheet" crossorigin href="/assets/side_panel.css">
|
|
@@ -308,13 +308,22 @@
|
|
|
308
308
|
<!-- 工具列表由 JS 动态生成 -->
|
|
309
309
|
</div>
|
|
310
310
|
<div class="modal-actions">
|
|
311
|
-
<
|
|
312
|
-
<
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
311
|
+
<div class="tool-toggles">
|
|
312
|
+
<label class="tool-preselect-toggle" id="toolsPreselectToggleLabel" data-i18n-title="toolPanel.preselectHint" title="开启:AI 先判断哪些工具可能用得上,只传相关工具。好处是 Token 省了,但万一判断不准,漏掉了关键工具,任务可能做不好 关闭:全部启用的工具一次性给模型。没有判断开销,启动更快,但工具太多会浪费 Token">
|
|
313
|
+
<input type="checkbox" id="toolsPreselectToggle" checked style="display: none;">
|
|
314
|
+
<span class="toggle-switch"></span>
|
|
315
|
+
<span id="toolsPreselectToggleText" style="font-size: 12px; color: #666;" data-i18n="toolPanel.preselect">工具预筛选</span>
|
|
316
|
+
</label>
|
|
317
|
+
<label class="tool-preselect-toggle" id="toolConfirmToggleLabel" data-i18n-title="toolPanel.confirmHint" title="启用后,当模型执行敏感操作(工具调用、命令执行等)时,会弹出确认框等待用户确认。 关闭后,所有操作将直接放行执行,无需确认。">
|
|
318
|
+
<input type="checkbox" id="toolConfirmToggle" checked style="display: none;">
|
|
319
|
+
<span class="toggle-switch"></span>
|
|
320
|
+
<span id="toolConfirmToggleText" style="font-size: 12px; color: #666;" data-i18n="react.toolConfirmation">敏感操作确认</span>
|
|
321
|
+
</label>
|
|
322
|
+
</div>
|
|
323
|
+
<div class="modal-btns">
|
|
324
|
+
<button class="modal-btn cancel" id="toolsPopupCancel" data-i18n="common.cancel">取消</button>
|
|
325
|
+
<button class="modal-btn confirm" id="toolsPopupSave" style="background: #667eea;" data-i18n="common.save">保存</button>
|
|
326
|
+
</div>
|
|
318
327
|
</div>
|
|
319
328
|
</div>
|
|
320
329
|
</div>
|
|
@@ -447,13 +456,91 @@
|
|
|
447
456
|
</div>
|
|
448
457
|
|
|
449
458
|
<div class="input-container">
|
|
450
|
-
<div class="input-
|
|
451
|
-
<div class="input-
|
|
459
|
+
<div class="input-bottom-row">
|
|
460
|
+
<div class="input-bottom-left">
|
|
461
|
+
<div class="input-add-wrapper">
|
|
462
|
+
<button class="input-add-btn" id="inputAddBtn" type="button" data-i18n-title="input.addMenuTitle" title="添加内容" aria-expanded="false"><span class="input-add-icon">+</span></button>
|
|
463
|
+
<div class="input-add-menu" id="inputAddMenu" style="display:none;">
|
|
464
|
+
<div class="input-add-nav">
|
|
465
|
+
<!-- 选择器直达组①(/ 弹窗):提示词 / 技能 / MCP;点击直接打开弹窗并定位对应 Tab -->
|
|
466
|
+
<button class="input-add-item" id="promptTriggerBtn" type="button">
|
|
467
|
+
<svg viewBox="0 0 1024 1024" width="16" height="16" fill="currentColor"><path d="M274.090667 107.861333l43.235555 116.792889 116.792889 43.235556-116.792889 43.235555-43.235555 116.736-43.235556-116.792889-116.736-43.235555 116.736-43.235556 43.235556-116.736zM717.937778 532.138667l51.825778 140.117333 140.117333 51.882667-140.117333 51.882666-51.882667 140.117334-51.825778-140.117334-140.174222-51.882666 140.174222-51.882667 51.825778-140.117333zM699.278222 190.350222a36.977778 36.977778 0 1 0-64.056889-36.977778L219.192889 873.927111a36.977778 36.977778 0 1 0 64.056889 36.977778l416.028444-720.554667z"/></svg>
|
|
468
|
+
<span class="add-item-label" data-i18n="input.addMenuPrompt">提示词</span>
|
|
469
|
+
<svg class="add-item-chevron" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
|
470
|
+
</button>
|
|
471
|
+
<button class="input-add-item" id="addMenuSkillBtn" type="button" style="display:none;">
|
|
472
|
+
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2L3 14h7l-1 8 10-12h-7l1-8z"/></svg>
|
|
473
|
+
<span class="add-item-label" data-i18n="promptSelector.skills">技能</span>
|
|
474
|
+
<svg class="add-item-chevron" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
|
475
|
+
</button>
|
|
476
|
+
<button class="input-add-item" id="addMenuMcpBtn" type="button" style="display:none;">
|
|
477
|
+
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="2" width="20" height="8" rx="2"/><rect x="2" y="14" width="20" height="8" rx="2"/><path d="M6 6h.01M6 18h.01"/></svg>
|
|
478
|
+
<span class="add-item-label">MCP</span>
|
|
479
|
+
<svg class="add-item-chevron" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
|
480
|
+
</button>
|
|
481
|
+
<div class="input-add-divider" role="separator"></div>
|
|
482
|
+
<!-- 选择器直达组②(@ 弹窗):网页 / 知识库 / 助手 / 代理 -->
|
|
483
|
+
<button class="input-add-item" id="addMenuPageBtn" type="button">
|
|
484
|
+
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M2 12h20"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
|
|
485
|
+
<span class="add-item-label" data-i18n="promptSelector.pages">网页</span>
|
|
486
|
+
<svg class="add-item-chevron" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
|
487
|
+
</button>
|
|
488
|
+
<button class="input-add-item" id="addMenuKnowledgeBtn" type="button" style="display:none;">
|
|
489
|
+
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>
|
|
490
|
+
<span class="add-item-label" data-i18n="promptSelector.knowledge">知识库</span>
|
|
491
|
+
<svg class="add-item-chevron" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
|
492
|
+
</button>
|
|
493
|
+
<button class="input-add-item" id="addMenuAgentBtn" type="button">
|
|
494
|
+
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
|
|
495
|
+
<span class="add-item-label" data-i18n="promptSelector.agents">助手</span>
|
|
496
|
+
<svg class="add-item-chevron" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
|
497
|
+
</button>
|
|
498
|
+
<button class="input-add-item" id="addMenuProxyBtn" type="button" style="display:none;">
|
|
499
|
+
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 3h5v5"/><path d="M4 20L21 3"/><path d="M21 16v5h-5"/><path d="M15 15l6 6"/><path d="M4 4l5 5"/></svg>
|
|
500
|
+
<span class="add-item-label" data-i18n="promptSelector.proxies">代理</span>
|
|
501
|
+
<svg class="add-item-chevron" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
|
502
|
+
</button>
|
|
503
|
+
<button class="input-add-item" id="addMenuWorkspaceBtn" type="button" style="display:none;">
|
|
504
|
+
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>
|
|
505
|
+
<span class="add-item-label" data-i18n="fileSelector.workspaceTitle">工作目录</span>
|
|
506
|
+
<svg class="add-item-chevron" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
|
507
|
+
</button>
|
|
508
|
+
<div class="input-add-divider" role="separator"></div>
|
|
509
|
+
<button class="input-add-item" id="screenshotBtn" type="button" style="display:none;">
|
|
510
|
+
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/><circle cx="12" cy="13" r="4"/></svg>
|
|
511
|
+
<span class="add-item-label" data-i18n="input.addMenuScreenshot">截图</span>
|
|
512
|
+
<svg class="add-item-chevron" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
|
513
|
+
</button>
|
|
514
|
+
<button class="input-add-item" id="fileAttachBtn" type="button" style="display:none;" data-i18n-title="input.uploadFile" title="上传文件(PDF/Word/Excel/文本)">
|
|
515
|
+
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>
|
|
516
|
+
<span class="add-item-label" data-i18n="input.addMenuFile">附件</span>
|
|
517
|
+
</button>
|
|
518
|
+
<div class="input-add-menu-switches" id="inputAddMenuSwitches">
|
|
519
|
+
<div class="input-add-menu-switches-title" data-i18n="input.addMenuSwitches">开关</div>
|
|
520
|
+
</div>
|
|
521
|
+
</div>
|
|
522
|
+
<div class="input-add-panel" id="inputAddPanel" style="display:none;">
|
|
523
|
+
<div class="input-add-panel-search-wrap" id="inputAddPanelSearchWrap">
|
|
524
|
+
<svg class="input-add-panel-search-icon" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="M21 21l-4.35-4.35"/></svg>
|
|
525
|
+
<input class="input-add-panel-search" id="inputAddPanelSearch" type="text" placeholder="搜索…">
|
|
526
|
+
<button class="input-add-panel-search-clear" id="inputAddPanelSearchClear" type="button" aria-label="清除搜索" style="display:none;">
|
|
527
|
+
<svg viewBox="0 0 24 24" width="10" height="10" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><path d="M18 6L6 18"/><path d="M6 6l12 12"/></svg>
|
|
528
|
+
</button>
|
|
529
|
+
<button class="input-add-panel-manage" id="inputAddPanelManage" type="button" style="display:none;">
|
|
530
|
+
<svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M12 5v14"/><path d="M5 12h14"/></svg>
|
|
531
|
+
</button>
|
|
532
|
+
</div>
|
|
533
|
+
<div class="input-add-panel-list" id="inputAddPanelList"></div>
|
|
534
|
+
</div>
|
|
535
|
+
</div>
|
|
536
|
+
</div>
|
|
537
|
+
<!-- 记忆组(原工具栏左组迁移) -->
|
|
452
538
|
<div class="toolbar-chip-group" id="memoryGroup">
|
|
453
539
|
<label class="check-toggle core-feature" for="isolateChatBtn" data-i18n-title="toggle.memoryHint" title="开启后,前文问答将作为上下文(默认全部,条数可配置)">
|
|
454
540
|
<input type="checkbox" id="isolateChatBtn">
|
|
455
541
|
<span class="checkmark"></span>
|
|
456
542
|
<span class="tool-toggle-label" data-i18n="memory.label">记忆</span>
|
|
543
|
+
<span class="toggle-icon" aria-hidden="true">🧠</span>
|
|
457
544
|
</label>
|
|
458
545
|
<label class="memory-limit-label" id="memoryLimitLabel" for="isolateChatBtn"></label>
|
|
459
546
|
<div class="memory-limit-dropdown" id="memoryLimitDropdown">
|
|
@@ -483,20 +570,28 @@
|
|
|
483
570
|
<input type="checkbox" id="enableToolsBtn">
|
|
484
571
|
<span class="checkmark"></span>
|
|
485
572
|
<span class="tool-toggle-label" data-i18n="toggle.tools">工具</span>
|
|
573
|
+
<span class="toggle-icon" aria-hidden="true">🔧</span>
|
|
486
574
|
</label>
|
|
487
|
-
|
|
575
|
+
<!-- 悬停提示由 tool-panel.js 动态组合(基础提示 + 两行开关状态),不挂 data-i18n-title 以免被 applyI18n 覆盖 -->
|
|
576
|
+
<button class="tool-config-btn" id="toolsConfigBtn" title="点击打开工具详细配置">
|
|
488
577
|
<span class="tools-config-count" id="toolsConfigCount">0</span>
|
|
578
|
+
<!-- 右上角状态角标:白底胶囊内两粒色块(左=预筛选/右=确认),由 updateToolsConfigIndicators 切换 .on(开显色/关浅灰) -->
|
|
579
|
+
<span class="tools-config-flags" id="toolsConfigFlags" aria-hidden="true">
|
|
580
|
+
<span class="tools-config-flag flag-preselect" id="toolsConfigFlagPreselect"></span>
|
|
581
|
+
<span class="tools-config-flag flag-confirm" id="toolsConfigFlagConfirm"></span>
|
|
582
|
+
</span>
|
|
489
583
|
</button>
|
|
490
584
|
</div>
|
|
491
|
-
<div class="toolbar-chip-group">
|
|
585
|
+
<div class="toolbar-chip-group" id="selectionToggleGroup">
|
|
492
586
|
<label class="check-toggle core-feature" data-i18n-title="toggle.selectionHint" title="开启后,划词选中内容时可快速提问">
|
|
493
587
|
<input type="checkbox" id="enableSelectionQueryBtn">
|
|
494
588
|
<span class="checkmark"></span>
|
|
495
589
|
<span class="tool-toggle-label" data-i18n="toggle.selection">划词</span>
|
|
590
|
+
<span class="toggle-icon" aria-hidden="true">✏️</span>
|
|
496
591
|
</label>
|
|
497
592
|
</div>
|
|
498
593
|
</div>
|
|
499
|
-
<div class="input-
|
|
594
|
+
<div class="input-bottom-right">
|
|
500
595
|
<div class="agent-selector-wrapper" id="agentSelectorWrapper">
|
|
501
596
|
<button class="agent-selector-btn" id="agentSelectorBtn" data-i18n-title="header.switchAgent" title="切换助手">
|
|
502
597
|
<span class="agent-selector-label" id="agentSelectorText" data-i18n="header.defaultAssistant">🤖 默认助手</span>
|
|
@@ -552,6 +647,9 @@
|
|
|
552
647
|
</div>
|
|
553
648
|
</div>
|
|
554
649
|
</div>
|
|
650
|
+
<button class="input-inner-btn send-inner-btn" id="sendBtn" data-i18n-title="input.send" title="发送">
|
|
651
|
+
<svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor"><path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8-8-8z"/></svg>
|
|
652
|
+
</button>
|
|
555
653
|
</div>
|
|
556
654
|
</div>
|
|
557
655
|
<div class="selection-indicator" id="selectionIndicator">
|
|
@@ -597,7 +695,7 @@
|
|
|
597
695
|
<button class="prompt-tab" data-tab="proxies" data-i18n="promptSelector.proxies">代理</button>
|
|
598
696
|
<div class="prompt-merged-title" id="agentAtMergedTitle" data-i18n="promptSelector.mergedTitle">聚合搜索</div>
|
|
599
697
|
</div>
|
|
600
|
-
<div class="prompt-dropdown-header"><span data-i18n="promptSelector.switchHintSelect">方向键切换 · Enter选择 · Ctrl+Enter选中并关闭 · Esc取消</span><span class="agent-add-btn" id="agentAddBtn" data-i18n-title="header.addEditAssistant" title="新增/编辑助手">✚</span><span class="agent-add-btn" id="proxyAddBtn" data-i18n-title="header.addEditAgent" title="新增/编辑代理" style="display:none;">✚</span><span class="agent-add-btn" id="knowledgeAddBtn" data-i18n-title="header.manageKnowledge" title="管理知识库" style="display:none;">✚</span></div>
|
|
698
|
+
<div class="prompt-dropdown-header"><span data-i18n="promptSelector.switchHintSelect">方向键切换 · Enter选择 · Ctrl+Enter选中并关闭 · Esc取消</span><span class="agent-add-btn" id="agentAddBtn" data-i18n-title="header.addEditAssistant" title="新增/编辑助手">✚</span><span class="agent-add-btn" id="proxyAddBtn" data-i18n-title="header.addEditAgent" title="新增/编辑代理" style="display:none;">✚</span><span class="agent-add-btn" id="knowledgeAddBtn" data-i18n-title="header.manageKnowledge" title="管理知识库" style="display:none;">✚</span><span class="agent-add-btn" id="pageAddBtn" data-i18n-title="pageSelector.openNewTab" title="新建标签页" style="display:none;">✚</span></div>
|
|
601
699
|
<div id="agentAtList"></div>
|
|
602
700
|
<div id="agentPageList" style="display: none;"></div>
|
|
603
701
|
<div id="agentProxyList" style="display: none;"></div>
|
|
@@ -607,7 +705,11 @@
|
|
|
607
705
|
<!-- $ 工作目录文件选择器 -->
|
|
608
706
|
<div class="prompt-selector" id="fileAtSelector" style="display: none;">
|
|
609
707
|
<div class="prompt-dropdown" id="fileAtDropdown">
|
|
610
|
-
<div class="
|
|
708
|
+
<div class="file-at-title">
|
|
709
|
+
<span class="file-at-title-label" data-i18n="fileSelector.workspaceTitle">工作目录</span>
|
|
710
|
+
<span class="file-at-title-path" id="fileAtTitlePath"></span>
|
|
711
|
+
</div>
|
|
712
|
+
<div class="prompt-dropdown-header"><span class="prompt-dropdown-header-text" data-i18n="fileSelector.switchHint">方向键切换 · Enter添加到文件问答 · Esc取消</span><span class="agent-add-btn" id="fileAtWorkspaceOpenBtn" data-i18n-title="workspace.openPanel" title="打开工作目录面板">✚</span></div>
|
|
611
713
|
<div id="fileAtList"></div>
|
|
612
714
|
</div>
|
|
613
715
|
</div>
|
|
@@ -619,21 +721,7 @@
|
|
|
619
721
|
<div class="input-disclaimer" data-i18n="input.aiDisclaimer">内容由 AI 生成,仅供参考</div>
|
|
620
722
|
<div class="input-wrapper">
|
|
621
723
|
<input type="file" id="fileInput" multiple accept=".png,.jpg,.jpeg,.gif,.webp,.bmp,.svg,.ico,.pdf,.docx,.xlsx,.xls,.txt,.md,.json,.js,.jsx,.ts,.tsx,.html,.css,.scss,.less,.xml,.yaml,.yml,.py,.java,.c,.cpp,.h,.go,.rs,.rb,.php,.sql,.sh,.bash,.zsh,.cfg,.ini,.toml,.conf,.log,.csv,.tsv,.env,.vue,.svelte,.astro,.rtf" style="display:none;">
|
|
622
|
-
<button class="input-inner-btn prompt-inner-btn" id="promptTriggerBtn" data-i18n-title="input.atHint" title="提示词 (单击) / 网页 (Ctrl/Cmd+单击)">
|
|
623
|
-
<svg viewBox="0 0 1024 1024" width="18" height="18"><path d="M274.090667 107.861333l43.235555 116.792889 116.792889 43.235556-116.792889 43.235555-43.235555 116.736-43.235556-116.792889-116.736-43.235555 116.736-43.235556 43.235556-116.736zM717.937778 532.138667l51.825778 140.117333 140.117333 51.882667-140.117333 51.882666-51.882667 140.117334-51.825778-140.117334-140.174222-51.882666 140.174222-51.882667 51.825778-140.117333zM699.278222 190.350222a36.977778 36.977778 0 1 0-64.056889-36.977778L219.192889 873.927111a36.977778 36.977778 0 1 0 64.056889 36.977778l416.028444-720.554667z" fill="currentColor"/></svg>
|
|
624
|
-
</button>
|
|
625
724
|
<textarea id="userInput" data-i18n-placeholder="input.placeholder" placeholder="输入'/'快捷提示、'@'切换助手或网页、'$'选择工作目录文件、'↑↓'切换历史输入、Esc清空" rows="1"></textarea>
|
|
626
|
-
<div class="input-right-buttons">
|
|
627
|
-
<button class="input-inner-btn screenshot-inner-btn" id="screenshotBtn" data-i18n-title="input.screenshot" title="截取当前页面(Ctrl/Shift+点击可区域截图)" style="display:none;">
|
|
628
|
-
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/><circle cx="12" cy="13" r="4"/></svg>
|
|
629
|
-
</button>
|
|
630
|
-
<button class="input-inner-btn file-attach-btn" id="fileAttachBtn" data-i18n-title="input.uploadFile" title="上传文件(PDF/Word/Excel/文本)" style="display:none;">
|
|
631
|
-
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>
|
|
632
|
-
</button>
|
|
633
|
-
<button class="input-inner-btn send-inner-btn" id="sendBtn" data-i18n-title="input.send" title="发送">
|
|
634
|
-
<svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor"><path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8-8-8z"/></svg>
|
|
635
|
-
</button>
|
|
636
|
-
</div>
|
|
637
725
|
</div>
|
|
638
726
|
</div>
|
|
639
727
|
</div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-helper-agent",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "AI Helper Agent - Local file access and system command execution proxy for Chrome extension / AI Helper 代理服务,为 Chrome 扩展提供本地文件读写和系统命令执行",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/server.js",
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// agent/src/install-mode.js - 安装模式检测与内嵌运行时工具函数
|
|
2
|
+
//
|
|
3
|
+
// 支持两种运行模式,所有功能模块通过本模块获取路径/配置,无需感知具体模式:
|
|
4
|
+
// 1. 内嵌模式:由 install.sh / install.ps1 安装,runtime + app 均在 ~/.ai-helper-agent/ 下
|
|
5
|
+
// 2. npm 全局模式:由 npm install -g ai-helper-agent 安装(传统路径)
|
|
6
|
+
//
|
|
7
|
+
// 判断依据:agent 包入口 (bin/agent.js) 所在路径是否在 ~/.ai-helper-agent/app/ 下。
|
|
8
|
+
// 设计原则:所有改动向后兼容——npm -g 用户 isEmbedded()=false,走原逻辑。
|
|
9
|
+
|
|
10
|
+
import { homedir } from 'os';
|
|
11
|
+
import { join, dirname, resolve } from 'path';
|
|
12
|
+
import { readFileSync, existsSync } from 'fs';
|
|
13
|
+
import { fileURLToPath } from 'url';
|
|
14
|
+
|
|
15
|
+
const EMBEDDED_ROOT = join(homedir(), '.ai-helper-agent');
|
|
16
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
// 本模块位于 <agent-package>/src/,向上两级到包根
|
|
18
|
+
const PACKAGE_ROOT = resolve(__dirname, '..');
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 是否运行在内嵌模式(由 install.sh 安装的自管理环境)
|
|
22
|
+
*/
|
|
23
|
+
export function isEmbedded() {
|
|
24
|
+
return PACKAGE_ROOT.startsWith(EMBEDDED_ROOT);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 内嵌模式的根目录(~/.ai-helper-agent/),非内嵌模式返回 null
|
|
29
|
+
*/
|
|
30
|
+
export function getEmbeddedRoot() {
|
|
31
|
+
return isEmbedded() ? EMBEDDED_ROOT : null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 获取 Node 可执行文件路径
|
|
36
|
+
* - 内嵌模式:~/.ai-helper-agent/runtime/bin/node
|
|
37
|
+
* - 全局模式:process.execPath(当前正在运行的 node)
|
|
38
|
+
*/
|
|
39
|
+
export function getNodePath() {
|
|
40
|
+
if (!isEmbedded()) return process.execPath;
|
|
41
|
+
const candidate = join(EMBEDDED_ROOT, 'runtime', 'bin', 'node');
|
|
42
|
+
return existsSync(candidate) ? candidate : process.execPath;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 获取 npm 可执行文件路径
|
|
47
|
+
* - 内嵌模式:~/.ai-helper-agent/runtime/bin/npm
|
|
48
|
+
* - 全局模式:'npm'(系统 PATH 中的)
|
|
49
|
+
*/
|
|
50
|
+
export function getNpmPath() {
|
|
51
|
+
if (!isEmbedded()) return 'npm';
|
|
52
|
+
const isWin = process.platform === 'win32';
|
|
53
|
+
const candidate = isWin
|
|
54
|
+
? join(EMBEDDED_ROOT, 'runtime', 'npm.cmd')
|
|
55
|
+
: join(EMBEDDED_ROOT, 'runtime', 'bin', 'npm');
|
|
56
|
+
return existsSync(candidate) ? candidate : 'npm';
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 读取镜像探测结果(~/.ai-helper-agent/mirrors.json)
|
|
61
|
+
* 文件不存在时返回 null(npm -g 用户通常没有此文件)
|
|
62
|
+
* @returns {{ registry?: string, node?: string, huggingface?: string, detectedAt?: string } | null}
|
|
63
|
+
*/
|
|
64
|
+
export function readMirrors() {
|
|
65
|
+
try {
|
|
66
|
+
const mirrorsFile = join(EMBEDDED_ROOT, 'mirrors.json');
|
|
67
|
+
if (!existsSync(mirrorsFile)) return null;
|
|
68
|
+
// 剥 BOM:Windows PowerShell 5.1 的 Set-Content -Encoding UTF8 会写入 BOM,导致 JSON.parse 抛错
|
|
69
|
+
const text = readFileSync(mirrorsFile, 'utf-8').replace(/^\uFEFF/, '');
|
|
70
|
+
return JSON.parse(text);
|
|
71
|
+
} catch {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 获取当前应使用的 npm registry URL
|
|
78
|
+
* - 有 mirrors.json 且 registry 字段为 mirror → https://registry.npmmirror.com
|
|
79
|
+
* - 否则 → undefined(使用 npm 默认)
|
|
80
|
+
* @returns {string|undefined}
|
|
81
|
+
*/
|
|
82
|
+
export function getRegistryUrl() {
|
|
83
|
+
const mirrors = readMirrors();
|
|
84
|
+
if (!mirrors) return undefined;
|
|
85
|
+
if (mirrors.registry === 'mirror') return 'https://registry.npmmirror.com';
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 获取 HuggingFace 模型下载端点
|
|
91
|
+
* - 有 mirrors.json 且 huggingface 为 mirror → https://hf-mirror.com/
|
|
92
|
+
* - 否则 → undefined(使用 transformers 默认)
|
|
93
|
+
* @returns {string|undefined}
|
|
94
|
+
*/
|
|
95
|
+
export function getHfEndpoint() {
|
|
96
|
+
const mirrors = readMirrors();
|
|
97
|
+
if (!mirrors) return undefined;
|
|
98
|
+
if (mirrors.huggingface === 'mirror') return 'https://hf-mirror.com/';
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* 获取主动停止标记文件路径(用于 autostart 检查)
|
|
104
|
+
*/
|
|
105
|
+
export function getStoppedFlagPath() {
|
|
106
|
+
return join(EMBEDDED_ROOT, '.stopped');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 获取 INSTALL_MANIFEST.json 路径与内容
|
|
111
|
+
*/
|
|
112
|
+
export function readInstallManifest() {
|
|
113
|
+
try {
|
|
114
|
+
const file = join(EMBEDDED_ROOT, 'INSTALL_MANIFEST.json');
|
|
115
|
+
if (!existsSync(file)) return null;
|
|
116
|
+
const text = readFileSync(file, 'utf-8').replace(/^\uFEFF/, '');
|
|
117
|
+
return JSON.parse(text);
|
|
118
|
+
} catch {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* agent 包根目录(无论哪种模式,都是本文件所在包的根)
|
|
125
|
+
*/
|
|
126
|
+
export function getAgentPackageRoot() {
|
|
127
|
+
return PACKAGE_ROOT;
|
|
128
|
+
}
|
package/src/locales/cli.json
CHANGED
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
"cmdConfig": " config 查看当前配置",
|
|
12
12
|
"cmdHelp": " help 显示此帮助信息",
|
|
13
13
|
"cmdRag": " rag 管理 RAG 可选依赖 (status | install)",
|
|
14
|
+
"cmdUpdate": " update 检查并更新到最新版本 (--check 仅检查)",
|
|
15
|
+
"cmdUninstall": " uninstall 一键卸载代理端",
|
|
16
|
+
"cmdAutostart": " autostart 开机自启管理 (on | off)",
|
|
14
17
|
"startupOptions": "启动选项:",
|
|
15
18
|
"optBackground": " --background, -b 后台运行(守护进程模式)",
|
|
16
19
|
"optPort": " --port <端口> 设置监听端口 (默认: 18910)",
|
|
@@ -69,6 +72,15 @@
|
|
|
69
72
|
"ragRestartAdvice": "提示:若多次安装失败,可尝试重启代理服务(aha restart)后再重试。",
|
|
70
73
|
"ragUnknownSub": "未知的 rag 子命令: {sub}",
|
|
71
74
|
"ragHelpUsage": "用法: aha rag <status|install>",
|
|
75
|
+
"updateLatest": "已是最新版本 v{version}",
|
|
76
|
+
"updateAvailable": "发现新版本: v{current} → v{latest}(运行 aha update 更新)",
|
|
77
|
+
"updateInstalling": "正在更新 v{current} → v{latest}...",
|
|
78
|
+
"updateFailed": "更新失败,请稍后重试",
|
|
79
|
+
"updateSuccess": "✅ 已更新至 v{version},服务已重启",
|
|
80
|
+
"uninstallAutostartRemoved": "已移除开机自启",
|
|
81
|
+
"uninstallComplete": "✅ 卸载完成。用户数据已保留在 {dataDir}",
|
|
82
|
+
"autostartDisabled": "开机自启已关闭",
|
|
83
|
+
"autostartUseScript": "开启自启请重新运行安装脚本,或手动配置系统服务",
|
|
72
84
|
"restartHelper": {
|
|
73
85
|
"waitingOldExit": "等待老进程 {pid} 退出...",
|
|
74
86
|
"waitOldTimeout": "等待老进程退出超时,尝试强制终止...",
|
|
@@ -91,6 +103,9 @@
|
|
|
91
103
|
"cmdConfig": " config View current configuration",
|
|
92
104
|
"cmdHelp": " help Show this help message",
|
|
93
105
|
"cmdRag": " rag Manage RAG optional dependencies (status | install)",
|
|
106
|
+
"cmdUpdate": " update Check and update to latest (--check for info only)",
|
|
107
|
+
"cmdUninstall": " uninstall One-click uninstall agent",
|
|
108
|
+
"cmdAutostart": " autostart Manage auto-start (on | off)",
|
|
94
109
|
"startupOptions": "Startup Options:",
|
|
95
110
|
"optBackground": " --background, -b Run in background (daemon mode)",
|
|
96
111
|
"optPort": " --port <port> Set listening port (default: 18910)",
|
|
@@ -149,6 +164,15 @@
|
|
|
149
164
|
"ragRestartAdvice": "Tip: if installation keeps failing, try restarting the agent (aha restart) and retry.",
|
|
150
165
|
"ragUnknownSub": "Unknown rag subcommand: {sub}",
|
|
151
166
|
"ragHelpUsage": "Usage: aha rag <status|install>",
|
|
167
|
+
"updateLatest": "Already at latest version v{version}",
|
|
168
|
+
"updateAvailable": "New version available: v{current} → v{latest} (run aha update)",
|
|
169
|
+
"updateInstalling": "Updating v{current} → v{latest}...",
|
|
170
|
+
"updateFailed": "Update failed, please retry",
|
|
171
|
+
"updateSuccess": "✅ Updated to v{version}, service restarted",
|
|
172
|
+
"uninstallAutostartRemoved": "Auto-start removed",
|
|
173
|
+
"uninstallComplete": "✅ Uninstall complete. User data kept at {dataDir}",
|
|
174
|
+
"autostartDisabled": "Auto-start disabled",
|
|
175
|
+
"autostartUseScript": "To enable auto-start, re-run the install script or configure system service manually",
|
|
152
176
|
"restartHelper": {
|
|
153
177
|
"waitingOldExit": "Waiting for old process {pid} to exit...",
|
|
154
178
|
"waitOldTimeout": "Wait for old process exit timeout, trying force kill...",
|
package/src/rag/install.js
CHANGED
|
@@ -27,6 +27,7 @@ import { resetRagDetection, detectRagAvailable, getLastRagProbeError, isNodeVers
|
|
|
27
27
|
import { stopProcessTree } from '../process-tree.js';
|
|
28
28
|
import { logSystem } from '../logger.js';
|
|
29
29
|
import { t as translate, parseAcceptLanguage } from '../i18n.js';
|
|
30
|
+
import { getRegistryUrl } from '../install-mode.js';
|
|
30
31
|
|
|
31
32
|
// ---- 安装清单(单一事实来源:包自身 package.json 的 ragDependencies 字段) ----
|
|
32
33
|
//
|
|
@@ -95,7 +96,10 @@ export function buildRagInstallCommand(opts = {}) {
|
|
|
95
96
|
// 包损坏/被裁剪:拒绝构建(无包名参数的 npm install 会按依赖树重算包目录,不可接受)
|
|
96
97
|
throw new Error('ragDependencies missing in package.json');
|
|
97
98
|
}
|
|
99
|
+
// 如果有探测出的镜像 registry,自动注入(npm -g 用户无 mirrors.json 时此值为 undefined)
|
|
100
|
+
const registryUrl = opts.registry ?? getRegistryUrl();
|
|
98
101
|
const baseArgs = ['install', '--no-save', '--no-audit', '--no-fund'];
|
|
102
|
+
if (registryUrl) baseArgs.push(`--registry=${registryUrl}`);
|
|
99
103
|
const cwd = getAgentRoot();
|
|
100
104
|
if (isWin) {
|
|
101
105
|
const npmCli = findWinNpmCli(execPath);
|
package/src/server.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// agent/src/server.js - HTTP Router + WebSocket 服务器
|
|
2
2
|
import http from 'http';
|
|
3
3
|
import { WebSocketServer } from 'ws';
|
|
4
|
-
import { readFileSync, createWriteStream, createReadStream, statSync, existsSync, watch } from 'fs';
|
|
4
|
+
import { readFileSync, writeFileSync, createWriteStream, createReadStream, statSync, existsSync, watch } from 'fs';
|
|
5
5
|
import { readFile, writeFile, readdir, stat, unlink, rmdir, chmod, mkdir, rename } from 'fs/promises';
|
|
6
6
|
import { join, dirname, basename, resolve, isAbsolute, relative } from 'path';
|
|
7
7
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
@@ -525,6 +525,8 @@ export function startServer() {
|
|
|
525
525
|
agentOperationInProgress = true;
|
|
526
526
|
lastOperationTime = Date.now();
|
|
527
527
|
logSystem('shutdown', { reason: 'api_request', local: isLocal, remote: remoteIp });
|
|
528
|
+
// 写入主动停止标记,阻止 autostart 自动拉起
|
|
529
|
+
try { writeFileSync(join(homedir(), '.ai-helper-agent', '.stopped'), new Date().toISOString()); } catch {}
|
|
528
530
|
jsonResponse(res, 200, { success: true, message: t('message.shuttingDown') });
|
|
529
531
|
// 延迟 200ms 再关闭,确保响应数据已送达客户端(res.end() 仅写入缓冲区,不保证客户端已接收)
|
|
530
532
|
setTimeout(() => shutdown(), 200);
|