@slope-dev/slope 1.16.0 → 1.19.1
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.
- package/dist/cli/commands/loop.js +2 -2
- package/dist/cli/commands/loop.js.map +1 -1
- package/dist/cli/commands/review-state.d.ts.map +1 -1
- package/dist/cli/commands/review-state.js +6 -45
- package/dist/cli/commands/review-state.js.map +1 -1
- package/dist/cli/guards/plan-analysis.d.ts +34 -0
- package/dist/cli/guards/plan-analysis.d.ts.map +1 -0
- package/dist/cli/guards/plan-analysis.js +102 -0
- package/dist/cli/guards/plan-analysis.js.map +1 -0
- package/dist/cli/guards/pr-review.d.ts.map +1 -1
- package/dist/cli/guards/pr-review.js +7 -0
- package/dist/cli/guards/pr-review.js.map +1 -1
- package/dist/cli/guards/review-tier.d.ts +4 -2
- package/dist/cli/guards/review-tier.d.ts.map +1 -1
- package/dist/cli/guards/review-tier.js +93 -60
- package/dist/cli/guards/review-tier.js.map +1 -1
- package/dist/cli/loop/continuous.d.ts.map +1 -1
- package/dist/cli/loop/continuous.js +36 -0
- package/dist/cli/loop/continuous.js.map +1 -1
- package/dist/cli/loop/executor.d.ts +3 -1
- package/dist/cli/loop/executor.d.ts.map +1 -1
- package/dist/cli/loop/executor.js +112 -67
- package/dist/cli/loop/executor.js.map +1 -1
- package/dist/cli/loop/guard-runner.d.ts +19 -3
- package/dist/cli/loop/guard-runner.d.ts.map +1 -1
- package/dist/cli/loop/guard-runner.js +108 -1
- package/dist/cli/loop/guard-runner.js.map +1 -1
- package/dist/cli/loop/model-selector.d.ts +6 -5
- package/dist/cli/loop/model-selector.d.ts.map +1 -1
- package/dist/cli/loop/model-selector.js +11 -6
- package/dist/cli/loop/model-selector.js.map +1 -1
- package/dist/cli/loop/planner.d.ts +21 -0
- package/dist/cli/loop/planner.d.ts.map +1 -0
- package/dist/cli/loop/planner.js +298 -0
- package/dist/cli/loop/planner.js.map +1 -0
- package/dist/cli/loop/pr-lifecycle.d.ts +6 -4
- package/dist/cli/loop/pr-lifecycle.d.ts.map +1 -1
- package/dist/cli/loop/pr-lifecycle.js +19 -17
- package/dist/cli/loop/pr-lifecycle.js.map +1 -1
- package/dist/cli/loop/staging.d.ts +19 -0
- package/dist/cli/loop/staging.d.ts.map +1 -0
- package/dist/cli/loop/staging.js +125 -0
- package/dist/cli/loop/staging.js.map +1 -0
- package/dist/cli/loop/types.d.ts +31 -1
- package/dist/cli/loop/types.d.ts.map +1 -1
- package/dist/cli/loop/worktree.d.ts +1 -1
- package/dist/cli/loop/worktree.d.ts.map +1 -1
- package/dist/cli/loop/worktree.js +53 -3
- package/dist/cli/loop/worktree.js.map +1 -1
- package/dist/core/guard.js +4 -4
- package/dist/core/guard.js.map +1 -1
- package/dist/mcp/index.test.js +30 -15
- package/dist/mcp/index.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,20 +1,44 @@
|
|
|
1
|
-
import { existsSync, readFileSync
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
+
import { selectSpecialists } from '../../core/index.js';
|
|
4
|
+
import { loadConfig } from '../config.js';
|
|
5
|
+
import { findPlanContent, countTickets, countPackageRefs, extractFilePatterns, extractTicketInfo, } from './plan-analysis.js';
|
|
3
6
|
/**
|
|
4
|
-
* Review-tier guard: fires
|
|
5
|
-
*
|
|
7
|
+
* Review-tier guard: fires PostToolUse on Write.
|
|
8
|
+
* When a plan file is written to .claude/plans/*.md, recommends review tier
|
|
9
|
+
* with specialist reviewers, surfaces relevant gotchas, and instructs
|
|
10
|
+
* Claude to use AskUserQuestion for review setup.
|
|
6
11
|
*/
|
|
7
12
|
export async function reviewTierGuard(input, cwd) {
|
|
8
|
-
//
|
|
9
|
-
const
|
|
10
|
-
if (!
|
|
13
|
+
// Only fire when a plan file is written
|
|
14
|
+
const filePath = input.tool_input?.file_path;
|
|
15
|
+
if (!filePath)
|
|
16
|
+
return {};
|
|
17
|
+
// Check if the written file is a plan file
|
|
18
|
+
const normalizedPath = filePath.replace(/\\/g, '/');
|
|
19
|
+
if (!normalizedPath.includes('.claude/plans/') || !normalizedPath.endsWith('.md')) {
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
// Read the plan content — prefer the just-written file path directly,
|
|
23
|
+
// since findPlanContent(cwd) only searches repo-local .claude/plans/ and
|
|
24
|
+
// Claude Code writes plans to ~/.claude/plans/ (global user directory).
|
|
25
|
+
let plan = null;
|
|
26
|
+
try {
|
|
27
|
+
const content = readFileSync(filePath, 'utf8');
|
|
28
|
+
plan = { path: normalizedPath, content };
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// File not readable — fall back to directory scan
|
|
32
|
+
plan = findPlanContent(cwd);
|
|
33
|
+
}
|
|
34
|
+
if (!plan)
|
|
11
35
|
return {};
|
|
12
36
|
// Analyze the plan
|
|
13
|
-
const ticketCount = countTickets(
|
|
14
|
-
const packageRefs = countPackageRefs(
|
|
15
|
-
const hasSchemaOrApi = /\b(schema|migration|api|endpoint)\b/i.test(
|
|
16
|
-
const hasInfra = /\b(infrastructure|new package|new service|architect)\b/i.test(
|
|
17
|
-
const isResearchOrDocs = /^#+\s*(research|docs|documentation|infra|spike)\b/im.test(
|
|
37
|
+
const ticketCount = countTickets(plan.content);
|
|
38
|
+
const packageRefs = countPackageRefs(plan.content);
|
|
39
|
+
const hasSchemaOrApi = /\b(schema|migration|api|endpoint)\b/i.test(plan.content);
|
|
40
|
+
const hasInfra = /\b(infrastructure|new package|new service|architect)\b/i.test(plan.content);
|
|
41
|
+
const isResearchOrDocs = /^#+\s*(research|docs|documentation|infra|spike)\b/im.test(plan.content)
|
|
18
42
|
&& ticketCount === 0;
|
|
19
43
|
// Determine recommended tier
|
|
20
44
|
let tier;
|
|
@@ -32,77 +56,86 @@ export async function reviewTierGuard(input, cwd) {
|
|
|
32
56
|
rounds = 3;
|
|
33
57
|
}
|
|
34
58
|
else {
|
|
35
|
-
// 3-4 tickets, or multi-package, or schema/API changes
|
|
36
59
|
tier = 'Standard';
|
|
37
60
|
rounds = 2;
|
|
38
61
|
}
|
|
39
|
-
// Check if review-state.json already
|
|
62
|
+
// Check if review-state.json already meets/exceeds tier
|
|
40
63
|
const statePath = join(cwd, '.slope', 'review-state.json');
|
|
41
64
|
if (existsSync(statePath)) {
|
|
42
65
|
try {
|
|
43
66
|
const state = JSON.parse(readFileSync(statePath, 'utf8'));
|
|
44
67
|
if (state.rounds_required >= rounds) {
|
|
45
|
-
// Already set to at least the recommended level — silent passthrough
|
|
46
68
|
return {};
|
|
47
69
|
}
|
|
48
70
|
}
|
|
49
|
-
catch { /* malformed — proceed
|
|
71
|
+
catch { /* malformed — proceed */ }
|
|
50
72
|
}
|
|
51
|
-
// Build
|
|
73
|
+
// Build scope description
|
|
52
74
|
const scopeDesc = [
|
|
53
75
|
`${ticketCount} ticket${ticketCount !== 1 ? 's' : ''}`,
|
|
54
76
|
packageRefs > 1 ? `${packageRefs} packages` : null,
|
|
55
77
|
hasSchemaOrApi ? 'schema/API changes' : null,
|
|
56
78
|
hasInfra ? 'new infrastructure' : null,
|
|
57
79
|
].filter(Boolean).join(', ');
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
80
|
+
// Select specialists from ticket info
|
|
81
|
+
const ticketInfo = extractTicketInfo(plan.content);
|
|
82
|
+
const specialists = selectSpecialists(ticketInfo);
|
|
83
|
+
const specialistList = specialists.length > 0 ? specialists.join(', ') : 'none detected';
|
|
84
|
+
// Load relevant gotchas (capped at 5)
|
|
85
|
+
const gotchas = loadRelevantGotchas(cwd, plan.content);
|
|
86
|
+
// Build context
|
|
87
|
+
const lines = [
|
|
88
|
+
`SLOPE plan-review: Plan detected with ${ticketCount} tickets, ${scopeDesc}.`,
|
|
89
|
+
`Recommended tier: ${tier} (${rounds} round${rounds !== 1 ? 's' : ''}).`,
|
|
90
|
+
`Recommended reviewers: architect + ${specialistList}.`,
|
|
91
|
+
];
|
|
92
|
+
if (gotchas.length > 0) {
|
|
93
|
+
lines.push('');
|
|
94
|
+
lines.push('Relevant gotchas from past sprints:');
|
|
95
|
+
for (const g of gotchas) {
|
|
96
|
+
lines.push(` - ${g}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
lines.push('');
|
|
100
|
+
lines.push('IMPORTANT: You MUST now ask the user how they want to handle the plan review using AskUserQuestion.');
|
|
101
|
+
lines.push('Present these options:');
|
|
102
|
+
lines.push(`1. Architect + ${specialistList} review (Recommended)`);
|
|
103
|
+
lines.push('2. Architect review only');
|
|
104
|
+
lines.push('3. Custom reviewers — user specifies');
|
|
105
|
+
lines.push('4. Skip review');
|
|
106
|
+
return { context: lines.join('\n') };
|
|
61
107
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (
|
|
83
|
-
|
|
108
|
+
/**
|
|
109
|
+
* Load gotchas from common-issues.json that are relevant to plan file patterns.
|
|
110
|
+
* Returns at most 5 entries.
|
|
111
|
+
*/
|
|
112
|
+
function loadRelevantGotchas(cwd, planContent) {
|
|
113
|
+
try {
|
|
114
|
+
const config = loadConfig(cwd);
|
|
115
|
+
const issuesPath = join(cwd, config.commonIssuesPath);
|
|
116
|
+
if (!existsSync(issuesPath))
|
|
117
|
+
return [];
|
|
118
|
+
const issues = JSON.parse(readFileSync(issuesPath, 'utf8'));
|
|
119
|
+
const filePatterns = extractFilePatterns(planContent);
|
|
120
|
+
const warnings = [];
|
|
121
|
+
for (const pattern of issues.recurring_patterns) {
|
|
122
|
+
const text = `${pattern.title} ${pattern.description} ${pattern.prevention}`.toLowerCase();
|
|
123
|
+
// Check if any plan file pattern segments match the issue
|
|
124
|
+
const isRelevant = filePatterns.some(fp => {
|
|
125
|
+
const segments = fp.toLowerCase().split('/').filter(Boolean);
|
|
126
|
+
return segments.some(seg => text.includes(seg));
|
|
127
|
+
});
|
|
128
|
+
if (isRelevant) {
|
|
129
|
+
const lastSprint = Math.max(...pattern.sprints_hit);
|
|
130
|
+
warnings.push(`[${pattern.category}] ${pattern.title} (last: S${lastSprint}) — ${pattern.prevention.slice(0, 100)}`);
|
|
84
131
|
}
|
|
132
|
+
if (warnings.length >= 5)
|
|
133
|
+
break;
|
|
85
134
|
}
|
|
86
|
-
|
|
135
|
+
return warnings;
|
|
87
136
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
function countTickets(content) {
|
|
91
|
-
// Match ticket patterns: ### S\d+-\d+, ### Ticket, numbered ticket headers
|
|
92
|
-
const ticketHeaders = content.match(/^###\s+S\d+-\d+/gm) ?? [];
|
|
93
|
-
if (ticketHeaders.length > 0)
|
|
94
|
-
return ticketHeaders.length;
|
|
95
|
-
// Fallback: count ### level headers that look like tickets
|
|
96
|
-
const h3Headers = content.match(/^###\s+/gm) ?? [];
|
|
97
|
-
return h3Headers.length;
|
|
98
|
-
}
|
|
99
|
-
function countPackageRefs(content) {
|
|
100
|
-
// Count distinct packages/ references
|
|
101
|
-
const refs = new Set();
|
|
102
|
-
const matches = content.matchAll(/packages\/(\w[\w-]*)/g);
|
|
103
|
-
for (const m of matches) {
|
|
104
|
-
refs.add(m[1]);
|
|
137
|
+
catch {
|
|
138
|
+
return [];
|
|
105
139
|
}
|
|
106
|
-
return refs.size;
|
|
107
140
|
}
|
|
108
141
|
//# sourceMappingURL=review-tier.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review-tier.js","sourceRoot":"","sources":["../../../src/cli/guards/review-tier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"review-tier.js","sourceRoot":"","sources":["../../../src/cli/guards/review-tier.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"continuous.d.ts","sourceRoot":"","sources":["../../../src/cli/loop/continuous.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"continuous.d.ts","sourceRoot":"","sources":["../../../src/cli/loop/continuous.ts"],"names":[],"mappings":"AAYA;;;GAGG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiH7F"}
|
|
@@ -4,6 +4,8 @@ import { execSync } from 'node:child_process';
|
|
|
4
4
|
import { resolveLoopConfig } from './config.js';
|
|
5
5
|
import { loadBacklog, getRemainingSprintIds } from './backlog.js';
|
|
6
6
|
import { runSprint, isShuttingDown } from './executor.js';
|
|
7
|
+
import { initStagingBranch, createUmbrellaPr, cleanupStagingBranch } from './staging.js';
|
|
8
|
+
import { checkGhCli } from './pr-lifecycle.js';
|
|
7
9
|
import { createLogger } from './logger.js';
|
|
8
10
|
/**
|
|
9
11
|
* Multi-sprint continuous loop with backlog auto-regeneration.
|
|
@@ -14,16 +16,33 @@ export async function runContinuous(flags, cwd) {
|
|
|
14
16
|
const maxSprints = parseInt(flags.max ?? '10', 10);
|
|
15
17
|
const pauseSeconds = parseInt(flags.pause ?? '30', 10);
|
|
16
18
|
const dryRun = flags['dry-run'] === 'true';
|
|
19
|
+
const useStaging = flags.staging === 'true';
|
|
17
20
|
mkdirSync(join(cwd, config.resultsDir), { recursive: true });
|
|
18
21
|
mkdirSync(join(cwd, config.logDir), { recursive: true });
|
|
19
22
|
const log = createLogger('loop:continuous', join(cwd, config.logDir, 'continuous.log'));
|
|
20
23
|
log.info('=== Continuous Loop Starting ===');
|
|
21
24
|
log.info(`Max sprints: ${maxSprints}`);
|
|
22
25
|
log.info(`Pause between sprints: ${pauseSeconds}s`);
|
|
26
|
+
if (useStaging)
|
|
27
|
+
log.info('Staging branch mode enabled');
|
|
23
28
|
if (dryRun)
|
|
24
29
|
log.info('DRY RUN mode');
|
|
30
|
+
// Initialize staging branch if requested
|
|
31
|
+
let stagingBranch = '';
|
|
32
|
+
if (useStaging && !dryRun) {
|
|
33
|
+
// Peek at backlog to get first sprint ID for branch naming
|
|
34
|
+
const peekBacklog = loadBacklogSafe(cwd, config, log);
|
|
35
|
+
const peekRemaining = peekBacklog ? getRemainingSprintIds(peekBacklog, cwd, config) : [];
|
|
36
|
+
if (peekRemaining.length > 0) {
|
|
37
|
+
stagingBranch = initStagingBranch(peekRemaining[0], cwd, log);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
log.warn('No sprints in backlog — skipping staging branch');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
25
43
|
let completed = 0;
|
|
26
44
|
let failures = 0;
|
|
45
|
+
const collectedResults = [];
|
|
27
46
|
while (completed < maxSprints) {
|
|
28
47
|
if (isShuttingDown()) {
|
|
29
48
|
log.warn('Shutdown requested — stopping loop');
|
|
@@ -51,9 +70,12 @@ export async function runContinuous(flags, cwd) {
|
|
|
51
70
|
const runFlags = { sprint: nextSprint };
|
|
52
71
|
if (dryRun)
|
|
53
72
|
runFlags['dry-run'] = 'true';
|
|
73
|
+
if (stagingBranch)
|
|
74
|
+
runFlags.stagingBranch = stagingBranch;
|
|
54
75
|
const result = await runSprint(runFlags, cwd);
|
|
55
76
|
if (result) {
|
|
56
77
|
log.info(`Sprint ${nextSprint} completed successfully`);
|
|
78
|
+
collectedResults.push(result);
|
|
57
79
|
failures = 0;
|
|
58
80
|
}
|
|
59
81
|
else {
|
|
@@ -76,9 +98,23 @@ export async function runContinuous(flags, cwd) {
|
|
|
76
98
|
await sleep(pauseSeconds * 1000);
|
|
77
99
|
}
|
|
78
100
|
}
|
|
101
|
+
// Create umbrella PR if staging mode was used (requires manual review and merge)
|
|
102
|
+
if (stagingBranch && collectedResults.length > 0 && checkGhCli(log)) {
|
|
103
|
+
log.info('Creating umbrella PR for staging branch...');
|
|
104
|
+
const umbrella = createUmbrellaPr(stagingBranch, collectedResults, cwd, log);
|
|
105
|
+
if (umbrella) {
|
|
106
|
+
log.info(`Umbrella PR: ${umbrella.url} (requires manual review)`);
|
|
107
|
+
}
|
|
108
|
+
// Cleanup staging branch if umbrella PR was created — safe delete refuses if unmerged
|
|
109
|
+
cleanupStagingBranch(stagingBranch, cwd, log);
|
|
110
|
+
}
|
|
79
111
|
log.info('=== Continuous Loop Complete ===');
|
|
80
112
|
log.info(`Sprints attempted: ${completed}`);
|
|
81
113
|
log.info(`Failures: ${failures}`);
|
|
114
|
+
if (stagingBranch) {
|
|
115
|
+
log.info(`Staging branch: ${stagingBranch}`);
|
|
116
|
+
log.info(`Sprint results collected: ${collectedResults.length}`);
|
|
117
|
+
}
|
|
82
118
|
}
|
|
83
119
|
function loadBacklogSafe(cwd, config, log) {
|
|
84
120
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"continuous.js","sourceRoot":"","sources":["../../../src/cli/loop/continuous.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAA6B,EAAE,GAAW;IAC5E,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC;IACnD,MAAM,YAAY,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC;IACvD,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,KAAK,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"continuous.js","sourceRoot":"","sources":["../../../src/cli/loop/continuous.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import type { SprintResult } from './types.js';
|
|
1
|
+
import type { LoopConfig, BacklogTicket, SprintResult } from './types.js';
|
|
2
2
|
export declare function isShuttingDown(): boolean;
|
|
3
3
|
/**
|
|
4
4
|
* Run a single sprint end-to-end.
|
|
5
5
|
* Main entry point for `slope loop run`.
|
|
6
6
|
*/
|
|
7
7
|
export declare function runSprint(flags: Record<string, string>, cwd: string): Promise<SprintResult | null>;
|
|
8
|
+
export declare function buildPrompt(ticket: BacklogTicket, model: string): string;
|
|
9
|
+
export declare function saveResult(result: SprintResult, cwd: string, config: LoopConfig): void;
|
|
8
10
|
//# sourceMappingURL=executor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../src/cli/loop/executor.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../src/cli/loop/executor.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,UAAU,EAAiB,aAAa,EAAgB,YAAY,EAAE,MAAM,YAAY,CAAC;AAWvG,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAwMxG;AAsRD,wBAAgB,WAAW,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAoExE;AAsBD,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAOtF"}
|