@codemem/opencode-plugin 0.21.2 → 0.22.0-alpha.2
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/.opencode/lib/compat.js +9 -25
- package/.opencode/plugins/codemem.js +67 -0
- package/package.json +2 -2
package/.opencode/lib/compat.js
CHANGED
|
@@ -37,8 +37,8 @@ export const resolveUpgradeGuidance = ({ runner, runnerFrom }) => {
|
|
|
37
37
|
|
|
38
38
|
if (normalizedRunner === "uv") {
|
|
39
39
|
return {
|
|
40
|
-
mode: "
|
|
41
|
-
action: "In your codemem repo, pull latest changes and run `
|
|
40
|
+
mode: "repo-dev",
|
|
41
|
+
action: "In your codemem repo, pull latest changes and run `pnpm install` and `pnpm build`, then restart OpenCode.",
|
|
42
42
|
note: "detected dev repo mode",
|
|
43
43
|
};
|
|
44
44
|
}
|
|
@@ -60,7 +60,7 @@ export const resolveUpgradeGuidance = ({ runner, runnerFrom }) => {
|
|
|
60
60
|
|
|
61
61
|
return {
|
|
62
62
|
mode: "generic",
|
|
63
|
-
action: "
|
|
63
|
+
action: "Update codemem using your normal install method, then restart OpenCode.",
|
|
64
64
|
note: "fallback guidance",
|
|
65
65
|
};
|
|
66
66
|
};
|
|
@@ -138,34 +138,18 @@ export const resolveAutoUpdatePlan = ({ runner, runnerFrom }) => {
|
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
if (normalizedRunner === "uvx") {
|
|
141
|
-
if (!source) {
|
|
142
|
-
return {
|
|
143
|
-
allowed: false,
|
|
144
|
-
reason: "missing-source",
|
|
145
|
-
command: null,
|
|
146
|
-
commandText: null,
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
if (isPinnedGitSource(source)) {
|
|
150
|
-
return {
|
|
151
|
-
allowed: false,
|
|
152
|
-
reason: "pinned-source",
|
|
153
|
-
command: null,
|
|
154
|
-
commandText: null,
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
141
|
return {
|
|
158
|
-
allowed:
|
|
159
|
-
reason:
|
|
160
|
-
command:
|
|
161
|
-
commandText:
|
|
142
|
+
allowed: false,
|
|
143
|
+
reason: !source ? "missing-source" : isPinnedGitSource(source) ? "pinned-source" : "custom-source",
|
|
144
|
+
command: null,
|
|
145
|
+
commandText: null,
|
|
162
146
|
};
|
|
163
147
|
}
|
|
164
148
|
|
|
165
149
|
return {
|
|
166
150
|
allowed: true,
|
|
167
151
|
reason: null,
|
|
168
|
-
command: ["
|
|
169
|
-
commandText: "
|
|
152
|
+
command: ["npm", "install", "-g", "codemem@latest"],
|
|
153
|
+
commandText: "npm install -g codemem@latest",
|
|
170
154
|
};
|
|
171
155
|
};
|
|
@@ -621,6 +621,14 @@ export const OpencodeMemPlugin = async ({
|
|
|
621
621
|
let fallbackFailureNoted = false;
|
|
622
622
|
let lastStatusCheckAt = 0;
|
|
623
623
|
let lastStatusAvailable = true;
|
|
624
|
+
|
|
625
|
+
// Viewer health-check state
|
|
626
|
+
const HEALTH_CHECK_INTERVAL_MS = 60_000;
|
|
627
|
+
const HEALTH_CONSECUTIVE_FAILURES_BEFORE_RESTART = 3;
|
|
628
|
+
const HEALTH_RESTART_COOLDOWN_MS = 5 * 60_000;
|
|
629
|
+
let healthCheckTimer = null;
|
|
630
|
+
let healthConsecutiveFailures = 0;
|
|
631
|
+
let healthLastRestartAttempt = 0;
|
|
624
632
|
const nextEventId = () => {
|
|
625
633
|
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
626
634
|
return crypto.randomUUID();
|
|
@@ -1081,6 +1089,7 @@ export const OpencodeMemPlugin = async ({
|
|
|
1081
1089
|
} catch (err) {
|
|
1082
1090
|
logLine(`viewer spawn failed: ${err}`).catch(() => {});
|
|
1083
1091
|
}
|
|
1092
|
+
startHealthCheck();
|
|
1084
1093
|
};
|
|
1085
1094
|
|
|
1086
1095
|
const runCommand = async (cmd, options = {}) => {
|
|
@@ -1399,10 +1408,68 @@ export const OpencodeMemPlugin = async ({
|
|
|
1399
1408
|
return;
|
|
1400
1409
|
}
|
|
1401
1410
|
viewerStarted = false;
|
|
1411
|
+
stopHealthCheck();
|
|
1402
1412
|
await logLine("viewer stop requested");
|
|
1403
1413
|
await runCli(["serve", "stop"]);
|
|
1404
1414
|
};
|
|
1405
1415
|
|
|
1416
|
+
const checkViewerHealth = async () => {
|
|
1417
|
+
if (!viewerStarted || !viewerEnabled) return;
|
|
1418
|
+
try {
|
|
1419
|
+
const resp = await fetch(rawEventsStatusUrl, {
|
|
1420
|
+
method: "GET",
|
|
1421
|
+
signal: AbortSignal.timeout(5000),
|
|
1422
|
+
});
|
|
1423
|
+
if (resp.ok) {
|
|
1424
|
+
if (healthConsecutiveFailures > 0) {
|
|
1425
|
+
await logLine(`viewer.health recovered after ${healthConsecutiveFailures} failure(s)`);
|
|
1426
|
+
}
|
|
1427
|
+
healthConsecutiveFailures = 0;
|
|
1428
|
+
return;
|
|
1429
|
+
}
|
|
1430
|
+
healthConsecutiveFailures++;
|
|
1431
|
+
await logLine(`viewer.health check failed (status=${resp.status}, consecutive=${healthConsecutiveFailures})`);
|
|
1432
|
+
} catch (err) {
|
|
1433
|
+
healthConsecutiveFailures++;
|
|
1434
|
+
await logLine(`viewer.health check error (consecutive=${healthConsecutiveFailures}): ${String(err).slice(0, 200)}`);
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
if (
|
|
1438
|
+
healthConsecutiveFailures >= HEALTH_CONSECUTIVE_FAILURES_BEFORE_RESTART &&
|
|
1439
|
+
Date.now() - healthLastRestartAttempt >= HEALTH_RESTART_COOLDOWN_MS
|
|
1440
|
+
) {
|
|
1441
|
+
healthLastRestartAttempt = Date.now();
|
|
1442
|
+
await logLine(`viewer.health restarting viewer after ${healthConsecutiveFailures} consecutive failures`);
|
|
1443
|
+
try {
|
|
1444
|
+
const result = await runCli(["serve", "restart"]);
|
|
1445
|
+
const ok = result?.exitCode === 0;
|
|
1446
|
+
await logLine(`viewer.health restart ${ok ? "succeeded" : "failed"} (exit=${result?.exitCode ?? "unknown"})`);
|
|
1447
|
+
if (ok) {
|
|
1448
|
+
healthConsecutiveFailures = 0;
|
|
1449
|
+
}
|
|
1450
|
+
} catch (restartErr) {
|
|
1451
|
+
await logLine(`viewer.health restart error: ${String(restartErr).slice(0, 200)}`);
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
};
|
|
1455
|
+
|
|
1456
|
+
const startHealthCheck = () => {
|
|
1457
|
+
if (healthCheckTimer) return;
|
|
1458
|
+
healthConsecutiveFailures = 0;
|
|
1459
|
+
healthCheckTimer = setInterval(() => {
|
|
1460
|
+
checkViewerHealth().catch(() => {});
|
|
1461
|
+
}, HEALTH_CHECK_INTERVAL_MS);
|
|
1462
|
+
if (healthCheckTimer.unref) healthCheckTimer.unref();
|
|
1463
|
+
};
|
|
1464
|
+
|
|
1465
|
+
const stopHealthCheck = () => {
|
|
1466
|
+
if (healthCheckTimer) {
|
|
1467
|
+
clearInterval(healthCheckTimer);
|
|
1468
|
+
healthCheckTimer = null;
|
|
1469
|
+
}
|
|
1470
|
+
healthConsecutiveFailures = 0;
|
|
1471
|
+
};
|
|
1472
|
+
|
|
1406
1473
|
// Get version info (commit hash) for debugging
|
|
1407
1474
|
let version = "unknown";
|
|
1408
1475
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codemem/opencode-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0-alpha.2",
|
|
4
4
|
"description": "CodeMem plugin for OpenCode",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
".opencode/lib/"
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@opencode-ai/plugin": "1.3.
|
|
21
|
+
"@opencode-ai/plugin": "1.3.3"
|
|
22
22
|
},
|
|
23
23
|
"repository": {
|
|
24
24
|
"type": "git",
|