ai-helper-agent 2.1.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.
Files changed (33) hide show
  1. package/README.md +20 -1
  2. package/README.zh-CN.md +20 -1
  3. package/bin/agent.js +150 -0
  4. package/dist/assets/{agent-store-C4hZkQT5.js → agent-store-DOyMdB_7.js} +2 -2
  5. package/dist/assets/{agent-store-C4hZkQT5.js.map → agent-store-DOyMdB_7.js.map} +1 -1
  6. package/dist/assets/background.js +84 -85
  7. package/dist/assets/background.js.map +1 -1
  8. package/dist/assets/content.js +80 -78
  9. package/dist/assets/{i18n-CAh-vB_T.js → i18n-MmYITlVj.js} +5 -5
  10. package/dist/assets/i18n-MmYITlVj.js.map +1 -0
  11. package/dist/assets/model-profiles-CV_sUuPf.js +25 -0
  12. package/dist/assets/model-profiles-CV_sUuPf.js.map +1 -0
  13. package/dist/assets/options.js +56 -56
  14. package/dist/assets/options.js.map +1 -1
  15. package/dist/assets/page-snapshot-renderer-CE53ibi-.js +4 -0
  16. package/dist/assets/page-snapshot-renderer-CE53ibi-.js.map +1 -0
  17. package/dist/assets/{session-store-uZ_LNasH.js → session-store-B0ZPGm7d.js} +4 -4
  18. package/dist/assets/{session-store-uZ_LNasH.js.map → session-store-B0ZPGm7d.js.map} +1 -1
  19. package/dist/assets/side_panel.css +1 -1
  20. package/dist/assets/side_panel.js +177 -171
  21. package/dist/assets/side_panel.js.map +1 -1
  22. package/dist/manifest.json +6 -3
  23. package/dist/offscreen/offscreen.js +6 -6
  24. package/dist/options.html +2 -11
  25. package/dist/side_panel.html +6 -6
  26. package/package.json +1 -1
  27. package/src/install-mode.js +128 -0
  28. package/src/locales/cli.json +24 -0
  29. package/src/rag/install.js +4 -0
  30. package/src/server.js +3 -1
  31. package/dist/assets/i18n-CAh-vB_T.js.map +0 -1
  32. package/dist/assets/model-profiles-CGxULM3O.js +0 -25
  33. package/dist/assets/model-profiles-CGxULM3O.js.map +0 -1
package/dist/options.html CHANGED
@@ -4,8 +4,8 @@
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-CAh-vB_T.js"></script>
8
- <script type="module" crossorigin src="/assets/model-profiles-CGxULM3O.js"></script>
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
11
  <link rel="stylesheet" crossorigin href="/assets/options-Df_1Dtn8.css">
@@ -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>
@@ -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-CAh-vB_T.js"></script>
9
- <script type="module" crossorigin src="/assets/model-profiles-CGxULM3O.js"></script>
10
- <script type="module" crossorigin src="/assets/session-store-uZ_LNasH.js"></script>
11
- <script type="module" crossorigin src="/assets/agent-store-C4hZkQT5.js"></script>
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">
@@ -695,7 +695,7 @@
695
695
  <button class="prompt-tab" data-tab="proxies" data-i18n="promptSelector.proxies">代理</button>
696
696
  <div class="prompt-merged-title" id="agentAtMergedTitle" data-i18n="promptSelector.mergedTitle">聚合搜索</div>
697
697
  </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></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>
699
699
  <div id="agentAtList"></div>
700
700
  <div id="agentPageList" style="display: none;"></div>
701
701
  <div id="agentProxyList" style="display: none;"></div>
@@ -709,7 +709,7 @@
709
709
  <span class="file-at-title-label" data-i18n="fileSelector.workspaceTitle">工作目录</span>
710
710
  <span class="file-at-title-path" id="fileAtTitlePath"></span>
711
711
  </div>
712
- <div class="prompt-dropdown-header"><span class="prompt-dropdown-header-text" data-i18n="fileSelector.switchHint">方向键切换 · Enter添加到文件问答 · Esc取消</span></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>
713
713
  <div id="fileAtList"></div>
714
714
  </div>
715
715
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-helper-agent",
3
- "version": "2.1.0",
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
+ }
@@ -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...",
@@ -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);