@lucenaone/coder 1.1.16 → 1.1.17
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 -1
- package/src/agent.js +13 -0
- package/src/main.js +30 -3
- package/src/pro-token.js +47 -0
package/package.json
CHANGED
package/src/agent.js
CHANGED
|
@@ -8,6 +8,7 @@ import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
|
8
8
|
import { FIREBASE_CONFIG } from './config.js';
|
|
9
9
|
import { buildIndex, reindexFile } from './cli-indexer.js';
|
|
10
10
|
import { LucenaShell } from './lucena-shell.js';
|
|
11
|
+
import { storeProToken } from './pro-token.js';
|
|
11
12
|
|
|
12
13
|
const IGNORED_PATTERNS = [
|
|
13
14
|
'node_modules', '.git', '.next', '.wrangler', '.DS_Store',
|
|
@@ -145,6 +146,11 @@ export class LucenaAgent {
|
|
|
145
146
|
if (typeof data.stripCwd === 'boolean') {
|
|
146
147
|
this.stripCwd = data.stripCwd;
|
|
147
148
|
}
|
|
149
|
+
|
|
150
|
+
if (data.proToken) {
|
|
151
|
+
await storeProToken({ tokenForPro: data.proToken, email: data.proEmail });
|
|
152
|
+
console.log(` ${'\x1b[36m'}PRO token stored. Future runs can auto-launch.${'\x1b[0m'}`);
|
|
153
|
+
}
|
|
148
154
|
|
|
149
155
|
// Index is guaranteed ready (awaited in start()), push immediately
|
|
150
156
|
if (this.indexData) {
|
|
@@ -218,11 +224,18 @@ export class LucenaAgent {
|
|
|
218
224
|
case 'delete_file': return this.deleteFile(command);
|
|
219
225
|
case 'mkdir': return this.mkdirCmd(command);
|
|
220
226
|
case 'search': return this.searchCodebase(command);
|
|
227
|
+
case 'store_pro_token': return this.storeProTokenCmd(command);
|
|
221
228
|
case 'ping': return this.pushResponse(messageId, 'pong', '');
|
|
222
229
|
default: return this.pushResponse(messageId, 'error', `Unknown command type: ${type}`);
|
|
223
230
|
}
|
|
224
231
|
}
|
|
225
232
|
|
|
233
|
+
async storeProTokenCmd({ messageId, tokenForPro, email }) {
|
|
234
|
+
if (!tokenForPro) return this.pushResponse(messageId, 'error', 'tokenForPro is required');
|
|
235
|
+
await storeProToken({ tokenForPro, email });
|
|
236
|
+
this.pushResponse(messageId, 'done', 'PRO token stored');
|
|
237
|
+
}
|
|
238
|
+
|
|
226
239
|
pushResponse(messageId, type, text, extra = {}) {
|
|
227
240
|
const responsesRef = ref(this.db, `tunnels/${this.tunnelId}/responses`);
|
|
228
241
|
push(responsesRef, {
|
package/src/main.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/main.js — CLI entry point for the Lucena agent
|
|
2
2
|
import { LucenaAgent } from './agent.js';
|
|
3
|
-
import {
|
|
3
|
+
import { spawn } from 'child_process';
|
|
4
|
+
import { validateStoredProToken } from './pro-token.js';
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
// Standard ANSI Terminal Colors
|
|
@@ -35,13 +36,28 @@ ${c.dim} =========================================${c.reset}
|
|
|
35
36
|
to your local folders.
|
|
36
37
|
`;
|
|
37
38
|
|
|
39
|
+
function openBrowser(url) {
|
|
40
|
+
const command = process.platform === 'darwin'
|
|
41
|
+
? 'open'
|
|
42
|
+
: process.platform === 'win32'
|
|
43
|
+
? 'cmd'
|
|
44
|
+
: 'xdg-open';
|
|
45
|
+
const args = process.platform === 'win32' ? ['/c', 'start', '', url] : [url];
|
|
46
|
+
const child = spawn(command, args, { detached: true, stdio: 'ignore' });
|
|
47
|
+
child.unref();
|
|
48
|
+
}
|
|
49
|
+
|
|
38
50
|
export async function main() {
|
|
39
51
|
const cwd = process.cwd();
|
|
52
|
+
const proStatus = await validateStoredProToken();
|
|
40
53
|
|
|
41
54
|
console.log(BANNER);
|
|
42
55
|
console.log(` ${c.cyan}📍 Scoped to:${c.reset} ${cwd}`);
|
|
43
56
|
console.log(` ${c.yellow}🛡️ Safe Mode:${c.reset} ON by default (All edits require approval)`);
|
|
44
57
|
console.log(` ${c.dim}Optionally switch to YOLO on LucenaCoder.com${c.reset}\n`);
|
|
58
|
+
if (proStatus.valid) {
|
|
59
|
+
console.log(` ${c.cyan}PRO detected.${c.reset} Browser auto-launch enabled.\n`);
|
|
60
|
+
}
|
|
45
61
|
|
|
46
62
|
const agent = new LucenaAgent(cwd);
|
|
47
63
|
|
|
@@ -72,11 +88,22 @@ export async function main() {
|
|
|
72
88
|
const urlBoxWidth = urlLabel.length + webUrl.length + 5;
|
|
73
89
|
const urlBorder = '─'.repeat(urlBoxWidth);
|
|
74
90
|
|
|
91
|
+
if (proStatus.valid) {
|
|
92
|
+
try {
|
|
93
|
+
openBrowser(webUrl);
|
|
94
|
+
console.log(`\n ${c.green}✔ Opening LucenaCoder...${c.reset}`);
|
|
95
|
+
} catch {
|
|
96
|
+
console.log(`\n ${c.yellow}Could not auto-open your browser.${c.reset}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
75
100
|
console.log(`\n ${c.dim}┌${urlBorder}┐${c.reset}`);
|
|
76
101
|
console.log(` ${c.dim}│${c.reset} ${urlLabel}${c.reset} ${c.bold}${webUrl}${c.reset} ${c.dim}│${c.reset}`);
|
|
77
102
|
console.log(` ${c.dim}└${urlBorder}┘${c.reset}`);
|
|
78
|
-
|
|
79
|
-
|
|
103
|
+
|
|
104
|
+
if (!proStatus.valid) {
|
|
105
|
+
console.log(`\n ${c.dim}Open the URL above in your browser to connect.${c.reset}`);
|
|
106
|
+
}
|
|
80
107
|
console.log(` ${c.dim}Press Ctrl+C to disconnect${c.reset}\n`);
|
|
81
108
|
} catch (err) {
|
|
82
109
|
console.error(`\n ${c.yellow}✖ Failed to start tunnel: ${err.message}${c.reset}\n`);
|
package/src/pro-token.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from 'fs/promises';
|
|
2
|
+
import { dirname, join } from 'path';
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
|
|
5
|
+
const TOKEN_PATH = join(homedir(), '.lucenacoder', 'pro.json');
|
|
6
|
+
const VALIDATE_URL = process.env.LUCENA_VALIDATE_PRO_URL || 'https://lucenacoder.com/api/pro/validate-token';
|
|
7
|
+
|
|
8
|
+
export async function readStoredProToken() {
|
|
9
|
+
try {
|
|
10
|
+
const raw = await readFile(TOKEN_PATH, 'utf-8');
|
|
11
|
+
const data = JSON.parse(raw);
|
|
12
|
+
if (!data?.tokenForPro) return null;
|
|
13
|
+
return data;
|
|
14
|
+
} catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function storeProToken({ tokenForPro, email }) {
|
|
20
|
+
if (!tokenForPro) return null;
|
|
21
|
+
const data = {
|
|
22
|
+
tokenForPro,
|
|
23
|
+
email: email || '',
|
|
24
|
+
savedAt: new Date().toISOString(),
|
|
25
|
+
};
|
|
26
|
+
await mkdir(dirname(TOKEN_PATH), { recursive: true });
|
|
27
|
+
await writeFile(TOKEN_PATH, JSON.stringify(data, null, 2), 'utf-8');
|
|
28
|
+
return data;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function validateStoredProToken() {
|
|
32
|
+
const stored = await readStoredProToken();
|
|
33
|
+
if (!stored?.tokenForPro) return { valid: false };
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
const response = await fetch(VALIDATE_URL, {
|
|
37
|
+
method: 'POST',
|
|
38
|
+
headers: { 'Content-Type': 'application/json' },
|
|
39
|
+
body: JSON.stringify({ tokenForPro: stored.tokenForPro }),
|
|
40
|
+
});
|
|
41
|
+
const payload = await response.json().catch(() => ({}));
|
|
42
|
+
if (!response.ok || !payload.valid) return { valid: false, stored };
|
|
43
|
+
return { valid: true, stored, ...payload };
|
|
44
|
+
} catch {
|
|
45
|
+
return { valid: false, stored };
|
|
46
|
+
}
|
|
47
|
+
}
|