uwonbot 1.0.0 → 1.0.2
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/package.json +1 -2
- package/src/assistants.js +5 -1
- package/src/auth.js +3 -2
- package/src/firebase-client.js +61 -41
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uwonbot",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Uwonbot AI Assistant CLI — Your AI controls your computer",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -26,7 +26,6 @@
|
|
|
26
26
|
"chalk": "^5.3.0",
|
|
27
27
|
"commander": "^12.1.0",
|
|
28
28
|
"conf": "^13.0.1",
|
|
29
|
-
"firebase": "^11.0.0",
|
|
30
29
|
"inquirer": "^12.0.0",
|
|
31
30
|
"node-fetch": "^3.3.2",
|
|
32
31
|
"open": "^10.1.0",
|
package/src/assistants.js
CHANGED
|
@@ -2,7 +2,7 @@ import chalk from 'chalk';
|
|
|
2
2
|
import inquirer from 'inquirer';
|
|
3
3
|
import ora from 'ora';
|
|
4
4
|
import { getConfig } from './config.js';
|
|
5
|
-
import { fetchAssistants } from './firebase-client.js';
|
|
5
|
+
import { fetchAssistants, setIdToken } from './firebase-client.js';
|
|
6
6
|
|
|
7
7
|
export async function listAssistants() {
|
|
8
8
|
const config = getConfig();
|
|
@@ -11,6 +11,8 @@ export async function listAssistants() {
|
|
|
11
11
|
console.log(chalk.yellow('\n ⚠️ Please log in first: uwonbot login\n'));
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
14
|
+
const token = config.get('idToken');
|
|
15
|
+
if (token) setIdToken(token);
|
|
14
16
|
|
|
15
17
|
const spinner = ora('Fetching assistants...').start();
|
|
16
18
|
try {
|
|
@@ -56,6 +58,8 @@ export async function selectAssistant() {
|
|
|
56
58
|
console.log(chalk.yellow('\n ⚠️ Please log in first: uwonbot login\n'));
|
|
57
59
|
return null;
|
|
58
60
|
}
|
|
61
|
+
const token = config.get('idToken');
|
|
62
|
+
if (token) setIdToken(token);
|
|
59
63
|
|
|
60
64
|
const spinner = ora('Loading assistants...').start();
|
|
61
65
|
try {
|
package/src/auth.js
CHANGED
|
@@ -50,9 +50,10 @@ export async function loginCommand() {
|
|
|
50
50
|
console.log('');
|
|
51
51
|
} catch (err) {
|
|
52
52
|
spinner.fail(chalk.red('Login failed'));
|
|
53
|
-
|
|
53
|
+
const msg = (err.message || '').toUpperCase();
|
|
54
|
+
if (msg.includes('EMAIL_NOT_FOUND') || msg.includes('USER_NOT_FOUND')) {
|
|
54
55
|
console.log(chalk.yellow(' No account found. Sign up at https://chartapp-653e1.web.app/auth'));
|
|
55
|
-
} else if (
|
|
56
|
+
} else if (msg.includes('INVALID_PASSWORD') || msg.includes('INVALID_LOGIN_CREDENTIALS')) {
|
|
56
57
|
console.log(chalk.yellow(' Invalid password. Try again.'));
|
|
57
58
|
} else {
|
|
58
59
|
console.log(chalk.red(` ${err.message}`));
|
package/src/firebase-client.js
CHANGED
|
@@ -1,53 +1,73 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
const API_KEY = 'AIzaSyATfC0Ycfkjhgoe-QeS-Vww5DSdQINSWNU';
|
|
2
|
+
const PROJECT_ID = 'chartapp-653e1';
|
|
3
|
+
const AUTH_URL = `https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=${API_KEY}`;
|
|
4
|
+
const FIRESTORE_URL = `https://firestore.googleapis.com/v1/projects/${PROJECT_ID}/databases/(default)/documents`;
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
apiKey: "AIzaSyCVq7IdMZCfWqFbd5gBle5JmMX5cVJx68o",
|
|
7
|
-
authDomain: "chartapp-653e1.firebaseapp.com",
|
|
8
|
-
projectId: "chartapp-653e1",
|
|
9
|
-
storageBucket: "chartapp-653e1.firebasestorage.app",
|
|
10
|
-
messagingSenderId: "273874051709",
|
|
11
|
-
appId: "1:273874051709:web:f31e4b40dacb3a0bc76c88",
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
let app = null;
|
|
15
|
-
let auth = null;
|
|
16
|
-
let db = null;
|
|
17
|
-
|
|
18
|
-
export function getFirebaseApp() {
|
|
19
|
-
if (!app) {
|
|
20
|
-
app = initializeApp(firebaseConfig);
|
|
21
|
-
auth = getAuth(app);
|
|
22
|
-
db = getFirestore(app);
|
|
23
|
-
}
|
|
24
|
-
return { app, auth, db };
|
|
25
|
-
}
|
|
6
|
+
let cachedIdToken = null;
|
|
26
7
|
|
|
27
8
|
export async function loginWithEmail(email, password) {
|
|
28
|
-
const
|
|
29
|
-
|
|
9
|
+
const res = await fetch(AUTH_URL, {
|
|
10
|
+
method: 'POST',
|
|
11
|
+
headers: { 'Content-Type': 'application/json' },
|
|
12
|
+
body: JSON.stringify({ email, password, returnSecureToken: true }),
|
|
13
|
+
});
|
|
14
|
+
const data = await res.json();
|
|
15
|
+
if (data.error) {
|
|
16
|
+
throw new Error(data.error.message || 'Login failed');
|
|
17
|
+
}
|
|
18
|
+
cachedIdToken = data.idToken;
|
|
30
19
|
return {
|
|
31
|
-
uid:
|
|
32
|
-
email:
|
|
33
|
-
displayName:
|
|
34
|
-
idToken:
|
|
35
|
-
refreshToken:
|
|
20
|
+
uid: data.localId,
|
|
21
|
+
email: data.email,
|
|
22
|
+
displayName: data.displayName || '',
|
|
23
|
+
idToken: data.idToken,
|
|
24
|
+
refreshToken: data.refreshToken,
|
|
36
25
|
};
|
|
37
26
|
}
|
|
38
27
|
|
|
28
|
+
function parseFirestoreDoc(doc) {
|
|
29
|
+
const fields = doc.fields || {};
|
|
30
|
+
const result = {};
|
|
31
|
+
for (const [key, val] of Object.entries(fields)) {
|
|
32
|
+
if ('stringValue' in val) result[key] = val.stringValue;
|
|
33
|
+
else if ('integerValue' in val) result[key] = Number(val.integerValue);
|
|
34
|
+
else if ('doubleValue' in val) result[key] = val.doubleValue;
|
|
35
|
+
else if ('booleanValue' in val) result[key] = val.booleanValue;
|
|
36
|
+
else if ('nullValue' in val) result[key] = null;
|
|
37
|
+
else if ('arrayValue' in val) {
|
|
38
|
+
result[key] = (val.arrayValue.values || []).map(v =>
|
|
39
|
+
v.stringValue ?? v.integerValue ?? v.doubleValue ?? v.booleanValue ?? null
|
|
40
|
+
);
|
|
41
|
+
} else if ('mapValue' in val) result[key] = parseFirestoreDoc(val.mapValue);
|
|
42
|
+
else if ('timestampValue' in val) result[key] = val.timestampValue;
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
|
|
39
47
|
export async function fetchAssistants(uid) {
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
48
|
+
if (!cachedIdToken) throw new Error('Not logged in');
|
|
49
|
+
const url = `${FIRESTORE_URL}/users/${uid}/assistants?orderBy=createdAt%20desc`;
|
|
50
|
+
const res = await fetch(url, {
|
|
51
|
+
headers: { 'Authorization': `Bearer ${cachedIdToken}` },
|
|
52
|
+
});
|
|
53
|
+
const data = await res.json();
|
|
54
|
+
if (data.error) throw new Error(data.error.message);
|
|
55
|
+
return (data.documents || []).map(doc => {
|
|
56
|
+
const parts = doc.name.split('/');
|
|
57
|
+
return { id: parts[parts.length - 1], ...parseFirestoreDoc(doc) };
|
|
58
|
+
});
|
|
45
59
|
}
|
|
46
60
|
|
|
47
61
|
export async function fetchAssistant(uid, assistantId) {
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
62
|
+
if (!cachedIdToken) throw new Error('Not logged in');
|
|
63
|
+
const url = `${FIRESTORE_URL}/users/${uid}/assistants/${assistantId}`;
|
|
64
|
+
const res = await fetch(url, {
|
|
65
|
+
headers: { 'Authorization': `Bearer ${cachedIdToken}` },
|
|
66
|
+
});
|
|
67
|
+
const data = await res.json();
|
|
68
|
+
if (data.error) return null;
|
|
69
|
+
const parts = data.name.split('/');
|
|
70
|
+
return { id: parts[parts.length - 1], ...parseFirestoreDoc(data) };
|
|
53
71
|
}
|
|
72
|
+
|
|
73
|
+
export function setIdToken(token) { cachedIdToken = token; }
|