@winspan/claude-forge 3.6.27 → 3.6.43

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 (239) hide show
  1. package/dist/autopilot/issue-tracker.js +1 -1
  2. package/dist/autopilot/issue-tracker.js.map +1 -1
  3. package/dist/autopilot/quality-gate.d.ts +20 -2
  4. package/dist/autopilot/quality-gate.d.ts.map +1 -1
  5. package/dist/autopilot/quality-gate.js +20 -2
  6. package/dist/autopilot/quality-gate.js.map +1 -1
  7. package/dist/cli/commands/logs.js +1 -1
  8. package/dist/cli/commands/logs.js.map +1 -1
  9. package/dist/config/defaults.d.ts.map +1 -1
  10. package/dist/config/defaults.js +5 -0
  11. package/dist/config/defaults.js.map +1 -1
  12. package/dist/config/schema.d.ts +9 -1
  13. package/dist/config/schema.d.ts.map +1 -1
  14. package/dist/config/schema.js +5 -0
  15. package/dist/config/schema.js.map +1 -1
  16. package/dist/convention/convention-loader.d.ts.map +1 -1
  17. package/dist/convention/convention-loader.js +3 -0
  18. package/dist/convention/convention-loader.js.map +1 -1
  19. package/dist/convention/types.d.ts +15 -5
  20. package/dist/convention/types.d.ts.map +1 -1
  21. package/dist/daemon/engine-registry.d.ts.map +1 -1
  22. package/dist/daemon/engine-registry.js +6 -0
  23. package/dist/daemon/engine-registry.js.map +1 -1
  24. package/dist/daemon/handler-context.d.ts +5 -1
  25. package/dist/daemon/handler-context.d.ts.map +1 -1
  26. package/dist/daemon/handlers/post-tool-use-handler.d.ts.map +1 -1
  27. package/dist/daemon/handlers/post-tool-use-handler.js +59 -2
  28. package/dist/daemon/handlers/post-tool-use-handler.js.map +1 -1
  29. package/dist/daemon/handlers/pre-tool-use-handler.d.ts.map +1 -1
  30. package/dist/daemon/handlers/pre-tool-use-handler.js +25 -2
  31. package/dist/daemon/handlers/pre-tool-use-handler.js.map +1 -1
  32. package/dist/daemon/handlers/session-cleanup.d.ts +2 -0
  33. package/dist/daemon/handlers/session-cleanup.d.ts.map +1 -1
  34. package/dist/daemon/handlers/session-cleanup.js +20 -0
  35. package/dist/daemon/handlers/session-cleanup.js.map +1 -1
  36. package/dist/daemon/handlers/stages/07-pipeline-reply.d.ts.map +1 -1
  37. package/dist/daemon/handlers/stages/07-pipeline-reply.js +3 -0
  38. package/dist/daemon/handlers/stages/07-pipeline-reply.js.map +1 -1
  39. package/dist/daemon/handlers/stages/18-complex-task.d.ts.map +1 -1
  40. package/dist/daemon/handlers/stages/18-complex-task.js +3 -0
  41. package/dist/daemon/handlers/stages/18-complex-task.js.map +1 -1
  42. package/dist/daemon/handlers/stages/19-moderate-task.d.ts.map +1 -1
  43. package/dist/daemon/handlers/stages/19-moderate-task.js +3 -0
  44. package/dist/daemon/handlers/stages/19-moderate-task.js.map +1 -1
  45. package/dist/daemon/handlers/stop-handler.d.ts.map +1 -1
  46. package/dist/daemon/handlers/stop-handler.js +1 -0
  47. package/dist/daemon/handlers/stop-handler.js.map +1 -1
  48. package/dist/daemon/index.d.ts.map +1 -1
  49. package/dist/daemon/index.js +80 -0
  50. package/dist/daemon/index.js.map +1 -1
  51. package/dist/pipeline/completion-gate.d.ts +1 -0
  52. package/dist/pipeline/completion-gate.d.ts.map +1 -1
  53. package/dist/pipeline/completion-gate.js +43 -3
  54. package/dist/pipeline/completion-gate.js.map +1 -1
  55. package/dist/pipeline/completion-verifier.d.ts +75 -0
  56. package/dist/pipeline/completion-verifier.d.ts.map +1 -0
  57. package/dist/pipeline/completion-verifier.js +217 -0
  58. package/dist/pipeline/completion-verifier.js.map +1 -0
  59. package/dist/pipeline/diagnosis-service.d.ts +43 -0
  60. package/dist/pipeline/diagnosis-service.d.ts.map +1 -0
  61. package/dist/pipeline/diagnosis-service.js +136 -0
  62. package/dist/pipeline/diagnosis-service.js.map +1 -0
  63. package/dist/pipeline/dynamic-node-types.d.ts +2 -0
  64. package/dist/pipeline/dynamic-node-types.d.ts.map +1 -1
  65. package/dist/pipeline/execution-engine.d.ts +79 -0
  66. package/dist/pipeline/execution-engine.d.ts.map +1 -0
  67. package/dist/pipeline/execution-engine.js +227 -0
  68. package/dist/pipeline/execution-engine.js.map +1 -0
  69. package/dist/pipeline/index.d.ts +27 -1
  70. package/dist/pipeline/index.d.ts.map +1 -1
  71. package/dist/pipeline/index.js +87 -72
  72. package/dist/pipeline/index.js.map +1 -1
  73. package/dist/pipeline/node-type-sync.d.ts.map +1 -1
  74. package/dist/pipeline/node-type-sync.js +25 -22
  75. package/dist/pipeline/node-type-sync.js.map +1 -1
  76. package/dist/pipeline/pipeline-state-machine.d.ts +19 -0
  77. package/dist/pipeline/pipeline-state-machine.d.ts.map +1 -0
  78. package/dist/pipeline/pipeline-state-machine.js +53 -0
  79. package/dist/pipeline/pipeline-state-machine.js.map +1 -0
  80. package/dist/pipeline/plan-service.d.ts +58 -0
  81. package/dist/pipeline/plan-service.d.ts.map +1 -0
  82. package/dist/pipeline/plan-service.js +382 -0
  83. package/dist/pipeline/plan-service.js.map +1 -0
  84. package/dist/pipeline/strategy-selector.d.ts +41 -0
  85. package/dist/pipeline/strategy-selector.d.ts.map +1 -0
  86. package/dist/pipeline/strategy-selector.js +112 -0
  87. package/dist/pipeline/strategy-selector.js.map +1 -0
  88. package/dist/pipeline/template-evolver.d.ts +45 -0
  89. package/dist/pipeline/template-evolver.d.ts.map +1 -0
  90. package/dist/pipeline/template-evolver.js +223 -0
  91. package/dist/pipeline/template-evolver.js.map +1 -0
  92. package/dist/pipeline/template-registry.d.ts.map +1 -1
  93. package/dist/pipeline/template-registry.js +4 -1
  94. package/dist/pipeline/template-registry.js.map +1 -1
  95. package/dist/storage/repositories/base-repository.d.ts +2 -0
  96. package/dist/storage/repositories/base-repository.d.ts.map +1 -1
  97. package/dist/storage/repositories/base-repository.js +12 -0
  98. package/dist/storage/repositories/base-repository.js.map +1 -1
  99. package/dist/storage/repositories/dynamic-pipeline-repository.d.ts +2 -2
  100. package/dist/storage/repositories/dynamic-pipeline-repository.d.ts.map +1 -1
  101. package/dist/storage/repositories/dynamic-pipeline-repository.js +28 -3
  102. package/dist/storage/repositories/dynamic-pipeline-repository.js.map +1 -1
  103. package/dist/storage/repositories/dynamic-pipeline-template-repository.d.ts +13 -0
  104. package/dist/storage/repositories/dynamic-pipeline-template-repository.d.ts.map +1 -0
  105. package/dist/storage/repositories/dynamic-pipeline-template-repository.js +117 -0
  106. package/dist/storage/repositories/dynamic-pipeline-template-repository.js.map +1 -0
  107. package/dist/storage/repositories/event-repository.d.ts.map +1 -1
  108. package/dist/storage/repositories/event-repository.js +1 -1
  109. package/dist/storage/repositories/event-repository.js.map +1 -1
  110. package/dist/storage/repositories/latency-repository.js +1 -1
  111. package/dist/storage/repositories/latency-repository.js.map +1 -1
  112. package/dist/storage/repositories/node-attempt-repository.d.ts +29 -0
  113. package/dist/storage/repositories/node-attempt-repository.d.ts.map +1 -0
  114. package/dist/storage/repositories/node-attempt-repository.js +57 -0
  115. package/dist/storage/repositories/node-attempt-repository.js.map +1 -0
  116. package/dist/storage/repositories/pipeline-plan-repository.d.ts +75 -0
  117. package/dist/storage/repositories/pipeline-plan-repository.d.ts.map +1 -0
  118. package/dist/storage/repositories/pipeline-plan-repository.js +123 -0
  119. package/dist/storage/repositories/pipeline-plan-repository.js.map +1 -0
  120. package/dist/storage/repositories/quality-repository.d.ts +16 -0
  121. package/dist/storage/repositories/quality-repository.d.ts.map +1 -0
  122. package/dist/storage/repositories/quality-repository.js +36 -0
  123. package/dist/storage/repositories/quality-repository.js.map +1 -0
  124. package/dist/storage/repositories/session-repository.d.ts +7 -0
  125. package/dist/storage/repositories/session-repository.d.ts.map +1 -1
  126. package/dist/storage/repositories/session-repository.js +33 -0
  127. package/dist/storage/repositories/session-repository.js.map +1 -1
  128. package/dist/storage/repositories/template-evolution-repository.d.ts +39 -0
  129. package/dist/storage/repositories/template-evolution-repository.d.ts.map +1 -0
  130. package/dist/storage/repositories/template-evolution-repository.js +83 -0
  131. package/dist/storage/repositories/template-evolution-repository.js.map +1 -0
  132. package/dist/storage/schema/migration-manager.d.ts +1 -1
  133. package/dist/storage/schema/migration-manager.d.ts.map +1 -1
  134. package/dist/storage/schema/migration-manager.js +27 -1
  135. package/dist/storage/schema/migration-manager.js.map +1 -1
  136. package/dist/storage/sqlite.d.ts +21 -0
  137. package/dist/storage/sqlite.d.ts.map +1 -1
  138. package/dist/storage/sqlite.js +105 -31
  139. package/dist/storage/sqlite.js.map +1 -1
  140. package/dist/types/session.d.ts +3 -0
  141. package/dist/types/session.d.ts.map +1 -1
  142. package/dist/utils/logger.d.ts +4 -4
  143. package/dist/utils/logger.d.ts.map +1 -1
  144. package/dist/utils/logger.js +24 -10
  145. package/dist/utils/logger.js.map +1 -1
  146. package/dist/web/routes/config.d.ts +2 -0
  147. package/dist/web/routes/config.d.ts.map +1 -1
  148. package/dist/web/routes/config.js +58 -3
  149. package/dist/web/routes/config.js.map +1 -1
  150. package/dist/web/routes/evolution.d.ts +4 -0
  151. package/dist/web/routes/evolution.d.ts.map +1 -0
  152. package/dist/web/routes/evolution.js +61 -0
  153. package/dist/web/routes/evolution.js.map +1 -0
  154. package/dist/web/routes/knowledge.d.ts.map +1 -1
  155. package/dist/web/routes/knowledge.js +44 -16
  156. package/dist/web/routes/knowledge.js.map +1 -1
  157. package/dist/web/routes/pipelines.d.ts.map +1 -1
  158. package/dist/web/routes/pipelines.js +72 -0
  159. package/dist/web/routes/pipelines.js.map +1 -1
  160. package/dist/web/routes/plans.d.ts +5 -0
  161. package/dist/web/routes/plans.d.ts.map +1 -0
  162. package/dist/web/routes/plans.js +163 -0
  163. package/dist/web/routes/plans.js.map +1 -0
  164. package/dist/web/routes/quality.d.ts.map +1 -1
  165. package/dist/web/routes/quality.js +6 -44
  166. package/dist/web/routes/quality.js.map +1 -1
  167. package/dist/web/routes/sessions.d.ts.map +1 -1
  168. package/dist/web/routes/sessions.js +27 -15
  169. package/dist/web/routes/sessions.js.map +1 -1
  170. package/dist/web/routes/skills.d.ts.map +1 -1
  171. package/dist/web/routes/skills.js +13 -6
  172. package/dist/web/routes/skills.js.map +1 -1
  173. package/dist/web/routes/stats.d.ts.map +1 -1
  174. package/dist/web/routes/stats.js +53 -2
  175. package/dist/web/routes/stats.js.map +1 -1
  176. package/dist/web/routes/templates.d.ts +4 -0
  177. package/dist/web/routes/templates.d.ts.map +1 -0
  178. package/dist/web/routes/templates.js +117 -0
  179. package/dist/web/routes/templates.js.map +1 -0
  180. package/dist/web/server.d.ts.map +1 -1
  181. package/dist/web/server.js +119 -26
  182. package/dist/web/server.js.map +1 -1
  183. package/dist/web/sse-broadcaster.d.ts +23 -0
  184. package/dist/web/sse-broadcaster.d.ts.map +1 -0
  185. package/dist/web/sse-broadcaster.js +73 -0
  186. package/dist/web/sse-broadcaster.js.map +1 -0
  187. package/dist/web/utils/error-response.d.ts +23 -0
  188. package/dist/web/utils/error-response.d.ts.map +1 -0
  189. package/dist/web/utils/error-response.js +26 -0
  190. package/dist/web/utils/error-response.js.map +1 -0
  191. package/dist/web/utils/validation.d.ts +10 -0
  192. package/dist/web/utils/validation.d.ts.map +1 -1
  193. package/dist/web/utils/validation.js +15 -0
  194. package/dist/web/utils/validation.js.map +1 -1
  195. package/dist/web-static/assets/Analytics-Bo74j97W.js +1 -0
  196. package/dist/web-static/assets/BatchProgress-BQ533tSf.js +1 -0
  197. package/dist/web-static/assets/Breadcrumb-DtfwnOx6.js +1 -0
  198. package/dist/web-static/assets/Config-DhfQsbT1.js +1 -0
  199. package/dist/web-static/assets/ConfirmDialog-CVzB7X5y.js +1 -0
  200. package/dist/web-static/assets/Conventions-BobuQiOk.js +1 -0
  201. package/dist/web-static/assets/Dashboard-Bj28rnDe.js +1 -0
  202. package/dist/web-static/assets/ErrorState-DXHA8lr8.js +1 -0
  203. package/dist/web-static/assets/Events-C0y7WcDP.js +1 -0
  204. package/dist/web-static/assets/Evolution-DimZAXFS.js +1 -0
  205. package/dist/web-static/assets/Knowledge-Y1lX6vor.js +2 -0
  206. package/dist/web-static/assets/NodeTypes-DyrDqhBp.js +1 -0
  207. package/dist/web-static/assets/Pagination-lp8b_3NR.js +1 -0
  208. package/dist/web-static/assets/PipelineDetail-DGKz18zu.js +4 -0
  209. package/dist/web-static/assets/PipelineTemplates-D4zvL6I1.js +1 -0
  210. package/dist/web-static/assets/Pipelines-CR9oD3Xy.js +2 -0
  211. package/dist/web-static/assets/ProjectDetail-RfdtEvTT.js +1 -0
  212. package/dist/web-static/assets/Projects-RGIPdiJn.js +1 -0
  213. package/dist/web-static/assets/Quality-BdvL1VQn.js +3 -0
  214. package/dist/web-static/assets/SessionDetail-BNDIfmmq.js +1 -0
  215. package/dist/web-static/assets/Sessions-CorfQV78.js +2 -0
  216. package/dist/web-static/assets/Skeleton-B7PVDJJ_.js +1 -0
  217. package/dist/web-static/assets/Skills-BJt0OrKj.js +1 -0
  218. package/dist/web-static/assets/TemplateDetail-DOfBYdQ3.js +1 -0
  219. package/dist/web-static/assets/Templates-Cp3yC5tv.js +1 -0
  220. package/dist/web-static/assets/client-BhcjNvkG.js +1 -0
  221. package/dist/web-static/assets/exportCsv-CSExJI8h.js +3 -0
  222. package/dist/web-static/assets/index-CqwJts5v.css +2 -0
  223. package/dist/web-static/assets/index-DdmJVOxm.js +2 -0
  224. package/dist/web-static/assets/rolldown-runtime-COnpUsM8.js +1 -0
  225. package/dist/web-static/assets/ui-CDL3BZ13.js +1 -0
  226. package/dist/web-static/assets/useDebounce-DNfPs3Tv.js +1 -0
  227. package/dist/web-static/assets/useSmartPolling-DYAVOihL.js +1 -0
  228. package/dist/web-static/assets/vendor-DRGPi8ui.js +9 -0
  229. package/dist/web-static/assets/vendor-charts-9eVsQvUV.js +36 -0
  230. package/dist/web-static/assets/vendor-editor-B1NX2ipj.js +11 -0
  231. package/dist/web-static/assets/vendor-flow-CHpVij2M.css +1 -0
  232. package/dist/web-static/assets/vendor-flow-srkes8If.js +7 -0
  233. package/dist/web-static/assets/vendor-motion-CQmdgnI8.js +9 -0
  234. package/dist/web-static/assets/vendor-query-DqPOMnuX.js +4 -0
  235. package/dist/web-static/assets/vendor-react-DJI9oneq.js +11 -0
  236. package/dist/web-static/index.html +13 -2
  237. package/package.json +2 -1
  238. package/dist/web-static/assets/index-BCgOtcuH.js +0 -91
  239. package/dist/web-static/assets/index-DwWCJY_u.css +0 -1
