@stackmemoryai/stackmemory 0.2.4 → 0.2.6

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 (179) hide show
  1. package/README.md +108 -0
  2. package/dist/index.js +382 -0
  3. package/dist/src/analytics/api/analytics-api.d.ts +24 -0
  4. package/dist/src/analytics/api/analytics-api.d.ts.map +1 -0
  5. package/dist/src/analytics/api/analytics-api.js +279 -0
  6. package/dist/src/analytics/api/analytics-api.js.map +1 -0
  7. package/dist/src/analytics/core/analytics-service.d.ts +23 -0
  8. package/dist/src/analytics/core/analytics-service.d.ts.map +1 -0
  9. package/dist/src/analytics/core/analytics-service.js +160 -0
  10. package/dist/src/analytics/core/analytics-service.js.map +1 -0
  11. package/dist/src/analytics/index.d.ts +12 -0
  12. package/dist/src/analytics/index.d.ts.map +1 -0
  13. package/dist/src/analytics/index.js +11 -0
  14. package/dist/src/analytics/index.js.map +1 -0
  15. package/dist/src/analytics/queries/metrics-queries.d.ts +11 -0
  16. package/dist/src/analytics/queries/metrics-queries.d.ts.map +1 -0
  17. package/dist/src/analytics/queries/metrics-queries.js +179 -0
  18. package/dist/src/analytics/queries/metrics-queries.js.map +1 -0
  19. package/dist/src/analytics/types/metrics.d.ts +60 -0
  20. package/dist/src/analytics/types/metrics.d.ts.map +1 -0
  21. package/dist/src/analytics/types/metrics.js +2 -0
  22. package/dist/src/analytics/types/metrics.js.map +1 -0
  23. package/dist/src/cli/analytics-viewer.d.ts +3 -0
  24. package/dist/src/cli/analytics-viewer.d.ts.map +1 -0
  25. package/dist/src/cli/analytics-viewer.js +89 -0
  26. package/dist/src/cli/analytics-viewer.js.map +1 -0
  27. package/dist/src/cli/browser-test.d.ts +6 -0
  28. package/dist/src/cli/browser-test.d.ts.map +1 -0
  29. package/dist/src/cli/browser-test.js +32 -0
  30. package/dist/src/cli/browser-test.js.map +1 -0
  31. package/dist/src/cli/cli.js +157 -0
  32. package/dist/src/cli/cli.js.map +1 -1
  33. package/dist/src/cli/commands/projects.d.ts +8 -0
  34. package/dist/src/cli/commands/projects.d.ts.map +1 -0
  35. package/dist/src/cli/commands/projects.js +220 -0
  36. package/dist/src/cli/commands/projects.js.map +1 -0
  37. package/dist/src/cli/index.d.ts +7 -0
  38. package/dist/src/cli/index.d.ts.map +1 -0
  39. package/dist/src/cli/index.js +704 -0
  40. package/dist/src/cli/index.js.map +1 -0
  41. package/dist/src/cli/project-commands.d.ts +8 -0
  42. package/dist/src/cli/project-commands.d.ts.map +1 -0
  43. package/dist/src/cli/project-commands.js +212 -0
  44. package/dist/src/cli/project-commands.js.map +1 -0
  45. package/dist/src/cli/utils/viewer.d.ts +3 -0
  46. package/dist/src/cli/utils/viewer.d.ts.map +1 -0
  47. package/dist/src/cli/utils/viewer.js +89 -0
  48. package/dist/src/cli/utils/viewer.js.map +1 -0
  49. package/dist/src/core/context/frame-manager.d.ts +106 -0
  50. package/dist/src/core/context/frame-manager.d.ts.map +1 -0
  51. package/dist/src/core/context/frame-manager.js +387 -0
  52. package/dist/src/core/context/frame-manager.js.map +1 -0
  53. package/dist/src/core/logger.test.js +1 -1
  54. package/dist/src/core/logger.test.js.map +1 -1
  55. package/dist/src/core/monitoring/error-handler.d.ts +46 -0
  56. package/dist/src/core/monitoring/error-handler.d.ts.map +1 -0
  57. package/dist/src/core/monitoring/error-handler.js +212 -0
  58. package/dist/src/core/monitoring/error-handler.js.map +1 -0
  59. package/dist/src/core/monitoring/logger.d.ts +24 -0
  60. package/dist/src/core/monitoring/logger.d.ts.map +1 -0
  61. package/dist/src/core/monitoring/logger.js +121 -0
  62. package/dist/src/core/monitoring/logger.js.map +1 -0
  63. package/dist/src/core/monitoring/metrics.d.ts +7 -0
  64. package/dist/src/core/monitoring/metrics.d.ts.map +1 -0
  65. package/dist/src/core/monitoring/metrics.js +13 -0
  66. package/dist/src/core/monitoring/metrics.js.map +1 -0
  67. package/dist/src/core/monitoring/progress-tracker.d.ts +95 -0
  68. package/dist/src/core/monitoring/progress-tracker.d.ts.map +1 -0
  69. package/dist/src/core/monitoring/progress-tracker.js +178 -0
  70. package/dist/src/core/monitoring/progress-tracker.js.map +1 -0
  71. package/dist/src/core/project-manager.d.ts +130 -0
  72. package/dist/src/core/project-manager.d.ts.map +1 -0
  73. package/dist/src/core/project-manager.js +582 -0
  74. package/dist/src/core/project-manager.js.map +1 -0
  75. package/dist/src/core/projects/project-manager.d.ts +130 -0
  76. package/dist/src/core/projects/project-manager.d.ts.map +1 -0
  77. package/dist/src/core/projects/project-manager.js +591 -0
  78. package/dist/src/core/projects/project-manager.js.map +1 -0
  79. package/dist/src/core/utils/update-checker.d.ts +38 -0
  80. package/dist/src/core/utils/update-checker.d.ts.map +1 -0
  81. package/dist/src/core/utils/update-checker.js +156 -0
  82. package/dist/src/core/utils/update-checker.js.map +1 -0
  83. package/dist/src/features/analytics/api/analytics-api.d.ts +24 -0
  84. package/dist/src/features/analytics/api/analytics-api.d.ts.map +1 -0
  85. package/dist/src/features/analytics/api/analytics-api.js +289 -0
  86. package/dist/src/features/analytics/api/analytics-api.js.map +1 -0
  87. package/dist/src/features/analytics/core/analytics-service.d.ts +23 -0
  88. package/dist/src/features/analytics/core/analytics-service.d.ts.map +1 -0
  89. package/dist/src/features/analytics/core/analytics-service.js +160 -0
  90. package/dist/src/features/analytics/core/analytics-service.js.map +1 -0
  91. package/dist/src/features/analytics/index.d.ts +12 -0
  92. package/dist/src/features/analytics/index.d.ts.map +1 -0
  93. package/dist/src/features/analytics/index.js +11 -0
  94. package/dist/src/features/analytics/index.js.map +1 -0
  95. package/dist/src/features/analytics/queries/metrics-queries.d.ts +11 -0
  96. package/dist/src/features/analytics/queries/metrics-queries.d.ts.map +1 -0
  97. package/dist/src/features/analytics/queries/metrics-queries.js +183 -0
  98. package/dist/src/features/analytics/queries/metrics-queries.js.map +1 -0
  99. package/dist/src/features/analytics/types/metrics.d.ts +60 -0
  100. package/dist/src/features/analytics/types/metrics.d.ts.map +1 -0
  101. package/dist/src/features/analytics/types/metrics.js +2 -0
  102. package/dist/src/features/analytics/types/metrics.js.map +1 -0
  103. package/dist/src/features/browser/browser-mcp.d.ts +94 -0
  104. package/dist/src/features/browser/browser-mcp.d.ts.map +1 -0
  105. package/dist/src/features/browser/browser-mcp.js +456 -0
  106. package/dist/src/features/browser/browser-mcp.js.map +1 -0
  107. package/dist/src/features/tasks/pebbles-task-store.d.ts +117 -0
  108. package/dist/src/features/tasks/pebbles-task-store.d.ts.map +1 -0
  109. package/dist/src/features/tasks/pebbles-task-store.js +335 -0
  110. package/dist/src/features/tasks/pebbles-task-store.js.map +1 -0
  111. package/dist/src/features/tasks/task-aware-context.d.ts +103 -0
  112. package/dist/src/features/tasks/task-aware-context.d.ts.map +1 -0
  113. package/dist/src/features/tasks/task-aware-context.js +412 -0
  114. package/dist/src/features/tasks/task-aware-context.js.map +1 -0
  115. package/dist/src/index.d.ts +4 -4
  116. package/dist/src/index.d.ts.map +1 -1
  117. package/dist/src/index.js +4 -4
  118. package/dist/src/index.js.map +1 -1
  119. package/dist/src/integrations/browser-mcp.d.ts +94 -0
  120. package/dist/src/integrations/browser-mcp.d.ts.map +1 -0
  121. package/dist/src/integrations/browser-mcp.js +431 -0
  122. package/dist/src/integrations/browser-mcp.js.map +1 -0
  123. package/dist/src/integrations/linear/auth.d.ts +99 -0
  124. package/dist/src/integrations/linear/auth.d.ts.map +1 -0
  125. package/dist/src/integrations/linear/auth.js +319 -0
  126. package/dist/src/integrations/linear/auth.js.map +1 -0
  127. package/dist/src/integrations/linear/auto-sync.d.ts +77 -0
  128. package/dist/src/integrations/linear/auto-sync.d.ts.map +1 -0
  129. package/dist/src/integrations/linear/auto-sync.js +268 -0
  130. package/dist/src/integrations/linear/auto-sync.js.map +1 -0
  131. package/dist/src/integrations/linear/client.d.ts +86 -0
  132. package/dist/src/integrations/linear/client.d.ts.map +1 -0
  133. package/dist/src/integrations/linear/client.js +277 -0
  134. package/dist/src/integrations/linear/client.js.map +1 -0
  135. package/dist/src/integrations/linear/config.d.ts +51 -0
  136. package/dist/src/integrations/linear/config.d.ts.map +1 -0
  137. package/dist/src/integrations/linear/config.js +103 -0
  138. package/dist/src/integrations/linear/config.js.map +1 -0
  139. package/dist/src/integrations/linear/sync.d.ts +97 -0
  140. package/dist/src/integrations/linear/sync.d.ts.map +1 -0
  141. package/dist/src/integrations/linear/sync.js +391 -0
  142. package/dist/src/integrations/linear/sync.js.map +1 -0
  143. package/dist/src/integrations/mcp/server.d.ts +40 -0
  144. package/dist/src/integrations/mcp/server.d.ts.map +1 -0
  145. package/dist/src/integrations/mcp/server.js +828 -0
  146. package/dist/src/integrations/mcp/server.js.map +1 -0
  147. package/dist/src/mcp/mcp-server.d.ts +1 -0
  148. package/dist/src/mcp/mcp-server.d.ts.map +1 -1
  149. package/dist/src/mcp/mcp-server.js +11 -0
  150. package/dist/src/mcp/mcp-server.js.map +1 -1
  151. package/dist/src/railway/index.d.ts +7 -0
  152. package/dist/src/railway/index.d.ts.map +1 -0
  153. package/dist/src/railway/index.js +401 -0
  154. package/dist/src/railway/index.js.map +1 -0
  155. package/dist/src/runway/auth/auth-middleware.d.ts +66 -0
  156. package/dist/src/runway/auth/auth-middleware.d.ts.map +1 -0
  157. package/dist/src/runway/auth/auth-middleware.js +337 -0
  158. package/dist/src/runway/auth/auth-middleware.js.map +1 -0
  159. package/dist/src/runway/server/runway-mcp-server.d.ts +46 -0
  160. package/dist/src/runway/server/runway-mcp-server.d.ts.map +1 -0
  161. package/dist/src/runway/server/runway-mcp-server.js +601 -0
  162. package/dist/src/runway/server/runway-mcp-server.js.map +1 -0
  163. package/dist/src/runway.bak/auth/auth-middleware.d.ts +66 -0
  164. package/dist/src/runway.bak/auth/auth-middleware.d.ts.map +1 -0
  165. package/dist/src/runway.bak/auth/auth-middleware.js +337 -0
  166. package/dist/src/runway.bak/auth/auth-middleware.js.map +1 -0
  167. package/dist/src/runway.bak/server/runway-mcp-server.d.ts +46 -0
  168. package/dist/src/runway.bak/server/runway-mcp-server.d.ts.map +1 -0
  169. package/dist/src/runway.bak/server/runway-mcp-server.js +601 -0
  170. package/dist/src/runway.bak/server/runway-mcp-server.js.map +1 -0
  171. package/dist/src/servers/production/auth-middleware.d.ts +66 -0
  172. package/dist/src/servers/production/auth-middleware.d.ts.map +1 -0
  173. package/dist/src/servers/production/auth-middleware.js +346 -0
  174. package/dist/src/servers/production/auth-middleware.js.map +1 -0
  175. package/dist/src/servers/railway/index.d.ts +7 -0
  176. package/dist/src/servers/railway/index.d.ts.map +1 -0
  177. package/dist/src/servers/railway/index.js +401 -0
  178. package/dist/src/servers/railway/index.js.map +1 -0
  179. package/package.json +27 -5
