@jmylchreest/aide-plugin 0.0.58 → 0.0.60

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jmylchreest/aide-plugin",
3
- "version": "0.0.58",
3
+ "version": "0.0.60",
4
4
  "description": "aide plugin for OpenCode and Codex CLI — multi-agent orchestration, memory, skills, and persistence",
5
5
  "type": "module",
6
6
  "main": "./src/opencode/index.ts",
@@ -806,6 +806,13 @@ function updateJournalAndResolve(
806
806
  const now = new Date().toISOString();
807
807
  const activePaths = new Set(sources.map((s) => s.path));
808
808
 
809
+ // Capture servers already in the journal before we process state
810
+ // transitions. The bootstrap phase should only backfill absence for
811
+ // these pre-existing servers — not for servers discovered for the
812
+ // first time in this run — to avoid treating "never existed in
813
+ // another platform's config" as "intentionally removed".
814
+ const preExistingServers = new Set(Object.keys(journal.servers));
815
+
809
816
  // Detect state transitions per server per source
810
817
  for (const source of sources) {
811
818
  const currentNames = new Set(Object.keys(source.servers));
@@ -841,12 +848,14 @@ function updateJournalAndResolve(
841
848
  }
842
849
  }
843
850
 
844
- // Bootstrap: for servers found in some sources but absent from others,
845
- // record "not present" entries for the missing sources. Without this,
846
- // a server deleted from one file before the v2 journal existed would
847
- // have no removal event to counterbalance presence in other files.
848
- const allServerNames = new Set(Object.keys(journal.servers));
849
- for (const serverName of allServerNames) {
851
+ // Bootstrap: for servers that were already tracked in the journal
852
+ // before this run, record "not present" entries for sources that
853
+ // have never been tracked for that server. Without this, a server
854
+ // deleted from one file before the v2 journal existed would have
855
+ // no removal event to counterbalance presence in other files.
856
+ // We only bootstrap pre-existing servers to avoid treating "never
857
+ // existed in another platform's config" as an intentional removal.
858
+ for (const serverName of preExistingServers) {
850
859
  const sourceMap = journal.servers[serverName];
851
860
  for (const source of sources) {
852
861
  if (!sourceMap[source.path]) {
@@ -161,25 +161,44 @@ export function compareVersions(a: string, b: string): number {
161
161
  }
162
162
 
163
163
  /**
164
- * Get the download URL for the current platform
164
+ * Get the platform-specific binary name
165
165
  */
166
- export function getDownloadUrl(): string {
167
- const platform = process.platform; // 'darwin', 'linux', 'win32'
168
- const arch = process.arch; // 'x64', 'arm64'
169
-
166
+ export function getBinaryName(): string {
167
+ const platform = process.platform;
168
+ const arch = process.arch;
170
169
  const goos = platform === "win32" ? "windows" : platform;
171
170
  const goarch = arch === "x64" ? "amd64" : arch;
172
171
  const ext = platform === "win32" ? ".exe" : "";
172
+ return `aide-${goos}-${goarch}${ext}`;
173
+ }
173
174
 
174
- const binaryName = `aide-${goos}-${goarch}${ext}`;
175
-
175
+ /**
176
+ * Get download URLs for the current platform, in priority order.
177
+ * Returns the versioned URL first (exact match), then the latest release
178
+ * URL as a fallback. The fallback handles the race condition where the
179
+ * marketplace pulls the new plugin version before the release action
180
+ * has finished publishing binary artifacts.
181
+ */
182
+ export function getDownloadUrls(): string[] {
183
+ const binaryName = getBinaryName();
176
184
  const version = getPluginVersion();
185
+
177
186
  if (version) {
178
- return `https://github.com/jmylchreest/aide/releases/download/v${version}/${binaryName}`;
187
+ return [
188
+ `https://github.com/jmylchreest/aide/releases/download/v${version}/${binaryName}`,
189
+ `https://github.com/jmylchreest/aide/releases/latest/download/${binaryName}`,
190
+ ];
179
191
  }
180
192
 
181
- // Fallback to latest if version can't be determined
182
- return `https://github.com/jmylchreest/aide/releases/latest/download/${binaryName}`;
193
+ return [`https://github.com/jmylchreest/aide/releases/latest/download/${binaryName}`];
194
+ }
195
+
196
+ /**
197
+ * Get the download URL for the current platform (first priority URL).
198
+ * @deprecated Use getDownloadUrls() for fallback support.
199
+ */
200
+ export function getDownloadUrl(): string {
201
+ return getDownloadUrls()[0];
183
202
  }
184
203
 
185
204
  /**
@@ -250,11 +269,7 @@ export async function downloadAideBinary(
250
269
  }
251
270
  }
252
271
 
253
- const url = getDownloadUrl();
254
-
255
- if (!quiet) {
256
- log(`[aide] Downloading from: ${url}`);
257
- }
272
+ const urls = getDownloadUrls();
258
273
 
259
274
  try {
260
275
  // Create bin directory
@@ -262,13 +277,35 @@ export async function downloadAideBinary(
262
277
  mkdirSync(destDir, { recursive: true });
263
278
  }
264
279
 
265
- // Download using native fetch (follows redirects by default)
266
- const response = await fetch(url, {
267
- headers: { "User-Agent": "aide-plugin" },
268
- });
280
+ // Try each URL in priority order, falling back on 404/network errors.
281
+ // This handles the race where the marketplace pulls a new plugin version
282
+ // before the release action has finished publishing binaries.
283
+ let response: Response | null = null;
284
+ let usedUrl = urls[0];
269
285
 
270
- if (!response.ok) {
271
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
286
+ for (const url of urls) {
287
+ if (!quiet) {
288
+ log(`[aide] Downloading from: ${url}`);
289
+ }
290
+ const resp = await fetch(url, {
291
+ headers: { "User-Agent": "aide-plugin" },
292
+ });
293
+ if (resp.ok) {
294
+ response = resp;
295
+ usedUrl = url;
296
+ break;
297
+ }
298
+ if (resp.status === 404 && url !== urls[urls.length - 1]) {
299
+ if (!quiet) {
300
+ log(`[aide] Release not found (HTTP 404), trying fallback...`);
301
+ }
302
+ continue;
303
+ }
304
+ throw new Error(`HTTP ${resp.status}: ${resp.statusText}`);
305
+ }
306
+
307
+ if (!response || !response.ok) {
308
+ throw new Error("All download URLs failed");
272
309
  }
273
310
 
274
311
  if (!response.body) {