@sibylline-labs/eris 0.0.0-stage → 0.3.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/LICENSE +202 -0
- package/NOTICE +2 -0
- package/README.md +146 -2
- package/bin/eris.ts +42 -0
- package/docs/ARCHITECTURE.md +188 -0
- package/docs/COMPLETION.md +106 -0
- package/docs/ERRORS.md +632 -0
- package/docs/OUTPUT-CONTRACT.md +219 -0
- package/docs/README.md +30 -0
- package/docs/UPDATE.md +159 -0
- package/docs/YAK.md +395 -0
- package/docs/dev/ADDING-A-COMMAND.md +79 -0
- package/docs/dev/DEVELOPMENT.md +88 -0
- package/docs/dev/LAYOUT.md +74 -0
- package/docs/dev/PLUGINS.md +382 -0
- package/docs/dev/RELEASING.md +157 -0
- package/docs/dev/TESTING.md +84 -0
- package/docs/dev/surfaces/secrets.md +95 -0
- package/package.json +55 -4
- package/packages/yak-contract/package.json +28 -0
- package/packages/yak-contract/schema/yak-v2.schema.json +416 -0
- package/packages/yak-contract/src/index.ts +1 -0
- package/packages/yak-contract/src/v2.ts +375 -0
- package/plugins/index.ts +12 -0
- package/plugins/yak/handlers.ts +128 -0
- package/plugins/yak/index.ts +51 -0
- package/plugins/yak/login.ts +300 -0
- package/plugins/yak/yak-context.ts +280 -0
- package/plugins/yak/yak-identity.ts +399 -0
- package/plugins/yak/yak-redact.ts +686 -0
- package/plugins/yak/yak-setup.ts +133 -0
- package/plugins/yak/yak-submit.ts +1166 -0
- package/plugins/yak/yak.ts +485 -0
- package/src/build.ts +248 -0
- package/src/cli/args.ts +434 -0
- package/src/cli/commands/completion/bash.ts +24 -0
- package/src/cli/commands/completion/domain.ts +203 -0
- package/src/cli/commands/completion/emit.ts +246 -0
- package/src/cli/commands/completion/shell.ts +24 -0
- package/src/cli/commands/completion/zsh.ts +24 -0
- package/src/cli/commands/completion.ts +48 -0
- package/src/cli/commands/update/github.ts +328 -0
- package/src/cli/commands/update/opt-in.ts +32 -0
- package/src/cli/commands/update/refusal.ts +21 -0
- package/src/cli/commands/update/release.ts +351 -0
- package/src/cli/commands/update/replace.ts +143 -0
- package/src/cli/commands/update/semver.ts +48 -0
- package/src/cli/commands/update.ts +47 -0
- package/src/cli/commands/usage.ts +68 -0
- package/src/cli/commands/version.ts +29 -0
- package/src/cli/compose.ts +273 -0
- package/src/cli/output.ts +81 -0
- package/src/cli/plugin.ts +85 -0
- package/src/cli/registry.ts +180 -0
- package/src/cli/router.ts +31 -0
- package/src/cli/ts-verb.ts +126 -0
- package/src/main.ts +223 -0
- package/src/runtime/env.ts +16 -0
- package/src/runtime/eris-assets.d.ts +5 -0
- package/src/runtime/home.ts +306 -0
- package/src/runtime/logging.ts +43 -0
- package/src/runtime/process.ts +388 -0
- package/src/runtime/settings.ts +191 -0
- package/src/sdk.ts +62 -0
- package/testing/build-child.ts +55 -0
- package/testing/fake-runner.ts +23 -0
- package/testing/index.ts +16 -0
- package/ts/lib/eris-fail.ts +180 -0
- package/ts/lib/pool.ts +63 -0
package/docs/ERRORS.md
ADDED
|
@@ -0,0 +1,632 @@
|
|
|
1
|
+
# eris failure model
|
|
2
|
+
|
|
3
|
+
Hard failures go through `renderFailureBlock` / `emitFailureAndExit`
|
|
4
|
+
(`ts/lib/eris-fail.ts`), which print one
|
|
5
|
+
actionable block and exit `1` immediately — a first failure never cascades
|
|
6
|
+
into follow-on ERROR lines. Output is one-line-per-field with stable prefixes
|
|
7
|
+
(all on stderr; stdout stays clean):
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
ERROR <what failed> # concrete — names the exact key/env/secret slot
|
|
11
|
+
slug: <slug> # stable machine key; heading in this file
|
|
12
|
+
fix: <line> # the exact command to run / eris.yaml block to add
|
|
13
|
+
docs: <local path> # $ERIS_HOME/docs/... (the checkout, or a binary's asset home)
|
|
14
|
+
docs: <github url> # same doc on github.com/sibylline-labs/eris
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
This block is a **parseable format, not a layout** — consumers line-prefix-parse
|
|
18
|
+
it today. Its full grammar (field order, the exact prefixes *including the
|
|
19
|
+
single trailing space* after `slug:` / `fix:` / `docs:`, the one-block rule, and
|
|
20
|
+
what a consumer may and may not assume) is specified in
|
|
21
|
+
[OUTPUT-CONTRACT.md §4](OUTPUT-CONTRACT.md#4-the-failure-block). Change the
|
|
22
|
+
grammar there and here in the same commit, never in one alone.
|
|
23
|
+
|
|
24
|
+
Agents: match on the `slug:` line, apply the `fix:` lines verbatim (yaml blocks
|
|
25
|
+
are indented continuation lines), read `docs:` for depth. Error messages name
|
|
26
|
+
the slot/path being resolved — never secret contents.
|
|
27
|
+
|
|
28
|
+
Exit codes: `1` = hard failure (a failure block or a `die`). `2` = idempotent
|
|
29
|
+
no-op where a command documents one.
|
|
30
|
+
The full stream + exit-code contract is
|
|
31
|
+
[OUTPUT-CONTRACT.md §1](OUTPUT-CONTRACT.md#1-the-stream-split).
|
|
32
|
+
|
|
33
|
+
## Slugs
|
|
34
|
+
|
|
35
|
+
### flag-value-missing
|
|
36
|
+
|
|
37
|
+
A value-taking flag was given no value, or was given the NEXT FLAG as its
|
|
38
|
+
value. A bare "is it non-empty" guard accepts both: `--owner --yes` would store
|
|
39
|
+
`owner: "--yes"` at exit 0 and swallow the `--yes`, which then re-arms the
|
|
40
|
+
confirmation gate the caller had already answered, so the parser
|
|
41
|
+
(`src/cli/args.ts`) refuses a value flag followed by another flag. The joined form (`--flag=value`) is checked for emptiness
|
|
42
|
+
only: an empty `--required=` once registered the opposite of what was asked
|
|
43
|
+
for.
|
|
44
|
+
|
|
45
|
+
### output-format-unknown
|
|
46
|
+
|
|
47
|
+
`--output` was given something other than `text` or `json` (or was given no
|
|
48
|
+
value at all). The flag is global and is parsed once in the entrypoint
|
|
49
|
+
(`parseGlobal`, `src/cli/args.ts`); there is no `ERIS_OUTPUT` env var, so
|
|
50
|
+
the flag is the only selector. Fix: `eris --output json <command>` for the
|
|
51
|
+
machine rendering, `--output text` (the default) for the human one. See
|
|
52
|
+
[OUTPUT-CONTRACT.md](OUTPUT-CONTRACT.md#2-the-flag).
|
|
53
|
+
|
|
54
|
+
### output-json-unsupported
|
|
55
|
+
|
|
56
|
+
`--output json` was asked of a command that has no JSON rendering. eris refuses
|
|
57
|
+
rather than falling back to the human rendering: a silent fallback hands a
|
|
58
|
+
parser a table, and the caller discovers it as a JSON syntax error somewhere
|
|
59
|
+
downstream instead of as a refusal here.
|
|
60
|
+
|
|
61
|
+
The refusal's `fix:` lines name the surfaces that accept it, including every
|
|
62
|
+
json row a plugin adds. Full table: [OUTPUT-CONTRACT.md](OUTPUT-CONTRACT.md#3-machine-surfaces).
|
|
63
|
+
|
|
64
|
+
### command-locked
|
|
65
|
+
|
|
66
|
+
A plugin command belongs to a product this workspace has not bought, so it is
|
|
67
|
+
locked (`src/cli/compose.ts`). Plugins compile into the binary, and the
|
|
68
|
+
entitlement check runs per command line: the command's help still prints, with a
|
|
69
|
+
`Locked:` line, and `eris --help` marks the group `[locked: <product>]`. Nothing
|
|
70
|
+
from the plugin's handler runs.
|
|
71
|
+
|
|
72
|
+
Fix: add the named product to the workspace, then run the command again.
|
|
73
|
+
Authoring side: [dev/PLUGINS.md](dev/PLUGINS.md#entitlements).
|
|
74
|
+
|
|
75
|
+
### eris-bun-missing
|
|
76
|
+
|
|
77
|
+
> Raised by the `eris` shim, before any command runs.
|
|
78
|
+
|
|
79
|
+
`bun` is not on `PATH`. The `eris` entrypoint is a POSIX `sh` shim that execs
|
|
80
|
+
`src/main.ts` under bun, and that router runs every command, so no command runs
|
|
81
|
+
without bun.
|
|
82
|
+
The shim renders this block itself, since nothing past it can run.
|
|
83
|
+
|
|
84
|
+
Fix: install bun (<https://bun.sh>), then run `bun install --frozen-lockfile` in the
|
|
85
|
+
eris checkout (the `node_modules` the verbs need). An installed package
|
|
86
|
+
(`npx @sibylline-labs/eris`) needs bun too.
|
|
87
|
+
|
|
88
|
+
### eris-cache-unwritable
|
|
89
|
+
|
|
90
|
+
> Raised by the entrypoint (`src/main.ts`) in a compiled eris binary, before the
|
|
91
|
+
> command runs.
|
|
92
|
+
|
|
93
|
+
The compiled binary carries the repo files it reads (the docs a failure block
|
|
94
|
+
names) and writes one copy per build to
|
|
95
|
+
`${ERIS_CACHE_DIR:-${XDG_CACHE_HOME:-~/.cache}/eris}/<build id>/` the first time
|
|
96
|
+
it runs. That directory could not be written: the filesystem is read-only or
|
|
97
|
+
full, the directory belongs to someone else, or a file sits where a directory
|
|
98
|
+
should be. The `ERROR` line names the cache directory and the operating
|
|
99
|
+
system's own reason.
|
|
100
|
+
|
|
101
|
+
`eris --help`, a `--help` on any command, and `eris completion` still run, since
|
|
102
|
+
they read none of those files and are how an operator finds this out. Every other
|
|
103
|
+
command is refused, because it may read one.
|
|
104
|
+
|
|
105
|
+
No asset home exists to hold the docs, so this block's first `docs:` line is the
|
|
106
|
+
repo-relative path rather than an absolute one. The second is the GitHub URL.
|
|
107
|
+
|
|
108
|
+
Fix: set `ERIS_CACHE_DIR` to a directory eris can write, or `XDG_CACHE_HOME` (eris
|
|
109
|
+
uses `$XDG_CACHE_HOME/eris`). On a read-only root filesystem, point it at a writable
|
|
110
|
+
volume. A checkout or an installed package writes no cache.
|
|
111
|
+
|
|
112
|
+
### eris-deps-not-installed
|
|
113
|
+
|
|
114
|
+
> Raised by the TypeScript verb runner (`src/cli/ts-verb.ts`), when a verb's
|
|
115
|
+
> module graph names a package the checkout's `node_modules` cannot resolve.
|
|
116
|
+
|
|
117
|
+
A TypeScript verb (every row the registry routes to `ts`, which is every row) is
|
|
118
|
+
imported lazily, and one of its packages is
|
|
119
|
+
missing: `node_modules` is absent, or is the install from before a pull that
|
|
120
|
+
added a dependency. The `ERROR` line names the package and the source file that
|
|
121
|
+
asked for it, instead of a bare `ERROR ResolveMessage: Cannot find package '…'`.
|
|
122
|
+
|
|
123
|
+
Fix: `bun install --frozen-lockfile` from the eris checkout (the `fix:` line names
|
|
124
|
+
the directory). eris does not run it for you: an inline install is unbounded and reaches the network mid-command.
|
|
125
|
+
|
|
126
|
+
Only a missing PACKAGE is reported this way. A missing relative module is a defect
|
|
127
|
+
in the checkout's own source and still crashes with bun's message.
|
|
128
|
+
|
|
129
|
+
### eris-verbose-fetch-set
|
|
130
|
+
|
|
131
|
+
> Raised by the package's `eris` command (`bin/eris.ts`), before any command runs.
|
|
132
|
+
|
|
133
|
+
`BUN_CONFIG_VERBOSE_FETCH` is set in the environment of an `eris` started from an
|
|
134
|
+
installed package (`npm i -g @sibylline-labs/eris`, `bun add -g`, `npx`, `bunx`).
|
|
135
|
+
Under that variable bun prints every fetch to stderr, the `Authorization` bearer
|
|
136
|
+
and the request body included, and for a secret write the body is the value. bun
|
|
137
|
+
reads it from its own environment when it fetches, and `delete process.env.X`
|
|
138
|
+
does not reach that read. The checkout's `eris` shim removes the variable before
|
|
139
|
+
bun starts; an installed command is started by its shebang and has no shim, so it
|
|
140
|
+
refuses to run rather than depend on an override from inside the process or print
|
|
141
|
+
a bearer token. No command runs, `--help` and `--version` included.
|
|
142
|
+
|
|
143
|
+
Fix: unset the variable, for the shell (`unset BUN_CONFIG_VERBOSE_FETCH`) or for
|
|
144
|
+
one command (`env -u BUN_CONFIG_VERBOSE_FETCH eris <command>`). The checkout's
|
|
145
|
+
shim and a compiled binary remove it themselves and never raise this.
|
|
146
|
+
|
|
147
|
+
### update-not-compiled
|
|
148
|
+
|
|
149
|
+
> Raised by a distribution's release `eris update` ([UPDATE.md](UPDATE.md#the-release-eris-update-distributions)) before any request.
|
|
150
|
+
|
|
151
|
+
This eris runs from source (a checkout, `./eris`), not from a compiled release
|
|
152
|
+
binary. A checkout has no single file to replace: it is a working tree under
|
|
153
|
+
version control.
|
|
154
|
+
|
|
155
|
+
Fix: update the checkout, `git pull && bun install --frozen-lockfile` in the
|
|
156
|
+
directory the `fix:` line names.
|
|
157
|
+
|
|
158
|
+
### update-unsupported-platform
|
|
159
|
+
|
|
160
|
+
> Raised by a distribution's release `eris update` ([UPDATE.md](UPDATE.md#the-release-eris-update-distributions)) before any request.
|
|
161
|
+
|
|
162
|
+
Releases publish a binary for `darwin-arm64` and `linux-x64` only, and this eris
|
|
163
|
+
was compiled for another platform (built from source on a machine with another
|
|
164
|
+
OS or CPU). There is no asset to download for it.
|
|
165
|
+
|
|
166
|
+
Fix: build eris from source for this platform and run that build; see
|
|
167
|
+
"From source" in the README. Updating means pulling and building again.
|
|
168
|
+
|
|
169
|
+
### update-api-invalid
|
|
170
|
+
|
|
171
|
+
> Raised by a distribution's release `eris update` ([UPDATE.md](UPDATE.md#the-release-eris-update-distributions)) before any request.
|
|
172
|
+
|
|
173
|
+
`ERIS_UPDATE_API`, the override for the releases API base (a GitHub Enterprise
|
|
174
|
+
host, or a test server), is set to something eris will not use: it is not a URL,
|
|
175
|
+
its scheme is neither `https` nor `http`, it is `http` to a host that is not
|
|
176
|
+
loopback, or it carries credentials, a query or a fragment. The refusal exists so
|
|
177
|
+
a stray variable cannot send a token in clear text to a host nobody chose. The
|
|
178
|
+
`ERROR` line shows the scheme and host only.
|
|
179
|
+
|
|
180
|
+
Fix: set it to an `https://` URL (for example `https://ghe.example.com/api/v3`),
|
|
181
|
+
or unset it to use `https://api.github.com`.
|
|
182
|
+
|
|
183
|
+
### update-token-invalid
|
|
184
|
+
|
|
185
|
+
> Raised by a distribution's release `eris update` ([UPDATE.md](UPDATE.md#the-release-eris-update-distributions)) before any request.
|
|
186
|
+
|
|
187
|
+
`GH_TOKEN` (or, when it is unset or blank, `GITHUB_TOKEN`) holds something no
|
|
188
|
+
GitHub token contains: a space or line break inside the value, or a non-ASCII
|
|
189
|
+
character. Leading and trailing whitespace is ignored, so a token read from a file
|
|
190
|
+
with its newline still works. The refusal names the variable and never shows its
|
|
191
|
+
value: sending such a value makes the HTTP client report an error that quotes it.
|
|
192
|
+
|
|
193
|
+
Fix: set the variable to the token alone, or unset it.
|
|
194
|
+
|
|
195
|
+
### update-unreachable
|
|
196
|
+
|
|
197
|
+
> Raised by a distribution's release `eris update` ([UPDATE.md](UPDATE.md#the-release-eris-update-distributions)) when the releases API or the download host does not
|
|
198
|
+
> answer.
|
|
199
|
+
|
|
200
|
+
The connection was refused, the name did not resolve, the connection dropped, or
|
|
201
|
+
a host went quiet: the API did not answer within 30 seconds, or a download sent
|
|
202
|
+
nothing for 60 seconds. Nothing was changed; a download in progress is removed.
|
|
203
|
+
|
|
204
|
+
Fix: check the network connection (eris update needs https access to
|
|
205
|
+
`api.github.com`, and to GitHub's release storage host for the download), then
|
|
206
|
+
run `eris update` again.
|
|
207
|
+
|
|
208
|
+
### update-rate-limited
|
|
209
|
+
|
|
210
|
+
> Raised by a distribution's release `eris update` ([UPDATE.md](UPDATE.md#the-release-eris-update-distributions)) when GitHub refuses the request for its rate limit.
|
|
211
|
+
|
|
212
|
+
GitHub answered 429, or 403 with the rate limit spent. An anonymous client gets
|
|
213
|
+
60 requests an hour per address; an authenticated one gets far more. `eris
|
|
214
|
+
update` makes up to three API requests per run. When GitHub reported when the
|
|
215
|
+
limit resets, the `ERROR` line says so.
|
|
216
|
+
|
|
217
|
+
Fix: set `GH_TOKEN` (or `GITHUB_TOKEN`) to a GitHub token. Any token works for
|
|
218
|
+
a public repository, with no scopes. If one is already set, its own limit is
|
|
219
|
+
spent: wait for the reset time, then run `eris update` again.
|
|
220
|
+
|
|
221
|
+
### update-needs-token
|
|
222
|
+
|
|
223
|
+
> Raised by a distribution's release `eris update` ([UPDATE.md](UPDATE.md#the-release-eris-update-distributions)) when GitHub answers 404 and no token is set.
|
|
224
|
+
|
|
225
|
+
GitHub answers 404, not 403, to a request that is not allowed to see a private
|
|
226
|
+
repository, so an anonymous 404 does not say whether the release is missing or
|
|
227
|
+
the repository is private. This refusal is the anonymous case.
|
|
228
|
+
|
|
229
|
+
Fix: if the repository is private, set `GH_TOKEN` (or `GITHUB_TOKEN`) to a token
|
|
230
|
+
that can read it and run `eris update` again. Otherwise the release does not
|
|
231
|
+
exist: list them at `https://github.com/<owner>/<repo>/releases`.
|
|
232
|
+
|
|
233
|
+
### update-release-not-found
|
|
234
|
+
|
|
235
|
+
> Raised by a distribution's release `eris update` ([UPDATE.md](UPDATE.md#the-release-eris-update-distributions)) when the release is not installable.
|
|
236
|
+
|
|
237
|
+
Either GitHub answered 404 to a request that carried a token, so the repository
|
|
238
|
+
has no such release (or the token cannot see the repository), or the release
|
|
239
|
+
found is a draft, or a prerelease that `--to` did not name. `eris update` installs
|
|
240
|
+
the latest published release; a prerelease only with `--to <tag>`.
|
|
241
|
+
|
|
242
|
+
Fix: check the tag against the repository's releases page. With a private
|
|
243
|
+
repository, the token must be able to read it.
|
|
244
|
+
|
|
245
|
+
### update-api-error
|
|
246
|
+
|
|
247
|
+
> Raised by a distribution's release `eris update` ([UPDATE.md](UPDATE.md#the-release-eris-update-distributions)) for any other answer the API gives.
|
|
248
|
+
|
|
249
|
+
An answer that is not a release and not one of the cases above: a 500, a 403 that
|
|
250
|
+
is not the rate limit, a 401 (the token was rejected, or the API wants one), a
|
|
251
|
+
body that is not a release record, a redirect chain that is too long or leaves
|
|
252
|
+
for a scheme eris will not follow, or a download larger than eris will accept.
|
|
253
|
+
The `ERROR` line names the host and the status.
|
|
254
|
+
|
|
255
|
+
Fix: for a 401, unset `GH_TOKEN` or replace it with a valid token. For a 403 on a
|
|
256
|
+
private repository, the token must be able to read it. Otherwise retry in a few
|
|
257
|
+
minutes.
|
|
258
|
+
|
|
259
|
+
### update-asset-missing
|
|
260
|
+
|
|
261
|
+
> Raised by a distribution's release `eris update` ([UPDATE.md](UPDATE.md#the-release-eris-update-distributions)) before it downloads the binary.
|
|
262
|
+
|
|
263
|
+
The release exists but cannot be installed: it lists no `eris-<os>-<arch>` for
|
|
264
|
+
this platform, no `SHA256SUMS`, or a `SHA256SUMS` with no line for this
|
|
265
|
+
platform's binary. eris never installs a binary it cannot check, so a release
|
|
266
|
+
without its checksum is refused. The same slug covers an asset the release lists
|
|
267
|
+
but the API answers 404 for.
|
|
268
|
+
|
|
269
|
+
Fix: choose another release with `eris update --to <tag>`.
|
|
270
|
+
|
|
271
|
+
### update-checksum-mismatch
|
|
272
|
+
|
|
273
|
+
> Raised by a distribution's release `eris update` ([UPDATE.md](UPDATE.md#the-release-eris-update-distributions)) after the download, before anything is replaced.
|
|
274
|
+
|
|
275
|
+
The downloaded binary's sha256 differs from the one in the release's
|
|
276
|
+
`SHA256SUMS`. The `ERROR` line gives both. The partial file is removed and the
|
|
277
|
+
installed binary is untouched.
|
|
278
|
+
|
|
279
|
+
Fix: run `eris update` again. If it repeats, the release is corrupt or has been
|
|
280
|
+
tampered with: do not install it.
|
|
281
|
+
|
|
282
|
+
### update-target-unwritable
|
|
283
|
+
|
|
284
|
+
> Raised by a distribution's release `eris update` ([UPDATE.md](UPDATE.md#the-release-eris-update-distributions)), before any request when it can tell.
|
|
285
|
+
|
|
286
|
+
The directory that holds the eris binary cannot be written, or a file there could
|
|
287
|
+
not be created: a read-only filesystem, a directory owned by another user (a
|
|
288
|
+
system-wide install), a full disk. `eris update` stages the new binary beside the
|
|
289
|
+
old one, so it needs write access to that directory, not only to the binary.
|
|
290
|
+
|
|
291
|
+
Fix: run `eris update` as a user who owns the directory, or reinstall eris into a
|
|
292
|
+
directory you own.
|
|
293
|
+
|
|
294
|
+
### update-smoke-failed
|
|
295
|
+
|
|
296
|
+
> Raised by a distribution's release `eris update` ([UPDATE.md](UPDATE.md#the-release-eris-update-distributions)) after the replacement.
|
|
297
|
+
|
|
298
|
+
The new binary was renamed into place and then run once (`eris --output json
|
|
299
|
+
--version`); it did not start, exited non-zero, did not answer within 20 seconds,
|
|
300
|
+
or reported a version other than the release's tag. The previous binary is put
|
|
301
|
+
back from `<binary>.old` and the `ERROR` line says so. If it could not be put
|
|
302
|
+
back, the `ERROR` line says that and the `fix:` line gives the `mv` that does it.
|
|
303
|
+
|
|
304
|
+
Fix: the release may be broken. Retry later, or install another with `eris update
|
|
305
|
+
--to <tag>`.
|
|
306
|
+
|
|
307
|
+
### yak-unknown-verb
|
|
308
|
+
|
|
309
|
+
`eris yak <verb>` was called with a verb other than `issue`, `suggest`, or
|
|
310
|
+
`fatal`. Fix: use one of those three.
|
|
311
|
+
|
|
312
|
+
### yak-unknown-flag
|
|
313
|
+
|
|
314
|
+
`eris yak` was given a flag it does not recognise. The full flag set is
|
|
315
|
+
`--summary`, `--body`/`--body-file`, `--evidence`/`--evidence-file`,
|
|
316
|
+
`--repro`, `--no-redact`, `--help`. Fix: `eris yak <verb> --help`.
|
|
317
|
+
|
|
318
|
+
### yak-positional-arg
|
|
319
|
+
|
|
320
|
+
`eris yak <verb>` was given a bare word, usually the report text itself
|
|
321
|
+
(`eris yak issue "the hook blocked a legal edit"`). The text rides on flags,
|
|
322
|
+
not positionals. Fix: `eris yak <verb> --summary "<one line>" --body "<what
|
|
323
|
+
happened>"`, or `--body-file <path|->` for a longer body.
|
|
324
|
+
|
|
325
|
+
### yak-flag-missing-value
|
|
326
|
+
|
|
327
|
+
A value-taking flag (`--summary`, `--body`, `--body-file`, `--evidence`,
|
|
328
|
+
`--evidence-file`, `--repro`) was the last token on the command line, with
|
|
329
|
+
nothing after it. Fix: pass the value, or drop the flag.
|
|
330
|
+
|
|
331
|
+
### yak-summary-required
|
|
332
|
+
|
|
333
|
+
`--summary` is required and was missing or empty. Fix: pass `--summary
|
|
334
|
+
"<text>"`, ≤200 chars.
|
|
335
|
+
|
|
336
|
+
### yak-body-required
|
|
337
|
+
|
|
338
|
+
Neither `--body` nor `--body-file` resolved to a non-empty string. Fix: pass
|
|
339
|
+
one of them.
|
|
340
|
+
|
|
341
|
+
### yak-body-conflicting-source
|
|
342
|
+
|
|
343
|
+
Both `--body` and `--body-file` were given. They are mutually exclusive — pass
|
|
344
|
+
exactly one.
|
|
345
|
+
|
|
346
|
+
### yak-evidence-conflicting-source
|
|
347
|
+
|
|
348
|
+
Both `--evidence` and `--evidence-file` were given. They are mutually
|
|
349
|
+
exclusive — pass exactly one, or neither (evidence is optional).
|
|
350
|
+
|
|
351
|
+
### yak-body-file-unreadable
|
|
352
|
+
|
|
353
|
+
`--body-file <path>` (or `--evidence-file <path>`, which raises the same slug
|
|
354
|
+
under the `evidence` label) could not be read — the path does not exist, or
|
|
355
|
+
the process lacks permission. Fix: check the path, or read stdin with `-`.
|
|
356
|
+
|
|
357
|
+
### yak-evidence-file-unreadable
|
|
358
|
+
|
|
359
|
+
The `--evidence-file` counterpart of
|
|
360
|
+
[`yak-body-file-unreadable`](#yak-body-file-unreadable) — same cause, same
|
|
361
|
+
fix, raised for the evidence field.
|
|
362
|
+
|
|
363
|
+
### yak-stdin-is-a-tty
|
|
364
|
+
|
|
365
|
+
`--body-file -` (or `--evidence-file -`) reads stdin, but stdin is a terminal
|
|
366
|
+
with nothing piped into it. Refused immediately rather than hanging forever on
|
|
367
|
+
a read that would never return. Fix: pipe the body in, e.g. `cat report.txt |
|
|
368
|
+
eris yak issue --summary "…" --body-file -`.
|
|
369
|
+
|
|
370
|
+
### yak-stdin-conflict
|
|
371
|
+
|
|
372
|
+
`--body-file -` and `--evidence-file -` were both given — only one stdin
|
|
373
|
+
exists to satisfy either. Fix: pass the other as inline text (`--evidence
|
|
374
|
+
"…"`) or a real file path.
|
|
375
|
+
|
|
376
|
+
### yak-summary-too-long
|
|
377
|
+
|
|
378
|
+
The (redacted) `summary` exceeds 200 chars. This is caught locally, before the
|
|
379
|
+
request, so the endpoint can never silently truncate it out of sync with the
|
|
380
|
+
idempotency key already derived from it. Fix: shorten it — redaction can grow
|
|
381
|
+
text, so check the real length with `--no-redact` if the count is surprising.
|
|
382
|
+
|
|
383
|
+
### yak-body-too-long
|
|
384
|
+
|
|
385
|
+
The `--body-file`/`--evidence-file` counterpart of
|
|
386
|
+
[`yak-summary-too-long`](#yak-summary-too-long) for the `body` field
|
|
387
|
+
(≤4000 chars). Same cause, same fix.
|
|
388
|
+
|
|
389
|
+
### yak-evidence-too-long
|
|
390
|
+
|
|
391
|
+
The `evidence` field exceeds 20000 chars. Same cause and fix as
|
|
392
|
+
[`yak-summary-too-long`](#yak-summary-too-long).
|
|
393
|
+
|
|
394
|
+
### yak-repro-too-long
|
|
395
|
+
|
|
396
|
+
The (redacted) `--repro <command>` exceeds 2000 chars — a local
|
|
397
|
+
courtesy bound, not a wire-contract one: `repro` rides inside `provenance`
|
|
398
|
+
(`provenance.repro.command`), which the contract package never
|
|
399
|
+
length-validates. Caught locally anyway, same reasoning as
|
|
400
|
+
[`yak-summary-too-long`](#yak-summary-too-long) — a repro is a command, not a
|
|
401
|
+
narrative, so 2000 chars is generous headroom over any real invocation. Fix:
|
|
402
|
+
shorten it — redaction can grow text, so check the real length with
|
|
403
|
+
`--no-redact` if the count is surprising.
|
|
404
|
+
|
|
405
|
+
### yak-repo-too-long
|
|
406
|
+
|
|
407
|
+
A (redacted) `--repo <owner/name>` hint exceeds 200 chars — a target-repo hint rides
|
|
408
|
+
inside `provenance` (`provenance.repo.target_repos`), which the contract
|
|
409
|
+
package types and bounds at the same 200 chars. Caught here first, so the
|
|
410
|
+
error names `--repo` rather than a generic payload failure, same reasoning as
|
|
411
|
+
[`yak-repro-too-long`](#yak-repro-too-long) — a hint is a short `owner/name`
|
|
412
|
+
identifier, so 200 chars is generous headroom over any real one. Fix:
|
|
413
|
+
shorten it — redaction can grow text, so check the real length with
|
|
414
|
+
`--no-redact` if the count is surprising.
|
|
415
|
+
|
|
416
|
+
### yak-repo-hints-too-many
|
|
417
|
+
|
|
418
|
+
More than 20 `--repo` hints were given on one submission. A
|
|
419
|
+
courtesy bound for the same DO-storage-hygiene reason as
|
|
420
|
+
[`yak-repo-too-long`](#yak-repo-too-long) — no single report genuinely spans
|
|
421
|
+
that many repos. Fix: narrow `--repo` to the repos this report actually
|
|
422
|
+
concerns.
|
|
423
|
+
|
|
424
|
+
### yak-payload-invalid
|
|
425
|
+
|
|
426
|
+
Local validation against the Yaks contract package
|
|
427
|
+
(`@sibylline-labs/yak-contract`) failed for a reason other than a length bound
|
|
428
|
+
(e.g. an empty required field after redaction). The `ERROR` line names the
|
|
429
|
+
field and the schema's message.
|
|
430
|
+
|
|
431
|
+
### yak-identity-id-too-long
|
|
432
|
+
|
|
433
|
+
`device_id` or `execution_id` exceeded the contract's 200-char bound. Unlike
|
|
434
|
+
[`yak-summary-too-long`](#yak-summary-too-long)/`yak-body-too-long`, this is
|
|
435
|
+
**never the caller's fault** — neither field is something an `eris yak`
|
|
436
|
+
invocation passes. `device_id` is resolved from `~/.eris/device-id` (a
|
|
437
|
+
corrupt or hand-edited file); `execution_id` from
|
|
438
|
+
`CLAUDE_CODE_SESSION_ID`/`CLAUDE_CODE_HOST_SESSION_ID` (an unusually long
|
|
439
|
+
value from the harness) or the shell ppid. Warn + exit 0 — the `WARN` line
|
|
440
|
+
names the real field and its real length; fix the identity source it names,
|
|
441
|
+
not the report.
|
|
442
|
+
|
|
443
|
+
### yak-redaction-overflow
|
|
444
|
+
|
|
445
|
+
The caller's ORIGINAL `summary`/`body`/`evidence`/`repro` was within its
|
|
446
|
+
length bound, but the secret-scrub pass (a marker like `«redacted:aws-key»`
|
|
447
|
+
can be longer than the text it replaces) grew it past the limit. Warn + exit
|
|
448
|
+
0, not misuse — the reported text is fine as authored. Retry with
|
|
449
|
+
`--no-redact` if the flagged text contains no real secret, or shorten it so
|
|
450
|
+
redaction has room to grow.
|
|
451
|
+
|
|
452
|
+
### yak-deps-not-installed
|
|
453
|
+
|
|
454
|
+
`eris`'s own `node_modules` is missing, or present but missing a package
|
|
455
|
+
`eris yak`'s TypeScript core imports (an interrupted `bun install`, a stale
|
|
456
|
+
checkout). `eris yak` refuses rather than running an unbounded `bun install`
|
|
457
|
+
inline mid-task, or letting `bun` crash with a raw, unslugged `Cannot find
|
|
458
|
+
package '…'` (`plugins/yak/handlers.ts`). Fix: `cd` to the eris checkout and run
|
|
459
|
+
`bun install` yourself. It warns and exits 0, like
|
|
460
|
+
[`yak-token-unresolved`](#yak-token-unresolved): the command that reports a
|
|
461
|
+
broken harness must not become one more thing that stops the agent. Under
|
|
462
|
+
`--output json` it is the bare record on stdout (`delivered: false`, `error.slug`)
|
|
463
|
+
with stderr empty.
|
|
464
|
+
|
|
465
|
+
### yak-url-unresolved
|
|
466
|
+
|
|
467
|
+
No longer raised. A Yaks base URL always resolves now: `ERIS_YAKS_URL`, then the
|
|
468
|
+
`"url"` in `~/.eris/yaks.json`, then the default `https://api.sibylline.group`.
|
|
469
|
+
An older eris warned with this slug (exit 0) when neither was set; with this
|
|
470
|
+
one, set `ERIS_YAKS_URL` only to use another endpoint.
|
|
471
|
+
|
|
472
|
+
### yak-unreachable
|
|
473
|
+
|
|
474
|
+
The Yaks endpoint could not be reached at all (connection refused, DNS failure,
|
|
475
|
+
etc.) within the request's bound. Warn + exit 0 — the report was dropped, not
|
|
476
|
+
delivered; the agent's task is unaffected.
|
|
477
|
+
|
|
478
|
+
### yak-timeout
|
|
479
|
+
|
|
480
|
+
The Yaks endpoint did not respond within the bounded request window (30s
|
|
481
|
+
default). No retry — matches the registry transport's own posture. Warn + exit 0.
|
|
482
|
+
|
|
483
|
+
### yak-unauthorized
|
|
484
|
+
|
|
485
|
+
The Yaks endpoint answered `401`: it rejected the bearer token. Check the
|
|
486
|
+
`"token"` in `~/.eris/yaks.json` or `ERIS_YAKS_TOKEN`, and that the token is
|
|
487
|
+
registered with the endpoint. Retrying the same call changes nothing. Warn +
|
|
488
|
+
exit 0; the report was dropped, not delivered, and the agent's task is
|
|
489
|
+
unaffected. A problem with eris itself is reported on the vendor route, the eris
|
|
490
|
+
project's own tracker, rather than into the workspace.
|
|
491
|
+
|
|
492
|
+
### yak-not-entitled
|
|
493
|
+
|
|
494
|
+
The Yaks endpoint answered `402`: the workspace is not entitled to Yaks (its
|
|
495
|
+
plan or seat does not include it). Ask whoever administers the workspace;
|
|
496
|
+
nothing on this machine fixes it. Warn + exit 0; the report was dropped, not
|
|
497
|
+
delivered, and the agent's task is unaffected. A problem with eris itself is
|
|
498
|
+
reported on the vendor route, the eris project's own tracker, rather than into the
|
|
499
|
+
workspace.
|
|
500
|
+
|
|
501
|
+
### yak-payload-too-large
|
|
502
|
+
|
|
503
|
+
The Yaks endpoint answered `413`: the submission exceeded the endpoint's
|
|
504
|
+
whole-body size cap. The per-field length checks pass locally first, so the sum
|
|
505
|
+
is what overflowed; trim `--evidence` (the largest field), `--repro` or the
|
|
506
|
+
`--repo` hints. Warn + exit 0; the
|
|
507
|
+
report was dropped, not delivered, and the agent's task is unaffected. A problem
|
|
508
|
+
with eris itself is reported on the vendor route, the eris project's own tracker,
|
|
509
|
+
rather than into the workspace.
|
|
510
|
+
|
|
511
|
+
### yak-transport-error
|
|
512
|
+
|
|
513
|
+
The Yaks endpoint responded, but not usably: a non-2xx status other than the
|
|
514
|
+
`401`, `402` and `413` that have their own slugs
|
|
515
|
+
([`yak-unauthorized`](#yak-unauthorized), [`yak-not-entitled`](#yak-not-entitled),
|
|
516
|
+
[`yak-payload-too-large`](#yak-payload-too-large)), an unparseable 2xx body, or a
|
|
517
|
+
2xx that does not match the receipt contract (`YakReceipt` in
|
|
518
|
+
`@sibylline-labs/yak-contract`). Warn + exit 0; the `WARN` line names the HTTP
|
|
519
|
+
status or the parse failure.
|
|
520
|
+
|
|
521
|
+
### yak-config-permissive
|
|
522
|
+
|
|
523
|
+
`~/.eris/yaks.json` is readable by users other than its owner (not mode
|
|
524
|
+
`0600`). Refused, never read — a credential file with group/world read is a
|
|
525
|
+
leak surface. Fix: `chmod 0600 ~/.eris/yaks.json`.
|
|
526
|
+
|
|
527
|
+
### yak-config-malformed
|
|
528
|
+
|
|
529
|
+
`~/.eris/yaks.json` exists but is not valid JSON, or is not a JSON object.
|
|
530
|
+
Fix: recreate it as `{"url": "...", "token": "..."}`.
|
|
531
|
+
|
|
532
|
+
### yak-config-unwritable
|
|
533
|
+
|
|
534
|
+
`eris login` or `eris logout` could not write `~/.eris/yaks.json` (the `ERROR`
|
|
535
|
+
line names the path and the errno). The previous file is untouched: the new
|
|
536
|
+
one is written to a temp file beside it and renamed into place. Fix: make
|
|
537
|
+
`~/.eris` writable by you, then run the command again.
|
|
538
|
+
|
|
539
|
+
### yak-token-unresolved
|
|
540
|
+
|
|
541
|
+
No bearer token resolved for the Yaks endpoint — neither `ERIS_YAKS_TOKEN` nor a
|
|
542
|
+
`"token"` field in a readable `~/.eris/yaks.json`. Environment/config, warn +
|
|
543
|
+
exit 0. Fix: run `eris login` and approve the code it shows in your browser; it
|
|
544
|
+
writes the token to `~/.eris/yaks.json`. Approving is a human step, not
|
|
545
|
+
something an agent can do mid-task.
|
|
546
|
+
|
|
547
|
+
### yak-device-id-unwritable
|
|
548
|
+
|
|
549
|
+
`~/.eris/device-id` does not exist and could not be minted (directory not
|
|
550
|
+
writable, disk full, etc.). Warn + exit 0 — the report still attempts to send
|
|
551
|
+
with whatever identity resolved.
|
|
552
|
+
|
|
553
|
+
### yak-key-mismatch
|
|
554
|
+
|
|
555
|
+
Informational only — not a failure, not a warn-and-drop. The submission WAS
|
|
556
|
+
delivered (`delivered: true`), but the idempotency key this CLI derived
|
|
557
|
+
locally does not match the one the endpoint's receipt reports back, which is the
|
|
558
|
+
only canonicalization-drift signal the contract exposes (the schema and the
|
|
559
|
+
endpoint must derive identically from the same redacted payload). Printed as a
|
|
560
|
+
`WARN` line alongside a successful receipt in text mode; worth reporting
|
|
561
|
+
upstream if seen. Under `--output json` this WARN is suppressed like every
|
|
562
|
+
other diagnostic — the record's `key_mismatch` field carries the
|
|
563
|
+
same fact instead.
|
|
564
|
+
|
|
565
|
+
### yak-no-redact
|
|
566
|
+
|
|
567
|
+
Informational only — printed whenever `--no-redact` is passed, regardless of
|
|
568
|
+
the outcome, so the operator knows the secret-scrub pass did not run on this
|
|
569
|
+
submission. Not a failure. Under `--output json` this WARN is suppressed like
|
|
570
|
+
every other diagnostic — `redactions.skipped: true` on the record
|
|
571
|
+
carries the same fact instead, which matters because a skipped scrub and a
|
|
572
|
+
scrub that ran and found nothing otherwise look identical (`count: 0,
|
|
573
|
+
classes: []`).
|
|
574
|
+
|
|
575
|
+
### login-url-unresolved
|
|
576
|
+
|
|
577
|
+
No longer raised. `eris login` always has an endpoint: `--url`, then
|
|
578
|
+
`ERIS_YAKS_URL`, then the `"url"` in `~/.eris/yaks.json`, then the default
|
|
579
|
+
`https://api.sibylline.group`. An empty `--url` is refused as
|
|
580
|
+
[`flag-value-missing`](#flag-value-missing). An older eris raised this slug when
|
|
581
|
+
none of the first three was set; with this one, run `eris login`.
|
|
582
|
+
|
|
583
|
+
### login-unreachable
|
|
584
|
+
|
|
585
|
+
The endpoint could not be reached when the device login started, or stopped
|
|
586
|
+
answering (a dropped connection or a 5xx, more than three polls in a row) while
|
|
587
|
+
waiting for approval. Nothing was written. Fix: check the url and your
|
|
588
|
+
connection, then run `eris login` again.
|
|
589
|
+
|
|
590
|
+
### login-refused
|
|
591
|
+
|
|
592
|
+
The endpoint answered, but not with a device login: it refused to start one
|
|
593
|
+
(the `ERROR` line carries its error code, from either the RFC `{"error": …}`
|
|
594
|
+
or the `{"error": {"code", "message"}}` shape, e.g. `invalid_device`,
|
|
595
|
+
`device_unconfigured`), sent a malformed response, or refused the device code
|
|
596
|
+
with a code other than the four RFC 8628 ones. Nothing was written. Fix: check
|
|
597
|
+
the url points at an endpoint that offers device login.
|
|
598
|
+
|
|
599
|
+
### login-denied
|
|
600
|
+
|
|
601
|
+
The sign-in was denied on the approval page (`access_denied`). Nothing was
|
|
602
|
+
written, and an existing `~/.eris/yaks.json` is left as it was. Fix: run
|
|
603
|
+
`eris login` again if the denial was not intended.
|
|
604
|
+
|
|
605
|
+
### login-expired
|
|
606
|
+
|
|
607
|
+
The device code expired before it was approved: the endpoint answered
|
|
608
|
+
`expired_token`, or the code's `expires_in` ran out locally. Nothing was
|
|
609
|
+
written. Fix: run `eris login` again and approve the new code in time.
|
|
610
|
+
|
|
611
|
+
### login-env-token-overrides
|
|
612
|
+
|
|
613
|
+
A `WARN`, exit 0: `ERIS_YAKS_TOKEN` is set, and it wins over the token in
|
|
614
|
+
`~/.eris/yaks.json`, so `eris yak` keeps using the environment's token after
|
|
615
|
+
`eris login` (or still has one after `eris logout`). Fix: unset
|
|
616
|
+
`ERIS_YAKS_TOKEN` to use the file's token.
|
|
617
|
+
|
|
618
|
+
## Adding a new slug
|
|
619
|
+
|
|
620
|
+
Call `emitFailureAndExit({ slug, what, fix, docs })` (or `reportFailure`, to
|
|
621
|
+
return 1 instead of exiting) from `ts/lib/eris-fail.ts` at the callsite (`docs`
|
|
622
|
+
defaults to `docs/ERRORS.md#<slug>`), then add a `### <slug>` heading here. A
|
|
623
|
+
plugin calls `renderFailureBlock` from the SDK (`src/cli/plugin.ts`). Slugs are
|
|
624
|
+
lowercase kebab-case, stable once shipped.
|
|
625
|
+
|
|
626
|
+
`tests/errors-doc.test.ts` asserts that every slug has a heading here, and it
|
|
627
|
+
**derives** the slug list from the raisers rather than carrying a copy: in the
|
|
628
|
+
`eris` shim, its `printf 'slug: …'` block; in every TypeScript tree (`src/`,
|
|
629
|
+
`ts/lib/`, `plugins/`), `slug: "…"` literals, the members of every `…Slug`
|
|
630
|
+
union, and `renderWarnLines(…, "<slug>")` arguments. So a new slug is covered
|
|
631
|
+
the moment it is raised — but it also fails the suite until its heading exists,
|
|
632
|
+
which is the point.
|