@lucenaone/coder 1.1.17 → 1.1.18

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lucenaone/coder",
3
- "version": "1.1.17",
3
+ "version": "1.1.18",
4
4
  "description": "Private tunnel for connecting LucenaCoder.com to your local folder. Always remains folder scoped while providing full terminal access.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/agent.js CHANGED
@@ -68,6 +68,7 @@ export class LucenaAgent {
68
68
  this.stripCwd = true; // Default: strip absolute paths (Browser Mode safety)
69
69
  this.indexData = null; // Pre-built index from CLI-side parsing
70
70
  this.indexPromise = null; // The in-flight indexing promise
71
+ this.browserConnected = false;
71
72
  this.shell = new LucenaShell(this.cwd);
72
73
  }
73
74
 
@@ -109,6 +110,9 @@ export class LucenaAgent {
109
110
  this.indexData = result;
110
111
  const { stats } = result;
111
112
  process.stdout.write(`\r ${'\x1b[32m'}✔ Indexed ${stats.filesParsed} files — ${stats.symbolCount} symbols, ${stats.stringCount} strings${'\x1b[0m'} \n`);
113
+ if (this.browserConnected && this.db) {
114
+ this.pushIndexSnapshot(result);
115
+ }
112
116
  return result;
113
117
  }).catch((err) => {
114
118
  console.warn(`\n ${'\x1b[33m'}⚠ Indexing failed: ${err.message}${'\x1b[0m'}`);
@@ -141,6 +145,7 @@ export class LucenaAgent {
141
145
  const data = snapshot.val();
142
146
  if (!data) return;
143
147
  remove(snapshot.ref);
148
+ this.browserConnected = true;
144
149
 
145
150
  // Browser tells us whether to strip cwd from output
146
151
  if (typeof data.stripCwd === 'boolean') {
@@ -152,7 +157,6 @@ export class LucenaAgent {
152
157
  console.log(` ${'\x1b[36m'}PRO token stored. Future runs can auto-launch.${'\x1b[0m'}`);
153
158
  }
154
159
 
155
- // Index is guaranteed ready (awaited in start()), push immediately
156
160
  if (this.indexData) {
157
161
  this.pushIndexSnapshot(this.indexData);
158
162
  }
@@ -174,10 +178,6 @@ export class LucenaAgent {
174
178
  this.startWatcher();
175
179
  this.connected = true;
176
180
 
177
- // ── Wait for indexing to finish before opening the browser ──
178
- // This guarantees the snapshot is ready the instant the browser connects
179
- await this.indexPromise;
180
-
181
181
  return this.tunnelId;
182
182
  }
183
183
 
package/src/main.js CHANGED
@@ -1,7 +1,8 @@
1
1
  // src/main.js — CLI entry point for the Lucena agent
2
2
  import { LucenaAgent } from './agent.js';
3
3
  import { spawn } from 'child_process';
4
- import { validateStoredProToken } from './pro-token.js';
4
+ import { registerProTunnel, validateStoredProToken } from './pro-token.js';
5
+ import { basename } from 'path';
5
6
 
6
7
 
7
8
  // Standard ANSI Terminal Colors
@@ -50,6 +51,7 @@ function openBrowser(url) {
50
51
  export async function main() {
51
52
  const cwd = process.cwd();
52
53
  const proStatus = await validateStoredProToken();
54
+ let activeTunnelId = null;
53
55
 
54
56
  console.log(BANNER);
55
57
  console.log(` ${c.cyan}📍 Scoped to:${c.reset} ${cwd}`);
@@ -63,6 +65,17 @@ export async function main() {
63
65
 
64
66
  const shutdown = async () => {
65
67
  console.log(`\n ${c.dim}Shutting down tunnel...${c.reset}`);
68
+ if (proStatus.valid && activeTunnelId) {
69
+ await registerProTunnel({
70
+ tokenForPro: proStatus.stored?.tokenForPro,
71
+ tunnelId: activeTunnelId,
72
+ cwdName: basename(cwd),
73
+ platform: process.platform,
74
+ pid: process.pid,
75
+ status: 'disconnected',
76
+ online: false,
77
+ });
78
+ }
66
79
  await agent.shutdown();
67
80
  process.exit(0);
68
81
  };
@@ -72,6 +85,21 @@ export async function main() {
72
85
 
73
86
  try {
74
87
  const tunnelId = await agent.start();
88
+ activeTunnelId = tunnelId;
89
+ if (proStatus.valid) {
90
+ const registered = await registerProTunnel({
91
+ tokenForPro: proStatus.stored?.tokenForPro,
92
+ tunnelId,
93
+ cwdName: basename(cwd),
94
+ platform: process.platform,
95
+ pid: process.pid,
96
+ });
97
+ if (registered.ok) {
98
+ console.log(` ${c.cyan}RemoteControl registered.${c.reset} This run is visible on rc.lucenacoder.com.`);
99
+ } else {
100
+ console.log(` ${c.yellow}RemoteControl registration failed.${c.reset} ${registered.error || 'Run will not appear in the remote list.'}`);
101
+ }
102
+ }
75
103
  console.log(` ${c.green}✔ Tunnel active!${c.reset}\n`);
76
104
 
77
105
  const idLabel = "Tunnel ID:";
package/src/pro-token.js CHANGED
@@ -4,6 +4,7 @@ import { homedir } from 'os';
4
4
 
5
5
  const TOKEN_PATH = join(homedir(), '.lucenacoder', 'pro.json');
6
6
  const VALIDATE_URL = process.env.LUCENA_VALIDATE_PRO_URL || 'https://lucenacoder.com/api/pro/validate-token';
7
+ const REGISTER_TUNNEL_URL = process.env.LUCENA_REGISTER_TUNNEL_URL || 'https://lucenacoder.com/api/remote/register-tunnel';
7
8
 
8
9
  export async function readStoredProToken() {
9
10
  try {
@@ -45,3 +46,30 @@ export async function validateStoredProToken() {
45
46
  return { valid: false, stored };
46
47
  }
47
48
  }
49
+
50
+ export async function registerProTunnel({ tokenForPro, tunnelId, cwdName, platform, pid, source = 'local-npx', status = 'active', online = true }) {
51
+ if (!tokenForPro || !tunnelId) return { ok: false };
52
+
53
+ try {
54
+ const response = await fetch(REGISTER_TUNNEL_URL, {
55
+ method: 'POST',
56
+ headers: { 'Content-Type': 'application/json' },
57
+ body: JSON.stringify({
58
+ tokenForPro,
59
+ tunnelId,
60
+ cwdName,
61
+ displayName: cwdName,
62
+ platform,
63
+ pid,
64
+ source,
65
+ status,
66
+ online,
67
+ }),
68
+ });
69
+ const payload = await response.json().catch(() => ({}));
70
+ if (!response.ok) return { ok: false, ...payload };
71
+ return { ok: true, ...payload };
72
+ } catch {
73
+ return { ok: false };
74
+ }
75
+ }