@patcherly/nodejs-connector 2.2.10 → 2.2.11
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/node_agent.js +57 -11
- package/package.json +1 -1
package/node_agent.js
CHANGED
|
@@ -193,7 +193,7 @@ const { DEFAULT_API_URL, getConfiguredServerUrl, isExplicitApiBaseConfigured } =
|
|
|
193
193
|
* update-release-latest.yml workflow so the value baked into every released tarball matches
|
|
194
194
|
* the GitHub release tag. Reported to the API on every context upload.
|
|
195
195
|
*/
|
|
196
|
-
const PATCHERLY_CONNECTOR_VERSION = '2.2.
|
|
196
|
+
const PATCHERLY_CONNECTOR_VERSION = '2.2.11';
|
|
197
197
|
let CENTRAL_SERVER_URL = getConfiguredServerUrl();
|
|
198
198
|
const IDS_PATH = process.env.PATCHERLY_IDS_PATH || path.join(__dirname, 'patcherly_ids.json');
|
|
199
199
|
const QUEUE_PATH = process.env.PATCHERLY_QUEUE_PATH || path.join(__dirname, 'patcherly_queue.jsonl');
|
|
@@ -1250,6 +1250,47 @@ async function maybeRunPostApply(errorId, fixJson) {
|
|
|
1250
1250
|
return telemetry;
|
|
1251
1251
|
}
|
|
1252
1252
|
|
|
1253
|
+
/**
|
|
1254
|
+
* Start durable analysis (analyze-async) and wait for a terminal outcome via
|
|
1255
|
+
* analysis-wait long-polls. The central API owns retries; this helper sleeps
|
|
1256
|
+
* locally on retry_after_seconds between polls — no tight API spam.
|
|
1257
|
+
*/
|
|
1258
|
+
async function analyzeAndWait(errorId) {
|
|
1259
|
+
const maxWallMs = 8 * 60 * 60 * 1000;
|
|
1260
|
+
const started = Date.now();
|
|
1261
|
+
const startPath = appPath('errors', String(errorId), 'analyze-async');
|
|
1262
|
+
const startHeaders = await signRequest('POST', startPath, '', { 'Content-Type': 'application/json' });
|
|
1263
|
+
const startEndpoint = buildApiEndpoint(startPath);
|
|
1264
|
+
const startResp = await fetch(startEndpoint, { method: 'POST', headers: startHeaders, body: '{}' });
|
|
1265
|
+
if (handleProtectionModeHttp(startResp.status, await startResp.clone().text())) {
|
|
1266
|
+
return { terminal: false, status: 'protection_mode', error_id: errorId };
|
|
1267
|
+
}
|
|
1268
|
+
if (!startResp.ok) {
|
|
1269
|
+
throw new Error(`analyze-async failed: ${startResp.status}`);
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
const waitBasePath = appPath('errors', String(errorId), 'analysis-wait');
|
|
1273
|
+
const waitSignPath = `${waitBasePath}?timeout=120`;
|
|
1274
|
+
while (Date.now() - started < maxWallMs) {
|
|
1275
|
+
const waitEndpoint = `${buildApiEndpoint(waitBasePath)}?timeout=120`;
|
|
1276
|
+
const waitHeaders = await signRequest('GET', waitSignPath, '', {});
|
|
1277
|
+
const waitResp = await fetch(waitEndpoint, { method: 'GET', headers: waitHeaders });
|
|
1278
|
+
if (handleProtectionModeHttp(waitResp.status, await waitResp.clone().text())) {
|
|
1279
|
+
return { terminal: false, status: 'protection_mode', error_id: errorId };
|
|
1280
|
+
}
|
|
1281
|
+
if (!waitResp.ok) {
|
|
1282
|
+
throw new Error(`analysis-wait failed: ${waitResp.status}`);
|
|
1283
|
+
}
|
|
1284
|
+
const data = await waitResp.json();
|
|
1285
|
+
if (data.terminal) {
|
|
1286
|
+
return data;
|
|
1287
|
+
}
|
|
1288
|
+
const sleepSec = Math.max(5, Number(data.retry_after_seconds) || 30);
|
|
1289
|
+
await new Promise((resolve) => setTimeout(resolve, sleepSec * 1000));
|
|
1290
|
+
}
|
|
1291
|
+
throw new Error(`analysis-wait exceeded 8h wall clock for error ${errorId}`);
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1253
1294
|
async function processError(errorContext) {
|
|
1254
1295
|
console.log('Processing error with context:', errorContext);
|
|
1255
1296
|
try {
|
|
@@ -1265,9 +1306,12 @@ async function processError(errorContext) {
|
|
|
1265
1306
|
// Update exclude_paths if cache is stale
|
|
1266
1307
|
await updateExcludePaths();
|
|
1267
1308
|
|
|
1268
|
-
// PRIMARY FILTERING:
|
|
1309
|
+
// PRIMARY FILTERING: require extractable source path; skip excluded paths
|
|
1269
1310
|
const filePath = extractFilePath(errorContext);
|
|
1270
|
-
if (filePath
|
|
1311
|
+
if (!filePath) {
|
|
1312
|
+
return; // Not ingestable — no file to back up or patch
|
|
1313
|
+
}
|
|
1314
|
+
if (isPathExcluded(filePath)) {
|
|
1271
1315
|
console.log(`Error from excluded path skipped: ${filePath}`);
|
|
1272
1316
|
return; // Skip ingestion entirely - don't send to server
|
|
1273
1317
|
}
|
|
@@ -1313,18 +1357,20 @@ async function processError(errorContext) {
|
|
|
1313
1357
|
const autoApply = item.auto_apply === true;
|
|
1314
1358
|
const ingestedStatus = item.status || 'pending';
|
|
1315
1359
|
|
|
1316
|
-
if (!autoAnalyze || ['ignored', 'excluded', 'dismissed'].includes(ingestedStatus)) {
|
|
1360
|
+
if (!autoAnalyze || ['ignored', 'excluded', 'dismissed', 'analysis_failed'].includes(ingestedStatus)) {
|
|
1317
1361
|
console.log(`Auto-analysis not enabled or error skipped (status=${ingestedStatus}); stopping after ingest.`);
|
|
1318
1362
|
return;
|
|
1319
1363
|
}
|
|
1320
1364
|
|
|
1321
|
-
// analyze (always runs when autoAnalyze is true)
|
|
1322
|
-
const
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
if (
|
|
1365
|
+
// analyze (always runs when autoAnalyze is true) — central retry via analyze-async + analysis-wait
|
|
1366
|
+
const analyzeOutcome = await analyzeAndWait(errorId);
|
|
1367
|
+
if (analyzeOutcome.status === 'analysis_failed') {
|
|
1368
|
+
console.warn('Analysis permanently failed after automatic retries; stopping auto-pipeline.');
|
|
1369
|
+
return;
|
|
1370
|
+
}
|
|
1371
|
+
if (analyzeOutcome.status === 'protection_mode') {
|
|
1372
|
+
return;
|
|
1373
|
+
}
|
|
1328
1374
|
|
|
1329
1375
|
// v1.49: only chain into approve+apply when autoApply is also true. Otherwise the
|
|
1330
1376
|
// human approves & applies the analyzed fix from the dashboard.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patcherly/nodejs-connector",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.11",
|
|
4
4
|
"description": "Patcherly detects bugs in real time in your app. It creates a customized AI patch, and once you approve it, backs up your code, fixes it & tests the patch for you. If anything is off, it rolls back the changes automatically, or you can always roll it back in a click. Website: https://patcherly.com · Docs: https://help.patcherly.com/connectors/nodejs/",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://patcherly.com",
|