@sigrun/shared 0.4.1 → 0.5.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.
Files changed (50) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/dist/access.d.ts +60 -0
  3. package/dist/access.js +87 -0
  4. package/dist/ambient.d.ts +54 -0
  5. package/dist/ambient.js +25 -0
  6. package/dist/blocks/format.d.ts +28 -0
  7. package/dist/blocks/format.js +199 -0
  8. package/dist/blocks/icons.d.ts +12 -0
  9. package/dist/blocks/icons.js +64 -0
  10. package/dist/blocks/index.d.ts +25 -0
  11. package/dist/blocks/index.js +21 -0
  12. package/dist/blocks/instance.d.ts +29 -0
  13. package/dist/blocks/instance.js +51 -0
  14. package/dist/blocks/lttb.d.ts +16 -0
  15. package/dist/blocks/lttb.js +67 -0
  16. package/dist/blocks/ops.d.ts +44 -0
  17. package/dist/blocks/ops.js +294 -0
  18. package/dist/blocks/text.d.ts +43 -0
  19. package/dist/blocks/text.js +804 -0
  20. package/dist/blocks/transport.d.ts +81 -0
  21. package/dist/blocks/transport.js +11 -0
  22. package/dist/blocks/types.d.ts +558 -0
  23. package/dist/blocks/types.js +17 -0
  24. package/dist/commands.d.ts +75 -0
  25. package/dist/commands.js +25 -0
  26. package/dist/conversations.d.ts +31 -0
  27. package/dist/conversations.js +94 -0
  28. package/dist/interactions.d.ts +65 -0
  29. package/dist/interactions.js +23 -0
  30. package/dist/jobs.d.ts +109 -0
  31. package/dist/jobs.js +19 -0
  32. package/dist/json.d.ts +20 -0
  33. package/dist/json.js +13 -0
  34. package/dist/live.d.ts +71 -0
  35. package/dist/live.js +82 -0
  36. package/dist/session-meta.d.ts +130 -0
  37. package/dist/session-meta.js +13 -0
  38. package/dist/settings.d.ts +449 -0
  39. package/dist/settings.js +19 -0
  40. package/dist/themes.d.ts +49 -0
  41. package/dist/themes.js +155 -0
  42. package/dist/turns.d.ts +133 -0
  43. package/dist/turns.js +247 -0
  44. package/dist/usernames.d.ts +8 -0
  45. package/dist/usernames.js +39 -0
  46. package/dist/view-delta.d.ts +54 -0
  47. package/dist/view-delta.js +135 -0
  48. package/dist/views.d.ts +1021 -0
  49. package/dist/views.js +54 -0
  50. package/package.json +3 -2
