hunter-mate 0.1.6 → 0.1.7

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 (120) hide show
  1. package/dist/assets/extension/background/service-worker.js +193 -16
  2. package/dist/assets/extension/manifest.json +1 -1
  3. package/dist/assets/extension/package.json +4 -3
  4. package/dist/assets/server/app.module.js +2 -1
  5. package/dist/assets/server/app.module.js.map +1 -1
  6. package/dist/assets/server/auth/auth.controller.d.ts +7 -0
  7. package/dist/assets/server/auth/auth.controller.js +20 -0
  8. package/dist/assets/server/auth/auth.controller.js.map +1 -1
  9. package/dist/assets/server/auth/auth.service.d.ts +11 -0
  10. package/dist/assets/server/auth/auth.service.js +58 -1
  11. package/dist/assets/server/auth/auth.service.js.map +1 -1
  12. package/dist/assets/server/build-info.json +1 -1
  13. package/dist/assets/server/extension/extension-control.controller.d.ts +3 -0
  14. package/dist/assets/server/extension/extension-control.controller.js +1 -1
  15. package/dist/assets/server/extension/extension-control.controller.js.map +1 -1
  16. package/dist/assets/server/extension/extension-control.service.d.ts +8 -0
  17. package/dist/assets/server/extension/extension-control.service.js +38 -1
  18. package/dist/assets/server/extension/extension-control.service.js.map +1 -1
  19. package/dist/assets/server/package.json +4 -3
  20. package/dist/assets/server/recording/recording-event-queue.service.d.ts +26 -0
  21. package/dist/assets/server/recording/recording-event-queue.service.js +115 -0
  22. package/dist/assets/server/recording/recording-event-queue.service.js.map +1 -0
  23. package/dist/assets/server/recording/recording-retention.service.d.ts +21 -0
  24. package/dist/assets/server/recording/recording-retention.service.js +85 -0
  25. package/dist/assets/server/recording/recording-retention.service.js.map +1 -0
  26. package/dist/assets/server/recording/recording.controller.d.ts +11 -1
  27. package/dist/assets/server/recording/recording.controller.js +18 -2
  28. package/dist/assets/server/recording/recording.controller.js.map +1 -1
  29. package/dist/assets/server/recording/recording.module.js +10 -1
  30. package/dist/assets/server/recording/recording.module.js.map +1 -1
  31. package/dist/assets/server/recording/recording.service.d.ts +5 -1
  32. package/dist/assets/server/recording/recording.service.js +21 -6
  33. package/dist/assets/server/recording/recording.service.js.map +1 -1
  34. package/dist/commands/cache.js +3 -4
  35. package/dist/commands/doctor.js +94 -12
  36. package/dist/commands/extension.js +14 -23
  37. package/dist/commands/extras.js +2 -2
  38. package/dist/commands/job.d.ts +4 -1
  39. package/dist/commands/job.js +51 -16
  40. package/dist/commands/login.d.ts +15 -0
  41. package/dist/commands/login.js +57 -12
  42. package/dist/commands/ops.js +18 -2
  43. package/dist/commands/record.js +2 -4
  44. package/dist/commands/report.js +2 -4
  45. package/dist/commands/search.js +9 -2
  46. package/dist/commands/server.d.ts +2 -2
  47. package/dist/commands/server.js +78 -17
  48. package/dist/commands/update.js +1 -1
  49. package/dist/i18n/locales/en-US.json +3 -1
  50. package/dist/i18n/locales/zh-CN.json +3 -1
  51. package/dist/index.js +38 -2
  52. package/dist/updater.d.ts +1 -1
  53. package/dist/updater.js +22 -5
  54. package/dist/utils/command-error.d.ts +9 -0
  55. package/dist/utils/command-error.js +31 -0
  56. package/dist/utils/proxy-detect.d.ts +20 -0
  57. package/dist/utils/proxy-detect.js +96 -0
  58. package/dist/utils/script-path.d.ts +5 -0
  59. package/dist/utils/script-path.js +27 -0
  60. package/dist/version.js +1 -1
  61. package/dist/watchdog.d.ts +23 -1
  62. package/dist/watchdog.js +95 -4
  63. package/dist/web/dist/404.html +1 -0
  64. package/dist/web/dist/_next/static/chunks/166.f30be223f694f8ee.js +1 -0
  65. package/dist/web/dist/_next/static/chunks/1e6d5a0c.0488932e17ecdf24.js +15 -0
  66. package/dist/web/dist/_next/static/chunks/539-5d0e8c5c238c56f8.js +1 -0
  67. package/dist/web/dist/_next/static/chunks/589-d632233641f35681.js +1 -0
  68. package/dist/web/dist/_next/static/chunks/671.3b8e9cc96b25b6ea.js +1 -0
  69. package/dist/web/dist/_next/static/chunks/935-99f57b7d4151d9e7.js +5 -0
  70. package/dist/web/dist/_next/static/chunks/a7067448-96dd4b8457c447e8.js +1 -0
  71. package/dist/web/dist/_next/static/chunks/app/_not-found/page-fdf1a13a7656886a.js +1 -0
  72. package/dist/web/dist/_next/static/chunks/app/auth/verify/page-8e5cff53d6f7d8e1.js +1 -0
  73. package/dist/web/dist/_next/static/chunks/app/companies/page-e38a69e1929d0953.js +1 -0
  74. package/dist/web/dist/_next/static/chunks/app/entity/page-250f8a9b6d91ab19.js +1 -0
  75. package/dist/web/dist/_next/static/chunks/app/jobs/page-6a281776fec065f6.js +1 -0
  76. package/dist/web/dist/_next/static/chunks/app/layout-83e623e973c1693f.js +1 -0
  77. package/dist/web/dist/_next/static/chunks/app/logs/page-9f41d44fa1add723.js +1 -0
  78. package/dist/web/dist/_next/static/chunks/app/matching/jobs/[id]/talents/page-f57f4b7529823601.js +1 -0
  79. package/dist/web/dist/_next/static/chunks/app/matching/portraits/[id]/jobs/page-614d1e62d7b9d215.js +1 -0
  80. package/dist/web/dist/_next/static/chunks/app/page-e3392de08ae81fba.js +1 -0
  81. package/dist/web/dist/_next/static/chunks/app/parselog/page-58d3acece95b4089.js +1 -0
  82. package/dist/web/dist/_next/static/chunks/app/recordings/page-e2e2e3c3a64083fb.js +1 -0
  83. package/dist/web/dist/_next/static/chunks/app/snapshots/[id]/agent-prompt/page-fd3b7d7373b8f8b7.js +1 -0
  84. package/dist/web/dist/_next/static/chunks/app/talents/page-30748338da20d7e0.js +1 -0
  85. package/dist/web/dist/_next/static/chunks/framework-b3a558b17a070965.js +1 -0
  86. package/dist/web/dist/_next/static/chunks/main-5a4e0cd75dd7f04b.js +1 -0
  87. package/dist/web/dist/_next/static/chunks/main-app-80b038a312917d90.js +1 -0
  88. package/dist/web/dist/_next/static/chunks/pages/_app-da7d628f49271ece.js +4 -0
  89. package/dist/web/dist/_next/static/chunks/pages/_error-17756f67e0a11350.js +1 -0
  90. package/dist/web/dist/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  91. package/dist/web/dist/_next/static/chunks/webpack-1784baecc6fdcf0b.js +1 -0
  92. package/dist/web/dist/_next/static/css/db881c5b3072b88a.css +3 -0
  93. package/dist/web/dist/_next/static/css/f60d210841fab76b.css +1 -0
  94. package/dist/web/dist/_next/static/hqJ-7vr4X71DNfzZugHJ-/_buildManifest.js +1 -0
  95. package/dist/web/dist/_next/static/hqJ-7vr4X71DNfzZugHJ-/_ssgManifest.js +1 -0
  96. package/dist/web/dist/auth/verify.html +1 -0
  97. package/dist/web/dist/auth/verify.txt +8 -0
  98. package/dist/web/dist/companies.html +1 -0
  99. package/dist/web/dist/companies.txt +7 -0
  100. package/dist/web/dist/entity.html +1 -0
  101. package/dist/web/dist/entity.txt +8 -0
  102. package/dist/web/dist/index.html +1 -0
  103. package/dist/web/dist/index.txt +8 -0
  104. package/dist/web/dist/jobs.html +1 -0
  105. package/dist/web/dist/jobs.txt +7 -0
  106. package/dist/web/dist/logs.html +1 -0
  107. package/dist/web/dist/logs.txt +8 -0
  108. package/dist/web/dist/matching/jobs/placeholder/talents.html +1 -0
  109. package/dist/web/dist/matching/jobs/placeholder/talents.txt +8 -0
  110. package/dist/web/dist/matching/portraits/placeholder/jobs.html +1 -0
  111. package/dist/web/dist/matching/portraits/placeholder/jobs.txt +8 -0
  112. package/dist/web/dist/parselog.html +1 -0
  113. package/dist/web/dist/parselog.txt +8 -0
  114. package/dist/web/dist/recordings.html +1 -0
  115. package/dist/web/dist/recordings.txt +8 -0
  116. package/dist/web/dist/snapshots/placeholder/agent-prompt.html +1 -0
  117. package/dist/web/dist/snapshots/placeholder/agent-prompt.txt +8 -0
  118. package/dist/web/dist/talents.html +1 -0
  119. package/dist/web/dist/talents.txt +7 -0
  120. package/package.json +25 -5
