openclaw-opencode-bridge 2.1.0 โ†’ 2.1.2

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.1.0",
3
+ "version": "2.1.2",
4
4
  "description": "Bridge OpenClaw messaging channels to OpenCode via tmux persistent sessions",
5
5
  "main": "./lib/onboard.js",
6
6
  "bin": {
@@ -37,10 +37,10 @@
37
37
  "name": "Febrian",
38
38
  "email": "febro.aw20@gmail.com"
39
39
  },
40
- "homepage": "https://febro.fun",
40
+ "homepage": "http://febro.fun",
41
41
  "license": "MIT",
42
42
  "repository": {
43
43
  "type": "git",
44
- "url": "https://github.com/bettep-dev/openclaw-opencode-bridge"
44
+ "url": "https://github.com/AganFebro/openclaw-opencode-bridge"
45
45
  }
46
46
  }
@@ -1,13 +1,15 @@
1
1
  #!/bin/bash
2
- # bridge-version: 4
2
+ # bridge-version: 6
3
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
- RUN_TIMEOUT_SEC=45
10
9
  LOG_FILE="/tmp/opencode-bridge-send.log"
10
+ BASE_TIMEOUT_SEC=45
11
+ MAX_TIMEOUT_SEC=300
12
+ LOCK_WAIT_SEC=600
11
13
 
12
14
  if [ -z "$MSG" ]; then
13
15
  echo "ERROR: No message provided"
@@ -27,6 +29,48 @@ normalize_text() {
27
29
  | sed -E 's/^๐Ÿ”—[[:space:]]*//; s/^["'\''`]+|["'\''`]+$//g; s/[[:space:]]+/ /g; s/^[[:space:]]+|[[:space:]]+$//g'
28
30
  }
29
31
 
