@ulthon/ul-opencode-event 0.1.20 → 0.1.22

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/dist/updater.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Auto-update module for @ulthon/ul-opencode-event.
3
3
  *
4
- * Checks npm registry for new versions, manages a 24h cache,
4
+ * Checks npm registry for new versions, manages a 1h cache,
5
5
  * and optionally runs `bun install` to auto-update.
6
6
  *
7
7
  * Zero runtime dependencies — only Node.js built-ins + project logger.
@@ -22,6 +22,22 @@ export declare function getCachedCheck(): {
22
22
  } | null;
23
23
  export declare function setCachedCheck(latestVersion: string): void;
24
24
  export declare function isCacheValid(): boolean;
25
+ interface PluginInfo {
26
+ entry: string;
27
+ isPinned: boolean;
28
+ pinnedVersion: string | null;
29
+ }
30
+ /**
31
+ * Sync the workspace package.json to match the intended version from config.
32
+ * Updates cacheDir/packages/@ulthon/ul-opencode-event@latest/package.json
33
+ * with the version intent (latest or pinned).
34
+ * Uses atomic write (write to temp + rename) to prevent corruption.
35
+ */
36
+ export declare function syncCachePackageJsonToIntent(pluginInfo: PluginInfo): {
37
+ synced: boolean;
38
+ error: string | null;
39
+ message?: string;
40
+ };
25
41
  /**
26
42
  * Execute `bun install` in the given workspace directory.
27
43
  * Uses Bun.spawn if available, otherwise falls back to child_process.spawn.
@@ -36,3 +52,4 @@ export declare function runBunInstall(workspaceDir: string): Promise<boolean>;
36
52
  * 5. Notify or auto-update
37
53
  */
38
54
  export declare function runAutoUpdate(ctx: any, autoUpdate: boolean): Promise<void>;
55
+ export {};
package/dist/updater.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Auto-update module for @ulthon/ul-opencode-event.
3
3
  *
4
- * Checks npm registry for new versions, manages a 24h cache,
4
+ * Checks npm registry for new versions, manages a 1h cache,
5
5
  * and optionally runs `bun install` to auto-update.
6
6
  *
7
7
  * Zero runtime dependencies — only Node.js built-ins + project logger.
@@ -9,6 +9,7 @@
9
9
  import * as fs from 'fs';
10
10
  import * as path from 'path';
11
11
  import * as os from 'os';
12
+ import * as crypto from 'crypto';
12
13
  import { fileURLToPath } from 'url';
13
14
  import { logger } from './logger.js';
14
15
  // ---------------------------------------------------------------------------
@@ -18,12 +19,12 @@ const PACKAGE_NAME = '@ulthon/ul-opencode-event';
18
19
  const NPM_REGISTRY_URL = `https://registry.npmjs.org/-/package/${encodeURIComponent(PACKAGE_NAME)}/dist-tags`;
19
20
  const NPM_FETCH_TIMEOUT = 5000; // 5 seconds
20
21
  const BUN_INSTALL_TIMEOUT = 60000; // 60 seconds
21
- const CACHE_TTL = 24 * 60 * 60 * 1000; // 24 hours in ms
22
+ const CACHE_TTL = 60 * 60 * 1000; // 1 hour in ms
22
23
  // ---------------------------------------------------------------------------
23
24
  // Helpers: cache paths
24
25
  // ---------------------------------------------------------------------------
25
26
  function getCacheDir() {
26
- return process.env.OPENCODE_DATA_DIR ?? path.join(os.homedir(), '.local', 'share', 'opencode');
27
+ return process.env.OPENCODE_DATA_DIR ?? path.join(os.homedir(), '.cache', 'opencode');
27
28
  }
