openclaw-opencode-bridge 2.1.2 → 2.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
[](package.json)
|
|
6
6
|
|
|
7
|
-
>
|
|
7
|
+
> Liked this project? Consider donating!
|
|
8
|
+
|
|
9
|
+
> EVM Address: 0xe81c32383C8F21A14E6C2264939dA512e9F9bb42
|
|
8
10
|
|
|
9
11
|
Bridge [OpenClaw](https://openclaw.ai) messaging channels to [OpenCode](https://opencode.ai) via persistent tmux sessions.
|
|
10
12
|
|
|
@@ -98,6 +100,8 @@ Removes all installed components — plugin, shell scripts, OPENCODE.md addition
|
|
|
98
100
|
| Delivery confirmed but no reply | Check `tmux ls` — session may have crashed |
|
|
99
101
|
| Multiline sends only first line | Re-run `openclaw-opencode-bridge onboard` (v2.0.6+) |
|
|
100
102
|
|
|
103
|
+
> Forked from [openclaw-claude-bridge](https://github.com/bettep-dev/openclaw-claude-bridge) by [@bettep-dev](https://github.com/bettep-dev) — modified to work with OpenCode instead of Claude CLI.
|
|
104
|
+
|
|
101
105
|
## License
|
|
102
106
|
|
|
103
107
|
[MIT](LICENSE)
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# bridge-version:
|
|
2
|
+
# bridge-version: 10
|
|
3
3
|
# Start fresh session asynchronously and send instruction
|
|
4
4
|
MSG="$1"
|
|
5
5
|
OPENCODE="{{OPENCODE_BIN}}"
|
|
@@ -78,6 +78,11 @@ is_trivial_echo() {
|
|
|
78
78
|
[ -n "$message_norm" ] && [ "$output_norm" = "$message_norm" ]
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
has_external_delivery_success() {
|
|
82
|
+
local raw="$1"
|
|
83
|
+
printf '%s\n' "$raw" | grep -Eqi 'Sent via [A-Za-z]+|Message ID:[[:space:]]*[0-9]+'
|
|
84
|
+
}
|
|
85
|
+
|
|
81
86
|
extract_last_marked_block() {
|
|
82
87
|
local raw="$1"
|
|
83
88
|
if ! printf '%s' "$raw" | grep -q '🔗'; then
|
|
@@ -111,8 +116,10 @@ sanitize_output() {
|
|
|
111
116
|
|
|
112
117
|
cleaned="$(printf '%s\n' "$cleaned" | sed -E 's/\[[0-9]{1,3}m//g')"
|
|
113
118
|
|
|
114
|
-
cleaned="$(printf '%s\n' "$cleaned" |
|
|
115
|
-
|
|
119
|
+
cleaned="$(printf '%s\n' "$cleaned" | sed -E 's/^[[:space:]]*>+[[:space:]]?//; /^```/d')"
|
|
120
|
+
|
|
121
|
+
cleaned="$(printf '%s\n' "$cleaned" | grep -Eiv \
|
|
122
|
+
'^[[:space:]]*$|^[[:space:]]*(build[[:space:]]*·|◇[[:space:]]+doctor warnings)[[:space:]]*$|^[[:space:]]*◇[[:space:]]+|^[[:space:]]*exa[[:space:]]+(web|code)[[:space:]]+search([[:space:]]+.*)?$|^[[:space:]]*[←→↳].*|^[[:space:]]*wrote file successfully\.?$|^[[:space:]]*(\$[[:space:]]*)?openclaw message send --channel[[:space:]]+|^[[:space:]]*error:[[:space:]]*too many arguments for '\''send'\''.*$|^[[:space:]]*sent via telegram|^[[:space:]]*\[(telegram|discord|slack|whatsapp|signal|irc|matrix|line|mattermost|teams)\]|autoselectfamily=|dnsresultorder=|^[[:space:]]*[│┌┐└┘├┤┬┴┼─═╭╮╰╯]+[[:space:]]*$')"
|
|
116
123
|
|
|
117
124
|
marked="$(extract_last_marked_block "$cleaned")"
|
|
118
125
|
if [ -n "$marked" ]; then
|
|
@@ -124,13 +131,49 @@ sanitize_output() {
|
|
|
124
131
|
printf '%s' "$(trim_text "$cleaned")"
|
|
125
132
|
}
|
|
126
133
|
|
|
134
|
+
sentence_case_first() {
|
|
135
|
+
local text="$1"
|
|
136
|
+
printf '%s' "$text" | awk '
|
|
137
|
+
BEGIN { done = 0 }
|
|
138
|
+
{
|
|
139
|
+
if (done) { print; next }
|
|
140
|
+
line = $0
|
|
141
|
+
for (i = 1; i <= length(line); i++) {
|
|
142
|
+
ch = substr(line, i, 1)
|
|
143
|
+
if (ch ~ /[a-z]/) {
|
|
144
|
+
pre = substr(line, 1, i - 1)
|
|
145
|
+
post = substr(line, i + 1)
|
|
146
|
+
line = pre toupper(ch) post
|
|
147
|
+
done = 1
|
|
148
|
+
break
|
|
149
|
+
} else if (ch ~ /[A-Z]/) {
|
|
150
|
+
done = 1
|
|
151
|
+
break
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
print line
|
|
155
|
+
}'
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
apply_reply_style() {
|
|
159
|
+
local text="$1"
|
|
160
|
+
text="$(trim_text "$text")"
|
|
161
|
+
[ -z "$text" ] && { printf '%s' "$text"; return; }
|
|
162
|
+
text="$(sentence_case_first "$text")"
|
|
163
|
+
printf '%s' "$text"
|
|
164
|
+
}
|
|
165
|
+
|
|
127
166
|
run_with_timeout() {
|
|
128
167
|
local mode="$1"
|
|
129
168
|
local prompt="$2"
|
|
130
169
|
local output rc tmp pid watchdog
|
|
131
170
|
|
|
132
171
|
tmp="$(mktemp /tmp/opencode-run.XXXXXX)"
|
|
133
|
-
|
|
172
|
+
if [ -n "$mode" ]; then
|
|
173
|
+
"$OPENCODE" run "$mode" "$prompt" >"$tmp" 2>&1 &
|
|
174
|
+
else
|
|
175
|
+
"$OPENCODE" run "$prompt" >"$tmp" 2>&1 &
|
|
176
|
+
fi
|
|
134
177
|
pid=$!
|
|
135
178
|
|
|
136
179
|
(
|
|
@@ -172,10 +215,11 @@ run_with_timeout() {
|
|
|
172
215
|
exit 0
|
|
173
216
|
fi
|
|
174
217
|
|
|
175
|
-
|
|
218
|
+
# Fresh request: run without --continue to avoid session carryover.
|
|
219
|
+
run_result="$(run_with_timeout "" "$FULL_MSG")"
|
|
176
220
|
rc="$(printf '%s' "$run_result" | head -n 1)"
|
|
177
|
-
|
|
178
|
-
output="$(sanitize_output "$
|
|
221
|
+
raw_output="$(printf '%s' "$run_result" | tail -n +2)"
|
|
222
|
+
output="$(sanitize_output "$raw_output")"
|
|
179
223
|
|
|
180
224
|
if [ "$rc" -eq 124 ] || [ "$rc" -eq 137 ]; then
|
|
181
225
|
output="OpenCode timed out after ${RUN_TIMEOUT_SEC}s. Task may still be running. Try waiting a bit or send a follow-up."
|
|
@@ -185,7 +229,13 @@ run_with_timeout() {
|
|
|
185
229
|
output="OpenCode ran, but returned a non-informative echo. Please retry with a more specific prompt."
|
|
186
230
|
fi
|
|
187
231
|
|
|
188
|
-
|
|
232
|
+
output="$(apply_reply_style "$output")"
|
|
233
|
+
|
|
234
|
+
if has_external_delivery_success "$raw_output"; then
|
|
235
|
+
printf '[%s] /ccn skipped bridge send (already sent by OpenCode)\n' "$(date '+%Y-%m-%d %H:%M:%S')"
|
|
236
|
+
else
|
|
237
|
+
openclaw message send --channel "$CHANNEL" --target "$TARGET" -m "$output"
|
|
238
|
+
fi
|
|
189
239
|
|
|
190
240
|
ended_at=$(date +%s)
|
|
191
241
|
elapsed=$((ended_at - started_at))
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# bridge-version:
|
|
2
|
+
# bridge-version: 10
|
|
3
3
|
# Dispatch instruction to OpenCode asynchronously and relay response
|
|
4
4
|
MSG="$1"
|
|
5
5
|
OPENCODE="{{OPENCODE_BIN}}"
|
|
@@ -78,6 +78,11 @@ is_trivial_echo() {
|
|
|
78
78
|
[ -n "$message_norm" ] && [ "$output_norm" = "$message_norm" ]
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
has_external_delivery_success() {
|
|
82
|
+
local raw="$1"
|
|
83
|
+
printf '%s\n' "$raw" | grep -Eqi 'Sent via [A-Za-z]+|Message ID:[[:space:]]*[0-9]+'
|
|
84
|
+
}
|
|
85
|
+
|
|
81
86
|
extract_last_marked_block() {
|
|
82
87
|
local raw="$1"
|
|
83
88
|
if ! printf '%s' "$raw" | grep -q '🔗'; then
|
|
@@ -111,8 +116,10 @@ sanitize_output() {
|
|
|
111
116
|
|
|
112
117
|
cleaned="$(printf '%s\n' "$cleaned" | sed -E 's/\[[0-9]{1,3}m//g')"
|
|
113
118
|
|
|
114
|
-
cleaned="$(printf '%s\n' "$cleaned" |
|
|
115
|
-
|
|
119
|
+
cleaned="$(printf '%s\n' "$cleaned" | sed -E 's/^[[:space:]]*>+[[:space:]]?//; /^```/d')"
|
|
120
|
+
|
|
121
|
+
cleaned="$(printf '%s\n' "$cleaned" | grep -Eiv \
|
|
122
|
+
'^[[:space:]]*$|^[[:space:]]*(build[[:space:]]*·|◇[[:space:]]+doctor warnings)[[:space:]]*$|^[[:space:]]*◇[[:space:]]+|^[[:space:]]*exa[[:space:]]+(web|code)[[:space:]]+search([[:space:]]+.*)?$|^[[:space:]]*[←→↳].*|^[[:space:]]*wrote file successfully\.?$|^[[:space:]]*(\$[[:space:]]*)?openclaw message send --channel[[:space:]]+|^[[:space:]]*error:[[:space:]]*too many arguments for '\''send'\''.*$|^[[:space:]]*sent via telegram|^[[:space:]]*\[(telegram|discord|slack|whatsapp|signal|irc|matrix|line|mattermost|teams)\]|autoselectfamily=|dnsresultorder=|^[[:space:]]*[│┌┐└┘├┤┬┴┼─═╭╮╰╯]+[[:space:]]*$')"
|
|
116
123
|
|
|
117
124
|
marked="$(extract_last_marked_block "$cleaned")"
|
|
118
125
|
if [ -n "$marked" ]; then
|
|
@@ -124,6 +131,38 @@ sanitize_output() {
|
|
|
124
131
|
printf '%s' "$(trim_text "$cleaned")"
|
|
125
132
|
}
|
|
126
133
|
|
|
134
|
+
sentence_case_first() {
|
|
135
|
+
local text="$1"
|
|
136
|
+
printf '%s' "$text" | awk '
|
|
137
|
+
BEGIN { done = 0 }
|
|
138
|
+
{
|
|
139
|
+
if (done) { print; next }
|
|
140
|
+
line = $0
|
|
141
|
+
for (i = 1; i <= length(line); i++) {
|
|
142
|
+
ch = substr(line, i, 1)
|
|
143
|
+
if (ch ~ /[a-z]/) {
|
|
144
|
+
pre = substr(line, 1, i - 1)
|
|
145
|
+
post = substr(line, i + 1)
|
|
146
|
+
line = pre toupper(ch) post
|
|
147
|
+
done = 1
|
|
148
|
+
break
|
|
149
|
+
} else if (ch ~ /[A-Z]/) {
|
|
150
|
+
done = 1
|
|
151
|
+
break
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
print line
|
|
155
|
+
}'
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
apply_reply_style() {
|
|
159
|
+
local text="$1"
|
|
160
|
+
text="$(trim_text "$text")"
|
|
161
|
+
[ -z "$text" ] && { printf '%s' "$text"; return; }
|
|
162
|
+
text="$(sentence_case_first "$text")"
|
|
163
|
+
printf '%s' "$text"
|
|
164
|
+
}
|
|
165
|
+
|
|
127
166
|
run_with_timeout() {
|
|
128
167
|
local mode="$1"
|
|
129
168
|
local prompt="$2"
|
|
@@ -174,8 +213,8 @@ run_with_timeout() {
|
|
|
174
213
|
|
|
175
214
|
run_result="$(run_with_timeout --continue "$FULL_MSG")"
|
|
176
215
|
rc="$(printf '%s' "$run_result" | head -n 1)"
|
|
177
|
-
|
|
178
|
-
output="$(sanitize_output "$
|
|
216
|
+
raw_output="$(printf '%s' "$run_result" | tail -n +2)"
|
|
217
|
+
output="$(sanitize_output "$raw_output")"
|
|
179
218
|
|
|
180
219
|
if [ "$rc" -eq 124 ] || [ "$rc" -eq 137 ]; then
|
|
181
220
|
output="OpenCode timed out after ${RUN_TIMEOUT_SEC}s. Task may still be running. Try waiting a bit or send a follow-up."
|
|
@@ -185,7 +224,13 @@ run_with_timeout() {
|
|
|
185
224
|
output="OpenCode ran, but returned a non-informative echo. Please retry with a more specific prompt."
|
|
186
225
|
fi
|
|
187
226
|
|
|
188
|
-
|
|
227
|
+
output="$(apply_reply_style "$output")"
|
|
228
|
+
|
|
229
|
+
if has_external_delivery_success "$raw_output"; then
|
|
230
|
+
printf '[%s] /cc skipped bridge send (already sent by OpenCode)\n' "$(date '+%Y-%m-%d %H:%M:%S')"
|
|
231
|
+
else
|
|
232
|
+
openclaw message send --channel "$CHANNEL" --target "$TARGET" -m "$output"
|
|
233
|
+
fi
|
|
189
234
|
|
|
190
235
|
ended_at=$(date +%s)
|
|
191
236
|
elapsed=$((ended_at - started_at))
|
|
@@ -39,4 +39,6 @@ The format is: `[CHANNEL:ID] actual message`
|
|
|
39
39
|
- For follow-up status questions such as "have you created it?", do not answer with only yes/no.
|
|
40
40
|
Always include short status details and the run command.
|
|
41
41
|
- Keep tone clear, proactive, and helpful. Prefer concise but complete responses.
|
|
42
|
+
- Use proper sentence case and punctuation. Start the first sentence with an uppercase letter.
|
|
43
|
+
- Avoid slang-only openings like "hey!" or "yep!" without context; provide a complete helpful sentence.
|
|
42
44
|
- Length guidance: trivial questions can be 1-2 lines; implementation results should usually be 4-10 lines.
|