claude-plugin-wordpress-manager 2.12.2 → 2.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/.claude-plugin/plugin.json +8 -3
  2. package/CHANGELOG.md +94 -2
  3. package/agents/wp-accessibility-auditor.md +1 -1
  4. package/agents/wp-content-strategist.md +2 -2
  5. package/agents/wp-deployment-engineer.md +1 -1
  6. package/agents/wp-distribution-manager.md +1 -1
  7. package/agents/wp-monitoring-agent.md +1 -1
  8. package/agents/wp-performance-optimizer.md +1 -1
  9. package/agents/wp-security-auditor.md +1 -1
  10. package/agents/wp-site-manager.md +3 -3
  11. package/commands/wp-setup.md +2 -2
  12. package/docs/GUIDE.md +260 -21
  13. package/docs/VALIDATION.md +341 -0
  14. package/docs/guides/wp-ecommerce.md +4 -4
  15. package/docs/plans/2026-03-01-tier3-wcop-implementation.md +1 -1
  16. package/docs/plans/2026-03-01-tier4-5-implementation.md +1 -1
  17. package/docs/plans/2026-03-02-content-framework-architecture.md +612 -0
  18. package/docs/plans/2026-03-02-content-framework-strategic-reflections.md +228 -0
  19. package/docs/plans/2026-03-02-content-intelligence-phase2.md +560 -0
  20. package/docs/plans/2026-03-02-content-pipeline-phase1.md +456 -0
  21. package/docs/plans/2026-03-02-dashboard-kanban-design.md +761 -0
  22. package/docs/plans/2026-03-02-dashboard-kanban-implementation.md +598 -0
  23. package/docs/plans/2026-03-02-dashboard-strategy.md +363 -0
  24. package/docs/plans/2026-03-02-editorial-calendar-phase3.md +490 -0
  25. package/docs/validation/.gitkeep +0 -0
  26. package/docs/validation/dashboard.html +286 -0
  27. package/docs/validation/results.json +1705 -0
  28. package/package.json +16 -3
  29. package/scripts/context-scanner.mjs +446 -0
  30. package/scripts/dashboard-renderer.mjs +553 -0
  31. package/scripts/run-validation.mjs +1132 -0
  32. package/servers/wp-rest-bridge/build/server.js +17 -6
  33. package/servers/wp-rest-bridge/build/tools/index.js +0 -9
  34. package/servers/wp-rest-bridge/build/tools/plugin-repository.js +23 -31
  35. package/servers/wp-rest-bridge/build/tools/schema.js +10 -2
  36. package/servers/wp-rest-bridge/build/tools/unified-content.js +10 -2
  37. package/servers/wp-rest-bridge/build/wordpress.d.ts +0 -3
  38. package/servers/wp-rest-bridge/build/wordpress.js +16 -98
  39. package/servers/wp-rest-bridge/package.json +1 -0
  40. package/skills/wp-analytics/SKILL.md +153 -0
  41. package/skills/wp-analytics/references/signals-feed-schema.md +417 -0
  42. package/skills/wp-content/references/content-templates.md +1 -1
  43. package/skills/wp-content/references/seo-optimization.md +8 -8
  44. package/skills/wp-content-attribution/references/roi-calculation.md +1 -1
  45. package/skills/wp-content-attribution/references/utm-tracking-setup.md +5 -5
  46. package/skills/wp-content-generation/references/generation-workflow.md +2 -2
  47. package/skills/wp-content-pipeline/SKILL.md +461 -0
  48. package/skills/wp-content-pipeline/references/content-brief-schema.md +377 -0
  49. package/skills/wp-content-pipeline/references/site-config-schema.md +431 -0
  50. package/skills/wp-content-repurposing/references/auto-transform-pipeline.md +1 -1
  51. package/skills/wp-content-repurposing/references/email-newsletter.md +1 -1
  52. package/skills/wp-content-repurposing/references/platform-specs.md +2 -2
  53. package/skills/wp-content-repurposing/references/transform-templates.md +27 -27
  54. package/skills/wp-dashboard/SKILL.md +121 -0
  55. package/skills/wp-deploy/references/ssh-deploy.md +2 -2
  56. package/skills/wp-editorial-planner/SKILL.md +262 -0
  57. package/skills/wp-editorial-planner/references/editorial-schema.md +268 -0
  58. package/skills/wp-multilang-network/references/content-sync.md +3 -3
  59. package/skills/wp-multilang-network/references/network-architecture.md +1 -1
  60. package/skills/wp-multilang-network/references/seo-international.md +7 -7
  61. package/skills/wp-structured-data/references/schema-types.md +4 -4
  62. package/skills/wp-webhooks/references/payload-formats.md +3 -3