@@ -0,0 +1,179 @@
1
+ import Database from 'better-sqlite3';
2
+ export class MetricsQueries {
3
+ db;
4
+ constructor(dbPath) {
5
+ this.db = new Database(dbPath, { readonly: false });
6
+ this.initializeTables();
7
+ }
8
+ initializeTables() {
9
+ this.db.exec(`
10
+ CREATE TABLE IF NOT EXISTS task_analytics (
11
+ id TEXT PRIMARY KEY,
12
+ title TEXT NOT NULL,
13
+ state TEXT NOT NULL,
14
+ created_at INTEGER NOT NULL,
15
+ completed_at INTEGER,
16
+ estimated_effort INTEGER,
17
+ actual_effort INTEGER,
18
+ assignee_id TEXT,
19
+ priority TEXT DEFAULT 'medium',
20
+ labels TEXT DEFAULT '[]',
21
+ blocking_issues TEXT DEFAULT '[]',
22
+ updated_at INTEGER DEFAULT (strftime('%s', 'now'))
23
+ );
24
+
25
+ CREATE INDEX IF NOT EXISTS idx_task_state ON task_analytics(state);
26
+ CREATE INDEX IF NOT EXISTS idx_task_created ON task_analytics(created_at);
27
+ CREATE INDEX IF NOT EXISTS idx_task_assignee ON task_analytics(assignee_id);
28
+ `);
29
+ }
30
+ getTaskMetrics(query = {}) {
31
+ const { timeRange, userIds, states, priorities } = query;
32
+ let whereConditions = ['1=1'];
33
+ const params = {};
34
+ if (timeRange) {
35
+ whereConditions.push('created_at >= @startTime AND created_at <= @endTime');
36
+ params.startTime = Math.floor(timeRange.start.getTime() / 1000);
37
+ params.endTime = Math.floor(timeRange.end.getTime() / 1000);
38
+ }
39
+ if (userIds && userIds.length > 0) {
40
+ whereConditions.push(`assignee_id IN (${userIds.map((_, i) => `@user${i}`).join(',')})`);
41
+ userIds.forEach((id, i) => params[`user${i}`] = id);
42
+ }
43
+ if (states && states.length > 0) {
44
+ whereConditions.push(`state IN (${states.map((_, i) => `@state${i}`).join(',')})`);
45
+ states.forEach((s, i) => params[`state${i}`] = s);
46
+ }
47
+ if (priorities && priorities.length > 0) {
48
+ whereConditions.push(`priority IN (${priorities.map((_, i) => `@priority${i}`).join(',')})`);
49
+ priorities.forEach((p, i) => params[`priority${i}`] = p);
50
+ }
51
+ const whereClause = whereConditions.join(' AND ');
52
+ const metricsQuery = this.db.prepare(`
53
+ SELECT
54
+ COUNT(*) as total_tasks,
55
+ SUM(CASE WHEN state = 'completed' THEN 1 ELSE 0 END) as completed_tasks,
56
+ SUM(CASE WHEN state = 'in_progress' THEN 1 ELSE 0 END) as in_progress_tasks,
57
+ SUM(CASE WHEN state = 'blocked' THEN 1 ELSE 0 END) as blocked_tasks,
58
+ AVG(CASE
59
+ WHEN state = 'completed' AND completed_at IS NOT NULL
60
+ THEN (completed_at - created_at) * 1000
61
+ ELSE NULL
62
+ END) as avg_time_to_complete,
63
+ AVG(CASE
64
+ WHEN actual_effort IS NOT NULL AND estimated_effort IS NOT NULL AND estimated_effort > 0
65
+ THEN (CAST(actual_effort AS REAL) / estimated_effort) * 100
66
+ ELSE NULL
67
+ END) as effort_accuracy,
68
+ SUM(CASE
69
+ WHEN json_array_length(blocking_issues) > 0
70
+ THEN json_array_length(blocking_issues)
71
+ ELSE 0
72
+ END) as blocking_issues_count
73
+ FROM task_analytics
74
+ WHERE ${whereClause}
75
+ `);
76
+ const result = metricsQuery.get(params);
77
+ const velocityQuery = this.db.prepare(`
78
+ SELECT
79
+ DATE(created_at, 'unixepoch') as day,
80
+ COUNT(*) as completed_count
81
+ FROM task_analytics
82
+ WHERE state = 'completed'
83
+ AND ${whereClause}
84
+ GROUP BY day
85
+ ORDER BY day DESC
86
+ LIMIT 30
87
+ `);
88
+ const velocityData = velocityQuery.all(params);
89
+ const velocityTrend = velocityData.map(v => v.completed_count).reverse();
90
+ return {
91
+ totalTasks: result.total_tasks || 0,
92
+ completedTasks: result.completed_tasks || 0,
93
+ inProgressTasks: result.in_progress_tasks || 0,
94
+ blockedTasks: result.blocked_tasks || 0,
95
+ completionRate: result.total_tasks > 0
96
+ ? (result.completed_tasks / result.total_tasks) * 100
97
+ : 0,
98
+ averageTimeToComplete: result.avg_time_to_complete || 0,
99
+ effortAccuracy: result.effort_accuracy || 100,
100
+ blockingIssuesCount: result.blocking_issues_count || 0,
101
+ velocityTrend
102
+ };
103
+ }
104
+ getRecentTasks(query = {}) {
105
+ const { limit = 100, offset = 0 } = query;
106
+ const tasksQuery = this.db.prepare(`
107
+ SELECT
108
+ id,
109
+ title,
110
+ state,
111
+ created_at,
112
+ completed_at,
113
+ estimated_effort,
114
+ actual_effort,
115
+ assignee_id,
116
+ priority,
117
+ labels,
118
+ blocking_issues
119
+ FROM task_analytics
120
+ ORDER BY updated_at DESC
121
+ LIMIT ? OFFSET ?
122
+ `);
123
+ const rows = tasksQuery.all(limit, offset);
124
+ return rows.map(row => ({
125
+ id: row.id,
126
+ title: row.title,
127
+ state: row.state,
128
+ createdAt: new Date(row.created_at * 1000),
129
+ completedAt: row.completed_at ? new Date(row.completed_at * 1000) : undefined,
130
+ estimatedEffort: row.estimated_effort,
131
+ actualEffort: row.actual_effort,
132
+ assigneeId: row.assignee_id,
133
+ priority: row.priority,
134
+ labels: JSON.parse(row.labels),
135
+ blockingIssues: JSON.parse(row.blocking_issues)
136
+ }));
137
+ }
138
+ upsertTask(task) {
139
+ const stmt = this.db.prepare(`
140
+ INSERT INTO task_analytics (
141
+ id, title, state, created_at, completed_at,
142
+ estimated_effort, actual_effort, assignee_id,
143
+ priority, labels, blocking_issues
144
+ ) VALUES (
145
+ @id, @title, @state, @created_at, @completed_at,
146
+ @estimated_effort, @actual_effort, @assignee_id,
147
+ @priority, @labels, @blocking_issues
148
+ )
149
+ ON CONFLICT(id) DO UPDATE SET
150
+ title = @title,
151
+ state = @state,
152
+ completed_at = @completed_at,
153
+ estimated_effort = @estimated_effort,
154
+ actual_effort = @actual_effort,
155
+ assignee_id = @assignee_id,
156
+ priority = @priority,
157
+ labels = @labels,
158
+ blocking_issues = @blocking_issues,
159
+ updated_at = strftime('%s', 'now')
160
+ `);
161
+ stmt.run({
162
+ id: task.id,
163
+ title: task.title,
164
+ state: task.state,
165
+ created_at: Math.floor(task.createdAt.getTime() / 1000),
166
+ completed_at: task.completedAt ? Math.floor(task.completedAt.getTime() / 1000) : null,
167
+ estimated_effort: task.estimatedEffort || null,
168
+ actual_effort: task.actualEffort || null,
169
+ assignee_id: task.assigneeId || null,
170
+ priority: task.priority,
171
+ labels: JSON.stringify(task.labels),
172
+ blocking_issues: JSON.stringify(task.blockingIssues)
173
+ });
174
+ }
175
+ close() {
176
+ this.db.close();
177
+ }
178
+ }
179
+ //# sourceMappingURL=metrics-queries.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics-queries.js","sourceRoot":"","sources":["../../../../src/analytics/queries/metrics-queries.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ export interface TimeRange {
2
+ start: Date;
3
+ end: Date;
4
+ preset?: 'today' | '7d' | '30d' | '90d' | 'custom';
5
+ }
6
+ export interface TaskMetrics {
7
+ completionRate: number;
8
+ averageTimeToComplete: number;
9
+ effortAccuracy: number;
10
+ blockingIssuesCount: number;
11
+ velocityTrend: number[];
12
+ totalTasks: number;
13
+ completedTasks: number;
14
+ inProgressTasks: number;
15
+ blockedTasks: number;
16
+ }
17
+ export interface TeamMetrics {
18
+ userId: string;
19
+ userName: string;
20
+ individualMetrics: TaskMetrics;
21
+ contributionPercentage: number;
22
+ lastActive: Date;
23
+ }
24
+ export interface TaskAnalytics {
25
+ id: string;
26
+ title: string;
27
+ state: 'todo' | 'in_progress' | 'completed' | 'blocked';
28
+ createdAt: Date;
29
+ completedAt?: Date;
30
+ estimatedEffort?: number;
31
+ actualEffort?: number;
32
+ assigneeId?: string;
33
+ priority: 'urgent' | 'high' | 'medium' | 'low';
34
+ labels: string[];
35
+ blockingIssues: string[];
36
+ }
37
+ export interface DashboardState {
38
+ metrics: TaskMetrics;
39
+ teamMetrics: TeamMetrics[];
40
+ recentTasks: TaskAnalytics[];
41
+ timeRange: TimeRange;
42
+ teamFilter: string[];
43
+ isLive: boolean;
44
+ lastUpdated: Date;
45
+ }
46
+ export interface MetricAggregation {
47
+ period: 'hour' | 'day' | 'week' | 'month';
48
+ timestamp: Date;
49
+ metrics: Partial<TaskMetrics>;
50
+ }
51
+ export interface AnalyticsQuery {
52
+ timeRange?: TimeRange;
53
+ userIds?: string[];
54
+ states?: TaskAnalytics['state'][];
55
+ priorities?: TaskAnalytics['priority'][];
56
+ labels?: string[];
57
+ limit?: number;
58
+ offset?: number;
59
+ }
60
+ //# sourceMappingURL=metrics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../../../src/analytics/types/metrics.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,IAAI,CAAC;IACZ,GAAG,EAAE,IAAI,CAAC;IACV,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,CAAC;CACpD;AAED,MAAM,WAAW,WAAW;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,WAAW,CAAC;IAC/B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,UAAU,EAAE,IAAI,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,aAAa,GAAG,WAAW,GAAG,SAAS,CAAC;IACxD,SAAS,EAAE,IAAI,CAAC;IAChB,WAAW,CAAC,EAAE,IAAI,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IAC/C,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,WAAW,CAAC;IACrB,WAAW,EAAE,WAAW,EAAE,CAAC;IAC3B,WAAW,EAAE,aAAa,EAAE,CAAC;IAC7B,SAAS,EAAE,SAAS,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,IAAI,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;IAC1C,SAAS,EAAE,IAAI,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;IAClC,UAAU,CAAC,EAAE,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../../../src/analytics/types/metrics.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export declare function displayAnalyticsDashboard(projectPath?: string): Promise<void>;
3
+ //# sourceMappingURL=analytics-viewer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics-viewer.d.ts","sourceRoot":"","sources":["../../../src/cli/analytics-viewer.ts"],"names":[],"mappings":";AAIA,wBAAsB,yBAAyB,CAC7C,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAwFf"}
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env node
2
+ import chalk from 'chalk';
3
+ import { AnalyticsService } from '../analytics/core/analytics-service.js';
4
+ export async function displayAnalyticsDashboard(projectPath) {
5
+ const service = new AnalyticsService(projectPath || process.cwd());
6
+ try {
7
+ const state = await service.getDashboardState();
8
+ const { metrics, recentTasks, teamMetrics } = state;
9
+ console.clear();
10
+ console.log(chalk.bold.cyan('\nšŸ“Š StackMemory Analytics Dashboard\n'));
11
+ console.log(chalk.gray('─'.repeat(50)));
12
+ // Key Metrics
13
+ console.log(chalk.bold.white('\nšŸ“ˆ Key Metrics\n'));
14
+ const metricsDisplay = [
15
+ ['Total Tasks', metrics.totalTasks],
16
+ ['Completed', chalk.green(metrics.completedTasks)],
17
+ ['In Progress', chalk.yellow(metrics.inProgressTasks)],
18
+ ['Blocked', chalk.red(metrics.blockedTasks)],
19
+ ['Completion Rate', `${metrics.completionRate.toFixed(1)}%`],
20
+ ['Avg Time to Complete', formatDuration(metrics.averageTimeToComplete)],
21
+ ['Effort Accuracy', `${metrics.effortAccuracy.toFixed(0)}%`],
22
+ ['Blocking Issues', metrics.blockingIssuesCount],
23
+ ];
24
+ metricsDisplay.forEach(([label, value]) => {
25
+ console.log(` ${chalk.gray(String(label).padEnd(20))} ${value}`);
26
+ });
27
+ // Velocity Trend (mini chart)
28
+ if (metrics.velocityTrend.length > 0) {
29
+ console.log(chalk.bold.white('\nšŸ“‰ Velocity Trend (last 7 days)\n'));
30
+ const maxVelocity = Math.max(...metrics.velocityTrend);
31
+ const scale = maxVelocity > 0 ? 10 / maxVelocity : 1;
32
+ metrics.velocityTrend.slice(-7).forEach((velocity, i) => {
33
+ const bar = 'ā–ˆ'.repeat(Math.round(velocity * scale));
34
+ const day = new Date();
35
+ day.setDate(day.getDate() - (6 - i));
36
+ console.log(` ${day.toLocaleDateString('en', { weekday: 'short' }).padEnd(4)} ${bar} ${velocity}`);
37
+ });
38
+ }
39
+ // Recent Tasks
40
+ if (recentTasks.length > 0) {
41
+ console.log(chalk.bold.white('\nšŸš€ Recent Tasks\n'));
42
+ recentTasks.slice(0, 5).forEach((task) => {
43
+ const stateEmoji = {
44
+ completed: 'āœ…',
45
+ in_progress: 'šŸ”„',
46
+ blocked: '🚫',
47
+ todo: 'šŸ“',
48
+ }[task.state];
49
+ const priorityColor = {
50
+ urgent: chalk.red,
51
+ high: chalk.yellow,
52
+ medium: chalk.blue,
53
+ low: chalk.gray,
54
+ }[task.priority];
55
+ console.log(` ${stateEmoji} ${priorityColor(`[${task.priority.toUpperCase()}]`)} ${task.title.slice(0, 50)}`);
56
+ });
57
+ }
58
+ // Team Performance
59
+ if (teamMetrics.length > 0) {
60
+ console.log(chalk.bold.white('\nšŸ‘„ Team Performance\n'));
61
+ teamMetrics.slice(0, 3).forEach((member) => {
62
+ const bar = 'ā–“'.repeat(Math.round(member.contributionPercentage / 10));
63
+ console.log(` ${member.userName.padEnd(15)} ${bar} ${member.contributionPercentage.toFixed(0)}% (${member.individualMetrics.completedTasks} tasks)`);
64
+ });
65
+ }
66
+ console.log(chalk.gray('\n─'.repeat(50)));
67
+ console.log(chalk.gray(`Last updated: ${state.lastUpdated.toLocaleString()}`));
68
+ console.log();
69
+ }
70
+ finally {
71
+ service.close();
72
+ }
73
+ }
74
+ function formatDuration(ms) {
75
+ if (ms === 0)
76
+ return 'N/A';
77
+ const hours = Math.floor(ms / 3600000);
78
+ const days = Math.floor(hours / 24);
79
+ if (days > 0)
80
+ return `${days}d ${hours % 24}h`;
81
+ if (hours > 0)
82
+ return `${hours}h`;
83
+ return '<1h';
84
+ }
85
+ // Allow direct execution
86
+ if (import.meta.url === `file://${process.argv[1]}`) {
87
+ displayAnalyticsDashboard().catch(console.error);
88
+ }
89
+ //# sourceMappingURL=analytics-viewer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics-viewer.js","sourceRoot":"","sources":["../../../src/cli/analytics-viewer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Test Browser MCP integration locally
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=browser-test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-test.d.ts","sourceRoot":"","sources":["../../../src/cli/browser-test.ts"],"names":[],"mappings":";AACA;;GAEG"}
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Test Browser MCP integration locally
4
+ */
5
+ import { BrowserMCPIntegration } from '../features/browser/browser-mcp.js';
6
+ async function testBrowserMCP() {
7
+ console.log('🧪 Testing Browser MCP Integration...\n');
8
+ const browser = new BrowserMCPIntegration({
9
+ headless: false, // Show browser for testing
10
+ defaultViewport: { width: 1280, height: 720 },
11
+ });
12
+ await browser.initialize();
13
+ console.log('āœ… Browser MCP initialized successfully!');
14
+ console.log('\nAvailable tools:');
15
+ console.log(' - browser_navigate');
16
+ console.log(' - browser_screenshot');
17
+ console.log(' - browser_click');
18
+ console.log(' - browser_type');
19
+ console.log(' - browser_evaluate');
20
+ console.log(' - browser_wait');
21
+ console.log(' - browser_get_content');
22
+ console.log(' - browser_close');
23
+ console.log('\nšŸŽÆ Browser MCP is ready to use with StackMemory!');
24
+ // Clean up
25
+ await browser.cleanup();
26
+ process.exit(0);
27
+ }
28
+ testBrowserMCP().catch((error) => {
29
+ console.error('āŒ Browser MCP test failed:', error);
30
+ process.exit(1);
31
+ });
32
+ //# sourceMappingURL=browser-test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-test.js","sourceRoot":"","sources":["../../../src/cli/browser-test.ts"],"names":[],"mappings":";AACA;;GAEG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAE3E,KAAK,UAAU,cAAc;IAC3B,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;IAEvD,MAAM,OAAO,GAAG,IAAI,qBAAqB,CAAC;QACxC,QAAQ,EAAE,KAAK,EAAE,2BAA2B;QAC5C,eAAe,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;KAC9C,CAAC,CAAC;IAEH,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;IAE3B,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAClC,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IACpC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;IACtC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACjC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IACpC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IACvC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAEjC,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;IAElE,WAAW;IACX,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;IACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,cAAc,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IAC/B,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAC;IACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -13,6 +13,8 @@ import { initializeAutoSync, getAutoSyncService, stopAutoSync, } from '../integr
13
13
  import { LinearConfigManager } from '../integrations/linear-config.js';
