tryassay 0.22.0 → 0.22.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/demo/css/style.css +495 -836
- package/demo/index.html +40 -184
- package/demo/js/chat.js +385 -142
- package/demo/js/preview.js +456 -0
- package/demo/js/sse-client.js +262 -135
- package/demo/js/state.js +11 -1
- package/demo/js/timeline.js +57 -371
- package/dist/api/server.d.ts +2 -0
- package/dist/api/server.js +63 -19
- package/dist/api/server.js.map +1 -1
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/assess.d.ts +2 -0
- package/dist/commands/assess.js +132 -164
- package/dist/commands/assess.js.map +1 -1
- package/dist/commands/demo.js +259 -9
- package/dist/commands/demo.js.map +1 -1
- package/dist/lib/__tests__/arithmetic-quick-test.d.ts +6 -0
- package/dist/lib/__tests__/arithmetic-quick-test.js +197 -0
- package/dist/lib/__tests__/arithmetic-quick-test.js.map +1 -0
- package/dist/lib/__tests__/arithmetic-real-llm-test.d.ts +13 -0
- package/dist/lib/__tests__/arithmetic-real-llm-test.js +284 -0
- package/dist/lib/__tests__/arithmetic-real-llm-test.js.map +1 -0
- package/dist/lib/__tests__/arithmetic-value-demo.d.ts +10 -0
- package/dist/lib/__tests__/arithmetic-value-demo.js +193 -0
- package/dist/lib/__tests__/arithmetic-value-demo.js.map +1 -0
- package/dist/lib/__tests__/flow-to-claims.test.d.ts +1 -0
- package/dist/lib/__tests__/flow-to-claims.test.js +91 -0
- package/dist/lib/__tests__/flow-to-claims.test.js.map +1 -0
- package/dist/lib/__tests__/formal-verifier-api-misuse.test.d.ts +9 -0
- package/dist/lib/__tests__/formal-verifier-api-misuse.test.js +391 -0
- package/dist/lib/__tests__/formal-verifier-api-misuse.test.js.map +1 -0
- package/dist/lib/__tests__/formal-verifier-arithmetic.test.d.ts +7 -0
- package/dist/lib/__tests__/formal-verifier-arithmetic.test.js +318 -0
- package/dist/lib/__tests__/formal-verifier-arithmetic.test.js.map +1 -0
- package/dist/lib/__tests__/intent-extractor.test.d.ts +1 -0
- package/dist/lib/__tests__/intent-extractor.test.js +97 -0
- package/dist/lib/__tests__/intent-extractor.test.js.map +1 -0
- package/dist/lib/__tests__/intent-reviewer.test.d.ts +1 -0
- package/dist/lib/__tests__/intent-reviewer.test.js +55 -0
- package/dist/lib/__tests__/intent-reviewer.test.js.map +1 -0
- package/dist/lib/__tests__/mr-gsm8k-benchmark.d.ts +11 -0
- package/dist/lib/__tests__/mr-gsm8k-benchmark.js +224 -0
- package/dist/lib/__tests__/mr-gsm8k-benchmark.js.map +1 -0
- package/dist/lib/anthropic.js +25 -33
- package/dist/lib/anthropic.js.map +1 -1
- package/dist/lib/assessment-reporter.js +9 -13
- package/dist/lib/assessment-reporter.js.map +1 -1
- package/dist/lib/claim-extractor.js +10 -19
- package/dist/lib/claim-extractor.js.map +1 -1
- package/dist/lib/code-verifier.js +16 -36
- package/dist/lib/code-verifier.js.map +1 -1
- package/dist/lib/constraint-engine.js +10 -19
- package/dist/lib/constraint-engine.js.map +1 -1
- package/dist/lib/formal-verifier.d.ts +1 -1
- package/dist/lib/formal-verifier.js +454 -0
- package/dist/lib/formal-verifier.js.map +1 -1
- package/dist/lib/guided-generator.js +19 -37
- package/dist/lib/guided-generator.js.map +1 -1
- package/dist/lib/intent-extractor.d.ts +47 -0
- package/dist/lib/intent-extractor.js +427 -0
- package/dist/lib/intent-extractor.js.map +1 -0
- package/dist/lib/intent-reviewer.d.ts +14 -0
- package/dist/lib/intent-reviewer.js +148 -0
- package/dist/lib/intent-reviewer.js.map +1 -0
- package/dist/lib/intent-types.d.ts +89 -0
- package/dist/lib/intent-types.js +5 -0
- package/dist/lib/intent-types.js.map +1 -0
- package/dist/lib/inventory-extractor.js +9 -22
- package/dist/lib/inventory-extractor.js.map +1 -1
- package/dist/lib/llm-provider.d.ts +23 -0
- package/dist/lib/llm-provider.js +130 -0
- package/dist/lib/llm-provider.js.map +1 -0
- package/dist/lib/remediator.js +20 -28
- package/dist/lib/remediator.js.map +1 -1
- package/dist/lib/requirements-generator.js +14 -19
- package/dist/lib/requirements-generator.js.map +1 -1
- package/dist/lib/spec-synthesizer.js +10 -19
- package/dist/lib/spec-synthesizer.js.map +1 -1
- package/dist/runtime/app-create-orchestrator.d.ts +5 -1
- package/dist/runtime/app-create-orchestrator.js +114 -39
- package/dist/runtime/app-create-orchestrator.js.map +1 -1
- package/dist/runtime/check-catalog.js +5 -3
- package/dist/runtime/check-catalog.js.map +1 -1
- package/dist/runtime/check-definitions.d.ts +10 -0
- package/dist/runtime/check-definitions.js +52 -2
- package/dist/runtime/check-definitions.js.map +1 -1
- package/dist/runtime/composition-verifier.js +8 -12
- package/dist/runtime/composition-verifier.js.map +1 -1
- package/dist/runtime/gap-detector.js +8 -10
- package/dist/runtime/gap-detector.js.map +1 -1
- package/dist/runtime/input-validator.d.ts +7 -0
- package/dist/runtime/input-validator.js +162 -0
- package/dist/runtime/input-validator.js.map +1 -0
- package/dist/runtime/model-router.d.ts +10 -0
- package/dist/runtime/model-router.js +42 -0
- package/dist/runtime/model-router.js.map +1 -0
- package/dist/runtime/pattern-extractor.js +8 -10
- package/dist/runtime/pattern-extractor.js.map +1 -1
- package/dist/runtime/planner.js +11 -16
- package/dist/runtime/planner.js.map +1 -1
- package/dist/runtime/prompt-guard.d.ts +2 -0
- package/dist/runtime/prompt-guard.js +180 -0
- package/dist/runtime/prompt-guard.js.map +1 -0
- package/dist/runtime/prompt-safety-analyzer.js +8 -13
- package/dist/runtime/prompt-safety-analyzer.js.map +1 -1
- package/dist/runtime/reasoner.js +19 -33
- package/dist/runtime/reasoner.js.map +1 -1
- package/dist/runtime/rule-meta-verifier.js +9 -11
- package/dist/runtime/rule-meta-verifier.js.map +1 -1
- package/dist/runtime/safe-executor.d.ts +23 -0
- package/dist/runtime/safe-executor.js +151 -0
- package/dist/runtime/safe-executor.js.map +1 -0
- package/dist/runtime/specialized-agent.js +10 -14
- package/dist/runtime/specialized-agent.js.map +1 -1
- package/dist/runtime/strategy-library.js +8 -10
- package/dist/runtime/strategy-library.js.map +1 -1
- package/dist/runtime/supabase-experience-store.js.map +1 -1
- package/dist/runtime/supabase-provisioner.d.ts +35 -0
- package/dist/runtime/supabase-provisioner.js +192 -0
- package/dist/runtime/supabase-provisioner.js.map +1 -0
- package/dist/runtime/types.d.ts +88 -0
- package/dist/sdk/forward-verify.js +16 -33
- package/dist/sdk/forward-verify.js.map +1 -1
- package/package.json +1 -1
- package/demo/data/demo-events.json +0 -103
- package/demo/js/demo-mode.js +0 -107
- package/demo/js/orb.js +0 -634
- package/demo/js/question-cards.js +0 -207
- package/demo/js/voice.js +0 -154
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import { MODEL } from './anthropic.js';
|
|
2
|
+
import { getProvider } from './llm-provider.js';
|
|
3
|
+
import { readFileContent } from './codebase-indexer.js';
|
|
4
|
+
const VALID_GAP_TYPES = [
|
|
5
|
+
'missing-flow', 'dead-code', 'unguarded-route', 'orphaned-table', 'incomplete-flow',
|
|
6
|
+
];
|
|
7
|
+
const VALID_COMPLETENESS = ['full', 'partial', 'stub'];
|
|
8
|
+
const VALID_RELATIONSHIP_TYPES = ['one-to-one', 'one-to-many', 'many-to-many'];
|
|
9
|
+
const VALID_DATA_OPS = ['read', 'write', 'delete'];
|
|
10
|
+
// ── File selection ───────────────────────────────────────────────────
|
|
11
|
+
/** Patterns that indicate files important for intent extraction */
|
|
12
|
+
const INTENT_FILE_PATTERNS = [
|
|
13
|
+
// Routers and routes
|
|
14
|
+
/router/i, /routes/i, /App\.tsx$/, /App\.jsx$/, /app\.ts$/, /layout\.tsx$/,
|
|
15
|
+
/page\.tsx$/, /page\.jsx$/, /_app\.tsx$/,
|
|
16
|
+
// Entry points
|
|
17
|
+
/main\.ts$/, /index\.ts$/, /server\.ts$/,
|
|
18
|
+
// Middleware
|
|
19
|
+
/middleware/i,
|
|
20
|
+
];
|
|
21
|
+
/**
|
|
22
|
+
* Select files most relevant for intent extraction.
|
|
23
|
+
* Prioritizes routers, schemas, auth, middleware, entry points, and package.json.
|
|
24
|
+
* Broader than inventory-extractor's selection — we want the full picture.
|
|
25
|
+
*/
|
|
26
|
+
export function selectIntentFiles(index, maxFiles = 30) {
|
|
27
|
+
const selected = new Set();
|
|
28
|
+
// Key files from indexer (config, auth, API routes, schemas)
|
|
29
|
+
for (const kf of index.keyFiles) {
|
|
30
|
+
selected.add(kf.path);
|
|
31
|
+
}
|
|
32
|
+
// Pattern-matched files from file tree
|
|
33
|
+
for (const filePath of index.fileTree) {
|
|
34
|
+
if (INTENT_FILE_PATTERNS.some((p) => p.test(filePath))) {
|
|
35
|
+
selected.add(filePath);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// Always include package.json if present
|
|
39
|
+
if (index.fileTree.includes('package.json')) {
|
|
40
|
+
selected.add('package.json');
|
|
41
|
+
}
|
|
42
|
+
const result = Array.from(selected);
|
|
43
|
+
return result.length > maxFiles ? result.slice(0, maxFiles) : result;
|
|
44
|
+
}
|
|
45
|
+
// ── JSON parsing ─────────────────────────────────────────────────────
|
|
46
|
+
function stripCodeFences(text) {
|
|
47
|
+
let s = text.trim();
|
|
48
|
+
if (s.startsWith('```')) {
|
|
49
|
+
const nl = s.indexOf('\n');
|
|
50
|
+
if (nl !== -1)
|
|
51
|
+
s = s.slice(nl + 1);
|
|
52
|
+
}
|
|
53
|
+
const lastFence = s.lastIndexOf('```');
|
|
54
|
+
if (lastFence !== -1)
|
|
55
|
+
s = s.slice(0, lastFence);
|
|
56
|
+
return s.trim();
|
|
57
|
+
}
|
|
58
|
+
function closeUnclosedJson(text) {
|
|
59
|
+
if (text.endsWith('}'))
|
|
60
|
+
return text;
|
|
61
|
+
const lastBrace = text.lastIndexOf('}');
|
|
62
|
+
if (lastBrace === -1)
|
|
63
|
+
return text;
|
|
64
|
+
let s = text.slice(0, lastBrace + 1);
|
|
65
|
+
let openBraces = 0;
|
|
66
|
+
let openBrackets = 0;
|
|
67
|
+
for (const ch of s) {
|
|
68
|
+
if (ch === '{')
|
|
69
|
+
openBraces++;
|
|
70
|
+
if (ch === '}')
|
|
71
|
+
openBraces--;
|
|
72
|
+
if (ch === '[')
|
|
73
|
+
openBrackets++;
|
|
74
|
+
if (ch === ']')
|
|
75
|
+
openBrackets--;
|
|
76
|
+
}
|
|
77
|
+
for (let i = 0; i < openBrackets; i++)
|
|
78
|
+
s += ']';
|
|
79
|
+
for (let i = 0; i < openBraces; i++)
|
|
80
|
+
s += '}';
|
|
81
|
+
return s;
|
|
82
|
+
}
|
|
83
|
+
function toStr(v) {
|
|
84
|
+
return v == null ? '' : String(v);
|
|
85
|
+
}
|
|
86
|
+
function normalizeCodeRef(r) {
|
|
87
|
+
return {
|
|
88
|
+
file: toStr(r.file),
|
|
89
|
+
...(r.function ? { function: toStr(r.function) } : {}),
|
|
90
|
+
...(Array.isArray(r.lineRange) ? { lineRange: [Number(r.lineRange[0]), Number(r.lineRange[1])] } : {}),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function normalizeDataAccess(d) {
|
|
94
|
+
const op = toStr(d.operation);
|
|
95
|
+
return {
|
|
96
|
+
table: toStr(d.table),
|
|
97
|
+
operation: VALID_DATA_OPS.includes(op) ? op : 'read',
|
|
98
|
+
...(Array.isArray(d.columns) ? { columns: d.columns.map(String) } : {}),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function normalizeStep(s) {
|
|
102
|
+
return {
|
|
103
|
+
order: Number(s.order) || 0,
|
|
104
|
+
action: toStr(s.action),
|
|
105
|
+
...(s.codeRef ? { codeRef: normalizeCodeRef(s.codeRef) } : {}),
|
|
106
|
+
...(s.dataAccess ? { dataAccess: normalizeDataAccess(s.dataAccess) } : {}),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function normalizeFlow(raw) {
|
|
110
|
+
return {
|
|
111
|
+
id: toStr(raw.id),
|
|
112
|
+
name: toStr(raw.name),
|
|
113
|
+
description: toStr(raw.description),
|
|
114
|
+
actor: toStr(raw.actor),
|
|
115
|
+
trigger: toStr(raw.trigger),
|
|
116
|
+
steps: Array.isArray(raw.steps) ? raw.steps.map(normalizeStep) : [],
|
|
117
|
+
successCriteria: toStr(raw.successCriteria),
|
|
118
|
+
errorPaths: Array.isArray(raw.errorPaths) ? raw.errorPaths.map(String) : [],
|
|
119
|
+
codePaths: Array.isArray(raw.codePaths) ? raw.codePaths.map(normalizeCodeRef) : [],
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function normalizeField(f) {
|
|
123
|
+
return {
|
|
124
|
+
name: toStr(f.name),
|
|
125
|
+
type: toStr(f.type),
|
|
126
|
+
constraints: Array.isArray(f.constraints) ? f.constraints.map(String) : [],
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function normalizeRelationship(r) {
|
|
130
|
+
const t = toStr(r.type);
|
|
131
|
+
return {
|
|
132
|
+
target: toStr(r.target),
|
|
133
|
+
type: VALID_RELATIONSHIP_TYPES.includes(t) ? t : 'one-to-many',
|
|
134
|
+
...(r.foreignKey ? { foreignKey: toStr(r.foreignKey) } : {}),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function normalizeEntity(raw) {
|
|
138
|
+
return {
|
|
139
|
+
name: toStr(raw.name),
|
|
140
|
+
source: toStr(raw.source),
|
|
141
|
+
fields: Array.isArray(raw.fields) ? raw.fields.map(normalizeField) : [],
|
|
142
|
+
relationships: Array.isArray(raw.relationships)
|
|
143
|
+
? raw.relationships.map(normalizeRelationship)
|
|
144
|
+
: [],
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function normalizeGuard(g) {
|
|
148
|
+
return {
|
|
149
|
+
pattern: toStr(g.pattern),
|
|
150
|
+
...(g.requiredRole ? { requiredRole: toStr(g.requiredRole) } : {}),
|
|
151
|
+
mechanism: toStr(g.mechanism),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function normalizeAuthModel(raw) {
|
|
155
|
+
return {
|
|
156
|
+
strategy: toStr(raw.strategy),
|
|
157
|
+
roles: Array.isArray(raw.roles) ? raw.roles.map(String) : [],
|
|
158
|
+
guards: Array.isArray(raw.guards) ? raw.guards.map(normalizeGuard) : [],
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function normalizeFeatureGroup(f) {
|
|
162
|
+
const c = toStr(f.completeness);
|
|
163
|
+
return {
|
|
164
|
+
name: toStr(f.name),
|
|
165
|
+
flows: Array.isArray(f.flows) ? f.flows.map(String) : [],
|
|
166
|
+
completeness: VALID_COMPLETENESS.includes(c) ? c : 'partial',
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
function normalizeGap(g) {
|
|
170
|
+
const t = toStr(g.type);
|
|
171
|
+
return {
|
|
172
|
+
type: VALID_GAP_TYPES.includes(t) ? t : 'incomplete-flow',
|
|
173
|
+
description: toStr(g.description),
|
|
174
|
+
evidence: toStr(g.evidence),
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Parse the LLM response into a partial IntentManifest (without version/timestamps).
|
|
179
|
+
* Handles code fences, truncation, and type normalization.
|
|
180
|
+
* Exported for testing.
|
|
181
|
+
*/
|
|
182
|
+
export function parseIntentResponse(rawText) {
|
|
183
|
+
let jsonText = stripCodeFences(rawText);
|
|
184
|
+
jsonText = closeUnclosedJson(jsonText);
|
|
185
|
+
let parsed;
|
|
186
|
+
try {
|
|
187
|
+
parsed = JSON.parse(jsonText);
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
const truncated = jsonText.length > 10_000;
|
|
191
|
+
throw new Error(`Failed to parse intent response as JSON${truncated ? ' (likely truncated — response was ' + jsonText.length + ' chars, try increasing maxTokens)' : ''}.\n` +
|
|
192
|
+
`Parse error: ${err instanceof Error ? err.message : err}\n` +
|
|
193
|
+
`First 500 chars: ${jsonText.slice(0, 500)}\n` +
|
|
194
|
+
`Last 200 chars: ${jsonText.slice(-200)}`);
|
|
195
|
+
}
|
|
196
|
+
return {
|
|
197
|
+
flows: Array.isArray(parsed.flows) ? parsed.flows.map(normalizeFlow) : [],
|
|
198
|
+
dataModel: Array.isArray(parsed.dataModel) ? parsed.dataModel.map(normalizeEntity) : [],
|
|
199
|
+
authModel: parsed.authModel ? normalizeAuthModel(parsed.authModel) : { strategy: '', roles: [], guards: [] },
|
|
200
|
+
featureMap: Array.isArray(parsed.featureMap) ? parsed.featureMap.map(normalizeFeatureGroup) : [],
|
|
201
|
+
gaps: Array.isArray(parsed.gaps) ? parsed.gaps.map(normalizeGap) : [],
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
// ── Flow → Claim conversion ─────────────────────────────────────────
|
|
205
|
+
const SEVERITY_KEYWORDS = [
|
|
206
|
+
{ pattern: /\b(auth|permission|role|guard|access control|login|session|token|password)\b/i, severity: 'critical' },
|
|
207
|
+
{ pattern: /\b(encrypt|hash|secret|credential|injection|xss|csrf|sanitiz)\b/i, severity: 'critical' },
|
|
208
|
+
{ pattern: /\b(delete|remove|drop|destroy|purge)\b/i, severity: 'high' },
|
|
209
|
+
{ pattern: /\b(payment|billing|charge|invoice|subscription|refund)\b/i, severity: 'high' },
|
|
210
|
+
{ pattern: /\b(creat|insert|update|save|submit|mutation|write)\b/i, severity: 'high' },
|
|
211
|
+
{ pattern: /\b(validat|required|constraint|unique|foreign key)\b/i, severity: 'medium' },
|
|
212
|
+
];
|
|
213
|
+
/**
|
|
214
|
+
* Assign severity based on keyword matching.
|
|
215
|
+
* First match wins; default is 'medium'.
|
|
216
|
+
*/
|
|
217
|
+
export function assignSeverity(text) {
|
|
218
|
+
for (const { pattern, severity } of SEVERITY_KEYWORDS) {
|
|
219
|
+
if (pattern.test(text)) {
|
|
220
|
+
return severity;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return 'medium';
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Convert an IntentFlow into Claim[].
|
|
227
|
+
* Replaces the old behaviorsToClaims() with flow-aware claim derivation.
|
|
228
|
+
*
|
|
229
|
+
* Produces claims from:
|
|
230
|
+
* 1. Each FlowStep (ID: {flow.id}-STEP-{order padded to 3})
|
|
231
|
+
* 2. successCriteria (ID: {flow.id}-SUCCESS)
|
|
232
|
+
* 3. Each errorPath (ID: {flow.id}-ERR-{index+1 padded to 3})
|
|
233
|
+
* 4. Each gap (ID: {flow.id}-GAP-{index+1 padded to 3}) — optional
|
|
234
|
+
*/
|
|
235
|
+
export function flowToClaims(flow, gaps) {
|
|
236
|
+
const claims = [];
|
|
237
|
+
// 1. Step claims
|
|
238
|
+
for (const step of flow.steps) {
|
|
239
|
+
const text = `Flow "${flow.name}" step ${step.order}: ${step.action}`;
|
|
240
|
+
claims.push({
|
|
241
|
+
id: `${flow.id}-STEP-${String(step.order).padStart(3, '0')}`,
|
|
242
|
+
section: flow.name,
|
|
243
|
+
category: 'functionality',
|
|
244
|
+
severity: assignSeverity(text),
|
|
245
|
+
text,
|
|
246
|
+
testable: true,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
// 2. Success criteria claim
|
|
250
|
+
if (flow.successCriteria) {
|
|
251
|
+
const text = `Flow "${flow.name}" success: ${flow.successCriteria}`;
|
|
252
|
+
claims.push({
|
|
253
|
+
id: `${flow.id}-SUCCESS`,
|
|
254
|
+
section: flow.name,
|
|
255
|
+
category: 'functionality',
|
|
256
|
+
severity: assignSeverity(text),
|
|
257
|
+
text,
|
|
258
|
+
testable: true,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
// 3. Error path claims
|
|
262
|
+
for (let i = 0; i < flow.errorPaths.length; i++) {
|
|
263
|
+
const text = `Flow "${flow.name}" error path: ${flow.errorPaths[i]}`;
|
|
264
|
+
claims.push({
|
|
265
|
+
id: `${flow.id}-ERR-${String(i + 1).padStart(3, '0')}`,
|
|
266
|
+
section: flow.name,
|
|
267
|
+
category: 'functionality',
|
|
268
|
+
severity: 'medium',
|
|
269
|
+
text,
|
|
270
|
+
testable: true,
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
// 4. Gap claims (optional)
|
|
274
|
+
if (gaps) {
|
|
275
|
+
for (let i = 0; i < gaps.length; i++) {
|
|
276
|
+
const gap = gaps[i];
|
|
277
|
+
claims.push({
|
|
278
|
+
id: `${flow.id}-GAP-${String(i + 1).padStart(3, '0')}`,
|
|
279
|
+
section: flow.name,
|
|
280
|
+
category: gap.type === 'unguarded-route' ? 'security' : 'functionality',
|
|
281
|
+
severity: 'high',
|
|
282
|
+
text: `Gap: ${gap.description}`,
|
|
283
|
+
testable: true,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return claims;
|
|
288
|
+
}
|
|
289
|
+
// ── LLM extraction ──────────────────────────────────────────────────
|
|
290
|
+
const INTENT_SYSTEM_PROMPT = `You are an application architect. Given a codebase's file tree and key file contents, extract the application's complete intent — what the app is supposed to do.
|
|
291
|
+
|
|
292
|
+
INSTRUCTIONS:
|
|
293
|
+
|
|
294
|
+
1. FLOWS: Identify every user-facing flow (journey) the application implements.
|
|
295
|
+
- A flow is a sequence of actions a user takes to accomplish a goal
|
|
296
|
+
- Each flow has: an actor (who), a trigger (what starts it), ordered steps, success criteria, and error paths
|
|
297
|
+
- Map each flow to its implementing code files
|
|
298
|
+
- Examples: "User signs up", "Admin creates invoice", "Customer checks out"
|
|
299
|
+
|
|
300
|
+
2. DATA MODEL: Identify every data entity (database table, collection, or model).
|
|
301
|
+
- Look for: Prisma schemas, SQL migrations, Drizzle schemas, Supabase table references, Mongoose models
|
|
302
|
+
- For each entity: name, source file, fields with types and constraints, relationships
|
|
303
|
+
|
|
304
|
+
3. AUTH MODEL: Identify the authentication and authorization strategy.
|
|
305
|
+
- Strategy: JWT, session-based, OAuth, Supabase Auth, etc.
|
|
306
|
+
- Roles: all distinct user roles found
|
|
307
|
+
- Guards: route protection patterns (middleware, RLS policies, component checks)
|
|
308
|
+
|
|
309
|
+
4. FEATURE MAP: Group related flows into feature groups.
|
|
310
|
+
- Each group has a name and completeness assessment (full, partial, stub)
|
|
311
|
+
|
|
312
|
+
5. GAPS: Identify things that look incomplete or missing.
|
|
313
|
+
- missing-flow: Route/endpoint exists but handler is empty or stub
|
|
314
|
+
- dead-code: Code exists but is unreachable or unused
|
|
315
|
+
- unguarded-route: Endpoint with no auth check that probably needs one
|
|
316
|
+
- orphaned-table: Table defined but never read or written
|
|
317
|
+
- incomplete-flow: Flow starts but doesn't complete (missing steps)
|
|
318
|
+
|
|
319
|
+
OUTPUT FORMAT:
|
|
320
|
+
Return ONLY a JSON object (no markdown fences, no commentary):
|
|
321
|
+
{
|
|
322
|
+
"flows": [
|
|
323
|
+
{
|
|
324
|
+
"id": "flow-signup",
|
|
325
|
+
"name": "User Signup",
|
|
326
|
+
"description": "New user creates an account with email and password",
|
|
327
|
+
"actor": "unauthenticated user",
|
|
328
|
+
"trigger": "POST /api/auth/signup",
|
|
329
|
+
"steps": [
|
|
330
|
+
{ "order": 1, "action": "validate email format and password strength", "codeRef": { "file": "src/routes/auth.ts", "function": "signup" } },
|
|
331
|
+
{ "order": 2, "action": "create user record in database", "dataAccess": { "table": "users", "operation": "write" } },
|
|
332
|
+
{ "order": 3, "action": "send verification email", "codeRef": { "file": "src/lib/email.ts", "function": "sendVerification" } }
|
|
333
|
+
],
|
|
334
|
+
"successCriteria": "User account created and verification email sent",
|
|
335
|
+
"errorPaths": ["Invalid email returns 400", "Duplicate email returns 409"],
|
|
336
|
+
"codePaths": [{ "file": "src/routes/auth.ts" }, { "file": "src/lib/email.ts" }]
|
|
337
|
+
}
|
|
338
|
+
],
|
|
339
|
+
"dataModel": [
|
|
340
|
+
{
|
|
341
|
+
"name": "users",
|
|
342
|
+
"source": "prisma/schema.prisma",
|
|
343
|
+
"fields": [
|
|
344
|
+
{ "name": "id", "type": "uuid", "constraints": ["PRIMARY KEY"] },
|
|
345
|
+
{ "name": "email", "type": "string", "constraints": ["UNIQUE", "NOT NULL"] }
|
|
346
|
+
],
|
|
347
|
+
"relationships": [
|
|
348
|
+
{ "target": "profiles", "type": "one-to-one", "foreignKey": "user_id" }
|
|
349
|
+
]
|
|
350
|
+
}
|
|
351
|
+
],
|
|
352
|
+
"authModel": {
|
|
353
|
+
"strategy": "JWT + Supabase Auth",
|
|
354
|
+
"roles": ["admin", "user", "unauthenticated"],
|
|
355
|
+
"guards": [
|
|
356
|
+
{ "pattern": "/api/admin/*", "requiredRole": "admin", "mechanism": "middleware" }
|
|
357
|
+
]
|
|
358
|
+
},
|
|
359
|
+
"featureMap": [
|
|
360
|
+
{ "name": "Authentication", "flows": ["flow-signup", "flow-login"], "completeness": "full" }
|
|
361
|
+
],
|
|
362
|
+
"gaps": [
|
|
363
|
+
{ "type": "missing-flow", "description": "No password reset flow", "evidence": "/forgot-password route exists but handler returns 501" }
|
|
364
|
+
]
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
Rules:
|
|
368
|
+
- Flow IDs must be unique and use the pattern "flow-<name>"
|
|
369
|
+
- Every step should have either a codeRef or dataAccess (or both) when identifiable
|
|
370
|
+
- Be thorough — extract ALL flows, not just the obvious ones
|
|
371
|
+
- codePaths should reference real files from the file tree
|
|
372
|
+
- gaps should have concrete evidence, not speculation`;
|
|
373
|
+
const MAX_INTENT_FILE_CHARS = 5000;
|
|
374
|
+
/**
|
|
375
|
+
* Extract application intent from a codebase.
|
|
376
|
+
* Single LLM call that produces a raw IntentManifest.
|
|
377
|
+
*/
|
|
378
|
+
export async function extractIntent(index, onProgress) {
|
|
379
|
+
const filesToRead = selectIntentFiles(index);
|
|
380
|
+
onProgress?.(`Reading ${filesToRead.length} key files for intent extraction...`);
|
|
381
|
+
let fileContents = '';
|
|
382
|
+
let filesRead = 0;
|
|
383
|
+
for (const filePath of filesToRead) {
|
|
384
|
+
const content = await readFileContent(index.rootPath, filePath);
|
|
385
|
+
if (content) {
|
|
386
|
+
const truncated = content.length > MAX_INTENT_FILE_CHARS
|
|
387
|
+
? content.slice(0, MAX_INTENT_FILE_CHARS) + '\n[... truncated]'
|
|
388
|
+
: content;
|
|
389
|
+
fileContents += `\n--- FILE: ${filePath} ---\n${truncated}\n`;
|
|
390
|
+
filesRead++;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
onProgress?.(`Sending ${filesRead} files for intent extraction...`);
|
|
394
|
+
const treeStr = index.fileTree.slice(0, 3000).join('\n');
|
|
395
|
+
const userMessage = [
|
|
396
|
+
`Analyze this codebase and extract its complete application intent.`,
|
|
397
|
+
``,
|
|
398
|
+
`CODEBASE FILE TREE (${index.totalFiles} files total):`,
|
|
399
|
+
treeStr,
|
|
400
|
+
``,
|
|
401
|
+
`FRAMEWORKS DETECTED: ${index.frameworks.join(', ') || 'unknown'}`,
|
|
402
|
+
``,
|
|
403
|
+
`KEY FILE CONTENTS:`,
|
|
404
|
+
fileContents,
|
|
405
|
+
].join('\n');
|
|
406
|
+
const result = await getProvider().complete({
|
|
407
|
+
model: MODEL,
|
|
408
|
+
maxTokens: 64_000,
|
|
409
|
+
systemPrompt: INTENT_SYSTEM_PROMPT,
|
|
410
|
+
userPrompt: userMessage,
|
|
411
|
+
});
|
|
412
|
+
const parsed = parseIntentResponse(result.content);
|
|
413
|
+
const manifest = {
|
|
414
|
+
version: 1,
|
|
415
|
+
extractedAt: new Date().toISOString(),
|
|
416
|
+
codebaseRoot: index.rootPath,
|
|
417
|
+
frameworks: index.frameworks,
|
|
418
|
+
...parsed,
|
|
419
|
+
};
|
|
420
|
+
return {
|
|
421
|
+
manifest,
|
|
422
|
+
rawResponse: result.content,
|
|
423
|
+
inputTokens: result.inputTokens ?? 0,
|
|
424
|
+
outputTokens: result.outputTokens ?? 0,
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
//# sourceMappingURL=intent-extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intent-extractor.js","sourceRoot":"","sources":["../../src/lib/intent-extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { IntentManifest, ManifestDelta } from './intent-types.js';
|
|
2
|
+
export declare function diffManifest(saved: IntentManifest, fresh: IntentManifest): ManifestDelta;
|
|
3
|
+
export declare function loadSavedManifest(codebaseRoot: string): Promise<IntentManifest | null>;
|
|
4
|
+
export declare function saveManifest(manifest: IntentManifest): Promise<string>;
|
|
5
|
+
/**
|
|
6
|
+
* Present the manifest to the user for interactive review.
|
|
7
|
+
* If delta is null (first run), shows everything.
|
|
8
|
+
* If delta exists (subsequent run), shows only changes.
|
|
9
|
+
* After user confirms, sets confirmedBy and confirmedAt on the manifest.
|
|
10
|
+
* Returns the (possibly modified) manifest.
|
|
11
|
+
*/
|
|
12
|
+
export declare function reviewManifest(manifest: IntentManifest, delta: ManifestDelta | null, options?: {
|
|
13
|
+
autoConfirm?: boolean;
|
|
14
|
+
}): Promise<IntentManifest>;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// Layer 0: Intent Reviewer
|
|
2
|
+
// Diff manifests, interactive CLI review, load/save persistence.
|
|
3
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
4
|
+
import { resolve, dirname } from 'node:path';
|
|
5
|
+
import { createInterface } from 'node:readline';
|
|
6
|
+
const MANIFEST_PATH = '.assay/intent-manifest.json';
|
|
7
|
+
// -- Diff --------------------------------------------------------------------
|
|
8
|
+
function flowsEqual(a, b) {
|
|
9
|
+
return (a.name === b.name &&
|
|
10
|
+
a.description === b.description &&
|
|
11
|
+
a.actor === b.actor &&
|
|
12
|
+
a.trigger === b.trigger &&
|
|
13
|
+
a.steps.length === b.steps.length &&
|
|
14
|
+
a.successCriteria === b.successCriteria);
|
|
15
|
+
}
|
|
16
|
+
export function diffManifest(saved, fresh) {
|
|
17
|
+
const savedFlowIds = new Set(saved.flows.map((f) => f.id));
|
|
18
|
+
const freshFlowIds = new Set(fresh.flows.map((f) => f.id));
|
|
19
|
+
const addedFlows = fresh.flows.filter((f) => !savedFlowIds.has(f.id));
|
|
20
|
+
const removedFlows = saved.flows.filter((f) => !freshFlowIds.has(f.id));
|
|
21
|
+
const changedFlows = [];
|
|
22
|
+
for (const freshFlow of fresh.flows) {
|
|
23
|
+
const savedFlow = saved.flows.find((f) => f.id === freshFlow.id);
|
|
24
|
+
if (savedFlow && !flowsEqual(savedFlow, freshFlow)) {
|
|
25
|
+
changedFlows.push({ before: savedFlow, after: freshFlow });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const savedEntityNames = new Set(saved.dataModel.map((e) => e.name));
|
|
29
|
+
const freshEntityNames = new Set(fresh.dataModel.map((e) => e.name));
|
|
30
|
+
const addedEntities = fresh.dataModel.filter((e) => !savedEntityNames.has(e.name));
|
|
31
|
+
const removedEntities = saved.dataModel.filter((e) => !freshEntityNames.has(e.name));
|
|
32
|
+
const savedGapDescs = new Set(saved.gaps.map((g) => g.description));
|
|
33
|
+
const freshGapDescs = new Set(fresh.gaps.map((g) => g.description));
|
|
34
|
+
const addedGaps = fresh.gaps.filter((g) => !savedGapDescs.has(g.description));
|
|
35
|
+
const removedGaps = saved.gaps.filter((g) => !freshGapDescs.has(g.description));
|
|
36
|
+
return { addedFlows, removedFlows, changedFlows, addedEntities, removedEntities, addedGaps, removedGaps };
|
|
37
|
+
}
|
|
38
|
+
// -- Load/Save ---------------------------------------------------------------
|
|
39
|
+
export async function loadSavedManifest(codebaseRoot) {
|
|
40
|
+
try {
|
|
41
|
+
const raw = await readFile(resolve(codebaseRoot, MANIFEST_PATH), 'utf-8');
|
|
42
|
+
return JSON.parse(raw);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export async function saveManifest(manifest) {
|
|
49
|
+
const filePath = resolve(manifest.codebaseRoot, MANIFEST_PATH);
|
|
50
|
+
await mkdir(dirname(filePath), { recursive: true });
|
|
51
|
+
await writeFile(filePath, JSON.stringify(manifest, null, 2));
|
|
52
|
+
return filePath;
|
|
53
|
+
}
|
|
54
|
+
// -- Interactive Review ------------------------------------------------------
|
|
55
|
+
function formatFlowSummary(flow, index) {
|
|
56
|
+
const steps = flow.steps.map((s) => s.action).join(' \u2192 ');
|
|
57
|
+
const code = flow.codePaths.map((c) => c.file).join(', ');
|
|
58
|
+
return [
|
|
59
|
+
` ${index + 1}. ${flow.name}`,
|
|
60
|
+
` Actor: ${flow.actor}`,
|
|
61
|
+
` Steps: ${steps || '(none)'}`,
|
|
62
|
+
` Code: ${code || '(unknown)'}`,
|
|
63
|
+
].join('\n');
|
|
64
|
+
}
|
|
65
|
+
function formatGap(gap) {
|
|
66
|
+
const icon = gap.type === 'unguarded-route' || gap.type === 'missing-flow' ? '\u26A0' : '\u25CB';
|
|
67
|
+
return ` ${icon} ${gap.type}: ${gap.description}`;
|
|
68
|
+
}
|
|
69
|
+
async function askYesNo(rl, question) {
|
|
70
|
+
return new Promise((res) => {
|
|
71
|
+
rl.question(`${question} (y/n) `, (answer) => {
|
|
72
|
+
res(answer.trim().toLowerCase().startsWith('y'));
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Present the manifest to the user for interactive review.
|
|
78
|
+
* If delta is null (first run), shows everything.
|
|
79
|
+
* If delta exists (subsequent run), shows only changes.
|
|
80
|
+
* After user confirms, sets confirmedBy and confirmedAt on the manifest.
|
|
81
|
+
* Returns the (possibly modified) manifest.
|
|
82
|
+
*/
|
|
83
|
+
export async function reviewManifest(manifest, delta, options) {
|
|
84
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
85
|
+
try {
|
|
86
|
+
console.log('\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550');
|
|
87
|
+
console.log(' Layer 0: Intent Extraction');
|
|
88
|
+
console.log('\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n');
|
|
89
|
+
if (delta) {
|
|
90
|
+
// Subsequent run -- show only changes
|
|
91
|
+
console.log(`Changes since last confirmed manifest:\n`);
|
|
92
|
+
if (delta.addedFlows.length > 0) {
|
|
93
|
+
console.log(`\u2500\u2500 New Flows (${delta.addedFlows.length}) \u2500\u2500`);
|
|
94
|
+
delta.addedFlows.forEach((f, i) => console.log(formatFlowSummary(f, i)));
|
|
95
|
+
}
|
|
96
|
+
if (delta.removedFlows.length > 0) {
|
|
97
|
+
console.log(`\n\u2500\u2500 Removed Flows (${delta.removedFlows.length}) \u2500\u2500`);
|
|
98
|
+
delta.removedFlows.forEach((f) => console.log(` \u2717 ${f.name} (${f.id})`));
|
|
99
|
+
}
|
|
100
|
+
if (delta.changedFlows.length > 0) {
|
|
101
|
+
console.log(`\n\u2500\u2500 Changed Flows (${delta.changedFlows.length}) \u2500\u2500`);
|
|
102
|
+
delta.changedFlows.forEach(({ before, after }) => {
|
|
103
|
+
console.log(` \u270E ${before.name} \u2192 ${after.name}`);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
if (delta.addedGaps.length > 0) {
|
|
107
|
+
console.log(`\n\u2500\u2500 New Gaps (${delta.addedGaps.length}) \u2500\u2500`);
|
|
108
|
+
delta.addedGaps.forEach((g) => console.log(formatGap(g)));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
// First run -- show everything
|
|
113
|
+
console.log(`Found ${manifest.flows.length} user flows, ${manifest.dataModel.length} data entities, ${manifest.authModel.roles.length} roles\n`);
|
|
114
|
+
if (manifest.flows.length > 0) {
|
|
115
|
+
console.log('\u2500\u2500 Flows \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n');
|
|
116
|
+
manifest.flows.forEach((f, i) => console.log(formatFlowSummary(f, i) + '\n'));
|
|
117
|
+
}
|
|
118
|
+
if (manifest.gaps.length > 0) {
|
|
119
|
+
console.log('\u2500\u2500 Gaps Found \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n');
|
|
120
|
+
manifest.gaps.forEach((g) => console.log(formatGap(g)));
|
|
121
|
+
console.log('');
|
|
122
|
+
}
|
|
123
|
+
if (manifest.dataModel.length > 0) {
|
|
124
|
+
console.log('\u2500\u2500 Data Model \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n');
|
|
125
|
+
manifest.dataModel.forEach((e) => {
|
|
126
|
+
console.log(` ${e.name} (${e.fields.length} fields, ${e.relationships.length} relationships)`);
|
|
127
|
+
});
|
|
128
|
+
console.log('');
|
|
129
|
+
}
|
|
130
|
+
console.log('\u2500\u2500 Auth Model \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n');
|
|
131
|
+
console.log(` Strategy: ${manifest.authModel.strategy || '(none detected)'}`);
|
|
132
|
+
console.log(` Roles: ${manifest.authModel.roles.join(', ') || '(none detected)'}`);
|
|
133
|
+
console.log(` Guards: ${manifest.authModel.guards.length} protected patterns`);
|
|
134
|
+
console.log('');
|
|
135
|
+
}
|
|
136
|
+
console.log('\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550');
|
|
137
|
+
const confirmed = options?.autoConfirm ?? await askYesNo(rl, 'Confirm manifest?');
|
|
138
|
+
if (confirmed) {
|
|
139
|
+
manifest.confirmedBy = 'user';
|
|
140
|
+
manifest.confirmedAt = new Date().toISOString();
|
|
141
|
+
}
|
|
142
|
+
return manifest;
|
|
143
|
+
}
|
|
144
|
+
finally {
|
|
145
|
+
rl.close();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=intent-reviewer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intent-reviewer.js","sourceRoot":"","sources":["../../src/lib/intent-reviewer.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,iEAAiE;AAEjE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAQhD,MAAM,aAAa,GAAG,6BAA6B,CAAC;AAEpD,+EAA+E;AAE/E,SAAS,UAAU,CAAC,CAAa,EAAE,CAAa;IAC9C,OAAO,CACL,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI;QACjB,CAAC,CAAC,WAAW,KAAK,CAAC,CAAC,WAAW;QAC/B,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK;QACnB,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO;QACvB,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM;QACjC,CAAC,CAAC,eAAe,KAAK,CAAC,CAAC,eAAe,CACxC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAqB,EAAE,KAAqB;IACvE,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3D,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAE3D,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACtE,MAAM,YAAY,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAExE,MAAM,YAAY,GAAkC,EAAE,CAAC;IACvD,KAAK,MAAM,SAAS,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QACpC,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,EAAE,CAAC,CAAC;QACjE,IAAI,SAAS,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC;YACnD,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IAED,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACrE,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACrE,MAAM,aAAa,GAAG,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACnF,MAAM,eAAe,GAAG,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAErF,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;IACpE,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;IACpE,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;IAC9E,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;IAEhF,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;AAC5G,CAAC;AAED,+EAA+E;AAE/E,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,YAAoB;IAC1D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,aAAa,CAAC,EAAE,OAAO,CAAC,CAAC;QAC1E,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAmB,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAwB;IACzD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;IAC/D,MAAM,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,MAAM,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7D,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,+EAA+E;AAE/E,SAAS,iBAAiB,CAAC,IAAgB,EAAE,KAAa;IACxD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC/D,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1D,OAAO;QACL,KAAK,KAAK,GAAG,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE;QAC9B,eAAe,IAAI,CAAC,KAAK,EAAE;QAC3B,eAAe,KAAK,IAAI,QAAQ,EAAE;QAClC,cAAc,IAAI,IAAI,WAAW,EAAE;KACpC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,SAAS,SAAS,CAAC,GAAc;IAC/B,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,KAAK,iBAAiB,IAAI,GAAG,CAAC,IAAI,KAAK,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;IACjG,OAAO,KAAK,IAAI,IAAI,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,WAAW,EAAE,CAAC;AACrD,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,EAAsC,EAAE,QAAgB;IAC9E,OAAO,IAAI,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;QACzB,EAAE,CAAC,QAAQ,CAAC,GAAG,QAAQ,SAAS,EAAE,CAAC,MAAM,EAAE,EAAE;YAC3C,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAAwB,EACxB,KAA2B,EAC3B,OAAmC;IAEnC,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAE7E,IAAI,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,sTAAsT,CAAC,CAAC;QACpU,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;QAC5C,OAAO,CAAC,GAAG,CAAC,sTAAsT,CAAC,CAAC;QAEpU,IAAI,KAAK,EAAE,CAAC;YACV,sCAAsC;YACtC,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;YACxD,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAChC,OAAO,CAAC,GAAG,CAAC,2BAA2B,KAAK,CAAC,UAAU,CAAC,MAAM,gBAAgB,CAAC,CAAC;gBAChF,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3E,CAAC;YACD,IAAI,KAAK,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAClC,OAAO,CAAC,GAAG,CAAC,iCAAiC,KAAK,CAAC,YAAY,CAAC,MAAM,gBAAgB,CAAC,CAAC;gBACxF,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YACjF,CAAC;YACD,IAAI,KAAK,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAClC,OAAO,CAAC,GAAG,CAAC,iCAAiC,KAAK,CAAC,YAAY,CAAC,MAAM,gBAAgB,CAAC,CAAC;gBACxF,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE;oBAC/C,OAAO,CAAC,GAAG,CAAC,YAAY,MAAM,CAAC,IAAI,WAAW,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;gBAC9D,CAAC,CAAC,CAAC;YACL,CAAC;YACD,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC/B,OAAO,CAAC,GAAG,CAAC,4BAA4B,KAAK,CAAC,SAAS,CAAC,MAAM,gBAAgB,CAAC,CAAC;gBAChF,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC;aAAM,CAAC;YACN,+BAA+B;YAC/B,OAAO,CAAC,GAAG,CAAC,SAAS,QAAQ,CAAC,KAAK,CAAC,MAAM,gBAAgB,QAAQ,CAAC,SAAS,CAAC,MAAM,mBAAmB,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,UAAU,CAAC,CAAC;YAEjJ,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC9B,OAAO,CAAC,GAAG,CAAC,mUAAmU,CAAC,CAAC;gBACjV,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;YAChF,CAAC;YAED,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC7B,OAAO,CAAC,GAAG,CAAC,0SAA0S,CAAC,CAAC;gBACxT,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBACxD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAClB,CAAC;YAED,IAAI,QAAQ,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAClC,OAAO,CAAC,GAAG,CAAC,0SAA0S,CAAC,CAAC;gBACxT,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;oBAC/B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,YAAY,CAAC,CAAC,aAAa,CAAC,MAAM,iBAAiB,CAAC,CAAC;gBAClG,CAAC,CAAC,CAAC;gBACH,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAClB,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,0SAA0S,CAAC,CAAC;YACxT,OAAO,CAAC,GAAG,CAAC,eAAe,QAAQ,CAAC,SAAS,CAAC,QAAQ,IAAI,iBAAiB,EAAE,CAAC,CAAC;YAC/E,OAAO,CAAC,GAAG,CAAC,YAAY,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,iBAAiB,EAAE,CAAC,CAAC;YACpF,OAAO,CAAC,GAAG,CAAC,aAAa,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,qBAAqB,CAAC,CAAC;YAChF,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClB,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,oTAAoT,CAAC,CAAC;QAElU,MAAM,SAAS,GAAG,OAAO,EAAE,WAAW,IAAI,MAAM,QAAQ,CAAC,EAAE,EAAE,mBAAmB,CAAC,CAAC;QAElF,IAAI,SAAS,EAAE,CAAC;YACd,QAAQ,CAAC,WAAW,GAAG,MAAM,CAAC;YAC9B,QAAQ,CAAC,WAAW,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAClD,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC"}
|