package/dist/watchdog.js CHANGED
@@ -1,11 +1,75 @@
1
1
  import { spawn } from 'child_process';
2
2
  import * as fs from 'fs';
3
3
  import * as path from 'path';
4
+ import * as http from 'http';
5
+ import { isMainModule } from './utils/script-path';
4
6
  const HOME = () => process.env.HUNTER_MATE_HOME || process.env.HOME || process.env.USERPROFILE || '.';
5
7
  const ROOT = () => path.join(HOME(), '.hunter-mate');
6
8
  const SERVER_PID_FILE = () => path.join(ROOT(), 'server.pid');
7
9
  const WATCHDOG_PID_FILE = () => path.join(ROOT(), 'watchdog.pid');
8
10
  const CRASH_LOG_FILE = () => path.join(ROOT(), 'server-crash.log');
11
+ /**
12
+ * server 活性探针(FID-057 #17-A3):子进程不退但假活(事件循环被拖死)时,
13
+ * exit 监听永远等不到触发。探针定时 GET /health,连续失败达到阈值判定假活,
14
+ * 由 watchdog kill 子进程走正常重启路径。
15
+ */
16
+ export class LivenessProbe {
17
+ opts;
18
+ failCount = 0;
19
+ timer = null;
20
+ constructor(opts) {
21
+ this.opts = opts;
22
+ }
23
+ async doCheck() {
24
+ const check = this.opts.check ||
25
+ ((url) => new Promise((resolve, reject) => {
26
+ const req = http.get(url, { timeout: 5000 }, (res) => {
27
+ res.resume();
28
+ if (res.statusCode && res.statusCode >= 200 && res.statusCode < 500) {
29
+ resolve();
30
+ }
31
+ else {
32
+ reject(new Error(`HTTP ${res.statusCode}`));
33
+ }
34
+ });
35
+ req.on('timeout', () => {
36
+ req.destroy(new Error('probe timeout'));
37
+ });
38
+ req.on('error', reject);
39
+ }));
40
+ await check(this.opts.healthUrl);
41
+ }
42
+ /** 立即探测一次并更新失败计数;达到阈值时回调 onFailure 并清零 */
43
+ async checkNow() {
44
+ try {
45
+ await this.doCheck();
46
+ this.failCount = 0;
47
+ }
48
+ catch (err) {
49
+ this.failCount++;
50
+ if (this.failCount >= this.opts.threshold) {
51
+ const lastError = err.message;
52
+ this.failCount = 0;
53
+ this.opts.onFailure(lastError);
54
+ }
55
+ }
56
+ }
57
+ start() {
58
+ if (this.timer)
59
+ return;
60
+ this.timer = setInterval(() => {
61
+ void this.checkNow().catch(() => undefined);
62
+ }, this.opts.intervalMs);
63
+ this.timer.unref?.();
64
+ }
65
+ stop() {
66
+ if (this.timer) {
67
+ clearInterval(this.timer);
68
+ this.timer = null;
69
+ }
70
+ this.failCount = 0;
71
+ }
72
+ }
9
73
  function writePid(file, pid) {
10
74
  try {
11
75
  fs.mkdirSync(path.dirname(file), { recursive: true });
@@ -32,10 +96,11 @@ function cleanPid(file) {
32
96
  }
33
97
  catch { /* ignore */ }
34
98
  }
35
- function logCrash(code, signal, restartCount) {
99
+ function logCrash(code, signal, restartCount, reason) {
36
100
  try {
37
101
  fs.mkdirSync(ROOT(), { recursive: true });
38
- const line = `[${new Date().toISOString()}] exit code=${code} signal=${signal} restartCount=${restartCount}\n`;
102
+ const reasonPart = reason ? ` reason=${reason}` : '';
103
+ const line = `[${new Date().toISOString()}] exit code=${code} signal=${signal}${reasonPart} restartCount=${restartCount}\n`;
39
104
  fs.appendFileSync(CRASH_LOG_FILE(), line);
40
105
  }
41
106
  catch { /* ignore */ }
@@ -66,6 +131,23 @@ function runWatchdog() {
66
131
  let restartCount = 0;
67
132
  let restartTimer = null;
68
133
  let stopping = false;
134
+ let crashReason; // 探针假活击杀时写入,exit 回调带入 crash log
135
+ // 活性探针:子进程活着但假活(事件循环冻结)时 kill 重启(FID-057 #17-A3)
136
+ const probe = new LivenessProbe({
137
+ healthUrl: process.env.HM_SERVER_HEALTH_URL || `http://127.0.0.1:${process.env.PORT || 34570}/health`,
138
+ intervalMs: Number(process.env.HM_WATCHDOG_PROBE_INTERVAL_MS || 30_000),
139
+ threshold: Number(process.env.HM_WATCHDOG_PROBE_THRESHOLD || 3),
140
+ onFailure: (lastError) => {
141
+ if (stopping || !child || child.killed)
142
+ return;
143
+ console.error(`[HunterMate watchdog] server unresponsive (last error: ${lastError}), killing for restart`);
144
+ crashReason = `liveness probe failed: ${lastError}`;
145
+ try {
146
+ child.kill('SIGKILL');
147
+ }
148
+ catch { /* ignore: exit handler will restart */ }
149
+ },
150
+ });
69
151
  function startChild() {
70
152
  if (stopping)
71
153
  return;
@@ -84,14 +166,17 @@ function runWatchdog() {
84
166
  });
85
167
  if (child.pid)
86
168
  writePid(SERVER_PID_FILE(), child.pid);
169
+ probe.start();
87
170
  child.on('exit', (code, signal) => {
88
171
  try {
89
172
  fs.closeSync(logFd);
90
173
  }
91
174
  catch { /* ignore */ }
175
+ probe.stop();
92
176
  if (stopping)
93
177
  return;
94
- logCrash(code ?? null, signal, restartCount);
178
+ logCrash(code ?? null, signal, restartCount, crashReason);
179
+ crashReason = undefined;
95
180
  child = null;
96
181
  restartCount++;
97
182
  const delay = Math.min(1000 * Math.pow(2, restartCount), maxRestartDelayMs);
@@ -113,6 +198,7 @@ function runWatchdog() {
113
198
  clearTimeout(restartTimer);
114
199
  restartTimer = null;
115
200
  }
201
+ probe.stop();
116
202
  if (child && !child.killed) {
117
203
  child.kill('SIGTERM');
118
204
  }
@@ -125,4 +211,9 @@ function runWatchdog() {
125
211
  });
126
212
  startChild();
127
213
  }
128
- runWatchdog();
214
+ // 仅作为独立入口(node watchdog.js,由 `server start` 拉起)时启动;
215
+ // 被单测 import 时不触发,避免缺 env 直接退出测试进程
216
+ const invokedAsEntry = isMainModule(import.meta.url);
217
+ if (invokedAsEntry) {
218
+ runWatchdog();
219
+ }
@@ -0,0 +1 @@
1
+ <!DOCTYPE html><html lang="zh-CN"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/css/db881c5b3072b88a.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-1784baecc6fdcf0b.js"/><script src="/_next/static/chunks/a7067448-96dd4b8457c447e8.js" async=""></script><script src="/_next/static/chunks/935-99f57b7d4151d9e7.js" async=""></script><script src="/_next/static/chunks/main-app-80b038a312917d90.js" async=""></script><script src="/_next/static/chunks/589-d632233641f35681.js" async=""></script><script src="/_next/static/chunks/app/layout-83e623e973c1693f.js" async=""></script><meta name="robots" content="noindex"/><title>404: This page could not be found.</title><title>HunterMate 采集仪表盘</title><meta name="description" content="HunterMate 采集/解析/入库仪表盘"/><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body class="flex h-screen overflow-hidden bg-gray-50 text-gray-900"><aside class="flex h-screen w-56 flex-col border-r border-gray-200 bg-white"><div class="flex items-center gap-2 border-b border-gray-200 px-4 py-3"><span class="text-xl">🤝</span><span class="font-semibold text-gray-900">HunterMate</span></div><nav class="flex-1 overflow-auto py-3"><a class="mx-2 flex items-center gap-3 rounded-lg px-3 py-2 text-sm transition-colors text-gray-600 hover:bg-gray-50 hover:text-gray-900" href="/"><span class="text-base">📊</span>仪表盘</a><a class="mx-2 flex items-center gap-3 rounded-lg px-3 py-2 text-sm transition-colors text-gray-600 hover:bg-gray-50 hover:text-gray-900" href="/talents"><span class="text-base">👤</span>人才</a><a class="mx-2 flex items-center gap-3 rounded-lg px-3 py-2 text-sm transition-colors text-gray-600 hover:bg-gray-50 hover:text-gray-900" href="/jobs"><span class="text-base">💼</span>职位</a><a class="mx-2 flex items-center gap-3 rounded-lg px-3 py-2 text-sm transition-colors text-gray-600 hover:bg-gray-50 hover:text-gray-900" href="/companies"><span class="text-base">🏢</span>公司</a><a class="mx-2 flex items-center gap-3 rounded-lg px-3 py-2 text-sm transition-colors text-gray-600 hover:bg-gray-50 hover:text-gray-900" href="/parselog"><span class="text-base">📋</span>解析日志</a><a class="mx-2 flex items-center gap-3 rounded-lg px-3 py-2 text-sm transition-colors text-gray-600 hover:bg-gray-50 hover:text-gray-900" href="/recordings"><span class="text-base">🔴</span>录制</a></nav></aside><main class="flex-1 overflow-hidden"><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div></main><script src="/_next/static/chunks/webpack-1784baecc6fdcf0b.js" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0]);self.__next_f.push([2,null])</script><script>self.__next_f.push([1,"1:HL[\"/_next/static/css/db881c5b3072b88a.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"2:I[6939,[],\"\"]\n4:I[4268,[],\"\"]\n5:I[1050,[],\"\"]\n6:I[4798,[\"589\",\"static/chunks/589-d632233641f35681.js\",\"185\",\"static/chunks/app/layout-83e623e973c1693f.js\"],\"SystemSidebar\"]\nc:I[2319,[],\"\"]\n7:{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"}\n8:{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"}\n9:{\"display\":\"inline-block\"}\na:{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0}\nd:[]\n"])</script><script>self.__next_f.push([1,"0:[\"$\",\"$L2\",null,{\"buildId\":\"hqJ-7vr4X71DNfzZugHJ-\",\"assetPrefix\":\"\",\"urlParts\":[\"\",\"_not-found\"],\"initialTree\":[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],\"initialSeedData\":[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{},[[\"$L3\",[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":\"404\"}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],null],null],null]},[null,[\"$\",\"$L4\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\",\"/_not-found\",\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L5\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"notFoundStyles\":\"$undefined\"}]],null]},[[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/db881c5b3072b88a.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"zh-CN\",\"children\":[\"$\",\"body\",null,{\"className\":\"flex h-screen overflow-hidden bg-gray-50 text-gray-900\",\"children\":[[\"$\",\"$L6\",null,{}],[\"$\",\"main\",null,{\"className\":\"flex-1 overflow-hidden\",\"children\":[\"$\",\"$L4\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L5\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":\"$7\",\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":\"$8\",\"children\":\"404\"}],[\"$\",\"div\",null,{\"style\":\"$9\",\"children\":[\"$\",\"h2\",null,{\"style\":\"$a\",\"children\":\"This page could not be found.\"}]}]]}]}]],\"notFoundStyles\":[]}]}]]}]}]],null],null],\"couldBeIntercepted\":false,\"initialHead\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],\"$Lb\"],\"globalErrorComponent\":\"$c\",\"missingSlots\":\"$Wd\"}]\n"])</script><script>self.__next_f.push([1,"b:[[\"$\",\"meta\",\"0\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"1\",{\"charSet\":\"utf-8\"}],[\"$\",\"title\",\"2\",{\"children\":\"HunterMate 采集仪表盘\"}],[\"$\",\"meta\",\"3\",{\"name\":\"description\",\"content\":\"HunterMate 采集/解析/入库仪表盘\"}]]\n3:null\n"])</script></body></html>
@@ -0,0 +1 @@
1
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="3f320bd5-6c8f-4684-8ab0-ca437c6aa2ad",e._sentryDebugIdIdentifier="sentry-dbid-3f320bd5-6c8f-4684-8ab0-ca437c6aa2ad")}catch(e){}}(),(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[166],{166:function(){}}]);