@@ -0,0 +1,598 @@
1
+ # Editorial Kanban Dashboard — Piano di Implementazione
2
+
3
+ > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
4
+
5
+ **Goal:** Implementare la skill `wp-dashboard` con Kanban editoriale HTML generato da `.content-state/`.
6
+
7
+ **Architecture:** Due script Node.js ESM — `context-scanner.mjs` (SCAN + AGGREGATE condiviso) e `dashboard-renderer.mjs` (RENDER HTML + CLI) — più la skill definition `wp-dashboard/SKILL.md`.
8
+
9
+ **Tech Stack:** Node.js ESM, template literal HTML, CSS Grid, zero dipendenze esterne.
10
+
11
+ **Parent**: [Dashboard Kanban Design](2026-03-02-dashboard-kanban-design.md)
12
+
13
+ ---
14
+
15
+ ### Task 1: Create context-scanner.mjs — Frontmatter & Table Parsing
16
+
17
+ **Files:**
18
+ - Create: `scripts/context-scanner.mjs`
19
+
20
+ **Step 1: Create the file with boilerplate and frontmatter parser**
21
+
22
+ Create `scripts/context-scanner.mjs` with:
23
+ - ESM module header (`#!/usr/bin/env node`)
24
+ - Imports: `fs/promises`, `path`, `url`
25
+ - `__dirname` and `PROJECT_ROOT` resolution (same pattern as `run-validation.mjs`)
26
+ - `CONTENT_STATE_DIR` constant pointing to `.content-state/`
27
+ - Function `parseFrontmatter(content)`:
28
+ - Match content between `---\n` delimiters
29
+ - Try to import `yaml` from `servers/wp-rest-bridge/node_modules/yaml` via `createRequire`
30
+ - If available, use `yaml.parse()` for robust parsing
31
+ - If not available, implement minimal manual parser:
32
+ - Handle scalar values (strings, numbers, booleans)
33
+ - Handle inline arrays `[a, b, c]`
34
+ - Handle multi-line arrays (`- item`)
35
+ - Handle one level of nested objects (indented keys)
36
+ - Return `{ frontmatter: object, body: string }`
37
+
38
+ **Step 2: Add editorial table parser**
39
+
40
+ Add function `parseEditorialTable(markdownBody, calendarPeriod)`:
41
+ - Split body by `## Settimana` headings
42
+ - For each section, find lines starting with `|` (skip header and separator rows)
43
+ - For each data row:
44
+ - Split by `|`, trim each cell
45
+ - Map to object: `{ date, title, type, status, briefId, postId, channels }`
46
+ - Convert date from `Mon DD` format (e.g., `Mar 18`) to `YYYY-MM-DD` using the year/month from `calendarPeriod`
47
+ - Handle special values: `—` → `null`, `[da assegnare]` → `title: null`
48
+ - Parse channels: split by `, ` into array, empty string → `[]`
49
+ - Return array of entry objects
50
+
51
+ **Step 3: Verify parsing with a quick test**
52
+
53
+ Run:
54
+ ```bash
55
+ node -e "
56
+ import { readFile } from 'fs/promises';
57
+ import { resolve } from 'path';
58
+ const mod = await import('./scripts/context-scanner.mjs');
59
+ // Test frontmatter parsing
60
+ const config = await readFile('.content-state/mysite.config.md', 'utf8');
61
+ const parsed = mod.parseFrontmatter(config);
62
+ console.log('Config site_id:', parsed.frontmatter.site_id);
63
+ console.log('Config channels:', Object.keys(parsed.frontmatter.channels || {}));
64
+ // Test table parsing
65
+ const cal = await readFile('.content-state/2026-03-editorial.state.md', 'utf8');
66
+ const calParsed = mod.parseFrontmatter(cal);
67
+ const entries = mod.parseEditorialTable(calParsed.body, calParsed.frontmatter.period);
68
+ console.log('Entries count:', entries.length);
69
+ console.log('First entry:', JSON.stringify(entries[0]));
70
+ console.log('Planned (no title):', entries.filter(e => !e.title).length);
71
+ "
72
+ ```
73
+
74
+ Expected:
75
+ - Config site_id: `mysite`
76
+ - Config channels include `linkedin`, `twitter`, `mailchimp`
77
+ - Entries count: `8`
78
+ - First entry has `date: "2026-03-04"`, `status: "published"`, `briefId: "BRF-2026-001"`
79
+ - Planned (no title): `3`
80
+
81
+ ---
82
+
83
+ ### Task 2: Create context-scanner.mjs — scanContentState Function
84
+
85
+ **Files:**
86
+ - Modify: `scripts/context-scanner.mjs`
87
+
88
+ **Step 1: Add scanContentState function**
89
+
90
+ Add `export async function scanContentState(contentStatePath, siteId)`:
91
+
92
+ 1. **Read site config**: `{contentStatePath}/{siteId}.config.md`
93
+ - Parse frontmatter → extract `site_id`, `site_url`, `brand`, `defaults`, `channels`, `seo`, `cadence`
94
+ - If file not found → throw with descriptive message
95
+
96
+ 2. **Find current calendar**: glob `{contentStatePath}/*-editorial.state.md`
97
+ - Filter by most recent (or by `--month` param passed externally)
98
+ - Parse frontmatter → extract `calendar_id`, `period`, `goals`
99
+ - Parse body → `parseEditorialTable()` for entries
100
+ - If no calendar found → return `calendar: null`
101
+
102
+ 3. **Read active briefs**: glob `{contentStatePath}/pipeline-active/*.brief.md`
103
+ - For each file: parse frontmatter, extract key fields
104
+ - Return array of brief summaries
105
+
106
+ 4. **Read archived briefs**: glob `{contentStatePath}/pipeline-archive/*.brief.md`
107
+ - Same as active briefs
108
+ - Return array of brief summaries
109
+
110
+ 5. **Read signals feed**: `{contentStatePath}/signals-feed.md`
111
+ - Parse frontmatter → extract `feed_id`, `period`
112
+ - Parse anomaly table in body (same table parsing logic)
113
+ - If file not found → return `signals: null`
114
+
115
+ 6. Return structured object:
116
+ ```javascript
117
+ { site, calendar, briefs: { active, archived }, signals }
118
+ ```
119
+
120
+ **Step 2: Implement glob helper without external dependency**
121
+
122
+ Add function `globFiles(dirPath, pattern)` using `fs.readdir` + simple pattern matching (e.g., `*.brief.md`). No need for a full glob library — the patterns are simple suffix matches.
123
+
124
+ **Step 3: Verify with real data**
125
+
126
+ Run:
127
+ ```bash
128
+ node -e "
129
+ const mod = await import('./scripts/context-scanner.mjs');
130
+ const data = await mod.scanContentState('.content-state', 'mysite');
131
+ console.log('Site:', data.site.id, data.site.url);
132
+ console.log('Calendar:', data.calendar?.id, '- entries:', data.calendar?.entries?.length);
133
+ console.log('Briefs active:', data.briefs.active.length);
134
+ console.log('Briefs archived:', data.briefs.archived.length);
135
+ console.log('Signals:', data.signals?.anomalies?.length, 'anomalies');
136
+ "
137
+ ```
138
+
139
+ Expected:
140
+ - Site: `mysite https://mysite.example.com`
141
+ - Calendar: `CAL-2026-03` - entries: `8`
142
+ - Briefs active: `1`
143
+ - Briefs archived: `1`
144
+ - Signals: `3` anomalies
145
+
146
+ ---
147
+
148
+ ### Task 3: Create context-scanner.mjs — aggregateMetrics Function
149
+
150
+ **Files:**
151
+ - Modify: `scripts/context-scanner.mjs`
152
+
153
+ **Step 1: Add aggregateMetrics function**
154
+
155
+ Add `export function aggregateMetrics(rawData, viewType = 'kanban')`:
156
+
157
+ For `viewType === 'kanban'`:
158
+
159
+ 1. **Column counts**: count entries by status (`planned`, `draft`, `ready`, `scheduled`, `published`)
160
+ 2. **Progress**: `postsPublished / postsTarget * 100`
161
+ 3. **Next deadline**: first entry (by date) with status not `published` and with a title assigned
162
+ 4. **Channel usage**: count entries per channel across all entries
163
+ 5. **Fill rate**: entries with title / total entries * 100
164
+ 6. **Signals summary**: count anomalies, identify highest delta
165
+ 7. **Generation metadata**: timestamp, version
166
+
167
+ Return the metrics object as specified in the design document section 3.2.
168
+
169
+ **Step 2: Add renderContextSnippet stub**
170
+
171
+ Add `export function renderContextSnippet(metrics, sliceType = 'pipeline')` as a stub that returns a placeholder string. This will be implemented in Fase B but the export must exist now for the module contract.
172
+
173
+ ```javascript
174
+ export function renderContextSnippet(metrics, sliceType = 'pipeline') {
175
+ // Fase B implementation — placeholder
176
+ const s = metrics;
177
+ const lines = [
178
+ `── Editorial Context ──────────────────────`,
179
+ ` ${s.siteId} | ${s.calendarPeriod || 'no calendar'}`,
180
+ ` Pipeline: ${s.columns?.draft ?? 0} draft → ${s.columns?.ready ?? 0} ready → ${s.columns?.scheduled ?? 0} scheduled`,
181
+ ` Posts: ${s.postsPublished ?? 0}/${s.postsTarget ?? '?'} pubblicati`,
182
+ `───────────────────────────────────────────`,
183
+ ];
184
+ return lines.join('\n');
185
+ }
186
+ ```
187
+
188
+ **Step 3: Verify aggregation**
189
+
190
+ Run:
191
+ ```bash
192
+ node -e "
193
+ const mod = await import('./scripts/context-scanner.mjs');
194
+ const data = await mod.scanContentState('.content-state', 'mysite');
195
+ const metrics = mod.aggregateMetrics(data, 'kanban');
196
+ console.log('Progress:', metrics.postsPublished + '/' + metrics.postsTarget, '(' + metrics.progressPercent + '%)');
197
+ console.log('Columns:', JSON.stringify(metrics.columns));
198
+ console.log('Next deadline:', metrics.nextDeadline?.date, '-', metrics.nextDeadline?.title?.substring(0, 40));
199
+ console.log('Fill rate:', metrics.fillRate + '%');
200
+ console.log('Signals:', metrics.signalsCount);
201
+ // Test context snippet
202
+ console.log('\\nSnippet:\\n' + mod.renderContextSnippet(metrics));
203
+ "
204
+ ```
205
+
206
+ Expected:
207
+ - Progress: `2/8 (25%)`
208
+ - Columns: `{"planned":3,"draft":1,"ready":2,"scheduled":0,"published":2}`
209
+ - Next deadline: `2026-03-11` - `Zero calorie, tutto gusto: la scienza`
210
+ - Fill rate: `62.5%`
211
+ - Signals: `3`
212
+ - Snippet: 5 lines of formatted terminal text
213
+
214
+ ---
215
+
216
+ ### Task 4: Create dashboard-renderer.mjs — HTML Template
217
+
218
+ **Files:**
219
+ - Create: `scripts/dashboard-renderer.mjs`
220
+
221
+ **Step 1: Create file with HTML template function**
222
+
223
+ Create `scripts/dashboard-renderer.mjs` with:
224
+ - ESM imports from `context-scanner.mjs`
225
+ - Function `renderKanbanHTML(rawData, metrics)` that returns a complete HTML string
226
+
227
+ The HTML template must include:
228
+
229
+ 1. **`<head>`**: charset, viewport, title, inline `<style>` with full CSS (~150 lines)
230
+ 2. **`<header>`**: site name, month, generation timestamp, progress bar, pipeline count badges
231
+ 3. **`<main class="kanban">`**: 5 columns (planned, draft, ready, scheduled, published)
232
+ 4. **Card generation**: loop through `rawData.calendar.entries`, group by status, render each as a card
233
+ 5. **`<section class="signals-strip">`**: render anomalies from `rawData.signals` (skip if null)
234
+ 6. **`<footer>`**: plugin version, skill name
235
+
236
+ CSS must include:
237
+ - CSS custom properties for the full palette (from design doc section 2.5)
238
+ - Reset styles (box-sizing, margin)
239
+ - Grid layout for kanban (5 columns, gap)
240
+ - Column styling (background, border-radius, flex column)
241
+ - Card styling (white bg, left border with status color, shadow)
242
+ - Card variants (`.card--empty` for planned without title)
243
+ - Header with progress bar
244
+ - Badge styles for pipeline counts and channels
245
+ - Signals strip styling
246
+ - Responsive breakpoint at 768px (single column stack)
247
+ - Print-friendly styles (`@media print`)
248
+
249
+ **Step 2: Implement helper functions**
250
+
251
+ - `escapeHtml(str)` — escape `<`, `>`, `&`, `"`, `'` for safe HTML output
252
+ - `truncate(str, maxLen)` — truncate string with `...`, return full string in `title` attribute
253
+ - `formatDate(dateStr)` — convert `YYYY-MM-DD` to localized display (e.g., `Mar 18`)
254
+ - `groupByStatus(entries)` — group entries array into object keyed by status
255
+ - `channelBadge(channel)` — return HTML for channel pill badge with correct color
256
+ - `statusColor(status)` — return CSS variable name for the status
257
+
258
+ **Step 3: Verify template generates valid HTML**
259
+
260
+ Run:
261
+ ```bash
262
+ node -e "
263
+ const scanner = await import('./scripts/context-scanner.mjs');
264
+ const renderer = await import('./scripts/dashboard-renderer.mjs');
265
+ const data = await scanner.scanContentState('.content-state', 'mysite');
266
+ const metrics = scanner.aggregateMetrics(data, 'kanban');
267
+ const html = renderer.renderKanbanHTML(data, metrics);
268
+ console.log('HTML length:', html.length, 'bytes');
269
+ console.log('Has DOCTYPE:', html.startsWith('<!DOCTYPE'));
270
+ console.log('Has 5 columns:', (html.match(/class=\"column\"/g) || []).length);
271
+ console.log('Has cards:', (html.match(/class=\"card/g) || []).length);
272
+ console.log('Has signals:', html.includes('signals-strip'));
273
+ "
274
+ ```
275
+
276
+ Expected:
277
+ - HTML length: between 5000-30000 bytes
278
+ - Has DOCTYPE: `true`
279
+ - Has 5 columns: `5`
280
+ - Has cards: `8` (one per calendar entry)
281
+ - Has signals: `true`
282
+
283
+ ---
284
+
285
+ ### Task 5: Create dashboard-renderer.mjs — CLI Entry Point
286
+
287
+ **Files:**
288
+ - Modify: `scripts/dashboard-renderer.mjs`
289
+
290
+ **Step 1: Add CLI argument parsing and main function**
291
+
292
+ Add to `dashboard-renderer.mjs`:
293
+
294
+ - CLI arg parsing (reuse `getArg`/`hasFlag` pattern from `run-validation.mjs`):
295
+ - `--site=X` — site ID
296
+ - `--month=YYYY-MM` — target month
297
+ - `--output=path` — custom output path
298
+ - `--no-open` — skip browser launch
299
+ - `RENDERER_VERSION` constant `'1.0.0'`
300
+ - Function `async function main()`:
301
+ 1. Parse CLI args
302
+ 2. Resolve `CONTENT_STATE_DIR` from `PROJECT_ROOT`
303
+ 3. If no `--site`: scan for `*.config.md` files, auto-select if only one, error with list if multiple
304
+ 4. If no `--month`: determine current month from the most recent `*-editorial.state.md`
305
+ 5. Call `scanContentState()`
306
+ 6. Call `aggregateMetrics()`
307
+ 7. Call `renderKanbanHTML()`
308
+ 8. Write HTML to output path (default: `.content-state/.dashboard-{site}-{month}.html`)
309
+ 9. If not `--no-open`: open in browser via `xdg-open` / `open` / `start`
310
+ 10. Print summary to terminal:
311
+ ```
312
+ Dashboard generated: .content-state/.dashboard-mysite-2026-03.html
313
+ Posts: 2/8 published | Pipeline: 1 draft, 2 ready | Signals: 3 anomalies
314
+ ```
315
+
316
+ - `main().catch(err => { console.error(err.message); process.exit(1); })`
317
+
318
+ **Step 2: Add platform-aware browser open**
319
+
320
+ ```javascript
321
+ import { exec } from 'node:child_process';
322
+ import { platform } from 'node:os';
323
+
324
+ function openInBrowser(filepath) {
325
+ const cmd = platform() === 'darwin' ? 'open' :
326
+ platform() === 'win32' ? 'start' :
327
+ 'xdg-open';
328
+ exec(`${cmd} "${filepath}"`);
329
+ }
330
+ ```
331
+
332
+ Note: on WSL2, `xdg-open` should open the default Windows browser if `wslu` is installed. If not available, the `--no-open` flag allows manual opening.
333
+
334
+ **Step 3: Test CLI**
335
+
336
+ Run:
337
+ ```bash
338
+ # Test with --no-open (don't open browser in CI-like context)
339
+ node scripts/dashboard-renderer.mjs --site=mysite --no-open
340
+ ```
341
+
342
+ Expected:
343
+ - File created at `.content-state/.dashboard-mysite-2026-03.html`
344
+ - Terminal output shows summary line
345
+ - Exit code 0
346
+
347
+ Verify the file:
348
+ ```bash
349
+ wc -c .content-state/.dashboard-mysite-2026-03.html
350
+ head -5 .content-state/.dashboard-mysite-2026-03.html
351
+ ```
352
+
353
+ Expected:
354
+ - Size between 5000-30000 bytes
355
+ - First line: `<!DOCTYPE html>`
356
+
357
+ ---
358
+
359
+ ### Task 6: Create wp-dashboard Skill Definition
360
+
361
+ **Files:**
362
+ - Create: `skills/wp-dashboard/SKILL.md`
363
+
364
+ **Step 1: Write the SKILL.md**
365
+
366
+ Create `skills/wp-dashboard/SKILL.md` with:
367
+
368
+ - YAML frontmatter: `name`, `description` (with trigger phrases), `version: 1.0.0`
369
+ - Overview section explaining what the skill does
370
+ - "When to Use" section with trigger phrases (italiano + inglese)
371
+ - Workflow section:
372
+ 1. Determine target site (from conversation context or ask user)
373
+ 2. Determine target month (default: current, or ask)
374
+ 3. Execute: `node scripts/dashboard-renderer.mjs --site={siteId} --month={YYYY-MM}`
375
+ 4. Report to user that dashboard is open
376
+ 5. Suggest next actions based on what the dashboard shows
377
+ - "Reading the Dashboard" section explaining:
378
+ - What each column means (planned → published lifecycle)
379
+ - What the card colors indicate
380
+ - What the signals strip shows
381
+ - How to use the dashboard for operational decisions
382
+ - "Next Actions" section mapping dashboard observations to skills:
383
+ - Empty `planned` slots → use `wp-editorial-planner` PLAN step
384
+ - `draft` entries needing content → fill briefs in `pipeline-active/`
385
+ - `ready` entries → use `wp-editorial-planner` SCHEDULE step
386
+ - Signals with high delta → use `wp-analytics` for deeper investigation
387
+ - Safety rules (same as other skills: always show before acting)
388
+ - Related skills section
389
+
390
+ **Step 2: Verify skill file is valid**
391
+
392
+ Check that the YAML frontmatter parses correctly:
393
+ ```bash
394
+ node -e "
395
+ import { readFile } from 'fs/promises';
396
+ const content = await readFile('skills/wp-dashboard/SKILL.md', 'utf8');
397
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
398
+ console.log('Has frontmatter:', !!match);
399
+ console.log('Content preview:', content.substring(0, 200));
400
+ "
401
+ ```
402
+
403
+ Expected: `Has frontmatter: true`
404
+
405
+ ---
406
+
407
+ ### Task 7: Test with Real Data — Visual Verification
408
+
409
+ **Files:**
410
+ - No files modified (test only)
411
+
412
+ **Step 1: Generate dashboard and inspect HTML**
413
+
414
+ ```bash
415
+ node scripts/dashboard-renderer.mjs --site=mysite --no-open --output=/tmp/kanban-test.html
416
+ ```
417
+
418
+ **Step 2: Verify HTML structure**
419
+
420
+ ```bash
421
+ # Check all 5 columns present
422
+ grep -c 'class="column"' /tmp/kanban-test.html
423
+
424
+ # Check all 8 cards present
425
+ grep -c 'class="card' /tmp/kanban-test.html
426
+
427
+ # Check published entries have post IDs
428
+ grep 'BRF-2026-001' /tmp/kanban-test.html
429
+
430
+ # Check signals strip
431
+ grep 'acqua premium' /tmp/kanban-test.html
432
+
433
+ # Check progress bar
434
+ grep 'pubblicati' /tmp/kanban-test.html
435
+
436
+ # Check no external dependencies (no http:// or https:// in link/script tags)
437
+ grep -E '<(link|script).*https?://' /tmp/kanban-test.html || echo "OK: no external deps"
438
+ ```
439
+
440
+ Expected:
441
+ - 5 columns
442
+ - 8 cards (or close — one per calendar entry)
443
+ - BRF-2026-001 present in a published card
444
+ - "acqua premium" in signals strip
445
+ - "pubblicati" in progress area
446
+ - No external dependencies
447
+
448
+ **Step 3: Open in browser for visual check**
449
+
450
+ ```bash
451
+ # On WSL2 with wslu installed:
452
+ xdg-open /tmp/kanban-test.html
453
+ # Or manually open the file in Windows browser
454
+ ```
455
+
456
+ Visual check:
457
+ - [ ] 5 columns visible with correct headers
458
+ - [ ] Cards have colored left border matching status
459
+ - [ ] Published cards are green, draft is yellow, ready is blue
460
+ - [ ] "[da assegnare]" cards show grey italic text
461
+ - [ ] Channel badges show colored pills
462
+ - [ ] Progress bar shows 2/8 (25%)
463
+ - [ ] Signals strip at bottom shows 3 anomalies
464
+ - [ ] Responsive: resize to mobile width → columns stack vertically
465
+
466
+ ---
467
+
468
+ ### Task 8: Update .gitignore and package.json
469
+
470
+ **Files:**
471
+ - Modify: `.gitignore`
472
+ - Modify: `package.json`
473
+ - Modify: `.claude-plugin/plugin.json`
474
+ - Modify: `CHANGELOG.md`
475
+ - Modify: `docs/GUIDE.md`
476
+
477
+ **Step 1: Add dashboard HTML to .gitignore**
478
+
479
+ Add to `.gitignore`:
480
+ ```
481
+ # Dashboard generated HTML (ephemeral artifacts)
482
+ .content-state/.dashboard-*.html
483
+ ```
484
+
485
+ **Step 2: Bump version to v2.14.0**
486
+
487
+ In `package.json`:
488
+ - `version`: `"2.13.0"` → `"2.14.0"`
489
+ - `description`: add "dashboard" mention, bump skill count from 45 to 46
490
+
491
+ In `.claude-plugin/plugin.json`:
492
+ - `version`: `"2.13.0"` → `"2.14.0"`
493
+ - `description`: add "dashboard" mention, bump skill count
494
+ - `keywords`: add `"dashboard"`, `"kanban"`, `"editorial-dashboard"`
495
+
496
+ **Step 3: Add scripts entry in package.json**
497
+
498
+ Add to `scripts` section:
499
+ ```json
500
+ "dashboard": "node scripts/dashboard-renderer.mjs"
501
+ ```
502
+
503
+ **Step 4: Update CHANGELOG.md**
504
+
505
+ Add `## v2.14.0` entry at top (before v2.13.0):
506
+ ```markdown
507
+ ## v2.14.0 — Editorial Kanban Dashboard
508
+
509
+ **New Skill: `wp-dashboard`** — Visual Kanban dashboard generated as self-contained HTML.
510
+
511
+ ### Dashboard System
512
+ - **`scripts/context-scanner.mjs`** — Shared SCAN + AGGREGATE module that reads `.content-state/` files
513
+ - Parses YAML frontmatter from config, calendar, brief, and signals files
514
+ - Parses editorial calendar Markdown tables into structured data
515
+ - Computes aggregate metrics (progress, pipeline counts, fill rate, next deadline)
516
+ - Exports `renderContextSnippet()` stub for future Fase B (step 0 context in content skills)
517
+ - **`scripts/dashboard-renderer.mjs`** — HTML renderer + CLI
518
+ - Generates self-contained HTML Kanban board (zero external dependencies)
519
+ - 5 columns: planned → draft → ready → scheduled → published
520
+ - Cards with status-colored borders, channel badges, brief IDs
521
+ - Progress bar, pipeline count badges, signals strip
522
+ - Responsive layout (CSS Grid, mobile stack at 768px)
523
+ - CLI: `--site`, `--month`, `--output`, `--no-open` flags
524
+ - Opens dashboard in default browser via `xdg-open`/`open`
525
+ - **`skills/wp-dashboard/SKILL.md`** — Skill definition with trigger phrases and workflow
526
+
527
+ ### Stats
528
+ - Skills: 45 → 46
529
+ - New scripts: 2 (`context-scanner.mjs`, `dashboard-renderer.mjs`)
530
+ ```
531
+
532
+ **Step 5: Update docs/GUIDE.md skill count**
533
+
534
+ Update skill count: `45` → `46`
535
+
536
+ **Step 6: Verify all changes**
537
+
538
+ ```bash
539
+ # Check version consistency
540
+ grep '"version"' package.json .claude-plugin/plugin.json
541
+ # Check gitignore has dashboard entry
542
+ grep 'dashboard' .gitignore
543
+ # Check CHANGELOG has new entry
544
+ head -20 CHANGELOG.md
545
+ ```
546
+
547
+ Expected: Both files show `2.14.0`, gitignore has dashboard pattern, CHANGELOG starts with v2.14.0.
548
+
549
+ ---
550
+
551
+ ### Task 9: Commit
552
+
553
+ **Step 1: Stage and commit**
554
+
555
+ ```bash
556
+ git add scripts/context-scanner.mjs scripts/dashboard-renderer.mjs skills/wp-dashboard/SKILL.md
557
+ git add .gitignore package.json .claude-plugin/plugin.json CHANGELOG.md docs/GUIDE.md
558
+ git status
559
+ git commit -m "feat: add wp-dashboard skill with Editorial Kanban HTML
560
+
561
+ Implements Fase A of the Dashboard Strategy:
562
+ - scripts/context-scanner.mjs: shared SCAN + AGGREGATE module
563
+ - Parses YAML frontmatter and editorial calendar tables
564
+ - Computes aggregate metrics (progress, pipeline, signals)
565
+ - Exports renderContextSnippet() stub for Fase B
566
+ - scripts/dashboard-renderer.mjs: HTML renderer + CLI
567
+ - Self-contained HTML Kanban (zero dependencies)
568
+ - 5 columns: planned → draft → ready → scheduled → published
569
+ - Cards, progress bar, signals strip, responsive layout
570
+ - CLI flags: --site, --month, --output, --no-open
571
+ - skills/wp-dashboard/SKILL.md: skill definition
572
+
573
+ Skills: 45 → 46 | Version: v2.13.0 → v2.14.0
574
+
575
+ Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>"
576
+ ```
577
+
578
+ ---
579
+
580
+ ## Sequence Summary
581
+
582
+ | Task | What | Files | Depends On |
583
+ |------|------|-------|------------|
584
+ | 1 | Frontmatter + table parser | `context-scanner.mjs` (create) | — |
585
+ | 2 | `scanContentState()` | `context-scanner.mjs` (modify) | Task 1 |
586
+ | 3 | `aggregateMetrics()` + snippet stub | `context-scanner.mjs` (modify) | Task 2 |
587
+ | 4 | HTML template + `renderKanbanHTML()` | `dashboard-renderer.mjs` (create) | Task 3 |
588
+ | 5 | CLI entry point + browser open | `dashboard-renderer.mjs` (modify) | Task 4 |
589
+ | 6 | Skill definition | `wp-dashboard/SKILL.md` (create) | — |
590
+ | 7 | Visual verification test | No files | Task 5 |
591
+ | 8 | gitignore, version bump, changelog | Multiple (modify) | Task 7 |
592
+ | 9 | Commit | — | Task 8 |
593
+
594
+ **Task 6 è indipendente** da Task 1-5 e può essere eseguito in parallelo.
595
+
596
+ ---
597
+
598
+ *Piano di implementazione per il Kanban editoriale del WordPress Manager Plugin. Fase A della Dashboard Strategy.*