yap2app 1.1.4 → 1.1.6
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/bin/cli-esm.js +11 -13
- package/bin/cli.bundle.js +454 -507
- package/bin/cli.js +454 -507
- package/bridge.js +113 -21
- package/mcp.js +1 -1
- package/package.json +1 -1
package/bridge.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import http from 'http';
|
|
2
|
+
import https from 'https';
|
|
2
3
|
import fsSync from 'fs';
|
|
3
4
|
import path from 'path';
|
|
4
5
|
import util from 'util';
|
|
@@ -14,6 +15,46 @@ const fs = fsSync.promises || {
|
|
|
14
15
|
|
|
15
16
|
const PORT = Number(process.env.YAP2APP_PORT) || 10420;
|
|
16
17
|
const PROJECT_ROOT = process.cwd();
|
|
18
|
+
const CLOUD_RELAY_URL = process.env.YAP2APP_CLOUD_URL || 'https://yap2app-dot-cybage-hackathon.uc.r.appspot.com';
|
|
19
|
+
const PAIR_CODE = (process.env.YAP2APP_PAIR_CODE || ('CYB-' + Math.floor(100 + Math.random() * 900))).toUpperCase();
|
|
20
|
+
|
|
21
|
+
// Helper to send outbound HTTPS requests to the Yap2App Cloud Relay
|
|
22
|
+
function sendCloudRelayRequest(method, endpoint, payload) {
|
|
23
|
+
return new Promise((resolve) => {
|
|
24
|
+
try {
|
|
25
|
+
const url = new URL(`${CLOUD_RELAY_URL}${endpoint}`);
|
|
26
|
+
const body = payload ? JSON.stringify(payload) : '';
|
|
27
|
+
const req = https.request({
|
|
28
|
+
hostname: url.hostname,
|
|
29
|
+
port: 443,
|
|
30
|
+
path: url.pathname + url.search,
|
|
31
|
+
method: method,
|
|
32
|
+
headers: {
|
|
33
|
+
'Content-Type': 'application/json',
|
|
34
|
+
'Content-Length': Buffer.byteLength(body),
|
|
35
|
+
'User-Agent': 'yap2app-cli/1.1.5'
|
|
36
|
+
},
|
|
37
|
+
timeout: 6000
|
|
38
|
+
}, (res) => {
|
|
39
|
+
let respData = '';
|
|
40
|
+
res.on('data', chunk => respData += chunk);
|
|
41
|
+
res.on('end', () => {
|
|
42
|
+
try {
|
|
43
|
+
resolve({ ok: res.statusCode >= 200 && res.statusCode < 300, status: res.statusCode, data: JSON.parse(respData || '{}') });
|
|
44
|
+
} catch {
|
|
45
|
+
resolve({ ok: false, status: res.statusCode, data: null });
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
req.on('error', () => resolve({ ok: false, status: 0, data: null }));
|
|
50
|
+
req.on('timeout', () => { req.destroy(); resolve({ ok: false, status: 0, data: null }); });
|
|
51
|
+
if (body) req.write(body);
|
|
52
|
+
req.end();
|
|
53
|
+
} catch {
|
|
54
|
+
resolve({ ok: false, status: 0, data: null });
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
17
58
|
|
|
18
59
|
// Bulletproof W3C Private Network Access (PNA) and Dynamic Origin CORS Headers
|
|
19
60
|
function getCorsHeaders(req) {
|
|
@@ -107,9 +148,10 @@ const server = http.createServer(async (req, res) => {
|
|
|
107
148
|
res.writeHead(200, headers);
|
|
108
149
|
res.end(JSON.stringify({
|
|
109
150
|
status: 'healthy',
|
|
110
|
-
service: '
|
|
111
|
-
version: '1.1.
|
|
151
|
+
service: 'yap2app-bridge',
|
|
152
|
+
version: '1.1.6',
|
|
112
153
|
port: PORT,
|
|
154
|
+
pair_code: PAIR_CODE,
|
|
113
155
|
project_root: PROJECT_ROOT,
|
|
114
156
|
project_name: path.basename(PROJECT_ROOT),
|
|
115
157
|
ready: true
|
|
@@ -121,12 +163,12 @@ const server = http.createServer(async (req, res) => {
|
|
|
121
163
|
if (req.method === 'GET' && (pathname === '/api/context' || pathname === '/context')) {
|
|
122
164
|
try {
|
|
123
165
|
const promptQuery = searchParams.get('q') || '';
|
|
124
|
-
console.log(`[
|
|
166
|
+
console.log(` [bridge] Scanning codebase in ${path.basename(PROJECT_ROOT)}${promptQuery ? ` (query: "${promptQuery}")` : ''}`);
|
|
125
167
|
const context = await scanCodebase(PROJECT_ROOT, promptQuery);
|
|
126
168
|
res.writeHead(200, headers);
|
|
127
169
|
res.end(JSON.stringify(context));
|
|
128
170
|
} catch (e) {
|
|
129
|
-
console.error('[
|
|
171
|
+
console.error(' [bridge] Context scan error:', e.message);
|
|
130
172
|
res.writeHead(500, headers);
|
|
131
173
|
res.end(JSON.stringify({ error: e.message }));
|
|
132
174
|
}
|
|
@@ -169,7 +211,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
169
211
|
diffs: diffResults
|
|
170
212
|
}));
|
|
171
213
|
} catch (e) {
|
|
172
|
-
console.error('[
|
|
214
|
+
console.error(' [bridge] Diff error:', e.message);
|
|
173
215
|
res.writeHead(500, headers);
|
|
174
216
|
res.end(JSON.stringify({ error: e.message }));
|
|
175
217
|
}
|
|
@@ -195,7 +237,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
195
237
|
|
|
196
238
|
// Write file with utf8 encoding
|
|
197
239
|
await fs.writeFile(fullPath, file.content, 'utf8');
|
|
198
|
-
console.log(`[
|
|
240
|
+
console.log(` [bridge] Wrote ${file.path}`);
|
|
199
241
|
written.push(file.path);
|
|
200
242
|
}
|
|
201
243
|
|
|
@@ -208,7 +250,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
208
250
|
message: `Successfully wrote ${written.length} files to ${path.basename(PROJECT_ROOT)}`
|
|
209
251
|
}));
|
|
210
252
|
} catch (e) {
|
|
211
|
-
console.error('[
|
|
253
|
+
console.error(' [bridge] Write error:', e.message);
|
|
212
254
|
res.writeHead(500, headers);
|
|
213
255
|
res.end(JSON.stringify({ error: e.message }));
|
|
214
256
|
}
|
|
@@ -224,26 +266,75 @@ const server = http.createServer(async (req, res) => {
|
|
|
224
266
|
// Gracefully handle EADDRINUSE without crashing
|
|
225
267
|
server.on('error', (err) => {
|
|
226
268
|
if (err && err.code === 'EADDRINUSE') {
|
|
227
|
-
console.log(`\n
|
|
228
|
-
console.log(
|
|
229
|
-
console.log(
|
|
230
|
-
console.log(
|
|
231
|
-
console.log(
|
|
269
|
+
console.log(`\n Yap2App Bridge\n`);
|
|
270
|
+
console.log(` Port ${PORT} is active. Cloud Relay connected.`);
|
|
271
|
+
console.log(` Workspace: ${PROJECT_ROOT}`);
|
|
272
|
+
console.log(` Pair Code: ${PAIR_CODE}`);
|
|
273
|
+
console.log(` Web Studio: ${CLOUD_RELAY_URL}\n`);
|
|
232
274
|
return;
|
|
233
275
|
}
|
|
234
|
-
console.error('[
|
|
276
|
+
console.error(' [bridge] Error:', err.message || err);
|
|
235
277
|
});
|
|
236
278
|
|
|
237
|
-
export function startBridge(port = PORT) {
|
|
279
|
+
export async function startBridge(port = PORT) {
|
|
238
280
|
server.listen(port, '0.0.0.0', () => {
|
|
239
|
-
console.log(`\n
|
|
240
|
-
console.log(
|
|
241
|
-
console.log(
|
|
242
|
-
console.log(
|
|
243
|
-
console.log(
|
|
244
|
-
console.log(
|
|
245
|
-
console.log(`Ready for 1-click sync from Yap2App Web Studio UI...\n`);
|
|
281
|
+
console.log(`\n Yap2App Bridge v1.1.6\n`);
|
|
282
|
+
console.log(` Local: http://127.0.0.1:${port}`);
|
|
283
|
+
console.log(` Workspace: ${PROJECT_ROOT}`);
|
|
284
|
+
console.log(` Pair Code: ${PAIR_CODE}`);
|
|
285
|
+
console.log(` Web Studio: ${CLOUD_RELAY_URL}\n`);
|
|
286
|
+
console.log(` Ready for sync.\n`);
|
|
246
287
|
});
|
|
288
|
+
|
|
289
|
+
// Initial scan and Cloud Relay registration
|
|
290
|
+
try {
|
|
291
|
+
const initialContext = await scanCodebase(PROJECT_ROOT);
|
|
292
|
+
await sendCloudRelayRequest('POST', '/api/v1/bridge/heartbeat', {
|
|
293
|
+
pair_code: PAIR_CODE,
|
|
294
|
+
project_name: path.basename(PROJECT_ROOT),
|
|
295
|
+
project_root: PROJECT_ROOT,
|
|
296
|
+
framework: initialContext.framework,
|
|
297
|
+
context: initialContext,
|
|
298
|
+
version: '1.1.6'
|
|
299
|
+
});
|
|
300
|
+
} catch (e) {}
|
|
301
|
+
|
|
302
|
+
// Periodic Cloud Relay heartbeat & write execution loop (every 3.5 seconds)
|
|
303
|
+
setInterval(async () => {
|
|
304
|
+
try {
|
|
305
|
+
const context = await scanCodebase(PROJECT_ROOT);
|
|
306
|
+
const hbResult = await sendCloudRelayRequest('POST', '/api/v1/bridge/heartbeat', {
|
|
307
|
+
pair_code: PAIR_CODE,
|
|
308
|
+
project_name: path.basename(PROJECT_ROOT),
|
|
309
|
+
project_root: PROJECT_ROOT,
|
|
310
|
+
framework: context.framework,
|
|
311
|
+
context: context,
|
|
312
|
+
version: '1.1.6'
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
// If pending write tasks, fetch and execute them on local disk
|
|
316
|
+
if (hbResult && hbResult.data && hbResult.data.pending_writes_count > 0) {
|
|
317
|
+
const pollResult = await sendCloudRelayRequest('GET', `/api/v1/bridge/poll-writes?pair_code=${PAIR_CODE}`);
|
|
318
|
+
const tasks = (pollResult.data && pollResult.data.pending_tasks) || [];
|
|
319
|
+
for (const task of tasks) {
|
|
320
|
+
const written = [];
|
|
321
|
+
for (const file of (task.files || [])) {
|
|
322
|
+
const fullPath = path.join(PROJECT_ROOT, file.path);
|
|
323
|
+
await fs.mkdir(path.dirname(fullPath), { recursive: true });
|
|
324
|
+
await fs.writeFile(fullPath, file.content, 'utf8');
|
|
325
|
+
console.log(` [bridge] Wrote ${file.path}`);
|
|
326
|
+
written.push(file.path);
|
|
327
|
+
}
|
|
328
|
+
await sendCloudRelayRequest('POST', '/api/v1/bridge/complete-write', {
|
|
329
|
+
task_id: task.task_id,
|
|
330
|
+
success: true,
|
|
331
|
+
written,
|
|
332
|
+
message: `Wrote ${written.length} file(s) directly to ${path.basename(PROJECT_ROOT)}`
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
} catch {}
|
|
337
|
+
}, 3500);
|
|
247
338
|
}
|
|
248
339
|
|
|
249
340
|
// Direct execution
|
|
@@ -252,3 +343,4 @@ if (isDirectRun) {
|
|
|
252
343
|
startBridge();
|
|
253
344
|
}
|
|
254
345
|
|
|
346
|
+
|
package/mcp.js
CHANGED
|
@@ -155,7 +155,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
155
155
|
export async function runMcpServer() {
|
|
156
156
|
const transport = new StdioServerTransport();
|
|
157
157
|
await server.connect(transport);
|
|
158
|
-
console.error("
|
|
158
|
+
console.error("Yap2App MCP Server running on stdio");
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
const isDirectRun = Boolean(typeof process !== 'undefined' && process.argv && process.argv[1] && (process.argv[1].endsWith('mcp.js') || process.argv[1].endsWith('mcp')));
|