@arka-labs/nemesis 1.2.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 +201 -0
- package/README.md +668 -0
- package/lib/core/agent-launcher.js +193 -0
- package/lib/core/audit.js +210 -0
- package/lib/core/connexions.js +80 -0
- package/lib/core/flowmap/api.js +111 -0
- package/lib/core/flowmap/cli-helpers.js +80 -0
- package/lib/core/flowmap/machine.js +281 -0
- package/lib/core/flowmap/persistence.js +83 -0
- package/lib/core/generators.js +183 -0
- package/lib/core/inbox.js +275 -0
- package/lib/core/logger.js +20 -0
- package/lib/core/mission.js +109 -0
- package/lib/core/notewriter/config.js +36 -0
- package/lib/core/notewriter/cr.js +237 -0
- package/lib/core/notewriter/log.js +112 -0
- package/lib/core/notewriter/notes.js +168 -0
- package/lib/core/notewriter/paths.js +45 -0
- package/lib/core/notewriter/reader.js +121 -0
- package/lib/core/notewriter/registry.js +80 -0
- package/lib/core/odm.js +191 -0
- package/lib/core/profile-picker.js +323 -0
- package/lib/core/project.js +287 -0
- package/lib/core/registry.js +129 -0
- package/lib/core/secrets.js +137 -0
- package/lib/core/services.js +45 -0
- package/lib/core/team.js +287 -0
- package/lib/core/templates.js +80 -0
- package/lib/kairos/agent-runner.js +261 -0
- package/lib/kairos/claude-invoker.js +90 -0
- package/lib/kairos/context-injector.js +331 -0
- package/lib/kairos/context-loader.js +108 -0
- package/lib/kairos/context-writer.js +45 -0
- package/lib/kairos/dispatcher-router.js +173 -0
- package/lib/kairos/dispatcher.js +139 -0
- package/lib/kairos/event-bus.js +287 -0
- package/lib/kairos/event-router.js +131 -0
- package/lib/kairos/flowmap-bridge.js +120 -0
- package/lib/kairos/hook-handlers.js +351 -0
- package/lib/kairos/hook-installer.js +207 -0
- package/lib/kairos/hook-prompts.js +54 -0
- package/lib/kairos/leader-rules.js +94 -0
- package/lib/kairos/pid-checker.js +108 -0
- package/lib/kairos/situation-detector.js +123 -0
- package/lib/sync/fallback-engine.js +97 -0
- package/lib/sync/hcm-client.js +170 -0
- package/lib/sync/health.js +47 -0
- package/lib/sync/llm-client.js +387 -0
- package/lib/sync/nemesis-client.js +379 -0
- package/lib/sync/service-session.js +74 -0
- package/lib/sync/sync-engine.js +178 -0
- package/lib/ui/box.js +104 -0
- package/lib/ui/brand.js +42 -0
- package/lib/ui/colors.js +57 -0
- package/lib/ui/dashboard.js +580 -0
- package/lib/ui/error-hints.js +49 -0
- package/lib/ui/format.js +61 -0
- package/lib/ui/menu.js +306 -0
- package/lib/ui/note-card.js +198 -0
- package/lib/ui/note-colors.js +26 -0
- package/lib/ui/note-detail.js +297 -0
- package/lib/ui/note-filters.js +252 -0
- package/lib/ui/note-views.js +283 -0
- package/lib/ui/prompt.js +81 -0
- package/lib/ui/spinner.js +139 -0
- package/lib/ui/streambox.js +46 -0
- package/lib/ui/table.js +42 -0
- package/lib/ui/tree.js +33 -0
- package/package.json +53 -0
- package/src/cli.js +457 -0
- package/src/commands/_helpers.js +119 -0
- package/src/commands/audit.js +187 -0
- package/src/commands/auth.js +316 -0
- package/src/commands/doctor.js +243 -0
- package/src/commands/hcm.js +147 -0
- package/src/commands/inbox.js +333 -0
- package/src/commands/init.js +160 -0
- package/src/commands/kairos.js +216 -0
- package/src/commands/kars.js +134 -0
- package/src/commands/mission.js +275 -0
- package/src/commands/notes.js +316 -0
- package/src/commands/notewriter.js +296 -0
- package/src/commands/odm.js +329 -0
- package/src/commands/orch.js +68 -0
- package/src/commands/project.js +123 -0
- package/src/commands/run.js +123 -0
- package/src/commands/services.js +705 -0
- package/src/commands/status.js +231 -0
- package/src/commands/team.js +572 -0
- package/src/config.js +84 -0
- package/src/index.js +5 -0
- package/templates/project-context.json +10 -0
- package/templates/template_CONTRIB-NAME.json +22 -0
- package/templates/template_CR-ODM-NAME-000.exemple.json +32 -0
- package/templates/template_DEC-NAME-000.json +18 -0
- package/templates/template_INTV-NAME-000.json +15 -0
- package/templates/template_MISSION_CONTRACT.json +46 -0
- package/templates/template_ODM-NAME-000.json +89 -0
- package/templates/template_REGISTRY-PROJECT.json +26 -0
- package/templates/template_TXN-NAME-000.json +24 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { detectProject } from '../../lib/core/project.js';
|
|
5
|
+
import { readRegistry, getLanes } from '../../lib/core/registry.js';
|
|
6
|
+
import { diagnoseHcm } from '../../lib/sync/health.js';
|
|
7
|
+
import { readServices, SERVICE_IDS } from '../../lib/core/services.js';
|
|
8
|
+
import { listConnexions } from '../../lib/core/connexions.js';
|
|
9
|
+
import { verifyHooks, ALL_HOOKS } from '../../lib/kairos/hook-installer.js';
|
|
10
|
+
import { style } from '../../lib/ui/colors.js';
|
|
11
|
+
|
|
12
|
+
const HELP = `
|
|
13
|
+
nemesis doctor — Diagnostic complet
|
|
14
|
+
|
|
15
|
+
Usage: nemesis doctor
|
|
16
|
+
|
|
17
|
+
Options:
|
|
18
|
+
-h, --help Aide
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
const HCM_EXPECTED_DIRS = [
|
|
22
|
+
'contracts', 'odm', 'cr', 'transactions', 'note',
|
|
23
|
+
'decisions', 'interventions', 'contributors', 'project', 'odm-cr-QA',
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
const EXPECTED_TEMPLATES = [
|
|
27
|
+
'template_ODM-NAME-000.json',
|
|
28
|
+
'template_CR-ODM-NAME-000.exemple.json',
|
|
29
|
+
'template_MISSION_CONTRACT.json',
|
|
30
|
+
'template_REGISTRY-PROJECT.json',
|
|
31
|
+
'template_DEC-NAME-000.json',
|
|
32
|
+
'template_INTV-NAME-000.json',
|
|
33
|
+
'template_CONTRIB-NAME.json',
|
|
34
|
+
'template_TXN-NAME-000.json',
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
const ok = (msg) => ` ${style.green('\u2713')} ${msg}`;
|
|
38
|
+
const ko = (msg) => ` ${style.red('\u2717')} ${msg}`;
|
|
39
|
+
const warn = (msg) => ` ${style.yellow('\u26A0')} ${msg}`;
|
|
40
|
+
|
|
41
|
+
export async function handler({ args, flags, config }) {
|
|
42
|
+
if (flags.help || args.includes('--help') || args.includes('-h')) {
|
|
43
|
+
console.log(HELP);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const project = detectProject(config.cwd);
|
|
48
|
+
let hasErrors = false;
|
|
49
|
+
|
|
50
|
+
// Check 1: Structure .nemesis/HCM/
|
|
51
|
+
console.log(`\n ${style.bold('Structure .nemesis/HCM/')} :`);
|
|
52
|
+
if (!project) {
|
|
53
|
+
console.log(ko('Aucun projet detecte'));
|
|
54
|
+
hasErrors = true;
|
|
55
|
+
} else {
|
|
56
|
+
for (const dir of HCM_EXPECTED_DIRS) {
|
|
57
|
+
const path = join(project.hcm_dir, dir);
|
|
58
|
+
if (existsSync(path)) {
|
|
59
|
+
console.log(ok(`${dir}/`));
|
|
60
|
+
} else {
|
|
61
|
+
console.log(ko(`${dir}/ MANQUANT`));
|
|
62
|
+
hasErrors = true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const processFile = join(project.hcm_dir, 'PROCESS.md');
|
|
66
|
+
if (existsSync(processFile)) {
|
|
67
|
+
console.log(ok('PROCESS.md'));
|
|
68
|
+
} else {
|
|
69
|
+
console.log(ko('PROCESS.md MANQUANT'));
|
|
70
|
+
hasErrors = true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Check 2: Templates
|
|
75
|
+
console.log(`\n ${style.bold('Templates .nemesis/template/')} :`);
|
|
76
|
+
const templateDir = join(config.cwd, '.nemesis', 'template');
|
|
77
|
+
if (existsSync(templateDir)) {
|
|
78
|
+
const files = readdirSync(templateDir);
|
|
79
|
+
let found = 0;
|
|
80
|
+
for (const tmpl of EXPECTED_TEMPLATES) {
|
|
81
|
+
if (files.includes(tmpl)) found++;
|
|
82
|
+
}
|
|
83
|
+
if (found === EXPECTED_TEMPLATES.length) {
|
|
84
|
+
console.log(ok(`${found} templates presents`));
|
|
85
|
+
} else {
|
|
86
|
+
console.log(warn(`${found}/${EXPECTED_TEMPLATES.length} templates`));
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
console.log(ko('.nemesis/template/ MANQUANT'));
|
|
90
|
+
hasErrors = true;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Check 3: Config
|
|
94
|
+
console.log(`\n ${style.bold('Config')} :`);
|
|
95
|
+
const configFile = join(homedir(), '.nemesis', 'config.json');
|
|
96
|
+
if (existsSync(configFile)) {
|
|
97
|
+
console.log(ok('~/.nemesis/config.json'));
|
|
98
|
+
} else {
|
|
99
|
+
console.log(warn('~/.nemesis/config.json absent (defaults utilises)'));
|
|
100
|
+
}
|
|
101
|
+
if (project) {
|
|
102
|
+
console.log(ok(`Projet detecte : ${project.id}`));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Check 4: HCM
|
|
106
|
+
console.log(`\n ${style.bold('HCM')} :`);
|
|
107
|
+
try {
|
|
108
|
+
const hcmResult = await diagnoseHcm();
|
|
109
|
+
console.log(` URL : ${hcmResult.url}`);
|
|
110
|
+
for (const check of hcmResult.checks) {
|
|
111
|
+
console.log(check.ok ? ok(`${check.label} : ${check.detail}`) : ko(`${check.label} : ${check.detail}`));
|
|
112
|
+
}
|
|
113
|
+
if (!hcmResult.ok) hasErrors = true;
|
|
114
|
+
} catch (err) {
|
|
115
|
+
console.log(ko(`Erreur : ${err.message}`));
|
|
116
|
+
hasErrors = true;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Check 5: Registry vs CLAUDE.md
|
|
120
|
+
console.log(`\n ${style.bold('Registre')} :`);
|
|
121
|
+
if (project) {
|
|
122
|
+
const registry = readRegistry(project.hcm_dir);
|
|
123
|
+
if (registry) {
|
|
124
|
+
const lanes = getLanes(registry);
|
|
125
|
+
console.log(ok(`REGISTRY (${lanes.length + 1} membres)`));
|
|
126
|
+
|
|
127
|
+
const claudeMdPath = join(homedir(), '.claude', 'CLAUDE.md');
|
|
128
|
+
if (existsSync(claudeMdPath)) {
|
|
129
|
+
const claudeContent = readFileSync(claudeMdPath, 'utf-8');
|
|
130
|
+
let syncCount = 0;
|
|
131
|
+
for (const lane of lanes) {
|
|
132
|
+
if (claudeContent.includes(lane.name || lane.id)) syncCount++;
|
|
133
|
+
}
|
|
134
|
+
if (syncCount === lanes.length) {
|
|
135
|
+
console.log(ok(`CLAUDE.md sync (${lanes.length} agents)`));
|
|
136
|
+
} else {
|
|
137
|
+
console.log(warn(`CLAUDE.md desync (${syncCount}/${lanes.length} agents)`));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
} else {
|
|
141
|
+
console.log(ko('Registry introuvable'));
|
|
142
|
+
hasErrors = true;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Check 6: Agent memory files
|
|
147
|
+
console.log(`\n ${style.bold('Agents')} :`);
|
|
148
|
+
if (project) {
|
|
149
|
+
const registry = readRegistry(project.hcm_dir);
|
|
150
|
+
if (registry) {
|
|
151
|
+
const lanes = getLanes(registry);
|
|
152
|
+
for (const lane of lanes) {
|
|
153
|
+
if (lane.memory_path) {
|
|
154
|
+
const fullPath = join(project.root, lane.memory_path);
|
|
155
|
+
if (existsSync(fullPath)) {
|
|
156
|
+
const stat = statSync(fullPath);
|
|
157
|
+
const size = (stat.size / 1024).toFixed(1);
|
|
158
|
+
console.log(ok(`${lane.name || lane.id} : memory.md present (${size} KB)`));
|
|
159
|
+
} else {
|
|
160
|
+
console.log(ko(`${lane.name || lane.id} : memory.md MANQUANT`));
|
|
161
|
+
hasErrors = true;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (lanes.length === 0) {
|
|
166
|
+
console.log(' (aucun agent enregistre)');
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Check 7: Services LLM
|
|
172
|
+
console.log(`\n ${style.bold('Services')} :`);
|
|
173
|
+
if (project) {
|
|
174
|
+
const svcData = readServices(project.root);
|
|
175
|
+
const allConnexions = listConnexions();
|
|
176
|
+
const now = Date.now();
|
|
177
|
+
const SEVEN_DAYS = 7 * 24 * 60 * 60 * 1000;
|
|
178
|
+
|
|
179
|
+
for (const sid of SERVICE_IDS) {
|
|
180
|
+
const svc = svcData.services[sid];
|
|
181
|
+
if (!svc) {
|
|
182
|
+
console.log(warn(`${sid} \u2014 non configure`));
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const cx = allConnexions.find(c => c.id === svc.connexion_id);
|
|
186
|
+
if (!cx) {
|
|
187
|
+
console.log(ko(`${sid} \u2014 connexion manquante`));
|
|
188
|
+
hasErrors = true;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (cx.status === 'connected') {
|
|
192
|
+
const latStr = cx.latency ? `, ${cx.latency}ms` : '';
|
|
193
|
+
console.log(ok(`${sid} \u2014 ${cx.name} (connected${latStr})`));
|
|
194
|
+
} else if (cx.status === 'error') {
|
|
195
|
+
console.log(ko(`${sid} \u2014 ${cx.name} (error)`));
|
|
196
|
+
hasErrors = true;
|
|
197
|
+
} else {
|
|
198
|
+
console.log(warn(`${sid} \u2014 ${cx.name} (non teste)`));
|
|
199
|
+
}
|
|
200
|
+
if (cx.last_tested && (now - new Date(cx.last_tested).getTime()) > SEVEN_DAYS) {
|
|
201
|
+
console.log(warn(`${sid} \u2014 ${cx.name} non teste depuis 7 jours`));
|
|
202
|
+
}
|
|
203
|
+
// Check fallbacks
|
|
204
|
+
for (const fb of (svc.fallback || [])) {
|
|
205
|
+
const fbCx = allConnexions.find(c => c.id === fb.connexion_id);
|
|
206
|
+
if (fbCx && fbCx.last_tested && (now - new Date(fbCx.last_tested).getTime()) > SEVEN_DAYS) {
|
|
207
|
+
console.log(warn(`${sid} \u2014 Fallback ${fbCx.name} non teste depuis 7 jours`));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
console.log(warn('Pas de projet — services non verifies'));
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Check 8: Hooks Kairos
|
|
216
|
+
console.log(`\n ${style.bold('Hooks Kairos')} :`);
|
|
217
|
+
if (project) {
|
|
218
|
+
const hookResult = verifyHooks(project.root);
|
|
219
|
+
const hookCount = Object.keys(ALL_HOOKS).length;
|
|
220
|
+
const activeCount = Object.values(hookResult.hooks).filter(Boolean).length;
|
|
221
|
+
if (activeCount === hookCount) {
|
|
222
|
+
console.log(ok(`Tous les hooks installes (${hookCount}/${hookCount})`));
|
|
223
|
+
} else if (activeCount > 0) {
|
|
224
|
+
console.log(warn(`${activeCount}/${hookCount} hooks installes`));
|
|
225
|
+
} else {
|
|
226
|
+
console.log(warn('Hooks non installes (nemesis services hooks setup)'));
|
|
227
|
+
}
|
|
228
|
+
} else {
|
|
229
|
+
console.log(warn('Pas de projet — hooks non verifies'));
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Summary
|
|
233
|
+
console.log('');
|
|
234
|
+
if (hasErrors) {
|
|
235
|
+
console.log(` ${style.red('Des problemes ont ete detectes.')} Voir ci-dessus.`);
|
|
236
|
+
if (!project) {
|
|
237
|
+
console.log(` ${style.dim('\u2192 Lancez')} nemesis init ${style.dim('pour creer un projet.')}`);
|
|
238
|
+
}
|
|
239
|
+
console.log('');
|
|
240
|
+
} else {
|
|
241
|
+
console.log(` ${style.green('Tout est OK.')}\n`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { createHcmClient } from '../../lib/sync/hcm-client.js';
|
|
2
|
+
import { diagnoseHcm } from '../../lib/sync/health.js';
|
|
3
|
+
import { fullSync } from '../../lib/sync/sync-engine.js';
|
|
4
|
+
import { interactiveMenu } from '../../lib/ui/menu.js';
|
|
5
|
+
import { createSpinner } from '../../lib/ui/spinner.js';
|
|
6
|
+
import { formatOutput } from '../../lib/ui/format.js';
|
|
7
|
+
import { askText } from '../../lib/ui/prompt.js';
|
|
8
|
+
import { style } from '../../lib/ui/colors.js';
|
|
9
|
+
import { ensureProject, BACK_ITEM, HOME_ITEM } from './_helpers.js';
|
|
10
|
+
|
|
11
|
+
const HELP = `
|
|
12
|
+
nemesis hcm — Synchronisation HCM
|
|
13
|
+
|
|
14
|
+
Usage: nemesis hcm <subcommand> [options]
|
|
15
|
+
|
|
16
|
+
Subcommands:
|
|
17
|
+
sync Force la synchronisation vers HCM
|
|
18
|
+
status Affiche le status HCM (connexion + stats)
|
|
19
|
+
search [query] Recherche dans les documents HCM
|
|
20
|
+
|
|
21
|
+
Options:
|
|
22
|
+
-h, --help Aide
|
|
23
|
+
`;
|
|
24
|
+
|
|
25
|
+
export async function handler({ args, flags, config }) {
|
|
26
|
+
if (flags.help || args.includes('--help') || args.includes('-h')) {
|
|
27
|
+
console.log(HELP);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let sub = args[0];
|
|
32
|
+
let subArgs = args.slice(1);
|
|
33
|
+
|
|
34
|
+
if (!sub) {
|
|
35
|
+
sub = await interactiveMenu([
|
|
36
|
+
{ label: 'status', value: 'status', description: 'Status HCM (connexion + stats)' },
|
|
37
|
+
{ label: 'sync', value: 'sync', description: 'Force la synchronisation' },
|
|
38
|
+
{ label: 'search', value: 'search', description: 'Recherche dans les documents' },
|
|
39
|
+
BACK_ITEM,
|
|
40
|
+
HOME_ITEM,
|
|
41
|
+
], { title: 'nemesis hcm' });
|
|
42
|
+
if (!sub || sub === '__back__') return '__back__';
|
|
43
|
+
if (sub === '__home__') return '__home__';
|
|
44
|
+
subArgs = [];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
switch (sub) {
|
|
48
|
+
case 'sync':
|
|
49
|
+
return handleSync(flags, config);
|
|
50
|
+
case 'status':
|
|
51
|
+
return handleStatus(flags, config);
|
|
52
|
+
case 'search':
|
|
53
|
+
return handleSearch(subArgs, flags, config);
|
|
54
|
+
default:
|
|
55
|
+
console.error(`Sous-commande inconnue : ${sub}`);
|
|
56
|
+
console.log(HELP);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function handleSync(flags, config) {
|
|
61
|
+
const project = await ensureProject(config, flags);
|
|
62
|
+
if (!project) return;
|
|
63
|
+
|
|
64
|
+
const spinner = createSpinner('Scanning .nemesis/HCM/...');
|
|
65
|
+
spinner.start();
|
|
66
|
+
|
|
67
|
+
const client = createHcmClient();
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
const results = await fullSync(project.hcm_dir, client);
|
|
71
|
+
spinner.stop('Sync termine');
|
|
72
|
+
|
|
73
|
+
console.log('');
|
|
74
|
+
for (const detail of results.details) {
|
|
75
|
+
const symbol = detail.status === 'synced' ? '\u2713' : detail.status === 'error' ? '\u2717' : '\u2713';
|
|
76
|
+
const suffix = detail.status === 'synced' ? 'SYNCED' :
|
|
77
|
+
detail.status === 'error' ? `ERREUR (${detail.error})` : 'deja a jour';
|
|
78
|
+
console.log(` ${symbol} ${detail.file} \u2192 ${suffix}`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.log(`\n ${results.total} fichiers scannes, ${results.synced} synchronises, ${results.unchanged} inchanges.`);
|
|
82
|
+
if (results.errors > 0) console.log(` ${results.errors} erreurs.`);
|
|
83
|
+
console.log('');
|
|
84
|
+
} catch (err) {
|
|
85
|
+
spinner.fail('Erreur sync');
|
|
86
|
+
console.error(` ${err.message}\n`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function handleStatus(flags, config) {
|
|
91
|
+
const diag = await diagnoseHcm();
|
|
92
|
+
|
|
93
|
+
if (flags.format === 'json') {
|
|
94
|
+
console.log(formatOutput(diag, 'json'));
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
console.log(`\n URL : ${diag.url}`);
|
|
99
|
+
for (const check of diag.checks) {
|
|
100
|
+
const symbol = check.ok ? '\u2713' : '\u2717';
|
|
101
|
+
console.log(` ${symbol} ${check.label} : ${check.detail}`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const { detectProject } = await import('../../lib/core/project.js');
|
|
105
|
+
const project = detectProject(config.cwd);
|
|
106
|
+
if (project) {
|
|
107
|
+
console.log(`\n Projet ${style.bold(project.id)} detecte localement`);
|
|
108
|
+
}
|
|
109
|
+
console.log('');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async function handleSearch(args, flags, _config) {
|
|
113
|
+
let query = args.join(' ');
|
|
114
|
+
|
|
115
|
+
// If no query → ask interactively
|
|
116
|
+
if (!query) {
|
|
117
|
+
query = await askText('Recherche HCM');
|
|
118
|
+
if (!query) return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const client = createHcmClient();
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
const results = await client.search(query);
|
|
125
|
+
|
|
126
|
+
if (flags.format === 'json') {
|
|
127
|
+
console.log(formatOutput(results, 'json'));
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const items = results.results || results.documents || results || [];
|
|
132
|
+
if (!Array.isArray(items) || items.length === 0) {
|
|
133
|
+
console.log('\n Aucun resultat.\n');
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
console.log(`\n ${items.length} resultats :\n`);
|
|
138
|
+
items.forEach((item, i) => {
|
|
139
|
+
const title = item.title || item.label || item.id || '(sans titre)';
|
|
140
|
+
const score = item.score ? ` (score: ${item.score.toFixed(1)})` : '';
|
|
141
|
+
console.log(` ${i + 1}. ${title}${score}`);
|
|
142
|
+
});
|
|
143
|
+
console.log('');
|
|
144
|
+
} catch (err) {
|
|
145
|
+
console.error(` Erreur HCM : ${err.message}\n`);
|
|
146
|
+
}
|
|
147
|
+
}
|