@awebai/oats 0.40.2 → 0.41.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/bin/oats.mjs +39 -12
- package/docs/capabilities.md +9 -1
- package/docs/desktop-cli-api.md +58 -16
- package/docs/desktop.md +5 -4
- package/docs/execution-targets.md +312 -9
- package/docs/implementation.md +37 -6
- package/docs/release-notes/v0.41.0.md +238 -0
- package/docs/release-notes/v0.41.1.md +7 -0
- package/docs/servers.md +4 -1
- package/docs/souls-and-instances.md +32 -6
- package/lib/core.mjs +552 -165
- package/lib/instance-git.mjs +113 -4
- package/lib/instance-lifecycle.mjs +3 -2
- package/lib/packages.mjs +1 -1
- package/lib/resolve.mjs +1 -1
- package/lib/servers.mjs +16 -8
- package/package.json +1 -1
|
@@ -55,11 +55,311 @@ inspect`. A recorded server that cannot be read gives `running: null` with
|
|
|
55
55
|
`runtimeState: "unreachable"`. The environment variables are read when the spawn runs, and `oats
|
|
56
56
|
inspect --json` reports the session a new spawn would open in as `session`
|
|
57
57
|
(`{tmuxSession}`). A spawn refuses an instance name that is a live window in the
|
|
58
|
-
session it would open in (`E_INSTANCE_NAME_TAKEN`); a
|
|
59
|
-
in another session, such as a `pi-agents` window
|
|
60
|
-
|
|
61
|
-
the two never mix. The
|
|
62
|
-
session, window and socket. The spawn result prints the
|
|
58
|
+
session it would open in, on the OATS tmux server (`E_INSTANCE_NAME_TAKEN`); a
|
|
59
|
+
live window of that name in another session, such as a `pi-agents` window
|
|
60
|
+
after the default moved, or on another tmux server, does not block it. Session
|
|
61
|
+
commands target each home's exact recorded window, so the two never mix. The
|
|
62
|
+
receipt records the session, window and socket. The spawn result prints the
|
|
63
|
+
attach command.
|
|
64
|
+
|
|
65
|
+
<a id="the-oats-tmux-server"></a>
|
|
66
|
+
#### The OATS tmux server
|
|
67
|
+
|
|
68
|
+
OATS creates sessions on a tmux server of its own, named `oats`
|
|
69
|
+
(`tmux -L oats`), not on your default tmux server, where earlier kernels
|
|
70
|
+
created them. A tool that restyles the
|
|
71
|
+
default server (a theme switcher, a script that runs `tmux set -g …` or
|
|
72
|
+
`tmux kill-server`) therefore no longer reaches agent terminals.
|
|
73
|
+
|
|
74
|
+
- **Where it is.** The server's socket is
|
|
75
|
+
`${TMUX_TMPDIR:-/tmp}/tmux-<uid>/oats`. The instance records the absolute
|
|
76
|
+
socket path it was created on, in `instance.json` and in the receipt, and
|
|
77
|
+
every later command uses that recorded path, never the name. OATS does not
|
|
78
|
+
compute the socket path and does not use `TMUX` to find a server: tmux
|
|
79
|
+
resolves the name once, when the session is ensured, from the
|
|
80
|
+
`TMUX_TMPDIR` of the process that runs OATS, which OATS passes on unchanged
|
|
81
|
+
when it replaces the environment for that call.
|
|
82
|
+
- **Your configuration loads.** The server starts as any tmux server does, so
|
|
83
|
+
your `~/.tmux.conf` (key bindings, status line, options) applies to it.
|
|
84
|
+
- **See what runs there:** `tmux -L oats ls`. Plain `tmux ls` and a bare
|
|
85
|
+
`tmux attach` show your default server, so they do not show the sessions
|
|
86
|
+
OATS creates now.
|
|
87
|
+
- **Attach:** `oats session attach --home <home>`. By hand, copy the
|
|
88
|
+
`attach:` line that spawn prints: `tmux -S <socket> attach -t <session>`,
|
|
89
|
+
with the recorded socket. `tmux -L oats attach -t <session>` is a
|
|
90
|
+
convenience that holds only in an environment with the same `TMUX_TMPDIR`
|
|
91
|
+
as the one that created the session.
|
|
92
|
+
- **`TMUX_TMPDIR`.** Two environments with different values (a login shell,
|
|
93
|
+
and a process started by a service manager or launchd, a schedule runner or
|
|
94
|
+
a GUI launch) each get their own `oats` server. Every instance stays
|
|
95
|
+
reachable, because its absolute socket is recorded.
|
|
96
|
+
- **A limit.** A tool that runs inside a pane of the OATS server has `TMUX`
|
|
97
|
+
pointing at that server and still reaches it.
|
|
98
|
+
|
|
99
|
+
**What OATS sets, and at which scope.** OATS sets nothing server-global on any
|
|
100
|
+
server when it creates a session or a window, and nothing at all on a server
|
|
101
|
+
other than the one the window is on.
|
|
102
|
+
|
|
103
|
+
| On | OATS sets | Scope |
|
|
104
|
+
|---|---|---|
|
|
105
|
+
| each agent window it creates | `window-style default`, `window-active-style default`, `cursor-colour default` | that window (`set-option -w`), by window id |
|
|
106
|
+
| each agent window, and the `hq` window of a session it creates | `window-size latest`, `aggressive-resize on` | that window |
|
|
107
|
+
| the pane of each window it launches a harness in, and a pane it respawns in place | no `COLORFGBG` in the pane's environment | that pane's command |
|
|
108
|
+
|
|
109
|
+
So an agent pane takes the colours of the terminal that views it, whatever
|
|
110
|
+
the server's own defaults say, and on tmux 3.1 or later the window follows
|
|
111
|
+
the size of the viewer that used it last. A window that is restarted in place
|
|
112
|
+
keeps the options it has. A session OATS did not create, and the server's global
|
|
113
|
+
options and environment, are left exactly as they were.
|
|
114
|
+
|
|
115
|
+
- `pane-colours` (the palette) is not reset: a local reset did not neutralise
|
|
116
|
+
inherited array entries, so OATS leaves the palette alone. A configuration
|
|
117
|
+
that sets `pane-colours` globally therefore reaches agent panes. It comes
|
|
118
|
+
from your own tmux configuration, which OATS loads on purpose: remove the
|
|
119
|
+
setting there, or unset it on the running server with `tmux -L oats
|
|
120
|
+
set-option -gu pane-colours`.
|
|
121
|
+
- The oldest supported tmux stays 3.0. On tmux 3.0 and 3.0a `window-size
|
|
122
|
+
latest` is not available and is skipped, as before this change;
|
|
123
|
+
`cursor-colour` is skipped below 3.3; no error in either case. On 3.0 and
|
|
124
|
+
3.0a the window therefore keeps the sizing that server gives it, not the
|
|
125
|
+
latest viewer's.
|
|
126
|
+
- The two sizing commands are each attempted on their own, and a refused one
|
|
127
|
+
is ignored: the launch goes on. Nothing else is tolerated: a refused
|
|
128
|
+
`window-style` or `window-active-style` is a launch failure (the spawn is
|
|
129
|
+
rolled back and fails; a start fails with `E_SESSION_START_FAILED`). An
|
|
130
|
+
earlier kernel failed a start whose recorded tmux server could not be
|
|
131
|
+
reached when a sizing command was refused; this one does not.
|
|
132
|
+
|
|
133
|
+
<a id="the-servers-start-environment"></a>
|
|
134
|
+
#### The environment of the server and its panes
|
|
135
|
+
|
|
136
|
+
A tmux server keeps the environment of the process that started it, as its
|
|
137
|
+
global environment. A pane gets that, plus its session's environment (the
|
|
138
|
+
variables tmux's `update-environment` names, taken from whoever created the
|
|
139
|
+
session), plus what the launch command sets (`OATS_INSTANCE`,
|
|
140
|
+
`OATS_INSTANCE_HOME`, the capabilities' and the launch configuration's
|
|
141
|
+
variables). One variable is different: **a pane's `PATH` is the `PATH` of the
|
|
142
|
+
process that creates its window**, that is of each `oats spawn` or `oats
|
|
143
|
+
session start`, with the home's own `oats` shim put first by the launch
|
|
144
|
+
command. So:
|
|
145
|
+
|
|
146
|
+
- `PATH` follows the process that runs each spawn or start, not whoever
|
|
147
|
+
started the server.
|
|
148
|
+
- The rest of the ambient environment follows the server's first creator,
|
|
149
|
+
and a server that already runs keeps what it started with. Creating a
|
|
150
|
+
session or a window on it changes nothing global.
|
|
151
|
+
|
|
152
|
+
Who starts the `oats` server, after an install, a reboot or its last session
|
|
153
|
+
ending, decides that ambient environment:
|
|
154
|
+
|
|
155
|
+
| Started by | The server's environment |
|
|
156
|
+
|---|---|
|
|
157
|
+
| an operator's shell | that shell's |
|
|
158
|
+
| the Desktop | your environment as the Desktop got it, without what the Desktop or its packaging added to its own, and with the login-shell `PATH` it puts in front ([desktop.md](desktop.md)) |
|
|
159
|
+
| a schedule runner or a trigger | the service's |
|
|
160
|
+
| an OATS instance that creates an agents' session | the global environment of the tmux server that instance's home records, reduced as described below; not the instance's own |
|
|
161
|
+
|
|
162
|
+
The first creator that succeeds determines it; when two start it at the same
|
|
163
|
+
moment, tmux starts one server and nothing says which of the two it is.
|
|
164
|
+
|
|
165
|
+
**What OATS removes, for every creator.** The names the kernel itself sets
|
|
166
|
+
never go into the environment OATS creates an agents' session or window
|
|
167
|
+
with: `COLORFGBG`, `TMUX`, `TMUX_PANE`; the launch identity and roots
|
|
168
|
+
(`OATS_INSTANCE`, `OATS_INSTANCE_HOME`, `OATS_HOME`, `OATS_AGENT`,
|
|
169
|
+
`OATS_SOUL`, `OATS_SOUL_ID`, `OATS_ROOT`, `OATS_CONTEXT`, `OATS_WORKSPACE`,
|
|
170
|
+
`OATS_EVENT`, `OATS_SETTINGS`, `OATS_SETTINGS_ORIGINS`, `OATS_CLI_BIN`,
|
|
171
|
+
`PI_AGENT_INSTANCE`, `PI_AGENT_HOME`, `PI_AGENTS_ROOT`); what a hook, an
|
|
172
|
+
operation, a retire or a trigger is given (`OATS_CAPABILITY`, `OATS_LAYER`,
|
|
173
|
+
`OATS_LEVEL`, `OATS_META`, `OATS_DEPLOYMENT`, `OATS_RESOLUTION`,
|
|
174
|
+
`OATS_OPERATION`, `OATS_REPO`, `OATS_BRANCH`, `OATS_WORK`, `OATS_KIND`,
|
|
175
|
+
`OATS_TASK`, `OATS_HARNESS`, `OATS_PREVIOUS_HARNESS`, `OATS_RUNTIME`,
|
|
176
|
+
`OATS_PREVIOUS_RUNTIME`, `OATS_LAUNCH_PREVIEW`, `OATS_RETIRE_INTENT`,
|
|
177
|
+
`OATS_TRIGGER_EVENT_FILE`, `OATS_TEAM_NAME`, `OATS_TEAM_SCOPE`,
|
|
178
|
+
`OATS_TEAM_ID`, `OATS_TEAM_LABEL`, `OATS_TEAM_LABELS`, `OATS_TEAMS`,
|
|
179
|
+
`OATS_TEAMS_SOURCE`, `OATS_DEFAULT_TEAM`, `OATS_DEFAULT_TEAM_ID`,
|
|
180
|
+
`OATS_DEFAULT_TEAM_FROM`, `OATS_WORKSPACE_NAME`, `OATS_WORKSPACE_KEY`); and
|
|
181
|
+
every launch reference (`OATS_LAUNCH_REF_<NAME>`) with the `<NAME>` it stands
|
|
182
|
+
for. Other `OATS_` variables you export (`OATS_HOME_DIR`,
|
|
183
|
+
`OATS_TMUX_SESSION`) are yours and stay. An agent's plain `oats` finds its
|
|
184
|
+
deployment from its home.
|
|
185
|
+
|
|
186
|
+
**An instance creates an agents' session or window without its own
|
|
187
|
+
environment.** Nothing of an instance's environment reaches a server or a
|
|
188
|
+
pane through the calls that create an agents' session or window. A harness
|
|
189
|
+
puts its own variables, credentials and identity into the environment of
|
|
190
|
+
what it runs. A process is inside an instance when `OATS_INSTANCE_HOME` names an instance
|
|
191
|
+
home, or its working directory is inside one. That covers an agent that
|
|
192
|
+
spawns or starts another instance, a capability hook that spawns or starts
|
|
193
|
+
(a hook runs with its instance's identity, also when a person ran the command
|
|
194
|
+
that triggered it), and `oats schedule run-now` typed inside an instance.
|
|
195
|
+
|
|
196
|
+
- When such a process has to create the tmux session, OATS reads the global
|
|
197
|
+
environment of the server its home records (`tmux -S <recorded socket>
|
|
198
|
+
show-environment -g -s`, the endpoint of the home's receipt, checked
|
|
199
|
+
against `instance.json` as every session command checks it) and creates
|
|
200
|
+
the session with that. What the new session gets is a reduction of that
|
|
201
|
+
environment, not an exact copy. It is read strictly and never run by a
|
|
202
|
+
shell; text that cannot be read to its end is a failed read. Not carried
|
|
203
|
+
from the recorded server:
|
|
204
|
+
- a hidden or removed variable;
|
|
205
|
+
- a variable whose value holds a line break;
|
|
206
|
+
- a variable whose value holds a `$`: tmux versions print it differently,
|
|
207
|
+
so OATS does not guess what the value was;
|
|
208
|
+
- on tmux 3.4 and 3.5, a variable whose value holds a control character or
|
|
209
|
+
a byte that is not UTF-8, which those versions print encoded. Other
|
|
210
|
+
versions print the line as it is: there a control character other than
|
|
211
|
+
a line break is carried exactly, and a byte that is not UTF-8 fails the
|
|
212
|
+
read.
|
|
213
|
+
|
|
214
|
+
Such a variable is absent in the panes of the new server unless the pane's
|
|
215
|
+
own shell start-up files set it; it is never filled in from the instance's
|
|
216
|
+
own environment. When the variable left out is one that decides which
|
|
217
|
+
configuration a tmux server loads or which programs it runs (`HOME`,
|
|
218
|
+
`XDG_CONFIG_HOME`, `PATH`, `SHELL`), the creation is refused instead, with
|
|
219
|
+
the same remedy as below.
|
|
220
|
+
- When it creates a window in a session that exists, the tmux client that
|
|
221
|
+
creates it runs with `PATH`, without any instance's `oats` shim directory,
|
|
222
|
+
and with `LANG`, `LC_ALL` and `LC_CTYPE`, which that client needs to start
|
|
223
|
+
on a host whose only UTF-8 locale is the one they name. tmux hands a pane
|
|
224
|
+
the `PATH` of that client and nothing else of it: the three locale names
|
|
225
|
+
stay with the client, and the pane, the session and the server keep the
|
|
226
|
+
values they had. Nothing else of the instance travels. When the instance
|
|
227
|
+
has no `PATH` to give (none is set, or only `oats` shim directories were
|
|
228
|
+
in it), none is passed: the pane then takes no `PATH` from the client. A
|
|
229
|
+
restart that reuses the pane the home already has runs its tmux client
|
|
230
|
+
with the same environment; where and whether the pane is reused does not
|
|
231
|
+
change.
|
|
232
|
+
- **It is refused** (`E_RUNTIME_ENDPOINT_UNKNOWN`; `oats spawn` reports it
|
|
233
|
+
as `E_SPAWN_FAILED` with the same message) when the session does not exist
|
|
234
|
+
on the `oats` server and there is no source to read: the home records no
|
|
235
|
+
tmux server (it was never launched), its receipt cannot be used, or its
|
|
236
|
+
recorded server cannot be reached or read. A process that carries an
|
|
237
|
+
instance's identity (`OATS_INSTANCE`, `OATS_INSTANCE_HOME`, `OATS_HOME`,
|
|
238
|
+
`PI_AGENT_INSTANCE` or `PI_AGENT_HOME`) with no home to be found is refused
|
|
239
|
+
the same way. Nothing falls back to the caller's environment, to another
|
|
240
|
+
server or to a built-in list.
|
|
241
|
+
- **When the refusal comes.** In `oats spawn`: before any scaffold, work
|
|
242
|
+
tree, identity or hook. In `oats session start`: after the start's
|
|
243
|
+
preflights and its planning, and before the real run of preview-aware
|
|
244
|
+
launch hooks, a stop and any write of the home's launch state (its record,
|
|
245
|
+
its receipt, a pending start). A launch hook that does not declare
|
|
246
|
+
`launchPreview` has already run by then, and a warning it returned is
|
|
247
|
+
already a `launch-warning` event of the home, as before any other late
|
|
248
|
+
refusal of a start (`E_SESSION_RUNNING`, `E_LAUNCH_ENV_MISSING`). Nothing
|
|
249
|
+
undoes what that hook did, and there is nothing to clean up: a launch hook
|
|
250
|
+
may do idempotent provider registration on a real start and no more
|
|
251
|
+
([capabilities.md](capabilities.md)), so the next start repeats it
|
|
252
|
+
harmlessly. Both launch hooks OATS ships are preview-aware. If the
|
|
253
|
+
session disappears between that check and the creation, the refusal comes
|
|
254
|
+
at the creation, and the spawn is rolled back as any failed launch is.
|
|
255
|
+
- **The remedy** is to create the session from your own shell, outside every
|
|
256
|
+
instance home, as below. The session name matters: it must be the
|
|
257
|
+
deployment's (the refusal names it); another deployment's session on the
|
|
258
|
+
same server does not help. Once the session exists, the instance spawns
|
|
259
|
+
and starts there without reading anything.
|
|
260
|
+
- The recorded server's environment is an existing baseline, chosen because
|
|
261
|
+
it is what a window that instance opened on that server got. It is not
|
|
262
|
+
proof that it holds no old identity or credential, and this is not a
|
|
263
|
+
promise that secrets are isolated between instances that run as the same
|
|
264
|
+
user on one tmux server.
|
|
265
|
+
- A server that already runs keeps its baseline. OATS creates sessions and
|
|
266
|
+
windows on it and does not certify where that baseline came from or that
|
|
267
|
+
it is clean: someone who started a server named `oats` by other means
|
|
268
|
+
decided it.
|
|
269
|
+
- These rules are about the calls that create an agents' session or window,
|
|
270
|
+
nothing wider. `oats session attach` creates a temporary viewer session on
|
|
271
|
+
the server the home records, with the attaching process's own environment
|
|
272
|
+
([#623](https://github.com/awebai/oats/issues/623)): tmux imports the
|
|
273
|
+
`update-environment` names into that temporary session, and if that
|
|
274
|
+
server exits between the viewer's check and its creation, the attaching
|
|
275
|
+
process is the one that starts it.
|
|
276
|
+
- Which server is reached is decided by the process that creates, never by
|
|
277
|
+
the environment it passes: its own `tmux`, its own `TMUX_TMPDIR`, and the
|
|
278
|
+
socket the lookup returned when the server runs. Its own `tmux` is the one
|
|
279
|
+
its own `PATH` finds, and the session is created by that program's full
|
|
280
|
+
path. A process whose `PATH` holds no tmux cannot read the server at all:
|
|
281
|
+
it is refused (`E_RUNTIME_ENDPOINT_UNKNOWN`) whether or not the session
|
|
282
|
+
exists, and told to run the command with a `PATH` that holds tmux. A
|
|
283
|
+
process whose `PATH` is not set is refused only when it has to create the
|
|
284
|
+
session (tmux used to be found by the system's default search then); with
|
|
285
|
+
the session already there, it is not refused. What the server process
|
|
286
|
+
gets (`HOME` and so which configuration loads, `PATH`, everything else)
|
|
287
|
+
comes from the passed environment alone. The global environment of the
|
|
288
|
+
server the session is created on is never read for this and never changed;
|
|
289
|
+
the one that is read is the recorded server's, as above.
|
|
290
|
+
|
|
291
|
+
A process that neither sign identifies as an instance is treated as any
|
|
292
|
+
other creator: its environment, without the names above, is what it passes.
|
|
293
|
+
|
|
294
|
+
By hand (`<session>` is the deployment's session name: `oats-agents` unless
|
|
295
|
+
`session.tmuxSession` or `OATS_TMUX_SESSION` says otherwise):
|
|
296
|
+
|
|
297
|
+
```sh
|
|
298
|
+
tmux -L oats new-session -d -s <session> -n hq # start it from your own shell, before anything else does
|
|
299
|
+
tmux -L oats show-environment -g # what environment the server has
|
|
300
|
+
tmux -L oats show-environment -g LANG # one variable
|
|
301
|
+
tmux -L oats set-environment -g LANG "$LANG" # repair a running server: windows created from now on inherit it
|
|
302
|
+
tmux -L oats kill-server # replace it: ends EVERY session on that server
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
- Start it yourself after an upgrade or a reboot, before agents, the Desktop
|
|
306
|
+
or a schedule run. OATS finds a session you created and uses it: it looks
|
|
307
|
+
the session up by its exact name and assumes nothing about its `hq`
|
|
308
|
+
window.
|
|
309
|
+
- `set-environment -g` is how a running server is repaired: it ends nothing,
|
|
310
|
+
and panes that already run keep the environment they have. A pane's `PATH`
|
|
311
|
+
is always that of the process that runs the spawn or the start, so setting
|
|
312
|
+
`PATH` on the server changes nothing for OATS panes.
|
|
313
|
+
- `kill-server` ends every session on that server, every running agent
|
|
314
|
+
included. It is for before agents are started, not for repairing a running
|
|
315
|
+
host. The next start takes the environment of whoever starts it.
|
|
316
|
+
- `-L oats` reaches the server of the environment you type it in
|
|
317
|
+
(`TMUX_TMPDIR`). For the server an instance is on, use the socket from its
|
|
318
|
+
row in `oats status --json`: `tmux -S <socket> …`.
|
|
319
|
+
- A tmux server whose socket file is missing or does not answer reads as not
|
|
320
|
+
reachable, which is not proof that it exited: status, start and stop read
|
|
321
|
+
that state as stopped
|
|
322
|
+
([#624](https://github.com/awebai/oats/issues/624)). That is an existing
|
|
323
|
+
limit of every tmux server OATS uses, not of the `oats` server in
|
|
324
|
+
particular.
|
|
325
|
+
|
|
326
|
+
<a id="existing-instances"></a>
|
|
327
|
+
#### Existing instances
|
|
328
|
+
|
|
329
|
+
Upgrading moves nothing. An instance launched by an earlier kernel stays on the server
|
|
330
|
+
it recorded (usually your default one), and status, inspect, input, attach,
|
|
331
|
+
stop and retire keep acting on that recorded socket. While a deployment has
|
|
332
|
+
both, look at both servers: `tmux ls` and `tmux -L oats ls`.
|
|
333
|
+
|
|
334
|
+
- A restart in place stays on the recorded server: a live harness that is
|
|
335
|
+
restarted, a fallback shell or a dead pane is reused where it is, and the
|
|
336
|
+
record does not change.
|
|
337
|
+
- **Changed:** a start that has to create the window again, because the
|
|
338
|
+
recorded window is gone or the recorded server cannot be reached, creates
|
|
339
|
+
it on the OATS server. Earlier kernels recreated it on the recorded socket.
|
|
340
|
+
The start records the new socket in `instance.json` and the receipt, and
|
|
341
|
+
says so: one line in its `warnings`, naming the instance, the old socket
|
|
342
|
+
and the new one, and the same text as a `launch-warning` instance event.
|
|
343
|
+
- A home that was never launched (`--no-launch`) starts on the OATS server,
|
|
344
|
+
with no warning.
|
|
345
|
+
|
|
346
|
+
To move a running instance deliberately:
|
|
347
|
+
|
|
348
|
+
```sh
|
|
349
|
+
oats instance stop <instance> --plan # then run the `apply with:` line it prints
|
|
350
|
+
tmux -S <recorded socket> kill-window -t '=<session>:=<instance>'
|
|
351
|
+
oats session start --home <home>
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
The socket and the session are the `tmux.socket` and `tmux.session` of the
|
|
355
|
+
instance's row in `oats status --json`. The stop leaves a fallback shell in the
|
|
356
|
+
window, which a start would reuse in place; closing the window is what makes
|
|
357
|
+
the start create a new one.
|
|
358
|
+
|
|
359
|
+
Do not end the agents' session by hand (`tmux kill-session`): that ends every
|
|
360
|
+
other instance whose window is in that session, not only the one you are
|
|
361
|
+
moving. And a window that a viewer still links would live on in that viewer,
|
|
362
|
+
so the next start would create a second window for the same home.
|
|
63
363
|
|
|
64
364
|
### Herdr (removed in 0.31.0)
|
|
65
365
|
|
|
@@ -99,16 +399,19 @@ saved route that records `herdrPath` still loads; the field is ignored.
|
|
|
99
399
|
### Start and restart
|
|
100
400
|
|
|
101
401
|
`session start` keeps the instance's identity, work tree and notes. It runs no
|
|
102
|
-
spawn hooks and creates no new home. It runs the recorded launch recipe
|
|
103
|
-
recorded tmux session
|
|
104
|
-
server
|
|
402
|
+
spawn hooks and creates no new home. It runs the recorded launch recipe in the
|
|
403
|
+
recorded tmux session. A window that is still there is reused on its recorded
|
|
404
|
+
server; a window that has to be created, a `--no-launch` home's first one
|
|
405
|
+
included, opens on [the OATS tmux server](#the-oats-tmux-server).
|
|
105
406
|
|
|
106
407
|
- `--model`, `--launch-config <name>|none`, `--harness` and `--yolo` /
|
|
107
408
|
`--no-yolo` re-resolve the recipe against the home's recorded context and
|
|
108
409
|
run every check before anything starts. `--model` replaces the recorded model
|
|
109
410
|
for this and later starts.
|
|
110
411
|
- A live harness is refused (`E_SESSION_RUNNING`). A fallback shell or a dead
|
|
111
|
-
pane is reused in place
|
|
412
|
+
pane is reused in place. A missing window, or one whose tmux server cannot
|
|
413
|
+
be reached, is created again on the OATS tmux server, and the start warns when that is
|
|
414
|
+
not the server the home recorded ([Existing instances](#existing-instances)).
|
|
112
415
|
- A state that cannot be established is refused (`E_SESSION_UNKNOWN`). Two
|
|
113
416
|
starts of one home serialize (`E_SESSION_START_BUSY`). A home being retired
|
|
114
417
|
is refused (`E_INSTANCE_RETIRING`).
|
package/docs/implementation.md
CHANGED
|
@@ -284,14 +284,25 @@ scaling by call count.
|
|
|
284
284
|
|
|
285
285
|
Locally, run the suites your change affects, plus `validate` and `check`; run
|
|
286
286
|
`smoke:tarball` when you change the smoke script or packaging. Pull-request CI
|
|
287
|
-
runs the full suite (sharded),
|
|
288
|
-
|
|
289
|
-
|
|
287
|
+
runs the full suite (sharded), the Desktop suite again with only Desktop
|
|
288
|
+
dependencies installed, `check`, `validate`, `pack:check` and the smoke test,
|
|
289
|
+
and is the gate. Tests use local bare repositories and fakes; none contacts
|
|
290
|
+
GitHub, aweb, Jira or Linear.
|
|
290
291
|
|
|
291
292
|
Desktop's standalone tests (`cd packages/desktop && npm ci && npm test`) must
|
|
292
|
-
load with only Desktop dependencies installed.
|
|
293
|
-
|
|
294
|
-
the root
|
|
293
|
+
load with only Desktop dependencies installed. The release builds Desktop that
|
|
294
|
+
way: its `desktop-build` job installs and tests inside `packages/desktop` and
|
|
295
|
+
never installs the root. The sharded suite installs the root first, so a
|
|
296
|
+
Desktop test that reaches a root-only dependency passes there and would fail
|
|
297
|
+
only at a tag. Pull-request CI therefore has a `desktop-standalone` job that
|
|
298
|
+
runs the same `npm ci` and `npm test` inside `packages/desktop` with no root
|
|
299
|
+
install, and the gate requires it. `test/continuous-integration.test.mjs` pins
|
|
300
|
+
that job against `desktop-build`: change how one installs or tests Desktop and
|
|
301
|
+
the other changes with it.
|
|
302
|
+
|
|
303
|
+
Cross-package tests that import both the kernel and Desktop belong under root
|
|
304
|
+
`test/`; install dependencies at the root and in `packages/desktop` before
|
|
305
|
+
running those tests. The schedule
|
|
295
306
|
round-trip case is `node --test test/desktop-schedule-roundtrip.integration.mjs`.
|
|
296
307
|
The root runner includes this file with its existing Desktop dependency group.
|
|
297
308
|
With only root dependencies installed, it omits both Desktop suites and this
|
|
@@ -316,3 +327,23 @@ which fails with `ENOTEMPTY` (awebai/oats#451). So:
|
|
|
316
327
|
it runs there.
|
|
317
328
|
|
|
318
329
|
Never paper over such a race with a retry around the cleanup.
|
|
330
|
+
|
|
331
|
+
A test never reaches the operator's tmux. The kernel creates sessions on the
|
|
332
|
+
server named `oats` (`tmux -L oats`), which tmux resolves under `TMUX_TMPDIR`,
|
|
333
|
+
and acts on every existing session through its recorded socket
|
|
334
|
+
([execution-targets.md](execution-targets.md#the-oats-tmux-server)). So:
|
|
335
|
+
|
|
336
|
+
- A test that runs real tmux installs `isolateSessionEnvironment(base)`
|
|
337
|
+
(`test/helpers/host-fixture.mjs`). It owns a private, short `TMUX_TMPDIR`
|
|
338
|
+
(socket paths are limited to about 104 bytes) and puts a `tmux` wrapper
|
|
339
|
+
first on `PATH` that admits only `-L oats` and `-S` of a socket inside the
|
|
340
|
+
fixture, with no user configuration unless the test asks for it;
|
|
341
|
+
`oatsSocket()` is the socket `-L oats` resolves to there. Its restore
|
|
342
|
+
function kills that server, by socket.
|
|
343
|
+
- The shared fixture (`test/helpers/v2-deployment.mjs`) gives every command
|
|
344
|
+
it runs a private `TMUX_TMPDIR` too, so a test with a fake `tmux` on `PATH`
|
|
345
|
+
cannot reach a real server either. A fake answers what the kernel asks:
|
|
346
|
+
`list-sessions`, `new-session` (it prints `<socket>\t<window id>`),
|
|
347
|
+
`list-windows`, `new-window` (a window id) and `set-option`.
|
|
348
|
+
- A server a test starts is killed by its socket, never by name and never
|
|
349
|
+
with a bare `tmux kill-server`.
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# OATS 0.41.0
|
|
2
|
+
|
|
3
|
+
## Changed
|
|
4
|
+
|
|
5
|
+
- **The framework workspace has a separate maintainer soul.** The new
|
|
6
|
+
`oats-maintainer` soul is the OATS maintainer: direction, the roadmap,
|
|
7
|
+
architecture coherence, routing work to experts, review, merge and releases.
|
|
8
|
+
It composes `oats.maintainer` and carries the OATS-only `/oats-pr-review` and
|
|
9
|
+
`/git-tag-release` skills. `oats-expert` stays an expert, the generalist that
|
|
10
|
+
leads cross-area work, coordinates the domain experts and reports to
|
|
11
|
+
`oats-maintainer`. The other souls send direction, contract decisions and
|
|
12
|
+
merges to `oats-maintainer`, and read its knowledge node
|
|
13
|
+
(`oats/oats-maintainer`, which holds what the `oats-expert` node held).
|
|
14
|
+
- The `oats` knowledge store's main must declare the `oats-maintainer`
|
|
15
|
+
node before this reaches a deployment: souls that read or own it fail
|
|
16
|
+
their knowledge check with `E_CONFIG unresolved node:
|
|
17
|
+
oats/oats-maintainer` against a base without it.
|
|
18
|
+
- Operators: `oats sync`, then spawn `oats-maintainer` for maintainer work.
|
|
19
|
+
Running instances keep what they were spawned with.
|
|
20
|
+
- **Desktop terminals keep text readable (#602).** Desktop terminals now keep
|
|
21
|
+
text at a contrast of at least 4.5:1 with its background, so coloured text written for
|
|
22
|
+
another palette (a grey meant for a dark terminal, shown in White) stays
|
|
23
|
+
readable. The built-in palettes' colours on the terminal background are
|
|
24
|
+
unchanged; text on a coloured background may be drawn lighter or darker than
|
|
25
|
+
the program asked.
|
|
26
|
+
- **Desktop can match this computer's theme (#602).** A fourth theme choice,
|
|
27
|
+
**This computer**, shows Desktop's chrome and every terminal in the theme of
|
|
28
|
+
the computer that runs Desktop. On an Omarchy computer that is the current
|
|
29
|
+
Omarchy theme, followed when it changes, with no restart. Elsewhere it is
|
|
30
|
+
Dark or White by the system's appearance. Text colours taken from the host
|
|
31
|
+
are adjusted where needed to stay at least 4.5:1 on Desktop's surfaces; a
|
|
32
|
+
terminal's 16 colours are the host's own. If the host's theme cannot be
|
|
33
|
+
read, Desktop shows Dark or White and says so. A theme you chose does not
|
|
34
|
+
change: choose **Theme: This computer** in the command palette, or cycle to
|
|
35
|
+
it with the theme button.
|
|
36
|
+
- On an Omarchy computer Desktop reads the theme's colours file at start and
|
|
37
|
+
each time a window gets focus, whichever theme is chosen. It opens the file
|
|
38
|
+
without blocking and reads it only if it is a regular file, so a colours
|
|
39
|
+
file replaced by a named pipe, for example, cannot hang it (#612).
|
|
40
|
+
- On Linux, This computer is the default: a Desktop where no theme was ever
|
|
41
|
+
chosen starts in This computer (the computer's Omarchy theme, or the
|
|
42
|
+
system's light or dark appearance where there is none) instead of White.
|
|
43
|
+
That includes an existing install where the theme was never changed. If
|
|
44
|
+
you chose White at any time, it stays White. Choose another theme with the
|
|
45
|
+
theme button or the palette, and it stays. On other platforms the default
|
|
46
|
+
is still White.
|
|
47
|
+
- **The Desktop accepts OATS CLIs `>=0.25.8 <0.42.0`**, so it runs against
|
|
48
|
+
this release's kernel; the Desktop 0.40.x refuses a 0.41 CLI.
|
|
49
|
+
- **Desktop's Remove has one choice, the worktree.** Remove no longer offers
|
|
50
|
+
to delete a branch: retirement leaves branches to the operator, and the
|
|
51
|
+
kernel refuses the flag. The dialog's one choice is **Also delete the
|
|
52
|
+
worktree**, and it says "Remove never deletes a branch." A home left by a
|
|
53
|
+
failed spawn that still owes its branch stays incomplete while that branch
|
|
54
|
+
exists, and Remove can no longer complete it: check the branch and delete it
|
|
55
|
+
with Git, then remove the home again.
|
|
56
|
+
- **New sessions run on an OATS-owned tmux server (#602).** The server is
|
|
57
|
+
`tmux -L oats`, so tools that restyle the default tmux server no longer
|
|
58
|
+
reach agent terminals. Running instances stay where they are. Plain
|
|
59
|
+
`tmux ls` and `tmux attach` no longer show new sessions: use `oats session
|
|
60
|
+
attach` or the `attach:` line that spawn prints. An existing instance moves
|
|
61
|
+
only when its window is recreated: a start after its window is gone or its
|
|
62
|
+
tmux server cannot be reached now opens on the OATS server instead of the
|
|
63
|
+
recorded socket. To move one deliberately, stop it, close its window and
|
|
64
|
+
start it: see
|
|
65
|
+
[Existing instances](../execution-targets.md#existing-instances).
|
|
66
|
+
- Operators: after upgrading, and after a reboot, start the `oats` server
|
|
67
|
+
from your own shell before anything else does: `tmux -L oats new-session
|
|
68
|
+
-d -s <session> -n hq` (`<session>` is the deployment's session name,
|
|
69
|
+
`oats-agents` by default). A tmux server keeps the environment of whoever
|
|
70
|
+
starts it: without this step the first Desktop-run or scheduled spawn
|
|
71
|
+
decides the ambient environment of later panes, and a spawn or start run
|
|
72
|
+
from inside an instance whose own tmux server cannot be read is refused
|
|
73
|
+
([the environment of the server and its panes](../execution-targets.md#the-servers-start-environment)).
|
|
74
|
+
- Nothing of an instance's environment reaches a server or a pane through
|
|
75
|
+
the calls that create an agents' session or window: an instance creates
|
|
76
|
+
the session with a reduced copy of the environment of the server its
|
|
77
|
+
home records (a variable whose value holds a `$`, a line break or a
|
|
78
|
+
character tmux prints encoded is not carried), and a window with only
|
|
79
|
+
`PATH` and the locale names tmux's client needs
|
|
80
|
+
(`LANG`, `LC_ALL`, `LC_CTYPE`), which tmux does not hand on. Every
|
|
81
|
+
creator's environment goes without the names the kernel sets
|
|
82
|
+
(`OATS_INSTANCE`, `OATS_ROOT`, `PI_AGENTS_ROOT`, launch references and
|
|
83
|
+
the others the docs list). A server that already runs keeps the
|
|
84
|
+
environment it has: OATS does not certify where that came from.
|
|
85
|
+
- On each agent window it creates, OATS resets `window-style`,
|
|
86
|
+
`window-active-style` and `cursor-colour` to `default`, and removes
|
|
87
|
+
`COLORFGBG` from the pane, so the pane shows the colours of the terminal
|
|
88
|
+
that views it. It does not reset `pane-colours`: a palette set in your
|
|
89
|
+
tmux configuration still reaches agent panes
|
|
90
|
+
([what OATS sets](../execution-targets.md#the-oats-tmux-server)).
|
|
91
|
+
- OATS sets nothing server-global on any server when it creates a session
|
|
92
|
+
or a window. `window-size latest` and `aggressive-resize on`, which it
|
|
93
|
+
used to set globally on the server it created its session on, are now set
|
|
94
|
+
on the windows it creates.
|
|
95
|
+
- The spawn result's `attach` is `tmux -S <socket> attach -t <session>` for
|
|
96
|
+
a launched spawn and `oats session attach --home <home>` for
|
|
97
|
+
`--no-launch`; a routed spawn (`--server`) prints `oats session attach
|
|
98
|
+
--server <id> --instance <instance>`. The JSON shapes are unchanged.
|
|
99
|
+
- The kernel no longer exports `launchEnvTmuxFlags` (it had no consumer).
|
|
100
|
+
|
|
101
|
+
## Upgrade
|
|
102
|
+
|
|
103
|
+
**Retirement no longer deletes branches.** What to do:
|
|
104
|
+
|
|
105
|
+
- **`oats retire --delete-branch` is refused** with `E_BAD_ARGS` before
|
|
106
|
+
anything happens: no child or session is stopped, no hook runs, nothing is
|
|
107
|
+
written. Retire without it; the branch is left in the repository. Inspect it
|
|
108
|
+
there and delete it with Git if it is no longer wanted. Scripts that pass the
|
|
109
|
+
flag must drop it. A self-retire an older OATS recorded with the flag is
|
|
110
|
+
completed with the branch and the worktree left, and its `retired` event says
|
|
111
|
+
so.
|
|
112
|
+
- **A home a failed spawn left that still owes its branch** stays incomplete
|
|
113
|
+
while that branch exists, with the item `the branch the failed spawn created
|
|
114
|
+
is left: OATS does not delete it. Inspect it and delete it with Git if it is
|
|
115
|
+
not wanted, then retry`. The item names no branch; the CLI prints it on the
|
|
116
|
+
next line (the receipt's `retention.recordedBranch`, or the `branch` in the
|
|
117
|
+
retained home's `instance.json` when the worktree step did not run). While
|
|
118
|
+
Git cannot show the branch gone, the item is `git branch <b>: could not
|
|
119
|
+
verify whether it still exists (…)`. Delete the branch with Git, then retire
|
|
120
|
+
again.
|
|
121
|
+
- **A worktree whose branch has no commit yet:** `oats retire
|
|
122
|
+
--discard-worktree`, or a retire that has work to copy, on such a worktree
|
|
123
|
+
refuses with `E_WORK_INSPECTION_FAILED` and removes nothing. Make a commit,
|
|
124
|
+
switch the worktree to a branch that has one, or remove the worktree with
|
|
125
|
+
Git; then retire again.
|
|
126
|
+
- **A worktree Git refuses to read without your own `safe.directory`**
|
|
127
|
+
(typically one owned by another user) now refuses a retire that has work to
|
|
128
|
+
preserve or that removes the worktree, with `E_WORK_INSPECTION_FAILED`. A
|
|
129
|
+
plain retire of such a worktree with nothing to preserve retains it under a
|
|
130
|
+
`detached-unknown` name, without its branch in the receipt. Retire as the
|
|
131
|
+
owner, or with Git's ownership check satisfied for that path.
|
|
132
|
+
|
|
133
|
+
## Fixed
|
|
134
|
+
|
|
135
|
+
- **A retire keeps what only the worktree has.** The recovery a retire writes
|
|
136
|
+
of a worktree is proven against the commit the worktree has checked out, and
|
|
137
|
+
is checked out at that commit on the worktree's own branch (detached, when
|
|
138
|
+
the branch's name is not one OATS carries). A clean worktree whose HEAD is
|
|
139
|
+
detached at a commit no ref of the repository reaches is preserved in a
|
|
140
|
+
recovery before `--discard-worktree` removes it, also when a retire hook made
|
|
141
|
+
that commit. HEAD is read again immediately before the worktree is removed:
|
|
142
|
+
if it moved since the retire's last inspection, the worktree is not removed
|
|
143
|
+
and the retire stops with `E_WORK_PRESERVATION_FAILED`; the home and the
|
|
144
|
+
worktree are kept, and so is any recovery the retire wrote.
|
|
145
|
+
- **A stopped instance's harness mark is readable in Solarized (#602).** In
|
|
146
|
+
the Desktop's roster, the harness mark of a stopped instance was drawn at
|
|
147
|
+
4.0:1 in Solarized, under the 4.5:1 the rest of the app keeps. It is now
|
|
148
|
+
4.7:1. The mark's block is slightly lighter in White and Solarized and
|
|
149
|
+
slightly darker in Dark.
|
|
150
|
+
- **Review threads reach an agent whose session is not on the default tmux
|
|
151
|
+
server (#602).** Sending a pull request's review threads to an agent's
|
|
152
|
+
terminal from the Desktop now uses the tmux socket the instance records, as
|
|
153
|
+
the Desktop's terminals do. Before, the paste always went to the default tmux
|
|
154
|
+
server: for an instance that records another socket it answered that the
|
|
155
|
+
paste failed, or it could go into a window of the same name on the default
|
|
156
|
+
server. An instance that records no socket is pasted to as before.
|
|
157
|
+
- **The Desktop names a retire refused at inspection.** When `oats retire`
|
|
158
|
+
refused a local instance with `E_WORK_INSPECTION_FAILED`, the Remove dialog
|
|
159
|
+
said "The lifecycle CLI is unavailable.", although the CLI had answered. It
|
|
160
|
+
now says: "Retirement was refused: the instance's home or work could not be
|
|
161
|
+
inspected. The home is kept; its session may already have been stopped, and
|
|
162
|
+
earlier retirement steps may have run." The outcome is still reported as
|
|
163
|
+
unknown, because the kernel can refuse after it stopped the children and the
|
|
164
|
+
session and ran the retire hooks. For an instance on a server the same
|
|
165
|
+
sentence replaces that headline, above the host's own message in Details.
|
|
166
|
+
For a local refusal the CLI's own message, which names the path and the
|
|
167
|
+
remedy, is in Details too (next entry). Part of
|
|
168
|
+
[#601](https://github.com/awebai/oats/issues/601).
|
|
169
|
+
- **The Desktop shows the kernel's own message when a local Stop or Remove
|
|
170
|
+
fails.** The dialog said only its own sentence for the error code; the
|
|
171
|
+
message the CLI answered with was dropped. It is now in the dialog's
|
|
172
|
+
**Details**, as the code and the message, under that sentence, as it already
|
|
173
|
+
was for an instance on a server. It is shown only when the installed CLI
|
|
174
|
+
answered with an error and the Desktop has a sentence for its code: a
|
|
175
|
+
timeout, an unreadable answer or an unknown code shows none. Closes
|
|
176
|
+
[#601](https://github.com/awebai/oats/issues/601).
|
|
177
|
+
- **The Desktop shows a kernel or host message as one plain line.** In the
|
|
178
|
+
Details of a refusal (Stop and Remove, the Git panel, Activity, readiness),
|
|
179
|
+
line feeds, the Unicode line and paragraph separators and tabs are collapsed
|
|
180
|
+
into single spaces. The C1 control characters, the bidirectional embedding,
|
|
181
|
+
override and isolate characters, the zero-width space, the word joiner, the
|
|
182
|
+
byte order mark and tag characters are each replaced by U+FFFD, the
|
|
183
|
+
replacement character. A message that holds a carriage return, DEL or
|
|
184
|
+
another ASCII control character other than tab and line feed (a message
|
|
185
|
+
with Windows line endings, for example), or that looks like a credential,
|
|
186
|
+
is withheld whole as `[Detail withheld]`, as before. A long message is cut
|
|
187
|
+
at 2048 characters. For readiness, the message is no longer in the "Couldn't
|
|
188
|
+
refresh" line's tooltip, which keeps the Desktop's sentence and the error
|
|
189
|
+
code; it stays in Details. In the Git panel a failed read's message, which
|
|
190
|
+
could span several lines, is now one line.
|
|
191
|
+
- **A tmux server started from the Desktop gets your environment, not the
|
|
192
|
+
Desktop's (#602).** A tmux server started from the Desktop (by a spawn or a
|
|
193
|
+
start, or by opening a terminal) no longer carries the Desktop's own runtime
|
|
194
|
+
settings. They made Electron programs started from an agent's pane run as
|
|
195
|
+
Node, and on the AppImage they pointed library and data paths into the
|
|
196
|
+
Desktop's mount, which exists only while that Desktop runs. Every program
|
|
197
|
+
the Desktop starts (the `oats` CLI, `tmux`, `gh`, the login shell that
|
|
198
|
+
resolves `PATH`) now gets your environment without them. One change in a
|
|
199
|
+
diagnostic: `probePath` in the backend's `GET /api/cli` answer no longer
|
|
200
|
+
lists the AppImage's own entries. A tmux server that was already running
|
|
201
|
+
keeps the environment it was started with (#616). Known limits are in the
|
|
202
|
+
Desktop README.
|
|
203
|
+
- **The Desktop builds a view's failure placeholder as text.** A tab whose
|
|
204
|
+
view fails to load or to mount shows the same words, built without markup.
|
|
205
|
+
- **`oats retire` no longer refuses a launched instance only because its
|
|
206
|
+
tmux socket file is missing.** After a reboot that cleared tmux's socket
|
|
207
|
+
directory, tmux answers `error connecting to <socket> (No such file or
|
|
208
|
+
directory)` for the socket the instance's session was recorded on, and
|
|
209
|
+
retire refused with `E_RUNTIME_QUIESCE_FAILED`. Retire now goes on when the
|
|
210
|
+
recorded server cannot be reached because its socket file is missing and no
|
|
211
|
+
process on the host works in the instance's home (any process whose working
|
|
212
|
+
directory is in the home, not only the harness). A tmux server keeps running
|
|
213
|
+
when its socket file is removed, so when a process still works in the home,
|
|
214
|
+
or the process scan (`lsof`) cannot run or does not complete, retire refuses
|
|
215
|
+
as before and the message says which. Such a server recreates its socket
|
|
216
|
+
when its process is sent `SIGUSR1`. The check needs `lsof`: on a host
|
|
217
|
+
without it, a retire whose recorded socket file is missing is still refused,
|
|
218
|
+
and the message says that `lsof` is missing; install it, then retire. The
|
|
219
|
+
scan counts only when `lsof` completed: one that was cut off (a timeout, too
|
|
220
|
+
much output, a signal) is no longer read as "no process", here, for a home
|
|
221
|
+
without its session receipt and for a home opened in Herdr; those retires
|
|
222
|
+
are refused. So is one whose listing names no process at all, which a
|
|
223
|
+
completed scan never prints. A window that is still running, or a server
|
|
224
|
+
that cannot be read for another reason, is refused as before.
|
|
225
|
+
[#620](https://github.com/awebai/oats/issues/620).
|
|
226
|
+
|
|
227
|
+
## Removed
|
|
228
|
+
|
|
229
|
+
- **Three unused routes of the Desktop's local server.**
|
|
230
|
+
`GET /api/session/<instance>` (a capture of the instance's terminal),
|
|
231
|
+
`POST /api/keys/<instance>` (keys or a paste typed into it) and
|
|
232
|
+
`POST /api/interrupt/<instance>` (Ctrl-C) are gone. Nothing in the Desktop
|
|
233
|
+
used them: its terminals attach to the instance's session directly. They
|
|
234
|
+
ran `tmux` without the socket an instance records, so for an instance on
|
|
235
|
+
its own tmux server they would have reached another one. Each path now
|
|
236
|
+
answers as any unknown route does (`404`, `not found`).
|
|
237
|
+
`GET /api/chat/<instance>` is unchanged. Closes
|
|
238
|
+
[#609](https://github.com/awebai/oats/issues/609).
|