openclaw-opencode-bridge 2.1.2 → 2.1.3
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: 9
|
|
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
|
|
@@ -124,13 +129,49 @@ sanitize_output() {
|
|
|
124
129
|
printf '%s' "$(trim_text "$cleaned")"
|
|
125
130
|
}
|
|
126
131
|
|
|
132
|
+
sentence_case_first() {
|
|
133
|
+
local text="$1"
|
|
134
|
+
printf '%s' "$text" | awk '
|
|
135
|
+
BEGIN { done = 0 }
|
|
136
|
+
{
|
|
137
|
+
if (done) { print; next }
|
|
138
|
+
line = $0
|
|
139
|
+
for (i = 1; i <= length(line); i++) {
|
|
140
|
+
ch = substr(line, i, 1)
|
|
141
|
+
if (ch ~ /[a-z]/) {
|
|
142
|
+
pre = substr(line, 1, i - 1)
|
|
143
|
+
post = substr(line, i + 1)
|
|
144
|
+
line = pre toupper(ch) post
|
|
145
|
+
done = 1
|
|
146
|
+
break
|
|
147
|
+
} else if (ch ~ /[A-Z]/) {
|
|
148
|
+
done = 1
|
|
149
|
+
break
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
print line
|
|
153
|
+
}'
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
apply_reply_style() {
|
|
157
|
+
local text="$1"
|
|
158
|
+
text="$(trim_text "$text")"
|
|
159
|
+
[ -z "$text" ] && { printf '%s' "$text"; return; }
|
|
160
|
+
text="$(sentence_case_first "$text")"
|
|
161
|
+
printf '%s' "$text"
|
|
162
|
+
}
|
|
163
|
+
|
|
127
164
|
run_with_timeout() {
|
|
128
165
|
local mode="$1"
|
|
129
166
|
local prompt="$2"
|
|
130
167
|
local output rc tmp pid watchdog
|
|
131
168
|
|
|
132
169
|
tmp="$(mktemp /tmp/opencode-run.XXXXXX)"
|
|
133
|
-
|
|
170
|
+
if [ -n "$mode" ]; then
|
|
171
|
+
"$OPENCODE" run "$mode" "$prompt" >"$tmp" 2>&1 &
|
|
172
|
+
else
|
|
173
|
+
"$OPENCODE" run "$prompt" >"$tmp" 2>&1 &
|
|
174
|
+
fi
|
|
134
175
|
pid=$!
|
|
135
176
|
|
|
136
177
|
(
|
|
@@ -172,10 +213,11 @@ run_with_timeout() {
|
|
|
172
213
|
exit 0
|
|
173
214
|
fi
|
|
174
215
|
|
|
175
|
-
|
|
216
|
+
# Fresh request: run without --continue to avoid session carryover.
|
|
217
|
+
run_result="$(run_with_timeout "" "$FULL_MSG")"
|
|
176
218
|
rc="$(printf '%s' "$run_result" | head -n 1)"
|
|
177
|
-
|
|
178
|
-
output="$(sanitize_output "$
|
|
219
|
+
raw_output="$(printf '%s' "$run_result" | tail -n +2)"
|
|
220
|
+
output="$(sanitize_output "$raw_output")"
|
|
179
221
|
|
|
180
222
|
if [ "$rc" -eq 124 ] || [ "$rc" -eq 137 ]; then
|
|
181
223
|
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 +227,13 @@ run_with_timeout() {
|
|
|
185
227
|
output="OpenCode ran, but returned a non-informative echo. Please retry with a more specific prompt."
|
|
186
228
|
fi
|
|
187
229
|
|
|
188
|
-
|
|
230
|
+
output="$(apply_reply_style "$output")"
|
|
231
|
+
|
|
232
|
+
if has_external_delivery_success "$raw_output"; then
|
|
233
|
+
printf '[%s] /ccn skipped bridge send (already sent by OpenCode)\n' "$(date '+%Y-%m-%d %H:%M:%S')"
|
|
234
|
+
else
|
|
235
|
+
openclaw message send --channel "$CHANNEL" --target "$TARGET" -m "$output"
|
|
236
|
+
fi
|
|
189
237
|
|
|
190
238
|
ended_at=$(date +%s)
|
|
191
239
|
elapsed=$((ended_at - started_at))
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# bridge-version:
|
|
2
|
+
# bridge-version: 9
|
|
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
|
|
@@ -124,6 +129,38 @@ sanitize_output() {
|
|
|
124
129
|
printf '%s' "$(trim_text "$cleaned")"
|
|
125
130
|
}
|
|
126
131
|
|
|
132
|
+
sentence_case_first() {
|
|
133
|
+
local text="$1"
|
|
134
|
+
printf '%s' "$text" | awk '
|
|
135
|
+
BEGIN { done = 0 }
|
|
136
|
+
{
|
|
137
|
+
if (done) { print; next }
|
|
138
|
+
line = $0
|
|
139
|
+
for (i = 1; i <= length(line); i++) {
|
|
140
|
+
ch = substr(line, i, 1)
|
|
141
|
+
if (ch ~ /[a-z]/) {
|
|
142
|
+
pre = substr(line, 1, i - 1)
|
|
143
|
+
post = substr(line, i + 1)
|
|
144
|
+
line = pre toupper(ch) post
|
|
145
|
+
done = 1
|
|
146
|
+
break
|
|
147
|
+
} else if (ch ~ /[A-Z]/) {
|
|
148
|
+
done = 1
|
|
149
|
+
break
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
print line
|
|
153
|
+
}'
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
apply_reply_style() {
|
|
157
|
+
local text="$1"
|
|
158
|
+
text="$(trim_text "$text")"
|
|
159
|
+
[ -z "$text" ] && { printf '%s' "$text"; return; }
|
|
160
|
+
text="$(sentence_case_first "$text")"
|
|
161
|
+
printf '%s' "$text"
|
|
162
|
+
}
|
|
163
|
+
|
|
127
164
|
run_with_timeout() {
|
|
128
165
|
local mode="$1"
|
|
129
166
|
local prompt="$2"
|
|
@@ -174,8 +211,8 @@ run_with_timeout() {
|
|
|
174
211
|
|
|
175
212
|
run_result="$(run_with_timeout --continue "$FULL_MSG")"
|
|
176
213
|
rc="$(printf '%s' "$run_result" | head -n 1)"
|
|
177
|
-
|
|
178
|
-
output="$(sanitize_output "$
|
|
214
|
+
raw_output="$(printf '%s' "$run_result" | tail -n +2)"
|
|
215
|
+
output="$(sanitize_output "$raw_output")"
|
|
179
216
|
|
|
180
217
|
if [ "$rc" -eq 124 ] || [ "$rc" -eq 137 ]; then
|
|
181
218
|
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 +222,13 @@ run_with_timeout() {
|
|
|
185
222
|
output="OpenCode ran, but returned a non-informative echo. Please retry with a more specific prompt."
|
|
186
223
|
fi
|
|
187
224
|
|
|
188
|
-
|
|
225
|
+
output="$(apply_reply_style "$output")"
|
|
226
|
+
|
|
227
|
+
if has_external_delivery_success "$raw_output"; then
|
|
228
|
+
printf '[%s] /cc skipped bridge send (already sent by OpenCode)\n' "$(date '+%Y-%m-%d %H:%M:%S')"
|
|
229
|
+
else
|
|
230
|
+
openclaw message send --channel "$CHANNEL" --target "$TARGET" -m "$output"
|
|
231
|
+
fi
|
|
189
232
|
|
|
190
233
|
ended_at=$(date +%s)
|
|
191
234
|
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.
|