Quellcode durchsuchen

fix: read Codex plugin version from manifest (PRI-2240)

Drew Ritter vor 2 Monaten
Ursprung
Commit
29c0b1b7db
2 geänderte Dateien mit 59 neuen und 16 gelöschten Zeilen
  1. 15 7
      skills/brainstorming/scripts/server.cjs
  2. 44 9
      tests/brainstorm-server/branding.test.js

+ 15 - 7
skills/brainstorming/scripts/server.cjs

@@ -206,14 +206,22 @@ const helperInjection = '<script>\n' + helperScript + '\n</script>';
 // ========== Helper Functions ==========
 
 function readSuperpowersVersion() {
-  try {
-    const packageJson = JSON.parse(
-      fs.readFileSync(path.join(__dirname, '../../..', 'package.json'), 'utf-8')
-    );
-    return String(packageJson.version || 'unknown');
-  } catch (e) {
-    return 'unknown';
+  const root = path.join(__dirname, '../../..');
+  const manifests = [
+    path.join(root, 'package.json'),
+    path.join(root, '.codex-plugin/plugin.json')
+  ];
+
+  for (const manifest of manifests) {
+    try {
+      const data = JSON.parse(fs.readFileSync(manifest, 'utf-8'));
+      if (data.version) return String(data.version);
+    } catch (e) {
+      // Packaged Codex plugins omit package.json; try the next manifest.
+    }
   }
+
+  return 'unknown';
 }
 
 function isTruthyEnv(value) {

+ 44 - 9
tests/brainstorm-server/branding.test.js

@@ -26,9 +26,9 @@ function sleep(ms) {
   return new Promise(resolve => setTimeout(resolve, ms));
 }
 
-function startServer({ port, dir, env = {} }) {
+function startServer({ port, dir, env = {}, serverPath = SERVER_PATH }) {
   cleanup(dir);
-  return spawn('node', [SERVER_PATH], {
+  return spawn('node', [serverPath], {
     env: {
       ...process.env,
       BRAINSTORM_PORT: String(port),
@@ -74,6 +74,21 @@ function writeFragment(dir) {
   fs.writeFileSync(path.join(contentDir, 'screen.html'), '<h2>Pick a layout</h2>');
 }
 
+function createPackagedServerFixture(version) {
+  const root = fs.mkdtempSync(path.join('/tmp', 'superpowers-packaged-server-'));
+  const scriptDir = path.join(root, 'skills/brainstorming/scripts');
+  fs.cpSync(path.join(REPO_ROOT, 'skills/brainstorming/scripts'), scriptDir, { recursive: true });
+  fs.mkdirSync(path.join(root, '.codex-plugin'), { recursive: true });
+  fs.writeFileSync(
+    path.join(root, '.codex-plugin/plugin.json'),
+    JSON.stringify({ name: 'superpowers', version }, null, 2)
+  );
+  return {
+    root,
+    serverPath: path.join(scriptDir, 'server.cjs')
+  };
+}
+
 async function withServer(options, fn) {
   const server = startServer(options);
   try {
@@ -104,13 +119,13 @@ async function test(name, fn) {
   }
 }
 
-function assertBrandedWithLogo(html) {
+function assertBrandedWithLogo(html, version = PACKAGE_VERSION) {
   assert(
-    html.includes(`Superpowers v${PACKAGE_VERSION}`),
+    html.includes(`Superpowers v${version}`),
     'branding text should include dynamic package version'
   );
   assert(
-    !html.includes(`Superpowers v${PACKAGE_VERSION} by`),
+    !html.includes(`Superpowers v${version} by`),
     'branding text should not include "by" when the logo is visible'
   );
   assert(
@@ -139,15 +154,15 @@ function assertBrandedWithLogo(html) {
   );
 }
 
-function assertBrandedFallbackText(html) {
+function assertBrandedFallbackText(html, version = PACKAGE_VERSION) {
   assert(
-    html.includes(`Prime Radiant Superpowers v${PACKAGE_VERSION}`),
+    html.includes(`Prime Radiant Superpowers v${version}`),
     'disabled telemetry should keep plain text Prime Radiant/Superpowers branding'
   );
 }
 
-function assertTelemetryImage(html) {
-  const expectedUrl = `${ASSET_URL}?v=${encodeURIComponent(PACKAGE_VERSION)}`;
+function assertTelemetryImage(html, version = PACKAGE_VERSION) {
+  const expectedUrl = `${ASSET_URL}?v=${encodeURIComponent(version)}`;
   assert(html.includes(`src="${expectedUrl}"`), 'remote image should use the dedicated main-domain asset with only v=');
   assert(!html.includes('event='), 'remote image URL must not include event=');
   assert(!html.includes('surface='), 'remote image URL must not include surface=');
@@ -255,6 +270,26 @@ async function main() {
     });
   });
 
+  await test('packaged Codex plugin reads version from .codex-plugin manifest', async () => {
+    const port = 3457;
+    const dir = '/tmp/brainstorm-branding-packaged-codex';
+    const packagedVersion = '7.8.9';
+    const fixture = createPackagedServerFixture(packagedVersion);
+
+    try {
+      await withServer({ port, dir, serverPath: fixture.serverPath }, async () => {
+        writeFragment(dir);
+        await sleep(300);
+        const html = await fetchHtml(port);
+        assertBrandedWithLogo(html, packagedVersion);
+        assertTelemetryImage(html, packagedVersion);
+        assert(!html.includes('Superpowers vunknown'), 'packaged plugin should not fall back to unknown version');
+      });
+    } finally {
+      cleanup(fixture.root);
+    }
+  });
+
   await test('SUPERPOWERS_DISABLE_TELEMETRY=true omits remote image but keeps local branding', async () => {
     const port = 3453;
     const dir = '/tmp/brainstorm-branding-disabled';