1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
use ;
/// v0.18 streaming semantics for hoisted bash.
///
/// Foreground `bash` execution may emit zero or more `progress` frames before
/// its final `Response`. Each progress frame is NDJSON on stdout with the same
/// `request_id` as the original request and a `kind` of `stdout` or `stderr`.
/// The final response remains the existing `{ id, success, ... }` envelope so
/// older callers can ignore streaming frames. Bash permission prompts use the
/// recognized `permission_required` error code; Phase 1 Track C will attach the
/// full permission ask payload and retry loop.
pub const ERROR_PERMISSION_REQUIRED: &str = "permission_required";
/// Fallback session identifier used when a request arrives without one.
///
/// Introduced alongside project-shared bridges (issue #14): one `aft` process
/// can now serve many OpenCode sessions in the same project. Undo/checkpoint
/// state is partitioned by session inside Rust, but callers that haven't been
/// updated to pass `session_id` (older plugins, direct CLI usage, tests) still
/// need to work — they share this default namespace.
///
/// Also used as the migration target for legacy pre-session backups on disk.
pub const DEFAULT_SESSION_ID: &str = "__default__";
/// Inbound request envelope.
///
/// Two-stage parse: deserialize this first to get `id` + `command`, then
/// dispatch on `command` and pull specific params from the flattened `params`.
/// Outbound response envelope.
///
/// `data` is flattened into the top-level JSON object, so a response like
/// `Response { id: "1", success: true, data: json!({"command": "pong"}) }`
/// serializes to `{"id":"1","success":true,"command":"pong"}`.
///
/// # Honest reporting convention (tri-state)
///
/// Tools that search, check, or otherwise produce results MUST follow this
/// convention so agents can distinguish "did the work, found nothing" from
/// "couldn't do the work" from "partially did the work":
///
/// 1. **`success: false`** — the requested work could not be performed.
/// Includes a `code` (e.g., `"path_not_found"`, `"no_lsp_server"`,
/// `"project_too_large"`) and a human-readable `message`. The agent
/// should treat this as an error and read the message.
///
/// 2. **`success: true` + completion signaling** — the work was performed.
/// Tools must report whether the result is *complete* OR which subset
/// was actually performed. Conventional fields:
/// - `complete: true` — full result, agent can trust absence of items
/// - `complete: false` + `pending_files: [...]` / `unchecked_files: [...]`
/// / `scope_warnings: [...]` — partial result, with named gaps
/// - `removed: true|false` (for mutations) — did the file actually change
/// - `skipped_files: [{file, reason}]` — files we couldn't process inside
/// the requested scope
/// - `no_files_matched_scope: bool` — the scope (path/glob) found zero
/// candidates (distinct from "candidates found, no matches")
///
/// 3. **Side-effect skip codes** — when the main work succeeded but a
/// non-essential side step was skipped (e.g., post-write formatting),
/// use a `<step>_skipped_reason` field. Approved values:
/// - `format_skipped_reason`: `"unsupported_language"` |
/// `"no_formatter_configured"` | `"formatter_not_installed"` |
/// `"timeout"` | `"error"`
/// - `validate_skipped_reason`: `"unsupported_language"` |
/// `"no_checker_configured"` | `"checker_not_installed"` |
/// `"timeout"` | `"error"`
///
/// **Anti-patterns to avoid:**
/// - Returning `success: true` with empty results when the scope didn't
/// resolve to any files — agent reads as "all clear" but really nothing
/// was checked. Use `no_files_matched_scope: true` or
/// `success: false, code: "path_not_found"`.
/// - Reusing `format_skipped_reason: "not_found"` for two different causes
/// ("no formatter configured" vs "configured formatter binary missing").
/// The agent can't act on the ambiguous code.
///
/// See ARCHITECTURE.md "Honest reporting convention" for the full rationale.
/// Parameters for the `echo` command.