@@ -22,9 +22,54 @@ import { registerSkillRoutes } from './routes/skills.js';
22
22
  import { registerConventionsRoutes } from './routes/conventions.js';
23
23
  import { registerProjectConventionRoutes } from './routes/project-conventions.js';
24
24
  import { registerNodeTypeRoutes } from './routes/node-types.js';
25
+ import { createPlansRouter } from './routes/plans.js';
26
+ import { createTemplatesRouter } from './routes/templates.js';
27
+ import { createEvolutionRouter } from './routes/evolution.js';
25
28
  import { authMiddleware } from './middleware/auth.js';
29
+ import { sendError, ErrorCodes } from './utils/error-response.js';
30
+ import { SseBroadcaster, startHeartbeat } from './sse-broadcaster.js';
26
31
  const __filename = fileURLToPath(import.meta.url);
27
32
  const __dirname = path.dirname(__filename);
33
+ const RATE_LIMIT_WINDOW_MS = 60_000;
34
+ const RATE_LIMIT_MAX = 200;
35
+ const FILE_UPLOAD_MAX_MB = 10;
36
+ const FILE_UPLOAD_MAX_BYTES = FILE_UPLOAD_MAX_MB * 1024 * 1024;
37
+ const rateLimitBuckets = new Map();
38
+ function getClientIp(req) {
39
+ const forwarded = req.headers['x-forwarded-for'];
40
+ if (typeof forwarded === 'string' && forwarded.length > 0) {
41
+ return forwarded.split(',')[0]?.trim() || req.ip || 'unknown';
42
+ }
43
+ return req.ip || 'unknown';
44
+ }
45
+ function rateLimitMiddleware(req, res, next) {
46
+ const ip = getClientIp(req);
47
+ const now = Date.now();
48
+ const bucket = rateLimitBuckets.get(ip) || [];
49
+ const recent = bucket.filter(t => now - t < RATE_LIMIT_WINDOW_MS);
50
+ if (recent.length >= RATE_LIMIT_MAX) {
51
+ sendError(res, 429, ErrorCodes.RATE_LIMITED, '请求过于频繁,请稍后重试', {
52
+ limit: RATE_LIMIT_MAX,
53
+ windowMs: RATE_LIMIT_WINDOW_MS,
54
+ });
55
+ return;
56
+ }
57
+ recent.push(now);
58
+ rateLimitBuckets.set(ip, recent);
59
+ next();
60
+ }
61
+ setInterval(() => {
62
+ const now = Date.now();
63
+ for (const [ip, bucket] of rateLimitBuckets.entries()) {
64
+ const recent = bucket.filter(t => now - t < RATE_LIMIT_WINDOW_MS);
65
+ if (recent.length === 0) {
66
+ rateLimitBuckets.delete(ip);
67
+ }
68
+ else {
69
+ rateLimitBuckets.set(ip, recent);
70
+ }
71
+ }
72
+ }, RATE_LIMIT_WINDOW_MS).unref();
28
73
  export class WebServer {
29
74
  app;
30
75
  server = null;
@@ -50,45 +95,92 @@ export class WebServer {
50
95
  },
51
96
  credentials: true,
52
97
  }));
53
- this.app.use(express.json({ limit: '2mb' }));
54
- this.app.use(express.urlencoded({ limit: '2mb', extended: true }));
98
+ this.app.use(express.json({ limit: `${FILE_UPLOAD_MAX_MB}mb` }));
99
+ this.app.use(express.urlencoded({ limit: `${FILE_UPLOAD_MAX_MB}mb`, extended: true }));
55
100
  // 全局请求超时(30s),防止长查询挂起连接
56
101
  this.app.use((req, res, next) => {
57
102
  req.setTimeout(30000, () => {
58
103
  if (!res.headersSent)
59
- res.status(408).json({ error: 'Request timeout' });
104
+ sendError(res, 408, ErrorCodes.REQUEST_TIMEOUT, 'Request timeout');
60
105
  });
61
106
  next();
62
107
  });
108
+ // API 限流(每分钟 200 次)
109
+ this.app.use('/api', rateLimitMiddleware);
110
+ // 上传体积限制(10MB):对 Content-Length 做预检,避免大包占满内存
111
+ this.app.use('/api', (req, res, next) => {
112
+ const contentLength = parseInt(req.headers['content-length'] || '0', 10);
113
+ if (contentLength > FILE_UPLOAD_MAX_BYTES) {
114
+ sendError(res, 413, ErrorCodes.PAYLOAD_TOO_LARGE, `请求体超过最大限制(${FILE_UPLOAD_MAX_MB}MB)`);
115
+ return;
116
+ }
117
+ next();
118
+ });
63
119
  // 认证中间件(仅 API 路由)
64
120
  if (this.options.authToken) {
65
121
  this.app.use('/api', authMiddleware(this.options.authToken));
66
122
  }
123
+ // 只读降级模式:拦截所有写请求
124
+ const { storage } = this.options;
125
+ if (storage.isReadonly()) {
126
+ this.app.use('/api', (req, res, next) => {
127
+ if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method)) {
128
+ sendError(res, 503, ErrorCodes.READONLY_MODE, '存储服务不可用(只读降级模式)', {
129
+ reason: storage.getReadonlyReason(),
130
+ });
131
+ return;
132
+ }
133
+ next();
134
+ });
135
+ }
67
136
  }
