intelwatch 1.0.0 → 1.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Recognity
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "intelwatch",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Competitive intelligence CLI — track competitors, keywords, and brand mentions from the terminal",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -0,0 +1,329 @@
1
+ import chalk from 'chalk';
2
+ import Table from 'cli-table3';
3
+ import { pappersGetFullDossier, pappersSearchByName } from '../scrapers/pappers.js';
4
+ import { searchPressMentions } from '../scrapers/brave-search.js';
5
+ import { analyzeSite } from '../scrapers/site-analyzer.js';
6
+ import { callAI, hasAIKey } from '../ai/client.js';
7
+ import { header, section, warn, error } from '../utils/display.js';
8
+
9
+ const LICENSE_URL = 'https://recognity.fr/tools/intelwatch';
10
+
11
+ export async function runMA(sirenOrName, options) {
12
+ const hasLicense = !!process.env.INTELWATCH_LICENSE_KEY;
13
+ const isPreview = !!options.preview;
14
+
15
+ // ── License gate ───────────────────────────────────────────────────────────
16
+ if (!hasLicense && !isPreview) {
17
+ console.log(chalk.yellow.bold('\n ⚡ Deep Profile Due Diligence — Module Premium\n'));
18
+ console.log(chalk.red(' The Deep Profile requires an Intelwatch Deep Profile license.'));
19
+ console.log(chalk.gray(` Get yours at ${LICENSE_URL}\n`));
20
+ console.log(chalk.gray(' Run with --preview for a limited preview (company identity + last year financials only).'));
21
+ console.log('');
22
+ process.exit(1);
23
+ }
24
+
25
+ if (isPreview && !hasLicense) {
26
+ console.log(chalk.yellow(' ⚡ PREVIEW MODE — Company identity + last year financials only'));
27
+ console.log(chalk.gray(` Upgrade to Intelwatch Deep Profile for full due diligence: ${LICENSE_URL}\n`));
28
+ }
29
+
30
+ // ── SIREN or name lookup ───────────────────────────────────────────────────
31
+ let siren = sirenOrName;
32
+
33
+ if (!/^\d{9}$/.test(sirenOrName)) {
34
+ console.log(chalk.gray(` Searching for: "${sirenOrName}"...`));
35
+ const { results, error: searchErr } = await pappersSearchByName(sirenOrName, { count: 1 });
36
+ if (searchErr || !results.length) {
37
+ error(`Company not found: ${searchErr || 'No results'}`);
38
+ process.exit(1);
39
+ }
40
+ siren = results[0].siren;
41
+ const foundName = results[0].nom_entreprise || results[0].denomination;
42
+ console.log(chalk.gray(` Found: ${foundName} (SIREN: ${siren})`));
43
+ }
44
+
45
+ // ── Fetch full dossier ─────────────────────────────────────────────────────
46
+ console.log(chalk.gray(' Fetching dossier from Pappers...'));
47
+ const { data, error: dossierErr } = await pappersGetFullDossier(siren);
48
+
49
+ if (dossierErr || !data) {
50
+ error(`Failed to fetch dossier: ${dossierErr || 'Unknown error'}`);
51
+ process.exit(1);
52
+ }
53
+
54
+ const { identity, financialHistory, ubo, bodacc, dirigeants, proceduresCollectives } = data;
55
+
56
+ // ── Header ─────────────────────────────────────────────────────────────────
57
+ header(`🏢 Due Diligence Deep Profile — ${identity.name || siren}`);
58
+
59
+ // ── Company Identity ───────────────────────────────────────────────────────
60
+ section(' 📋 Identité');
61
+ const statusColor = identity.status === 'Actif' ? chalk.green : chalk.red;
62
+ printRow('Nom', identity.name);
63
+ printRow('SIREN', identity.siren);
64
+ printRow('SIRET siège', identity.siret);
65
+ printRow('Forme juridique', identity.formeJuridique);
66
+ printRow('Capital', identity.capital != null ? `${formatEuro(identity.capital)} ${identity.capitalMonnaie}` : null);
67
+ printRow('NAF', identity.nafCode ? `${identity.nafCode} — ${identity.nafLabel}` : null);
68
+ printRow('Création', identity.dateCreation);
69
+ printRow('Statut', identity.status, statusColor(identity.status));
70
+ printRow('Effectifs', identity.effectifs);
71
+ printRow('Adresse', [identity.adresse, identity.codePostal, identity.ville].filter(Boolean).join(' ') || null);
72
+ if (identity.website) printRow('Site web', identity.website);
73
+
74
+ // ── Preview mode stops here (one year of financials) ──────────────────────
75
+ if (isPreview) {
76
+ const lastFin = financialHistory[0];
77
+ section(' 💶 Derniers résultats financiers (preview)');
78
+ if (lastFin) {
79
+ printRow('Année', String(lastFin.annee));
80
+ printRow('Chiffre d\'affaires', lastFin.ca != null ? formatEuro(lastFin.ca) : null);
81
+ printRow('Résultat net', lastFin.resultat != null ? formatEuro(lastFin.resultat) : null);
82
+ printRow('Capitaux propres', lastFin.capitauxPropres != null ? formatEuro(lastFin.capitauxPropres) : null);
83
+ } else {
84
+ console.log(chalk.gray(' Données financières non disponibles.'));
85
+ }
86
+ console.log('');
87
+ console.log(chalk.yellow(` ⚡ Accédez au rapport complet avec Intelwatch Deep Profile : ${LICENSE_URL}`));
88
+ console.log('');
89
+ return;
90
+ }
91
+
92
+ // ══════════════════════════════════════════════════════════════════════════
93
+ // FULL MODE (licensed users)
94
+ // ══════════════════════════════════════════════════════════════════════════
95
+
96
+ // ── Procédures collectives (alert at top if any) ──────────────────────────
97
+ if (proceduresCollectives.length > 0) {
98
+ section(' 🚨 Procédures collectives');
99
+ for (const p of proceduresCollectives) {
100
+ const label = [p.type, p.jugement].filter(Boolean).join(' — ');
101
+ const loc = p.tribunal ? ` (${p.tribunal})` : '';
102
+ console.log(chalk.red(` [${p.date || '?'}] ${label}${loc}`));
103
+ }
104
+ }
105
+
106
+ // ── Dirigeants & mandats ───────────────────────────────────────────────────
107
+ if (dirigeants.length > 0) {
108
+ section(` 👔 Dirigeants (${dirigeants.length})`);
109
+ for (const d of dirigeants) {
110
+ const name = [d.prenom, d.nom].filter(Boolean).join(' ');
111
+ console.log('');
112
+ console.log(' ' + chalk.white.bold(name) + chalk.gray(` — ${d.role || '?'}`));
113
+ if (d.dateNomination) console.log(chalk.gray(` Nommé le : ${d.dateNomination}`));
114
+ if (d.nationalite) console.log(chalk.gray(` Nationalité : ${d.nationalite}`));
115
+ if (d.mandats.length > 0) {
116
+ console.log(chalk.gray(` Mandats (${d.mandats.length}) :`));
117
+ for (const m of d.mandats.slice(0, 6)) {
118
+ const dot = m.etat === 'actif' ? chalk.green('●') : chalk.gray('○');
119
+ const denom = m.denomination || m.siren || '?';
120
+ console.log(chalk.gray(` ${dot} ${denom} — ${m.role || '?'}`));
121
+ }
122
+ if (d.mandats.length > 6) {
123
+ console.log(chalk.gray(` ... et ${d.mandats.length - 6} autre(s)`));
124
+ }
125
+ }
126
+ }
127
+ console.log('');
128
+ }
129
+
130
+ // ── UBO ───────────────────────────────────────────────────────────────────
131
+ section(` 🔑 Bénéficiaires effectifs — UBO (${ubo.length})`);
132
+ if (ubo.length > 0) {
133
+ for (const b of ubo) {
134
+ const name = [b.prenom, b.nom].filter(Boolean).join(' ');
135
+ const stakes = [];
136
+ if (b.pourcentageParts != null) stakes.push(`${b.pourcentageParts}% parts`);
137
+ if (b.pourcentageVotes != null) stakes.push(`${b.pourcentageVotes}% votes`);
138
+ const stakeStr = stakes.length ? chalk.yellow(` — ${stakes.join(', ')}`) : '';
139
+ console.log(' ' + chalk.white(name) + stakeStr);
140
+ if (b.nationalite) console.log(chalk.gray(` Nationalité : ${b.nationalite}`));
141
+ if (b.dateNaissance) console.log(chalk.gray(` Né(e) le : ${b.dateNaissance}`));
142
+ }
143
+ } else {
144
+ console.log(chalk.gray(' Non disponible ou non déclaré.'));
145
+ }
146
+
147
+ // ── Financial history table ────────────────────────────────────────────────
148
+ section(' 💶 Historique financier');
149
+ if (financialHistory.length > 0) {
150
+ const table = new Table({
151
+ head: ['Année', 'Chiffre d\'affaires', 'Résultat net', 'Capitaux propres'].map(h => chalk.cyan.bold(h)),
152
+ style: { head: [], border: ['grey'] },
153
+ colAligns: ['left', 'right', 'right', 'right'],
154
+ });
155
+ for (const f of financialHistory) {
156
+ table.push([
157
+ chalk.white(f.annee ?? '—'),
158
+ f.ca != null ? chalk.white(formatEuro(f.ca)) : chalk.gray('—'),
159
+ f.resultat != null
160
+ ? (f.resultat >= 0 ? chalk.green(formatEuro(f.resultat)) : chalk.red(formatEuro(f.resultat)))
161
+ : chalk.gray('—'),
162
+ f.capitauxPropres != null
163
+ ? (f.capitauxPropres >= 0 ? chalk.white(formatEuro(f.capitauxPropres)) : chalk.red(formatEuro(f.capitauxPropres)))
164
+ : chalk.gray('—'),
165
+ ]);
166
+ }
167
+ console.log(table.toString());
168
+ } else {
169
+ console.log(chalk.gray(' Aucune donnée financière disponible.'));
170
+ }
171
+
172
+ // ── BODACC publications ────────────────────────────────────────────────────
173
+ if (bodacc.length > 0) {
174
+ section(` 📰 Publications BODACC (${bodacc.length} dernières)`);
175
+ for (const pub of bodacc) {
176
+ const label = pub.description || pub.type || '?';
177
+ const trib = pub.tribunal ? chalk.gray(` — ${pub.tribunal}`) : '';
178
+ console.log(chalk.gray(` [${pub.date || '?'}] `) + chalk.white(label) + trib);
179
+ }
180
+ }
181
+
182
+ // ── Digital footprint ─────────────────────────────────────────────────────
183
+ const websiteUrl = identity.website
184
+ ? (identity.website.startsWith('http') ? identity.website : `https://${identity.website}`)
185
+ : null;
186
+
187
+ if (websiteUrl) {
188
+ section(' 🌐 Empreinte numérique');
189
+ console.log(chalk.gray(` Analyzing ${websiteUrl}...`));
190
+ try {
191
+ const siteData = await analyzeSite(websiteUrl);
192
+ if (siteData.error) {
193
+ warn(` Site non accessible: ${siteData.error}`);
194
+ } else {
195
+ const techNames = (siteData.techStack || []).map(t => t.name).join(', ') || 'aucune détectée';
196
+ printRow('Technologies', techNames);
197
+ if (siteData.performance) {
198
+ printRow('Performance', `${siteData.performance.responseTimeMs}ms, ${siteData.performance.htmlSizeKB} KB`);
199
+ }
200
+ if (siteData.security) {
201
+ const s = siteData.security;
202
+ const score = [s.https, s.hsts, s.xFrameOptions, s.csp, s.xContentType].filter(Boolean).length;
203
+ printRow('Sécurité', `${score}/5 (HTTPS:${s.https ? '✓' : '✗'} HSTS:${s.hsts ? '✓' : '✗'} CSP:${s.csp ? '✓' : '✗'})`);
204
+ }
205
+ if (siteData.socialLinks && Object.keys(siteData.socialLinks).length > 0) {
206
+ printRow('Réseaux sociaux', Object.keys(siteData.socialLinks).join(', '));
207
+ }
208
+ if (siteData.contentStats?.recentArticles?.length > 0) {
209
+ printRow('Blog', `${siteData.contentStats.articleCount} articles récents`);
210
+ }
211
+ }
212
+ } catch (e) {
213
+ warn(` Impossible d'analyser le site: ${e.message}`);
214
+ }
215
+ }
216
+
217
+ // ── Press & mentions ───────────────────────────────────────────────────────
218
+ if (identity.name) {
219
+ section(' 📣 Presse & réputation');
220
+ console.log(chalk.gray(` Searching mentions for "${identity.name}"...`));
221
+ try {
222
+ const press = await searchPressMentions(identity.name);
223
+ if (press.mentionCount > 0) {
224
+ const bd = press.mentions.reduce((acc, m) => {
225
+ const k = /positive/.test(m.sentiment) ? 'positive'
226
+ : /negative/.test(m.sentiment) ? 'negative' : 'neutral';
227
+ acc[k] = (acc[k] || 0) + 1;
228
+ return acc;
229
+ }, {});
230
+ console.log(chalk.magenta(` ${press.mentionCount} mentions | 👍${bd.positive || 0} 😐${bd.neutral || 0} 👎${bd.negative || 0}`));
231
+ for (const m of press.mentions.slice(0, 8)) {
232
+ const emoji = /positive/.test(m.sentiment) ? '👍' : /negative/.test(m.sentiment) ? '👎' : '😐';
233
+ console.log(chalk.gray(` ${emoji} [${m.category}] ${(m.title || '').substring(0, 80)} (${m.domain})`));
234
+ }
235
+ } else {
236
+ console.log(chalk.gray(' Aucune mention récente trouvée.'));
237
+ }
238
+ } catch (e) {
239
+ warn(` Press search failed: ${e.message}`);
240
+ }
241
+ }
242
+
243
+ // ── AI Summary ────────────────────────────────────────────────────────────
244
+ if (options.ai) {
245
+ section(' 🤖 Synthèse IA — Due Diligence');
246
+ if (!hasAIKey()) {
247
+ warn(' No AI API key. Set OPENAI_API_KEY or ANTHROPIC_API_KEY.');
248
+ } else {
249
+ console.log(chalk.gray(' Generating AI due diligence summary...'));
250
+ try {
251
+ const finSummary = financialHistory
252
+ .map(f => `${f.annee}: CA=${f.ca != null ? formatEuro(f.ca) : 'N/A'}, Résultat=${f.resultat != null ? formatEuro(f.resultat) : 'N/A'}, CP=${f.capitauxPropres != null ? formatEuro(f.capitauxPropres) : 'N/A'}`)
253
+ .join('\n') || 'Non disponible';
254
+
255
+ const dirStr = dirigeants
256
+ .map(d => `${d.prenom || ''} ${d.nom || ''} (${d.role || '?'}): ${d.mandats.length} mandats`)
257
+ .join(', ') || 'Non disponible';
258
+
259
+ const uboStr = ubo
260
+ .map(b => `${b.prenom || ''} ${b.nom || ''}: ${b.pourcentageParts ?? '?'}% parts`)
261
+ .join(', ') || 'Non déclaré';
262
+
263
+ const procStr = proceduresCollectives.length
264
+ ? proceduresCollectives.map(p => `${p.date || '?'}: ${p.type || '?'}`).join(', ')
265
+ : 'Aucune';
266
+
267
+ const systemPrompt = 'Tu es un analyste Deep Profile expert. Rédige une synthèse de due diligence concise et professionnelle en français.';
268
+ const userPrompt = `Synthèse due diligence pour ${identity.name} (SIREN: ${identity.siren})
269
+
270
+ **Identité**
271
+ - Forme: ${identity.formeJuridique || '?'}
272
+ - Création: ${identity.dateCreation || '?'}
273
+ - Effectifs: ${identity.effectifs || '?'}
274
+ - NAF: ${identity.nafCode} — ${identity.nafLabel}
275
+ - Capital: ${identity.capital != null ? formatEuro(identity.capital) : '?'}
276
+
277
+ **Dirigeants**
278
+ ${dirStr}
279
+
280
+ **UBO (${ubo.length})**
281
+ ${uboStr}
282
+
283
+ **Historique financier**
284
+ ${finSummary}
285
+
286
+ **Procédures collectives**
287
+ ${procStr}
288
+
289
+ **Publications BODACC récentes**
290
+ ${bodacc.slice(0, 5).map(b => `${b.date || '?'}: ${b.type || '?'}`).join(', ') || 'Aucune'}
291
+
292
+ Rédige une synthèse en 5 points : 1) Profil, 2) Gouvernance & actionnariat, 3) Situation financière, 4) Risques identifiés, 5) Points d'attention pour l'acquéreur. Sois factuel, max 400 mots.`;
293
+
294
+ const summary = await callAI(systemPrompt, userPrompt, { maxTokens: 600 });
295
+ console.log('\n' + chalk.white(summary) + '\n');
296
+ } catch (e) {
297
+ warn(` AI summary failed: ${e.message}`);
298
+ }
299
+ }
300
+ }
301
+
302
+ // ── Footer ─────────────────────────────────────────────────────────────────
303
+ console.log('');
304
+ const today = new Date().toLocaleDateString('fr-FR', { year: 'numeric', month: 'long', day: 'numeric' });
305
+ console.log(chalk.gray(` Source : Pappers.fr — ${today}`));
306
+ console.log('');
307
+ }
308
+
309
+ // ── Helpers ───────────────────────────────────────────────────────────────────
310
+
311
+ function printRow(label, value, coloredValue) {
312
+ const padded = label.padEnd(16);
313
+ const display = coloredValue ?? (value != null ? chalk.white(value) : chalk.gray('—'));
314
+ console.log(chalk.gray(` ${padded}: `) + display);
315
+ }
316
+
317
+ function formatNum(n) {
318
+ return Number(n).toLocaleString('fr-FR');
319
+ }
320
+
321
+ function formatEuro(n) {
322
+ if (n == null) return '—';
323
+ const abs = Math.abs(n);
324
+ const sign = n < 0 ? '-' : '';
325
+ if (abs >= 1_000_000_000) return `${sign}${(abs / 1_000_000_000).toFixed(2).replace('.', ',')} Md€`;
326
+ if (abs >= 1_000_000) return `${sign}${(abs / 1_000_000).toFixed(1).replace('.', ',')} M€`;
327
+ if (abs >= 1_000) return `${sign}${formatNum(Math.round(abs / 1_000))} K€`;
328
+ return `${sign}${formatNum(abs)} €`;
329
+ }
package/src/index.js CHANGED
@@ -11,6 +11,7 @@ import { setupNotifications } from './commands/notify.js';
11
11
  import { listTrackers, removeTrackerCmd } from './commands/list.js';