14
14
  import { UpdateChecker } from '../core/update-checker.js';
15
15
  import { ProgressTracker } from '../core/progress-tracker.js';
16
+ import { registerProjectCommands } from './project-commands.js';
17
+ import { ProjectManager } from '../core/project-manager.js';
16
18
  import Database from 'better-sqlite3';
17
19
  import { join } from 'path';
18
20
  import { existsSync, mkdirSync } from 'fs';
@@ -500,6 +502,152 @@ program
500
502
  process.exit(1);
501
503
  }
502
504
  });
505
+ program
506
+ .command('analytics')
507
+ .description('Launch task analytics dashboard')
508
+ .option('-p, --port <port>', 'Port for dashboard server', '3000')
509
+ .option('-o, --open', 'Open dashboard in browser')
510
+ .option('--export <format>', 'Export metrics (json|csv)')
511
+ .option('--sync', 'Sync with Linear before launching')
512
+ .option('--view', 'Show analytics in terminal')
513
+ .action(async (options) => {
514
+ try {
515
+ const projectRoot = process.cwd();
516
+ const dbPath = join(projectRoot, '.stackmemory', 'context.db');
517
+ if (!existsSync(dbPath)) {
518
+ console.log('āŒ StackMemory not initialized. Run "stackmemory init" first.');
519
+ return;
520
+ }
521
+ if (options.view) {
522
+ const { displayAnalyticsDashboard } = await import('./analytics-viewer.js');
523
+ await displayAnalyticsDashboard(projectRoot);
524
+ return;
525
+ }
526
+ if (options.export) {
527
+ const { AnalyticsService } = await import('../analytics/index.js');
528
+ const service = new AnalyticsService(projectRoot);
529
+ if (options.sync) {
530
+ console.log('šŸ”„ Syncing with Linear...');
531
+ await service.syncLinearTasks();
532
+ }
533
+ const state = await service.getDashboardState();
534
+ if (options.export === 'csv') {
535
+ console.log('šŸ“Š Exporting metrics as CSV...');
536
+ // Convert to CSV format
537
+ const tasks = state.recentTasks;
538
+ const headers = [
539
+ 'ID',
540
+ 'Title',
541
+ 'State',
542
+ 'Priority',
543
+ 'Created',
544
+ 'Completed',
545
+ ];
546
+ const rows = tasks.map((t) => [
547
+ t.id,
548
+ t.title,
549
+ t.state,
550
+ t.priority,
551
+ t.createdAt.toISOString(),
552
+ t.completedAt?.toISOString() || '',
553
+ ]);
554
+ console.log(headers.join(','));
555
+ rows.forEach((r) => console.log(r.join(',')));
556
+ }
557
+ else {
558
+ console.log(JSON.stringify(state, null, 2));
559
+ }
560
+ service.close();
561
+ return;
562
+ }
563
+ // Launch dashboard server
564
+ console.log(`šŸš€ Launching analytics dashboard on port ${options.port}...`);
565
+ const express = (await import('express')).default;
566
+ const { AnalyticsAPI } = await import('../analytics/index.js');
567
+ const { createServer } = await import('http');
568
+ const app = express();
569
+ const analyticsAPI = new AnalyticsAPI(projectRoot);
570
+ if (options.sync) {
571
+ console.log('šŸ”„ Syncing with Linear...');
572
+ const service = new (await import('../analytics/index.js')).AnalyticsService(projectRoot);
573
+ await service.syncLinearTasks();
574
+ service.close();
575
+ }
576
+ app.use('/api/analytics', analyticsAPI.getRouter());
577
+ // Serve the HTML dashboard
578
+ app.get('/', async (req, res) => {
579
+ const { fileURLToPath } = await import('url');
580
+ const { dirname } = await import('path');
581
+ const __filename = fileURLToPath(import.meta.url);
582
+ const __dirname = dirname(__filename);
583
+ const dashboardPath = join(__dirname, '../analytics/dashboard.html');
584
+ if (existsSync(dashboardPath)) {
585
+ res.sendFile(dashboardPath);
586
+ }
587
+ else {
588
+ // Fallback to inline HTML if file not found
589
+ const { existsSync: fsExists } = await import('fs');
590
+ const { join: pathJoin } = await import('path');
591
+ const htmlPath = pathJoin(__dirname, '../analytics/dashboard.html');
592
+ if (fsExists(htmlPath)) {
593
+ res.sendFile(htmlPath);
594
+ }
595
+ else {
596
+ res.send(`
597
+ <!DOCTYPE html>
598
+ <html>
599
+ <head>
600
+ <title>StackMemory Analytics</title>
601
+ <style>
602
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; padding: 20px; }
603
+ h1 { color: #333; }
604
+ .status { color: #22c55e; }
605
+ </style>
606
+ </head>
607
+ <body>
608
+ <h1>šŸ“Š StackMemory Analytics Dashboard</h1>
609
+ <p class="status">āœ… Server running</p>
610
+ <p>Dashboard available at: /src/analytics/dashboard.html</p>
611
+ <p>API Endpoints:</p>
612
+ <ul>
613
+ <li>GET /api/analytics/metrics</li>
614
+ <li>GET /api/analytics/tasks</li>
615
+ <li>POST /api/analytics/sync</li>
616
+ </ul>
617
+ </body>
618
+ </html>
619
+ `);
620
+ }
621
+ }
622
+ });
623
+ const server = createServer(app);
624
+ analyticsAPI.setupWebSocket(server);
625
+ server.listen(options.port, async () => {
626
+ console.log(`āœ… Analytics dashboard running at http://localhost:${options.port}`);
627
+ if (options.open) {
628
+ const { exec } = await import('child_process');
629
+ const url = `http://localhost:${options.port}`;
630
+ const command = process.platform === 'darwin'
631
+ ? `open ${url}`
632
+ : process.platform === 'win32'
633
+ ? `start ${url}`
634
+ : `xdg-open ${url}`;
635
+ exec(command);
636
+ }
637
+ });
638
+ process.on('SIGINT', () => {
639
+ console.log('\nšŸ‘‹ Shutting down analytics dashboard...');
640
+ analyticsAPI.close();
641
+ server.close();
642
+ process.exit(0);
643
+ });
644
+ }
645
+ catch (error) {
646
+ logger.error('Analytics command failed', error);
647
+ console.error('āŒ Analytics failed:', error.message);
648
+ process.exit(1);
649
+ }
650
+ });
503
651
  program
504
652
  .command('progress')
505
653
  .description('Show current progress and recent changes')
@@ -543,5 +691,14 @@ program
543
691
  process.exit(1);
544
692
  }
545
693
  });
694
+ // Register project management commands
695
+ registerProjectCommands(program);
696
+ // Auto-detect current project on startup
697
+ if (process.argv.length > 2) {
698
+ const manager = ProjectManager.getInstance();
699
+ manager.detectProject().catch(() => {
700
+ // Silently fail if not in a project directory
701
+ });
702
+ }
546
703
  program.parse();
547
704
  //# sourceMappingURL=cli.js.map