@sibylline-labs/eris 0.0.0-stage → 0.3.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/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/LICENSE
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright [yyyy] [name of copyright owner]
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
|
202
|
+
|
package/NOTICE
ADDED
package/README.md
CHANGED
|
@@ -1,3 +1,147 @@
|
|
|
1
|
-
#
|
|
1
|
+
# eris
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
eris is a small, plugin-composed command-line tool written in TypeScript on
|
|
4
|
+
[Bun](https://bun.sh). Core supplies the router, the verb registry, argument
|
|
5
|
+
parsing, the output contract (`--output text|json`, slugged failure blocks)
|
|
6
|
+
and shell completion; every verb group beyond that is a plugin composed in at
|
|
7
|
+
build time.
|
|
8
|
+
|
|
9
|
+
This build ships one plugin, `eris yak`, which AI coding agents (and people)
|
|
10
|
+
use to file observations about their own tooling: a broken command, a
|
|
11
|
+
misleading doc, a missing capability. A yak is redacted, given a dedup key and
|
|
12
|
+
sent in one bounded request to a Yaks endpoint you configure. It never fails
|
|
13
|
+
the task that filed it.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
eris is published to npm as `@sibylline-labs/eris` and runs on Bun, which must be on
|
|
18
|
+
PATH. npm is the only install path:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx @sibylline-labs/eris@latest --help # run the latest release, no install
|
|
22
|
+
bunx @sibylline-labs/eris@latest --help # the same, through bun
|
|
23
|
+
bun add -g @sibylline-labs/eris@latest # install `eris` globally
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### From source
|
|
27
|
+
|
|
28
|
+
You need Bun (the version in `.bun-version`) and git.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
git clone https://github.com/sibylline-labs/eris && cd eris
|
|
32
|
+
bun install --frozen-lockfile
|
|
33
|
+
./eris --help
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Put the checkout on your `PATH` to run it as `eris`. To build a standalone binary,
|
|
37
|
+
run `bun scripts/build.ts`; it writes `dist/eris-<os>-<arch>`, which runs without Bun.
|
|
38
|
+
|
|
39
|
+
### Version and updates
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
eris --version # eris v0.3.0 (sibylline-labs/eris)
|
|
43
|
+
eris update # prints the npx / bunx / bun add -g commands for the latest release
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`eris update` changes nothing: the package manager that installed eris updates it.
|
|
47
|
+
[docs/UPDATE.md](docs/UPDATE.md) has the details.
|
|
48
|
+
|
|
49
|
+
## Quickstart
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
eris --help # the commands this build composes
|
|
53
|
+
source <(eris completion zsh) # or bash; see docs/COMPLETION.md
|
|
54
|
+
eris yak --help
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Filing a yak
|
|
58
|
+
|
|
59
|
+
Sign in once with a device code. `eris login` shows a code to approve in the
|
|
60
|
+
browser and writes the token to `~/.eris/yaks.json` (mode `0600`):
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
eris login
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
That signs in to `https://api.sibylline.group`. For another endpoint, pass
|
|
67
|
+
`--url`, or configure it with environment variables:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
export ERIS_YAKS_URL=https://yaks.example.com # your Yaks endpoint
|
|
71
|
+
export ERIS_YAKS_TOKEN=<bearer token>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Or, for a self-hosted endpoint without device login, mint a bearer into
|
|
75
|
+
`~/.eris/yaks.json` from a checkout. The script prints the entry your endpoint's
|
|
76
|
+
operator needs to register:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
bun plugins/yak/yak-setup.ts --url https://yaks.example.com
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Then file reports:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
eris yak issue --summary "completion fails on Alpine" --body "busybox sh lacks compgen"
|
|
86
|
+
eris yak suggest --summary "a --dry-run for completion" --body-file notes.md
|
|
87
|
+
eris yak fatal --summary "eris exits before any verb runs" --body-file - < log.txt
|
|
88
|
+
eris yak issue --summary "…" --body "…" --repro "bun test tests/foo.test.ts" --repo acme/widgets
|
|
89
|
+
eris --output json yak issue --summary "…" --body "…" # one JSON record on stdout
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
A delivered yak prints `recorded: <id>`. A missing URL or token, an
|
|
93
|
+
unreachable endpoint or a timeout prints a `WARN` line with its slug and still
|
|
94
|
+
exits 0. Only misuse (a missing `--summary`, an over-long field, an unknown
|
|
95
|
+
flag) exits 1. [docs/YAK.md](docs/YAK.md) has the full reference.
|
|
96
|
+
|
|
97
|
+
### Agent skill
|
|
98
|
+
|
|
99
|
+
[`skills/eris-yaks`](skills/eris-yaks/SKILL.md) is an agent skill that walks a coding agent
|
|
100
|
+
through setting up Yaks for its user: running eris, the browser steps to connect Linear and
|
|
101
|
+
create a token, a test yak, and the `AGENTS.md` block that teaches later sessions to file. Install
|
|
102
|
+
it with the [skills](https://github.com/vercel-labs/skills) CLI:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
npx skills add sibylline-labs/eris --skill eris-yaks
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Writing a plugin
|
|
109
|
+
|
|
110
|
+
A plugin is registry rows plus lazily loaded handlers, written against the SDK
|
|
111
|
+
in `src/cli/plugin.ts`. Start with [docs/dev/PLUGINS.md](docs/dev/PLUGINS.md)
|
|
112
|
+
and copy the worked example in [`examples/plugins/widgets/`](examples/plugins/widgets).
|
|
113
|
+
A build's plugin list is `plugins/index.ts`.
|
|
114
|
+
|
|
115
|
+
To ship your own binary with plugins of your own, write a distribution: depend
|
|
116
|
+
on this repository, import `eris/sdk`, compose, and build with `build()`
|
|
117
|
+
([docs/dev/PLUGINS.md#distributions](docs/dev/PLUGINS.md#distributions); the
|
|
118
|
+
worked example is [`examples/distribution/`](examples/distribution)).
|
|
119
|
+
|
|
120
|
+
## The Yaks wire contract
|
|
121
|
+
|
|
122
|
+
[`packages/yak-contract`](packages/yak-contract) is `@sibylline-labs/yak-contract`:
|
|
123
|
+
the Yaks submission contract v2 as Zod schemas, their inferred TypeScript
|
|
124
|
+
types, and the JSON Schema they emit (`schema/yak-v2.schema.json`) for
|
|
125
|
+
consumers in other languages. A repository that depends on this one (a git
|
|
126
|
+
dependency pinned to a merge commit on `main`) imports the TypeScript contract
|
|
127
|
+
as `eris/yak-contract`. The `eris yak` client in this build imports it and
|
|
128
|
+
posts contract v2 submissions.
|
|
129
|
+
|
|
130
|
+
The client's redaction pass, [`plugins/yak/yak-redact.ts`](plugins/yak/yak-redact.ts), is
|
|
131
|
+
exported as `eris/yak-redact` (`redact`, `redactDeep`), so a server that redacts a submission
|
|
132
|
+
before it commits runs the same rules. The module imports nothing.
|
|
133
|
+
|
|
134
|
+
## Documentation
|
|
135
|
+
|
|
136
|
+
[docs/README.md](docs/README.md) indexes the references: the architecture,
|
|
137
|
+
the output contract every command follows, every error slug, and the
|
|
138
|
+
developer guides.
|
|
139
|
+
|
|
140
|
+
## Contributing and security
|
|
141
|
+
|
|
142
|
+
We do not accept outside contributions; see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
143
|
+
Report vulnerabilities privately as described in [SECURITY.md](SECURITY.md).
|
|
144
|
+
|
|
145
|
+
## Licence
|
|
146
|
+
|
|
147
|
+
Apache License, Version 2.0. See [LICENSE](LICENSE) and [NOTICE](NOTICE).
|
package/bin/eris.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env -S bun --no-env-file --config=/dev/null
|
|
2
|
+
/**
|
|
3
|
+
* eris.ts — the `eris` command an install of this package links (package.json
|
|
4
|
+
* `bin`): `npm i -g`, `bun add -g`, `npx`, `bunx`.
|
|
5
|
+
*
|
|
6
|
+
* A checkout starts through the POSIX shim, `eris`. An installed package has no
|
|
7
|
+
* shell to run, so this file's shebang is the entrypoint, and it keeps the
|
|
8
|
+
* shim's invariants (the shim's header says why each exists):
|
|
9
|
+
*
|
|
10
|
+
* - bun never reads the caller's cwd: `--no-env-file` stops it loading a
|
|
11
|
+
* service dir's generated `.env`, and `--config=/dev/null` stops a cwd
|
|
12
|
+
* `bunfig.toml` preload from running. A bare `#!/usr/bin/env bun` does
|
|
13
|
+
* neither. `env -S` is what splits the flags out of one shebang line.
|
|
14
|
+
* - BUN_CONFIG_VERBOSE_FETCH never reaches a fetch. The shim removes it
|
|
15
|
+
* before bun starts; this file refuses to run under it
|
|
16
|
+
* (`eris-verbose-fetch-set`) rather than print a bearer token.
|
|
17
|
+
* - The install root is the package: src/runtime/home.ts resolves it from its
|
|
18
|
+
* own location, so the symlink an install links this file under changes
|
|
19
|
+
* nothing. Only the shim sets `_ERIS_SHIM_DIR`, so a stray value in the
|
|
20
|
+
* caller's environment is removed before the program reads it.
|
|
21
|
+
*
|
|
22
|
+
* `src/main.ts` runs itself only when it is the entry, so this calls
|
|
23
|
+
* `runProgram`. The refusal comes first and `src/main` is imported after it:
|
|
24
|
+
* nothing of the program is evaluated under the variable.
|
|
25
|
+
*
|
|
26
|
+
* tests/bin.test.ts pins each of these.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import { reportFailure } from "../ts/lib/eris-fail";
|
|
30
|
+
|
|
31
|
+
if (process.env.BUN_CONFIG_VERBOSE_FETCH !== undefined) {
|
|
32
|
+
// Not `process.exit`: the exit code is set and the stream left to drain, as src/main.ts does.
|
|
33
|
+
process.exitCode = reportFailure({
|
|
34
|
+
slug: "eris-verbose-fetch-set",
|
|
35
|
+
what: "BUN_CONFIG_VERBOSE_FETCH is set — under it bun prints every fetch, Authorization bearer and body included, to stderr",
|
|
36
|
+
fix: "unset BUN_CONFIG_VERBOSE_FETCH, or run: env -u BUN_CONFIG_VERBOSE_FETCH eris <command>",
|
|
37
|
+
});
|
|
38
|
+
} else {
|
|
39
|
+
delete process.env._ERIS_SHIM_DIR;
|
|
40
|
+
const { runProgram } = await import("../src/main");
|
|
41
|
+
runProgram();
|
|
42
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# Eris architecture
|
|
2
|
+
|
|
3
|
+
The current-state map: what eris is made of, what calls what, and the constraints any change has to
|
|
4
|
+
survive. A claim here that no longer resolves against the tree is a bug in this file; fixing it
|
|
5
|
+
belongs to the change that moved the code.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. What eris is
|
|
10
|
+
|
|
11
|
+
Eris is a TypeScript program run by bun, behind a POSIX `sh` shim: a small core (the router, the
|
|
12
|
+
verb registry, the output contract, the plugin host and its SDK, shell completion and the top-level
|
|
13
|
+
usage) plus the plugins a build composes in. This build's plugin is `eris yak`
|
|
14
|
+
([YAK.md](YAK.md)).
|
|
15
|
+
|
|
16
|
+
- **`eris`** finds bun and execs `src/main.ts`. Nothing else.
|
|
17
|
+
- **`bin/eris.ts`** is the same entry for an installed package: the `eris` command that `npm i -g
|
|
18
|
+
@sibylline-labs/eris`, `bun add -g`, `npx` and `bunx` link (`bin` in `package.json`). It starts under bun
|
|
19
|
+
through its shebang and calls `runProgram`.
|
|
20
|
+
- **`src/main.ts`** routes every command line.
|
|
21
|
+
- **`plugins/index.ts`** lists the plugins this build compiles in.
|
|
22
|
+
- **`src/sdk.ts`** is `eris/sdk`, the one module through which another repository reaches core
|
|
23
|
+
(the `exports` map names `eris/sdk/testing`, `eris/yak-contract` and `eris/yak-redact` beside it,
|
|
24
|
+
nothing deeper).
|
|
25
|
+
A **distribution** depends on this package, composes core with this build's plugins and its own,
|
|
26
|
+
and compiles its own binary with `build()` ([`dev/PLUGINS.md`](dev/PLUGINS.md#distributions)).
|
|
27
|
+
- **`packages/yak-contract`** is the Yaks wire contract v2, a bun workspace package that builds
|
|
28
|
+
standalone. The `exports` map also names it, as `eris/yak-contract`, so a repository pinned to
|
|
29
|
+
this one imports the contract without core.
|
|
30
|
+
|
|
31
|
+
eris installs from npm only (`npx`, `bunx`, `bun add -g @sibylline-labs/eris`); the package's
|
|
32
|
+
`bin/eris.ts` is the command. A checkout needs `bun install --frozen-lockfile` and no build step:
|
|
33
|
+
`bash <checkout>/eris` and `sh <checkout>/eris` run it as it stands.
|
|
34
|
+
|
|
35
|
+
`bun scripts/build.ts` also compiles the same program into one executable,
|
|
36
|
+
`dist/eris-<os>-<arch>`, through `build()` (`src/build.ts`), the same call a distribution makes
|
|
37
|
+
with its own entry. It carries the docs the source names and writes them once per
|
|
38
|
+
build to `${ERIS_CACHE_DIR:-${XDG_CACHE_HOME:-~/.cache}/eris}/<build id>/`, its install root
|
|
39
|
+
(`src/runtime/home.ts`), so a failure block's `docs:` line names a file that exists.
|
|
40
|
+
|
|
41
|
+
A binary also knows which build it is, from the same call: `build({ tag })` bakes the version,
|
|
42
|
+
the release repository, an optional version line and the docs base of a failure block
|
|
43
|
+
(`VERSION` and `identity()`, `src/runtime/home.ts`); a distribution run from source hands the
|
|
44
|
+
same identity to `runProgram({ identity })`, and a binary keeps what its build baked. `eris --version`
|
|
45
|
+
prints them. Core's `eris update` (`src/cli/commands/update.ts`) prints the npm commands for the
|
|
46
|
+
latest release. A distribution that publishes binaries composes `RELEASE_UPDATE`
|
|
47
|
+
(`src/cli/commands/update/`) in its place, which replaces the binary with the newest release of
|
|
48
|
+
its own repository, after checking it ([`UPDATE.md`](UPDATE.md)). The release is cut by
|
|
49
|
+
`.github/workflows/release.yml`, which builds and tests both binaries, publishes them with a
|
|
50
|
+
`SHA256SUMS`, and publishes the package to npm
|
|
51
|
+
([`dev/RELEASING.md`](dev/RELEASING.md)). The npm package is the source, run by bun: `exports` and
|
|
52
|
+
`bin` name `.ts` files, and `files` in `package.json` is the allow-list of what the tarball holds
|
|
53
|
+
(`tests/package.test.ts`).
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 2. The layers, as built
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
eris POSIX sh shim: unset BUN_CONFIG_VERBOSE_FETCH; exec bun src/main.ts
|
|
61
|
+
bin/eris.ts the npm bin: refuse BUN_CONFIG_VERBOSE_FETCH; runProgram()
|
|
62
|
+
└─ src/main.ts settings fill → route → handler (lazy import) | unknown
|
|
63
|
+
├─ src/sdk.ts eris/sdk: what a distribution imports · src/build.ts: build()
|
|
64
|
+
├─ src/cli/ registry.ts (core's verbs) · compose.ts (core + plugins) · plugin.ts
|
|
65
|
+
│ (the SDK) · router.ts · args.ts (argv + the global --output pre-pass)
|
|
66
|
+
│ · output.ts (the json allow-list) · ts-verb.ts
|
|
67
|
+
├─ src/cli/commands/ completion/ · usage.ts · version.ts · update.ts + update/
|
|
68
|
+
├─ src/runtime/ logging · process · settings · env · home
|
|
69
|
+
├─ ts/lib/eris-fail.ts the failure block
|
|
70
|
+
└─ plugins/ index.ts (the build's list) · yak/
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### The shim
|
|
74
|
+
|
|
75
|
+
`eris` is POSIX `sh` because consumers run it as `bash eris`, `sh eris` and `exec <repo>/eris`. It:
|
|
76
|
+
|
|
77
|
+
- removes `BUN_CONFIG_VERBOSE_FETCH` before bun starts. Under it bun prints every fetch, bearer and
|
|
78
|
+
body included, to stderr, and bun reads it from its own environment at fetch time, so
|
|
79
|
+
`delete process.env.X` inside `src/main.ts` cannot turn it off;
|
|
80
|
+
- refuses a missing bun with the `eris-bun-missing` failure block, rendered by the shim itself;
|
|
81
|
+
- execs `bun --no-env-file --config=/dev/null src/main.ts`, so bun never loads a service
|
|
82
|
+
directory's generated `.env` or runs a cwd `bunfig.toml` preload;
|
|
83
|
+
- exports nothing. It hands the router its logical directory through `_ERIS_SHIM_DIR`, which
|
|
84
|
+
`src/main.ts` removes before anything is spawned.
|
|
85
|
+
|
|
86
|
+
`tests/cli-shim.test.ts` pins each of these.
|
|
87
|
+
|
|
88
|
+
### The package's bin
|
|
89
|
+
|
|
90
|
+
`bin/eris.ts` is what an install links as `eris`. It has no shell to run, so its shebang,
|
|
91
|
+
`#!/usr/bin/env -S bun --no-env-file --config=/dev/null`, does what the shim's `exec` does: bun never
|
|
92
|
+
reads the caller's cwd `.env` or `bunfig.toml` preload. A bare `#!/usr/bin/env bun` does neither, so
|
|
93
|
+
`npx eris` run in a service directory would load that directory's `.env` and run its preload.
|
|
94
|
+
`env -S` splits the flags out of the one shebang line (GNU coreutils 8.30 and newer, macOS).
|
|
95
|
+
|
|
96
|
+
The bin does not remove `BUN_CONFIG_VERBOSE_FETCH`; it refuses to run under it, with the
|
|
97
|
+
`eris-verbose-fetch-set` failure block, before it imports the program. With bun absent the operating
|
|
98
|
+
system's own `env: bun: No such file or directory` is the diagnostic; there is no `eris-bun-missing`
|
|
99
|
+
block, because nothing of eris has started to print one. The install root is the package directory,
|
|
100
|
+
whatever symlink the install put the bin behind. `tests/bin.test.ts` pins each of these.
|
|
101
|
+
|
|
102
|
+
### The router
|
|
103
|
+
|
|
104
|
+
`src/cli/registry.ts` `REGISTRY` has a row per group, sub and nested sub: `impl` (`ts`; a sub
|
|
105
|
+
inherits its group's), long flags with value arity, `json`, and a summary. From it
|
|
106
|
+
are derived:
|
|
107
|
+
|
|
108
|
+
- the router table (`src/cli/router.ts`, `deriveTable`): every group, empty argv, `-h`, `--help`,
|
|
109
|
+
and a `"group sub"` key where a sub's impl differs from its group's (the longer key wins);
|
|
110
|
+
- the `--output json` allow-list (`src/cli/output.ts`);
|
|
111
|
+
- the shell completion tree (`src/cli/commands/completion/emit.ts`);
|
|
112
|
+
- every TS verb's argv parse (`src/cli/args.ts`): `readVerbArgs` accepts exactly the row's flags
|
|
113
|
+
and `pos` operands, refuses anything else uniformly, and types the handler's args from the row.
|
|
114
|
+
|
|
115
|
+
The registry those planes read is core's rows composed with the build's plugins
|
|
116
|
+
(`src/cli/compose.ts`, over the list in `plugins/index.ts`): a plugin is rows plus lazily loaded
|
|
117
|
+
handlers, written against the SDK `src/cli/plugin.ts`, composed at build time, with collisions, a
|
|
118
|
+
non-`ts` row and a json group with subs refused, and a group whose product the workspace has not
|
|
119
|
+
bought locked per command line. [`dev/PLUGINS.md`](dev/PLUGINS.md).
|
|
120
|
+
|
|
121
|
+
A `ts` route runs the composed handler for the verb (`HANDLERS` in `src/main.ts`, plus each
|
|
122
|
+
plugin's), imported lazily, behind the global `--output` pre-pass. A command line whose verb is not in the table is refused by the router as an unknown
|
|
123
|
+
command. Adding or flipping a verb is a registry edit; `tests/cli-registry.test.ts` and
|
|
124
|
+
`tests/cli-router.test.ts` hold the rows against `HANDLERS`.
|
|
125
|
+
|
|
126
|
+
`runTsVerb` (`src/cli/ts-verb.ts`) turns a package that cannot be resolved into the
|
|
127
|
+
`eris-deps-not-installed` block, read from the error's `code` and `specifier`. Nothing on the path
|
|
128
|
+
`src/main.ts` → `src/cli/ts-verb.ts` → `src/cli/output.ts` may import a third-party package, or that
|
|
129
|
+
block cannot be reached.
|
|
130
|
+
|
|
131
|
+
The top-level usage (`src/cli/commands/usage.ts`) is a `HANDLERS` row too: bare `eris`, `-h` and
|
|
132
|
+
`--help` all print it. `--version` is the fourth argv shape (`ARGV_SHAPES`, `src/cli/registry.ts`):
|
|
133
|
+
it is not a verb, but it renders JSON under `--output` and reads no file from the install root.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## 3. Dependency direction
|
|
138
|
+
|
|
139
|
+
- **A plugin imports the SDK and nothing else of core.** `src/cli/plugin.ts` is the one core module
|
|
140
|
+
under `plugins/` may import (`plugin-imports-sdk-only`, in `rules/`).
|
|
141
|
+
- **A distribution imports `eris/sdk` and nothing else of core.** The `exports` map refuses a
|
|
142
|
+
deeper path; `distribution-imports-sdk-only` holds the example distribution to it. Its suites
|
|
143
|
+
may also import `eris/sdk/testing` (`testing/`), which no source the binary bundles imports
|
|
144
|
+
(`runtime-imports-no-testing`). `eris/yak-contract` is not core: it is the workspace package
|
|
145
|
+
`packages/yak-contract`, which imports nothing of core (`tests/yak-contract-v2.test.ts`).
|
|
146
|
+
`eris/yak-redact` is `plugins/yak/yak-redact.ts`, the client's redaction pass, so a server that
|
|
147
|
+
redacts a submission runs the client's rules; it imports nothing (`tests/distribution.test.ts`).
|
|
148
|
+
- **Completion imports the registry and nothing else.** `source <(eris completion bash)` runs on
|
|
149
|
+
every shell start, so a broken source file elsewhere must not break a login shell.
|
|
150
|
+
`tests/completion.test.ts` corrupts every other verb and every plugin's handler code in a copied
|
|
151
|
+
tree and asserts byte-identical emission. Plugin rows reach completion through their manifests,
|
|
152
|
+
which import nothing but the SDK (`plugin-manifest-lazy-handlers`); `tests/plugins.test.ts`
|
|
153
|
+
composes a plugin whose handler module throws on evaluation and completes past it.
|
|
154
|
+
- **Only `src/runtime/process.ts` spawns.** Argv arrays only, an explicit
|
|
155
|
+
timeout, and the whole tree killed on expiry.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## 4. Constraints
|
|
160
|
+
|
|
161
|
+
**C1 — `bash <checkout>/eris` runs from a git checkout with no build step**, with bun at
|
|
162
|
+
`.bun-version` and `bun install --frozen-lockfile`.
|
|
163
|
+
|
|
164
|
+
**C2 — the output contract and the error slugs are stable.** The failure block
|
|
165
|
+
(`ts/lib/eris-fail.ts`, one `### <slug>` heading per slug in [`ERRORS.md`](ERRORS.md),
|
|
166
|
+
harvested by `tests/errors-doc.test.ts`); exit `1` = failure and `2` = idempotent no-op; stdout
|
|
167
|
+
carries the payload and nothing else. Stated in [`OUTPUT-CONTRACT.md`](OUTPUT-CONTRACT.md) and pinned
|
|
168
|
+
by `tests/output-contract.test.ts`.
|
|
169
|
+
|
|
170
|
+
**C3 — `eris completion` emits without loading any other verb**, and its output is
|
|
171
|
+
byte-deterministic for a given composed registry. A row's completion domain is data on the row:
|
|
172
|
+
its helper text is checked at composition (`src/cli/commands/completion/domain.ts`) so sourcing
|
|
173
|
+
the script runs nothing and no helper can swallow core's text.
|
|
174
|
+
|
|
175
|
+
**C4 — the shell only shrinks.** The shim is frozen as one total (`.sh` files,
|
|
176
|
+
code lines, function definitions) by `tests/source-is-text.test.ts` against
|
|
177
|
+
`tests/fixtures/ratchet-baseline.json` `FREEZE`. Growth fails; a shrink fails until the baseline is
|
|
178
|
+
lowered in the same change, so freed room is never re-spent. The same file bans the quadratic
|
|
179
|
+
`${v//pattern/repl}` blank test in that shell. New logic goes to TypeScript.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## See also
|
|
184
|
+
|
|
185
|
+
- [`OUTPUT-CONTRACT.md`](OUTPUT-CONTRACT.md): what eris guarantees to a program.
|
|
186
|
+
- [`dev/ADDING-A-COMMAND.md`](dev/ADDING-A-COMMAND.md): adding a verb behind the registry.
|
|
187
|
+
- [`dev/PLUGINS.md`](dev/PLUGINS.md): adding a verb group as a build-time plugin.
|
|
188
|
+
- [`ERRORS.md`](ERRORS.md): the error-slug catalogue.
|