68
137
  setupRoutes() {
69
138
  const { storage, aiProvider, pipelineEngine } = this.options;
70
- // API 路由
71
- registerConfigRoutes(this.app, storage);
72
- registerPipelineRoutes(this.app, storage, pipelineEngine);
73
- registerQualityRoutes(this.app, storage, aiProvider);
74
- registerEventRoutes(this.app, storage);
75
- registerSessionRoutes(this.app, storage);
76
- registerStatsRoutes(this.app, storage);
77
- registerKnowledgeRoutes(this.app, storage);
78
- registerDaemonRoutes(this.app, storage);
79
- registerLogsRoutes(this.app, storage);
80
- registerProjectRoutes(this.app, storage);
81
- registerConventionRoutes(this.app, storage);
82
- registerClaudeMdRoutes(this.app, storage);
83
- registerMemoryRoutes(this.app);
84
- registerProjectMetaRoutes(this.app, storage);
85
- registerSkillRoutes(this.app);
86
- registerConventionsRoutes(this.app, storage);
87
- registerProjectConventionRoutes(this.app);
88
- registerNodeTypeRoutes(this.app, storage);
139
+ // API 路由(兼容 /api/* 与 /api/v1/*)
140
+ const registerAllRoutes = (app) => {
141
+ registerConfigRoutes(app, storage);
142
+ registerPipelineRoutes(app, storage, pipelineEngine);
143
+ registerQualityRoutes(app, storage, aiProvider);
144
+ registerEventRoutes(app, storage);
145
+ registerSessionRoutes(app, storage);
146
+ registerStatsRoutes(app, storage);
147
+ registerKnowledgeRoutes(app, storage);
148
+ registerDaemonRoutes(app, storage);
149
+ registerLogsRoutes(app, storage);
150
+ registerProjectRoutes(app, storage);
151
+ registerConventionRoutes(app, storage);
152
+ registerClaudeMdRoutes(app, storage);
153
+ registerMemoryRoutes(app);
154
+ registerProjectMetaRoutes(app, storage);
155
+ registerSkillRoutes(app);
156
+ registerConventionsRoutes(app, storage);
157
+ registerProjectConventionRoutes(app);
158
+ registerNodeTypeRoutes(app, storage);
159
+ app.use('/api/plans', createPlansRouter(storage, aiProvider));
160
+ app.use('/api/templates', createTemplatesRouter(storage));
161
+ app.use('/api/evolution', createEvolutionRouter(storage));
162
+ };
163
+ // SSE 实时推送端点(不走限流和超时中间件)
164
+ this.app.get('/api/events/stream', (req, res) => {
165
+ // SSE 连接不设超时
166
+ req.setTimeout(0);
167
+ SseBroadcaster.getInstance().addClient(res);
168
+ });
169
+ registerAllRoutes(this.app);
89
170
  // 健康检查
90
- this.app.get('/api/health', (req, res) => {
91
- res.json({ status: 'ok', timestamp: new Date().toISOString() });
171
+ this.app.get('/api/health', (_req, res) => {
172
+ const { storage } = this.options;
173
+ res.json({
174
+ status: storage.isReadonly() ? 'degraded' : 'ok',
175
+ readonly: storage.isReadonly(),
176
+ readonlyReason: storage.isReadonly() ? storage.getReadonlyReason() : undefined,
177
+ timestamp: new Date().toISOString(),
178
+ });
179
+ });
180
+ // /api/v1 前缀兼容层(重写到现有 /api/* 路由)
181
+ this.app.use('/api/v1', (req, _res, next) => {
182
+ req.url = `/api${req.url}`;
183
+ next();
92
184
  });
93
185
  }
94
186
  setupStaticFiles() {
@@ -100,7 +192,7 @@ export class WebServer {
100
192
  this.app.use((req, res) => {
101
193
  // API 路由不走 fallback
102
194
  if (req.path.startsWith('/api/')) {
103
- res.status(404).json({ error: 'API 端点不存在' });
195
+ sendError(res, 404, ErrorCodes.NOT_FOUND, 'API 端点不存在');
104
196
  return;
105
197
  }
106
198
  const indexPath = path.resolve(webDir, 'index.html');
@@ -128,7 +220,7 @@ export class WebServer {
128
220
  this.app.use((err, req, res, _next) => {
129
221
  logger.warn(`[Web] 请求处理失败:${err.message} | ${req.method} ${req.path}`);
130
222
  if (!res.headersSent) {
131
- res.status(500).json({ error: '服务器内部错误' });
223
+ sendError(res, 500, ErrorCodes.INTERNAL_ERROR, '服务器内部错误');
132
224
  }
133
225
  });
134
226
  }
@@ -137,6 +229,7 @@ export class WebServer {
137
229
  try {
138
230
  this.server = this.app.listen(this.options.port, () => {
139
231
  logger.info(`[Web] 管理后台已启动:http://localhost:${this.options.port}`);
232
+ startHeartbeat();
140
233
  resolve();
141
234
  });
142
235
  }
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/web/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/web/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { Response } from 'express';
2
+ export type SseEventType = 'pipeline:status' | 'pipeline:node' | 'quality:issue' | 'session:event' | 'session:status' | 'daemon:status' | 'heartbeat';
3
+ export interface SseMessage {
4
+ type: SseEventType;
5
+ data: unknown;
6
+ ts?: string;
7
+ }
8
+ export declare class SseBroadcaster {
9
+ private clients;
10
+ private clientIdCounter;
11
+ static getInstance(): SseBroadcaster;
12
+ /** 注册新的 SSE 客户端连接,返回 clientId */
13
+ addClient(res: Response): string;
14
+ /** 广播消息到所有连接的客户端 */
15
+ broadcast(msg: SseMessage): void;
16
+ /** 发送给单个客户端 */
17
+ private sendToClient;
18
+ get connectionCount(): number;
19
+ private format;
20
+ }
21
+ /** 启动心跳定时器(每 25s),防止代理/浏览器断开空闲连接 */
22
+ export declare function startHeartbeat(): void;
23
+ //# sourceMappingURL=sse-broadcaster.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse-broadcaster.d.ts","sourceRoot":"","sources":["../../src/web/sse-broadcaster.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGxC,MAAM,MAAM,YAAY,GACpB,iBAAiB,GACjB,eAAe,GACf,eAAe,GACf,eAAe,GACf,gBAAgB,GAChB,eAAe,GACf,WAAW,CAAC;AAEhB,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAWD,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,eAAe,CAAK;IAE5B,MAAM,CAAC,WAAW,IAAI,cAAc;IAKpC,iCAAiC;IACjC,SAAS,CAAC,GAAG,EAAE,QAAQ,GAAG,MAAM;IAqBhC,oBAAoB;IACpB,SAAS,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI;IAYhC,eAAe;IACf,OAAO,CAAC,YAAY;IAUpB,IAAI,eAAe,IAAI,MAAM,CAE5B;IAED,OAAO,CAAC,MAAM;CAIf;AAED,oCAAoC;AACpC,wBAAgB,cAAc,IAAI,IAAI,CAOrC"}
@@ -0,0 +1,73 @@
1
+ import { logger } from '../utils/logger.js';
2
+ /** 全局单例,daemon 和 web server 共享同一个 broadcaster 实例 */
3
+ let _instance = null;
4
+ export class SseBroadcaster {
5
+ clients = new Map();
6
+ clientIdCounter = 0;
7
+ static getInstance() {
8
+ if (!_instance)
9
+ _instance = new SseBroadcaster();
10
+ return _instance;
11
+ }
12
+ /** 注册新的 SSE 客户端连接,返回 clientId */
13
+ addClient(res) {
14
+ const id = String(++this.clientIdCounter);
15
+ res.setHeader('Content-Type', 'text/event-stream');
16
+ res.setHeader('Cache-Control', 'no-cache');
17
+ res.setHeader('Connection', 'keep-alive');
18
+ res.setHeader('X-Accel-Buffering', 'no');
19
+ res.flushHeaders();
20
+ this.clients.set(id, { id, res, connectedAt: Date.now() });
21
+ logger.debug(`[SSE] 客户端连接 #${id},当前连接数:${this.clients.size}`);
22
+ res.on('close', () => {
23
+ this.clients.delete(id);
24
+ logger.debug(`[SSE] 客户端断开 #${id},当前连接数:${this.clients.size}`);
25
+ });
26
+ // 立即发送连接确认
27
+ this.sendToClient(id, { type: 'heartbeat', data: { connected: true } });
28
+ return id;
29
+ }
30
+ /** 广播消息到所有连接的客户端 */
31
+ broadcast(msg) {
32
+ if (this.clients.size === 0)
33
+ return;
34
+ const payload = this.format(msg);
35
+ for (const [id, client] of this.clients) {
36
+ try {
37
+ client.res.write(payload);
38
+ }
39
+ catch {
40
+ this.clients.delete(id);
41
+ }
42
+ }
43
+ }
44
+ /** 发送给单个客户端 */
45
+ sendToClient(id, msg) {
46
+ const client = this.clients.get(id);
47
+ if (!client)
48
+ return;
49
+ try {
50
+ client.res.write(this.format(msg));
51
+ }
52
+ catch {
53
+ this.clients.delete(id);
54
+ }
55
+ }
56
+ get connectionCount() {
57
+ return this.clients.size;
58
+ }
59
+ format(msg) {
60
+ const payload = JSON.stringify({ ...msg, ts: msg.ts ?? new Date().toISOString() });
61
+ return `event: ${msg.type}\ndata: ${payload}\n\n`;
62
+ }
63
+ }
64
+ /** 启动心跳定时器(每 25s),防止代理/浏览器断开空闲连接 */
65
+ export function startHeartbeat() {
66
+ const broadcaster = SseBroadcaster.getInstance();
67
+ setInterval(() => {
68
+ if (broadcaster.connectionCount > 0) {
69
+ broadcaster.broadcast({ type: 'heartbeat', data: { ts: Date.now() } });
70
+ }
71
+ }, 25_000).unref();
72
+ }
73
+ //# sourceMappingURL=sse-broadcaster.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse-broadcaster.js","sourceRoot":"","sources":["../../src/web/sse-broadcaster.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { Response } from 'express';
2
+ export interface ErrorResponse {
3
+ error: {
4
+ code: string;
5
+ message: string;
6
+ details?: unknown;
7
+ };
8
+ }
9
+ export declare function sendError(res: Response, statusCode: number, code: string, message: string, details?: unknown): void;
10
+ export declare const ErrorCodes: {
11
+ readonly BAD_REQUEST: "BAD_REQUEST";
12
+ readonly UNAUTHORIZED: "UNAUTHORIZED";
13
+ readonly FORBIDDEN: "FORBIDDEN";
14
+ readonly NOT_FOUND: "NOT_FOUND";
15
+ readonly CONFLICT: "CONFLICT";
16
+ readonly PAYLOAD_TOO_LARGE: "PAYLOAD_TOO_LARGE";
17
+ readonly RATE_LIMITED: "RATE_LIMITED";
18
+ readonly REQUEST_TIMEOUT: "REQUEST_TIMEOUT";
19
+ readonly INTERNAL_ERROR: "INTERNAL_ERROR";
20
+ readonly SERVICE_UNAVAILABLE: "SERVICE_UNAVAILABLE";
21
+ readonly READONLY_MODE: "READONLY_MODE";
22
+ };
23
+ //# sourceMappingURL=error-response.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-response.d.ts","sourceRoot":"","sources":["../../../src/web/utils/error-response.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,CAAC;CACH;AAED,wBAAgB,SAAS,CACvB,GAAG,EAAE,QAAQ,EACb,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,OAAO,GAChB,IAAI,CASN;AAED,eAAO,MAAM,UAAU;;;;;;;;;;;;CAeb,CAAC"}
@@ -0,0 +1,26 @@
1
+ export function sendError(res, statusCode, code, message, details) {
2
+ const response = {
3
+ error: {
4
+ code,
5
+ message,
6
+ details,
7
+ },
8
+ };
9
+ res.status(statusCode).json(response);
10
+ }
11
+ export const ErrorCodes = {
12
+ // 4xx Client Errors
13
+ BAD_REQUEST: 'BAD_REQUEST',
14
+ UNAUTHORIZED: 'UNAUTHORIZED',
15
+ FORBIDDEN: 'FORBIDDEN',
16
+ NOT_FOUND: 'NOT_FOUND',
17
+ CONFLICT: 'CONFLICT',
18
+ PAYLOAD_TOO_LARGE: 'PAYLOAD_TOO_LARGE',
19
+ RATE_LIMITED: 'RATE_LIMITED',
20
+ REQUEST_TIMEOUT: 'REQUEST_TIMEOUT',
21
+ // 5xx Server Errors
22
+ INTERNAL_ERROR: 'INTERNAL_ERROR',
23
+ SERVICE_UNAVAILABLE: 'SERVICE_UNAVAILABLE',
24
+ READONLY_MODE: 'READONLY_MODE',
25
+ };
26
+ //# sourceMappingURL=error-response.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-response.js","sourceRoot":"","sources":["../../../src/web/utils/error-response.ts"],"names":[],"mappings":"AAUA,MAAM,UAAU,SAAS,CACvB,GAAa,EACb,UAAkB,EAClB,IAAY,EACZ,OAAe,EACf,OAAiB;IAEjB,MAAM,QAAQ,GAAkB;QAC9B,KAAK,EAAE;YACL,IAAI;YACJ,OAAO;YACP,OAAO;SACR;KACF,CAAC;IACF,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,oBAAoB;IACpB,WAAW,EAAE,aAAa;IAC1B,YAAY,EAAE,cAAc;IAC5B,SAAS,EAAE,WAAW;IACtB,SAAS,EAAE,WAAW;IACtB,QAAQ,EAAE,UAAU;IACpB,iBAAiB,EAAE,mBAAmB;IACtC,YAAY,EAAE,cAAc;IAC5B,eAAe,EAAE,iBAAiB;IAElC,oBAAoB;IACpB,cAAc,EAAE,gBAAgB;IAChC,mBAAmB,EAAE,qBAAqB;IAC1C,aAAa,EAAE,eAAe;CACtB,CAAC"}
@@ -22,6 +22,16 @@ export declare const NumberIdsBodySchema: z.ZodObject<{
22
22
  export declare const FileUploadSchema: z.ZodObject<{
23
23
  filename: z.ZodString;
24
24
  }, z.core.$strip>;
25
+ export declare const UrlSchema: z.ZodObject<{
26
+ url: z.ZodString;
27
+ }, z.core.$strip>;
28
+ /**
29
+ * 校验文件扩展名是否在白名单中
30
+ * @param filename 文件名或 URL
31
+ * @param allowedExtensions 允许的扩展名列表(如 ['.yaml', '.yml', '.json'])
32
+ * @throws Error 如果扩展名不在白名单中
33
+ */
34
+ export declare function validateFileExtension(filename: string, allowedExtensions: string[]): void;
25
35
  /**
26
36
  * 解析并校验请求 body,失败时自动返回 400
27
37
  * @returns 解析后的数据,或 null(已写入响应)
@@ -1 +1 @@
1
- {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../../src/web/utils/validation.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAIjD,eAAO,MAAM,gBAAgB;;;;;iBAK3B,CAAC;AAEH,eAAO,MAAM,aAAa;;iBAExB,CAAC;AAEH,eAAO,MAAM,mBAAmB;;iBAE9B,CAAC;AAEH,eAAO,MAAM,mBAAmB;;iBAE9B,CAAC;AAEH,eAAO,MAAM,gBAAgB;;iBAE3B,CAAC;AAEH;;;GAGG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EAC9C,MAAM,EAAE,CAAC,EACT,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,GACZ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAUnB;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EAC/C,MAAM,EAAE,CAAC,EACT,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,GACZ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAUnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,OAAO,EACd,GAAG,SAAI,EACP,GAAG,SAAM,EACT,YAAY,SAAK,GAChB,MAAM,CAMR;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,OAAO,EACd,GAAG,SAAQ,EACX,YAAY,SAAI,GACf,MAAM,CAMR;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAM7E;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAMhF;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,MAAM,EACjB,SAAS,SAAI,EACb,SAAS,SAAO,GACf,MAAM,CAQR;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,EAC3C,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,SAAS,CAAC,EAAE,GAC1B,CAAC,CAKH;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAC7B,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,MAAM,EACjB,SAAS,SAAM,EACf,SAAS,SAAI,GACZ,CAAC,EAAE,CAWL"}
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../../src/web/utils/validation.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAIjD,eAAO,MAAM,gBAAgB;;;;;iBAK3B,CAAC;AAEH,eAAO,MAAM,aAAa;;iBAExB,CAAC;AAEH,eAAO,MAAM,mBAAmB;;iBAE9B,CAAC;AAEH,eAAO,MAAM,mBAAmB;;iBAE9B,CAAC;AAEH,eAAO,MAAM,gBAAgB;;iBAE3B,CAAC;AAEH,eAAO,MAAM,SAAS;;iBAEpB,CAAC;AAEH;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,iBAAiB,EAAE,MAAM,EAAE,GAC1B,IAAI,CAKN;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EAC9C,MAAM,EAAE,CAAC,EACT,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,GACZ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAUnB;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EAC/C,MAAM,EAAE,CAAC,EACT,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,GACZ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAUnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,OAAO,EACd,GAAG,SAAI,EACP,GAAG,SAAM,EACT,YAAY,SAAK,GAChB,MAAM,CAMR;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,OAAO,EACd,GAAG,SAAQ,EACX,YAAY,SAAI,GACf,MAAM,CAMR;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAM7E;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAMhF;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,MAAM,EACjB,SAAS,SAAI,EACb,SAAS,SAAO,GACf,MAAM,CAQR;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,EAC3C,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,SAAS,CAAC,EAAE,GAC1B,CAAC,CAKH;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAC7B,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,MAAM,EACjB,SAAS,SAAM,EACf,SAAS,SAAI,GACZ,CAAC,EAAE,CAWL"}
@@ -22,6 +22,21 @@ export const NumberIdsBodySchema = z.object({
22
22
  export const FileUploadSchema = z.object({
23
23
  filename: z.string().regex(/\.(yaml|yml|json|csv)$/i, '只允许上传 .yaml/.json/.csv 文件'),
24
24
  });
25
+ export const UrlSchema = z.object({
26
+ url: z.string().url('无效的 URL 格式').regex(/\.(yaml|yml|json|csv)$/i, 'URL 必须指向 .yaml/.json/.csv 文件'),
27
+ });
28
+ /**
29
+ * 校验文件扩展名是否在白名单中
30
+ * @param filename 文件名或 URL
31
+ * @param allowedExtensions 允许的扩展名列表(如 ['.yaml', '.yml', '.json'])
32
+ * @throws Error 如果扩展名不在白名单中
33
+ */
34
+ export function validateFileExtension(filename, allowedExtensions) {
35
+ const ext = filename.toLowerCase().match(/\.[^.]+$/)?.[0];
36
+ if (!ext || !allowedExtensions.includes(ext)) {
37
+ throw new Error(`不允许的文件类型,只允许:${allowedExtensions.join(', ')}`);
38
+ }
39
+ }
25
40
  /**
26
41
  * 解析并校验请求 body,失败时自动返回 400
27
42
  * @returns 解析后的数据,或 null(已写入响应)
@@ -1 +1 @@
1
- {"version":3,"file":"validation.js","sourceRoot":"","sources":["../../../src/web/utils/validation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../../../src/web/utils/validation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ import{a as e}from"./rolldown-runtime-COnpUsM8.js";import{Dn as t,Ft as n,Gn as r,Ht as i,Rn as a,Vt as o,fn as ee,gr as s,ir as te,o as c,pr as l,s as u,zn as ne}from"./vendor-DRGPi8ui.js";import{S as d,_ as f,c as p,d as m,f as h,g,h as _,l as v,m as y,p as b,s as x,u as S,v as C,x as w,y as T}from"./vendor-charts-9eVsQvUV.js";import{r as E}from"./vendor-query-DqPOMnuX.js";import{c as D}from"./vendor-flow-srkes8If.js";import{J as re,L as ie,St as ae,Y as oe,ht as se,wt as ce,xt as le}from"./client-BhcjNvkG.js";import{a as O,l as k,n as ue,r as A}from"./ui-CDL3BZ13.js";import{t as de}from"./ErrorState-DXHA8lr8.js";import{t as j}from"./exportCsv-CSExJI8h.js";var M=e(s(),1),N=D();function P({children:e,fallback:t,rootMargin:n=`200px`}){let[r,i]=(0,M.useState)(!1),a=(0,M.useRef)(null);return(0,M.useEffect)(()=>{let e=new IntersectionObserver(([t])=>{t.isIntersecting&&(i(!0),e.disconnect())},{rootMargin:n,threshold:.01});return a.current&&e.observe(a.current),()=>e.disconnect()},[n]),(0,N.jsx)(`div`,{ref:a,style:{minHeight:r?`auto`:`400px`},children:r?e:t||(0,N.jsx)(`div`,{className:`flex items-center justify-center h-96 text-gray-400`,children:`加载中...`})})}var F=[`#667eea`,`#10b981`,`#f59e0b`,`#ef4444`,`#8b5cf6`,`#06b6d4`],fe={"7d":7,"30d":30,"90d":90,custom:0};function I(){let[e,s]=(0,M.useState)(`30d`),[D,I]=(0,M.useState)(``),[L,pe]=(0,M.useState)(``),[R,z]=(0,M.useState)(`sessions`),B=fe[e],V=e===`custom`?D?`${D}T00:00:00`:void 0:u(c(new Date,B),`yyyy-MM-dd'T'HH:mm:ss`),H=e===`custom`&&L?`${L}T23:59:59`:void 0,{data:U,isLoading:me,isError:he,refetch:ge}=E({queryKey:[`sessions`,{limit:100,startTime:V,endTime:H}],queryFn:()=>ce({limit:100,start_time:V,end_time:H}).then(e=>e.data)}),{data:W,isLoading:_e,isError:ve,refetch:ye}=E({queryKey:[`events`,{limit:100,startTime:V,endTime:H}],queryFn:()=>oe({limit:100,start_time:V,end_time:H}).then(e=>e.data)}),{data:be,isLoading:xe}=E({queryKey:[`event-stats`],queryFn:()=>re().then(e=>e.data)}),{data:G}=E({queryKey:[`api-usage-stats`,e],queryFn:()=>ie(e===`custom`?90:B).then(e=>e.data),staleTime:6e4}),{data:K}=E({queryKey:[`roi-stats-analytics`],queryFn:()=>ae().then(e=>e.data),staleTime:6e4}),{data:q}=E({queryKey:[`pipelines-analytics`,{limit:100}],queryFn:()=>se({limit:100}).then(e=>e.data),enabled:R===`pipelines`}),{data:J}=E({queryKey:[`quality-history-analytics`,{limit:100}],queryFn:()=>le({limit:100}).then(e=>e.data),enabled:R===`pipelines`}),Se=me||_e||xe,Ce=he||ve,we=()=>{j(`analytics-sessions-${u(new Date,`yyyyMMdd`)}.csv`,[`日期`,`会话数`],Y.map(e=>[e.date,e.count])),j(`analytics-tools-${u(new Date,`yyyyMMdd`)}.csv`,[`工具`,`使用次数`],De.map(e=>[e.name,e.value])),j(`analytics-projects-${u(new Date,`yyyyMMdd`)}.csv`,[`项目`,`事件数`],X.map(e=>[e.name,e.value])),j(`analytics-durations-${u(new Date,`yyyyMMdd`)}.csv`,[`时长区间`,`会话数`],Z.map(e=>[e.range,e.count]))},Y=(0,M.useMemo)(()=>{if(!U?.items)return[];if(e===`custom`){if(!D||!L)return[];let e=new Date(D),t=new Date(L),n=Math.ceil((t.getTime()-e.getTime())/(1e3*60*60*24))+1;return Array.from({length:n},(t,n)=>{let r=u(new Date(e.getTime()+n*24*60*60*1e3),`MM-dd`);return{date:r,count:U.items.filter(e=>u(k(e.start_time),`MM-dd`)===r).length}})}return Array.from({length:B},(e,t)=>{let n=u(c(new Date,B-1-t),`MM-dd`);return{date:n,count:U.items.filter(e=>u(k(e.start_time),`MM-dd`)===n).length}})},[U?.items,B,e,D,L]),Te=(0,M.useMemo)(()=>W?.items?Array.from({length:24},(e,t)=>{let n=W.items.filter(e=>k(e.timestamp).getHours()===t).length;return{hour:`${t}:00`,count:n}}):[],[W?.items]),X=(0,M.useMemo)(()=>{if(!W?.items)return[];let e=W.items.reduce((e,t)=>{let n=t.project_path.split(`/`).pop()||`Unknown`;return e[n]=(e[n]||0)+1,e},{});return Object.entries(e).sort((e,t)=>t[1]-e[1]).slice(0,10).map(([e,t])=>({name:e,value:t}))},[W?.items]),Ee={Bash:`Bash 命令`,Read:`读取文件`,Edit:`编辑文件`,Write:`写入文件`,Grep:`搜索内容`,Glob:`查找文件`,Agent:`子代理`,WebFetch:`网页获取`,WebSearch:`网页搜索`,TodoWrite:`任务管理`,NotebookEdit:`笔记编辑`,stop:`停止`,notification:`通知`,UserPrompt:`用户输入`,TaskCreate:`创建任务`,TaskUpdate:`更新任务`,TaskList:`任务列表`,TaskGet:`获取任务`,TaskStop:`停止任务`,TaskOutput:`任务输出`},De=(0,M.useMemo)(()=>{if(!W?.items)return[];let e=W.items.reduce((e,t)=>{let n=t.tool_name||`N/A`;return e[n]=(e[n]||0)+1,e},{});return Object.entries(e).sort((e,t)=>t[1]-e[1]).slice(0,15).map(([e,t])=>({name:Ee[e]||e,value:t}))},[W?.items]),{sessionDurations:Oe,durationBuckets:Z}=(0,M.useMemo)(()=>{if(!U?.items)return{sessionDurations:[],durationBuckets:[]};let e=U.items.filter(e=>e.end_time).map(e=>{let t=(k(e.end_time).getTime()-k(e.start_time).getTime())/1e3/60;return Math.round(t)});return{sessionDurations:e,durationBuckets:[{range:`0-5分钟`,count:e.filter(e=>e<=5).length},{range:`5-15分钟`,count:e.filter(e=>e>5&&e<=15).length},{range:`15-30分钟`,count:e.filter(e=>e>15&&e<=30).length},{range:`30-60分钟`,count:e.filter(e=>e>30&&e<=60).length},{range:`60+分钟`,count:e.filter(e=>e>60).length}]}},[U?.items]),{avgSessionEvents:ke,avgSessionDuration:Ae}=(0,M.useMemo)(()=>{let e=Oe.filter(e=>e>0&&e<=480),t=e.length>0?e.reduce((e,t)=>e+t,0)/e.length:0,n=U?.items.filter(e=>e.event_count>0&&e.event_count<=500)??[];return{avgSessionEvents:n.length>0?n.reduce((e,t)=>e+t.event_count,0)/n.length:0,avgSessionDuration:t}},[U?.items,Oe]),Q=(0,M.useMemo)(()=>{if(!q?.items)return null;let e=q.items,t=e.filter(e=>e.status===`completed`).length;return{completed:t,failed:e.filter(e=>e.status===`failed`).length,completionRate:e.length>0?(t/e.length*100).toFixed(1):`0`,complexityDist:e.reduce((e,t)=>(e[t.complexity]=(e[t.complexity]||0)+1,e),{}),avgNodes:e.length>0?(e.reduce((e,t)=>e+(t.stats?.totalNodes||0),0)/e.length).toFixed(1):`0`,total:e.length}},[q?.items]),$=(0,M.useMemo)(()=>J?.items?Array.from({length:B},(e,t)=>{let n=u(c(new Date,B-1-t),`MM-dd`),r=J.items.filter(e=>u(k(e.created_at),`MM-dd`)===n);return{date:n,total:r.length,unresolved:r.filter(e=>!e.resolved).length}}):[],[J?.items,B]);return Se?(0,N.jsx)(`div`,{className:`flex items-center justify-center h-96`,children:(0,N.jsx)(`div`,{className:`animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600`})}):Ce?(0,N.jsx)(de,{message:`分析数据加载失败`,onRetry:()=>{ge(),ye()}}):(0,N.jsxs)(`div`,{className:`space-y-6`,children:[(0,N.jsx)(A,{children:(0,N.jsxs)(`div`,{className:`flex flex-col gap-4`,children:[(0,N.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,N.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,N.jsx)(te,{className:`h-4 w-4 text-gray-400`}),(0,N.jsx)(`span`,{className:`text-sm text-gray-600`,children:`时间范围:`}),(0,N.jsx)(`div`,{className:`flex gap-1 border border-gray-200 rounded-lg overflow-hidden`,children:[`7d`,`30d`,`90d`,`custom`].map(t=>(0,N.jsx)(`button`,{onClick:()=>s(t),className:O(`px-3 py-1.5 text-sm transition-colors`,e===t?`bg-blue-50 text-blue-700 font-medium`:`text-gray-600 hover:bg-gray-50`),children:t===`7d`?`7 天`:t===`30d`?`30 天`:t===`90d`?`90 天`:`自定义`},t))})]}),(0,N.jsx)(ue,{variant:`outline`,size:`sm`,icon:a,onClick:we,children:`导出数据`})]}),e===`custom`&&(0,N.jsxs)(`div`,{className:`flex items-center gap-3 pl-6`,children:[(0,N.jsx)(`label`,{className:`text-sm text-gray-600`,children:`开始日期:`}),(0,N.jsx)(`input`,{type:`date`,value:D,onChange:e=>I(e.target.value),className:`px-3 py-1.5 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500`}),(0,N.jsx)(`label`,{className:`text-sm text-gray-600`,children:`结束日期:`}),(0,N.jsx)(`input`,{type:`date`,value:L,onChange:e=>pe(e.target.value),className:`px-3 py-1.5 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500`})]})]})}),(0,N.jsxs)(`div`,{className:`flex gap-1 bg-gray-100 p-1 rounded-lg w-fit`,children:[(0,N.jsxs)(`button`,{onClick:()=>z(`sessions`),className:O(`flex items-center gap-2 px-4 py-2 rounded-md text-sm font-medium transition-colors`,R===`sessions`?`bg-white text-gray-900 shadow-sm`:`text-gray-600 hover:text-gray-900`),children:[(0,N.jsx)(l,{className:`h-4 w-4`}),`会话分析`]}),(0,N.jsxs)(`button`,{onClick:()=>z(`pipelines`),className:O(`flex items-center gap-2 px-4 py-2 rounded-md text-sm font-medium transition-colors`,R===`pipelines`?`bg-white text-gray-900 shadow-sm`:`text-gray-600 hover:text-gray-900`),children:[(0,N.jsx)(t,{className:`h-4 w-4`}),`Pipeline 分析`]})]}),R===`sessions`&&(0,N.jsxs)(`div`,{className:`space-y-6`,children:[K&&(0,N.jsx)(`div`,{className:`grid grid-cols-2 md:grid-cols-3 gap-3`,children:[{label:`本周会话`,curr:K.week.sessions,pct:K.weekOverWeek.sessions},{label:`本周写入操作`,curr:K.week.writeOps,pct:K.weekOverWeek.writeOps},{label:`本周节省时间`,curr:`${K.week.timeSavedHours}h`,pct:K.weekOverWeek.timeSaved},{label:`本周质量拦截`,curr:K.week.qualityBlocked,pct:K.weekOverWeek.qualityBlocked},{label:`本月会话`,curr:K.month.sessions,pct:K.monthOverMonth.sessions},{label:`本月质量拦截`,curr:K.month.qualityBlocked,pct:K.monthOverMonth.qualityBlocked}].map(e=>(0,N.jsxs)(A,{className:`!p-3`,children:[(0,N.jsx)(`div`,{className:`text-xs text-gray-500 mb-1`,children:e.label}),(0,N.jsxs)(`div`,{className:`flex items-end justify-between`,children:[(0,N.jsx)(`span`,{className:`text-xl font-bold text-gray-900`,children:e.curr}),e.pct!==null&&e.pct!==void 0?(0,N.jsxs)(`span`,{className:O(`flex items-center gap-0.5 text-xs font-medium`,e.pct>0?`text-green-600`:e.pct<0?`text-red-500`:`text-gray-400`),children:[e.pct>0?(0,N.jsx)(o,{className:`h-3 w-3`}):e.pct<0?(0,N.jsx)(i,{className:`h-3 w-3`}):(0,N.jsx)(ee,{className:`h-3 w-3`}),e.pct>0?`+`:``,e.pct,`%`]}):(0,N.jsx)(`span`,{className:`text-xs text-gray-300`,children:`—`})]}),(0,N.jsx)(`div`,{className:`text-xs text-gray-400 mt-0.5`,children:`较上期`})]},e.label))}),(0,N.jsxs)(`div`,{className:`grid grid-cols-2 md:grid-cols-4 gap-4`,children:[(0,N.jsxs)(A,{className:`text-center !p-4`,children:[(0,N.jsx)(l,{className:`h-7 w-7 text-indigo-500 mx-auto mb-2`}),(0,N.jsx)(`div`,{className:`text-2xl font-bold text-gray-900`,children:ke.toFixed(1)}),(0,N.jsx)(`div`,{className:`text-sm text-gray-500`,children:`平均会话事件数`})]}),(0,N.jsxs)(A,{className:`text-center !p-4`,children:[(0,N.jsx)(r,{className:`h-7 w-7 text-green-500 mx-auto mb-2`}),(0,N.jsx)(`div`,{className:`text-2xl font-bold text-gray-900`,children:Ae.toFixed(1)}),(0,N.jsx)(`div`,{className:`text-sm text-gray-500`,children:`平均会话时长(分钟)`})]}),(0,N.jsxs)(A,{className:`text-center !p-4`,children:[(0,N.jsx)(n,{className:`h-7 w-7 text-amber-500 mx-auto mb-2`}),(0,N.jsx)(`div`,{className:`text-2xl font-bold text-gray-900`,children:W?.total||0}),(0,N.jsx)(`div`,{className:`text-sm text-gray-500`,children:`总事件数`})]}),(0,N.jsxs)(A,{className:`text-center !p-4`,children:[(0,N.jsx)(o,{className:`h-7 w-7 text-purple-500 mx-auto mb-2`}),(0,N.jsx)(`div`,{className:`text-2xl font-bold text-gray-900`,children:U?.total||0}),(0,N.jsx)(`div`,{className:`text-sm text-gray-500`,children:`总会话数`})]})]}),(0,N.jsxs)(`div`,{className:`grid grid-cols-1 xl:grid-cols-2 gap-6`,children:[(0,N.jsx)(A,{title:`最近 ${B} 天会话趋势`,children:(0,N.jsx)(P,{children:(0,N.jsx)(d,{width:`100%`,height:250,children:(0,N.jsxs)(x,{data:Y,children:[(0,N.jsx)(g,{strokeDasharray:`3 3`}),(0,N.jsx)(h,{dataKey:`date`}),(0,N.jsx)(m,{}),(0,N.jsx)(T,{}),(0,N.jsx)(y,{type:`monotone`,dataKey:`count`,stroke:`#667eea`,fill:`#667eea`,fillOpacity:.3})]})})})}),(0,N.jsx)(A,{title:`24 小时事件分布`,children:(0,N.jsx)(P,{children:(0,N.jsx)(d,{width:`100%`,height:250,children:(0,N.jsxs)(S,{data:Te,children:[(0,N.jsx)(g,{strokeDasharray:`3 3`}),(0,N.jsx)(h,{dataKey:`hour`}),(0,N.jsx)(m,{}),(0,N.jsx)(T,{}),(0,N.jsx)(_,{type:`monotone`,dataKey:`count`,stroke:`#10b981`,strokeWidth:2})]})})})}),(0,N.jsx)(A,{title:`项目活跃度 Top 10`,children:(0,N.jsx)(P,{children:(0,N.jsx)(d,{width:`100%`,height:250,children:(0,N.jsxs)(v,{data:X,layout:`vertical`,children:[(0,N.jsx)(g,{strokeDasharray:`3 3`}),(0,N.jsx)(h,{type:`number`}),(0,N.jsx)(m,{dataKey:`name`,type:`category`,width:100}),(0,N.jsx)(T,{}),(0,N.jsx)(b,{dataKey:`value`,fill:`#667eea`})]})})})}),(0,N.jsx)(A,{title:`工具使用排行 Top 15`,children:(0,N.jsx)(P,{children:(0,N.jsx)(d,{width:`100%`,height:250,children:(0,N.jsxs)(v,{data:De,children:[(0,N.jsx)(g,{strokeDasharray:`3 3`}),(0,N.jsx)(h,{dataKey:`name`,angle:-45,textAnchor:`end`,height:80}),(0,N.jsx)(m,{}),(0,N.jsx)(T,{}),(0,N.jsx)(b,{dataKey:`value`,fill:`#10b981`})]})})})}),(0,N.jsx)(A,{title:`会话时长分布`,children:(0,N.jsx)(P,{children:(0,N.jsx)(d,{width:`100%`,height:250,children:(0,N.jsxs)(p,{children:[(0,N.jsx)(f,{data:Z,cx:`50%`,cy:`50%`,labelLine:!1,label:({range:e,count:t})=>`${e}: ${t}`,outerRadius:80,fill:`#8884d8`,dataKey:`count`,children:Z.map((e,t)=>(0,N.jsx)(C,{fill:F[t%F.length]},`cell-${t}`))}),(0,N.jsx)(T,{})]})})})}),(0,N.jsx)(A,{title:`事件类型趋势`,children:(0,N.jsx)(P,{children:(0,N.jsx)(d,{width:`100%`,height:250,children:(0,N.jsxs)(x,{data:be?.stats.slice(0,30)||[],children:[(0,N.jsx)(g,{strokeDasharray:`3 3`}),(0,N.jsx)(h,{dataKey:`date`}),(0,N.jsx)(m,{}),(0,N.jsx)(T,{}),(0,N.jsx)(w,{}),(0,N.jsx)(y,{type:`monotone`,dataKey:`count`,stackId:`1`,stroke:`#667eea`,fill:`#667eea`})]})})})})]}),G&&(0,N.jsxs)(N.Fragment,{children:[(0,N.jsxs)(`div`,{className:`flex items-center gap-2 mt-2`,children:[(0,N.jsx)(ne,{className:`h-5 w-5 text-gray-500`}),(0,N.jsx)(`h2`,{className:`text-base font-semibold text-gray-800`,children:`Token 与费用统计`})]}),(0,N.jsxs)(`div`,{className:`grid grid-cols-2 md:grid-cols-4 gap-4`,children:[(0,N.jsxs)(A,{className:`text-center !p-4`,children:[(0,N.jsxs)(`div`,{className:`text-2xl font-bold text-gray-900`,children:[`$`,G.summary.totalCost.toFixed(4)]}),(0,N.jsx)(`div`,{className:`text-sm text-gray-500`,children:`总费用(USD)`})]}),(0,N.jsxs)(A,{className:`text-center !p-4`,children:[(0,N.jsxs)(`div`,{className:`text-2xl font-bold text-gray-900`,children:[(G.summary.totalTokens/1e3).toFixed(1),`K`]}),(0,N.jsx)(`div`,{className:`text-sm text-gray-500`,children:`总 Token 数`})]}),(0,N.jsxs)(A,{className:`text-center !p-4`,children:[(0,N.jsxs)(`div`,{className:`text-2xl font-bold text-gray-900`,children:[(G.summary.totalTokensIn/1e3).toFixed(1),`K`]}),(0,N.jsx)(`div`,{className:`text-sm text-gray-500`,children:`输入 Token`})]}),(0,N.jsxs)(A,{className:`text-center !p-4`,children:[(0,N.jsxs)(`div`,{className:`text-2xl font-bold text-gray-900`,children:[(G.summary.totalTokensOut/1e3).toFixed(1),`K`]}),(0,N.jsx)(`div`,{className:`text-sm text-gray-500`,children:`输出 Token`})]})]}),(0,N.jsxs)(`div`,{className:`grid grid-cols-1 xl:grid-cols-2 gap-6`,children:[(0,N.jsx)(A,{title:`每日 Token 趋势`,children:(0,N.jsx)(P,{children:(0,N.jsx)(d,{width:`100%`,height:250,children:(0,N.jsxs)(x,{data:G.dailyTrend,children:[(0,N.jsx)(g,{strokeDasharray:`3 3`}),(0,N.jsx)(h,{dataKey:`date`}),(0,N.jsx)(m,{}),(0,N.jsx)(T,{formatter:e=>`${(e/1e3).toFixed(1)}K`}),(0,N.jsx)(w,{}),(0,N.jsx)(y,{type:`monotone`,dataKey:`tokens_in`,name:`输入`,stroke:`#667eea`,fill:`#667eea`,fillOpacity:.3,stackId:`1`}),(0,N.jsx)(y,{type:`monotone`,dataKey:`tokens_out`,name:`输出`,stroke:`#10b981`,fill:`#10b981`,fillOpacity:.3,stackId:`1`})]})})})}),(0,N.jsx)(A,{title:`每日费用趋势(USD)`,children:(0,N.jsx)(P,{children:(0,N.jsx)(d,{width:`100%`,height:250,children:(0,N.jsxs)(v,{data:G.dailyTrend,children:[(0,N.jsx)(g,{strokeDasharray:`3 3`}),(0,N.jsx)(h,{dataKey:`date`}),(0,N.jsx)(m,{tickFormatter:e=>`$${e.toFixed(3)}`}),(0,N.jsx)(T,{formatter:e=>`$${e.toFixed(4)}`}),(0,N.jsx)(b,{dataKey:`cost_usd`,name:`费用`,fill:`#f59e0b`})]})})})}),G.byModel.length>0&&(0,N.jsx)(A,{title:`按模型费用分布`,children:(0,N.jsx)(P,{children:(0,N.jsx)(d,{width:`100%`,height:250,children:(0,N.jsxs)(p,{children:[(0,N.jsx)(f,{data:G.byModel,dataKey:`cost`,nameKey:`model`,cx:`50%`,cy:`50%`,outerRadius:80,label:({model:e,cost:t})=>`${e}: $${t.toFixed(4)}`,children:G.byModel.map((e,t)=>(0,N.jsx)(C,{fill:F[t%F.length]},t))}),(0,N.jsx)(T,{formatter:e=>`$${e.toFixed(4)}`})]})})})})]})]})]}),R===`pipelines`&&Q&&(0,N.jsxs)(`div`,{className:`space-y-6`,children:[(0,N.jsxs)(`div`,{className:`grid grid-cols-1 md:grid-cols-4 gap-4`,children:[(0,N.jsxs)(A,{className:`text-center`,children:[(0,N.jsx)(`div`,{className:`text-3xl font-bold text-blue-600`,children:Q.total}),(0,N.jsx)(`div`,{className:`text-sm text-gray-600 mt-1`,children:`总 Pipeline`})]}),(0,N.jsxs)(A,{className:`text-center`,children:[(0,N.jsxs)(`div`,{className:`text-3xl font-bold text-green-600`,children:[Q.completionRate,`%`]}),(0,N.jsx)(`div`,{className:`text-sm text-gray-600 mt-1`,children:`完成率`})]}),(0,N.jsxs)(A,{className:`text-center`,children:[(0,N.jsx)(`div`,{className:`text-3xl font-bold text-purple-600`,children:Q.avgNodes}),(0,N.jsx)(`div`,{className:`text-sm text-gray-600 mt-1`,children:`平均节点数`})]}),(0,N.jsxs)(A,{className:`text-center`,children:[(0,N.jsx)(`div`,{className:`text-3xl font-bold text-red-600`,children:Q.failed}),(0,N.jsx)(`div`,{className:`text-sm text-gray-600 mt-1`,children:`失败数`})]})]}),(0,N.jsx)(A,{title:`复杂度分布`,children:(0,N.jsx)(P,{children:(0,N.jsx)(d,{width:`100%`,height:250,children:(0,N.jsxs)(v,{data:Object.entries(Q.complexityDist).map(([e,t])=>({name:e===`simple`?`简单`:e===`moderate`?`中等`:`复杂`,value:t})),children:[(0,N.jsx)(g,{strokeDasharray:`3 3`}),(0,N.jsx)(h,{dataKey:`name`}),(0,N.jsx)(m,{}),(0,N.jsx)(T,{}),(0,N.jsx)(b,{dataKey:`value`,name:`数量`,fill:`#667eea`})]})})})}),$.length>0&&(0,N.jsx)(A,{title:`质量问题趋势`,children:(0,N.jsx)(P,{children:(0,N.jsx)(d,{width:`100%`,height:250,children:(0,N.jsxs)(S,{data:$,children:[(0,N.jsx)(g,{strokeDasharray:`3 3`}),(0,N.jsx)(h,{dataKey:`date`}),(0,N.jsx)(m,{}),(0,N.jsx)(T,{}),(0,N.jsx)(w,{}),(0,N.jsx)(_,{type:`monotone`,dataKey:`total`,name:`总问题`,stroke:`#667eea`,strokeWidth:2}),(0,N.jsx)(_,{type:`monotone`,dataKey:`unresolved`,name:`未解决`,stroke:`#ef4444`,strokeWidth:2})]})})})})]})]})}export{I as default};
@@ -0,0 +1 @@
1
+ import{c as e}from"./vendor-flow-srkes8If.js";var t=e();function n({total:e,done:n,label:r=`处理中`}){let i=e>0?Math.round(n/e*100):0;return(0,t.jsxs)(`div`,{className:`flex items-center gap-3 text-sm`,children:[(0,t.jsxs)(`span`,{className:`text-gray-500 whitespace-nowrap`,children:[r,` `,n,`/`,e]}),(0,t.jsx)(`div`,{className:`flex-1 h-1.5 bg-gray-100 rounded-full overflow-hidden min-w-[80px]`,children:(0,t.jsx)(`div`,{className:`h-full bg-blue-500 rounded-full transition-all duration-300`,style:{width:`${i}%`}})}),(0,t.jsxs)(`span`,{className:`text-gray-400 w-8 text-right`,children:[i,`%`]})]})}export{n as t};
@@ -0,0 +1 @@
1
+ import{Qn as e}from"./vendor-DRGPi8ui.js";import{n as t}from"./vendor-react-DJI9oneq.js";import{c as n}from"./vendor-flow-srkes8If.js";var r=n();function i({items:n}){return(0,r.jsx)(`nav`,{className:`flex items-center gap-2 text-sm text-gray-600`,children:n.map((n,i)=>(0,r.jsxs)(`div`,{className:`flex items-center gap-2`,children:[i>0&&(0,r.jsx)(e,{className:`h-3.5 w-3.5 text-gray-400`}),n.path?(0,r.jsx)(t,{to:n.path,className:`hover:text-gray-900 transition-colors`,children:n.label}):(0,r.jsx)(`span`,{className:`text-gray-900 font-medium`,children:n.label})]},i))})}export{i as t};
@@ -0,0 +1 @@
1
+ import{a as e}from"./rolldown-runtime-COnpUsM8.js";import{Bn as t,Bt as n,Fn as r,In as i,Lt as a,Qt as o,Rn as s,Tn as c,Vn as l,Yn as u,gr as d,hn as f,nn as p,qn as m,rn as h,s as g,tn as _,zt as v}from"./vendor-DRGPi8ui.js";import{a as y,n as b,r as x}from"./vendor-query-DqPOMnuX.js";import{c as S}from"./vendor-flow-srkes8If.js";import{A as C,Bt as w,Gt as T,H as E,Lt as D,Qt as O,R as k,U as A,a as j,at as M,h as N,it as P,m as F,q as I,r as L,tn as ee,un as R}from"./client-BhcjNvkG.js";import{a as z,n as B,r as V,t as te}from"./ui-CDL3BZ13.js";import{n as H,t as U}from"./vendor-motion-CQmdgnI8.js";import{t as W}from"./ConfirmDialog-CVzB7X5y.js";var G=e(d(),1),K=S();function ne({onConfirm:e}){let n=y(),[a,o]=(0,G.useState)(!1),[l,u]=(0,G.useState)(``),[d,p]=(0,G.useState)(!1),[m,_]=(0,G.useState)({}),{data:v,refetch:S}=x({queryKey:[`backups`],queryFn:()=>D().then(e=>e.data)}),{data:C}=x({queryKey:[`daemon-status`],queryFn:()=>I().then(e=>e.data)}),w=b({mutationFn:()=>j(a?{encrypt:!0,password:l}:{}),onSuccess:()=>{R(`备份创建成功`,`success`),u(``),o(!1),S()},onError:()=>R(`备份创建失败`,`error`)}),E=b({mutationFn:({filename:e,password:t})=>T(e,t),onSuccess:()=>{R(`数据库恢复成功,daemon 将自动重启`,`success`),n.clear()},onError:()=>R(`恢复失败,请检查密码或文件完整性`,`error`)});return(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(V,{children:(0,K.jsxs)(`div`,{className:`flex items-start justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,K.jsx)(`div`,{className:`flex-shrink-0 w-10 h-10 rounded-full bg-blue-50 flex items-center justify-center`,children:(0,K.jsx)(c,{className:`h-5 w-5 text-blue-600`})}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`font-medium text-gray-900`,children:`当前数据库`}),(0,K.jsxs)(`p`,{className:`text-sm text-gray-500 mt-1`,children:[`内存占用:`,C?.memory?`${(C.memory.heapUsed/1024/1024).toFixed(2)} MB`:`加载中...`]})]})]}),(0,K.jsxs)(`div`,{className:`flex flex-col items-end gap-2`,children:[(0,K.jsx)(`div`,{className:`flex items-center gap-2`,children:(0,K.jsxs)(`label`,{className:`flex items-center gap-1.5 text-sm text-gray-600 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:a,onChange:e=>o(e.target.checked),className:`rounded`}),(0,K.jsx)(f,{className:`h-3.5 w-3.5`}),`加密备份`]})}),a&&(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`input`,{type:d?`text`:`password`,placeholder:`备份密码(≥8位)`,value:l,onChange:e=>u(e.target.value),className:`px-3 py-1.5 text-sm border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 pr-8 w-48`}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>p(e=>!e),className:`absolute right-2 top-1/2 -translate-y-1/2 text-gray-400`,children:d?(0,K.jsx)(i,{className:`h-3.5 w-3.5`}):(0,K.jsx)(r,{className:`h-3.5 w-3.5`})})]}),(0,K.jsx)(B,{variant:`primary`,size:`sm`,icon:t,onClick:()=>w.mutate(),loading:w.isPending,disabled:a&&l.length<8,children:`立即备份`})]})]})}),(0,K.jsxs)(V,{children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between mb-4`,children:[(0,K.jsx)(`h3`,{className:`font-medium text-gray-900`,children:`备份历史`}),(0,K.jsx)(B,{variant:`ghost`,size:`sm`,icon:h,onClick:()=>void S(),children:`刷新`})]}),v&&v.items.length>0?(0,K.jsx)(`div`,{className:`space-y-2`,children:v.items.map(t=>(0,K.jsxs)(`div`,{className:`flex flex-col gap-2 py-3 px-4 bg-gray-50 rounded-lg`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`p`,{className:`text-sm font-medium text-gray-900 truncate`,children:t.filename}),t.encrypted&&(0,K.jsxs)(`span`,{className:`flex items-center gap-0.5 text-xs text-amber-600 bg-amber-50 px-1.5 py-0.5 rounded`,children:[(0,K.jsx)(f,{className:`h-3 w-3`}),` 已加密`]}),!t.hasChecksum&&(0,K.jsx)(`span`,{className:`text-xs text-gray-400 bg-gray-100 px-1.5 py-0.5 rounded`,children:`无校验`})]}),(0,K.jsxs)(`p`,{className:`text-xs text-gray-500 mt-0.5`,children:[g(new Date(t.createdAt),`yyyy-MM-dd HH:mm:ss`),` · `,t.sizeMb,` MB`]})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 ml-3 flex-shrink-0`,children:[(0,K.jsx)(B,{variant:`outline`,size:`sm`,onClick:()=>e({title:`恢复数据库`,description:`确定要从 ${t.filename} 恢复数据库吗?当前数据库将被覆盖(会自动备份)。恢复后 daemon 将自动重启。`,onConfirm:()=>E.mutate({filename:t.filename,password:m[t.filename]})}),loading:E.isPending&&E.variables?.filename===t.filename,children:`恢复`}),(0,K.jsx)(`a`,{href:k(t.filename),download:t.filename,children:(0,K.jsx)(B,{variant:`ghost`,size:`sm`,icon:s,children:`下载`})})]})]}),t.encrypted&&(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(f,{className:`h-3.5 w-3.5 text-amber-500 flex-shrink-0`}),(0,K.jsx)(`input`,{type:`password`,placeholder:`输入解密密码后点击恢复`,value:m[t.filename]||``,onChange:e=>_(n=>({...n,[t.filename]:e.target.value})),className:`flex-1 px-2 py-1 text-xs border border-amber-200 rounded focus:outline-none focus:ring-1 focus:ring-amber-400`})]})]},t.filename))}):(0,K.jsx)(`div`,{className:`text-center py-8 text-gray-400 text-sm`,children:`暂无备份记录`})]}),(0,K.jsxs)(V,{children:[(0,K.jsx)(`div`,{className:`flex items-center justify-between mb-4`,children:(0,K.jsx)(`h3`,{className:`font-medium text-gray-900`,children:`数据管理`})}),(0,K.jsxs)(`div`,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between py-3 px-4 bg-gray-50 rounded-lg`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-sm font-medium text-gray-900`,children:`清理历史事件`}),(0,K.jsx)(`p`,{className:`text-xs text-gray-500 mt-0.5`,children:`删除超过指定天数的事件记录`})]}),(0,K.jsx)(B,{variant:`outline`,size:`sm`,onClick:()=>e({title:`清理历史事件`,description:`确定要清理 30 天前的事件记录吗?此操作不可撤销。`,onConfirm:()=>{L.post(`/events/purge`,{retentionDays:30}).then(()=>R(`事件清理完成`,`success`)).catch(()=>R(`事件清理失败`,`error`))}}),children:`清理 30 天前`})]}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between py-3 px-4 bg-gray-50 rounded-lg`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-sm font-medium text-gray-900`,children:`数据库优化`}),(0,K.jsx)(`p`,{className:`text-xs text-gray-500 mt-0.5`,children:`执行 VACUUM 回收空间,提升性能`})]}),(0,K.jsx)(B,{variant:`outline`,size:`sm`,onClick:()=>e({title:`数据库优化`,description:`确定要执行 VACUUM 优化吗?此操作可能需要几分钟。`,onConfirm:()=>{L.post(`/config/vacuum`).then(()=>R(`数据库优化完成`,`success`)).catch(()=>R(`数据库优化失败`,`error`))}}),children:`立即优化`})]})]})]})]})}function re({onConfirm:e}){let{data:t,refetch:n}=x({queryKey:[`memory-caches`],queryFn:()=>P().then(e=>e.data),refetchInterval:5e3}),{data:r}=x({queryKey:[`memory-process`],queryFn:()=>M().then(e=>e.data),refetchInterval:5e3}),i=b({mutationFn:e=>N(e),onSuccess:()=>{R(`缓存已清空`,`success`),n()},onError:()=>R(`清空失败`,`error`)}),a=b({mutationFn:()=>F(),onSuccess:()=>{R(`所有缓存已清空`,`success`),n()},onError:()=>R(`清空失败`,`error`)}),o=b({mutationFn:()=>O(),onSuccess:()=>R(`GC 已触发`,`success`),onError:()=>R(`GC 触发失败`,`error`)});return(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(V,{children:(0,K.jsxs)(`div`,{className:`flex items-start justify-between mb-4`,children:[(0,K.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,K.jsx)(`div`,{className:`flex-shrink-0 w-10 h-10 rounded-full bg-purple-50 flex items-center justify-center`,children:(0,K.jsx)(l,{className:`h-5 w-5 text-purple-600`})}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`font-medium text-gray-900`,children:`进程内存`}),r&&(0,K.jsxs)(`div`,{className:`text-sm text-gray-600 mt-2 space-y-1`,children:[(0,K.jsxs)(`div`,{children:[`RSS: `,r.rssMB,` MB`]}),(0,K.jsxs)(`div`,{children:[`堆已用: `,r.heapUsedMB,` MB / `,r.heapTotalMB,` MB`]}),(0,K.jsxs)(`div`,{children:[`外部: `,r.externalMB,` MB`]})]})]})]}),(0,K.jsx)(B,{variant:`outline`,size:`sm`,onClick:()=>o.mutate(),loading:o.isPending,children:`触发 GC`})]})}),(0,K.jsxs)(V,{children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between mb-4`,children:[(0,K.jsx)(`h3`,{className:`font-medium text-gray-900`,children:`LRU 缓存`}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(B,{variant:`ghost`,size:`sm`,icon:h,onClick:()=>void n(),children:`刷新`}),(0,K.jsx)(B,{variant:`outline`,size:`sm`,onClick:()=>e({title:`清空所有缓存`,description:`确定要清空所有 LRU 缓存吗?`,onConfirm:()=>a.mutate()}),loading:a.isPending,children:`清空全部`})]})]}),t&&t.caches.length>0?(0,K.jsx)(`div`,{className:`space-y-2`,children:t.caches.map(e=>(0,K.jsxs)(`div`,{className:`flex items-center justify-between py-3 px-4 bg-gray-50 rounded-lg`,children:[(0,K.jsxs)(`div`,{className:`flex-1`,children:[(0,K.jsx)(`p`,{className:`text-sm font-medium text-gray-900`,children:e.name}),(0,K.jsxs)(`p`,{className:`text-xs text-gray-500 mt-0.5`,children:[e.size,` / `,e.maxSize,` 条`,e.hitRate!==void 0&&` · 命中率 ${(e.hitRate*100).toFixed(1)}%`]})]}),(0,K.jsx)(B,{variant:`ghost`,size:`sm`,onClick:()=>i.mutate(e.name),loading:i.isPending&&i.variables===e.name,children:`清空`})]},e.name))}):(0,K.jsx)(`div`,{className:`text-center py-8 text-gray-400 text-sm`,children:`暂无缓存数据`})]})]})}function ie({currentConfig:e,onRestore:t,onConfirm:n}){let[r,i]=(0,G.useState)(null),{data:a}=x({queryKey:[`config-history`],queryFn:()=>A().then(e=>e.data)});return(0,K.jsxs)(V,{children:[(0,K.jsx)(`div`,{className:`flex items-center justify-between mb-4`,children:(0,K.jsx)(`h3`,{className:`font-medium text-gray-900`,children:`最近 10 次配置变更`})}),a&&a.items.length>0?(0,K.jsx)(`div`,{className:`space-y-2`,children:a.items.map(a=>{let o=r===String(a.id),s=e,c=[];if(o&&s){let e=(t,n=``)=>typeof t!=`object`||!t?{[n]:JSON.stringify(t)}:Object.entries(t).reduce((t,[r,i])=>{let a=n?`${n}.${r}`:r;return typeof i==`object`&&i&&!Array.isArray(i)?Object.assign(t,e(i,a)):t[a]=JSON.stringify(i),t},{}),t=e(a.config),n=e(s);new Set([...Object.keys(t),...Object.keys(n)]).forEach(e=>{let r=t[e]??`(无)`,i=n[e]??`(无)`;r!==i&&c.push({key:e,old:r,cur:i})})}return(0,K.jsxs)(`div`,{className:`py-3 px-4 bg-gray-50 rounded-lg`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsxs)(`span`,{className:`text-sm font-medium text-gray-900`,children:[`#`,a.id]}),(0,K.jsx)(`span`,{className:`text-xs text-gray-500`,children:g(new Date(a.savedAt),`yyyy-MM-dd HH:mm:ss`)})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(B,{variant:`ghost`,size:`sm`,onClick:()=>i(o?null:String(a.id)),children:o?`收起对比`:`与当前对比`}),(0,K.jsx)(B,{variant:`outline`,size:`sm`,onClick:()=>n({title:`确认恢复配置`,description:`确定要恢复到 ${g(new Date(a.savedAt),`yyyy-MM-dd HH:mm:ss`)} 的配置吗?当前配置将被覆盖。`,onConfirm:()=>t(a.config)}),children:`恢复到此版本`})]})]}),(0,K.jsx)(H,{children:o&&(0,K.jsx)(U.div,{initial:{height:0,opacity:0},animate:{height:`auto`,opacity:1},exit:{height:0,opacity:0},transition:{duration:.2},className:`overflow-hidden`,children:(0,K.jsxs)(`div`,{className:`mt-3 rounded border border-gray-200 overflow-hidden text-xs font-mono`,children:[(0,K.jsxs)(`div`,{className:`grid grid-cols-3 bg-gray-100 px-3 py-1.5 text-gray-500 font-medium text-xs`,children:[(0,K.jsx)(`span`,{children:`配置项`}),(0,K.jsx)(`span`,{className:`text-red-600`,children:`历史值`}),(0,K.jsx)(`span`,{className:`text-green-600`,children:`当前值`})]}),c.length===0?(0,K.jsx)(`div`,{className:`px-3 py-3 text-gray-400 text-center`,children:`与当前配置完全一致`}):c.map(({key:e,old:t,cur:n})=>(0,K.jsxs)(`div`,{className:`grid grid-cols-3 px-3 py-2 border-t border-gray-100 hover:bg-gray-50`,children:[(0,K.jsx)(`span`,{className:`text-gray-700 truncate`,children:e}),(0,K.jsx)(`span`,{className:`text-red-600 truncate`,children:t}),(0,K.jsx)(`span`,{className:`text-green-600 truncate`,children:n})]},e))]})})})]},a.id)})}):(0,K.jsx)(`div`,{className:`text-center py-8 text-gray-400 text-sm`,children:`暂无历史记录`})]})}function ae({content:e,children:t,className:n}){let[r,i]=(0,G.useState)(!1),[a,o]=(0,G.useState)(`top`),s=(0,G.useRef)(null);return(0,G.useEffect)(()=>{r&&s.current&&o(s.current.getBoundingClientRect().top<80?`bottom`:`top`)},[r]),(0,K.jsxs)(`span`,{ref:s,className:z(`relative inline-flex items-center cursor-help`,n),onMouseEnter:()=>i(!0),onMouseLeave:()=>i(!1),children:[t,r&&(0,K.jsx)(`span`,{className:z(`absolute z-50 w-max max-w-xs px-2.5 py-1.5 text-xs text-white bg-gray-800 rounded-lg shadow-lg pointer-events-none whitespace-normal`,a===`top`?`bottom-full mb-1.5 left-1/2 -translate-x-1/2`:`top-full mt-1.5 left-1/2 -translate-x-1/2`),children:e})]})}var q={Pipeline:`自动化工作流,将需求分解为多个节点依次执行`,Daemon:`后台守护进程,监听 Claude Code 事件并驱动编排引擎`,Hook:`Claude Code 生命周期钩子,在工具调用前后触发`,Distill:`将会话事件提炼为结构化知识,沉淀到知识图谱`,"Quality Gate":`质量门禁,在关键节点检测代码/文档质量问题`,Convention:`项目规范配置,定义节点类型、技能绑定和质量标准`,Skill:`可复用的 Claude Code 技能脚本,绑定到 Pipeline 节点`,ROI:`投资回报率,统计 AI 辅助节省的时间和 Token 用量`,Token:`LLM 处理的最小文本单元,影响 API 调用成本`,SSE:`Server-Sent Events,服务端向客户端推送实时事件的协议`},J=[{key:`distill`,title:`蒸馏配置`,description:`AI 知识蒸馏的触发条件和参数`,fields:[{key:`provider`,label:`提供商`,type:`select`,options:[{value:`claude`,label:`Claude`},{value:`openai`,label:`OpenAI`},{value:`ollama`,label:`Ollama`}]},{key:`auto_trigger`,label:`自动触发`,type:`boolean`,description:`达到事件阈值时自动蒸馏`},{key:`event_threshold`,label:`事件阈值`,type:`number`,description:`触发蒸馏的最小事件数`,min:1,max:1e4},{key:`timer_interval_minutes`,label:`定时器间隔(分钟)`,type:`number`,min:1,max:1440},{key:`model`,label:`模型`,type:`text`},{key:`api_key`,label:`API Key`,type:`text`,sensitive:!0,description:`留空自动从环境变量获取`},{key:`base_url`,label:`API 地址`,type:`text`,description:`留空使用默认地址`}]},{key:`autopilot`,title:`自动驾驶`,description:`意图分析、质量门禁、Pipeline 编排`,fields:[{key:`enabled`,label:`启用`,type:`boolean`},{key:`intent_analysis`,label:`意图分析`,type:`boolean`,description:`AI 分析用户意图和任务复杂度`},{key:`quality_gate`,label:`质量门禁`,type:`boolean`,description:`代码变更时自动审查质量`},{key:`quality_review_interval`,label:`审查间隔`,type:`number`,description:`每 N 次 Write/Edit 触发一次审查`,min:1,max:100},{key:`auto_start_pipeline`,label:`自动启动流水线`,type:`boolean`},{key:`pipeline_confirm_mode`,label:`确认模式`,type:`select`,options:[{value:`prompt`,label:`提示确认`},{value:`auto`,label:`自动启动`},{value:`preview`,label:`仅预览`}]}]},{key:`resume`,title:`会话续接`,description:`中断会话的自动恢复`,fields:[{key:`enabled`,label:`启用`,type:`boolean`},{key:`timeout_minutes`,label:`超时时间(分钟)`,type:`number`,min:1,max:1440},{key:`max_age_days`,label:`最大保留天数`,type:`number`,min:1,max:365}]},{key:`claudemd`,title:`CLAUDE.md 管理`,description:`项目级 CLAUDE.md 的自动生成与精炼`,fields:[{key:`auto_generate`,label:`自动生成`,type:`boolean`},{key:`auto_refine`,label:`自动精炼`,type:`boolean`},{key:`refine_interval`,label:`精炼间隔`,type:`number`,description:`每 N 次蒸馏后精炼一次`,min:1,max:100}]},{key:`orchestration`,title:`编排通知`,description:`蒸馏和 CLAUDE.md 更新的通知`,fields:[{key:`enabled`,label:`启用`,type:`boolean`},{key:`notify_on_distill`,label:`蒸馏完成通知`,type:`boolean`},{key:`notify_on_claudemd`,label:`CLAUDE.md 更新通知`,type:`boolean`}]},{key:`web`,title:`Web 管理后台`,description:`Web 服务配置`,fields:[{key:`enabled`,label:`启用`,type:`boolean`},{key:`port`,label:`端口`,type:`number`,min:1024,max:65535}]},{key:`ai`,title:`AI 模型`,description:`分层模型配置(Haiku/Sonnet/Opus)`,fields:[{key:`models.haiku`,label:`Haiku 模型`,type:`text`},{key:`models.sonnet`,label:`Sonnet 模型`,type:`text`},{key:`models.opus`,label:`Opus 模型`,type:`text`}]},{key:`storage`,title:`存储`,description:`数据库路径和容量限制`,fields:[{key:`path`,label:`数据库路径`,type:`text`},{key:`max_size_mb`,label:`最大容量(MB)`,type:`number`,min:100,max:102400}]},{key:`backup`,title:`备份配置`,description:`数据备份策略`,fields:[{key:`include_profile`,label:`包含用户画像`,type:`boolean`,description:`备份时包含用户画像数据`},{key:`encrypt_by_default`,label:`默认加密`,type:`boolean`,description:`备份文件默认加密`}]},{key:`pattern_engine`,title:`模式引擎`,description:`模式识别与演化配置`,fields:[{key:`enabled`,label:`启用`,type:`boolean`},{key:`route_timeout_ms`,label:`路由超时(毫秒)`,type:`number`,min:100,max:6e4},{key:`evolve_interval_days`,label:`演化间隔(天)`,type:`number`,min:1,max:365},{key:`evolve_min_executions`,label:`最小执行次数`,type:`number`,description:`触发演化的最小执行次数`,min:1,max:1e3}]},{key:`ui`,title:`UI 配置`,description:`前端界面参数`,fields:[{key:`skill_repair_limit`,label:`Skill 修复上限`,type:`number`,min:1,max:100},{key:`logs_tail_default`,label:`日志默认条数`,type:`number`,min:10,max:1e3},{key:`pipeline_expire_hours`,label:`Pipeline 过期时间(小时)`,type:`number`,min:1,max:720}]},{key:`history`,title:`配置历史`,description:`查看最近 10 次配置变更记录`,fields:[]}];function Y(){let e=y(),[t,r]=(0,G.useState)(null),[i,c]=(0,G.useState)(`idle`),[l,d]=(0,G.useState)(`distill`),[f,g]=(0,G.useState)(new Set),S=f.size>0,[T,D]=(0,G.useState)(null),[O,k]=(0,G.useState)(new Set),[A,j]=(0,G.useState)({open:!1,title:``,description:``,onConfirm:()=>{}}),{data:M,isLoading:N}=x({queryKey:[`config`],queryFn:()=>E().then(e=>e.data)}),{data:P,refetch:F}=x({queryKey:[`daemon-diagnosis`],queryFn:()=>C().then(e=>e.data),enabled:l===`environment`}),I=b({mutationFn:()=>w(),onSuccess:e=>{D(e.data),F()}});(0,G.useEffect)(()=>{M&&!t&&r(M)},[M,t]);let Y=b({mutationFn:e=>ee(e),onSuccess:()=>{e.invalidateQueries({queryKey:[`config`]}),c(`success`),g(new Set),setTimeout(()=>c(`idle`),3e3)},onError:()=>{c(`error`),setTimeout(()=>c(`idle`),3e3)}}),X=b({mutationFn:()=>L.post(`/config/reset`),onSuccess:()=>{e.invalidateQueries({queryKey:[`config`]}),r(null),c(`success`),setTimeout(()=>c(`idle`),3e3)}});if(N||!t)return(0,K.jsx)(`div`,{className:`flex items-center justify-center h-96`,children:(0,K.jsx)(`div`,{className:`animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600`})});let Z=(e,n)=>{let r=t[e];if(!r)return``;let i=n.split(`.`),a=r;for(let e of i)a=a?.[e];return a??``},Q=(e,t,n)=>{g(t=>new Set(t).add(e)),r(r=>{if(!r)return r;let i={...r[e]||{}},a=t.split(`.`);if(a.length===1)i[t]=n;else{let e={...i[a[0]]||{}};e[a[1]]=n,i[a[0]]=e}return{...r,[e]:i}})},oe=()=>{if(!t)return;let e={};f.forEach(n=>{e[n]=t[n]}),Y.mutate(e)},se=()=>{r(M),g(new Set)},ce=()=>{let e=JSON.stringify(t,null,2),n=new Blob([e],{type:`application/json`}),r=URL.createObjectURL(n),i=document.createElement(`a`);i.href=r,i.download=`claude-forge-config-${new Date().toISOString().slice(0,10)}.json`,i.click(),URL.revokeObjectURL(r)},le=()=>{let e=document.createElement(`input`);e.type=`file`,e.accept=`.json`,e.onchange=e=>{let t=e.target.files?.[0];if(!t)return;let n=new FileReader;n.onload=e=>{try{r(JSON.parse(e.target?.result)),g(new Set(J.map(e=>e.key)))}catch{R(`配置文件格式错误,请选择有效的 JSON 文件`,`error`)}},n.readAsText(t)},e.click()},$=J.find(e=>e.key===l);return(0,K.jsxs)(`div`,{className:`flex gap-6`,children:[(0,K.jsx)(`div`,{className:`w-56 flex-shrink-0`,children:(0,K.jsx)(V,{className:`!p-2 sticky top-6`,children:(0,K.jsxs)(`nav`,{className:`space-y-1`,children:[J.map(e=>(0,K.jsx)(`button`,{onClick:()=>d(e.key),className:z(`w-full text-left px-3 py-2.5 rounded-lg text-sm transition-colors`,l===e.key?`bg-blue-50 text-blue-700 font-medium`:`text-gray-600 hover:bg-gray-50 hover:text-gray-900`),children:q[e.title]?(0,K.jsx)(ae,{content:q[e.title],children:e.title}):e.title},e.key)),(0,K.jsx)(`div`,{className:`border-t border-gray-100 my-1`}),(0,K.jsxs)(`button`,{onClick:()=>d(`backup_mgmt`),className:z(`w-full text-left px-3 py-2.5 rounded-lg text-sm transition-colors flex items-center gap-2`,l===`backup_mgmt`?`bg-blue-50 text-blue-700 font-medium`:`text-gray-600 hover:bg-gray-50 hover:text-gray-900`),children:[(0,K.jsx)(Database,{className:`h-3.5 w-3.5`}),`数据备份`]}),(0,K.jsxs)(`button`,{onClick:()=>d(`memory_mgmt`),className:z(`w-full text-left px-3 py-2.5 rounded-lg text-sm transition-colors flex items-center gap-2`,l===`memory_mgmt`?`bg-blue-50 text-blue-700 font-medium`:`text-gray-600 hover:bg-gray-50 hover:text-gray-900`),children:[(0,K.jsx)(Cpu,{className:`h-3.5 w-3.5`}),`内存管理`]}),(0,K.jsxs)(`button`,{onClick:()=>d(`environment`),className:z(`w-full text-left px-3 py-2.5 rounded-lg text-sm transition-colors flex items-center gap-2`,l===`environment`?`bg-blue-50 text-blue-700 font-medium`:`text-gray-600 hover:bg-gray-50 hover:text-gray-900`),children:[(0,K.jsx)(o,{className:`h-3.5 w-3.5`}),`环境检测`]})]})})}),(0,K.jsxs)(`div`,{className:`flex-1 space-y-6`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h2`,{className:`text-lg font-semibold text-gray-900`,children:l===`environment`?`环境检测`:l===`backup_mgmt`?`数据备份`:l===`memory_mgmt`?`内存管理`:l===`history`?`配置历史`:$?.title}),(0,K.jsx)(`p`,{className:`text-sm text-gray-500`,children:l===`environment`?`Hook 脚本与 Claude settings.json 注入状态检测与修复`:l===`backup_mgmt`?`数据库备份与历史备份管理`:l===`memory_mgmt`?`LRU 缓存状态与进程内存管理`:l===`history`?`查看最近 10 次配置变更记录`:$?.description??``})]}),l!==`environment`&&l!==`backup_mgmt`&&l!==`memory_mgmt`&&l!==`history`&&(0,K.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,K.jsxs)(H,{children:[i===`success`&&(0,K.jsxs)(U.div,{initial:{opacity:0,x:10},animate:{opacity:1,x:0},exit:{opacity:0},className:`flex items-center gap-1.5 text-green-600 text-sm`,children:[(0,K.jsx)(u,{className:`h-4 w-4`}),`已保存`]}),i===`error`&&(0,K.jsxs)(U.div,{initial:{opacity:0,x:10},animate:{opacity:1,x:0},exit:{opacity:0},className:`flex items-center gap-1.5 text-red-600 text-sm`,children:[(0,K.jsx)(m,{className:`h-4 w-4`}),`保存失败`]})]}),S&&(0,K.jsx)(te,{variant:`warning`,children:`未保存`}),(0,K.jsx)(B,{variant:`ghost`,size:`sm`,icon:s,onClick:ce,children:`导出`}),(0,K.jsx)(B,{variant:`ghost`,size:`sm`,icon:v,onClick:le,children:`导入`}),(0,K.jsx)(B,{variant:`ghost`,size:`sm`,icon:p,onClick:se,disabled:!S,children:`撤销`}),(0,K.jsx)(B,{variant:`primary`,size:`sm`,icon:_,onClick:oe,loading:Y.isPending,disabled:!S,children:`保存`})]})]}),l!==`environment`&&l!==`backup_mgmt`&&l!==`memory_mgmt`&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(V,{children:(0,K.jsx)(`div`,{className:`space-y-6`,children:$?.fields.map(e=>(0,K.jsxs)(`div`,{className:`flex items-start gap-4`,children:[(0,K.jsxs)(`div`,{className:`w-48 flex-shrink-0 pt-2`,children:[(0,K.jsx)(`label`,{className:`text-sm font-medium text-gray-700`,children:e.label}),e.description&&(0,K.jsx)(`p`,{className:`text-xs text-gray-400 mt-0.5`,children:e.description})]}),(0,K.jsx)(`div`,{className:`flex-1`,children:e.type===`boolean`?(0,K.jsx)(`button`,{onClick:()=>Q(l,e.key,!Z(l,e.key)),className:z(`relative inline-flex h-6 w-11 items-center rounded-full transition-colors`,Z(l,e.key)?`bg-blue-600`:`bg-gray-300`),children:(0,K.jsx)(`span`,{className:z(`inline-block h-4 w-4 transform rounded-full bg-white transition-transform`,Z(l,e.key)?`translate-x-6`:`translate-x-1`)})}):e.type===`select`?(0,K.jsx)(`select`,{value:String(Z(l,e.key)||``),onChange:t=>Q(l,e.key,t.target.value),className:`w-full max-w-xs px-3 py-2 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 text-sm`,children:e.options?.map(e=>(0,K.jsx)(`option`,{value:e.value,children:e.label},e.value))}):e.type===`number`?(0,K.jsx)(`input`,{type:`number`,value:Number(Z(l,e.key))||0,onChange:t=>Q(l,e.key,Number(t.target.value)),min:e.min,max:e.max,className:`w-full max-w-xs px-3 py-2 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 text-sm`}):(0,K.jsxs)(`div`,{className:`relative flex items-center max-w-xs`,children:[(0,K.jsx)(`input`,{type:e.sensitive&&!O.has(`${l}.${e.key}`)?`password`:`text`,value:String(Z(l,e.key)||``),onChange:t=>Q(l,e.key,t.target.value),className:`w-full px-3 py-2 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 text-sm pr-9`}),e.sensitive&&(0,K.jsx)(`button`,{type:`button`,onClick:()=>k(t=>{let n=new Set(t),r=`${l}.${e.key}`;return n.has(r)?n.delete(r):n.add(r),n}),className:`absolute right-2 text-gray-400 hover:text-gray-600`,children:O.has(`${l}.${e.key}`)?(0,K.jsx)(EyeOff,{className:`h-4 w-4`}):(0,K.jsx)(Eye,{className:`h-4 w-4`})})]})})]},e.key))})}),(0,K.jsx)(V,{className:`!border-red-200`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`text-sm font-semibold text-red-600`,children:`重置配置`}),(0,K.jsx)(`p`,{className:`text-xs text-gray-500 mt-1`,children:`将所有配置恢复为默认值,此操作不可撤销`})]}),(0,K.jsx)(B,{variant:`danger`,size:`sm`,icon:n,onClick:()=>{j({open:!0,title:`重置配置`,description:`确定要重置所有配置为默认值吗?此操作不可撤销。`,onConfirm:()=>{X.mutate(),j({...A,open:!1})}})},loading:X.isPending,children:`重置`})]})})]}),l===`backup_mgmt`&&(0,K.jsx)(ne,{onConfirm:e=>j({...e,open:!0})}),l===`memory_mgmt`&&(0,K.jsx)(re,{onConfirm:e=>j({...e,open:!0})}),l===`history`&&(0,K.jsx)(ie,{currentConfig:M,onRestore:e=>Y.mutate(e),onConfirm:e=>j({...e,open:!0})}),l===`environment`&&(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(V,{children:(0,K.jsxs)(`div`,{className:`flex items-start justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`font-medium text-gray-900 mb-1`,children:`Hook 环境诊断`}),(0,K.jsx)(`p`,{className:`text-sm text-gray-500`,children:`检测 Forge hooks 脚本与 Claude settings.json 中 Forge 注入是否完整`})]}),(0,K.jsxs)(`div`,{className:`flex gap-2 flex-shrink-0`,children:[(0,K.jsx)(B,{variant:`secondary`,size:`sm`,icon:h,onClick:()=>F(),children:`重新检测`}),(0,K.jsx)(B,{size:`sm`,icon:a,onClick:()=>I.mutate(),disabled:I.isPending||P?.hooksHealthy,children:I.isPending?`修复中...`:`一键修复`})]})]})}),T&&(0,K.jsx)(V,{children:(0,K.jsxs)(`div`,{className:`flex items-start justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex items-start gap-2`,children:[T.hooksHealthy?(0,K.jsx)(u,{className:`h-4 w-4 text-green-500 mt-0.5 flex-shrink-0`}):(0,K.jsx)(n,{className:`h-4 w-4 text-yellow-500 mt-0.5 flex-shrink-0`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:z(`text-sm font-medium`,T.hooksHealthy?`text-gray-900`:`text-yellow-600`),children:T.hooksHealthy?`Hooks 环境已恢复正常`:`修复后仍有未通过项,请根据下方列表排查`}),T.backupPath&&(0,K.jsxs)(`p`,{className:`text-xs text-gray-500 mt-0.5`,children:[`已备份 settings: `,T.backupPath.split(`/`).pop()]})]})]}),(0,K.jsx)(B,{variant:`ghost`,size:`sm`,icon:m,onClick:()=>D(null)})]})}),P&&(0,K.jsx)(V,{children:(0,K.jsx)(`div`,{className:`space-y-2`,children:P.items.map(e=>(0,K.jsxs)(`div`,{className:`flex items-start gap-3 py-2 border-b border-gray-50 last:border-0`,children:[(0,K.jsx)(`div`,{className:`flex-shrink-0 mt-0.5`,children:e.ok?(0,K.jsx)(u,{className:`h-4 w-4 text-green-500`}):e.id===`daemon_process`?(0,K.jsx)(n,{className:`h-4 w-4 text-yellow-500`}):(0,K.jsx)(m,{className:`h-4 w-4 text-red-500`})}),(0,K.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,K.jsx)(`p`,{className:`text-sm font-medium text-gray-900`,children:e.label}),(0,K.jsx)(`p`,{className:`text-xs text-gray-500 mt-0.5 break-all`,children:e.detail})]})]},e.id))})}),P&&(0,K.jsx)(V,{className:P.hooksHealthy?`!border-green-200 !bg-green-50`:`!border-yellow-200 !bg-yellow-50`,children:(0,K.jsx)(`div`,{className:`flex items-center gap-2`,children:P.hooksHealthy?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(u,{className:`h-5 w-5 text-green-600`}),(0,K.jsx)(`p`,{className:`text-sm font-medium text-green-700`,children:`Hooks 相关环境正常`})]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(n,{className:`h-5 w-5 text-yellow-600`}),(0,K.jsx)(`p`,{className:`text-sm font-medium text-yellow-700`,children:`检测到 Hooks 环境不完整,请点击「一键修复」`})]})})})]})]}),(0,K.jsx)(W,{open:A.open,title:A.title,description:A.description,variant:`danger`,onConfirm:A.onConfirm,onCancel:()=>j({...A,open:!1})})]})}export{Y as default};