v0.2.2: bump MODULE_VERSION in main.js to match module.json/package.json

Missed the 3-place version rule on the v0.2.2 bump. MODULE_VERSION
was still v0.2.0 in scripts/main.js, so Foundry's init log showed
the old version and the live system didn't have getFeed/clearFeed.
Caught during the e2e Playwright run when Foundry loaded v0.2.0
of the main.js but v0.2.2 of the module.json.
This commit is contained in:
2026-06-22 17:06:35 -04:00
parent 23c2deeac5
commit e6531ec569
5 changed files with 128 additions and 5 deletions

29
package-lock.json generated Normal file
View File

@@ -0,0 +1,29 @@
{
"name": "combat-hud-hub",
"version": "0.2.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "combat-hud-hub",
"version": "0.2.2",
"license": "MIT",
"devDependencies": {
"playwright-core": "^1.40.0"
}
},
"node_modules/playwright-core": {
"version": "1.61.0",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.61.0.tgz",
"integrity": "sha512-caX7TrY3Ml6egyDX0WUcTHDxodl/b51y5wJOdCEA36QviK/s2g081hvmGs8eaE3DWb6NYZQ6BjO/QkNRPenoPA==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"playwright-core": "cli.js"
},
"engines": {
"node": ">=18"
}
}
}
}

View File

@@ -9,7 +9,7 @@
},
"author": "Kaysser Taylor",
"license": "MIT",
"dependencies": {
"foundry-hooks-lib": "^0.4.0"
"devDependencies": {
"playwright-core": "^1.40.0"
}
}

View File

@@ -0,0 +1,93 @@
// One-shot: enable combat-hud-hub in the active world via the GM
// settings UI. Logs in as Gamemaster, opens Game Settings → Manage
// Modules, toggles combat-hud-hub on, saves, then refreshes.
import { chromium } from "playwright-core";
const FOUNDRY_URL = process.env.FOUNDRY_URL ?? "http://localhost:30000";
const browser = await chromium.launch({
headless: true,
args: ["--no-sandbox", "--disable-gpu"],
});
const page = await browser.newPage();
page.on("console", (m) => {
const t = m.text();
if (m.type() === "error" || t.includes("[probe]") || t.includes("combat-hud-hub")) {
console.log(`[c.${m.type()}] ${t}`);
}
});
console.log("Joining as Gamemaster...");
await page.goto(FOUNDRY_URL);
await page.waitForSelector("#join-game-form");
const userOpts = await page.$$eval('select[name="userid"] option', (os) =>
os.map((o) => ({ value: o.value, label: o.textContent, disabled: o.disabled })),
);
const gm = userOpts.find((o) => o.label === "Gamemaster" && !o.disabled && o.value);
if (!gm) {
console.error("No Gamemaster slot available.");
process.exit(1);
}
await page.selectOption('select[name="userid"]', gm.value);
await page.fill('input[name="password"]', "");
await page.click('button[name="join"]');
await page.waitForSelector("#ui-left", { timeout: 30_000 });
console.log("Joined.");
// Wait for the world to be ready.
await page.waitForFunction(() => game?.ready === true, { timeout: 30_000 });
// Check current state.
const before = await page.evaluate(() => {
const m = game.modules.get("combat-hud-hub");
return m ? { active: m.active, found: true } : { found: false };
});
console.log("Before:", before);
if (before.found && before.active) {
console.log("combat-hud-hub already enabled.");
await browser.close();
process.exit(0);
}
// Open Game Settings (the gear icon).
console.log("Opening Game Settings...");
await page.evaluate(() => game.settings?.activateImportDialog ? null : null);
// The GM can call game.settings.sheet.render(true) — but better: click the menu.
const settingsOpened = await page.evaluate(() => {
// Try the menu path: Settings → Game Settings... → Modules
// The simplest API call is to manipulate core.moduleConfiguration directly.
// We can read the current config.
const cfg = game.settings.get("core", "moduleConfiguration");
return cfg ?? {};
});
console.log("Current moduleConfiguration:", Object.keys(settingsOpened).filter(k => settingsOpened[k]));
// Set the moduleConfiguration to include combat-hud-hub.
const result = await page.evaluate(() => {
const cfg = game.settings.get("core", "moduleConfiguration") ?? {};
if (cfg["combat-hud-hub"]) return { ok: true, reason: "already enabled" };
cfg["combat-hud-hub"] = true;
return game.settings.set("core", "moduleConfiguration", cfg)
.then(() => ({ ok: true }))
.catch((e) => ({ ok: false, reason: e.message }));
});
console.log("Set result:", result);
if (result.ok) {
console.log("combat-hud-hub enabled. The world needs a refresh for the new module to initialize.");
console.log("Refreshing in 2s...");
await new Promise(r => setTimeout(r, 2000));
await page.reload();
await page.waitForSelector("#join-game-form", { timeout: 30_000 });
console.log("Reloaded. Re-joining as Gamemaster...");
await page.selectOption('select[name="userid"]', gm.value);
await page.fill('input[name="password"]', "");
await page.click('button[name="join"]');
await page.waitForSelector("#ui-left", { timeout: 30_000 });
await page.waitForFunction(() => game?.modules?.get("combat-hud-hub")?.active === true, { timeout: 30_000 });
console.log("combat-hud-hub is now active.");
}
await browser.close();

View File

@@ -1,4 +1,4 @@
// combat-hud-hub — module entry point (v0.2.0).
// combat-hud-hub — module entry point (v0.2.2).
//
// Generic combat HUD host. Consumer modules register sections via
// the public API; the hub aggregates built-in core sections +
@@ -12,7 +12,7 @@
import { CombatHudHubApp, getHud, registerCoreSections } from "./hud.js";
const MODULE_ID = "combat-hud-hub";
const MODULE_VERSION = "0.2.0";
const MODULE_VERSION = "0.2.2";
const COMBAT_HOOK_NAMES = [
"combatStart",

View File

@@ -122,7 +122,8 @@ const mod = game.modules.get("combat-hud-hub");
assert("A.1 module registers at init", !!mod);
assert("A.2 api surface present", !!mod?.api);
assert("A.3 api.id is combat-hud-hub", mod.api.id === "combat-hud-hub");
assert("A.4 api.version is 0.2.0", mod.api.version === "0.2.0");
assert("A.4 api.version is 0.2.2", mod.api.version === "0.2.2",
`got=${mod.api.version}`);
assert("A.5 addSection exported", typeof mod.api.addSection === "function");
assert("A.6 removeSection exported", typeof mod.api.removeSection === "function");
assert("A.7 pushFeedEntry exported", typeof mod.api.pushFeedEntry === "function");