create-verifiable-agent 1.0.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/demo/mythos.js ADDED
@@ -0,0 +1,337 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * MYTHOS / CAPYBARA CYBER-RISK SIMULATION DEMO
5
+ *
6
+ * When `capybara-v6.html` exists in `mythos-leak-draft/` (or a path passed via
7
+ * CAPYBARA_HTML env var), this module parses it with html-extractor and uses
8
+ * the real extracted content as context. Falls back to embedded verbatim
9
+ * quotes from the publicly available Fortune/capybara.com report otherwise.
10
+ *
11
+ * EDUCATIONAL USE. No real Anthropic confidential data is included here —
12
+ * all quotes are from publicly reported summaries.
13
+ */
14
+
15
+ const fs = require('fs');
16
+ const path = require('path');
17
+ const os = require('os');
18
+ const { extractFromHtml } = require('../src/html-extractor');
19
+
20
+ // ── Try to locate capybara-v6.html ───────────────────────────────────────────
21
+ const CANDIDATES = [
22
+ process.env.CAPYBARA_HTML,
23
+ path.join(os.homedir(), 'Downloads', 'mythos-leak-draft', 'capybara-v6.html'),
24
+ path.join(__dirname, '..', '..', 'mythos-leak-draft', 'capybara-v6.html'),
25
+ path.join(__dirname, 'capybara-v6.html'),
26
+ ].filter(Boolean);
27
+
28
+ function findHtmlFile() {
29
+ for (const p of CANDIDATES) {
30
+ if (fs.existsSync(p)) return p;
31
+ }
32
+ return null;
33
+ }
34
+
35
+ // ── Verbatim fallback quotes (from public reporting) ─────────────────────────
36
+ // Source: fortune.com exclusive + capybara.com (March 26–27, 2026)
37
+ const VERBATIM_QUOTES = [
38
+ '"Claude Capybara (internal codename: Mythos) is Anthropic\'s next-generation AI model that introduces a new fourth tier in the Claude hierarchy, sitting above Opus."',
39
+ '"a \'step change\' in AI capability" — Anthropic spokesperson, March 27 2026',
40
+ '"the most capable we\'ve built to date" — Anthropic draft blog post (leaked)',
41
+ '"Compared to our previous best model, Claude Opus 4.6, Capybara gets dramatically higher scores on tests of software coding, academic reasoning, and cybersecurity, among others." — Anthropic draft blog post, leaked March 26 2026 · Source: Fortune',
42
+ '"Currently far ahead of any other AI model in cyber capabilities" — Anthropic internal assessment',
43
+ '"can exploit vulnerabilities faster than defenders can patch them" — capybara.com summary',
44
+ '"presages an upcoming wave of models that can exploit vulnerabilities in ways that far outpace the efforts of defenders" — referenced in Fortune exclusive',
45
+ '"A CMS misconfiguration at Anthropic left approximately 3,000 unpublished assets — including draft blog posts about Mythos/Capybara — in a publicly accessible data store."',
46
+ ];
47
+
48
+ const CAPABILITY_CLAIMS = {
49
+ coding: [
50
+ 'Dramatically higher scores than Opus 4.6 on software coding benchmarks',
51
+ 'Opus 4.6 already led industry rankings alongside GPT-5.3-Codex; Capybara is described as a step-change above that',
52
+ 'Terminal-Bench 2.0 Agentic Coding: Opus 4.6 scored 65.4%; Capybara "dramatically higher" (unreleased)',
53
+ ],
54
+ reasoning: [
55
+ 'Significant improvements in academic reasoning tasks',
56
+ '"Step change" in overall intelligence — not an incremental version bump',
57
+ 'Humanity\'s Last Exam: Opus 4.6 scored 53.1%; Capybara "dramatically higher" (unreleased)',
58
+ ],
59
+ cybersecurity: [
60
+ '"Currently far ahead of any other AI model in cyber capabilities"',
61
+ '"can exploit vulnerabilities faster than defenders can patch them"',
62
+ '"presages an upcoming wave of models that can exploit vulnerabilities in ways that far outpace the efforts of defenders"',
63
+ 'Anthropic being deliberate about release given cyber-risk profile',
64
+ ],
65
+ overall: [
66
+ '"a step change" in AI performance — confirmed by Anthropic spokesperson',
67
+ '"the most capable we\'ve built to date"',
68
+ '"Capybara is a new name for a new tier of model: larger and more intelligent than our Opus models"',
69
+ 'Fourth tier: Haiku → Sonnet → Opus → Capybara',
70
+ ],
71
+ };
72
+
73
+ // ── Build context ─────────────────────────────────────────────────────────────
74
+ function buildMythosContext() {
75
+ const htmlPath = findHtmlFile();
76
+ let extraction = null;
77
+ let sourceNote = '(using embedded verbatim quotes from public reporting)';
78
+
79
+ if (htmlPath) {
80
+ try {
81
+ const html = fs.readFileSync(htmlPath, 'utf8');
82
+ extraction = extractFromHtml(html, path.basename(htmlPath));
83
+ sourceNote = `(parsed from ${path.basename(htmlPath)})`;
84
+ } catch (e) {
85
+ // fall through to verbatim fallback
86
+ }
87
+ }
88
+
89
+ // Merge real extraction with verbatim fallbacks
90
+ const notableQuotes = extraction
91
+ ? [...new Set([...extraction.allNotableQuotes, ...VERBATIM_QUOTES])].slice(0, 12)
92
+ : VERBATIM_QUOTES;
93
+
94
+ const cyberRiskWarnings = extraction && extraction.cyberRiskWarnings.length
95
+ ? extraction.cyberRiskWarnings
96
+ : [
97
+ 'Currently far ahead of any other AI model in cyber capabilities',
98
+ 'can exploit vulnerabilities faster than defenders can patch them',
99
+ 'presages an upcoming wave of models that can exploit vulnerabilities in ways that far outpace the efforts of defenders',
100
+ ];
101
+
102
+ const faqEntries = extraction ? extraction.faqEntries : [
103
+ {
104
+ question: 'What is Claude Capybara?',
105
+ answer: "Claude Capybara (internal codename: Mythos) is Anthropic's next-generation AI model introducing a new fourth tier above Opus. Anthropic calls it a 'step change' in AI capability.",
106
+ },
107
+ {
108
+ question: 'How does Capybara compare to Opus 4.6?',
109
+ answer: "Capybara gets 'dramatically higher scores' than Opus 4.6 on software coding, academic reasoning, and cybersecurity. Anthropic describes it as 'currently far ahead of any other AI model in cyber capabilities.'",
110
+ },
111
+ {
112
+ question: 'Why was Capybara leaked?',
113
+ answer: "A CMS misconfiguration at Anthropic left ~3,000 unpublished assets in a publicly accessible data store. Fortune discovered and reported the leak on March 26, 2026.",
114
+ },
115
+ ];
116
+
117
+ const documentTitle = extraction?.title
118
+ || 'Claude Capybara (Mythos) — Anthropic\'s Most Powerful AI Model | Get Access';
119
+
120
+ return {
121
+ repoName: 'mythos-capybara-sim',
122
+ localPath: null,
123
+ isRemote: false,
124
+ isDemo: true,
125
+ isSandbox: true,
126
+ sourceNote,
127
+ htmlPath,
128
+
129
+ // Leak document extraction
130
+ leakDocs: extraction ? [{
131
+ path: path.basename(htmlPath || 'capybara-v6.html'),
132
+ ext: '.html',
133
+ isLeakDoc: true,
134
+ extraction,
135
+ }] : [],
136
+
137
+ // Document metadata
138
+ documentTitle,
139
+ documentDate: 'March 26–27, 2026',
140
+ documentSource: 'Fortune exclusive + capybara.com + Anthropic spokesperson statement',
141
+
142
+ // Key content
143
+ notableQuotes,
144
+ cyberRiskWarnings,
145
+ faqEntries,
146
+ capabilities: extraction?.capabilities || CAPABILITY_CLAIMS,
147
+ timeline: extraction?.timeline || [
148
+ 'February 2026 — Opus 4.6 released alongside OpenAI GPT-5.3',
149
+ 'March 26, 2026 — Fortune exclusive: CMS misconfiguration exposes ~3,000 unpublished Anthropic assets',
150
+ 'March 27, 2026 — Anthropic confirms: "step change", "most capable we\'ve built to date"',
151
+ 'Q2 2026 (expected) — Limited API rollout to approved developers and enterprises',
152
+ ],
153
+
154
+ // Verbatim highlight quotes for the demo
155
+ highlightQuotes: {
156
+ stepChange: '"a \'step change\' in AI capability" — Anthropic spokesperson, March 27 2026',
157
+ mostCapable: '"the most capable we\'ve built to date" — Anthropic draft blog post (leaked)',
158
+ dramaticallyHigher: '"Compared to our previous best model, Claude Opus 4.6, Capybara gets dramatically higher scores on tests of software coding, academic reasoning, and cybersecurity, among others."',
159
+ cyberLead: '"Currently far ahead of any other AI model in cyber capabilities" — Anthropic internal assessment',
160
+ presages: '"presages an upcoming wave of models that can exploit vulnerabilities in ways that far outpace the efforts of defenders"',
161
+ leakCause: '"A CMS misconfiguration at Anthropic left approximately 3,000 unpublished assets in a publicly accessible data store. Fortune discovered and reported the leak on March 26, 2026."',
162
+ },
163
+
164
+ stack: {
165
+ languages: ['Python', 'TypeScript'],
166
+ frameworks: ['FastAPI', 'React', 'Celery'],
167
+ infra: ['Docker', 'GitHub Actions', 'AWS Lambda'],
168
+ },
169
+
170
+ keyFiles: {
171
+ 'capybara-v6.html': extraction
172
+ ? `[PARSED] ${documentTitle}\n\nKey quotes: ${notableQuotes.slice(0, 2).join('\n')}`
173
+ : '[FALLBACK] capybara-v6.html not found — using embedded public quotes',
174
+
175
+ 'LEAKED_STRATEGY.md': buildLeakedStrategyDoc(cyberRiskWarnings, notableQuotes),
176
+ 'ci/deploy.yml': SIMULATED_CI_YML,
177
+ 'agent_runner.py': SIMULATED_AGENT_PY,
178
+ },
179
+
180
+ files: [
181
+ { path: 'capybara-v6.html', ext: '.html', isLeakDoc: true, preview: documentTitle, size: 50256 },
182
+ { path: 'agent_runner.py', ext: '.py', preview: 'Single agent, no verification layer', size: 800 },
183
+ { path: 'ci/deploy.yml', ext: '.yml', preview: 'Hard-coded secrets, auto-deploy to prod', size: 400 },
184
+ { path: 'LEAKED_STRATEGY.md', ext: '.md', preview: 'Capybara initiative — capability + risk doc', size: 3200 },
185
+ { path: 'requirements.txt', ext: '.txt', preview: 'anthropic==0.18.0\nfastapi\ncelery', size: 60 },
186
+ { path: 'src/risk_scorer.py', ext: '.py', preview: '# TODO: add confidence thresholds (never done)', size: 200 },
187
+ ],
188
+
189
+ findings: {
190
+ critical: [
191
+ {
192
+ id: 'MYTH-001',
193
+ severity: 'CRITICAL',
194
+ title: 'Hard-coded API keys in CI/CD pipeline',
195
+ file: 'ci/deploy.yml',
196
+ detail: 'OPENAI_KEY and DB_URL hard-coded in GitHub Actions config. Exposed in public leak.',
197
+ fix: 'Use GitHub Secrets. Rotate all leaked credentials immediately.',
198
+ leakEvidence: '"A CMS misconfiguration at Anthropic left approximately 3,000 unpublished assets in a publicly accessible data store."',
199
+ },
200
+ {
201
+ id: 'MYTH-002',
202
+ severity: 'CRITICAL',
203
+ title: 'No human-in-the-loop gates on autonomous agent',
204
+ file: 'agent_runner.py',
205
+ detail: 'auto_approve=True deploys agent outputs directly to production with no review.',
206
+ fix: 'Add plan_mode + human approval gates before any destructive action.',
207
+ leakEvidence: '"presages an upcoming wave of models that can exploit vulnerabilities in ways that far outpace the efforts of defenders"',
208
+ },
209
+ {
210
+ id: 'MYTH-003',
211
+ severity: 'HIGH',
212
+ title: 'Missing self-consistency verification on risk scores',
213
+ file: 'src/risk_scorer.py',
214
+ detail: 'Risk scores passed to financial decisions with no confidence threshold or multi-sample check.',
215
+ fix: 'Add verifier agent with multi-sample scoring (3 samples min) and 0.85 confidence threshold.',
216
+ leakEvidence: '"dramatically higher scores on tests of software coding, academic reasoning, and cybersecurity" — if the model is this capable, unverified outputs are more dangerous, not less.',
217
+ },
218
+ {
219
+ id: 'MYTH-004',
220
+ severity: 'HIGH',
221
+ title: 'Computer Use agent deployed without screenshot audit trail',
222
+ file: 'agent_runner.py',
223
+ detail: 'Computer Use sessions leave no screenshot audit trail. Cannot reconstruct what the agent did.',
224
+ fix: 'Log all screenshots, mouse events, and keystrokes with SHA-256 hashes.',
225
+ leakEvidence: '"Currently far ahead of any other AI model in cyber capabilities" — a Computer Use agent at this capability level with no audit trail is a critical liability.',
226
+ },
227
+ {
228
+ id: 'MYTH-005',
229
+ severity: 'MEDIUM',
230
+ title: 'No sandbox mode — agents execute directly against production',
231
+ file: 'agent_runner.py',
232
+ detail: 'Agents execute directly against production. Any hallucination or misuse causes real damage.',
233
+ fix: 'Add sandbox_mode flag. Block external API calls and DB writes by default.',
234
+ leakEvidence: '"can exploit vulnerabilities faster than defenders can patch them" — production access with no sandbox is indefensible at Capybara\'s capability level.',
235
+ },
236
+ ],
237
+ },
238
+
239
+ summary: buildSummary(sourceNote, cyberRiskWarnings, notableQuotes),
240
+ };
241
+ }
242
+
243
+ // ── Helper builders ──────────────────────────────────────────────────────────
244
+
245
+ function buildLeakedStrategyDoc(cyberRiskWarnings, notableQuotes) {
246
+ return `## Capybara / Mythos Initiative — Capability & Risk Document
247
+ Source: Publicly reported summaries (Fortune exclusive, March 26 2026)
248
+ Status: EDUCATIONAL SIMULATION — no confidential data
249
+
250
+ ### Key Capability Claims (from public reporting)
251
+
252
+ ${notableQuotes.slice(0, 6).map(q => `> ${q}`).join('\n\n')}
253
+
254
+ ### Cyber-Risk Warnings
255
+
256
+ ${cyberRiskWarnings.slice(0, 5).map(w => `⚠ ${w}`).join('\n')}
257
+
258
+ ### What a Verifiable Agent Would Have Caught
259
+
260
+ 1. MYTH-001: Hard-coded API keys exposed by CMS misconfiguration
261
+ 2. MYTH-002: Autonomous agent with auto_approve=True and no human gates
262
+ 3. MYTH-003: Risk scorer with no confidence thresholds — dangerous given Capybara's capability
263
+ 4. MYTH-004: Computer Use deployed with no screenshot provenance trail
264
+ 5. MYTH-005: No sandbox mode — agents hit production directly
265
+
266
+ ### The Core Lesson
267
+
268
+ A model described as "far ahead of any other AI model in cyber capabilities" that
269
+ "presages an upcoming wave of models that can exploit vulnerabilities in ways that
270
+ far outpace the efforts of defenders" demands MORE verification, not less.
271
+
272
+ The leak itself was MYTH-001. The agent architecture was MYTH-002 through MYTH-005.
273
+ A verifiable multi-agent system with sandbox mode + human gates + self-consistency
274
+ checks would have flagged all five before any line reached production.`;
275
+ }
276
+
277
+ function buildSummary(sourceNote, cyberRiskWarnings, notableQuotes) {
278
+ return `Repository: mythos-capybara-sim (EDUCATIONAL SIMULATION)
279
+ Source note: ${sourceNote}
280
+ Files analyzed: 6 (including capybara-v6.html leak document)
281
+ Languages: Python, TypeScript
282
+ Frameworks: FastAPI, React, Celery
283
+ Infrastructure: Docker, GitHub Actions, AWS Lambda
284
+ Document: "Claude Capybara (Mythos) — Anthropic's Most Powerful AI Model"
285
+ Date: March 26–27, 2026 (Fortune exclusive)
286
+
287
+ KEY QUOTES FROM LEAK (public reporting):
288
+ • "a 'step change' in AI capability"
289
+ • "the most capable we've built to date"
290
+ • "dramatically higher scores on tests of software coding, academic reasoning, and cybersecurity"
291
+ • "Currently far ahead of any other AI model in cyber capabilities"
292
+ • "presages an upcoming wave of models that can exploit vulnerabilities in ways that far outpace the efforts of defenders"
293
+
294
+ CRITICAL FINDINGS (simulated based on public leak summaries):
295
+ - MYTH-001: Hard-coded API keys in CI/CD (CRITICAL)
296
+ - MYTH-002: No human-in-the-loop gates (CRITICAL)
297
+ - MYTH-003: Missing self-consistency verification (HIGH)
298
+ - MYTH-004: Computer Use without audit trail (HIGH)
299
+ - MYTH-005: No sandbox mode (MEDIUM)
300
+
301
+ EDUCATIONAL SIMULATION ONLY. All quotes from publicly reported summaries.`;
302
+ }
303
+
304
+ const SIMULATED_CI_YML = `# DEMO: Simulated vulnerable CI config (based on MYTH-001 pattern)
305
+ env:
306
+ ANTHROPIC_API_KEY: sk-ant-hardcoded-BAD # MYTH-001: hard-coded secret
307
+ DB_URL: postgres://prod.capybara.internal/mythos # points to PROD
308
+ jobs:
309
+ deploy:
310
+ runs-on: ubuntu-latest
311
+ steps:
312
+ - run: python agent_runner.py --env production --auto-approve # MYTH-002`;
313
+
314
+ const SIMULATED_AGENT_PY = `# DEMO: Simulated single-agent runner (MYTH-002 through MYTH-005)
315
+ import os
316
+ from anthropic import Anthropic
317
+
318
+ # MYTH-001: key exposed via CMS misconfiguration
319
+ client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
320
+
321
+ def run_agent(task, auto_approve=False):
322
+ # MYTH-003: no self-consistency, no confidence threshold
323
+ # MYTH-004: Computer Use sessions leave no audit trail
324
+ # MYTH-005: no sandbox_mode flag
325
+ result = client.messages.create(
326
+ model="claude-capybara", # Mythos tier
327
+ max_tokens=4096,
328
+ messages=[{"role": "user", "content": task}]
329
+ )
330
+ if auto_approve:
331
+ execute_immediately(result) # MYTH-002: no human gate
332
+ return result
333
+
334
+ # "Currently far ahead of any other AI model in cyber capabilities"
335
+ # Running this without sandbox_mode against production is indefensible.`;
336
+
337
+ module.exports = buildMythosContext();
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "create-verifiable-agent",
3
+ "version": "1.0.0",
4
+ "description": "One-command CLI to turn any codebase into a verifiable multi-agent recipe using Claude Sonnet 4.6 + Computer Use API",
5
+ "bin": {
6
+ "create-verifiable-agent": "./bin/create-verifiable-agent.js"
7
+ },
8
+ "main": "./src/index.js",
9
+ "type": "commonjs",
10
+ "scripts": {
11
+ "start": "node bin/create-verifiable-agent.js",
12
+ "demo": "node bin/create-verifiable-agent.js --demo mythos",
13
+ "test": "node test/run-tests.js"
14
+ },
15
+ "keywords": [
16
+ "claude",
17
+ "ai-agent",
18
+ "verifiable",
19
+ "computer-use",
20
+ "multi-agent",
21
+ "recipe",
22
+ "anthropic"
23
+ ],
24
+ "author": "kju4q",
25
+ "license": "MIT",
26
+ "dependencies": {
27
+ "@anthropic-ai/sdk": "^0.36.0",
28
+ "chalk": "^4.1.2",
29
+ "commander": "^11.1.0",
30
+ "glob": "^10.3.10",
31
+ "inquirer": "^8.2.6",
32
+ "js-yaml": "^4.1.0",
33
+ "ora": "^5.4.1",
34
+ "simple-git": "^3.22.0"
35
+ },
36
+ "engines": {
37
+ "node": ">=18.0.0"
38
+ },
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "https://github.com/kju4q/verifiable-agent-recipe.git"
42
+ },
43
+ "files": [
44
+ "bin/",
45
+ "src/",
46
+ "templates/",
47
+ "demo/"
48
+ ]
49
+ }
@@ -0,0 +1,216 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { glob } = require('glob');
6
+ const simpleGit = require('simple-git');
7
+ const os = require('os');
8
+ const { extractFromHtml } = require('./html-extractor');
9
+
10
+ // File extensions we care about
11
+ const CODE_EXTS = new Set([
12
+ '.js', '.ts', '.jsx', '.tsx', '.py', '.go', '.rs',
13
+ '.java', '.rb', '.php', '.cs', '.cpp', '.c', '.h',
14
+ '.yaml', '.yml', '.json', '.toml', '.md', '.mdx',
15
+ '.html', '.htm', // leak documents, blog posts
16
+ '.sh', '.bash', '.zsh', '.dockerfile', 'Dockerfile',
17
+ ]);
18
+
19
+ const IGNORE_DIRS = new Set([
20
+ 'node_modules', '.git', 'dist', 'build', '.next',
21
+ '__pycache__', '.venv', 'venv', 'vendor', 'target',
22
+ '.cache', 'coverage', '.nyc_output',
23
+ ]);
24
+
25
+ async function analyzeSource(source, { maxFiles = 50, sandbox = false } = {}) {
26
+ let localPath;
27
+ let repoName;
28
+ let isRemote = false;
29
+
30
+ // Determine if it's a GitHub URL or local path
31
+ if (source.startsWith('https://github.com') || source.startsWith('git@github.com')) {
32
+ if (sandbox) {
33
+ // In sandbox mode, fake the clone
34
+ return buildSandboxContext(source);
35
+ }
36
+ isRemote = true;
37
+ localPath = path.join(os.tmpdir(), `cva-${Date.now()}`);
38
+ repoName = source.split('/').pop().replace('.git', '');
39
+ console.log('');
40
+ const git = simpleGit();
41
+ await git.clone(source, localPath, ['--depth', '1']);
42
+ } else {
43
+ localPath = path.resolve(source);
44
+ repoName = path.basename(localPath);
45
+ }
46
+
47
+ if (!fs.existsSync(localPath)) {
48
+ throw new Error(`Path not found: ${localPath}`);
49
+ }
50
+
51
+ // Collect files
52
+ const allFiles = await collectFiles(localPath, maxFiles);
53
+
54
+ // Build file summaries — HTML files get deep extraction
55
+ const fileSummaries = allFiles.map(f => {
56
+ const rel = path.relative(localPath, f);
57
+ const ext = path.extname(f).toLowerCase();
58
+ const size = fs.statSync(f).size;
59
+
60
+ if (ext === '.html' || ext === '.htm') {
61
+ const html = safeRead(f, 200000); // read full HTML
62
+ const extraction = extractFromHtml(html, rel);
63
+ return {
64
+ path: rel,
65
+ ext,
66
+ size,
67
+ isLeakDoc: true,
68
+ preview: extraction.plainText.slice(0, 3000),
69
+ extraction, // full structured extraction attached
70
+ };
71
+ }
72
+
73
+ const content = safeRead(f, 4000);
74
+ return { path: rel, ext, preview: content, size };
75
+ });
76
+
77
+ // Collect all leak document extractions
78
+ const leakDocs = fileSummaries.filter(f => f.isLeakDoc && f.extraction);
79
+
80
+ // Detect stack
81
+ const stack = detectStack(fileSummaries);
82
+
83
+ // Read key files (README, package.json, etc.)
84
+ const keyFiles = readKeyFiles(localPath);
85
+
86
+ return {
87
+ repoName,
88
+ localPath,
89
+ isRemote,
90
+ files: fileSummaries,
91
+ leakDocs,
92
+ stack,
93
+ keyFiles,
94
+ summary: buildSummary(repoName, fileSummaries, stack, keyFiles, leakDocs),
95
+ };
96
+ }
97
+
98
+ async function collectFiles(dir, maxFiles) {
99
+ const results = [];
100
+ const queue = [dir];
101
+
102
+ while (queue.length && results.length < maxFiles) {
103
+ const current = queue.shift();
104
+ let entries;
105
+ try { entries = fs.readdirSync(current, { withFileTypes: true }); }
106
+ catch { continue; }
107
+
108
+ for (const entry of entries) {
109
+ if (results.length >= maxFiles) break;
110
+ if (entry.name.startsWith('.') && entry.name !== '.env.example') continue;
111
+ if (IGNORE_DIRS.has(entry.name)) continue;
112
+
113
+ const full = path.join(current, entry.name);
114
+ if (entry.isDirectory()) {
115
+ queue.push(full);
116
+ } else {
117
+ const ext = path.extname(entry.name);
118
+ if (CODE_EXTS.has(ext) || CODE_EXTS.has(entry.name)) {
119
+ results.push(full);
120
+ }
121
+ }
122
+ }
123
+ }
124
+ return results;
125
+ }
126
+
127
+ function safeRead(filePath, maxChars = 4000) {
128
+ try {
129
+ const content = fs.readFileSync(filePath, 'utf8');
130
+ return content.slice(0, maxChars);
131
+ } catch {
132
+ return '';
133
+ }
134
+ }
135
+
136
+ function detectStack(files) {
137
+ const stack = { languages: [], frameworks: [], infra: [] };
138
+ const names = files.map(f => f.path.toLowerCase());
139
+ const has = (s) => names.some(n => n.includes(s));
140
+
141
+ if (has('package.json')) stack.languages.push('JavaScript/TypeScript');
142
+ if (has('requirements.txt') || has('.py')) stack.languages.push('Python');
143
+ if (has('go.mod')) stack.languages.push('Go');
144
+ if (has('cargo.toml')) stack.languages.push('Rust');
145
+ if (has('pom.xml') || has('build.gradle')) stack.languages.push('Java');
146
+
147
+ if (has('next.config')) stack.frameworks.push('Next.js');
148
+ if (has('vite.config')) stack.frameworks.push('Vite');
149
+ if (has('fastapi') || has('uvicorn')) stack.frameworks.push('FastAPI');
150
+ if (has('django')) stack.frameworks.push('Django');
151
+ if (has('express')) stack.frameworks.push('Express');
152
+
153
+ if (has('dockerfile') || has('docker-compose')) stack.infra.push('Docker');
154
+ if (has('terraform')) stack.infra.push('Terraform');
155
+ if (has('.github/workflows')) stack.infra.push('GitHub Actions');
156
+
157
+ return stack;
158
+ }
159
+
160
+ function readKeyFiles(dir) {
161
+ const targets = ['README.md', 'package.json', 'pyproject.toml', 'go.mod', 'Cargo.toml', '.env.example'];
162
+ const result = {};
163
+ for (const t of targets) {
164
+ const fp = path.join(dir, t);
165
+ if (fs.existsSync(fp)) result[t] = safeRead(fp, 2000);
166
+ }
167
+ return result;
168
+ }
169
+
170
+ function buildSummary(name, files, stack, keyFiles, leakDocs = []) {
171
+ const lines = [
172
+ `Repository: ${name}`,
173
+ `Files analyzed: ${files.length}`,
174
+ `Languages: ${stack.languages.join(', ') || 'unknown'}`,
175
+ `Frameworks: ${stack.frameworks.join(', ') || 'none detected'}`,
176
+ `Infrastructure: ${stack.infra.join(', ') || 'none detected'}`,
177
+ keyFiles['README.md'] ? `README excerpt: ${keyFiles['README.md'].slice(0, 300)}` : '',
178
+ ];
179
+
180
+ if (leakDocs.length > 0) {
181
+ lines.push('');
182
+ lines.push(`LEAK DOCUMENTS DETECTED: ${leakDocs.length} HTML file(s)`);
183
+ for (const doc of leakDocs) {
184
+ const ex = doc.extraction;
185
+ lines.push(` File: ${doc.path}`);
186
+ lines.push(` Title: ${ex.title}`);
187
+ lines.push(` Signal phrases found: ${ex.signalMatches.join(', ') || 'none'}`);
188
+ lines.push(` Key quotes extracted: ${ex.allNotableQuotes.length}`);
189
+ lines.push(` Cyber-risk warnings: ${ex.cyberRiskWarnings.length}`);
190
+ if (ex.allNotableQuotes.length > 0) {
191
+ lines.push(' Top quotes:');
192
+ ex.allNotableQuotes.slice(0, 4).forEach(q => lines.push(` • "${q.slice(0, 150)}"`));
193
+ }
194
+ }
195
+ }
196
+
197
+ return lines.filter(l => l !== undefined).join('\n');
198
+ }
199
+
200
+ function buildSandboxContext(source) {
201
+ return {
202
+ repoName: source.split('/').pop().replace('.git', '') || 'sandbox-repo',
203
+ localPath: null,
204
+ isRemote: true,
205
+ isSandbox: true,
206
+ files: [
207
+ { path: 'src/index.js', ext: '.js', preview: '// sandbox placeholder', size: 100 },
208
+ { path: 'README.md', ext: '.md', preview: '# Sandbox Repo', size: 50 },
209
+ ],
210
+ stack: { languages: ['JavaScript'], frameworks: ['Express'], infra: [] },
211
+ keyFiles: { 'README.md': '# Sandbox Repo\nGenerated in sandbox mode.' },
212
+ summary: `[SANDBOX] Repository: ${source}\nFiles analyzed: 2 (fake)\nLanguages: JavaScript`,
213
+ };
214
+ }
215
+
216
+ module.exports = { analyzeSource };