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](https://img.shields.io/npm/l/openclaw-opencode-bridge)](LICENSE)
5
5
  [![node](https://img.shields.io/node/v/openclaw-opencode-bridge)](package.json)
6
6
 
7
- > 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.
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,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-opencode-bridge",
3
- "version": "2.1.2",
3
+ "version": "2.1.3",
4
4
  "description": "Bridge OpenClaw messaging channels to OpenCode via tmux persistent sessions",
5
5
  "main": "./lib/onboard.js",
6
6
  "bin": {
@@ -1,5 +1,5 @@
1
1
  #!/bin/bash
2
- # bridge-version: 6
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
- "$OPENCODE" run "$mode" "$prompt" >"$tmp" 2>&1 &
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
- run_result="$(run_with_timeout --fork "$FULL_MSG")"
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
- output="$(printf '%s' "$run_result" | tail -n +2)"
178
- output="$(sanitize_output "$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
- openclaw message send --channel "$CHANNEL" --target "$TARGET" -m "$output"
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: 6
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
- output="$(printf '%s' "$run_result" | tail -n +2)"
178
- output="$(sanitize_output "$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
- openclaw message send --channel "$CHANNEL" --target "$TARGET" -m "$output"
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.