refactor(linkedin-studio): M0-10 — content-filter recognizes external drafts (after negatives, before infraDirs)

This commit is contained in:
Kjell Tore Guttormsen 2026-06-18 11:50:04 +02:00
commit c35e9fc9d3
2 changed files with 40 additions and 1 deletions

View file

@ -85,3 +85,35 @@ describe('isLinkedInContent — code/config/template/meta files (negative)', ()
assert.equal(isLinkedInContent(undefined), false);
});
});
// M0-10: after drafts relocate to the external data root, the gate must still
// fire on them. `.claude` is an infraDir, so a naive check rejects any /.claude/
// path — the external-drafts positive must short-circuit BEFORE that negative,
// while the state file (.local.md) and REMEMBER.md stay excluded.
describe('isLinkedInContent — external data-root drafts (M0-10)', () => {
const H = '/Users/test';
test('fires on a relocated draft under ~/.claude/linkedin-studio/drafts/', () => {
assert.equal(isLinkedInContent(`${H}/.claude/linkedin-studio/drafts/2026-06-20-post.md`), true);
});
test('fires on a relocated carousel slide under the external drafts dir', () => {
assert.equal(isLinkedInContent(`${H}/.claude/linkedin-studio/drafts/carousel-x/slide-1.png`), true);
});
test('does NOT fire on the external state file (.local.md)', () => {
assert.equal(isLinkedInContent(`${H}/.claude/linkedin-studio.local.md`), false);
});
test('does NOT fire on the external REMEMBER.md', () => {
assert.equal(isLinkedInContent(`${H}/.claude/linkedin-studio/REMEMBER.md`), false);
});
test('does NOT fire on ~/.claude/settings.json', () => {
assert.equal(isLinkedInContent(`${H}/.claude/settings.json`), false);
});
test('still fires on in-plugin assets/drafts/ (migration-window back-compat)', () => {
assert.equal(isLinkedInContent('assets/drafts/2026-06-20-post.md'), true);
});
});

View file

@ -23,9 +23,16 @@ export function isLinkedInContent(filePath) {
const nonContent = ['.local.md', 'CLAUDE.md', 'README.md', 'CHANGELOG.md', 'REMEMBER.md', 'BACKLOG.md', 'DEVELOPMENT-LOG.md'];
if (nonContent.some(n => base.endsWith(n) || base === n)) return false;
const normalized = filePath.replace(/\\/g, '/');
// POSITIVE (external): relocated drafts under the per-user data root are the
// only external data class the Write/Edit quality gate guards (voice-samples /
// analytics / profile are not editor-gated content). Must come BEFORE the
// infraDirs negative below, which would otherwise reject any /.claude/ path.
if (normalized.startsWith('.claude/linkedin-studio/drafts/') || normalized.includes('/.claude/linkedin-studio/drafts/')) return true;
// NEGATIVE: infrastructure paths
const infraDirs = ['hooks', 'scripts', 'config', 'commands', 'agents', 'skills', 'references', 'docs', '.claude', '.claude-plugin', 'node_modules'];
const normalized = filePath.replace(/\\/g, '/');
for (const dir of infraDirs) {
if (normalized.startsWith(dir + '/') || normalized.includes('/' + dir + '/')) return false;
}