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.
Files changed (93) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +553 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +80 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/assess.d.ts +6 -0
  7. package/dist/commands/assess.js +267 -0
  8. package/dist/commands/assess.js.map +1 -0
  9. package/dist/commands/describe.d.ts +3 -0
  10. package/dist/commands/describe.js +114 -0
  11. package/dist/commands/describe.js.map +1 -0
  12. package/dist/commands/extract.d.ts +4 -0
  13. package/dist/commands/extract.js +144 -0
  14. package/dist/commands/extract.js.map +1 -0
  15. package/dist/commands/hallucinate.d.ts +3 -0
  16. package/dist/commands/hallucinate.js +100 -0
  17. package/dist/commands/hallucinate.js.map +1 -0
  18. package/dist/commands/init.d.ts +1 -0
  19. package/dist/commands/init.js +39 -0
  20. package/dist/commands/init.js.map +1 -0
  21. package/dist/commands/regenerate.d.ts +3 -0
  22. package/dist/commands/regenerate.js +158 -0
  23. package/dist/commands/regenerate.js.map +1 -0
  24. package/dist/commands/remediate.d.ts +5 -0
  25. package/dist/commands/remediate.js +155 -0
  26. package/dist/commands/remediate.js.map +1 -0
  27. package/dist/commands/report.d.ts +3 -0
  28. package/dist/commands/report.js +84 -0
  29. package/dist/commands/report.js.map +1 -0
  30. package/dist/commands/reverse.d.ts +9 -0
  31. package/dist/commands/reverse.js +115 -0
  32. package/dist/commands/reverse.js.map +1 -0
  33. package/dist/commands/verify.d.ts +4 -0
  34. package/dist/commands/verify.js +112 -0
  35. package/dist/commands/verify.js.map +1 -0
  36. package/dist/lib/anthropic.d.ts +13 -0
  37. package/dist/lib/anthropic.js +60 -0
  38. package/dist/lib/anthropic.js.map +1 -0
  39. package/dist/lib/assessment-reporter.d.ts +5 -0
  40. package/dist/lib/assessment-reporter.js +266 -0
  41. package/dist/lib/assessment-reporter.js.map +1 -0
  42. package/dist/lib/claim-extractor.d.ts +6 -0
  43. package/dist/lib/claim-extractor.js +138 -0
  44. package/dist/lib/claim-extractor.js.map +1 -0
  45. package/dist/lib/code-verifier.d.ts +7 -0
  46. package/dist/lib/code-verifier.js +265 -0
  47. package/dist/lib/code-verifier.js.map +1 -0
  48. package/dist/lib/codebase-indexer.d.ts +15 -0
  49. package/dist/lib/codebase-indexer.js +156 -0
  50. package/dist/lib/codebase-indexer.js.map +1 -0
  51. package/dist/lib/config.d.ts +7 -0
  52. package/dist/lib/config.js +38 -0
  53. package/dist/lib/config.js.map +1 -0
  54. package/dist/lib/constraint-engine.d.ts +2 -0
  55. package/dist/lib/constraint-engine.js +337 -0
  56. package/dist/lib/constraint-engine.js.map +1 -0
  57. package/dist/lib/fs-utils.d.ts +1 -0
  58. package/dist/lib/fs-utils.js +11 -0
  59. package/dist/lib/fs-utils.js.map +1 -0
  60. package/dist/lib/guided-generator.d.ts +2 -0
  61. package/dist/lib/guided-generator.js +195 -0
  62. package/dist/lib/guided-generator.js.map +1 -0
  63. package/dist/lib/inventory-extractor.d.ts +7 -0
  64. package/dist/lib/inventory-extractor.js +238 -0
  65. package/dist/lib/inventory-extractor.js.map +1 -0
  66. package/dist/lib/prompts.d.ts +3 -0
  67. package/dist/lib/prompts.js +50 -0
  68. package/dist/lib/prompts.js.map +1 -0
  69. package/dist/lib/publisher.d.ts +2 -0
  70. package/dist/lib/publisher.js +71 -0
  71. package/dist/lib/publisher.js.map +1 -0
  72. package/dist/lib/remediation-generator.d.ts +2 -0
  73. package/dist/lib/remediation-generator.js +136 -0
  74. package/dist/lib/remediation-generator.js.map +1 -0
  75. package/dist/lib/remediator.d.ts +7 -0
  76. package/dist/lib/remediator.js +209 -0
  77. package/dist/lib/remediator.js.map +1 -0
  78. package/dist/lib/report-generator.d.ts +8 -0
  79. package/dist/lib/report-generator.js +190 -0
  80. package/dist/lib/report-generator.js.map +1 -0
  81. package/dist/lib/requirements-generator.d.ts +14 -0
  82. package/dist/lib/requirements-generator.js +311 -0
  83. package/dist/lib/requirements-generator.js.map +1 -0
  84. package/dist/lib/spec-synthesizer.d.ts +2 -0
  85. package/dist/lib/spec-synthesizer.js +136 -0
  86. package/dist/lib/spec-synthesizer.js.map +1 -0
  87. package/dist/lib/system-prompts.d.ts +12 -0
  88. package/dist/lib/system-prompts.js +254 -0
  89. package/dist/lib/system-prompts.js.map +1 -0
  90. package/dist/types.d.ts +243 -0
  91. package/dist/types.js +2 -0
  92. package/dist/types.js.map +1 -0
  93. package/package.json +49 -0
