@ycniuqton/devlens 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +164 -0
  2. package/bin/devlens.js +2 -0
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.js +205 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/init.d.ts +3 -0
  7. package/dist/init.js +239 -0
  8. package/dist/init.js.map +1 -0
  9. package/dist/routes/diff.d.ts +1 -0
  10. package/dist/routes/diff.js +39 -0
  11. package/dist/routes/diff.js.map +1 -0
  12. package/dist/routes/integrations.d.ts +1 -0
  13. package/dist/routes/integrations.js +132 -0
  14. package/dist/routes/integrations.js.map +1 -0
  15. package/dist/routes/rules.d.ts +1 -0
  16. package/dist/routes/rules.js +115 -0
  17. package/dist/routes/rules.js.map +1 -0
  18. package/dist/routes/tasks.d.ts +4 -0
  19. package/dist/routes/tasks.js +360 -0
  20. package/dist/routes/tasks.js.map +1 -0
  21. package/dist/server.d.ts +7 -0
  22. package/dist/server.js +112 -0
  23. package/dist/server.js.map +1 -0
  24. package/dist/services/claudeTasks.d.ts +23 -0
  25. package/dist/services/claudeTasks.js +160 -0
  26. package/dist/services/claudeTasks.js.map +1 -0
  27. package/dist/services/config.d.ts +3 -0
  28. package/dist/services/config.js +25 -0
  29. package/dist/services/config.js.map +1 -0
  30. package/dist/services/git.d.ts +8 -0
  31. package/dist/services/git.js +90 -0
  32. package/dist/services/git.js.map +1 -0
  33. package/dist/services/jira.d.ts +11 -0
  34. package/dist/services/jira.js +52 -0
  35. package/dist/services/jira.js.map +1 -0
  36. package/dist/services/linear.d.ts +9 -0
  37. package/dist/services/linear.js +69 -0
  38. package/dist/services/linear.js.map +1 -0
  39. package/dist/services/rules.d.ts +14 -0
  40. package/dist/services/rules.js +133 -0
  41. package/dist/services/rules.js.map +1 -0
  42. package/dist/services/taskStore.d.ts +27 -0
  43. package/dist/services/taskStore.js +261 -0
  44. package/dist/services/taskStore.js.map +1 -0
  45. package/dist/services/tunnel.d.ts +8 -0
  46. package/dist/services/tunnel.js +152 -0
  47. package/dist/services/tunnel.js.map +1 -0
  48. package/dist/services/watcher.d.ts +2 -0
  49. package/dist/services/watcher.js +30 -0
  50. package/dist/services/watcher.js.map +1 -0
  51. package/dist/types/index.d.ts +87 -0
  52. package/dist/types/index.js +3 -0
  53. package/dist/types/index.js.map +1 -0
  54. package/package.json +53 -0
  55. package/public/css/style.css +1613 -0
  56. package/public/index.html +395 -0
  57. package/public/js/app.js +104 -0
  58. package/public/js/diff.js +337 -0
  59. package/public/js/integrations.js +194 -0
  60. package/public/js/rules.js +174 -0
  61. package/public/js/tasks.js +301 -0
