mstro-app 0.3.8 → 0.4.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 (109) hide show
  1. package/LICENSE +191 -21
  2. package/PRIVACY.md +286 -62
  3. package/README.md +81 -58
  4. package/bin/commands/status.js +1 -1
  5. package/dist/server/cli/headless/claude-invoker.d.ts.map +1 -1
  6. package/dist/server/cli/headless/claude-invoker.js +22 -12
  7. package/dist/server/cli/headless/claude-invoker.js.map +1 -1
  8. package/dist/server/cli/headless/headless-logger.d.ts +10 -0
  9. package/dist/server/cli/headless/headless-logger.d.ts.map +1 -0
  10. package/dist/server/cli/headless/headless-logger.js +66 -0
  11. package/dist/server/cli/headless/headless-logger.js.map +1 -0
  12. package/dist/server/cli/headless/mcp-config.d.ts.map +1 -1
  13. package/dist/server/cli/headless/mcp-config.js +6 -5
  14. package/dist/server/cli/headless/mcp-config.js.map +1 -1
  15. package/dist/server/cli/headless/runner.d.ts.map +1 -1
  16. package/dist/server/cli/headless/runner.js +4 -0
  17. package/dist/server/cli/headless/runner.js.map +1 -1
  18. package/dist/server/cli/headless/stall-assessor.d.ts +21 -0
  19. package/dist/server/cli/headless/stall-assessor.d.ts.map +1 -1
  20. package/dist/server/cli/headless/stall-assessor.js +100 -24
  21. package/dist/server/cli/headless/stall-assessor.js.map +1 -1
  22. package/dist/server/cli/headless/tool-watchdog.d.ts +0 -12
  23. package/dist/server/cli/headless/tool-watchdog.d.ts.map +1 -1
  24. package/dist/server/cli/headless/tool-watchdog.js +22 -9
  25. package/dist/server/cli/headless/tool-watchdog.js.map +1 -1
  26. package/dist/server/cli/headless/types.d.ts +8 -1
  27. package/dist/server/cli/headless/types.d.ts.map +1 -1
  28. package/dist/server/cli/improvisation-session-manager.d.ts +16 -0
  29. package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -1
  30. package/dist/server/cli/improvisation-session-manager.js +94 -11
  31. package/dist/server/cli/improvisation-session-manager.js.map +1 -1
  32. package/dist/server/mcp/bouncer-cli.d.ts +3 -0
  33. package/dist/server/mcp/bouncer-cli.d.ts.map +1 -0
  34. package/dist/server/mcp/bouncer-cli.js +54 -0
  35. package/dist/server/mcp/bouncer-cli.js.map +1 -0
  36. package/dist/server/services/plan/composer.d.ts +4 -0
  37. package/dist/server/services/plan/composer.d.ts.map +1 -0
  38. package/dist/server/services/plan/composer.js +181 -0
  39. package/dist/server/services/plan/composer.js.map +1 -0
  40. package/dist/server/services/plan/dependency-resolver.d.ts +28 -0
  41. package/dist/server/services/plan/dependency-resolver.d.ts.map +1 -0
  42. package/dist/server/services/plan/dependency-resolver.js +154 -0
  43. package/dist/server/services/plan/dependency-resolver.js.map +1 -0
  44. package/dist/server/services/plan/executor.d.ts +110 -0
  45. package/dist/server/services/plan/executor.d.ts.map +1 -0
  46. package/dist/server/services/plan/executor.js +641 -0
  47. package/dist/server/services/plan/executor.js.map +1 -0
  48. package/dist/server/services/plan/parser.d.ts +11 -0
  49. package/dist/server/services/plan/parser.d.ts.map +1 -0
  50. package/dist/server/services/plan/parser.js +445 -0
  51. package/dist/server/services/plan/parser.js.map +1 -0
  52. package/dist/server/services/plan/state-reconciler.d.ts +2 -0
  53. package/dist/server/services/plan/state-reconciler.d.ts.map +1 -0
  54. package/dist/server/services/plan/state-reconciler.js +145 -0
  55. package/dist/server/services/plan/state-reconciler.js.map +1 -0
  56. package/dist/server/services/plan/types.d.ts +121 -0
  57. package/dist/server/services/plan/types.d.ts.map +1 -0
  58. package/dist/server/services/plan/types.js +4 -0
  59. package/dist/server/services/plan/types.js.map +1 -0
  60. package/dist/server/services/plan/watcher.d.ts +14 -0
  61. package/dist/server/services/plan/watcher.d.ts.map +1 -0
  62. package/dist/server/services/plan/watcher.js +69 -0
  63. package/dist/server/services/plan/watcher.js.map +1 -0
  64. package/dist/server/services/websocket/file-explorer-handlers.js +20 -0
  65. package/dist/server/services/websocket/file-explorer-handlers.js.map +1 -1
  66. package/dist/server/services/websocket/handler.d.ts.map +1 -1
  67. package/dist/server/services/websocket/handler.js +21 -0
  68. package/dist/server/services/websocket/handler.js.map +1 -1
  69. package/dist/server/services/websocket/plan-handlers.d.ts +6 -0
  70. package/dist/server/services/websocket/plan-handlers.d.ts.map +1 -0
  71. package/dist/server/services/websocket/plan-handlers.js +494 -0
  72. package/dist/server/services/websocket/plan-handlers.js.map +1 -0
  73. package/dist/server/services/websocket/quality-handlers.d.ts.map +1 -1
  74. package/dist/server/services/websocket/quality-handlers.js +384 -12
  75. package/dist/server/services/websocket/quality-handlers.js.map +1 -1
  76. package/dist/server/services/websocket/quality-persistence.d.ts +45 -0
  77. package/dist/server/services/websocket/quality-persistence.d.ts.map +1 -0
  78. package/dist/server/services/websocket/quality-persistence.js +187 -0
  79. package/dist/server/services/websocket/quality-persistence.js.map +1 -0
  80. package/dist/server/services/websocket/quality-service.d.ts +12 -2
  81. package/dist/server/services/websocket/quality-service.d.ts.map +1 -1
  82. package/dist/server/services/websocket/quality-service.js +162 -18
  83. package/dist/server/services/websocket/quality-service.js.map +1 -1
  84. package/dist/server/services/websocket/types.d.ts +2 -2
  85. package/dist/server/services/websocket/types.d.ts.map +1 -1
  86. package/package.json +3 -3
  87. package/server/cli/headless/claude-invoker.ts +25 -12
  88. package/server/cli/headless/headless-logger.ts +78 -0
  89. package/server/cli/headless/mcp-config.ts +6 -5
  90. package/server/cli/headless/runner.ts +4 -0
  91. package/server/cli/headless/stall-assessor.ts +131 -24
  92. package/server/cli/headless/tool-watchdog.ts +10 -9
  93. package/server/cli/headless/types.ts +10 -1
  94. package/server/cli/improvisation-session-manager.ts +118 -11
  95. package/server/mcp/bouncer-cli.ts +73 -0
  96. package/server/services/plan/composer.ts +199 -0
  97. package/server/services/plan/dependency-resolver.ts +182 -0
  98. package/server/services/plan/executor.ts +700 -0
  99. package/server/services/plan/parser.ts +491 -0
  100. package/server/services/plan/state-reconciler.ts +174 -0
  101. package/server/services/plan/types.ts +166 -0
  102. package/server/services/plan/watcher.ts +73 -0
  103. package/server/services/websocket/file-explorer-handlers.ts +20 -0
  104. package/server/services/websocket/handler.ts +21 -0
  105. package/server/services/websocket/plan-handlers.ts +592 -0
  106. package/server/services/websocket/quality-handlers.ts +450 -12
  107. package/server/services/websocket/quality-persistence.ts +250 -0
  108. package/server/services/websocket/quality-service.ts +183 -18
  109. package/server/services/websocket/types.ts +48 -2
