@heart-of-gold/toolkit 0.1.32 → 0.1.33
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 +3 -3
- package/package.json +1 -1
- package/plugins/babel-fish/.claude-plugin/plugin.json +1 -1
- package/plugins/babel-fish/skills/visualize/SKILL.md +19 -16
- package/plugins/babel-fish/skills/visualize/scripts/render-and-share.sh +18 -2
- package/plugins/deep-thought/.claude-plugin/plugin.json +1 -1
- package/plugins/deep-thought/skills/architect/SKILL.md +2 -2
- package/plugins/deep-thought/skills/brainstorm/SKILL.md +2 -2
- package/plugins/deep-thought/skills/plan/SKILL.md +2 -2
- package/plugins/guide/scripts/fetch-gmail.sh +21 -88
- package/plugins/marvin/.claude-plugin/plugin.json +1 -1
|
@@ -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.
|
|
18
|
+
"version": "0.2.3"
|
|
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.
|
|
24
|
+
"version": "0.3.3"
|
|
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.
|
|
30
|
+
"version": "0.2.1"
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
"name": "quellis",
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: visualize
|
|
3
3
|
description: >
|
|
4
|
-
Render mind maps and tree visualizations from markdown. Prefer
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
mindmap, mind map, show me the structure, draw a map.
|
|
4
|
+
Render mind maps and tree visualizations from markdown. Prefer shareable HTML first for brainstorms, plans,
|
|
5
|
+
architecture docs, and other structured workflow artifacts when share-html infrastructure is configured;
|
|
6
|
+
otherwise fall back to terminal output for quick local inspection. Works on markdown files or any structured
|
|
7
|
+
content. Triggers: visualize, mindmap, mind map, show me the structure, draw a map.
|
|
8
8
|
allowed-tools:
|
|
9
9
|
- Read
|
|
10
10
|
- Bash
|
|
@@ -88,25 +88,26 @@ This script:
|
|
|
88
88
|
|
|
89
89
|
## Phase 0 — Determine What to Visualize
|
|
90
90
|
|
|
91
|
-
First decide whether
|
|
92
|
-
- a quick terminal view
|
|
93
|
-
- a browser/shareable HTML view
|
|
91
|
+
First decide whether this should be a browser/shareable HTML view or a quick terminal view.
|
|
94
92
|
|
|
95
|
-
**Prefer browser/shareable HTML when:**
|
|
93
|
+
**Prefer browser/shareable HTML first when:**
|
|
94
|
+
- the source is a brainstorm, plan, architecture doc, or other structured workflow artifact
|
|
96
95
|
- the user asks to open it in a browser
|
|
97
96
|
- the user wants to share the result with another person or device
|
|
98
97
|
- the structure is large enough that browser navigation is more useful than terminal rendering
|
|
98
|
+
- `share-html` is configured
|
|
99
99
|
|
|
100
100
|
**Prefer terminal rendering when:**
|
|
101
|
-
- the user wants a quick local look
|
|
102
|
-
- the environment is SSH-heavy or browser access is not requested
|
|
103
101
|
- share-html is not configured
|
|
102
|
+
- the user explicitly wants a quick terminal-only look
|
|
103
|
+
- the environment is SSH-heavy and the browser/share path is not requested
|
|
104
104
|
|
|
105
105
|
When invoked as `/visualize [path]`:
|
|
106
106
|
|
|
107
107
|
**If a file path is provided:**
|
|
108
108
|
1. Read the file
|
|
109
|
-
2.
|
|
109
|
+
2. If it looks like a brainstorm, plan, architecture doc, or the user asked for browser viewing, try the shareable HTML path first
|
|
110
|
+
3. Otherwise render it directly with the mind map renderer
|
|
110
111
|
|
|
111
112
|
**If no path is provided:**
|
|
112
113
|
1. Check if there's a recent brainstorm or plan document in the conversation context
|
|
@@ -140,17 +141,19 @@ The default mode is **vertical layout** — boxes on main branches, compact leav
|
|
|
140
141
|
|
|
141
142
|
### Path B — Shareable HTML
|
|
142
143
|
|
|
143
|
-
|
|
144
|
+
For brainstorms, plans, architecture docs, and other structured workflow artifacts, prefer this path first when `share-html` is configured.
|
|
144
145
|
|
|
145
146
|
1. Verify or assume the input markdown is ready
|
|
146
147
|
2. Run:
|
|
147
148
|
```bash
|
|
148
|
-
bash scripts/render-and-share.sh [file]
|
|
149
|
+
bash scripts/render-and-share.sh --url-only [file]
|
|
149
150
|
```
|
|
150
|
-
3. Read the returned
|
|
151
|
-
4. Return
|
|
151
|
+
3. Read the returned URL from stdout
|
|
152
|
+
4. Return that URL to the user as the primary result
|
|
152
153
|
5. Briefly explain what was published
|
|
153
154
|
|
|
155
|
+
If you need more detail for debugging, you may run the helper without `--url-only` and inspect the returned JSON.
|
|
156
|
+
|
|
154
157
|
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.
|
|
155
158
|
|
|
156
159
|
**For shell usage** (not through assistant panels): terminal rendering can use ANSI colors, or `--horizontal` for the wide spatial layout.
|
|
@@ -160,7 +163,7 @@ If publishing fails because the share server is not configured, say so clearly a
|
|
|
160
163
|
After rendering or sharing, briefly note:
|
|
161
164
|
- for terminal mode: "Use `--depth N` to see more/less detail"
|
|
162
165
|
- for terminal mode: "Use `--width N` to fit a different terminal size"
|
|
163
|
-
- for shared HTML: return the
|
|
166
|
+
- for shared HTML: return the final browser URL as the main result and say whether it is local-only or publicly reachable on the user's tailnet
|
|
164
167
|
- if publishing failed due to missing share infrastructure: suggest `share-server-setup`
|
|
165
168
|
- if the source was a brainstorm/plan/architecture doc, offer to continue the workflow (e.g., proceed to `/plan`, `/work`, or implementation)
|
|
166
169
|
|
|
@@ -9,14 +9,16 @@ SLUG=""
|
|
|
9
9
|
TITLE=""
|
|
10
10
|
ALIAS=""
|
|
11
11
|
KEEP_HTML=0
|
|
12
|
+
URL_ONLY=0
|
|
12
13
|
HTML_OUT=""
|
|
13
14
|
TEMP_DIR=""
|
|
14
15
|
|
|
15
16
|
usage() {
|
|
16
17
|
cat <<'EOF'
|
|
17
|
-
Usage: render-and-share.sh <markdown-file> [--slug STEM] [--title TITLE] [--alias ALIAS] [--html-out PATH] [--keep-html]
|
|
18
|
+
Usage: render-and-share.sh <markdown-file> [--slug STEM] [--title TITLE] [--alias ALIAS] [--html-out PATH] [--keep-html] [--url-only]
|
|
18
19
|
|
|
19
20
|
Generate an HTML mind map from a markdown file, publish it via share-html, and print the publish JSON.
|
|
21
|
+
Use --url-only to print only the final browser URL.
|
|
20
22
|
EOF
|
|
21
23
|
}
|
|
22
24
|
|
|
@@ -27,6 +29,7 @@ while [[ $# -gt 0 ]]; do
|
|
|
27
29
|
--alias) ALIAS="$2"; shift 2 ;;
|
|
28
30
|
--html-out) HTML_OUT="$2"; shift 2 ;;
|
|
29
31
|
--keep-html) KEEP_HTML=1; shift ;;
|
|
32
|
+
--url-only) URL_ONLY=1; shift ;;
|
|
30
33
|
--help) usage; exit 0 ;;
|
|
31
34
|
--*) echo "Unknown argument: $1" >&2; exit 1 ;;
|
|
32
35
|
*)
|
|
@@ -104,4 +107,17 @@ if [[ -n "$SLUG" ]]; then CMD+=(--slug "$SLUG"); fi
|
|
|
104
107
|
if [[ -n "$TITLE" ]]; then CMD+=(--title "$TITLE"); fi
|
|
105
108
|
if [[ -n "$ALIAS" ]]; then CMD+=(--alias "$ALIAS"); fi
|
|
106
109
|
|
|
107
|
-
"${CMD[@]}"
|
|
110
|
+
PUBLISH_JSON="$("${CMD[@]}")"
|
|
111
|
+
|
|
112
|
+
if [[ "$URL_ONLY" -eq 1 ]]; then
|
|
113
|
+
python3 - <<'PY' "$PUBLISH_JSON"
|
|
114
|
+
import json, sys
|
|
115
|
+
payload = json.loads(sys.argv[1])
|
|
116
|
+
if not payload.get("ok", True):
|
|
117
|
+
print(json.dumps(payload))
|
|
118
|
+
raise SystemExit(1)
|
|
119
|
+
print(payload.get("url") or payload.get("viewerUrl") or "")
|
|
120
|
+
PY
|
|
121
|
+
else
|
|
122
|
+
printf '%s\n' "$PUBLISH_JSON"
|
|
123
|
+
fi
|
|
@@ -176,12 +176,12 @@ Use **AskUserQuestion** with:
|
|
|
176
176
|
- header: "Next step"
|
|
177
177
|
- options:
|
|
178
178
|
1. label: "Start implementation (Recommended)", description: "Proceed to scaffold or test writing"
|
|
179
|
-
2. label: "Visualize / Share", description: "
|
|
179
|
+
2. label: "Visualize / Share", description: "Generate a shareable HTML view first when sharing is configured; otherwise render structure in the terminal"
|
|
180
180
|
3. label: "Review and refine", description: "Adjust stories or architecture based on feedback"
|
|
181
181
|
4. label: "Done for now", description: "Return later"
|
|
182
182
|
- multiSelect: false
|
|
183
183
|
|
|
184
|
-
**If user selects "Visualize / Share":** Run `/babel-fish:visualize {stories_path}/{slug}.architecture.md` and
|
|
184
|
+
**If user selects "Visualize / Share":** Run `/babel-fish:visualize {stories_path}/{slug}.architecture.md` and try the shareable HTML flow first when `share-html` is configured. Otherwise render the terminal mind map. After rendering or sharing, return to this handoff with the remaining options.
|
|
185
185
|
|
|
186
186
|
**If pipeline mode (`$BRAINSTORM_PATH` set):**
|
|
187
187
|
Complete without asking. Output paths for downstream consumers:
|
|
@@ -291,13 +291,13 @@ Ask the user what to do next.
|
|
|
291
291
|
- Prefer the harness's structured choice UI if available
|
|
292
292
|
- Otherwise present this short plain-text choice list:
|
|
293
293
|
1. **Proceed to /plan** — Turn these decisions into an implementation plan
|
|
294
|
-
2. **Visualize / Share** —
|
|
294
|
+
2. **Visualize / Share** — Generate a shareable HTML mind map first when sharing is configured; otherwise render in the terminal
|
|
295
295
|
3. **Keep exploring** — More questions or refine decisions before moving on
|
|
296
296
|
4. **Done for now** — Return later; to plan: `/plan {brainstorm-path}`
|
|
297
297
|
|
|
298
298
|
**If user selects "Proceed to /plan":** Suggest running `/plan {brainstorm-path}`.
|
|
299
299
|
|
|
300
|
-
**If user selects "Visualize / Share":** Run `/babel-fish:visualize {brainstorm-path}` and
|
|
300
|
+
**If user selects "Visualize / Share":** Run `/babel-fish:visualize {brainstorm-path}` and try the shareable HTML flow first when `share-html` is configured. Otherwise render the terminal mind map. After rendering or sharing, return to this handoff with the remaining options.
|
|
301
301
|
|
|
302
302
|
**If user selects "Keep exploring":** Return to Phase 3 and continue asking questions one at a time. When satisfied, update the document and return to this handoff.
|
|
303
303
|
|
|
@@ -283,13 +283,13 @@ Ask the user what to do next.
|
|
|
283
283
|
- Prefer the harness's structured choice UI if available
|
|
284
284
|
- Otherwise present this short plain-text choice list:
|
|
285
285
|
1. **Start /work (Recommended)** — Begin implementing this plan
|
|
286
|
-
2. **Visualize / Share** —
|
|
286
|
+
2. **Visualize / Share** — Generate a shareable HTML mind map first when sharing is configured; otherwise render in the terminal
|
|
287
287
|
3. **Review and refine** — Adjust the plan based on feedback
|
|
288
288
|
4. **Done for now** — Return later; to start: `/work {plan-path}`
|
|
289
289
|
|
|
290
290
|
**If user selects "Start /work":** Suggest running `/work {plan-path}`.
|
|
291
291
|
|
|
292
|
-
**If user selects "Visualize / Share":** Run `/babel-fish:visualize {plan-path}` and
|
|
292
|
+
**If user selects "Visualize / Share":** Run `/babel-fish:visualize {plan-path}` and try the shareable HTML flow first when `share-html` is configured. Otherwise render the terminal mind map. After rendering or sharing, return to this handoff with the remaining options.
|
|
293
293
|
|
|
294
294
|
**If user selects "Review and refine":** Accept feedback, update the plan, then present these options again.
|
|
295
295
|
|
|
@@ -82,15 +82,11 @@ print(fetch_body)
|
|
|
82
82
|
PY
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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}"
|
|
85
|
+
if mapfile -t GMAIL_SETTINGS < <(read_gmail_settings "$CONFIG_PATH" 2>/dev/null); then
|
|
86
|
+
GMAIL_LABEL="${GMAIL_SETTINGS[0]:-Content-Feed}"
|
|
87
|
+
MAX_ITEMS="${GMAIL_SETTINGS[1]:-20}"
|
|
88
|
+
GMAIL_LABEL_ID="${GMAIL_SETTINGS[2]:-}"
|
|
89
|
+
FETCH_BODY="${GMAIL_SETTINGS[3]:-false}"
|
|
94
90
|
else
|
|
95
91
|
GMAIL_LABEL="Content-Feed"
|
|
96
92
|
MAX_ITEMS="20"
|
|
@@ -98,61 +94,14 @@ else
|
|
|
98
94
|
FETCH_BODY="false"
|
|
99
95
|
fi
|
|
100
96
|
|
|
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
|
-
|
|
148
97
|
# Fetch emails using gws +triage helper (more reliable than raw API calls —
|
|
149
98
|
# the helper handles auth scopes internally, avoiding insufficientPermissions errors)
|
|
150
99
|
# Fetch recent emails with labels, then filter by label ID in Python
|
|
151
100
|
GWS_ERR=$(mktemp)
|
|
152
101
|
trap "rm -f $GWS_ERR" EXIT
|
|
153
102
|
EMAILS_JSON=$(gws gmail +triage \
|
|
154
|
-
--query "newer_than:
|
|
155
|
-
--max
|
|
103
|
+
--query "newer_than:3d" \
|
|
104
|
+
--max 50 \
|
|
156
105
|
--format json \
|
|
157
106
|
--labels \
|
|
158
107
|
2>"$GWS_ERR") || {
|
|
@@ -173,21 +122,17 @@ EMAILS_JSON=$(gws gmail +triage \
|
|
|
173
122
|
# Determine the scripts directory (where this script lives)
|
|
174
123
|
SCRIPTS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
175
124
|
|
|
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
|
-
|
|
181
125
|
if [[ "$FETCH_BODY" == "true" ]]; then
|
|
182
126
|
# Deep mode: filter messages first, then pass to fetch-gmail-deep.py for
|
|
183
127
|
# full body fetching, link extraction, and article following
|
|
184
|
-
echo "$EMAILS_JSON" | python3 -
|
|
185
|
-
import json
|
|
128
|
+
echo "$EMAILS_JSON" | python3 - "$GMAIL_LABEL_ID" "$MAX_ITEMS" "$CONFIG_PATH" <<'PY' 2>/dev/null | python3 "$SCRIPTS_DIR/fetch-gmail-deep.py" || {
|
|
129
|
+
import json
|
|
130
|
+
import sys
|
|
131
|
+
import yaml
|
|
186
132
|
|
|
187
|
-
label_id =
|
|
188
|
-
max_items = int(
|
|
189
|
-
config_path =
|
|
190
|
-
seen_ids = set(os.environ.get('_GMAIL_SEEN_IDS', '').split(',')) - {''}
|
|
133
|
+
label_id = sys.argv[1]
|
|
134
|
+
max_items = int(sys.argv[2])
|
|
135
|
+
config_path = sys.argv[3]
|
|
191
136
|
|
|
192
137
|
data = json.load(sys.stdin)
|
|
193
138
|
messages = data.get('messages', []) if isinstance(data, dict) else data
|
|
@@ -195,12 +140,6 @@ messages = data.get('messages', []) if isinstance(data, dict) else data
|
|
|
195
140
|
if label_id:
|
|
196
141
|
messages = [m for m in messages if label_id in m.get('labels', [])]
|
|
197
142
|
|
|
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
|
-
|
|
204
143
|
messages = messages[:max_items]
|
|
205
144
|
|
|
206
145
|
with open(config_path) as f:
|
|
@@ -208,19 +147,19 @@ with open(config_path) as f:
|
|
|
208
147
|
gmail_config = config.get('sources', {}).get('gmail', {}) or {}
|
|
209
148
|
|
|
210
149
|
json.dump({'messages': messages, 'config': gmail_config}, sys.stdout)
|
|
211
|
-
|
|
150
|
+
PY
|
|
212
151
|
echo "Error: Deep Gmail processing failed" >&2
|
|
213
152
|
exit 1
|
|
214
153
|
}
|
|
215
154
|
else
|
|
216
155
|
# Shallow mode: subject-only signals (original behavior)
|
|
217
|
-
echo "$EMAILS_JSON" | python3 -
|
|
218
|
-
import json
|
|
156
|
+
echo "$EMAILS_JSON" | python3 - "$GMAIL_LABEL_ID" "$MAX_ITEMS" <<'PY' 2>/dev/null || {
|
|
157
|
+
import json
|
|
158
|
+
import sys
|
|
219
159
|
from datetime import datetime, timezone
|
|
220
160
|
|
|
221
|
-
label_id =
|
|
222
|
-
max_items = int(
|
|
223
|
-
seen_ids = set(os.environ.get('_GMAIL_SEEN_IDS', '').split(',')) - {''}
|
|
161
|
+
label_id = sys.argv[1]
|
|
162
|
+
max_items = int(sys.argv[2])
|
|
224
163
|
|
|
225
164
|
data = json.load(sys.stdin)
|
|
226
165
|
messages = data.get('messages', []) if isinstance(data, dict) else data
|
|
@@ -228,12 +167,6 @@ messages = data.get('messages', []) if isinstance(data, dict) else data
|
|
|
228
167
|
if label_id:
|
|
229
168
|
messages = [m for m in messages if label_id in m.get('labels', [])]
|
|
230
169
|
|
|
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
|
-
|
|
237
170
|
messages = messages[:max_items]
|
|
238
171
|
|
|
239
172
|
signals = []
|
|
@@ -270,7 +203,7 @@ for email in messages:
|
|
|
270
203
|
})
|
|
271
204
|
|
|
272
205
|
json.dump(signals, sys.stdout, indent=2)
|
|
273
|
-
|
|
206
|
+
PY
|
|
274
207
|
echo "Error: Failed to parse gws output" >&2
|
|
275
208
|
exit 1
|
|
276
209
|
}
|