From 7f386943c663062eebf7e124e9ebea712c69355c Mon Sep 17 00:00:00 2001 From: Kjell Tore Guttormsen Date: Thu, 18 Jun 2026 11:31:56 +0200 Subject: [PATCH] =?UTF-8?q?refactor(linkedin-studio):=20M0-5=20=E2=80=94?= =?UTF-8?q?=20queue-manager.mjs=20via=20getDataRoot('drafts')?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../scripts/__tests__/queue-manager.test.mjs | 57 +++++++++++++++++++ hooks/scripts/queue-manager.mjs | 6 +- 2 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 hooks/scripts/__tests__/queue-manager.test.mjs diff --git a/hooks/scripts/__tests__/queue-manager.test.mjs b/hooks/scripts/__tests__/queue-manager.test.mjs new file mode 100644 index 0000000..9c36f49 --- /dev/null +++ b/hooks/scripts/__tests__/queue-manager.test.mjs @@ -0,0 +1,57 @@ +import { describe, test, before, after } from 'node:test'; +import assert from 'node:assert/strict'; +import { mkdtempSync, rmSync, existsSync } from 'node:fs'; +import { join } from 'node:path'; +import { tmpdir } from 'node:os'; + +// M0-5: queue-manager must resolve its queue under the EXTERNAL data root +// (getDataRoot('drafts')), never the plugin tree. The module binds QUEUE_FILE at +// load time, so LINKEDIN_STUDIO_DATA is stubbed BEFORE the dynamic import. A +// separate PLUGIN_ROOT tempdir lets us assert the queue does NOT land in the +// plugin tree without polluting the real working tree (the old default would +// have written there). +// Pattern: data-root.test.mjs env-stub + personalization-score.test.mjs tempdir. +describe('queue-manager — external data root (M0-5)', () => { + let dataDir, pluginDir, qm; + const saved = { + LINKEDIN_STUDIO_DATA: process.env.LINKEDIN_STUDIO_DATA, + PLUGIN_ROOT: process.env.PLUGIN_ROOT, + }; + + before(async () => { + dataDir = mkdtempSync(join(tmpdir(), 'lis-queue-data-')); + pluginDir = mkdtempSync(join(tmpdir(), 'lis-queue-plugin-')); + process.env.LINKEDIN_STUDIO_DATA = dataDir; + process.env.PLUGIN_ROOT = pluginDir; + qm = await import('../queue-manager.mjs'); + }); + + after(() => { + for (const d of [dataDir, pluginDir]) { + if (d && existsSync(d)) rmSync(d, { recursive: true, force: true }); + } + for (const [k, v] of Object.entries(saved)) { + if (v === undefined) delete process.env[k]; + else process.env[k] = v; + } + }); + + test('an empty queue materializes under /drafts/queue.json', () => { + assert.deepEqual(qm.queueRead(), []); + assert.ok( + existsSync(join(dataDir, 'drafts', 'queue.json')), + 'queue file must be created under the external drafts dir', + ); + }); + + test('queueAdd persists to the external root, never the plugin tree', () => { + qm.queueAdd('m0-5', '/tmp/draft.md', '2026-06-20', '09:00', 'ai', 'text', 'hook', 1234); + const entries = qm.queueRead(); + assert.equal(entries.length, 1); + assert.equal(entries[0].id, 'm0-5'); + assert.ok( + !existsSync(join(pluginDir, 'assets', 'drafts', 'queue.json')), + 'queue must NOT land in the plugin tree (PLUGIN_ROOT default removed)', + ); + }); +}); diff --git a/hooks/scripts/queue-manager.mjs b/hooks/scripts/queue-manager.mjs index 871a202..928a61b 100644 --- a/hooks/scripts/queue-manager.mjs +++ b/hooks/scripts/queue-manager.mjs @@ -5,11 +5,9 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs'; import { join, dirname } from 'node:path'; -import { fileURLToPath } from 'node:url'; +import { getDataRoot } from './data-root.mjs'; -const __dirname = dirname(fileURLToPath(import.meta.url)); -const PLUGIN_ROOT = process.env.PLUGIN_ROOT || join(__dirname, '..', '..'); -const QUEUE_FILE = join(PLUGIN_ROOT, 'assets', 'drafts', 'queue.json'); +const QUEUE_FILE = join(getDataRoot('drafts'), 'queue.json'); function ensureQueue() { if (!existsSync(QUEUE_FILE)) {