@drunkcoding/agents-and-skills 0.0.13 → 0.0.15

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 (83) hide show
  1. package/.claude-plugin/marketplace.json +9 -6
  2. package/README.md +1 -1
  3. package/package.json +1 -1
  4. package/plugins/html-effectiveness/.claude-plugin/plugin.json +1 -1
  5. package/plugins/html-effectiveness/README.md +9 -4
  6. package/plugins/html-effectiveness/agents/report-builder.md +4 -0
  7. package/plugins/html-effectiveness/assets/base.css +40 -20
  8. package/plugins/html-effectiveness/docs/template-gallery.md +28 -0
  9. package/plugins/html-effectiveness/scripts/_tmp.js +37 -0
  10. package/plugins/html-effectiveness/scripts/catalog.js +47 -0
  11. package/plugins/html-effectiveness/scripts/extract.js +104 -0
  12. package/plugins/html-effectiveness/scripts/render.js +2 -2
  13. package/plugins/html-effectiveness/skills/html-effectiveness/SKILL.md +4 -4
  14. package/plugins/html-effectiveness/templates/01-exploration-code-approaches.html.tmpl +400 -0
  15. package/plugins/html-effectiveness/templates/02-exploration-visual-designs.html.tmpl +456 -0
  16. package/plugins/html-effectiveness/templates/03-code-review-pr.html.tmpl +581 -0
  17. package/plugins/html-effectiveness/templates/04-code-understanding.html.tmpl +443 -0
  18. package/plugins/html-effectiveness/templates/05-design-system.html.tmpl +578 -0
  19. package/plugins/html-effectiveness/templates/06-component-variants.html.tmpl +557 -0
  20. package/plugins/html-effectiveness/templates/07-prototype-animation.html.tmpl +417 -0
  21. package/plugins/html-effectiveness/templates/08-prototype-interaction.html.tmpl +363 -0
  22. package/plugins/html-effectiveness/templates/09-slide-deck.html.tmpl +535 -0
  23. package/plugins/html-effectiveness/templates/10-svg-illustrations.html.tmpl +444 -0
  24. package/plugins/html-effectiveness/templates/11-status-report.html.tmpl +152 -0
  25. package/plugins/html-effectiveness/templates/12-incident-report.html.tmpl +547 -0
  26. package/plugins/html-effectiveness/templates/13-flowchart-diagram.html.tmpl +361 -0
  27. package/plugins/html-effectiveness/templates/14-research-feature-explainer.html.tmpl +348 -0
  28. package/plugins/html-effectiveness/templates/15-research-concept-explainer.html.tmpl +334 -0
  29. package/plugins/html-effectiveness/templates/16-implementation-plan.html.tmpl +657 -0
  30. package/plugins/html-effectiveness/templates/17-pr-writeup.html.tmpl +553 -0
  31. package/plugins/html-effectiveness/templates/18-editor-triage-board.html.tmpl +541 -0
  32. package/plugins/html-effectiveness/templates/19-editor-feature-flags.html.tmpl +627 -0
  33. package/plugins/html-effectiveness/templates/20-editor-prompt-tuner.html.tmpl +687 -0
  34. package/plugins/html-effectiveness/templates/manifest.json +436 -2
  35. package/plugins/html-effectiveness/tests/_tmp.test.js +58 -0
  36. package/plugins/html-effectiveness/tests/fixtures/01-exploration-code-approaches.data.json +3 -0
  37. package/plugins/html-effectiveness/tests/fixtures/02-exploration-visual-designs.data.json +3 -0
  38. package/plugins/html-effectiveness/tests/fixtures/03-code-review-pr.data.json +3 -0
  39. package/plugins/html-effectiveness/tests/fixtures/04-code-understanding.data.json +3 -0
  40. package/plugins/html-effectiveness/tests/fixtures/05-design-system.data.json +3 -0
  41. package/plugins/html-effectiveness/tests/fixtures/06-component-variants.data.json +3 -0
  42. package/plugins/html-effectiveness/tests/fixtures/07-prototype-animation.data.json +3 -0
  43. package/plugins/html-effectiveness/tests/fixtures/08-prototype-interaction.data.json +3 -0
  44. package/plugins/html-effectiveness/tests/fixtures/09-slide-deck.data.json +3 -0
  45. package/plugins/html-effectiveness/tests/fixtures/10-svg-illustrations.data.json +3 -0
  46. package/plugins/html-effectiveness/tests/fixtures/11-status-report.data.json +37 -0
  47. package/plugins/html-effectiveness/tests/fixtures/12-incident-report.data.json +3 -0
  48. package/plugins/html-effectiveness/tests/fixtures/13-flowchart-diagram.data.json +3 -0
  49. package/plugins/html-effectiveness/tests/fixtures/14-research-feature-explainer.data.json +3 -0
  50. package/plugins/html-effectiveness/tests/fixtures/15-research-concept-explainer.data.json +3 -0
  51. package/plugins/html-effectiveness/tests/fixtures/16-implementation-plan.data.json +3 -0
  52. package/plugins/html-effectiveness/tests/fixtures/17-pr-writeup.data.json +3 -0
  53. package/plugins/html-effectiveness/tests/fixtures/18-editor-triage-board.data.json +3 -0
  54. package/plugins/html-effectiveness/tests/fixtures/19-editor-feature-flags.data.json +3 -0
  55. package/plugins/html-effectiveness/tests/fixtures/20-editor-prompt-tuner.data.json +3 -0
  56. package/plugins/html-effectiveness/tests/manifest.test.js +61 -0
  57. package/plugins/plugin-validator/.claude-plugin/plugin.json +1 -1
  58. package/plugins/plugin-validator/skills/validate-agents/SKILL.md +2 -2
  59. package/plugins/plugin-validator/skills/validate-commands/SKILL.md +2 -2
  60. package/plugins/plugin-validator/skills/validate-hooks/SKILL.md +57 -18
  61. package/plugins/team-superpower/.claude-plugin/plugin.json +7 -39
  62. package/plugins/team-superpower/README.md +85 -24
  63. package/plugins/team-superpower/agents/backend-developer.md +82 -0
  64. package/plugins/team-superpower/agents/designer.md +5 -1
  65. package/plugins/team-superpower/agents/frontend-developer.md +96 -0
  66. package/plugins/team-superpower/agents/planner.md +144 -16
  67. package/plugins/team-superpower/agents/qa-engineer.md +30 -0
  68. package/plugins/team-superpower/agents/reviewer.md +68 -22
  69. package/plugins/team-superpower/agents/security-engineer.md +110 -0
  70. package/plugins/team-superpower/agents/software-architect.md +30 -0
  71. package/plugins/team-superpower/assets/CLAUDE.md.template +96 -0
  72. package/plugins/team-superpower/assets/ESCALATION.md +19 -5
  73. package/plugins/team-superpower/assets/SESSION_README.md +119 -11
  74. package/plugins/team-superpower/commands/team-feature-resume.md +72 -6
  75. package/plugins/team-superpower/commands/team-feature.md +329 -28
  76. package/plugins/team-superpower/hooks/hooks.json +0 -3
  77. package/plugins/team-superpower/hooks/task-completed.sh +54 -5
  78. package/plugins/team-superpower/hooks/task-created.sh +79 -4
  79. package/plugins/team-superpower/scripts/detect-stack.sh +434 -0
  80. package/plugins/team-superpower/scripts/parse-claudemd.sh +194 -0
  81. package/plugins/tech-graph/.claude-plugin/plugin.json +1 -1
  82. package/plugins/tech-graph/agents/tech-graph.md +8 -0
  83. package/plugins/team-superpower/agents/implementer.md +0 -46
