@orbitpanel/cli 0.4.4 → 0.5.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/dist/lib/shell.d.ts +2 -1
- package/dist/lib/shell.js +592 -576
- package/dist/lib/shell.js.map +1 -1
- package/oclif.manifest.json +49 -49
- package/package.json +1 -11
package/dist/lib/shell.js
CHANGED
|
@@ -1,23 +1,38 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
1
|
/**
|
|
3
2
|
* Interactive REPL shell for @orbitpanel/cli.
|
|
4
|
-
*
|
|
3
|
+
* Pure readline + chalk — no Ink/React dependency.
|
|
4
|
+
* Stable, works in all terminals and TTY contexts.
|
|
5
5
|
*/
|
|
6
|
-
import
|
|
7
|
-
import { render, Box, Text, useApp, useInput } from 'ink';
|
|
8
|
-
import TextInput from 'ink-text-input';
|
|
9
|
-
import Spinner from 'ink-spinner';
|
|
6
|
+
import chalk from 'chalk';
|
|
10
7
|
import gradient from 'gradient-string';
|
|
8
|
+
import ora from 'ora';
|
|
9
|
+
import { createInterface } from 'node:readline';
|
|
11
10
|
import { loadConfig, DEFAULT_API_URL } from './config.js';
|
|
12
11
|
import { OrbitClient } from './client.js';
|
|
13
|
-
import {
|
|
12
|
+
import { requestDeviceCode, pollDeviceCode, saveDeviceAuth, openBrowser } from './device-auth.js';
|
|
14
13
|
import { loadSiteLink } from './site.js';
|
|
15
|
-
import { loadActiveSession, createSession, addNote, endSession
|
|
14
|
+
import { loadActiveSession, createSession, addNote, endSession } from './session.js';
|
|
16
15
|
import { getGitBranch, getGitCommitHead, getGitDiffStat } from './git.js';
|
|
17
16
|
import { buildReportPayload } from './report-builder.js';
|
|
18
17
|
import { sendChat } from './ai-chat.js';
|
|
18
|
+
// Brand
|
|
19
|
+
const B = chalk.rgb(37, 99, 235);
|
|
20
|
+
const BL = chalk.hex('#60A5FA');
|
|
21
|
+
const BB = chalk.bold.rgb(37, 99, 235);
|
|
22
|
+
const GREEN = chalk.hex('#22C55E');
|
|
23
|
+
const YELLOW = chalk.hex('#EAB308');
|
|
24
|
+
const DIM = chalk.dim;
|
|
25
|
+
const WHITE = chalk.white;
|
|
19
26
|
const orbitGrad = gradient(['#2563EB', '#3B82F6', '#60A5FA', '#0D9488']);
|
|
20
|
-
|
|
27
|
+
const sparkle = BL('✦');
|
|
28
|
+
const logoLines = [
|
|
29
|
+
' ██████╗ ██████╗ ██████╗ ██╗████████╗',
|
|
30
|
+
' ██╔═══██╗██╔══██╗██╔══██╗██║╚══██╔══╝',
|
|
31
|
+
' ██║ ██║██████╔╝██████╔╝██║ ██║ ',
|
|
32
|
+
' ██║ ██║██╔══██╗██╔══██╗██║ ██║ ',
|
|
33
|
+
' ╚██████╔╝██║ ██║██████╔╝██║ ██║ ',
|
|
34
|
+
' ╚═════╝ ╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝ ',
|
|
35
|
+
];
|
|
21
36
|
const SLASH_COMMANDS = [
|
|
22
37
|
{ cmd: '/status', alias: '/s', desc: 'panoramica completa' },
|
|
23
38
|
{ cmd: '/doctor', alias: '/doc', desc: 'verifica configurazione' },
|
|
@@ -29,628 +44,629 @@ const SLASH_COMMANDS = [
|
|
|
29
44
|
{ cmd: '/list', alias: '/ls', desc: 'lista interventi' },
|
|
30
45
|
{ cmd: '/get', alias: '/g', desc: 'dettaglio intervento (+ id)' },
|
|
31
46
|
{ cmd: '/sites', alias: '', desc: 'lista siti e seleziona' },
|
|
32
|
-
{ cmd: '/auth', alias: '', desc: 'accedi con browser
|
|
47
|
+
{ cmd: '/auth', alias: '', desc: 'accedi con browser' },
|
|
33
48
|
{ cmd: '/login', alias: '', desc: 'configura token (+ token)' },
|
|
34
49
|
{ cmd: '/link', alias: '', desc: 'collega directory (+ site_id)' },
|
|
35
50
|
{ cmd: '/clear', alias: '', desc: 'pulisci schermo' },
|
|
36
51
|
{ cmd: '/help', alias: '/h', desc: 'lista comandi' },
|
|
37
52
|
{ cmd: '/exit', alias: '/q', desc: 'esci' },
|
|
38
53
|
];
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (!input.startsWith('/'))
|
|
42
|
-
return [];
|
|
43
|
-
const query = input.toLowerCase();
|
|
44
|
-
if (query === '/')
|
|
45
|
-
return SLASH_COMMANDS;
|
|
46
|
-
return SLASH_COMMANDS.filter(c => c.cmd.startsWith(query) || (c.alias && c.alias.startsWith(query)));
|
|
47
|
-
}
|
|
48
|
-
/** Autocomplete suggestions component with arrow key navigation. */
|
|
49
|
-
function CommandSuggestions({ input, selectedIndex }) {
|
|
50
|
-
const suggestions = getCommandSuggestions(input);
|
|
51
|
-
if (suggestions.length === 0)
|
|
52
|
-
return null;
|
|
53
|
-
return (_jsx(Box, { flexDirection: "column", marginLeft: 2, marginBottom: 1, children: suggestions.map((s, i) => {
|
|
54
|
-
const isSelected = i === selectedIndex;
|
|
55
|
-
return (_jsxs(Box, { children: [_jsx(Text, { color: isSelected ? '#2563EB' : undefined, children: isSelected ? '❯ ' : ' ' }), _jsx(Text, { color: isSelected ? '#2563EB' : undefined, bold: isSelected, children: s.cmd.padEnd(18) }), s.alias ? _jsx(Text, { dimColor: true, children: s.alias.padEnd(6) }) : _jsx(Text, { children: ' ' }), _jsx(Text, { dimColor: true, children: s.desc })] }, i));
|
|
56
|
-
}) }));
|
|
54
|
+
function sleep(ms) {
|
|
55
|
+
return new Promise(r => setTimeout(r, ms));
|
|
57
56
|
}
|
|
58
|
-
|
|
59
|
-
'
|
|
60
|
-
' ██╔═══██╗██╔══██╗██╔══██╗██║╚══██╔══╝',
|
|
61
|
-
' ██║ ██║██████╔╝██████╔╝██║ ██║ ',
|
|
62
|
-
' ██║ ██║██╔══██╗██╔══██╗██║ ██║ ',
|
|
63
|
-
' ╚██████╔╝██║ ██║██████╔╝██║ ██║ ',
|
|
64
|
-
' ╚═════╝ ╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝ ',
|
|
65
|
-
];
|
|
66
|
-
function Header({ version }) {
|
|
67
|
-
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [logoLines.map((line, i) => (_jsx(Text, { children: orbitGrad(line) }, i))), _jsx(Text, { children: '' }), _jsxs(Text, { children: [_jsx(Text, { backgroundColor: "#2563EB", color: "white", bold: true, children: ' CLI ' }), _jsx(Text, { backgroundColor: "#1E293B", color: "#60A5FA", children: ` v${version} ` }), _jsx(Text, { dimColor: true, children: " \u00B7 " }), _jsx(Text, { color: "#60A5FA", children: "Gestione Orbit Panel AI-powered" })] })] }));
|
|
57
|
+
function sep() {
|
|
58
|
+
console.log(orbitGrad(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
68
59
|
}
|
|
69
|
-
function
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
(async () => {
|
|
73
|
-
const config = await loadConfig();
|
|
74
|
-
const tokenEntry = config.default_site ? config.tokens[config.default_site] : undefined;
|
|
75
|
-
const siteLink = await loadSiteLink(process.cwd());
|
|
76
|
-
const session = siteLink ? await loadActiveSession(siteLink.orbit_site_id) : null;
|
|
77
|
-
const parts = [];
|
|
78
|
-
parts.push(tokenEntry ? '● Connesso' : '○ Non connesso');
|
|
79
|
-
if (siteLink)
|
|
80
|
-
parts.push(siteLink.final_url ?? siteLink.orbit_site_id.slice(0, 16));
|
|
81
|
-
if (session) {
|
|
82
|
-
const elapsed = Math.round((Date.now() - new Date(session.started_at).getTime()) / 60_000);
|
|
83
|
-
parts.push(`● Sessione ${elapsed}min`);
|
|
84
|
-
if (session.git_branch)
|
|
85
|
-
parts.push(session.git_branch);
|
|
86
|
-
}
|
|
87
|
-
setStatus(parts);
|
|
88
|
-
})();
|
|
89
|
-
}, []);
|
|
90
|
-
if (status.length === 0)
|
|
60
|
+
function getClient(config) {
|
|
61
|
+
const t = config.default_site ? config.tokens[config.default_site] : undefined;
|
|
62
|
+
if (!t)
|
|
91
63
|
return null;
|
|
92
|
-
return
|
|
64
|
+
return new OrbitClient(t.token, config.api_url);
|
|
93
65
|
}
|
|
94
|
-
|
|
95
|
-
|
|
66
|
+
// Tab-completion handler
|
|
67
|
+
function completer(line) {
|
|
68
|
+
if (!line.startsWith('/'))
|
|
69
|
+
return [[], line];
|
|
70
|
+
const hits = SLASH_COMMANDS
|
|
71
|
+
.filter(c => c.cmd.startsWith(line.toLowerCase()) || (c.alias && c.alias.startsWith(line.toLowerCase())))
|
|
72
|
+
.map(c => c.cmd);
|
|
73
|
+
return [hits.length ? hits : SLASH_COMMANDS.map(c => c.cmd), line];
|
|
96
74
|
}
|
|
97
|
-
function
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if (
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
75
|
+
export async function startShell(version) {
|
|
76
|
+
// Header with line-by-line animation
|
|
77
|
+
console.clear();
|
|
78
|
+
console.log('');
|
|
79
|
+
for (const line of logoLines) {
|
|
80
|
+
console.log(orbitGrad(line));
|
|
81
|
+
await sleep(50);
|
|
82
|
+
}
|
|
83
|
+
console.log('');
|
|
84
|
+
console.log(` ${chalk.bgRgb(37, 99, 235).white.bold(' CLI ')} ${chalk.bgHex('#1E293B').hex('#60A5FA')(` v${version} `)} ${DIM('·')} ${BL('Gestione Orbit Panel AI-powered')}`);
|
|
85
|
+
// Status bar
|
|
86
|
+
const config = await loadConfig();
|
|
87
|
+
const tokenEntry = config.default_site ? config.tokens[config.default_site] : undefined;
|
|
88
|
+
const siteLink = await loadSiteLink(process.cwd());
|
|
89
|
+
const session = siteLink ? await loadActiveSession(siteLink.orbit_site_id) : null;
|
|
90
|
+
const parts = [];
|
|
91
|
+
if (tokenEntry)
|
|
92
|
+
parts.push(`${GREEN('●')} Connesso`);
|
|
93
|
+
else
|
|
94
|
+
parts.push(`${chalk.red('●')} Non connesso`);
|
|
95
|
+
if (siteLink)
|
|
96
|
+
parts.push(BL(siteLink.final_url ?? siteLink.orbit_site_id.slice(0, 16)));
|
|
97
|
+
if (session) {
|
|
98
|
+
const elapsed = Math.round((Date.now() - new Date(session.started_at).getTime()) / 60_000);
|
|
99
|
+
parts.push(`${GREEN('●')} Sessione ${DIM(`${elapsed}min`)}`);
|
|
100
|
+
if (session.git_branch)
|
|
101
|
+
parts.push(BL(session.git_branch));
|
|
102
|
+
}
|
|
103
|
+
console.log('');
|
|
104
|
+
console.log(` ${parts.join(` ${DIM('│')} `)}`);
|
|
105
|
+
console.log('');
|
|
106
|
+
sep();
|
|
107
|
+
// Auto-prompt auth
|
|
108
|
+
if (!tokenEntry) {
|
|
109
|
+
console.log('');
|
|
110
|
+
console.log(` ${YELLOW('Non sei autenticato.')}`);
|
|
111
|
+
console.log('');
|
|
112
|
+
console.log(` ${BL('/auth')} accedi con il browser (consigliato)`);
|
|
113
|
+
console.log(` ${DIM('/login <t>')} inserisci un token MCP manualmente`);
|
|
114
|
+
console.log('');
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
console.log(` ${DIM('Digita /help per la lista comandi, o scrivi in linguaggio naturale.')}`);
|
|
118
|
+
}
|
|
119
|
+
console.log('');
|
|
120
|
+
// REPL
|
|
121
|
+
const rl = createInterface({
|
|
122
|
+
input: process.stdin,
|
|
123
|
+
output: process.stdout,
|
|
124
|
+
prompt: ` ${B('orbit')} ${DIM('›')} `,
|
|
125
|
+
completer,
|
|
126
|
+
terminal: true,
|
|
127
|
+
});
|
|
128
|
+
// Ctrl+C and Ctrl+Z to exit
|
|
129
|
+
rl.on('SIGINT', () => {
|
|
130
|
+
console.log(`\n\n ${DIM('Alla prossima!')}\n`);
|
|
131
|
+
rl.close();
|
|
132
|
+
});
|
|
133
|
+
process.on('SIGTSTP', () => {
|
|
134
|
+
console.log(`\n\n ${DIM('Alla prossima!')}\n`);
|
|
135
|
+
rl.close();
|
|
136
|
+
process.exit(0);
|
|
137
|
+
});
|
|
138
|
+
rl.prompt();
|
|
139
|
+
return new Promise((resolve) => {
|
|
140
|
+
rl.on('close', () => resolve());
|
|
141
|
+
rl.on('line', async (input) => {
|
|
142
|
+
const raw = input.trim();
|
|
143
|
+
const cmd = raw.toLowerCase();
|
|
144
|
+
if (!cmd) {
|
|
145
|
+
rl.prompt();
|
|
131
146
|
return;
|
|
132
147
|
}
|
|
133
|
-
|
|
134
|
-
|
|
148
|
+
// Exit
|
|
149
|
+
if (cmd === '/exit' || cmd === '/quit' || cmd === '/q') {
|
|
150
|
+
console.log(`\n ${DIM('Alla prossima!')}\n`);
|
|
151
|
+
rl.close();
|
|
135
152
|
return;
|
|
136
153
|
}
|
|
137
|
-
//
|
|
138
|
-
if (
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
setInput(selected.cmd + (needsArg ? ' ' : ''));
|
|
142
|
-
setSelectedIndex(-1);
|
|
154
|
+
// Clear
|
|
155
|
+
if (cmd === '/clear' || cmd === '/cls') {
|
|
156
|
+
console.clear();
|
|
157
|
+
rl.prompt();
|
|
143
158
|
return;
|
|
144
159
|
}
|
|
145
|
-
//
|
|
146
|
-
if (
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
// Submit directly
|
|
156
|
-
setInput(selected.cmd);
|
|
157
|
-
setSelectedIndex(-1);
|
|
158
|
-
// Don't return — let TextInput handle the submit
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
// Reset selection when typing
|
|
162
|
-
if (!key.downArrow && !key.upArrow && !key.tab && !key.return) {
|
|
163
|
-
setSelectedIndex(-1);
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
const handleSubmit = async (value) => {
|
|
167
|
-
const raw = value.trim();
|
|
168
|
-
setInput('');
|
|
169
|
-
if (!raw)
|
|
170
|
-
return;
|
|
171
|
-
setHistory(prev => [...prev, raw]);
|
|
172
|
-
const cmd = raw.toLowerCase();
|
|
173
|
-
// Exit
|
|
174
|
-
if (cmd === '/exit' || cmd === '/quit' || cmd === '/q') {
|
|
175
|
-
addOutput({ text: '' }, { text: ' Alla prossima!', dim: true }, { text: '' });
|
|
176
|
-
setTimeout(() => exit(), 100);
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
// Clear
|
|
180
|
-
if (cmd === '/clear' || cmd === '/cls') {
|
|
181
|
-
clearOutput();
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
|
-
// Help / List
|
|
185
|
-
if (cmd === '/help' || cmd === '/h') {
|
|
186
|
-
const helpLines = [
|
|
187
|
-
{ text: '' },
|
|
188
|
-
{ text: ' ✦ Comandi disponibili', color: '#60A5FA', bold: true },
|
|
189
|
-
{ text: '' },
|
|
190
|
-
];
|
|
191
|
-
for (const c of SLASH_COMMANDS) {
|
|
192
|
-
const alias = c.alias ? ` ${c.alias}` : '';
|
|
193
|
-
helpLines.push({ text: ` ${c.cmd.padEnd(18)}${alias.padEnd(8)}${c.desc}` });
|
|
194
|
-
}
|
|
195
|
-
helpLines.push({ text: '' });
|
|
196
|
-
addOutput(...helpLines);
|
|
197
|
-
return;
|
|
198
|
-
}
|
|
199
|
-
// Status
|
|
200
|
-
if (cmd === '/status' || cmd === '/s') {
|
|
201
|
-
setLoading(true);
|
|
202
|
-
setLoadingText('Caricamento stato...');
|
|
203
|
-
try {
|
|
204
|
-
const config = await loadConfig();
|
|
205
|
-
const client = getClient(config);
|
|
206
|
-
const lines = [{ text: '' }, { text: ' ✦ Stato', color: '#2563EB', bold: true }, { text: '' }];
|
|
207
|
-
if (!client) {
|
|
208
|
-
lines.push({ text: ' ✗ Token non configurato', color: '#EF4444' });
|
|
209
|
-
lines.push({ text: ' Esegui: /login <token>', dim: true });
|
|
210
|
-
}
|
|
211
|
-
else {
|
|
212
|
-
const t = config.tokens[config.default_site];
|
|
213
|
-
const v = await client.validateToken();
|
|
214
|
-
lines.push({ text: ` ✓ Token ${t.token.slice(0, 15)}...`, color: v.valid ? '#22C55E' : '#EF4444' });
|
|
215
|
-
lines.push({ text: ` ✓ API ${v.valid ? 'raggiungibile' : v.error}`, color: v.valid ? '#22C55E' : '#EF4444' });
|
|
216
|
-
const siteLink = await loadSiteLink(process.cwd());
|
|
217
|
-
if (siteLink)
|
|
218
|
-
lines.push({ text: ` ✓ Sito ${siteLink.final_url ?? siteLink.orbit_site_id}`, color: '#60A5FA' });
|
|
219
|
-
const session = siteLink ? await loadActiveSession(siteLink.orbit_site_id) : null;
|
|
220
|
-
if (session) {
|
|
221
|
-
const elapsed = Math.round((Date.now() - new Date(session.started_at).getTime()) / 60_000);
|
|
222
|
-
lines.push({ text: ` ✓ Sessione attiva (${elapsed}min · ${session.notes.length} note)`, color: '#22C55E' });
|
|
223
|
-
}
|
|
224
|
-
if (v.valid) {
|
|
225
|
-
try {
|
|
226
|
-
const stats = await client.getStats();
|
|
227
|
-
const total = stats.total_interventions ?? 0;
|
|
228
|
-
lines.push({ text: '' });
|
|
229
|
-
lines.push({ text: ` ${total} interventi totali`, color: '#60A5FA' });
|
|
230
|
-
}
|
|
231
|
-
catch { }
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
lines.push({ text: '' });
|
|
235
|
-
addOutput(...lines);
|
|
236
|
-
}
|
|
237
|
-
finally {
|
|
238
|
-
setLoading(false);
|
|
239
|
-
}
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
// Doctor
|
|
243
|
-
if (cmd === '/doctor' || cmd === '/doc') {
|
|
244
|
-
setLoading(true);
|
|
245
|
-
setLoadingText('Diagnostica...');
|
|
246
|
-
try {
|
|
247
|
-
const config = await loadConfig();
|
|
248
|
-
const lines = [{ text: '' }, { text: ' ✦ Diagnostica', color: '#2563EB', bold: true }, { text: '' }];
|
|
249
|
-
const t = config.default_site ? config.tokens[config.default_site] : undefined;
|
|
250
|
-
lines.push({ text: ` ${t ? '✓' : '!'} Token ${t ? t.token.slice(0, 15) + '...' : 'non configurato'}`, color: t ? '#22C55E' : '#EAB308' });
|
|
251
|
-
if (t) {
|
|
252
|
-
const c = new OrbitClient(t.token, config.api_url);
|
|
253
|
-
const start = Date.now();
|
|
254
|
-
const v = await c.validateToken();
|
|
255
|
-
lines.push({ text: ` ${v.valid ? '✓' : '✗'} API ${v.valid ? `raggiungibile (${Date.now() - start}ms)` : v.error}`, color: v.valid ? '#22C55E' : '#EF4444' });
|
|
160
|
+
// Help
|
|
161
|
+
if (cmd === '/help' || cmd === '/h') {
|
|
162
|
+
console.log('');
|
|
163
|
+
console.log(` ${sparkle} ${BB('Comandi disponibili')}`);
|
|
164
|
+
console.log('');
|
|
165
|
+
for (const c of SLASH_COMMANDS) {
|
|
166
|
+
const alias = c.alias ? DIM(` ${c.alias}`) : '';
|
|
167
|
+
console.log(` ${WHITE(c.cmd.padEnd(18))}${alias.padEnd(12)}${DIM(c.desc)}`);
|
|
256
168
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
const allOk = !!(t && site && branch);
|
|
262
|
-
lines.push({ text: '' });
|
|
263
|
-
lines.push({ text: allOk ? ' ✓ Tutto ok — pronto per lavorare' : ' ! Attenzione — vedi sopra', color: allOk ? '#22C55E' : '#EAB308', bold: true });
|
|
264
|
-
lines.push({ text: '' });
|
|
265
|
-
addOutput(...lines);
|
|
266
|
-
}
|
|
267
|
-
finally {
|
|
268
|
-
setLoading(false);
|
|
269
|
-
}
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
// Session start
|
|
273
|
-
if (cmd === '/session start' || cmd === '/ss') {
|
|
274
|
-
setLoading(true);
|
|
275
|
-
setLoadingText('Avvio sessione...');
|
|
276
|
-
try {
|
|
277
|
-
const siteLink = await loadSiteLink(process.cwd());
|
|
278
|
-
if (!siteLink) {
|
|
279
|
-
addOutput({ text: '' }, { text: ' ✗ Nessun sito collegato. Esegui: /link <site_id>', color: '#EF4444' }, { text: '' });
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
const existing = await loadActiveSession(siteLink.orbit_site_id);
|
|
283
|
-
if (existing) {
|
|
284
|
-
addOutput({ text: '' }, { text: ` ! Sessione gia attiva (${existing.id}). Chiudi con: /session end`, color: '#EAB308' }, { text: '' });
|
|
285
|
-
return;
|
|
286
|
-
}
|
|
287
|
-
const branch = await getGitBranch();
|
|
288
|
-
const commit = await getGitCommitHead();
|
|
289
|
-
const s = await createSession(siteLink.orbit_site_id, { git_branch: branch ?? undefined, git_commit: commit ?? undefined });
|
|
290
|
-
addOutput({ text: '' }, { text: ' ✦ Sessione avviata', color: '#2563EB', bold: true }, { text: '' }, { text: ` ID ${s.id}`, color: '#60A5FA' }, ...(branch ? [{ text: ` Branch ${branch}` }] : []), ...(commit ? [{ text: ` Commit ${commit}`, color: '#60A5FA' }] : []), { text: ` Inizio ${new Date().toLocaleTimeString('it-IT', { hour: '2-digit', minute: '2-digit' })}` }, { text: '' });
|
|
291
|
-
}
|
|
292
|
-
finally {
|
|
293
|
-
setLoading(false);
|
|
294
|
-
}
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
// Session end
|
|
298
|
-
if (cmd === '/session end' || cmd === '/se') {
|
|
299
|
-
setLoading(true);
|
|
300
|
-
setLoadingText('Chiusura sessione...');
|
|
301
|
-
try {
|
|
302
|
-
const siteLink = await loadSiteLink(process.cwd());
|
|
303
|
-
if (!siteLink) {
|
|
304
|
-
addOutput({ text: ' ✗ Nessun sito collegato', color: '#EF4444' });
|
|
305
|
-
return;
|
|
306
|
-
}
|
|
307
|
-
const session = await loadActiveSession(siteLink.orbit_site_id);
|
|
308
|
-
if (!session) {
|
|
309
|
-
addOutput({ text: ' Nessuna sessione attiva', dim: true });
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
const commitEnd = await getGitCommitHead();
|
|
313
|
-
await endSession(session.id, { git_commit_end: commitEnd ?? undefined });
|
|
314
|
-
const elapsed = Math.round((Date.now() - new Date(session.started_at).getTime()) / 60_000);
|
|
315
|
-
addOutput({ text: '' }, { text: ` ✓ Sessione chiusa (${elapsed}min · ${session.notes.length} note)`, color: '#22C55E', bold: true }, { text: ' Invia il report con: /report', dim: true }, { text: '' });
|
|
316
|
-
}
|
|
317
|
-
finally {
|
|
318
|
-
setLoading(false);
|
|
319
|
-
}
|
|
320
|
-
return;
|
|
321
|
-
}
|
|
322
|
-
// Session info
|
|
323
|
-
if (cmd === '/session' || cmd === '/session info') {
|
|
324
|
-
const siteLink = await loadSiteLink(process.cwd());
|
|
325
|
-
if (!siteLink) {
|
|
326
|
-
addOutput({ text: ' Nessun sito collegato', dim: true });
|
|
169
|
+
console.log('');
|
|
170
|
+
console.log(` ${DIM('Oppure scrivi in linguaggio naturale per parlare con Orbit AI.')}`);
|
|
171
|
+
console.log('');
|
|
172
|
+
rl.prompt();
|
|
327
173
|
return;
|
|
328
174
|
}
|
|
329
|
-
|
|
330
|
-
if (
|
|
331
|
-
|
|
175
|
+
// Status
|
|
176
|
+
if (cmd === '/status' || cmd === '/s') {
|
|
177
|
+
await cmdStatus();
|
|
178
|
+
rl.prompt();
|
|
332
179
|
return;
|
|
333
180
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
{ text: ` ID ${session.id}`, color: '#60A5FA' },
|
|
340
|
-
{ text: ` Durata ${elapsed} min` },
|
|
341
|
-
];
|
|
342
|
-
if (session.git_branch)
|
|
343
|
-
lines.push({ text: ` Branch ${session.git_branch}`, color: '#60A5FA' });
|
|
344
|
-
lines.push({ text: ` Note ${session.notes.length}` });
|
|
345
|
-
for (const n of session.notes.slice(-5)) {
|
|
346
|
-
lines.push({ text: ` · ${n.text}` });
|
|
181
|
+
// Doctor
|
|
182
|
+
if (cmd === '/doctor' || cmd === '/doc') {
|
|
183
|
+
await cmdDoctor();
|
|
184
|
+
rl.prompt();
|
|
185
|
+
return;
|
|
347
186
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
// Note
|
|
353
|
-
if (cmd.startsWith('/note ') || cmd.startsWith('/n ')) {
|
|
354
|
-
const text = raw.slice(raw.indexOf(' ') + 1);
|
|
355
|
-
const siteLink = await loadSiteLink(process.cwd());
|
|
356
|
-
if (!siteLink) {
|
|
357
|
-
addOutput({ text: ' ✗ Nessun sito collegato', color: '#EF4444' });
|
|
187
|
+
// Session start
|
|
188
|
+
if (cmd === '/session start' || cmd === '/ss') {
|
|
189
|
+
await cmdSessionStart();
|
|
190
|
+
rl.prompt();
|
|
358
191
|
return;
|
|
359
192
|
}
|
|
360
|
-
|
|
361
|
-
if (
|
|
362
|
-
|
|
193
|
+
// Session end
|
|
194
|
+
if (cmd === '/session end' || cmd === '/se') {
|
|
195
|
+
await cmdSessionEnd();
|
|
196
|
+
rl.prompt();
|
|
363
197
|
return;
|
|
364
198
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
if (cmd === '/report' || cmd === '/r') {
|
|
371
|
-
setLoading(true);
|
|
372
|
-
setLoadingText('Invio report a Orbit...');
|
|
373
|
-
try {
|
|
374
|
-
const config = await loadConfig();
|
|
375
|
-
const client = getClient(config);
|
|
376
|
-
if (!client) {
|
|
377
|
-
addOutput({ text: ' ✗ Token non configurato', color: '#EF4444' });
|
|
378
|
-
return;
|
|
379
|
-
}
|
|
380
|
-
const siteLink = await loadSiteLink(process.cwd());
|
|
381
|
-
if (!siteLink) {
|
|
382
|
-
addOutput({ text: ' ✗ Nessun sito collegato', color: '#EF4444' });
|
|
383
|
-
return;
|
|
384
|
-
}
|
|
385
|
-
let session = await loadActiveSession(siteLink.orbit_site_id);
|
|
386
|
-
const commitEnd = await getGitCommitHead();
|
|
387
|
-
let filesChanged = 0;
|
|
388
|
-
if (session?.git_commit_start && commitEnd) {
|
|
389
|
-
const diff = await getGitDiffStat(session.git_commit_start, commitEnd);
|
|
390
|
-
filesChanged = diff.files_changed;
|
|
391
|
-
}
|
|
392
|
-
if (session && session.status === 'active') {
|
|
393
|
-
session = await endSession(session.id, { git_commit_end: commitEnd ?? undefined });
|
|
394
|
-
}
|
|
395
|
-
const payload = buildReportPayload({
|
|
396
|
-
session: session ?? { id: 'no-session', site_id: siteLink.orbit_site_id, started_at: new Date().toISOString(), notes: [], status: 'completed' },
|
|
397
|
-
git_commit_end: commitEnd ?? undefined, files_changed: filesChanged,
|
|
398
|
-
});
|
|
399
|
-
payload.site_id = siteLink.orbit_site_id;
|
|
400
|
-
const result = await client.createIntervention(payload);
|
|
401
|
-
addOutput({ text: '' }, { text: ` ✓ Report inviato ${String(result.id).slice(0, 8)}`, color: '#22C55E', bold: true }, { text: '' });
|
|
199
|
+
// Session info
|
|
200
|
+
if (cmd === '/session' || cmd === '/session info') {
|
|
201
|
+
await cmdSessionInfo();
|
|
202
|
+
rl.prompt();
|
|
203
|
+
return;
|
|
402
204
|
}
|
|
403
|
-
|
|
404
|
-
|
|
205
|
+
// Note
|
|
206
|
+
if (cmd.startsWith('/note ') || cmd.startsWith('/n ')) {
|
|
207
|
+
await cmdNoteAdd(raw.slice(raw.indexOf(' ') + 1));
|
|
208
|
+
rl.prompt();
|
|
209
|
+
return;
|
|
405
210
|
}
|
|
406
|
-
|
|
407
|
-
|
|
211
|
+
// Report
|
|
212
|
+
if (cmd === '/report' || cmd === '/r') {
|
|
213
|
+
await cmdReport();
|
|
214
|
+
rl.prompt();
|
|
215
|
+
return;
|
|
408
216
|
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
setLoadingText('Caricamento interventi...');
|
|
415
|
-
try {
|
|
416
|
-
const config = await loadConfig();
|
|
417
|
-
const client = getClient(config);
|
|
418
|
-
if (!client) {
|
|
419
|
-
addOutput({ text: ' ✗ Token non configurato', color: '#EF4444' });
|
|
420
|
-
return;
|
|
421
|
-
}
|
|
422
|
-
const siteLink = await loadSiteLink(process.cwd());
|
|
423
|
-
const filters = { limit: 10, sort: '-created_at' };
|
|
424
|
-
if (siteLink)
|
|
425
|
-
filters.site_id = siteLink.orbit_site_id;
|
|
426
|
-
const result = await client.listInterventions(filters);
|
|
427
|
-
const lines = [{ text: '' }, { text: ' ✦ Interventi', color: '#2563EB', bold: true }, { text: '' }];
|
|
428
|
-
if (result.items.length === 0) {
|
|
429
|
-
lines.push({ text: ' Nessun intervento trovato', dim: true });
|
|
430
|
-
}
|
|
431
|
-
else {
|
|
432
|
-
for (const item of result.items) {
|
|
433
|
-
const id = String(item.id ?? '').slice(0, 8);
|
|
434
|
-
const t = String(item.title ?? '').slice(0, 35).padEnd(35);
|
|
435
|
-
const s = item.status;
|
|
436
|
-
const sIcon = s === 'completed' ? '●' : s === 'in_progress' ? '●' : '●';
|
|
437
|
-
const sColor = s === 'completed' ? '#22C55E' : s === 'in_progress' ? '#EAB308' : '#60A5FA';
|
|
438
|
-
const sLabel = s === 'completed' ? 'completato' : s === 'in_progress' ? 'in corso' : s === 'verified' ? 'verificato' : 'pianificato';
|
|
439
|
-
const date = String(item.created_at ?? '').slice(5, 10);
|
|
440
|
-
const origin = item.origin === 'cli' ? 'CLI' : String(item.origin);
|
|
441
|
-
lines.push({ text: ` ${sIcon} ${id} ${t} ${sLabel.padEnd(12)} ${origin.padEnd(6)} ${date}`, color: sColor });
|
|
442
|
-
}
|
|
443
|
-
lines.push({ text: '' });
|
|
444
|
-
lines.push({ text: ` ${result.total} interventi`, dim: true });
|
|
445
|
-
}
|
|
446
|
-
lines.push({ text: '' });
|
|
447
|
-
addOutput(...lines);
|
|
217
|
+
// List interventions
|
|
218
|
+
if (cmd === '/list' || cmd === '/ls' || cmd === '/interventions') {
|
|
219
|
+
await cmdList();
|
|
220
|
+
rl.prompt();
|
|
221
|
+
return;
|
|
448
222
|
}
|
|
449
|
-
|
|
450
|
-
|
|
223
|
+
// Get intervention
|
|
224
|
+
if (cmd.startsWith('/get ') || cmd.startsWith('/g ')) {
|
|
225
|
+
await cmdGet(raw.split(' ')[1]);
|
|
226
|
+
rl.prompt();
|
|
227
|
+
return;
|
|
451
228
|
}
|
|
452
|
-
|
|
453
|
-
|
|
229
|
+
// Sites
|
|
230
|
+
if (cmd === '/sites' || cmd.startsWith('/sites ')) {
|
|
231
|
+
await cmdSites(cmd.split(' ')[1]);
|
|
232
|
+
rl.prompt();
|
|
233
|
+
return;
|
|
454
234
|
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
const id = raw.split(' ')[1];
|
|
460
|
-
if (!id) {
|
|
461
|
-
addOutput({ text: ' Uso: /get <intervention_id>', dim: true });
|
|
235
|
+
// Auth (device code)
|
|
236
|
+
if (cmd === '/auth') {
|
|
237
|
+
await cmdAuth();
|
|
238
|
+
rl.prompt();
|
|
462
239
|
return;
|
|
463
240
|
}
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
if (!client) {
|
|
470
|
-
addOutput({ text: ' ✗ Token non configurato', color: '#EF4444' });
|
|
471
|
-
return;
|
|
472
|
-
}
|
|
473
|
-
const item = await client.getIntervention(id);
|
|
474
|
-
addOutput({ text: '' }, { text: ` ✦ ${String(item.title)}`, color: '#2563EB', bold: true }, { text: '' }, { text: ` ID ${String(item.id)}`, color: '#60A5FA' }, { text: ` Stato ${String(item.status)}` }, { text: ` Priorita ${String(item.priority)}` }, { text: ` Origin ${item.origin === 'cli' ? 'CLI' : String(item.origin)}`, color: item.origin === 'cli' ? '#2563EB' : undefined }, ...(item.type_tag ? [{ text: ` Tipo ${String(item.type_tag)}`, color: '#60A5FA' }] : []), { text: ` Creato ${String(item.created_at)}`, dim: true }, { text: '' });
|
|
241
|
+
// Login (token)
|
|
242
|
+
if (cmd.startsWith('/login ')) {
|
|
243
|
+
await cmdLogin(raw.split(' ')[1]);
|
|
244
|
+
rl.prompt();
|
|
245
|
+
return;
|
|
475
246
|
}
|
|
476
|
-
|
|
477
|
-
|
|
247
|
+
// Link
|
|
248
|
+
if (cmd.startsWith('/link ')) {
|
|
249
|
+
await cmdLink(raw.split(' ')[1]);
|
|
250
|
+
rl.prompt();
|
|
251
|
+
return;
|
|
478
252
|
}
|
|
479
|
-
|
|
480
|
-
|
|
253
|
+
// Unknown slash command
|
|
254
|
+
if (cmd.startsWith('/')) {
|
|
255
|
+
console.log(`\n ${DIM('Comando sconosciuto:')} ${WHITE(cmd)} ${DIM('— digita /help')}\n`);
|
|
256
|
+
rl.prompt();
|
|
257
|
+
return;
|
|
481
258
|
}
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
// List and select sites
|
|
485
|
-
if (cmd === '/sites' || cmd.startsWith('/sites ')) {
|
|
486
|
-
setLoading(true);
|
|
487
|
-
setLoadingText('Caricamento siti...');
|
|
259
|
+
// Free text → AI chat
|
|
260
|
+
const spinner = ora({ text: 'Orbit AI sta pensando...', color: 'blue', indent: 2 }).start();
|
|
488
261
|
try {
|
|
489
|
-
const
|
|
490
|
-
|
|
491
|
-
if (
|
|
492
|
-
|
|
493
|
-
addOutput({ text: ' ✗ Non autenticato. Usa /auth', color: '#EF4444' });
|
|
494
|
-
return;
|
|
495
|
-
}
|
|
496
|
-
const sites = await client.listSites();
|
|
497
|
-
setLoading(false);
|
|
498
|
-
if (!Array.isArray(sites) || sites.length === 0) {
|
|
499
|
-
addOutput({ text: '' }, { text: ' Nessun sito trovato.', dim: true }, { text: '' });
|
|
500
|
-
return;
|
|
262
|
+
const chatResult = await sendChat(raw);
|
|
263
|
+
spinner.stop();
|
|
264
|
+
if (chatResult.error) {
|
|
265
|
+
console.log(`\n ${chalk.red('✗')} ${chatResult.error}\n`);
|
|
501
266
|
}
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
const domain = String(site.domain ?? site.home_url ?? siteId);
|
|
510
|
-
const { saveSiteLink } = await import('./site.js');
|
|
511
|
-
await saveSiteLink(process.cwd(), {
|
|
512
|
-
orbit_site_id: siteId,
|
|
513
|
-
platform: 'wordpress',
|
|
514
|
-
final_url: String(site.home_url ?? site.domain ?? ''),
|
|
515
|
-
});
|
|
516
|
-
addOutput({ text: '' }, { text: ` ✓ Sito selezionato: ${domain}`, color: '#22C55E', bold: true }, { text: ` ID: ${siteId}`, dim: true }, { text: '' });
|
|
517
|
-
}
|
|
518
|
-
else {
|
|
519
|
-
addOutput({ text: ` ✗ Numero non valido. Scegli tra 1 e ${sites.length}`, color: '#EF4444' });
|
|
267
|
+
else {
|
|
268
|
+
const provider = chatResult.provider_used ? DIM(` (${chatResult.provider_used})`) : '';
|
|
269
|
+
console.log('');
|
|
270
|
+
console.log(` ${sparkle} ${BB('Orbit AI')}${provider}`);
|
|
271
|
+
console.log('');
|
|
272
|
+
for (const line of (chatResult.response ?? '').split('\n')) {
|
|
273
|
+
console.log(` ${line}`);
|
|
520
274
|
}
|
|
521
|
-
|
|
275
|
+
console.log('');
|
|
522
276
|
}
|
|
523
|
-
// Show list with numbers
|
|
524
|
-
const lines = [
|
|
525
|
-
{ text: '' },
|
|
526
|
-
{ text: ' ✦ Siti disponibili', color: '#2563EB', bold: true },
|
|
527
|
-
{ text: '' },
|
|
528
|
-
];
|
|
529
|
-
sites.forEach((site, i) => {
|
|
530
|
-
const num = String(i + 1).padStart(2);
|
|
531
|
-
const domain = String(site.domain ?? site.home_url ?? '—').slice(0, 35).padEnd(35);
|
|
532
|
-
const status = site.status;
|
|
533
|
-
const statusIcon = status === 'active' ? '●' : '○';
|
|
534
|
-
const statusColor = status === 'active' ? '#22C55E' : '#EF4444';
|
|
535
|
-
const platform = String(site.wp_version ? `WP ${site.wp_version}` : 'wordpress').padEnd(10);
|
|
536
|
-
const id = String(site.id ?? '').slice(0, 8);
|
|
537
|
-
lines.push({
|
|
538
|
-
text: ` ${num}. ${statusIcon} ${domain} ${platform} ${id}`,
|
|
539
|
-
color: statusColor,
|
|
540
|
-
});
|
|
541
|
-
});
|
|
542
|
-
lines.push({ text: '' });
|
|
543
|
-
lines.push({ text: ' Seleziona con: /sites <numero>', dim: true });
|
|
544
|
-
lines.push({ text: '' });
|
|
545
|
-
addOutput(...lines);
|
|
546
277
|
}
|
|
547
278
|
catch (err) {
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
}
|
|
551
|
-
return;
|
|
552
|
-
}
|
|
553
|
-
// Auth via browser (Device Code Flow)
|
|
554
|
-
if (cmd === '/auth') {
|
|
555
|
-
setLoading(true);
|
|
556
|
-
setLoadingText('Generazione codice...');
|
|
557
|
-
try {
|
|
558
|
-
const config = await loadConfig();
|
|
559
|
-
const apiUrl = config.api_url || DEFAULT_API_URL;
|
|
560
|
-
const deviceCode = await requestDeviceCode(apiUrl);
|
|
561
|
-
setLoading(false);
|
|
562
|
-
addOutput({ text: '' }, { text: ' ✦ Accesso con browser', color: '#2563EB', bold: true }, { text: '' }, { text: ` Apri questo URL nel browser:`, dim: false }, { text: ` ${deviceCode.verification_url}`, color: '#60A5FA' }, { text: '' }, { text: ` Codice: ${deviceCode.user_code}`, color: '#2563EB', bold: true }, { text: '' }, { text: ' In attesa di autorizzazione...', dim: true });
|
|
563
|
-
// Open browser automatically
|
|
564
|
-
await openBrowser(deviceCode.verification_url);
|
|
565
|
-
// Poll for authorization
|
|
566
|
-
setLoading(true);
|
|
567
|
-
setLoadingText('In attesa di autorizzazione dal browser...');
|
|
568
|
-
const result = await pollDeviceCode(apiUrl, deviceCode.device_code);
|
|
569
|
-
await saveDeviceAuth(result);
|
|
570
|
-
setLoading(false);
|
|
571
|
-
addOutput({ text: '' }, { text: ` ✓ Autenticato come ${result.user_email ?? 'utente'}`, color: '#22C55E', bold: true }, { text: ' Token salvato in ~/.orbit/config.json', dim: true }, { text: '' });
|
|
279
|
+
spinner.stop();
|
|
280
|
+
console.log(`\n ${chalk.red('✗')} ${err instanceof Error ? err.message : String(err)}\n`);
|
|
572
281
|
}
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
282
|
+
rl.prompt();
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
// --- Command handlers ---
|
|
287
|
+
async function cmdStatus() {
|
|
288
|
+
const config = await loadConfig();
|
|
289
|
+
const client = getClient(config);
|
|
290
|
+
console.log('');
|
|
291
|
+
console.log(` ${sparkle} ${BB('Stato')}`);
|
|
292
|
+
console.log('');
|
|
293
|
+
if (!client) {
|
|
294
|
+
console.log(` ${chalk.red('✗')} ${WHITE('Token')} ${DIM('non configurato')}`);
|
|
295
|
+
console.log(` ${DIM('Esegui: /auth o /login <token>')}`);
|
|
296
|
+
console.log('');
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
const tokenEntry = config.tokens[config.default_site];
|
|
300
|
+
const spinner = ora({ text: 'Verifica connessione...', color: 'blue', indent: 5 }).start();
|
|
301
|
+
const v = await client.validateToken();
|
|
302
|
+
if (!v.valid) {
|
|
303
|
+
spinner.fail(`API: ${v.error}`);
|
|
304
|
+
console.log('');
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
spinner.stop();
|
|
308
|
+
console.log(` ${GREEN('✓')} ${WHITE('Token')} ${DIM(tokenEntry.token.slice(0, 15) + '...')}`);
|
|
309
|
+
console.log(` ${GREEN('✓')} ${WHITE('API')} ${GREEN('raggiungibile')}`);
|
|
310
|
+
const siteLink = await loadSiteLink(process.cwd());
|
|
311
|
+
if (siteLink)
|
|
312
|
+
console.log(` ${GREEN('✓')} ${WHITE('Sito')} ${BL(siteLink.final_url ?? siteLink.orbit_site_id)}`);
|
|
313
|
+
const session = siteLink ? await loadActiveSession(siteLink.orbit_site_id) : null;
|
|
314
|
+
if (session) {
|
|
315
|
+
const elapsed = Math.round((Date.now() - new Date(session.started_at).getTime()) / 60_000);
|
|
316
|
+
console.log(` ${GREEN('✓')} ${WHITE('Sessione')} ${GREEN('attiva')} ${DIM(`${elapsed}min · ${session.notes.length} note`)}`);
|
|
317
|
+
}
|
|
318
|
+
try {
|
|
319
|
+
const stats = await client.getStats();
|
|
320
|
+
const total = stats.total_interventions ?? 0;
|
|
321
|
+
const by = stats.by_status ?? {};
|
|
322
|
+
console.log('');
|
|
323
|
+
console.log(` ${BL(String(total))} interventi totali`);
|
|
324
|
+
const p = [];
|
|
325
|
+
if (by.completed)
|
|
326
|
+
p.push(GREEN(`${by.completed} completati`));
|
|
327
|
+
if (by.in_progress)
|
|
328
|
+
p.push(YELLOW(`${by.in_progress} in corso`));
|
|
329
|
+
if (by.scheduled)
|
|
330
|
+
p.push(BL(`${by.scheduled} pianificati`));
|
|
331
|
+
if (p.length)
|
|
332
|
+
console.log(` ${p.join(DIM(' · '))}`);
|
|
333
|
+
}
|
|
334
|
+
catch { }
|
|
335
|
+
console.log('');
|
|
336
|
+
}
|
|
337
|
+
async function cmdDoctor() {
|
|
338
|
+
const config = await loadConfig();
|
|
339
|
+
console.log('');
|
|
340
|
+
console.log(` ${sparkle} ${BB('Diagnostica')}`);
|
|
341
|
+
console.log('');
|
|
342
|
+
const t = config.default_site ? config.tokens[config.default_site] : undefined;
|
|
343
|
+
console.log(` ${t ? GREEN('✓') : YELLOW('!')} ${WHITE('Token')} ${t ? DIM(t.token.slice(0, 15) + '...') : DIM('non configurato')}`);
|
|
344
|
+
if (t) {
|
|
345
|
+
const c = new OrbitClient(t.token, config.api_url);
|
|
346
|
+
const start = Date.now();
|
|
347
|
+
const v = await c.validateToken();
|
|
348
|
+
console.log(` ${v.valid ? GREEN('✓') : chalk.red('✗')} ${WHITE('API')} ${v.valid ? `${GREEN('raggiungibile')} ${DIM(`(${Date.now() - start}ms)`)}` : DIM(v.error ?? 'errore')}`);
|
|
349
|
+
}
|
|
350
|
+
const site = await loadSiteLink(process.cwd());
|
|
351
|
+
console.log(` ${site ? GREEN('✓') : YELLOW('!')} ${WHITE('Sito')} ${site ? `${BL('.orbit.json')} ${DIM('presente')}` : DIM('non collegato')}`);
|
|
352
|
+
const branch = await getGitBranch();
|
|
353
|
+
console.log(` ${branch ? GREEN('✓') : YELLOW('!')} ${WHITE('Git')} ${branch ? BL(branch) : DIM('nessun repository')}`);
|
|
354
|
+
const allOk = !!(t && site && branch);
|
|
355
|
+
console.log('');
|
|
356
|
+
console.log(` ${allOk ? GREEN.bold('✓ Tutto ok') : YELLOW('! Attenzione')} ${DIM(allOk ? '— pronto per lavorare' : '— vedi sopra')}`);
|
|
357
|
+
console.log('');
|
|
358
|
+
}
|
|
359
|
+
async function cmdSessionStart() {
|
|
360
|
+
const siteLink = await loadSiteLink(process.cwd());
|
|
361
|
+
if (!siteLink) {
|
|
362
|
+
console.log(`\n ${chalk.red('✗')} ${DIM('Nessun sito collegato. Esegui: /sites o /link <id>')}\n`);
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
const existing = await loadActiveSession(siteLink.orbit_site_id);
|
|
366
|
+
if (existing) {
|
|
367
|
+
console.log(`\n ${YELLOW('!')} ${DIM(`Sessione gia attiva (${existing.id}). Chiudi con: /session end`)}\n`);
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
const branch = await getGitBranch();
|
|
371
|
+
const commit = await getGitCommitHead();
|
|
372
|
+
const s = await createSession(siteLink.orbit_site_id, { git_branch: branch ?? undefined, git_commit: commit ?? undefined });
|
|
373
|
+
console.log('');
|
|
374
|
+
console.log(` ${sparkle} ${BB('Sessione avviata')}`);
|
|
375
|
+
console.log('');
|
|
376
|
+
console.log(` ${DIM('ID')} ${BL(s.id)}`);
|
|
377
|
+
if (branch)
|
|
378
|
+
console.log(` ${DIM('Branch')} ${WHITE(branch)}`);
|
|
379
|
+
if (commit)
|
|
380
|
+
console.log(` ${DIM('Commit')} ${BL(commit)}`);
|
|
381
|
+
console.log(` ${DIM('Inizio')} ${WHITE(new Date().toLocaleTimeString('it-IT', { hour: '2-digit', minute: '2-digit' }))}`);
|
|
382
|
+
console.log('');
|
|
383
|
+
}
|
|
384
|
+
async function cmdSessionEnd() {
|
|
385
|
+
const siteLink = await loadSiteLink(process.cwd());
|
|
386
|
+
if (!siteLink) {
|
|
387
|
+
console.log(`\n ${chalk.red('✗')} ${DIM('Nessun sito collegato')}\n`);
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
const session = await loadActiveSession(siteLink.orbit_site_id);
|
|
391
|
+
if (!session) {
|
|
392
|
+
console.log(`\n ${DIM('Nessuna sessione attiva. /session start')}\n`);
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
const commitEnd = await getGitCommitHead();
|
|
396
|
+
await endSession(session.id, { git_commit_end: commitEnd ?? undefined });
|
|
397
|
+
const elapsed = Math.round((Date.now() - new Date(session.started_at).getTime()) / 60_000);
|
|
398
|
+
console.log('');
|
|
399
|
+
console.log(` ${GREEN('✓')} ${GREEN.bold('Sessione chiusa')} ${DIM(`(${elapsed}min · ${session.notes.length} note)`)}`);
|
|
400
|
+
console.log(` ${DIM('Invia il report con: /report')}`);
|
|
401
|
+
console.log('');
|
|
402
|
+
}
|
|
403
|
+
async function cmdSessionInfo() {
|
|
404
|
+
const siteLink = await loadSiteLink(process.cwd());
|
|
405
|
+
if (!siteLink) {
|
|
406
|
+
console.log(`\n ${DIM('Nessun sito collegato')}\n`);
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
const session = siteLink ? await loadActiveSession(siteLink.orbit_site_id) : null;
|
|
410
|
+
if (!session) {
|
|
411
|
+
console.log(`\n ${DIM('Nessuna sessione attiva')}\n`);
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
const elapsed = Math.round((Date.now() - new Date(session.started_at).getTime()) / 60_000);
|
|
415
|
+
console.log('');
|
|
416
|
+
console.log(` ${sparkle} ${BB('Sessione attiva')}`);
|
|
417
|
+
console.log('');
|
|
418
|
+
console.log(` ${DIM('ID')} ${BL(session.id)}`);
|
|
419
|
+
console.log(` ${DIM('Durata')} ${WHITE(`${elapsed} min`)}`);
|
|
420
|
+
if (session.git_branch)
|
|
421
|
+
console.log(` ${DIM('Branch')} ${BL(session.git_branch)}`);
|
|
422
|
+
console.log(` ${DIM('Note')} ${WHITE(String(session.notes.length))}`);
|
|
423
|
+
for (const n of session.notes.slice(-5))
|
|
424
|
+
console.log(` ${DIM('·')} ${WHITE(n.text)}`);
|
|
425
|
+
console.log('');
|
|
426
|
+
}
|
|
427
|
+
async function cmdNoteAdd(text) {
|
|
428
|
+
const siteLink = await loadSiteLink(process.cwd());
|
|
429
|
+
if (!siteLink) {
|
|
430
|
+
console.log(`\n ${chalk.red('✗')} ${DIM('Nessun sito collegato')}\n`);
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
const session = await loadActiveSession(siteLink.orbit_site_id);
|
|
434
|
+
if (!session) {
|
|
435
|
+
console.log(`\n ${DIM('Nessuna sessione attiva. /session start')}\n`);
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
await addNote(session.id, text, 'medium');
|
|
439
|
+
console.log('');
|
|
440
|
+
console.log(` ${GREEN('✓')} ${GREEN.bold('Nota aggiunta')} ${DIM(`(${session.notes.length + 1} totali)`)}`);
|
|
441
|
+
console.log(` ${B('│')} ${WHITE(text)}`);
|
|
442
|
+
console.log('');
|
|
443
|
+
}
|
|
444
|
+
async function cmdReport() {
|
|
445
|
+
const config = await loadConfig();
|
|
446
|
+
const client = getClient(config);
|
|
447
|
+
if (!client) {
|
|
448
|
+
console.log(`\n ${chalk.red('✗')} ${DIM('Non autenticato. /auth')}\n`);
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
const siteLink = await loadSiteLink(process.cwd());
|
|
452
|
+
if (!siteLink) {
|
|
453
|
+
console.log(`\n ${chalk.red('✗')} ${DIM('Nessun sito collegato')}\n`);
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
let session = await loadActiveSession(siteLink.orbit_site_id);
|
|
457
|
+
const commitEnd = await getGitCommitHead();
|
|
458
|
+
let filesChanged = 0;
|
|
459
|
+
if (session?.git_commit_start && commitEnd) {
|
|
460
|
+
const diff = await getGitDiffStat(session.git_commit_start, commitEnd);
|
|
461
|
+
filesChanged = diff.files_changed;
|
|
462
|
+
}
|
|
463
|
+
if (session && session.status === 'active') {
|
|
464
|
+
session = await endSession(session.id, { git_commit_end: commitEnd ?? undefined });
|
|
465
|
+
}
|
|
466
|
+
const payload = buildReportPayload({
|
|
467
|
+
session: session ?? { id: 'no-session', site_id: siteLink.orbit_site_id, started_at: new Date().toISOString(), notes: [], status: 'completed' },
|
|
468
|
+
git_commit_end: commitEnd ?? undefined, files_changed: filesChanged,
|
|
469
|
+
});
|
|
470
|
+
payload.site_id = siteLink.orbit_site_id;
|
|
471
|
+
const spinner = ora({ text: 'Invio report a Orbit...', color: 'blue', indent: 2 }).start();
|
|
472
|
+
try {
|
|
473
|
+
const result = await client.createIntervention(payload);
|
|
474
|
+
spinner.succeed(`${GREEN.bold('Report inviato')} ${DIM(String(result.id).slice(0, 8))}`);
|
|
475
|
+
}
|
|
476
|
+
catch (err) {
|
|
477
|
+
spinner.fail(`Invio fallito: ${err instanceof Error ? err.message : String(err)}`);
|
|
478
|
+
}
|
|
479
|
+
console.log('');
|
|
480
|
+
}
|
|
481
|
+
async function cmdList() {
|
|
482
|
+
const config = await loadConfig();
|
|
483
|
+
const client = getClient(config);
|
|
484
|
+
if (!client) {
|
|
485
|
+
console.log(`\n ${chalk.red('✗')} ${DIM('Non autenticato')}\n`);
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
const siteLink = await loadSiteLink(process.cwd());
|
|
489
|
+
const filters = { limit: 10, sort: '-created_at' };
|
|
490
|
+
if (siteLink)
|
|
491
|
+
filters.site_id = siteLink.orbit_site_id;
|
|
492
|
+
const spinner = ora({ text: 'Caricamento...', color: 'blue', indent: 2 }).start();
|
|
493
|
+
try {
|
|
494
|
+
const result = await client.listInterventions(filters);
|
|
495
|
+
spinner.stop();
|
|
496
|
+
console.log('');
|
|
497
|
+
console.log(` ${sparkle} ${BB('Interventi')}`);
|
|
498
|
+
console.log('');
|
|
499
|
+
if (result.items.length === 0) {
|
|
500
|
+
console.log(` ${DIM('Nessun intervento trovato')}`);
|
|
578
501
|
}
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
const { setToken } = await import('./config.js');
|
|
593
|
-
await setToken('default', { token, label: 'default', site_id: 'default', created_at: new Date().toISOString() });
|
|
594
|
-
addOutput({ text: '' }, { text: ' ✓ Autenticazione riuscita', color: '#22C55E', bold: true }, { text: '' });
|
|
595
|
-
}
|
|
596
|
-
else {
|
|
597
|
-
addOutput({ text: ` ✗ Token non valido: ${v.error}`, color: '#EF4444' });
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
finally {
|
|
601
|
-
setLoading(false);
|
|
602
|
-
}
|
|
603
|
-
return;
|
|
502
|
+
else {
|
|
503
|
+
for (const item of result.items) {
|
|
504
|
+
const id = DIM(String(item.id ?? '').slice(0, 8));
|
|
505
|
+
const t = WHITE(String(item.title ?? '').slice(0, 35).padEnd(35));
|
|
506
|
+
const s = item.status;
|
|
507
|
+
const sColor = s === 'completed' ? GREEN : s === 'in_progress' ? YELLOW : BL;
|
|
508
|
+
const sLabel = s === 'completed' ? 'completato' : s === 'in_progress' ? 'in corso' : s === 'verified' ? 'verificato' : 'pianificato';
|
|
509
|
+
const date = DIM(String(item.created_at ?? '').slice(5, 10));
|
|
510
|
+
const origin = item.origin === 'cli' ? B('CLI') : DIM(String(item.origin));
|
|
511
|
+
console.log(` ${sColor('●')} ${id} ${t} ${sColor(sLabel.padEnd(12))} ${origin.padEnd(10)} ${date}`);
|
|
512
|
+
}
|
|
513
|
+
console.log('');
|
|
514
|
+
console.log(` ${DIM(`${result.total} interventi`)}`);
|
|
604
515
|
}
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
516
|
+
}
|
|
517
|
+
catch (err) {
|
|
518
|
+
spinner.fail(err instanceof Error ? err.message : String(err));
|
|
519
|
+
}
|
|
520
|
+
console.log('');
|
|
521
|
+
}
|
|
522
|
+
async function cmdGet(id) {
|
|
523
|
+
if (!id) {
|
|
524
|
+
console.log(`\n ${DIM('Uso: /get <intervention_id>')}\n`);
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
const config = await loadConfig();
|
|
528
|
+
const client = getClient(config);
|
|
529
|
+
if (!client) {
|
|
530
|
+
console.log(`\n ${chalk.red('✗')} ${DIM('Non autenticato')}\n`);
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
const spinner = ora({ text: 'Caricamento...', color: 'blue', indent: 2 }).start();
|
|
534
|
+
try {
|
|
535
|
+
const item = await client.getIntervention(id);
|
|
536
|
+
spinner.stop();
|
|
537
|
+
console.log('');
|
|
538
|
+
console.log(` ${sparkle} ${BB(String(item.title))}`);
|
|
539
|
+
console.log('');
|
|
540
|
+
console.log(` ${DIM('ID')} ${BL(String(item.id))}`);
|
|
541
|
+
console.log(` ${DIM('Stato')} ${WHITE(String(item.status))}`);
|
|
542
|
+
console.log(` ${DIM('Priorita')} ${WHITE(String(item.priority))}`);
|
|
543
|
+
console.log(` ${DIM('Origin')} ${item.origin === 'cli' ? B('CLI') : DIM(String(item.origin))}`);
|
|
544
|
+
if (item.type_tag)
|
|
545
|
+
console.log(` ${DIM('Tipo')} ${BL(String(item.type_tag))}`);
|
|
546
|
+
console.log(` ${DIM('Creato')} ${DIM(String(item.created_at))}`);
|
|
547
|
+
if (item.description) {
|
|
548
|
+
console.log('');
|
|
549
|
+
console.log(` ${DIM(String(item.description).slice(0, 300))}`);
|
|
617
550
|
}
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
551
|
+
}
|
|
552
|
+
catch (err) {
|
|
553
|
+
spinner.fail(err instanceof Error ? err.message : String(err));
|
|
554
|
+
}
|
|
555
|
+
console.log('');
|
|
556
|
+
}
|
|
557
|
+
async function cmdSites(selectNum) {
|
|
558
|
+
const config = await loadConfig();
|
|
559
|
+
const client = getClient(config);
|
|
560
|
+
if (!client) {
|
|
561
|
+
console.log(`\n ${chalk.red('✗')} ${DIM('Non autenticato. /auth')}\n`);
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
const spinner = ora({ text: 'Caricamento siti...', color: 'blue', indent: 2 }).start();
|
|
565
|
+
try {
|
|
566
|
+
const sites = await client.listSites();
|
|
567
|
+
spinner.stop();
|
|
568
|
+
if (!Array.isArray(sites) || sites.length === 0) {
|
|
569
|
+
console.log(`\n ${DIM('Nessun sito trovato.')}\n`);
|
|
621
570
|
return;
|
|
622
571
|
}
|
|
623
|
-
//
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
572
|
+
// Select by number
|
|
573
|
+
if (selectNum && /^\d+$/.test(selectNum)) {
|
|
574
|
+
const idx = parseInt(selectNum, 10) - 1;
|
|
575
|
+
if (idx >= 0 && idx < sites.length) {
|
|
576
|
+
const site = sites[idx];
|
|
577
|
+
const siteId = String(site.id);
|
|
578
|
+
const domain = String(site.domain ?? site.home_url ?? siteId);
|
|
579
|
+
const { saveSiteLink } = await import('./site.js');
|
|
580
|
+
await saveSiteLink(process.cwd(), {
|
|
581
|
+
orbit_site_id: siteId,
|
|
582
|
+
platform: 'wordpress',
|
|
583
|
+
final_url: String(site.home_url ?? site.domain ?? ''),
|
|
584
|
+
});
|
|
585
|
+
console.log('');
|
|
586
|
+
console.log(` ${GREEN('✓')} ${GREEN.bold('Sito selezionato:')} ${BL(domain)}`);
|
|
587
|
+
console.log(` ${DIM('ID:')} ${DIM(siteId)}`);
|
|
588
|
+
console.log('');
|
|
631
589
|
}
|
|
632
590
|
else {
|
|
633
|
-
|
|
634
|
-
addOutput({ text: '' }, { text: ` ✦ Orbit AI${providerInfo}`, color: '#2563EB', bold: true }, { text: '' },
|
|
635
|
-
// Split response into lines for proper rendering
|
|
636
|
-
...(chatResult.response ?? '').split('\n').map(line => ({ text: ` ${line}` })), { text: '' });
|
|
591
|
+
console.log(`\n ${chalk.red('✗')} Numero non valido. Scegli tra 1 e ${sites.length}\n`);
|
|
637
592
|
}
|
|
593
|
+
return;
|
|
638
594
|
}
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
595
|
+
// Show list
|
|
596
|
+
console.log('');
|
|
597
|
+
console.log(` ${sparkle} ${BB('Siti disponibili')}`);
|
|
598
|
+
console.log('');
|
|
599
|
+
sites.forEach((site, i) => {
|
|
600
|
+
const num = String(i + 1).padStart(2);
|
|
601
|
+
const domain = WHITE(String(site.domain ?? site.home_url ?? '—').slice(0, 35).padEnd(35));
|
|
602
|
+
const status = site.status;
|
|
603
|
+
const icon = status === 'active' ? GREEN('●') : chalk.red('○');
|
|
604
|
+
const wp = DIM(String(site.wp_version ? `WP ${site.wp_version}` : '').padEnd(10));
|
|
605
|
+
const id = DIM(String(site.id ?? '').slice(0, 8));
|
|
606
|
+
console.log(` ${DIM(num)}. ${icon} ${domain} ${wp} ${id}`);
|
|
607
|
+
});
|
|
608
|
+
console.log('');
|
|
609
|
+
console.log(` ${DIM('Seleziona con: /sites <numero>')}`);
|
|
610
|
+
console.log('');
|
|
611
|
+
}
|
|
612
|
+
catch (err) {
|
|
613
|
+
spinner.fail(err instanceof Error ? err.message : String(err));
|
|
614
|
+
}
|
|
645
615
|
}
|
|
646
|
-
function
|
|
647
|
-
const
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
616
|
+
async function cmdAuth() {
|
|
617
|
+
const config = await loadConfig();
|
|
618
|
+
const apiUrl = config.api_url || DEFAULT_API_URL;
|
|
619
|
+
const spinner = ora({ text: 'Generazione codice...', color: 'blue', indent: 2 }).start();
|
|
620
|
+
try {
|
|
621
|
+
const deviceCode = await requestDeviceCode(apiUrl);
|
|
622
|
+
spinner.stop();
|
|
623
|
+
console.log('');
|
|
624
|
+
console.log(` ${sparkle} ${BB('Accesso con browser')}`);
|
|
625
|
+
console.log('');
|
|
626
|
+
console.log(` Apri questo URL nel browser:`);
|
|
627
|
+
console.log(` ${BL(deviceCode.verification_url)}`);
|
|
628
|
+
console.log('');
|
|
629
|
+
console.log(` Codice: ${chalk.bgRgb(37, 99, 235).white.bold(` ${deviceCode.user_code} `)}`);
|
|
630
|
+
console.log('');
|
|
631
|
+
await openBrowser(deviceCode.verification_url);
|
|
632
|
+
const pollSpinner = ora({ text: 'In attesa di autorizzazione dal browser...', color: 'blue', indent: 2 }).start();
|
|
633
|
+
const result = await pollDeviceCode(apiUrl, deviceCode.device_code);
|
|
634
|
+
await saveDeviceAuth(result);
|
|
635
|
+
pollSpinner.succeed(`${GREEN.bold(`Autenticato come ${result.user_email ?? 'utente'}`)}`);
|
|
636
|
+
console.log(` ${DIM('Token salvato in ~/.orbit/config.json')}`);
|
|
637
|
+
console.log('');
|
|
638
|
+
}
|
|
639
|
+
catch (err) {
|
|
640
|
+
spinner.stop();
|
|
641
|
+
console.log(`\n ${chalk.red('✗')} Auth fallita: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
642
|
+
}
|
|
651
643
|
}
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
644
|
+
async function cmdLogin(token) {
|
|
645
|
+
if (!token?.startsWith('orbit_mcp_')) {
|
|
646
|
+
console.log(`\n ${DIM('Uso: /login orbit_mcp_xxx')}\n`);
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
const spinner = ora({ text: 'Validazione...', color: 'blue', indent: 2 }).start();
|
|
650
|
+
const client = new OrbitClient(token, DEFAULT_API_URL);
|
|
651
|
+
const v = await client.validateToken();
|
|
652
|
+
if (v.valid) {
|
|
653
|
+
const { setToken } = await import('./config.js');
|
|
654
|
+
await setToken('default', { token, label: 'default', site_id: 'default', created_at: new Date().toISOString() });
|
|
655
|
+
spinner.succeed(GREEN.bold('Autenticazione riuscita'));
|
|
656
|
+
}
|
|
657
|
+
else {
|
|
658
|
+
spinner.fail(`Token non valido: ${v.error}`);
|
|
659
|
+
}
|
|
660
|
+
console.log('');
|
|
661
|
+
}
|
|
662
|
+
async function cmdLink(siteId) {
|
|
663
|
+
if (!siteId) {
|
|
664
|
+
console.log(`\n ${DIM('Uso: /link <site_id>')}\n`);
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
const { saveSiteLink, detectPlatform } = await import('./site.js');
|
|
668
|
+
const platform = await detectPlatform(process.cwd());
|
|
669
|
+
await saveSiteLink(process.cwd(), { orbit_site_id: siteId, platform });
|
|
670
|
+
console.log(`\n ${GREEN('✓')} ${GREEN.bold('Sito collegato')} ${DIM(`(${platform})`)}\n`);
|
|
655
671
|
}
|
|
656
672
|
//# sourceMappingURL=shell.js.map
|