@@ -0,0 +1,11 @@
1
+ import type { Issue, Milestone, PlanFullState, Sprint } from './types.js';
2
+ /** Resolve the PM directory — prefers .pm/, falls back to legacy .plan/ */
3
+ export declare function resolvePmDir(workingDir: string): string | null;
4
+ export declare function planDirExists(workingDir: string): boolean;
5
+ export declare function parsePlanDirectory(workingDir: string): PlanFullState | null;
6
+ export declare function parseSingleIssue(workingDir: string, issuePath: string): Issue | null;
7
+ export declare function parseSingleSprint(workingDir: string, sprintPath: string): Sprint | null;
8
+ export declare function parseSingleMilestone(workingDir: string, milestonePath: string): Milestone | null;
9
+ /** Compute the next available ID for a given prefix (e.g., "IS" → "IS-004") */
10
+ export declare function getNextId(issues: Issue[], prefix: string): string;
11
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../../../server/services/plan/parser.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAEV,KAAK,EAEL,SAAS,EAET,aAAa,EAGb,MAAM,EAIP,MAAM,YAAY,CAAC;AA2WpB,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM9D;AAED,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAEzD;AAqBD,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CA6B3E;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,CAOpF;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOvF;AAED,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAOhG;AAED,+EAA+E;AAC/E,wBAAgB,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAYjE"}
@@ -0,0 +1,445 @@
1
+ // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file for details.
3
+ /**
4
+ * PPS Parser — Parses .pm/ (or legacy .plan/) directory files into structured TypeScript objects.
5
+ *
6
+ * Handles YAML front matter extraction and markdown body parsing.
7
+ */
8
+ import { existsSync, readdirSync, readFileSync } from 'node:fs';
9
+ import { join } from 'node:path';
10
+ function stripQuotes(v) {
11
+ if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'"))) {
12
+ return v.slice(1, -1);
13
+ }
14
+ return v;
15
+ }
16
+ function parseYamlValue(v) {
17
+ if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'"))) {
18
+ return v.slice(1, -1);
19
+ }
20
+ if (v.startsWith('[') && v.endsWith(']')) {
21
+ return v.slice(1, -1).split(',').map(s => stripQuotes(s.trim())).filter(Boolean);
22
+ }
23
+ if (v === 'true')
24
+ return true;
25
+ if (v === 'false')
26
+ return false;
27
+ if (v === 'null' || v === '~' || v === '')
28
+ return null;
29
+ if (/^-?\d+(\.\d+)?$/.test(v))
30
+ return Number(v);
31
+ return v;
32
+ }
33
+ function parseFrontMatter(content) {
34
+ const match = content.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
35
+ if (!match) {
36
+ return { frontMatter: {}, body: content };
37
+ }
38
+ const frontMatter = {};
39
+ const lines = match[1].split('\n');
40
+ for (let i = 0; i < lines.length; i++) {
41
+ const trimmed = lines[i].trim();
42
+ if (!trimmed || trimmed.startsWith('#'))
43
+ continue;
44
+ const colonIdx = trimmed.indexOf(':');
45
+ if (colonIdx === -1)
46
+ continue;
47
+ const key = trimmed.slice(0, colonIdx).trim();
48
+ const rawValue = trimmed.slice(colonIdx + 1).trim();
49
+ // Handle multi-line indented YAML lists (key:\n - item1\n - item2)
50
+ if (!rawValue) {
51
+ const items = [];
52
+ while (i + 1 < lines.length && /^\s+-\s/.test(lines[i + 1])) {
53
+ i++;
54
+ const item = lines[i].trim().replace(/^-\s+/, '');
55
+ items.push(stripQuotes(item));
56
+ }
57
+ frontMatter[key] = items.length > 0 ? items : null;
58
+ }
59
+ else {
60
+ frontMatter[key] = parseYamlValue(rawValue);
61
+ }
62
+ }
63
+ return { frontMatter, body: match[2] };
64
+ }
65
+ // ============================================================================
66
+ // Section Extraction
67
+ // ============================================================================
68
+ function extractSections(body) {
69
+ const sections = new Map();
70
+ const lines = body.split('\n');
71
+ let currentSection = '';
72
+ let currentContent = [];
73
+ for (const line of lines) {
74
+ if (line.startsWith('## ')) {
75
+ if (currentSection) {
76
+ sections.set(currentSection, currentContent.join('\n').trim());
77
+ }
78
+ currentSection = line.slice(3).trim();
79
+ currentContent = [];
80
+ }
81
+ else {
82
+ currentContent.push(line);
83
+ }
84
+ }
85
+ if (currentSection) {
86
+ sections.set(currentSection, currentContent.join('\n').trim());
87
+ }
88
+ return sections;
89
+ }
90
+ function parseCheckboxes(content) {
91
+ const items = [];
92
+ for (const line of content.split('\n')) {
93
+ const match = line.match(/^[-*]\s+\[([ xX])\]\s+(.+)$/);
94
+ if (match) {
95
+ items.push({ text: match[2].trim(), checked: match[1] !== ' ' });
96
+ }
97
+ }
98
+ return items;
99
+ }
100
+ function parseListItems(content) {
101
+ const items = [];
102
+ for (const line of content.split('\n')) {
103
+ const match = line.match(/^[-*]\s+(.+)$/);
104
+ if (match)
105
+ items.push(match[1].trim());
106
+ }
107
+ return items;
108
+ }
109
+ function parseIssueSummaries(content) {
110
+ const summaries = [];
111
+ for (const line of content.split('\n')) {
112
+ // Match: 1. [IS-003](backlog/IS-003.md) — Title (P1)
113
+ const match = line.match(/\d+\.\s+\[([^\]]+)\]\(([^)]+)\)\s*[—–-]\s*(.+?)(?:\s*\((\w+)\))?\s*$/);
114
+ if (match) {
115
+ summaries.push({
116
+ id: match[1],
117
+ path: match[2],
118
+ title: match[3].trim(),
119
+ priority: match[4] || '',
120
+ });
121
+ continue;
122
+ }
123
+ // Match: - [IS-001](backlog/IS-001.md) — Title
124
+ const match2 = line.match(/^[-*]\s+\[([^\]]+)\]\(([^)]+)\)\s*[—–-]\s*(.+?)(?:\s*[→→]\s*blocked by\s+\[([^\]]+)\])?\s*$/i);
125
+ if (match2) {
126
+ summaries.push({
127
+ id: match2[1],
128
+ path: match2[2],
129
+ title: match2[3].trim(),
130
+ priority: '',
131
+ blockedBy: match2[4] || undefined,
132
+ });
133
+ }
134
+ }
135
+ return summaries;
136
+ }
137
+ function parseCompletedSummaries(content) {
138
+ const summaries = [];
139
+ for (const line of content.split('\n')) {
140
+ const match = line.match(/^[-*]\s+\[([^\]]+)\]\(([^)]+)\)\s*[—–-]\s*(.+?)(?:\s*✓)?\s*$/);
141
+ if (match) {
142
+ summaries.push({
143
+ id: match[1],
144
+ path: match[2],
145
+ title: match[3].trim(),
146
+ priority: '',
147
+ });
148
+ }
149
+ }
150
+ return summaries;
151
+ }
152
+ // ============================================================================
153
+ // Entity Parsers
154
+ // ============================================================================
155
+ function parseWorkflows(section) {
156
+ if (!section)
157
+ return [];
158
+ const workflows = [];
159
+ for (const line of section.split('\n')) {
160
+ const match = line.match(/\|\s*(\w+)\s*\|\s*(\w+)\s*\|\s*(.+?)\s*\|/);
161
+ if (match && match[1] !== 'Status') {
162
+ workflows.push({
163
+ status: match[1],
164
+ category: match[2],
165
+ description: match[3].trim(),
166
+ });
167
+ }
168
+ }
169
+ return workflows;
170
+ }
171
+ function parseTeams(section) {
172
+ if (!section)
173
+ return [];
174
+ const teams = [];
175
+ for (const line of section.split('\n')) {
176
+ const match = line.match(/^[-*]\s+(\w+)(?:\s*[—–-]\s*(.+))?$/);
177
+ if (match)
178
+ teams.push({ name: match[1], description: match[2]?.trim() });
179
+ }
180
+ return teams;
181
+ }
182
+ function parseProjectConfig(content) {
183
+ const { frontMatter, body } = parseFrontMatter(content);
184
+ const sections = extractSections(body);
185
+ const idPrefixes = {};
186
+ const rawPrefixes = frontMatter.id_prefixes;
187
+ if (rawPrefixes && typeof rawPrefixes === 'object') {
188
+ Object.assign(idPrefixes, rawPrefixes);
189
+ }
190
+ return {
191
+ name: String(frontMatter.name || ''),
192
+ id: String(frontMatter.id || ''),
193
+ created: String(frontMatter.created || ''),
194
+ status: frontMatter.status || 'active',
195
+ estimation: frontMatter.estimation || 'none',
196
+ idPrefixes,
197
+ workflows: parseWorkflows(sections.get('Workflows')),
198
+ labels: (Array.isArray(frontMatter.labels) ? frontMatter.labels : []),
199
+ teams: parseTeams(sections.get('Teams')),
200
+ };
201
+ }
202
+ function parseProjectState(content) {
203
+ const { frontMatter, body } = parseFrontMatter(content);
204
+ const sections = extractSections(body);
205
+ return {
206
+ project: String(frontMatter.project || ''),
207
+ currentSprint: frontMatter.current_sprint || null,
208
+ activeMilestone: frontMatter.active_milestone || null,
209
+ paused: frontMatter.paused === true,
210
+ lastSession: frontMatter.last_session || null,
211
+ readyToWork: parseIssueSummaries(sections.get('Ready to Work') || ''),
212
+ inProgress: parseIssueSummaries(sections.get('In Progress') || ''),
213
+ blocked: parseIssueSummaries(sections.get('Blocked') || ''),
214
+ recentlyCompleted: parseCompletedSummaries(sections.get('Recently Completed') || ''),
215
+ warnings: parseListItems(sections.get('Warnings') || ''),
216
+ };
217
+ }
218
+ function toStringArray(val) {
219
+ return Array.isArray(val) ? val.map(String) : [];
220
+ }
221
+ function optionalString(val) {
222
+ if (val == null)
223
+ return null;
224
+ const s = String(val);
225
+ return s === '' ? null : s;
226
+ }
227
+ function parseIssue(content, filePath) {
228
+ const { frontMatter: fm, body } = parseFrontMatter(content);
229
+ const sections = extractSections(body);
230
+ return {
231
+ id: String(fm.id || ''),
232
+ title: String(fm.title || ''),
233
+ type: fm.type || 'issue',
234
+ status: String(fm.status || 'backlog'),
235
+ priority: String(fm.priority || 'P2'),
236
+ estimate: fm.estimate != null ? fm.estimate : null,
237
+ labels: toStringArray(fm.labels),
238
+ epic: optionalString(fm.epic),
239
+ sprint: optionalString(fm.sprint),
240
+ milestone: optionalString(fm.milestone),
241
+ assigned: optionalString(fm.assigned),
242
+ created: String(fm.created || ''),
243
+ updated: optionalString(fm.updated),
244
+ due: optionalString(fm.due),
245
+ blockedBy: toStringArray(fm.blocked_by),
246
+ blocks: toStringArray(fm.blocks),
247
+ relatesTo: toStringArray(fm.relates_to),
248
+ children: toStringArray(fm.children),
249
+ progress: optionalString(fm.progress),
250
+ description: sections.get('Description') || '',
251
+ acceptanceCriteria: parseCheckboxes(sections.get('Acceptance Criteria') || ''),
252
+ technicalNotes: sections.get('Technical Notes') || null,
253
+ filesToModify: parseListItems(sections.get('Files to Modify') || ''),
254
+ activity: parseListItems(sections.get('Activity') || ''),
255
+ outputFile: optionalString(fm.output_file),
256
+ body,
257
+ path: filePath,
258
+ };
259
+ }
260
+ function parseSprintIssues(section) {
261
+ if (!section)
262
+ return [];
263
+ const issues = [];
264
+ for (const line of section.split('\n')) {
265
+ const match = line.match(/\|\s*\[([^\]]+)\]\(([^)]+)\)\s*\|\s*(.+?)\s*\|\s*(\S+)\s*\|\s*(\S+)\s*\|/);
266
+ if (match) {
267
+ issues.push({
268
+ id: match[1],
269
+ path: match[2],
270
+ title: match[3].trim(),
271
+ points: /^\d+$/.test(match[4]) ? Number(match[4]) : match[4],
272
+ status: match[5],
273
+ });
274
+ }
275
+ }
276
+ return issues;
277
+ }
278
+ function optionalNumber(val) {
279
+ return val != null ? Number(val) : null;
280
+ }
281
+ function parseSprint(content, filePath) {
282
+ const { frontMatter: fm, body } = parseFrontMatter(content);
283
+ const sections = extractSections(body);
284
+ // Table-based parsing (markdown links in table rows)
285
+ let issues = parseSprintIssues(sections.get('Issues'));
286
+ // Fallback: front matter issues array (e.g., ["backlog/IS-001.md", ...])
287
+ if (issues.length === 0 && Array.isArray(fm.issues)) {
288
+ issues = fm.issues.map(path => {
289
+ const id = path.replace(/^backlog\//, '').replace(/\.md$/, '');
290
+ return { id, path, title: '', points: null, status: '' };
291
+ });
292
+ }
293
+ return {
294
+ id: String(fm.id || ''),
295
+ title: String(fm.title || ''),
296
+ status: fm.status || 'planned',
297
+ start: String(fm.start || fm.start_date || ''),
298
+ end: String(fm.end || fm.end_date || ''),
299
+ goal: String(fm.goal || sections.get('Goal') || sections.get('Sprint Goal') || ''),
300
+ capacity: optionalNumber(fm.capacity),
301
+ committed: optionalNumber(fm.committed),
302
+ completed: optionalNumber(fm.completed),
303
+ issues,
304
+ path: filePath,
305
+ };
306
+ }
307
+ function parseMilestone(content, filePath) {
308
+ const { frontMatter, body } = parseFrontMatter(content);
309
+ const sections = extractSections(body);
310
+ const epics = [];
311
+ const epicSection = sections.get('Epics');
312
+ if (epicSection) {
313
+ for (const line of epicSection.split('\n')) {
314
+ const match = line.match(/\|\s*\[([^\]]+)\]\(([^)]+)\)\s*\|\s*(.+?)\s*\|\s*(\S+)\s*\|/);
315
+ if (match) {
316
+ epics.push({
317
+ id: match[1],
318
+ path: match[2],
319
+ title: match[3].trim(),
320
+ progress: match[4],
321
+ });
322
+ }
323
+ }
324
+ }
325
+ return {
326
+ id: String(frontMatter.id || ''),
327
+ title: String(frontMatter.title || ''),
328
+ status: frontMatter.status || 'planned',
329
+ targetDate: frontMatter.target_date || null,
330
+ progress: frontMatter.progress || null,
331
+ definition: sections.get('Definition of Done') || '',
332
+ epics,
333
+ path: filePath,
334
+ };
335
+ }
336
+ // ============================================================================
337
+ // Directory Parser
338
+ // ============================================================================
339
+ /** Resolve the PM directory — prefers .pm/, falls back to legacy .plan/ */
340
+ export function resolvePmDir(workingDir) {
341
+ const pmDir = join(workingDir, '.pm');
342
+ if (existsSync(pmDir))
343
+ return pmDir;
344
+ const legacyDir = join(workingDir, '.plan');
345
+ if (existsSync(legacyDir))
346
+ return legacyDir;
347
+ return null;
348
+ }
349
+ export function planDirExists(workingDir) {
350
+ return resolvePmDir(workingDir) !== null;
351
+ }
352
+ function readFileIfExists(path) {
353
+ try {
354
+ if (existsSync(path))
355
+ return readFileSync(path, 'utf-8');
356
+ }
357
+ catch { /* skip */ }
358
+ return null;
359
+ }
360
+ function readMdFilesInDir(dirPath) {
361
+ if (!existsSync(dirPath))
362
+ return [];
363
+ try {
364
+ return readdirSync(dirPath)
365
+ .filter(f => f.endsWith('.md'))
366
+ .map(name => {
367
+ const content = readFileSync(join(dirPath, name), 'utf-8');
368
+ return { name, content };
369
+ });
370
+ }
371
+ catch {
372
+ return [];
373
+ }
374
+ }
375
+ export function parsePlanDirectory(workingDir) {
376
+ const planDir = resolvePmDir(workingDir);
377
+ if (!planDir)
378
+ return null;
379
+ // Parse project.md
380
+ const projectContent = readFileIfExists(join(planDir, 'project.md'));
381
+ const project = projectContent
382
+ ? parseProjectConfig(projectContent)
383
+ : { name: '', id: '', created: '', status: 'active', estimation: 'none', idPrefixes: {}, workflows: [], labels: [], teams: [] };
384
+ // Parse STATE.md
385
+ const stateContent = readFileIfExists(join(planDir, 'STATE.md'));
386
+ const state = stateContent
387
+ ? parseProjectState(stateContent)
388
+ : { project: '', currentSprint: null, activeMilestone: null, paused: false, lastSession: null, readyToWork: [], inProgress: [], blocked: [], recentlyCompleted: [], warnings: [] };
389
+ // Parse backlog issues
390
+ const issueFiles = readMdFilesInDir(join(planDir, 'backlog'));
391
+ const issues = issueFiles.map(f => parseIssue(f.content, `backlog/${f.name}`));
392
+ // Parse sprints
393
+ const sprintFiles = readMdFilesInDir(join(planDir, 'sprints'));
394
+ const sprints = sprintFiles.map(f => parseSprint(f.content, `sprints/${f.name}`));
395
+ // Parse milestones
396
+ const milestoneFiles = readMdFilesInDir(join(planDir, 'milestones'));
397
+ const milestones = milestoneFiles.map(f => parseMilestone(f.content, `milestones/${f.name}`));
398
+ return { project, state, issues, sprints, milestones };
399
+ }
400
+ export function parseSingleIssue(workingDir, issuePath) {
401
+ const pmDir = resolvePmDir(workingDir);
402
+ if (!pmDir)
403
+ return null;
404
+ const fullPath = join(pmDir, issuePath);
405
+ const content = readFileIfExists(fullPath);
406
+ if (!content)
407
+ return null;
408
+ return parseIssue(content, issuePath);
409
+ }
410
+ export function parseSingleSprint(workingDir, sprintPath) {
411
+ const pmDir = resolvePmDir(workingDir);
412
+ if (!pmDir)
413
+ return null;
414
+ const fullPath = join(pmDir, sprintPath);
415
+ const content = readFileIfExists(fullPath);
416
+ if (!content)
417
+ return null;
418
+ return parseSprint(content, sprintPath);
419
+ }
420
+ export function parseSingleMilestone(workingDir, milestonePath) {
421
+ const pmDir = resolvePmDir(workingDir);
422
+ if (!pmDir)
423
+ return null;
424
+ const fullPath = join(pmDir, milestonePath);
425
+ const content = readFileIfExists(fullPath);
426
+ if (!content)
427
+ return null;
428
+ return parseMilestone(content, milestonePath);
429
+ }
430
+ /** Compute the next available ID for a given prefix (e.g., "IS" → "IS-004") */
431
+ export function getNextId(issues, prefix) {
432
+ const escaped = prefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
433
+ const pattern = new RegExp(`^${escaped}-(\\d+)$`);
434
+ let max = 0;
435
+ for (const issue of issues) {
436
+ const match = issue.id.match(pattern);
437
+ if (match) {
438
+ const num = Number.parseInt(match[1], 10);
439
+ if (num > max)
440
+ max = num;
441
+ }
442
+ }
443
+ return `${prefix}-${String(max + 1).padStart(3, '0')}`;
444
+ }
445
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../../../server/services/plan/parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function reconcileState(workingDir: string): void;
2
+ //# sourceMappingURL=state-reconciler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-reconciler.d.ts","sourceRoot":"","sources":["../../../../server/services/plan/state-reconciler.ts"],"names":[],"mappings":"AAoJA,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAyBvD"}
@@ -0,0 +1,145 @@
1
+ // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file for details.
3
+ /**
4
+ * State Reconciler — Recomputes STATE.md from individual issue files.
5
+ *
6
+ * When individual issues change (detected by watcher), this module
7
+ * scans all backlog files and rebuilds the STATE.md sections.
8
+ */
9
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
10
+ import { join } from 'node:path';
11
+ import { resolveReadyToWork } from './dependency-resolver.js';
12
+ import { parsePlanDirectory, resolvePmDir } from './parser.js';
13
+ function categorizeIssues(issues, issueByPath) {
14
+ const inProgress = [];
15
+ const blocked = [];
16
+ const recentlyCompleted = [];
17
+ const readyToWork = resolveReadyToWork(issues);
18
+ for (const issue of issues) {
19
+ if (issue.type === 'epic')
20
+ continue;
21
+ if (issue.status === 'in_progress' || issue.status === 'in_review') {
22
+ inProgress.push(issue);
23
+ }
24
+ else if (issue.blockedBy.length > 0 && issue.status !== 'done' && issue.status !== 'cancelled') {
25
+ const allBlockersDone = issue.blockedBy.every(bp => {
26
+ const blocker = issueByPath.get(bp);
27
+ return blocker && (blocker.status === 'done' || blocker.status === 'cancelled');
28
+ });
29
+ if (!allBlockersDone) {
30
+ blocked.push(issue);
31
+ }
32
+ }
33
+ if (issue.status === 'done') {
34
+ recentlyCompleted.push(issue);
35
+ }
36
+ }
37
+ return { inProgress, blocked, recentlyCompleted, readyToWork };
38
+ }
39
+ function computeWarnings(issues) {
40
+ const warnings = [];
41
+ const today = new Date().toISOString().split('T')[0];
42
+ for (const issue of issues) {
43
+ if (issue.due && issue.due <= today && issue.status !== 'done' && issue.status !== 'cancelled') {
44
+ const daysOverdue = Math.ceil((Date.now() - new Date(issue.due).getTime()) / (1000 * 60 * 60 * 24));
45
+ warnings.push(`${issue.id} due date was ${issue.due} (${daysOverdue} day${daysOverdue !== 1 ? 's' : ''} overdue)`);
46
+ }
47
+ }
48
+ return warnings;
49
+ }
50
+ function buildStateMarkdown(frontMatter, categories, warnings, issueByPath) {
51
+ const formatSummary = (issue, index) => {
52
+ return `${index + 1}. [${issue.id}](${issue.path}) — ${issue.title} (${issue.priority})`;
53
+ };
54
+ const formatBlocked = (issue) => {
55
+ const blockerIds = issue.blockedBy.map(bp => {
56
+ const blocker = issueByPath.get(bp);
57
+ return blocker ? `[${blocker.id}](${blocker.path})` : bp;
58
+ }).join(', ');
59
+ return `- [${issue.id}](${issue.path}) — ${issue.title} → blocked by ${blockerIds}`;
60
+ };
61
+ const sections = [
62
+ '# Project State',
63
+ '',
64
+ '## Current Focus',
65
+ '',
66
+ '## Ready to Work',
67
+ ...categories.readyToWork.map(formatSummary),
68
+ '',
69
+ '## In Progress',
70
+ ...categories.inProgress.map(issue => `- [${issue.id}](${issue.path}) — ${issue.title}`),
71
+ '',
72
+ '## Blocked',
73
+ ...categories.blocked.map(formatBlocked),
74
+ '',
75
+ '## Recently Completed',
76
+ ...categories.recentlyCompleted.slice(0, 10).map(issue => `- [${issue.id}](${issue.path}) — ${issue.title} ✓`),
77
+ '',
78
+ '## Warnings',
79
+ ...warnings.map(w => `- ${w}`),
80
+ '',
81
+ ];
82
+ return `---\n${frontMatter}\n---\n\n${sections.join('\n')}`;
83
+ }
84
+ /**
85
+ * Derive sprint status from its issues' actual statuses.
86
+ * - All issues done/cancelled → completed
87
+ * - Any issue in_progress/in_review → active
88
+ * - Otherwise → planned (unchanged)
89
+ */
90
+ function deriveSprintStatus(sprint, issueByPath) {
91
+ // Sprint references issues by path (e.g., "backlog/IS-001.md")
92
+ const issuePaths = sprint.issues.map(si => si.path);
93
+ if (issuePaths.length === 0)
94
+ return null;
95
+ const statuses = issuePaths.map(p => issueByPath.get(p)?.status).filter(Boolean);
96
+ if (statuses.length === 0)
97
+ return null;
98
+ const allFinished = statuses.every(s => s === 'done' || s === 'cancelled');
99
+ if (allFinished)
100
+ return 'completed';
101
+ const anyStarted = statuses.some(s => s === 'in_progress' || s === 'in_review');
102
+ if (anyStarted)
103
+ return 'active';
104
+ return null;
105
+ }
106
+ function reconcileSprintStatuses(pmDir, sprints, issueByPath) {
107
+ for (const sprint of sprints) {
108
+ const derived = deriveSprintStatus(sprint, issueByPath);
109
+ if (!derived || derived === sprint.status)
110
+ continue;
111
+ const sprintPath = join(pmDir, sprint.path);
112
+ try {
113
+ let content = readFileSync(sprintPath, 'utf-8');
114
+ content = content.replace(/^(status:\s*).+$/m, `$1${derived}`);
115
+ writeFileSync(sprintPath, content, 'utf-8');
116
+ }
117
+ catch {
118
+ // Sprint file may be missing or unwritable
119
+ }
120
+ }
121
+ }
122
+ export function reconcileState(workingDir) {
123
+ const pmDir = resolvePmDir(workingDir);
124
+ if (!pmDir)
125
+ return;
126
+ const statePath = join(pmDir, 'STATE.md');
127
+ if (!existsSync(statePath))
128
+ return;
129
+ const fullState = parsePlanDirectory(workingDir);
130
+ if (!fullState)
131
+ return;
132
+ const { issues, sprints, project } = fullState;
133
+ const issueByPath = new Map(issues.map(i => [i.path, i]));
134
+ const categories = categorizeIssues(issues, issueByPath);
135
+ const warnings = computeWarnings(issues);
136
+ // Read existing front matter
137
+ const content = readFileSync(statePath, 'utf-8');
138
+ const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
139
+ const frontMatter = fmMatch ? fmMatch[1] : `project: "${project.name}"\ncurrent_sprint: null\nactive_milestone: null\npaused: false\nlast_session: null`;
140
+ const newContent = buildStateMarkdown(frontMatter, categories, warnings, issueByPath);
141
+ writeFileSync(statePath, newContent, 'utf-8');
142
+ // Reconcile sprint statuses from actual issue statuses
143
+ reconcileSprintStatuses(pmDir, sprints, issueByPath);
144
+ }
145
+ //# sourceMappingURL=state-reconciler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-reconciler.js","sourceRoot":"","sources":["../../../../server/services/plan/state-reconciler.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,gEAAgE;AAEhE;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAU/D,SAAS,gBAAgB,CAAC,MAAe,EAAE,WAA+B;IACxE,MAAM,UAAU,GAAY,EAAE,CAAC;IAC/B,MAAM,OAAO,GAAY,EAAE,CAAC;IAC5B,MAAM,iBAAiB,GAAY,EAAE,CAAC;IACtC,MAAM,WAAW,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAE/C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;YAAE,SAAS;QAEpC,IAAI,KAAK,CAAC,MAAM,KAAK,aAAa,IAAI,KAAK,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YACnE,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;aAAM,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,IAAI,KAAK,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YACjG,MAAM,eAAe,GAAG,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;gBACjD,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACpC,OAAO,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,MAAM,IAAI,OAAO,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC;YAClF,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,eAAe,EAAE,CAAC;gBACrB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC5B,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,CAAC;AACjE,CAAC;AAED,SAAS,eAAe,CAAC,MAAe;IACtC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAErD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC,GAAG,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,IAAI,KAAK,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YAC/F,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;YACpG,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,EAAE,iBAAiB,KAAK,CAAC,GAAG,KAAK,WAAW,OAAO,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;QACrH,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,kBAAkB,CACzB,WAAmB,EACnB,UAA6B,EAC7B,QAAkB,EAClB,WAA+B;IAE/B,MAAM,aAAa,GAAG,CAAC,KAAY,EAAE,KAAa,EAAU,EAAE;QAC5D,OAAO,GAAG,KAAK,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,KAAK,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,QAAQ,GAAG,CAAC;IAC3F,CAAC,CAAC;IAEF,MAAM,aAAa,GAAG,CAAC,KAAY,EAAU,EAAE;QAC7C,MAAM,UAAU,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;YAC1C,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACpC,OAAO,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,EAAE,KAAK,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3D,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,OAAO,MAAM,KAAK,CAAC,EAAE,KAAK,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,KAAK,iBAAiB,UAAU,EAAE,CAAC;IACtF,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG;QACf,iBAAiB;QACjB,EAAE;QACF,kBAAkB;QAClB,EAAE;QACF,kBAAkB;QAClB,GAAG,UAAU,CAAC,WAAW,CAAC,GAAG,CAAC,aAAa,CAAC;QAC5C,EAAE;QACF,gBAAgB;QAChB,GAAG,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,KAAK,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,KAAK,EAAE,CAAC;QACxF,EAAE;QACF,YAAY;QACZ,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;QACxC,EAAE;QACF,uBAAuB;QACvB,GAAG,UAAU,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,KAAK,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,KAAK,IAAI,CAAC;QAC9G,EAAE;QACF,aAAa;QACb,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,EAAE;KACH,CAAC;IAEF,OAAO,QAAQ,WAAW,YAAY,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AAC9D,CAAC;AAED;;;;;GAKG;AACH,SAAS,kBAAkB,CAAC,MAAc,EAAE,WAA+B;IACzE,+DAA+D;IAC/D,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;IACpD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEzC,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAa,CAAC;IAC7F,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEvC,MAAM,WAAW,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,WAAW,CAAC,CAAC;IAC3E,IAAI,WAAW;QAAE,OAAO,WAAW,CAAC;IAEpC,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,aAAa,IAAI,CAAC,KAAK,WAAW,CAAC,CAAC;IAChF,IAAI,UAAU;QAAE,OAAO,QAAQ,CAAC;IAEhC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,uBAAuB,CAAC,KAAa,EAAE,OAAiB,EAAE,WAA+B;IAChG,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,kBAAkB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QACxD,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,MAAM,CAAC,MAAM;YAAE,SAAS;QAEpD,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,CAAC;YACH,IAAI,OAAO,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAChD,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,mBAAmB,EAAE,KAAK,OAAO,EAAE,CAAC,CAAC;YAC/D,aAAa,CAAC,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAC9C,CAAC;QAAC,MAAM,CAAC;YACP,2CAA2C;QAC7C,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,UAAkB;IAC/C,MAAM,KAAK,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;IACvC,IAAI,CAAC,KAAK;QAAE,OAAO;IACnB,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IAC1C,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO;IAEnC,MAAM,SAAS,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;IACjD,IAAI,CAAC,SAAS;QAAE,OAAO;IAEvB,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,SAAS,CAAC;IAE/C,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1D,MAAM,UAAU,GAAG,gBAAgB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACzD,MAAM,QAAQ,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAEzC,6BAA6B;IAC7B,MAAM,OAAO,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;IACvD,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,OAAO,CAAC,IAAI,oFAAoF,CAAC;IAEzJ,MAAM,UAAU,GAAG,kBAAkB,CAAC,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;IACtF,aAAa,CAAC,SAAS,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;IAE9C,uDAAuD;IACvD,uBAAuB,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;AACvD,CAAC"}