12
12
  import { runAISummary } from './commands/ai-summary.js';
13
13
  import { runPitch } from './commands/pitch.js';
14
+ import { runMA } from './commands/profile.js';
14
15
 
15
16
  const program = new Command();
16
17
 
@@ -154,6 +155,17 @@ program
154
155
  await runPitch(trackerId, options);
155
156
  });
156
157
 
158
+ // ─── m-a ──────────────────────────────────────────────────────────────────────
159
+
160
+ program
161
+ .command('profile <siren-or-name>')
162
+ .description('M&A due diligence report for a French company (requires Pro license)')
163
+ .option('--preview', 'Run limited preview: company identity + last year financials only')
164
+ .option('--ai', 'Generate an AI-powered due diligence summary (requires AI API key)')
165
+ .action(async (sirenOrName, options) => {
166
+ await runMA(sirenOrName, options);
167
+ });
168
+
157
169
  // ─── discover ─────────────────────────────────────────────────────────────────
158
170
 
159
171
  program
@@ -1,6 +1,7 @@
1
1
  import axios from 'axios';
2
2
 
3
3
  const PAPPERS_API = 'https://api.pappers.fr/v1';
4
+ const PAPPERS_API_V2 = 'https://api.pappers.fr/v2';
4
5
 
5
6
  function getApiKey() {
6
7
  return process.env.PAPPERS_API_KEY || null;
@@ -71,6 +72,104 @@ export async function pappersLookup(companyName) {
71
72
  return formatPappersDetail(detail.data);
72
73
  }
73
74
 
75
+ /**
76
+ * Get full M&A dossier for a company by SIREN.
77
+ * Returns parsed financial history, UBO, BODACC, dirigeants with mandats,
78
+ * and collective procedures.
79
+ */
80
+ export async function pappersGetFullDossier(siren) {
81
+ const apiKey = getApiKey();
82
+ if (!apiKey) return { data: null, error: 'No PAPPERS_API_KEY set' };
83
+
84
+ try {
85
+ const resp = await axios.get(`${PAPPERS_API}/entreprise`, {
86
+ params: { api_token: apiKey, siren },
87
+ timeout: 15000,
88
+ });
89
+
90
+ const d = resp.data;
91
+
92
+ // Financial history — last 5 years
93
+ const financialHistory = (d.finances || []).slice(0, 5).map(f => ({
94
+ annee: f.annee,
95
+ ca: f.chiffre_affaires ?? null,
96
+ resultat: f.resultat ?? null,
97
+ capitauxPropres: f.capitaux_propres ?? null,
98
+ effectif: f.effectif ?? null,
99
+ }));
100
+
101
+ // UBO — bénéficiaires effectifs
102
+ const ubo = (d.beneficiaires_effectifs || []).map(b => ({
103
+ nom: b.nom,
104
+ prenom: b.prenom,
105
+ dateNaissance: b.date_de_naissance_formate || b.date_naissance || null,
106
+ nationalite: b.nationalite || null,
107
+ pourcentageParts: b.pourcentage_parts ?? null,
108
+ pourcentageVotes: b.pourcentage_votes ?? null,
109
+ }));
110
+
111
+ // BODACC publications — last 10
112
+ const bodacc = (d.publications_bodacc || []).slice(0, 10).map(p => ({
113
+ date: p.date,
114
+ type: p.type,
115
+ tribunal: p.tribunal || null,
116
+ numero: p.numero_annonce || null,
117
+ description: p.acte?.actes_publies?.[0]?.type_acte || p.type || null,
118
+ }));
119
+
120
+ // Dirigeants with their mandats in other companies
121
+ const dirigeants = (d.dirigeants || []).map(dir => ({
122
+ nom: dir.nom,
123
+ prenom: dir.prenom,
124
+ role: dir.fonction,
125
+ dateNomination: dir.date_prise_de_poste || null,
126
+ dateNaissance: dir.date_de_naissance_formate || null,
127
+ nationalite: dir.nationalite || null,
128
+ mandats: (dir.entreprises_dirigees || []).map(e => ({
129
+ siren: e.siren,
130
+ denomination: e.denomination || e.nom_entreprise || null,
131
+ role: e.fonction || null,
132
+ etat: e.etat || null,
133
+ })),
134
+ }));
135
+
136
+ // Procédures collectives
137
+ const proceduresCollectives = (d.procedures_collectives || []).map(p => ({
138
+ date: p.date_effet || p.date || null,
139
+ type: p.type || null,
140
+ jugement: p.nature_jugement || null,
141
+ tribunal: p.tribunal || null,
142
+ }));
143
+
144
+ // Company identity
145
+ const identity = {
146
+ siren: d.siren,
147
+ siret: d.siege?.siret || null,
148
+ name: d.nom_entreprise || d.denomination || null,
149
+ dateCreation: d.date_creation || null,
150
+ nafCode: d.code_naf || null,
151
+ nafLabel: d.libelle_code_naf || null,
152
+ formeJuridique: d.forme_juridique || null,
153
+ effectifs: d.tranche_effectif || d.effectif || null,
154
+ adresse: d.siege?.adresse_ligne_1 || d.siege?.adresse || null,
155
+ ville: d.siege?.ville || null,
156
+ codePostal: d.siege?.code_postal || null,
157
+ capital: d.capital ?? null,
158
+ capitalMonnaie: d.devise_capital || 'EUR',
159
+ website: d.site_internet || d.domaine_de_messagerie || null,
160
+ status: d.etat === 'actif' ? 'Actif' : (d.etat || 'Inconnu'),
161
+ dateRadiation: d.date_radiation || null,
162
+ };
163
+
164
+ return {
165
+ data: { identity, financialHistory, ubo, bodacc, dirigeants, proceduresCollectives, raw: d },
166
+ error: null,
167
+ };
168
+ } catch (err) {
169
+ return { data: null, error: err.message };
170
+ }
171
+ }
172
+
74
173
  function formatPappersResult(r) {
75
174
  return {
76
175
  siren: r.siren,