28
29
  function getCacheFilePath() {
29
30
  return path.join(getCacheDir(), 'ul-opencode-event-update-cache.json');
@@ -176,8 +177,10 @@ function isPinnedVersion(directory) {
176
177
  // ---------------------------------------------------------------------------
177
178
  function invalidatePackage() {
178
179
  try {
180
+ const scopedFlatDir = path.join(getCacheDir(), 'packages', `${PACKAGE_NAME}@latest`);
179
181
  const dirs = [
180
182
  path.join(getCacheDir(), 'packages', 'node_modules', PACKAGE_NAME),
183
+ path.join(scopedFlatDir, 'node_modules', PACKAGE_NAME),
181
184
  path.join(getUserConfigDir(), 'node_modules', PACKAGE_NAME),
182
185
  ];
183
186
  for (const pkgDir of dirs) {
@@ -191,6 +194,16 @@ function invalidatePackage() {
191
194
  logger.debug(`[updater] Could not remove ${pkgDir}: ${err}`);
192
195
  }
193
196
  }
197
+ // Also remove the scoped flat install directory contents if present
198
+ try {
199
+ if (fs.existsSync(scopedFlatDir)) {
200
+ fs.rmSync(scopedFlatDir, { recursive: true, force: true });
201
+ logger.info(`[updater] Removed scoped flat directory ${scopedFlatDir}`);
202
+ }
203
+ }
204
+ catch (err) {
205
+ logger.debug(`[updater] Could not remove ${scopedFlatDir}: ${err}`);
206
+ }
194
207
  // Also remove bun.lock / bun.lockb from workspace dirs
195
208
  const workspaceDirs = [
196
209
  path.join(getCacheDir(), 'packages'),
@@ -215,26 +228,62 @@ function invalidatePackage() {
215
228
  logger.error(`[updater] Package invalidation failed: ${err}`);
216
229
  }
217
230
  }
231
+ /**
232
+ * Sync the workspace package.json to match the intended version from config.
233
+ * Updates cacheDir/packages/@ulthon/ul-opencode-event@latest/package.json
234
+ * with the version intent (latest or pinned).
235
+ * Uses atomic write (write to temp + rename) to prevent corruption.
236
+ */
237
+ export function syncCachePackageJsonToIntent(pluginInfo) {
238
+ const intentVersion = pluginInfo.isPinned && pluginInfo.pinnedVersion ? pluginInfo.pinnedVersion : 'latest';
239
+ const scopedDir = path.join(getCacheDir(), 'packages', `${PACKAGE_NAME}@latest`);
240
+ const pkgJsonPath = path.join(scopedDir, 'package.json');
241
+ try {
242
+ // Ensure directory exists
243
+ fs.mkdirSync(scopedDir, { recursive: true });
244
+ let pkgJson = {};
245
+ if (fs.existsSync(pkgJsonPath)) {
246
+ const content = fs.readFileSync(pkgJsonPath, 'utf-8');
247
+ pkgJson = JSON.parse(content);
248
+ if (pkgJson.dependencies?.[PACKAGE_NAME] === intentVersion) {
249
+ return { synced: false, error: null, message: `Already matches intent: ${intentVersion}` };
250
+ }
251
+ }
252
+ pkgJson.dependencies = { ...pkgJson.dependencies, [PACKAGE_NAME]: intentVersion };
253
+ // Atomic write: temp file + rename
254
+ const tmpPath = `${pkgJsonPath}.${crypto.randomUUID()}`;
255
+ fs.writeFileSync(tmpPath, JSON.stringify(pkgJson, null, 2));
256
+ fs.renameSync(tmpPath, pkgJsonPath);
257
+ return { synced: true, error: null, message: `Updated to ${intentVersion}` };
258
+ }
259
+ catch (err) {
260
+ return { synced: false, error: String(err) };
261
+ }
262
+ }
218
263
  // ---------------------------------------------------------------------------
219
264
  // Helper: resolve workspace directory
220
265
  // ---------------------------------------------------------------------------
221
266
  function resolveWorkspaceDir() {
222
267
  const configDir = getUserConfigDir();
223
268
  const packagesDir = path.join(getCacheDir(), 'packages');
224
- // Check if installed in config dir
269
+ // 1. Config dir node_modules
225
270
  const configPkg = path.join(configDir, 'node_modules', PACKAGE_NAME, 'package.json');
226
271
  if (fs.existsSync(configPkg))
227
272
  return configDir;
228
- // Check packages dir (node_modules style)
273
+ // 2. Cache packages node_modules (traditional)
229
274
  const packagesPkg = path.join(packagesDir, 'node_modules', PACKAGE_NAME, 'package.json');
230
275
  if (fs.existsSync(packagesPkg))
231
276
  return packagesDir;
232
- // Check packages dir (flat)
277
+ // 3. Cache packages flat (package.json in root)
233
278
  const flatPkg = path.join(packagesDir, 'package.json');
234
279
  if (fs.existsSync(flatPkg))
235
280
  return packagesDir;
236
- // Default to config dir
237
- return configDir;
281
+ // 4. Cache packages scoped flat (@ulthon/ul-opencode-event@latest/package.json)
282
+ const scopedPkg = path.join(packagesDir, `${PACKAGE_NAME}@latest`, 'package.json');
283
+ if (fs.existsSync(scopedPkg))
284
+ return path.join(packagesDir, `${PACKAGE_NAME}@latest`);
285
+ // Default to packages dir (let bun install create what it needs)
286
+ return packagesDir;
238
287
  }
239
288
  // ---------------------------------------------------------------------------
240
289
  // Exported: bun install
@@ -366,8 +415,24 @@ export async function runAutoUpdate(ctx, autoUpdate) {
366
415
  await showToast(ctx, `ul-opencode-event ${latestVersion}`, `Update available: v${currentVersion} -> v${latestVersion}\nRun: npm update @ulthon/ul-opencode-event`, 'info', 8000);
367
416
  return;
368
417
  }
369
- // 7. Auto-update: invalidate + bun install
418
+ // 7. Auto-update: sync -> invalidate -> resolve workspace -> bun install
419
+ // First, find plugin info for sync
420
+ const plugins = readPluginList(ctx.directory);
421
+ const pluginEntry = plugins.find((e) => e.includes('ul-opencode-event')) ?? PACKAGE_NAME;
422
+ const atIndex = pluginEntry.lastIndexOf('@');
423
+ const pinnedVersion = atIndex > 0 ? pluginEntry.slice(atIndex + 1) : null;
424
+ const isPinned = pinnedVersion !== null && EXACT_SEMVER_RE.test(pinnedVersion);
425
+ const pluginInfo = { entry: pluginEntry, isPinned, pinnedVersion: isPinned ? pinnedVersion : null };
426
+ // Sync workspace package.json to intent
427
+ const syncResult = syncCachePackageJsonToIntent(pluginInfo);
428
+ if (syncResult.error) {
429
+ logger.warn(`[updater] Sync failed: ${syncResult.error}, continuing with notification only`);
430
+ await showToast(ctx, `ul-opencode-event ${latestVersion}`, `Update available: v${currentVersion} -> v${latestVersion}\nSync failed, try manual update.`, 'info', 8000);
431
+ return;
432
+ }
433
+ // Invalidate old package
370
434
  invalidatePackage();
435
+ // Resolve workspace and install
371
436
  const workspaceDir = resolveWorkspaceDir();
372
437
  const success = await runBunInstall(workspaceDir);
373
438
  if (success) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ulthon/ul-opencode-event",
3
- "version": "0.1.20",
3
+ "version": "0.1.22",
4
4
  "description": "OpenCode notification plugin - sends notifications via email or DingTalk when session events occur",
5
5
  "author": "augushong",
6
6
  "license": "MIT",