yap2app 1.1.2 → 1.1.4
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 +1 -0
- package/bin/cli.bundle.js +1060 -785
- package/bin/cli.js +1060 -785
- package/bridge.js +49 -15
- package/mcp.js +2 -1
- package/package.json +5 -2
- package/polyfills.js +126 -0
package/bridge.js
CHANGED
|
@@ -12,18 +12,21 @@ const fs = fsSync.promises || {
|
|
|
12
12
|
stat: util.promisify(fsSync.stat)
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
-
const PORT = process.env.YAP2APP_PORT || 10420;
|
|
15
|
+
const PORT = Number(process.env.YAP2APP_PORT) || 10420;
|
|
16
16
|
const PROJECT_ROOT = process.cwd();
|
|
17
17
|
|
|
18
18
|
// Bulletproof W3C Private Network Access (PNA) and Dynamic Origin CORS Headers
|
|
19
19
|
function getCorsHeaders(req) {
|
|
20
20
|
const origin = req?.headers?.origin || '*';
|
|
21
|
+
const requestedHeaders = req?.headers?.['access-control-request-headers'] || '*';
|
|
21
22
|
return {
|
|
22
23
|
'Access-Control-Allow-Origin': origin,
|
|
23
|
-
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS, PUT, DELETE, HEAD',
|
|
24
|
-
'Access-Control-Allow-Headers':
|
|
24
|
+
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS, PUT, DELETE, HEAD, PATCH',
|
|
25
|
+
'Access-Control-Allow-Headers': requestedHeaders === '*' ? 'Content-Type, Authorization, Access-Control-Request-Private-Network, X-Requested-With, Accept, Origin, *' : requestedHeaders,
|
|
25
26
|
'Access-Control-Allow-Private-Network': 'true',
|
|
27
|
+
'Access-Control-Allow-Credentials': 'true',
|
|
26
28
|
'Access-Control-Max-Age': '86400',
|
|
29
|
+
'Vary': 'Origin, Access-Control-Request-Headers, Access-Control-Request-Private-Network',
|
|
27
30
|
'Content-Type': 'application/json'
|
|
28
31
|
};
|
|
29
32
|
}
|
|
@@ -83,25 +86,41 @@ const server = http.createServer(async (req, res) => {
|
|
|
83
86
|
return;
|
|
84
87
|
}
|
|
85
88
|
|
|
86
|
-
|
|
87
|
-
|
|
89
|
+
let pathname = '/';
|
|
90
|
+
let searchParams = new URLSearchParams();
|
|
91
|
+
try {
|
|
92
|
+
const parsedUrl = new URL(req.url, `http://${req.headers.host || '127.0.0.1:10420'}`);
|
|
93
|
+
pathname = parsedUrl.pathname.replace(/\/+$/, '') || '/';
|
|
94
|
+
searchParams = parsedUrl.searchParams;
|
|
95
|
+
} catch {
|
|
96
|
+
pathname = (req.url || '/').split('?')[0].replace(/\/+$/, '') || '/';
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// 2. Health & Root Info (fast ping endpoints)
|
|
100
|
+
if (req.method === 'GET' && (
|
|
101
|
+
pathname === '/' ||
|
|
102
|
+
pathname === '/health' ||
|
|
103
|
+
pathname === '/api/health' ||
|
|
104
|
+
pathname === '/ping' ||
|
|
105
|
+
pathname === '/api/ping'
|
|
106
|
+
)) {
|
|
88
107
|
res.writeHead(200, headers);
|
|
89
108
|
res.end(JSON.stringify({
|
|
90
109
|
status: 'healthy',
|
|
91
110
|
service: 'Yap2App-Localhost-Bridge',
|
|
92
|
-
version: '1.
|
|
111
|
+
version: '1.1.4',
|
|
93
112
|
port: PORT,
|
|
94
113
|
project_root: PROJECT_ROOT,
|
|
95
|
-
project_name: path.basename(PROJECT_ROOT)
|
|
114
|
+
project_name: path.basename(PROJECT_ROOT),
|
|
115
|
+
ready: true
|
|
96
116
|
}));
|
|
97
117
|
return;
|
|
98
118
|
}
|
|
99
119
|
|
|
100
120
|
// 3. GET /api/context (Shallow Codebase Scanner with Optional Prompt Query)
|
|
101
|
-
if (req.method === 'GET' &&
|
|
121
|
+
if (req.method === 'GET' && (pathname === '/api/context' || pathname === '/context')) {
|
|
102
122
|
try {
|
|
103
|
-
const
|
|
104
|
-
const promptQuery = parsedUrl.searchParams.get('q') || '';
|
|
123
|
+
const promptQuery = searchParams.get('q') || '';
|
|
105
124
|
console.log(`[Yap2App Bridge] 🔍 Scanning shallow codebase context in: ${PROJECT_ROOT}${promptQuery ? ` (ranking for query: "${promptQuery}")` : ''}`);
|
|
106
125
|
const context = await scanCodebase(PROJECT_ROOT, promptQuery);
|
|
107
126
|
res.writeHead(200, headers);
|
|
@@ -115,7 +134,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
115
134
|
}
|
|
116
135
|
|
|
117
136
|
// 4. POST /api/diff (Enterprise Diff & Safety Gate Review)
|
|
118
|
-
if (req.method === 'POST' &&
|
|
137
|
+
if (req.method === 'POST' && (pathname === '/api/diff' || pathname === '/diff')) {
|
|
119
138
|
let body = '';
|
|
120
139
|
req.on('data', chunk => body += chunk.toString());
|
|
121
140
|
req.on('end', async () => {
|
|
@@ -159,7 +178,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
159
178
|
}
|
|
160
179
|
|
|
161
180
|
// 5. POST /api/write (Approved Write to Disk)
|
|
162
|
-
if (req.method === 'POST' &&
|
|
181
|
+
if (req.method === 'POST' && (pathname === '/api/write' || pathname === '/write')) {
|
|
163
182
|
let body = '';
|
|
164
183
|
req.on('data', chunk => body += chunk.toString());
|
|
165
184
|
req.on('end', async () => {
|
|
@@ -199,11 +218,24 @@ const server = http.createServer(async (req, res) => {
|
|
|
199
218
|
|
|
200
219
|
// 404 Fallback
|
|
201
220
|
res.writeHead(404, headers);
|
|
202
|
-
res.end(JSON.stringify({ error: 'Endpoint Not Found' }));
|
|
221
|
+
res.end(JSON.stringify({ error: 'Endpoint Not Found', path: pathname }));
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
// Gracefully handle EADDRINUSE without crashing
|
|
225
|
+
server.on('error', (err) => {
|
|
226
|
+
if (err && err.code === 'EADDRINUSE') {
|
|
227
|
+
console.log(`\n===============================================================`);
|
|
228
|
+
console.log(`📡 Yap2App Localhost Bridge is ALREADY active on port ${PORT}!`);
|
|
229
|
+
console.log(`📁 Active Workspace: ${PROJECT_ROOT}`);
|
|
230
|
+
console.log(`🌐 Ready for 1-click sync from Yap2App Web Studio UI...`);
|
|
231
|
+
console.log(`===============================================================\n`);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
console.error('[Yap2App Bridge Error]:', err);
|
|
203
235
|
});
|
|
204
236
|
|
|
205
237
|
export function startBridge(port = PORT) {
|
|
206
|
-
server.listen(port, () => {
|
|
238
|
+
server.listen(port, '0.0.0.0', () => {
|
|
207
239
|
console.log(`\n===============================================================`);
|
|
208
240
|
console.log(`🚀 Yap2App Localhost Bridge & Shallow Scanner is ACTIVE!`);
|
|
209
241
|
console.log(`📡 Listening on: http://127.0.0.1:${port}`);
|
|
@@ -215,6 +247,8 @@ export function startBridge(port = PORT) {
|
|
|
215
247
|
}
|
|
216
248
|
|
|
217
249
|
// Direct execution
|
|
218
|
-
|
|
250
|
+
const isDirectRun = Boolean(typeof process !== 'undefined' && process.argv && process.argv[1] && (process.argv[1].endsWith('bridge.js') || process.argv[1].endsWith('bridge')));
|
|
251
|
+
if (isDirectRun) {
|
|
219
252
|
startBridge();
|
|
220
253
|
}
|
|
254
|
+
|
package/mcp.js
CHANGED
|
@@ -158,7 +158,8 @@ export async function runMcpServer() {
|
|
|
158
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')));
|
|
162
|
+
if (isDirectRun) {
|
|
162
163
|
runMcpServer().catch(err => {
|
|
163
164
|
console.error("MCP Server Error:", err);
|
|
164
165
|
process.exit(1);
|
package/package.json
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yap2app",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"type": "module",
|
|
3
|
+
"version": "1.1.4",
|
|
5
4
|
"description": "Autonomous Vibe-to-Prod Localhost Bridge & Model Context Protocol (MCP) Server",
|
|
6
5
|
"main": "bin/cli.bundle.js",
|
|
7
6
|
"bin": {
|
|
8
7
|
"yap2app": "./bin/cli.js"
|
|
9
8
|
},
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=10.0.0"
|
|
11
|
+
},
|
|
10
12
|
"files": [
|
|
11
13
|
"bin",
|
|
12
14
|
"bridge.js",
|
|
13
15
|
"mcp.js",
|
|
16
|
+
"polyfills.js",
|
|
14
17
|
"scanner.js",
|
|
15
18
|
"v2p.js",
|
|
16
19
|
"README.md"
|
package/polyfills.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Universal Node.js Polyfills & Warning Suppressors for Yap2App CLI
|
|
3
|
+
* Enables full backwards compatibility and clean startup across all NVM Node versions (Node 10.x to 23.x+)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// 0. Suppress noisy Node 18 experimental warnings and punycode deprecation warnings (DEP0040)
|
|
7
|
+
if (typeof process !== 'undefined' && process.emitWarning) {
|
|
8
|
+
var _originalEmitWarning = process.emitWarning;
|
|
9
|
+
process.emitWarning = function (warning) {
|
|
10
|
+
if (typeof warning === 'string') {
|
|
11
|
+
if (warning.includes('punycode') || warning.includes('ExperimentalWarning') || warning.includes('DEP0040')) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
} else if (warning && typeof warning === 'object') {
|
|
15
|
+
if (warning.code === 'DEP0040' || warning.name === 'ExperimentalWarning') {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (String(warning.message || '').includes('punycode')) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return _originalEmitWarning.apply(process, arguments);
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// 1. globalThis polyfill (Node <12)
|
|
27
|
+
if (typeof globalThis === 'undefined') {
|
|
28
|
+
if (typeof global !== 'undefined') {
|
|
29
|
+
global.globalThis = global;
|
|
30
|
+
} else if (typeof window !== 'undefined') {
|
|
31
|
+
window.globalThis = window;
|
|
32
|
+
} else if (typeof self !== 'undefined') {
|
|
33
|
+
self.globalThis = self;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 2. Object.fromEntries polyfill (Node <12.0)
|
|
38
|
+
if (typeof Object.fromEntries === 'undefined') {
|
|
39
|
+
Object.fromEntries = function (entries) {
|
|
40
|
+
if (!entries) return {};
|
|
41
|
+
var obj = {};
|
|
42
|
+
var arr = Array.isArray(entries) ? entries : Array.from(entries);
|
|
43
|
+
for (var i = 0; i < arr.length; i++) {
|
|
44
|
+
var pair = arr[i];
|
|
45
|
+
if (pair && pair.length >= 2) {
|
|
46
|
+
obj[pair[0]] = pair[1];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return obj;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// 3. Object.hasOwn polyfill (Node <16.9)
|
|
54
|
+
if (typeof Object.hasOwn === 'undefined') {
|
|
55
|
+
Object.hasOwn = function (obj, prop) {
|
|
56
|
+
return obj != null && Object.prototype.hasOwnProperty.call(obj, prop);
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 4. Array.prototype.flat polyfill (Node <11.0)
|
|
61
|
+
if (!Array.prototype.flat) {
|
|
62
|
+
Array.prototype.flat = function (depth) {
|
|
63
|
+
var flattend = [];
|
|
64
|
+
var d = typeof depth === 'number' ? depth : 1;
|
|
65
|
+
(function flat(array, currentDepth) {
|
|
66
|
+
for (var i = 0; i < array.length; i++) {
|
|
67
|
+
if (Array.isArray(array[i]) && currentDepth > 0) {
|
|
68
|
+
flat(array[i], currentDepth - 1);
|
|
69
|
+
} else {
|
|
70
|
+
flattend.push(array[i]);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
})(this, d);
|
|
74
|
+
return flattend;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// 5. String.prototype.replaceAll polyfill (Node <15.0)
|
|
79
|
+
if (!String.prototype.replaceAll) {
|
|
80
|
+
String.prototype.replaceAll = function (search, replacement) {
|
|
81
|
+
if (search instanceof RegExp) {
|
|
82
|
+
return this.replace(search, replacement);
|
|
83
|
+
}
|
|
84
|
+
return this.split(search).join(replacement);
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// 6. String.prototype.matchAll polyfill (Node <12.0)
|
|
89
|
+
if (!String.prototype.matchAll) {
|
|
90
|
+
String.prototype.matchAll = function (regexp) {
|
|
91
|
+
var flags = regexp.flags;
|
|
92
|
+
if (!flags.includes('g')) {
|
|
93
|
+
flags += 'g';
|
|
94
|
+
}
|
|
95
|
+
var rx = new RegExp(regexp.source, flags);
|
|
96
|
+
var str = String(this);
|
|
97
|
+
var matches = [];
|
|
98
|
+
var match;
|
|
99
|
+
while ((match = rx.exec(str)) !== null) {
|
|
100
|
+
matches.push(match);
|
|
101
|
+
if (match.index === rx.lastIndex) {
|
|
102
|
+
rx.lastIndex++;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return matches[Symbol.iterator] ? matches[Symbol.iterator]() : matches;
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 7. Promise.allSettled polyfill (Node <12.9)
|
|
110
|
+
if (!Promise.allSettled) {
|
|
111
|
+
Promise.allSettled = function (promises) {
|
|
112
|
+
return Promise.all(
|
|
113
|
+
Array.from(promises).map(function (p) {
|
|
114
|
+
return Promise.resolve(p).then(
|
|
115
|
+
function (value) {
|
|
116
|
+
return { status: 'fulfilled', value: value };
|
|
117
|
+
},
|
|
118
|
+
function (reason) {
|
|
119
|
+
return { status: 'rejected', reason: reason };
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
})
|
|
123
|
+
);
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|