@invizi/cli 0.1.12 → 0.1.15
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/auth.js +4 -61
- package/dist/config.js +5 -0
- package/dist/http.js +11 -0
- package/dist/invizi.js +12 -7
- package/dist/setup.js +8 -3
- package/dist/track.js +3 -2
- package/package.json +1 -1
package/dist/auth.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getApiUrl, loadConfig, saveConfig } from './config.js';
|
|
2
|
+
import { getDefaultHeaders } from './http.js';
|
|
2
3
|
const DEFAULT_SCOPE = 'openid profile email offline_access';
|
|
3
4
|
function sleep(ms) {
|
|
4
5
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
@@ -106,66 +107,8 @@ export async function getAuthorizationHeader() {
|
|
|
106
107
|
return null;
|
|
107
108
|
}
|
|
108
109
|
async function login() {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
method: 'POST',
|
|
112
|
-
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
113
|
-
body: new URLSearchParams({
|
|
114
|
-
client_id: clientId,
|
|
115
|
-
audience,
|
|
116
|
-
scope: DEFAULT_SCOPE,
|
|
117
|
-
}),
|
|
118
|
-
});
|
|
119
|
-
if (!deviceRes.ok) {
|
|
120
|
-
const body = await deviceRes.text();
|
|
121
|
-
throw new Error(`Auth0 device flow init failed: ${body}`);
|
|
122
|
-
}
|
|
123
|
-
const device = await deviceRes.json();
|
|
124
|
-
console.log('\nAuth0 login required');
|
|
125
|
-
console.log(`1) Open: ${device.verification_uri_complete || device.verification_uri}`);
|
|
126
|
-
if (!device.verification_uri_complete) {
|
|
127
|
-
console.log(`2) Enter code: ${device.user_code}`);
|
|
128
|
-
}
|
|
129
|
-
const deadline = Date.now() + (device.expires_in * 1000);
|
|
130
|
-
let intervalMs = (device.interval || 5) * 1000;
|
|
131
|
-
while (Date.now() < deadline) {
|
|
132
|
-
await sleep(intervalMs);
|
|
133
|
-
const tokenRes = await fetch(`https://${domain}/oauth/token`, {
|
|
134
|
-
method: 'POST',
|
|
135
|
-
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
136
|
-
body: new URLSearchParams({
|
|
137
|
-
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
|
|
138
|
-
device_code: device.device_code,
|
|
139
|
-
client_id: clientId,
|
|
140
|
-
}),
|
|
141
|
-
});
|
|
142
|
-
const token = await tokenRes.json();
|
|
143
|
-
if (tokenRes.ok && token.access_token && token.expires_in) {
|
|
144
|
-
setStoredAuth({
|
|
145
|
-
accessToken: token.access_token,
|
|
146
|
-
refreshToken: token.refresh_token,
|
|
147
|
-
expiresAt: Date.now() + (token.expires_in * 1000),
|
|
148
|
-
tokenType: token.token_type,
|
|
149
|
-
scope: token.scope,
|
|
150
|
-
domain,
|
|
151
|
-
audience,
|
|
152
|
-
clientId,
|
|
153
|
-
});
|
|
154
|
-
console.log('\nLogin successful.');
|
|
155
|
-
return 0;
|
|
156
|
-
}
|
|
157
|
-
if (token.error === 'authorization_pending')
|
|
158
|
-
continue;
|
|
159
|
-
if (token.error === 'slow_down') {
|
|
160
|
-
intervalMs += 5000;
|
|
161
|
-
continue;
|
|
162
|
-
}
|
|
163
|
-
if (token.error === 'expired_token') {
|
|
164
|
-
throw new Error('Device code expired. Run `invizi auth login` again.');
|
|
165
|
-
}
|
|
166
|
-
throw new Error(`Login failed: ${token.error || 'unknown error'}`);
|
|
167
|
-
}
|
|
168
|
-
throw new Error('Login timed out before authorization completed.');
|
|
110
|
+
console.log('Login is not available yet. Coming soon!');
|
|
111
|
+
return 1;
|
|
169
112
|
}
|
|
170
113
|
async function status() {
|
|
171
114
|
const header = await getAuthorizationHeader();
|
|
@@ -176,7 +119,7 @@ async function status() {
|
|
|
176
119
|
// Use v1 protocol (auth.me) instead of /api/me (not exposed via nginx)
|
|
177
120
|
const res = await fetch(`${getApiUrl()}/cli/v1/execute`, {
|
|
178
121
|
method: 'POST',
|
|
179
|
-
headers: { 'Content-Type': 'application/json', Authorization: header },
|
|
122
|
+
headers: getDefaultHeaders({ 'Content-Type': 'application/json', Authorization: header }),
|
|
180
123
|
body: JSON.stringify({ commandId: 'auth.me' }),
|
|
181
124
|
});
|
|
182
125
|
if (!res.ok) {
|
package/dist/config.js
CHANGED
|
@@ -3,6 +3,11 @@ import { dirname, join } from 'node:path';
|
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
export const DEFAULT_API_URL = 'https://api.invizi.co';
|
|
5
5
|
export function getConfigDir(home = homedir()) {
|
|
6
|
+
// Respect XDG_CONFIG_HOME if set (used for test isolation + Linux standard)
|
|
7
|
+
const xdgOverride = process.env.XDG_CONFIG_HOME;
|
|
8
|
+
if (xdgOverride) {
|
|
9
|
+
return join(xdgOverride, 'invizi');
|
|
10
|
+
}
|
|
6
11
|
const xdg = join(home, '.config', 'invizi');
|
|
7
12
|
const fallback = join(home, '.invizi');
|
|
8
13
|
if (existsSync(join(home, '.config'))) {
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf-8'));
|
|
3
|
+
export const CLI_VERSION = pkg.version || 'unknown';
|
|
4
|
+
export const INVIZI_CLI_USER_AGENT = `invizi-cli/${CLI_VERSION}`;
|
|
5
|
+
export function getDefaultHeaders(headers = {}) {
|
|
6
|
+
const merged = new Headers(headers);
|
|
7
|
+
if (!merged.has('User-Agent')) {
|
|
8
|
+
merged.set('User-Agent', INVIZI_CLI_USER_AGENT);
|
|
9
|
+
}
|
|
10
|
+
return merged;
|
|
11
|
+
}
|
package/dist/invizi.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs';
|
|
2
1
|
import { auth, getAuthorizationHeader } from './auth.js';
|
|
3
2
|
import { track } from './track.js';
|
|
4
3
|
import { getApiUrl, getConfigPath, loadConfig, redactConfig } from './config.js';
|
|
4
|
+
import { CLI_VERSION, getDefaultHeaders } from './http.js';
|
|
5
5
|
import { setup } from './setup.js';
|
|
6
6
|
import { trades } from './commands/index.js';
|
|
7
7
|
function showLocalHelp() {
|
|
@@ -34,10 +34,10 @@ async function executeProtocol(args, authHeader) {
|
|
|
34
34
|
const apiUrl = getApiUrl();
|
|
35
35
|
const res = await fetch(`${apiUrl}/cli/v1/execute`, {
|
|
36
36
|
method: 'POST',
|
|
37
|
-
headers: {
|
|
37
|
+
headers: getDefaultHeaders({
|
|
38
38
|
'Content-Type': 'application/json',
|
|
39
39
|
Authorization: authHeader,
|
|
40
|
-
},
|
|
40
|
+
}),
|
|
41
41
|
body: JSON.stringify({ argv: serverArgs }),
|
|
42
42
|
});
|
|
43
43
|
if (res.status === 404) {
|
|
@@ -71,7 +71,7 @@ async function executeProtocol(args, authHeader) {
|
|
|
71
71
|
async function showRemoteHelp(authHeader) {
|
|
72
72
|
const apiUrl = getApiUrl();
|
|
73
73
|
const res = await fetch(`${apiUrl}/cli/v1/commands`, {
|
|
74
|
-
headers: { Authorization: authHeader },
|
|
74
|
+
headers: getDefaultHeaders({ Authorization: authHeader }),
|
|
75
75
|
});
|
|
76
76
|
if (!res.ok) {
|
|
77
77
|
throw new Error(`Unable to fetch command catalog (${res.status})`);
|
|
@@ -140,16 +140,21 @@ export async function main(rawArgs = process.argv.slice(2)) {
|
|
|
140
140
|
return track(args.slice(1));
|
|
141
141
|
if (command === 'trades')
|
|
142
142
|
return trades(args.slice(1));
|
|
143
|
-
if (command === 'setup')
|
|
143
|
+
if (command === 'setup') {
|
|
144
|
+
const header = await getAuthorizationHeader();
|
|
145
|
+
if (!header) {
|
|
146
|
+
console.error('Not authenticated. Run: invizi login');
|
|
147
|
+
return 1;
|
|
148
|
+
}
|
|
144
149
|
return setup(args.slice(1));
|
|
150
|
+
}
|
|
145
151
|
if (command === 'config') {
|
|
146
152
|
console.log(JSON.stringify(redactConfig(loadConfig()), null, 2));
|
|
147
153
|
console.log(`\nConfig path: ${getConfigPath()}`);
|
|
148
154
|
return 0;
|
|
149
155
|
}
|
|
150
156
|
if (command === 'version' || command === '--version' || command === '-v') {
|
|
151
|
-
|
|
152
|
-
console.log(`invizi-cli v${pkg.version || 'unknown'}`);
|
|
157
|
+
console.log(`invizi-cli v${CLI_VERSION}`);
|
|
153
158
|
return 0;
|
|
154
159
|
}
|
|
155
160
|
return executeRemote(args);
|
package/dist/setup.js
CHANGED
|
@@ -2,6 +2,7 @@ import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { loadConfig, saveConfig, getConfigPath } from './config.js';
|
|
5
|
+
import { getDefaultHeaders } from './http.js';
|
|
5
6
|
const SKILLS_URL = 'https://pub-6e61fc0656544ad3bf01416b1d0a6065.r2.dev';
|
|
6
7
|
function detectAiTool() {
|
|
7
8
|
const checks = [
|
|
@@ -26,7 +27,7 @@ export async function setup(args) {
|
|
|
26
27
|
const customOutput = outputIdx !== -1 ? args[outputIdx + 1] : null;
|
|
27
28
|
const dryRun = args.includes('--dry-run');
|
|
28
29
|
const isDev = args.includes('--dev');
|
|
29
|
-
const apiUrl = isDev ? 'http://localhost:3000' : 'https://api.invizi.co';
|
|
30
|
+
const apiUrl = process.env.INVIZI_API_URL || (isDev ? 'http://localhost:3000' : 'https://api.invizi.co');
|
|
30
31
|
// Step 0: Configure API URL + Auth0
|
|
31
32
|
console.log(`Configuring Invizi CLI (${isDev ? 'dev' : 'prod'})...`);
|
|
32
33
|
if (!dryRun) {
|
|
@@ -82,7 +83,9 @@ export async function setup(args) {
|
|
|
82
83
|
console.log('(dry run - no files will be written)');
|
|
83
84
|
}
|
|
84
85
|
console.log('Fetching skills...');
|
|
85
|
-
const listRes = await fetch(`${SKILLS_URL}/list.json
|
|
86
|
+
const listRes = await fetch(`${SKILLS_URL}/list.json`, {
|
|
87
|
+
headers: getDefaultHeaders(),
|
|
88
|
+
});
|
|
86
89
|
if (!listRes.ok) {
|
|
87
90
|
console.error('Failed to fetch skill list from Invizi.');
|
|
88
91
|
return 1;
|
|
@@ -99,7 +102,9 @@ export async function setup(args) {
|
|
|
99
102
|
continue;
|
|
100
103
|
}
|
|
101
104
|
}
|
|
102
|
-
const res = await fetch(`${SKILLS_URL}/${name}/SKILL.md
|
|
105
|
+
const res = await fetch(`${SKILLS_URL}/${name}/SKILL.md`, {
|
|
106
|
+
headers: getDefaultHeaders(),
|
|
107
|
+
});
|
|
103
108
|
if (!res.ok) {
|
|
104
109
|
console.error(` [x] ${name} (download failed)`);
|
|
105
110
|
continue;
|
package/dist/track.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getApiUrl, loadConfig, saveConfig } from './config.js';
|
|
2
2
|
import { getAuthorizationHeader } from './auth.js';
|
|
3
|
+
import { getDefaultHeaders } from './http.js';
|
|
3
4
|
const HLP_API = 'https://api.hyperliquid.xyz/info';
|
|
4
5
|
function detectChain(address) {
|
|
5
6
|
if (/^0x[0-9a-fA-F]{40}$/.test(address))
|
|
@@ -41,10 +42,10 @@ async function registerWithServer(exchange, address, label) {
|
|
|
41
42
|
}
|
|
42
43
|
const res = await fetch(`${apiUrl}/api/connect`, {
|
|
43
44
|
method: 'POST',
|
|
44
|
-
headers: {
|
|
45
|
+
headers: getDefaultHeaders({
|
|
45
46
|
'Content-Type': 'application/json',
|
|
46
47
|
Authorization: authHeader,
|
|
47
|
-
},
|
|
48
|
+
}),
|
|
48
49
|
body: JSON.stringify({ exchange, address, label }),
|
|
49
50
|
});
|
|
50
51
|
if (!res.ok) {
|