openclaw-opencode-bridge 2.0.9 โ†’ 2.1.1

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/lib/onboard.js CHANGED
@@ -336,6 +336,53 @@ function openBrowser(url) {
336
336
  }
337
337
  }
338
338
 
339
+ function compactError(err) {
340
+ const text =
341
+ err?.stderr?.trim() ||
342
+ err?.stdout?.trim() ||
343
+ err?.message ||
344
+ String(err || "");
345
+ return text.split("\n").map((s) => s.trim()).filter(Boolean)[0] || "unknown error";
346
+ }
347
+
348
+ async function runGatewayCommand(action, timeoutMs) {
349
+ try {
350
+ await execAsync(`openclaw gateway ${action}`, { timeout: timeoutMs });
351
+ return { ok: true, action };
352
+ } catch (e) {
353
+ return { ok: false, action, error: compactError(e) };
354
+ }
355
+ }
356
+
357
+ async function restartGatewayResilient() {
358
+ // 1) Normal restart with a longer timeout (gateway shutdown/startup can exceed 15s).
359
+ const primary = await runGatewayCommand("restart", 45000);
360
+ if (primary.ok) {
361
+ return { ok: true, mode: "restart" };
362
+ }
363
+
364
+ // 2) Fallback sequence: stop -> start.
365
+ const stop = await runGatewayCommand("stop", 20000);
366
+ await sleep(800);
367
+ const start = await runGatewayCommand("start", 45000);
368
+ if (start.ok) {
369
+ const warning = stop.ok ? "" : ` (stop warning: ${stop.error})`;
370
+ return { ok: true, mode: `stop/start${warning}` };
371
+ }
372
+
373
+ // 3) Final retry.
374
+ await sleep(1000);
375
+ const retry = await runGatewayCommand("restart", 45000);
376
+ if (retry.ok) {
377
+ return { ok: true, mode: "restart-retry" };
378
+ }
379
+
380
+ return {
381
+ ok: false,
382
+ error: retry.error || start.error || primary.error || "gateway restart failed",
383
+ };
384
+ }
385
+
339
386
  // --- Main onboard flow ---
340
387
 
