@heart-of-gold/toolkit 0.1.35 → 0.1.37

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.
@@ -15,19 +15,19 @@
15
15
  "name": "deep-thought",
16
16
  "source": "./plugins/deep-thought",
17
17
  "description": "The Answer Computer — reasoning tools for brainstorming, planning, and deep thinking",
18
- "version": "0.2.5"
18
+ "version": "0.2.7"
19
19
  },
20
20
  {
21
21
  "name": "marvin",
22
22
  "source": "./plugins/marvin",
23
23
  "description": "The Paranoid Android — quality tools for code review, knowledge compounding, and work execution",
24
- "version": "0.3.5"
24
+ "version": "0.3.7"
25
25
  },
26
26
  {
27
27
  "name": "babel-fish",
28
28
  "source": "./plugins/babel-fish",
29
29
  "description": "Universal Translator — media generation tools for audio, image, and video content",
30
- "version": "0.2.3"
30
+ "version": "0.2.5"
31
31
  },
32
32
  {
33
33
  "name": "quellis",
package/README.md CHANGED
@@ -26,13 +26,16 @@ bunx @heart-of-gold/toolkit install --to opencode
26
26
 
27
27
  ### Pi Coding Agent
28
28
  ```bash
29
- # Install shared skills into Pi's native skill directory
30
- bunx @heart-of-gold/toolkit install --to pi
31
-
32
- # Or install the package directly in Pi to get skills + pi-native extensions
29
+ # Option A: install the package directly in Pi to get skills + pi-native extensions
33
30
  pi install npm:@heart-of-gold/toolkit
31
+
32
+ # Option B: install shared skills only into Pi's native skill directory
33
+ bunx @heart-of-gold/toolkit install --to pi
34
34
  ```
35
35
 
36
+ **Important:** choose one Pi install path or the other.
37
+ Do **not** use both the Pi package install and `install --to pi` at the same time, or Pi will report duplicate skill collisions on reload.
38
+
36
39
  Pi also discovers skills from the shared `~/.agents/skills/` location, so installs done with the OpenCode target are usable from Pi too.
37
40
 
38
41
  When installed as a Pi package, Heart of Gold exposes Pi-native extension commands for the flagship workflows:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heart-of-gold/toolkit",
3
- "version": "0.1.35",
3
+ "version": "0.1.37",
4
4
  "type": "module",
5
5
  "description": "Cross-platform installer for Heart of Gold skills — works with Codex, OpenCode, Pi, Claude Code, and more",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "babel-fish",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "Universal Translator — media generation tools for audio, image, video, and visualization",
5
5
  "author": {
6
6
  "name": "ondrej-svec",
@@ -21,6 +21,7 @@ Translating structured text into spatial understanding. The job is not to "turn
21
21
  Create one clear, polished, shareable visual artifact that:
22
22
  - matches the user's actual need
23
23
  - feels intentionally designed, not markdown restyled in boxes
24
+ - is authored deliberately by the coding agent whenever possible
24
25
  - summarizes before detailing
25
26
  - uses browser HTML as the primary medium for substantial artifacts
26
27
  - falls back to terminal rendering only when that is the better fit
@@ -34,12 +35,16 @@ Create one clear, polished, shareable visual artifact that:
34
35
 
35
36
  Do **not** mirror the source document structure one-to-one unless the user explicitly wants a document view.
36
37
 
38
+ The coding agent should be the **author** of the visual artifact.
39
+ The renderer is a **finisher/fallback**, not the brain.
40
+
37
41
  Instead:
38
42
  1. understand the source
39
43
  2. decide what the artifact is trying to communicate
40
44
  3. choose the visual form that best serves that goal
41
- 4. compress and reshape the content into a stronger visual story
42
- 5. keep raw/source detail secondary or collapsible when possible
45
+ 4. author the HTML artifact directly when practical
46
+ 5. use toolkit renderers only as helpers or fallback paths
47
+ 6. keep raw/source detail secondary or collapsible when possible
43
48
 
44
49
  HTML should feel like:
45
50
  - a dashboard
@@ -115,6 +120,26 @@ Apply these defaults unless the user asks for something else:
115
120
  See also:
116
121
  - `docs/architecture/visualize-design-rules.md`
117
122
 
123
+ ## Writing Tone
124
+
125
+ Write artifact copy like a strong product/design-systems editor:
126
+ - concise
127
+ - confident
128
+ - specific
129
+ - implementation-aware
130
+ - high signal-to-noise
131
+
132
+ Prefer lines like:
133
+ - `One code change, bounded migration risk`
134
+ - `Three priority tiers, one direction`
135
+ - `Deferred — tracked, not scheduled`
136
+
137
+ Avoid:
138
+ - fluffy marketing copy
139
+ - generic AI hype
140
+ - long throat-clearing intros
141
+ - repeating the source document verbatim
142
+
118
143
  ## Rules: Do
119
144
 
120
145
  - Decide the communication goal before choosing the renderer.
@@ -125,6 +150,7 @@ See also:
125
150
  - Use `roadmap` or richer execution-oriented views for plans when that improves understanding.
126
151
  - Use `architecture` views for system/design-heavy documents.
127
152
  - Keep raw source detail available, but secondary.
153
+ - Make section labels do real editorial work: `Scope at a glance`, `Why this shape`, `What could go wrong`, `Deferred — tracked, not scheduled`.
128
154
  - Briefly explain why you chose the visualization mode when sharing the result.
129
155
 
130
156
  ## Rules: Don't
@@ -136,6 +162,8 @@ See also:
136
162
  - Do not use flashy gradients, glass, shadows, or color noise unless they clearly improve hierarchy.
137
163
  - Do not silently guess when the visualization choice is materially ambiguous.
138
164
  - Do not create multiple competing artifacts unless the user explicitly asks for comparison.
165
+ - Do not preserve source heading order if a clearer narrative order exists.
166
+ - Do not expose every extracted detail at the same visual weight.
139
167
 
140
168
  ## Expected Behavior
141
169
 
@@ -150,8 +178,9 @@ When invoked, behave like a visual editor, not a format converter.
150
178
  - UI/product visualization
151
179
  3. Choose the best artifact family.
152
180
  4. If uncertain, ask one concise question.
153
- 5. Generate one HTML artifact first when browser rendering will help.
154
- 6. Fall back to terminal rendering when browser/share is unavailable or explicitly not wanted.
181
+ 5. Prefer **agent-authored HTML** when browser rendering will help and the artifact needs real design judgment.
182
+ 6. Use toolkit renderers as a fallback when a quick structured artifact is sufficient.
183
+ 7. Fall back to terminal rendering when browser/share is unavailable or explicitly not wanted.
155
184
 
156
185
  If the user says "you decide," choose the clearest non-gimmicky artifact, not the fanciest one.
157
186
 
@@ -189,12 +218,15 @@ If the user does not care or says "you decide," choose the safest useful mode:
189
218
  - use `architecture` for clearly system-design-heavy docs
190
219
  - use `mindmap` only when the artifact is genuinely concise and branchy
191
220
 
192
- ## Renderers
221
+ ## Authoring & Renderers
193
222
 
194
- Visualization has two implementation layers:
195
- - `scripts/smart-render.js` — renders one HTML artifact using the mode the coding agent chose, with a safe fallback
223
+ Preferred implementation order:
224
+ - **Agent-authored HTML** primary path for high-quality shareable artifacts
225
+ - `scripts/smart-render.js` — fallback renderer when the agent wants a quick scaffold or safe structured default
196
226
  - `scripts/render-mindmap/index.js` — specialized mind-map renderer for branchy content
197
227
 
228
+ The key rule: if the artifact needs real design judgment, the coding agent should author the HTML directly instead of delegating the whole job to a parser.
229
+
198
230
  **Locations:**
199
231
  - `scripts/smart-render.js`
200
232
  - `scripts/render-mindmap/index.js`
@@ -220,6 +252,31 @@ fi
220
252
 
221
253
  ## Usage
222
254
 
255
+ ### Preferred: agent-authored HTML
256
+
257
+ When quality matters more than speed, start from the shared authored-artifact template, write the HTML directly, then publish it.
258
+
259
+ **Cross-platform preferred path:** use the Node helpers first. They work better across macOS, Linux, Windows, Codex, Claude Code, and Pi than shell-specific one-liners.
260
+
261
+ ```bash
262
+ # 1. Print a fresh temp HTML path based on the shared template
263
+ node /absolute/path/to/new-authored-artifact.js
264
+
265
+ # 2. After editing the file, publish it
266
+ node /absolute/path/to/publish-authored-html.js --url-only /tmp/path/from-step-1/artifact.html
267
+ ```
268
+
269
+ **Shell fallback:** if Node helper usage is awkward in a specific harness, the `.sh` helpers are still available.
270
+
271
+ Template and helper files:
272
+ - `scripts/agent-artifact-template.html`
273
+ - `scripts/new-authored-artifact.js`
274
+ - `scripts/publish-authored-html.js`
275
+ - `scripts/new-authored-artifact.sh`
276
+ - `scripts/publish-authored-html.sh`
277
+
278
+ ### Fallback: toolkit renderer
279
+
223
280
  ```bash
224
281
  # Generate a safe default HTML visualization for a markdown file
225
282
  node "$SCRIPT" path/to/file.md --out /tmp/view.html
@@ -236,7 +293,29 @@ node "$(dirname "$SCRIPT")/render-mindmap/index.js" --html /tmp/map.html path/to
236
293
 
237
294
  ## HTML Share Flow
238
295
 
239
- Use the helper script when the user wants a browser URL and the share server is already configured:
296
+ ### Preferred share flow: publish agent-authored HTML
297
+
298
+ Use this when the artifact needs stronger design judgment than the fallback renderer can provide.
299
+
300
+ 1. Create the scaffold with a standalone cross-platform command:
301
+ ```bash
302
+ node /absolute/path/to/new-authored-artifact.js
303
+ ```
304
+ 2. Read the printed temp path from stdout.
305
+ 3. Author the HTML artifact directly into that file.
306
+ 4. Publish it with a standalone cross-platform command:
307
+ ```bash
308
+ node /absolute/path/to/publish-authored-html.js --url-only /tmp/your-artifact.html
309
+ ```
310
+ 5. Read the returned URL from stdout.
311
+ 6. Return that URL to the user as the primary result.
312
+ 7. Briefly explain what was published and why this visual form was chosen.
313
+
314
+ Shell helpers remain available as a fallback if a harness prefers `bash`.
315
+
316
+ ### Fallback share flow: render then publish
317
+
318
+ Use the helper script when the user wants a browser URL and the fallback renderer is sufficient:
240
319
 
241
320
  ```bash
242
321
  bash scripts/render-and-share.sh path/to/file.md
@@ -249,18 +328,6 @@ This script:
249
328
  4. publishes the artifact to the configured local share server
250
329
  5. prints the publish result so you can return the URL
251
330
 
252
- ### Recommended share flow
253
-
254
- 1. Verify or assume the input markdown is ready.
255
- 2. Choose the mode from context.
256
- 3. Run:
257
- ```bash
258
- bash scripts/render-and-share.sh --mode <chosen-mode> --url-only [file]
259
- ```
260
- 4. Read the returned URL from stdout.
261
- 5. Return that URL to the user as the primary result.
262
- 6. Briefly explain what was published and why this mode was chosen.
263
-
264
331
  If publishing fails because the share server is not configured, say so clearly and fall back to terminal rendering unless the user wants to stop and run `share-server-setup` first.
265
332
 
266
333
  ## Terminal Rendering
@@ -289,6 +356,34 @@ Many harness bash panels truncate long output and wrap wide content, breaking al
289
356
 
290
357
  The default mode is vertical layout — boxes on main branches, compact leaves, about 40 chars wide.
291
358
 
359
+ ## Agent-Authored HTML Workflow
360
+
361
+ When authoring HTML directly, follow this sequence:
362
+
363
+ 1. Read the source and decide the artifact family.
364
+ 2. Decide the audience and the first question the page should answer.
365
+ 3. Create the scaffold with `new-authored-artifact.js` or `new-authored-artifact.sh`.
366
+ 4. Draft the page in three layers:
367
+ - **summary layer** — what matters first
368
+ - **decision / execution layer** — the main story
369
+ - **source layer** — appendix, evidence, or raw detail
370
+ 5. Replace the template content with a real designed artifact.
371
+ 6. Keep source detail secondary.
372
+ 7. Publish with `publish-authored-html.js` or `publish-authored-html.sh`.
373
+
374
+ Harness note:
375
+ - prefer separate commands over complex one-liners
376
+ - prefer the Node helpers for cross-platform behavior
377
+ - avoid assuming `mktemp /tmp/name-XXXXXX.html` works on every shell; use the provided helper instead
378
+ - if a harness only supports shell comfortably, use the `.sh` helpers as fallback
379
+
380
+ For plans specifically:
381
+ - do not dump the full task prose into the primary lanes
382
+ - summarize workstreams into short cards or task tiles
383
+ - show dependencies, risks, and acceptance separately
384
+ - keep raw markdown only in an appendix or disclosure block
385
+ - compress long task descriptions into one-sentence operational summaries first
386
+
292
387
  ## Required Output Structure
293
388
 
294
389
  For substantial HTML artifacts, prefer this structure:
@@ -319,6 +414,53 @@ For substantial HTML artifacts, prefer this structure:
319
414
  - what happens next
320
415
  - supporting source detail below
321
416
 
417
+ ## Expected Behavior by Artifact Family
418
+
419
+ ### Plan / roadmap artifacts
420
+ Must usually include:
421
+ - a top-line mission
422
+ - scope or execution stats
423
+ - grouped workstreams or phases
424
+ - key decisions / rationale
425
+ - explicit risks / acceptance posture
426
+ - deferred or out-of-scope work if relevant
427
+
428
+ ### Architecture artifacts
429
+ Must usually include:
430
+ - system framing
431
+ - major components / boundaries
432
+ - integration or dependency context
433
+ - key tradeoffs / decisions
434
+ - assumptions / risks
435
+
436
+ ### Explainers
437
+ Must usually include:
438
+ - what this is
439
+ - why it matters
440
+ - the recommendation or conclusion
441
+ - supporting evidence
442
+ - what happens next
443
+
444
+ ## Recommended Authoring Moves
445
+
446
+ When the artifact still feels too markdown-like, do one or more of these:
447
+ - replace raw section names with editorial section labels
448
+ - compress paragraphs into 1–3 sentence summary cards
449
+ - convert repeated prose into chips, bullets, metrics, or compact lists
450
+ - surface one key takeaway per section before the detail
451
+ - split `what / why / risk / next` into separate visual units
452
+ - move citations, raw notes, and source text into a secondary appendix
453
+
454
+ ## Guideline Authoring Workflow
455
+
456
+ 1. Restate the artifact purpose in one sentence.
457
+ 2. Decide the audience and primary question.
458
+ 3. Choose the artifact family and page shape.
459
+ 4. Extract only what is needed for the summary layer.
460
+ 5. Build the main body around grouped visual units, not source sections.
461
+ 6. Add source appendix or evidence only after the main page works.
462
+ 7. Run the quality gates before publishing.
463
+
322
464
  ## Quality Gates
323
465
 
324
466
  Before returning a shared HTML result, check mentally:
@@ -330,9 +472,37 @@ Before returning a shared HTML result, check mentally:
330
472
  - Is the chosen mode actually appropriate for the content?
331
473
  - If this is a plan, does it foreground execution rather than document order?
332
474
  - If this is a brainstorm, is it actually branch-shaped enough for a mind map?
475
+ - Do the section titles help scanning?
476
+ - Is secondary detail actually secondary?
333
477
 
334
478
  If the answer to several of these is no, reconsider the mode or ask the user.
335
479
 
480
+ ## Pattern Examples
481
+
482
+ ### Good plan framing
483
+ - `Scope at a glance`
484
+ - `Three priority tiers, one direction`
485
+ - `What could go wrong`
486
+ - `Deferred — tracked, not scheduled`
487
+
488
+ ### Good risk cards
489
+ - short risk title
490
+ - severity or posture badge
491
+ - one-sentence mitigation
492
+ - accepted vs mitigated distinction when relevant
493
+
494
+ ### Good summary stats
495
+ - workstreams
496
+ - tasks
497
+ - code edits
498
+ - new files
499
+ - doctrine docs touched
500
+
501
+ ### Good appendix behavior
502
+ - source plan path
503
+ - cited references
504
+ - raw plan or evidence hidden behind disclosure
505
+
336
506
  ## Input Formats
337
507
 
338
508
  ### Markdown (primary)
@@ -0,0 +1,169 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Heart of Gold Visual Artifact</title>
7
+ <style>
8
+ :root {
9
+ --bg: #09111f;
10
+ --bg-2: #0f1a31;
11
+ --panel: rgba(255,255,255,0.06);
12
+ --panel-soft: rgba(255,255,255,0.04);
13
+ --text: #eef2ff;
14
+ --muted: #b8c0d9;
15
+ --muted-2: #91a1c2;
16
+ --border: rgba(255,255,255,0.11);
17
+ --accent: #7c9cff;
18
+ --accent-2: #80e0d0;
19
+ --success: #86efac;
20
+ --warn: #fbbf24;
21
+ --danger: #fca5a5;
22
+ --shadow: 0 24px 80px rgba(0,0,0,0.34);
23
+ --radius-xl: 28px;
24
+ --radius-lg: 20px;
25
+ --radius-md: 16px;
26
+ }
27
+ * { box-sizing: border-box; }
28
+ html, body { margin: 0; padding: 0; }
29
+ html { color-scheme: dark; }
30
+ body {
31
+ font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
32
+ line-height: 1.55;
33
+ color: var(--text);
34
+ background:
35
+ radial-gradient(circle at top left, rgba(124,156,255,0.18), transparent 32%),
36
+ radial-gradient(circle at top right, rgba(128,224,208,0.12), transparent 24%),
37
+ linear-gradient(180deg, var(--bg-2) 0%, var(--bg) 100%);
38
+ }
39
+ main { max-width: 1480px; margin: 0 auto; padding: 36px 22px 84px; }
40
+ .hero, .section, .rail-card, .card, .stat, .chip, .callout {
41
+ border: 1px solid var(--border);
42
+ box-shadow: var(--shadow);
43
+ backdrop-filter: blur(14px);
44
+ }
45
+ .hero, .section, .rail-card { background: var(--panel); }
46
+ .hero {
47
+ padding: 28px;
48
+ border-radius: 32px;
49
+ margin-bottom: 24px;
50
+ display: grid;
51
+ gap: 16px;
52
+ }
53
+ .eyebrow {
54
+ color: var(--accent-2);
55
+ text-transform: uppercase;
56
+ letter-spacing: 0.16em;
57
+ font-size: 12px;
58
+ font-weight: 700;
59
+ }
60
+ h1 { margin: 0; font-size: clamp(34px, 4vw, 62px); line-height: 1.02; text-wrap: balance; }
61
+ h2 { margin: 0 0 12px; font-size: clamp(22px, 2vw, 32px); text-wrap: balance; }
62
+ h3 { margin: 0 0 10px; font-size: 18px; }
63
+ p { margin: 0; color: var(--muted); }
64
+ .hero p { max-width: 78ch; font-size: 17px; }
65
+ .page { display: grid; grid-template-columns: minmax(0, 1fr) minmax(260px, 320px); gap: 24px; align-items: start; }
66
+ .rail { position: sticky; top: 16px; display: grid; gap: 16px; }
67
+ .rail-card, .section { padding: 22px; border-radius: var(--radius-xl); }
68
+ .section { margin-bottom: 20px; }
69
+ .grid-2, .grid-3, .grid-4, .lane-grid { display: grid; gap: 16px; }
70
+ .grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
71
+ .grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
72
+ .grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
73
+ .lane-grid { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
74
+ .card, .stat, .lane, .callout {
75
+ padding: 18px;
76
+ border-radius: var(--radius-md);
77
+ background: var(--panel-soft);
78
+ }
79
+ .label {
80
+ color: var(--accent-2);
81
+ text-transform: uppercase;
82
+ letter-spacing: 0.11em;
83
+ font-size: 12px;
84
+ margin-bottom: 8px;
85
+ }
86
+ .stat .value { font-size: 28px; font-weight: 700; color: var(--text); margin-top: 6px; }
87
+ .stat .hint { color: var(--muted-2); font-size: 13px; margin-top: 6px; }
88
+ .chip-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
89
+ .chip {
90
+ display: inline-flex; align-items: center; gap: 6px; padding: 8px 10px; border-radius: 999px;
91
+ background: rgba(255,255,255,0.05); color: var(--muted-2); font-size: 12px;
92
+ }
93
+ .chip.good { color: #c7ffd7; }
94
+ .chip.warn { color: #ffd88d; }
95
+ .chip.danger { color: #ffd1d1; }
96
+ details { margin-top: 12px; }
97
+ summary { cursor: pointer; font-weight: 600; }
98
+ .raw {
99
+ margin-top: 12px; padding: 14px; border-radius: 14px; border: 1px solid var(--border);
100
+ background: rgba(0,0,0,0.22); color: #d8e1fb; white-space: pre-wrap;
101
+ font: 13px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
102
+ }
103
+ a { color: #dce6ff; }
104
+ ul { margin: 0; padding-left: 18px; color: var(--muted); }
105
+ @media (max-width: 1080px) {
106
+ .page { grid-template-columns: 1fr; }
107
+ .rail { position: static; }
108
+ .grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
109
+ }
110
+ @media (max-width: 720px) {
111
+ main { padding: 20px 14px 60px; }
112
+ .hero, .section, .rail-card { padding: 18px; }
113
+ .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
114
+ }
115
+ </style>
116
+ </head>
117
+ <body>
118
+ <main>
119
+ <section class="hero">
120
+ <div class="eyebrow">Artifact Family</div>
121
+ <h1>Title</h1>
122
+ <p>One-line framing that explains what this artifact is, why it matters, and how to read it.</p>
123
+ <div class="chip-row">
124
+ <span class="chip">Mode</span>
125
+ <span class="chip">Audience</span>
126
+ <span class="chip">Purpose</span>
127
+ </div>
128
+ </section>
129
+
130
+ <div class="page">
131
+ <section>
132
+ <section class="section">
133
+ <div class="label">Summary</div>
134
+ <h2>Start With the Story</h2>
135
+ <div class="grid-4">
136
+ <div class="stat"><div class="label">Stat</div><div class="value">4</div><div class="hint">What this number means</div></div>
137
+ <div class="stat"><div class="label">Stat</div><div class="value">18</div><div class="hint">What this number means</div></div>
138
+ <div class="stat"><div class="label">Stat</div><div class="value">11</div><div class="hint">What this number means</div></div>
139
+ <div class="stat"><div class="label">Stat</div><div class="value">2</div><div class="hint">What this number means</div></div>
140
+ </div>
141
+ </section>
142
+
143
+ <section class="section">
144
+ <div class="label">Main Body</div>
145
+ <h2>Transform the Source</h2>
146
+ <div class="grid-2">
147
+ <div class="card">
148
+ <div class="label">Use cards</div>
149
+ <p>Summaries, priorities, risks, decisions, and recommendations should be grouped into visual units rather than dumped as prose.</p>
150
+ </div>
151
+ <div class="card">
152
+ <div class="label">Use disclosure</div>
153
+ <p>Keep raw source detail secondary. Put it behind details/summary or a source appendix.</p>
154
+ </div>
155
+ </div>
156
+ </section>
157
+ </section>
158
+
159
+ <aside class="rail">
160
+ <section class="rail-card">
161
+ <div class="label">Rail</div>
162
+ <h3>Keep It Focused</h3>
163
+ <p>Use the right rail for compact metadata, jump links, or decision context — not for a massive table of contents.</p>
164
+ </section>
165
+ </aside>
166
+ </div>
167
+ </main>
168
+ </body>
169
+ </html>
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { copyFileSync, mkdirSync, mkdtempSync } from 'node:fs';
4
+ import { dirname, join, resolve } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { tmpdir } from 'node:os';
7
+
8
+ const __dirname = dirname(fileURLToPath(import.meta.url));
9
+ const templatePath = join(__dirname, 'agent-artifact-template.html');
10
+ const providedPath = process.argv[2] ? resolve(process.argv[2]) : null;
11
+
12
+ const outPath = (() => {
13
+ if (providedPath) return providedPath;
14
+ const tempDir = mkdtempSync(join(tmpdir(), 'hog-visualize-artifact-'));
15
+ return join(tempDir, 'artifact.html');
16
+ })();
17
+
18
+ mkdirSync(dirname(outPath), { recursive: true });
19
+ copyFileSync(templatePath, outPath);
20
+ process.stdout.write(`${outPath}\n`);
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
5
+ TEMPLATE="$SCRIPT_DIR/agent-artifact-template.html"
6
+ OUT_PATH="${1:-}"
7
+
8
+ if [[ -z "$OUT_PATH" ]]; then
9
+ TEMP_BASE="$(mktemp /tmp/hog-visualize-artifact-XXXXXX)"
10
+ OUT_PATH="${TEMP_BASE}.html"
11
+ fi
12
+
13
+ cp "$TEMPLATE" "$OUT_PATH"
14
+ printf '%s\n' "$OUT_PATH"
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { existsSync, readFileSync } from 'node:fs';
4
+ import { basename, resolve } from 'node:path';
5
+ import { homedir } from 'node:os';
6
+
7
+ function fail(code, message, status = 1) {
8
+ process.stdout.write(`${JSON.stringify({ ok: false, error: { code, message } })}\n`);
9
+ process.exit(status);
10
+ }
11
+
12
+ function parseArgs(argv) {
13
+ const opts = {
14
+ htmlPath: null,
15
+ configPath: resolve(homedir(), '.agent-share', 'config.json'),
16
+ slug: '',
17
+ title: '',
18
+ alias: '',
19
+ urlOnly: false,
20
+ };
21
+
22
+ for (let i = 0; i < argv.length; i++) {
23
+ const arg = argv[i];
24
+ if (arg === '--config' && i + 1 < argv.length) opts.configPath = resolve(argv[++i]);
25
+ else if (arg === '--slug' && i + 1 < argv.length) opts.slug = argv[++i];
26
+ else if (arg === '--title' && i + 1 < argv.length) opts.title = argv[++i];
27
+ else if (arg === '--alias' && i + 1 < argv.length) opts.alias = argv[++i];
28
+ else if (arg === '--url-only') opts.urlOnly = true;
29
+ else if (arg === '--help') {
30
+ process.stdout.write('Usage: publish-authored-html.js <html-file> [--config PATH] [--slug STEM] [--title TITLE] [--alias ALIAS] [--url-only]\n');
31
+ process.exit(0);
32
+ } else if (!arg.startsWith('-') && !opts.htmlPath) {
33
+ opts.htmlPath = resolve(arg);
34
+ } else {
35
+ fail('INVALID_ARGS', `Unknown or misplaced argument: ${arg}`);
36
+ }
37
+ }
38
+
39
+ return opts;
40
+ }
41
+
42
+ async function main() {
43
+ const opts = parseArgs(process.argv.slice(2));
44
+
45
+ if (!opts.htmlPath) fail('MISSING_PATH', 'HTML file path is required.');
46
+ if (!existsSync(opts.configPath)) fail('MISSING_CONFIG', 'Share server config not found. Run share-server-setup first.');
47
+ if (!existsSync(opts.htmlPath)) fail('MISSING_PATH', `HTML file does not exist: ${opts.htmlPath}`);
48
+ if (!opts.htmlPath.toLowerCase().endsWith('.html')) fail('UNSUPPORTED_ARTIFACT', 'Only .html files are supported for authored artifact publishing.');
49
+
50
+ const cfg = JSON.parse(readFileSync(opts.configPath, 'utf8'));
51
+ const apiUrl = String(cfg?.server?.apiUrl || '').replace(/\/$/, '');
52
+ if (!apiUrl) fail('INVALID_CONFIG', 'share server apiUrl missing from config.');
53
+
54
+ const htmlBuffer = readFileSync(opts.htmlPath);
55
+ const form = new FormData();
56
+ form.append('artifact', new Blob([htmlBuffer], { type: 'text/html' }), basename(opts.htmlPath));
57
+ form.append('artifactType', 'html-file');
58
+ if (opts.slug) form.append('slug', opts.slug);
59
+ if (opts.title) form.append('title', opts.title);
60
+ if (opts.alias) form.append('alias', opts.alias);
61
+
62
+ const response = await fetch(`${apiUrl}/publish`, { method: 'POST', body: form });
63
+ const text = await response.text();
64
+
65
+ let payload;
66
+ try {
67
+ payload = JSON.parse(text);
68
+ } catch {
69
+ fail('INVALID_RESPONSE', `Share server returned non-JSON response: ${text}`, 1);
70
+ }
71
+
72
+ if (!response.ok || payload?.ok === false) {
73
+ process.stdout.write(`${JSON.stringify(payload)}\n`);
74
+ process.exit(1);
75
+ }
76
+
77
+ if (opts.urlOnly) {
78
+ process.stdout.write(`${payload.url || payload.viewerUrl || ''}\n`);
79
+ return;
80
+ }
81
+
82
+ process.stdout.write(`${JSON.stringify(payload)}\n`);
83
+ }
84
+
85
+ main().catch((error) => {
86
+ fail('PUBLISH_FAILED', error instanceof Error ? error.message : String(error));
87
+ });
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
5
+ HTML_PATH=""
6
+ SLUG=""
7
+ TITLE=""
8
+ ALIAS=""
9
+ URL_ONLY=0
10
+
11
+ usage() {
12
+ cat <<'EOF'
13
+ Usage: publish-authored-html.sh <html-file> [--slug STEM] [--title TITLE] [--alias ALIAS] [--url-only]
14
+
15
+ Publish an already-authored HTML artifact via share-html.
16
+ Use this when the coding agent wrote the HTML directly and only needs the share pipeline.
17
+ EOF
18
+ }
19
+
20
+ while [[ $# -gt 0 ]]; do
21
+ case "$1" in
22
+ --slug) SLUG="$2"; shift 2 ;;
23
+ --title) TITLE="$2"; shift 2 ;;
24
+ --alias) ALIAS="$2"; shift 2 ;;
25
+ --url-only) URL_ONLY=1; shift ;;
26
+ --help) usage; exit 0 ;;
27
+ --*) echo "Unknown argument: $1" >&2; exit 1 ;;
28
+ *)
29
+ if [[ -z "$HTML_PATH" ]]; then
30
+ HTML_PATH="$1"
31
+ shift
32
+ else
33
+ echo "Unexpected positional argument: $1" >&2
34
+ exit 1
35
+ fi
36
+ ;;
37
+ esac
38
+ done
39
+
40
+ if [[ -z "$HTML_PATH" ]]; then
41
+ usage >&2
42
+ exit 1
43
+ fi
44
+
45
+ if [[ ! -f "$HTML_PATH" ]]; then
46
+ echo "HTML file does not exist: $HTML_PATH" >&2
47
+ exit 1
48
+ fi
49
+
50
+ find_share_publish_script() {
51
+ local candidates=(
52
+ "$SCRIPT_DIR/../../share-html/scripts/publish.sh"
53
+ "$SCRIPT_DIR/../../../marvin/skills/share-html/scripts/publish.sh"
54
+ "$SCRIPT_DIR/../../../../marvin/skills/share-html/scripts/publish.sh"
55
+ "$HOME/.agents/skills/share-html/scripts/publish.sh"
56
+ "$HOME/.pi/agent/skills/share-html/scripts/publish.sh"
57
+ )
58
+
59
+ for candidate in "${candidates[@]}"; do
60
+ if [[ -f "$candidate" ]]; then
61
+ printf '%s\n' "$candidate"
62
+ return 0
63
+ fi
64
+ done
65
+
66
+ find "$(cd "$SCRIPT_DIR/../../../../.." && pwd)" -path '*/share-html/scripts/publish.sh' 2>/dev/null | head -1
67
+ }
68
+
69
+ PUBLISH_SCRIPT="$(find_share_publish_script)"
70
+ if [[ -z "$PUBLISH_SCRIPT" || ! -f "$PUBLISH_SCRIPT" ]]; then
71
+ echo '{"ok":false,"error":{"code":"MISSING_SHARE_HTML","message":"Could not find share-html publish.sh. Install the share-html skill first."}}'
72
+ exit 1
73
+ fi
74
+
75
+ CMD=(bash "$PUBLISH_SCRIPT" "$HTML_PATH")
76
+ if [[ -n "$SLUG" ]]; then CMD+=(--slug "$SLUG"); fi
77
+ if [[ -n "$TITLE" ]]; then CMD+=(--title "$TITLE"); fi
78
+ if [[ -n "$ALIAS" ]]; then CMD+=(--alias "$ALIAS"); fi
79
+
80
+ PUBLISH_JSON="$(${CMD[@]})"
81
+
82
+ if [[ "$URL_ONLY" -eq 1 ]]; then
83
+ python3 - <<'PY' "$PUBLISH_JSON"
84
+ import json, sys
85
+ payload = json.loads(sys.argv[1])
86
+ if not payload.get("ok", True):
87
+ print(json.dumps(payload))
88
+ raise SystemExit(1)
89
+ print(payload.get("url") or payload.get("viewerUrl") or "")
90
+ PY
91
+ else
92
+ printf '%s\n' "$PUBLISH_JSON"
93
+ fi
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deep-thought",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "description": "The Answer Computer — reasoning tools for brainstorming, planning, architecture design, and deep thinking",
5
5
  "author": {
6
6
  "name": "ondrej-svec",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "marvin",
3
- "version": "0.3.5",
3
+ "version": "0.3.7",
4
4
  "description": "The Paranoid Android — quality tools for code review, knowledge compounding, and work execution",
5
5
  "author": {
6
6
  "name": "ondrej-svec",
@@ -1,7 +1,9 @@
1
1
  import { defineCommand } from "citty";
2
2
  import { loadAllPlugins, loadPlugin } from "../parsers/claude";
3
3
  import { targets } from "../targets/index";
4
- import { resolve } from "path";
4
+ import { resolve, join } from "path";
5
+ import { existsSync } from "fs";
6
+ import { execSync } from "child_process";
5
7
 
6
8
  export const installCommand = defineCommand({
7
9
  meta: {
@@ -27,6 +29,20 @@ export const installCommand = defineCommand({
27
29
  },
28
30
  async run({ args }) {
29
31
  const targetName = args.to;
32
+
33
+ if (targetName === "pi") {
34
+ try {
35
+ const npmRoot = execSync("npm root -g", { encoding: "utf8" }).trim();
36
+ const packagePath = join(npmRoot, "@heart-of-gold", "toolkit", "package.json");
37
+ if (existsSync(packagePath)) {
38
+ console.warn("Warning: @heart-of-gold/toolkit is already installed as a Pi package.");
39
+ console.warn("Using 'install --to pi' as well will create duplicate Pi skill collisions on reload.");
40
+ console.warn("Prefer one Pi install path: either 'pi install npm:@heart-of-gold/toolkit' or 'bunx @heart-of-gold/toolkit install --to pi'.\n");
41
+ }
42
+ } catch {
43
+ // ignore detection failures and proceed normally
44
+ }
45
+ }
30
46
  const target = targets[targetName];
31
47
  if (!target) {
32
48
  const available = Object.keys(targets).join(", ");