@@ -0,0 +1,238 @@
1
+ import { getClient, MODEL } from './anthropic.js';
2
+ import { readFileContent } from './codebase-indexer.js';
3
+ const INVENTORY_SYSTEM_PROMPT = `You are a codebase analyst. Given a file tree and key file contents, identify ALL routes, database tables, and permission systems in the application.
4
+
5
+ INSTRUCTIONS:
6
+
7
+ 1. ROUTES: Identify every route/page in the application.
8
+ - Look for router configurations, page components, API endpoints
9
+ - Group routes into domains: auth, billing, admin, dashboard, settings, api, public, etc.
10
+ - For each route identify: path, component file, domain, guard/permission check, required roles, database tables used
11
+
12
+ 2. TABLES: Identify every database table.
13
+ - Look for schema definitions (Prisma, SQL, Drizzle, Supabase migrations, etc.)
14
+ - For each table: name, domain, columns, relationships to other tables
15
+
16
+ 3. PERMISSIONS: Identify every permission/role system.
17
+ - Look for role definitions, permission codes, access control lists
18
+ - Flag any conflicts between different permission systems
19
+ - For each system: name, permission codes, roles, conflicts
20
+
21
+ OUTPUT FORMAT:
22
+ Return ONLY a JSON object (no markdown fences, no commentary):
23
+ {
24
+ "routes": [
25
+ {
26
+ "path": "/dashboard",
27
+ "component": "src/pages/Dashboard.tsx",
28
+ "domain": "dashboard",
29
+ "guard": "requireAuth",
30
+ "roles": ["user", "admin"],
31
+ "tables": ["users", "activity"]
32
+ }
33
+ ],
34
+ "tables": [
35
+ {
36
+ "name": "users",
37
+ "domain": "auth",
38
+ "columns": ["id", "email", "role", "created_at"],
39
+ "relationships": ["has_many:orders", "has_one:profile"]
40
+ }
41
+ ],
42
+ "permissions": [
43
+ {
44
+ "system": "RBAC",
45
+ "codes": ["VIEW_DASHBOARD", "MANAGE_USERS"],
46
+ "roles": ["admin", "user", "guest"],
47
+ "conflicts": ["Role 'viewer' defined in auth.ts but not in permissions.ts"]
48
+ }
49
+ ]
50
+ }
51
+
52
+ Be thorough. Include ALL routes, tables, and permission systems you find. If you cannot determine a field, use an empty string or empty array rather than omitting it.`;
53
+ /** Patterns that indicate router/route configuration files */
54
+ const ROUTER_PATTERNS = [
55
+ /router/i,
56
+ /routes/i,
57
+ /App\.tsx$/,
58
+ /App\.jsx$/,
59
+ /app\.ts$/,
60
+ /layout\.tsx$/,
61
+ /layout\.jsx$/,
62
+ /page\.tsx$/,
63
+ /page\.jsx$/,
64
+ /_app\.tsx$/,
65
+ /_app\.jsx$/,
66
+ ];
67
+ /**
68
+ * Select key files to send to Claude for inventory extraction.
69
+ * Prioritizes configuration, auth, API routes, schemas, and router files.
70
+ * Limits to maxFiles to avoid context overflow.
71
+ */
72
+ function selectFilesForContext(index, maxFiles = 30) {
73
+ const selected = new Set();
74
+ // Add key files identified by the indexer (config, auth, API routes, schemas)
75
+ for (const kf of index.keyFiles) {
76
+ if (kf.reason === 'configuration' ||
77
+ kf.reason === 'authentication' ||
78
+ kf.reason === 'API route' ||
79
+ kf.reason === 'schema/database') {
80
+ selected.add(kf.path);
81
+ }
82
+ }
83
+ // Scan file tree for router-related files
84
+ for (const filePath of index.fileTree) {
85
+ if (ROUTER_PATTERNS.some((p) => p.test(filePath))) {
86
+ selected.add(filePath);
87
+ }
88
+ }
89
+ // Convert to array and limit
90
+ const result = Array.from(selected);
91
+ if (result.length > maxFiles) {
92
+ return result.slice(0, maxFiles);
93
+ }
94
+ return result;
95
+ }
96
+ /**
97
+ * Strip markdown code fences from Claude's response and parse as JSON.
98
+ * Handles truncated responses by closing unclosed braces/brackets.
99
+ */
100
+ function parseInventoryResponse(rawText) {
101
+ let jsonText = rawText.trim();
102
+ // Remove opening code fence
103
+ if (jsonText.startsWith('```')) {
104
+ const firstNewline = jsonText.indexOf('\n');
105
+ if (firstNewline !== -1) {
106
+ jsonText = jsonText.slice(firstNewline + 1);
107
+ }
108
+ }
109
+ // Remove closing code fence
110
+ const lastFence = jsonText.lastIndexOf('```');
111
+ if (lastFence !== -1) {
112
+ jsonText = jsonText.slice(0, lastFence);
113
+ }
114
+ jsonText = jsonText.trim();
115
+ // Handle truncation: try to close unclosed structures
116
+ if (!jsonText.endsWith('}')) {
117
+ // Find the last complete object close
118
+ const lastCloseBrace = jsonText.lastIndexOf('}');
119
+ if (lastCloseBrace !== -1) {
120
+ jsonText = jsonText.slice(0, lastCloseBrace + 1);
121
+ // Count unclosed brackets and braces to close them
122
+ let openBraces = 0;
123
+ let openBrackets = 0;
124
+ for (const ch of jsonText) {
125
+ if (ch === '{')
126
+ openBraces++;
127
+ if (ch === '}')
128
+ openBraces--;
129
+ if (ch === '[')
130
+ openBrackets++;
131
+ if (ch === ']')
132
+ openBrackets--;
133
+ }
134
+ // Close any remaining open structures
135
+ let suffix = '';
136
+ for (let i = 0; i < openBrackets; i++)
137
+ suffix += ']';
138
+ for (let i = 0; i < openBraces; i++)
139
+ suffix += '}';
140
+ jsonText += suffix;
141
+ }
142
+ }
143
+ let parsed;
144
+ try {
145
+ parsed = JSON.parse(jsonText);
146
+ }
147
+ catch {
148
+ throw new Error(`Failed to parse inventory response as JSON.\n` +
149
+ `First 300 chars: ${jsonText.slice(0, 300)}`);
150
+ }
151
+ const obj = parsed;
152
+ // Validate and normalize routes
153
+ const routes = Array.isArray(obj.routes)
154
+ ? obj.routes.map((r) => ({
155
+ path: String(r.path || ''),
156
+ component: String(r.component || ''),
157
+ domain: String(r.domain || 'unknown'),
158
+ guard: r.guard ? String(r.guard) : undefined,
159
+ roles: Array.isArray(r.roles) ? r.roles.map(String) : undefined,
160
+ tables: Array.isArray(r.tables) ? r.tables.map(String) : undefined,
161
+ }))
162
+ : [];
163
+ // Validate and normalize tables
164
+ const tables = Array.isArray(obj.tables)
165
+ ? obj.tables.map((t) => ({
166
+ name: String(t.name || ''),
167
+ domain: String(t.domain || 'unknown'),
168
+ columns: Array.isArray(t.columns) ? t.columns.map(String) : [],
169
+ relationships: Array.isArray(t.relationships) ? t.relationships.map(String) : [],
170
+ }))
171
+ : [];
172
+ // Validate and normalize permissions
173
+ const permissions = Array.isArray(obj.permissions)
174
+ ? obj.permissions.map((p) => ({
175
+ system: String(p.system || ''),
176
+ codes: Array.isArray(p.codes) ? p.codes.map(String) : [],
177
+ roles: Array.isArray(p.roles) ? p.roles.map(String) : [],
178
+ conflicts: Array.isArray(p.conflicts) ? p.conflicts.map(String) : undefined,
179
+ }))
180
+ : [];
181
+ return { routes, tables, permissions };
182
+ }
183
+ const MAX_FILE_CHARS = 5000;
184
+ export async function extractInventory(index, onProgress) {
185
+ const client = getClient();
186
+ // Select files to read for context
187
+ const filesToRead = selectFilesForContext(index);
188
+ onProgress?.(` Reading ${filesToRead.length} key files...`);
189
+ // Read file contents (truncated)
190
+ let fileContents = '';
191
+ let filesRead = 0;
192
+ for (const filePath of filesToRead) {
193
+ const content = await readFileContent(index.rootPath, filePath);
194
+ if (content) {
195
+ const truncated = content.length > MAX_FILE_CHARS
196
+ ? content.slice(0, MAX_FILE_CHARS) + '\n[... truncated]'
197
+ : content;
198
+ fileContents += `\n--- FILE: ${filePath} ---\n${truncated}\n`;
199
+ filesRead++;
200
+ }
201
+ }
202
+ onProgress?.(` Sending ${filesRead} files to Claude for inventory extraction...`);
203
+ // Build file tree string (limit to avoid context overflow)
204
+ const treeStr = index.fileTree.slice(0, 3000).join('\n');
205
+ const userMessage = [
206
+ `Analyze this codebase and extract the full inventory of routes, database tables, and permission systems.`,
207
+ ``,
208
+ `CODEBASE FILE TREE (${index.totalFiles} files total):`,
209
+ treeStr,
210
+ ``,
211
+ `FRAMEWORKS DETECTED: ${index.frameworks.join(', ') || 'unknown'}`,
212
+ ``,
213
+ `KEY FILE CONTENTS:`,
214
+ fileContents,
215
+ ].join('\n');
216
+ const response = await client.messages.create({
217
+ model: MODEL,
218
+ max_tokens: 16_000,
219
+ system: INVENTORY_SYSTEM_PROMPT,
220
+ messages: [
221
+ {
222
+ role: 'user',
223
+ content: userMessage,
224
+ },
225
+ ],
226
+ });
227
+ const rawText = response.content
228
+ .filter((b) => b.type === 'text')
229
+ .map((b) => b.text)
230
+ .join('');
231
+ const inventory = parseInventoryResponse(rawText);
232
+ return {
233
+ inventory,
234
+ inputTokens: response.usage.input_tokens,
235
+ outputTokens: response.usage.output_tokens,
236
+ };
237
+ }
238
+ //# sourceMappingURL=inventory-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inventory-extractor.js","sourceRoot":"","sources":["../../src/lib/inventory-extractor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AASxD,MAAM,uBAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uKAiDuI,CAAC;AAExK,8DAA8D;AAC9D,MAAM,eAAe,GAAG;IACtB,SAAS;IACT,SAAS;IACT,WAAW;IACX,WAAW;IACX,UAAU;IACV,cAAc;IACd,cAAc;IACd,YAAY;IACZ,YAAY;IACZ,YAAY;IACZ,YAAY;CACb,CAAC;AAEF;;;;GAIG;AACH,SAAS,qBAAqB,CAC5B,KAAoB,EACpB,QAAQ,GAAG,EAAE;IAEb,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IAEnC,8EAA8E;IAC9E,KAAK,MAAM,EAAE,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QAChC,IACE,EAAE,CAAC,MAAM,KAAK,eAAe;YAC7B,EAAE,CAAC,MAAM,KAAK,gBAAgB;YAC9B,EAAE,CAAC,MAAM,KAAK,WAAW;YACzB,EAAE,CAAC,MAAM,KAAK,iBAAiB,EAC/B,CAAC;YACD,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,0CAA0C;IAC1C,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QACtC,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;YAClD,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,6BAA6B;IAC7B,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACpC,IAAI,MAAM,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC;QAC7B,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,SAAS,sBAAsB,CAAC,OAAe;IAC7C,IAAI,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAE9B,4BAA4B;IAC5B,IAAI,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/B,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,YAAY,KAAK,CAAC,CAAC,EAAE,CAAC;YACxB,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IAED,4BAA4B;IAC5B,MAAM,SAAS,GAAG,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAC9C,IAAI,SAAS,KAAK,CAAC,CAAC,EAAE,CAAC;QACrB,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAC1C,CAAC;IAED,QAAQ,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;IAE3B,sDAAsD;IACtD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5B,sCAAsC;QACtC,MAAM,cAAc,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACjD,IAAI,cAAc,KAAK,CAAC,CAAC,EAAE,CAAC;YAC1B,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,GAAG,CAAC,CAAC,CAAC;YAEjD,mDAAmD;YACnD,IAAI,UAAU,GAAG,CAAC,CAAC;YACnB,IAAI,YAAY,GAAG,CAAC,CAAC;YACrB,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;gBAC1B,IAAI,EAAE,KAAK,GAAG;oBAAE,UAAU,EAAE,CAAC;gBAC7B,IAAI,EAAE,KAAK,GAAG;oBAAE,UAAU,EAAE,CAAC;gBAC7B,IAAI,EAAE,KAAK,GAAG;oBAAE,YAAY,EAAE,CAAC;gBAC/B,IAAI,EAAE,KAAK,GAAG;oBAAE,YAAY,EAAE,CAAC;YACjC,CAAC;YAED,sCAAsC;YACtC,IAAI,MAAM,GAAG,EAAE,CAAC;YAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,EAAE,CAAC,EAAE;gBAAE,MAAM,IAAI,GAAG,CAAC;YACrD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,EAAE;gBAAE,MAAM,IAAI,GAAG,CAAC;YACnD,QAAQ,IAAI,MAAM,CAAC;QACrB,CAAC;IACH,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,+CAA+C;YAC/C,oBAAoB,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAC7C,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,MAAiC,CAAC;IAE9C,gCAAgC;IAChC,MAAM,MAAM,GAAyB,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;QAC5D,CAAC,CAAE,GAAG,CAAC,MAAoC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACpD,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;YAC1B,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC;YACpC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,SAAS,CAAC;YACrC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS;YAC5C,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS;YAC/D,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS;SACnE,CAAC,CAAC;QACL,CAAC,CAAC,EAAE,CAAC;IAEP,gCAAgC;IAChC,MAAM,MAAM,GAAyB,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;QAC5D,CAAC,CAAE,GAAG,CAAC,MAAoC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACpD,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;YAC1B,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,SAAS,CAAC;YACrC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;YAC9D,aAAa,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;SACjF,CAAC,CAAC;QACL,CAAC,CAAC,EAAE,CAAC;IAEP,qCAAqC;IACrC,MAAM,WAAW,GAA8B,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;QAC3E,CAAC,CAAE,GAAG,CAAC,WAAyC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACzD,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC;YAC9B,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;YACxD,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;YACxD,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS;SAC5E,CAAC,CAAC;QACL,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;AACzC,CAAC;AAED,MAAM,cAAc,GAAG,IAAI,CAAC;AAE5B,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,KAAoB,EACpB,UAAkC;IAElC,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAE3B,mCAAmC;IACnC,MAAM,WAAW,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;IACjD,UAAU,EAAE,CAAC,kBAAkB,WAAW,CAAC,MAAM,eAAe,CAAC,CAAC;IAElE,iCAAiC;IACjC,IAAI,YAAY,GAAG,EAAE,CAAC;IACtB,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,KAAK,MAAM,QAAQ,IAAI,WAAW,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAChE,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,SAAS,GACb,OAAO,CAAC,MAAM,GAAG,cAAc;gBAC7B,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,GAAG,mBAAmB;gBACxD,CAAC,CAAC,OAAO,CAAC;YACd,YAAY,IAAI,eAAe,QAAQ,SAAS,SAAS,IAAI,CAAC;YAC9D,SAAS,EAAE,CAAC;QACd,CAAC;IACH,CAAC;IAED,UAAU,EAAE,CAAC,kBAAkB,SAAS,8CAA8C,CAAC,CAAC;IAExF,2DAA2D;IAC3D,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEzD,MAAM,WAAW,GAAG;QAClB,0GAA0G;QAC1G,EAAE;QACF,uBAAuB,KAAK,CAAC,UAAU,gBAAgB;QACvD,OAAO;QACP,EAAE;QACF,wBAAwB,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,SAAS,EAAE;QAClE,EAAE;QACF,oBAAoB;QACpB,YAAY;KACb,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;QAC5C,KAAK,EAAE,KAAK;QACZ,UAAU,EAAE,MAAM;QAClB,MAAM,EAAE,uBAAuB;QAC/B,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,WAAW;aACrB;SACF;KACF,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO;SAC7B,MAAM,CAAC,CAAC,CAAC,EAA4B,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;SAC1D,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;SAClB,IAAI,CAAC,EAAE,CAAC,CAAC;IAEZ,MAAM,SAAS,GAAG,sBAAsB,CAAC,OAAO,CAAC,CAAC;IAElD,OAAO;QACL,SAAS;QACT,WAAW,EAAE,QAAQ,CAAC,KAAK,CAAC,YAAY;QACxC,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa;KAC3C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function closePrompts(): void;
2
+ export declare function prompt(question: string, defaultValue?: string): Promise<string>;
3
+ export declare function confirm(question: string): Promise<boolean>;
@@ -0,0 +1,50 @@
1
+ import { createInterface } from 'node:readline/promises';
2
+ import { stdin, stdout } from 'node:process';
3
+ let rl = null;
4
+ let pipeLines = null;
5
+ let pipeLinesLoaded = false;
6
+ async function loadPipeLines() {
7
+ if (pipeLinesLoaded)
8
+ return;
9
+ pipeLinesLoaded = true;
10
+ if (stdin.isTTY)
11
+ return;
12
+ // Read all lines from piped stdin upfront
13
+ const chunks = [];
14
+ for await (const chunk of stdin) {
15
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
16
+ }
17
+ const text = Buffer.concat(chunks).toString('utf-8');
18
+ pipeLines = text.split('\n');
19
+ }
20
+ function getInterface() {
21
+ if (!rl) {
22
+ rl = createInterface({ input: stdin, output: stdout });
23
+ rl.on('close', () => { rl = null; });
24
+ }
25
+ return rl;
26
+ }
27
+ export function closePrompts() {
28
+ if (rl) {
29
+ rl.close();
30
+ rl = null;
31
+ }
32
+ }
33
+ export async function prompt(question, defaultValue) {
34
+ const suffix = defaultValue ? ` (${defaultValue})` : '';
35
+ const display = `${question}${suffix}: `;
36
+ await loadPipeLines();
37
+ if (pipeLines !== null) {
38
+ const line = pipeLines.shift() ?? '';
39
+ stdout.write(display + line + '\n');
40
+ return line.trim() || defaultValue || '';
41
+ }
42
+ const iface = getInterface();
43
+ const answer = await iface.question(display);
44
+ return answer.trim() || defaultValue || '';
45
+ }
46
+ export async function confirm(question) {
47
+ const answer = await prompt(`${question} [y/N]`);
48
+ return answer.toLowerCase() === 'y';
49
+ }
50
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/lib/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAkB,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE7C,IAAI,EAAE,GAAqB,IAAI,CAAC;AAChC,IAAI,SAAS,GAAoB,IAAI,CAAC;AACtC,IAAI,eAAe,GAAG,KAAK,CAAC;AAE5B,KAAK,UAAU,aAAa;IAC1B,IAAI,eAAe;QAAE,OAAO;IAC5B,eAAe,GAAG,IAAI,CAAC;IAEvB,IAAI,KAAK,CAAC,KAAK;QAAE,OAAO;IAExB,0CAA0C;IAC1C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;QAChC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IACnE,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACrD,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC;AAED,SAAS,YAAY;IACnB,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QACvD,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,IAAI,EAAE,EAAE,CAAC;QACP,EAAE,CAAC,KAAK,EAAE,CAAC;QACX,EAAE,GAAG,IAAI,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,QAAgB,EAAE,YAAqB;IAClE,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,KAAK,YAAY,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACxD,MAAM,OAAO,GAAG,GAAG,QAAQ,GAAG,MAAM,IAAI,CAAC;IAEzC,MAAM,aAAa,EAAE,CAAC;IAEtB,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC,IAAI,EAAE,IAAI,YAAY,IAAI,EAAE,CAAC;IAC3C,CAAC;IAED,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;IAC7B,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC7C,OAAO,MAAM,CAAC,IAAI,EAAE,IAAI,YAAY,IAAI,EAAE,CAAC;AAC7C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,QAAgB;IAC5C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,GAAG,QAAQ,QAAQ,CAAC,CAAC;IACjD,OAAO,MAAM,CAAC,WAAW,EAAE,KAAK,GAAG,CAAC;AACtC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { AssessmentResult } from '../types.js';
2
+ export declare function publishAssessment(result: AssessmentResult, apiUrl: string, onProgress?: (msg: string) => void): Promise<string>;
@@ -0,0 +1,71 @@
1
+ export async function publishAssessment(result, apiUrl, onProgress) {
2
+ // 1. Create assessment
3
+ onProgress?.('Creating assessment...');
4
+ const createRes = await fetch(`${apiUrl}/api/v1/assessments`, {
5
+ method: 'POST',
6
+ headers: { 'Content-Type': 'application/json' },
7
+ body: JSON.stringify({
8
+ repo_name: result.repoName,
9
+ repo_url: result.repoUrl,
10
+ frameworks: result.frameworks,
11
+ }),
12
+ });
13
+ if (!createRes.ok) {
14
+ const text = await createRes.text().catch(() => '');
15
+ throw new Error(`Failed to create assessment: ${createRes.status} ${text}`);
16
+ }
17
+ const { id, upload_token } = (await createRes.json());
18
+ // 2. Upload claims in batches of 100
19
+ const allClaims = result.routeResults.flatMap((rr) => rr.verifications.map((v) => ({
20
+ domain: rr.requirement.domain,
21
+ route: rr.requirement.route,
22
+ claim_text: v.claim,
23
+ category: rr.claims.find((c) => c.id === v.claimId)?.category || 'functionality',
24
+ severity: rr.claims.find((c) => c.id === v.claimId)?.severity || 'medium',
25
+ verdict: v.verdict,
26
+ evidence: v.evidence,
27
+ reasoning: v.reasoning,
28
+ is_bug: v.verdict === 'FAIL' || v.verdict === 'PARTIAL',
29
+ })));
30
+ const BATCH = 100;
31
+ for (let i = 0; i < allClaims.length; i += BATCH) {
32
+ const batch = allClaims.slice(i, i + BATCH);
33
+ onProgress?.(`Uploading claims ${i + 1}-${Math.min(i + BATCH, allClaims.length)}/${allClaims.length}...`);
34
+ const res = await fetch(`${apiUrl}/api/v1/assessments/${id}/claims`, {
35
+ method: 'PUT',
36
+ headers: {
37
+ 'Content-Type': 'application/json',
38
+ Authorization: `Bearer ${upload_token}`,
39
+ },
40
+ body: JSON.stringify({ claims: batch }),
41
+ });
42
+ if (!res.ok) {
43
+ const text = await res.text().catch(() => '');
44
+ throw new Error(`Failed to upload claims: ${res.status} ${text}`);
45
+ }
46
+ }
47
+ // 3. Mark complete
48
+ onProgress?.('Finalizing assessment...');
49
+ const completeRes = await fetch(`${apiUrl}/api/v1/assessments/${id}/complete`, {
50
+ method: 'PUT',
51
+ headers: {
52
+ 'Content-Type': 'application/json',
53
+ Authorization: `Bearer ${upload_token}`,
54
+ },
55
+ body: JSON.stringify({
56
+ verdicts: result.verdicts,
57
+ bugs: result.bugs,
58
+ score: result.score,
59
+ executive_summary: result.executiveSummary,
60
+ total_routes: result.totalRoutes,
61
+ total_claims: result.totalClaims,
62
+ frameworks: result.frameworks,
63
+ }),
64
+ });
65
+ if (!completeRes.ok) {
66
+ const text = await completeRes.text().catch(() => '');
67
+ throw new Error(`Failed to complete assessment: ${completeRes.status} ${text}`);
68
+ }
69
+ return `${apiUrl}/reports/${id}`;
70
+ }
71
+ //# sourceMappingURL=publisher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publisher.js","sourceRoot":"","sources":["../../src/lib/publisher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { RemediationPlan } from '../types.js';
2
+ export declare function generateRemediationReport(plan: RemediationPlan, projectName?: string): string;
@@ -0,0 +1,136 @@
1
+ export function generateRemediationReport(plan, projectName) {
2
+ const lines = [];
3
+ const gap = plan.targetScore - plan.currentScore;
4
+ const now = new Date().toISOString().split('T')[0];
5
+ // --- Header ---
6
+ lines.push(`# Assay Remediation Plan — ${projectName || 'Audit Results'}`);
7
+ lines.push('');
8
+ lines.push(`*Generated: ${now}*`);
9
+ lines.push(`*Iteration: ${plan.iteration}*`);
10
+ lines.push(`*Codebase: ${plan.codebasePath}*`);
11
+ lines.push('');
12
+ lines.push('---');
13
+ lines.push('');
14
+ // --- Score Summary ---
15
+ lines.push('## Compliance Gap');
16
+ lines.push('');
17
+ lines.push(`| Metric | Value |`);
18
+ lines.push(`|--------|-------|`);
19
+ lines.push(`| Current score | **${plan.currentScore.toFixed(1)}%** |`);
20
+ lines.push(`| Target score | ${plan.targetScore}% |`);
21
+ lines.push(`| Gap | ${gap.toFixed(1)} points |`);
22
+ lines.push(`| Total fix tasks | ${plan.totalTasks} |`);
23
+ lines.push('');
24
+ // --- Summary Tables ---
25
+ lines.push('## Task Summary');
26
+ lines.push('');
27
+ lines.push('**By verdict:**');
28
+ lines.push('');
29
+ lines.push(`| Verdict | Tasks |`);
30
+ lines.push(`|---------|-------|`);
31
+ lines.push(`| FAIL | ${plan.tasksByVerdict.fail} |`);
32
+ lines.push(`| PARTIAL | ${plan.tasksByVerdict.partial} |`);
33
+ lines.push('');
34
+ lines.push('**By severity:**');
35
+ lines.push('');
36
+ lines.push(`| Severity | Tasks |`);
37
+ lines.push(`|----------|-------|`);
38
+ lines.push(`| Critical | ${plan.tasksBySeverity.critical} |`);
39
+ lines.push(`| High | ${plan.tasksBySeverity.high} |`);
40
+ lines.push(`| Medium | ${plan.tasksBySeverity.medium} |`);
41
+ lines.push(`| Low | ${plan.tasksBySeverity.low} |`);
42
+ lines.push('');
43
+ // Effort distribution
44
+ const effortCounts = { trivial: 0, small: 0, medium: 0, large: 0 };
45
+ for (const t of plan.tasks) {
46
+ effortCounts[t.estimatedEffort]++;
47
+ }
48
+ lines.push('**By effort:**');
49
+ lines.push('');
50
+ lines.push(`| Effort | Tasks |`);
51
+ lines.push(`|--------|-------|`);
52
+ lines.push(`| Trivial | ${effortCounts.trivial} |`);
53
+ lines.push(`| Small | ${effortCounts.small} |`);
54
+ lines.push(`| Medium | ${effortCounts.medium} |`);
55
+ lines.push(`| Large | ${effortCounts.large} |`);
56
+ lines.push('');
57
+ // --- Priority sections ---
58
+ const severityGroups = [
59
+ { label: 'Critical Priority', severity: 'critical' },
60
+ { label: 'High Priority', severity: 'high' },
61
+ { label: 'Medium Priority', severity: 'medium' },
62
+ { label: 'Low Priority', severity: 'low' },
63
+ ];
64
+ for (const group of severityGroups) {
65
+ const groupTasks = plan.tasks.filter((t) => t.severity === group.severity);
66
+ if (groupTasks.length === 0)
67
+ continue;
68
+ lines.push('---');
69
+ lines.push('');
70
+ lines.push(`## ${group.label} (${groupTasks.length} tasks)`);
71
+ lines.push('');
72
+ for (const task of groupTasks) {
73
+ renderTask(lines, task);
74
+ }
75
+ }
76
+ // --- Quick Wins ---
77
+ const quickWins = plan.tasks
78
+ .filter((t) => t.verdict === 'PARTIAL')
79
+ .sort((a, b) => {
80
+ const effortOrder = { trivial: 0, small: 1, medium: 2, large: 3 };
81
+ return effortOrder[a.estimatedEffort] - effortOrder[b.estimatedEffort];
82
+ });
83
+ if (quickWins.length > 0) {
84
+ lines.push('---');
85
+ lines.push('');
86
+ lines.push(`## Quick Wins (${quickWins.length} partial implementations)`);
87
+ lines.push('');
88
+ lines.push('These claims are partially implemented — completing them yields the most score improvement per effort.');
89
+ lines.push('');
90
+ for (const task of quickWins) {
91
+ lines.push(`- [ ] **${task.id}** [${task.estimatedEffort}] ${task.title} → \`${task.targetFiles.join('`, `')}\``);
92
+ }
93
+ lines.push('');
94
+ }
95
+ // --- Footer ---
96
+ lines.push('---');
97
+ lines.push('');
98
+ lines.push('## Next Steps');
99
+ lines.push('');
100
+ lines.push('1. Fix the tasks above, starting with Critical Priority');
101
+ lines.push('2. Re-verify: `assay verify`');
102
+ lines.push('3. Re-report: `assay report`');
103
+ lines.push(`4. Repeat until compliance score >= ${plan.targetScore}%`);
104
+ lines.push('');
105
+ lines.push('```');
106
+ lines.push('verify → report → remediate → [fix code] → verify → report → ...');
107
+ lines.push('```');
108
+ lines.push('');
109
+ lines.push(`*Report generated by Assay v0.1.0 — powered by the LUCID methodology (Leveraging Unverified Claims Into Deliverables)*`);
110
+ lines.push(`*https://tryassay.ai*`);
111
+ lines.push('');
112
+ return lines.join('\n');
113
+ }
114
+ function renderTask(lines, task) {
115
+ const verdictBadge = task.verdict === 'FAIL' ? '[FAIL]' : '[PARTIAL]';
116
+ lines.push(`### ${task.id}: ${task.title}`);
117
+ lines.push('');
118
+ lines.push(`${verdictBadge} **${task.severity}** | Action: \`${task.action}\` | Effort: \`${task.estimatedEffort}\` | Claim: \`${task.claimId}\``);
119
+ lines.push('');
120
+ lines.push(task.description);
121
+ lines.push('');
122
+ if (task.targetFiles.length > 0) {
123
+ lines.push('**Target files:**');
124
+ for (const f of task.targetFiles) {
125
+ lines.push(`- \`${f}\``);
126
+ }
127
+ lines.push('');
128
+ }
129
+ if (task.codeGuidance) {
130
+ lines.push('**Code guidance:**');
131
+ lines.push('');
132
+ lines.push(`> ${task.codeGuidance.split('\n').join('\n> ')}`);
133
+ lines.push('');
134
+ }
135
+ }
136
+ //# sourceMappingURL=remediation-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remediation-generator.js","sourceRoot":"","sources":["../../src/lib/remediation-generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { CodebaseIndex } from './codebase-indexer.js';
2
+ import type { Claim, ClaimVerification, RemediationTask } from '../types.js';
3
+ export declare function generateRemediationTasks(failedVerifications: ClaimVerification[], partialVerifications: ClaimVerification[], claims: Claim[], index: CodebaseIndex, onProgress?: (msg: string) => void): Promise<{
4
+ tasks: RemediationTask[];
5
+ inputTokens: number;
6
+ outputTokens: number;
7
+ }>;