341
388
  async function onboard() {
@@ -825,18 +872,13 @@ async function onboard() {
825
872
  const spinner5 = startSpinner("Restarting OpenClaw Gateway...");
826
873
  await sleep(300);
827
874
 
828
- let restarted = false;
829
- let restartError = "";
830
- try {
831
- await execAsync("openclaw gateway restart", { timeout: 15000 });
832
- restarted = true;
833
- } catch (e) {
834
- restartError = e.stderr?.trim() || e.message;
835
- }
875
+ const gatewayRestart = await restartGatewayResilient();
876
+ const restarted = gatewayRestart.ok;
877
+ const restartError = gatewayRestart.error || "";
836
878
 
837
879
  if (restarted) {
838
880
  spinner5.stop(
839
- `Gateway ${chalk.dim("->")} restarted ${chalk.dim("(skills loaded)")}`,
881
+ `Gateway ${chalk.dim("->")} restarted ${chalk.dim(`(${gatewayRestart.mode})`)}`,
840
882
  );
841
883
  } else {
842
884
  spinner5.fail(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-opencode-bridge",
3
- "version": "2.0.9",
3
+ "version": "2.1.1",
4
4
  "description": "Bridge OpenClaw messaging channels to OpenCode via tmux persistent sessions",
5
5
  "main": "./lib/onboard.js",
6
6
  "bin": {
package/plugin/index.ts CHANGED
@@ -12,7 +12,8 @@ const SCRIPT_MAP: Record<string, string> = {
12
12
  };
13
13
 
14
14
  const REQUIRES_ARG = new Set(["cc", "ccn"]);
15
- const EXEC_TIMEOUT = 120_000;
15
+ const EXEC_TIMEOUT = 15_000;
16
+ const SUPPRESSION_WINDOW = 15_000;
16
17
 
17
18
  const DELIVERY_MSG = "๐Ÿ”— OpenCode will reply shortly.";
18
19
 
@@ -57,15 +58,6 @@ export default function register(api: OpenClawPluginApi) {
57
58
  const script = SCRIPT_MAP[command];
58
59
  if (!script) return;
59
60
 
60
- // Set flag for before_prompt_build to consume
61
- pendingBridgeCommand = true;
62
- // Also set suppression timer as safety net
63
- bridgeSuppressUntil = Date.now() + EXEC_TIMEOUT + 5_000;
64
-
65
- api.logger.debug?.(
66
- `[opencode-bridge] message_received: command=${command}, pendingBridgeCommand=true`,
67
- );
68
-
69
61
  const arg = match[2].trim();
70
62
 
71
63
  if (REQUIRES_ARG.has(command) && !arg) {
@@ -73,17 +65,32 @@ export default function register(api: OpenClawPluginApi) {
73
65
  return;
74
66
  }
75
67
 
68
+ // Set flag for before_prompt_build to consume
69
+ pendingBridgeCommand = true;
70
+ // Keep suppression narrow to this turn to avoid cross-message blocking.
71
+ bridgeSuppressUntil = Date.now() + SUPPRESSION_WINDOW;
72
+
73
+ api.logger.debug?.(
74
+ `[opencode-bridge] message_received: command=${command}, pendingBridgeCommand=true`,
75
+ );
76
+
76
77
  const scriptPath = `${scriptsDir}/${script}`;
77
78
  const args = arg ? [arg] : [];
79
+ const startedAt = Date.now();
78
80
 
79
81
  execFile(
80
82
  scriptPath,
81
83
  args,
82
84
  { timeout: EXEC_TIMEOUT },
83
85
  (error, _stdout, stderr) => {
86
+ const elapsedMs = Date.now() - startedAt;
84
87
  if (error) {
85
88
  api.logger.error?.(
86
- `[opencode-bridge] ${script} failed: ${stderr?.trim() || error.message}`,
89
+ `[opencode-bridge] ${script} failed after ${elapsedMs}ms: ${stderr?.trim() || error.message}`,
90
+ );
91
+ } else {
92
+ api.logger.debug?.(
93
+ `[opencode-bridge] ${script} queued/completed in ${elapsedMs}ms`,
87
94
  );
88
95
  }
89
96
  },
@@ -102,7 +109,7 @@ export default function register(api: OpenClawPluginApi) {
102
109
 
103
110
  if (shouldSuppress) {
104
111
  pendingBridgeCommand = false;
105
- bridgeSuppressUntil = Date.now() + EXEC_TIMEOUT + 5_000;
112
+ bridgeSuppressUntil = Date.now() + SUPPRESSION_WINDOW;
106
113
  return { systemPrompt: SILENT_PROMPT, prependContext: SILENT_PROMPT };
107
114
  } else {
108
115
  // Clear suppression for non-bridge messages
@@ -119,6 +126,8 @@ export default function register(api: OpenClawPluginApi) {
119
126
  );
120
127
 
121
128
  if (suppressing) {
129
+ // One-shot override for the intercepted bridge message.
130
+ bridgeSuppressUntil = 0;
122
131
  return { content: DELIVERY_MSG, cancel: false };
123
132
  }
124
133
  });
@@ -1,22 +1,163 @@
1
1
  #!/bin/bash
2
- # bridge-version: 3
3
- # Start fresh session and send instruction
2
+ # bridge-version: 5
3
+ # Start fresh session asynchronously and send instruction
4
4
  MSG="$1"
5
5
  OPENCODE="{{OPENCODE_BIN}}"
6
6
  CHANNEL="{{CHANNEL}}"
7
7
  TARGET="{{TARGET_ID}}"
8
8
  WORKSPACE="{{WORKSPACE}}"
9
+ LOG_FILE="/tmp/opencode-bridge-send.log"
10
+ BASE_TIMEOUT_SEC=45
11
+ MAX_TIMEOUT_SEC=300
9
12
 
10
13
  if [ -z "$MSG" ]; then
11
14
  echo "ERROR: No message provided"
12
15
  exit 1
13
16
  fi
14
17
 
15
- cd "$WORKSPACE"
16
- FULL_MSG="[${CHANNEL}:${TARGET}] $MSG"
18
+ trim_text() {
19
+ local value="$1"
20
+ value="${value#"${value%%[![:space:]]*}"}"
21
+ value="${value%"${value##*[![:space:]]}"}"
22
+ printf '%s' "$value"
23
+ }
17
24
 
18
- OUTPUT=$("$OPENCODE" run --fork "$FULL_MSG" 2>&1)
25
+ normalize_text() {
26
+ printf '%s' "$1" \
27
+ | tr '[:upper:]' '[:lower:]' \
28
+ | sed -E 's/^๐Ÿ”—[[:space:]]*//; s/^["'\''`]+|["'\''`]+$//g; s/[[:space:]]+/ /g; s/^[[:space:]]+|[[:space:]]+$//g'
29
+ }
19
30
 
20
- openclaw message send --channel "$CHANNEL" --target "$TARGET" -m "$OUTPUT"
31
+ compute_timeout() {
32
+ local msg="$1"
33
+ local timeout="$BASE_TIMEOUT_SEC"
34
+ local chars words
21
35
 
22
- echo "โœ… OpenCode response sent."
36
+ chars=${#msg}
37
+ words="$(printf '%s' "$msg" | wc -w | tr -d '[:space:]')"
38
+
39
+ if [ "$chars" -gt 120 ]; then timeout=$((timeout + 15)); fi
40
+ if [ "$chars" -gt 280 ]; then timeout=$((timeout + 20)); fi
41
+ if [ "$words" -gt 25 ]; then timeout=$((timeout + 20)); fi
42
+
43
+ if printf '%s' "$msg" | grep -Eqi '\b(create|build|write|implement|script|code|program|refactor|debug|fix|test|automation|deploy|migrate|api|database|project)\b'; then
44
+ timeout=$((timeout + 60))
45
+ fi
46
+
47
+ if printf '%s' "$msg" | grep -Eqi '\b(from scratch|end[- ]to[- ]end|single file|one file|only 1|complex|demanding)\b'; then
48
+ timeout=$((timeout + 30))
49
+ fi
50
+
51
+ if [ "$timeout" -gt "$MAX_TIMEOUT_SEC" ]; then
52
+ timeout="$MAX_TIMEOUT_SEC"
53
+ fi
54
+
55
+ printf '%s' "$timeout"
56
+ }
57
+
58
+ is_trivial_echo() {
59
+ local output_norm message_norm
60
+ output_norm="$(normalize_text "$1")"
61
+ message_norm="$(normalize_text "$2")"
62
+ [ -n "$message_norm" ] && [ "$output_norm" = "$message_norm" ]
63
+ }
64
+
65
+ extract_embedded_send_message() {
66
+ local raw="$1"
67
+ local line message
68
+
69
+ line="$(printf '%s\n' "$raw" | grep -E 'openclaw message send --channel' | tail -n 1)"
70
+ [ -z "$line" ] && return 0
71
+
72
+ if printf '%s' "$line" | grep -q -- "-m '"; then
73
+ message="$(printf '%s' "$line" | sed -n "s/.* -m '\(.*\)'.*/\1/p")"
74
+ elif printf '%s' "$line" | grep -q -- '-m "'; then
75
+ message="$(printf '%s' "$line" | sed -n 's/.* -m "\(.*\)".*/\1/p')"
76
+ fi
77
+
78
+ printf '%s' "$(trim_text "$message")"
79
+ }
80
+
81
+ sanitize_output() {
82
+ local raw="$1"
83
+ local extracted cleaned
84
+
85
+ extracted="$(extract_embedded_send_message "$raw")"
86
+ if [ -n "$extracted" ]; then
87
+ printf '%s' "$extracted"
88
+ return 0
89
+ fi
90
+
91
+ cleaned="$(printf '%s' "$raw" \
92
+ | tr '\r' '\n' \
93
+ | sed -E $'s/\x1B\\[[0-9;?]*[ -/]*[@-~]//g; s/\x1B\\][^\a]*(\a|\x1B\\\\)//g')"
94
+
95
+ cleaned="$(printf '%s\n' "$cleaned" | grep -Ev \
96
+ '^[[:space:]]*$|^[[:space:]]*(build ยท|โ—‡ Doctor warnings)[[:space:]]*$|^[[:space:]]*openclaw message send --channel[[:space:]]+|^[[:space:]]*Sent via Telegram|^[[:space:]]*\[[0-9]{1,3}m|^[[:space:]]*\[(telegram|discord|slack|whatsapp|signal|irc|matrix|line|mattermost|teams)\]|autoSelectFamily=|dnsResultOrder=|^[[:space:]]*[โ”‚โ”Œโ”โ””โ”˜โ”œโ”คโ”ฌโ”ดโ”ผโ”€โ•โ•ญโ•ฎโ•ฐโ•ฏ]+[[:space:]]*$|^[[:space:]]*\$[[:space:]]*\[[0-9]{1,3}m')"
97
+
98
+ printf '%s' "$(trim_text "$cleaned")"
99
+ }
100
+
101
+ run_with_timeout() {
102
+ local mode="$1"
103
+ local prompt="$2"
104
+ local output rc tmp pid watchdog
105
+
106
+ tmp="$(mktemp /tmp/opencode-run.XXXXXX)"
107
+ "$OPENCODE" run "$mode" "$prompt" >"$tmp" 2>&1 &
108
+ pid=$!
109
+
110
+ (
111
+ sleep "$RUN_TIMEOUT_SEC"
112
+ if kill -0 "$pid" 2>/dev/null; then
113
+ touch "${tmp}.timeout"
114
+ kill "$pid" 2>/dev/null
115
+ sleep 2
116
+ kill -9 "$pid" 2>/dev/null
117
+ fi
118
+ ) &
119
+ watchdog=$!
120
+
121
+ wait "$pid"
122
+ rc=$?
123
+ kill "$watchdog" 2>/dev/null
124
+
125
+ if [ -f "${tmp}.timeout" ]; then
126
+ rc=124
127
+ rm -f "${tmp}.timeout"
128
+ fi
129
+
130
+ output="$(cat "$tmp")"
131
+ rm -f "$tmp"
132
+
133
+ printf '%s\n' "$rc"
134
+ printf '%s' "$output"
135
+ }
136
+
137
+ (
138
+ started_at=$(date +%s)
139
+ RUN_TIMEOUT_SEC="$(compute_timeout "$MSG")"
140
+ cd "$WORKSPACE" || exit 1
141
+ FULL_MSG="[${CHANNEL}:${TARGET}] $MSG"
142
+
143
+ run_result="$(run_with_timeout --fork "$FULL_MSG")"
144
+ rc="$(printf '%s' "$run_result" | head -n 1)"
145
+ output="$(printf '%s' "$run_result" | tail -n +2)"
146
+ output="$(sanitize_output "$output")"
147
+
148
+ if [ "$rc" -eq 124 ] || [ "$rc" -eq 137 ]; then
149
+ output="OpenCode timed out after ${RUN_TIMEOUT_SEC}s. Task may still be running. Try waiting a bit or send a follow-up."
150
+ elif [ -z "$output" ]; then
151
+ output="OpenCode finished, but returned an empty response."
152
+ elif is_trivial_echo "$output" "$MSG"; then
153
+ output="OpenCode ran, but returned a non-informative echo. Please retry with a more specific prompt."
154
+ fi
155
+
156
+ openclaw message send --channel "$CHANNEL" --target "$TARGET" -m "$output"
157
+
158
+ ended_at=$(date +%s)
159
+ elapsed=$((ended_at - started_at))
160
+ printf '[%s] /ccn completed in %ss (exit=%s timeout=%ss)\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$elapsed" "$rc" "$RUN_TIMEOUT_SEC"
161
+ ) >>"$LOG_FILE" 2>&1 &
162
+
163
+ echo "โœ… OpenCode new session queued."
@@ -1,22 +1,163 @@
1
1
  #!/bin/bash
2
- # bridge-version: 3
3
- # Send instruction to OpenCode and relay response to telegram
2
+ # bridge-version: 5
3
+ # Dispatch instruction to OpenCode asynchronously and relay response
4
4
  MSG="$1"
5
5
  OPENCODE="{{OPENCODE_BIN}}"
6
6
  CHANNEL="{{CHANNEL}}"
7
7
  TARGET="{{TARGET_ID}}"
8
8
  WORKSPACE="{{WORKSPACE}}"
9
+ LOG_FILE="/tmp/opencode-bridge-send.log"
10
+ BASE_TIMEOUT_SEC=45
11
+ MAX_TIMEOUT_SEC=300
9
12
 
10
13
  if [ -z "$MSG" ]; then
11
14
  echo "ERROR: No message provided"
12
15
  exit 1
13
16
  fi
14
17
 
15
- cd "$WORKSPACE"
16
- FULL_MSG="[${CHANNEL}:${TARGET}] $MSG"
18
+ trim_text() {
19
+ local value="$1"
20
+ value="${value#"${value%%[![:space:]]*}"}"
21
+ value="${value%"${value##*[![:space:]]}"}"
22
+ printf '%s' "$value"
23
+ }
17
24
 
18
- OUTPUT=$("$OPENCODE" run --continue "$FULL_MSG" 2>&1)
25
+ normalize_text() {
26
+ printf '%s' "$1" \
27
+ | tr '[:upper:]' '[:lower:]' \
28
+ | sed -E 's/^๐Ÿ”—[[:space:]]*//; s/^["'\''`]+|["'\''`]+$//g; s/[[:space:]]+/ /g; s/^[[:space:]]+|[[:space:]]+$//g'
29
+ }
19
30
 
20
- openclaw message send --channel "$CHANNEL" --target "$TARGET" -m "$OUTPUT"
31
+ compute_timeout() {
32
+ local msg="$1"
33
+ local timeout="$BASE_TIMEOUT_SEC"
34
+ local chars words
21
35
 
22
- echo "โœ… OpenCode response sent."
36
+ chars=${#msg}
37
+ words="$(printf '%s' "$msg" | wc -w | tr -d '[:space:]')"
38
+
39
+ if [ "$chars" -gt 120 ]; then timeout=$((timeout + 15)); fi
40
+ if [ "$chars" -gt 280 ]; then timeout=$((timeout + 20)); fi
41
+ if [ "$words" -gt 25 ]; then timeout=$((timeout + 20)); fi
42
+
43
+ if printf '%s' "$msg" | grep -Eqi '\b(create|build|write|implement|script|code|program|refactor|debug|fix|test|automation|deploy|migrate|api|database|project)\b'; then
44
+ timeout=$((timeout + 60))
45
+ fi
46
+
47
+ if printf '%s' "$msg" | grep -Eqi '\b(from scratch|end[- ]to[- ]end|single file|one file|only 1|complex|demanding)\b'; then
48
+ timeout=$((timeout + 30))
49
+ fi
50
+
51
+ if [ "$timeout" -gt "$MAX_TIMEOUT_SEC" ]; then
52
+ timeout="$MAX_TIMEOUT_SEC"
53
+ fi
54
+
55
+ printf '%s' "$timeout"
56
+ }
57
+
58
+ is_trivial_echo() {
59
+ local output_norm message_norm
60
+ output_norm="$(normalize_text "$1")"
61
+ message_norm="$(normalize_text "$2")"
62
+ [ -n "$message_norm" ] && [ "$output_norm" = "$message_norm" ]
63
+ }
64
+
65
+ extract_embedded_send_message() {
66
+ local raw="$1"
67
+ local line message
68
+
69
+ line="$(printf '%s\n' "$raw" | grep -E 'openclaw message send --channel' | tail -n 1)"
70
+ [ -z "$line" ] && return 0
71
+
72
+ if printf '%s' "$line" | grep -q -- "-m '"; then
73
+ message="$(printf '%s' "$line" | sed -n "s/.* -m '\(.*\)'.*/\1/p")"
74
+ elif printf '%s' "$line" | grep -q -- '-m "'; then
75
+ message="$(printf '%s' "$line" | sed -n 's/.* -m "\(.*\)".*/\1/p')"
76
+ fi
77
+
78
+ printf '%s' "$(trim_text "$message")"
79
+ }
80
+
81
+ sanitize_output() {
82
+ local raw="$1"
83
+ local extracted cleaned
84
+
85
+ extracted="$(extract_embedded_send_message "$raw")"
86
+ if [ -n "$extracted" ]; then
87
+ printf '%s' "$extracted"
88
+ return 0
89
+ fi
90
+
91
+ cleaned="$(printf '%s' "$raw" \
92
+ | tr '\r' '\n' \
93
+ | sed -E $'s/\x1B\\[[0-9;?]*[ -/]*[@-~]//g; s/\x1B\\][^\a]*(\a|\x1B\\\\)//g')"
94
+
95
+ cleaned="$(printf '%s\n' "$cleaned" | grep -Ev \
96
+ '^[[:space:]]*$|^[[:space:]]*(build ยท|โ—‡ Doctor warnings)[[:space:]]*$|^[[:space:]]*openclaw message send --channel[[:space:]]+|^[[:space:]]*Sent via Telegram|^[[:space:]]*\[[0-9]{1,3}m|^[[:space:]]*\[(telegram|discord|slack|whatsapp|signal|irc|matrix|line|mattermost|teams)\]|autoSelectFamily=|dnsResultOrder=|^[[:space:]]*[โ”‚โ”Œโ”โ””โ”˜โ”œโ”คโ”ฌโ”ดโ”ผโ”€โ•โ•ญโ•ฎโ•ฐโ•ฏ]+[[:space:]]*$|^[[:space:]]*\$[[:space:]]*\[[0-9]{1,3}m')"
97
+
98
+ printf '%s' "$(trim_text "$cleaned")"
99
+ }
100
+
101
+ run_with_timeout() {
102
+ local mode="$1"
103
+ local prompt="$2"
104
+ local output rc tmp pid watchdog
105
+
106
+ tmp="$(mktemp /tmp/opencode-run.XXXXXX)"
107
+ "$OPENCODE" run "$mode" "$prompt" >"$tmp" 2>&1 &
108
+ pid=$!
109
+
110
+ (
111
+ sleep "$RUN_TIMEOUT_SEC"
112
+ if kill -0 "$pid" 2>/dev/null; then
113
+ touch "${tmp}.timeout"
114
+ kill "$pid" 2>/dev/null
115
+ sleep 2
116
+ kill -9 "$pid" 2>/dev/null
117
+ fi
118
+ ) &
119
+ watchdog=$!
120
+
121
+ wait "$pid"
122
+ rc=$?
123
+ kill "$watchdog" 2>/dev/null
124
+
125
+ if [ -f "${tmp}.timeout" ]; then
126
+ rc=124
127
+ rm -f "${tmp}.timeout"
128
+ fi
129
+
130
+ output="$(cat "$tmp")"
131
+ rm -f "$tmp"
132
+
133
+ printf '%s\n' "$rc"
134
+ printf '%s' "$output"
135
+ }
136
+
137
+ (
138
+ started_at=$(date +%s)
139
+ RUN_TIMEOUT_SEC="$(compute_timeout "$MSG")"
140
+ cd "$WORKSPACE" || exit 1
141
+ FULL_MSG="[${CHANNEL}:${TARGET}] $MSG"
142
+
143
+ run_result="$(run_with_timeout --continue "$FULL_MSG")"
144
+ rc="$(printf '%s' "$run_result" | head -n 1)"
145
+ output="$(printf '%s' "$run_result" | tail -n +2)"
146
+ output="$(sanitize_output "$output")"
147
+
148
+ if [ "$rc" -eq 124 ] || [ "$rc" -eq 137 ]; then
149
+ output="OpenCode timed out after ${RUN_TIMEOUT_SEC}s. Task may still be running. Try waiting a bit or send a follow-up."
150
+ elif [ -z "$output" ]; then
151
+ output="OpenCode finished, but returned an empty response."
152
+ elif is_trivial_echo "$output" "$MSG"; then
153
+ output="OpenCode ran, but returned a non-informative echo. Please retry with a more specific prompt."
154
+ fi
155
+
156
+ openclaw message send --channel "$CHANNEL" --target "$TARGET" -m "$output"
157
+
158
+ ended_at=$(date +%s)
159
+ elapsed=$((ended_at - started_at))
160
+ printf '[%s] /cc completed in %ss (exit=%s timeout=%ss)\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$elapsed" "$rc" "$RUN_TIMEOUT_SEC"
161
+ ) >>"$LOG_FILE" 2>&1 &
162
+
163
+ echo "โœ… OpenCode request queued."
@@ -17,18 +17,26 @@ The format is: `[CHANNEL:ID] actual message`
17
17
  ### Procedure
18
18
 
19
19
  1. Extract `{CHANNEL}` and `{ID}` from the `[...]` prefix
20
- 2. Ignore everything before `] ` โ€” that is the prefix, not the message
20
+ 2. Ignore everything before `] ` โ€” that is metadata, not user content
21
21
  3. Perform the task described in the actual message
22
- 4. **After completion, send the response via:**
23
- ```bash
24
- openclaw message send --channel {CHANNEL} --target {ID} -m '๐Ÿ”— your response here'
25
- ```
26
- 5. **Every message MUST start with ๐Ÿ”—** โ€” this identifies you as OpenCode
27
- 6. Split messages over 4000 characters into multiple sends (each starts with ๐Ÿ”—)
28
-
29
- ### Response transmission is mandatory (never skip)
30
-
31
- - **Every message MUST receive a response.**
32
- - Ignore the prefix, only respond to the actual message content.
33
- - If the task failed, send the failure reason. If it succeeded, send the result.
34
- - If you did not run `openclaw message send`, the task is **NOT** complete.
22
+ 4. Return only the assistant answer text
23
+
24
+ ### Output rules
25
+
26
+ - Do not output or suggest `openclaw message send` commands.
27
+ - Do not include the `[channel:id]` prefix in your response.
28
+ - Do not prepend delivery markers such as `๐Ÿ”—` unless explicitly requested by the user.
29
+ - If the task fails, return a direct failure reason in plain text.
30
+
31
+ ### Response quality (default)
32
+
33
+ - Be informative and actionable by default. Avoid dry one-line replies for non-trivial work.
34
+ - For create/build/modify tasks, include:
35
+ 1. What was completed
36
+ 2. Main artifact names (files/scripts) or key outputs
37
+ 3. How to run/use the result
38
+ 4. A quick verification step or expected outcome
39
+ - For follow-up status questions such as "have you created it?", do not answer with only yes/no.
40
+ Always include short status details and the run command.
41
+ - Keep tone clear, proactive, and helpful. Prefer concise but complete responses.
42
+ - Length guidance: trivial questions can be 1-2 lines; implementation results should usually be 4-10 lines.