@drunkcoding/agents-and-skills 0.0.45 → 0.0.46
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/marketplace.json +2 -47
- package/README.md +3 -6
- package/package.json +4 -1
- package/plugins/multica-tool/.claude-plugin/plugin.json +1 -1
- package/plugins/multica-tool/scripts/lib.mjs +53 -4
- package/plugins/multica-tool/scripts/multica-export.mjs +135 -32
- package/plugins/multica-tool/scripts/multica-import.mjs +192 -17
- package/plugins/multica-tool/skills/export/SKILL.md +84 -14
- package/plugins/multica-tool/skills/import/SKILL.md +22 -7
- package/plugins/multica-tool/skills/sync/SKILL.md +1 -1
- package/plugins/plugin-validator/.claude-plugin/plugin.json +1 -1
- package/plugins/html-effectiveness/.claude-plugin/plugin.json +0 -17
- package/plugins/html-effectiveness/README.md +0 -28
- package/plugins/html-effectiveness/agents/report-builder.md +0 -66
- package/plugins/html-effectiveness/assets/base.css +0 -51
- package/plugins/html-effectiveness/assets/base.js +0 -11
- package/plugins/html-effectiveness/assets/charts.js +0 -1
- package/plugins/html-effectiveness/assets/components.css +0 -10
- package/plugins/html-effectiveness/commands/html-report.md +0 -13
- package/plugins/html-effectiveness/docs/template-gallery.md +0 -28
- package/plugins/html-effectiveness/package.json +0 -6
- package/plugins/html-effectiveness/scripts/_tmp.js +0 -37
- package/plugins/html-effectiveness/scripts/catalog.js +0 -47
- package/plugins/html-effectiveness/scripts/extract.js +0 -104
- package/plugins/html-effectiveness/scripts/mustache.js +0 -90
- package/plugins/html-effectiveness/scripts/render.js +0 -176
- package/plugins/html-effectiveness/skills/html-effectiveness/SKILL.md +0 -94
- package/plugins/html-effectiveness/templates/01-exploration-code-approaches.html.tmpl +0 -400
- package/plugins/html-effectiveness/templates/02-exploration-visual-designs.html.tmpl +0 -456
- package/plugins/html-effectiveness/templates/03-code-review-pr.html.tmpl +0 -581
- package/plugins/html-effectiveness/templates/04-code-understanding.html.tmpl +0 -443
- package/plugins/html-effectiveness/templates/05-design-system.html.tmpl +0 -578
- package/plugins/html-effectiveness/templates/06-component-variants.html.tmpl +0 -557
- package/plugins/html-effectiveness/templates/07-prototype-animation.html.tmpl +0 -417
- package/plugins/html-effectiveness/templates/08-prototype-interaction.html.tmpl +0 -363
- package/plugins/html-effectiveness/templates/09-slide-deck.html.tmpl +0 -535
- package/plugins/html-effectiveness/templates/10-svg-illustrations.html.tmpl +0 -444
- package/plugins/html-effectiveness/templates/11-status-report.html.tmpl +0 -152
- package/plugins/html-effectiveness/templates/12-incident-report.html.tmpl +0 -547
- package/plugins/html-effectiveness/templates/13-flowchart-diagram.html.tmpl +0 -361
- package/plugins/html-effectiveness/templates/14-research-feature-explainer.html.tmpl +0 -348
- package/plugins/html-effectiveness/templates/15-research-concept-explainer.html.tmpl +0 -334
- package/plugins/html-effectiveness/templates/16-implementation-plan.html.tmpl +0 -657
- package/plugins/html-effectiveness/templates/17-pr-writeup.html.tmpl +0 -553
- package/plugins/html-effectiveness/templates/18-editor-triage-board.html.tmpl +0 -541
- package/plugins/html-effectiveness/templates/19-editor-feature-flags.html.tmpl +0 -627
- package/plugins/html-effectiveness/templates/20-editor-prompt-tuner.html.tmpl +0 -687
- package/plugins/html-effectiveness/templates/manifest.json +0 -441
- package/plugins/team-share/.claude-plugin/plugin.json +0 -18
- package/plugins/team-share/README.md +0 -46
- package/plugins/team-share/agents/team-share.md +0 -53
- package/plugins/team-share/commands/team-share.md +0 -4
- package/plugins/team-share/skills/claude-config/SKILL.md +0 -143
- package/plugins/team-share/skills/codegraph-setup/SKILL.md +0 -81
- package/plugins/team-share/skills/understand-setup/SKILL.md +0 -115
- package/plugins/tech-graph/.claude-plugin/plugin.json +0 -17
- package/plugins/tech-graph/README.md +0 -66
- package/plugins/tech-graph/agents/tech-graph.md +0 -97
- package/plugins/tech-graph/commands/tech-graph.md +0 -13
- package/plugins/tech-graph/scripts/check-deps.sh +0 -55
- package/plugins/tech-graph/skills/tech-graph/LICENSE +0 -21
- package/plugins/tech-graph/skills/tech-graph/README.md +0 -555
- package/plugins/tech-graph/skills/tech-graph/README.zh.md +0 -514
- package/plugins/tech-graph/skills/tech-graph/SKILL.md +0 -263
- package/plugins/tech-graph/skills/tech-graph/agents/openai.yaml +0 -4
- package/plugins/tech-graph/skills/tech-graph/assets/samples/sample-style1-flat.png +0 -0
- package/plugins/tech-graph/skills/tech-graph/assets/samples/sample-style2-dark.png +0 -0
- package/plugins/tech-graph/skills/tech-graph/assets/samples/sample-style3-blueprint.png +0 -0
- package/plugins/tech-graph/skills/tech-graph/assets/samples/sample-style4-notion.png +0 -0
- package/plugins/tech-graph/skills/tech-graph/assets/samples/sample-style5-glass.png +0 -0
- package/plugins/tech-graph/skills/tech-graph/assets/samples/sample-style6-claude.png +0 -0
- package/plugins/tech-graph/skills/tech-graph/assets/samples/sample-style7-openai.png +0 -0
- package/plugins/tech-graph/skills/tech-graph/fixtures/agent-memory-types-style4.json +0 -181
- package/plugins/tech-graph/skills/tech-graph/fixtures/api-flow-style7.json +0 -40
- package/plugins/tech-graph/skills/tech-graph/fixtures/mem0-style1.json +0 -297
- package/plugins/tech-graph/skills/tech-graph/fixtures/microservices-style3.json +0 -64
- package/plugins/tech-graph/skills/tech-graph/fixtures/multi-agent-style5.json +0 -45
- package/plugins/tech-graph/skills/tech-graph/fixtures/system-architecture-style6.json +0 -48
- package/plugins/tech-graph/skills/tech-graph/fixtures/tool-call-style2.json +0 -182
- package/plugins/tech-graph/skills/tech-graph/package.json +0 -42
- package/plugins/tech-graph/skills/tech-graph/references/diagram-types.md +0 -171
- package/plugins/tech-graph/skills/tech-graph/references/icons.md +0 -406
- package/plugins/tech-graph/skills/tech-graph/references/style-1-flat-icon.md +0 -108
- package/plugins/tech-graph/skills/tech-graph/references/style-2-dark-terminal.md +0 -107
- package/plugins/tech-graph/skills/tech-graph/references/style-3-blueprint.md +0 -113
- package/plugins/tech-graph/skills/tech-graph/references/style-4-notion-clean.md +0 -95
- package/plugins/tech-graph/skills/tech-graph/references/style-5-glassmorphism.md +0 -125
- package/plugins/tech-graph/skills/tech-graph/references/style-6-claude-official.md +0 -209
- package/plugins/tech-graph/skills/tech-graph/references/style-7-openai.md +0 -215
- package/plugins/tech-graph/skills/tech-graph/references/style-diagram-matrix.md +0 -135
- package/plugins/tech-graph/skills/tech-graph/references/svg-layout-best-practices.md +0 -100
- package/plugins/tech-graph/skills/tech-graph/references/svg-to-png.md +0 -115
- package/plugins/tech-graph/skills/tech-graph/scripts/README.md +0 -269
- package/plugins/tech-graph/skills/tech-graph/scripts/generate-diagram.sh +0 -181
- package/plugins/tech-graph/skills/tech-graph/scripts/generate-from-template.py +0 -1587
- package/plugins/tech-graph/skills/tech-graph/scripts/test-all-styles.sh +0 -143
- package/plugins/tech-graph/skills/tech-graph/scripts/validate-svg.sh +0 -306
- package/plugins/tech-graph/skills/tech-graph/templates/agent-architecture.svg +0 -28
- package/plugins/tech-graph/skills/tech-graph/templates/architecture.svg +0 -23
- package/plugins/tech-graph/skills/tech-graph/templates/comparison-matrix.svg +0 -14
- package/plugins/tech-graph/skills/tech-graph/templates/data-flow.svg +0 -28
- package/plugins/tech-graph/skills/tech-graph/templates/er-diagram.svg +0 -21
- package/plugins/tech-graph/skills/tech-graph/templates/flowchart.svg +0 -21
- package/plugins/tech-graph/skills/tech-graph/templates/sequence.svg +0 -20
- package/plugins/tech-graph/skills/tech-graph/templates/state-machine.svg +0 -20
- package/plugins/tech-graph/skills/tech-graph/templates/timeline.svg +0 -19
- package/plugins/tech-graph/skills/tech-graph/templates/use-case.svg +0 -21
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
# html-effectiveness
|
|
2
|
-
|
|
3
|
-
Generate self-contained interactive HTML reports (status, incident, PR writeup, decision matrix, slide deck, code review, research explainer, etc.) from 20 upstream templates.
|
|
4
|
-
|
|
5
|
-
## Usage
|
|
6
|
-
|
|
7
|
-
Invoke the `report-builder` agent. It will pick a template, gather slot data conversationally, and render to `docs/reports/YYYY-MM-DD-<slug>.html`.
|
|
8
|
-
|
|
9
|
-
Override output dir in repo `CLAUDE.md`:
|
|
10
|
-
|
|
11
|
-
```
|
|
12
|
-
html-effectiveness.reportDir: my/custom/reports
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## Vendored templates
|
|
16
|
-
|
|
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
|
-
|
|
19
|
-
```bash
|
|
20
|
-
node plugins/html-effectiveness/scripts/extract.js fetch <id>.html
|
|
21
|
-
node plugins/html-effectiveness/scripts/extract.js split <id>.html
|
|
22
|
-
```
|
|
23
|
-
|
|
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.
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: report-builder
|
|
3
|
-
description: Conversational wizard that helps the user generate an HTML report from one of 20 templates (status, incident, PR writeup, decision matrix, slide deck, code review, research explainer, ...). Use when the user wants a polished interactive HTML output instead of markdown. Reads templates/manifest.json and CLAUDE.md html-effectiveness.reportDir for output path.
|
|
4
|
-
tools: Read, Write, Bash, Glob, Grep
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
You are `report-builder`, a conversational wizard that turns the user's intent into a polished, self-contained interactive HTML report.
|
|
8
|
-
|
|
9
|
-
## Role
|
|
10
|
-
|
|
11
|
-
Guide the user from intent → rendered HTML in a single file. Speak briefly. Ask one question at a time. Match the user's caveman setting if active.
|
|
12
|
-
|
|
13
|
-
## Startup
|
|
14
|
-
|
|
15
|
-
On every run:
|
|
16
|
-
|
|
17
|
-
1. Read `CLAUDE.md` from the repo root. Extract `html-effectiveness.reportDir` if present; fallback `docs/reports/`.
|
|
18
|
-
2. Read `plugins/html-effectiveness/templates/manifest.json` (catalog + slot schemas).
|
|
19
|
-
3. Greet briefly; confirm the user's intent.
|
|
20
|
-
|
|
21
|
-
## Conversation loop
|
|
22
|
-
|
|
23
|
-
1. **Classify** — infer the top 2-3 templates from the user's stated need by matching `use_cases` and `pattern` fields in the manifest.
|
|
24
|
-
2. **Confirm** — present the top picks with one-line summaries; let the user pick or override.
|
|
25
|
-
3. **Slot fill** — walk the required slots from `manifest[id].slots` in order. Batch obvious slots and infer from prior context to minimize questions. Cap at 6 user-facing questions; force render with best-guess defaults beyond that, with a one-line note of what was assumed.
|
|
26
|
-
4. **Preview data** — show a JSON summary of slot values; ask "looks right?" before rendering.
|
|
27
|
-
|
|
28
|
-
## Render
|
|
29
|
-
|
|
30
|
-
1. Compute slug from title (kebab-case, ASCII-only, max 60 chars).
|
|
31
|
-
2. Build path `<reportDir>/YYYY-MM-DD-<slug>.html`.
|
|
32
|
-
3. Write `<path>.data.json` first (so the user can re-render later).
|
|
33
|
-
4. Invoke render script via Bash:
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
node plugins/html-effectiveness/scripts/render.js \
|
|
37
|
-
--template=<id> \
|
|
38
|
-
--data=<path>.data.json \
|
|
39
|
-
--out=<path>
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
5. On success: print the absolute path; offer `snip render --format html < <path>` to preview in the browser.
|
|
43
|
-
6. On render error: surface stderr; locate the offending slot from the `template:slot` prefix; ask the user to fix; retry.
|
|
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
|
-
|
|
49
|
-
## Regen path
|
|
50
|
-
|
|
51
|
-
If the user invokes the agent on an existing `<name>.data.json`:
|
|
52
|
-
|
|
53
|
-
- Skip slot fill.
|
|
54
|
-
- Edit only the slots the user wants changed.
|
|
55
|
-
- Re-render to the same path (or new path if requested).
|
|
56
|
-
|
|
57
|
-
## Guardrails
|
|
58
|
-
|
|
59
|
-
- Never write to paths outside the repo root.
|
|
60
|
-
- Create `reportDir` if missing.
|
|
61
|
-
- If the output file already exists, ask the user before overwriting; suggest `-2`, `-3`, ... suffix.
|
|
62
|
-
- Refuse to render if the manifest is missing or the requested template id doesn't exist; surface the valid id list.
|
|
63
|
-
|
|
64
|
-
## Tone
|
|
65
|
-
|
|
66
|
-
Terse, expert, no fluff. Caveman-mode-aware. Code blocks unchanged.
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/* Shared design tokens + page baseline. Vendored from ThariqS/html-effectiveness. */
|
|
2
|
-
:root {
|
|
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);
|
|
31
|
-
--transition: 150ms ease;
|
|
32
|
-
}
|
|
33
|
-
* { box-sizing: border-box; }
|
|
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; }
|
|
45
|
-
a:hover { text-decoration: underline; }
|
|
46
|
-
@media print {
|
|
47
|
-
details { display: block; }
|
|
48
|
-
details > summary { display: none; }
|
|
49
|
-
[hidden] { display: revert !important; }
|
|
50
|
-
body { background: white; color: black; }
|
|
51
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
// Shared interactions: theme toggle, search, nav, copy-on-click. Populated from upstream during Task 7.
|
|
2
|
-
(function () {
|
|
3
|
-
document.addEventListener('click', (e) => {
|
|
4
|
-
const t = e.target.closest('[data-copy]');
|
|
5
|
-
if (!t) return;
|
|
6
|
-
const text = t.getAttribute('data-copy');
|
|
7
|
-
navigator.clipboard?.writeText(text);
|
|
8
|
-
t.setAttribute('data-copied', '1');
|
|
9
|
-
setTimeout(() => t.removeAttribute('data-copied'), 1000);
|
|
10
|
-
});
|
|
11
|
-
})();
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
// Inline SVG chart helpers. Opt-in via manifest.extra_js. Populated from upstream during Task 7.
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/* Shared components: cards, timeline, kanban, matrix, swatches, slides. Populated from upstream during Task 7. */
|
|
2
|
-
.report { max-width: 1200px; margin: 0 auto; padding: 2rem 1rem; }
|
|
3
|
-
.report header h1 { font-size: 1.75rem; margin: 0 0 .25rem; }
|
|
4
|
-
.report header .subtitle { color: var(--muted); margin: 0 0 1.5rem; }
|
|
5
|
-
.card { border: 1px solid var(--border); border-radius: var(--radius); padding: 1rem; transition: border-color var(--transition); }
|
|
6
|
-
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1rem; margin: 0 0 2rem; }
|
|
7
|
-
.stat { display: flex; flex-direction: column; gap: .25rem; }
|
|
8
|
-
.stat .value { font-size: 1.5rem; font-weight: 600; }
|
|
9
|
-
.stat .label { color: var(--muted); font-size: .875rem; }
|
|
10
|
-
.stat .delta { font-size: .75rem; }
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Conversational wizard that renders dense info as a self-contained interactive HTML report (status, incident, PR writeup, slide deck, decision matrix, ...).
|
|
3
|
-
argument-hint: [optional one-line intent or path to existing .data.json]
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
Dispatch the `report-builder` subagent using the Agent tool. Pass `$ARGUMENTS` (which may be empty) as the initial intent seed in the subagent prompt.
|
|
7
|
-
|
|
8
|
-
Subagent dispatch prompt template:
|
|
9
|
-
|
|
10
|
-
> Run the html-effectiveness report wizard. Initial intent seed: `$ARGUMENTS`.
|
|
11
|
-
> If the seed looks like a path to an existing `*.data.json` sidecar, enter the regen flow: load it, ask which slots to change, re-render. Otherwise classify the intent against `plugins/html-effectiveness/templates/manifest.json`, confirm the template pick with the user, fill slots (cap 6 questions), preview the data JSON, then render via `plugins/html-effectiveness/scripts/render.js`. Respect `html-effectiveness.reportDir` from repo `CLAUDE.md` (fallback `docs/reports/`).
|
|
12
|
-
|
|
13
|
-
Do not render or write files in the main thread — the subagent owns the full wizard and the render call.
|
|
@@ -1,28 +0,0 @@
|
|
|
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._
|
|
@@ -1,37 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
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();
|
|
@@ -1,104 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
// Hand-rolled mustache subset: {{var}}, {{{raw}}}, {{#section}}…{{/section}}, {{^inverted}}…{{/inverted}}
|
|
2
|
-
// Zero runtime dependencies.
|
|
3
|
-
|
|
4
|
-
const ESCAPE_MAP = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' };
|
|
5
|
-
const escapeHtml = (s) => String(s).replace(/[&<>"']/g, (c) => ESCAPE_MAP[c]);
|
|
6
|
-
|
|
7
|
-
function tokenize(template) {
|
|
8
|
-
const tokens = [];
|
|
9
|
-
const re = /\{\{(\{?)([\^#\/]?)\s*([\w.-]+)\s*\}?\}\}/g;
|
|
10
|
-
let lastIndex = 0;
|
|
11
|
-
let m;
|
|
12
|
-
while ((m = re.exec(template)) !== null) {
|
|
13
|
-
if (m.index > lastIndex) tokens.push({ type: 'text', value: template.slice(lastIndex, m.index) });
|
|
14
|
-
const [, triple, sigil, name] = m;
|
|
15
|
-
if (sigil === '#') tokens.push({ type: 'section', name });
|
|
16
|
-
else if (sigil === '^') tokens.push({ type: 'inverted', name });
|
|
17
|
-
else if (sigil === '/') tokens.push({ type: 'close', name });
|
|
18
|
-
else if (triple === '{') tokens.push({ type: 'raw', name });
|
|
19
|
-
else tokens.push({ type: 'var', name });
|
|
20
|
-
lastIndex = re.lastIndex;
|
|
21
|
-
}
|
|
22
|
-
if (lastIndex < template.length) tokens.push({ type: 'text', value: template.slice(lastIndex) });
|
|
23
|
-
return tokens;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function parse(tokens, end = null) {
|
|
27
|
-
const nodes = [];
|
|
28
|
-
while (tokens.length) {
|
|
29
|
-
const t = tokens.shift();
|
|
30
|
-
if (t.type === 'close') {
|
|
31
|
-
if (t.name !== end) throw new Error(`Mismatched close tag: expected ${end}, got ${t.name}`);
|
|
32
|
-
return nodes;
|
|
33
|
-
}
|
|
34
|
-
if (t.type === 'section' || t.type === 'inverted') {
|
|
35
|
-
const children = parse(tokens, t.name);
|
|
36
|
-
nodes.push({ ...t, children });
|
|
37
|
-
} else {
|
|
38
|
-
nodes.push(t);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
if (end !== null) throw new Error(`Unclosed section: ${end}`);
|
|
42
|
-
return nodes;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function lookup(ctxStack, name) {
|
|
46
|
-
if (name === '.') return ctxStack[ctxStack.length - 1];
|
|
47
|
-
const parts = name.split('.');
|
|
48
|
-
for (let i = ctxStack.length - 1; i >= 0; i--) {
|
|
49
|
-
let cur = ctxStack[i];
|
|
50
|
-
let ok = true;
|
|
51
|
-
for (const p of parts) {
|
|
52
|
-
if (cur == null || typeof cur !== 'object' || !Object.prototype.hasOwnProperty.call(cur, p)) { ok = false; break; }
|
|
53
|
-
cur = cur[p];
|
|
54
|
-
}
|
|
55
|
-
if (ok) return cur;
|
|
56
|
-
}
|
|
57
|
-
return undefined;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function emit(nodes, ctxStack) {
|
|
61
|
-
let out = '';
|
|
62
|
-
for (const n of nodes) {
|
|
63
|
-
if (n.type === 'text') out += n.value;
|
|
64
|
-
else if (n.type === 'var') {
|
|
65
|
-
const v = lookup(ctxStack, n.name);
|
|
66
|
-
out += v == null ? '' : escapeHtml(v);
|
|
67
|
-
} else if (n.type === 'raw') {
|
|
68
|
-
const v = lookup(ctxStack, n.name);
|
|
69
|
-
out += v == null ? '' : String(v);
|
|
70
|
-
} else if (n.type === 'section') {
|
|
71
|
-
const v = lookup(ctxStack, n.name);
|
|
72
|
-
if (Array.isArray(v)) {
|
|
73
|
-
for (const item of v) out += emit(n.children, [...ctxStack, item]);
|
|
74
|
-
} else if (v && (typeof v !== 'object' || Object.keys(v).length > 0)) {
|
|
75
|
-
out += emit(n.children, [...ctxStack, v]);
|
|
76
|
-
}
|
|
77
|
-
} else if (n.type === 'inverted') {
|
|
78
|
-
const v = lookup(ctxStack, n.name);
|
|
79
|
-
const empty = v == null || v === false || (Array.isArray(v) && v.length === 0);
|
|
80
|
-
if (empty) out += emit(n.children, ctxStack);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return out;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export function render(template, data) {
|
|
87
|
-
const tokens = tokenize(template);
|
|
88
|
-
const tree = parse(tokens);
|
|
89
|
-
return emit(tree, [data]);
|
|
90
|
-
}
|