opencode-mem 2.8.2 → 2.8.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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AAkB/D,eAAO,MAAM,iBAAiB,EAAE,MA+Z/B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AAkB/D,eAAO,MAAM,iBAAiB,EAAE,MA8a/B,CAAC"}
package/dist/index.js CHANGED
@@ -36,6 +36,20 @@ export const OpenCodeMemPlugin = async (ctx) => {
36
36
  .then((server) => {
37
37
  webServer = server;
38
38
  const url = webServer.getUrl();
39
+ webServer.setOnTakeoverCallback(async () => {
40
+ if (ctx.client?.tui) {
41
+ ctx.client.tui
42
+ .showToast({
43
+ body: {
44
+ title: "Memory Explorer",
45
+ message: "Took over web server ownership",
46
+ variant: "success",
47
+ duration: 3000,
48
+ },
49
+ })
50
+ .catch(() => { });
51
+ }
52
+ });
39
53
  if (webServer.isServerOwner()) {
40
54
  if (ctx.client?.tui) {
41
55
  ctx.client.tui
@@ -8,9 +8,15 @@ export declare class WebServer {
8
8
  private config;
9
9
  private isOwner;
10
10
  private startPromise;
11
+ private healthCheckInterval;
12
+ private onTakeoverCallback;
11
13
  constructor(config: WebServerConfig);
14
+ setOnTakeoverCallback(callback: () => Promise<void>): void;
12
15
  start(): Promise<void>;
13
16
  private _start;
17
+ private startHealthCheckLoop;
18
+ private stopHealthCheckLoop;
19
+ private attemptTakeover;
14
20
  stop(): Promise<void>;
15
21
  isRunning(): boolean;
16
22
  isServerOwner(): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"web-server.d.ts","sourceRoot":"","sources":["../../src/services/web-server.ts"],"names":[],"mappings":"AAOA,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAeD,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,YAAY,CAA8B;gBAEtC,MAAM,EAAE,eAAe;IAI7B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YASd,MAAM;IAyEd,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAiC3B,SAAS,IAAI,OAAO;IAIpB,aAAa,IAAI,OAAO;IAIxB,MAAM,IAAI,MAAM;IAIV,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC;CAW/C;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC,CAIhF"}
1
+ {"version":3,"file":"web-server.d.ts","sourceRoot":"","sources":["../../src/services/web-server.ts"],"names":[],"mappings":"AAOA,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAeD,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,YAAY,CAA8B;IAClD,OAAO,CAAC,mBAAmB,CAA+B;IAC1D,OAAO,CAAC,kBAAkB,CAAsC;gBAEpD,MAAM,EAAE,eAAe;IAInC,qBAAqB,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAIpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YASd,MAAM;IAiFpB,OAAO,CAAC,oBAAoB;IAe5B,OAAO,CAAC,mBAAmB;YAOb,eAAe;IA2BvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAmC3B,SAAS,IAAI,OAAO;IAIpB,aAAa,IAAI,OAAO;IAIxB,MAAM,IAAI,MAAM;IAIV,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC;CAW/C;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC,CAIhF"}
@@ -8,9 +8,14 @@ export class WebServer {
8
8
  config;
9
9
  isOwner = false;
10
10
  startPromise = null;
11
+ healthCheckInterval = null;
12
+ onTakeoverCallback = null;
11
13
  constructor(config) {
12
14
  this.config = config;
13
15
  }
16
+ setOnTakeoverCallback(callback) {
17
+ this.onTakeoverCallback = callback;
18
+ }
14
19
  async start() {
15
20
  if (this.startPromise) {
16
21
  return this.startPromise;
@@ -38,7 +43,9 @@ export class WebServer {
38
43
  }
39
44
  else if (response.type === "error") {
40
45
  const errorMsg = response.error || "Unknown error";
41
- if (errorMsg.includes("EADDRINUSE") || errorMsg.includes("address already in use")) {
46
+ if (errorMsg.includes("EADDRINUSE") ||
47
+ errorMsg.includes("address already in use") ||
48
+ /^Error: Failed to start server\. Is port \d+ in use\?$/.test(errorMsg)) {
42
49
  this.isOwner = false;
43
50
  resolve();
44
51
  }
@@ -73,6 +80,9 @@ export class WebServer {
73
80
  host: this.config.host,
74
81
  });
75
82
  await startedPromise;
83
+ if (!this.isOwner) {
84
+ this.startHealthCheckLoop();
85
+ }
76
86
  }
77
87
  catch (error) {
78
88
  this.isOwner = false;
@@ -84,7 +94,51 @@ export class WebServer {
84
94
  throw error;
85
95
  }
86
96
  }
97
+ startHealthCheckLoop() {
98
+ if (this.healthCheckInterval) {
99
+ return;
100
+ }
101
+ this.healthCheckInterval = setInterval(async () => {
102
+ const isAvailable = await this.checkServerAvailable();
103
+ if (!isAvailable) {
104
+ this.stopHealthCheckLoop();
105
+ await this.attemptTakeover();
106
+ }
107
+ }, 5000);
108
+ }
109
+ stopHealthCheckLoop() {
110
+ if (this.healthCheckInterval) {
111
+ clearInterval(this.healthCheckInterval);
112
+ this.healthCheckInterval = null;
113
+ }
114
+ }
115
+ async attemptTakeover() {
116
+ // prevent thundering herd: multiple non-owners racing to bind port
117
+ const jitterMs = 500 + Math.random() * 1000;
118
+ await new Promise((resolve) => setTimeout(resolve, jitterMs));
119
+ if (await this.checkServerAvailable()) {
120
+ this.startHealthCheckLoop();
121
+ return;
122
+ }
123
+ try {
124
+ await this._start();
125
+ this.isOwner = true;
126
+ log("Web server takeover successful", { port: this.config.port });
127
+ if (this.onTakeoverCallback) {
128
+ try {
129
+ await this.onTakeoverCallback();
130
+ }
131
+ catch (error) {
132
+ log("Takeover callback error", { error: String(error) });
133
+ }
134
+ }
135
+ }
136
+ catch (error) {
137
+ this.startHealthCheckLoop();
138
+ }
139
+ }
87
140
  async stop() {
141
+ this.stopHealthCheckLoop();
88
142
  if (!this.isOwner || !this.worker) {
89
143
  return;
90
144
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-mem",
3
- "version": "2.8.2",
3
+ "version": "2.8.4",
4
4
  "description": "OpenCode plugin that gives coding agents persistent memory using local vector database",
5
5
  "type": "module",
6
6
  "main": "dist/plugin.js",