crewly 1.5.14 → 1.5.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/skills/_common/lib.sh +4 -2
- package/config/skills/_common/lib.test.sh +28 -0
- package/config/skills/agent/screenshot-compare/execute.sh +4 -4
- package/config/skills/agent/xhs-article-to-image/SKILL.md +52 -0
- package/config/skills/agent/xhs-article-to-image/execute.sh +120 -0
- package/config/skills/agent/xhs-article-to-image/render.mjs +601 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/communication.module.d.ts +8 -2
- package/dist/backend/backend/src/services/ai/prompt-modules/communication.module.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/communication.module.js +11 -3
- package/dist/backend/backend/src/services/ai/prompt-modules/communication.module.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts +8 -2
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js +22 -11
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
- package/package.json +1 -1
|
@@ -21,8 +21,10 @@ CREWLY_API_URL="${CREWLY_API_URL:-http://localhost:8787}"
|
|
|
21
21
|
# and replaces the script's positional parameters with the file contents.
|
|
22
22
|
# All downstream parsing (read_json_input, custom arg loops) works unchanged.
|
|
23
23
|
#
|
|
24
|
-
# Usage (by LLM CLI):
|
|
25
|
-
#
|
|
24
|
+
# Usage (by LLM CLI — use heredoc to avoid single-quote EOF issues):
|
|
25
|
+
# cat > /tmp/crewly_input.json << 'CREWLY_EOF'
|
|
26
|
+
# {"summary":"text with 'quotes' and special chars"}
|
|
27
|
+
# CREWLY_EOF
|
|
26
28
|
# bash execute.sh --file /tmp/crewly_input.json
|
|
27
29
|
#
|
|
28
30
|
# This runs at source-time, so every script that sources lib.sh gets it for free.
|
|
@@ -156,6 +156,34 @@ echo '{}' > "$TEMP_DIR/empty.json"
|
|
|
156
156
|
RESULT=$(bash "$TEMP_DIR/test_read_json.sh" --file "$TEMP_DIR/empty.json")
|
|
157
157
|
assert_eq "--file with empty JSON" '{}' "$RESULT"
|
|
158
158
|
|
|
159
|
+
# ---- Test 14: --file with heredoc-created file (single quotes in JSON) ----
|
|
160
|
+
# This simulates the exact pattern Gemini CLI agents now use:
|
|
161
|
+
# cat > /tmp/file << 'CREWLY_EOF'
|
|
162
|
+
# {"summary":"it's working — don't worry"}
|
|
163
|
+
# CREWLY_EOF
|
|
164
|
+
cat > "$TEMP_DIR/heredoc_single_quotes.json" << 'CREWLY_EOF'
|
|
165
|
+
{"summary":"it's working — don't worry about 'edge cases'"}
|
|
166
|
+
CREWLY_EOF
|
|
167
|
+
RESULT=$(bash "$TEMP_DIR/test_skill.sh" --file "$TEMP_DIR/heredoc_single_quotes.json")
|
|
168
|
+
assert_contains "heredoc with single quotes" "it's working" "$RESULT"
|
|
169
|
+
assert_contains "heredoc with multiple single quotes" "edge cases" "$RESULT"
|
|
170
|
+
|
|
171
|
+
# ---- Test 15: --file with heredoc-created file (backticks and $vars) ----
|
|
172
|
+
cat > "$TEMP_DIR/heredoc_special.json" << 'CREWLY_EOF'
|
|
173
|
+
{"text":"Use `jq` to parse $HOME and $(whoami) safely"}
|
|
174
|
+
CREWLY_EOF
|
|
175
|
+
RESULT=$(bash "$TEMP_DIR/test_skill.sh" --file "$TEMP_DIR/heredoc_special.json")
|
|
176
|
+
assert_contains "heredoc preserves backticks" '`jq`' "$RESULT"
|
|
177
|
+
assert_contains "heredoc preserves \$HOME" '$HOME' "$RESULT"
|
|
178
|
+
assert_contains "heredoc preserves \$()" '$(whoami)' "$RESULT"
|
|
179
|
+
|
|
180
|
+
# ---- Test 16: --file with heredoc-created file (mixed quotes) ----
|
|
181
|
+
cat > "$TEMP_DIR/heredoc_mixed.json" << 'CREWLY_EOF'
|
|
182
|
+
{"text":"He said \"it's fine\" and she said 'OK'"}
|
|
183
|
+
CREWLY_EOF
|
|
184
|
+
RESULT=$(bash "$TEMP_DIR/test_skill.sh" --file "$TEMP_DIR/heredoc_mixed.json")
|
|
185
|
+
assert_contains "heredoc handles mixed quotes" "it's fine" "$RESULT"
|
|
186
|
+
|
|
159
187
|
echo ""
|
|
160
188
|
echo "=== Results: $PASS/$TOTAL passed, $FAIL failed ==="
|
|
161
189
|
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
set -euo pipefail
|
|
16
16
|
|
|
17
17
|
# ── Configuration ──────────────────────────────────────────────────────────────
|
|
18
|
-
MODEL="${GEMINI_MODEL:-gemini-2.
|
|
18
|
+
MODEL="${GEMINI_MODEL:-gemini-2.0-flash}"
|
|
19
19
|
GEMINI_API_BASE="https://generativelanguage.googleapis.com"
|
|
20
20
|
GEMINI_CONTENT_URL="${GEMINI_API_BASE}/v1beta/models/${MODEL}:generateContent"
|
|
21
21
|
MAX_IMAGE_SIZE_MB=4
|
|
@@ -149,12 +149,12 @@ REQUEST_BODY=$(cat <<ENDJSON
|
|
|
149
149
|
ENDJSON
|
|
150
150
|
)
|
|
151
151
|
|
|
152
|
-
TMPFILE
|
|
152
|
+
TMPFILE="/tmp/gemini-compare-$(date +%s).json"
|
|
153
153
|
echo "$REQUEST_BODY" > "$TMPFILE"
|
|
154
|
-
RESPONSE=$(curl -
|
|
154
|
+
RESPONSE=$(curl -s -X POST \
|
|
155
155
|
"${GEMINI_CONTENT_URL}?key=${GEMINI_API_KEY}" \
|
|
156
156
|
-H "Content-Type: application/json" \
|
|
157
|
-
-d "@${TMPFILE}"
|
|
157
|
+
-d "@${TMPFILE}")
|
|
158
158
|
rm -f "$TMPFILE"
|
|
159
159
|
|
|
160
160
|
HTTP_CODE=$?
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# xhs-article-to-image
|
|
2
|
+
|
|
3
|
+
Convert markdown articles into XiaoHongShu (小红书) style image cards.
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Generates multiple PNG images (1080×1440, 3:4 portrait ratio) from markdown article content, styled in the popular XiaoHongShu magazine-layout format: bold titles, clean white backgrounds, structured paragraphs with visual hierarchy.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
bash execute.sh '{"content":"# Title\n\nArticle body...","outputDir":"/tmp/xhs-output"}'
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Or from a file:
|
|
16
|
+
```bash
|
|
17
|
+
bash execute.sh '{"sourceFile":"/path/to/article.md","outputDir":"/tmp/xhs-output"}'
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Parameters
|
|
21
|
+
|
|
22
|
+
| Parameter | Required | Default | Description |
|
|
23
|
+
|-----------|----------|---------|-------------|
|
|
24
|
+
| content | Yes* | - | Markdown article content (required if no sourceFile) |
|
|
25
|
+
| sourceFile | Yes* | - | Path to markdown file (required if no content) |
|
|
26
|
+
| outputDir | Yes | - | Directory to write PNG images to |
|
|
27
|
+
| title | No | auto | Override the article title (auto-extracts from first H1) |
|
|
28
|
+
| author | No | "" | Author name shown at bottom of pages |
|
|
29
|
+
| accentColor | No | "#1a1a1a" | Accent color for decorative elements |
|
|
30
|
+
| bgColor | No | "#fafaf8" | Background color |
|
|
31
|
+
| maxCharsPerPage | No | 350 | Approximate characters per page before splitting |
|
|
32
|
+
| coverImage | No | "" | URL or path to image for the cover page |
|
|
33
|
+
|
|
34
|
+
## Output
|
|
35
|
+
|
|
36
|
+
- Multiple PNG files: `page-01.png`, `page-02.png`, etc.
|
|
37
|
+
- First page is the title/cover page
|
|
38
|
+
- Returns JSON with file paths and metadata
|
|
39
|
+
|
|
40
|
+
## Dependencies
|
|
41
|
+
|
|
42
|
+
- Node.js 18+
|
|
43
|
+
- Playwright (chromium)
|
|
44
|
+
|
|
45
|
+
## Style Features
|
|
46
|
+
|
|
47
|
+
- 3:4 portrait ratio (1080×1440px) optimized for XHS
|
|
48
|
+
- Bold sans-serif Chinese/English typography (Noto Sans SC)
|
|
49
|
+
- Clean white/cream background with subtle decorative elements
|
|
50
|
+
- Magazine-style paragraph layout with visual breathing room
|
|
51
|
+
- Page numbering (current/total)
|
|
52
|
+
- Optional author attribution
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Convert markdown articles into XiaoHongShu-style image cards (1080x1440 PNG)
|
|
3
|
+
# Uses Playwright to render HTML+CSS templates and capture screenshots.
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
|
+
source "${SCRIPT_DIR}/../_common/lib.sh"
|
|
7
|
+
|
|
8
|
+
INPUT=$(read_json_input "${1:-}")
|
|
9
|
+
[ -z "$INPUT" ] && error_exit "Usage: execute.sh '{\"content\":\"# Title\\n\\nBody...\",\"outputDir\":\"/tmp/xhs\"}' or '{\"sourceFile\":\"/path/to/article.md\",\"outputDir\":\"/tmp/xhs\"}'"
|
|
10
|
+
|
|
11
|
+
# Parse parameters
|
|
12
|
+
CONTENT=$(printf '%s' "$INPUT" | jq -r '.content // empty')
|
|
13
|
+
SOURCE_FILE=$(printf '%s' "$INPUT" | jq -r '.sourceFile // empty')
|
|
14
|
+
OUTPUT_DIR=$(printf '%s' "$INPUT" | jq -r '.outputDir // empty')
|
|
15
|
+
TITLE_OVERRIDE=$(printf '%s' "$INPUT" | jq -r '.title // empty')
|
|
16
|
+
AUTHOR=$(printf '%s' "$INPUT" | jq -r '.author // empty')
|
|
17
|
+
ACCENT_COLOR=$(printf '%s' "$INPUT" | jq -r '.accentColor // "#1a1a1a"')
|
|
18
|
+
BG_COLOR=$(printf '%s' "$INPUT" | jq -r '.bgColor // "#fafaf8"')
|
|
19
|
+
MAX_CHARS=$(printf '%s' "$INPUT" | jq -r '.maxCharsPerPage // "350"')
|
|
20
|
+
COVER_IMAGE=$(printf '%s' "$INPUT" | jq -r '.coverImage // empty')
|
|
21
|
+
|
|
22
|
+
# Load content from file if sourceFile is provided
|
|
23
|
+
if [ -n "$SOURCE_FILE" ]; then
|
|
24
|
+
if [ ! -f "$SOURCE_FILE" ]; then
|
|
25
|
+
error_exit "Source file not found: $SOURCE_FILE"
|
|
26
|
+
fi
|
|
27
|
+
CONTENT=$(cat "$SOURCE_FILE")
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
require_param "content" "$CONTENT"
|
|
31
|
+
require_param "outputDir" "$OUTPUT_DIR"
|
|
32
|
+
|
|
33
|
+
# Create output directory
|
|
34
|
+
mkdir -p "$OUTPUT_DIR"
|
|
35
|
+
|
|
36
|
+
# Extract title from markdown (first # heading)
|
|
37
|
+
if [ -n "$TITLE_OVERRIDE" ]; then
|
|
38
|
+
TITLE="$TITLE_OVERRIDE"
|
|
39
|
+
else
|
|
40
|
+
TITLE=$(echo "$CONTENT" | grep -m1 '^# ' | sed 's/^# //' || echo "Untitled")
|
|
41
|
+
if [ -z "$TITLE" ]; then
|
|
42
|
+
TITLE="Untitled"
|
|
43
|
+
fi
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# Remove title line from content body
|
|
47
|
+
BODY=$(echo "$CONTENT" | sed '0,/^# .*$/d')
|
|
48
|
+
if [ -z "$BODY" ]; then
|
|
49
|
+
BODY="$CONTENT"
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# ─── Split content into pages ─────────────────────────────────────────────────
|
|
53
|
+
# Split on explicit --- page breaks first, then by character count
|
|
54
|
+
|
|
55
|
+
# Use node to do the splitting and rendering (complex text processing)
|
|
56
|
+
RENDER_INPUT=$(jq -n \
|
|
57
|
+
--arg title "$TITLE" \
|
|
58
|
+
--arg author "$AUTHOR" \
|
|
59
|
+
--arg accentColor "$ACCENT_COLOR" \
|
|
60
|
+
--arg bgColor "$BG_COLOR" \
|
|
61
|
+
--arg outputDir "$OUTPUT_DIR" \
|
|
62
|
+
--arg coverImage "$COVER_IMAGE" \
|
|
63
|
+
--arg body "$BODY" \
|
|
64
|
+
--argjson maxChars "$MAX_CHARS" \
|
|
65
|
+
'{
|
|
66
|
+
title: $title,
|
|
67
|
+
author: $author,
|
|
68
|
+
accentColor: $accentColor,
|
|
69
|
+
bgColor: $bgColor,
|
|
70
|
+
outputDir: $outputDir,
|
|
71
|
+
coverImage: $coverImage,
|
|
72
|
+
maxChars: $maxChars,
|
|
73
|
+
body: $body
|
|
74
|
+
}')
|
|
75
|
+
|
|
76
|
+
# Use Node.js to split content into pages (handles complex markdown parsing)
|
|
77
|
+
PAGES_JSON=$(node -e "
|
|
78
|
+
const input = JSON.parse(process.argv[1]);
|
|
79
|
+
const body = input.body;
|
|
80
|
+
const maxChars = input.maxChars;
|
|
81
|
+
|
|
82
|
+
function splitIntoPages(markdown, maxChars) {
|
|
83
|
+
const explicitSections = markdown.split(/\n---\n/).filter(s => s.trim());
|
|
84
|
+
const pages = [];
|
|
85
|
+
for (const section of explicitSections) {
|
|
86
|
+
if (section.length <= maxChars) {
|
|
87
|
+
pages.push(section.trim());
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const blocks = section.split(/\n\n/).filter(b => b.trim());
|
|
91
|
+
let currentPage = '';
|
|
92
|
+
for (const block of blocks) {
|
|
93
|
+
if (currentPage.length > 0 && currentPage.length + block.length > maxChars) {
|
|
94
|
+
pages.push(currentPage.trim());
|
|
95
|
+
currentPage = block;
|
|
96
|
+
} else {
|
|
97
|
+
currentPage += (currentPage ? '\n\n' : '') + block;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (currentPage.trim()) pages.push(currentPage.trim());
|
|
101
|
+
}
|
|
102
|
+
return pages.length > 0 ? pages : [markdown.trim()];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const pages = splitIntoPages(body, maxChars);
|
|
106
|
+
console.log(JSON.stringify(pages));
|
|
107
|
+
" "$RENDER_INPUT")
|
|
108
|
+
|
|
109
|
+
# Build final render input with pages array
|
|
110
|
+
FINAL_INPUT=$(printf '%s' "$RENDER_INPUT" | jq --argjson pages "$PAGES_JSON" '. + {pages: $pages} | del(.body, .maxChars)')
|
|
111
|
+
|
|
112
|
+
# Run Playwright renderer
|
|
113
|
+
RESULT=$(node "$SCRIPT_DIR/render.mjs" "$FINAL_INPUT" 2>&1)
|
|
114
|
+
|
|
115
|
+
# Check for errors
|
|
116
|
+
if echo "$RESULT" | jq -e '.success == true' > /dev/null 2>&1; then
|
|
117
|
+
echo "$RESULT" | jq --arg title "$TITLE" '. + {title: $title}'
|
|
118
|
+
else
|
|
119
|
+
error_exit "Rendering failed: $RESULT"
|
|
120
|
+
fi
|
|
@@ -0,0 +1,601 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XHS Article-to-Image Renderer
|
|
3
|
+
*
|
|
4
|
+
* Converts markdown article content into multiple XiaoHongShu-style
|
|
5
|
+
* PNG image cards (1080×1440, 3:4 portrait) using Playwright.
|
|
6
|
+
*
|
|
7
|
+
* Input: JSON via argv[2] with { pages, title, author, accentColor, bgColor, outputDir, coverImage }
|
|
8
|
+
* Output: PNG files written to outputDir, JSON result to stdout.
|
|
9
|
+
*/
|
|
10
|
+
import { chromium } from 'playwright';
|
|
11
|
+
import { writeFileSync, mkdirSync, existsSync } from 'fs';
|
|
12
|
+
import { join, resolve } from 'path';
|
|
13
|
+
|
|
14
|
+
const WIDTH = 1080;
|
|
15
|
+
const HEIGHT = 1440;
|
|
16
|
+
|
|
17
|
+
const input = JSON.parse(process.argv[2]);
|
|
18
|
+
const {
|
|
19
|
+
pages,
|
|
20
|
+
title = 'Untitled',
|
|
21
|
+
author = '',
|
|
22
|
+
accentColor = '#1a1a1a',
|
|
23
|
+
bgColor = '#fafaf8',
|
|
24
|
+
outputDir,
|
|
25
|
+
coverImage = '',
|
|
26
|
+
} = input;
|
|
27
|
+
|
|
28
|
+
mkdirSync(outputDir, { recursive: true });
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Generate the HTML for the cover (first) page.
|
|
32
|
+
*
|
|
33
|
+
* @param {string} title - Article title
|
|
34
|
+
* @param {string} author - Author name
|
|
35
|
+
* @param {string} accentColor - Accent color hex
|
|
36
|
+
* @param {string} bgColor - Background color hex
|
|
37
|
+
* @param {string} coverImage - Optional cover image URL/path
|
|
38
|
+
* @param {number} totalPages - Total page count
|
|
39
|
+
* @returns {string} Complete HTML string
|
|
40
|
+
*/
|
|
41
|
+
function buildCoverHTML(title, author, accentColor, bgColor, coverImage, totalPages) {
|
|
42
|
+
const imageBlock = coverImage
|
|
43
|
+
? `<div class="cover-image"><img src="${coverImage}" alt="cover" /></div>`
|
|
44
|
+
: '';
|
|
45
|
+
|
|
46
|
+
return `<!DOCTYPE html>
|
|
47
|
+
<html>
|
|
48
|
+
<head>
|
|
49
|
+
<meta charset="utf-8">
|
|
50
|
+
<style>
|
|
51
|
+
${getBaseStyles(bgColor, accentColor)}
|
|
52
|
+
|
|
53
|
+
.cover-container {
|
|
54
|
+
display: flex;
|
|
55
|
+
flex-direction: column;
|
|
56
|
+
justify-content: center;
|
|
57
|
+
align-items: center;
|
|
58
|
+
height: 100%;
|
|
59
|
+
padding: 100px 80px;
|
|
60
|
+
box-sizing: border-box;
|
|
61
|
+
text-align: center;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.cover-decoration-top {
|
|
65
|
+
width: 60px;
|
|
66
|
+
height: 4px;
|
|
67
|
+
background: ${accentColor};
|
|
68
|
+
margin-bottom: 50px;
|
|
69
|
+
border-radius: 2px;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.cover-title {
|
|
73
|
+
font-size: 72px;
|
|
74
|
+
font-weight: 900;
|
|
75
|
+
line-height: 1.4;
|
|
76
|
+
color: ${accentColor};
|
|
77
|
+
letter-spacing: -1px;
|
|
78
|
+
margin-bottom: 40px;
|
|
79
|
+
max-width: 900px;
|
|
80
|
+
word-break: break-word;
|
|
81
|
+
padding: 0 20px;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.cover-container::before {
|
|
85
|
+
content: '';
|
|
86
|
+
position: absolute;
|
|
87
|
+
top: 0; left: 0; right: 0; height: 15px;
|
|
88
|
+
background: ${accentColor};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.cover-decoration-bottom {
|
|
92
|
+
width: 120px;
|
|
93
|
+
height: 2px;
|
|
94
|
+
background: ${accentColor}33;
|
|
95
|
+
margin-bottom: 40px;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.cover-author {
|
|
99
|
+
font-size: 28px;
|
|
100
|
+
color: #888;
|
|
101
|
+
font-weight: 400;
|
|
102
|
+
letter-spacing: 2px;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.cover-image {
|
|
106
|
+
width: 100%;
|
|
107
|
+
max-width: 700px;
|
|
108
|
+
margin-bottom: 50px;
|
|
109
|
+
border-radius: 16px;
|
|
110
|
+
overflow: hidden;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.cover-image img {
|
|
114
|
+
width: 100%;
|
|
115
|
+
height: auto;
|
|
116
|
+
display: block;
|
|
117
|
+
object-fit: cover;
|
|
118
|
+
max-height: 500px;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.page-indicator {
|
|
122
|
+
position: absolute;
|
|
123
|
+
bottom: 50px;
|
|
124
|
+
right: 80px;
|
|
125
|
+
font-size: 22px;
|
|
126
|
+
color: #ccc;
|
|
127
|
+
font-weight: 300;
|
|
128
|
+
}
|
|
129
|
+
</style>
|
|
130
|
+
</head>
|
|
131
|
+
<body>
|
|
132
|
+
<div class="cover-container">
|
|
133
|
+
<div class="cover-decoration-top"></div>
|
|
134
|
+
${imageBlock}
|
|
135
|
+
<div class="cover-title">${escapeHTML(title)}</div>
|
|
136
|
+
<div class="cover-decoration-bottom"></div>
|
|
137
|
+
${author ? `<div class="cover-author">${escapeHTML(author)}</div>` : ''}
|
|
138
|
+
</div>
|
|
139
|
+
<div class="page-indicator">1 / ${totalPages}</div>
|
|
140
|
+
</body>
|
|
141
|
+
</html>`;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Generate the HTML for a content page.
|
|
146
|
+
*
|
|
147
|
+
* @param {string} contentHTML - Pre-rendered HTML content for this page
|
|
148
|
+
* @param {number} pageNum - Current page number (1-based)
|
|
149
|
+
* @param {number} totalPages - Total page count
|
|
150
|
+
* @param {string} title - Article title (shown as header)
|
|
151
|
+
* @param {string} accentColor - Accent color hex
|
|
152
|
+
* @param {string} bgColor - Background color hex
|
|
153
|
+
* @returns {string} Complete HTML string
|
|
154
|
+
*/
|
|
155
|
+
function buildContentPageHTML(contentHTML, pageNum, totalPages, title, accentColor, bgColor) {
|
|
156
|
+
return `<!DOCTYPE html>
|
|
157
|
+
<html>
|
|
158
|
+
<head>
|
|
159
|
+
<meta charset="utf-8">
|
|
160
|
+
<style>
|
|
161
|
+
${getBaseStyles(bgColor, accentColor)}
|
|
162
|
+
|
|
163
|
+
.page-header {
|
|
164
|
+
padding: 60px 80px 0 80px;
|
|
165
|
+
display: flex;
|
|
166
|
+
align-items: center;
|
|
167
|
+
gap: 16px;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.page-header-line {
|
|
171
|
+
width: 30px;
|
|
172
|
+
height: 3px;
|
|
173
|
+
background: ${accentColor};
|
|
174
|
+
border-radius: 2px;
|
|
175
|
+
flex-shrink: 0;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.page-header-title {
|
|
179
|
+
font-size: 20px;
|
|
180
|
+
font-weight: 600;
|
|
181
|
+
color: #bbb;
|
|
182
|
+
letter-spacing: 1px;
|
|
183
|
+
white-space: nowrap;
|
|
184
|
+
overflow: hidden;
|
|
185
|
+
text-overflow: ellipsis;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.content-area {
|
|
189
|
+
padding: 40px 80px 80px 80px;
|
|
190
|
+
flex: 1;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.content-area h2 {
|
|
194
|
+
font-size: 42px;
|
|
195
|
+
font-weight: 800;
|
|
196
|
+
color: ${accentColor};
|
|
197
|
+
margin: 0 0 28px 0;
|
|
198
|
+
line-height: 1.35;
|
|
199
|
+
letter-spacing: -0.5px;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.content-area h3 {
|
|
203
|
+
font-size: 34px;
|
|
204
|
+
font-weight: 700;
|
|
205
|
+
color: ${accentColor};
|
|
206
|
+
margin: 0 0 22px 0;
|
|
207
|
+
line-height: 1.35;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.content-area p {
|
|
211
|
+
font-size: 30px;
|
|
212
|
+
line-height: 1.75;
|
|
213
|
+
color: #333;
|
|
214
|
+
margin: 0 0 24px 0;
|
|
215
|
+
font-weight: 400;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.content-area ul, .content-area ol {
|
|
219
|
+
padding-left: 40px;
|
|
220
|
+
margin: 0 0 24px 0;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.content-area li {
|
|
224
|
+
font-size: 30px;
|
|
225
|
+
line-height: 1.7;
|
|
226
|
+
color: #333;
|
|
227
|
+
margin-bottom: 12px;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.content-area strong {
|
|
231
|
+
font-weight: 700;
|
|
232
|
+
color: ${accentColor};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.content-area em {
|
|
236
|
+
font-style: italic;
|
|
237
|
+
color: #555;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.content-area blockquote {
|
|
241
|
+
border-left: 4px solid ${accentColor}44;
|
|
242
|
+
margin: 0 0 24px 0;
|
|
243
|
+
padding: 16px 24px;
|
|
244
|
+
background: ${accentColor}08;
|
|
245
|
+
border-radius: 0 12px 12px 0;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.content-area blockquote p {
|
|
249
|
+
font-size: 28px;
|
|
250
|
+
color: #555;
|
|
251
|
+
margin: 0;
|
|
252
|
+
font-style: italic;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.content-area img {
|
|
256
|
+
max-width: 100%;
|
|
257
|
+
border-radius: 12px;
|
|
258
|
+
margin: 16px 0;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.content-area code {
|
|
262
|
+
background: #f0f0f0;
|
|
263
|
+
padding: 2px 8px;
|
|
264
|
+
border-radius: 4px;
|
|
265
|
+
font-size: 26px;
|
|
266
|
+
font-family: 'SF Mono', 'Menlo', monospace;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.page-indicator {
|
|
270
|
+
position: absolute;
|
|
271
|
+
bottom: 50px;
|
|
272
|
+
right: 80px;
|
|
273
|
+
font-size: 22px;
|
|
274
|
+
color: #ccc;
|
|
275
|
+
font-weight: 300;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.page-footer-decoration {
|
|
279
|
+
position: absolute;
|
|
280
|
+
bottom: 45px;
|
|
281
|
+
left: 80px;
|
|
282
|
+
width: 40px;
|
|
283
|
+
height: 3px;
|
|
284
|
+
background: ${accentColor}22;
|
|
285
|
+
border-radius: 2px;
|
|
286
|
+
}
|
|
287
|
+
</style>
|
|
288
|
+
</head>
|
|
289
|
+
<body>
|
|
290
|
+
<div class="page-header">
|
|
291
|
+
<div class="page-header-line"></div>
|
|
292
|
+
<div class="page-header-title">${escapeHTML(title)}</div>
|
|
293
|
+
</div>
|
|
294
|
+
<div class="content-area">
|
|
295
|
+
${contentHTML}
|
|
296
|
+
</div>
|
|
297
|
+
<div class="page-footer-decoration"></div>
|
|
298
|
+
<div class="page-indicator">${pageNum} / ${totalPages}</div>
|
|
299
|
+
</body>
|
|
300
|
+
</html>`;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Shared base CSS styles for all pages.
|
|
305
|
+
*
|
|
306
|
+
* @param {string} bgColor - Background color
|
|
307
|
+
* @param {string} accentColor - Accent/text color
|
|
308
|
+
* @returns {string} CSS string
|
|
309
|
+
*/
|
|
310
|
+
function getBaseStyles(bgColor, accentColor) {
|
|
311
|
+
return `
|
|
312
|
+
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700;800;900&display=swap');
|
|
313
|
+
|
|
314
|
+
* {
|
|
315
|
+
margin: 0;
|
|
316
|
+
padding: 0;
|
|
317
|
+
box-sizing: border-box;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
body {
|
|
321
|
+
width: ${WIDTH}px;
|
|
322
|
+
height: ${HEIGHT}px;
|
|
323
|
+
background: ${bgColor};
|
|
324
|
+
font-family: 'Noto Sans SC', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
325
|
+
overflow: hidden;
|
|
326
|
+
position: relative;
|
|
327
|
+
}
|
|
328
|
+
`;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Escape HTML special characters.
|
|
333
|
+
*
|
|
334
|
+
* @param {string} str - Raw string
|
|
335
|
+
* @returns {string} Escaped HTML string
|
|
336
|
+
*/
|
|
337
|
+
function escapeHTML(str) {
|
|
338
|
+
return str
|
|
339
|
+
.replace(/&/g, '&')
|
|
340
|
+
.replace(/</g, '<')
|
|
341
|
+
.replace(/>/g, '>')
|
|
342
|
+
.replace(/"/g, '"');
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Simple markdown to HTML converter.
|
|
347
|
+
* Handles: h1-h3, bold, italic, lists, blockquotes, images, links, code, paragraphs.
|
|
348
|
+
*
|
|
349
|
+
* @param {string} md - Markdown text
|
|
350
|
+
* @returns {string} HTML string
|
|
351
|
+
*/
|
|
352
|
+
function markdownToHTML(md) {
|
|
353
|
+
let html = md;
|
|
354
|
+
|
|
355
|
+
// Images: 
|
|
356
|
+
html = html.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '<img src="$2" alt="$1" />');
|
|
357
|
+
|
|
358
|
+
// Links: [text](url) → just text (no clickable links in images)
|
|
359
|
+
html = html.replace(/\[([^\]]+)\]\([^)]+\)/g, '<strong>$1</strong>');
|
|
360
|
+
|
|
361
|
+
// Bold: **text** or __text__
|
|
362
|
+
html = html.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
|
|
363
|
+
html = html.replace(/__(.+?)__/g, '<strong>$1</strong>');
|
|
364
|
+
|
|
365
|
+
// Italic: *text* or _text_
|
|
366
|
+
html = html.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, '<em>$1</em>');
|
|
367
|
+
html = html.replace(/(?<!_)_(?!_)(.+?)(?<!_)_(?!_)/g, '<em>$1</em>');
|
|
368
|
+
|
|
369
|
+
// Inline code: `code`
|
|
370
|
+
html = html.replace(/`([^`]+)`/g, '<code>$1</code>');
|
|
371
|
+
|
|
372
|
+
// Process line by line
|
|
373
|
+
const lines = html.split('\n');
|
|
374
|
+
const result = [];
|
|
375
|
+
let inList = false;
|
|
376
|
+
let listType = '';
|
|
377
|
+
let inBlockquote = false;
|
|
378
|
+
let blockquoteLines = [];
|
|
379
|
+
|
|
380
|
+
for (let i = 0; i < lines.length; i++) {
|
|
381
|
+
const line = lines[i];
|
|
382
|
+
const trimmed = line.trim();
|
|
383
|
+
|
|
384
|
+
// End blockquote
|
|
385
|
+
if (inBlockquote && !trimmed.startsWith('>')) {
|
|
386
|
+
result.push(`<blockquote><p>${blockquoteLines.join('<br/>')}</p></blockquote>`);
|
|
387
|
+
blockquoteLines = [];
|
|
388
|
+
inBlockquote = false;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// End list
|
|
392
|
+
if (inList && !trimmed.match(/^[-*]\s/) && !trimmed.match(/^\d+\.\s/) && trimmed !== '') {
|
|
393
|
+
result.push(listType === 'ul' ? '</ul>' : '</ol>');
|
|
394
|
+
inList = false;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Skip empty lines
|
|
398
|
+
if (trimmed === '') {
|
|
399
|
+
if (inList) {
|
|
400
|
+
result.push(listType === 'ul' ? '</ul>' : '</ol>');
|
|
401
|
+
inList = false;
|
|
402
|
+
}
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Headers (skip h1 — it's the title, shown on cover)
|
|
407
|
+
if (trimmed.startsWith('### ')) {
|
|
408
|
+
result.push(`<h3>${trimmed.slice(4)}</h3>`);
|
|
409
|
+
} else if (trimmed.startsWith('## ')) {
|
|
410
|
+
result.push(`<h2>${trimmed.slice(3)}</h2>`);
|
|
411
|
+
} else if (trimmed.startsWith('# ')) {
|
|
412
|
+
// Skip h1 (title page handles it)
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
// Blockquote
|
|
416
|
+
else if (trimmed.startsWith('>')) {
|
|
417
|
+
inBlockquote = true;
|
|
418
|
+
blockquoteLines.push(trimmed.slice(1).trim());
|
|
419
|
+
}
|
|
420
|
+
// Unordered list
|
|
421
|
+
else if (trimmed.match(/^[-*]\s/)) {
|
|
422
|
+
if (!inList || listType !== 'ul') {
|
|
423
|
+
if (inList) result.push(listType === 'ul' ? '</ul>' : '</ol>');
|
|
424
|
+
result.push('<ul>');
|
|
425
|
+
inList = true;
|
|
426
|
+
listType = 'ul';
|
|
427
|
+
}
|
|
428
|
+
result.push(`<li>${trimmed.slice(2)}</li>`);
|
|
429
|
+
}
|
|
430
|
+
// Ordered list
|
|
431
|
+
else if (trimmed.match(/^\d+\.\s/)) {
|
|
432
|
+
if (!inList || listType !== 'ol') {
|
|
433
|
+
if (inList) result.push(listType === 'ul' ? '</ul>' : '</ol>');
|
|
434
|
+
result.push('<ol>');
|
|
435
|
+
inList = true;
|
|
436
|
+
listType = 'ol';
|
|
437
|
+
}
|
|
438
|
+
result.push(`<li>${trimmed.replace(/^\d+\.\s/, '')}</li>`);
|
|
439
|
+
}
|
|
440
|
+
// Horizontal rule → page break hint (handled at split level)
|
|
441
|
+
else if (trimmed.match(/^[-*_]{3,}$/)) {
|
|
442
|
+
result.push('<hr/>');
|
|
443
|
+
}
|
|
444
|
+
// Paragraph
|
|
445
|
+
else {
|
|
446
|
+
result.push(`<p>${trimmed}</p>`);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// Close any open structures
|
|
451
|
+
if (inBlockquote) {
|
|
452
|
+
result.push(`<blockquote><p>${blockquoteLines.join('<br/>')}</p></blockquote>`);
|
|
453
|
+
}
|
|
454
|
+
if (inList) {
|
|
455
|
+
result.push(listType === 'ul' ? '</ul>' : '</ol>');
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
return result.join('\n');
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Split markdown content into pages.
|
|
463
|
+
* Splits on --- (horizontal rules) first, then by approximate character count.
|
|
464
|
+
*
|
|
465
|
+
* @param {string} markdown - Full markdown (without title line)
|
|
466
|
+
* @param {number} maxChars - Max chars per page
|
|
467
|
+
* @returns {string[]} Array of markdown chunks, one per page
|
|
468
|
+
*/
|
|
469
|
+
function splitIntoPages(markdown, maxChars) {
|
|
470
|
+
// First split on explicit --- page breaks
|
|
471
|
+
const explicitSections = markdown.split(/\n---\n/).filter((s) => s.trim());
|
|
472
|
+
|
|
473
|
+
const pages = [];
|
|
474
|
+
|
|
475
|
+
for (const section of explicitSections) {
|
|
476
|
+
// If section fits, keep as one page
|
|
477
|
+
if (section.length <= maxChars) {
|
|
478
|
+
pages.push(section.trim());
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Split further by paragraphs (double newline)
|
|
483
|
+
const blocks = section.split(/\n\n/).filter((b) => b.trim());
|
|
484
|
+
let currentPage = '';
|
|
485
|
+
|
|
486
|
+
for (const block of blocks) {
|
|
487
|
+
// If adding this block exceeds limit, start a new page
|
|
488
|
+
if (currentPage.length > 0 && currentPage.length + block.length > maxChars) {
|
|
489
|
+
pages.push(currentPage.trim());
|
|
490
|
+
currentPage = block;
|
|
491
|
+
} else {
|
|
492
|
+
currentPage += (currentPage ? '\n\n' : '') + block;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
if (currentPage.trim()) {
|
|
497
|
+
pages.push(currentPage.trim());
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
return pages.length > 0 ? pages : [markdown.trim()];
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Extract the title from markdown content (first # heading).
|
|
506
|
+
*
|
|
507
|
+
* @param {string} markdown - Full markdown content
|
|
508
|
+
* @returns {{ title: string, body: string }} Extracted title and remaining body
|
|
509
|
+
*/
|
|
510
|
+
function extractTitle(markdown) {
|
|
511
|
+
const lines = markdown.split('\n');
|
|
512
|
+
let title = '';
|
|
513
|
+
let bodyStart = 0;
|
|
514
|
+
|
|
515
|
+
for (let i = 0; i < lines.length; i++) {
|
|
516
|
+
const trimmed = lines[i].trim();
|
|
517
|
+
if (trimmed.startsWith('# ') && !trimmed.startsWith('## ')) {
|
|
518
|
+
title = trimmed.slice(2).trim();
|
|
519
|
+
bodyStart = i + 1;
|
|
520
|
+
break;
|
|
521
|
+
}
|
|
522
|
+
if (trimmed !== '') {
|
|
523
|
+
// No h1 found before content — use first non-empty line
|
|
524
|
+
break;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
const body = lines.slice(bodyStart).join('\n').trim();
|
|
529
|
+
return { title, body };
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// ─── Main ───────────────────────────────────────────────────────────────────
|
|
533
|
+
|
|
534
|
+
async function main() {
|
|
535
|
+
const totalContentPages = pages.length;
|
|
536
|
+
const totalPages = totalContentPages + 1; // +1 for cover
|
|
537
|
+
|
|
538
|
+
const browser = await chromium.launch({ headless: true });
|
|
539
|
+
const context = await browser.newContext({
|
|
540
|
+
viewport: { width: WIDTH, height: HEIGHT },
|
|
541
|
+
deviceScaleFactor: 2, // Retina for crisp text
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
const filePaths = [];
|
|
545
|
+
|
|
546
|
+
try {
|
|
547
|
+
// Page 1: Cover
|
|
548
|
+
const coverHTML = buildCoverHTML(title, author, accentColor, bgColor, coverImage, totalPages);
|
|
549
|
+
const coverPage = await context.newPage();
|
|
550
|
+
await coverPage.setContent(coverHTML, { waitUntil: 'networkidle' });
|
|
551
|
+
// Wait for fonts to load
|
|
552
|
+
await coverPage.waitForTimeout(500);
|
|
553
|
+
const coverPath = join(outputDir, 'page-01.png');
|
|
554
|
+
await coverPage.screenshot({ path: coverPath, type: 'png' });
|
|
555
|
+
filePaths.push(coverPath);
|
|
556
|
+
await coverPage.close();
|
|
557
|
+
|
|
558
|
+
// Content pages
|
|
559
|
+
for (let i = 0; i < pages.length; i++) {
|
|
560
|
+
const pageNum = i + 2; // 1-based, after cover
|
|
561
|
+
const contentHTML = markdownToHTML(pages[i]);
|
|
562
|
+
const pageHTML = buildContentPageHTML(
|
|
563
|
+
contentHTML,
|
|
564
|
+
pageNum,
|
|
565
|
+
totalPages,
|
|
566
|
+
title,
|
|
567
|
+
accentColor,
|
|
568
|
+
bgColor
|
|
569
|
+
);
|
|
570
|
+
|
|
571
|
+
const contentPage = await context.newPage();
|
|
572
|
+
await contentPage.setContent(pageHTML, { waitUntil: 'networkidle' });
|
|
573
|
+
await contentPage.waitForTimeout(300);
|
|
574
|
+
|
|
575
|
+
const pagePath = join(outputDir, `page-${String(pageNum).padStart(2, '0')}.png`);
|
|
576
|
+
await contentPage.screenshot({ path: pagePath, type: 'png' });
|
|
577
|
+
filePaths.push(pagePath);
|
|
578
|
+
await contentPage.close();
|
|
579
|
+
}
|
|
580
|
+
} finally {
|
|
581
|
+
await browser.close();
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
return {
|
|
585
|
+
success: true,
|
|
586
|
+
totalPages,
|
|
587
|
+
files: filePaths,
|
|
588
|
+
dimensions: { width: WIDTH, height: HEIGHT },
|
|
589
|
+
outputDir: resolve(outputDir),
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
main()
|
|
594
|
+
.then((result) => {
|
|
595
|
+
console.log(JSON.stringify(result));
|
|
596
|
+
process.exit(0);
|
|
597
|
+
})
|
|
598
|
+
.catch((err) => {
|
|
599
|
+
console.error(JSON.stringify({ success: false, error: err.message }));
|
|
600
|
+
process.exit(1);
|
|
601
|
+
});
|
|
@@ -31,8 +31,14 @@ export declare class CommunicationModule implements PromptModule {
|
|
|
31
31
|
build(config: ModuleConfig): Promise<string>;
|
|
32
32
|
/**
|
|
33
33
|
* Build a skill call example snippet. For gemini-cli runtime, uses --file
|
|
34
|
-
* pattern to avoid shell escaping EOF errors. For other runtimes,
|
|
35
|
-
* inline JSON argument.
|
|
34
|
+
* pattern with heredoc to avoid shell escaping EOF errors. For other runtimes,
|
|
35
|
+
* uses inline JSON argument.
|
|
36
|
+
*
|
|
37
|
+
* Uses heredoc with single-quoted delimiter (`<< 'CREWLY_EOF'`) instead of
|
|
38
|
+
* `printf '%s' '...'` because heredoc prevents ALL shell interpretation —
|
|
39
|
+
* single quotes, double quotes, backticks, $variables, and parentheses all
|
|
40
|
+
* pass through literally. The previous printf approach broke when JSON
|
|
41
|
+
* contained single quotes (e.g., "it's working").
|
|
36
42
|
*
|
|
37
43
|
* @param config - Module configuration with runtime type
|
|
38
44
|
* @param skillPath - Relative path to the skill (e.g., 'core/report-status')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"communication.module.d.ts","sourceRoot":"","sources":["../../../../../../../backend/src/services/ai/prompt-modules/communication.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAoB,MAAM,8BAA8B,CAAC;AAE5F;;;;;;;;;;;GAWG;AACH,qBAAa,mBAAoB,YAAW,YAAY;IACvD,IAAI,SAAmB;IACvB,QAAQ,SAAK;IACb,SAAS,SAAQ;IACjB,WAAW,UAAQ;IAEnB;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO;IAI7C;;;;;;;OAOG;IACG,KAAK,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAkBlD
|
|
1
|
+
{"version":3,"file":"communication.module.d.ts","sourceRoot":"","sources":["../../../../../../../backend/src/services/ai/prompt-modules/communication.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAoB,MAAM,8BAA8B,CAAC;AAE5F;;;;;;;;;;;GAWG;AACH,qBAAa,mBAAoB,YAAW,YAAY;IACvD,IAAI,SAAmB;IACvB,QAAQ,SAAK;IACb,SAAS,SAAQ;IACjB,WAAW,UAAQ;IAEnB;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO;IAI7C;;;;;;;OAOG;IACG,KAAK,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAkBlD;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,iBAAiB;IAezB;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAyE9B;;OAEG;IACH,OAAO,CAAC,YAAY;IA8BpB;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAqBxB"}
|
|
@@ -48,8 +48,14 @@ export class CommunicationModule {
|
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
50
|
* Build a skill call example snippet. For gemini-cli runtime, uses --file
|
|
51
|
-
* pattern to avoid shell escaping EOF errors. For other runtimes,
|
|
52
|
-
* inline JSON argument.
|
|
51
|
+
* pattern with heredoc to avoid shell escaping EOF errors. For other runtimes,
|
|
52
|
+
* uses inline JSON argument.
|
|
53
|
+
*
|
|
54
|
+
* Uses heredoc with single-quoted delimiter (`<< 'CREWLY_EOF'`) instead of
|
|
55
|
+
* `printf '%s' '...'` because heredoc prevents ALL shell interpretation —
|
|
56
|
+
* single quotes, double quotes, backticks, $variables, and parentheses all
|
|
57
|
+
* pass through literally. The previous printf approach broke when JSON
|
|
58
|
+
* contained single quotes (e.g., "it's working").
|
|
53
59
|
*
|
|
54
60
|
* @param config - Module configuration with runtime type
|
|
55
61
|
* @param skillPath - Relative path to the skill (e.g., 'core/report-status')
|
|
@@ -62,7 +68,9 @@ export class CommunicationModule {
|
|
|
62
68
|
const resolvedBase = basePath || config.agentSkillsPath;
|
|
63
69
|
if (config.runtimeType === 'gemini-cli') {
|
|
64
70
|
return `\`\`\`bash
|
|
65
|
-
|
|
71
|
+
cat > /tmp/crewly_skill_input.json << 'CREWLY_EOF'
|
|
72
|
+
${jsonExample}
|
|
73
|
+
CREWLY_EOF
|
|
66
74
|
bash ${resolvedBase}/${skillPath}/execute.sh --file /tmp/crewly_skill_input.json
|
|
67
75
|
\`\`\``;
|
|
68
76
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"communication.module.js","sourceRoot":"","sources":["../../../../../../../backend/src/services/ai/prompt-modules/communication.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAE5F;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,mBAAmB;IAC/B,IAAI,GAAG,eAAe,CAAC;IACvB,QAAQ,GAAG,CAAC,CAAC;IACb,SAAS,GAAG,IAAI,CAAC;IACjB,WAAW,GAAG,IAAI,CAAC;IAEnB;;OAEG;IACH,aAAa,CAAC,OAAqB;QAClC,OAAO,IAAI,CAAC;IACb,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,KAAK,CAAC,MAAoB;QAC/B,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,KAAK,cAAc,CAAC;QACtD,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,KAAK,IAAI,CAAC;QAEzC,4EAA4E;QAC5E,IAAI,cAAc,EAAE,CAAC;YACpB,MAAM,QAAQ,GAAG,gBAAgB,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;YACpF,IAAI,QAAQ,EAAE,CAAC;gBACd,OAAO,QAAQ,CAAC;YACjB,CAAC;YACD,OAAO,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC;QAC5C,CAAC;QACD,IAAI,IAAI,EAAE,CAAC;YACV,OAAO,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QAClC,CAAC;QACD,OAAO,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IAED
|
|
1
|
+
{"version":3,"file":"communication.module.js","sourceRoot":"","sources":["../../../../../../../backend/src/services/ai/prompt-modules/communication.module.ts"],"names":[],"mappings":"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"}
|
|
@@ -39,8 +39,14 @@ export declare class SkillsReferenceModule implements PromptModule {
|
|
|
39
39
|
*
|
|
40
40
|
* Gemini CLI's run_shell_command mangles JSON arguments containing quotes,
|
|
41
41
|
* backticks, and parentheses, causing "unexpected EOF" shell errors.
|
|
42
|
-
* This guide instructs the agent to write JSON to a temp file
|
|
43
|
-
* then pass --file <path
|
|
42
|
+
* This guide instructs the agent to write JSON to a temp file using heredoc
|
|
43
|
+
* with a single-quoted delimiter, then pass --file <path>.
|
|
44
|
+
*
|
|
45
|
+
* Uses `<< 'CREWLY_EOF'` instead of `printf '%s' '...'` because:
|
|
46
|
+
* - Single-quoted heredoc delimiter prevents ALL shell interpretation
|
|
47
|
+
* - Single quotes, double quotes, backticks, $, () all pass through literally
|
|
48
|
+
* - The previous printf approach broke when JSON contained single quotes
|
|
49
|
+
* (e.g., "it's working" or "don't forget")
|
|
44
50
|
*
|
|
45
51
|
* Only included for gemini-cli runtime type.
|
|
46
52
|
*
|
package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills-reference.module.d.ts","sourceRoot":"","sources":["../../../../../../../backend/src/services/ai/prompt-modules/skills-reference.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAE1E;;;;;;;;GAQG;AACH,qBAAa,qBAAsB,YAAW,YAAY;IACzD,IAAI,SAAuB;IAC3B,QAAQ,SAAK;IACb,SAAS,SAAO;IAChB,WAAW,UAAS;IAEpB;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO;IAI7C;;;;;;OAMG;IACG,KAAK,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAalD;;OAEG;IACH,OAAO,CAAC,eAAe;IAoDvB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAiCzB
|
|
1
|
+
{"version":3,"file":"skills-reference.module.d.ts","sourceRoot":"","sources":["../../../../../../../backend/src/services/ai/prompt-modules/skills-reference.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAE1E;;;;;;;;GAQG;AACH,qBAAa,qBAAsB,YAAW,YAAY;IACzD,IAAI,SAAuB;IAC3B,QAAQ,SAAK;IACb,SAAS,SAAO;IAChB,WAAW,UAAS;IAEpB;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO;IAI7C;;;;;;OAMG;IACG,KAAK,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAalD;;OAEG;IACH,OAAO,CAAC,eAAe;IAoDvB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAiCzB;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,CAAC,kBAAkB;IAsC1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;CAkB1B"}
|
|
@@ -84,8 +84,14 @@ export class SkillsReferenceModule {
|
|
|
84
84
|
*
|
|
85
85
|
* Gemini CLI's run_shell_command mangles JSON arguments containing quotes,
|
|
86
86
|
* backticks, and parentheses, causing "unexpected EOF" shell errors.
|
|
87
|
-
* This guide instructs the agent to write JSON to a temp file
|
|
88
|
-
* then pass --file <path
|
|
87
|
+
* This guide instructs the agent to write JSON to a temp file using heredoc
|
|
88
|
+
* with a single-quoted delimiter, then pass --file <path>.
|
|
89
|
+
*
|
|
90
|
+
* Uses `<< 'CREWLY_EOF'` instead of `printf '%s' '...'` because:
|
|
91
|
+
* - Single-quoted heredoc delimiter prevents ALL shell interpretation
|
|
92
|
+
* - Single quotes, double quotes, backticks, $, () all pass through literally
|
|
93
|
+
* - The previous printf approach broke when JSON contained single quotes
|
|
94
|
+
* (e.g., "it's working" or "don't forget")
|
|
89
95
|
*
|
|
90
96
|
* Only included for gemini-cli runtime type.
|
|
91
97
|
*
|
|
@@ -98,13 +104,15 @@ export class SkillsReferenceModule {
|
|
|
98
104
|
}
|
|
99
105
|
return `## Safe Skill Calling (MANDATORY)
|
|
100
106
|
|
|
101
|
-
**CRITICAL:** When calling any bash skill, you MUST use the \`--file\` pattern to avoid shell escaping errors.
|
|
107
|
+
**CRITICAL:** When calling any bash skill, you MUST use the \`--file\` pattern with heredoc to avoid shell escaping errors.
|
|
102
108
|
Passing JSON directly as a shell argument will cause "unexpected EOF" errors when the content contains quotes, backticks, or parentheses.
|
|
103
109
|
|
|
104
110
|
### Required Pattern
|
|
105
111
|
\`\`\`bash
|
|
106
|
-
# Step 1: Write JSON to a temp file (
|
|
107
|
-
|
|
112
|
+
# Step 1: Write JSON to a temp file using heredoc (single-quoted delimiter prevents ALL shell interpretation)
|
|
113
|
+
cat > /tmp/crewly_skill_input.json << 'CREWLY_EOF'
|
|
114
|
+
{"sessionName":"my-agent","status":"done","summary":"Fixed the bug — it's working now"}
|
|
115
|
+
CREWLY_EOF
|
|
108
116
|
|
|
109
117
|
# Step 2: Call the skill with --file flag
|
|
110
118
|
bash ${config.agentSkillsPath}/core/report-status/execute.sh --file /tmp/crewly_skill_input.json
|
|
@@ -112,16 +120,19 @@ bash ${config.agentSkillsPath}/core/report-status/execute.sh --file /tmp/crewly_
|
|
|
112
120
|
|
|
113
121
|
### Team Leader Skills (delegate-task, verify-output, schedule-check)
|
|
114
122
|
\`\`\`bash
|
|
115
|
-
|
|
123
|
+
cat > /tmp/crewly_skill_input.json << 'CREWLY_EOF'
|
|
124
|
+
{"to":"worker-session","task":"implement feature","priority":"high"}
|
|
125
|
+
CREWLY_EOF
|
|
116
126
|
bash ${config.tlSkillsPath}/delegate-task/execute.sh --file /tmp/crewly_skill_input.json
|
|
117
127
|
\`\`\`` : ''}
|
|
118
128
|
|
|
119
129
|
### Rules
|
|
120
|
-
1. **ALWAYS** use
|
|
121
|
-
2. **NEVER** pass JSON directly as a shell argument: \`bash execute.sh '{"key":"value
|
|
122
|
-
3.
|
|
123
|
-
4.
|
|
124
|
-
5.
|
|
130
|
+
1. **ALWAYS** use heredoc to write JSON: \`cat > /tmp/crewly_skill_input.json << 'CREWLY_EOF'\` then the JSON, then \`CREWLY_EOF\` on its own line
|
|
131
|
+
2. **NEVER** pass JSON directly as a shell argument: \`bash execute.sh '{"key":"value"}'\`
|
|
132
|
+
3. **NEVER** use \`printf '%s' '...'\` — single quotes inside JSON will break it
|
|
133
|
+
4. Use \`/tmp/crewly_skill_input.json\` as the temp file (overwritten each call)
|
|
134
|
+
5. This applies to ALL skills: report-status, send-message, remember, recall, delegate-task, reply-slack, reply-gchat, etc.
|
|
135
|
+
6. For skills that support named flags (reply-slack, reply-gchat), you may also use \`--text-file\` for the message body`;
|
|
125
136
|
}
|
|
126
137
|
/**
|
|
127
138
|
* Build communication and memory tool instructions.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills-reference.module.js","sourceRoot":"","sources":["../../../../../../../backend/src/services/ai/prompt-modules/skills-reference.module.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"skills-reference.module.js","sourceRoot":"","sources":["../../../../../../../backend/src/services/ai/prompt-modules/skills-reference.module.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "crewly",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.15",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Multi-agent orchestration platform for AI coding teams — coordinates Claude Code, Gemini CLI, and Codex agents with a real-time web dashboard",
|
|
6
6
|
"main": "dist/cli/cli/src/index.js",
|