tryassay 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +553 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +80 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/assess.d.ts +6 -0
- package/dist/commands/assess.js +267 -0
- package/dist/commands/assess.js.map +1 -0
- package/dist/commands/describe.d.ts +3 -0
- package/dist/commands/describe.js +114 -0
- package/dist/commands/describe.js.map +1 -0
- package/dist/commands/extract.d.ts +4 -0
- package/dist/commands/extract.js +144 -0
- package/dist/commands/extract.js.map +1 -0
- package/dist/commands/hallucinate.d.ts +3 -0
- package/dist/commands/hallucinate.js +100 -0
- package/dist/commands/hallucinate.js.map +1 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +39 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/regenerate.d.ts +3 -0
- package/dist/commands/regenerate.js +158 -0
- package/dist/commands/regenerate.js.map +1 -0
- package/dist/commands/remediate.d.ts +5 -0
- package/dist/commands/remediate.js +155 -0
- package/dist/commands/remediate.js.map +1 -0
- package/dist/commands/report.d.ts +3 -0
- package/dist/commands/report.js +84 -0
- package/dist/commands/report.js.map +1 -0
- package/dist/commands/reverse.d.ts +9 -0
- package/dist/commands/reverse.js +115 -0
- package/dist/commands/reverse.js.map +1 -0
- package/dist/commands/verify.d.ts +4 -0
- package/dist/commands/verify.js +112 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/lib/anthropic.d.ts +13 -0
- package/dist/lib/anthropic.js +60 -0
- package/dist/lib/anthropic.js.map +1 -0
- package/dist/lib/assessment-reporter.d.ts +5 -0
- package/dist/lib/assessment-reporter.js +266 -0
- package/dist/lib/assessment-reporter.js.map +1 -0
- package/dist/lib/claim-extractor.d.ts +6 -0
- package/dist/lib/claim-extractor.js +138 -0
- package/dist/lib/claim-extractor.js.map +1 -0
- package/dist/lib/code-verifier.d.ts +7 -0
- package/dist/lib/code-verifier.js +265 -0
- package/dist/lib/code-verifier.js.map +1 -0
- package/dist/lib/codebase-indexer.d.ts +15 -0
- package/dist/lib/codebase-indexer.js +156 -0
- package/dist/lib/codebase-indexer.js.map +1 -0
- package/dist/lib/config.d.ts +7 -0
- package/dist/lib/config.js +38 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/constraint-engine.d.ts +2 -0
- package/dist/lib/constraint-engine.js +337 -0
- package/dist/lib/constraint-engine.js.map +1 -0
- package/dist/lib/fs-utils.d.ts +1 -0
- package/dist/lib/fs-utils.js +11 -0
- package/dist/lib/fs-utils.js.map +1 -0
- package/dist/lib/guided-generator.d.ts +2 -0
- package/dist/lib/guided-generator.js +195 -0
- package/dist/lib/guided-generator.js.map +1 -0
- package/dist/lib/inventory-extractor.d.ts +7 -0
- package/dist/lib/inventory-extractor.js +238 -0
- package/dist/lib/inventory-extractor.js.map +1 -0
- package/dist/lib/prompts.d.ts +3 -0
- package/dist/lib/prompts.js +50 -0
- package/dist/lib/prompts.js.map +1 -0
- package/dist/lib/publisher.d.ts +2 -0
- package/dist/lib/publisher.js +71 -0
- package/dist/lib/publisher.js.map +1 -0
- package/dist/lib/remediation-generator.d.ts +2 -0
- package/dist/lib/remediation-generator.js +136 -0
- package/dist/lib/remediation-generator.js.map +1 -0
- package/dist/lib/remediator.d.ts +7 -0
- package/dist/lib/remediator.js +209 -0
- package/dist/lib/remediator.js.map +1 -0
- package/dist/lib/report-generator.d.ts +8 -0
- package/dist/lib/report-generator.js +190 -0
- package/dist/lib/report-generator.js.map +1 -0
- package/dist/lib/requirements-generator.d.ts +14 -0
- package/dist/lib/requirements-generator.js +311 -0
- package/dist/lib/requirements-generator.js.map +1 -0
- package/dist/lib/spec-synthesizer.d.ts +2 -0
- package/dist/lib/spec-synthesizer.js +136 -0
- package/dist/lib/spec-synthesizer.js.map +1 -0
- package/dist/lib/system-prompts.d.ts +12 -0
- package/dist/lib/system-prompts.js +254 -0
- package/dist/lib/system-prompts.js.map +1 -0
- package/dist/types.d.ts +243 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +49 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { readdir, mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { readConfig, getIterationsDir } from '../lib/config.js';
|
|
4
|
+
import { exists } from '../lib/fs-utils.js';
|
|
5
|
+
import { streamHallucination } from '../lib/anthropic.js';
|
|
6
|
+
const VALID_TYPES = ['tos', 'api-docs', 'user-manual'];
|
|
7
|
+
function countSections(content) {
|
|
8
|
+
// Count markdown headings (## or ###) as sections
|
|
9
|
+
const headings = content.match(/^#{1,3}\s+.+$/gm);
|
|
10
|
+
return headings?.length ?? 0;
|
|
11
|
+
}
|
|
12
|
+
function estimateClaims(content) {
|
|
13
|
+
// Heuristic: count sentences with specific numbers, named technologies,
|
|
14
|
+
// or declarative statements about capabilities
|
|
15
|
+
const sentences = content.split(/[.!]\s+/);
|
|
16
|
+
let claims = 0;
|
|
17
|
+
for (const sentence of sentences) {
|
|
18
|
+
const hasNumber = /\d+/.test(sentence);
|
|
19
|
+
const hasDeclarative = /\b(is|are|will|provides?|supports?|includes?|requires?|limits?|allows?|ensures?|stores?|encrypts?|processes?|retains?)\b/i.test(sentence);
|
|
20
|
+
const hasSpecific = /\b(GB|MB|TB|ms|seconds?|minutes?|hours?|days?|%|per|AES|SHA|RSA|SSL|TLS|HTTPS|OAuth|JWT|REST|GraphQL)\b/i.test(sentence);
|
|
21
|
+
if (hasNumber || (hasDeclarative && hasSpecific)) {
|
|
22
|
+
claims++;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return claims;
|
|
26
|
+
}
|
|
27
|
+
async function getNextIteration(iterDir) {
|
|
28
|
+
if (!(await exists(iterDir))) {
|
|
29
|
+
return 1;
|
|
30
|
+
}
|
|
31
|
+
const entries = await readdir(iterDir, { withFileTypes: true });
|
|
32
|
+
const nums = entries
|
|
33
|
+
.filter(e => e.isDirectory())
|
|
34
|
+
.map(e => parseInt(e.name, 10))
|
|
35
|
+
.filter(n => !isNaN(n));
|
|
36
|
+
return nums.length === 0 ? 1 : Math.max(...nums) + 1;
|
|
37
|
+
}
|
|
38
|
+
export async function hallucinateCommand(options) {
|
|
39
|
+
const type = (options.type ?? 'tos');
|
|
40
|
+
if (!VALID_TYPES.includes(type)) {
|
|
41
|
+
console.error(` Error: Invalid type "${type}". Must be one of: ${VALID_TYPES.join(', ')}`);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
let config;
|
|
45
|
+
try {
|
|
46
|
+
config = await readConfig();
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
console.error(` Error: ${err instanceof Error ? err.message : err}`);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
const iterDir = getIterationsDir();
|
|
53
|
+
const iteration = await getNextIteration(iterDir);
|
|
54
|
+
console.log(`\n Assay — Hallucinating ${type} (iteration ${iteration})`);
|
|
55
|
+
console.log(` Project: ${config.projectName}`);
|
|
56
|
+
console.log(` ─────────────────────────────────────\n`);
|
|
57
|
+
let result;
|
|
58
|
+
const startTime = Date.now();
|
|
59
|
+
try {
|
|
60
|
+
result = await streamHallucination(config, type);
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
console.error(`\n Error: ${err instanceof Error ? err.message : err}`);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
const durationMs = Date.now() - startTime;
|
|
67
|
+
// Create iteration directory only after successful generation
|
|
68
|
+
const iterPath = join(iterDir, String(iteration));
|
|
69
|
+
await mkdir(iterPath, { recursive: true });
|
|
70
|
+
// Save hallucinated document
|
|
71
|
+
const docPath = join(iterPath, `hallucinated-${type}.md`);
|
|
72
|
+
await writeFile(docPath, result.content, 'utf-8');
|
|
73
|
+
// Compute stats
|
|
74
|
+
const sectionCount = countSections(result.content);
|
|
75
|
+
const estimatedClaims = estimateClaims(result.content);
|
|
76
|
+
// Save metadata
|
|
77
|
+
const meta = {
|
|
78
|
+
type,
|
|
79
|
+
iteration,
|
|
80
|
+
model: 'claude-sonnet-4-5-20250929',
|
|
81
|
+
inputTokens: result.inputTokens,
|
|
82
|
+
outputTokens: result.outputTokens,
|
|
83
|
+
sectionCount,
|
|
84
|
+
estimatedClaims,
|
|
85
|
+
generatedAt: new Date().toISOString(),
|
|
86
|
+
durationMs,
|
|
87
|
+
};
|
|
88
|
+
const metaPath = join(iterPath, 'meta.json');
|
|
89
|
+
await writeFile(metaPath, JSON.stringify(meta, null, 2) + '\n', 'utf-8');
|
|
90
|
+
// Print summary
|
|
91
|
+
console.log(`\n ─────────────────────────────────────`);
|
|
92
|
+
console.log(` Saved: .assay/iterations/${iteration}/hallucinated-${type}.md`);
|
|
93
|
+
console.log(` Meta: .assay/iterations/${iteration}/meta.json`);
|
|
94
|
+
console.log(`\n Sections: ${sectionCount}`);
|
|
95
|
+
console.log(` Estimated claims: ${estimatedClaims}`);
|
|
96
|
+
console.log(` Input tokens: ${result.inputTokens.toLocaleString()}`);
|
|
97
|
+
console.log(` Output tokens: ${result.outputTokens.toLocaleString()}`);
|
|
98
|
+
console.log(` Duration: ${(durationMs / 1000).toFixed(1)}s\n`);
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=hallucinate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hallucinate.js","sourceRoot":"","sources":["../../src/commands/hallucinate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function initCommand(): Promise<void>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { configExists, writeConfig } from '../lib/config.js';
|
|
2
|
+
import { prompt, confirm, closePrompts } from '../lib/prompts.js';
|
|
3
|
+
export async function initCommand() {
|
|
4
|
+
console.log('\n Assay — Project Initialization\n');
|
|
5
|
+
if (await configExists()) {
|
|
6
|
+
const overwrite = await confirm(' .assay/config.json already exists. Overwrite?');
|
|
7
|
+
if (!overwrite) {
|
|
8
|
+
console.log(' Aborted.');
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
const projectName = await prompt(' Project name');
|
|
13
|
+
if (!projectName) {
|
|
14
|
+
console.error(' Error: Project name is required.');
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
const description = await prompt(' Description (what does it do?)');
|
|
18
|
+
if (!description) {
|
|
19
|
+
console.error(' Error: Description is required.');
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
const techStack = await prompt(' Tech stack', 'TypeScript, Node.js');
|
|
23
|
+
const targetAudience = await prompt(' Target audience', 'developers');
|
|
24
|
+
closePrompts();
|
|
25
|
+
const config = {
|
|
26
|
+
projectName,
|
|
27
|
+
description,
|
|
28
|
+
techStack,
|
|
29
|
+
targetAudience,
|
|
30
|
+
createdAt: new Date().toISOString(),
|
|
31
|
+
};
|
|
32
|
+
await writeConfig(config);
|
|
33
|
+
console.log('\n Created:');
|
|
34
|
+
console.log(' .assay/config.json');
|
|
35
|
+
console.log(' .assay/iterations/');
|
|
36
|
+
console.log('\n Tip: Add .assay/ to your .gitignore');
|
|
37
|
+
console.log(`\n Next: Run \`assay hallucinate\` to generate your first hallucinated spec.\n`);
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGlE,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;IAEpD,IAAI,MAAM,YAAY,EAAE,EAAE,CAAC;QACzB,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,iDAAiD,CAAC,CAAC;QACnF,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;YAC1B,OAAO;QACT,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC;IACnD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;QACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,kCAAkC,CAAC,CAAC;IACrE,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,cAAc,EAAE,qBAAqB,CAAC,CAAC;IACtE,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC,mBAAmB,EAAE,YAAY,CAAC,CAAC;IAEvE,YAAY,EAAE,CAAC;IAEf,MAAM,MAAM,GAAgB;QAC1B,WAAW;QACX,WAAW;QACX,SAAS;QACT,cAAc;QACd,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IAEF,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;IAE1B,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAC5B,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;IACtC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;IACtC,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,iFAAiF,CAAC,CAAC;AACjG,CAAC"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { readdir, readFile, mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { readConfig, getIterationsDir } from '../lib/config.js';
|
|
4
|
+
import { exists } from '../lib/fs-utils.js';
|
|
5
|
+
import { streamRegeneration } from '../lib/anthropic.js';
|
|
6
|
+
const VALID_TYPES = ['tos', 'api-docs', 'user-manual'];
|
|
7
|
+
async function findLatestIteration(iterDir) {
|
|
8
|
+
if (!(await exists(iterDir)))
|
|
9
|
+
return null;
|
|
10
|
+
const entries = await readdir(iterDir, { withFileTypes: true });
|
|
11
|
+
const nums = entries
|
|
12
|
+
.filter((e) => e.isDirectory())
|
|
13
|
+
.map((e) => parseInt(e.name, 10))
|
|
14
|
+
.filter((n) => !isNaN(n));
|
|
15
|
+
return nums.length === 0 ? null : Math.max(...nums);
|
|
16
|
+
}
|
|
17
|
+
async function findHallucinatedDoc(iterPath) {
|
|
18
|
+
const entries = await readdir(iterPath);
|
|
19
|
+
const doc = entries.find((e) => e.startsWith('hallucinated-') && e.endsWith('.md'));
|
|
20
|
+
if (!doc)
|
|
21
|
+
return null;
|
|
22
|
+
const type = doc.replace('hallucinated-', '').replace('.md', '');
|
|
23
|
+
if (!VALID_TYPES.includes(type))
|
|
24
|
+
return null;
|
|
25
|
+
return { path: join(iterPath, doc), type };
|
|
26
|
+
}
|
|
27
|
+
function countSections(content) {
|
|
28
|
+
const headings = content.match(/^#{1,3}\s+.+$/gm);
|
|
29
|
+
return headings?.length ?? 0;
|
|
30
|
+
}
|
|
31
|
+
function estimateClaims(content) {
|
|
32
|
+
const sentences = content.split(/[.!]\s+/);
|
|
33
|
+
let claims = 0;
|
|
34
|
+
for (const sentence of sentences) {
|
|
35
|
+
const hasNumber = /\d+/.test(sentence);
|
|
36
|
+
const hasDeclarative = /\b(is|are|will|provides?|supports?|includes?|requires?|limits?|allows?|ensures?|stores?|encrypts?|processes?|retains?)\b/i.test(sentence);
|
|
37
|
+
const hasSpecific = /\b(GB|MB|TB|ms|seconds?|minutes?|hours?|days?|%|per|AES|SHA|RSA|SSL|TLS|HTTPS|OAuth|JWT|REST|GraphQL)\b/i.test(sentence);
|
|
38
|
+
if (hasNumber || (hasDeclarative && hasSpecific)) {
|
|
39
|
+
claims++;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return claims;
|
|
43
|
+
}
|
|
44
|
+
export async function regenerateCommand(options) {
|
|
45
|
+
const iterDir = getIterationsDir();
|
|
46
|
+
// Determine source iteration
|
|
47
|
+
let sourceIteration;
|
|
48
|
+
if (options.iteration) {
|
|
49
|
+
sourceIteration = parseInt(options.iteration, 10);
|
|
50
|
+
if (isNaN(sourceIteration)) {
|
|
51
|
+
console.error(` Error: Invalid iteration "${options.iteration}".`);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
const latest = await findLatestIteration(iterDir);
|
|
57
|
+
if (latest === null) {
|
|
58
|
+
console.error(' Error: No iterations found. Run the full pipeline first:');
|
|
59
|
+
console.error(' assay hallucinate → assay extract → assay verify');
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
sourceIteration = latest;
|
|
63
|
+
}
|
|
64
|
+
const sourcePath = join(iterDir, String(sourceIteration));
|
|
65
|
+
// Verify all required files exist
|
|
66
|
+
const claimsPath = join(sourcePath, 'claims.json');
|
|
67
|
+
const verificationPath = join(sourcePath, 'verification.json');
|
|
68
|
+
if (!(await exists(claimsPath))) {
|
|
69
|
+
console.error(` Error: No claims.json found for iteration ${sourceIteration}.`);
|
|
70
|
+
console.error(' Run `assay extract` first.');
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
if (!(await exists(verificationPath))) {
|
|
74
|
+
console.error(` Error: No verification.json found for iteration ${sourceIteration}.`);
|
|
75
|
+
console.error(' Run `assay verify` first.');
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
const doc = await findHallucinatedDoc(sourcePath);
|
|
79
|
+
if (!doc) {
|
|
80
|
+
console.error(` Error: No hallucinated-*.md found in iteration ${sourceIteration}.`);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
// Read all inputs
|
|
84
|
+
let config;
|
|
85
|
+
try {
|
|
86
|
+
config = await readConfig();
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
console.error(` Error: ${err instanceof Error ? err.message : err}`);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
const priorDocument = await readFile(doc.path, 'utf-8');
|
|
93
|
+
const extraction = JSON.parse(await readFile(claimsPath, 'utf-8'));
|
|
94
|
+
const verification = JSON.parse(await readFile(verificationPath, 'utf-8'));
|
|
95
|
+
const { verdicts } = verification;
|
|
96
|
+
const total = verification.verifications.length;
|
|
97
|
+
const assessed = total - verdicts.na;
|
|
98
|
+
const score = assessed > 0
|
|
99
|
+
? ((verdicts.pass + verdicts.partial * 0.5) / assessed) * 100
|
|
100
|
+
: 0;
|
|
101
|
+
const nextIteration = sourceIteration + 1;
|
|
102
|
+
console.log(`\n Assay — Regenerating ${doc.type} (iteration ${sourceIteration} → ${nextIteration})`);
|
|
103
|
+
console.log(` Project: ${config.projectName}`);
|
|
104
|
+
console.log(` Prior compliance: ${score.toFixed(1)}% (${verdicts.pass} pass, ${verdicts.partial} partial, ${verdicts.fail} fail)`);
|
|
105
|
+
console.log(` ─────────────────────────────────────\n`);
|
|
106
|
+
const ctx = {
|
|
107
|
+
config,
|
|
108
|
+
type: doc.type,
|
|
109
|
+
priorDocument,
|
|
110
|
+
extraction,
|
|
111
|
+
verification,
|
|
112
|
+
};
|
|
113
|
+
let result;
|
|
114
|
+
const startTime = Date.now();
|
|
115
|
+
try {
|
|
116
|
+
result = await streamRegeneration(ctx);
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
console.error(`\n Error: ${err instanceof Error ? err.message : err}`);
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
const durationMs = Date.now() - startTime;
|
|
123
|
+
// Create next iteration directory
|
|
124
|
+
const nextPath = join(iterDir, String(nextIteration));
|
|
125
|
+
await mkdir(nextPath, { recursive: true });
|
|
126
|
+
// Save regenerated document
|
|
127
|
+
const docPath = join(nextPath, `hallucinated-${doc.type}.md`);
|
|
128
|
+
await writeFile(docPath, result.content, 'utf-8');
|
|
129
|
+
// Compute stats
|
|
130
|
+
const sectionCount = countSections(result.content);
|
|
131
|
+
const estimatedClaimCount = estimateClaims(result.content);
|
|
132
|
+
// Save metadata
|
|
133
|
+
const meta = {
|
|
134
|
+
type: doc.type,
|
|
135
|
+
iteration: nextIteration,
|
|
136
|
+
model: 'claude-sonnet-4-5-20250929',
|
|
137
|
+
inputTokens: result.inputTokens,
|
|
138
|
+
outputTokens: result.outputTokens,
|
|
139
|
+
sectionCount,
|
|
140
|
+
estimatedClaims: estimatedClaimCount,
|
|
141
|
+
generatedAt: new Date().toISOString(),
|
|
142
|
+
durationMs,
|
|
143
|
+
};
|
|
144
|
+
const metaPath = join(nextPath, 'meta.json');
|
|
145
|
+
await writeFile(metaPath, JSON.stringify(meta, null, 2) + '\n', 'utf-8');
|
|
146
|
+
// Print summary
|
|
147
|
+
console.log(`\n ─────────────────────────────────────`);
|
|
148
|
+
console.log(` Saved: .assay/iterations/${nextIteration}/hallucinated-${doc.type}.md`);
|
|
149
|
+
console.log(` Meta: .assay/iterations/${nextIteration}/meta.json`);
|
|
150
|
+
console.log(`\n Sections: ${sectionCount}`);
|
|
151
|
+
console.log(` Estimated claims: ${estimatedClaimCount}`);
|
|
152
|
+
console.log(` Input tokens: ${result.inputTokens.toLocaleString()}`);
|
|
153
|
+
console.log(` Output tokens: ${result.outputTokens.toLocaleString()}`);
|
|
154
|
+
console.log(` Duration: ${(durationMs / 1000).toFixed(1)}s`);
|
|
155
|
+
console.log(`\n The convergence loop continues.`);
|
|
156
|
+
console.log(` Next: Run \`assay extract -i ${nextIteration}\` → \`assay verify\` → \`assay report\`\n`);
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=regenerate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"regenerate.js","sourceRoot":"","sources":["../../src/commands/regenerate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { readdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join, resolve } from 'node:path';
|
|
3
|
+
import { readConfig, getIterationsDir } from '../lib/config.js';
|
|
4
|
+
import { exists } from '../lib/fs-utils.js';
|
|
5
|
+
import { indexCodebase } from '../lib/codebase-indexer.js';
|
|
6
|
+
import { generateRemediationTasks } from '../lib/remediator.js';
|
|
7
|
+
import { generateRemediationReport } from '../lib/remediation-generator.js';
|
|
8
|
+
async function findLatestIteration(iterDir) {
|
|
9
|
+
if (!(await exists(iterDir)))
|
|
10
|
+
return null;
|
|
11
|
+
const entries = await readdir(iterDir, { withFileTypes: true });
|
|
12
|
+
const nums = entries
|
|
13
|
+
.filter((e) => e.isDirectory())
|
|
14
|
+
.map((e) => parseInt(e.name, 10))
|
|
15
|
+
.filter((n) => !isNaN(n));
|
|
16
|
+
return nums.length === 0 ? null : Math.max(...nums);
|
|
17
|
+
}
|
|
18
|
+
export async function remediateCommand(options) {
|
|
19
|
+
const iterDir = getIterationsDir();
|
|
20
|
+
const repoPath = resolve(options.repo || '.');
|
|
21
|
+
const threshold = parseFloat(options.threshold || '95');
|
|
22
|
+
// Determine iteration
|
|
23
|
+
let iteration;
|
|
24
|
+
if (options.iteration) {
|
|
25
|
+
iteration = parseInt(options.iteration, 10);
|
|
26
|
+
if (isNaN(iteration)) {
|
|
27
|
+
console.error(` Error: Invalid iteration "${options.iteration}".`);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
const latest = await findLatestIteration(iterDir);
|
|
33
|
+
if (latest === null) {
|
|
34
|
+
console.error(' Error: No iterations found. Run the full pipeline first:');
|
|
35
|
+
console.error(' assay hallucinate → assay extract → assay verify');
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
iteration = latest;
|
|
39
|
+
}
|
|
40
|
+
const iterPath = join(iterDir, String(iteration));
|
|
41
|
+
const claimsPath = join(iterPath, 'claims.json');
|
|
42
|
+
const verificationPath = join(iterPath, 'verification.json');
|
|
43
|
+
if (!(await exists(claimsPath))) {
|
|
44
|
+
console.error(` Error: No claims.json found for iteration ${iteration}.`);
|
|
45
|
+
console.error(' Run `assay extract` first.');
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
if (!(await exists(verificationPath))) {
|
|
49
|
+
console.error(` Error: No verification.json found for iteration ${iteration}.`);
|
|
50
|
+
console.error(' Run `assay verify` first.');
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
// Read inputs
|
|
54
|
+
const extraction = JSON.parse(await readFile(claimsPath, 'utf-8'));
|
|
55
|
+
const verification = JSON.parse(await readFile(verificationPath, 'utf-8'));
|
|
56
|
+
// Compute current score
|
|
57
|
+
const { verdicts, verifications } = verification;
|
|
58
|
+
const total = verifications.length;
|
|
59
|
+
const assessed = total - verdicts.na;
|
|
60
|
+
const currentScore = assessed > 0
|
|
61
|
+
? ((verdicts.pass + verdicts.partial * 0.5) / assessed) * 100
|
|
62
|
+
: 0;
|
|
63
|
+
// Check convergence
|
|
64
|
+
if (currentScore >= threshold) {
|
|
65
|
+
console.log(`\n Assay — Remediation (iteration ${iteration})`);
|
|
66
|
+
console.log(` ─────────────────────────────────────`);
|
|
67
|
+
console.log(`\n CONVERGED: Compliance score ${currentScore.toFixed(1)}% >= ${threshold}% threshold.`);
|
|
68
|
+
console.log(` No remediation tasks needed.\n`);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
// Read config for project name
|
|
72
|
+
let projectName;
|
|
73
|
+
try {
|
|
74
|
+
const config = await readConfig();
|
|
75
|
+
projectName = config.projectName;
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// Config is optional for display purposes
|
|
79
|
+
}
|
|
80
|
+
console.log(`\n Assay — Generating remediation tasks (iteration ${iteration})`);
|
|
81
|
+
console.log(` Codebase: ${repoPath}`);
|
|
82
|
+
console.log(` Score: ${currentScore.toFixed(1)}% (target: ${threshold}%)`);
|
|
83
|
+
console.log(` Gap: ${(threshold - currentScore).toFixed(1)} points`);
|
|
84
|
+
console.log(` ─────────────────────────────────────\n`);
|
|
85
|
+
// Filter verifications
|
|
86
|
+
const failVerifications = verifications.filter((v) => v.verdict === 'FAIL');
|
|
87
|
+
const partialVerifications = verifications.filter((v) => v.verdict === 'PARTIAL');
|
|
88
|
+
console.log(` Claims to remediate: ${failVerifications.length} FAIL, ${partialVerifications.length} PARTIAL\n`);
|
|
89
|
+
// Index codebase
|
|
90
|
+
console.log(` Indexing codebase...`);
|
|
91
|
+
const index = await indexCodebase(repoPath);
|
|
92
|
+
console.log(` ${index.summary.split('\n').join('\n ')}\n`);
|
|
93
|
+
// Generate remediation tasks
|
|
94
|
+
const startTime = Date.now();
|
|
95
|
+
const { tasks, inputTokens, outputTokens } = await generateRemediationTasks(failVerifications, partialVerifications, extraction.claims, index, (msg) => console.log(` ${msg}`));
|
|
96
|
+
const durationMs = Date.now() - startTime;
|
|
97
|
+
// Build plan
|
|
98
|
+
const tasksBySeverity = { critical: 0, high: 0, medium: 0, low: 0 };
|
|
99
|
+
for (const t of tasks) {
|
|
100
|
+
tasksBySeverity[t.severity]++;
|
|
101
|
+
}
|
|
102
|
+
const plan = {
|
|
103
|
+
iteration,
|
|
104
|
+
codebasePath: repoPath,
|
|
105
|
+
currentScore,
|
|
106
|
+
targetScore: threshold,
|
|
107
|
+
totalTasks: tasks.length,
|
|
108
|
+
tasksByVerdict: {
|
|
109
|
+
fail: tasks.filter((t) => t.verdict === 'FAIL').length,
|
|
110
|
+
partial: tasks.filter((t) => t.verdict === 'PARTIAL').length,
|
|
111
|
+
},
|
|
112
|
+
tasksBySeverity,
|
|
113
|
+
tasks,
|
|
114
|
+
generatedAt: new Date().toISOString(),
|
|
115
|
+
inputTokens,
|
|
116
|
+
outputTokens,
|
|
117
|
+
durationMs,
|
|
118
|
+
};
|
|
119
|
+
// Write outputs
|
|
120
|
+
const jsonPath = join(iterPath, 'remediation.json');
|
|
121
|
+
const mdPath = join(iterPath, 'remediation.md');
|
|
122
|
+
await writeFile(jsonPath, JSON.stringify(plan, null, 2) + '\n', 'utf-8');
|
|
123
|
+
const report = generateRemediationReport(plan, projectName);
|
|
124
|
+
await writeFile(mdPath, report, 'utf-8');
|
|
125
|
+
// Print summary
|
|
126
|
+
console.log(`\n ─────────────────────────────────────`);
|
|
127
|
+
console.log(` Saved: .assay/iterations/${iteration}/remediation.json`);
|
|
128
|
+
console.log(` Saved: .assay/iterations/${iteration}/remediation.md`);
|
|
129
|
+
console.log(`\n Remediation Tasks: ${tasks.length}`);
|
|
130
|
+
console.log(` FAIL tasks: ${plan.tasksByVerdict.fail}`);
|
|
131
|
+
console.log(` PARTIAL tasks: ${plan.tasksByVerdict.partial}`);
|
|
132
|
+
console.log(`\n By severity:`);
|
|
133
|
+
if (tasksBySeverity.critical > 0)
|
|
134
|
+
console.log(` Critical: ${tasksBySeverity.critical}`);
|
|
135
|
+
if (tasksBySeverity.high > 0)
|
|
136
|
+
console.log(` High: ${tasksBySeverity.high}`);
|
|
137
|
+
if (tasksBySeverity.medium > 0)
|
|
138
|
+
console.log(` Medium: ${tasksBySeverity.medium}`);
|
|
139
|
+
if (tasksBySeverity.low > 0)
|
|
140
|
+
console.log(` Low: ${tasksBySeverity.low}`);
|
|
141
|
+
// Show top priority tasks
|
|
142
|
+
const topTasks = tasks.slice(0, 3);
|
|
143
|
+
if (topTasks.length > 0) {
|
|
144
|
+
console.log(`\n Top priority tasks:`);
|
|
145
|
+
for (const t of topTasks) {
|
|
146
|
+
console.log(` ${t.id} [${t.severity}] ${t.title}`);
|
|
147
|
+
console.log(` → ${t.targetFiles.join(', ')}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
console.log(`\n Input tokens: ${inputTokens.toLocaleString()}`);
|
|
151
|
+
console.log(` Output tokens: ${outputTokens.toLocaleString()}`);
|
|
152
|
+
console.log(` Duration: ${(durationMs / 1000).toFixed(1)}s`);
|
|
153
|
+
console.log(`\n Fix the tasks above, then re-verify: \`assay verify → assay report\`\n`);
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=remediate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remediate.js","sourceRoot":"","sources":["../../src/commands/remediate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { readdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { getIterationsDir, readConfig } from '../lib/config.js';
|
|
4
|
+
import { exists } from '../lib/fs-utils.js';
|
|
5
|
+
import { generateGapReport } from '../lib/report-generator.js';
|
|
6
|
+
async function findLatestIteration(iterDir) {
|
|
7
|
+
if (!(await exists(iterDir)))
|
|
8
|
+
return null;
|
|
9
|
+
const entries = await readdir(iterDir, { withFileTypes: true });
|
|
10
|
+
const nums = entries
|
|
11
|
+
.filter((e) => e.isDirectory())
|
|
12
|
+
.map((e) => parseInt(e.name, 10))
|
|
13
|
+
.filter((n) => !isNaN(n));
|
|
14
|
+
return nums.length === 0 ? null : Math.max(...nums);
|
|
15
|
+
}
|
|
16
|
+
export async function reportCommand(options) {
|
|
17
|
+
const iterDir = getIterationsDir();
|
|
18
|
+
// Determine iteration
|
|
19
|
+
let iteration;
|
|
20
|
+
if (options.iteration) {
|
|
21
|
+
iteration = parseInt(options.iteration, 10);
|
|
22
|
+
if (isNaN(iteration)) {
|
|
23
|
+
console.error(` Error: Invalid iteration "${options.iteration}".`);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
const latest = await findLatestIteration(iterDir);
|
|
29
|
+
if (latest === null) {
|
|
30
|
+
console.error(' Error: No iterations found.');
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
iteration = latest;
|
|
34
|
+
}
|
|
35
|
+
const iterPath = join(iterDir, String(iteration));
|
|
36
|
+
const claimsPath = join(iterPath, 'claims.json');
|
|
37
|
+
const verificationPath = join(iterPath, 'verification.json');
|
|
38
|
+
if (!(await exists(claimsPath))) {
|
|
39
|
+
console.error(` Error: No claims.json found for iteration ${iteration}.`);
|
|
40
|
+
console.error(' Run `assay extract` first.');
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
if (!(await exists(verificationPath))) {
|
|
44
|
+
console.error(` Error: No verification.json found for iteration ${iteration}.`);
|
|
45
|
+
console.error(' Run `assay verify` first.');
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
const extraction = JSON.parse(await readFile(claimsPath, 'utf-8'));
|
|
49
|
+
const verification = JSON.parse(await readFile(verificationPath, 'utf-8'));
|
|
50
|
+
// Try to get project name from config
|
|
51
|
+
let projectName;
|
|
52
|
+
try {
|
|
53
|
+
const config = await readConfig();
|
|
54
|
+
projectName = config.projectName;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// Config not required for report
|
|
58
|
+
}
|
|
59
|
+
console.log(`\n Assay — Generating gap report (iteration ${iteration})`);
|
|
60
|
+
console.log(` ─────────────────────────────────────\n`);
|
|
61
|
+
const report = generateGapReport({
|
|
62
|
+
extraction,
|
|
63
|
+
verification,
|
|
64
|
+
projectName,
|
|
65
|
+
});
|
|
66
|
+
const reportPath = join(iterPath, 'gap-report.md');
|
|
67
|
+
await writeFile(reportPath, report, 'utf-8');
|
|
68
|
+
const { verdicts } = verification;
|
|
69
|
+
const total = verification.verifications.length;
|
|
70
|
+
const assessed = total - verdicts.na;
|
|
71
|
+
const score = assessed > 0
|
|
72
|
+
? ((verdicts.pass + verdicts.partial * 0.5) / assessed) * 100
|
|
73
|
+
: 0;
|
|
74
|
+
console.log(` Saved: .assay/iterations/${iteration}/gap-report.md`);
|
|
75
|
+
console.log(`\n Report Summary:`);
|
|
76
|
+
console.log(` Total claims: ${total}`);
|
|
77
|
+
console.log(` PASS: ${verdicts.pass}`);
|
|
78
|
+
console.log(` PARTIAL: ${verdicts.partial}`);
|
|
79
|
+
console.log(` FAIL: ${verdicts.fail}`);
|
|
80
|
+
console.log(` N/A: ${verdicts.na}`);
|
|
81
|
+
console.log(` Compliance score: ${score.toFixed(1)}%`);
|
|
82
|
+
console.log(`\n The gap report is ready for delivery.\n`);
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/commands/report.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAG/D,KAAK,UAAU,mBAAmB,CAAC,OAAe;IAChD,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1C,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAChE,MAAM,IAAI,GAAG,OAAO;SACjB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;SAC9B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;SAChC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5B,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAEnC;IACC,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;IAEnC,sBAAsB;IACtB,IAAI,SAAiB,CAAC;IACtB,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACtB,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAC5C,IAAI,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;YACrB,OAAO,CAAC,KAAK,CAAC,+BAA+B,OAAO,CAAC,SAAS,IAAI,CAAC,CAAC;YACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;SAAM,CAAC;QACN,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,OAAO,CAAC,CAAC;QAClD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;YAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,SAAS,GAAG,MAAM,CAAC;IACrB,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;IAClD,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;IACjD,MAAM,gBAAgB,GAAG,IAAI,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC;IAE7D,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC;QAChC,OAAO,CAAC,KAAK,CAAC,+CAA+C,SAAS,GAAG,CAAC,CAAC;QAC3E,OAAO,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC;QACtC,OAAO,CAAC,KAAK,CAAC,qDAAqD,SAAS,GAAG,CAAC,CAAC;QACjF,OAAO,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;QAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAC3B,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAChB,CAAC;IAEtB,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAC7B,MAAM,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC,CACpB,CAAC;IAExB,sCAAsC;IACtC,IAAI,WAA+B,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;QAClC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,iCAAiC;IACnC,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,gDAAgD,SAAS,GAAG,CAAC,CAAC;IAC1E,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;IAEzD,MAAM,MAAM,GAAG,iBAAiB,CAAC;QAC/B,UAAU;QACV,YAAY;QACZ,WAAW;KACZ,CAAC,CAAC;IAEH,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;IACnD,MAAM,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAE7C,MAAM,EAAE,QAAQ,EAAE,GAAG,YAAY,CAAC;IAClC,MAAM,KAAK,GAAG,YAAY,CAAC,aAAa,CAAC,MAAM,CAAC;IAChD,MAAM,QAAQ,GAAG,KAAK,GAAG,QAAQ,CAAC,EAAE,CAAC;IACrC,MAAM,KAAK,GACT,QAAQ,GAAG,CAAC;QACV,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,GAAG,QAAQ,CAAC,OAAO,GAAG,GAAG,CAAC,GAAG,QAAQ,CAAC,GAAG,GAAG;QAC7D,CAAC,CAAC,CAAC,CAAC;IAER,OAAO,CAAC,GAAG,CAAC,8BAA8B,SAAS,gBAAgB,CAAC,CAAC;IACrE,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;IACnC,OAAO,CAAC,GAAG,CAAC,yBAAyB,KAAK,EAAE,CAAC,CAAC;IAC9C,OAAO,CAAC,GAAG,CAAC,yBAAyB,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACtD,OAAO,CAAC,GAAG,CAAC,yBAAyB,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACzD,OAAO,CAAC,GAAG,CAAC,yBAAyB,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACtD,OAAO,CAAC,GAAG,CAAC,yBAAyB,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,yBAAyB,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC1D,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;AAC7D,CAAC"}
|