@winspan/claude-forge 1.4.6 → 1.6.3

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 (78) hide show
  1. package/README.md +23 -2
  2. package/dist/cli/commands/status.d.ts +3 -0
  3. package/dist/cli/commands/status.d.ts.map +1 -0
  4. package/dist/cli/commands/status.js +64 -0
  5. package/dist/cli/commands/status.js.map +1 -0
  6. package/dist/cli/commands/web.d.ts +3 -0
  7. package/dist/cli/commands/web.d.ts.map +1 -0
  8. package/dist/cli/commands/web.js +30 -0
  9. package/dist/cli/commands/web.js.map +1 -0
  10. package/dist/cli/index.js +4 -0
  11. package/dist/cli/index.js.map +1 -1
  12. package/dist/config/defaults.d.ts.map +1 -1
  13. package/dist/config/defaults.js +5 -0
  14. package/dist/config/defaults.js.map +1 -1
  15. package/dist/config/index.d.ts.map +1 -1
  16. package/dist/config/index.js +1 -0
  17. package/dist/config/index.js.map +1 -1
  18. package/dist/config/schema.d.ts +5 -0
  19. package/dist/config/schema.d.ts.map +1 -1
  20. package/dist/config/schema.js +12 -0
  21. package/dist/config/schema.js.map +1 -1
  22. package/dist/daemon/index.d.ts.map +1 -1
  23. package/dist/daemon/index.js +30 -0
  24. package/dist/daemon/index.js.map +1 -1
  25. package/dist/pipeline/index.d.ts.map +1 -1
  26. package/dist/pipeline/index.js +7 -0
  27. package/dist/pipeline/index.js.map +1 -1
  28. package/dist/storage/repositories/knowledge-repository.d.ts.map +1 -1
  29. package/dist/storage/repositories/knowledge-repository.js +22 -9
  30. package/dist/storage/repositories/knowledge-repository.js.map +1 -1
  31. package/dist/storage/repositories/task-repository.d.ts +10 -0
  32. package/dist/storage/repositories/task-repository.d.ts.map +1 -1
  33. package/dist/storage/repositories/task-repository.js +8 -0
  34. package/dist/storage/repositories/task-repository.js.map +1 -1
  35. package/dist/storage/sqlite.d.ts +10 -0
  36. package/dist/storage/sqlite.d.ts.map +1 -1
  37. package/dist/storage/sqlite.js +3 -0
  38. package/dist/storage/sqlite.js.map +1 -1
  39. package/dist/web/middleware/auth.d.ts +3 -0
  40. package/dist/web/middleware/auth.d.ts.map +1 -0
  41. package/dist/web/middleware/auth.js +11 -0
  42. package/dist/web/middleware/auth.js.map +1 -0
  43. package/dist/web/routes/config.d.ts +4 -0
  44. package/dist/web/routes/config.d.ts.map +1 -0
  45. package/dist/web/routes/config.js +102 -0
  46. package/dist/web/routes/config.js.map +1 -0
  47. package/dist/web/routes/events.d.ts +4 -0
  48. package/dist/web/routes/events.d.ts.map +1 -0
  49. package/dist/web/routes/events.js +71 -0
  50. package/dist/web/routes/events.js.map +1 -0
  51. package/dist/web/routes/knowledge.d.ts +4 -0
  52. package/dist/web/routes/knowledge.d.ts.map +1 -0
  53. package/dist/web/routes/knowledge.js +76 -0
  54. package/dist/web/routes/knowledge.js.map +1 -0
  55. package/dist/web/routes/pipelines.d.ts +4 -0
  56. package/dist/web/routes/pipelines.d.ts.map +1 -0
  57. package/dist/web/routes/pipelines.js +40 -0
  58. package/dist/web/routes/pipelines.js.map +1 -0
  59. package/dist/web/routes/quality.d.ts +4 -0
  60. package/dist/web/routes/quality.d.ts.map +1 -0
  61. package/dist/web/routes/quality.js +72 -0
  62. package/dist/web/routes/quality.js.map +1 -0
  63. package/dist/web/routes/sessions.d.ts +4 -0
  64. package/dist/web/routes/sessions.d.ts.map +1 -0
  65. package/dist/web/routes/sessions.js +207 -0
  66. package/dist/web/routes/sessions.js.map +1 -0
  67. package/dist/web/routes/stats.d.ts +4 -0
  68. package/dist/web/routes/stats.d.ts.map +1 -0
  69. package/dist/web/routes/stats.js +145 -0
  70. package/dist/web/routes/stats.js.map +1 -0
  71. package/dist/web/server.d.ts +18 -0
  72. package/dist/web/server.d.ts.map +1 -0
  73. package/dist/web/server.js +93 -0
  74. package/dist/web/server.js.map +1 -0
  75. package/dist/web-static/assets/index-3Sw33EKn.js +62 -0
  76. package/dist/web-static/assets/index-wxH-x453.css +2 -0
  77. package/dist/web-static/index.html +13 -0
  78. package/package.json +31 -2
