@heart-of-gold/toolkit 0.1.29 → 0.1.30
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/README.md +20 -18
- package/extensions/pi/index.ts +2 -0
- package/package.json +3 -3
- package/plugins/guide/.claude-plugin/plugin.json +1 -1
- package/plugins/guide/README.md +0 -20
- package/plugins/guide/scripts/fetch-gmail.sh +88 -21
- package/plugins/marvin/.claude-plugin/plugin.json +1 -1
- package/plugins/marvin/README.md +7 -1
- package/src/index.ts +1 -1
- /package/plugins/{guide → marvin}/skills/share-html/SKILL.md +0 -0
- /package/plugins/{guide → marvin}/skills/share-html/scripts/healthcheck.sh +0 -0
- /package/plugins/{guide → marvin}/skills/share-html/scripts/publish.sh +0 -0
- /package/plugins/{guide → marvin}/skills/share-server-setup/SKILL.md +0 -0
- /package/plugins/{guide → marvin}/skills/share-server-setup/scripts/configure-existing-server.sh +0 -0
- /package/plugins/{guide → marvin}/skills/share-server-setup/scripts/configure-tailscale-viewer.sh +0 -0
- /package/plugins/{guide → marvin}/skills/share-server-setup/scripts/healthcheck.sh +0 -0
- /package/plugins/{guide → marvin}/skills/share-server-setup/scripts/install-launch-agent.sh +0 -0
- /package/plugins/{guide → marvin}/skills/share-server-setup/scripts/install-reference-server.sh +0 -0
package/README.md
CHANGED
|
@@ -39,6 +39,8 @@ When installed as a Pi package, Heart of Gold exposes Pi-native extension comman
|
|
|
39
39
|
- `/deep-thought-brainstorm` — start a brainstorm (collaborative discovery)
|
|
40
40
|
- `/deep-thought-plan` — start planning (research and produce a plan document)
|
|
41
41
|
- `/deep-thought-architect` — turn brainstorm decisions into stories and architecture docs
|
|
42
|
+
- `/share` — publish an HTML file or static site directory through the portable `share-html` skill
|
|
43
|
+
- `/share-server-setup` — set up or adopt the local share server through the portable `share-server-setup` skill
|
|
42
44
|
- `/marvin-work` — start executing a plan (with always-on safety guardrails)
|
|
43
45
|
|
|
44
46
|
Pi package installs also include a Pi-only guided workflow enhancer for supported Heart of Gold skills. For `brainstorm`, `plan`, and `architect`, when the assistant asks a high-confidence structured question, Pi can upgrade it into a custom interactive TUI and feed the answer back into the same workflow. Shared skills remain plain-text portable in every other harness.
|
|
@@ -95,16 +97,18 @@ The unglamorous work that compounds.
|
|
|
95
97
|
|
|
96
98
|
Execute plans task by task with tests after every change. Quick-review code with an emphasis on simplicity — catch YAGNI violations, premature abstractions, and code that solves problems that don't exist yet. Document solutions so the next person doesn't waste time re-discovering what you already figured out.
|
|
97
99
|
|
|
98
|
-
|
|
100
|
+
9 skills · 2 agents · 3 knowledge files
|
|
99
101
|
|
|
100
102
|
```
|
|
101
|
-
/marvin:work
|
|
102
|
-
/marvin:quick-review
|
|
103
|
-
/marvin:compound
|
|
104
|
-
/marvin:redteam
|
|
105
|
-
/marvin:scaffold
|
|
106
|
-
/marvin:test-writer
|
|
107
|
-
/marvin:copy-editor
|
|
103
|
+
/marvin:work # execute plans — implement, test, commit, ship
|
|
104
|
+
/marvin:quick-review # fast opinionated quality pass (simplicity, tests, correctness)
|
|
105
|
+
/marvin:compound # document solved problems for future reference
|
|
106
|
+
/marvin:redteam # adversarial review — find weaknesses, expose with failing tests
|
|
107
|
+
/marvin:scaffold # prepare project structure, configs, dependencies
|
|
108
|
+
/marvin:test-writer # write failing tests from user stories
|
|
109
|
+
/marvin:copy-editor # two-layer copy editor (typography audit + LLM judgment)
|
|
110
|
+
/marvin:share-server-setup # set up local artifact sharing infrastructure
|
|
111
|
+
/marvin:share-html # publish HTML/static output to a browser URL
|
|
108
112
|
```
|
|
109
113
|
|
|
110
114
|
### [Guide](plugins/guide/) — The Hitchhiker's Guide
|
|
@@ -113,18 +117,16 @@ Your personal content engine.
|
|
|
113
117
|
|
|
114
118
|
Configurable sources (RSS, Gmail, HN, web search), narrative briefs, LinkedIn drafts, blog outlines, voice fidelity checking, iMessage delivery, and two-way captures.
|
|
115
119
|
|
|
116
|
-
|
|
120
|
+
7 skills · 2 agents · 5 scripts
|
|
117
121
|
|
|
118
122
|
```
|
|
119
|
-
/guide:setup
|
|
120
|
-
/guide:pipeline
|
|
121
|
-
/guide:capture
|
|
122
|
-
/guide:write-post
|
|
123
|
-
/guide:
|
|
124
|
-
/guide:
|
|
125
|
-
/guide:
|
|
126
|
-
/guide:codex # Codex CLI guidance
|
|
127
|
-
/guide:gemini # Gemini CLI guidance
|
|
123
|
+
/guide:setup # configure your sources, themes, and voice
|
|
124
|
+
/guide:pipeline # run the full content engine
|
|
125
|
+
/guide:capture # morning/evening thought capture
|
|
126
|
+
/guide:write-post # guided blog writing (7 phases)
|
|
127
|
+
/guide:claude-code # Claude Code CLI guidance
|
|
128
|
+
/guide:codex # Codex CLI guidance
|
|
129
|
+
/guide:gemini # Gemini CLI guidance
|
|
128
130
|
```
|
|
129
131
|
|
|
130
132
|
### [Babel Fish](plugins/babel-fish/) — Universal Translator
|
package/extensions/pi/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ import architectExtension from "./architect";
|
|
|
4
4
|
import brainstormExtension from "./brainstorm";
|
|
5
5
|
import guidedWorkflowsExtension from "./guided-workflows";
|
|
6
6
|
import planExtension from "./plan";
|
|
7
|
+
import shareExtension from "./share";
|
|
7
8
|
import workExtension from "./work";
|
|
8
9
|
|
|
9
10
|
export default function heartOfGoldPiExtensions(pi: ExtensionAPI) {
|
|
@@ -11,5 +12,6 @@ export default function heartOfGoldPiExtensions(pi: ExtensionAPI) {
|
|
|
11
12
|
brainstormExtension(pi);
|
|
12
13
|
planExtension(pi);
|
|
13
14
|
architectExtension(pi);
|
|
15
|
+
shareExtension(pi);
|
|
14
16
|
workExtension(pi);
|
|
15
17
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heart-of-gold/toolkit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.30",
|
|
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": {
|
|
@@ -65,10 +65,10 @@
|
|
|
65
65
|
"./plugins/guide/skills/gemini",
|
|
66
66
|
"./plugins/guide/skills/pipeline",
|
|
67
67
|
"./plugins/guide/skills/setup",
|
|
68
|
-
"./plugins/guide/skills/share-html",
|
|
69
|
-
"./plugins/guide/skills/share-server-setup",
|
|
70
68
|
"./plugins/guide/skills/write-post",
|
|
71
69
|
"./plugins/marvin/skills/compound",
|
|
70
|
+
"./plugins/marvin/skills/share-html",
|
|
71
|
+
"./plugins/marvin/skills/share-server-setup",
|
|
72
72
|
"./plugins/marvin/skills/quick-review",
|
|
73
73
|
"./plugins/marvin/skills/redteam",
|
|
74
74
|
"./plugins/marvin/skills/scaffold",
|
package/plugins/guide/README.md
CHANGED
|
@@ -73,26 +73,6 @@ Guided blog writing in seven phases:
|
|
|
73
73
|
|
|
74
74
|
Can pick up blog outlines generated by the pipeline (`needs_write_post: true` in frontmatter).
|
|
75
75
|
|
|
76
|
-
### /guide:share-server-setup
|
|
77
|
-
|
|
78
|
-
Set up or adopt a local share server for browser-viewable coding-agent artifacts.
|
|
79
|
-
|
|
80
|
-
Use it when you want a reusable local service that can host generated HTML reports or static previews, optionally exposed privately over Tailscale. The setup flow supports:
|
|
81
|
-
- configuring an already-running compatible server
|
|
82
|
-
- installing the reference Heart of Gold share server
|
|
83
|
-
- setting up macOS LaunchAgent persistence for long-running use
|
|
84
|
-
- optionally wiring only the viewer surface through `tailscale serve`
|
|
85
|
-
|
|
86
|
-
### /guide:share-html
|
|
87
|
-
|
|
88
|
-
Publish a local HTML file or static site directory to the configured share server and return a browser URL.
|
|
89
|
-
|
|
90
|
-
Supports:
|
|
91
|
-
- a single `.html` file
|
|
92
|
-
- a directory containing `index.html`
|
|
93
|
-
|
|
94
|
-
If the server is not configured yet, run `/guide:share-server-setup` first.
|
|
95
|
-
|
|
96
76
|
### /guide:claude-code
|
|
97
77
|
|
|
98
78
|
Headless Claude Code handoff for second opinions, code review, targeted analysis, or follow-up on a bounded task.
|
|
@@ -82,11 +82,15 @@ print(fetch_body)
|
|
|
82
82
|
PY
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
85
|
+
GMAIL_SETTINGS_RAW=$(read_gmail_settings "$CONFIG_PATH" 2>/dev/null) || GMAIL_SETTINGS_RAW=""
|
|
86
|
+
if [[ -n "$GMAIL_SETTINGS_RAW" ]]; then
|
|
87
|
+
GMAIL_LABEL=$(echo "$GMAIL_SETTINGS_RAW" | sed -n '1p')
|
|
88
|
+
MAX_ITEMS=$(echo "$GMAIL_SETTINGS_RAW" | sed -n '2p')
|
|
89
|
+
GMAIL_LABEL_ID=$(echo "$GMAIL_SETTINGS_RAW" | sed -n '3p')
|
|
90
|
+
FETCH_BODY=$(echo "$GMAIL_SETTINGS_RAW" | sed -n '4p')
|
|
91
|
+
GMAIL_LABEL="${GMAIL_LABEL:-Content-Feed}"
|
|
92
|
+
MAX_ITEMS="${MAX_ITEMS:-20}"
|
|
93
|
+
FETCH_BODY="${FETCH_BODY:-false}"
|
|
90
94
|
else
|
|
91
95
|
GMAIL_LABEL="Content-Feed"
|
|
92
96
|
MAX_ITEMS="20"
|
|
@@ -94,14 +98,61 @@ else
|
|
|
94
98
|
FETCH_BODY="false"
|
|
95
99
|
fi
|
|
96
100
|
|
|
101
|
+
# Collect seen Gmail message IDs from previous days to avoid duplicates
|
|
102
|
+
PIPELINE_DIR=$(python3 -c "
|
|
103
|
+
import yaml, sys
|
|
104
|
+
with open(sys.argv[1]) as f:
|
|
105
|
+
c = yaml.safe_load(f)
|
|
106
|
+
print(c.get('output', {}).get('pipeline_dir', 'content/pipeline'))
|
|
107
|
+
" "$CONFIG_PATH" 2>/dev/null || echo "content/pipeline")
|
|
108
|
+
|
|
109
|
+
SEEN_IDS=$(python3 -c "
|
|
110
|
+
import json, glob, os, sys
|
|
111
|
+
|
|
112
|
+
pipeline_dir = sys.argv[1]
|
|
113
|
+
config_path = sys.argv[2]
|
|
114
|
+
|
|
115
|
+
# Resolve relative pipeline_dir against project root (config's grandparent,
|
|
116
|
+
# since config lives in content/ which is one level below project root)
|
|
117
|
+
if not os.path.isabs(pipeline_dir):
|
|
118
|
+
config_dir = os.path.dirname(os.path.abspath(config_path))
|
|
119
|
+
# Walk up until we find .git or use config's parent's parent as fallback
|
|
120
|
+
project_root = config_dir
|
|
121
|
+
while project_root != '/':
|
|
122
|
+
if os.path.isdir(os.path.join(project_root, '.git')):
|
|
123
|
+
break
|
|
124
|
+
project_root = os.path.dirname(project_root)
|
|
125
|
+
pipeline_dir = os.path.join(project_root, pipeline_dir)
|
|
126
|
+
|
|
127
|
+
seen = set()
|
|
128
|
+
# Check last 7 days of signals files
|
|
129
|
+
for path in sorted(glob.glob(os.path.join(pipeline_dir, '*/signals.json')))[-7:]:
|
|
130
|
+
try:
|
|
131
|
+
signals = json.load(open(path))
|
|
132
|
+
for s in signals:
|
|
133
|
+
if s.get('source') == 'gmail':
|
|
134
|
+
mid = s.get('metadata', {}).get('message_id', '')
|
|
135
|
+
if mid:
|
|
136
|
+
seen.add(mid)
|
|
137
|
+
except (json.JSONDecodeError, KeyError):
|
|
138
|
+
pass
|
|
139
|
+
# Output as comma-separated IDs
|
|
140
|
+
print(','.join(seen))
|
|
141
|
+
" "$PIPELINE_DIR" "$CONFIG_PATH" 2>/dev/null || echo "")
|
|
142
|
+
|
|
143
|
+
if [[ -n "$SEEN_IDS" ]]; then
|
|
144
|
+
SEEN_COUNT=$(echo "$SEEN_IDS" | tr ',' '\n' | wc -l | tr -d ' ')
|
|
145
|
+
echo " · $SEEN_COUNT previously seen Gmail message IDs loaded" >&2
|
|
146
|
+
fi
|
|
147
|
+
|
|
97
148
|
# Fetch emails using gws +triage helper (more reliable than raw API calls —
|
|
98
149
|
# the helper handles auth scopes internally, avoiding insufficientPermissions errors)
|
|
99
150
|
# Fetch recent emails with labels, then filter by label ID in Python
|
|
100
151
|
GWS_ERR=$(mktemp)
|
|
101
152
|
trap "rm -f $GWS_ERR" EXIT
|
|
102
153
|
EMAILS_JSON=$(gws gmail +triage \
|
|
103
|
-
--query "newer_than:
|
|
104
|
-
--max
|
|
154
|
+
--query "newer_than:7d" \
|
|
155
|
+
--max 200 \
|
|
105
156
|
--format json \
|
|
106
157
|
--labels \
|
|
107
158
|
2>"$GWS_ERR") || {
|
|
@@ -122,17 +173,21 @@ EMAILS_JSON=$(gws gmail +triage \
|
|
|
122
173
|
# Determine the scripts directory (where this script lives)
|
|
123
174
|
SCRIPTS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
124
175
|
|
|
176
|
+
export _GMAIL_LABEL_ID="$GMAIL_LABEL_ID"
|
|
177
|
+
export _GMAIL_MAX_ITEMS="$MAX_ITEMS"
|
|
178
|
+
export _GMAIL_CONFIG_PATH="$CONFIG_PATH"
|
|
179
|
+
export _GMAIL_SEEN_IDS="$SEEN_IDS"
|
|
180
|
+
|
|
125
181
|
if [[ "$FETCH_BODY" == "true" ]]; then
|
|
126
182
|
# Deep mode: filter messages first, then pass to fetch-gmail-deep.py for
|
|
127
183
|
# full body fetching, link extraction, and article following
|
|
128
|
-
echo "$EMAILS_JSON" | python3 - "
|
|
129
|
-
import json
|
|
130
|
-
import sys
|
|
131
|
-
import yaml
|
|
184
|
+
echo "$EMAILS_JSON" | python3 -c "
|
|
185
|
+
import json, sys, yaml, os
|
|
132
186
|
|
|
133
|
-
label_id =
|
|
134
|
-
max_items = int(
|
|
135
|
-
config_path =
|
|
187
|
+
label_id = os.environ['_GMAIL_LABEL_ID']
|
|
188
|
+
max_items = int(os.environ['_GMAIL_MAX_ITEMS'])
|
|
189
|
+
config_path = os.environ['_GMAIL_CONFIG_PATH']
|
|
190
|
+
seen_ids = set(os.environ.get('_GMAIL_SEEN_IDS', '').split(',')) - {''}
|
|
136
191
|
|
|
137
192
|
data = json.load(sys.stdin)
|
|
138
193
|
messages = data.get('messages', []) if isinstance(data, dict) else data
|
|
@@ -140,6 +195,12 @@ messages = data.get('messages', []) if isinstance(data, dict) else data
|
|
|
140
195
|
if label_id:
|
|
141
196
|
messages = [m for m in messages if label_id in m.get('labels', [])]
|
|
142
197
|
|
|
198
|
+
before = len(messages)
|
|
199
|
+
messages = [m for m in messages if m.get('id', '') not in seen_ids]
|
|
200
|
+
skipped = before - len(messages)
|
|
201
|
+
if skipped:
|
|
202
|
+
print(f' Dedup: skipped {skipped} already-seen messages', file=sys.stderr)
|
|
203
|
+
|
|
143
204
|
messages = messages[:max_items]
|
|
144
205
|
|
|
145
206
|
with open(config_path) as f:
|
|
@@ -147,19 +208,19 @@ with open(config_path) as f:
|
|
|
147
208
|
gmail_config = config.get('sources', {}).get('gmail', {}) or {}
|
|
148
209
|
|
|
149
210
|
json.dump({'messages': messages, 'config': gmail_config}, sys.stdout)
|
|
150
|
-
|
|
211
|
+
" | python3 "$SCRIPTS_DIR/fetch-gmail-deep.py" || {
|
|
151
212
|
echo "Error: Deep Gmail processing failed" >&2
|
|
152
213
|
exit 1
|
|
153
214
|
}
|
|
154
215
|
else
|
|
155
216
|
# Shallow mode: subject-only signals (original behavior)
|
|
156
|
-
echo "$EMAILS_JSON" | python3 - "
|
|
157
|
-
import json
|
|
158
|
-
import sys
|
|
217
|
+
echo "$EMAILS_JSON" | python3 -c "
|
|
218
|
+
import json, sys, os
|
|
159
219
|
from datetime import datetime, timezone
|
|
160
220
|
|
|
161
|
-
label_id =
|
|
162
|
-
max_items = int(
|
|
221
|
+
label_id = os.environ.get('_GMAIL_LABEL_ID', '')
|
|
222
|
+
max_items = int(os.environ.get('_GMAIL_MAX_ITEMS', '20'))
|
|
223
|
+
seen_ids = set(os.environ.get('_GMAIL_SEEN_IDS', '').split(',')) - {''}
|
|
163
224
|
|
|
164
225
|
data = json.load(sys.stdin)
|
|
165
226
|
messages = data.get('messages', []) if isinstance(data, dict) else data
|
|
@@ -167,6 +228,12 @@ messages = data.get('messages', []) if isinstance(data, dict) else data
|
|
|
167
228
|
if label_id:
|
|
168
229
|
messages = [m for m in messages if label_id in m.get('labels', [])]
|
|
169
230
|
|
|
231
|
+
before = len(messages)
|
|
232
|
+
messages = [m for m in messages if m.get('id', '') not in seen_ids]
|
|
233
|
+
skipped = before - len(messages)
|
|
234
|
+
if skipped:
|
|
235
|
+
print(f' Dedup: skipped {skipped} already-seen messages', file=sys.stderr)
|
|
236
|
+
|
|
170
237
|
messages = messages[:max_items]
|
|
171
238
|
|
|
172
239
|
signals = []
|
|
@@ -203,7 +270,7 @@ for email in messages:
|
|
|
203
270
|
})
|
|
204
271
|
|
|
205
272
|
json.dump(signals, sys.stdout, indent=2)
|
|
206
|
-
|
|
273
|
+
" 2>/dev/null || {
|
|
207
274
|
echo "Error: Failed to parse gws output" >&2
|
|
208
275
|
exit 1
|
|
209
276
|
}
|
package/plugins/marvin/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> "Here I am, brain the size of a planet, and they ask me to review your code. Call that job satisfaction? 'Cause I don't."
|
|
4
4
|
|
|
5
|
-
A quality plugin for Claude Code.
|
|
5
|
+
A quality plugin for Claude Code. Nine skills for the unglamorous work that compounds: executing plans, reviewing code, documenting solutions, scaffolding projects, writing failing tests, adversarial review, keeping copy clean, and publishing browser-viewable artifacts.
|
|
6
6
|
|
|
7
7
|
## Skills
|
|
8
8
|
|
|
@@ -29,6 +29,12 @@ Write failing tests from user stories and architecture docs. Behavioral tests ve
|
|
|
29
29
|
### `/marvin:copy-editor`
|
|
30
30
|
Two-layer copy editor. Layer 1 is a deterministic typography audit (regex-level, auto-closeable). Layer 2 is LLM judgment — reject-list hits, nominal-style detection, clarity/ambiguity pass for participant-facing content, voice/register check, and spoken-readability read. Loads repo-local `.copy-editor.yaml` to compose the baked-in language profile with the repo's style guide.
|
|
31
31
|
|
|
32
|
+
### `/marvin:share-server-setup`
|
|
33
|
+
Set up or adopt a local share server for browser-viewable coding-agent artifacts. Supports configuring an existing compatible server, installing the Heart of Gold reference share server, adding macOS LaunchAgent persistence, and optionally exposing only the viewer surface over `tailscale serve`.
|
|
34
|
+
|
|
35
|
+
### `/marvin:share-html`
|
|
36
|
+
Publish a local HTML file or static site directory to the configured share server and return a browser URL. Supports a single `.html` file or a directory containing `index.html`.
|
|
37
|
+
|
|
32
38
|
## Agents
|
|
33
39
|
|
|
34
40
|
| Agent | Focus |
|
package/src/index.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { shareServerCommand } from "./commands/share-server";
|
|
|
8
8
|
const main = defineCommand({
|
|
9
9
|
meta: {
|
|
10
10
|
name: "heart-of-gold",
|
|
11
|
-
version: "0.1.
|
|
11
|
+
version: "0.1.30",
|
|
12
12
|
description:
|
|
13
13
|
"Cross-platform installer for Heart of Gold skills — Codex, OpenCode, Pi, Claude Code, and more",
|
|
14
14
|
},
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/plugins/{guide → marvin}/skills/share-server-setup/scripts/configure-existing-server.sh
RENAMED
|
File without changes
|
/package/plugins/{guide → marvin}/skills/share-server-setup/scripts/configure-tailscale-viewer.sh
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/plugins/{guide → marvin}/skills/share-server-setup/scripts/install-reference-server.sh
RENAMED
|
File without changes
|