32
+ acquire_bridge_lock() {
33
+ local safe_channel safe_target lock_file
34
+ safe_channel="$(printf '%s' "$CHANNEL" | sed -E 's/[^a-zA-Z0-9._-]/_/g')"
35
+ safe_target="$(printf '%s' "$TARGET" | sed -E 's/[^a-zA-Z0-9._-]/_/g')"
36
+ lock_file="/tmp/opencode-bridge-${safe_channel}-${safe_target}.lock"
37
+
38
+ if command -v flock >/dev/null 2>&1; then
39
+ exec 200>"$lock_file"
40
+ flock -w "$LOCK_WAIT_SEC" 200
41
+ return $?
42
+ fi
43
+
44
+ return 0
45
+ }
46
+
47
+ compute_timeout() {
48
+ local msg="$1"
49
+ local timeout="$BASE_TIMEOUT_SEC"
50
+ local chars words
51
+
52
+ chars=${#msg}
53
+ words="$(printf '%s' "$msg" | wc -w | tr -d '[:space:]')"
54
+
55
+ if [ "$chars" -gt 120 ]; then timeout=$((timeout + 15)); fi
56
+ if [ "$chars" -gt 280 ]; then timeout=$((timeout + 20)); fi
57
+ if [ "$words" -gt 25 ]; then timeout=$((timeout + 20)); fi
58
+
59
+ 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
60
+ timeout=$((timeout + 60))
61
+ fi
62
+
63
+ if printf '%s' "$msg" | grep -Eqi '\b(from scratch|end[- ]to[- ]end|single file|one file|only 1|complex|demanding)\b'; then
64
+ timeout=$((timeout + 30))
65
+ fi
66
+
67
+ if [ "$timeout" -gt "$MAX_TIMEOUT_SEC" ]; then
68
+ timeout="$MAX_TIMEOUT_SEC"
69
+ fi
70
+
71
+ printf '%s' "$timeout"
72
+ }
73
+
30
74
  is_trivial_echo() {
31
75
  local output_norm message_norm
32
76
  output_norm="$(normalize_text "$1")"
@@ -34,40 +78,107 @@ is_trivial_echo() {
34
78
  [ -n "$message_norm" ] && [ "$output_norm" = "$message_norm" ]
35
79
  }
36
80
 
81
+ extract_last_marked_block() {
82
+ local raw="$1"
83
+ if ! printf '%s' "$raw" | grep -q '๐Ÿ”—'; then
84
+ return 0
85
+ fi
86
+
87
+ printf '%s\n' "$raw" | awk '
88
+ {
89
+ pos = index($0, "๐Ÿ”—");
90
+ if (pos > 0) {
91
+ out = substr($0, pos);
92
+ capture = 1;
93
+ next;
94
+ }
95
+ if (capture) {
96
+ out = out "\n" $0;
97
+ }
98
+ }
99
+ END {
100
+ if (capture) print out;
101
+ }'
102
+ }
103
+
104
+ sanitize_output() {
105
+ local raw="$1"
106
+ local cleaned marked
107
+
108
+ cleaned="$(printf '%s' "$raw" \
109
+ | tr '\r' '\n' \
110
+ | sed -E $'s/\x1B\\[[0-9;?]*[ -/]*[@-~]//g; s/\x1B\\][^\a]*(\a|\x1B\\\\)//g')"
111
+
112
+ cleaned="$(printf '%s\n' "$cleaned" | sed -E 's/\[[0-9]{1,3}m//g')"
113
+
114
+ cleaned="$(printf '%s\n' "$cleaned" | grep -Ev \
115
+ '^[[:space:]]*$|^[[:space:]]*(build[[:space:]]*ยท|โ—‡[[:space:]]+Doctor warnings)[[:space:]]*$|^[[:space:]]*โ—‡[[: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
+
117
+ marked="$(extract_last_marked_block "$cleaned")"
118
+ if [ -n "$marked" ]; then
119
+ cleaned="$marked"
120
+ fi
121
+
122
+ cleaned="$(printf '%s\n' "$cleaned" | sed -E 's/^๐Ÿ”—[[:space:]]*//')"
123
+
124
+ printf '%s' "$(trim_text "$cleaned")"
125
+ }
126
+
37
127
  run_with_timeout() {
38
128
  local mode="$1"
39
129
  local prompt="$2"
40
- local output rc
41
-
42
- if command -v timeout >/dev/null 2>&1; then
43
- output=$(timeout "${RUN_TIMEOUT_SEC}s" "$OPENCODE" run "$mode" "$prompt" 2>&1)
44
- rc=$?
45
- elif command -v gtimeout >/dev/null 2>&1; then
46
- output=$(gtimeout "${RUN_TIMEOUT_SEC}s" "$OPENCODE" run "$mode" "$prompt" 2>&1)
47
- rc=$?
48
- else
49
- output=$("$OPENCODE" run "$mode" "$prompt" 2>&1)
50
- rc=$?
130
+ local output rc tmp pid watchdog
131
+
132
+ tmp="$(mktemp /tmp/opencode-run.XXXXXX)"
133
+ "$OPENCODE" run "$mode" "$prompt" >"$tmp" 2>&1 &
134
+ pid=$!
135
+
136
+ (
137
+ sleep "$RUN_TIMEOUT_SEC"
138
+ if kill -0 "$pid" 2>/dev/null; then
139
+ touch "${tmp}.timeout"
140
+ kill "$pid" 2>/dev/null
141
+ sleep 2
142
+ kill -9 "$pid" 2>/dev/null
143
+ fi
144
+ ) &
145
+ watchdog=$!
146
+
147
+ wait "$pid"
148
+ rc=$?
149
+ kill "$watchdog" 2>/dev/null
150
+
151
+ if [ -f "${tmp}.timeout" ]; then
152
+ rc=124
153
+ rm -f "${tmp}.timeout"
51
154
  fi
52
155
 
156
+ output="$(cat "$tmp")"
157
+ rm -f "$tmp"
158
+
53
159
  printf '%s\n' "$rc"
54
160
  printf '%s' "$output"
55
161
  }
56
162
 
57
163
  (
58
164
  started_at=$(date +%s)
165
+ RUN_TIMEOUT_SEC="$(compute_timeout "$MSG")"
59
166
  cd "$WORKSPACE" || exit 1
60
167
  FULL_MSG="[${CHANNEL}:${TARGET}] $MSG"
61
168
 
169
+ if ! acquire_bridge_lock; then
170
+ openclaw message send --channel "$CHANNEL" --target "$TARGET" -m "Bridge is still processing a previous request. Please retry in a moment."
171
+ printf '[%s] /ccn lock timeout after %ss\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$LOCK_WAIT_SEC"
172
+ exit 0
173
+ fi
174
+
62
175
  run_result="$(run_with_timeout --fork "$FULL_MSG")"
63
176
  rc="$(printf '%s' "$run_result" | head -n 1)"
64
177
  output="$(printf '%s' "$run_result" | tail -n +2)"
65
-
66
- output="$(printf '%s\n' "$output" | sed -E '/^[[:space:]]*openclaw message send --channel[[:space:]]+/d')"
67
- output="$(trim_text "$output")"
178
+ output="$(sanitize_output "$output")"
68
179
 
69
180
  if [ "$rc" -eq 124 ] || [ "$rc" -eq 137 ]; then
70
- output="OpenCode timed out after ${RUN_TIMEOUT_SEC}s. Please retry with a narrower request."
181
+ output="OpenCode timed out after ${RUN_TIMEOUT_SEC}s. Task may still be running. Try waiting a bit or send a follow-up."
71
182
  elif [ -z "$output" ]; then
72
183
  output="OpenCode finished, but returned an empty response."
73
184
  elif is_trivial_echo "$output" "$MSG"; then
@@ -78,7 +189,7 @@ run_with_timeout() {
78
189
 
79
190
  ended_at=$(date +%s)
80
191
  elapsed=$((ended_at - started_at))
81
- printf '[%s] /ccn completed in %ss (exit=%s)\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$elapsed" "$rc"
192
+ printf '[%s] /ccn completed in %ss (exit=%s timeout=%ss)\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$elapsed" "$rc" "$RUN_TIMEOUT_SEC"
82
193
  ) >>"$LOG_FILE" 2>&1 &
83
194
 
84
195
  echo "โœ… OpenCode new session queued."
@@ -1,13 +1,15 @@
1
1
  #!/bin/bash
2
- # bridge-version: 4
2
+ # bridge-version: 6
3
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
- RUN_TIMEOUT_SEC=45
10
9
  LOG_FILE="/tmp/opencode-bridge-send.log"
10
+ BASE_TIMEOUT_SEC=45
11
+ MAX_TIMEOUT_SEC=300
12
+ LOCK_WAIT_SEC=600
11
13
 
12
14
  if [ -z "$MSG" ]; then
13
15
  echo "ERROR: No message provided"
@@ -27,6 +29,48 @@ normalize_text() {
27
29
  | sed -E 's/^๐Ÿ”—[[:space:]]*//; s/^["'\''`]+|["'\''`]+$//g; s/[[:space:]]+/ /g; s/^[[:space:]]+|[[:space:]]+$//g'
28
30
  }
29
31
 
32
+ acquire_bridge_lock() {
33
+ local safe_channel safe_target lock_file
34
+ safe_channel="$(printf '%s' "$CHANNEL" | sed -E 's/[^a-zA-Z0-9._-]/_/g')"
35
+ safe_target="$(printf '%s' "$TARGET" | sed -E 's/[^a-zA-Z0-9._-]/_/g')"
36
+ lock_file="/tmp/opencode-bridge-${safe_channel}-${safe_target}.lock"
37
+
38
+ if command -v flock >/dev/null 2>&1; then
39
+ exec 200>"$lock_file"
40
+ flock -w "$LOCK_WAIT_SEC" 200
41
+ return $?
42
+ fi
43
+
44
+ return 0
45
+ }
46
+
47
+ compute_timeout() {
48
+ local msg="$1"
49
+ local timeout="$BASE_TIMEOUT_SEC"
50
+ local chars words
51
+
52
+ chars=${#msg}
53
+ words="$(printf '%s' "$msg" | wc -w | tr -d '[:space:]')"
54
+
55
+ if [ "$chars" -gt 120 ]; then timeout=$((timeout + 15)); fi
56
+ if [ "$chars" -gt 280 ]; then timeout=$((timeout + 20)); fi
57
+ if [ "$words" -gt 25 ]; then timeout=$((timeout + 20)); fi
58
+
59
+ 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
60
+ timeout=$((timeout + 60))
61
+ fi
62
+
63
+ if printf '%s' "$msg" | grep -Eqi '\b(from scratch|end[- ]to[- ]end|single file|one file|only 1|complex|demanding)\b'; then
64
+ timeout=$((timeout + 30))
65
+ fi
66
+
67
+ if [ "$timeout" -gt "$MAX_TIMEOUT_SEC" ]; then
68
+ timeout="$MAX_TIMEOUT_SEC"
69
+ fi
70
+
71
+ printf '%s' "$timeout"
72
+ }
73
+
30
74
  is_trivial_echo() {
31
75
  local output_norm message_norm
32
76
  output_norm="$(normalize_text "$1")"
@@ -34,40 +78,107 @@ is_trivial_echo() {
34
78
  [ -n "$message_norm" ] && [ "$output_norm" = "$message_norm" ]
35
79
  }
36
80
 
81
+ extract_last_marked_block() {
82
+ local raw="$1"
83
+ if ! printf '%s' "$raw" | grep -q '๐Ÿ”—'; then
84
+ return 0
85
+ fi
86
+
87
+ printf '%s\n' "$raw" | awk '
88
+ {
89
+ pos = index($0, "๐Ÿ”—");
90
+ if (pos > 0) {
91
+ out = substr($0, pos);
92
+ capture = 1;
93
+ next;
94
+ }
95
+ if (capture) {
96
+ out = out "\n" $0;
97
+ }
98
+ }
99
+ END {
100
+ if (capture) print out;
101
+ }'
102
+ }
103
+
104
+ sanitize_output() {
105
+ local raw="$1"
106
+ local cleaned marked
107
+
108
+ cleaned="$(printf '%s' "$raw" \
109
+ | tr '\r' '\n' \
110
+ | sed -E $'s/\x1B\\[[0-9;?]*[ -/]*[@-~]//g; s/\x1B\\][^\a]*(\a|\x1B\\\\)//g')"
111
+
112
+ cleaned="$(printf '%s\n' "$cleaned" | sed -E 's/\[[0-9]{1,3}m//g')"
113
+
114
+ cleaned="$(printf '%s\n' "$cleaned" | grep -Ev \
115
+ '^[[:space:]]*$|^[[:space:]]*(build[[:space:]]*ยท|โ—‡[[:space:]]+Doctor warnings)[[:space:]]*$|^[[:space:]]*โ—‡[[: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
+
117
+ marked="$(extract_last_marked_block "$cleaned")"
118
+ if [ -n "$marked" ]; then
119
+ cleaned="$marked"
120
+ fi
121
+
122
+ cleaned="$(printf '%s\n' "$cleaned" | sed -E 's/^๐Ÿ”—[[:space:]]*//')"
123
+
124
+ printf '%s' "$(trim_text "$cleaned")"
125
+ }
126
+
37
127
  run_with_timeout() {
38
128
  local mode="$1"
39
129
  local prompt="$2"
40
- local output rc
41
-
42
- if command -v timeout >/dev/null 2>&1; then
43
- output=$(timeout "${RUN_TIMEOUT_SEC}s" "$OPENCODE" run "$mode" "$prompt" 2>&1)
44
- rc=$?
45
- elif command -v gtimeout >/dev/null 2>&1; then
46
- output=$(gtimeout "${RUN_TIMEOUT_SEC}s" "$OPENCODE" run "$mode" "$prompt" 2>&1)
47
- rc=$?
48
- else
49
- output=$("$OPENCODE" run "$mode" "$prompt" 2>&1)
50
- rc=$?
130
+ local output rc tmp pid watchdog
131
+
132
+ tmp="$(mktemp /tmp/opencode-run.XXXXXX)"
133
+ "$OPENCODE" run "$mode" "$prompt" >"$tmp" 2>&1 &
134
+ pid=$!
135
+
136
+ (
137
+ sleep "$RUN_TIMEOUT_SEC"
138
+ if kill -0 "$pid" 2>/dev/null; then
139
+ touch "${tmp}.timeout"
140
+ kill "$pid" 2>/dev/null
141
+ sleep 2
142
+ kill -9 "$pid" 2>/dev/null
143
+ fi
144
+ ) &
145
+ watchdog=$!
146
+
147
+ wait "$pid"
148
+ rc=$?
149
+ kill "$watchdog" 2>/dev/null
150
+
151
+ if [ -f "${tmp}.timeout" ]; then
152
+ rc=124
153
+ rm -f "${tmp}.timeout"
51
154
  fi
52
155
 
156
+ output="$(cat "$tmp")"
157
+ rm -f "$tmp"
158
+
53
159
  printf '%s\n' "$rc"
54
160
  printf '%s' "$output"
55
161
  }
56
162
 
57
163
  (
58
164
  started_at=$(date +%s)
165
+ RUN_TIMEOUT_SEC="$(compute_timeout "$MSG")"
59
166
  cd "$WORKSPACE" || exit 1
60
167
  FULL_MSG="[${CHANNEL}:${TARGET}] $MSG"
61
168
 
169
+ if ! acquire_bridge_lock; then
170
+ openclaw message send --channel "$CHANNEL" --target "$TARGET" -m "Bridge is still processing a previous request. Please retry in a moment."
171
+ printf '[%s] /cc lock timeout after %ss\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$LOCK_WAIT_SEC"
172
+ exit 0
173
+ fi
174
+
62
175
  run_result="$(run_with_timeout --continue "$FULL_MSG")"
63
176
  rc="$(printf '%s' "$run_result" | head -n 1)"
64
177
  output="$(printf '%s' "$run_result" | tail -n +2)"
65
-
66
- output="$(printf '%s\n' "$output" | sed -E '/^[[:space:]]*openclaw message send --channel[[:space:]]+/d')"
67
- output="$(trim_text "$output")"
178
+ output="$(sanitize_output "$output")"
68
179
 
69
180
  if [ "$rc" -eq 124 ] || [ "$rc" -eq 137 ]; then
70
- output="OpenCode timed out after ${RUN_TIMEOUT_SEC}s. Please retry with a narrower request."
181
+ output="OpenCode timed out after ${RUN_TIMEOUT_SEC}s. Task may still be running. Try waiting a bit or send a follow-up."
71
182
  elif [ -z "$output" ]; then
72
183
  output="OpenCode finished, but returned an empty response."
73
184
  elif is_trivial_echo "$output" "$MSG"; then
@@ -78,7 +189,7 @@ run_with_timeout() {
78
189
 
79
190
  ended_at=$(date +%s)
80
191
  elapsed=$((ended_at - started_at))
81
- printf '[%s] /cc completed in %ss (exit=%s)\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$elapsed" "$rc"
192
+ printf '[%s] /cc completed in %ss (exit=%s timeout=%ss)\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$elapsed" "$rc" "$RUN_TIMEOUT_SEC"
82
193
  ) >>"$LOG_FILE" 2>&1 &
83
194
 
84
195
  echo "โœ… OpenCode request queued."
@@ -27,3 +27,16 @@ The format is: `[CHANNEL:ID] actual message`
27
27
  - Do not include the `[channel:id]` prefix in your response.
28
28
  - Do not prepend delivery markers such as `๐Ÿ”—` unless explicitly requested by the user.
29
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.