diff --git a/skills/brainstorming/scripts/server.cjs b/skills/brainstorming/scripts/server.cjs
index a4e18284..a828b35a 100644
--- a/skills/brainstorming/scripts/server.cjs
+++ b/skills/brainstorming/scripts/server.cjs
@@ -206,14 +206,22 @@ const helperInjection = '';
// ========== 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) {
diff --git a/tests/brainstorm-server/branding.test.js b/tests/brainstorm-server/branding.test.js
index 6e5b6362..6acda4e3 100644
--- a/tests/brainstorm-server/branding.test.js
+++ b/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'), '
Pick a layout
');
}
+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';