@@ -0,0 +1,71 @@
1
+ export function registerEventRoutes(app, storage) {
2
+ // 获取事件列表
3
+ app.get('/api/events', (req, res) => {
4
+ try {
5
+ const { session_id, tool_name, start_time, end_time, limit = 100 } = req.query;
6
+ const events = storage.queryEvents({
7
+ session_id: session_id,
8
+ tool_name: tool_name,
9
+ start_time: start_time,
10
+ end_time: end_time,
11
+ limit: Number(limit),
12
+ });
13
+ res.json({
14
+ total: events.length,
15
+ items: events,
16
+ });
17
+ }
18
+ catch (err) {
19
+ res.status(500).json({ error: String(err) });
20
+ }
21
+ });
22
+ // 获取会话列表
23
+ app.get('/api/sessions', (req, res) => {
24
+ try {
25
+ const { project_path, status, limit = 50 } = req.query;
26
+ const sessions = storage.querySessions({
27
+ project_path: project_path,
28
+ status: status,
29
+ limit: Number(limit),
30
+ });
31
+ res.json({
32
+ total: sessions.length,
33
+ items: sessions,
34
+ });
35
+ }
36
+ catch (err) {
37
+ res.status(500).json({ error: String(err) });
38
+ }
39
+ });
40
+ // 获取事件统计
41
+ app.get('/api/events/stats', (req, res) => {
42
+ try {
43
+ const { project_path } = req.query;
44
+ if (!project_path || typeof project_path !== 'string') {
45
+ return res.status(400).json({ error: 'project_path 参数必填' });
46
+ }
47
+ // 使用 storage 封装的方法,避免直接访问 db
48
+ const events = storage.queryEvents({ project_path, limit: 10000 });
49
+ // 在内存中聚合统计
50
+ const statsMap = new Map();
51
+ for (const event of events) {
52
+ const date = event.timestamp.split('T')[0];
53
+ if (!statsMap.has(event.hook_type)) {
54
+ statsMap.set(event.hook_type, new Map());
55
+ }
56
+ const dateMap = statsMap.get(event.hook_type);
57
+ dateMap.set(date, (dateMap.get(date) || 0) + 1);
58
+ }
59
+ const stats = Array.from(statsMap.entries()).flatMap(([hook_type, dateMap]) => Array.from(dateMap.entries()).map(([date, count]) => ({
60
+ hook_type,
61
+ count,
62
+ date,
63
+ }))).sort((a, b) => b.date.localeCompare(a.date)).slice(0, 30);
64
+ res.json({ stats });
65
+ }
66
+ catch (err) {
67
+ res.status(500).json({ error: String(err) });
68
+ }
69
+ });
70
+ }
71
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../../src/web/routes/events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { Express } from 'express';
2
+ import type { SQLiteStorage } from '../../storage/sqlite.js';
3
+ export declare function registerKnowledgeRoutes(app: Express, storage: SQLiteStorage): void;
4
+ //# sourceMappingURL=knowledge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"knowledge.d.ts","sourceRoot":"","sources":["../../../src/web/routes/knowledge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI,CA8ElF"}
@@ -0,0 +1,76 @@
1
+ export function registerKnowledgeRoutes(app, storage) {
2
+ // 搜索知识节点
3
+ app.get('/api/knowledge/search', (req, res) => {
4
+ try {
5
+ const { q = '', project_path = '', limit = 50 } = req.query;
6
+ const query = typeof q === 'string' ? q : '';
7
+ const projectPath = typeof project_path === 'string' ? project_path : '';
8
+ const nodes = storage.searchKnowledgeNodes(query, projectPath, Number(limit));
9
+ res.json({
10
+ total: nodes.length,
11
+ items: nodes,
12
+ });
13
+ }
14
+ catch (err) {
15
+ res.status(500).json({ error: String(err) });
16
+ }
17
+ });
18
+ // 获取节点的关联边
19
+ app.get('/api/knowledge/edges', (req, res) => {
20
+ try {
21
+ const { node_id } = req.query;
22
+ if (!node_id || typeof node_id !== 'string') {
23
+ return res.status(400).json({ error: 'node_id 参数必填' });
24
+ }
25
+ const edges = storage.getKnowledgeEdges(node_id);
26
+ res.json({
27
+ total: edges.length,
28
+ items: edges,
29
+ });
30
+ }
31
+ catch (err) {
32
+ res.status(500).json({ error: String(err) });
33
+ }
34
+ });
35
+ // 获取邻居节点(图谱浏览)
36
+ app.get('/api/knowledge/neighbors', (req, res) => {
37
+ try {
38
+ const { node_id, project_path = '', limit = 10 } = req.query;
39
+ if (!node_id || typeof node_id !== 'string') {
40
+ return res.status(400).json({ error: 'node_id 参数必填' });
41
+ }
42
+ const projectPath = typeof project_path === 'string' ? project_path : '';
43
+ const neighbors = storage.getNeighborNodes(node_id, projectPath, Number(limit));
44
+ res.json({
45
+ total: neighbors.length,
46
+ items: neighbors,
47
+ });
48
+ }
49
+ catch (err) {
50
+ res.status(500).json({ error: String(err) });
51
+ }
52
+ });
53
+ // 获取知识图谱概览
54
+ app.get('/api/knowledge/overview', (req, res) => {
55
+ try {
56
+ const { project_path = '' } = req.query;
57
+ const projectPath = typeof project_path === 'string' ? project_path : '';
58
+ const allNodes = storage.searchKnowledgeNodes('', projectPath, 500);
59
+ // 按类型分组
60
+ const byType = allNodes.reduce((acc, n) => {
61
+ const type = n.node_type || 'unknown';
62
+ acc[type] = (acc[type] || 0) + 1;
63
+ return acc;
64
+ }, {});
65
+ res.json({
66
+ totalNodes: allNodes.length,
67
+ byType,
68
+ recentNodes: allNodes.slice(0, 20),
69
+ });
70
+ }
71
+ catch (err) {
72
+ res.status(500).json({ error: String(err) });
73
+ }
74
+ });
75
+ }
76
+ //# sourceMappingURL=knowledge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"knowledge.js","sourceRoot":"","sources":["../../../src/web/routes/knowledge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { Express } from 'express';
2
+ import type { SQLiteStorage } from '../../storage/sqlite.js';
3
+ export declare function registerPipelineRoutes(app: Express, storage: SQLiteStorage): void;
4
+ //# sourceMappingURL=pipelines.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipelines.d.ts","sourceRoot":"","sources":["../../../src/web/routes/pipelines.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI,CAyCjF"}
@@ -0,0 +1,40 @@
1
+ export function registerPipelineRoutes(app, storage) {
2
+ // 获取 Pipeline 列表
3
+ app.get('/api/pipelines', (req, res) => {
4
+ try {
5
+ const { project_path, limit = 50 } = req.query;
6
+ // 从 task_sessions 表查询 Pipeline 记录
7
+ const pipelines = storage.getTaskSessionsByType('pipeline').slice(0, Number(limit));
8
+ res.json({
9
+ total: pipelines.length,
10
+ items: pipelines.map(p => ({
11
+ id: p.task_id,
12
+ project: p.project_path,
13
+ phase: p.metadata?.phase || 'unknown',
14
+ status: p.status,
15
+ created_at: p.created_at,
16
+ completed_at: p.completed_at,
17
+ })),
18
+ });
19
+ }
20
+ catch (err) {
21
+ res.status(500).json({ error: String(err) });
22
+ }
23
+ });
24
+ // 获取单个 Pipeline 详情
25
+ app.get('/api/pipelines/:id', (req, res) => {
26
+ try {
27
+ const id = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
28
+ const pipeline = storage.getTaskSession(id);
29
+ if (!pipeline) {
30
+ res.status(404).json({ error: 'Pipeline not found' });
31
+ return;
32
+ }
33
+ res.json(pipeline);
34
+ }
35
+ catch (err) {
36
+ res.status(500).json({ error: String(err) });
37
+ }
38
+ });
39
+ }
40
+ //# sourceMappingURL=pipelines.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipelines.js","sourceRoot":"","sources":["../../../src/web/routes/pipelines.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,sBAAsB,CAAC,GAAY,EAAE,OAAsB;IACzE,iBAAiB;IACjB,GAAG,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;QACxD,IAAI,CAAC;YACH,MAAM,EAAE,YAAY,EAAE,KAAK,GAAG,EAAE,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC;YAE/C,kCAAkC;YAClC,MAAM,SAAS,GAAG,OAAO,CAAC,qBAAqB,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAEpF,GAAG,CAAC,IAAI,CAAC;gBACP,KAAK,EAAE,SAAS,CAAC,MAAM;gBACvB,KAAK,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;oBACzB,EAAE,EAAE,CAAC,CAAC,OAAO;oBACb,OAAO,EAAE,CAAC,CAAC,YAAY;oBACvB,KAAK,EAAG,CAAC,CAAC,QAAgD,EAAE,KAAK,IAAI,SAAS;oBAC9E,MAAM,EAAE,CAAC,CAAC,MAAM;oBAChB,UAAU,EAAE,CAAC,CAAC,UAAU;oBACxB,YAAY,EAAE,CAAC,CAAC,YAAY;iBAC7B,CAAC,CAAC;aACJ,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,mBAAmB;IACnB,GAAG,CAAC,GAAG,CAAC,oBAAoB,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;QAC5D,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3E,MAAM,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;YAE5C,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC,CAAC;gBACtD,OAAO;YACT,CAAC;YAED,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Express } from 'express';
2
+ import type { SQLiteStorage } from '../../storage/sqlite.js';
3
+ export declare function registerQualityRoutes(app: Express, storage: SQLiteStorage): void;
4
+ //# sourceMappingURL=quality.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality.d.ts","sourceRoot":"","sources":["../../../src/web/routes/quality.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI,CA+EhF"}
@@ -0,0 +1,72 @@
1
+ export function registerQualityRoutes(app, storage) {
2
+ // 获取质量门禁历史
3
+ app.get('/api/quality/history', (req, res) => {
4
+ try {
5
+ const { session_id, project_path, limit = 100 } = req.query;
6
+ // 使用 storage 封装的方法
7
+ const allIssues = storage.getQualityHistory();
8
+ let filtered = allIssues;
9
+ if (session_id && typeof session_id === 'string') {
10
+ filtered = filtered.filter(i => i.session_id === session_id);
11
+ }
12
+ if (project_path && typeof project_path === 'string') {
13
+ filtered = filtered.filter(i => i.project_path === project_path);
14
+ }
15
+ const limitNum = Number(limit);
16
+ const items = filtered.slice(0, limitNum);
17
+ res.json({
18
+ total: items.length,
19
+ items,
20
+ });
21
+ }
22
+ catch (err) {
23
+ res.status(500).json({ error: String(err) });
24
+ }
25
+ });
26
+ // 获取未解决的质量问题
27
+ app.get('/api/quality/unresolved', (req, res) => {
28
+ try {
29
+ const { project_path } = req.query;
30
+ const issues = storage.getUnresolvedIssues(project_path);
31
+ res.json({
32
+ total: issues.length,
33
+ items: issues,
34
+ });
35
+ }
36
+ catch (err) {
37
+ res.status(500).json({ error: String(err) });
38
+ }
39
+ });
40
+ // 获取质量统计
41
+ app.get('/api/quality/stats', (req, res) => {
42
+ try {
43
+ const { project_path } = req.query;
44
+ if (!project_path || typeof project_path !== 'string') {
45
+ return res.status(400).json({ error: 'project_path 参数必填' });
46
+ }
47
+ // 使用 storage 封装的方法
48
+ const history = storage.getQualityHistory().filter(h => h.project_path === project_path);
49
+ // 在内存中聚合统计
50
+ const statsMap = new Map();
51
+ for (const item of history) {
52
+ if (!statsMap.has(item.level)) {
53
+ statsMap.set(item.level, { count: 0, resolved: 0 });
54
+ }
55
+ const stat = statsMap.get(item.level);
56
+ stat.count++;
57
+ if (item.resolved)
58
+ stat.resolved++;
59
+ }
60
+ const stats = Array.from(statsMap.entries()).map(([level, { count, resolved }]) => ({
61
+ level,
62
+ count,
63
+ resolve_rate: count > 0 ? resolved / count : 0,
64
+ }));
65
+ res.json({ stats });
66
+ }
67
+ catch (err) {
68
+ res.status(500).json({ error: String(err) });
69
+ }
70
+ });
71
+ }
72
+ //# sourceMappingURL=quality.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality.js","sourceRoot":"","sources":["../../../src/web/routes/quality.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { Express } from 'express';
2
+ import type { SQLiteStorage } from '../../storage/sqlite.js';
3
+ export declare function registerSessionRoutes(app: Express, storage: SQLiteStorage): void;
4
+ //# sourceMappingURL=sessions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../../src/web/routes/sessions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AA6I7D,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI,CAoHhF"}
@@ -0,0 +1,207 @@
1
+ /** 从事件流中提取阶段信息 */
2
+ function extractPhases(events) {
3
+ const phases = [];
4
+ let currentPhase = null;
5
+ for (const event of events) {
6
+ const msg = typeof event.tool_input === 'string' ? event.tool_input : JSON.stringify(event.tool_input || '');
7
+ const outMsg = typeof event.tool_output === 'string' ? event.tool_output : JSON.stringify(event.tool_output || '');
8
+ // 检测阶段推进
9
+ if (event.hook_type === 'UserPromptSubmit') {
10
+ if (currentPhase) {
11
+ currentPhase.endTime = event.timestamp;
12
+ currentPhase.duration = new Date(event.timestamp).getTime() - new Date(currentPhase.startTime).getTime();
13
+ phases.push(currentPhase);
14
+ }
15
+ currentPhase = {
16
+ name: `用户输入 #${phases.length + 1}`,
17
+ startTime: event.timestamp,
18
+ events: [],
19
+ artifacts: [],
20
+ toolCalls: 0,
21
+ writeOps: 0,
22
+ };
23
+ }
24
+ if (currentPhase) {
25
+ currentPhase.events.push({
26
+ time: event.timestamp,
27
+ hookType: event.hook_type,
28
+ toolName: event.tool_name,
29
+ input: msg.slice(0, 200),
30
+ output: outMsg.slice(0, 200),
31
+ });
32
+ if (event.hook_type === 'PostToolUse') {
33
+ currentPhase.toolCalls++;
34
+ if (event.tool_name === 'Write' || event.tool_name === 'Edit') {
35
+ currentPhase.writeOps++;
36
+ const filePath = event.tool_input?.file_path;
37
+ if (typeof filePath === 'string') {
38
+ currentPhase.artifacts.push(filePath.split('/').pop() || filePath);
39
+ }
40
+ }
41
+ }
42
+ }
43
+ }
44
+ if (currentPhase) {
45
+ currentPhase.endTime = events[events.length - 1]?.timestamp;
46
+ if (currentPhase.endTime) {
47
+ currentPhase.duration = new Date(currentPhase.endTime).getTime() - new Date(currentPhase.startTime).getTime();
48
+ }
49
+ phases.push(currentPhase);
50
+ }
51
+ return phases;
52
+ }
53
+ /** 从事件流中构建数据流图 */
54
+ function buildDataFlow(events) {
55
+ const nodes = [];
56
+ const edges = [];
57
+ let nodeId = 0;
58
+ let lastNodeId = null;
59
+ for (const event of events) {
60
+ const id = `n${nodeId++}`;
61
+ if (event.hook_type === 'UserPromptSubmit') {
62
+ nodes.push({
63
+ id,
64
+ type: 'intent',
65
+ label: '用户输入',
66
+ detail: typeof event.tool_input === 'string' ? event.tool_input.slice(0, 100) : '',
67
+ time: event.timestamp,
68
+ status: 'info',
69
+ });
70
+ if (lastNodeId)
71
+ edges.push({ from: lastNodeId, to: id });
72
+ lastNodeId = id;
73
+ }
74
+ else if (event.hook_type === 'PreToolUse' && event.tool_name) {
75
+ const isWrite = event.tool_name === 'Write' || event.tool_name === 'Edit';
76
+ nodes.push({
77
+ id,
78
+ type: isWrite ? 'artifact' : 'tool',
79
+ label: event.tool_name,
80
+ detail: (() => {
81
+ const input = event.tool_input;
82
+ if (input?.file_path)
83
+ return String(input.file_path).split('/').pop() || '';
84
+ if (input?.command)
85
+ return String(input.command).slice(0, 60);
86
+ if (input?.pattern)
87
+ return String(input.pattern);
88
+ return '';
89
+ })(),
90
+ time: event.timestamp,
91
+ status: isWrite ? 'success' : 'info',
92
+ });
93
+ if (lastNodeId)
94
+ edges.push({ from: lastNodeId, to: id, label: event.tool_name });
95
+ lastNodeId = id;
96
+ }
97
+ }
98
+ return { nodes, edges };
99
+ }
100
+ export function registerSessionRoutes(app, storage) {
101
+ // 获取会话详情(含阶段、数据流)
102
+ app.get('/api/sessions/:id', (req, res) => {
103
+ try {
104
+ const id = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
105
+ const session = storage.getSession(id);
106
+ if (!session) {
107
+ return res.status(404).json({ error: '会话不存在' });
108
+ }
109
+ const events = storage.queryEvents({ session_id: id, limit: 5000 });
110
+ // 工具使用统计
111
+ const toolUsage = events.reduce((acc, e) => {
112
+ const tool = e.tool_name || 'N/A';
113
+ acc[tool] = (acc[tool] || 0) + 1;
114
+ return acc;
115
+ }, {});
116
+ // 事件类型统计
117
+ const hookTypes = events.reduce((acc, e) => {
118
+ acc[e.hook_type] = (acc[e.hook_type] || 0) + 1;
119
+ return acc;
120
+ }, {});
121
+ // 提取阶段信息
122
+ const phases = extractPhases(events);
123
+ // 构建数据流图
124
+ const dataFlow = buildDataFlow(events);
125
+ // 时间线(按分钟聚合)
126
+ const timeline = events.reduce((acc, e) => {
127
+ const minute = e.timestamp.slice(0, 16); // YYYY-MM-DDTHH:MM
128
+ const last = acc[acc.length - 1];
129
+ if (last && last.time === minute) {
130
+ last.count++;
131
+ }
132
+ else {
133
+ acc.push({ time: minute, count: 1 });
134
+ }
135
+ return acc;
136
+ }, []);
137
+ res.json({
138
+ session,
139
+ events: events.slice(0, 200), // 前端展示用
140
+ phases,
141
+ dataFlow,
142
+ timeline,
143
+ stats: {
144
+ totalEvents: events.length,
145
+ toolUsage,
146
+ hookTypes,
147
+ writeOps: events.filter(e => e.tool_name === 'Write' || e.tool_name === 'Edit').length,
148
+ readOps: events.filter(e => e.tool_name === 'Read' || e.tool_name === 'Glob' || e.tool_name === 'Grep').length,
149
+ bashOps: events.filter(e => e.tool_name === 'Bash').length,
150
+ duration: session.end_time
151
+ ? new Date(session.end_time).getTime() - new Date(session.start_time).getTime()
152
+ : Date.now() - new Date(session.start_time).getTime(),
153
+ },
154
+ });
155
+ }
156
+ catch (err) {
157
+ res.status(500).json({ error: String(err) });
158
+ }
159
+ });
160
+ // 删除会话
161
+ app.delete('/api/sessions/:id', (req, res) => {
162
+ try {
163
+ const id = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
164
+ res.json({ success: true, message: '会话已删除' });
165
+ }
166
+ catch (err) {
167
+ res.status(500).json({ error: String(err) });
168
+ }
169
+ });
170
+ // 实时统计
171
+ app.get('/api/sessions/stats/realtime', (req, res) => {
172
+ try {
173
+ const sessions = storage.querySessions({ limit: 1000 });
174
+ const events = storage.queryEvents({ limit: 5000 });
175
+ const now = Date.now();
176
+ const last24h = now - 24 * 60 * 60 * 1000;
177
+ const last7d = now - 7 * 24 * 60 * 60 * 1000;
178
+ res.json({
179
+ total: {
180
+ sessions: sessions.length,
181
+ events: events.length,
182
+ activeSessions: sessions.filter(s => s.status === 'active').length,
183
+ },
184
+ last24h: {
185
+ sessions: sessions.filter(s => new Date(s.start_time).getTime() > last24h).length,
186
+ events: events.filter(e => new Date(e.timestamp).getTime() > last24h).length,
187
+ },
188
+ last7d: {
189
+ sessions: sessions.filter(s => new Date(s.start_time).getTime() > last7d).length,
190
+ events: events.filter(e => new Date(e.timestamp).getTime() > last7d).length,
191
+ },
192
+ topProjects: Object.entries(sessions.reduce((acc, s) => {
193
+ const project = s.project_path.split('/').pop() || 'Unknown';
194
+ acc[project] = (acc[project] || 0) + 1;
195
+ return acc;
196
+ }, {}))
197
+ .sort((a, b) => b[1] - a[1])
198
+ .slice(0, 5)
199
+ .map(([name, count]) => ({ name, count: count })),
200
+ });
201
+ }
202
+ catch (err) {
203
+ res.status(500).json({ error: String(err) });
204
+ }
205
+ });
206
+ }
207
+ //# sourceMappingURL=sessions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../../src/web/routes/sessions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { Express } from 'express';
2
+ import type { SQLiteStorage } from '../../storage/sqlite.js';
3
+ export declare function registerStatsRoutes(app: Express, storage: SQLiteStorage): void;
4
+ //# sourceMappingURL=stats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../../src/web/routes/stats.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI,CAoK9E"}