@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
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pending-restart derivation (UI-blocks U4 Task 1, spec §13.2): the
|
|
3
|
+
* server keeps a BOOT SNAPSHOT of every `restart` key's stored value,
|
|
4
|
+
* taken once after settings load and before listen (openHarness is
|
|
5
|
+
* pre-listen by construction). `pendingRestart` is the diff: the
|
|
6
|
+
* restart keys whose CURRENT stored value differs from the snapshot —
|
|
7
|
+
* so patching a key BACK to its boot value removes it (Review Focus 2:
|
|
8
|
+
* the callout disappears without a restart).
|
|
9
|
+
*
|
|
10
|
+
* Also here: the WRITE classification. A PATCH body names top-level or
|
|
11
|
+
* `server.*` sub-keys; `classifyPatch` expands those to the flattened
|
|
12
|
+
* registry paths the patch TOUCHED (a `server: {port: 1}` patch touches
|
|
13
|
+
* `server.port` only) and splits them into `applied` (live) and
|
|
14
|
+
* `pending` (restart) per the registry.
|
|
15
|
+
*/
|
|
16
|
+
import { DEFAULT_PROVIDER_REFRESH_MINUTES } from "../config.js";
|
|
17
|
+
import { CORE_SETTING_KEYS, applyOf } from "./registry.js";
|
|
18
|
+
/**
|
|
19
|
+
* The sub-object keys a PATCH merges per-key (matching the store's
|
|
20
|
+
* update() sub-merge grammar). A patch naming one of these top-level
|
|
21
|
+
* keys with an object value touches only the SUB-keys present.
|
|
22
|
+
*/
|
|
23
|
+
const SUB_MERGED = new Set([
|
|
24
|
+
"retry",
|
|
25
|
+
"stream",
|
|
26
|
+
"perModelThinking",
|
|
27
|
+
"defaultProvider",
|
|
28
|
+
"skills",
|
|
29
|
+
"jobHistory",
|
|
30
|
+
"builtinExtensions",
|
|
31
|
+
"notifications",
|
|
32
|
+
]);
|
|
33
|
+
/**
|
|
34
|
+
* Expand one PATCH body to the flattened registry paths it touches.
|
|
35
|
+
* Top-level scalars map 1:1; `server` walks its nested sections; the
|
|
36
|
+
* other sub-merged objects expand their present sub-keys (a `null`
|
|
37
|
+
* sub-value clears exactly that key). Unknown paths are kept verbatim
|
|
38
|
+
* (validation rejects them before this runs, so they never surface —
|
|
39
|
+
* but keeping them makes the classification total, never lossy).
|
|
40
|
+
*/
|
|
41
|
+
export function touchedKeys(patch) {
|
|
42
|
+
const out = [];
|
|
43
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
44
|
+
if (key === "server") {
|
|
45
|
+
if (typeof value !== "object" || value === null) {
|
|
46
|
+
out.push("server");
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
for (const [serverKey, serverValue] of Object.entries(value)) {
|
|
50
|
+
const base = `server.${serverKey}`;
|
|
51
|
+
if ((serverKey === "webui" ||
|
|
52
|
+
serverKey === "compaction" ||
|
|
53
|
+
serverKey === "memorySeam" ||
|
|
54
|
+
serverKey === "providers" ||
|
|
55
|
+
serverKey === "backup") &&
|
|
56
|
+
typeof serverValue === "object" &&
|
|
57
|
+
serverValue !== null) {
|
|
58
|
+
for (const sub of Object.keys(serverValue)) {
|
|
59
|
+
out.push(`${base}.${sub}`);
|
|
60
|
+
}
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (serverKey === "auth" && typeof serverValue === "object" && serverValue !== null) {
|
|
64
|
+
for (const [authKey, authValue] of Object.entries(serverValue)) {
|
|
65
|
+
if (authKey === "proxy" &&
|
|
66
|
+
typeof authValue === "object" &&
|
|
67
|
+
authValue !== null) {
|
|
68
|
+
for (const proxyKey of Object.keys(authValue)) {
|
|
69
|
+
out.push(`server.auth.proxy.${proxyKey}`);
|
|
70
|
+
}
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
out.push(`server.auth.${authKey}`);
|
|
74
|
+
}
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (serverKey === "metrics" && typeof serverValue === "object" && serverValue !== null) {
|
|
78
|
+
for (const sub of Object.keys(serverValue)) {
|
|
79
|
+
out.push(`${base}.${sub}`);
|
|
80
|
+
}
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
out.push(base);
|
|
84
|
+
}
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (SUB_MERGED.has(key) && typeof value === "object" && value !== null) {
|
|
88
|
+
for (const sub of Object.keys(value)) {
|
|
89
|
+
out.push(`${key}.${sub}`);
|
|
90
|
+
}
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
out.push(key);
|
|
94
|
+
}
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Classify a write over the registry: which touched keys are live
|
|
99
|
+
* (`applied`) and which restart (`pending`). A key with no registry
|
|
100
|
+
* entry classifies as restart (the conservative default).
|
|
101
|
+
*/
|
|
102
|
+
export function classifyPatch(patch) {
|
|
103
|
+
const keys = touchedKeys(patch);
|
|
104
|
+
const applied = [];
|
|
105
|
+
const pending = [];
|
|
106
|
+
for (const key of keys) {
|
|
107
|
+
if (applyOf(key) === "live")
|
|
108
|
+
applied.push(key);
|
|
109
|
+
else
|
|
110
|
+
pending.push(key);
|
|
111
|
+
}
|
|
112
|
+
return { applied, pending, keys };
|
|
113
|
+
}
|
|
114
|
+
/** Canonical JSON of one value (object keys sorted, stable). */
|
|
115
|
+
function canonical(value) {
|
|
116
|
+
return JSON.stringify(value, (_key, v) => typeof v === "object" && v !== null && !Array.isArray(v)
|
|
117
|
+
? Object.fromEntries(Object.entries(v).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0))
|
|
118
|
+
: v);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Take the boot snapshot: read the restart keys' values from the
|
|
122
|
+
* CURRENT settings file. Called ONCE per boot, after the settings load
|
|
123
|
+
* validates and before listen.
|
|
124
|
+
*/
|
|
125
|
+
export function snapshotRestartKeys(file) {
|
|
126
|
+
const snapshot = new Map();
|
|
127
|
+
for (const entry of CORE_SETTING_KEYS) {
|
|
128
|
+
if (entry.apply !== "restart")
|
|
129
|
+
continue;
|
|
130
|
+
snapshot.set(entry.key, canonicalAt(file, entry.key));
|
|
131
|
+
}
|
|
132
|
+
return snapshot;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* The pending-restart diff: restart keys whose stored value differs
|
|
136
|
+
* from the boot snapshot. Registry order (stable, matches the audit).
|
|
137
|
+
*/
|
|
138
|
+
export function pendingRestart(file, snapshot) {
|
|
139
|
+
const pending = [];
|
|
140
|
+
for (const entry of CORE_SETTING_KEYS) {
|
|
141
|
+
if (entry.apply !== "restart")
|
|
142
|
+
continue;
|
|
143
|
+
if (canonicalAt(file, entry.key) !== snapshot.get(entry.key)) {
|
|
144
|
+
pending.push(entry.key);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return pending;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* The CANONICAL JSON at one flattened dotted path: object keys
|
|
151
|
+
* sorted (stable), `"undefined"` at any missing level — the exact
|
|
152
|
+
* cell form the snapshot map stores, so the diff is one string
|
|
153
|
+
* comparison per key (the per-key value shape is the store's
|
|
154
|
+
* validation domain, never re-parsed here).
|
|
155
|
+
*/
|
|
156
|
+
function canonicalAt(file, path) {
|
|
157
|
+
let node = file;
|
|
158
|
+
for (const key of path.split(".")) {
|
|
159
|
+
if (typeof node !== "object" || node === null) {
|
|
160
|
+
return canonical(undefined);
|
|
161
|
+
}
|
|
162
|
+
node = node[key];
|
|
163
|
+
}
|
|
164
|
+
return canonical(node);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Resolve the provider refresh cadence ENV-OVER-FILE (U4 §13.1's
|
|
168
|
+
* re-arm): `SIGRUN_PROVIDER_REFRESH_MINUTES` when set, else the fresh
|
|
169
|
+
* file value, else the code default — exactly `loadConfig`'s
|
|
170
|
+
* resolution for the same key, read live for the scheduler re-arm.
|
|
171
|
+
*/
|
|
172
|
+
export function resolveRefreshMinutes(env, file) {
|
|
173
|
+
const fromEnv = env.SIGRUN_PROVIDER_REFRESH_MINUTES;
|
|
174
|
+
if (fromEnv !== undefined && fromEnv !== "") {
|
|
175
|
+
const parsed = Number(fromEnv);
|
|
176
|
+
if (Number.isInteger(parsed) && parsed >= 0)
|
|
177
|
+
return parsed;
|
|
178
|
+
}
|
|
179
|
+
return (file.read().server?.providers?.refreshIntervalMinutes ??
|
|
180
|
+
DEFAULT_PROVIDER_REFRESH_MINUTES);
|
|
181
|
+
}
|
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The core settings key registry (UI-blocks U4 Task 1, spec §13.1,
|
|
3
|
+
* ruling 18): ONE entry per key of `SettingsFile` (flattened dotted
|
|
4
|
+
* paths for nested sections) declaring HOW the setting applies —
|
|
5
|
+
*
|
|
6
|
+
* - `live`: the value is read where it's used, at the time it's used.
|
|
7
|
+
* Saving it takes effect without a restart.
|
|
8
|
+
* - `restart`: the value is read at boot. Saving stores it and marks it
|
|
9
|
+
* pending (the `pendingRestart` diff, src/settings/pending.ts).
|
|
10
|
+
*
|
|
11
|
+
* This SUPERSEDES core-hardening §5.7's blanket "every `server.*` key
|
|
12
|
+
* is restart-required" (ruling 18): each core key is marked
|
|
13
|
+
* individually, and the reasons below are the audit's one-line record
|
|
14
|
+
* (the where-it's-read evidence for every entry).
|
|
15
|
+
*
|
|
16
|
+
* NOT here (deliberately — spec §13.1): the listen host (a launch
|
|
17
|
+
* option: `serve` binds `0.0.0.0`, `run` binds `127.0.0.1`) and the
|
|
18
|
+
* config dir (`SIGRUN_CONFIG_DIR`, env-only — it locates the settings
|
|
19
|
+
* file itself). Neither is a stored setting.
|
|
20
|
+
*
|
|
21
|
+
* Extension-declared fields are also NOT here: they default to `live`
|
|
22
|
+
* (§13.1); an extension marks a field `restart` when its factory reads
|
|
23
|
+
* the value at load (Task 3's sections carry that).
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* Every core key, in `SettingsFile` declaration order (top-level keys
|
|
27
|
+
* first, then the `server.*` leaves). `test/settings-apply.test.ts`
|
|
28
|
+
* pins this list against the TYPE with a compile-time tie: a key added
|
|
29
|
+
* to `SettingsFile` without an entry here fails the suite naming it.
|
|
30
|
+
*/
|
|
31
|
+
export const CORE_SETTING_KEYS = [
|
|
32
|
+
// ── HarnessSettings pass-throughs: pi-durable re-reads per boundary ──
|
|
33
|
+
{
|
|
34
|
+
key: "steeringMode",
|
|
35
|
+
apply: "live",
|
|
36
|
+
section: "general",
|
|
37
|
+
reason: "pi-durable HarnessSettings pass-through, re-read at every resolution boundary",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
key: "followUpMode",
|
|
41
|
+
apply: "live",
|
|
42
|
+
section: "general",
|
|
43
|
+
reason: "pi-durable HarnessSettings pass-through, re-read at every resolution boundary",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
key: "retry.enabled",
|
|
47
|
+
apply: "live",
|
|
48
|
+
section: "general",
|
|
49
|
+
reason: "HarnessSettings.retry merge, re-read per resolution",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
key: "retry.maxRetries",
|
|
53
|
+
apply: "live",
|
|
54
|
+
section: "general",
|
|
55
|
+
reason: "HarnessSettings.retry merge, re-read per resolution",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
key: "retry.baseDelayMs",
|
|
59
|
+
apply: "live",
|
|
60
|
+
section: "general",
|
|
61
|
+
reason: "HarnessSettings.retry merge, re-read per resolution",
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
key: "retry.maxAgentDelayMs",
|
|
65
|
+
apply: "live",
|
|
66
|
+
section: "general",
|
|
67
|
+
reason: "HarnessSettings.retry merge, re-read per resolution",
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
key: "stream.timeoutMs",
|
|
71
|
+
apply: "live",
|
|
72
|
+
section: "general",
|
|
73
|
+
reason: "HarnessSettings.stream merge, re-read per resolution",
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
key: "stream.maxRetries",
|
|
77
|
+
apply: "live",
|
|
78
|
+
section: "general",
|
|
79
|
+
reason: "HarnessSettings.stream merge, re-read per resolution",
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
key: "stream.maxRetryDelayMs",
|
|
83
|
+
apply: "live",
|
|
84
|
+
section: "general",
|
|
85
|
+
reason: "HarnessSettings.stream merge, re-read per resolution",
|
|
86
|
+
},
|
|
87
|
+
// ── Per-use readers ──
|
|
88
|
+
{
|
|
89
|
+
key: "defaultTools",
|
|
90
|
+
apply: "live",
|
|
91
|
+
section: "tools",
|
|
92
|
+
reason: "read per conversation create (storeAgentChange), so a PATCH reaches new conversations",
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
key: "perModelThinking",
|
|
96
|
+
apply: "live",
|
|
97
|
+
section: "tools",
|
|
98
|
+
reason: "read per conversation create and configure",
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
key: "extensions",
|
|
102
|
+
apply: "restart",
|
|
103
|
+
section: "extensions",
|
|
104
|
+
reason: "boot reconciliation: syncPackages installs/uninstalls and the loader resolves the list at boot",
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
key: "jobs",
|
|
108
|
+
apply: "restart",
|
|
109
|
+
section: "advanced",
|
|
110
|
+
reason: "boot reconciliation: the file job list resolves into job records at boot",
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
key: "jobHistory.runs",
|
|
114
|
+
apply: "live",
|
|
115
|
+
section: "advanced",
|
|
116
|
+
reason: "read per prune at run-settle (spec §8.1, ruling 14)",
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
key: "jobHistory.revisions",
|
|
120
|
+
apply: "live",
|
|
121
|
+
section: "advanced",
|
|
122
|
+
reason: "read per prune at revision-write (spec §8.1, ruling 14)",
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
key: "defaultModel",
|
|
126
|
+
apply: "restart",
|
|
127
|
+
section: "general",
|
|
128
|
+
reason: "boot model resolution: env over file resolves once into the served default",
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
key: "namingModel",
|
|
132
|
+
apply: "live",
|
|
133
|
+
section: "general",
|
|
134
|
+
reason: "read per settled run by the auto-namer (src/harness/naming.ts)",
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
key: "defaultProvider.baseUrl",
|
|
138
|
+
apply: "restart",
|
|
139
|
+
section: "providers",
|
|
140
|
+
reason: "the env-driven provider's endpoint resolves into the boot provider construction",
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
key: "skills.sectionMaxBytes",
|
|
144
|
+
apply: "live",
|
|
145
|
+
section: "general",
|
|
146
|
+
reason: "read per skills-section render (the live cap closure in boot)",
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
key: "notifications.runSettled",
|
|
150
|
+
apply: "live",
|
|
151
|
+
section: "general",
|
|
152
|
+
reason: "read per run.settled event by the notifications surface",
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
key: "builtinExtensions.codemode",
|
|
156
|
+
apply: "restart",
|
|
157
|
+
section: "extensions",
|
|
158
|
+
reason: "the built-in set resolves at boot (a disabled built-in never loads)",
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
key: "builtinExtensions.mcp",
|
|
162
|
+
apply: "restart",
|
|
163
|
+
section: "extensions",
|
|
164
|
+
reason: "the built-in set resolves at boot (a disabled built-in never loads)",
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
key: "builtinExtensions.toolSearch",
|
|
168
|
+
apply: "restart",
|
|
169
|
+
section: "extensions",
|
|
170
|
+
reason: "the built-in set resolves at boot (a disabled built-in never loads)",
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
key: "builtinExtensions.oauth",
|
|
174
|
+
apply: "restart",
|
|
175
|
+
section: "extensions",
|
|
176
|
+
reason: "the built-in set resolves at boot (a disabled built-in never loads)",
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
key: "autoEnableCodemode",
|
|
180
|
+
apply: "live",
|
|
181
|
+
section: "tools",
|
|
182
|
+
reason: "read at conversation create alongside defaultTools",
|
|
183
|
+
},
|
|
184
|
+
// ── server.* (each key marked individually — ruling 18) ──
|
|
185
|
+
{
|
|
186
|
+
key: "server.port",
|
|
187
|
+
apply: "restart",
|
|
188
|
+
section: "server",
|
|
189
|
+
reason: "the listener binds at boot (serve's app.listen)",
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
key: "server.workspacePath",
|
|
193
|
+
apply: "restart",
|
|
194
|
+
section: "server",
|
|
195
|
+
reason: "boot-resolved workspace root (the workspace service is built once)",
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
key: "server.storagePath",
|
|
199
|
+
apply: "restart",
|
|
200
|
+
section: "server",
|
|
201
|
+
reason: "boot-resolved sqlite path (the storage opens once at boot)",
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
key: "server.extensionsDir",
|
|
205
|
+
apply: "restart",
|
|
206
|
+
section: "server",
|
|
207
|
+
reason: "deprecated path key (§6.7, accepted one release); root resolution is boot-time",
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
key: "server.maxUploadBytes",
|
|
211
|
+
apply: "restart",
|
|
212
|
+
section: "server",
|
|
213
|
+
reason: "route bodyLimit values are set at route registration (boot)",
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
key: "server.maxFileReadBytes",
|
|
217
|
+
apply: "restart",
|
|
218
|
+
section: "server",
|
|
219
|
+
reason: "the files/raw cap reads the boot-resolved config value per request",
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
key: "server.dataDir",
|
|
223
|
+
apply: "restart",
|
|
224
|
+
section: "server",
|
|
225
|
+
reason: "boot-resolved store root (resolveStoreRoots folds it once)",
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
key: "server.cacheDir",
|
|
229
|
+
apply: "restart",
|
|
230
|
+
section: "server",
|
|
231
|
+
reason: "boot-resolved store root",
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
key: "server.stateDir",
|
|
235
|
+
apply: "restart",
|
|
236
|
+
section: "server",
|
|
237
|
+
reason: "boot-resolved store root",
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
key: "server.publicUrl",
|
|
241
|
+
apply: "restart",
|
|
242
|
+
section: "server",
|
|
243
|
+
reason: "extension-route base URLs and notification deep links read the boot-resolved config",
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
key: "server.webui.enabled",
|
|
247
|
+
apply: "restart",
|
|
248
|
+
section: "interface",
|
|
249
|
+
reason: "the bundle resolves and mounts at serve time (boot)",
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
key: "server.webui.bundle",
|
|
253
|
+
apply: "restart",
|
|
254
|
+
section: "interface",
|
|
255
|
+
reason: "the bundle selection resolves at serve time (boot)",
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
key: "server.webuiBundle",
|
|
259
|
+
apply: "restart",
|
|
260
|
+
section: "interface",
|
|
261
|
+
reason: "deprecated alias of webui.bundle (one release); the selection resolves at serve time",
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
key: "server.timezone",
|
|
265
|
+
apply: "restart",
|
|
266
|
+
section: "server",
|
|
267
|
+
reason: "the jobs defaultTz resolves once into the schedule runtime at boot",
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
key: "server.compaction.enabled",
|
|
271
|
+
apply: "restart",
|
|
272
|
+
section: "advanced",
|
|
273
|
+
reason: "compaction policy resolves into the boot harness settings",
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
key: "server.compaction.reserveTokens",
|
|
277
|
+
apply: "restart",
|
|
278
|
+
section: "advanced",
|
|
279
|
+
reason: "compaction policy resolves into the boot harness settings",
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
key: "server.compaction.keepRecentTokens",
|
|
283
|
+
apply: "restart",
|
|
284
|
+
section: "advanced",
|
|
285
|
+
reason: "compaction policy resolves into the boot harness settings",
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
key: "server.compaction.backgroundTokens",
|
|
289
|
+
apply: "restart",
|
|
290
|
+
section: "advanced",
|
|
291
|
+
reason: "compaction policy resolves into the boot harness settings",
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
key: "server.memorySeam.hookDeadlineMs",
|
|
295
|
+
apply: "restart",
|
|
296
|
+
section: "advanced",
|
|
297
|
+
reason: "the event bus's bounds are set at open (boot)",
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
key: "server.memorySeam.idleThresholdMs",
|
|
301
|
+
apply: "restart",
|
|
302
|
+
section: "advanced",
|
|
303
|
+
reason: "the event bus's idle detection arms at open (boot)",
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
key: "server.memorySeam.workerDeadlineMs",
|
|
307
|
+
apply: "restart",
|
|
308
|
+
section: "advanced",
|
|
309
|
+
reason: "the event bus's worker bound is set at open (boot)",
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
key: "server.memorySeam.queueMax",
|
|
313
|
+
apply: "restart",
|
|
314
|
+
section: "advanced",
|
|
315
|
+
reason: "the event bus's queue bound is set at open (boot)",
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
key: "server.providers.refreshIntervalMinutes",
|
|
319
|
+
apply: "live",
|
|
320
|
+
section: "providers",
|
|
321
|
+
reason: "the interval scheduler re-arms on change (the settings-changed wiring in boot)",
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
key: "server.auth.methods",
|
|
325
|
+
apply: "restart",
|
|
326
|
+
section: "server",
|
|
327
|
+
reason: "the auth pipeline's method list resolves once at server construction",
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
key: "server.auth.sessionDays",
|
|
331
|
+
apply: "live",
|
|
332
|
+
section: "server",
|
|
333
|
+
reason: "read from the live settings store when a login creates a session",
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
key: "server.auth.proxy.trustedProxies",
|
|
337
|
+
apply: "restart",
|
|
338
|
+
section: "server",
|
|
339
|
+
reason: "proxy trust resolves once into the pipeline's peer check",
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
key: "server.auth.proxy.secretHeader",
|
|
343
|
+
apply: "restart",
|
|
344
|
+
section: "server",
|
|
345
|
+
reason: "header names resolve once into the pipeline's forward-auth stage",
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
key: "server.auth.proxy.userHeader",
|
|
349
|
+
apply: "restart",
|
|
350
|
+
section: "server",
|
|
351
|
+
reason: "header names resolve once into the pipeline's forward-auth stage",
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
key: "server.auth.proxy.groupsHeader",
|
|
355
|
+
apply: "restart",
|
|
356
|
+
section: "server",
|
|
357
|
+
reason: "header names resolve once into the pipeline's forward-auth stage",
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
key: "server.auth.proxy.nameHeader",
|
|
361
|
+
apply: "restart",
|
|
362
|
+
section: "server",
|
|
363
|
+
reason: "header names resolve once into the pipeline's forward-auth stage",
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
key: "server.auth.proxy.emailHeader",
|
|
367
|
+
apply: "restart",
|
|
368
|
+
section: "server",
|
|
369
|
+
reason: "header names resolve once into the pipeline's forward-auth stage",
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
key: "server.auth.proxy.autoProvision",
|
|
373
|
+
apply: "restart",
|
|
374
|
+
section: "server",
|
|
375
|
+
reason: "provisioning posture resolves once at pipeline construction",
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
key: "server.auth.adminGroups",
|
|
379
|
+
apply: "restart",
|
|
380
|
+
section: "server",
|
|
381
|
+
reason: "the admin-group mapping resolves once at pipeline construction",
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
key: "server.auth.allowedHosts",
|
|
385
|
+
apply: "restart",
|
|
386
|
+
section: "server",
|
|
387
|
+
reason: "the Host allowlist resolves once at pipeline construction",
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
key: "server.auth.allowedOrigins",
|
|
391
|
+
apply: "restart",
|
|
392
|
+
section: "server",
|
|
393
|
+
reason: "the Origin allowlist resolves once at pipeline construction",
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
key: "server.metrics.public",
|
|
397
|
+
apply: "restart",
|
|
398
|
+
section: "server",
|
|
399
|
+
reason: "the /metrics route's public gate registers at boot",
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
key: "server.dev",
|
|
403
|
+
apply: "restart",
|
|
404
|
+
section: "server",
|
|
405
|
+
reason: "read from the boot config (meta, U1 gallery, U3 error bodies)",
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
key: "server.supervised",
|
|
409
|
+
apply: "restart",
|
|
410
|
+
section: "server",
|
|
411
|
+
reason: "read from the boot config (U4 §13.3): gates POST /v1/admin/restart and meta's supervised — and a write can only take effect at the NEXT boot, since the route it gates is this boot's",
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
key: "server.backup.path",
|
|
415
|
+
apply: "restart",
|
|
416
|
+
section: "advanced",
|
|
417
|
+
reason: "the backup target and honesty window resolve into the boot config's health",
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
key: "server.backup.staleAfterHours",
|
|
421
|
+
apply: "restart",
|
|
422
|
+
section: "advanced",
|
|
423
|
+
reason: "the backup honesty window resolves into the boot config's health",
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
key: "server.backup.s3.bucket",
|
|
427
|
+
apply: "restart",
|
|
428
|
+
section: "advanced",
|
|
429
|
+
reason: "the backup target resolves into the boot config's health",
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
key: "server.backup.s3.prefix",
|
|
433
|
+
apply: "restart",
|
|
434
|
+
section: "advanced",
|
|
435
|
+
reason: "the backup target resolves into the boot config's health",
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
key: "server.backup.s3.endpoint",
|
|
439
|
+
apply: "restart",
|
|
440
|
+
section: "advanced",
|
|
441
|
+
reason: "the backup target resolves into the boot config's health",
|
|
442
|
+
},
|
|
443
|
+
];
|
|
444
|
+
/** The registry keyed by `key` (constant lookup for classification). */
|
|
445
|
+
const BY_KEY = new Map(CORE_SETTING_KEYS.map((entry) => [entry.key, entry]));
|
|
446
|
+
/**
|
|
447
|
+
* Classify one flattened key path. Keys the registry has not classified
|
|
448
|
+
* read as `"restart"` (conservative: a boot-read default is the safe
|
|
449
|
+
* assumption for an unclassified knob).
|
|
450
|
+
*/
|
|
451
|
+
export function applyOf(key) {
|
|
452
|
+
return BY_KEY.get(key)?.apply ?? "restart";
|
|
453
|
+
}
|
package/dist/skills/index.js
CHANGED
|
@@ -197,6 +197,12 @@ export async function scanSkills(env, context, opts) {
|
|
|
197
197
|
if (!listing.ok) {
|
|
198
198
|
if (listing.error.code === "not_found")
|
|
199
199
|
return [];
|
|
200
|
+
// An unavailable sandbox env (the host has no usable isolation
|
|
201
|
+
// helper) degrades to "no skills" rather than failing the submit:
|
|
202
|
+
// the expansion is a courtesy lookup, and a 500 here would strand
|
|
203
|
+
// an ordinary user message on a Landlock-less machine.
|
|
204
|
+
if (listing.error.message.includes("isolation_unavailable"))
|
|
205
|
+
return [];
|
|
200
206
|
throw new Error(`Failed to list the ${SKILLS_DIRECTORY}/ directory: ${listing.error.message}`, { cause: listing.error });
|
|
201
207
|
}
|
|
202
208
|
const directories = listing.value
|
|
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.1] - 2026-10-28
|
|
11
|
+
### Added
|
|
12
|
+
- Additive listener metadata on the meta response: host, port, and
|
|
13
|
+
measured address families.
|
|
14
|
+
|
|
15
|
+
## [0.2.0] - 2026-10-27
|
|
16
|
+
### Added
|
|
17
|
+
- Surface and block wire types extended for the U5/U6/U7 workstreams:
|
|
18
|
+
chat-block entry and state families, interaction and ambient bindings,
|
|
19
|
+
block transport contracts, and settings-section types.
|
|
20
|
+
|
|
10
21
|
## [0.1.2] - 2026-10-24
|
|
11
22
|
### Added
|
|
12
23
|
- Extension-surface wire types, including block-instance and live-view
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Per-resource sharing and content access (core hardening W1 Task 5, spec
|
|
3
|
-
* §5.9 ruling 6/10: per-resource sharing; groups
|
|
3
|
+
* §5.9 ruling 6/10: per-resource sharing; multi-user M3b adds groups).
|
|
4
4
|
*
|
|
5
5
|
* Part of the shared leaf package (`@sigrun/shared`): the server computes
|
|
6
6
|
* access through `accessOf`, the clients render the `sharing` state — one
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* 2. ownerless resource → household write (everyone);
|
|
14
14
|
* 3. user === owner → write;
|
|
15
15
|
* 4. household sharing with a defined user → the shared level;
|
|
16
|
-
* 5. people sharing including the user → the shared level;
|
|
16
|
+
* 5. people sharing including the user or one of their groups → the shared level;
|
|
17
17
|
* 6. otherwise none (hidden: 404 on every :id route, absent from lists).
|
|
18
18
|
*
|
|
19
19
|
* Anonymous callers (a principal with no user) get nothing from a shared
|
|
@@ -30,6 +30,7 @@ export type Sharing = {
|
|
|
30
30
|
} | {
|
|
31
31
|
readonly scope: "people";
|
|
32
32
|
readonly users: string[];
|
|
33
|
+
readonly groups?: string[];
|
|
33
34
|
readonly level: "read" | "write";
|
|
34
35
|
};
|
|
35
36
|
/** The resolved access level of a principal to one resource. */
|
|
@@ -38,6 +39,7 @@ export type Access = "none" | "read" | "write";
|
|
|
38
39
|
export interface AccessPrincipal {
|
|
39
40
|
readonly user?: string;
|
|
40
41
|
readonly superuser?: boolean;
|
|
42
|
+
readonly groups?: readonly string[];
|
|
41
43
|
}
|
|
42
44
|
/**
|
|
43
45
|
* Resolve one principal's access to one resource. Rule order per the
|