@stratusagent/cli 0.2.5 → 0.4.0
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 +372 -4
- package/dist/bin.js +13 -4
- package/dist/bin.js.map +1 -1
- package/dist/index.d.ts +124 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1724 -83
- package/dist/index.js.map +1 -1
- package/dist/logs.d.ts +123 -0
- package/dist/logs.d.ts.map +1 -0
- package/dist/logs.js +358 -0
- package/dist/logs.js.map +1 -0
- package/dist/service.d.ts +82 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +380 -0
- package/dist/service.js.map +1 -0
- package/package.json +15 -11
package/README.md
CHANGED
|
@@ -2,27 +2,53 @@
|
|
|
2
2
|
|
|
3
3
|
Stratus Agent CLI — create always-on agents that get smarter over time. Quickly set up Stratus Agent on your machine, create new agents, connect AI providers, and configure channels.
|
|
4
4
|
|
|
5
|
+
<img width="2400" height="1004" alt="image" src="https://github.com/user-attachments/assets/ef16d58f-694c-406e-b201-aee61b093753" />
|
|
6
|
+
|
|
5
7
|
## Install
|
|
6
8
|
|
|
9
|
+
Needs **Node.js 22.13+** — the gateway's session store uses `node:sqlite`, which runs unflagged from 22.13. On the 23.x line that landed separately, in **23.4**, so 23.0–23.3 are too old despite the higher number. Every package declares the range, and the CLI checks it at startup, so an unsupported Node gets a line naming what it needs rather than a missing-builtin error later on.
|
|
10
|
+
|
|
7
11
|
```bash
|
|
8
12
|
npm install -g @stratusagent/cli
|
|
9
13
|
stratus setup
|
|
10
14
|
```
|
|
11
15
|
|
|
16
|
+
That one package is everything you need to run agents: the runtime, the
|
|
17
|
+
providers, the agent roster, and the always-on gateway all come with it.
|
|
18
|
+
|
|
19
|
+
### Optional channel packages
|
|
20
|
+
|
|
21
|
+
Channels are the exception — the CLI ships **no** transport, so an install that
|
|
22
|
+
never touches Slack never carries the Slack SDKs (~9 MB). Add the one you want
|
|
23
|
+
alongside the CLI and `stratus serve` picks it up automatically:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install -g @stratusagent/channel-slack
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
If tokens are stored for an agent but the package isn't installed, `stratus
|
|
30
|
+
serve` says so and starts anyway, serving every other channel.
|
|
31
|
+
|
|
32
|
+
## Setup
|
|
33
|
+
|
|
12
34
|
`stratus setup` is the whole onboarding, as a small navigable menu:
|
|
13
35
|
|
|
14
36
|
```
|
|
15
37
|
1) Providers anthropic — signed in with your Claude subscription
|
|
16
38
|
2) Models default claude-opus-5 · fallback gpt-4.1-mini
|
|
17
39
|
3) Agent ~/.stratus/agents/ava.md
|
|
18
|
-
4)
|
|
19
|
-
5)
|
|
40
|
+
4) Channels Slack: 1 agent connected
|
|
41
|
+
5) Always on stratusd runs after setup, and at every login
|
|
42
|
+
6) Test run say hello with the current settings
|
|
43
|
+
7) Save & finish
|
|
20
44
|
```
|
|
21
45
|
|
|
22
46
|
- **Providers** — sign in to one or more. For Claude, choose how you pay: a **Claude Pro/Max subscription** (run `claude setup-token`, paste the token — runs route through the Claude Code runtime, so your plan covers usage; requires Claude Code installed and signed in. Tool runs and memory work there too, so it's the same agent as on an API key) or an **Anthropic API key**, pasted straight into the prompt (input is hidden) and checked against the live API when the endpoint supports it — a rejected key is refused; an unreachable endpoint saves the key and verifies it on your first run. OpenAI-compatible services work like API keys, including local models and proxies via a custom base URL.
|
|
23
47
|
- **Models** — pick a **default** and a **fallback**, listed live from the provider APIs where possible (subscription sign-ins and offline setups fall back to the known Claude lineup). If the default model errors mid-run, the run automatically retries on the fallback — even across providers.
|
|
24
48
|
- **Menus are keyboard-driven** — arrow keys (or `j`/`k`) to move, Enter to pick, digits to jump, Esc to go back.
|
|
25
49
|
- **Agent** — name your agent (or accept a generated identity), describe their personality, and their soul file lands in `~/.stratus/agents/`, ready to edit.
|
|
50
|
+
- **Channels** — put an agent on Slack without opening a file. Pick the agent, and setup prints the app manifest with their name already filled in, walks you through the two tokens (input hidden), verifies each against Slack before accepting it, and stores them where `stratus serve` looks. The list marks who is connected; picking a connected agent offers to replace their tokens or disconnect.
|
|
51
|
+
- **Always on** — whether the roster keeps answering once you close the terminal. On by default, because an agent you have to remember to start is not always-on, and every Slack app you connected above stays silent until `stratusd` runs. Save & finish installs it (see [Always on](#always-on)); choose *do not run it for me* and setup removes any service it previously installed.
|
|
26
52
|
- **Test run** — say hello with the current settings before saving anything.
|
|
27
53
|
|
|
28
54
|
Credentials are stored in `~/.stratus/credentials.json` (owner-read-only) and settings in `~/.stratus/config.json`, so `stratus run` works from any directory afterwards. No env vars to export, no config files to hand-edit.
|
|
@@ -30,18 +56,315 @@ Credentials are stored in `~/.stratus/credentials.json` (owner-read-only) and se
|
|
|
30
56
|
## Usage
|
|
31
57
|
|
|
32
58
|
```bash
|
|
59
|
+
stratus setup # onboarding menu: providers, models, agent, channels
|
|
33
60
|
stratus chat # talk — the conversation persists
|
|
34
61
|
stratus chat --soul ./ava.md
|
|
35
62
|
stratus run "say hello"
|
|
36
63
|
stratus run --soul ./ava.md "introduce yourself"
|
|
37
64
|
stratus run --provider anthropic --model claude-opus-5 "hello"
|
|
38
65
|
stratus run --prompt "use the echo tool" --format json
|
|
66
|
+
stratus serve # stratusd: the whole roster, always on
|
|
67
|
+
stratus serve --idle-timeout 120 --no-events
|
|
68
|
+
stratus serve --approvals remote # ask a human in Slack instead of refusing
|
|
69
|
+
stratus service install # keep stratusd running under launchd/systemd
|
|
70
|
+
stratus service status
|
|
71
|
+
stratus logs -f # what the daemon has been doing
|
|
72
|
+
stratus logs --agent ava -n 200
|
|
73
|
+
stratus doctor # what a run would use right now, and why
|
|
39
74
|
stratus agent new # create an agent (guided on a terminal)
|
|
40
75
|
stratus agent new --format soul > ava.md
|
|
41
76
|
stratus agents # who's on the team: souls, models, memory
|
|
42
77
|
stratus dashboard # local browser dashboard
|
|
43
78
|
```
|
|
44
79
|
|
|
80
|
+
`stratus serve` runs the gateway in the foreground: every agent in your roster
|
|
81
|
+
live at once on its own provider and model, sessions in SQLite so they survive
|
|
82
|
+
restarts, delegation between agents, a watchdog for stalled turns, and any
|
|
83
|
+
installed channels connected. Ctrl+C or SIGTERM drains cleanly.
|
|
84
|
+
|
|
85
|
+
### What the daemon will do on its own
|
|
86
|
+
|
|
87
|
+
Tools declare how much damage they could do — `safe`, `gated`, or
|
|
88
|
+
`dangerous` — and the daemon runs only the safe ones without asking. Anything
|
|
89
|
+
riskier is refused, with a line in the log saying which agent wanted what:
|
|
90
|
+
|
|
91
|
+
```text
|
|
92
|
+
09:14:36 — warning: ava: shell.run is gated and nobody is available to approve it (session slack:ava:…)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
That is the honest default behind a service manager, where there is no
|
|
96
|
+
terminal to prompt on. If somebody *is* reachable, `--approvals remote` asks
|
|
97
|
+
them instead — see [Asking a human](#asking-a-human-remote-approval).
|
|
98
|
+
|
|
99
|
+
A tool that declares no risk counts as `gated`, never `safe` — forgetting to
|
|
100
|
+
classify something should cost a prompt, not an unattended command. Every
|
|
101
|
+
tool that ships today (`demo.echo`, `memory.remember`, `agent.delegate`) is
|
|
102
|
+
`safe`, so nothing changes until you add one that isn't.
|
|
103
|
+
|
|
104
|
+
The line is *acting outside Stratus* — the filesystem, the network, another
|
|
105
|
+
service — not cost. Every turn spends provider tokens, including the one
|
|
106
|
+
that decided to call a tool, so a policy that gated on spend would have to
|
|
107
|
+
gate the conversation itself. Delegation stays `safe` for the same reason:
|
|
108
|
+
it hands work to a teammate inside the fleet, that teammate's own tool
|
|
109
|
+
calls face this policy again under their allowlist, and the chain is depth
|
|
110
|
+
bounded.
|
|
111
|
+
|
|
112
|
+
`stratus chat` and `stratus run` are unaffected: at a terminal, `--approvals`
|
|
113
|
+
works exactly as before (`always`, `ask`, `never`).
|
|
114
|
+
|
|
115
|
+
### Asking a human: remote approval
|
|
116
|
+
|
|
117
|
+
In `remote` mode a gated call does not fail — the turn parks, the request is
|
|
118
|
+
posted to Slack with **Allow once**, **Always allow**, and **Deny**, and the
|
|
119
|
+
turn resumes on the answer. The question goes to the thread the turn is
|
|
120
|
+
happening in, so whoever is talking to the agent sees it where they already
|
|
121
|
+
are.
|
|
122
|
+
|
|
123
|
+
Turn it on for the daemon with `--approvals remote`, or in
|
|
124
|
+
`~/.stratus/config.json` so the installed service picks it up too:
|
|
125
|
+
|
|
126
|
+
```jsonc
|
|
127
|
+
{
|
|
128
|
+
"approvals": {
|
|
129
|
+
"mode": "remote", // headless (default) or remote
|
|
130
|
+
"timeoutMs": 900000, // unanswered after 15 minutes → denied (max 2147483647)
|
|
131
|
+
"slackApprovers": ["U01OPS"], // who may decide, for every agent
|
|
132
|
+
"slackChannel": "C07OPS", // where to ask when the turn isn't in Slack
|
|
133
|
+
"agents": {
|
|
134
|
+
"ava": { "slackApprovers": ["U01DYLAN"] }
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
An agent inherits the top-level route key by key, so `ava` above asks her own
|
|
141
|
+
approver in the shared `C07OPS` fallback channel. An explicit
|
|
142
|
+
`"slackApprovers": []` on an agent excludes it from the default list — that
|
|
143
|
+
agent's gated calls are then denied outright — while omitting the key
|
|
144
|
+
inherits.
|
|
145
|
+
|
|
146
|
+
**Only a config you chose is allowed to set this block** — `--config`,
|
|
147
|
+
`STRATUS_CONFIG`, or the global `~/.stratus/config.json`. An auto-discovered
|
|
148
|
+
project-local `stratus.config.json` outranks the global one for provider
|
|
149
|
+
settings, but it can be checked into any repository, and appointing the
|
|
150
|
+
people who may authorize an agent's tool calls is not something a clone gets
|
|
151
|
+
to do. Its `approvals` block is ignored, with a warning naming the file.
|
|
152
|
+
|
|
153
|
+
Three things are worth knowing before you turn it on:
|
|
154
|
+
|
|
155
|
+
- **Approvers are people, not places.** Posting into a channel does not make
|
|
156
|
+
everyone in it an approver: each request is bound to the ids configured for
|
|
157
|
+
that agent, and anyone else's click is refused with a notice only they see.
|
|
158
|
+
The request stays open for someone who may actually answer it. This matters
|
|
159
|
+
most for **Always allow**, which widens what the agent may do unattended.
|
|
160
|
+
- **An agent with no approver configured is denied immediately**, not left to
|
|
161
|
+
time out — `remote` with nobody listed behaves exactly like `headless`. If
|
|
162
|
+
no channel can ask for an agent at all (no Slack tokens for it, or
|
|
163
|
+
`@stratusagent/channel-slack` not installed) there is nothing to render the
|
|
164
|
+
request, so its gated calls wait out the timeout instead. The daemon names
|
|
165
|
+
those agents at startup, rather than leaving you to find out at 3am:
|
|
166
|
+
|
|
167
|
+
```text
|
|
168
|
+
approvals: remote — gated calls are parked and asked in Slack (approvers set for ava)
|
|
169
|
+
```
|
|
170
|
+
- **A parked turn survives a restart.** The daemon records what has not run
|
|
171
|
+
before it asks, so an approval outstanding when it stops is finished when
|
|
172
|
+
it starts again — the question is re-asked in Slack, the call runs on the
|
|
173
|
+
answer, and anything queued behind it still runs too. The re-asked request
|
|
174
|
+
keeps the window it started with rather than getting a fresh one, and a
|
|
175
|
+
wait that has already used up its `timeoutMs` is denied instead of
|
|
176
|
+
re-asked: downtime is not a reason to extend a security decision.
|
|
177
|
+
- **A turn that was mid-flight is failed, not left hanging.** Parking is the
|
|
178
|
+
one state a restart can resume from — a turn that stopped anywhere else
|
|
179
|
+
(waiting on the provider, inside a tool, or on an approval asked by an
|
|
180
|
+
agent billed through a Claude subscription, which is deliberately not
|
|
181
|
+
checkpointed) cannot be. Those sessions come back marked `failed`, with a
|
|
182
|
+
reason saying stratusd stopped while they were running and to send the
|
|
183
|
+
message again, rather than claiming to still be running forever. This is
|
|
184
|
+
only for an ungraceful stop: a normal restart denies what is parked and
|
|
185
|
+
finishes the turns those denials release before it exits.
|
|
186
|
+
- **Always allow lasts for the session**, not forever. It stops the same tool
|
|
187
|
+
asking again in the same conversation, and it is forgotten when the daemon
|
|
188
|
+
restarts. A durable per-agent whitelist is a narrower promise (a normalized
|
|
189
|
+
command scope) and ships with the shell tool that needs one.
|
|
190
|
+
|
|
191
|
+
The request shows the tool's **arguments**, not just its name — for anything
|
|
192
|
+
whose danger lives in what it was called with, approving a bare tool name is
|
|
193
|
+
approving something you cannot see. Arguments are escaped (a model-written
|
|
194
|
+
argument cannot mention or broadcast to the workspace through the prompt)
|
|
195
|
+
and truncated with a visible notice when they are long.
|
|
196
|
+
|
|
197
|
+
Requests are also denied — visibly, with a reason — when they expire, when
|
|
198
|
+
the turn is cancelled, when the daemon shuts down, and when a turn reaches a
|
|
199
|
+
gated call while the daemon is already stopping. Every one of those retracts
|
|
200
|
+
the buttons in Slack, so a message never keeps offering a decision with
|
|
201
|
+
nowhere to land.
|
|
202
|
+
|
|
203
|
+
`timeoutMs` is capped at 2147483647 (~24.8 days), the longest timer Node can
|
|
204
|
+
hold. A larger value is rejected at startup rather than accepted: it would
|
|
205
|
+
not wait longer, it would expire every approval almost immediately.
|
|
206
|
+
|
|
207
|
+
Approval buttons need the Slack app's **Interactivity** switched on. Apps
|
|
208
|
+
created from the manifest that `stratus setup` prints already have it; an app
|
|
209
|
+
created before this shipped needs it enabled once, in its App Manifest.
|
|
210
|
+
|
|
211
|
+
## Always on
|
|
212
|
+
|
|
213
|
+
`stratus serve` stays a foreground process on purpose — debuggable, and
|
|
214
|
+
composable with whatever supervisor you already run. Surviving logout, crashes,
|
|
215
|
+
and reboots is the platform's job, so `stratus service` hands the daemon to
|
|
216
|
+
launchd on macOS and to systemd on Linux:
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
stratus service install # write the unit, start now, start at every login
|
|
220
|
+
stratus service install --no-login
|
|
221
|
+
stratus service status
|
|
222
|
+
stratus service start
|
|
223
|
+
stratus service stop
|
|
224
|
+
stratus service uninstall
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
`stratus setup` installs it for you at Save & finish unless you opt out, so
|
|
228
|
+
most people never run these by hand. What they get:
|
|
229
|
+
|
|
230
|
+
- **macOS** — a LaunchAgent at `~/Library/LaunchAgents/com.stratusagent.stratusd.plist`
|
|
231
|
+
- **Linux** — a systemd user unit at `~/.config/systemd/user/stratusd.service`
|
|
232
|
+
|
|
233
|
+
The unit runs the daemon by **absolute path** — the node binary and script of
|
|
234
|
+
the process that installed it, never a bare `stratus`. A service manager starts
|
|
235
|
+
with a minimal environment and never loads the shell profile that puts `stratus`
|
|
236
|
+
on your `PATH`. It stops with SIGTERM, so the gateway's drain actually runs.
|
|
237
|
+
|
|
238
|
+
A default install restarts the daemon if it crashes, but not after a clean
|
|
239
|
+
exit — stopping it yourself keeps it stopped. **`--no-login` gives up crash
|
|
240
|
+
restarts on macOS**, and that is launchd's rule rather than a choice: `KeepAlive`
|
|
241
|
+
implies `RunAtLoad`, so a job that must not start at login cannot ask to be
|
|
242
|
+
revived either. `stratus service install --no-login` says so when it finishes.
|
|
243
|
+
On Linux the two are independent, and `Restart=on-failure` applies either way.
|
|
244
|
+
|
|
245
|
+
`status` asks the service manager, not the unit file, whether the daemon is
|
|
246
|
+
alive, and exits non-zero when it isn't — so it works in a health check:
|
|
247
|
+
|
|
248
|
+
```text
|
|
249
|
+
stratusd running
|
|
250
|
+
manager launchd
|
|
251
|
+
unit ~/Library/LaunchAgents/com.stratusagent.stratusd.plist
|
|
252
|
+
at login yes
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
**One limit worth knowing before you rely on it.** A LaunchAgent starts at
|
|
256
|
+
**login, not at power-on**, and only while that user is logged in — an
|
|
257
|
+
unattended Mac needs automatic login turned on too. (A `LaunchDaemon` would
|
|
258
|
+
start without a login, but it runs as a system user, which breaks `~/.stratus`
|
|
259
|
+
paths and the Claude subscription token entirely, so the LaunchAgent is the
|
|
260
|
+
right choice.) The systemd equivalent is `loginctl enable-linger` on a machine
|
|
261
|
+
you don't stay logged in to. Setup says both in the menu rather than leaving
|
|
262
|
+
them to be discovered after a reboot.
|
|
263
|
+
|
|
264
|
+
## Logs
|
|
265
|
+
|
|
266
|
+
Under a service manager the daemon's stdout is gone, so everything `stratus
|
|
267
|
+
serve` says is also written to `~/.stratus/logs/stratusd.jsonl` (owner-read-only,
|
|
268
|
+
rotated at 8 MB, three generations kept). That file is the record of an
|
|
269
|
+
overnight run, and `stratus logs` reads it from any terminal:
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
stratus logs # the last 50 records
|
|
273
|
+
stratus logs -f # follow, across rotations
|
|
274
|
+
stratus logs -n 200
|
|
275
|
+
stratus logs --agent ava
|
|
276
|
+
stratus logs --session slack:ava:T01ABCDEF:C07GHIJKL:1731900000.123456
|
|
277
|
+
stratus logs --format json # the raw records, for jq
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
```text
|
|
281
|
+
09:14:02 — stratusd ready — 3 agents, slack connected
|
|
282
|
+
09:14:31 ava session.created [slack:ava:T01ABCDEF:C07GHIJKL:1731900000.123456]
|
|
283
|
+
09:14:36 ava tool.completed tool=memory.remember ok=true [slack:ava:T01ABCDEF:C07GHIJKL:1731900000.123456]
|
|
284
|
+
09:21:07 — warning: anthropic returned 529; retrying on the fallback model
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Session ids are the channel's own key — `channel:agent:team:conversation[:thread]`
|
|
288
|
+
— so the id in the last column is exactly what `--session` wants, and the same
|
|
289
|
+
conversation keeps it across daemon restarts.
|
|
290
|
+
|
|
291
|
+
The log is a **trace, not a second transcript**: it records that a tool ran and
|
|
292
|
+
that a session completed, with the tool's name, the agent, and the session id.
|
|
293
|
+
Prompts, replies, and tool inputs are not written — what was said lives in the
|
|
294
|
+
session store instead.
|
|
295
|
+
|
|
296
|
+
One exception worth knowing before you paste a log anywhere. A failed session
|
|
297
|
+
records the **provider's error text verbatim**, and providers routinely quote
|
|
298
|
+
the request that failed — so a malformed prompt can end up inside an error
|
|
299
|
+
message. Skim a log before sharing it, and prefer `--agent` or `--session` to
|
|
300
|
+
narrow it to the run you actually mean.
|
|
301
|
+
|
|
302
|
+
### When the log is empty
|
|
303
|
+
|
|
304
|
+
A daemon that fails *before* it starts serving — a broken install, an
|
|
305
|
+
unreadable credentials file — never gets as far as opening the structured log,
|
|
306
|
+
so `stratus logs` shows nothing or shows yesterday. Those errors go to stderr,
|
|
307
|
+
and where stderr lands is the service manager's business, so it differs by
|
|
308
|
+
platform:
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
tail ~/.stratus/logs/stratusd.err.log # macOS
|
|
312
|
+
journalctl --user-unit=stratusd.service # Linux
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
That is where a restart loop explains itself. On macOS the LaunchAgent redirects
|
|
316
|
+
both streams to files, so Stratus truncates them when `serve` starts and every
|
|
317
|
+
five minutes while it runs — a crash loop cannot fill the disk with the same
|
|
318
|
+
error a million times. On Linux systemd keeps the same output in the journal
|
|
319
|
+
instead, which does its own rotation, so there is nothing beside the JSONL to
|
|
320
|
+
bound and nothing to clean up.
|
|
321
|
+
|
|
322
|
+
## When something looks off
|
|
323
|
+
|
|
324
|
+
`stratus doctor` answers one question — *what would a run use right now, and
|
|
325
|
+
who decided that?* Every setting is shown with the file or environment variable
|
|
326
|
+
it came from, because the answer is usually that something outranks what you
|
|
327
|
+
thought you configured:
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
stratus doctor
|
|
331
|
+
stratus doctor --format json
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
```text
|
|
335
|
+
Stratus Agent — what a run would use right now
|
|
336
|
+
|
|
337
|
+
provider anthropic
|
|
338
|
+
from ~/.stratus/agents/ava.md (soul frontmatter)
|
|
339
|
+
model claude-opus-5
|
|
340
|
+
from ~/.stratus/agents/ava.md (soul frontmatter)
|
|
341
|
+
soul ~/.stratus/agents/ava.md
|
|
342
|
+
from ~/.stratus/config.json
|
|
343
|
+
agent Ava (ava)
|
|
344
|
+
|
|
345
|
+
Files
|
|
346
|
+
config ~/.stratus/config.json
|
|
347
|
+
agents 1 soul file
|
|
348
|
+
|
|
349
|
+
Sign-ins
|
|
350
|
+
anthropic Claude subscription (Pro/Max) — runs go through the Claude Code runtime
|
|
351
|
+
openai not signed in
|
|
352
|
+
|
|
353
|
+
Channels
|
|
354
|
+
slack no agents connected
|
|
355
|
+
@stratusagent/channel-slack installed
|
|
356
|
+
|
|
357
|
+
1 problem found:
|
|
358
|
+
! A fallback model (gpt-4.1-mini) is configured but could not be resolved — usually
|
|
359
|
+
no sign-in for its provider. A failing primary model has nothing to retry on.
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
It resolves the config exactly the way a run does rather than re-deriving the
|
|
363
|
+
rules, so what it prints is what you would get. It exits non-zero when it finds
|
|
364
|
+
a problem, and it is the fastest answer to the two most common surprises: a run
|
|
365
|
+
that turns out to be on the `demo` provider, and an `ANTHROPIC_API_KEY` in the
|
|
366
|
+
environment quietly demoting a Claude subscription sign-in to per-token billing.
|
|
367
|
+
|
|
45
368
|
## Agents are people
|
|
46
369
|
|
|
47
370
|
An agent's identity lives in a **soul file** — markdown with frontmatter for the structured parts (name, provider, model, tool allowlists) and prose for the personality:
|
|
@@ -61,6 +384,44 @@ You are a sharp, warm generalist. Answer first, explain second...
|
|
|
61
384
|
|
|
62
385
|
Agents remember: facts saved with the built-in `memory.remember` tool persist to `~/.stratus/memory.jsonl`, keyed to the agent — so the Ava you talk to tomorrow remembers today, from any directory.
|
|
63
386
|
|
|
387
|
+
**Ids are not labels.** Frontmatter may set `id:` explicitly, and it keys the
|
|
388
|
+
agent's sessions, memory, credentials, Slack tokens, and every per-agent path
|
|
389
|
+
on disk. So it has to stay one path segment, and one ordinary map key: an id
|
|
390
|
+
may not start with a dot or contain a slash, a backslash, a control
|
|
391
|
+
character, or leading or trailing whitespace, and it may not be a name every
|
|
392
|
+
object already answers to (`__proto__`, `constructor`, `toString`). Anything that would leave its directory is rejected when the soul
|
|
393
|
+
loads rather than quietly cleaned up — `id: ../../escape` is refused, not
|
|
394
|
+
rewritten to `escape`.
|
|
395
|
+
|
|
396
|
+
Anything else is yours. An id like `Ava_1` or `team.alpha` is unusual but
|
|
397
|
+
harmless, and it is already keying that agent's sessions and sign-ins, so it
|
|
398
|
+
is left exactly as written. Omit `id:` and one is derived from the name as a
|
|
399
|
+
plain slug (`ava`); a generated agent's id is also capped at 64 characters,
|
|
400
|
+
but a slug derived from a name you chose is used whole, because shortening
|
|
401
|
+
an id moves the agent it belongs to.
|
|
402
|
+
|
|
403
|
+
Creating an agent checks the id against every id the served roster holds,
|
|
404
|
+
not against the filenames on disk: what the roster files *declare* (a soul
|
|
405
|
+
at `renamed.md` can declare `id: ava`), the configured default soul even
|
|
406
|
+
when its file lives elsewhere, and the reserved `stratus`. A new agent gets
|
|
407
|
+
a suffixed id (`ava-3f9c`) rather than one that would collide. Its name
|
|
408
|
+
stays the one you chose.
|
|
409
|
+
|
|
410
|
+
**Two souls cannot share an id.** That is not two agents; it is one agent
|
|
411
|
+
whose memory and sign-ins belong to whichever file sorted first. The roster
|
|
412
|
+
refuses to load and names both files, `stratus serve` will not start,
|
|
413
|
+
`stratus doctor` reports it, and `stratus setup` → Channels offers no
|
|
414
|
+
agents at all — nothing is servable while the roster is ambiguous, so
|
|
415
|
+
connecting a Slack app would configure something that cannot run. Neither
|
|
416
|
+
command offers to clear "unmatched" Slack tokens in that state either: a
|
|
417
|
+
roster that would not load cannot prove which ids are missing, and the
|
|
418
|
+
tokens at risk belong to agents that are perfectly fine. (An unreadable *single* soul still degrades to a
|
|
419
|
+
warning — one broken file never takes the team down. A collision has no
|
|
420
|
+
correct winner, which is the difference.) The built-in `stratus` id is
|
|
421
|
+
reserved: souls claiming it are skipped — including two of them, since
|
|
422
|
+
neither was going to get the id, so their agreeing on it is not a collision
|
|
423
|
+
to refuse over.
|
|
424
|
+
|
|
64
425
|
## Options
|
|
65
426
|
|
|
66
427
|
| Flag | Purpose |
|
|
@@ -70,12 +431,19 @@ Agents remember: facts saved with the built-in `memory.remember` tool persist to
|
|
|
70
431
|
| `--model` | Model for real providers (anthropic default: `claude-opus-5`) |
|
|
71
432
|
| `--base-url` | Override the provider API base URL |
|
|
72
433
|
| `--config <file>` | Load settings from a specific config file |
|
|
73
|
-
| `--approvals` |
|
|
434
|
+
| `--approvals` | `run`/`chat`: tool approval mode — `always`, `ask`, or `never`. `serve`: how the daemon reaches a human — `headless` (refuse gated calls) or `remote` (ask in Slack); overrides the config's `approvals.mode` |
|
|
74
435
|
| `--max-turns` | Max provider turns per run (default 8) |
|
|
75
436
|
| `--format` | `text` or `json` |
|
|
437
|
+
| `--idle-timeout` | `stratus serve`: seconds of provider silence before the watchdog aborts a turn (default 120) |
|
|
438
|
+
| `--no-events` | Hide the event log |
|
|
439
|
+
| `--no-log-file` | `stratus serve`: do not write `~/.stratus/logs/stratusd.jsonl` |
|
|
440
|
+
| `--no-login` | `stratus service install`: install without the start-at-login trigger |
|
|
441
|
+
| `-f`, `--follow` | `stratus logs`: follow the log, across rotations |
|
|
442
|
+
| `-n <count>` | `stratus logs`: how much backlog to print (default 50) |
|
|
443
|
+
| `--agent`, `--session` | `stratus logs`: show only one agent's or one session's records |
|
|
76
444
|
|
|
77
445
|
Precedence: flags → `STRATUS_*` env vars → soul file hints → config file. Project-local `stratus.config.json` outranks the global `~/.stratus/config.json`; stored sign-ins are endpoint-bound and never sent to endpoints a project config selects.
|
|
78
446
|
|
|
79
|
-
Today the CLI covers setup, chat, one-shot runs, agent creation, and the local dashboard
|
|
447
|
+
Today the CLI covers setup, chat, one-shot runs, agent creation, the always-on gateway and its service integration, logs, diagnostics, Slack, and the local dashboard. More channels — and one control API that every surface talks to — are next.
|
|
80
448
|
|
|
81
449
|
Part of [Stratus Agent](https://github.com/stratuslabs/agent) — a tiny TypeScript agent runtime.
|
package/dist/bin.js
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { runCli } from "./index.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import { runCli, unsupportedNodeMessage } from "./index.js";
|
|
3
|
+
// Before anything else imports: the point is to explain the floor rather
|
|
4
|
+
// than to fail somewhere further in with a builtin-module error.
|
|
5
|
+
const unsupported = unsupportedNodeMessage(process.versions.node);
|
|
6
|
+
if (unsupported) {
|
|
7
|
+
process.stderr.write(`${unsupported}\n`);
|
|
8
|
+
process.exitCode = 1;
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
const exitCode = await runCli({ argv: process.argv.slice(2) });
|
|
12
|
+
if (exitCode !== 0) {
|
|
13
|
+
process.exitCode = exitCode;
|
|
14
|
+
}
|
|
6
15
|
}
|
|
7
16
|
//# sourceMappingURL=bin.js.map
|
package/dist/bin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAE5D,yEAAyE;AACzE,iEAAiE;AACjE,MAAM,WAAW,GAAG,sBAAsB,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAClE,IAAI,WAAW,EAAE,CAAC;IAChB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,WAAW,IAAI,CAAC,CAAC;IACzC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC;KAAM,CAAC;IACN,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC/D,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;QACnB,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC9B,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { type JsonValue, type Session, type StratusEvent } from '@stratusagent/core';
|
|
2
|
-
import { type RuntimeConfig, type StratusProviderName } from '@stratusagent/state';
|
|
2
|
+
import { type CredentialProviderName, type RuntimeSelection, type RuntimeConfig, type StratusProviderName } from '@stratusagent/state';
|
|
3
|
+
import { type ServiceRunner } from './service.ts';
|
|
4
|
+
export { installService, launchdPlist, readServiceStatus, servicePlatform, serviceUnitPath, startService, stopService, systemdUnit, uninstallService, SERVICE_LABEL, type ServiceRunner, type ServiceStatus, } from './service.ts';
|
|
5
|
+
export { createLogWriter, currentLogPosition, truncateRedirectLogs, formatLogRecord, parseLogLines, readRecentRecords, tailLog, type LogRecord, } from './logs.ts';
|
|
3
6
|
export { createFileMemoryStore } from '@stratusagent/state';
|
|
4
7
|
export type { StoredCredential, RuntimeConfig } from '@stratusagent/state';
|
|
5
8
|
export interface CliStreams {
|
|
@@ -20,6 +23,8 @@ export interface CliEnvironment {
|
|
|
20
23
|
dashboardAutoShutdownMs?: number;
|
|
21
24
|
/** Shuts down `stratus serve` the way SIGTERM would (tests). */
|
|
22
25
|
shutdownSignal?: AbortSignal;
|
|
26
|
+
/** Runs launchctl/systemctl. Injected so tests never touch the real one. */
|
|
27
|
+
serviceRunner?: ServiceRunner;
|
|
23
28
|
}
|
|
24
29
|
export interface CliRunOptions {
|
|
25
30
|
argv: string[];
|
|
@@ -74,27 +79,93 @@ export interface ParsedAgentsCommand {
|
|
|
74
79
|
command: 'agents';
|
|
75
80
|
format: 'text' | 'json';
|
|
76
81
|
}
|
|
82
|
+
export interface ParsedDoctorCommand {
|
|
83
|
+
command: 'doctor';
|
|
84
|
+
format: 'text' | 'json';
|
|
85
|
+
configPath?: string;
|
|
86
|
+
}
|
|
87
|
+
export interface ParsedServiceCommand {
|
|
88
|
+
command: 'service';
|
|
89
|
+
action: 'install' | 'uninstall' | 'status' | 'start' | 'stop';
|
|
90
|
+
/** install only: start automatically at login. Defaults to true. */
|
|
91
|
+
runAtLogin?: boolean;
|
|
92
|
+
/** install only: the config the managed daemon should load. */
|
|
93
|
+
configPath?: string;
|
|
94
|
+
}
|
|
95
|
+
export interface ParsedLogsCommand {
|
|
96
|
+
command: 'logs';
|
|
97
|
+
/** Keep streaming new records instead of exiting after the backlog. */
|
|
98
|
+
follow: boolean;
|
|
99
|
+
/** How many recent records to show before following. */
|
|
100
|
+
limit: number;
|
|
101
|
+
agentId?: string;
|
|
102
|
+
sessionId?: string;
|
|
103
|
+
format: 'text' | 'json';
|
|
104
|
+
}
|
|
105
|
+
export type ServeApprovalMode = 'headless' | 'remote';
|
|
77
106
|
export interface ParsedServeCommand {
|
|
78
107
|
command: 'serve';
|
|
79
108
|
configPath?: string;
|
|
109
|
+
/** Overrides `approvals.mode` in the config file. */
|
|
110
|
+
approvals?: ServeApprovalMode;
|
|
80
111
|
/** Watchdog idle timeout in milliseconds. 0 disables. */
|
|
81
112
|
idleTimeoutMs?: number;
|
|
82
113
|
events: boolean;
|
|
114
|
+
/** Write the structured log to ~/.stratus/logs. Defaults to true. */
|
|
115
|
+
logToFile?: boolean;
|
|
83
116
|
}
|
|
84
117
|
export interface ParsedHelpCommand {
|
|
85
118
|
command: 'help';
|
|
86
119
|
}
|
|
87
|
-
export type ParsedCommand = ParsedRunCommand | ParsedChatCommand | ParsedDashboardCommand | ParsedSetupCommand | ParsedAgentNewCommand | ParsedAgentsCommand | ParsedServeCommand | ParsedHelpCommand;
|
|
120
|
+
export type ParsedCommand = ParsedRunCommand | ParsedChatCommand | ParsedDashboardCommand | ParsedSetupCommand | ParsedAgentNewCommand | ParsedAgentsCommand | ParsedDoctorCommand | ParsedLogsCommand | ParsedServiceCommand | ParsedServeCommand | ParsedHelpCommand;
|
|
88
121
|
export interface DashboardServerHandle {
|
|
89
122
|
url: string;
|
|
90
123
|
close: () => Promise<void>;
|
|
91
124
|
}
|
|
92
|
-
export declare const CLI_VERSION = "0.
|
|
93
|
-
|
|
125
|
+
export declare const CLI_VERSION = "0.4.0";
|
|
126
|
+
/**
|
|
127
|
+
* The range every package declares in its `engines` field. Two floors, not
|
|
128
|
+
* one: `node:sqlite` was unflagged in 22.13.0 on the LTS line and in 23.4.0
|
|
129
|
+
* on the 23.x line, so 23.0 through 23.3 are NEWER than the 22.x floor and
|
|
130
|
+
* still ship it behind `--experimental-sqlite`. A plain `>=22.13` admits
|
|
131
|
+
* exactly those releases.
|
|
132
|
+
*/
|
|
133
|
+
export declare const SUPPORTED_NODE_RANGE = ">=22.13 <23 || >=23.4";
|
|
134
|
+
/**
|
|
135
|
+
* Why the CLI checks a version its manifests already declare: `engines` is
|
|
136
|
+
* advisory. npm and pnpm print EBADENGINE and carry on unless the user has
|
|
137
|
+
* turned on engine-strict, so an install on Node 20 succeeds and the floor
|
|
138
|
+
* is discovered later as an ERR_UNKNOWN_BUILTIN_MODULE for `node:sqlite`,
|
|
139
|
+
* thrown from a lazy import inside whichever command first needed the
|
|
140
|
+
* session store. That error names neither Node nor the version required.
|
|
141
|
+
*
|
|
142
|
+
* Returns the message to print, or undefined when the version is fine —
|
|
143
|
+
* including when it cannot be parsed at all, since an unrecognized build
|
|
144
|
+
* string is a bad reason to refuse to run.
|
|
145
|
+
*/
|
|
146
|
+
export declare const unsupportedNodeMessage: (version: string) => string | undefined;
|
|
147
|
+
declare const HELP_TEXT = "Stratus Agent CLI\n\nUsage:\n stratus setup\n stratus chat\n stratus chat --soul ./examples/souls/ava.md\n stratus run --prompt \"Use the demo tool\"\n stratus run \"Say hello\"\n ANTHROPIC_API_KEY=... stratus run --provider anthropic \"Say hello\"\n stratus run --soul ./examples/souls/ava.md \"Say hello\"\n echo \"Use the echo tool\" | stratus run --stdin\n STRATUS_PROVIDER=openai OPENAI_API_KEY=... stratus run \"Say hello\"\n stratus run --config ./stratus.config.json --provider openai \"Say hello\"\n stratus agents\n stratus doctor\n stratus service install\n stratus service status\n stratus logs -f\n stratus logs --agent ava -n 200\n stratus dashboard\n stratus dashboard --port 4123 --host 0.0.0.0 --no-open\n\nCommands:\n setup Menu-driven onboarding: pick a provider, sign in (Claude\n subscription or API key), create your agent, connect it to\n Slack, and test it \u2014 settings go to ~/.stratus/config.json,\n sign-ins and channel tokens to ~/.stratus/credentials.json\n (0600)\n chat Talk with your agent \u2014 the conversation persists across turns\n and remembered facts accumulate; /exit or Ctrl+C to leave\n run Execute one local Stratus Agent session\n serve Run stratusd, the always-on gateway: durable sessions, the\n whole roster live at once (each agent on its own provider),\n delegation, and a watchdog \u2014 Ctrl+C / SIGTERM drains cleanly\n (--idle-timeout <seconds>, --approvals <headless|remote>,\n --no-events, --no-log-file, --config <path>); everything it\n says is also written to ~/.stratus/logs, which\n \"stratus logs\" reads\n service Keep stratusd running under launchd (macOS) or systemd\n (Linux): install, uninstall, status, start, stop.\n Installing starts it now and at every login\n (--no-login installs without the login trigger,\n --config <path> pins the daemon to one config file)\n logs Read the daemon's log from any terminal: -f to follow,\n -n <count> for backlog, --agent / --session to filter,\n --format json for the raw records\n agent new Create an agent identity (generates a human-ish name + avatar theme)\n agents List your agents: who they are, where their souls live, what\n they run on, what they remember (also: stratus agent list)\n doctor Show what a run would use right now \u2014 provider, model, soul \u2014\n and which file or environment variable decided each, then\n flag anything that would surprise you (--format json)\n dashboard Start the local Stratus Agent dashboard and open it in your browser\n help Show this help message\n\nAgent options:\n --name Agent name (omit to have one generated)\n --instructions The agent's persona/instructions\n --format Output format for agent new: text, json, or soul (a ready-to-edit soul file)\n\nOptions:\n --prompt, -p Prompt to send to the local agent loop\n --stdin Read the prompt from stdin\n --provider Provider to use: anthropic, openai, or demo\n --model Model name for real providers (anthropic default: claude-opus-5, openai default: gpt-4.1-mini)\n --base-url Override the provider API base URL\n --soul Run as the agent defined by a soul file (markdown + frontmatter, see examples/souls)\n --config Config file path (run: load settings from it, setup: write it)\n --format Output format: text or json (default: text)\n --no-events Hide event-by-event progress lines in text mode\n --approvals run/chat: tool approval mode \u2014 always, ask, or never (default: always)\n serve: how the daemon reaches a human \u2014 headless (refuse every\n gated call) or remote (ask in Slack). Default headless, or\n the config file's \"approvals.mode\"\n --max-turns Maximum provider turns per run (default: 8)\n --port Dashboard port, defaults to an open local port\n --host Dashboard host (default: 127.0.0.1)\n --no-open Do not open the browser automatically\n --help, -h Show this help message\n\nConfig file:\n The CLI looks for ./stratus.config.json first, then a path from --config / STRATUS_CONFIG,\n then the global ~/.stratus/config.json written by `stratus setup`.\n A \"soul\" key (or STRATUS_SOUL) points at a soul file so every run uses that agent.\n Legacy STRATUSCLAW_* env vars and stratusclaw.config.json are still supported for compatibility.\n\nSoul files:\n A soul file is markdown with frontmatter (name, provider, model, tools, credentials)\n followed by the agent's persona in prose. See examples/souls/ava.md.\n";
|
|
94
148
|
declare const stringifyValue: (value: JsonValue) => string;
|
|
95
149
|
export declare const parseCommand: (argv: string[], env?: CliEnvironment) => ParsedCommand;
|
|
96
150
|
export declare const formatEvent: (event: StratusEvent) => string | null;
|
|
97
|
-
|
|
151
|
+
/**
|
|
152
|
+
* Kept with its historical CLI signature: a parsed run command is a
|
|
153
|
+
* RuntimeSelection plus CLI-only fields the resolver ignores.
|
|
154
|
+
*
|
|
155
|
+
* Those fields are *permitted*, not required. Demanding a whole
|
|
156
|
+
* `ParsedRunCommand` made the type claim the resolver cared about
|
|
157
|
+
* `approvals`, `format`, and `events` — it reads none of them — so every
|
|
158
|
+
* caller with a selection in hand had to invent values to get past it.
|
|
159
|
+
*/
|
|
160
|
+
export declare const resolveRuntimeConfig: (command: RuntimeSelection & Partial<Omit<ParsedRunCommand, keyof RuntimeSelection>>, env?: CliEnvironment) => Promise<RuntimeConfig>;
|
|
161
|
+
/**
|
|
162
|
+
* A saved subscription sign-in silently demoted to per-token billing is the
|
|
163
|
+
* one config surprise that costs money — an API key in the environment
|
|
164
|
+
* outranks the stored credential, and the run otherwise looks identical.
|
|
165
|
+
* Detected from the resolved config: an apiKey where the stored credential
|
|
166
|
+
* is a subscription token means the environment won.
|
|
167
|
+
*/
|
|
168
|
+
export declare const warnOnCredentialOverride: (runtime: RuntimeConfig, streams: CliStreams, env?: CliEnvironment) => Promise<void>;
|
|
98
169
|
export declare const runSingleLoop: (prompt: string, streams: CliStreams, options: {
|
|
99
170
|
events?: boolean;
|
|
100
171
|
runtime: RuntimeConfig;
|
|
@@ -109,8 +180,56 @@ export declare const startDashboardServer: (options: {
|
|
|
109
180
|
host: string;
|
|
110
181
|
port?: number;
|
|
111
182
|
}) => Promise<DashboardServerHandle>;
|
|
183
|
+
export declare const slackAppManifest: (agentName: string) => string;
|
|
112
184
|
export declare const runSetup: (command: ParsedSetupCommand, streams: CliStreams, env?: CliEnvironment) => Promise<number>;
|
|
113
185
|
export declare const runAgents: (command: ParsedAgentsCommand, streams: CliStreams, env?: CliEnvironment) => Promise<number>;
|
|
186
|
+
/** One resolved setting, with the thing that decided it. */
|
|
187
|
+
interface DoctorSetting {
|
|
188
|
+
value: string;
|
|
189
|
+
source: string;
|
|
190
|
+
}
|
|
191
|
+
export interface DoctorReport {
|
|
192
|
+
configInUse?: string;
|
|
193
|
+
/** Config files that exist but lost to `configInUse`, nearest first. */
|
|
194
|
+
configShadowed: string[];
|
|
195
|
+
provider: DoctorSetting;
|
|
196
|
+
model?: DoctorSetting;
|
|
197
|
+
soul?: DoctorSetting;
|
|
198
|
+
agent?: string;
|
|
199
|
+
/** The model a failing run retries on, when one is configured. */
|
|
200
|
+
fallback?: {
|
|
201
|
+
provider: string;
|
|
202
|
+
model: string;
|
|
203
|
+
};
|
|
204
|
+
signIns: Array<{
|
|
205
|
+
provider: CredentialProviderName;
|
|
206
|
+
status: string;
|
|
207
|
+
}>;
|
|
208
|
+
slackAgents: string[];
|
|
209
|
+
slackPackageInstalled: boolean;
|
|
210
|
+
rosterCount: number;
|
|
211
|
+
problems: string[];
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* `stratus doctor` — what a run would resolve to right now, and which file
|
|
215
|
+
* or variable decided each part. Every "why is it using X" question needs
|
|
216
|
+
* the precedence chain, and reading it out of the source is not something
|
|
217
|
+
* anyone should have to do.
|
|
218
|
+
*/
|
|
219
|
+
export declare const collectDoctorReport: (command: ParsedDoctorCommand, warn: (message: string) => void, env?: CliEnvironment) => Promise<DoctorReport>;
|
|
220
|
+
export declare const runDoctor: (command: ParsedDoctorCommand, streams: CliStreams, env?: CliEnvironment) => Promise<number>;
|
|
221
|
+
/**
|
|
222
|
+
* `stratus logs` — the daemon's structured log, filtered. `serve` streams
|
|
223
|
+
* to its own stdout, which is gone the moment it runs under a service
|
|
224
|
+
* manager; this reads the file it also writes, from any terminal.
|
|
225
|
+
*/
|
|
226
|
+
export declare const runLogs: (command: ParsedLogsCommand, streams: CliStreams, env?: CliEnvironment) => Promise<number>;
|
|
227
|
+
/**
|
|
228
|
+
* `stratus service` — run the daemon under launchd or systemd, so it
|
|
229
|
+
* survives logout, crashes, and reboots. `serve` itself stays a plain
|
|
230
|
+
* foreground process; this only tells the platform how to keep it up.
|
|
231
|
+
*/
|
|
232
|
+
export declare const runService: (command: ParsedServiceCommand, streams: CliStreams, env?: CliEnvironment) => Promise<number>;
|
|
114
233
|
export declare const runAgentNew: (command: ParsedAgentNewCommand, streams: CliStreams, env?: CliEnvironment) => Promise<number>;
|
|
115
234
|
export declare const runDashboard: (command: ParsedDashboardCommand, streams: CliStreams, env?: CliEnvironment) => Promise<number>;
|
|
116
235
|
/**
|