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.
- package/.claude-plugin/plugin.json +8 -3
- package/CHANGELOG.md +94 -2
- package/agents/wp-accessibility-auditor.md +1 -1
- package/agents/wp-content-strategist.md +2 -2
- package/agents/wp-deployment-engineer.md +1 -1
- package/agents/wp-distribution-manager.md +1 -1
- package/agents/wp-monitoring-agent.md +1 -1
- package/agents/wp-performance-optimizer.md +1 -1
- package/agents/wp-security-auditor.md +1 -1
- package/agents/wp-site-manager.md +3 -3
- package/commands/wp-setup.md +2 -2
- package/docs/GUIDE.md +260 -21
- package/docs/VALIDATION.md +341 -0
- package/docs/guides/wp-ecommerce.md +4 -4
- package/docs/plans/2026-03-01-tier3-wcop-implementation.md +1 -1
- package/docs/plans/2026-03-01-tier4-5-implementation.md +1 -1
- package/docs/plans/2026-03-02-content-framework-architecture.md +612 -0
- package/docs/plans/2026-03-02-content-framework-strategic-reflections.md +228 -0
- package/docs/plans/2026-03-02-content-intelligence-phase2.md +560 -0
- package/docs/plans/2026-03-02-content-pipeline-phase1.md +456 -0
- package/docs/plans/2026-03-02-dashboard-kanban-design.md +761 -0
- package/docs/plans/2026-03-02-dashboard-kanban-implementation.md +598 -0
- package/docs/plans/2026-03-02-dashboard-strategy.md +363 -0
- package/docs/plans/2026-03-02-editorial-calendar-phase3.md +490 -0
- package/docs/validation/.gitkeep +0 -0
- package/docs/validation/dashboard.html +286 -0
- package/docs/validation/results.json +1705 -0
- package/package.json +16 -3
- package/scripts/context-scanner.mjs +446 -0
- package/scripts/dashboard-renderer.mjs +553 -0
- package/scripts/run-validation.mjs +1132 -0
- package/servers/wp-rest-bridge/build/server.js +17 -6
- package/servers/wp-rest-bridge/build/tools/index.js +0 -9
- package/servers/wp-rest-bridge/build/tools/plugin-repository.js +23 -31
- package/servers/wp-rest-bridge/build/tools/schema.js +10 -2
- package/servers/wp-rest-bridge/build/tools/unified-content.js +10 -2
- package/servers/wp-rest-bridge/build/wordpress.d.ts +0 -3
- package/servers/wp-rest-bridge/build/wordpress.js +16 -98
- package/servers/wp-rest-bridge/package.json +1 -0
- package/skills/wp-analytics/SKILL.md +153 -0
- package/skills/wp-analytics/references/signals-feed-schema.md +417 -0
- package/skills/wp-content/references/content-templates.md +1 -1
- package/skills/wp-content/references/seo-optimization.md +8 -8
- package/skills/wp-content-attribution/references/roi-calculation.md +1 -1
- package/skills/wp-content-attribution/references/utm-tracking-setup.md +5 -5
- package/skills/wp-content-generation/references/generation-workflow.md +2 -2
- package/skills/wp-content-pipeline/SKILL.md +461 -0
- package/skills/wp-content-pipeline/references/content-brief-schema.md +377 -0
- package/skills/wp-content-pipeline/references/site-config-schema.md +431 -0
- package/skills/wp-content-repurposing/references/auto-transform-pipeline.md +1 -1
- package/skills/wp-content-repurposing/references/email-newsletter.md +1 -1
- package/skills/wp-content-repurposing/references/platform-specs.md +2 -2
- package/skills/wp-content-repurposing/references/transform-templates.md +27 -27
- package/skills/wp-dashboard/SKILL.md +121 -0
- package/skills/wp-deploy/references/ssh-deploy.md +2 -2
- package/skills/wp-editorial-planner/SKILL.md +262 -0
- package/skills/wp-editorial-planner/references/editorial-schema.md +268 -0
- package/skills/wp-multilang-network/references/content-sync.md +3 -3
- package/skills/wp-multilang-network/references/network-architecture.md +1 -1
- package/skills/wp-multilang-network/references/seo-international.md +7 -7
- package/skills/wp-structured-data/references/schema-types.md +4 -4
- 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.*
|