crewly 1.5.12 → 1.5.13

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.
@@ -7,6 +7,37 @@
7
7
  # Base URL for the Crewly backend API
8
8
  CREWLY_API_URL="${CREWLY_API_URL:-http://localhost:8787}"
9
9
 
10
+ # -----------------------------------------------------------------------------
11
+ # Universal --file flag preprocessor (#EOF-fix)
12
+ #
13
+ # Fixes Gemini CLI's "unexpected EOF while looking for matching `'" errors.
14
+ #
15
+ # Root cause: When an LLM CLI passes JSON as a shell argument, special chars
16
+ # inside the JSON (single quotes, backticks, parentheses, $variables) get
17
+ # interpreted by the shell BEFORE the script runs, causing parse errors.
18
+ #
19
+ # Solution: The LLM writes JSON to a temp file, then passes --file <path>.
20
+ # This preprocessor detects --file as the first argument, reads the file,
21
+ # and replaces the script's positional parameters with the file contents.
22
+ # All downstream parsing (read_json_input, custom arg loops) works unchanged.
23
+ #
24
+ # Usage (by LLM CLI):
25
+ # printf '%s' '{"summary":"text with 'quotes'"}' > /tmp/crewly_input.json
26
+ # bash execute.sh --file /tmp/crewly_input.json
27
+ #
28
+ # This runs at source-time, so every script that sources lib.sh gets it for free.
29
+ # -----------------------------------------------------------------------------
30
+ if [ "${1:-}" = "--file" ] && [ -n "${2:-}" ]; then
31
+ if [ -f "$2" ]; then
32
+ _CREWLY_FILE_CONTENT="$(cat "$2")"
33
+ set -- "$_CREWLY_FILE_CONTENT"
34
+ unset _CREWLY_FILE_CONTENT
35
+ else
36
+ echo '{"error":"File not found: '"$2"'"}' >&2
37
+ exit 1
38
+ fi
39
+ fi
40
+
10
41
  # -----------------------------------------------------------------------------
11
42
  # read_json_input [arg]
12
43
  #
