@sigrun/sigrun 0.1.6 → 0.2.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/CHANGELOG.md +192 -0
- package/README.md +445 -42
- package/dist/blocks/build-stamp.json +13 -0
- package/dist/blocks/builders.d.ts +57 -0
- package/dist/blocks/images.d.ts +26 -0
- package/dist/blocks/index.d.ts +20 -0
- package/dist/blocks/limits.d.ts +25 -0
- package/dist/blocks/placements.d.ts +26 -0
- package/dist/blocks/schema.d.ts +38 -0
- package/dist/blocks/schema.js +9 -2
- package/dist/blocks/validate.d.ts +73 -0
- package/dist/blocks/validate.js +57 -8
- package/dist/cli.js +26 -2
- package/dist/config.js +67 -1
- package/dist/extension.d.ts +230 -22
- package/dist/harness/ambient.js +39 -185
- package/dist/harness/blocks/entries.js +47 -0
- package/dist/harness/blocks/state.js +58 -0
- package/dist/harness/blocks/tools.js +274 -0
- package/dist/harness/boot.js +259 -20
- package/dist/harness/builtins.js +15 -11
- package/dist/harness/event-bus.js +105 -10
- package/dist/harness/identity/accounts.js +186 -0
- package/dist/harness/identity/groups.js +14 -0
- package/dist/harness/identity/index.js +13 -6
- package/dist/harness/identity/json-store.js +15 -4
- package/dist/harness/identity/setup-code-check.js +9 -0
- package/dist/harness/identity/tokens.js +28 -5
- package/dist/harness/identity/users.js +111 -12
- package/dist/harness/interactions.js +292 -136
- package/dist/harness/loader.js +271 -17
- package/dist/harness/packages.js +1 -1
- package/dist/harness/reserved-sections.js +21 -0
- package/dist/harness/seam-host.js +92 -6
- package/dist/harness/sections/context-files.js +1 -1
- package/dist/harness/settings.js +63 -2
- package/dist/harness/stores.js +241 -4
- package/dist/harness/user-services.js +391 -0
- package/dist/harness/user-tools.js +187 -0
- package/dist/harness/workspace.js +61 -57
- package/dist/jobs/fire.js +10 -16
- package/dist/sandbox/availability.js +211 -0
- package/dist/sandbox/command-observer.js +59 -0
- package/dist/sandbox/grants.js +159 -0
- package/dist/sandbox/helper.js +29 -0
- package/dist/sandbox/isolation.js +29 -0
- package/dist/sandbox/launch.js +31 -0
- package/dist/sandbox/os-account.js +49 -0
- package/dist/sandbox/policy.js +274 -0
- package/dist/sandbox/pool.js +548 -0
- package/dist/sandbox/protocol.js +167 -0
- package/dist/sandbox/sandboxed-env.js +245 -0
- package/dist/sandbox/unavailable-env.js +49 -0
- package/dist/sandbox/worker.js +261 -0
- package/dist/serve.js +213 -25
- package/dist/server/auth/access-principal.js +16 -0
- package/dist/server/auth/pipeline.js +99 -36
- package/dist/server/blocks/answers.js +94 -0
- package/dist/server/blocks/chat-surfaces.js +393 -0
- package/dist/server/blocks/notes.js +216 -0
- package/dist/server/blocks/summaries.js +328 -0
- package/dist/server/commands.js +5 -0
- package/dist/server/content-parts-lazy.js +13 -0
- package/dist/server/conversation-handler.js +2 -5
- package/dist/server/conversation-ops.js +138 -37
- package/dist/server/helpers.js +18 -6
- package/dist/server/host-bridge.js +40 -20
- package/dist/server/images/cache.js +213 -0
- package/dist/server/images/convert.js +13 -0
- package/dist/server/images/fetch.js +302 -0
- package/dist/server/images/ranges.js +42 -0
- package/dist/server/images/rewrite.js +94 -0
- package/dist/server/images/sign.js +84 -0
- package/dist/server/images/sniff.js +62 -0
- package/dist/server/index.js +152 -4
- package/dist/server/login/flows.js +126 -0
- package/dist/server/login/http.js +31 -0
- package/dist/server/login/resolve.js +133 -0
- package/dist/server/login/setup-claim.js +55 -0
- package/dist/server/login/usernames.js +15 -0
- package/dist/server/notifications.js +21 -4
- package/dist/server/ownership.js +13 -0
- package/dist/server/routes/admin.js +58 -0
- package/dist/server/routes/auth.js +88 -2
- package/dist/server/routes/conversations.js +3 -6
- package/dist/server/routes/events.js +28 -3
- package/dist/server/routes/extensions.js +37 -5
- package/dist/server/routes/images.js +274 -0
- package/dist/server/routes/interactions.js +57 -68
- package/dist/server/routes/jobs.js +2 -8
- package/dist/server/routes/login.js +223 -0
- package/dist/server/routes/me.js +90 -0
- package/dist/server/routes/meta.js +19 -0
- package/dist/server/routes/onboarding.js +94 -84
- package/dist/server/routes/settings-sections.js +190 -0
- package/dist/server/routes/settings.js +16 -4
- package/dist/server/routes/submissions.js +1 -1
- package/dist/server/routes/surfaces.js +175 -23
- package/dist/server/routes/users.js +116 -20
- package/dist/server/schema-fixture.js +213 -0
- package/dist/server/session-meta.js +3 -0
- package/dist/server/shutdown.js +11 -4
- package/dist/server/static.js +18 -0
- package/dist/server/surfaces/dedup.js +9 -2
- package/dist/server/surfaces/service.js +181 -13
- package/dist/server/surfaces/settings-surfaces.js +597 -0
- package/dist/server/turns/submit-turn.js +26 -0
- package/dist/server/views.js +16 -0
- package/dist/settings/core-sections.js +532 -0
- package/dist/settings/pending.js +181 -0
- package/dist/settings/registry.js +453 -0
- package/dist/skills/index.js +6 -0
- package/node_modules/@sigrun/shared/CHANGELOG.md +11 -0
- package/node_modules/@sigrun/shared/dist/access.d.ts +4 -2
- package/node_modules/@sigrun/shared/dist/access.js +11 -4
- package/node_modules/@sigrun/shared/dist/ambient.d.ts +17 -74
- package/node_modules/@sigrun/shared/dist/ambient.js +8 -6
- package/node_modules/@sigrun/shared/dist/blocks/text.js +16 -2
- package/node_modules/@sigrun/shared/dist/blocks/transport.d.ts +4 -0
- package/node_modules/@sigrun/shared/dist/blocks/types.d.ts +21 -4
- package/node_modules/@sigrun/shared/dist/interactions.d.ts +22 -48
- package/node_modules/@sigrun/shared/dist/interactions.js +9 -7
- package/node_modules/@sigrun/shared/dist/settings.d.ts +27 -2
- package/node_modules/@sigrun/shared/dist/themes.d.ts +2 -3
- package/node_modules/@sigrun/shared/dist/themes.js +2 -3
- package/node_modules/@sigrun/shared/dist/turns.d.ts +14 -0
- package/node_modules/@sigrun/shared/dist/turns.js +53 -3
- package/node_modules/@sigrun/shared/dist/views.d.ts +202 -12
- package/node_modules/@sigrun/shared/dist/views.js +16 -0
- package/node_modules/@sigrun/shared/package.json +1 -1
- package/package.json +13 -9
- package/webui/dist/assets/index-SO2W4jjk.js +55 -0
- package/webui/dist/assets/index-yqkL6BSS.css +1 -0
- package/webui/dist/index.html +2 -2
- package/CONTEXT.md +0 -163
- package/webui/dist/assets/index-CiYInlLx.css +0 -1
- package/webui/dist/assets/index-JDfOQV9z.js +0 -52
package/README.md
CHANGED
|
@@ -1,11 +1,28 @@
|
|
|
1
1
|
# Sigrun
|
|
2
2
|
|
|
3
|
-
Sigrun is a durable personal-assistant
|
|
4
|
-
[pi-durable](https://www.npmjs.com/package/@earendil-works/pi-durable)
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
Sigrun is a **durable, multi-user personal-assistant server** built on
|
|
4
|
+
[pi-durable](https://www.npmjs.com/package/@earendil-works/pi-durable).
|
|
5
|
+
One agent loop serves every surface — a web UI, a terminal UI, an HTTP
|
|
6
|
+
API, and (via the gateway extension) chat channels — over long-lived
|
|
7
|
+
conversations stored in SQLite.
|
|
8
|
+
An extension model installs extra tools, providers, prompt sections,
|
|
9
|
+
memory systems, and login providers at boot.
|
|
10
|
+
|
|
11
|
+
**Why use it?** Conversations survive restarts and resume where they
|
|
12
|
+
stopped; memory and integrations are extension-owned and individually
|
|
13
|
+
replaceable; multi-user boundaries are explicit (real authentication plus
|
|
14
|
+
a per-user execution jail); and it deploys as an npm package, a Docker
|
|
15
|
+
compose reference, or a Helm chart. [`docs/why.md`](docs/why.md) is the
|
|
16
|
+
longer rationale.
|
|
17
|
+
|
|
18
|
+
**Status:** 0.x — useful and exercised, but extension and settings
|
|
19
|
+
contracts can still evolve between minor releases. See
|
|
20
|
+
[`SECURITY.md`](SECURITY.md) for the support, trust, and verification
|
|
21
|
+
posture, and [`CONTRIBUTING.md`](CONTRIBUTING.md) to build and test.
|
|
22
|
+
|
|
23
|
+
**Try it:** `npm i -g @sigrun/sigrun && sigrun run` — or jump to
|
|
24
|
+
[Install](#install) and [Quickstart](#quickstart) for the model/credential
|
|
25
|
+
setup every install needs.
|
|
9
26
|
|
|
10
27
|
- **Durable** — conversations, submissions, and schedules live in one
|
|
11
28
|
SQLite database (`SIGRUN_STORAGE_PATH`); a restart resumes where it
|
|
@@ -104,7 +121,7 @@ entrypoints:
|
|
|
104
121
|
| Command | Behavior |
|
|
105
122
|
|---|---|
|
|
106
123
|
| `sigrun [--user <name>]` | Workstation mode: boot the harness + server **in-process** and launch the terminal UI against the loopback port — the server binds **loopback (`127.0.0.1`) only**, so the naive-identity API never answers the LAN. The agent dies with the TUI — when the TUI exits, server and harness shut down with it. |
|
|
107
|
-
| `sigrun serve` | Headless: boot the API + web UI statics, no TUI. This is exactly the `npm start` / `src/index.ts` composition the Docker image and Helm chart run. Binds all interfaces (`0.0.0.0`) — the container default; workstation `sigrun` (run) binds loopback only. |
|
|
124
|
+
| `sigrun serve` | Headless: boot the API + web UI statics, no TUI. This is exactly the `npm start` / `src/index.ts` composition the Docker image and Helm chart run. Binds all interfaces (`::`, the dual-stack wildcard — accepts IPv4 and IPv6; a v4-only `0.0.0.0` bind is unreachable on a dual-stack pod's IPv6 endpoint) — the container default; workstation `sigrun` (run) binds loopback only. |
|
|
108
125
|
| `sigrun attach [--server <url>] [--user <name>]` | TUI only, against a harness it can reach — the remote-client mode (e.g. attaching to a cluster or tailnet deployment). |
|
|
109
126
|
|
|
110
127
|
Resolution chains for `attach` (and for the workstation-mode user):
|
|
@@ -156,6 +173,7 @@ still override it per field.
|
|
|
156
173
|
| `OPENAI_API_KEY` | string | — | `auth.json` (see below) | Credential for the env-driven OpenAI-compatible provider; the `auth.json` fallback after file entries. |
|
|
157
174
|
| `OPENAI_BASE_URL` | URL | OpenAI | `defaultProvider.baseUrl` | Endpoint for the env-driven provider (any compatible host). |
|
|
158
175
|
| `SIGRUN_PORT` | positive int | `3000` | `server.port` | HTTP listen port. |
|
|
176
|
+
| `SIGRUN_LISTEN_HOST` | host | `::` | — | HTTP listen host — the environment equivalent of the programmatic `serve({host})` option (the option wins when both are set). One resolved value drives the bind AND the auth defaults: a loopback bind derives the no-auth workstation posture, any other bind derives `token` auth. `GET /v1/meta` reports the effective listener (`listener.host`/`port`/`families`). |
|
|
159
177
|
| `SIGRUN_STORAGE_PATH` | path | `<dataDir>/sigrun.db` | `server.storagePath` | SQLite database location. Relative values resolve against the data root (absolute values verbatim; the cwd-relative `data/sigrun.db` default is retired). |
|
|
160
178
|
| `SIGRUN_WORKSPACE_PATH` | path | `<dataDir>/workspace` | `server.workspacePath` | Root of the static local workspace every conversation's tools run against. The default rides the data root (chart/compose deploys set the path explicitly); it is never persisted on first boot. |
|
|
161
179
|
| `SIGRUN_DATA_DIR` | path | `$XDG_DATA_HOME/sigrun` or `~/.local/share/sigrun` | `server.dataDir` | Data root (the DB default and extension data dirs). Env/file values win verbatim. |
|
|
@@ -265,8 +283,10 @@ list explicitly — explicit always wins, including `[]` on a non-
|
|
|
265
283
|
loopback bind, which boots with a warning that any reachable client is
|
|
266
284
|
trusted. The related env knobs: `SIGRUN_AUTH_TRUSTED_PROXIES` (CIDR
|
|
267
285
|
csv), `SIGRUN_PROXY_SECRET` and `SIGRUN_API_TOKEN` (credentials —
|
|
268
|
-
env-only, never in `settings.json`). Every auth setting
|
|
269
|
-
restart-required.
|
|
286
|
+
env-only, never in `settings.json`). Every auth setting except
|
|
287
|
+
`server.auth.sessionDays` is restart-required. `sessionDays` applies live to
|
|
288
|
+
new sessions and has no core settings-section field; change it in the
|
|
289
|
+
settings file or with `PATCH /v1/settings`.
|
|
270
290
|
|
|
271
291
|
**Tokens.** API tokens are `sgr_`-prefixed secrets shown once at
|
|
272
292
|
creation (the store keeps only SHA-256 digests) and are self-service:
|
|
@@ -275,7 +295,8 @@ an authenticated user lists and mints their own via
|
|
|
275
295
|
admins may revoke anyone's). A token whose user was deleted is dead.
|
|
276
296
|
A browser exchanges a token for a `sigrun_session` cookie at
|
|
277
297
|
`POST /v1/auth/login` — invalid attempts are delayed and rate-limited —
|
|
278
|
-
and `GET /v1/auth/whoami` returns the resolved principal.
|
|
298
|
+
and `GET /v1/auth/whoami` returns the resolved principal. An IdP-signed-in
|
|
299
|
+
user can mint their own API token for the TUI through the same token routes.
|
|
279
300
|
|
|
280
301
|
**Proxy method (forward auth).** A trusted reverse proxy vouches for
|
|
281
302
|
the caller through headers (Authelia's `Remote-*` defaults,
|
|
@@ -286,19 +307,166 @@ configurable) when the request comes from a peer inside
|
|
|
286
307
|
proxy and nothing else: every peer in `trustedProxies` can forge any
|
|
287
308
|
identity, including an admin.
|
|
288
309
|
|
|
289
|
-
**
|
|
290
|
-
|
|
291
|
-
admins.
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
310
|
+
**Stored groups and group-derived admin.** `server.auth.adminGroups`
|
|
311
|
+
lists groups (Authelia's `Remote-Groups`, for example) whose members act as
|
|
312
|
+
admins. Core stores groups per authenticating source: `proxy` for validated
|
|
313
|
+
forward-auth headers and `login:<slug>:<id>` for an external login. Effective
|
|
314
|
+
admin is the stored `admin` flag OR any stored group in `adminGroups`, so
|
|
315
|
+
web, chat, and host-side checks agree. `/v1/users` keeps `admin` as the
|
|
316
|
+
stored flag the users-admin UI toggles; its `groupAdmin` compatibility field
|
|
317
|
+
is derived, never persisted, and is retained for one release. Group-derived
|
|
318
|
+
admin never counts toward the last-admin guard — demoting or deleting the
|
|
319
|
+
only stored admin is still refused.
|
|
320
|
+
|
|
321
|
+
Login-provider groups participate in `server.auth.adminGroups`, so configure
|
|
322
|
+
only providers whose group claims are administrator-controlled. A linked
|
|
323
|
+
account's groups come from the provider at each sign-in; removing admin
|
|
324
|
+
therefore requires changing the provider's claim or removing the link/user.
|
|
325
|
+
|
|
326
|
+
Groups refresh only at that user's next login or proxy request. This
|
|
327
|
+
staleness is deliberate: a group removal at the IdP does not take effect
|
|
328
|
+
until then. Token and session requests only read the stored record; they
|
|
329
|
+
never accept groups from the request. People-scoped conversation shares may
|
|
330
|
+
also name groups, matched against the same stored groups.
|
|
331
|
+
|
|
332
|
+
### External sign-in (OIDC and OAuth 2)
|
|
333
|
+
|
|
334
|
+
The web sign-in screen lists configured external providers above the token
|
|
335
|
+
form when the effective auth methods include `token`; `/v1/auth/providers`
|
|
336
|
+
returns an empty list on proxy-only deployments because their completed
|
|
337
|
+
sign-ins could not authenticate the resulting session. The TUI continues to
|
|
338
|
+
use tokens. Login providers come from extensions.
|
|
339
|
+
The reference implementation is **`@sigrun/oauth`, the fourth built-in
|
|
340
|
+
extension**. It is bundled and loads by default, so no `extensions` entry is
|
|
341
|
+
needed. Set `"builtinExtensions": {"oauth": false}` to disable it; like the
|
|
342
|
+
other built-in toggles, this is restart-required. A configured extension
|
|
343
|
+
whose package name is also `@sigrun/oauth` replaces the built-in. If the
|
|
344
|
+
built-in cannot be resolved or loaded, it is quarantined without aborting
|
|
345
|
+
boot. Standalone installation outside the built-in is not a supported use
|
|
346
|
+
case in 0.2; the package's type-only core dependency posture is accepted
|
|
347
|
+
for this release. It is inert when its settings contain no valid providers.
|
|
348
|
+
|
|
349
|
+
Create an OAuth/OIDC client at the identity service, with the redirect URI
|
|
350
|
+
shown below. Configure providers in the extension's
|
|
351
|
+
`<config-dir>/settings/oauth.json`; an administrator can edit that JSON in
|
|
352
|
+
Settings → Extensions → oauth. Set `server.publicUrl` (or
|
|
353
|
+
`SIGRUN_PUBLIC_URL`) to sigrun's externally reachable origin so callback
|
|
354
|
+
URLs are stable; otherwise core derives one from the request.
|
|
355
|
+
|
|
356
|
+
For a generic OIDC service — Authelia, Authentik, and Keycloak are examples
|
|
357
|
+
of products this form fits, not service-specific presets — configure its
|
|
358
|
+
issuer and client:
|
|
359
|
+
|
|
360
|
+
```json
|
|
361
|
+
{
|
|
362
|
+
"providers": [
|
|
363
|
+
{
|
|
364
|
+
"id": "company",
|
|
365
|
+
"label": "Company SSO",
|
|
366
|
+
"kind": "oidc",
|
|
367
|
+
"issuer": "https://idp.example.invalid",
|
|
368
|
+
"clientId": "sigrun",
|
|
369
|
+
"scopes": "openid profile email",
|
|
370
|
+
"usernameClaim": "preferred_username",
|
|
371
|
+
"groupsClaim": "groups",
|
|
372
|
+
"autoProvision": false,
|
|
373
|
+
"allowedGroups": ["staff"],
|
|
374
|
+
"allowedDomains": ["example.invalid"]
|
|
375
|
+
}
|
|
376
|
+
]
|
|
377
|
+
}
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
The extension uses OIDC discovery, authorization code with PKCE S256 and a
|
|
381
|
+
nonce, and validates the ID token. `scopes`, `usernameClaim`, and
|
|
382
|
+
`groupsClaim` shown above are the defaults. For this example, register
|
|
383
|
+
`https://sigrun.example.invalid/v1/auth/callback/login:oauth:company` as
|
|
384
|
+
the redirect URI (the provider id is qualified, not merely `company`).
|
|
385
|
+
Production identity endpoints must use HTTPS; plain HTTP is restricted to
|
|
386
|
+
loopback development and tests.
|
|
387
|
+
|
|
388
|
+
Every provider needs a client secret named `<id>.clientSecret` in the
|
|
389
|
+
**oauth extension secret store** — `company.clientSecret` here. Set it in
|
|
390
|
+
Settings → Extensions → oauth (write-only), or as an administrator with
|
|
391
|
+
`PUT /v1/extensions/oauth/secrets/company.clientSecret` and body
|
|
392
|
+
`{"value":"<client-secret>"}`. Never put a client secret in
|
|
393
|
+
`settings/oauth.json`. Extension settings are read at boot; restart after
|
|
394
|
+
changing them. Secrets are re-read per use, so a rotated client secret
|
|
395
|
+
applies to the next login without a restart.
|
|
396
|
+
|
|
397
|
+
The GitHub and Discord presets replace issuer/endpoint discovery with their
|
|
398
|
+
protocol endpoints and user field mappings:
|
|
399
|
+
|
|
400
|
+
```json
|
|
401
|
+
{
|
|
402
|
+
"providers": [
|
|
403
|
+
{
|
|
404
|
+
"id": "github",
|
|
405
|
+
"label": "GitHub",
|
|
406
|
+
"kind": "oauth2",
|
|
407
|
+
"preset": "github",
|
|
408
|
+
"clientId": "acme-github-client-id"
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
"id": "discord",
|
|
412
|
+
"label": "Discord",
|
|
413
|
+
"kind": "oauth2",
|
|
414
|
+
"preset": "discord",
|
|
415
|
+
"clientId": "acme-discord-client-id"
|
|
416
|
+
}
|
|
417
|
+
]
|
|
418
|
+
}
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
**Both presets require `clientId` in settings and a client secret in the
|
|
422
|
+
extension secret store** (`github.clientSecret` and
|
|
423
|
+
`discord.clientSecret`). Their redirect URIs end in
|
|
424
|
+
`/v1/auth/callback/login:oauth:github` and
|
|
425
|
+
`/v1/auth/callback/login:oauth:discord` on the same sigrun origin. GitHub
|
|
426
|
+
uses only a primary, verified email; Discord uses its verified flag.
|
|
427
|
+
Neither preset supplies groups. A malformed provider entry is skipped with
|
|
428
|
+
a warning naming it; other valid entries still load.
|
|
429
|
+
|
|
430
|
+
For another OAuth 2 service, use `kind: "oauth2"` with explicit
|
|
431
|
+
`authorizeUrl`, `tokenUrl`, and `userinfoUrl`, plus `fields` mapping a
|
|
432
|
+
required `subject` and optional `username`, `name`, `email`,
|
|
433
|
+
`emailVerified`, and `groups` dot-separated response paths. `clientId`, its
|
|
434
|
+
`<id>.clientSecret` secret, and the same optional policy fields apply.
|
|
435
|
+
|
|
436
|
+
**First login never auto-links by username or email.** An unlinked subject
|
|
437
|
+
on an unclaimed server needs the one-shot setup code and becomes the first
|
|
438
|
+
admin. On a claimed server, `autoProvision: false` (the default) requires an
|
|
439
|
+
invite code; `true` creates a non-admin user, optionally restricted by
|
|
440
|
+
`allowedGroups` and `allowedDomains`. **These filters apply only when
|
|
441
|
+
creating a new user by auto-provisioning** — not to an already-linked
|
|
442
|
+
account's logins or to invite-based provisioning. A linked account keeps
|
|
443
|
+
working; remove its link (or the user) to remove access. A domain match
|
|
444
|
+
additionally requires `emailVerified === true` from the provider. Core
|
|
445
|
+
enforces the M1 admission prerequisites: adding a second user is refused
|
|
446
|
+
without available execution isolation and real `token` and/or `proxy`
|
|
447
|
+
authentication. An external IdP is not itself a trusted proxy.
|
|
448
|
+
|
|
449
|
+
### Browser sessions and account links
|
|
450
|
+
|
|
451
|
+
A successful external sign-in creates a `sigrun_session` cookie backed by a
|
|
452
|
+
revocable session record in the token store. `server.auth.sessionDays`
|
|
453
|
+
controls its lifetime (default **30 days**, live for newly created
|
|
454
|
+
sessions). An expired session is rejected as unknown (401) and its record
|
|
455
|
+
is pruned on the next token-store write. Logout revokes the current
|
|
456
|
+
session; users can also see and revoke sessions in their token list.
|
|
457
|
+
|
|
458
|
+
A session has the user's normal rights, including creating that user's own
|
|
459
|
+
API tokens for the TUI. **Revoking a session does not revoke API tokens
|
|
460
|
+
created with it**; revoke those separately. Core does not store provider
|
|
461
|
+
access or refresh tokens.
|
|
462
|
+
|
|
463
|
+
Settings → Account links is the self-service panel for external identities.
|
|
464
|
+
Connect starts the provider flow with `?link=1` while signed in; the
|
|
465
|
+
identity is linked to the caller instead of creating another sign-in.
|
|
466
|
+
Users can remove their own links and administrators can manage others'
|
|
467
|
+
links. One `(provider, subject)` pair belongs to one user: a link is never
|
|
468
|
+
re-pointed to a different user. The holder or an administrator must remove
|
|
469
|
+
a conflicting old link first.
|
|
302
470
|
|
|
303
471
|
**Onboarding (the first claim).** An unclaimed server serves
|
|
304
472
|
`GET /v1/onboarding` + `POST /v1/onboarding/claim`. On a loopback bind
|
|
@@ -313,11 +481,195 @@ users (`PATCH`/`DELETE /v1/users/{user}` — deletion transfers their
|
|
|
313
481
|
conversations).
|
|
314
482
|
|
|
315
483
|
**Sharing.** Conversations are private to their owner by default. The
|
|
316
|
-
owner can share one — household-wide or with named users
|
|
317
|
-
`write` — through the web UI's ⋯ menu
|
|
484
|
+
owner can share one — household-wide or with named users and groups,
|
|
485
|
+
`read` or `write` — through the web UI's ⋯ menu; `write`
|
|
318
486
|
lets a recipient submit, answer, and fork, but only the owner can
|
|
319
487
|
re-share. Household sharing defaults to `read`.
|
|
320
488
|
|
|
489
|
+
### Per-user extensions and deletion
|
|
490
|
+
|
|
491
|
+
Extensions can offer personal tools, settings, credentials, and services
|
|
492
|
+
instead of only server-wide resources. Each conversation selects its
|
|
493
|
+
owner's per-user tools, and core also checks the committed owner every
|
|
494
|
+
time one executes: selecting another user's entry does not permit its
|
|
495
|
+
use. Per-user services run as that user in their own service jail,
|
|
496
|
+
sibling to the agent's worker. A credential supplied to a service never
|
|
497
|
+
belongs in the agent workspace. See
|
|
498
|
+
[`docs/extending.md`](docs/extending.md#per-user-stores) for the extension
|
|
499
|
+
contract and `/v1/me` self-service routes.
|
|
500
|
+
|
|
501
|
+
A user's extension secrets live in
|
|
502
|
+
`<configDir>/user-secrets/<user>.json`, mode `0600`, with one section
|
|
503
|
+
per extension slug. Their settings live under
|
|
504
|
+
`<configDir>/user-settings/<user>/`; extension data, state, and cache
|
|
505
|
+
have separate per-user paths. Login, sessions, and account linking are
|
|
506
|
+
documented in [External sign-in](#external-sign-in-oidc-and-oauth-2) and
|
|
507
|
+
[Browser sessions and account links](#browser-sessions-and-account-links).
|
|
508
|
+
|
|
509
|
+
`DELETE /v1/users/{user}?transferTo={recipient}` requires an admin and
|
|
510
|
+
another directory user as recipient. Core transfers conversations and
|
|
511
|
+
owned resources, then revokes the departing user's tokens and account
|
|
512
|
+
links, stops their worker and services, and removes their per-user tool
|
|
513
|
+
entries. Extensions then receive `userDeleted` while the old record and
|
|
514
|
+
secrets remain readable, so they can revoke external provider
|
|
515
|
+
credentials. Finally core removes the directory record, per-user secrets,
|
|
516
|
+
user-settings directory, and per-user cache directories.
|
|
517
|
+
|
|
518
|
+
**Credentials belong to a person and never transfer.** Data and state
|
|
519
|
+
stay for the extension to retain, move, or delete according to its own
|
|
520
|
+
rules; core does not make that choice.
|
|
521
|
+
|
|
522
|
+
## Multi-user execution isolation
|
|
523
|
+
|
|
524
|
+
`server.isolation.mode` (or `SIGRUN_ISOLATION`) controls the execution jail:
|
|
525
|
+
|
|
526
|
+
| Mode | Behavior |
|
|
527
|
+
|---|---|
|
|
528
|
+
| `auto` (default) | Turns isolation on when the directory has more than one user. Once active, it stays active until restart. |
|
|
529
|
+
| `always` | Confines every user, including a lone admin. |
|
|
530
|
+
| `off` | No jail; permitted only with at most one directory user. |
|
|
531
|
+
|
|
532
|
+
A second user is refused when isolation is unavailable or `off`, and a
|
|
533
|
+
multi-user server never falls back to unconfined execution. Multi-user also
|
|
534
|
+
requires real authentication (`token` and/or `proxy`).
|
|
535
|
+
|
|
536
|
+
Isolation requires Linux with Landlock ABI 6 or newer (Linux 6.12+) and the
|
|
537
|
+
`sigrun-sandbox` helper. Debian 12's default 6.1 kernel does not qualify;
|
|
538
|
+
bookworm-backports' 6.12 kernel does. Ubuntu 24.04's GA 6.8 kernel does not
|
|
539
|
+
qualify; its HWE 7.0 kernel does. Check the running host with
|
|
540
|
+
`sigrun-sandbox probe`. The container needs no extra capabilities: uid 1000,
|
|
541
|
+
no capabilities, and `RuntimeDefault` seccomp are sufficient.
|
|
542
|
+
|
|
543
|
+
**When isolation is on**, a user's agent can reach only their workspace,
|
|
544
|
+
their grants, their home and temp directories, and read-only system paths.
|
|
545
|
+
It cannot read sigrun's files or environment, other users' files, or signal
|
|
546
|
+
processes outside its jail.
|
|
547
|
+
|
|
548
|
+
The kernel boundary suite has not run yet; CI is its first execution.
|
|
549
|
+
Isolation must therefore not be treated as kernel-verified from the unit
|
|
550
|
+
suite alone.
|
|
551
|
+
|
|
552
|
+
**Not covered:** extensions run inside sigrun with full access, like any
|
|
553
|
+
installed package — install only extensions you trust. One user's agent can
|
|
554
|
+
still exhaust CPU, memory, or disk. Outbound network is not restricted.
|
|
555
|
+
macOS and Windows hosts run single-user only.
|
|
556
|
+
|
|
557
|
+
**Shared MCP servers** hand every permitted user's agent the admin's
|
|
558
|
+
credential for that service.
|
|
559
|
+
|
|
560
|
+
**File modes are not the boundary.** Workers that share sigrun's uid are
|
|
561
|
+
confined by Landlock alone; `0700` directories are hygiene.
|
|
562
|
+
|
|
563
|
+
**Single-user servers** run the agent with full host access.
|
|
564
|
+
|
|
565
|
+
**Every peer in `trustedProxies` can forge any identity**; with isolation
|
|
566
|
+
on, the shared secret is required for that reason. Configure
|
|
567
|
+
`server.auth.proxy.secretHeader` and the env-only `SIGRUN_PROXY_SECRET`.
|
|
568
|
+
|
|
569
|
+
For bare-metal OS-account mappings, enable `server.isolation.osUsers` and
|
|
570
|
+
set a directory record's `osUser`. Grant the installed helper only the
|
|
571
|
+
identity-switch capabilities once (replace `<helper>` with its path):
|
|
572
|
+
|
|
573
|
+
```sh
|
|
574
|
+
sudo setcap cap_setuid,cap_setgid+ep <helper>
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
The helper's boot self-test verifies the switch. `SIGRUN_SANDBOX_HELPER`
|
|
578
|
+
points sigrun at a helper binary at a non-default absolute path (it falls back
|
|
579
|
+
to the installed location with one warning if the path does not exist), which is
|
|
580
|
+
how a staged copy gets used.
|
|
581
|
+
|
|
582
|
+
File capabilities only take effect when the capabilities they grant are
|
|
583
|
+
already in the **caller's** bounding set: executing the capped helper needs
|
|
584
|
+
`CAP_SETUID` and `CAP_SETGID` present in the process that launches it —
|
|
585
|
+
`CAP_SETFCAP` alone only permits writing the xattr and is not enough. A root
|
|
586
|
+
shell, or a host that runs sigrun as root and maps users to real OS accounts,
|
|
587
|
+
normally satisfies this.
|
|
588
|
+
|
|
589
|
+
This mapping is bare-metal only. The container entrypoint starts as the image's
|
|
590
|
+
non-root `USER` and execs straight through (one uid for the whole container), so
|
|
591
|
+
it holds no identity-switch capabilities to inherit — containers use the
|
|
592
|
+
Landlock jail alone, which is where container multi-user isolation comes from.
|
|
593
|
+
A root container start (`SIGRUN_UID=0`) does exist, but it is a mount-point
|
|
594
|
+
ownership trampoline, not an `osUsers` enabler: it needs
|
|
595
|
+
`CAP_CHOWN`/`CAP_SETUID`/`CAP_SETGID` for the chown-and-drop and still leaves
|
|
596
|
+
you with a single container uid.
|
|
597
|
+
|
|
598
|
+
#### If you insist on `osUsers` in a container — and why you shouldn't
|
|
599
|
+
|
|
600
|
+
It is possible, and two of the three pieces need no image change. A capped
|
|
601
|
+
helper can be staged at runtime on any writable path (a named volume, a
|
|
602
|
+
`tmpfs`, a bind mount), and the caps come from the container's own flags:
|
|
603
|
+
|
|
604
|
+
```yaml
|
|
605
|
+
# the runtime half — no derived image required
|
|
606
|
+
services:
|
|
607
|
+
sigrun:
|
|
608
|
+
user: "1000:1000"
|
|
609
|
+
cap_add: [SETUID, SETGID] # bounding set for the helper's file caps
|
|
610
|
+
volumes:
|
|
611
|
+
- sigrun-data:/data
|
|
612
|
+
- helper:/opt/helper # a writable path for the capped copy
|
|
613
|
+
# then, once per volume: copy the helper in, chmod 755, setcap
|
|
614
|
+
# cap_setuid,cap_setgid+ep under --cap-add SETFCAP, and point
|
|
615
|
+
# SIGRUN_SANDBOX_HELPER at it
|
|
616
|
+
security_opt:
|
|
617
|
+
- no-new-privileges:false # REQUIRED — see below
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
The blocker is the third piece: **`osUser` maps to a login name**, resolved from
|
|
621
|
+
`/etc/passwd`, so every user you want needs an account. The image ships exactly
|
|
622
|
+
two non-root accounts (`node` and `nobody`). That is what forces either a
|
|
623
|
+
derived image (`RUN useradd …` per user) or mounting a `passwd` file over
|
|
624
|
+
`/etc/passwd` through a `subPath`, which is fragile and surprises tooling.
|
|
625
|
+
|
|
626
|
+
And the default posture actively prevents it, three ways: `read_only: true`
|
|
627
|
+
makes `setcap` on the image layer fail with "Read-only file system",
|
|
628
|
+
`cap_drop: ALL` grants nothing, and `no-new-privileges: true` suppresses the
|
|
629
|
+
file-capability gain on `execve` even when `SETUID`/`SETGID` are in the bounding
|
|
630
|
+
set (the helper dies at its first privileged call). Enabling this therefore
|
|
631
|
+
means adding capabilities **and** permitting privilege escalation — a
|
|
632
|
+
deliberate threat-model relaxation, not a configuration tweak.
|
|
633
|
+
|
|
634
|
+
The reason not to is structural rather than configurational: inside one
|
|
635
|
+
container every `osUser` shares **one filesystem and one mount namespace**. You
|
|
636
|
+
would gain per-process uids and Landlock's per-process confinement, but not the
|
|
637
|
+
kernel-level user separation a host provides — because there is only one
|
|
638
|
+
container boundary to separate. You would be paying a real security cost (an
|
|
639
|
+
identity-switch capability held by the main process, privilege escalation
|
|
640
|
+
permitted) for isolation the container boundary already substantially provides.
|
|
641
|
+
Use the Landlock jail alone in containers; use `osUsers` on bare metal, where
|
|
642
|
+
the accounts and the separation are real.
|
|
643
|
+
|
|
644
|
+
### Kernel integration runner controls
|
|
645
|
+
|
|
646
|
+
The opt-in suite is `SIGRUN_SANDBOX_IT=1 npx vitest run test/sandbox-it`.
|
|
647
|
+
The CI `sandbox-it` job requires Landlock ABI 6 before running it. Its
|
|
648
|
+
`/proc` and ptrace cases also perform the same operation as the same uid
|
|
649
|
+
from outside any jail. The run log states, per case, either **Landlock
|
|
650
|
+
discriminating** (the outside operation succeeds) or **Yama/host-policy
|
|
651
|
+
satisfied, not Landlock-discriminating** (the outside operation is denied
|
|
652
|
+
too). The latter still checks the denial but does not claim Landlock caused
|
|
653
|
+
it. The abstract-socket case requires a successful outside-jail connection.
|
|
654
|
+
The `pkill -x node` case needs unprivileged user/PID namespaces and `nsenter`:
|
|
655
|
+
its outside control kills only PID 1 of a disposable namespace, never the
|
|
656
|
+
test runner or another host Node process. If namespaces are unavailable,
|
|
657
|
+
the suite skips with that named reason.
|
|
658
|
+
|
|
659
|
+
The `osUser` success case and the in-jail uid-switch discrimination require
|
|
660
|
+
a **privileged runner** with `CAP_SETFCAP` and
|
|
661
|
+
`SIGRUN_SANDBOX_IT_PRIVILEGED=1`. The suite grants only
|
|
662
|
+
`cap_setuid,cap_setgid+ep` to a temporary helper copy and verifies an
|
|
663
|
+
unjailed uid/gid switch before testing the jailed denial. Without that
|
|
664
|
+
successful outside control, both tests skip with a named reason; they never
|
|
665
|
+
claim to prove confinement. An ordinary CI runner without file-capability
|
|
666
|
+
permission therefore leaves these two cases unproven. The suite never runs
|
|
667
|
+
`sudo` itself.
|
|
668
|
+
|
|
669
|
+
The per-user-service process tests use a separate real-helper-launched
|
|
670
|
+
service fixture. They cover the sibling-jail `/proc` and ptrace boundary;
|
|
671
|
+
the per-user service API and lifecycle are documented above.
|
|
672
|
+
|
|
321
673
|
## Backup
|
|
322
674
|
|
|
323
675
|
Set a target (`SIGRUN_BACKUP_PATH` or `SIGRUN_BACKUP_S3_BUCKET`+`SIGRUN_BACKUP_S3_PREFIX`,
|
|
@@ -509,18 +861,31 @@ wins, env bootstraps). The author-facing contract — the store taxonomy,
|
|
|
509
861
|
the directory map, the slug rule, the `host.stores` handle, uninstall
|
|
510
862
|
and backup posture — is [`docs/extending.md`](docs/extending.md).
|
|
511
863
|
|
|
864
|
+
**Building surfaces:** an extension can also contribute UI — views,
|
|
865
|
+
panels, settings sections, chat and interaction cards, ambient status —
|
|
866
|
+
as **block trees** rendered identically by the webui and the TUI. The
|
|
867
|
+
typed builders come from `@sigrun/sigrun/blocks`; the placement table,
|
|
868
|
+
block catalog, action kinds, access and `sharedData`, uploads, images,
|
|
869
|
+
and three complete worked examples (a lanes board, a settings section,
|
|
870
|
+
a dashboard) are in
|
|
871
|
+
[`docs/extending.md`](docs/extending.md#building-surfaces).
|
|
872
|
+
|
|
512
873
|
## Built-in extensions
|
|
513
874
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
875
|
+
Five extensions are built into core — **codemode**, **MCP**, **tool
|
|
876
|
+
search**, **gateway**, and **OAuth login**. The first three mirror
|
|
877
|
+
what pi 1.3.0 ships built-in; the gateway is sigrun's own channel-adapter
|
|
878
|
+
engine; OAuth provides OIDC, GitHub, and Discord login providers. They
|
|
879
|
+
load by default on every boot, with no settings entry, and resolve from
|
|
880
|
+
core's own `node_modules` (they are core dependencies, never installed
|
|
881
|
+
into the packages dir — `extensions` has nothing to install for them,
|
|
882
|
+
unless a same-named package is deliberately installed to replace one;
|
|
883
|
+
see below).
|
|
521
884
|
A default install therefore has pi's tool surface without configuring
|
|
522
885
|
anything. On `GET /v1/extensions` they report under the names
|
|
523
|
-
`codemode`, `sigrun-mcp`,
|
|
886
|
+
`codemode`, `sigrun-mcp`, `tool-search`, `gateway`, and `oauth`.
|
|
887
|
+
Configure OAuth providers in `settings/oauth.json`; see the
|
|
888
|
+
`@sigrun/oauth` package README for provider settings and secrets.
|
|
524
889
|
|
|
525
890
|
**The tools stay off until needed** (pi parity): `codemode` and
|
|
526
891
|
`tool_search` are not in a new conversation's model-offered tool set by
|
|
@@ -534,10 +899,10 @@ default. They join the offered set when an enabled MCP server's
|
|
|
534
899
|
automatic decision (auto-enable only narrows the default set, never a
|
|
535
900
|
named list).
|
|
536
901
|
- **Turning one off** — `"builtinExtensions": {"codemode": false,
|
|
537
|
-
"mcp": false, "toolSearch": false
|
|
538
|
-
restart-required. A disabled built-in
|
|
539
|
-
`GET /v1/extensions` entirely — no row, not even a
|
|
540
|
-
its config is then ignored.
|
|
902
|
+
"mcp": false, "toolSearch": false, "gateway": false, "oauth": false}`.
|
|
903
|
+
Each defaults to `true`; each is restart-required. A disabled built-in
|
|
904
|
+
disappears from `GET /v1/extensions` entirely — no row, not even a
|
|
905
|
+
skipped one — and its config is then ignored.
|
|
541
906
|
- **Replacing one** — installing a package that resolves to the same
|
|
542
907
|
package name as a built-in replaces it: the installed copy loads, the
|
|
543
908
|
built-in is skipped, boot logs one warning naming both, and
|
|
@@ -550,16 +915,23 @@ default. They join the offered set when an enabled MCP server's
|
|
|
550
915
|
The MCP servers themselves live in the MCP config file — the
|
|
551
916
|
`@sigrun/ext-mcp` package's README documents its format, including each
|
|
552
917
|
server's `exposure` and the `SIGRUN_MCP_CONFIG` override.
|
|
918
|
+
**User-supplied MCP servers are remote-only in 0.2** (URL transport);
|
|
919
|
+
a user-supplied stdio server fails loudly with a config error. Dynamic
|
|
920
|
+
jailed per-user stdio services are a post-release feature — per-user
|
|
921
|
+
services are declared statically by extensions (see
|
|
922
|
+
docs/extending.md).
|
|
553
923
|
|
|
554
924
|
```jsonc
|
|
555
925
|
{
|
|
556
926
|
"extensions": [ // configured extensions install + load as above
|
|
557
927
|
"@acme/sigrun-ext-example@^0.1.0"
|
|
558
928
|
],
|
|
559
|
-
"builtinExtensions": { // all
|
|
929
|
+
"builtinExtensions": { // all five default to true; restart required
|
|
560
930
|
"codemode": true,
|
|
561
931
|
"mcp": true,
|
|
562
|
-
"toolSearch": false
|
|
932
|
+
"toolSearch": false,
|
|
933
|
+
"gateway": true,
|
|
934
|
+
"oauth": true
|
|
563
935
|
}
|
|
564
936
|
}
|
|
565
937
|
```
|
|
@@ -680,11 +1052,38 @@ In the web UI the Jobs panel (the clock icon in the header) lists jobs
|
|
|
680
1052
|
with a “Run now” button; in the TUI `/jobs` prints the table (name,
|
|
681
1053
|
next run, last outcome).
|
|
682
1054
|
|
|
1055
|
+
## Restarting
|
|
1056
|
+
|
|
1057
|
+
Restart-only settings (the registry marks every key `live` or
|
|
1058
|
+
`restart` — a `restart` key's stored write applies at the next boot)
|
|
1059
|
+
surface as `pendingRestart` on `GET /v1/settings`, and the settings
|
|
1060
|
+
panel lists them with a Restart button for admins. The button calls:
|
|
1061
|
+
|
|
1062
|
+
- `POST /v1/admin/restart` — admin-only; runs the normal graceful
|
|
1063
|
+
shutdown (SSE drains, in-flight runs reach a durable boundary and
|
|
1064
|
+
resume after the restart — pi-durable's recovery) and exits 0, so the
|
|
1065
|
+
deployment's supervisor brings the process back. Both channels show
|
|
1066
|
+
"Restarting…" and reconnect when `/readyz` answers.
|
|
1067
|
+
|
|
1068
|
+
The route exists ONLY when the server knows something restarts it:
|
|
1069
|
+
`server.supervised` (env `SIGRUN_SUPERVISED=1`, strict true/false)
|
|
1070
|
+
must be true, else 409 `not_supervised`. The Helm chart and
|
|
1071
|
+
`docker/docker-compose.yaml` set the env (both restart the container);
|
|
1072
|
+
the Dockerfile deliberately does NOT — a bare `docker run` without a
|
|
1073
|
+
restart policy would exit and stay down. `sigrun run` (the local TUI
|
|
1074
|
+
launcher) is not supervised either; there the callout says "Restart
|
|
1075
|
+
sigrun to apply" with no button. `GET /v1/meta` reports the posture
|
|
1076
|
+
(`supervised`).
|
|
1077
|
+
|
|
683
1078
|
## API sketch
|
|
684
1079
|
|
|
685
1080
|
- `GET /v1/meta` — version, extensions, health, auth posture
|
|
686
1081
|
(`methods`, `claimed`), capabilities.
|
|
687
|
-
- `GET`/`PATCH /v1/settings` — the settings file (see above)
|
|
1082
|
+
- `GET`/`PATCH /v1/settings` — the settings file (see above);
|
|
1083
|
+
responses carry `pendingRestart` (restart keys whose stored value
|
|
1084
|
+
differs from boot) and PATCH reports `{applied, pending}`.
|
|
1085
|
+
- `POST /v1/admin/restart` — graceful restart (admin, supervised
|
|
1086
|
+
deploys only; see Restarting).
|
|
688
1087
|
- `GET /v1/jobs`, `POST /v1/jobs`, `PATCH`/`DELETE /v1/jobs/{id}` —
|
|
689
1088
|
the jobs surface (see [Jobs](#jobs)); `POST /v1/jobs/{id}/run` fires
|
|
690
1089
|
now; `GET /v1/jobs/{id}/runs` and `GET /v1/jobs/{id}/revisions` are
|
|
@@ -697,9 +1096,13 @@ next run, last outcome).
|
|
|
697
1096
|
- `GET /v1/onboarding`, `POST /v1/onboarding/claim` — the unclaimed
|
|
698
1097
|
state and the first-user claim.
|
|
699
1098
|
- `POST /v1/auth/login`, `POST /v1/auth/logout`, `GET /v1/auth/whoami` —
|
|
700
|
-
|
|
1099
|
+
token sign-in, logout, and the resolved principal.
|
|
1100
|
+
- `GET /v1/auth/providers`, `GET /v1/auth/login/{provider}`,
|
|
1101
|
+
`GET`/`POST /v1/auth/callback/{provider}` — external sign-in.
|
|
701
1102
|
- `GET`/`POST /v1/auth/tokens`, `DELETE /v1/auth/tokens/{id}` —
|
|
702
|
-
self-service API tokens.
|
|
1103
|
+
self-service API tokens and browser sessions.
|
|
1104
|
+
- `GET /v1/auth/accounts`, `DELETE /v1/auth/accounts` — self-service
|
|
1105
|
+
external-account links (administrators may manage another user's).
|
|
703
1106
|
- `GET /v1/users`, `PATCH`/`DELETE /v1/users/{user}`,
|
|
704
1107
|
`POST /v1/users/invites` — the user directory and invite codes
|
|
705
1108
|
(admin-gated).
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"algorithm": "sha256",
|
|
3
|
+
"sources": {
|
|
4
|
+
"shared/src/blocks/index.ts": "ca37dbb56a4a1a05a40a0125a06d864b9a0671c70817c83a44dd0e3962999e30",
|
|
5
|
+
"src/blocks/builders.ts": "a0c9835aaeab871bc2548d4b8d4426849c60cdb0cb1b20142d3bbe11e8377005",
|
|
6
|
+
"src/blocks/images.ts": "2e1bd54546c9c1c5bf0cfe9b488aaffd7c37979ef84bae9789168275e63e202f",
|
|
7
|
+
"src/blocks/index.ts": "8878a2e2269572ebdecca2cf3b95fa67f144232d8a8fe4258b120948064d0520",
|
|
8
|
+
"src/blocks/limits.ts": "1e913f29167114e26bed6f8c1fd04c64b119ee1db3f4e9e2ae161ddf70578683",
|
|
9
|
+
"src/blocks/placements.ts": "fccda42669713d91dc78d025268ee127f926891cf383727c1e235a39b9f15c6f",
|
|
10
|
+
"src/blocks/schema.ts": "27dbc5cdf1152a16a75bfb1a70383f1a456999a41d393308c05079b41f087a83",
|
|
11
|
+
"src/blocks/validate.ts": "31b9fc78f569cceff229bd1f28bfc62e2f8da437684100e051104f059a1ca19f"
|
|
12
|
+
}
|
|
13
|
+
}
|