@@ -0,0 +1,360 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.tasksRouter = void 0;
7
+ exports.checkSessionLiveness = checkSessionLiveness;
8
+ const express_1 = require("express");
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const path_1 = __importDefault(require("path"));
11
+ const os_1 = __importDefault(require("os"));
12
+ // Extract rich context from the conversation transcript
13
+ function extractContext(transcriptPath, toolUseId) {
14
+ const empty = { userPrompt: '', claudeReasoning: '', filesTouched: [] };
15
+ if (!transcriptPath || !toolUseId)
16
+ return empty;
17
+ try {
18
+ if (!fs_1.default.existsSync(transcriptPath))
19
+ return empty;
20
+ const lines = fs_1.default.readFileSync(transcriptPath, 'utf-8').split('\n').filter(Boolean);
21
+ // Find the line with this tool_use_id
22
+ let toolLineIdx = -1;
23
+ for (let i = lines.length - 1; i >= 0; i--) {
24
+ if (lines[i].includes(toolUseId)) {
25
+ toolLineIdx = i;
26
+ break;
27
+ }
28
+ }
29
+ if (toolLineIdx === -1)
30
+ return empty;
31
+ let userPrompt = '';
32
+ let claudeReasoning = '';
33
+ const filesTouched = [];
34
+ for (let j = toolLineIdx - 1; j >= Math.max(0, toolLineIdx - 50); j--) {
35
+ try {
36
+ const entry = JSON.parse(lines[j]);
37
+ const content = entry.message?.content;
38
+ // Claude's reasoning — assistant text before the tool call
39
+ if (entry.type === 'assistant' && !claudeReasoning) {
40
+ if (typeof content === 'string' && content.trim().length > 10) {
41
+ claudeReasoning = content.trim().substring(0, 500);
42
+ }
43
+ else if (Array.isArray(content)) {
44
+ for (const block of content) {
45
+ if (block?.type === 'text' && block.text?.trim().length > 10) {
46
+ claudeReasoning = block.text.trim().substring(0, 500);
47
+ break;
48
+ }
49
+ }
50
+ }
51
+ }
52
+ // User prompt
53
+ if (entry.type === 'user' && !userPrompt) {
54
+ let text = '';
55
+ if (typeof content === 'string')
56
+ text = content;
57
+ else if (Array.isArray(content)) {
58
+ for (const block of content) {
59
+ if (block?.type === 'text' && block.text)
60
+ text += block.text;
61
+ }
62
+ }
63
+ if (text.trim().length > 5) {
64
+ userPrompt = text.trim().substring(0, 500);
65
+ }
66
+ }
67
+ // Files touched (Read/Edit/Write tool calls)
68
+ if (entry.type === 'assistant' && Array.isArray(content)) {
69
+ for (const block of content) {
70
+ if (block?.type === 'tool_use' && ['Read', 'Edit', 'Write', 'Glob'].includes(block.name)) {
71
+ const fp = block.input?.file_path || block.input?.pattern || '';
72
+ if (fp && !filesTouched.includes(fp)) {
73
+ filesTouched.push(fp);
74
+ }
75
+ }
76
+ }
77
+ }
78
+ if (userPrompt && claudeReasoning)
79
+ break;
80
+ }
81
+ catch { }
82
+ }
83
+ return { userPrompt, claudeReasoning, filesTouched: filesTouched.slice(0, 10) };
84
+ }
85
+ catch { }
86
+ return empty;
87
+ }
88
+ exports.tasksRouter = (0, express_1.Router)();
89
+ // Sync endpoint — receives Claude Code hook payloads (PostToolUse on TaskCreate/TaskUpdate)
90
+ exports.tasksRouter.post('/sync', async (req, res) => {
91
+ const store = req.app.locals.taskStore;
92
+ const broadcast = req.app.locals.broadcast;
93
+ try {
94
+ const { tool_name, tool_input, tool_response, tool_output, session_id, transcript_path, tool_use_id } = req.body;
95
+ if (!tool_name) {
96
+ return res.status(400).json({ error: 'Invalid hook payload' });
97
+ }
98
+ const sessionShort = session_id ? String(session_id).substring(0, 8) : '';
99
+ // Upsert session from hook payload + session metadata
100
+ if (session_id) {
101
+ const meta = readSessionMeta(session_id);
102
+ store.upsertSession({
103
+ sessionId: session_id,
104
+ name: meta?.name,
105
+ cwd: meta?.cwd,
106
+ pid: meta?.pid,
107
+ startedAt: meta?.startedAt ? new Date(meta.startedAt).toISOString() : undefined,
108
+ status: 'active',
109
+ });
110
+ }
111
+ // Detect WAITING_APPROVAL — Claude is asking for commit approval
112
+ {
113
+ const projectDir = req.app.locals.projectDir;
114
+ const candidates = [];
115
+ const collect = (v) => { if (typeof v === 'string')
116
+ candidates.push(v); };
117
+ collect(tool_input?.subject);
118
+ collect(tool_input?.title);
119
+ collect(tool_input?.content);
120
+ if (Array.isArray(tool_input?.todos)) {
121
+ for (const t of tool_input.todos)
122
+ collect(t?.content);
123
+ }
124
+ const approvalLine = candidates.find(c => c.includes('WAITING_APPROVAL:'));
125
+ if (approvalLine) {
126
+ const message = approvalLine.split('WAITING_APPROVAL:')[1].trim();
127
+ const pendingFile = path_1.default.join(projectDir, '.devlens', 'commit-pending.md');
128
+ const dir = path_1.default.dirname(pendingFile);
129
+ if (!fs_1.default.existsSync(dir))
130
+ fs_1.default.mkdirSync(dir, { recursive: true });
131
+ fs_1.default.writeFileSync(pendingFile, message);
132
+ // Remove any prior approval so a new commit cycle starts clean
133
+ const approvedFile = path_1.default.join(projectDir, '.devlens', 'commit-approved.md');
134
+ if (fs_1.default.existsSync(approvedFile))
135
+ fs_1.default.unlinkSync(approvedFile);
136
+ if (broadcast)
137
+ broadcast({ type: 'commit-approval-update', payload: { pending: message, approved: false } });
138
+ }
139
+ }
140
+ // Extract Claude task ID
141
+ let claudeTaskId = null;
142
+ if (tool_response?.task?.id) {
143
+ claudeTaskId = String(tool_response.task.id);
144
+ }
145
+ else if (tool_response?.taskId) {
146
+ claudeTaskId = String(tool_response.taskId);
147
+ }
148
+ else {
149
+ const outputStr = typeof tool_output === 'string' ? tool_output : JSON.stringify(tool_output || '');
150
+ const idMatch = outputStr.match(/#(\d+)/);
151
+ claudeTaskId = idMatch ? idMatch[1] : null;
152
+ }
153
+ const claudeTag = claudeTaskId ? `claude:${sessionShort}:${claudeTaskId}` : null;
154
+ if (tool_name === 'TaskCreate') {
155
+ const subject = tool_input?.subject || tool_input?.title || 'Untitled';
156
+ const description = tool_input?.description || '';
157
+ if (claudeTag) {
158
+ const existing = await store.getTasks();
159
+ const found = existing.find(t => t.tags.includes(claudeTag));
160
+ if (found)
161
+ return res.json({ ok: true });
162
+ }
163
+ // Extract user prompt context from transcript
164
+ const context = extractContext(transcript_path, tool_use_id);
165
+ const task = await store.createTask({
166
+ title: subject,
167
+ description,
168
+ status: 'pending',
169
+ priority: 'medium',
170
+ tags: claudeTag ? [claudeTag] : [],
171
+ });
172
+ // Store Claude-specific fields directly on the task object
173
+ if (claudeTaskId || tool_input?.activeForm || tool_input?.owner || tool_input?.metadata || context) {
174
+ const extra = {};
175
+ if (session_id)
176
+ extra.claudeSessionId = session_id;
177
+ if (claudeTaskId)
178
+ extra.claudeTaskId = claudeTaskId;
179
+ if (tool_input?.activeForm)
180
+ extra.activeForm = tool_input.activeForm;
181
+ if (tool_input?.owner)
182
+ extra.owner = tool_input.owner;
183
+ if (tool_input?.metadata)
184
+ extra.metadata = tool_input.metadata;
185
+ if (context.userPrompt || context.claudeReasoning || context.filesTouched.length) {
186
+ extra.context = JSON.stringify(context);
187
+ }
188
+ await store.updateTask(task.id, extra);
189
+ }
190
+ if (broadcast)
191
+ broadcast({ type: 'task-update', payload: { action: 'created', task } });
192
+ }
193
+ if (tool_name === 'TaskUpdate') {
194
+ const status = tool_input?.status;
195
+ const claudeId = tool_input?.taskId;
196
+ // Find by session-scoped tag
197
+ const existing = await store.getTasks();
198
+ const tag = `claude:${sessionShort}:${claudeId}`;
199
+ let found = existing.find(t => t.tags.includes(tag));
200
+ // Fallback: try old format without session
201
+ if (!found) {
202
+ found = existing.find(t => t.tags.includes(`claude:${claudeId}`));
203
+ }
204
+ if (found) {
205
+ const updates = {};
206
+ if (status) {
207
+ if (status === 'deleted') {
208
+ updates.status = 'archived';
209
+ }
210
+ else {
211
+ const statusMap = {
212
+ 'in_progress': 'in-progress',
213
+ 'completed': 'completed',
214
+ 'pending': 'pending',
215
+ };
216
+ updates.status = statusMap[status] || status;
217
+ }
218
+ }
219
+ // Capture any field updates from Claude
220
+ if (tool_input?.subject)
221
+ updates.title = tool_input.subject;
222
+ if (tool_input?.description)
223
+ updates.description = tool_input.description;
224
+ if (tool_input?.activeForm)
225
+ updates.activeForm = tool_input.activeForm;
226
+ if (tool_input?.owner)
227
+ updates.owner = tool_input.owner;
228
+ if (tool_input?.metadata)
229
+ updates.metadata = { ...found.metadata, ...tool_input.metadata };
230
+ // On completion/archive — capture what Claude did to finish
231
+ if (status === 'completed' || status === 'deleted') {
232
+ const completionCtx = extractContext(transcript_path, tool_use_id);
233
+ if (completionCtx.claudeReasoning || completionCtx.filesTouched.length) {
234
+ updates.completionContext = JSON.stringify(completionCtx);
235
+ }
236
+ }
237
+ const updated = await store.updateTask(found.id, updates);
238
+ if (broadcast)
239
+ broadcast({ type: 'task-update', payload: { action: 'updated', task: updated } });
240
+ }
241
+ }
242
+ res.json({ ok: true });
243
+ }
244
+ catch (err) {
245
+ res.status(500).json({ error: err.message });
246
+ }
247
+ });
248
+ exports.tasksRouter.get('/', async (req, res) => {
249
+ const store = req.app.locals.taskStore;
250
+ try {
251
+ const status = req.query.status;
252
+ const sessionId = req.query.session;
253
+ const filter = {};
254
+ if (status)
255
+ filter.status = status;
256
+ if (sessionId)
257
+ filter.sessionId = sessionId;
258
+ const tasks = await store.getTasks(Object.keys(filter).length ? filter : undefined);
259
+ res.json(tasks);
260
+ }
261
+ catch (err) {
262
+ res.status(500).json({ error: err.message });
263
+ }
264
+ });
265
+ // GET /api/tasks/sessions — must be before /:id
266
+ exports.tasksRouter.get('/sessions', (req, res) => {
267
+ const store = req.app.locals.taskStore;
268
+ const projectDir = req.app.locals.projectDir;
269
+ const sessions = store.getSessions().filter(s => !s.cwd || s.cwd === projectDir);
270
+ res.json(sessions);
271
+ });
272
+ exports.tasksRouter.get('/:id', async (req, res) => {
273
+ const store = req.app.locals.taskStore;
274
+ try {
275
+ const task = await store.getTask(req.params.id);
276
+ if (!task)
277
+ return res.status(404).json({ error: 'Task not found' });
278
+ res.json(task);
279
+ }
280
+ catch (err) {
281
+ res.status(500).json({ error: err.message });
282
+ }
283
+ });
284
+ exports.tasksRouter.post('/', async (req, res) => {
285
+ const store = req.app.locals.taskStore;
286
+ try {
287
+ if (!req.body.title) {
288
+ return res.status(400).json({ error: 'Title is required' });
289
+ }
290
+ const task = await store.createTask(req.body);
291
+ res.status(201).json(task);
292
+ }
293
+ catch (err) {
294
+ res.status(500).json({ error: err.message });
295
+ }
296
+ });
297
+ exports.tasksRouter.put('/:id', async (req, res) => {
298
+ const store = req.app.locals.taskStore;
299
+ try {
300
+ const task = await store.updateTask(req.params.id, req.body);
301
+ res.json(task);
302
+ }
303
+ catch (err) {
304
+ if (err.message === 'Task not found') {
305
+ return res.status(404).json({ error: err.message });
306
+ }
307
+ res.status(500).json({ error: err.message });
308
+ }
309
+ });
310
+ exports.tasksRouter.delete('/:id', async (req, res) => {
311
+ const store = req.app.locals.taskStore;
312
+ try {
313
+ await store.deleteTask(req.params.id);
314
+ res.status(204).send();
315
+ }
316
+ catch (err) {
317
+ res.status(500).json({ error: err.message });
318
+ }
319
+ });
320
+ // ---- Sessions ----
321
+ // Read session metadata from ~/.claude/sessions/*.json
322
+ function readSessionMeta(sessionId) {
323
+ const sessionsDir = path_1.default.join(os_1.default.homedir(), '.claude', 'sessions');
324
+ if (!fs_1.default.existsSync(sessionsDir))
325
+ return null;
326
+ try {
327
+ const files = fs_1.default.readdirSync(sessionsDir).filter(f => f.endsWith('.json'));
328
+ let best = null;
329
+ for (const file of files) {
330
+ try {
331
+ const data = JSON.parse(fs_1.default.readFileSync(path_1.default.join(sessionsDir, file), 'utf-8'));
332
+ if (data.sessionId === sessionId) {
333
+ if (!best || (data.startedAt && (!best.startedAt || data.startedAt > best.startedAt))) {
334
+ best = data;
335
+ }
336
+ }
337
+ }
338
+ catch { }
339
+ }
340
+ return best;
341
+ }
342
+ catch { }
343
+ return null;
344
+ }
345
+ // Check session liveness by watching lock files
346
+ function checkSessionLiveness(store) {
347
+ const tasksDir = path_1.default.join(os_1.default.homedir(), '.claude', 'tasks');
348
+ if (!fs_1.default.existsSync(tasksDir))
349
+ return;
350
+ const sessions = store.getSessions();
351
+ for (const session of sessions) {
352
+ if (session.status !== 'active')
353
+ continue;
354
+ const lockFile = path_1.default.join(tasksDir, session.sessionId, '.lock');
355
+ if (!fs_1.default.existsSync(lockFile)) {
356
+ store.updateSessionStatus(session.sessionId, 'ended');
357
+ }
358
+ }
359
+ }
360
+ //# sourceMappingURL=tasks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tasks.js","sourceRoot":"","sources":["../../src/routes/tasks.ts"],"names":[],"mappings":";;;;;;AA2WS,oDAAoB;AA3W7B,qCAAoD;AACpD,4CAAoB;AACpB,gDAAwB;AACxB,4CAAoB;AAUpB,wDAAwD;AACxD,SAAS,cAAc,CAAC,cAAkC,EAAE,SAA6B;IACvF,MAAM,KAAK,GAAgB,EAAE,UAAU,EAAE,EAAE,EAAE,eAAe,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;IACrF,IAAI,CAAC,cAAc,IAAI,CAAC,SAAS;QAAE,OAAO,KAAK,CAAC;IAChD,IAAI,CAAC;QACH,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,cAAc,CAAC;YAAE,OAAO,KAAK,CAAC;QACjD,MAAM,KAAK,GAAG,YAAE,CAAC,YAAY,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAEnF,sCAAsC;QACtC,IAAI,WAAW,GAAG,CAAC,CAAC,CAAC;QACrB,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3C,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;gBACjC,WAAW,GAAG,CAAC,CAAC;gBAChB,MAAM;YACR,CAAC;QACH,CAAC;QACD,IAAI,WAAW,KAAK,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;QAErC,IAAI,UAAU,GAAG,EAAE,CAAC;QACpB,IAAI,eAAe,GAAG,EAAE,CAAC;QACzB,MAAM,YAAY,GAAa,EAAE,CAAC;QAElC,KAAK,IAAI,CAAC,GAAG,WAAW,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACtE,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;gBACnC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC;gBAEvC,2DAA2D;gBAC3D,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,eAAe,EAAE,CAAC;oBACnD,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;wBAC9D,eAAe,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;oBACrD,CAAC;yBAAM,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;wBAClC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;4BAC5B,IAAI,KAAK,EAAE,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;gCAC7D,eAAe,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;gCACtD,MAAM;4BACR,CAAC;wBACH,CAAC;oBACH,CAAC;gBACH,CAAC;gBAED,cAAc;gBACd,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;oBACzC,IAAI,IAAI,GAAG,EAAE,CAAC;oBACd,IAAI,OAAO,OAAO,KAAK,QAAQ;wBAAE,IAAI,GAAG,OAAO,CAAC;yBAC3C,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;wBAChC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;4BAC5B,IAAI,KAAK,EAAE,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI;gCAAE,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC;wBAC/D,CAAC;oBACH,CAAC;oBACD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBAC3B,UAAU,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;oBAC7C,CAAC;gBACH,CAAC;gBAED,6CAA6C;gBAC7C,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;oBACzD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;wBAC5B,IAAI,KAAK,EAAE,IAAI,KAAK,UAAU,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;4BACzF,MAAM,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,SAAS,IAAI,KAAK,CAAC,KAAK,EAAE,OAAO,IAAI,EAAE,CAAC;4BAChE,IAAI,EAAE,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;gCACrC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;4BACxB,CAAC;wBACH,CAAC;oBACH,CAAC;gBACH,CAAC;gBAED,IAAI,UAAU,IAAI,eAAe;oBAAE,MAAM;YAC3C,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;QACZ,CAAC;QAED,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,YAAY,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;IAClF,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IACV,OAAO,KAAK,CAAC;AACf,CAAC;AAEY,QAAA,WAAW,GAAG,IAAA,gBAAM,GAAE,CAAC;AAEpC,4FAA4F;AAC5F,mBAAW,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;IAC9D,MAAM,KAAK,GAAqB,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC;IACzD,MAAM,SAAS,GAA6B,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC;IAErE,IAAI,CAAC;QACH,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC;QAEjH,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC,CAAC;QACjE,CAAC;QAED,MAAM,YAAY,GAAG,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAE1E,sDAAsD;QACtD,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,IAAI,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;YACzC,KAAK,CAAC,aAAa,CAAC;gBAClB,SAAS,EAAE,UAAU;gBACrB,IAAI,EAAE,IAAI,EAAE,IAAI;gBAChB,GAAG,EAAE,IAAI,EAAE,GAAG;gBACd,GAAG,EAAE,IAAI,EAAE,GAAG;gBACd,SAAS,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS;gBAC/E,MAAM,EAAE,QAAQ;aACjB,CAAC,CAAC;QACL,CAAC;QAED,iEAAiE;QACjE,CAAC;YACC,MAAM,UAAU,GAAW,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC;YACrD,MAAM,UAAU,GAAa,EAAE,CAAC;YAChC,MAAM,OAAO,GAAG,CAAC,CAAM,EAAE,EAAE,GAAG,IAAI,OAAO,CAAC,KAAK,QAAQ;gBAAE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/E,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAC7B,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;YAC3B,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAC7B,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC;gBACrC,KAAK,MAAM,CAAC,IAAI,UAAU,CAAC,KAAK;oBAAE,OAAO,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;YACxD,CAAC;YACD,MAAM,YAAY,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC;YAC3E,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBAClE,MAAM,WAAW,GAAG,cAAI,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE,mBAAmB,CAAC,CAAC;gBAC3E,MAAM,GAAG,GAAG,cAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;gBACtC,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,GAAG,CAAC;oBAAE,YAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBAChE,YAAE,CAAC,aAAa,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;gBACvC,+DAA+D;gBAC/D,MAAM,YAAY,GAAG,cAAI,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE,oBAAoB,CAAC,CAAC;gBAC7E,IAAI,YAAE,CAAC,UAAU,CAAC,YAAY,CAAC;oBAAE,YAAE,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;gBAC7D,IAAI,SAAS;oBAAE,SAAS,CAAC,EAAE,IAAI,EAAE,wBAAwB,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAS,CAAC,CAAC;YACtH,CAAC;QACH,CAAC;QAED,yBAAyB;QACzB,IAAI,YAAY,GAAkB,IAAI,CAAC;QACvC,IAAI,aAAa,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;YAC5B,YAAY,GAAG,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC/C,CAAC;aAAM,IAAI,aAAa,EAAE,MAAM,EAAE,CAAC;YACjC,YAAY,GAAG,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;QAC9C,CAAC;aAAM,CAAC;YACN,MAAM,SAAS,GAAG,OAAO,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;YACpG,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC1C,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC7C,CAAC;QAED,MAAM,SAAS,GAAG,YAAY,CAAC,CAAC,CAAC,UAAU,YAAY,IAAI,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QAEjF,IAAI,SAAS,KAAK,YAAY,EAAE,CAAC;YAC/B,MAAM,OAAO,GAAG,UAAU,EAAE,OAAO,IAAI,UAAU,EAAE,KAAK,IAAI,UAAU,CAAC;YACvE,MAAM,WAAW,GAAG,UAAU,EAAE,WAAW,IAAI,EAAE,CAAC;YAElD,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACxC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;gBAC7D,IAAI,KAAK;oBAAE,OAAO,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;YAC3C,CAAC;YAED,8CAA8C;YAC9C,MAAM,OAAO,GAAG,cAAc,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC;YAE7D,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC;gBAClC,KAAK,EAAE,OAAO;gBACd,WAAW;gBACX,MAAM,EAAE,SAAS;gBACjB,QAAQ,EAAE,QAAQ;gBAClB,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE;aACnC,CAAC,CAAC;YAEH,2DAA2D;YAC3D,IAAI,YAAY,IAAI,UAAU,EAAE,UAAU,IAAI,UAAU,EAAE,KAAK,IAAI,UAAU,EAAE,QAAQ,IAAI,OAAO,EAAE,CAAC;gBACnG,MAAM,KAAK,GAAwB,EAAE,CAAC;gBACtC,IAAI,UAAU;oBAAE,KAAK,CAAC,eAAe,GAAG,UAAU,CAAC;gBACnD,IAAI,YAAY;oBAAE,KAAK,CAAC,YAAY,GAAG,YAAY,CAAC;gBACpD,IAAI,UAAU,EAAE,UAAU;oBAAE,KAAK,CAAC,UAAU,GAAG,UAAU,CAAC,UAAU,CAAC;gBACrE,IAAI,UAAU,EAAE,KAAK;oBAAE,KAAK,CAAC,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC;gBACtD,IAAI,UAAU,EAAE,QAAQ;oBAAE,KAAK,CAAC,QAAQ,GAAG,UAAU,CAAC,QAAQ,CAAC;gBAC/D,IAAI,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,eAAe,IAAI,OAAO,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;oBACjF,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;gBAC1C,CAAC;gBACD,MAAM,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,KAAY,CAAC,CAAC;YAChD,CAAC;YAED,IAAI,SAAS;gBAAE,SAAS,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;QAC1F,CAAC;QAED,IAAI,SAAS,KAAK,YAAY,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,UAAU,EAAE,MAAM,CAAC;YAClC,MAAM,QAAQ,GAAG,UAAU,EAAE,MAAM,CAAC;YAEpC,6BAA6B;YAC7B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE,CAAC;YACxC,MAAM,GAAG,GAAG,UAAU,YAAY,IAAI,QAAQ,EAAE,CAAC;YACjD,IAAI,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;YACrD,2CAA2C;YAC3C,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,QAAQ,EAAE,CAAC,CAAC,CAAC;YACpE,CAAC;YAED,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,OAAO,GAAwB,EAAE,CAAC;gBAExC,IAAI,MAAM,EAAE,CAAC;oBACX,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;wBACzB,OAAO,CAAC,MAAM,GAAG,UAAU,CAAC;oBAC9B,CAAC;yBAAM,CAAC;wBACN,MAAM,SAAS,GAA2B;4BACxC,aAAa,EAAE,aAAa;4BAC5B,WAAW,EAAE,WAAW;4BACxB,SAAS,EAAE,SAAS;yBACrB,CAAC;wBACF,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC;oBAC/C,CAAC;gBACH,CAAC;gBAED,wCAAwC;gBACxC,IAAI,UAAU,EAAE,OAAO;oBAAE,OAAO,CAAC,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC;gBAC5D,IAAI,UAAU,EAAE,WAAW;oBAAE,OAAO,CAAC,WAAW,GAAG,UAAU,CAAC,WAAW,CAAC;gBAC1E,IAAI,UAAU,EAAE,UAAU;oBAAE,OAAO,CAAC,UAAU,GAAG,UAAU,CAAC,UAAU,CAAC;gBACvE,IAAI,UAAU,EAAE,KAAK;oBAAE,OAAO,CAAC,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC;gBACxD,IAAI,UAAU,EAAE,QAAQ;oBAAE,OAAO,CAAC,QAAQ,GAAG,EAAE,GAAI,KAAa,CAAC,QAAQ,EAAE,GAAG,UAAU,CAAC,QAAQ,EAAE,CAAC;gBAEpG,4DAA4D;gBAC5D,IAAI,MAAM,KAAK,WAAW,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;oBACnD,MAAM,aAAa,GAAG,cAAc,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC;oBACnE,IAAI,aAAa,CAAC,eAAe,IAAI,aAAa,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;wBACvE,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;oBAC5D,CAAC;gBACH,CAAC;gBAED,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,EAAE,OAAc,CAAC,CAAC;gBACjE,IAAI,SAAS;oBAAE,SAAS,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;YACnG,CAAC;QACH,CAAC;QAED,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACzB,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC,CAAC,CAAC;AAGH,mBAAW,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;IACzD,MAAM,KAAK,GAAqB,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC;IACzD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,MAA4B,CAAC;QACtD,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,OAA6B,CAAC;QAC1D,MAAM,MAAM,GAAQ,EAAE,CAAC;QACvB,IAAI,MAAM;YAAE,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QACnC,IAAI,SAAS;YAAE,MAAM,CAAC,SAAS,GAAG,SAAS,CAAC;QAC5C,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACpF,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,gDAAgD;AAChD,mBAAW,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;IAC3D,MAAM,KAAK,GAAqB,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC;IACzD,MAAM,UAAU,GAAW,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC;IACrD,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,KAAK,UAAU,CAAC,CAAC;IACjF,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACrB,CAAC,CAAC,CAAC;AAEH,mBAAW,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;IAC5D,MAAM,KAAK,GAAqB,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC;IACzD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAChD,IAAI,CAAC,IAAI;YAAE,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,CAAC;QACpE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjB,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,mBAAW,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;IAC1D,MAAM,KAAK,GAAqB,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC;IACzD,IAAI,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YACpB,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;QAC9D,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC9C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,mBAAW,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;IAC5D,MAAM,KAAK,GAAqB,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC;IACzD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QAC7D,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjB,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,IAAI,GAAG,CAAC,OAAO,KAAK,gBAAgB,EAAE,CAAC;YACrC,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,mBAAW,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;IAC/D,MAAM,KAAK,GAAqB,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC;IACzD,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACtC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACzB,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,qBAAqB;AAErB,uDAAuD;AACvD,SAAS,eAAe,CAAC,SAAiB;IACxC,MAAM,WAAW,GAAG,cAAI,CAAC,IAAI,CAAC,YAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IACnE,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,IAAI,CAAC;IAE7C,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,YAAE,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QAC3E,IAAI,IAAI,GAAQ,IAAI,CAAC;QACrB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAE,CAAC,YAAY,CAAC,cAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;gBAChF,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;oBACjC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;wBACtF,IAAI,GAAG,IAAI,CAAC;oBACd,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;QACZ,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IACV,OAAO,IAAI,CAAC;AACd,CAAC;AAGD,gDAAgD;AAChD,SAAS,oBAAoB,CAAC,KAAuB;IACnD,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,YAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IAC7D,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO;IAErC,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IACrC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,OAAO,CAAC,MAAM,KAAK,QAAQ;YAAE,SAAS;QAC1C,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACjE,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,KAAK,CAAC,mBAAmB,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,7 @@
1
+ import http from 'http';
2
+ import { ServerOptions } from './types';
3
+ export declare function createServer(options: ServerOptions): {
4
+ app: import("express-serve-static-core").Express;
5
+ httpServer: http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>;
6
+ wss: import("ws").Server<typeof import("ws"), typeof http.IncomingMessage>;
7
+ };
package/dist/server.js ADDED
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createServer = createServer;
7
+ const express_1 = __importDefault(require("express"));
8
+ const http_1 = __importDefault(require("http"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const ws_1 = require("ws");
11
+ const chokidar_1 = __importDefault(require("chokidar"));
12
+ const git_1 = require("./services/git");
13
+ const watcher_1 = require("./services/watcher");
14
+ const taskStore_1 = require("./services/taskStore");
15
+ const rules_1 = require("./services/rules");
16
+ const diff_1 = require("./routes/diff");
17
+ const tasks_1 = require("./routes/tasks");
18
+ const integrations_1 = require("./routes/integrations");
19
+ const rules_2 = require("./routes/rules");
20
+ function createServer(options) {
21
+ const app = (0, express_1.default)();
22
+ const httpServer = http_1.default.createServer(app);
23
+ const wss = new ws_1.WebSocketServer({ server: httpServer, path: '/ws' });
24
+ // Middleware
25
+ app.use(express_1.default.json());
26
+ // Services
27
+ const gitService = (0, git_1.createGitService)(options.projectDir);
28
+ const taskStore = (0, taskStore_1.createTaskStore)(options.projectDir);
29
+ const rulesService = (0, rules_1.createRulesService)(options.projectDir);
30
+ rulesService.ensureDefault();
31
+ // Attach to app.locals for route access
32
+ app.locals.gitService = gitService;
33
+ app.locals.taskStore = taskStore;
34
+ app.locals.rulesService = rulesService;
35
+ app.locals.projectDir = options.projectDir;
36
+ app.locals.port = options.port;
37
+ // API routes
38
+ app.use('/api', diff_1.diffRouter);
39
+ app.use('/api/tasks', tasks_1.tasksRouter);
40
+ app.use('/api/integrations', integrations_1.integrationsRouter);
41
+ app.use('/api/rules', rules_2.rulesRouter);
42
+ // Static files
43
+ const publicDir = path_1.default.resolve(__dirname, '../public');
44
+ app.use(express_1.default.static(publicDir));
45
+ // SPA fallback
46
+ app.get('*', (_req, res) => {
47
+ res.sendFile(path_1.default.join(publicDir, 'index.html'));
48
+ });
49
+ // WebSocket broadcast helper
50
+ function broadcast(message) {
51
+ const data = JSON.stringify(message);
52
+ wss.clients.forEach((client) => {
53
+ if (client.readyState === ws_1.WebSocket.OPEN) {
54
+ client.send(data);
55
+ }
56
+ });
57
+ }
58
+ // File watcher -> WebSocket broadcast
59
+ const watcher = (0, watcher_1.createWatcher)(options.projectDir, async () => {
60
+ try {
61
+ const diff = await gitService.getDiff();
62
+ const status = await gitService.getStatus();
63
+ broadcast({ type: 'diff-update', payload: { diff } });
64
+ broadcast({ type: 'status-update', payload: { status } });
65
+ }
66
+ catch {
67
+ // Git service may fail if not a git repo
68
+ }
69
+ });
70
+ // Watch rules.md for external changes
71
+ const rulesPath = path_1.default.join(options.projectDir, '.devlens', 'rules.md');
72
+ const rulesWatcher = chokidar_1.default.watch(rulesPath, { ignoreInitial: true });
73
+ rulesWatcher.on('change', () => {
74
+ broadcast({ type: 'rules-update', payload: { rules: rulesService.getRules() } });
75
+ });
76
+ // Watch commit approval files
77
+ const devlensDir = path_1.default.join(options.projectDir, '.devlens');
78
+ const approvalWatcher = chokidar_1.default.watch([
79
+ path_1.default.join(devlensDir, 'commit-pending.md'),
80
+ path_1.default.join(devlensDir, 'commit-approved.md'),
81
+ ], { ignoreInitial: false });
82
+ function broadcastApprovalState() {
83
+ const fs = require('fs');
84
+ const pendingFile = path_1.default.join(devlensDir, 'commit-pending.md');
85
+ const approvedFile = path_1.default.join(devlensDir, 'commit-approved.md');
86
+ let pending = null;
87
+ let approved = false;
88
+ let approvedAt = null;
89
+ if (fs.existsSync(pendingFile))
90
+ pending = fs.readFileSync(pendingFile, 'utf-8').trim();
91
+ if (fs.existsSync(approvedFile)) {
92
+ approved = true;
93
+ const m = fs.readFileSync(approvedFile, 'utf-8').match(/timestamp:\s*(.+)/);
94
+ if (m)
95
+ approvedAt = m[1].trim();
96
+ }
97
+ broadcast({ type: 'commit-approval-update', payload: { pending, approved, approvedAt } });
98
+ }
99
+ approvalWatcher.on('add', broadcastApprovalState);
100
+ approvalWatcher.on('change', broadcastApprovalState);
101
+ approvalWatcher.on('unlink', broadcastApprovalState);
102
+ // Check session liveness every 30 seconds
103
+ const livenessInterval = setInterval(() => {
104
+ (0, tasks_1.checkSessionLiveness)(taskStore);
105
+ }, 30000);
106
+ // Attach broadcast and watcher for cleanup
107
+ app.locals.broadcast = broadcast;
108
+ app.locals.watcher = watcher;
109
+ app.locals.livenessInterval = livenessInterval;
110
+ return { app, httpServer, wss };
111
+ }
112
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import chokidar from 'chokidar';
2
+ export interface ClaudeTodo {
3
+ id: string;
4
+ content: string;
5
+ status: 'pending' | 'in_progress' | 'completed';
6
+ priority?: string;
7
+ updatedAt: string;
8
+ }
9
+ export interface ClaudeSession {
10
+ sessionId: string;
11
+ name?: string;
12
+ cwd?: string;
13
+ pid?: number;
14
+ startedAt?: string;
15
+ taskCount: number;
16
+ active: boolean;
17
+ }
18
+ export declare function getTodos(): ClaudeTodo[];
19
+ export declare function upsertTodo(todo: ClaudeTodo): void;
20
+ export declare function clearTodos(): void;
21
+ export declare function parseTodoWritePayload(toolInput: any): ClaudeTodo[];
22
+ export declare function watchClaudeTasks(onChange: (sessions: ClaudeSession[]) => void): chokidar.FSWatcher | null;
23
+ export declare function readClaudeSessions(): ClaudeSession[];