@@ -0,0 +1,164 @@
1
+ #!/bin/bash
2
+ # =============================================================================
3
+ # Tests for lib.sh — shared skills library
4
+ # Covers: --file preprocessor, read_json_input, require_param, error_exit
5
+ # =============================================================================
6
+ set -euo pipefail
7
+
8
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9
+ PASS=0
10
+ FAIL=0
11
+ TOTAL=0
12
+
13
+ # Color output
14
+ RED='\033[0;31m'
15
+ GREEN='\033[0;32m'
16
+ NC='\033[0m' # No Color
17
+
18
+ assert_eq() {
19
+ local test_name="$1" expected="$2" actual="$3"
20
+ TOTAL=$((TOTAL + 1))
21
+ if [ "$expected" = "$actual" ]; then
22
+ echo -e "${GREEN}PASS${NC}: $test_name"
23
+ PASS=$((PASS + 1))
24
+ else
25
+ echo -e "${RED}FAIL${NC}: $test_name"
26
+ echo " Expected: $expected"
27
+ echo " Actual: $actual"
28
+ FAIL=$((FAIL + 1))
29
+ fi
30
+ }
31
+
32
+ assert_contains() {
33
+ local test_name="$1" expected_substr="$2" actual="$3"
34
+ TOTAL=$((TOTAL + 1))
35
+ if echo "$actual" | grep -q "$expected_substr"; then
36
+ echo -e "${GREEN}PASS${NC}: $test_name"
37
+ PASS=$((PASS + 1))
38
+ else
39
+ echo -e "${RED}FAIL${NC}: $test_name"
40
+ echo " Expected to contain: $expected_substr"
41
+ echo " Actual: $actual"
42
+ FAIL=$((FAIL + 1))
43
+ fi
44
+ }
45
+
46
+ assert_exit_code() {
47
+ local test_name="$1" expected_code="$2"
48
+ shift 2
49
+ local actual_code=0
50
+ "$@" >/dev/null 2>&1 || actual_code=$?
51
+ TOTAL=$((TOTAL + 1))
52
+ if [ "$expected_code" = "$actual_code" ]; then
53
+ echo -e "${GREEN}PASS${NC}: $test_name"
54
+ PASS=$((PASS + 1))
55
+ else
56
+ echo -e "${RED}FAIL${NC}: $test_name"
57
+ echo " Expected exit code: $expected_code"
58
+ echo " Actual exit code: $actual_code"
59
+ FAIL=$((FAIL + 1))
60
+ fi
61
+ }
62
+
63
+ # Create a minimal test skill script that sources lib.sh and echoes $1
64
+ TEMP_DIR=$(mktemp -d)
65
+ trap "rm -rf $TEMP_DIR" EXIT
66
+
67
+ cat > "$TEMP_DIR/test_skill.sh" << 'SKILL_EOF'
68
+ #!/bin/bash
69
+ set -euo pipefail
70
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
71
+ # Source lib.sh via the real path
72
+ source "$LIB_PATH"
73
+ # Output the first positional parameter (after preprocessor runs)
74
+ echo "$1"
75
+ SKILL_EOF
76
+ chmod +x "$TEMP_DIR/test_skill.sh"
77
+
78
+ # Also create a test skill that uses read_json_input
79
+ cat > "$TEMP_DIR/test_read_json.sh" << 'SKILL_EOF'
80
+ #!/bin/bash
81
+ set -euo pipefail
82
+ source "$LIB_PATH"
83
+ INPUT=$(read_json_input "${1:-}")
84
+ echo "$INPUT"
85
+ SKILL_EOF
86
+ chmod +x "$TEMP_DIR/test_read_json.sh"
87
+
88
+ export LIB_PATH="$SCRIPT_DIR/lib.sh"
89
+
90
+ echo "=== lib.sh Test Suite ==="
91
+ echo ""
92
+
93
+ # ---- Test 1: --file flag reads JSON from file ----
94
+ echo '{"key":"value","text":"hello world"}' > "$TEMP_DIR/input.json"
95
+ RESULT=$(bash "$TEMP_DIR/test_skill.sh" --file "$TEMP_DIR/input.json")
96
+ assert_eq "--file reads JSON from file" '{"key":"value","text":"hello world"}' "$RESULT"
97
+
98
+ # ---- Test 2: --file with special characters (the whole point!) ----
99
+ printf '%s' '{"summary":"text with '\''quotes'\'' and (parens) and `backticks`"}' > "$TEMP_DIR/special.json"
100
+ RESULT=$(bash "$TEMP_DIR/test_skill.sh" --file "$TEMP_DIR/special.json")
101
+ assert_contains "--file handles single quotes" "quotes" "$RESULT"
102
+ assert_contains "--file handles parentheses" "(parens)" "$RESULT"
103
+ assert_contains "--file handles backticks" "backticks" "$RESULT"
104
+
105
+ # ---- Test 3: --file with multiline JSON ----
106
+ cat > "$TEMP_DIR/multiline.json" << 'MULTI_EOF'
107
+ {"summary":"line 1\nline 2\nline 3","status":"done"}
108
+ MULTI_EOF
109
+ RESULT=$(bash "$TEMP_DIR/test_skill.sh" --file "$TEMP_DIR/multiline.json")
110
+ assert_contains "--file handles multiline content" "line 1" "$RESULT"
111
+
112
+ # ---- Test 4: --file with nonexistent file fails ----
113
+ RESULT=$(bash "$TEMP_DIR/test_skill.sh" --file "/tmp/nonexistent_crewly_test_file.json" 2>&1 || true)
114
+ assert_contains "--file with missing file reports error" "File not found" "$RESULT"
115
+
116
+ # ---- Test 5: Direct JSON argument still works (backward compat) ----
117
+ RESULT=$(bash "$TEMP_DIR/test_skill.sh" '{"key":"direct"}')
118
+ assert_eq "Direct JSON argument works" '{"key":"direct"}' "$RESULT"
119
+
120
+ # ---- Test 6: read_json_input with --file ----
121
+ echo '{"agentId":"dev-1","content":"test memory"}' > "$TEMP_DIR/read_input.json"
122
+ RESULT=$(bash "$TEMP_DIR/test_read_json.sh" --file "$TEMP_DIR/read_input.json")
123
+ assert_contains "read_json_input with --file" "dev-1" "$RESULT"
124
+
125
+ # ---- Test 7: read_json_input with @filepath ----
126
+ echo '{"agentId":"dev-2","content":"at-file test"}' > "$TEMP_DIR/at_input.json"
127
+ RESULT=$(bash "$TEMP_DIR/test_read_json.sh" "@$TEMP_DIR/at_input.json")
128
+ assert_contains "read_json_input with @filepath" "dev-2" "$RESULT"
129
+
130
+ # ---- Test 8: read_json_input with stdin pipe ----
131
+ RESULT=$(echo '{"agentId":"dev-3","content":"stdin test"}' | bash "$TEMP_DIR/test_read_json.sh")
132
+ assert_contains "read_json_input with stdin pipe" "dev-3" "$RESULT"
133
+
134
+ # ---- Test 9: read_json_input with direct JSON arg ----
135
+ RESULT=$(bash "$TEMP_DIR/test_read_json.sh" '{"agentId":"dev-4"}')
136
+ assert_contains "read_json_input with direct arg" "dev-4" "$RESULT"
137
+
138
+ # ---- Test 10: --file with Unicode content ----
139
+ printf '%s' '{"text":"Chinese: 你好世界, Japanese: こんにちは"}' > "$TEMP_DIR/unicode.json"
140
+ RESULT=$(bash "$TEMP_DIR/test_skill.sh" --file "$TEMP_DIR/unicode.json")
141
+ assert_contains "--file handles Unicode" "你好世界" "$RESULT"
142
+
143
+ # ---- Test 11: --file with dollar signs and variables ----
144
+ printf '%s' '{"text":"Price is $100, env is ${HOME}"}' > "$TEMP_DIR/dollar.json"
145
+ RESULT=$(bash "$TEMP_DIR/test_skill.sh" --file "$TEMP_DIR/dollar.json")
146
+ assert_contains "--file preserves dollar signs" '$100' "$RESULT"
147
+ assert_contains "--file preserves \\\${} syntax" '${HOME}' "$RESULT"
148
+
149
+ # ---- Test 12: --file with newlines in JSON values ----
150
+ printf '%s' '{"text":"line1\nline2\nline3"}' > "$TEMP_DIR/newlines.json"
151
+ RESULT=$(bash "$TEMP_DIR/test_skill.sh" --file "$TEMP_DIR/newlines.json")
152
+ assert_contains "--file preserves escaped newlines" 'line1\\nline2' "$RESULT"
153
+
154
+ # ---- Test 13: --file with empty JSON ----
155
+ echo '{}' > "$TEMP_DIR/empty.json"
156
+ RESULT=$(bash "$TEMP_DIR/test_read_json.sh" --file "$TEMP_DIR/empty.json")
157
+ assert_eq "--file with empty JSON" '{}' "$RESULT"
158
+
159
+ echo ""
160
+ echo "=== Results: $PASS/$TOTAL passed, $FAIL failed ==="
161
+
162
+ if [ "$FAIL" -gt 0 ]; then
163
+ exit 1
164
+ fi
@@ -29,6 +29,17 @@ export declare class CommunicationModule implements PromptModule {
29
29
  * @returns Formatted markdown communication section
30
30
  */
31
31
  build(config: ModuleConfig): Promise<string>;
32
+ /**
33
+ * Build a skill call example snippet. For gemini-cli runtime, uses --file
34
+ * pattern to avoid shell escaping EOF errors. For other runtimes, uses
35
+ * inline JSON argument.
36
+ *
37
+ * @param config - Module configuration with runtime type
38
+ * @param skillPath - Relative path to the skill (e.g., 'core/report-status')
39
+ * @param jsonExample - Example JSON string for inline mode
40
+ * @returns Formatted bash code block
41
+ */
42
+ private buildSkillExample;
32
43
  /**
33
44
  * Full orchestrator communication spec — Slack, Chat UI, NOTIFY markers,
34
45
  * thread management, message formatting, and notification protocol.
@@ -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;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IA0D9B;;OAEG;IACH,OAAO,CAAC,YAAY;IAuBpB;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAoBxB"}
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;;;;;;;;;OASG;IACH,OAAO,CAAC,iBAAiB;IAYzB;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IA2D9B;;OAEG;IACH,OAAO,CAAC,YAAY;IAwBpB;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAqBxB"}
@@ -46,11 +46,36 @@ export class CommunicationModule {
46
46
  }
47
47
  return this.buildWorkerComms(config);
48
48
  }
49
+ /**
50
+ * Build a skill call example snippet. For gemini-cli runtime, uses --file
51
+ * pattern to avoid shell escaping EOF errors. For other runtimes, uses
52
+ * inline JSON argument.
53
+ *
54
+ * @param config - Module configuration with runtime type
55
+ * @param skillPath - Relative path to the skill (e.g., 'core/report-status')
56
+ * @param jsonExample - Example JSON string for inline mode
57
+ * @returns Formatted bash code block
58
+ */
59
+ buildSkillExample(config, skillPath, jsonExample) {
60
+ if (config.runtimeType === 'gemini-cli') {
61
+ return `\`\`\`bash
62
+ printf '%s' '${jsonExample}' > /tmp/crewly_skill_input.json
63
+ bash ${config.agentSkillsPath}/${skillPath}/execute.sh --file /tmp/crewly_skill_input.json
64
+ \`\`\``;
65
+ }
66
+ return `\`\`\`bash
67
+ bash ${config.agentSkillsPath}/${skillPath}/execute.sh '${jsonExample}'
68
+ \`\`\``;
69
+ }
49
70
  /**
50
71
  * Full orchestrator communication spec — Slack, Chat UI, NOTIFY markers,
51
72
  * thread management, message formatting, and notification protocol.
52
73
  */
53
74
  buildOrchestratorComms(config) {
75
+ const reportStatusJson = `{"sessionName":"${config.sessionName}","status":"<status>","summary":"<summary>","projectPath":"${config.projectPath || config.projectRoot}"}`;
76
+ const sendMessageJson = '{"to":"<session>","message":"<msg>"}';
77
+ const reportExample = this.buildSkillExample(config, 'core/report-status', reportStatusJson);
78
+ const sendExample = this.buildSkillExample(config, 'core/send-message', sendMessageJson);
54
79
  return `## Communication Protocol
55
80
 
56
81
  ### Message Channels
@@ -100,30 +125,26 @@ When you receive a message from the user (via Slack, Chat UI, or Google Chat):
100
125
  This prevents the user from wondering if their message was received or if the agent is stuck.
101
126
 
102
127
  ### Communication Skills
103
- \`\`\`bash
104
- bash ${config.agentSkillsPath}/core/report-status/execute.sh '{"sessionName":"${config.sessionName}","status":"<status>","summary":"<summary>","projectPath":"${config.projectPath || config.projectRoot}"}'
105
- \`\`\`
106
- \`\`\`bash
107
- bash ${config.agentSkillsPath}/core/send-message/execute.sh '{"to":"<session>","message":"<msg>"}'
108
- \`\`\``;
128
+ ${reportExample}
129
+ ${sendExample}`;
109
130
  }
110
131
  /**
111
132
  * TL communication — delegation-focused messaging plus basic user comms.
112
133
  */
113
134
  buildTLComms(config) {
135
+ const reportStatusJson = `{"sessionName":"${config.sessionName}","status":"<status>","summary":"<summary>","projectPath":"${config.projectPath || config.projectRoot}"}`;
136
+ const sendMessageJson = '{"to":"<worker-session>","message":"<task or feedback>"}';
137
+ const reportExample = this.buildSkillExample(config, 'core/report-status', reportStatusJson);
138
+ const sendExample = this.buildSkillExample(config, 'core/send-message', sendMessageJson);
114
139
  return `## Communication Protocol
115
140
 
116
141
  ### Reporting to Orchestrator
117
142
  Use \`report-status\` to keep the orchestrator informed of progress:
118
- \`\`\`bash
119
- bash ${config.agentSkillsPath}/core/report-status/execute.sh '{"sessionName":"${config.sessionName}","status":"<status>","summary":"<summary>","projectPath":"${config.projectPath || config.projectRoot}"}'
120
- \`\`\`
143
+ ${reportExample}
121
144
 
122
145
  ### Messaging Workers
123
146
  Use \`send-message\` to communicate with your subordinates:
124
- \`\`\`bash
125
- bash ${config.agentSkillsPath}/core/send-message/execute.sh '{"to":"<worker-session>","message":"<task or feedback>"}'
126
- \`\`\`
147
+ ${sendExample}
127
148
 
128
149
  ### Communication Rules
129
150
  1. **Report up** — Keep orchestrator informed of progress and blockers
@@ -136,19 +157,19 @@ bash ${config.agentSkillsPath}/core/send-message/execute.sh '{"to":"<worker-sess
136
157
  * Worker communication — compact report-status and send-message only.
137
158
  */
138
159
  buildWorkerComms(config) {
160
+ const reportStatusJson = `{"sessionName":"${config.sessionName}","status":"<status>","summary":"<summary>","projectPath":"${config.projectPath || config.projectRoot}"}`;
161
+ const sendMessageJson = '{"to":"<session>","message":"<msg>"}';
162
+ const reportExample = this.buildSkillExample(config, 'core/report-status', reportStatusJson);
163
+ const sendExample = this.buildSkillExample(config, 'core/send-message', sendMessageJson);
139
164
  return `## Communication
140
165
 
141
166
  ### Reporting Progress
142
167
  Use \`report-status\` to update your team leader on task progress:
143
- \`\`\`bash
144
- bash ${config.agentSkillsPath}/core/report-status/execute.sh '{"sessionName":"${config.sessionName}","status":"<status>","summary":"<summary>","projectPath":"${config.projectPath || config.projectRoot}"}'
145
- \`\`\`
168
+ ${reportExample}
146
169
 
147
170
  ### Messaging
148
171
  Use \`send-message\` to communicate with other agents:
149
- \`\`\`bash
150
- bash ${config.agentSkillsPath}/core/send-message/execute.sh '{"to":"<session>","message":"<msg>"}'
151
- \`\`\`
172
+ ${sendExample}
152
173
 
153
174
  ### Rules
154
175
  - Report progress periodically so your team leader stays informed
@@ -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;;;OAGG;IACK,sBAAsB,CAAC,MAAoB;QAClD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAkDF,MAAM,CAAC,eAAe,mDAAmD,MAAM,CAAC,WAAW,8DAA8D,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,WAAW;;;OAGjM,MAAM,CAAC,eAAe;OACtB,CAAC;IACP,CAAC;IAED;;OAEG;IACK,YAAY,CAAC,MAAoB;QACxC,OAAO;;;;;OAKF,MAAM,CAAC,eAAe,mDAAmD,MAAM,CAAC,WAAW,8DAA8D,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,WAAW;;;;;;OAMjM,MAAM,CAAC,eAAe;;;;;;;;yEAQ4C,CAAC;IACzE,CAAC;IAED;;OAEG;IACK,gBAAgB,CAAC,MAAoB;QAC5C,OAAO;;;;;OAKF,MAAM,CAAC,eAAe,mDAAmD,MAAM,CAAC,WAAW,8DAA8D,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,WAAW;;;;;;OAMjM,MAAM,CAAC,eAAe;;;;;;uCAMU,CAAC;IACvC,CAAC;CACD"}
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;;;;;;;;;OASG;IACK,iBAAiB,CAAC,MAAoB,EAAE,SAAiB,EAAE,WAAmB;QACrF,IAAI,MAAM,CAAC,WAAW,KAAK,YAAY,EAAE,CAAC;YACzC,OAAO;eACK,WAAW;OACnB,MAAM,CAAC,eAAe,IAAI,SAAS;OACnC,CAAC;QACN,CAAC;QACD,OAAO;OACF,MAAM,CAAC,eAAe,IAAI,SAAS,gBAAgB,WAAW;OAC9D,CAAC;IACP,CAAC;IAED;;;OAGG;IACK,sBAAsB,CAAC,MAAoB;QAClD,MAAM,gBAAgB,GAAG,mBAAmB,MAAM,CAAC,WAAW,8DAA8D,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,WAAW,IAAI,CAAC;QACzK,MAAM,eAAe,GAAG,sCAAsC,CAAC;QAC/D,MAAM,aAAa,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,oBAAoB,EAAE,gBAAgB,CAAC,CAAC;QAC7F,MAAM,WAAW,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,mBAAmB,EAAE,eAAe,CAAC,CAAC;QAEzF,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiDP,aAAa;EACb,WAAW,EAAE,CAAC;IACf,CAAC;IAED;;OAEG;IACK,YAAY,CAAC,MAAoB;QACxC,MAAM,gBAAgB,GAAG,mBAAmB,MAAM,CAAC,WAAW,8DAA8D,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,WAAW,IAAI,CAAC;QACzK,MAAM,eAAe,GAAG,0DAA0D,CAAC;QACnF,MAAM,aAAa,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,oBAAoB,EAAE,gBAAgB,CAAC,CAAC;QAC7F,MAAM,WAAW,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,mBAAmB,EAAE,eAAe,CAAC,CAAC;QAEzF,OAAO;;;;EAIP,aAAa;;;;EAIb,WAAW;;;;;;;yEAO4D,CAAC;IACzE,CAAC;IAED;;OAEG;IACK,gBAAgB,CAAC,MAAoB;QAC5C,MAAM,gBAAgB,GAAG,mBAAmB,MAAM,CAAC,WAAW,8DAA8D,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,WAAW,IAAI,CAAC;QACzK,MAAM,eAAe,GAAG,sCAAsC,CAAC;QAC/D,MAAM,aAAa,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,oBAAoB,EAAE,gBAAgB,CAAC,CAAC;QAC7F,MAAM,WAAW,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,mBAAmB,EAAE,eAAe,CAAC,CAAC;QAEzF,OAAO;;;;EAIP,aAAa;;;;EAIb,WAAW;;;;;uCAK0B,CAAC;IACvC,CAAC;CACD"}
@@ -34,6 +34,20 @@ export declare class SkillsReferenceModule implements PromptModule {
34
34
  * Workers get narrow read+execute scope; orchestrators get broader coordination scope.
35
35
  */
36
36
  private buildCapabilities;
37
+ /**
38
+ * Build safe skill calling guide for runtimes with shell escaping issues.
39
+ *
40
+ * Gemini CLI's run_shell_command mangles JSON arguments containing quotes,
41
+ * backticks, and parentheses, causing "unexpected EOF" shell errors.
42
+ * This guide instructs the agent to write JSON to a temp file first,
43
+ * then pass --file <path> to avoid shell interpretation entirely.
44
+ *
45
+ * Only included for gemini-cli runtime type.
46
+ *
47
+ * @param config - Module configuration with runtime type
48
+ * @returns Safe calling guide markdown, or null if not needed
49
+ */
50
+ private buildSafeCallGuide;
37
51
  /**
38
52
  * Build communication and memory tool instructions.
39
53
  */
@@ -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;IAQlD;;OAEG;IACH,OAAO,CAAC,eAAe;IAoDvB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAiCzB;;OAEG;IACH,OAAO,CAAC,kBAAkB;CAkB1B"}
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;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,kBAAkB;IA2B1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;CAkB1B"}
@@ -29,7 +29,12 @@ export class SkillsReferenceModule {
29
29
  const coreSkills = this.buildCoreSkills(config);
30
30
  const capabilities = this.buildCapabilities(config);
31
31
  const communication = this.buildCommunication(config);
32
- return `${coreSkills}\n\n${capabilities}\n\n${communication}`;
32
+ const safeCallGuide = this.buildSafeCallGuide(config);
33
+ const parts = [coreSkills, capabilities, communication];
34
+ if (safeCallGuide) {
35
+ parts.push(safeCallGuide);
36
+ }
37
+ return parts.join('\n\n');
33
38
  }
34
39
  /**
35
40
  * Build the core skills list — available to all roles.
@@ -74,6 +79,44 @@ export class SkillsReferenceModule {
74
79
  }
75
80
  return lines.join('\n');
76
81
  }
82
+ /**
83
+ * Build safe skill calling guide for runtimes with shell escaping issues.
84
+ *
85
+ * Gemini CLI's run_shell_command mangles JSON arguments containing quotes,
86
+ * backticks, and parentheses, causing "unexpected EOF" shell errors.
87
+ * This guide instructs the agent to write JSON to a temp file first,
88
+ * then pass --file <path> to avoid shell interpretation entirely.
89
+ *
90
+ * Only included for gemini-cli runtime type.
91
+ *
92
+ * @param config - Module configuration with runtime type
93
+ * @returns Safe calling guide markdown, or null if not needed
94
+ */
95
+ buildSafeCallGuide(config) {
96
+ if (config.runtimeType !== 'gemini-cli') {
97
+ return null;
98
+ }
99
+ return `## Safe Skill Calling (MANDATORY)
100
+
101
+ **CRITICAL:** When calling any bash skill, you MUST use the \`--file\` pattern to avoid shell escaping errors.
102
+ Passing JSON directly as a shell argument will cause "unexpected EOF" errors when the content contains quotes, backticks, or parentheses.
103
+
104
+ ### Required Pattern
105
+ \`\`\`bash
106
+ # Step 1: Write JSON to a temp file (printf preserves all special characters)
107
+ printf '%s' '{"sessionName":"my-agent","status":"done","summary":"Fixed the bug"}' > /tmp/crewly_skill_input.json
108
+
109
+ # Step 2: Call the skill with --file flag
110
+ bash ${config.agentSkillsPath}/core/report-status/execute.sh --file /tmp/crewly_skill_input.json
111
+ \`\`\`
112
+
113
+ ### Rules
114
+ 1. **ALWAYS** use \`printf '%s' '<json>' > /tmp/crewly_skill_input.json\` then \`--file\`
115
+ 2. **NEVER** pass JSON directly as a shell argument: \`bash execute.sh '{"key":"value with 'quotes'"}'\`
116
+ 3. Use \`/tmp/crewly_skill_input.json\` as the temp file (overwritten each call)
117
+ 4. This applies to ALL skills: report-status, send-message, remember, recall, delegate-task, reply-slack, reply-gchat, etc.
118
+ 5. For skills that support named flags (reply-slack, reply-gchat), you may also use \`--text-file\` for the message body`;
119
+ }
77
120
  /**
78
121
  * Build communication and memory tool instructions.
79
122
  */
@@ -1 +1 @@
1
- {"version":3,"file":"skills-reference.module.js","sourceRoot":"","sources":["../../../../../../../backend/src/services/ai/prompt-modules/skills-reference.module.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,OAAO,qBAAqB;IACjC,IAAI,GAAG,mBAAmB,CAAC;IAC3B,QAAQ,GAAG,CAAC,CAAC;IACb,SAAS,GAAG,GAAG,CAAC;IAChB,WAAW,GAAG,KAAK,CAAC;IAEpB;;OAEG;IACH,aAAa,CAAC,OAAqB;QAClC,OAAO,IAAI,CAAC;IACb,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,KAAK,CAAC,MAAoB;QAC/B,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QAChD,MAAM,YAAY,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;QACpD,MAAM,aAAa,GAAG,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;QAEtD,OAAO,GAAG,UAAU,OAAO,YAAY,OAAO,aAAa,EAAE,CAAC;IAC/D,CAAC;IAED;;OAEG;IACK,eAAe,CAAC,MAAoB;QAC3C,MAAM,KAAK,GAAG;YACb,qBAAqB;YACrB,EAAE;YACF,oBAAoB,MAAM,CAAC,eAAe,MAAM;YAChD,2DAA2D;YAC3D,0DAA0D;YAC1D,2DAA2D;YAC3D,uEAAuE;SACvE,CAAC;QAEF,2DAA2D;QAC3D,IAAI,MAAM,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YACpC,KAAK,CAAC,IAAI,CACT,iDAAiD,EACjD,2CAA2C,EAC3C,yDAAyD,EACzD,2DAA2D,EAC3D,6DAA6D,EAC7D,6DAA6D,EAC7D,qDAAqD,EACrD,6EAA6E,EAC7E,wDAAwD,EACxD,6DAA6D,EAC7D,iEAAiE,EACjE,kFAAkF,EAClF,wEAAwE,EACxE,mFAAmF,EACnF,EAAE,EACF,6GAA6G,CAC7G,CAAC;QACH,CAAC;aAAM,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CACT,wEAAwE,EACxE,2CAA2C,EAC3C,6BAA6B,MAAM,CAAC,YAAY,MAAM,EACtD,oDAAoD,EACpD,oDAAoD,EACpD,qDAAqD,CACrD,CAAC;QACH,CAAC;aAAM,CAAC;YACP,KAAK,CAAC,IAAI,CACT,sDAAsD,EACtD,iEAAiE,CACjE,CAAC;QACH,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,4DAA4D,CAAC,CAAC;QAE7E,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAED;;;OAGG;IACK,iBAAiB,CAAC,MAAoB;QAC7C,MAAM,KAAK,GAAG,CAAC,2BAA2B,EAAE,EAAE,CAAC,CAAC;QAEhD,IAAI,MAAM,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YACpC,KAAK,CAAC,IAAI,CACT,6BAA6B,EAC7B,wEAAwE,EACxE,gEAAgE,EAChE,qEAAqE,EACrE,mEAAmE,EACnE,EAAE,EACF,mFAAmF,CACnF,CAAC;QACH,CAAC;aAAM,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CACT,6BAA6B,EAC7B,qDAAqD,EACrD,mCAAmC,MAAM,CAAC,eAAe,yBAAyB,EAClF,mCAAmC,MAAM,CAAC,YAAY,0BAA0B,EAChF,mEAAmE,CACnE,CAAC;QACH,CAAC;aAAM,CAAC;YACP,KAAK,CAAC,IAAI,CACT,6BAA6B,EAC7B,qDAAqD,EACrD,mCAAmC,MAAM,CAAC,eAAe,yBAAyB,EAClF,mEAAmE,CACnE,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAED;;OAEG;IACK,kBAAkB,CAAC,MAAoB;QAC9C,OAAO;;uBAEc,MAAM,CAAC,eAAe;;;;;;;;;;;;;kLAaqI,CAAC;IAClL,CAAC;CACD"}
1
+ {"version":3,"file":"skills-reference.module.js","sourceRoot":"","sources":["../../../../../../../backend/src/services/ai/prompt-modules/skills-reference.module.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,OAAO,qBAAqB;IACjC,IAAI,GAAG,mBAAmB,CAAC;IAC3B,QAAQ,GAAG,CAAC,CAAC;IACb,SAAS,GAAG,GAAG,CAAC;IAChB,WAAW,GAAG,KAAK,CAAC;IAEpB;;OAEG;IACH,aAAa,CAAC,OAAqB;QAClC,OAAO,IAAI,CAAC;IACb,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,KAAK,CAAC,MAAoB;QAC/B,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QAChD,MAAM,YAAY,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;QACpD,MAAM,aAAa,GAAG,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;QAEtD,MAAM,aAAa,GAAG,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACtD,MAAM,KAAK,GAAG,CAAC,UAAU,EAAE,YAAY,EAAE,aAAa,CAAC,CAAC;QACxD,IAAI,aAAa,EAAE,CAAC;YACnB,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC3B,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3B,CAAC;IAED;;OAEG;IACK,eAAe,CAAC,MAAoB;QAC3C,MAAM,KAAK,GAAG;YACb,qBAAqB;YACrB,EAAE;YACF,oBAAoB,MAAM,CAAC,eAAe,MAAM;YAChD,2DAA2D;YAC3D,0DAA0D;YAC1D,2DAA2D;YAC3D,uEAAuE;SACvE,CAAC;QAEF,2DAA2D;QAC3D,IAAI,MAAM,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YACpC,KAAK,CAAC,IAAI,CACT,iDAAiD,EACjD,2CAA2C,EAC3C,yDAAyD,EACzD,2DAA2D,EAC3D,6DAA6D,EAC7D,6DAA6D,EAC7D,qDAAqD,EACrD,6EAA6E,EAC7E,wDAAwD,EACxD,6DAA6D,EAC7D,iEAAiE,EACjE,kFAAkF,EAClF,wEAAwE,EACxE,mFAAmF,EACnF,EAAE,EACF,6GAA6G,CAC7G,CAAC;QACH,CAAC;aAAM,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CACT,wEAAwE,EACxE,2CAA2C,EAC3C,6BAA6B,MAAM,CAAC,YAAY,MAAM,EACtD,oDAAoD,EACpD,oDAAoD,EACpD,qDAAqD,CACrD,CAAC;QACH,CAAC;aAAM,CAAC;YACP,KAAK,CAAC,IAAI,CACT,sDAAsD,EACtD,iEAAiE,CACjE,CAAC;QACH,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,4DAA4D,CAAC,CAAC;QAE7E,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAED;;;OAGG;IACK,iBAAiB,CAAC,MAAoB;QAC7C,MAAM,KAAK,GAAG,CAAC,2BAA2B,EAAE,EAAE,CAAC,CAAC;QAEhD,IAAI,MAAM,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YACpC,KAAK,CAAC,IAAI,CACT,6BAA6B,EAC7B,wEAAwE,EACxE,gEAAgE,EAChE,qEAAqE,EACrE,mEAAmE,EACnE,EAAE,EACF,mFAAmF,CACnF,CAAC;QACH,CAAC;aAAM,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CACT,6BAA6B,EAC7B,qDAAqD,EACrD,mCAAmC,MAAM,CAAC,eAAe,yBAAyB,EAClF,mCAAmC,MAAM,CAAC,YAAY,0BAA0B,EAChF,mEAAmE,CACnE,CAAC;QACH,CAAC;aAAM,CAAC;YACP,KAAK,CAAC,IAAI,CACT,6BAA6B,EAC7B,qDAAqD,EACrD,mCAAmC,MAAM,CAAC,eAAe,yBAAyB,EAClF,mEAAmE,CACnE,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAED;;;;;;;;;;;;OAYG;IACK,kBAAkB,CAAC,MAAoB;QAC9C,IAAI,MAAM,CAAC,WAAW,KAAK,YAAY,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC;QACb,CAAC;QAED,OAAO;;;;;;;;;;;OAWF,MAAM,CAAC,eAAe;;;;;;;;yHAQ4F,CAAC;IACzH,CAAC;IAED;;OAEG;IACK,kBAAkB,CAAC,MAAoB;QAC9C,OAAO;;uBAEc,MAAM,CAAC,eAAe;;;;;;;;;;;;;kLAaqI,CAAC;IAClL,CAAC;CACD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "crewly",
3
- "version": "1.5.12",
3
+ "version": "1.5.13",
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",