@@ -12,7 +12,7 @@
12
12
  "name": "tech-graph",
13
13
  "source": "./plugins/tech-graph",
14
14
  "description": "6-step wizard for technical diagrams (SVG/PNG) via fireworks-tech-graph",
15
- "version": "0.0.13",
15
+ "version": "0.0.15",
16
16
  "category": "diagram",
17
17
  "keywords": [
18
18
  "diagram",
@@ -26,7 +26,7 @@
26
26
  "name": "html-effectiveness",
27
27
  "source": "./plugins/html-effectiveness",
28
28
  "description": "Generate self-contained interactive HTML reports from 20 upstream templates via a conversational agent.",
29
- "version": "0.0.13",
29
+ "version": "0.0.15",
30
30
  "category": "reports",
31
31
  "keywords": [
32
32
  "html",
@@ -40,8 +40,8 @@
40
40
  {
41
41
  "name": "team-superpower",
42
42
  "source": "./plugins/team-superpower",
43
- "description": "Coordination layer that runs the obra/superpowers skill chain across a Claude Code agent teamone /team-feature command takes an idea through brainstorming, plan, TDD implementation, review, and finish with at most 4 owner touchpoints.",
44
- "version": "0.0.13",
43
+ "description": "Shape-adaptive engineering team that runs the Superpowers skill chain across up to 8 roles designer, planner, software-architect, security-engineer, backend-developer, frontend-developer, qa-engineer, reviewer driven by a `team-superpower` block in CLAUDE.md. Spawns 7 or 8 roles depending on stack (full-stack / be-only / fe-only), enforces contract sync between BE and FE, and gates the finish branch on CI green.",
44
+ "version": "0.0.15",
45
45
  "category": "workflow",
46
46
  "keywords": [
47
47
  "agent-teams",
@@ -50,14 +50,17 @@
50
50
  "orchestration",
51
51
  "workflow",
52
52
  "brainstorming",
53
- "code-review"
53
+ "code-review",
54
+ "architecture",
55
+ "security",
56
+ "qa"
54
57
  ]
55
58
  },
56
59
  {
57
60
  "name": "plugin-validator",
58
61
  "source": "./plugins/plugin-validator",
59
62
  "description": "Orchestrated validator for Claude Code plugins — validates skills, agents, commands, and hooks across every plugin under plugins/**.",
60
- "version": "0.0.13",
63
+ "version": "0.0.15",
61
64
  "category": "tooling",
62
65
  "keywords": [
63
66
  "validation",
package/README.md CHANGED
@@ -10,7 +10,7 @@ Published on npm as [`@drunkcoding/agents-and-skills`](https://www.npmjs.com/pac
10
10
  |--------|-------------|
11
11
  | [`tech-graph`](plugins/tech-graph) | 6-step wizard for technical diagrams (SVG + PNG). |
12
12
  | [`html-effectiveness`](plugins/html-effectiveness) | Conversational agent that generates self-contained interactive HTML reports from 20 templates. |
13
- | [`team-superpower`](plugins/team-superpower) | Agent-team conductor that runs the obra/superpowers skill chain end-to-end with at most 4 owner touchpoints. |
13
+ | [`team-superpower`](plugins/team-superpower) | Shape-adaptive engineering team running the Superpowers skill chain — up to 8 roles (designer, planner, software-architect, security-engineer, backend-developer, frontend-developer, qa-engineer, reviewer); spawns 7 or 8 depending on stack (`full-stack` / `be-only` / `fe-only`) declared in `CLAUDE.md`. Test/build commands, contract publish + sync, security checklist, and CI gate before merge are all driven by the project's `CLAUDE.md` `team-superpower` block. |
14
14
  | [`plugin-validator`](plugins/plugin-validator) | Orchestrated validator that checks every plugin's skills, agents, commands, and hooks for spec compliance — runs in parallel and proposes batched fixes. |
15
15
 
16
16
  ## Install
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drunkcoding/agents-and-skills",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
4
  "description": "Personal collection of Claude Code skills and agents, installable via `npx skills`.",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "html-effectiveness",
3
3
  "displayName": "HTML Effectiveness Reports",
4
- "version": "0.0.13",
4
+ "version": "0.0.15",
5
5
  "description": "Generate self-contained interactive HTML reports from 20 upstream templates via a conversational agent.",
6
6
  "author": {
7
7
  "name": "Steven Hoang"
@@ -12,12 +12,17 @@ Override output dir in repo `CLAUDE.md`:
12
12
  html-effectiveness.reportDir: my/custom/reports
13
13
  ```
14
14
 
15
- ## Sync upstream
15
+ ## Vendored templates
16
16
 
17
- Re-fetch templates from `ThariqS/html-effectiveness`:
17
+ Templates are vendored from `ThariqS/html-effectiveness`. The pinned SHA lives in `templates/manifest.json` (`_meta.upstream_sha`). Re-fetch is **manual** — only run when you want to refresh the snapshot:
18
18
 
19
19
  ```bash
20
- node plugins/html-effectiveness/scripts/sync-upstream.js
20
+ node plugins/html-effectiveness/scripts/extract.js fetch <id>.html
21
+ node plugins/html-effectiveness/scripts/extract.js split <id>.html
21
22
  ```
22
23
 
23
- See `docs/template-gallery.md` for the full pattern catalog.
24
+ Files land under `.tmp/html-effectiveness/extract/` and are cleaned up automatically. Hand-merge any changes back into `templates/<id>.html.tmpl`.
25
+
26
+ ## Scratch convention
27
+
28
+ All plugin scratch lives under `.tmp/html-effectiveness/<purpose>/` (gitignored). Helper API: `scripts/_tmp.js` exports `getTmpDir`, `cleanup`, and `withTmp` for try/finally + signal-handler cleanup.
@@ -42,6 +42,10 @@ On every run:
42
42
  5. On success: print the absolute path; offer `snip render --format html < <path>` to preview in the browser.
43
43
  6. On render error: surface stderr; locate the offending slot from the `template:slot` prefix; ask the user to fix; retry.
44
44
 
45
+ ## Output
46
+
47
+ A self-contained interactive HTML report at `<reportDir>/YYYY-MM-DD-<slug>.html` plus a `<slug>.html.data.json` sidecar for later re-rendering. The absolute path is printed to the user on success, with an offer to preview via `snip render --format html`.
48
+
45
49
  ## Regen path
46
50
 
47
51
  If the user invokes the agent on an existing `<name>.data.json`:
@@ -1,27 +1,47 @@
1
- /* Theme variables, typography, print baseline. Populated from upstream during Task 7. */
1
+ /* Shared design tokens + page baseline. Vendored from ThariqS/html-effectiveness. */
2
2
  :root {
3
- --bg: #ffffff;
4
- --fg: #111111;
5
- --muted: #666666;
6
- --accent: #2563eb;
7
- --border: #e5e7eb;
8
- --radius: 6px;
9
- --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
10
- --mono: ui-monospace, "SF Mono", Menlo, Monaco, Consolas, monospace;
3
+ --ivory: #FAF9F5;
4
+ --slate: #141413;
5
+ --clay: #D97757;
6
+ --oat: #E3DACC;
7
+ --olive: #788C5D;
8
+ --rust: #B04A3F;
9
+ --gray-100: #F0EEE6;
10
+ --gray-300: #D1CFC5;
11
+ --gray-500: #87867F;
12
+ --gray-700: #3D3D3A;
13
+ --white: #FFFFFF;
14
+
15
+ --serif: ui-serif, Georgia, serif;
16
+ --sans: system-ui, -apple-system, sans-serif;
17
+ --mono: ui-monospace, "SF Mono", Menlo, monospace;
18
+
19
+ --radius-panel: 12px;
20
+ --radius-row: 8px;
21
+ --border-thick: 1.5px solid var(--gray-300);
22
+
23
+ /* legacy aliases for components.css stubs */
24
+ --bg: var(--ivory);
25
+ --fg: var(--slate);
26
+ --muted: var(--gray-500);
27
+ --accent: var(--clay);
28
+ --border: 1px solid var(--gray-300);
29
+ --radius: var(--radius-panel);
30
+ --font: var(--sans);
11
31
  --transition: 150ms ease;
12
32
  }
13
- @media (prefers-color-scheme: dark) {
14
- :root {
15
- --bg: #0b0b0c;
16
- --fg: #f5f5f7;
17
- --muted: #9aa0a6;
18
- --accent: #60a5fa;
19
- --border: #2a2a2c;
20
- }
21
- }
22
33
  * { box-sizing: border-box; }
23
- html, body { margin: 0; padding: 0; background: var(--bg); color: var(--fg); font-family: var(--font); }
24
- a { color: var(--accent); text-decoration: none; }
34
+ html, body {
35
+ margin: 0;
36
+ padding: 0;
37
+ background: var(--ivory);
38
+ color: var(--slate);
39
+ font-family: var(--sans);
40
+ font-size: 15px;
41
+ line-height: 1.6;
42
+ -webkit-font-smoothing: antialiased;
43
+ }
44
+ a { color: var(--clay); text-decoration: none; }
25
45
  a:hover { text-decoration: underline; }
26
46
  @media print {
27
47
  details { display: block; }
@@ -0,0 +1,28 @@
1
+ # Template Gallery
2
+
3
+ Generated from `templates/manifest.json`. Upstream: `ThariqS/html-effectiveness@a1fb5673c26f87be9b833e1876cf4fd0f30f5f2d` (fetched 2026-05-13).
4
+
5
+ | ID | Title | Pattern | Use cases | Required slots |
6
+ |----|-------|---------|-----------|----------------|
7
+ | `01-exploration-code-approaches` | Code-Approaches Exploration | `comparison_board` | "compare implementations", "approach trade-offs", "design alternatives" | `title` |
8
+ | `02-exploration-visual-designs` | Visual Design Exploration | `comparison_board` | "compare designs", "UI alternatives", "visual options" | `title` |
9
+ | `03-code-review-pr` | PR Code Review Board | `code_review_board` | "PR review", "code review", "diff review" | `title` |
10
+ | `04-code-understanding` | Code Walkthrough | `knowledge_explorer` | "explain code", "walk through architecture", "trace logic" | `title` |
11
+ | `05-design-system` | Design System Sheet | `design_system_sheet` | "design tokens", "color palette", "typography" | `title` |
12
+ | `06-component-variants` | Component Variant Matrix | `design_system_sheet` | "component variants", "states gallery" | `title` |
13
+ | `07-prototype-animation` | Animation Prototype | `interactive_report` | "animation prototype", "motion preview" | `title` |
14
+ | `08-prototype-interaction` | Interaction Prototype | `interactive_report` | "interaction prototype", "ux flow" | `title` |
15
+ | `09-slide-deck` | Slide Deck | `slide_deck` | "slide deck", "presentation", "pitch" | `title` |
16
+ | `10-svg-illustrations` | SVG Illustration Gallery | `knowledge_explorer` | "illustrate concept", "svg gallery" | `title` |
17
+ | `11-status-report` | Status Report | `interactive_report` | "weekly status", "project update", "team digest", "monthly recap", "engineering status" | `title`, `date_range` |
18
+ | `12-incident-report` | Incident Report | `interactive_report` | "incident report", "post-mortem", "outage writeup" | `title` |
19
+ | `13-flowchart-diagram` | Flowchart Diagram | `knowledge_explorer` | "flowchart", "process diagram", "decision tree" | `title` |
20
+ | `14-research-feature-explainer` | Feature Explainer | `knowledge_explorer` | "explain feature", "feature deep-dive" | `title` |
21
+ | `15-research-concept-explainer` | Concept Explainer | `knowledge_explorer` | "explain concept", "tutorial", "primer" | `title` |
22
+ | `16-implementation-plan` | Implementation Plan | `annotated_timeline` | "implementation plan", "phased rollout", "roadmap" | `title` |
23
+ | `17-pr-writeup` | PR Writeup | `interactive_report` | "PR description", "release notes", "change writeup" | `title` |
24
+ | `18-editor-triage-board` | Triage Board | `kanban_board` | "bug triage", "issue board", "kanban" | `title` |
25
+ | `19-editor-feature-flags` | Feature Flags Matrix | `decision_matrix` | "feature flags", "rollout matrix" | `title` |
26
+ | `20-editor-prompt-tuner` | Prompt Tuner | `interactive_report` | "prompt tuning", "LLM config" | `title` |
27
+
28
+ _20 templates._
@@ -0,0 +1,37 @@
1
+ import { mkdirSync, rmSync } from 'node:fs';
2
+ import { dirname, resolve, join } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ const HERE = dirname(fileURLToPath(import.meta.url));
6
+ const REPO_ROOT = resolve(HERE, '..', '..', '..');
7
+ export const ROOT = join(REPO_ROOT, '.tmp', 'html-effectiveness');
8
+
9
+ export function getTmpDir(purpose) {
10
+ if (!purpose || /[\\/]/.test(purpose)) {
11
+ throw new Error(`purpose must be a single path segment, got: ${purpose}`);
12
+ }
13
+ const dir = join(ROOT, purpose);
14
+ rmSync(dir, { recursive: true, force: true });
15
+ mkdirSync(dir, { recursive: true });
16
+ return dir;
17
+ }
18
+
19
+ export function cleanup(purpose) {
20
+ rmSync(join(ROOT, purpose), { recursive: true, force: true });
21
+ }
22
+
23
+ export function withTmp(purpose, fn) {
24
+ const dir = getTmpDir(purpose);
25
+ const onSig = () => {
26
+ try { cleanup(purpose); } finally { process.exit(130); }
27
+ };
28
+ process.once('SIGINT', onSig);
29
+ process.once('SIGTERM', onSig);
30
+ try {
31
+ return fn(dir);
32
+ } finally {
33
+ cleanup(purpose);
34
+ process.off('SIGINT', onSig);
35
+ process.off('SIGTERM', onSig);
36
+ }
37
+ }
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env node
2
+ // Generate docs/template-gallery.md from templates/manifest.json.
3
+ // Idempotent. Run after editing manifest.
4
+
5
+ import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
6
+ import { dirname, join, resolve } from 'node:path';
7
+ import { fileURLToPath, pathToFileURL } from 'node:url';
8
+
9
+ const HERE = dirname(fileURLToPath(import.meta.url));
10
+ const PLUGIN_ROOT = dirname(HERE);
11
+
12
+ function build() {
13
+ const manifest = JSON.parse(readFileSync(join(PLUGIN_ROOT, 'templates/manifest.json'), 'utf8'));
14
+ const meta = manifest._meta || {};
15
+ const rows = Object.entries(manifest)
16
+ .filter(([k]) => k !== '_meta')
17
+ .sort(([a], [b]) => a.localeCompare(b));
18
+
19
+ const lines = [];
20
+ lines.push('# Template Gallery');
21
+ lines.push('');
22
+ lines.push(`Generated from \`templates/manifest.json\`. Upstream: \`${meta.upstream_repo}@${meta.upstream_sha}\` (fetched ${meta.fetched_at}).`);
23
+ lines.push('');
24
+ lines.push('| ID | Title | Pattern | Use cases | Required slots |');
25
+ lines.push('|----|-------|---------|-----------|----------------|');
26
+ for (const [id, e] of rows) {
27
+ const reqSlots = Object.entries(e.slots || {})
28
+ .filter(([, s]) => (typeof s === 'object' ? s.required : false))
29
+ .map(([n]) => `\`${n}\``)
30
+ .join(', ') || '—';
31
+ const use = (e.use_cases || []).map((u) => `"${u}"`).join(', ');
32
+ lines.push(`| \`${id}\` | ${e.title} | \`${e.pattern}\` | ${use} | ${reqSlots} |`);
33
+ }
34
+ lines.push('');
35
+ lines.push(`_${rows.length} templates._`);
36
+ lines.push('');
37
+ return lines.join('\n');
38
+ }
39
+
40
+ function main() {
41
+ const out = join(PLUGIN_ROOT, 'docs/template-gallery.md');
42
+ mkdirSync(dirname(out), { recursive: true });
43
+ writeFileSync(out, build(), 'utf8');
44
+ process.stdout.write(out + '\n');
45
+ }
46
+
47
+ if (import.meta.url === pathToFileURL(process.argv[1]).href) main();
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env node
2
+ import { writeFileSync, readFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { pathToFileURL } from 'node:url';
5
+ import { getTmpDir, ROOT } from './_tmp.js';
6
+
7
+ const UPSTREAM_REPO = 'ThariqS/html-effectiveness';
8
+ const API_BASE = 'https://api.github.com';
9
+ const RAW_BASE = 'https://raw.githubusercontent.com';
10
+
11
+ async function ghFetch(url, accept = 'application/vnd.github+json') {
12
+ const headers = { 'Accept': accept, 'User-Agent': 'html-effectiveness-vendor' };
13
+ if (process.env.GITHUB_TOKEN) headers['Authorization'] = `Bearer ${process.env.GITHUB_TOKEN}`;
14
+ const res = await fetch(url, { headers });
15
+ if (!res.ok) {
16
+ throw new Error(`HTTP ${res.status} ${res.statusText} for ${url}`);
17
+ }
18
+ return res;
19
+ }
20
+
21
+ export async function fetchUpstreamFile(filename, ref = 'main') {
22
+ const url = `${RAW_BASE}/${UPSTREAM_REPO}/${ref}/${filename}`;
23
+ const res = await ghFetch(url, 'text/plain');
24
+ return await res.text();
25
+ }
26
+
27
+ export async function fetchUpstreamSha(ref = 'main') {
28
+ const url = `${API_BASE}/repos/${UPSTREAM_REPO}/commits/${ref}`;
29
+ const res = await ghFetch(url);
30
+ const json = await res.json();
31
+ return json.sha;
32
+ }
33
+
34
+ export async function listUpstreamFiles(ref = 'main') {
35
+ const url = `${API_BASE}/repos/${UPSTREAM_REPO}/contents?ref=${ref}`;
36
+ const res = await ghFetch(url);
37
+ const json = await res.json();
38
+ return json.filter((e) => e.type === 'file').map((e) => e.name);
39
+ }
40
+
41
+ export function extractParts(html) {
42
+ const styles = [];
43
+ const scripts = [];
44
+ let body = html;
45
+ body = body.replace(/<style[^>]*>([\s\S]*?)<\/style>/g, (_, css) => {
46
+ styles.push(css.trim());
47
+ return '';
48
+ });
49
+ body = body.replace(/<script[^>]*>([\s\S]*?)<\/script>/g, (_, js) => {
50
+ if (js.trim()) scripts.push(js.trim());
51
+ return '';
52
+ });
53
+ body = body
54
+ .replace(/<!doctype[^>]*>/i, '')
55
+ .replace(/<\/?html[^>]*>/gi, '')
56
+ .replace(/<head[\s\S]*?<\/head>/gi, '')
57
+ .replace(/<\/?body[^>]*>/gi, '');
58
+ return { styles, scripts, body: body.trim() };
59
+ }
60
+
61
+ function ensureWorkdir() {
62
+ return getTmpDir('extract');
63
+ }
64
+
65
+ function readFromWorkdir(name) {
66
+ return readFileSync(join(ROOT, 'extract', name), 'utf8');
67
+ }
68
+
69
+ function writeToWorkdir(dir, name, content) {
70
+ writeFileSync(join(dir, name), content);
71
+ }
72
+
73
+ async function cli() {
74
+ const [, , cmd, arg] = process.argv;
75
+ if (cmd === 'fetch') {
76
+ if (!arg) { process.stderr.write('usage: extract.js fetch <file>\n'); process.exit(1); }
77
+ const dir = ensureWorkdir();
78
+ const html = await fetchUpstreamFile(arg);
79
+ writeToWorkdir(dir, arg, html);
80
+ process.stdout.write(`${join(dir, arg)}\n`);
81
+ } else if (cmd === 'sha') {
82
+ process.stdout.write(await fetchUpstreamSha() + '\n');
83
+ } else if (cmd === 'list') {
84
+ const files = await listUpstreamFiles();
85
+ process.stdout.write(files.join('\n') + '\n');
86
+ } else if (cmd === 'split') {
87
+ if (!arg) { process.stderr.write('usage: extract.js split <file>\n'); process.exit(1); }
88
+ const html = readFromWorkdir(arg);
89
+ const { styles, scripts, body } = extractParts(html);
90
+ const base = arg.replace(/\.html$/, '');
91
+ const dir = join(ROOT, 'extract');
92
+ writeToWorkdir(dir, `${base}.body.html`, body + '\n');
93
+ writeToWorkdir(dir, `${base}.styles.css`, styles.join('\n\n/* --- */\n\n') + '\n');
94
+ writeToWorkdir(dir, `${base}.scripts.js`, scripts.join('\n\n/* --- */\n\n') + '\n');
95
+ process.stdout.write(`${dir}/${base}.{body.html,styles.css,scripts.js}\n`);
96
+ } else {
97
+ process.stderr.write('usage: extract.js {fetch <file>|sha|list|split <file>}\n');
98
+ process.exit(1);
99
+ }
100
+ }
101
+
102
+ if (import.meta.url === pathToFileURL(process.argv[1]).href) {
103
+ cli().catch((e) => { process.stderr.write(e.stack + '\n'); process.exit(1); });
104
+ }
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
6
6
  import { dirname, resolve, join } from 'node:path';
7
- import { fileURLToPath } from 'node:url';
7
+ import { fileURLToPath, pathToFileURL } from 'node:url';
8
8
  import { parseArgs } from 'node:util';
9
9
  import { render as mustache } from './mustache.js';
10
10
 
@@ -173,4 +173,4 @@ function cli() {
173
173
  }
174
174
  }
175
175
 
176
- if (import.meta.url === `file://${process.argv[1]}`) cli();
176
+ if (import.meta.url === pathToFileURL(process.argv[1]).href) cli();
@@ -26,7 +26,7 @@ If the request fits a report-style output and rendering as HTML would be clearer
26
26
 
27
27
  ## Template catalog
28
28
 
29
- 20 templates ship with this plugin. See `docs/template-gallery.md` for the full table (auto-generated from `templates/manifest.json`). Highlights:
29
+ 20 templates ship with this plugin. Full table in `plugins/html-effectiveness/docs/template-gallery.md` (regen via `node plugins/html-effectiveness/scripts/catalog.js`). Highlights:
30
30
 
31
31
  - `01` / `02` — exploration comparisons (code approaches, visual designs)
32
32
  - `03` — code review board
@@ -77,7 +77,7 @@ Preserved from upstream `ThariqS/html-effectiveness`:
77
77
  ## Technical requirements
78
78
 
79
79
  - Single `.html` file, fully self-contained.
80
- - CSS variables for light/dark theming via `prefers-color-scheme`.
80
+ - CSS variables for theming (light-only baseline, matching upstream palette).
81
81
  - System font stack and 150ms smooth transitions.
82
82
  - Responsive design 375px–1440px.
83
83
  - Semantic HTML5 with ARIA labels.
@@ -89,6 +89,6 @@ Preserved from upstream `ThariqS/html-effectiveness`:
89
89
  - **Missing slot data**: ask one question at a time; respect the cap of 6 questions before forcing render with best-guess defaults plus a note of what was assumed.
90
90
  - **Render error**: surface `template:slot expected <type> got <type>` to the user; fix the slot value; retry.
91
91
 
92
- ## Sync
92
+ ## Vendored templates
93
93
 
94
- Generated from upstream `ThariqS/html-effectiveness@<sha pinned in manifest>`. To refresh: `node plugins/html-effectiveness/scripts/sync-upstream.js check`. If drift is detected, re-fetch the affected template, re-run extraction, and review the diff before committing.
94
+ Templates are vendored, not auto-synced. The pinned upstream SHA lives at `templates/manifest.json` → `_meta.upstream_sha`. To refresh a single template: `node plugins/html-effectiveness/scripts/extract.js fetch <id>.html` then `split <id>.html`. Files land in `.tmp/html-effectiveness/extract/` (gitignored). Hand-merge the diff back into `templates/<id>.html.tmpl` and update `_meta.upstream_sha` if pinning a new revision.