@@ -0,0 +1,130 @@
1
+ /**
2
+ * The session-meta WIRE types (spec §5) — the client-facing half of
3
+ * `src/server/session-meta.ts` (which owns the document/patch runtime).
4
+ *
5
+ * This module is part of the shared leaf package (`@sigrun/shared`): the
6
+ * tui and webui import these shapes from here, never from server source
7
+ * (the load-bearing decoupling — the tui is a pure client of the wire).
8
+ *
9
+ * PURE module: no imports at all (the views-purity guard enforces this
10
+ * across `shared/src`) — the `import type` below is the sanctioned wire-
11
+ * module exception: sibling-only (`./access.js`), type-only.
12
+ */
13
+ import type { Sharing } from "./access.js";
14
+ export type { Sharing } from "./access.js";
15
+ /**
16
+ * Doc header (from the server module — the runtime semantics live there):
17
+ *
18
+ * One latest-only singleton doc per conversation (kind
19
+ * `"sigrun.session-meta"`): pin/tag/archive flags, the composer draft
20
+ * (survives reloads — `draft.attachments` are workspace-relative paths
21
+ * from the uploads endpoint), the session source, the user-facing session
22
+ * name (T5d), the multi-user `owner` seam, and the §5.9 `sharing` state.
23
+ * `owner` and `source` are SERVER-ONLY: the auth hook stamps the owner at
24
+ * create/fork/import, and a client PATCH carrying either key is a 400
25
+ * `invalid_field`.
26
+ *
27
+ * Server-owned fields (`autoName`, `autoNameAttempts`,
28
+ * `lastActivityAt`, `jobId`, `deliver`, `internal`) are written by host
29
+ * code only (activity.ts, the A2 auto-namer, fire.ts's job stamp, the
30
+ * curator's creating commit); they are NOT patch surface — the strict
31
+ * validator keeps rejecting them as `invalid_field`.
32
+ */
33
+ /** The per-conversation session metadata (spec §5). */
34
+ export type SessionMeta = {
35
+ /** Sidebar pin (pinned conversations float to the top). */
36
+ pinned: boolean;
37
+ /** Sidebar tags; a PATCH replaces the array wholesale. */
38
+ tagged: string[];
39
+ /** Archived/hidden from the default sidebar listing. */
40
+ archived: boolean;
41
+ /** The composer draft; survives a reload. */
42
+ draft: {
43
+ text: string;
44
+ attachments: string[];
45
+ };
46
+ /** Who created the session: an interactive user, a cron job, a channel
47
+ * adapter — a free-form server-owned label (spec §5.9: no longer a
48
+ * closed enum; never patchable). */
49
+ source: string;
50
+ /**
51
+ * Multi-user seam (spec §5.9): the caller identity the auth hook
52
+ * stamped at create/fork/import, read by the listing route and the
53
+ * access checks. SERVER-ONLY — a PATCH carrying the key is a 400
54
+ * `invalid_field`.
55
+ */
56
+ owner?: string;
57
+ /** The user-facing session name; absent = unnamed (T5d). */
58
+ name?: string;
59
+ /**
60
+ * Server-owned automatic name (the auto-namer writes it, A2); the
61
+ * listing serves it only while `name` is unset. NEVER patchable — the
62
+ * strict validator rejects the key as `invalid_field`.
63
+ */
64
+ autoName?: string;
65
+ /** Server-owned: the auto-namer's attempt count (A2). Never patchable. */
66
+ autoNameAttempts?: number;
67
+ /**
68
+ * Server-owned: the last activity instant, ISO 8601 (`activity.ts`
69
+ * stamps it at submission admission and run settlement). Never
70
+ * patchable — the strict validator rejects the key as `invalid_field`.
71
+ */
72
+ lastActivityAt?: string;
73
+ /**
74
+ * Server-owned job stamp (gateway C7, spec §8.0): the id of the job
75
+ * whose fire created this conversation (`fire.ts` writes it inside the
76
+ * creating commit). Never patchable — the strict validator rejects
77
+ * the key as `invalid_field`.
78
+ */
79
+ jobId?: string;
80
+ /**
81
+ * Server-owned job delivery targets (gateway C7, spec §8.0): the job
82
+ * action's `deliver` array, stamped onto the run conversation by
83
+ * `fire.ts` in the creating commit — the gateway's runSettled delivery
84
+ * reads it to route the answer to chats. Never patchable — the
85
+ * strict validator rejects the key as `invalid_field`.
86
+ */
87
+ deliver?: string[];
88
+ /**
89
+ * Server-owned internal-run marker (curator P5, spec §6.1): true on a
90
+ * conversation created for curator work — hidden from every list and
91
+ * view, 404 on every `:id` route for every caller (superuser
92
+ * included), never named, never notified, never idle-clocked, and
93
+ * absent from every event surface. Written ONCE by the curator's
94
+ * creating commit (`markInternal`); the flag never changes after
95
+ * creation. Never patchable — the strict validator rejects the key
96
+ * as `invalid_field`.
97
+ */
98
+ internal?: true;
99
+ /**
100
+ * The §5.9 per-resource sharing state; absent = private (owner and
101
+ * superuser only). Patchable by the OWNER or a superuser (403
102
+ * otherwise); `sharing: null` clears back to private.
103
+ */
104
+ sharing?: Sharing;
105
+ };
106
+ /** A validated PATCH body: present keys apply, `null` clears to default. */
107
+ export interface SessionMetaPatch {
108
+ readonly pinned?: boolean | null;
109
+ readonly tagged?: readonly string[] | null;
110
+ readonly archived?: boolean | null;
111
+ readonly draft?: {
112
+ readonly text?: string | null;
113
+ readonly attachments?: readonly string[] | null;
114
+ } | null;
115
+ readonly name?: string | null;
116
+ /**
117
+ * The §5.9 sharing set/clear (`null` → private). `owner` and `source`
118
+ * are deliberately ABSENT — the validator rejects them as
119
+ * `invalid_field`, so a patch type that cannot express them keeps the
120
+ * apply step honest by construction.
121
+ */
122
+ readonly sharing?: Sharing | null;
123
+ }
124
+ /** Why a PATCH body was rejected (the configure endpoint's error contract). */
125
+ export type SessionMetaPatchError = {
126
+ readonly error: "invalid_body";
127
+ } | {
128
+ readonly error: "invalid_field";
129
+ readonly field: string;
130
+ };
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The session-meta WIRE types (spec §5) — the client-facing half of
3
+ * `src/server/session-meta.ts` (which owns the document/patch runtime).
4
+ *
5
+ * This module is part of the shared leaf package (`@sigrun/shared`): the
6
+ * tui and webui import these shapes from here, never from server source
7
+ * (the load-bearing decoupling — the tui is a pure client of the wire).
8
+ *
9
+ * PURE module: no imports at all (the views-purity guard enforces this
10
+ * across `shared/src`) — the `import type` below is the sanctioned wire-
11
+ * module exception: sibling-only (`./access.js`), type-only.
12
+ */
13
+ export {};
@@ -0,0 +1,449 @@
1
+ /**
2
+ * The settings-file TYPES (Task 8a, pi parity spec: the settings file) —
3
+ * the persisted `SettingsFile` shape and its sections.
4
+ *
5
+ * The CANONICAL type declarations live here (the shared leaf package);
6
+ * `src/harness/settings.ts` imports them (type-only) for the store/
7
+ * validation runtime. The `GET/PATCH /v1/settings` wire serves this
8
+ * shape verbatim (`SettingsResponse` = `SettingsFile` + the
9
+ * server-computed `toolRoster`; see `@sigrun/shared/views`), so both
10
+ * clients read these fields straight off the wire.
11
+ *
12
+ * The file is a JSON document at `<config-dir>/settings.json`. It
13
+ * carries the `HarnessSettings` pass-throughs (`steeringMode`,
14
+ * `followUpMode`, `retry`, `stream`) plus sigrun's own resolved fields
15
+ * (`defaultTools`, `perModelThinking`, `extensions`, `jobs`, `jobHistory`,
16
+ * `defaultModel`, `namingModel`, `defaultProvider`, `server`). Credentials
17
+ * never live here (they live in the sibling `auth.json`).
18
+ */
19
+ import type { JobSpec } from "./jobs.js";
20
+ /**
21
+ * One entry of the unified `extensions` list: an install-and-load
22
+ * declaration. The string form is shorthand for `{source}`; the object
23
+ * form adds the git/entry/enabled knobs. See the `extensions` field
24
+ * docblock on {@link SettingsFile} for the full grammar.
25
+ */
26
+ export type ExtensionSpec = string | {
27
+ /** The source: npm specifier, bare name, file:/path, or git source. */
28
+ readonly source: string;
29
+ /** Entry-point override (path relative to the resolved source root). */
30
+ readonly entry?: string;
31
+ /** Git ref (same as the `@ref` suffix, spelled out). */
32
+ readonly ref?: string;
33
+ /** Default true; `false` = directory state retained, not loaded. */
34
+ readonly enabled?: boolean;
35
+ };
36
+ /**
37
+ * The job-history retention limits (spec §8.1, ruling 14), applied per
38
+ * job at run-settle and revision-write: keep the newest `runs` run
39
+ * records and the newest `revisions` revisions (plus any revision a
40
+ * retained run references). Live settings — both positive integers,
41
+ * default 50.
42
+ */
43
+ export interface JobHistorySettings {
44
+ readonly runs?: number;
45
+ readonly revisions?: number;
46
+ }
47
+ /**
48
+ * The `server` section: static boot configuration mirrored from the
49
+ * `SIGRUN_*` env knobs. Every field is optional; a present field is the
50
+ * deployment default applied when the corresponding env var is ABSENT
51
+ * (env always wins, validated first). Not here: the extensions list and
52
+ * the model (top-level fields of {@link SettingsFile}).
53
+ */
54
+ export interface ServerSettings {
55
+ /** `SIGRUN_PORT` — a positive integer. */
56
+ readonly port?: number;
57
+ /** `SIGRUN_WORKSPACE_PATH` — a non-empty path. */
58
+ readonly workspacePath?: string;
59
+ /** `SIGRUN_STORAGE_PATH` — a non-empty path. */
60
+ readonly storagePath?: string;
61
+ /** `SIGRUN_EXTENSIONS_DIR` — a non-empty path. */
62
+ readonly extensionsDir?: string;
63
+ /**
64
+ * `SIGRUN_MAX_UPLOAD_BYTES` — a positive integer. The raw-upload
65
+ * PUT route's body limit; the base64 POST and the JSONL import derive
66
+ * theirs from it (the 4/3 base64 inflation plus the JSON wrapper).
67
+ * Default 64 MiB (spec §6.2).
68
+ */
69
+ readonly maxUploadBytes?: number;
70
+ /**
71
+ * `SIGRUN_MAX_FILE_READ_BYTES` — a positive integer. The raw
72
+ * file-read cap (`GET .../files/raw`): 413 `file_too_large` beyond
73
+ * it. Default 16 MiB (spec §7.8) — the agent writes workspace
74
+ * files, so nothing else bounds them.
75
+ */
76
+ readonly maxFileReadBytes?: number;
77
+ /**
78
+ * `SIGRUN_DATA_DIR` — a non-empty path. Applied where the env var is
79
+ * absent; the env-or-file value wins VERBATIM (no `/sigrun` suffix),
80
+ * exactly like the stores resolver's explicit tier. The DB default
81
+ * and relative `SIGRUN_STORAGE_PATH` values resolve under this root.
82
+ */
83
+ readonly dataDir?: string;
84
+ /** `SIGRUN_CACHE_DIR` — a non-empty path, verbatim (see `dataDir`). */
85
+ readonly cacheDir?: string;
86
+ /** `SIGRUN_STATE_DIR` — a non-empty path, verbatim (see `dataDir`). */
87
+ readonly stateDir?: string;
88
+ /**
89
+ * `SIGRUN_PUBLIC_URL` (core hardening W5 Task 2, spec §9.2): the
90
+ * deployment's absolute base URL — http(s) with a hostname, any
91
+ * trailing slash stripped at resolution. `undefined` when neither
92
+ * env nor file sets it; the extension-route adapter bases handlers'
93
+ * absolute `Request` URLs on it and notification deep links are
94
+ * omitted without it.
95
+ */
96
+ publicUrl?: string;
97
+ /**
98
+ * The webui channel's gate + bundle selector (build-and-webui Task 4):
99
+ * `SIGRUN_WEBUI` maps to `enabled` (strict true/false parse), the
100
+ * selector comes from `SIGRUN_WEBUI_BUNDLE` over `bundle` over the
101
+ * legacy `webuiBundle` (deprecated alias, one release). Both keys are
102
+ * OPTIONAL — the settings bootstrap OMITS the section entirely when
103
+ * fully defaulted (a mirrored default would read as an explicit
104
+ * selection on the next boot and make absent-default → API-only
105
+ * unreachable).
106
+ */
107
+ readonly webui?: {
108
+ /** `SIGRUN_WEBUI` — boolean, default true. `false` = API-only. */
109
+ readonly enabled?: boolean;
110
+ /**
111
+ * The bundle selector (non-empty string): a contributed-bundle NAME
112
+ * or a PATH, discriminated syntactically at serve time (Task 5).
113
+ * Absent = the built-in default bundle.
114
+ */
115
+ readonly bundle?: string;
116
+ };
117
+ /**
118
+ * DEPRECATED ALIAS for `webui.bundle` (build-and-webui Task 4), kept
119
+ * for one release: `SIGRUN_WEBUI_BUNDLE` over `webui.bundle` over THIS
120
+ * key over the default. Accepted by validation with a deprecation
121
+ * warn; the bootstrap never writes it.
122
+ *
123
+ * @deprecated use `webui.bundle`
124
+ */
125
+ readonly webuiBundle?: string;
126
+ /**
127
+ * The timezone `SIGRUN_TIMEZONE` mirrors (jobs §8.2): an IANA name —
128
+ * the default timezone for cron schedules that declare none (default:
129
+ * the process TZ). Validated as an IANA name (an `Intl.DateTimeFormat`
130
+ * construction succeeds).
131
+ */
132
+ readonly timezone?: string;
133
+ /** The `SIGRUN_COMPACTION_*` policy knobs. */
134
+ readonly compaction?: {
135
+ readonly enabled?: boolean;
136
+ readonly reserveTokens?: number;
137
+ readonly keepRecentTokens?: number;
138
+ readonly backgroundTokens?: number;
139
+ /**
140
+ * Per-model compaction policy overrides, keyed by the exact
141
+ * `provider/modelId` string pi-durable composes — a chain-shaped
142
+ * model id doubles the prefix (e.g. `bifrost/bifrost/<chain>`).
143
+ * Each field replaces the harness-wide one for that model, so a
144
+ * small-window model can sit alongside the large-window default.
145
+ * Boot-time lifetime, like the rest of compaction.
146
+ */
147
+ readonly modelOverrides?: Readonly<Record<string, Partial<{
148
+ enabled: boolean;
149
+ reserveTokens: number;
150
+ keepRecentTokens: number;
151
+ backgroundTokens: number;
152
+ }>>>;
153
+ };
154
+ /**
155
+ * The memory-seam bounds (memory-seam Task 6), mirroring the
156
+ * `SIGRUN_{HOOK_DEADLINE,IDLE_THRESHOLD,WORKER_DEADLINE,QUEUE_MAX}`
157
+ * env knobs — each a positive integer applied per-field where the
158
+ * corresponding env var is absent.
159
+ */
160
+ readonly memorySeam?: {
161
+ readonly hookDeadlineMs?: number;
162
+ readonly idleThresholdMs?: number;
163
+ readonly workerDeadlineMs?: number;
164
+ readonly queueMax?: number;
165
+ };
166
+ /** The multi-user execution jail (M1). `mode` and `osUsers` are restart-required. */
167
+ readonly isolation?: {
168
+ /** `SIGRUN_ISOLATION` — auto, always, or off; default auto. */
169
+ readonly mode?: "auto" | "always" | "off";
170
+ /** Per-user uid/gid isolation; default false. */
171
+ readonly osUsers?: boolean;
172
+ /** Idle worker lifetime in minutes; default 10. */
173
+ readonly workerIdleMinutes?: number;
174
+ };
175
+ /**
176
+ * The provider plugins' runtime knobs (provider plugins Task 5):
177
+ * `SIGRUN_PROVIDER_REFRESH_MINUTES` — the interval refresh cadence
178
+ * in minutes, a non-negative integer where `0` disables the
179
+ * scheduler. Applied per-field where the env var is absent.
180
+ */
181
+ readonly providers?: {
182
+ readonly refreshIntervalMinutes?: number;
183
+ };
184
+ /**
185
+ * The auth surface (core-hardening W1, spec §5.2/§5.3): the
186
+ * authenticator method list, the forward-auth (proxy) config, the
187
+ * admin group mapping, and the Host/Origin allowlists. Mirrors the
188
+ * `SIGRUN_AUTH`/`SIGRUN_AUTH_TRUSTED_PROXIES` env knobs (the env
189
+ * service token `SIGRUN_API_TOKEN` and the shared secret
190
+ * `SIGRUN_PROXY_SECRET` are ENV-ONLY credentials — validation rejects
191
+ * a `secret` key here, key material never lives in this file).
192
+ * `methods` ABSENT means derive from the listen host (`[]` on
193
+ * loopback, `["token"]` otherwise) — which is why a defaulted auth
194
+ * section is omitted from the bootstrap projection entirely (an
195
+ * explicit `methods: []` would read as intent on the next boot).
196
+ */
197
+ readonly auth?: {
198
+ /** `SIGRUN_AUTH` — csv of `token`/`proxy`; absent = derive from the listen host. */
199
+ readonly methods?: readonly ("token" | "proxy")[];
200
+ /** Browser-session lifetime in days. Positive integer; default 30; LIVE. */
201
+ readonly sessionDays?: number;
202
+ readonly proxy?: {
203
+ readonly trustedProxies?: readonly string[];
204
+ readonly secretHeader?: string;
205
+ readonly userHeader?: string;
206
+ readonly groupsHeader?: string;
207
+ readonly nameHeader?: string;
208
+ readonly emailHeader?: string;
209
+ readonly autoProvision?: boolean;
210
+ };
211
+ readonly adminGroups?: readonly string[];
212
+ readonly allowedHosts?: readonly string[];
213
+ readonly allowedOrigins?: readonly string[];
214
+ };
215
+ /**
216
+ * `/metrics` exposure (core-hardening W1): `SIGRUN_METRICS_PUBLIC`
217
+ * over this key, default `false` (a principal is required). Omitted
218
+ * from the bootstrap projection when defaulted (the webui pattern).
219
+ */
220
+ readonly metrics?: {
221
+ readonly public?: boolean;
222
+ };
223
+ /**
224
+ * The development flag (spec §14.2/§14.4): `SIGRUN_DEV` (strict
225
+ * true/false — the spec's `SIGRUN_DEV=1` form reads as true) over this
226
+ * key, default `false`. Surfaces on `GET /v1/meta` (`dev`); gates the
227
+ * U1 blocks gallery, U3's development error bodies, and U4.
228
+ */
229
+ readonly dev?: boolean;
230
+ /**
231
+ * The supervised flag (UI-blocks U4 Task 2, spec §13.3):
232
+ * `SIGRUN_SUPERVISED` (strict true/false, `1`/`0` accepted) over this
233
+ * key, default `false`. `true` promises a supervisor restarts the
234
+ * process after an intentional `exit 0` — the Helm chart and docker
235
+ * compose set the env (both restart the container); the Dockerfile
236
+ * deliberately does NOT. Gates `POST /v1/admin/restart`; `/v1/meta`
237
+ * reports it (`supervised`).
238
+ */
239
+ readonly supervised?: boolean;
240
+ /**
241
+ * The backup target — exactly one of the two shapes (mirroring the
242
+ * env rule: `SIGRUN_BACKUP_PATH` XOR `SIGRUN_BACKUP_S3_BUCKET`), plus
243
+ * the §6.8 honesty knob: `staleAfterHours`, how old the
244
+ * `backup/last-success.json` marker may be before `health.backup`
245
+ * reports `"degraded"` (positive number; no env var exists — file or
246
+ * the 36 h code default).
247
+ */
248
+ readonly backup?: {
249
+ readonly path?: string;
250
+ readonly staleAfterHours?: number;
251
+ } | {
252
+ readonly s3?: {
253
+ readonly bucket?: string;
254
+ readonly prefix?: string;
255
+ readonly endpoint?: string;
256
+ };
257
+ readonly staleAfterHours?: number;
258
+ };
259
+ }
260
+ /**
261
+ * Which tier supplied a resolved server key (the `/v1/settings`
262
+ * `effective` block, spec §6.6): the env var was set (`"env"`), the
263
+ * settings file's `server` section set it (`"file"`), or neither and
264
+ * the code default applied (`"default"`).
265
+ */
266
+ export type ServerSettingSource = "env" | "file" | "default";
267
+ /**
268
+ * One `effective` entry: the RESOLVED value (what boot actually used)
269
+ * plus the {@link ServerSettingSource} that won. Keys are flattened
270
+ * dotted paths (`"server.port"`, `"server.compaction.reserveTokens"`).
271
+ */
272
+ export interface EffectiveServerSetting {
273
+ readonly value: unknown;
274
+ readonly source: ServerSettingSource;
275
+ }
276
+ /**
277
+ * The degenerate env-driven provider's static configuration (ruling 7).
278
+ * Only the endpoint is here — credentials live in `auth.json`.
279
+ */
280
+ export interface DefaultProviderSettings {
281
+ /** `OPENAI_BASE_URL` — a non-empty URL. */
282
+ readonly baseUrl?: string;
283
+ }
284
+ /**
285
+ * The skills surface's settings (core hardening W5 Task 4, spec §9.4) —
286
+ * live, read per skills-section render.
287
+ */
288
+ export interface SkillsSettings {
289
+ /** The rendered-section byte cap (default 4096, notice included). */
290
+ readonly sectionMaxBytes?: number;
291
+ }
292
+ /**
293
+ * The notifications surface's settings (core hardening W5 Task 6, spec
294
+ * §9.6) — live, read per event.
295
+ */
296
+ export interface NotificationsSettings {
297
+ /**
298
+ * When a `run.settled` notification fires: `"unwatched"` (default)
299
+ * only when no client stream is attached to the conversation (the
300
+ * away-from-desk case), `"cron"` only for job-run conversations,
301
+ * `"always"` every settle, `"never"` none.
302
+ */
303
+ readonly runSettled?: "unwatched" | "cron" | "always" | "never";
304
+ }
305
+ /**
306
+ * The built-in extensions toggles: codemode, MCP, tool search, the
307
+ * gateway, OAuth and the curator ship WITH core. Each key defaults to
308
+ * `true`; `false` removes the built-in entirely (absent from
309
+ * `/v1/extensions`, its config ignored with one log line).
310
+ * RESTART-REQUIRED: the built-in set resolves at boot, like `extensions`.
311
+ */
312
+ export interface BuiltinExtensionsSettings {
313
+ readonly codemode?: boolean;
314
+ readonly mcp?: boolean;
315
+ readonly toolSearch?: boolean;
316
+ /** Gateway (gateway C3): the built-in engine, default true. */
317
+ readonly gateway?: boolean;
318
+ /** OAuth login providers (multi-user M3b), default true. */
319
+ readonly oauth?: boolean;
320
+ /** Curator (Task B1): the per-user curation loops, default true. */
321
+ readonly curator?: boolean;
322
+ }
323
+ /**
324
+ * The persisted shape: HarnessSettings pass-throughs + sigrun fields.
325
+ */
326
+ export interface SettingsFile {
327
+ /** pi-durable `HarnessSettings.steeringMode`. */
328
+ readonly steeringMode?: "all" | "one-at-a-time";
329
+ /** pi-durable `HarnessSettings.followUpMode`. */
330
+ readonly followUpMode?: "all" | "one-at-a-time";
331
+ /** pi-durable `HarnessSettings.retry` (partial policy, merged over defaults). */
332
+ readonly retry?: {
333
+ readonly enabled?: boolean;
334
+ readonly maxRetries?: number;
335
+ readonly baseDelayMs?: number;
336
+ readonly maxAgentDelayMs?: number;
337
+ };
338
+ /** pi-durable `HarnessSettings.stream` (partial, merged over defaults). */
339
+ readonly stream?: {
340
+ readonly timeoutMs?: number;
341
+ readonly maxRetries?: number;
342
+ readonly maxRetryDelayMs?: number;
343
+ };
344
+ /**
345
+ * Sigrun: tool-name filter applied at conversation creation; maps to
346
+ * pi-durable 1.3.0's `AgentChange.modelTools` (the model-offered
347
+ * filter — never the enabled filter `AgentChange.tools`).
348
+ */
349
+ readonly defaultTools?: readonly string[];
350
+ /**
351
+ * Sigrun: per-model thinking-level overrides, keyed by
352
+ * `"provider/modelId"`.
353
+ */
354
+ readonly perModelThinking?: Readonly<Record<string, string>>;
355
+ /**
356
+ * Sigrun: the unified extension list — each entry is the DESIRED
357
+ * INSTALL+LOAD state (one list, no install/load split). Entry forms:
358
+ *
359
+ * - a string: an npm specifier ("name", "name@range",
360
+ * "@scope/name@range"), a bare name (app-tree/vendor shorthand,
361
+ * load-only), a `file:`/absolute path (loaded in place, nothing
362
+ * installed), or a git source ("git:host/path" or an https git
363
+ * URL, with an optional `@ref` suffix) — cloned into
364
+ * `<config-dir>/git/` and loaded after entry discovery.
365
+ * - an object: `{ source, entry?, ref?, enabled? }` — the explicit
366
+ * form. `entry` overrides entry discovery (path relative to the
367
+ * resolved source root); `ref` is the git ref (same as the `@ref`
368
+ * suffix, spelled out); `enabled: false` keeps the directory
369
+ * state but does not load (the installed-but-disabled case).
370
+ *
371
+ * npm + git entries are installed/fetched at boot by `syncPackages`
372
+ * into the packages/git dirs under the config dir; REMOVING an entry
373
+ * uninstalls it. Applied when `SIGRUN_EXTENSIONS` is absent.
374
+ * Changes require a restart.
375
+ */
376
+ readonly extensions?: readonly ExtensionSpec[];
377
+ /**
378
+ * Sigrun: the file-declared job list (spec §8.3 — the `file` source).
379
+ * Each entry is a `JobSpec` validated with `validateJobSpec` (the
380
+ * jobs §8.2 grammar); names double as the id suffix (`file:<name>`).
381
+ * Duplicate names are a validation error. Restart-required: like
382
+ * `extensions`, the list resolves at boot reconciliation.
383
+ */
384
+ readonly jobs?: readonly JobSpec[];
385
+ /**
386
+ * Sigrun: per-job history retention (spec §8.1, ruling 14) — LIVE
387
+ * (read per prune, not restart-required): keep the newest `runs` run
388
+ * records and the newest `revisions` revisions per job, plus any
389
+ * revision a retained run references. Both positive integers,
390
+ * default 50 each.
391
+ */
392
+ readonly jobHistory?: JobHistorySettings;
393
+ /**
394
+ * Sigrun: the boot default model (ruling 3), a non-empty
395
+ * `provider/model-id` spec parsed exactly like `SIGRUN_DEFAULT_MODEL`
396
+ * (bare id implies the `openai` provider). Applied when the env var is
397
+ * absent; REQUIRED overall — neither env nor file is a fail-loud boot
398
+ * error, no code default.
399
+ */
400
+ readonly defaultModel?: string;
401
+ /**
402
+ * Sigrun: the model the auto-namer (UI refresh A2) completes through, a
403
+ * non-empty `provider/model-id` spec validated exactly like
404
+ * `defaultModel`, or `false` to disable automatic naming. Absent = the
405
+ * boot default model. Read live per settled run, so a PATCH reaches the
406
+ * next naming call without a restart.
407
+ */
408
+ readonly namingModel?: string | false;
409
+ /**
410
+ * Sigrun: the env-driven OpenAI-compatible provider's endpoint
411
+ * (ruling 7), applied when `OPENAI_BASE_URL` is absent.
412
+ */
413
+ readonly defaultProvider?: DefaultProviderSettings;
414
+ /**
415
+ * Sigrun: the skills surface's knob (core hardening W5 Task 4, spec
416
+ * §9.4). `sectionMaxBytes` caps the rendered skills section (default
417
+ * 4096, truncation notice included). LIVE — read per render, so a
418
+ * PATCH reaches the next prompt without a restart.
419
+ */
420
+ readonly skills?: SkillsSettings;
421
+ /**
422
+ * Sigrun: the notifications surface's knob (core hardening W5 Task 6,
423
+ * spec §9.6). `runSettled` gates when a settled run notifies (default
424
+ * `"unwatched"`). LIVE — read per event, so a PATCH reaches the next
425
+ * settle without a restart.
426
+ */
427
+ readonly notifications?: NotificationsSettings;
428
+ /**
429
+ * Sigrun: the built-in extensions toggles (Task 2). Each defaults to
430
+ * `true`. RESTART-REQUIRED (resolved at boot).
431
+ */
432
+ readonly builtinExtensions?: BuiltinExtensionsSettings;
433
+ /**
434
+ * Sigrun: the MCP-driven auto-enable (Task 2, ruling 4). Default
435
+ * `true`: when at least one enabled MCP server's effective exposure is
436
+ * `codemode`, the `codemode` tool stays in the default model-offered
437
+ * set for newly created conversations; when any is `deferred`,
438
+ * `tool_search` stays offered. `false` turns both arms off. An
439
+ * explicit `defaultTools` filter always wins (auto-enable only edits
440
+ * the DEFAULT set). LIVE — read at conversation create, like
441
+ * `defaultTools`.
442
+ */
443
+ readonly autoEnableCodemode?: boolean;
444
+ /**
445
+ * Sigrun: the static boot configuration (see {@link ServerSettings}).
446
+ * Deployment defaults under env — changes require a restart.
447
+ */
448
+ readonly server?: ServerSettings;
449
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The settings-file TYPES (Task 8a, pi parity spec: the settings file) —
3
+ * the persisted `SettingsFile` shape and its sections.
4
+ *
5
+ * The CANONICAL type declarations live here (the shared leaf package);
6
+ * `src/harness/settings.ts` imports them (type-only) for the store/
7
+ * validation runtime. The `GET/PATCH /v1/settings` wire serves this
8
+ * shape verbatim (`SettingsResponse` = `SettingsFile` + the
9
+ * server-computed `toolRoster`; see `@sigrun/shared/views`), so both
10
+ * clients read these fields straight off the wire.
11
+ *
12
+ * The file is a JSON document at `<config-dir>/settings.json`. It
13
+ * carries the `HarnessSettings` pass-throughs (`steeringMode`,
14
+ * `followUpMode`, `retry`, `stream`) plus sigrun's own resolved fields
15
+ * (`defaultTools`, `perModelThinking`, `extensions`, `jobs`, `jobHistory`,
16
+ * `defaultModel`, `namingModel`, `defaultProvider`, `server`). Credentials
17
+ * never live here (they live in the sibling `auth.json`).
18
+ */
19
+ export {};
@@ -0,0 +1,49 @@
1
+ /**
2
+ * The shared theme data (Task B1, UI refresh): the four palettes and
3
+ * seven accents of the UI refresh, plus their name guards.
4
+ *
5
+ * PURE module: no imports at all (test/views-purity.test.ts enforces
6
+ * this). Both clients — webui (bundler, DOM) and tui (NodeNext) —
7
+ * consume this file from a single source; any import would drag a
8
+ * dependency only one client can load or resolve.
9
+ *
10
+ * Colour values are copied verbatim from the UI-refresh palette mockup
11
+ * (palettes.html), with the mockup ids renamed to the plan ids: palette `iron` →
12
+ * `iron-ember`, `aurora` → `polar-night`, `birch` → `birch-moss`;
13
+ * accent `amber` → `baltic-amber`; token key `surface-2` → `surface2`.
14
+ */
15
+ export type PaletteName = "fjord" | "iron-ember" | "polar-night" | "birch-moss";
16
+ export type AccentName = "baltic-amber" | "ember" | "lingonberry" | "glacier" | "aurora" | "lichen" | "heather";
17
+ export type ModeName = "dark" | "light";
18
+ /** One mode's tokens: every value a CSS colour literal. */
19
+ export interface PaletteTokens {
20
+ readonly bg: string;
21
+ readonly surface: string;
22
+ readonly surface2: string;
23
+ readonly border: string;
24
+ readonly text: string;
25
+ readonly muted: string;
26
+ readonly faint: string;
27
+ readonly ok: string;
28
+ readonly code: string;
29
+ }
30
+ export interface Palette {
31
+ readonly label: string;
32
+ readonly defaultAccent: AccentName;
33
+ readonly dark: PaletteTokens;
34
+ readonly light: PaletteTokens;
35
+ }
36
+ export interface Accent {
37
+ readonly label: string;
38
+ readonly dark: string;
39
+ readonly light: string;
40
+ }
41
+ export declare const PALETTES: Readonly<Record<PaletteName, Palette>>;
42
+ export declare const ACCENTS: Readonly<Record<AccentName, Accent>>;
43
+ export declare const PALETTE_NAMES: readonly PaletteName[];
44
+ export declare const ACCENT_NAMES: readonly AccentName[];
45
+ /** The shipped default: Polar Night + Baltic Amber. */
46
+ export declare const DEFAULT_PALETTE: PaletteName;
47
+ export declare const DEFAULT_ACCENT: AccentName;
48
+ export declare function isPaletteName(value: unknown): value is PaletteName;
49
+ export declare function isAccentName(value: unknown): value is AccentName;